bridge: Add option to enable port isolation
Enable bridge CNI plugin setting port-isolation [1] the interface. When port-isolation is enabled, containers connected to the network cannot communicate with each other over the linux-bridge. Communication will be enable depending on the gateway appliance according to its restrictions / policies. For example: in a scenario the env connected to smart switch, enabling port-isolation ensure traffic will go outbound, allowing the smart-switch routing the traffic according to policies. Add "portIsolation" flag to bridge plugin. When true, configure the node interface with port-isolation [1]. Default is false. [1] https://man7.org/linux/man-pages/man8/bridge.8.html (see "isolated" option) Signed-off-by: Or Mergi <ormergi@redhat.com>
This commit is contained in:
parent
e4ca66b414
commit
7c122fabb4
@ -61,6 +61,7 @@ type NetConf struct {
|
|||||||
MacSpoofChk bool `json:"macspoofchk,omitempty"`
|
MacSpoofChk bool `json:"macspoofchk,omitempty"`
|
||||||
EnableDad bool `json:"enabledad,omitempty"`
|
EnableDad bool `json:"enabledad,omitempty"`
|
||||||
DisableContainerInterface bool `json:"disableContainerInterface,omitempty"`
|
DisableContainerInterface bool `json:"disableContainerInterface,omitempty"`
|
||||||
|
PortIsolation bool `json:"portIsolation,omitempty"`
|
||||||
|
|
||||||
Args struct {
|
Args struct {
|
||||||
Cni BridgeArgs `json:"cni,omitempty"`
|
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)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("faild to create vlan gateway %q: %v", name, err)
|
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
|
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{}
|
contIface := ¤t.Interface{}
|
||||||
hostIface := ¤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)
|
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 {
|
if (vlanID != 0 || len(vlans) > 0) && !preserveDefaultVlan {
|
||||||
err = removeDefaultVlan(hostVeth)
|
err = removeDefaultVlan(hostVeth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -549,7 +566,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
defer netns.Close()
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,7 @@ type testCase struct {
|
|||||||
ipMasqBackend string
|
ipMasqBackend string
|
||||||
macspoofchk bool
|
macspoofchk bool
|
||||||
disableContIface bool
|
disableContIface bool
|
||||||
|
portIsolation bool
|
||||||
|
|
||||||
AddErr020 string
|
AddErr020 string
|
||||||
DelErr020 string
|
DelErr020 string
|
||||||
@ -162,6 +163,9 @@ const (
|
|||||||
disableContainerInterface = `,
|
disableContainerInterface = `,
|
||||||
"disableContainerInterface": true`
|
"disableContainerInterface": true`
|
||||||
|
|
||||||
|
portIsolation = `,
|
||||||
|
"portIsolation": true`
|
||||||
|
|
||||||
ipamStartStr = `,
|
ipamStartStr = `,
|
||||||
"ipam": {
|
"ipam": {
|
||||||
"type": "host-local"`
|
"type": "host-local"`
|
||||||
@ -266,6 +270,10 @@ func (tc testCase) netConfJSON(dataDir string) string {
|
|||||||
conf += disableContainerInterface
|
conf += disableContainerInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tc.portIsolation {
|
||||||
|
conf += portIsolation
|
||||||
|
}
|
||||||
|
|
||||||
if !tc.isLayer2 {
|
if !tc.isLayer2 {
|
||||||
conf += netDefault
|
conf += netDefault
|
||||||
if tc.subnet != "" || tc.ranges != nil {
|
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{}))
|
Expect(link).To(BeAssignableToTypeOf(&netlink.Veth{}))
|
||||||
tester.vethName = result.Interfaces[1].Name
|
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
|
// check vlan exist on the veth interface
|
||||||
if tc.vlan != 0 {
|
if tc.vlan != 0 {
|
||||||
interfaceMap, err := netlink.BridgeVlanList()
|
interfaceMap, err := netlink.BridgeVlanList()
|
||||||
@ -2588,6 +2600,36 @@ var _ = Describe("bridge Operations", func() {
|
|||||||
return nil
|
return nil
|
||||||
})).To(Succeed())
|
})).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() {
|
It("check vlan id when loading net conf", func() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user