Skip to content

Commit a82b312

Browse files
Set constant mac for host veth interface in transparent vlan mode (#1906)
* set constant mac for host veth interface * fixed a race issue in transparent-vlan where delete can happen after add and removes route add by ADD call * moved log to place where its executed * enable proxy arp on bridge to allow public connectivity from apipa interface * validate newly created namespace is not same as host namespace * addressed comments and added UTs * fixed cni delete call for linux multitenancy * lint fixes * windows lint fixes * lint fixes * fix issues with network namespace creation and vlan interface creation * Removed deletehostveth flag and delete host veth on delete endpoint trigger * lint fix * address comment
1 parent a024d7d commit a82b312

22 files changed

+359
-120
lines changed

cni/network/network.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -466,10 +466,11 @@ func (plugin *NetPlugin) Add(args *cniSkel.CmdArgs) error {
466466

467467
// iterate ipamAddResults and program the endpoint
468468
for i := 0; i < len(ipamAddResults); i++ {
469+
var networkID string
469470
ipamAddResult = ipamAddResults[i]
470471

471472
options := make(map[string]any)
472-
networkID, err := plugin.getNetworkName(args.Netns, &ipamAddResult, nwCfg)
473+
networkID, err = plugin.getNetworkName(args.Netns, &ipamAddResult, nwCfg)
473474

474475
endpointID := GetEndpointID(args)
475476
policies := cni.GetPoliciesFromNwCfg(nwCfg.AdditionalArgs)
@@ -557,7 +558,8 @@ func (plugin *NetPlugin) Add(args *cniSkel.CmdArgs) error {
557558
natInfo: natInfo,
558559
}
559560

560-
epInfo, err := plugin.createEndpointInternal(&createEndpointInternalOpt)
561+
var epInfo network.EndpointInfo
562+
epInfo, err = plugin.createEndpointInternal(&createEndpointInternalOpt)
561563
if err != nil {
562564
log.Errorf("Endpoint creation failed:%w", err)
563565
return err
@@ -953,7 +955,7 @@ func (plugin *NetPlugin) Delete(args *cniSkel.CmdArgs) error {
953955
numEndpointsToDelete := 1
954956
// only get number of endpoints if it's multitenancy mode
955957
if nwCfg.MultiTenancy {
956-
numEndpointsToDelete = plugin.nm.GetNumEndpointsInNetNs(args.Netns)
958+
numEndpointsToDelete = plugin.nm.GetNumEndpointsByContainerID(args.ContainerID)
957959
}
958960

959961
log.Printf("[cni-net] number of endpoints to be deleted %d", numEndpointsToDelete)
@@ -973,23 +975,21 @@ func (plugin *NetPlugin) Delete(args *cniSkel.CmdArgs) error {
973975
}
974976
// Query the network.
975977
if nwInfo, err = plugin.nm.GetNetworkInfo(networkID); err != nil {
976-
if !nwCfg.MultiTenancy {
977-
log.Printf("[cni-net] Failed to query network:%s: %v", networkID, err)
978-
// Log the error but return success if the network is not found.
979-
// if cni hits this, mostly state file would be missing and it can be reboot scenario where
980-
// container runtime tries to delete and create pods which existed before reboot.
981-
err = nil
982-
return err
983-
}
978+
// Log the error but return success if the network is not found.
979+
// if cni hits this, mostly state file would be missing and it can be reboot scenario where
980+
// container runtime tries to delete and create pods which existed before reboot.
981+
log.Printf("[cni-net] Failed to query network:%s: %v", networkID, err)
982+
err = nil
983+
return err
984984
}
985985

986986
endpointID := GetEndpointID(args)
987987
// Query the endpoint.
988988
if epInfo, err = plugin.nm.GetEndpointInfo(networkID, endpointID); err != nil {
989+
log.Printf("[cni-net] GetEndpoint for endpointID: %s returns: %v", endpointID, err)
989990
if !nwCfg.MultiTenancy {
990991
// attempt to release address associated with this Endpoint id
991992
// This is to ensure clean up is done even in failure cases
992-
log.Printf("[cni-net] Failed to query endpoint %s: %v", endpointID, err)
993993
logAndSendEvent(plugin, fmt.Sprintf("Release ip by ContainerID (endpoint not found):%v", args.ContainerID))
994994
if err = plugin.ipamInvoker.Delete(nil, nwCfg, args, nwInfo.Options); err != nil {
995995
return plugin.RetriableError(fmt.Errorf("failed to release address(no endpoint): %w", err))

netio/mocknetio.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ import (
66
"net"
77
)
88

9+
type getInterfaceValidationFn func(name string) (*net.Interface, error)
10+
911
type MockNetIO struct {
1012
fail bool
1113
failAttempt int
1214
numTimesCalled int
15+
getInterfaceFn getInterfaceValidationFn
1316
}
1417

1518
// ErrMockNetIOFail - mock netio error
@@ -22,13 +25,21 @@ func NewMockNetIO(fail bool, failAttempt int) *MockNetIO {
2225
}
2326
}
2427

28+
func (netshim *MockNetIO) SetGetInterfaceValidatonFn(fn getInterfaceValidationFn) {
29+
netshim.getInterfaceFn = fn
30+
}
31+
2532
func (netshim *MockNetIO) GetNetworkInterfaceByName(name string) (*net.Interface, error) {
2633
netshim.numTimesCalled++
2734

2835
if netshim.fail && netshim.failAttempt == netshim.numTimesCalled {
2936
return nil, fmt.Errorf("%w:%s", ErrMockNetIOFail, name)
3037
}
3138

39+
if netshim.getInterfaceFn != nil {
40+
return netshim.getInterfaceFn(name)
41+
}
42+
3243
hwAddr, _ := net.ParseMAC("ab:cd:ef:12:34:56")
3344

3445
return &net.Interface{

netlink/mocknetlink.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ func newErrorMockNetlink(errStr string) error {
1313
return fmt.Errorf("%w : %s", ErrorMockNetlink, errStr)
1414
}
1515

16+
type routeValidateFn func(route *Route) error
17+
1618
type MockNetlink struct {
17-
returnError bool
18-
errorString string
19+
returnError bool
20+
errorString string
21+
deleteRouteFn routeValidateFn
22+
addRouteFn routeValidateFn
1923
}
2024

2125
func NewMockNetlink(returnError bool, errorString string) *MockNetlink {
@@ -25,6 +29,14 @@ func NewMockNetlink(returnError bool, errorString string) *MockNetlink {
2529
}
2630
}
2731

32+
func (f *MockNetlink) SetDeleteRouteValidationFn(fn routeValidateFn) {
33+
f.deleteRouteFn = fn
34+
}
35+
36+
func (f *MockNetlink) SetAddRouteValidationFn(fn routeValidateFn) {
37+
f.addRouteFn = fn
38+
}
39+
2840
func (f *MockNetlink) error() error {
2941
if f.returnError {
3042
return newErrorMockNetlink(f.errorString)
@@ -88,10 +100,16 @@ func (f *MockNetlink) GetIPRoute(*Route) ([]*Route, error) {
88100
return nil, f.error()
89101
}
90102

91-
func (f *MockNetlink) AddIPRoute(*Route) error {
103+
func (f *MockNetlink) AddIPRoute(r *Route) error {
104+
if f.addRouteFn != nil {
105+
return f.addRouteFn(r)
106+
}
92107
return f.error()
93108
}
94109

95-
func (f *MockNetlink) DeleteIPRoute(*Route) error {
110+
func (f *MockNetlink) DeleteIPRoute(r *Route) error {
111+
if f.deleteRouteFn != nil {
112+
return f.deleteRouteFn(r)
113+
}
96114
return f.error()
97115
}

netns/netns.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,11 @@ func (f *Netns) NewNamed(name string) (int, error) {
3636
func (f *Netns) DeleteNamed(name string) error {
3737
return errors.Wrap(netns.DeleteNamed(name), "netns impl")
3838
}
39+
40+
func (f *Netns) IsNamespaceEqual(fd1, fd2 int) bool {
41+
return netns.NsHandle(fd1).Equal(netns.NsHandle(fd2))
42+
}
43+
44+
func (f *Netns) NamespaceUniqueID(fd int) string {
45+
return netns.NsHandle(fd).UniqueId()
46+
}

network/bridge_endpointclient_linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ func (client *LinuxBridgeEndpointClient) ConfigureContainerInterfacesAndRoutes(e
210210
return nil
211211
}
212212

213-
func (client *LinuxBridgeEndpointClient) DeleteEndpoints(ep *endpoint, _ bool) error {
213+
func (client *LinuxBridgeEndpointClient) DeleteEndpoints(ep *endpoint) error {
214214
log.Printf("[net] Deleting veth pair %v %v.", ep.HostIfName, ep.IfName)
215215
err := client.netlink.DeleteLink(ep.HostIfName)
216216
if err != nil {

network/endpoint_linux.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ func (nw *network) newEndpointImpl(
158158
}
159159
// set deleteHostVeth to true to cleanup host veth interface if created
160160
//nolint:errcheck // ignore error
161-
epClient.DeleteEndpoints(endpt, true)
161+
epClient.DeleteEndpoints(endpt)
162162
}
163163
}()
164164

@@ -284,7 +284,7 @@ func (nw *network) deleteEndpointImpl(nl netlink.NetlinkInterface, plc platform.
284284
// deleteHostVeth set to false not to delete veth as CRI will remove network namespace and
285285
// veth will get removed as part of that.
286286
//nolint:errcheck // ignore error
287-
epClient.DeleteEndpoints(ep, false)
287+
epClient.DeleteEndpoints(ep)
288288

289289
return nil
290290
}
@@ -297,8 +297,6 @@ func addRoutes(nl netlink.NetlinkInterface, netioshim netio.NetIOInterface, inte
297297
ifIndex := 0
298298

299299
for _, route := range routes {
300-
log.Printf("[net] Adding IP route %+v to link %v.", route, interfaceName)
301-
302300
if route.DevName != "" {
303301
devIf, _ := netioshim.GetNetworkInterfaceByName(route.DevName)
304302
ifIndex = devIf.Index
@@ -327,6 +325,7 @@ func addRoutes(nl netlink.NetlinkInterface, netioshim netio.NetIOInterface, inte
327325
Table: route.Table,
328326
}
329327

328+
log.Printf("[net] Adding IP route %+v to link %v.", route, interfaceName)
330329
if err := nl.AddIPRoute(nlRoute); err != nil {
331330
if !strings.Contains(strings.ToLower(err.Error()), "file exists") {
332331
return err
@@ -343,8 +342,6 @@ func deleteRoutes(nl netlink.NetlinkInterface, netioshim netio.NetIOInterface, i
343342
ifIndex := 0
344343

345344
for _, route := range routes {
346-
log.Printf("[net] Deleting IP route %+v from link %v.", route, interfaceName)
347-
348345
if route.DevName != "" {
349346
devIf, _ := netioshim.GetNetworkInterfaceByName(route.DevName)
350347
if devIf == nil {
@@ -353,15 +350,15 @@ func deleteRoutes(nl netlink.NetlinkInterface, netioshim netio.NetIOInterface, i
353350
}
354351

355352
ifIndex = devIf.Index
356-
} else {
353+
} else if interfaceName != "" {
357354
interfaceIf, _ := netioshim.GetNetworkInterfaceByName(interfaceName)
358355
if interfaceIf == nil {
359356
log.Printf("[net] Not deleting route. Interface %v doesn't exist", interfaceName)
360357
continue
361358
}
362-
363359
ifIndex = interfaceIf.Index
364360
}
361+
365362
family := netlink.GetIPAddressFamily(route.Gw)
366363
if route.Gw == nil {
367364
family = netlink.GetIPAddressFamily(route.Dst.IP)
@@ -370,12 +367,13 @@ func deleteRoutes(nl netlink.NetlinkInterface, netioshim netio.NetIOInterface, i
370367
nlRoute := &netlink.Route{
371368
Family: family,
372369
Dst: &route.Dst,
373-
Gw: route.Gw,
374370
LinkIndex: ifIndex,
371+
Gw: route.Gw,
375372
Protocol: route.Protocol,
376373
Scope: route.Scope,
377374
}
378375

376+
log.Printf("[net] Deleting IP route %+v from link %v.", route, interfaceName)
379377
if err := nl.DeleteIPRoute(nlRoute); err != nil {
380378
return err
381379
}

network/endpoint_linux_test.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package network
2+
3+
import (
4+
"net"
5+
"testing"
6+
7+
"github.com/Azure/azure-container-networking/netio"
8+
"github.com/Azure/azure-container-networking/netlink"
9+
. "github.com/onsi/ginkgo"
10+
. "github.com/onsi/gomega"
11+
"github.com/pkg/errors"
12+
)
13+
14+
func TestEndpointLinux(t *testing.T) {
15+
RegisterFailHandler(Fail)
16+
RunSpecs(t, "Endpoint Suite")
17+
}
18+
19+
var _ = Describe("Test TestEndpointLinux", func() {
20+
Describe("Test deleteRoutes", func() {
21+
_, dst, _ := net.ParseCIDR("192.168.0.0/16")
22+
23+
It("DeleteRoute with interfacename explicit", func() {
24+
nlc := netlink.NewMockNetlink(false, "")
25+
nlc.SetDeleteRouteValidationFn(func(r *netlink.Route) error {
26+
Expect(r.LinkIndex).To(Equal(5))
27+
return nil
28+
})
29+
30+
netiocl := netio.NewMockNetIO(false, 0)
31+
netiocl.SetGetInterfaceValidatonFn(func(ifName string) (*net.Interface, error) {
32+
Expect(ifName).To(Equal("eth0"))
33+
return &net.Interface{
34+
Index: 5,
35+
}, nil
36+
})
37+
38+
err := deleteRoutes(nlc, netiocl, "eth0", []RouteInfo{{Dst: *dst, DevName: ""}})
39+
Expect(err).To(BeNil())
40+
})
41+
It("DeleteRoute with interfacename set in Route", func() {
42+
nlc := netlink.NewMockNetlink(false, "")
43+
nlc.SetDeleteRouteValidationFn(func(r *netlink.Route) error {
44+
Expect(r.LinkIndex).To(Equal(6))
45+
return nil
46+
})
47+
48+
netiocl := netio.NewMockNetIO(false, 0)
49+
netiocl.SetGetInterfaceValidatonFn(func(ifName string) (*net.Interface, error) {
50+
Expect(ifName).To(Equal("eth1"))
51+
return &net.Interface{
52+
Index: 6,
53+
}, nil
54+
})
55+
56+
err := deleteRoutes(nlc, netiocl, "", []RouteInfo{{Dst: *dst, DevName: "eth1"}})
57+
Expect(err).To(BeNil())
58+
})
59+
It("DeleteRoute with no ifindex", func() {
60+
nlc := netlink.NewMockNetlink(false, "")
61+
nlc.SetDeleteRouteValidationFn(func(r *netlink.Route) error {
62+
Expect(r.LinkIndex).To(Equal(0))
63+
return nil
64+
})
65+
66+
netiocl := netio.NewMockNetIO(false, 0)
67+
netiocl.SetGetInterfaceValidatonFn(func(ifName string) (*net.Interface, error) {
68+
Expect(ifName).To(Equal("eth1"))
69+
return &net.Interface{
70+
Index: 6,
71+
}, nil
72+
})
73+
74+
err := deleteRoutes(nlc, netiocl, "", []RouteInfo{{Dst: *dst, DevName: ""}})
75+
Expect(err).To(BeNil())
76+
})
77+
})
78+
Describe("Test addRoutes", func() {
79+
_, dst, _ := net.ParseCIDR("192.168.0.0/16")
80+
It("AddRoute with interfacename explicit", func() {
81+
nlc := netlink.NewMockNetlink(false, "")
82+
nlc.SetAddRouteValidationFn(func(r *netlink.Route) error {
83+
Expect(r).NotTo(BeNil())
84+
Expect(r.LinkIndex).To(Equal(5))
85+
return nil
86+
})
87+
88+
netiocl := netio.NewMockNetIO(false, 0)
89+
netiocl.SetGetInterfaceValidatonFn(func(ifName string) (*net.Interface, error) {
90+
Expect(ifName).To(Equal("eth0"))
91+
return &net.Interface{
92+
Index: 5,
93+
}, nil
94+
})
95+
96+
err := addRoutes(nlc, netiocl, "eth0", []RouteInfo{{Dst: *dst, DevName: ""}})
97+
Expect(err).To(BeNil())
98+
})
99+
It("AddRoute with interfacename set in route", func() {
100+
nlc := netlink.NewMockNetlink(false, "")
101+
nlc.SetAddRouteValidationFn(func(r *netlink.Route) error {
102+
Expect(r.LinkIndex).To(Equal(6))
103+
return nil
104+
})
105+
106+
netiocl := netio.NewMockNetIO(false, 0)
107+
netiocl.SetGetInterfaceValidatonFn(func(ifName string) (*net.Interface, error) {
108+
Expect(ifName).To(Equal("eth1"))
109+
return &net.Interface{
110+
Index: 6,
111+
}, nil
112+
})
113+
114+
err := addRoutes(nlc, netiocl, "", []RouteInfo{{Dst: *dst, DevName: "eth1"}})
115+
Expect(err).To(BeNil())
116+
})
117+
It("AddRoute with interfacename not set should return error", func() {
118+
nlc := netlink.NewMockNetlink(false, "")
119+
nlc.SetAddRouteValidationFn(func(r *netlink.Route) error {
120+
Expect(r.LinkIndex).To(Equal(0))
121+
//nolint:goerr113 // for testing
122+
return errors.New("Cannot add route")
123+
})
124+
125+
netiocl := netio.NewMockNetIO(false, 0)
126+
netiocl.SetGetInterfaceValidatonFn(func(ifName string) (*net.Interface, error) {
127+
Expect(ifName).To(Equal(""))
128+
return &net.Interface{
129+
Index: 0,
130+
}, errors.Wrapf(netio.ErrInterfaceNil, "Cannot get interface")
131+
})
132+
133+
err := addRoutes(nlc, netiocl, "", []RouteInfo{{Dst: *dst, DevName: ""}})
134+
Expect(err).ToNot(BeNil())
135+
})
136+
})
137+
})

network/endpoint_windows.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ func (nw *network) newEndpointImplHnsV1(epInfo *EndpointInfo) (*endpoint, error)
157157
VlanID: vlanid,
158158
EnableSnatOnHost: epInfo.EnableSnatOnHost,
159159
NetNs: epInfo.NetNsPath,
160+
ContainerID: epInfo.ContainerID,
160161
}
161162

162163
for _, route := range epInfo.Routes {

0 commit comments

Comments
 (0)