diff --git a/.circleci/config.yml b/.circleci/config.yml index a23e86f824..de6b141455 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,10 +4,10 @@ jobs: # docker: # - image: golang:1.12 machine: - image: circleci/classic:latest + image: ubuntu-1604:201903-01 steps: - checkout - - run: + - run: name: Setup-and-test command: | sudo -E env "PATH=$PATH" apt-get update @@ -34,6 +34,7 @@ jobs: sudo -E env "PATH=$PATH" go test ./netlink/ -coverprofile coverage-netlink.out sudo -E env "PATH=$PATH" go test ./store/ -coverprofile coverage-store.out sudo -E env "PATH=$PATH" go test ./telemetry/ -coverprofile coverage-telemetry.out + sudo -E env "PATH=$PATH" go test ./network/ovssnat/ -coverprofile coverage-ovssnat.out sudo -E env "PATH=$PATH" go test ./cni/ipam/ -coverprofile coverage-ipam.out sudo -E env "PATH=$PATH" go test ./cnm/network/ -coverprofile coverage-network.out sudo -E env "PATH=$PATH" go test ./cns/ipamclient/ -coverprofile coverage-ipamclient.out diff --git a/Makefile b/Makefile index 297cee0fc9..af3b7b4a84 100644 --- a/Makefile +++ b/Makefile @@ -8,11 +8,12 @@ COREFILES = \ $(wildcard network/*.go) \ $(wildcard telemetry/*.go) \ $(wildcard network/epcommon/*.go) \ - $(wildcard network/ovsnfravnet/*.go) \ - $(wildcard network/ovssnat/*.go) \ $(wildcard network/policy/*.go) \ $(wildcard platform/*.go) \ - $(wildcard store/*.go) + $(wildcard store/*.go) \ + $(wildcard ovsctl/*.go) \ + $(wildcard network/ovssnat*.go) \ + $(wildcard network/ovsinfravnet*.go) # Source files for building CNM plugin. CNMFILES = \ diff --git a/cni/plugin.go b/cni/plugin.go index a15f66ba49..0a6cb7f0cb 100644 --- a/cni/plugin.go +++ b/cni/plugin.go @@ -35,18 +35,6 @@ func NewPlugin(name, version string) (*Plugin, error) { return nil, err } - // Initialize logging. - log.SetName(plugin.Name) - log.SetLevel(log.LevelInfo) - err = log.SetTarget(log.TargetLogfile) - if err != nil { - log.Printf("[cni] Failed to configure logging, err:%v.\n", err) - return &Plugin{ - Plugin: plugin, - version: version, - }, err - } - return &Plugin{ Plugin: plugin, version: version, diff --git a/docs/cnimultitenancy.md b/docs/cnimultitenancy.md new file mode 100644 index 0000000000..3153934317 --- /dev/null +++ b/docs/cnimultitenancy.md @@ -0,0 +1,16 @@ +# Microsoft Azure Container Networking +CNI Multitenacy binaries are meant only for 1st party customers for now. + +Conflist Fields Description +--------------------------- +multiTenancy - To indicate CNI to use multitenancy network setup using ovs bridge. Thefollowing fields will be processed + only if this fields is set to true + +enableExactMatchForPodName - If this set to false, then CNI strips the last two hex fields added by container runtime to locate the pod. + For Eg: In kubernetes, if pod name is samplepod, then container runtime generates this as samplepod-3e4a-5e4a. + CNI would strip 3e4a-5e4a and keep it as samplepod to locate the pod in CNS. + If the field is set to true, CNI would take whatever container runtime provides. + +enableSnatOnHost - If pod/container wants outbound connectivity, this field should be set to true. Enabling this field also enables + ip forwarding kernel setting in container host and adds iptable rule to allow forward traffic from snat bridge. + diff --git a/network/epcommon/endpoint_common.go b/network/epcommon/endpoint_common.go index 7b75a0283a..5d7c9d5065 100644 --- a/network/epcommon/endpoint_common.go +++ b/network/epcommon/endpoint_common.go @@ -9,6 +9,7 @@ import ( "github.com/Azure/azure-container-networking/iptables" "github.com/Azure/azure-container-networking/log" "github.com/Azure/azure-container-networking/netlink" + "github.com/Azure/azure-container-networking/platform" ) /*RFC For Private Address Space: https://tools.ietf.org/html/rfc1918 @@ -26,6 +27,10 @@ RFC for Link Local Addresses: https://tools.ietf.org/html/rfc3927 connected to the same physical (or logical) link. */ +const ( + enableIPForwardCmd = "sysctl -w net.ipv4.ip_forward=1" +) + func getPrivateIPSpace() []string { privateIPAddresses := []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "169.254.0.0/16"} return privateIPAddresses @@ -167,3 +172,25 @@ func BlockIPAddresses(bridgeName string, action string) error { return nil } + +/** + This fucntion enables ip forwarding in VM and allow forwarding packets from the interface +**/ +func EnableIPForwarding(ifName string) error { + // Enable ip forwading on linux vm. + // sysctl -w net.ipv4.ip_forward=1 + cmd := fmt.Sprintf(enableIPForwardCmd) + _, err := platform.ExecuteCommand(cmd) + if err != nil { + log.Printf("[net] Enable ipforwarding failed with: %v", err) + return err + } + + // Append a rule in forward chain to allow forwarding from bridge + if err := iptables.AppendIptableRule(iptables.Filter, iptables.Forward, "", iptables.Accept); err != nil { + log.Printf("[net] Appending forward chain rule: allow traffic coming from snatbridge failed with: %v", err) + return err + } + + return nil +} diff --git a/network/ovs_endpoint_snatroute_linux.go b/network/ovs_endpoint_snatroute_linux.go index b15f82518d..1d15593ae9 100644 --- a/network/ovs_endpoint_snatroute_linux.go +++ b/network/ovs_endpoint_snatroute_linux.go @@ -3,6 +3,7 @@ package network import ( "fmt" + "github.com/Azure/azure-container-networking/network/epcommon" "github.com/Azure/azure-container-networking/network/ovssnat" ) @@ -43,6 +44,10 @@ func AddSnatEndpointRules(client *OVSEndpointClient) error { return err } + if err := epcommon.EnableIPForwarding(ovssnat.SnatBridgeName); err != nil { + return err + } + if client.allowInboundFromHostToNC { if err := client.snatClient.AllowInboundFromHostToNC(); err != nil { return err diff --git a/network/ovssnat/ovssnat_test.go b/network/ovssnat/ovssnat_test.go new file mode 100644 index 0000000000..0b0c8dbaa5 --- /dev/null +++ b/network/ovssnat/ovssnat_test.go @@ -0,0 +1,100 @@ +package ovssnat + +import ( + "os" + "testing" + + "github.com/Azure/azure-container-networking/netlink" +) + +var anyInterface = "dummy" + +func TestMain(m *testing.M) { + exitCode := m.Run() + + // Create a dummy test network interface. + + os.Exit(exitCode) +} + +func TestAllowInboundFromHostToNC(t *testing.T) { + client := &OVSSnatClient{ + snatBridgeIP: "169.254.0.1/16", + localIP: "169.254.0.4/16", + containerSnatVethName: anyInterface, + } + + if err := netlink.AddLink(&netlink.DummyLink{ + LinkInfo: netlink.LinkInfo{ + Type: netlink.LINK_TYPE_DUMMY, + Name: anyInterface, + }, + }); err != nil { + t.Errorf("Error adding dummy interface %v", err) + } + + if err := netlink.AddLink(&netlink.DummyLink{ + LinkInfo: netlink.LinkInfo{ + Type: netlink.LINK_TYPE_DUMMY, + Name: SnatBridgeName, + }, + }); err != nil { + t.Errorf("Error adding dummy interface %v", err) + } + + if err := client.AllowInboundFromHostToNC(); err != nil { + t.Errorf("Error adding inbound rule: %v", err) + } + + if err := client.AllowInboundFromHostToNC(); err != nil { + t.Errorf("Error adding existing inbound rule: %v", err) + } + + if err := client.DeleteInboundFromHostToNC(); err != nil { + t.Errorf("Error removing inbound rule: %v", err) + } + + netlink.DeleteLink(anyInterface) + netlink.DeleteLink(SnatBridgeName) +} + +func TestAllowInboundFromNCToHost(t *testing.T) { + client := &OVSSnatClient{ + snatBridgeIP: "169.254.0.1/16", + localIP: "169.254.0.4/16", + containerSnatVethName: anyInterface, + } + + if err := netlink.AddLink(&netlink.DummyLink{ + LinkInfo: netlink.LinkInfo{ + Type: netlink.LINK_TYPE_DUMMY, + Name: anyInterface, + }, + }); err != nil { + t.Errorf("Error adding dummy interface %v", err) + } + + if err := netlink.AddLink(&netlink.DummyLink{ + LinkInfo: netlink.LinkInfo{ + Type: netlink.LINK_TYPE_DUMMY, + Name: SnatBridgeName, + }, + }); err != nil { + t.Errorf("Error adding dummy interface %v", err) + } + + if err := client.AllowInboundFromNCToHost(); err != nil { + t.Errorf("Error adding inbound rule: %v", err) + } + + if err := client.AllowInboundFromNCToHost(); err != nil { + t.Errorf("Error adding existing inbound rule: %v", err) + } + + if err := client.DeleteInboundFromNCToHost(); err != nil { + t.Errorf("Error removing inbound rule: %v", err) + } + + netlink.DeleteLink(anyInterface) + netlink.DeleteLink(SnatBridgeName) +}