diff --git a/plugins/main/bridge/bridge.go b/plugins/main/bridge/bridge.go index 2ee6e0edc..905676e42 100644 --- a/plugins/main/bridge/bridge.go +++ b/plugins/main/bridge/bridge.go @@ -61,6 +61,7 @@ type NetConf struct { MacSpoofChk bool `json:"macspoofchk,omitempty"` EnableDad bool `json:"enabledad,omitempty"` DisableContainerInterface bool `json:"disableContainerInterface,omitempty"` + PortIsolation bool `json:"portIsolation,omitempty"` Args struct { Cni BridgeArgs `json:"cni,omitempty"` @@ -387,7 +388,7 @@ func ensureVlanInterface(br *netlink.Bridge, vlanID int, preserveDefaultVlan boo return nil, fmt.Errorf("faild to find host namespace: %v", err) } - _, brGatewayIface, err := setupVeth(hostNS, br, name, br.MTU, false, vlanID, nil, preserveDefaultVlan, "") + _, brGatewayIface, err := setupVeth(hostNS, br, name, br.MTU, false, vlanID, nil, preserveDefaultVlan, "", false) if err != nil { return nil, fmt.Errorf("faild to create vlan gateway %q: %v", name, err) } @@ -406,7 +407,18 @@ func ensureVlanInterface(br *netlink.Bridge, vlanID int, preserveDefaultVlan boo return brGatewayVeth, nil } -func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairpinMode bool, vlanID int, vlans []int, preserveDefaultVlan bool, mac string) (*current.Interface, *current.Interface, error) { +func setupVeth( + netns ns.NetNS, + br *netlink.Bridge, + ifName string, + mtu int, + hairpinMode bool, + vlanID int, + vlans []int, + preserveDefaultVlan bool, + mac string, + portIsolation bool, +) (*current.Interface, *current.Interface, error) { contIface := ¤t.Interface{} hostIface := ¤t.Interface{} @@ -443,6 +455,11 @@ func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairp return nil, nil, fmt.Errorf("failed to setup hairpin mode for %v: %v", hostVeth.Attrs().Name, err) } + // set isolation mode + if err = netlink.LinkSetIsolated(hostVeth, portIsolation); err != nil { + return nil, nil, fmt.Errorf("failed to set isolated on for %v: %v", hostVeth.Attrs().Name, err) + } + if (vlanID != 0 || len(vlans) > 0) && !preserveDefaultVlan { err = removeDefaultVlan(hostVeth) if err != nil { @@ -549,7 +566,7 @@ func cmdAdd(args *skel.CmdArgs) error { } defer netns.Close() - hostInterface, containerInterface, err := setupVeth(netns, br, args.IfName, n.MTU, n.HairpinMode, n.Vlan, n.vlans, n.PreserveDefaultVlan, n.mac) + hostInterface, containerInterface, err := setupVeth(netns, br, args.IfName, n.MTU, n.HairpinMode, n.Vlan, n.vlans, n.PreserveDefaultVlan, n.mac, n.PortIsolation) if err != nil { return err } diff --git a/plugins/main/bridge/bridge_test.go b/plugins/main/bridge/bridge_test.go index a1e133139..4e6939afd 100644 --- a/plugins/main/bridge/bridge_test.go +++ b/plugins/main/bridge/bridge_test.go @@ -82,6 +82,7 @@ type testCase struct { ipMasqBackend string macspoofchk bool disableContIface bool + portIsolation bool AddErr020 string DelErr020 string @@ -162,6 +163,9 @@ const ( disableContainerInterface = `, "disableContainerInterface": true` + portIsolation = `, + "portIsolation": true` + ipamStartStr = `, "ipam": { "type": "host-local"` @@ -266,6 +270,10 @@ func (tc testCase) netConfJSON(dataDir string) string { conf += disableContainerInterface } + if tc.portIsolation { + conf += portIsolation + } + if !tc.isLayer2 { conf += netDefault if tc.subnet != "" || tc.ranges != nil { @@ -649,6 +657,10 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result, Expect(link).To(BeAssignableToTypeOf(&netlink.Veth{})) tester.vethName = result.Interfaces[1].Name + protInfo, err := netlink.LinkGetProtinfo(link) + Expect(err).NotTo(HaveOccurred()) + Expect(protInfo.Isolated).To(Equal(tc.portIsolation), "link isolation should be on when portIsolation is set") + // check vlan exist on the veth interface if tc.vlan != 0 { interfaceMap, err := netlink.BridgeVlanList() @@ -2588,6 +2600,36 @@ var _ = Describe("bridge Operations", func() { return nil })).To(Succeed()) }) + + It(fmt.Sprintf("[%s] when port-isolation is off, should set the veth peer on node with isolation off", ver), func() { + Expect(originalNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + tc := testCase{ + cniVersion: ver, + portIsolation: false, + isLayer2: true, + AddErr020: "cannot convert: no valid IP addresses", + AddErr010: "cannot convert: no valid IP addresses", + } + cmdAddDelTest(originalNS, targetNS, tc, dataDir) + return nil + })).To(Succeed()) + }) + + It(fmt.Sprintf("[%s] when port-isolation is on, should set the veth peer on node with isolation on", ver), func() { + Expect(originalNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + tc := testCase{ + cniVersion: ver, + portIsolation: true, + isLayer2: true, + AddErr020: "cannot convert: no valid IP addresses", + AddErr010: "cannot convert: no valid IP addresses", + } + cmdAddDelTest(originalNS, targetNS, tc, dataDir) + return nil + })).To(Succeed()) + }) } It("check vlan id when loading net conf", func() {