From b569b594748a9303a3496e77709df14b57a984a5 Mon Sep 17 00:00:00 2001 From: liwen wu Date: Sun, 7 Oct 2018 19:51:45 +0000 Subject: [PATCH] Add logic to dynamically discover primary interface name --- ipamd/ipamd.go | 2 +- ipamd/ipamd_test.go | 3 +- pkg/awsutils/awsutils.go | 7 +++++ pkg/awsutils/mocks/awsutils_mocks.go | 12 ++++++++ pkg/networkutils/mocks/network_mocks.go | 10 +++--- pkg/networkutils/network.go | 41 ++++++++++++++++++++++--- pkg/networkutils/network_test.go | 6 ++-- 7 files changed, 67 insertions(+), 14 deletions(-) diff --git a/ipamd/ipamd.go b/ipamd/ipamd.go index ce0d80633e..318a5c9081 100644 --- a/ipamd/ipamd.go +++ b/ipamd/ipamd.go @@ -218,7 +218,7 @@ func (c *IPAMContext) nodeInit() error { primaryIP := net.ParseIP(c.awsClient.GetLocalIPv4()) - err = c.networkClient.SetupHostNetwork(vpcCIDR, &primaryIP) + err = c.networkClient.SetupHostNetwork(vpcCIDR, c.awsClient.GetPrimaryENImac(), &primaryIP) if err != nil { log.Error("Failed to setup host network", err) return errors.Wrap(err, "ipamd init: failed to setup host network") diff --git a/ipamd/ipamd_test.go b/ipamd/ipamd_test.go index 3070d12f01..45f76511ec 100644 --- a/ipamd/ipamd_test.go +++ b/ipamd/ipamd_test.go @@ -105,7 +105,8 @@ func TestNodeInit(t *testing.T) { _, vpcCIDR, _ := net.ParseCIDR(vpcCIDR) primaryIP := net.ParseIP(ipaddr01) - mockNetwork.EXPECT().SetupHostNetwork(vpcCIDR, &primaryIP).Return(nil) + mockAWS.EXPECT().GetPrimaryENImac().Return("") + mockNetwork.EXPECT().SetupHostNetwork(vpcCIDR, "", &primaryIP).Return(nil) //primaryENIid mockAWS.EXPECT().GetPrimaryENI().Return(primaryENIid) diff --git a/pkg/awsutils/awsutils.go b/pkg/awsutils/awsutils.go index e08f8053a9..4ce7bcc655 100644 --- a/pkg/awsutils/awsutils.go +++ b/pkg/awsutils/awsutils.go @@ -124,6 +124,8 @@ type APIs interface { // GetENILimit returns the number of enis can be attached to an instance GetENILimit() (int, error) + // GetPrimaryENImac returns the mac address of the primary eni + GetPrimaryENImac() string } // EC2InstanceMetadataCache caches instance metadata @@ -939,3 +941,8 @@ func (cache *EC2InstanceMetadataCache) GetLocalIPv4() string { func (cache *EC2InstanceMetadataCache) GetPrimaryENI() string { return cache.primaryENI } + +// GetPrimaryENIMAC returns the mac address of primary eni +func (cache *EC2InstanceMetadataCache) GetPrimaryENImac() string { + return cache.primaryENImac +} diff --git a/pkg/awsutils/mocks/awsutils_mocks.go b/pkg/awsutils/mocks/awsutils_mocks.go index 784a4c9f5f..104d86cd56 100644 --- a/pkg/awsutils/mocks/awsutils_mocks.go +++ b/pkg/awsutils/mocks/awsutils_mocks.go @@ -186,6 +186,18 @@ func (mr *MockAPIsMockRecorder) GetPrimaryENI() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPrimaryENI", reflect.TypeOf((*MockAPIs)(nil).GetPrimaryENI)) } +// GetPrimaryENImac mocks base method +func (m *MockAPIs) GetPrimaryENImac() string { + ret := m.ctrl.Call(m, "GetPrimaryENImac") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetPrimaryENImac indicates an expected call of GetPrimaryENImac +func (mr *MockAPIsMockRecorder) GetPrimaryENImac() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPrimaryENImac", reflect.TypeOf((*MockAPIs)(nil).GetPrimaryENImac)) +} + // GetVPCIPv4CIDR mocks base method func (m *MockAPIs) GetVPCIPv4CIDR() string { ret := m.ctrl.Call(m, "GetVPCIPv4CIDR") diff --git a/pkg/networkutils/mocks/network_mocks.go b/pkg/networkutils/mocks/network_mocks.go index 8fc3882683..821162ecae 100644 --- a/pkg/networkutils/mocks/network_mocks.go +++ b/pkg/networkutils/mocks/network_mocks.go @@ -1,4 +1,4 @@ -// Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may // not use this file except in compliance with the License. A copy of the @@ -60,13 +60,13 @@ func (mr *MockNetworkAPIsMockRecorder) SetupENINetwork(arg0, arg1, arg2, arg3 in } // SetupHostNetwork mocks base method -func (m *MockNetworkAPIs) SetupHostNetwork(arg0 *net.IPNet, arg1 *net.IP) error { - ret := m.ctrl.Call(m, "SetupHostNetwork", arg0, arg1) +func (m *MockNetworkAPIs) SetupHostNetwork(arg0 *net.IPNet, arg1 string, arg2 *net.IP) error { + ret := m.ctrl.Call(m, "SetupHostNetwork", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // SetupHostNetwork indicates an expected call of SetupHostNetwork -func (mr *MockNetworkAPIsMockRecorder) SetupHostNetwork(arg0, arg1 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetupHostNetwork", reflect.TypeOf((*MockNetworkAPIs)(nil).SetupHostNetwork), arg0, arg1) +func (mr *MockNetworkAPIsMockRecorder) SetupHostNetwork(arg0, arg1, arg2 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetupHostNetwork", reflect.TypeOf((*MockNetworkAPIs)(nil).SetupHostNetwork), arg0, arg1, arg2) } diff --git a/pkg/networkutils/network.go b/pkg/networkutils/network.go index 6b45076806..9fc875bd68 100644 --- a/pkg/networkutils/network.go +++ b/pkg/networkutils/network.go @@ -75,7 +75,7 @@ const ( // NetworkAPIs defines the host level and the eni level network related operations type NetworkAPIs interface { // SetupNodeNetwork performs node level network configuration - SetupHostNetwork(vpcCIDR *net.IPNet, primaryAddr *net.IP) error + SetupHostNetwork(vpcCIDR *net.IPNet, primaryMAC string, primaryAddr *net.IP) error // SetupENINetwork performs eni level network configuration SetupENINetwork(eniIP string, mac string, table int, subnetCIDR string) error } @@ -126,9 +126,34 @@ func isDuplicateRuleAdd(err error) bool { return strings.Contains(err.Error(), "File exists") } +// find out the primary interface name +func findPrimaryInterfaceName(primaryMAC string) (string, error) { + + log.Debugf("Trying to find primary interface that has mac : %s", primaryMAC) + + interfaces, err := net.Interfaces() + + if err != nil { + log.Errorf("Failed to read all interfaces: %v", err) + return "", errors.Wrapf(err, "findPrimaryInterfaceName: failed to find interfaces") + } + + for _, intf := range interfaces { + log.Debugf("Discovered interface: %v, mac: %v", intf.Name, intf.HardwareAddr) + + if strings.Compare(primaryMAC, intf.HardwareAddr.String()) == 0 { + log.Infof("Discovered primary interface: %s", intf.Name) + return intf.Name, nil + } + } + + log.Errorf("No primary interface found") + return "", errors.New("no primary interface found") +} + // SetupHostNetwork performs node level network configuration // TODO : implement ip rule not to 10.0.0.0/16(vpc'subnet) table main priority 1024 -func (n *linuxNetwork) SetupHostNetwork(vpcCIDR *net.IPNet, primaryAddr *net.IP) error { +func (n *linuxNetwork) SetupHostNetwork(vpcCIDR *net.IPNet, primaryMAC string, primaryAddr *net.IP) error { log.Info("Setting up host network") hostRule := n.netLink.NewRule() hostRule.Dst = vpcCIDR @@ -154,6 +179,12 @@ func (n *linuxNetwork) SetupHostNetwork(vpcCIDR *net.IPNet, primaryAddr *net.IP) } if n.nodePortSupportEnabled { + + primaryIntf, err := findPrimaryInterfaceName(primaryMAC) + + if err != nil { + return errors.Wrapf(err, "failed to SetupHostNetwork") + } // If node port support is enabled, configure the kernel's reverse path filter check on eth0 for "loose" // filtering. This is required because // - NodePorts are exposed on eth0 @@ -163,9 +194,11 @@ func (n *linuxNetwork) SetupHostNetwork(vpcCIDR *net.IPNet, primaryAddr *net.IP) // - Thus, it finds the source-based route that leaves via the secondary ENI. // - In "strict" mode, the RPF check fails because the return path uses a different interface to the incoming // packet. In "loose" mode, the check passes because some route was found. - const eth0RPFilter = "/proc/sys/net/ipv4/conf/eth0/rp_filter" + primaryIntfRPFilter := "/proc/sys/net/ipv4/conf/" + primaryIntf + "/rp_filter" const rpFilterLoose = "2" - err := n.setProcSys(eth0RPFilter, rpFilterLoose) + + log.Debugf("Setting RPF for primary interface: %s", primaryIntfRPFilter) + err = n.setProcSys(primaryIntfRPFilter, rpFilterLoose) if err != nil { return errors.Wrapf(err, "failed to configure eth0 RPF check") } diff --git a/pkg/networkutils/network_test.go b/pkg/networkutils/network_test.go index ed778c39fd..1c302581fe 100644 --- a/pkg/networkutils/network_test.go +++ b/pkg/networkutils/network_test.go @@ -136,7 +136,7 @@ func TestSetupHostNetworkNodePortDisabled(t *testing.T) { mockNetLink.EXPECT().NewRule().Return(&mainENIRule) mockNetLink.EXPECT().RuleDel(&mainENIRule) - err := ln.SetupHostNetwork(testENINetIPNet, &testENINetIP) + err := ln.SetupHostNetwork(testENINetIPNet, "", &testENINetIP) assert.NoError(t, err) assert.Equal(t, map[string]map[string][][]string{ @@ -181,7 +181,7 @@ func TestSetupHostNetworkNodePortEnabled(t *testing.T) { mockNetLink.EXPECT().RuleDel(&mainENIRule) mockNetLink.EXPECT().RuleAdd(&mainENIRule) - err := ln.SetupHostNetwork(testENINetIPNet, &testENINetIP) + err := ln.SetupHostNetwork(testENINetIPNet, "", &testENINetIP) assert.NoError(t, err) assert.Equal(t, map[string]map[string][][]string{ @@ -241,7 +241,7 @@ func (ipt *mockIptables) Delete(table, chainName string, rulespec ...string) err } updatedChain = append(updatedChain, r) } - if ! found { + if !found { return errors.New("not found") } ipt.dataplaneState[table][chainName] = updatedChain