Skip to content

Commit 9ad07d1

Browse files
Merge pull request #21446 from vikas-goel/network
Set interface name to the network_interface name for macvlan and ipvlan networks
2 parents 4c9bd24 + a8b2256 commit 9ad07d1

File tree

3 files changed

+313
-8
lines changed

3 files changed

+313
-8
lines changed

libpod/networking_common.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
353353

354354
// check if network exists and if the input is an ID we get the name
355355
// CNI and netavark and the libpod db only uses names so it is important that we only use the name
356-
netName, err = c.runtime.normalizeNetworkName(netName)
356+
netName, _, err = c.runtime.normalizeNetworkName(netName)
357357
if err != nil {
358358
return err
359359
}
@@ -467,7 +467,8 @@ func (c *Container) NetworkConnect(nameOrID, netName string, netOpts types.PerNe
467467

468468
// check if network exists and if the input is an ID we get the name
469469
// CNI and netavark and the libpod db only uses names so it is important that we only use the name
470-
netName, err = c.runtime.normalizeNetworkName(netName)
470+
var nicName string
471+
netName, nicName, err = c.runtime.normalizeNetworkName(netName)
471472
if err != nil {
472473
return err
473474
}
@@ -481,6 +482,13 @@ func (c *Container) NetworkConnect(nameOrID, netName string, netOpts types.PerNe
481482

482483
netOpts.Aliases = append(netOpts.Aliases, getExtraNetworkAliases(c)...)
483484

485+
// check whether interface is to be named as the network_interface
486+
// when name left unspecified
487+
if netOpts.InterfaceName == "" {
488+
netOpts.InterfaceName = nicName
489+
}
490+
491+
// set default interface name
484492
if netOpts.InterfaceName == "" {
485493
netOpts.InterfaceName = getFreeInterfaceName(networks)
486494
if netOpts.InterfaceName == "" {
@@ -632,14 +640,24 @@ func (r *Runtime) ConnectContainerToNetwork(nameOrID, netName string, netOpts ty
632640
return ctr.NetworkConnect(nameOrID, netName, netOpts)
633641
}
634642

635-
// normalizeNetworkName takes a network name, a partial or a full network ID and returns the network name.
643+
// normalizeNetworkName takes a network name, a partial or a full network ID and
644+
// returns: 1) the network name and 2) the network_interface name for macvlan
645+
// and ipvlan drivers if the naming pattern is "device" defined in the
646+
// containers.conf file. Else, "".
636647
// If the network is not found an error is returned.
637-
func (r *Runtime) normalizeNetworkName(nameOrID string) (string, error) {
648+
func (r *Runtime) normalizeNetworkName(nameOrID string) (string, string, error) {
638649
net, err := r.network.NetworkInspect(nameOrID)
639650
if err != nil {
640-
return "", err
651+
return "", "", err
641652
}
642-
return net.Name, nil
653+
654+
netIface := ""
655+
namingPattern := r.config.Containers.InterfaceName
656+
if namingPattern == "device" && (net.Driver == types.MacVLANNetworkDriver || net.Driver == types.IPVLANNetworkDriver) {
657+
netIface = net.NetworkInterface
658+
}
659+
660+
return net.Name, netIface, nil
643661
}
644662

645663
// ocicniPortsToNetTypesPorts convert the old port format to the new one

libpod/runtime_ctr.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,18 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
264264
}
265265
i := 0
266266
for nameOrID, opts := range ctr.config.Networks {
267-
netName, err := r.normalizeNetworkName(nameOrID)
267+
netName, nicName, err := r.normalizeNetworkName(nameOrID)
268268
if err != nil {
269269
return nil, err
270270
}
271-
// assign interface name if empty
271+
272+
// check whether interface is to be named as the network_interface
273+
// when name left unspecified
274+
if opts.InterfaceName == "" {
275+
opts.InterfaceName = nicName
276+
}
277+
278+
// assign default interface name if empty
272279
if opts.InterfaceName == "" {
273280
for i < 100000 {
274281
ifName := fmt.Sprintf("eth%d", i)
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
package integration
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
7+
. "github.com/containers/podman/v4/test/utils"
8+
. "github.com/onsi/ginkgo/v2"
9+
. "github.com/onsi/gomega"
10+
)
11+
12+
func isDebianRunc(pTest *PodmanTestIntegration) bool {
13+
info := GetHostDistributionInfo()
14+
if info.Distribution == "debian" && pTest.OCIRuntime == "runc" {
15+
return true
16+
}
17+
18+
return false
19+
}
20+
21+
func createNetworkDevice(name string) {
22+
session := SystemExec("ip", []string{"link", "add", name, "type", "bridge"})
23+
session.WaitWithDefaultTimeout()
24+
Expect(session).Should(ExitCleanly())
25+
}
26+
27+
func deleteNetworkDevice(name string) {
28+
session := SystemExec("ip", []string{"link", "delete", name})
29+
session.WaitWithDefaultTimeout()
30+
Expect(session).Should(ExitCleanly())
31+
}
32+
33+
func createContainersConfFileWithDeviceIfaceName(pTest *PodmanTestIntegration) {
34+
configPath := filepath.Join(pTest.TempDir, "containers.conf")
35+
containersConf := []byte("[containers]\ninterface_name = \"device\"\n")
36+
err := os.WriteFile(configPath, containersConf, os.ModePerm)
37+
Expect(err).ToNot(HaveOccurred())
38+
39+
// Set custom containers.conf file
40+
os.Setenv("CONTAINERS_CONF_OVERRIDE", configPath)
41+
if IsRemote() {
42+
pTest.RestartRemoteService()
43+
}
44+
}
45+
46+
var _ = Describe("Podman container interface name", func() {
47+
48+
It("podman container interface name for bridge network", func() {
49+
// Assert that the network interface name inside container for
50+
// bridge network is ethX regardless of interface_name setting
51+
// in the containers.conf file.
52+
53+
netName1 := createNetworkName("bridge")
54+
netName2 := createNetworkName("bridge")
55+
56+
defer podmanTest.removeNetwork(netName1)
57+
nc1 := podmanTest.Podman([]string{"network", "create", netName1})
58+
nc1.WaitWithDefaultTimeout()
59+
Expect(nc1).Should(ExitCleanly())
60+
61+
defer podmanTest.removeNetwork(netName2)
62+
nc2 := podmanTest.Podman([]string{"network", "create", netName2})
63+
nc2.WaitWithDefaultTimeout()
64+
Expect(nc2).Should(ExitCleanly())
65+
66+
for _, override := range []bool{false, true} {
67+
if override {
68+
createContainersConfFileWithDeviceIfaceName(podmanTest)
69+
}
70+
71+
ctr := podmanTest.Podman([]string{"run", "-d", "--network", netName1, "--name", "test", ALPINE, "top"})
72+
ctr.WaitWithDefaultTimeout()
73+
Expect(ctr).Should(ExitCleanly())
74+
75+
exec1 := podmanTest.Podman([]string{"exec", "test", "ip", "addr", "show", "eth0"})
76+
exec1.WaitWithDefaultTimeout()
77+
Expect(exec1).Should(ExitCleanly())
78+
Expect(exec1.OutputToString()).Should(ContainSubstring("eth0"))
79+
80+
conn := podmanTest.Podman([]string{"network", "connect", netName2, "test"})
81+
conn.WaitWithDefaultTimeout()
82+
Expect(conn).Should(ExitCleanly())
83+
84+
exec2 := podmanTest.Podman([]string{"exec", "test", "ip", "addr", "show", "eth1"})
85+
exec2.WaitWithDefaultTimeout()
86+
Expect(exec2).Should(ExitCleanly())
87+
Expect(exec2.OutputToString()).Should(ContainSubstring("eth1"))
88+
89+
rm := podmanTest.Podman([]string{"rm", "--time=0", "-f", "test"})
90+
rm.WaitWithDefaultTimeout()
91+
Expect(rm).Should(ExitCleanly())
92+
}
93+
})
94+
95+
It("podman container interface name for macvlan/ipvlan network with no parent", func() {
96+
// Assert that the network interface name inside container for
97+
// macvlan/ipvlan network with no parent interface is ethX
98+
// regardless of interface_name setting in the containers.conf
99+
// file.
100+
101+
for _, override := range []bool{false, true} {
102+
if override {
103+
createContainersConfFileWithDeviceIfaceName(podmanTest)
104+
}
105+
106+
for _, driverType := range []string{"macvlan", "ipvlan"} {
107+
if driverType == "ipvlan" && isDebianRunc(podmanTest) {
108+
GinkgoWriter.Println("FIXME: Fails with netavark < 1.10. Re-enable once Debian gets an update")
109+
continue
110+
}
111+
112+
netName1 := createNetworkName(driverType)
113+
netName2 := createNetworkName(driverType)
114+
115+
// There is no nic created by the macvlan/ipvlan driver.
116+
defer podmanTest.removeNetwork(netName1)
117+
nc1 := podmanTest.Podman([]string{"network", "create", "-d", driverType, "--subnet", "10.10.0.0/24", netName1})
118+
nc1.WaitWithDefaultTimeout()
119+
Expect(nc1).Should(ExitCleanly())
120+
121+
ctr := podmanTest.Podman([]string{"run", "-d", "--network", netName1, "--name", "test", ALPINE, "top"})
122+
ctr.WaitWithDefaultTimeout()
123+
Expect(ctr).Should(ExitCleanly())
124+
125+
exec1 := podmanTest.Podman([]string{"exec", "test", "ip", "addr", "show", "eth0"})
126+
exec1.WaitWithDefaultTimeout()
127+
Expect(exec1).Should(ExitCleanly())
128+
Expect(exec1.OutputToString()).Should(ContainSubstring("eth0"))
129+
130+
defer podmanTest.removeNetwork(netName2)
131+
nc2 := podmanTest.Podman([]string{"network", "create", "-d", driverType, "--subnet", "10.25.40.0/24", netName2})
132+
nc2.WaitWithDefaultTimeout()
133+
Expect(nc2).Should(ExitCleanly())
134+
135+
conn := podmanTest.Podman([]string{"network", "connect", netName2, "test"})
136+
conn.WaitWithDefaultTimeout()
137+
Expect(conn).Should(ExitCleanly())
138+
139+
exec2 := podmanTest.Podman([]string{"exec", "test", "ip", "addr", "show", "eth1"})
140+
exec2.WaitWithDefaultTimeout()
141+
Expect(exec2).Should(ExitCleanly())
142+
Expect(exec2.OutputToString()).Should(ContainSubstring("eth1"))
143+
144+
rm := podmanTest.Podman([]string{"rm", "--time=0", "-f", "test"})
145+
rm.WaitWithDefaultTimeout()
146+
Expect(rm).Should(ExitCleanly())
147+
}
148+
}
149+
})
150+
151+
It("podman container interface name with default scheme for macvlan/ipvlan network with parent", func() {
152+
// Assert that the network interface name inside container for
153+
// macvlan/ipvlan network, created with a specific parent
154+
// interface, continues to be ethX when interface_name in the
155+
// containers.conf file is set to default value, i.e., "".
156+
157+
SkipIfRootless("cannot create network device in rootless mode.")
158+
159+
for _, driverType := range []string{"macvlan", "ipvlan"} {
160+
if driverType == "ipvlan" && isDebianRunc(podmanTest) {
161+
GinkgoWriter.Println("FIXME: Fails with netavark < 1.10. Re-enable once Debian gets an update")
162+
continue
163+
}
164+
165+
// Create a nic to be used as a parent for macvlan/ipvlan network.
166+
nicName1 := createNetworkName("nic")[:8]
167+
nicName2 := createNetworkName("nic")[:8]
168+
169+
netName1 := createNetworkName(driverType)
170+
netName2 := createNetworkName(driverType)
171+
172+
parent1 := "parent=" + nicName1
173+
parent2 := "parent=" + nicName2
174+
175+
defer deleteNetworkDevice(nicName1)
176+
createNetworkDevice(nicName1)
177+
178+
defer podmanTest.removeNetwork(netName1)
179+
nc1 := podmanTest.Podman([]string{"network", "create", "-d", driverType, "-o", parent1, "--subnet", "10.10.0.0/24", netName1})
180+
nc1.WaitWithDefaultTimeout()
181+
Expect(nc1).Should(ExitCleanly())
182+
183+
ctr := podmanTest.Podman([]string{"run", "-d", "--network", netName1, "--name", "test", ALPINE, "top"})
184+
ctr.WaitWithDefaultTimeout()
185+
Expect(ctr).Should(ExitCleanly())
186+
187+
exec1 := podmanTest.Podman([]string{"exec", "test", "ip", "addr", "show", "eth0"})
188+
exec1.WaitWithDefaultTimeout()
189+
Expect(exec1).Should(ExitCleanly())
190+
Expect(exec1.OutputToString()).Should(ContainSubstring("eth0"))
191+
192+
defer deleteNetworkDevice(nicName2)
193+
createNetworkDevice(nicName2)
194+
195+
defer podmanTest.removeNetwork(netName2)
196+
nc2 := podmanTest.Podman([]string{"network", "create", "-d", driverType, "-o", parent2, "--subnet", "10.25.40.0/24", netName2})
197+
nc2.WaitWithDefaultTimeout()
198+
Expect(nc2).Should(ExitCleanly())
199+
200+
conn := podmanTest.Podman([]string{"network", "connect", netName2, "test"})
201+
conn.WaitWithDefaultTimeout()
202+
Expect(conn).Should(ExitCleanly())
203+
204+
exec2 := podmanTest.Podman([]string{"exec", "test", "ip", "addr", "show", "eth1"})
205+
exec2.WaitWithDefaultTimeout()
206+
Expect(exec2).Should(ExitCleanly())
207+
Expect(exec2.OutputToString()).Should(ContainSubstring("eth1"))
208+
209+
rm := podmanTest.Podman([]string{"rm", "--time=0", "-f", "test"})
210+
rm.WaitWithDefaultTimeout()
211+
Expect(rm).Should(ExitCleanly())
212+
}
213+
})
214+
215+
It("podman container interface name with device scheme for macvlan/ipvlan network with parent", func() {
216+
// Assert that the network interface name inside container for
217+
// macvlan/ipvlan network, created with a specific parent
218+
// interface, is the parent interface name ethX when
219+
// interface_name in the containers.conf file is set to "device"
220+
221+
SkipIfRootless("cannot create network device in rootless mode.")
222+
223+
createContainersConfFileWithDeviceIfaceName(podmanTest)
224+
225+
for _, driverType := range []string{"macvlan", "ipvlan"} {
226+
if driverType == "ipvlan" && isDebianRunc(podmanTest) {
227+
GinkgoWriter.Println("FIXME: Fails with netavark < 1.10. Re-enable once Debian gets an update")
228+
continue
229+
}
230+
231+
// Create a nic to be used as a parent for the network.
232+
nicName1 := createNetworkName("nic")[:8]
233+
nicName2 := createNetworkName("nic")[:8]
234+
235+
netName1 := createNetworkName(driverType)
236+
netName2 := createNetworkName(driverType)
237+
238+
parent1 := "parent=" + nicName1
239+
parent2 := "parent=" + nicName2
240+
241+
defer deleteNetworkDevice(nicName1)
242+
createNetworkDevice(nicName1)
243+
244+
defer podmanTest.removeNetwork(netName1)
245+
nc1 := podmanTest.Podman([]string{"network", "create", "-d", driverType, "-o", parent1, "--subnet", "10.10.0.0/24", netName1})
246+
nc1.WaitWithDefaultTimeout()
247+
Expect(nc1).Should(ExitCleanly())
248+
249+
ctr := podmanTest.Podman([]string{"run", "-d", "--network", netName1, "--name", "test", ALPINE, "top"})
250+
ctr.WaitWithDefaultTimeout()
251+
Expect(ctr).Should(ExitCleanly())
252+
253+
exec1 := podmanTest.Podman([]string{"exec", "test", "ip", "addr", "show", nicName1})
254+
exec1.WaitWithDefaultTimeout()
255+
Expect(exec1).Should(ExitCleanly())
256+
Expect(exec1.OutputToString()).Should(ContainSubstring(nicName1))
257+
258+
defer deleteNetworkDevice(nicName2)
259+
createNetworkDevice(nicName2)
260+
261+
defer podmanTest.removeNetwork(netName2)
262+
nc2 := podmanTest.Podman([]string{"network", "create", "-d", driverType, "-o", parent2, "--subnet", "10.25.40.0/24", netName2})
263+
nc2.WaitWithDefaultTimeout()
264+
Expect(nc2).Should(ExitCleanly())
265+
266+
conn := podmanTest.Podman([]string{"network", "connect", netName2, "test"})
267+
conn.WaitWithDefaultTimeout()
268+
Expect(conn).Should(ExitCleanly())
269+
270+
exec2 := podmanTest.Podman([]string{"exec", "test", "ip", "addr", "show", nicName2})
271+
exec2.WaitWithDefaultTimeout()
272+
Expect(exec2).Should(ExitCleanly())
273+
Expect(exec2.OutputToString()).Should(ContainSubstring(nicName2))
274+
275+
rm := podmanTest.Podman([]string{"rm", "--time=0", "-f", "test"})
276+
rm.WaitWithDefaultTimeout()
277+
Expect(rm).Should(ExitCleanly())
278+
}
279+
})
280+
})

0 commit comments

Comments
 (0)