Skip to content

Commit

Permalink
Mock /proc/sys
Browse files Browse the repository at this point in the history
  • Loading branch information
anguslees authored and mogren committed Mar 17, 2020
1 parent a4dc9f5 commit 71538ac
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 53 deletions.
25 changes: 5 additions & 20 deletions pkg/networkutils/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (

"github.com/aws/amazon-vpc-cni-k8s/pkg/netlinkwrapper"
"github.com/aws/amazon-vpc-cni-k8s/pkg/nswrapper"
"github.com/aws/amazon-vpc-cni-k8s/pkg/procsyswrapper"
)

const (
Expand Down Expand Up @@ -133,7 +134,7 @@ type linuxNetwork struct {
ns nswrapper.NS
newIptables func() (iptablesIface, error)
mainENIMark uint32
openFile func(name string, flag int, perm os.FileMode) (stringWriteCloser, error)
procSys procsyswrapper.ProcSys
}

type iptablesIface interface {
Expand Down Expand Up @@ -173,9 +174,7 @@ func New() NetworkAPIs {
ipt, err := iptables.New()
return ipt, err
},
openFile: func(name string, flag int, perm os.FileMode) (stringWriteCloser, error) {
return os.OpenFile(name, flag, perm)
},
procSys: procsyswrapper.NewProcSys(),
}
}

