Skip to content

Commit b027258

Browse files
Enable IP forwarding for Linux mulititenancy (#386)
* Enable ipforwarding, prevent ip spoofing and other security concern * added ovssnat test to circleci * fixed compiler error * updated circleci image * fixed circleci yaml * updated circleci image * fixed UT * fixed UTs * addressed review comments * added comments * addressed review comments * fixed UT * separating PRs - removing ip spoofing check changes * added document for describing multitenancy fields * fixed docs/cnimultitenancy.md * removed a condition as it seems to be not working
1 parent d7320a9 commit b027258

File tree

7 files changed

+155
-17
lines changed

7 files changed

+155
-17
lines changed

.circleci/config.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ jobs:
44
# docker:
55
# - image: golang:1.12
66
machine:
7-
image: circleci/classic:latest
7+
image: ubuntu-1604:201903-01
88
steps:
99
- checkout
10-
- run:
10+
- run:
1111
name: Setup-and-test
1212
command: |
1313
sudo -E env "PATH=$PATH" apt-get update
@@ -34,6 +34,7 @@ jobs:
3434
sudo -E env "PATH=$PATH" go test ./netlink/ -coverprofile coverage-netlink.out
3535
sudo -E env "PATH=$PATH" go test ./store/ -coverprofile coverage-store.out
3636
sudo -E env "PATH=$PATH" go test ./telemetry/ -coverprofile coverage-telemetry.out
37+
sudo -E env "PATH=$PATH" go test ./network/ovssnat/ -coverprofile coverage-ovssnat.out
3738
sudo -E env "PATH=$PATH" go test ./cni/ipam/ -coverprofile coverage-ipam.out
3839
sudo -E env "PATH=$PATH" go test ./cnm/network/ -coverprofile coverage-network.out
3940
sudo -E env "PATH=$PATH" go test ./cns/ipamclient/ -coverprofile coverage-ipamclient.out

Makefile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ COREFILES = \
88
$(wildcard network/*.go) \
99
$(wildcard telemetry/*.go) \
1010
$(wildcard network/epcommon/*.go) \
11-
$(wildcard network/ovsnfravnet/*.go) \
12-
$(wildcard network/ovssnat/*.go) \
1311
$(wildcard network/policy/*.go) \
1412
$(wildcard platform/*.go) \
15-
$(wildcard store/*.go)
13+
$(wildcard store/*.go) \
14+
$(wildcard ovsctl/*.go) \
15+
$(wildcard network/ovssnat*.go) \
16+
$(wildcard network/ovsinfravnet*.go)
1617

1718
# Source files for building CNM plugin.
1819
CNMFILES = \

cni/plugin.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,6 @@ func NewPlugin(name, version string) (*Plugin, error) {
3535
return nil, err
3636
}
3737

38-
// Initialize logging.
39-
log.SetName(plugin.Name)
40-
log.SetLevel(log.LevelInfo)
41-
err = log.SetTarget(log.TargetLogfile)
42-
if err != nil {
43-
log.Printf("[cni] Failed to configure logging, err:%v.\n", err)
44-
return &Plugin{
45-
Plugin: plugin,
46-
version: version,
47-
}, err
48-
}
49-
5038
return &Plugin{
5139
Plugin: plugin,
5240
version: version,

docs/cnimultitenancy.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Microsoft Azure Container Networking
2+
CNI Multitenacy binaries are meant only for 1st party customers for now.
3+
4+
Conflist Fields Description
5+
---------------------------
6+
multiTenancy - To indicate CNI to use multitenancy network setup using ovs bridge. Thefollowing fields will be processed
7+
only if this fields is set to true
8+
9+
enableExactMatchForPodName - If this set to false, then CNI strips the last two hex fields added by container runtime to locate the pod.
10+
For Eg: In kubernetes, if pod name is samplepod, then container runtime generates this as samplepod-3e4a-5e4a.
11+
CNI would strip 3e4a-5e4a and keep it as samplepod to locate the pod in CNS.
12+
If the field is set to true, CNI would take whatever container runtime provides.
13+
14+
enableSnatOnHost - If pod/container wants outbound connectivity, this field should be set to true. Enabling this field also enables
15+
ip forwarding kernel setting in container host and adds iptable rule to allow forward traffic from snat bridge.
16+

network/epcommon/endpoint_common.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/Azure/azure-container-networking/iptables"
1010
"github.com/Azure/azure-container-networking/log"
1111
"github.com/Azure/azure-container-networking/netlink"
12+
"github.com/Azure/azure-container-networking/platform"
1213
)
1314

1415
/*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
2627
connected to the same physical (or logical) link.
2728
*/
2829

30+
const (
31+
enableIPForwardCmd = "sysctl -w net.ipv4.ip_forward=1"
32+
)
33+
2934
func getPrivateIPSpace() []string {
3035
privateIPAddresses := []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "169.254.0.0/16"}
3136
return privateIPAddresses
@@ -167,3 +172,25 @@ func BlockIPAddresses(bridgeName string, action string) error {
167172

168173
return nil
169174
}
175+
176+
/**
177+
This fucntion enables ip forwarding in VM and allow forwarding packets from the interface
178+
**/
179+
func EnableIPForwarding(ifName string) error {
180+
// Enable ip forwading on linux vm.
181+
// sysctl -w net.ipv4.ip_forward=1
182+
cmd := fmt.Sprintf(enableIPForwardCmd)
183+
_, err := platform.ExecuteCommand(cmd)
184+
if err != nil {
185+
log.Printf("[net] Enable ipforwarding failed with: %v", err)
186+
return err
187+
}
188+
189+
// Append a rule in forward chain to allow forwarding from bridge
190+
if err := iptables.AppendIptableRule(iptables.Filter, iptables.Forward, "", iptables.Accept); err != nil {
191+
log.Printf("[net] Appending forward chain rule: allow traffic coming from snatbridge failed with: %v", err)
192+
return err
193+
}
194+
195+
return nil
196+
}

network/ovs_endpoint_snatroute_linux.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package network
33
import (
44
"fmt"
55

6+
"github.com/Azure/azure-container-networking/network/epcommon"
67
"github.com/Azure/azure-container-networking/network/ovssnat"
78
)
89

@@ -43,6 +44,10 @@ func AddSnatEndpointRules(client *OVSEndpointClient) error {
4344
return err
4445
}
4546

47+
if err := epcommon.EnableIPForwarding(ovssnat.SnatBridgeName); err != nil {
48+
return err
49+
}
50+
4651
if client.allowInboundFromHostToNC {
4752
if err := client.snatClient.AllowInboundFromHostToNC(); err != nil {
4853
return err

network/ovssnat/ovssnat_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package ovssnat
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/Azure/azure-container-networking/netlink"
8+
)
9+
10+
var anyInterface = "dummy"
11+
12+
func TestMain(m *testing.M) {
13+
exitCode := m.Run()
14+
15+
// Create a dummy test network interface.
16+
17+
os.Exit(exitCode)
18+
}
19+
20+
func TestAllowInboundFromHostToNC(t *testing.T) {
21+
client := &OVSSnatClient{
22+
snatBridgeIP: "169.254.0.1/16",
23+
localIP: "169.254.0.4/16",
24+
containerSnatVethName: anyInterface,
25+
}
26+
27+
if err := netlink.AddLink(&netlink.DummyLink{
28+
LinkInfo: netlink.LinkInfo{
29+
Type: netlink.LINK_TYPE_DUMMY,
30+
Name: anyInterface,
31+
},
32+
}); err != nil {
33+
t.Errorf("Error adding dummy interface %v", err)
34+
}
35+
36+
if err := netlink.AddLink(&netlink.DummyLink{
37+
LinkInfo: netlink.LinkInfo{
38+
Type: netlink.LINK_TYPE_DUMMY,
39+
Name: SnatBridgeName,
40+
},
41+
}); err != nil {
42+
t.Errorf("Error adding dummy interface %v", err)
43+
}
44+
45+
if err := client.AllowInboundFromHostToNC(); err != nil {
46+
t.Errorf("Error adding inbound rule: %v", err)
47+
}
48+
49+
if err := client.AllowInboundFromHostToNC(); err != nil {
50+
t.Errorf("Error adding existing inbound rule: %v", err)
51+
}
52+
53+
if err := client.DeleteInboundFromHostToNC(); err != nil {
54+
t.Errorf("Error removing inbound rule: %v", err)
55+
}
56+
57+
netlink.DeleteLink(anyInterface)
58+
netlink.DeleteLink(SnatBridgeName)
59+
}
60+
61+
func TestAllowInboundFromNCToHost(t *testing.T) {
62+
client := &OVSSnatClient{
63+
snatBridgeIP: "169.254.0.1/16",
64+
localIP: "169.254.0.4/16",
65+
containerSnatVethName: anyInterface,
66+
}
67+
68+
if err := netlink.AddLink(&netlink.DummyLink{
69+
LinkInfo: netlink.LinkInfo{
70+
Type: netlink.LINK_TYPE_DUMMY,
71+
Name: anyInterface,
72+
},
73+
}); err != nil {
74+
t.Errorf("Error adding dummy interface %v", err)
75+
}
76+
77+
if err := netlink.AddLink(&netlink.DummyLink{
78+
LinkInfo: netlink.LinkInfo{
79+
Type: netlink.LINK_TYPE_DUMMY,
80+
Name: SnatBridgeName,
81+
},
82+
}); err != nil {
83+
t.Errorf("Error adding dummy interface %v", err)
84+
}
85+
86+
if err := client.AllowInboundFromNCToHost(); err != nil {
87+
t.Errorf("Error adding inbound rule: %v", err)
88+
}
89+
90+
if err := client.AllowInboundFromNCToHost(); err != nil {
91+
t.Errorf("Error adding existing inbound rule: %v", err)
92+
}
93+
94+
if err := client.DeleteInboundFromNCToHost(); err != nil {
95+
t.Errorf("Error removing inbound rule: %v", err)
96+
}
97+
98+
netlink.DeleteLink(anyInterface)
99+
netlink.DeleteLink(SnatBridgeName)
100+
}

0 commit comments

Comments
 (0)