diff --git a/hack/update-codegen-dockerized.sh b/hack/update-codegen-dockerized.sh index 6c4fa2d6fd4..270e7637566 100755 --- a/hack/update-codegen-dockerized.sh +++ b/hack/update-codegen-dockerized.sh @@ -58,6 +58,7 @@ MOCKGEN_TARGETS=( "pkg/agent/util/ipset Interface testing" "pkg/agent/util/iptables Interface testing mock_iptables_linux.go" # Must specify linux.go suffix, otherwise compilation would fail on windows platform as source file has linux build tag. "pkg/agent/util/netlink Interface testing mock_netlink_linux.go" + "pkg/agent/util Interface testing mock_net_windows.go" "pkg/antctl AntctlClient ." "pkg/controller/networkpolicy EndpointQuerier testing" "pkg/controller/querier ControllerQuerier testing" diff --git a/pkg/agent/route/route_linux_test.go b/pkg/agent/route/route_linux_test.go index be179f22036..c164d118d42 100644 --- a/pkg/agent/route/route_linux_test.go +++ b/pkg/agent/route/route_linux_test.go @@ -926,8 +926,6 @@ func TestAddRoutes(t *testing.T) { func TestDeleteRoutes(t *testing.T) { tests := []struct { name string - networkConfig *config.NetworkConfig - nodeConfig *config.NodeConfig podCIDR *net.IPNet existingNodeRoutes map[string][]*netlink.Route existingNodeNeighbors map[string]*netlink.Neigh @@ -972,8 +970,6 @@ func TestDeleteRoutes(t *testing.T) { mockIPSet := ipsettest.NewMockInterface(ctrl) c := &Client{netlink: mockNetlink, ipset: mockIPSet, - networkConfig: tt.networkConfig, - nodeConfig: tt.nodeConfig, nodeRoutes: sync.Map{}, nodeNeighbors: sync.Map{}, } @@ -1462,15 +1458,10 @@ func TestAddExternalIPRoute(t *testing.T) { tests := []struct { name string externalIPs []string - serviceRoutes map[string]*netlink.Route expectedCalls func(mockNetlink *netlinktest.MockInterfaceMockRecorder) }{ { - name: "IPv4", - serviceRoutes: map[string]*netlink.Route{ - externalIPv4Addr1: ipv4Route1, - externalIPv4Addr2: ipv4Route2, - }, + name: "IPv4", externalIPs: []string{externalIPv4Addr1, externalIPv4Addr2}, expectedCalls: func(mockNetlink *netlinktest.MockInterfaceMockRecorder) { mockNetlink.RouteReplace(ipv4Route1) @@ -1478,11 +1469,7 @@ func TestAddExternalIPRoute(t *testing.T) { }, }, { - name: "IPv6", - serviceRoutes: map[string]*netlink.Route{ - externalIPv6Addr1: ipv6Route1, - externalIPv6Addr2: ipv6Route2, - }, + name: "IPv6", externalIPs: []string{externalIPv6Addr1, externalIPv6Addr2}, expectedCalls: func(mockNetlink *netlinktest.MockInterfaceMockRecorder) { mockNetlink.RouteReplace(ipv6Route1) diff --git a/pkg/agent/route/route_windows.go b/pkg/agent/route/route_windows.go index 7a67d6475b7..cbd79d1fe6c 100644 --- a/pkg/agent/route/route_windows.go +++ b/pkg/agent/route/route_windows.go @@ -35,6 +35,7 @@ import ( "antrea.io/antrea/pkg/agent/util/winfirewall" binding "antrea.io/antrea/pkg/ovs/openflow" iputil "antrea.io/antrea/pkg/util/ip" + "antrea.io/antrea/pkg/agent/util/winnet" ) const ( @@ -56,12 +57,13 @@ var ( type Client struct { nodeConfig *config.NodeConfig networkConfig *config.NetworkConfig + netUtil winnet.Interface // nodeRoutes caches ip routes to remote Pods. It's a map of podCIDR to routes. - nodeRoutes *sync.Map + nodeRoutes sync.Map // serviceRoutes caches ip routes about Services. - serviceRoutes *sync.Map + serviceRoutes sync.Map // netNatStaticMappings caches Windows NetNat for NodePort. - netNatStaticMappings *sync.Map + netNatStaticMappings sync.Map fwClient *winfirewall.Client bridgeInfIndex int noSNAT bool @@ -73,14 +75,12 @@ type Client struct { // NewClient returns a route client. func NewClient(networkConfig *config.NetworkConfig, noSNAT, proxyAll, connectUplinkToBridge, multicastEnabled bool, serviceCIDRProvider servicecidr.Interface) (*Client, error) { return &Client{ - networkConfig: networkConfig, - nodeRoutes: &sync.Map{}, - serviceRoutes: &sync.Map{}, - netNatStaticMappings: &sync.Map{}, - fwClient: winfirewall.NewClient(), - noSNAT: noSNAT, - proxyAll: proxyAll, - serviceCIDRProvider: serviceCIDRProvider, + networkConfig: networkConfig, + netUtil: &util.Handle{}, + fwClient: winfirewall.NewClient(), + noSNAT: noSNAT, + proxyAll: proxyAll, + serviceCIDRProvider: serviceCIDRProvider, }, nil } @@ -187,7 +187,7 @@ func (c *Client) Reconcile(podCIDRs []string) error { if c.proxyAll && c.isServiceRoute(&routes[i]) { continue } - err = util.RemoveNetRoute(&routes[i]) + err = c.netUtil.RemoveNetRoute(&routes[i]) if err != nil { return err } @@ -222,7 +222,7 @@ func (c *Client) AddRoutes(podCIDR *net.IPNet, nodeName string, peerNodeIP, peer return nil } // Remove the existing route entry if the gateway address is not as expected. - if err := util.RemoveNetRoute(existingRoute); err != nil { + if err := c.netUtil.RemoveNetRoute(existingRoute); err != nil { klog.Errorf("Failed to delete existing route entry with destination %s gateway %s on %s (%s)", podCIDR.String(), peerGwIP.String(), nodeName, peerNodeIP) return err } @@ -232,7 +232,7 @@ func (c *Client) AddRoutes(podCIDR *net.IPNet, nodeName string, peerNodeIP, peer return nil } - if err := util.ReplaceNetRoute(route); err != nil { + if err := c.netUtil.ReplaceNetRoute(route); err != nil { return err } @@ -251,7 +251,7 @@ func (c *Client) DeleteRoutes(podCIDR *net.IPNet) error { } rt := obj.(*util.Route) - if err := util.RemoveNetRoute(rt); err != nil { + if err := c.netUtil.RemoveNetRoute(rt); err != nil { return err } c.nodeRoutes.Delete(podCIDR.String()) @@ -266,13 +266,13 @@ func (c *Client) addVirtualServiceIPRoute(isIPv6 bool) error { svcIP := config.VirtualServiceIPv4 neigh := generateNeigh(svcIP, linkIndex) - if err := util.ReplaceNetNeighbor(neigh); err != nil { + if err := c.netUtil.ReplaceNetNeighbor(neigh); err != nil { return fmt.Errorf("failed to add new IP neighbour for %s: %w", svcIP, err) } klog.InfoS("Added virtual Service IP neighbor", "neighbor", neigh) route := generateRoute(virtualServiceIPv4Net, net.IPv4zero, linkIndex, util.MetricHigh) - if err := util.ReplaceNetRoute(route); err != nil { + if err := c.netUtil.ReplaceNetRoute(route); err != nil { return fmt.Errorf("failed to install route for virtual Service IP %s: %w", svcIP.String(), err) } c.serviceRoutes.Store(svcIP.String(), route) @@ -289,7 +289,7 @@ func (c *Client) addServiceCIDRRoute(serviceCIDR *net.IPNet) error { oldServiceCIDRRoute, serviceCIDRRouteExists := c.serviceRoutes.Load(serviceIPv4CIDRKey) // Generate a route with the new ClusterIP CIDR and install it. route := generateRoute(serviceCIDR, gw, linkIndex, metric) - if err := util.ReplaceNetRoute(route); err != nil { + if err := c.netUtil.ReplaceNetRoute(route); err != nil { return fmt.Errorf("failed to install a new Service CIDR route: %w", err) } @@ -329,7 +329,7 @@ func (c *Client) addServiceCIDRRoute(serviceCIDR *net.IPNet) error { // Remove stale routes. for _, rt := range staleRoutes { - if err := util.RemoveNetRoute(rt); err != nil { + if err := c.netUtil.RemoveNetRoute(rt); err != nil { return fmt.Errorf("failed to delete stale Service CIDR route %s: %w", rt.String(), err) } else { klog.V(4).InfoS("Deleted stale Service CIDR route successfully", "route", rt) @@ -346,7 +346,7 @@ func (c *Client) addVirtualNodePortDNATIPRoute(isIPv6 bool) error { gw := config.VirtualServiceIPv4 route := generateRoute(virtualNodePortDNATIPv4Net, gw, linkIndex, util.MetricHigh) - if err := util.ReplaceNetRoute(route); err != nil { + if err := c.netUtil.ReplaceNetRoute(route); err != nil { return fmt.Errorf("failed to install route for NodePort DNAT IP %s: %w", vIP.String(), err) } c.serviceRoutes.Store(vIP.String(), route) @@ -387,7 +387,7 @@ func (c *Client) syncIPInfra() { func (c *Client) syncRoute() error { restoreRoute := func(route *util.Route) bool { - if err := util.ReplaceNetRoute(route); err != nil { + if err := c.netUtil.ReplaceNetRoute(route); err != nil { klog.ErrorS(err, "Failed to sync route", "Route", route) return false } @@ -423,7 +423,7 @@ func (c *Client) syncNetNatStaticMapping() error { c.netNatStaticMappings.Range(func(_, v interface{}) bool { mapping := v.(*util.NetNatStaticMapping) - if err := util.ReplaceNetNatStaticMapping(mapping); err != nil { + if err := c.netUtil.ReplaceNetNatStaticMapping(mapping); err != nil { klog.ErrorS(err, "Failed to add netNatStaticMapping", "netNatStaticMapping", mapping) return false } @@ -445,7 +445,7 @@ func (c *Client) isServiceRoute(route *util.Route) bool { func (c *Client) listIPRoutesOnGW() ([]util.Route, error) { family := antreasyscall.AF_INET filter := &util.Route{LinkIndex: c.nodeConfig.GatewayConfig.LinkIndex} - return util.RouteListFiltered(family, filter, util.RT_FILTER_IF) + return c.netUtil.RouteListFiltered(family, filter, util.RT_FILTER_IF) } // initFwRules adds Windows Firewall rules to accept the traffic that is sent to or from local Pods. @@ -479,7 +479,7 @@ func (c *Client) AddNodePort(nodePortAddresses []net.IP, port uint16, protocol b InternalPort: port, Protocol: protocol, } - if err := util.ReplaceNetNatStaticMapping(netNatStaticMapping); err != nil { + if err := c.netUtil.ReplaceNetNatStaticMapping(netNatStaticMapping); err != nil { return err } c.netNatStaticMappings.Store(fmt.Sprintf("%d-%s", port, protocol), netNatStaticMapping) @@ -495,7 +495,7 @@ func (c *Client) DeleteNodePort(nodePortAddresses []net.IP, port uint16, protoco return nil } netNatStaticMapping := obj.(*util.NetNatStaticMapping) - if err := util.RemoveNetNatStaticMapping(netNatStaticMapping); err != nil { + if err := c.netUtil.RemoveNetNatStaticMapping(netNatStaticMapping); err != nil { return err } c.netNatStaticMappings.Delete(key) @@ -512,7 +512,7 @@ func (c *Client) AddExternalIPRoute(externalIP net.IP) error { svcIPNet := util.NewIPNet(externalIP) route := generateRoute(svcIPNet, gw, linkIndex, metric) - if err := util.ReplaceNetRoute(route); err != nil { + if err := c.netUtil.ReplaceNetRoute(route); err != nil { return fmt.Errorf("failed to install route for external IP %s: %w", externalIPStr, err) } c.serviceRoutes.Store(externalIPStr, route) @@ -528,7 +528,7 @@ func (c *Client) DeleteExternalIPRoute(externalIP net.IP) error { klog.V(2).InfoS("Didn't find route for external IP", "IP", externalIPStr) return nil } - if err := util.RemoveNetRoute(route.(*util.Route)); err != nil { + if err := c.netUtil.RemoveNetRoute(route.(*util.Route)); err != nil { return fmt.Errorf("failed to delete route for external IP %s: %w", externalIPStr, err) } c.serviceRoutes.Delete(externalIPStr) diff --git a/pkg/agent/route/route_windows_test.go b/pkg/agent/route/route_windows_test.go index c29afd469dc..7c1399fcaef 100644 --- a/pkg/agent/route/route_windows_test.go +++ b/pkg/agent/route/route_windows_test.go @@ -18,101 +18,423 @@ package route import ( + "fmt" "net" "sync" "testing" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "k8s.io/klog/v2" "antrea.io/antrea/pkg/agent/config" + servicecidrtest "antrea.io/antrea/pkg/agent/servicecidr/testing" "antrea.io/antrea/pkg/agent/util" antreasyscall "antrea.io/antrea/pkg/agent/util/syscall" + winnettesting "antrea.io/antrea/pkg/agent/util/testing" + "antrea.io/antrea/pkg/ovs/openflow" + "antrea.io/antrea/pkg/util/ip" ) var ( - // Leverage loopback interface for testing. - hostGateway = "Loopback Pseudo-Interface 1" - gwLink = getNetLinkIndex("Loopback Pseudo-Interface 1") - nodeConfig = &config.NodeConfig{ - OVSBridge: "Loopback Pseudo-Interface 1", - GatewayConfig: &config.GatewayConfig{ - Name: hostGateway, - LinkIndex: gwLink, - }, + externalIPv4Addr1 = "1.1.1.1" + externalIPv4Addr2 = "1.1.1.2" + externalIPv4Addr1WithPrefix = externalIPv4Addr1 + "/32" + externalIPv4Addr2WithPrefix = externalIPv4Addr2 + "/32" + + ipv4Route1 = generateRoute(ip.MustParseCIDR(externalIPv4Addr1WithPrefix), config.VirtualServiceIPv4, 10, util.MetricHigh) + ipv4Route2 = generateRoute(ip.MustParseCIDR(externalIPv4Addr2WithPrefix), config.VirtualServiceIPv4, 10, util.MetricHigh) + + nodePort = uint16(30000) + protocol = openflow.ProtocolTCP + nodePortNetNatStaticMapping = &util.NetNatStaticMapping{ + Name: antreaNatNodePort, + ExternalIP: net.ParseIP("0.0.0.0"), + ExternalPort: nodePort, + InternalIP: config.VirtualNodePortDNATIPv4, + InternalPort: nodePort, + Protocol: protocol, } ) -func getNetLinkIndex(dev string) int { - link, err := net.InterfaceByName(dev) - if err != nil { - klog.Fatalf("cannot find dev %s: %v", dev, err) +func TestSyncRoutes(t *testing.T) { + ctrl := gomock.NewController(t) + mockNetUtil := winnettesting.NewMockInterface(ctrl) + + nodeRoute1 := &util.Route{DestinationSubnet: ip.MustParseCIDR("192.168.1.0/24"), GatewayAddress: net.ParseIP("1.1.1.1")} + nodeRoute2 := &util.Route{DestinationSubnet: ip.MustParseCIDR("192.168.2.0/24"), GatewayAddress: net.ParseIP("1.1.1.2")} + serviceRoute1 := &util.Route{DestinationSubnet: ip.MustParseCIDR("169.254.0.253/32"), LinkIndex: 10} + serviceRoute2 := &util.Route{DestinationSubnet: ip.MustParseCIDR("169.254.0.252/32"), GatewayAddress: net.ParseIP("169.254.0.253")} + mockNetUtil.EXPECT().ReplaceNetRoute(nodeRoute1) + mockNetUtil.EXPECT().ReplaceNetRoute(nodeRoute2) + mockNetUtil.EXPECT().ReplaceNetRoute(serviceRoute1) + mockNetUtil.EXPECT().ReplaceNetRoute(serviceRoute2) + mockNetUtil.EXPECT().ReplaceNetRoute(&util.Route{ + LinkIndex: 10, + DestinationSubnet: ip.MustParseCIDR("192.168.0.0/24"), + GatewayAddress: net.IPv4zero, + RouteMetric: util.MetricDefault, + }) + + c := &Client{ + netUtil: mockNetUtil, + proxyAll: true, + nodeRoutes: sync.Map{}, + serviceRoutes: sync.Map{}, + nodeConfig: &config.NodeConfig{ + GatewayConfig: &config.GatewayConfig{LinkIndex: 10, IPv4: net.ParseIP("192.168.0.1")}, + PodIPv4CIDR: ip.MustParseCIDR("192.168.0.0/24"), + }, + } + c.nodeRoutes.Store("192.168.1.0/24", nodeRoute1) + c.nodeRoutes.Store("192.168.2.0/24", nodeRoute2) + c.serviceRoutes.Store("169.254.0.253/32", serviceRoute1) + c.serviceRoutes.Store("169.254.0.252/32", serviceRoute2) + + assert.NoError(t, c.syncRoute()) +} + +func TestInitServiceIPRoutes(t *testing.T) { + ctrl := gomock.NewController(t) + mockNetUtil := winnettesting.NewMockInterface(ctrl) + mockServiceCIDRProvider := servicecidrtest.NewMockInterface(ctrl) + c := &Client{netUtil: mockNetUtil, + networkConfig: &config.NetworkConfig{ + TrafficEncapMode: config.TrafficEncapModeEncap, + IPv4Enabled: true, + }, + nodeConfig: &config.NodeConfig{ + GatewayConfig: &config.GatewayConfig{Name: "antrea-gw0", LinkIndex: 10}, + }, + serviceCIDRProvider: mockServiceCIDRProvider, + } + mockNetUtil.EXPECT().ReplaceNetRoute(generateRoute(virtualServiceIPv4Net, net.IPv4zero, 10, util.MetricHigh)) + mockNetUtil.EXPECT().ReplaceNetRoute(generateRoute(virtualNodePortDNATIPv4Net, config.VirtualServiceIPv4, 10, util.MetricHigh)) + mockNetUtil.EXPECT().ReplaceNetNeighbor(generateNeigh(config.VirtualServiceIPv4, 10)) + mockServiceCIDRProvider.EXPECT().AddEventHandler(gomock.Any()) + assert.NoError(t, c.initServiceIPRoutes()) +} + +func TestReconcile(t *testing.T) { + ctrl := gomock.NewController(t) + mockNetUtil := winnettesting.NewMockInterface(ctrl) + c := &Client{netUtil: mockNetUtil, + proxyAll: true, + networkConfig: &config.NetworkConfig{}, + nodeConfig: &config.NodeConfig{ + PodIPv4CIDR: ip.MustParseCIDR("192.168.10.0/24"), + GatewayConfig: &config.GatewayConfig{LinkIndex: 10}, + }, + } + + mockNetUtil.EXPECT().RouteListFiltered(antreasyscall.AF_INET, &util.Route{LinkIndex: 10}, util.RT_FILTER_IF).Return([]util.Route{ + {DestinationSubnet: ip.MustParseCIDR("192.168.10.0/24"), LinkIndex: 10}, // local podCIDR, should not be deleted. + {DestinationSubnet: ip.MustParseCIDR("192.168.1.0/24"), LinkIndex: 10}, // existing podCIDR, should not be deleted. + {DestinationSubnet: ip.MustParseCIDR("169.254.0.253/32"), LinkIndex: 10}, // service route, should not be deleted. + {DestinationSubnet: ip.MustParseCIDR("192.168.11.0/24"), LinkIndex: 10}, // non-existing podCIDR, should be deleted. + }, nil) + + podCIDRs := []string{"192.168.0.0/24", "192.168.1.0/24"} + mockNetUtil.EXPECT().RemoveNetRoute(&util.Route{DestinationSubnet: ip.MustParseCIDR("192.168.11.0/24"), LinkIndex: 10}) + assert.NoError(t, c.Reconcile(podCIDRs)) +} + +func TestAddRoutes(t *testing.T) { + ipv4, nodeTransPortIPv4Addr, _ := net.ParseCIDR("172.16.10.2/24") + nodeTransPortIPv4Addr.IP = ipv4 + + tests := []struct { + name string + networkConfig *config.NetworkConfig + nodeConfig *config.NodeConfig + podCIDR *net.IPNet + nodeName string + nodeIP net.IP + nodeGwIP net.IP + expectedNetUtilCalls func(mockNetUtil *winnettesting.MockInterfaceMockRecorder) + }{ + { + name: "encap IPv4", + networkConfig: &config.NetworkConfig{ + TrafficEncapMode: config.TrafficEncapModeEncap, + IPv4Enabled: true, + }, + nodeConfig: &config.NodeConfig{ + GatewayConfig: &config.GatewayConfig{ + Name: "antrea-gw0", + IPv4: net.ParseIP("1.1.1.1"), + LinkIndex: 10, + }, + NodeTransportIPv4Addr: nodeTransPortIPv4Addr, + }, + podCIDR: ip.MustParseCIDR("192.168.10.0/24"), + nodeName: "node0", + nodeIP: net.ParseIP("1.1.1.10"), + nodeGwIP: net.ParseIP("192.168.10.1"), + expectedNetUtilCalls: func(mockNetUtil *winnettesting.MockInterfaceMockRecorder) { + mockNetUtil.ReplaceNetRoute(&util.Route{ + GatewayAddress: net.ParseIP("192.168.10.1"), + DestinationSubnet: ip.MustParseCIDR("192.168.10.0/24"), + LinkIndex: 10, + RouteMetric: util.MetricDefault, + }) + }, + }, + { + name: "noencap IPv4, direct routing", + networkConfig: &config.NetworkConfig{ + TrafficEncapMode: config.TrafficEncapModeNoEncap, + IPv4Enabled: true, + }, + nodeConfig: &config.NodeConfig{ + GatewayConfig: &config.GatewayConfig{ + Name: "antrea-gw0", + IPv4: net.ParseIP("192.168.1.1"), + LinkIndex: 10, + }, + NodeTransportIPv4Addr: nodeTransPortIPv4Addr, + }, + podCIDR: ip.MustParseCIDR("192.168.10.0/24"), + nodeName: "node0", + nodeIP: net.ParseIP("172.16.10.3"), // In the same subnet as local Node IP. + nodeGwIP: net.ParseIP("192.168.10.1"), + expectedNetUtilCalls: func(mockNetUtil *winnettesting.MockInterfaceMockRecorder) { + mockNetUtil.ReplaceNetRoute(&util.Route{ + GatewayAddress: net.ParseIP("172.16.10.3"), + DestinationSubnet: ip.MustParseCIDR("192.168.10.0/24"), + RouteMetric: util.MetricDefault, + }) + }, + }, + { + name: "noencap IPv4, no direct routing", + networkConfig: &config.NetworkConfig{ + TrafficEncapMode: config.TrafficEncapModeNoEncap, + IPv4Enabled: true, + }, + nodeConfig: &config.NodeConfig{ + GatewayConfig: &config.GatewayConfig{ + Name: "antrea-gw0", + IPv4: net.ParseIP("192.168.1.1"), + LinkIndex: 10, + }, + NodeTransportIPv4Addr: nodeTransPortIPv4Addr, + }, + podCIDR: ip.MustParseCIDR("192.168.10.0/24"), + nodeName: "node0", + nodeIP: net.ParseIP("172.16.11.3"), // In different subnet from local Node IP. + nodeGwIP: net.ParseIP("192.168.10.1"), + expectedNetUtilCalls: func(mockNetUtil *winnettesting.MockInterfaceMockRecorder) {}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + netutil := winnettesting.NewMockInterface(ctrl) + c := &Client{netUtil: netutil, + networkConfig: tt.networkConfig, + nodeConfig: tt.nodeConfig, + } + tt.expectedNetUtilCalls(netutil.EXPECT()) + assert.NoError(t, c.AddRoutes(tt.podCIDR, tt.nodeName, tt.nodeIP, tt.nodeGwIP)) + }) + } +} + +func TestDeleteRoutes(t *testing.T) { + existingNodeRoutes := map[string]*util.Route{ + "192.168.10.0/24": {GatewayAddress: net.ParseIP("172.16.10.3"), DestinationSubnet: ip.MustParseCIDR("192.168.10.0/24")}, + "192.168.11.0/24": {GatewayAddress: net.ParseIP("172.16.10.4"), DestinationSubnet: ip.MustParseCIDR("192.168.11.0/24")}, + } + podCIDR := ip.MustParseCIDR("192.168.10.0/24") + ctrl := gomock.NewController(t) + mockNetUtil := winnettesting.NewMockInterface(ctrl) + c := &Client{netUtil: mockNetUtil, + nodeRoutes: sync.Map{}, } - return link.Index + for podCIDRStr, nodeRoute := range existingNodeRoutes { + c.nodeRoutes.Store(podCIDRStr, nodeRoute) + } + mockNetUtil.EXPECT().RemoveNetRoute(&util.Route{GatewayAddress: net.ParseIP("172.16.10.3"), DestinationSubnet: ip.MustParseCIDR("192.168.10.0/24")}) + assert.NoError(t, c.DeleteRoutes(podCIDR)) } -func TestRouteOperation(t *testing.T) { - peerNodeIP1 := net.ParseIP("10.0.0.2") - peerNodeIP2 := net.ParseIP("10.0.0.3") - gwIP1 := net.ParseIP("192.168.2.1") - _, destCIDR1, _ := net.ParseCIDR("192.168.2.0/24") - dest2 := "192.168.3.0/24" - gwIP2 := net.ParseIP("192.168.3.1") - _, destCIDR2, _ := net.ParseCIDR(dest2) - - client, err := NewClient(&config.NetworkConfig{}, true, false, false, false, nil) - - require.Nil(t, err) - called := false - err = client.Initialize(nodeConfig, func() { called = true }) - require.Nil(t, err) - require.True(t, called) - - // Add initial routes. - err = client.AddRoutes(destCIDR1, "node1", peerNodeIP1, gwIP1) - require.Nil(t, err) - routes1, err := util.RouteListFiltered(antreasyscall.AF_INET, &util.Route{LinkIndex: gwLink, DestinationSubnet: destCIDR1}, util.RT_FILTER_IF|util.RT_FILTER_DST) - require.Nil(t, err) - assert.Equal(t, 1, len(routes1)) - - err = client.AddRoutes(destCIDR2, "node2", peerNodeIP2, gwIP2) - require.Nil(t, err) - routes2, err := util.RouteListFiltered(antreasyscall.AF_INET, &util.Route{LinkIndex: gwLink, DestinationSubnet: destCIDR2}, util.RT_FILTER_IF|util.RT_FILTER_DST) - require.Nil(t, err) - assert.Equal(t, 1, len(routes2)) - - err = client.Reconcile([]string{dest2}) - require.Nil(t, err) - - err = client.DeleteRoutes(destCIDR2) - require.Nil(t, err) - routes7, err := util.RouteListFiltered(antreasyscall.AF_INET, &util.Route{LinkIndex: gwLink, DestinationSubnet: destCIDR2}, util.RT_FILTER_IF|util.RT_FILTER_DST) - require.Nil(t, err) - assert.Equal(t, 0, len(routes7)) +func TestAddNodePort(t *testing.T) { + ctrl := gomock.NewController(t) + mockNetUtil := winnettesting.NewMockInterface(ctrl) + c := &Client{ + netUtil: mockNetUtil, + netNatStaticMappings: sync.Map{}, + } + mockNetUtil.EXPECT().ReplaceNetNatStaticMapping(nodePortNetNatStaticMapping) + assert.NoError(t, c.AddNodePort(nil, nodePort, protocol)) } -func TestAddAndDeleteExternalIPRoute(t *testing.T) { +func TestDeleteNodePort(t *testing.T) { + ctrl := gomock.NewController(t) + mockNetUtil := winnettesting.NewMockInterface(ctrl) c := &Client{ - nodeConfig: nodeConfig, - serviceRoutes: &sync.Map{}, - } - externalIP := net.ParseIP("1.1.1.1") - - assert.NoError(t, c.AddExternalIPRoute(externalIP)) - externalIPNet := util.NewIPNet(externalIP) - routes, err := util.RouteListFiltered(antreasyscall.AF_INET, &util.Route{LinkIndex: gwLink, DestinationSubnet: externalIPNet}, util.RT_FILTER_IF|util.RT_FILTER_DST) - require.Nil(t, err) - assert.Equal(t, 1, len(routes)) - - route, ok := c.serviceRoutes.Load(externalIP.String()) - assert.True(t, ok) - assert.EqualValues(t, routes[0], *route.(*util.Route)) - - assert.NoError(t, c.DeleteExternalIPRoute(externalIP)) - routes, err = util.RouteListFiltered(antreasyscall.AF_INET, &util.Route{LinkIndex: gwLink, DestinationSubnet: externalIPNet}, util.RT_FILTER_IF|util.RT_FILTER_DST) - require.Nil(t, err) - assert.Equal(t, 0, len(routes)) - _, ok = c.serviceRoutes.Load(externalIP.String()) - assert.False(t, ok) + netUtil: mockNetUtil, + netNatStaticMappings: sync.Map{}, + } + c.netNatStaticMappings.Store(fmt.Sprintf("%d-%s", nodePort, protocol), nodePortNetNatStaticMapping) + mockNetUtil.EXPECT().RemoveNetNatStaticMapping(nodePortNetNatStaticMapping) + assert.NoError(t, c.DeleteNodePort(nil, nodePort, protocol)) +} + +func TestAddServiceCIDRRoute(t *testing.T) { + _, serviceIPv4CIDR1, _ := net.ParseCIDR("10.96.0.1/32") + _, serviceIPv4CIDR2, _ := net.ParseCIDR("10.96.0.0/28") + nodeConfig := &config.NodeConfig{GatewayConfig: &config.GatewayConfig{LinkIndex: 10}} + tests := []struct { + name string + curServiceIPv4CIDR *net.IPNet + newServiceIPv4CIDR *net.IPNet + expectedNetUtilCalls func(mockNetUtil *winnettesting.MockInterfaceMockRecorder) + }{ + { + name: "Add route for Service IPv4 CIDR", + curServiceIPv4CIDR: nil, + newServiceIPv4CIDR: serviceIPv4CIDR1, + expectedNetUtilCalls: func(mockNetUtil *winnettesting.MockInterfaceMockRecorder) { + mockNetUtil.ReplaceNetRoute(&util.Route{ + DestinationSubnet: &net.IPNet{IP: net.ParseIP("10.96.0.1").To4(), Mask: net.CIDRMask(32, 32)}, + GatewayAddress: config.VirtualServiceIPv4, + RouteMetric: util.MetricHigh, + LinkIndex: 10, + }) + mockNetUtil.RouteListFiltered(antreasyscall.AF_INET, &util.Route{LinkIndex: 10}, util.RT_FILTER_IF).Return([]util.Route{ + { + DestinationSubnet: ip.MustParseCIDR("10.96.0.0/24"), + GatewayAddress: config.VirtualServiceIPv4, + RouteMetric: util.MetricHigh, + LinkIndex: 10, + }, + }, nil) + mockNetUtil.RemoveNetRoute(&util.Route{ + DestinationSubnet: ip.MustParseCIDR("10.96.0.0/24"), + GatewayAddress: config.VirtualServiceIPv4, + RouteMetric: util.MetricHigh, + LinkIndex: 10, + }) + }, + }, + { + name: "Add route for Service IPv4 CIDR and clean up stale routes", + curServiceIPv4CIDR: nil, + newServiceIPv4CIDR: ip.MustParseCIDR("10.96.0.0/28"), + expectedNetUtilCalls: func(mockNetUtil *winnettesting.MockInterfaceMockRecorder) { + mockNetUtil.ReplaceNetRoute(&util.Route{ + DestinationSubnet: &net.IPNet{IP: net.ParseIP("10.96.0.0").To4(), Mask: net.CIDRMask(28, 32)}, + GatewayAddress: config.VirtualServiceIPv4, + RouteMetric: util.MetricHigh, + LinkIndex: 10, + }) + mockNetUtil.RouteListFiltered(antreasyscall.AF_INET, &util.Route{LinkIndex: 10}, util.RT_FILTER_IF).Return([]util.Route{ + { + DestinationSubnet: ip.MustParseCIDR("10.96.0.0/24"), + GatewayAddress: config.VirtualServiceIPv4, + RouteMetric: util.MetricHigh, + LinkIndex: 10, + }, + { + DestinationSubnet: ip.MustParseCIDR("10.96.0.0/30"), + GatewayAddress: config.VirtualServiceIPv4, + RouteMetric: util.MetricHigh, + LinkIndex: 10, + }, + }, nil) + mockNetUtil.RemoveNetRoute(&util.Route{ + DestinationSubnet: ip.MustParseCIDR("10.96.0.0/24"), + GatewayAddress: config.VirtualServiceIPv4, + RouteMetric: util.MetricHigh, + LinkIndex: 10, + }) + mockNetUtil.RemoveNetRoute(&util.Route{ + DestinationSubnet: ip.MustParseCIDR("10.96.0.0/30"), + GatewayAddress: config.VirtualServiceIPv4, + RouteMetric: util.MetricHigh, + LinkIndex: 10, + }) + }, + }, + { + name: "Update route for Service IPv4 CIDR", + curServiceIPv4CIDR: serviceIPv4CIDR1, + newServiceIPv4CIDR: serviceIPv4CIDR2, + expectedNetUtilCalls: func(mockNetUtil *winnettesting.MockInterfaceMockRecorder) { + mockNetUtil.ReplaceNetRoute(&util.Route{ + DestinationSubnet: &net.IPNet{IP: net.ParseIP("10.96.0.0").To4(), Mask: net.CIDRMask(28, 32)}, + GatewayAddress: config.VirtualServiceIPv4, + RouteMetric: util.MetricHigh, + LinkIndex: 10, + }) + mockNetUtil.RemoveNetRoute(&util.Route{ + DestinationSubnet: &net.IPNet{IP: net.ParseIP("10.96.0.1").To4(), Mask: net.CIDRMask(32, 32)}, + GatewayAddress: config.VirtualServiceIPv4, + RouteMetric: util.MetricHigh, + LinkIndex: 10, + }) + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + mockNetUtil := winnettesting.NewMockInterface(ctrl) + c := &Client{ + netUtil: mockNetUtil, + nodeConfig: nodeConfig, + } + tt.expectedNetUtilCalls(mockNetUtil.EXPECT()) + + if tt.curServiceIPv4CIDR != nil { + c.serviceRoutes.Store(serviceIPv4CIDRKey, &util.Route{ + DestinationSubnet: &net.IPNet{IP: net.ParseIP("10.96.0.1").To4(), Mask: net.CIDRMask(32, 32)}, + GatewayAddress: config.VirtualServiceIPv4, + RouteMetric: util.MetricHigh, + LinkIndex: 10, + }) + } + + assert.NoError(t, c.addServiceCIDRRoute(tt.newServiceIPv4CIDR)) + }) + } +} + +func TestAddExternalIPRoute(t *testing.T) { + externalIPs := []string{externalIPv4Addr1, externalIPv4Addr2} + + ctrl := gomock.NewController(t) + mockNetUtil := winnettesting.NewMockInterface(ctrl) + c := &Client{netUtil: mockNetUtil, + nodeConfig: &config.NodeConfig{ + GatewayConfig: &config.GatewayConfig{ + LinkIndex: 10, + }, + }, + } + mockNetUtil.EXPECT().ReplaceNetRoute(ipv4Route1) + mockNetUtil.EXPECT().ReplaceNetRoute(ipv4Route2) + + for _, externalIP := range externalIPs { + assert.NoError(t, c.AddExternalIPRoute(net.ParseIP(externalIP))) + } +} + +func TestDeleteExternalIPRoute(t *testing.T) { + externalIPs := []string{externalIPv4Addr1, externalIPv4Addr2} + + ctrl := gomock.NewController(t) + mockNetUtil := winnettesting.NewMockInterface(ctrl) + c := &Client{netUtil: mockNetUtil} + for ipStr, route := range map[string]*util.Route{externalIPv4Addr1: ipv4Route1, externalIPv4Addr2: ipv4Route2} { + c.serviceRoutes.Store(ipStr, route) + } + + mockNetUtil.EXPECT().RemoveNetRoute(ipv4Route1) + mockNetUtil.EXPECT().RemoveNetRoute(ipv4Route2) + + for _, externalIP := range externalIPs { + assert.NoError(t, c.DeleteExternalIPRoute(net.ParseIP(externalIP))) + } } diff --git a/pkg/agent/util/net.go b/pkg/agent/util/net.go index 4e684b3b305..573b1c1b674 100644 --- a/pkg/agent/util/net.go +++ b/pkg/agent/util/net.go @@ -29,6 +29,7 @@ import ( "k8s.io/klog/v2" utilnet "k8s.io/utils/net" + binding "antrea.io/antrea/pkg/ovs/openflow" "antrea.io/antrea/pkg/util/ip" ) @@ -51,6 +52,32 @@ var ( netInterfaceAddrs = (*net.Interface).Addrs ) +// Route stores Windows route item. In order to be able to read it when generating mocking code, define it in the file +// rather than in net_windows.go. If it is defined in net_windows.go, it cannot be read when generating mocking code. +// So do to Neighbor and NetNatStaticMapping. +type Route struct { + LinkIndex int + DestinationSubnet *net.IPNet + GatewayAddress net.IP + RouteMetric int +} + +type Neighbor struct { + LinkIndex int + IPAddress net.IP + LinkLayerAddress net.HardwareAddr + State string +} + +type NetNatStaticMapping struct { + Name string + ExternalIP net.IP + ExternalPort uint16 + InternalIP net.IP + InternalPort uint16 + Protocol binding.Protocol +} + func generateInterfaceName(key string, name string, useHead bool) string { hash := sha1.New() // #nosec G401: not used for security purposes io.WriteString(hash, key) diff --git a/pkg/agent/util/net_windows.go b/pkg/agent/util/net_windows.go index c97e5399761..2ec83c1083b 100644 --- a/pkg/agent/util/net_windows.go +++ b/pkg/agent/util/net_windows.go @@ -41,7 +41,6 @@ import ( ps "antrea.io/antrea/pkg/agent/util/powershell" antreasyscall "antrea.io/antrea/pkg/agent/util/syscall" - binding "antrea.io/antrea/pkg/ovs/openflow" iputil "antrea.io/antrea/pkg/util/ip" ) @@ -68,6 +67,8 @@ const ( RT_FILTER_GW ) +type Handle struct{} + var ( // Declared variables which are meant to be overridden for testing. antreaNetIO = antreasyscall.NewNetIO() @@ -79,14 +80,7 @@ var ( hnsNetworkDelete = (*hcsshim.HNSNetwork).Delete ) -type Route struct { - LinkIndex int - DestinationSubnet *net.IPNet - GatewayAddress net.IP - RouteMetric int -} - -func (r *Route) String() string { +func (r Route) String() string { return fmt.Sprintf("LinkIndex: %d, DestinationSubnet: %s, GatewayAddress: %s, RouteMetric: %d", r.LinkIndex, r.DestinationSubnet, r.GatewayAddress, r.RouteMetric) } @@ -119,26 +113,10 @@ func routeFromIPForwardRow(row *antreasyscall.MibIPForwardRow) *Route { } } -type Neighbor struct { - LinkIndex int - IPAddress net.IP - LinkLayerAddress net.HardwareAddr - State string -} - func (n Neighbor) String() string { return fmt.Sprintf("LinkIndex: %d, IPAddress: %s, LinkLayerAddress: %s", n.LinkIndex, n.IPAddress, n.LinkLayerAddress) } -type NetNatStaticMapping struct { - Name string - ExternalIP net.IP - ExternalPort uint16 - InternalIP net.IP - InternalPort uint16 - Protocol binding.Protocol -} - func (n NetNatStaticMapping) String() string { return fmt.Sprintf("Name: %s, ExternalIP %s, ExternalPort: %d, InternalIP: %s, InternalPort: %d, Protocol: %s", n.Name, n.ExternalIP, n.ExternalPort, n.InternalIP, n.InternalPort, n.Protocol) } @@ -669,6 +647,10 @@ func NewNetRoute(route *Route) error { return nil } +func (h *Handle) NewNetRoute(route *Route) error { + return NewNetRoute(route) +} + func RemoveNetRoute(route *Route) error { if route == nil || route.DestinationSubnet == nil { return nil @@ -689,6 +671,10 @@ func RemoveNetRoute(route *Route) error { return nil } +func (h *Handle) RemoveNetRoute(route *Route) error { + return RemoveNetRoute(route) +} + func ReplaceNetRoute(route *Route) error { if route == nil || route.DestinationSubnet == nil { return nil @@ -713,6 +699,10 @@ func ReplaceNetRoute(route *Route) error { return NewNetRoute(route) } +func (h *Handle) ReplaceNetRoute(route *Route) error { + return ReplaceNetRoute(route) +} + func RouteListFiltered(family uint16, filter *Route, filterMask uint64) ([]Route, error) { rows, err := antreaNetIO.ListIPForwardRows(family) if err != nil { @@ -740,6 +730,10 @@ func RouteListFiltered(family uint16, filter *Route, filterMask uint64) ([]Route return rts, nil } +func (h *Handle) RouteListFiltered(family uint16, filter *Route, filterMask uint64) ([]Route, error) { + return RouteListFiltered(family, filter, filterMask) +} + func addressFamilyByIP(ip net.IP) uint16 { if ip.To4() != nil { return antreasyscall.AF_INET @@ -812,6 +806,10 @@ func ReplaceNetNatStaticMapping(mapping *NetNatStaticMapping) error { return AddNetNatStaticMapping(mapping) } +func (h *Handle) ReplaceNetNatStaticMapping(mapping *NetNatStaticMapping) error { + return ReplaceNetNatStaticMapping(mapping) +} + // GetNetNatStaticMapping checks if a NetNatStaticMapping exists. func GetNetNatStaticMapping(mapping *NetNatStaticMapping) (string, error) { cmd := fmt.Sprintf("Get-NetNatStaticMapping -NatName %s", mapping.Name) + @@ -826,6 +824,10 @@ func GetNetNatStaticMapping(mapping *NetNatStaticMapping) (string, error) { return staticMappingStr, nil } +func (h *Handle) GetNetNatStaticMapping(mapping *NetNatStaticMapping) (string, error) { + return GetNetNatStaticMapping(mapping) +} + // AddNetNatStaticMapping adds a static mapping to a NAT instance. func AddNetNatStaticMapping(mapping *NetNatStaticMapping) error { cmd := fmt.Sprintf("Add-NetNatStaticMapping -NatName %s -ExternalIPAddress %s -ExternalPort %d -InternalIPAddress %s -InternalPort %d -Protocol %s", @@ -834,6 +836,10 @@ func AddNetNatStaticMapping(mapping *NetNatStaticMapping) error { return err } +func (h *Handle) AddNetNatStaticMapping(mapping *NetNatStaticMapping) error { + return AddNetNatStaticMapping(mapping) +} + func RemoveNetNatStaticMapping(mapping *NetNatStaticMapping) error { staticMappingStr, err := GetNetNatStaticMapping(mapping) if err != nil { @@ -852,6 +858,10 @@ func RemoveNetNatStaticMapping(mapping *NetNatStaticMapping) error { return RemoveNetNatStaticMappingByID(mapping.Name, id) } +func (h *Handle) RemoveNetNatStaticMapping(mapping *NetNatStaticMapping) error { + return RemoveNetNatStaticMapping(mapping) +} + func RemoveNetNatStaticMappingByNPLTuples(mapping *NetNatStaticMapping) error { staticMappingStr, err := GetNetNatStaticMapping(mapping) if err != nil { @@ -937,6 +947,10 @@ func RemoveNetNeighbor(neighbor *Neighbor) error { return err } +func (h *Handle) ReplaceNetNeighbor(neighbor *Neighbor) error { + return ReplaceNetNeighbor(neighbor) +} + func ReplaceNetNeighbor(neighbor *Neighbor) error { neighbors, err := GetNetNeighbor(neighbor) if err != nil { diff --git a/pkg/agent/util/net_windows_test.go b/pkg/agent/util/net_windows_test.go index 743b478a0c3..6c145ac6dac 100644 --- a/pkg/agent/util/net_windows_test.go +++ b/pkg/agent/util/net_windows_test.go @@ -24,14 +24,14 @@ import ( "strings" "testing" - antreasyscalltest "antrea.io/antrea/pkg/agent/util/syscall/testing" - "github.com/Microsoft/hcsshim" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/sys/windows" antreasyscall "antrea.io/antrea/pkg/agent/util/syscall" + antreasyscalltest "antrea.io/antrea/pkg/agent/util/syscall/testing" + "antrea.io/antrea/pkg/agent/util/winnet" "antrea.io/antrea/pkg/ovs/openflow" ) @@ -1068,7 +1068,7 @@ func TestGetAdapterInAllCompartmentsByName(t *testing.T) { testName := "host" testFlags := net.FlagUp | net.FlagBroadcast | net.FlagPointToPoint | net.FlagMulticast testAdapter := adapter{ - Interface: net.Interface{ + winnet.Interface: net.Interface{ Index: 1, Name: testName, Flags: testFlags, diff --git a/pkg/agent/util/winnet/interfaces.go b/pkg/agent/util/winnet/interfaces.go new file mode 100644 index 00000000000..779f30bc3f6 --- /dev/null +++ b/pkg/agent/util/winnet/interfaces.go @@ -0,0 +1,37 @@ +// Copyright 2023 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package winnet + +import "antrea.io/antrea/pkg/agent/util" + +type Interface interface { + NewNetRoute(route *util.Route) error + + RemoveNetRoute(route *util.Route) error + + ReplaceNetRoute(route *util.Route) error + + ReplaceNetNeighbor(neighbor *util.Neighbor) error + + RouteListFiltered(family uint16, filter *util.Route, filterMask uint64) ([]util.Route, error) + + ReplaceNetNatStaticMapping(mapping *util.NetNatStaticMapping) error + + GetNetNatStaticMapping(mapping *util.NetNatStaticMapping) (string, error) + + AddNetNatStaticMapping(mapping *util.NetNatStaticMapping) error + + RemoveNetNatStaticMapping(mapping *util.NetNatStaticMapping) error +} diff --git a/pkg/agent/util/winnet/testing/mock_net_windows.go b/pkg/agent/util/winnet/testing/mock_net_windows.go new file mode 100644 index 00000000000..85d83d75cf3 --- /dev/null +++ b/pkg/agent/util/winnet/testing/mock_net_windows.go @@ -0,0 +1,177 @@ +// Copyright 2023 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Code generated by MockGen. DO NOT EDIT. +// Source: antrea.io/antrea/pkg/agent/util (interfaces: Interface) + +// Package testing is a generated GoMock package. +package testing + +import ( + util "antrea.io/antrea/pkg/agent/util" + gomock "github.com/golang/mock/gomock" + reflect "reflect" +) + +// MockInterface is a mock of Interface interface +type MockInterface struct { + ctrl *gomock.Controller + recorder *MockInterfaceMockRecorder +} + +// MockInterfaceMockRecorder is the mock recorder for MockInterface +type MockInterfaceMockRecorder struct { + mock *MockInterface +} + +// NewMockInterface creates a new mock instance +func NewMockInterface(ctrl *gomock.Controller) *MockInterface { + mock := &MockInterface{ctrl: ctrl} + mock.recorder = &MockInterfaceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder { + return m.recorder +} + +// AddNetNatStaticMapping mocks base method +func (m *MockInterface) AddNetNatStaticMapping(arg0 *util.NetNatStaticMapping) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddNetNatStaticMapping", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddNetNatStaticMapping indicates an expected call of AddNetNatStaticMapping +func (mr *MockInterfaceMockRecorder) AddNetNatStaticMapping(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNetNatStaticMapping", reflect.TypeOf((*MockInterface)(nil).AddNetNatStaticMapping), arg0) +} + +// GetNetNatStaticMapping mocks base method +func (m *MockInterface) GetNetNatStaticMapping(arg0 *util.NetNatStaticMapping) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetNetNatStaticMapping", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetNetNatStaticMapping indicates an expected call of GetNetNatStaticMapping +func (mr *MockInterfaceMockRecorder) GetNetNatStaticMapping(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNetNatStaticMapping", reflect.TypeOf((*MockInterface)(nil).GetNetNatStaticMapping), arg0) +} + +// NewNetRoute mocks base method +func (m *MockInterface) NewNetRoute(arg0 *util.Route) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewNetRoute", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// NewNetRoute indicates an expected call of NewNetRoute +func (mr *MockInterfaceMockRecorder) NewNetRoute(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewNetRoute", reflect.TypeOf((*MockInterface)(nil).NewNetRoute), arg0) +} + +// RemoveNetNatStaticMapping mocks base method +func (m *MockInterface) RemoveNetNatStaticMapping(arg0 *util.NetNatStaticMapping) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveNetNatStaticMapping", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveNetNatStaticMapping indicates an expected call of RemoveNetNatStaticMapping +func (mr *MockInterfaceMockRecorder) RemoveNetNatStaticMapping(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveNetNatStaticMapping", reflect.TypeOf((*MockInterface)(nil).RemoveNetNatStaticMapping), arg0) +} + +// RemoveNetRoute mocks base method +func (m *MockInterface) RemoveNetRoute(arg0 *util.Route) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveNetRoute", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveNetRoute indicates an expected call of RemoveNetRoute +func (mr *MockInterfaceMockRecorder) RemoveNetRoute(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveNetRoute", reflect.TypeOf((*MockInterface)(nil).RemoveNetRoute), arg0) +} + +// ReplaceNetNatStaticMapping mocks base method +func (m *MockInterface) ReplaceNetNatStaticMapping(arg0 *util.NetNatStaticMapping) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReplaceNetNatStaticMapping", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// ReplaceNetNatStaticMapping indicates an expected call of ReplaceNetNatStaticMapping +func (mr *MockInterfaceMockRecorder) ReplaceNetNatStaticMapping(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReplaceNetNatStaticMapping", reflect.TypeOf((*MockInterface)(nil).ReplaceNetNatStaticMapping), arg0) +} + +// ReplaceNetNeighbor mocks base method +func (m *MockInterface) ReplaceNetNeighbor(arg0 *util.Neighbor) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReplaceNetNeighbor", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// ReplaceNetNeighbor indicates an expected call of ReplaceNetNeighbor +func (mr *MockInterfaceMockRecorder) ReplaceNetNeighbor(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReplaceNetNeighbor", reflect.TypeOf((*MockInterface)(nil).ReplaceNetNeighbor), arg0) +} + +// ReplaceNetRoute mocks base method +func (m *MockInterface) ReplaceNetRoute(arg0 *util.Route) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReplaceNetRoute", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// ReplaceNetRoute indicates an expected call of ReplaceNetRoute +func (mr *MockInterfaceMockRecorder) ReplaceNetRoute(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReplaceNetRoute", reflect.TypeOf((*MockInterface)(nil).ReplaceNetRoute), arg0) +} + +// RouteListFiltered mocks base method +func (m *MockInterface) RouteListFiltered(arg0 uint16, arg1 *util.Route, arg2 uint64) ([]util.Route, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RouteListFiltered", arg0, arg1, arg2) + ret0, _ := ret[0].([]util.Route) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RouteListFiltered indicates an expected call of RouteListFiltered +func (mr *MockInterfaceMockRecorder) RouteListFiltered(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteListFiltered", reflect.TypeOf((*MockInterface)(nil).RouteListFiltered), arg0, arg1, arg2) +}