Expand Down Expand Up @@ -239,11 +238,11 @@ func (n *linuxNetwork) SetupHostNetwork(vpcCIDR *net.IPNet, vpcCIDRs []*string,
// - 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.
primaryIntfRPFilter := "/proc/sys/net/ipv4/conf/" + primaryIntf + "/rp_filter"
primaryIntfRPFilter := "net/ipv4/conf/" + primaryIntf + "/rp_filter"
const rpFilterLoose = "2"

log.Debugf("Setting RPF for primary interface: %s", primaryIntfRPFilter)
err = n.setProcSys(primaryIntfRPFilter, rpFilterLoose)
err = n.procSys.Set(primaryIntfRPFilter, rpFilterLoose)
if err != nil {
return errors.Wrapf(err, "failed to configure %s RPF check", primaryIntf)
}
Expand Down Expand Up @@ -497,20 +496,6 @@ func containChainExistErr(err error) bool {
return strings.Contains(err.Error(), "Chain already exists")
}

func (n *linuxNetwork) setProcSys(key, value string) error {
f, err := n.openFile(key, os.O_WRONLY, 0644)
if err != nil {
return err
}
_, err = f.WriteString(value)
if err != nil {
// If the write failed, just close
_ = f.Close()
return err
}
return f.Close()
}

type iptablesRule struct {
name string
shouldExist bool
Expand Down
63 changes: 30 additions & 33 deletions pkg/networkutils/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/aws/amazon-vpc-cni-k8s/pkg/netlinkwrapper/mock_netlink"
mock_netlinkwrapper "github.com/aws/amazon-vpc-cni-k8s/pkg/netlinkwrapper/mocks"
mock_nswrapper "github.com/aws/amazon-vpc-cni-k8s/pkg/nswrapper/mocks"
mock_procsyswrapper "github.com/aws/amazon-vpc-cni-k8s/pkg/procsyswrapper/mocks"
)

const (
Expand All @@ -58,17 +59,19 @@ func setup(t *testing.T) (*gomock.Controller,
*mock_netlinkwrapper.MockNetLink,
*mocks_ip.MockIP,
*mock_nswrapper.MockNS,
*mockIptables) {
*mockIptables,
*mock_procsyswrapper.MockProcSys) {
ctrl := gomock.NewController(t)
return ctrl,
mock_netlinkwrapper.NewMockNetLink(ctrl),
mocks_ip.NewMockIP(ctrl),
mock_nswrapper.NewMockNS(ctrl),
newMockIptables()
newMockIptables(),
mock_procsyswrapper.NewMockProcSys(ctrl)
}

func TestSetupENINetwork(t *testing.T) {
ctrl, mockNetLink, _, _, _ := setup(t)
ctrl, mockNetLink, _, _, _, _ := setup(t)
defer ctrl.Finish()

hwAddr, err := net.ParseMAC(testMAC1)
Expand Down Expand Up @@ -118,7 +121,7 @@ func TestSetupENINetwork(t *testing.T) {
}

func TestSetupENINetworkMACFail(t *testing.T) {
ctrl, mockNetLink, _, _, _ := setup(t)
ctrl, mockNetLink, _, _, _, _ := setup(t)
defer ctrl.Finish()

// Emulate a delay attaching the ENI so a retry is necessary
Expand All @@ -132,15 +135,15 @@ func TestSetupENINetworkMACFail(t *testing.T) {
}

func TestSetupENINetworkPrimary(t *testing.T) {
ctrl, mockNetLink, _, _, _ := setup(t)
ctrl, mockNetLink, _, _, _, _ := setup(t)
defer ctrl.Finish()

err := setupENINetwork(testeniIP, testMAC2, 0, testeniSubnet, mockNetLink, 0*time.Second, 0*time.Second, testMTU)
assert.NoError(t, err)
}

func TestSetupHostNetworkNodePortDisabled(t *testing.T) {
ctrl, mockNetLink, _, mockNS, mockIptables := setup(t)
ctrl, mockNetLink, _, mockNS, mockIptables, _ := setup(t)
defer ctrl.Finish()

ln := &linuxNetwork{
Expand Down Expand Up @@ -177,7 +180,7 @@ func mockPrimaryInterfaceLookup(ctrl *gomock.Controller, mockNetLink *mock_netli
}

func TestUpdateRuleListBySrc(t *testing.T) {
ctrl, mockNetLink, _, _, _ := setup(t)
ctrl, mockNetLink, _, _, _, _ := setup(t)
defer ctrl.Finish()

ln := &linuxNetwork{netLink: mockNetLink}
Expand Down Expand Up @@ -265,10 +268,9 @@ func TestUpdateRuleListBySrc(t *testing.T) {
}

func TestSetupHostNetworkNodePortEnabled(t *testing.T) {
ctrl, mockNetLink, _, mockNS, mockIptables := setup(t)
ctrl, mockNetLink, _, mockNS, mockIptables, mockProcSys := setup(t)
defer ctrl.Finish()

var mockRPFilter mockFile
ln := &linuxNetwork{
useExternalSNAT: true,
nodePortSupportEnabled: true,
Expand All @@ -280,9 +282,7 @@ func TestSetupHostNetworkNodePortEnabled(t *testing.T) {
newIptables: func() (iptablesIface, error) {
return mockIptables, nil
},
openFile: func(name string, flag int, perm os.FileMode) (stringWriteCloser, error) {
return &mockRPFilter, nil
},
procSys: mockProcSys,
}

mockPrimaryInterfaceLookup(ctrl, mockNetLink)
Expand All @@ -296,6 +296,8 @@ func TestSetupHostNetworkNodePortEnabled(t *testing.T) {
mockNetLink.EXPECT().RuleDel(&mainENIRule)
mockNetLink.EXPECT().RuleAdd(&mainENIRule)

mockProcSys.EXPECT().Set("net/ipv4/conf/lo/rp_filter", "2").Return(nil)

var vpcCIDRs []*string

err := ln.SetupHostNetwork(testENINetIPNet, vpcCIDRs, loopback, &testENINetIP)
Expand All @@ -317,7 +319,6 @@ func TestSetupHostNetworkNodePortEnabled(t *testing.T) {
},
},
}, mockIptables.dataplaneState)
assert.Equal(t, mockFile{closed: true, data: "2"}, mockRPFilter)
}

func TestLoadMTUFromEnvTooLow(t *testing.T) {
Expand All @@ -344,10 +345,9 @@ func TestLoadExcludeSNATCIDRsFromEnv(t *testing.T) {
}

func TestSetupHostNetworkWithExcludeSNATCIDRs(t *testing.T) {
ctrl, mockNetLink, _, mockNS, mockIptables := setup(t)
ctrl, mockNetLink, _, mockNS, mockIptables, mockProcSys := setup(t)
defer ctrl.Finish()

var mockRPFilter mockFile
ln := &linuxNetwork{
useExternalSNAT: false,
excludeSNATCIDRs: []string{"10.12.0.0/16", "10.13.0.0/16"},
Expand All @@ -360,9 +360,7 @@ func TestSetupHostNetworkWithExcludeSNATCIDRs(t *testing.T) {
newIptables: func() (iptablesIface, error) {
return mockIptables, nil
},
openFile: func(name string, flag int, perm os.FileMode) (stringWriteCloser, error) {
return &mockRPFilter, nil
},
procSys: mockProcSys,
}

mockPrimaryInterfaceLookup(ctrl, mockNetLink)
Expand All @@ -376,6 +374,8 @@ func TestSetupHostNetworkWithExcludeSNATCIDRs(t *testing.T) {
mockNetLink.EXPECT().RuleDel(&mainENIRule)
mockNetLink.EXPECT().RuleAdd(&mainENIRule)

mockProcSys.EXPECT().Set("net/ipv4/conf/lo/rp_filter", "2").Return(nil)

var vpcCIDRs []*string
vpcCIDRs = []*string{aws.String("10.10.0.0/16"), aws.String("10.11.0.0/16")}
err := ln.SetupHostNetwork(testENINetIPNet, vpcCIDRs, loopback, &testENINetIP)
Expand All @@ -399,10 +399,9 @@ func TestSetupHostNetworkWithExcludeSNATCIDRs(t *testing.T) {
}

func TestSetupHostNetworkCleansUpStaleSNATRules(t *testing.T) {
ctrl, mockNetLink, _, mockNS, mockIptables := setup(t)
ctrl, mockNetLink, _, mockNS, mockIptables, mockProcSys := setup(t)
defer ctrl.Finish()

var mockRPFilter mockFile
ln := &linuxNetwork{
useExternalSNAT: false,
excludeSNATCIDRs: nil,
Expand All @@ -415,9 +414,7 @@ func TestSetupHostNetworkCleansUpStaleSNATRules(t *testing.T) {
newIptables: func() (iptablesIface, error) {
return mockIptables, nil
},
openFile: func(name string, flag int, perm os.FileMode) (stringWriteCloser, error) {
return &mockRPFilter, nil
},
procSys: mockProcSys,
}
mockPrimaryInterfaceLookup(ctrl, mockNetLink)

Expand All @@ -430,6 +427,8 @@ func TestSetupHostNetworkCleansUpStaleSNATRules(t *testing.T) {
mockNetLink.EXPECT().RuleDel(&mainENIRule)
mockNetLink.EXPECT().RuleAdd(&mainENIRule)

mockProcSys.EXPECT().Set("net/ipv4/conf/lo/rp_filter", "2").Return(nil)

vpcCIDRs := []*string{aws.String("10.10.0.0/16"), aws.String("10.11.0.0/16")}
_ = mockIptables.Append("nat", "AWS-SNAT-CHAIN-0", "!", "-d", "10.10.0.0/16", "-m", "comment", "--comment", "AWS SNAT CHAN", "-j", "AWS-SNAT-CHAIN-1") //AWS SNAT CHAN proves backwards compatibility
_ = mockIptables.Append("nat", "AWS-SNAT-CHAIN-1", "!", "-d", "10.11.0.0/16", "-m", "comment", "--comment", "AWS SNAT CHAIN", "-j", "AWS-SNAT-CHAIN-2")
Expand Down Expand Up @@ -461,10 +460,9 @@ func TestSetupHostNetworkCleansUpStaleSNATRules(t *testing.T) {
}

func TestSetupHostNetworkExcludedSNATCIDRsIdempotent(t *testing.T) {
ctrl, mockNetLink, _, mockNS, mockIptables := setup(t)
ctrl, mockNetLink, _, mockNS, mockIptables, mockProcSys := setup(t)
defer ctrl.Finish()

var mockRPFilter mockFile
ln := &linuxNetwork{
useExternalSNAT: false,
excludeSNATCIDRs: []string{"10.12.0.0/16", "10.13.0.0/16"},
Expand All @@ -477,9 +475,7 @@ func TestSetupHostNetworkExcludedSNATCIDRsIdempotent(t *testing.T) {
newIptables: func() (iptablesIface, error) {
return mockIptables, nil
},
openFile: func(name string, flag int, perm os.FileMode) (stringWriteCloser, error) {
return &mockRPFilter, nil
},
procSys: mockProcSys,
}
mockPrimaryInterfaceLookup(ctrl, mockNetLink)

Expand All @@ -492,6 +488,8 @@ func TestSetupHostNetworkExcludedSNATCIDRsIdempotent(t *testing.T) {
mockNetLink.EXPECT().RuleDel(&mainENIRule)
mockNetLink.EXPECT().RuleAdd(&mainENIRule)

mockProcSys.EXPECT().Set("net/ipv4/conf/lo/rp_filter", "2").Return(nil)

_ = mockIptables.Append("nat", "AWS-SNAT-CHAIN-0", "!", "-d", "10.10.0.0/16", "-m", "comment", "--comment", "AWS SNAT CHAIN", "-j", "AWS-SNAT-CHAIN-1")
_ = mockIptables.Append("nat", "AWS-SNAT-CHAIN-1", "!", "-d", "10.11.0.0/16", "-m", "comment", "--comment", "AWS SNAT CHAIN", "-j", "AWS-SNAT-CHAIN-2")
_ = mockIptables.Append("nat", "AWS-SNAT-CHAIN-2", "!", "-d", "10.12.0.0/16", "-m", "comment", "--comment", "AWS SNAT CHAIN EXCLUSION", "-j", "AWS-SNAT-CHAIN-3")
Expand Down Expand Up @@ -523,10 +521,9 @@ func TestSetupHostNetworkExcludedSNATCIDRsIdempotent(t *testing.T) {
}

func TestSetupHostNetworkMultipleCIDRs(t *testing.T) {
ctrl, mockNetLink, _, mockNS, mockIptables := setup(t)
ctrl, mockNetLink, _, mockNS, mockIptables, mockProcSys := setup(t)
defer ctrl.Finish()

var mockRPFilter mockFile
ln := &linuxNetwork{
useExternalSNAT: true,
nodePortSupportEnabled: true,
Expand All @@ -538,9 +535,7 @@ func TestSetupHostNetworkMultipleCIDRs(t *testing.T) {
newIptables: func() (iptablesIface, error) {
return mockIptables, nil
},
openFile: func(name string, flag int, perm os.FileMode) (stringWriteCloser, error) {
return &mockRPFilter, nil
},
procSys: mockProcSys,
}
mockPrimaryInterfaceLookup(ctrl, mockNetLink)

Expand All @@ -553,6 +548,8 @@ func TestSetupHostNetworkMultipleCIDRs(t *testing.T) {
mockNetLink.EXPECT().RuleDel(&mainENIRule)
mockNetLink.EXPECT().RuleAdd(&mainENIRule)

mockProcSys.EXPECT().Set("net/ipv4/conf/lo/rp_filter", "2").Return(nil)

var vpcCIDRs []*string
vpcCIDRs = []*string{aws.String("10.10.0.0/16"), aws.String("10.11.0.0/16")}
err := ln.SetupHostNetwork(testENINetIPNet, vpcCIDRs, loopback, &testENINetIP)
Expand Down
16 changes: 16 additions & 0 deletions pkg/procsyswrapper/generate_mocks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 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
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 procsyswrapper

//go:generate go run github.com/golang/mock/mockgen -destination mocks/procsys_mocks.go -copyright_file ../../scripts/copyright.txt . ProcSys
77 changes: 77 additions & 0 deletions pkg/procsyswrapper/mocks/procsys_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 71538ac

Please sign in to comment.