Merge pull request #997 from ormergi/bridge-cont-iface-state
bridge: Enable disabling bridge interface
This commit is contained in:
commit
14bdce598f
@ -47,19 +47,20 @@ const defaultBrName = "cni0"
|
|||||||
|
|
||||||
type NetConf struct {
|
type NetConf struct {
|
||||||
types.NetConf
|
types.NetConf
|
||||||
BrName string `json:"bridge"`
|
BrName string `json:"bridge"`
|
||||||
IsGW bool `json:"isGateway"`
|
IsGW bool `json:"isGateway"`
|
||||||
IsDefaultGW bool `json:"isDefaultGateway"`
|
IsDefaultGW bool `json:"isDefaultGateway"`
|
||||||
ForceAddress bool `json:"forceAddress"`
|
ForceAddress bool `json:"forceAddress"`
|
||||||
IPMasq bool `json:"ipMasq"`
|
IPMasq bool `json:"ipMasq"`
|
||||||
MTU int `json:"mtu"`
|
MTU int `json:"mtu"`
|
||||||
HairpinMode bool `json:"hairpinMode"`
|
HairpinMode bool `json:"hairpinMode"`
|
||||||
PromiscMode bool `json:"promiscMode"`
|
PromiscMode bool `json:"promiscMode"`
|
||||||
Vlan int `json:"vlan"`
|
Vlan int `json:"vlan"`
|
||||||
VlanTrunk []*VlanTrunk `json:"vlanTrunk,omitempty"`
|
VlanTrunk []*VlanTrunk `json:"vlanTrunk,omitempty"`
|
||||||
PreserveDefaultVlan bool `json:"preserveDefaultVlan"`
|
PreserveDefaultVlan bool `json:"preserveDefaultVlan"`
|
||||||
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"`
|
||||||
|
|
||||||
Args struct {
|
Args struct {
|
||||||
Cni BridgeArgs `json:"cni,omitempty"`
|
Cni BridgeArgs `json:"cni,omitempty"`
|
||||||
@ -530,6 +531,10 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
|
|
||||||
isLayer3 := n.IPAM.Type != ""
|
isLayer3 := n.IPAM.Type != ""
|
||||||
|
|
||||||
|
if isLayer3 && n.DisableContainerInterface {
|
||||||
|
return fmt.Errorf("cannot use IPAM when DisableContainerInterface flag is set")
|
||||||
|
}
|
||||||
|
|
||||||
if n.IsDefaultGW {
|
if n.IsDefaultGW {
|
||||||
n.IsGW = true
|
n.IsGW = true
|
||||||
}
|
}
|
||||||
@ -676,12 +681,13 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if !n.DisableContainerInterface {
|
||||||
if err := netns.Do(func(_ ns.NetNS) error {
|
if err := netns.Do(func(_ ns.NetNS) error {
|
||||||
link, err := netlink.LinkByName(args.IfName)
|
link, err := netlink.LinkByName(args.IfName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to retrieve link: %v", err)
|
return fmt.Errorf("failed to retrieve link: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If layer 2 we still need to set the container veth to up
|
// If layer 2 we still need to set the container veth to up
|
||||||
if err = netlink.LinkSetUp(link); err != nil {
|
if err = netlink.LinkSetUp(link); err != nil {
|
||||||
return fmt.Errorf("failed to set %q up: %v", args.IfName, err)
|
return fmt.Errorf("failed to set %q up: %v", args.IfName, err)
|
||||||
@ -692,23 +698,28 @@ func cmdAdd(args *skel.CmdArgs) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var hostVeth netlink.Link
|
hostVeth, err := netlink.LinkByName(hostInterface.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// check bridge port state
|
if !n.DisableContainerInterface {
|
||||||
retries := []int{0, 50, 500, 1000, 1000}
|
// check bridge port state
|
||||||
for idx, sleep := range retries {
|
retries := []int{0, 50, 500, 1000, 1000}
|
||||||
time.Sleep(time.Duration(sleep) * time.Millisecond)
|
for idx, sleep := range retries {
|
||||||
|
time.Sleep(time.Duration(sleep) * time.Millisecond)
|
||||||
|
|
||||||
hostVeth, err = netlink.LinkByName(hostInterface.Name)
|
hostVeth, err = netlink.LinkByName(hostInterface.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if hostVeth.Attrs().OperState == netlink.OperUp {
|
if hostVeth.Attrs().OperState == netlink.OperUp {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if idx == len(retries)-1 {
|
if idx == len(retries)-1 {
|
||||||
return fmt.Errorf("bridge port in error state: %s", hostVeth.Attrs().OperState)
|
return fmt.Errorf("bridge port in error state: %s", hostVeth.Attrs().OperState)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,10 +78,12 @@ type testCase struct {
|
|||||||
removeDefaultVlan bool
|
removeDefaultVlan bool
|
||||||
ipMasq bool
|
ipMasq bool
|
||||||
macspoofchk bool
|
macspoofchk bool
|
||||||
AddErr020 string
|
disableContIface bool
|
||||||
DelErr020 string
|
|
||||||
AddErr010 string
|
AddErr020 string
|
||||||
DelErr010 string
|
DelErr020 string
|
||||||
|
AddErr010 string
|
||||||
|
DelErr010 string
|
||||||
|
|
||||||
envArgs string // CNI_ARGS
|
envArgs string // CNI_ARGS
|
||||||
runtimeConfig struct {
|
runtimeConfig struct {
|
||||||
@ -154,6 +156,9 @@ const (
|
|||||||
netDefault = `,
|
netDefault = `,
|
||||||
"isDefaultGateway": true`
|
"isDefaultGateway": true`
|
||||||
|
|
||||||
|
disableContainerInterface = `,
|
||||||
|
"disableContainerInterface": true`
|
||||||
|
|
||||||
ipamStartStr = `,
|
ipamStartStr = `,
|
||||||
"ipam": {
|
"ipam": {
|
||||||
"type": "host-local"`
|
"type": "host-local"`
|
||||||
@ -248,6 +253,10 @@ func (tc testCase) netConfJSON(dataDir string) string {
|
|||||||
conf += fmt.Sprintf(macspoofchkFormat, tc.macspoofchk)
|
conf += fmt.Sprintf(macspoofchkFormat, tc.macspoofchk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tc.disableContIface {
|
||||||
|
conf += disableContainerInterface
|
||||||
|
}
|
||||||
|
|
||||||
if !tc.isLayer2 {
|
if !tc.isLayer2 {
|
||||||
conf += netDefault
|
conf += netDefault
|
||||||
if tc.subnet != "" || tc.ranges != nil {
|
if tc.subnet != "" || tc.ranges != nil {
|
||||||
@ -677,14 +686,16 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(link.Attrs().Name).To(Equal(IFNAME))
|
Expect(link.Attrs().Name).To(Equal(IFNAME))
|
||||||
Expect(link).To(BeAssignableToTypeOf(&netlink.Veth{}))
|
Expect(link).To(BeAssignableToTypeOf(&netlink.Veth{}))
|
||||||
|
assertContainerInterfaceLinkState(&tc, link)
|
||||||
|
|
||||||
expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs()
|
expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs()
|
||||||
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
|
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(addrs).To(HaveLen(len(expCIDRsV4)))
|
Expect(addrs).To(HaveLen(len(expCIDRsV4)))
|
||||||
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
|
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
|
||||||
Expect(addrs).To(HaveLen(len(expCIDRsV6) + 1)) // add one for the link-local
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
assertIPv6Addresses(&tc, addrs, expCIDRsV6)
|
||||||
|
|
||||||
// Ignore link local address which may or may not be
|
// Ignore link local address which may or may not be
|
||||||
// ready when we read addresses.
|
// ready when we read addresses.
|
||||||
var foundAddrs int
|
var foundAddrs int
|
||||||
@ -728,6 +739,15 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertContainerInterfaceLinkState(tc *testCase, link netlink.Link) {
|
||||||
|
linkState := int(link.Attrs().OperState)
|
||||||
|
if tc.disableContIface {
|
||||||
|
Expect(linkState).ToNot(Equal(netlink.OperUp))
|
||||||
|
} else {
|
||||||
|
Expect(linkState).To(Equal(netlink.OperUp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (tester *testerV10x) cmdCheckTest(tc testCase, conf *Net, _ string) {
|
func (tester *testerV10x) cmdCheckTest(tc testCase, conf *Net, _ string) {
|
||||||
// Generate network config and command arguments
|
// Generate network config and command arguments
|
||||||
tester.args = tc.createCheckCmdArgs(tester.targetNS, conf)
|
tester.args = tc.createCheckCmdArgs(tester.targetNS, conf)
|
||||||
@ -1008,8 +1028,9 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(addrs).To(HaveLen(len(expCIDRsV4)))
|
Expect(addrs).To(HaveLen(len(expCIDRsV4)))
|
||||||
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
|
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
|
||||||
Expect(addrs).To(HaveLen(len(expCIDRsV6) + 1)) // add one for the link-local
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
assertIPv6Addresses(&tc, addrs, expCIDRsV6)
|
||||||
|
|
||||||
// Ignore link local address which may or may not be
|
// Ignore link local address which may or may not be
|
||||||
// ready when we read addresses.
|
// ready when we read addresses.
|
||||||
var foundAddrs int
|
var foundAddrs int
|
||||||
@ -1053,6 +1074,14 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertIPv6Addresses(tc *testCase, addrs []netlink.Addr, expCIDRsV6 []*net.IPNet) {
|
||||||
|
if tc.disableContIface {
|
||||||
|
Expect(addrs).To(BeEmpty())
|
||||||
|
} else {
|
||||||
|
Expect(addrs).To(HaveLen(len(expCIDRsV6) + 1)) // add one for the link-local
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (tester *testerV04x) cmdCheckTest(tc testCase, conf *Net, _ string) {
|
func (tester *testerV04x) cmdCheckTest(tc testCase, conf *Net, _ string) {
|
||||||
// Generate network config and command arguments
|
// Generate network config and command arguments
|
||||||
tester.args = tc.createCheckCmdArgs(tester.targetNS, conf)
|
tester.args = tc.createCheckCmdArgs(tester.targetNS, conf)
|
||||||
@ -2461,6 +2490,36 @@ var _ = Describe("bridge Operations", func() {
|
|||||||
return nil
|
return nil
|
||||||
})).To(Succeed())
|
})).To(Succeed())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] should fail when both IPAM and DisableContainerInterface are set", ver), func() {
|
||||||
|
Expect(originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
tc := testCase{
|
||||||
|
cniVersion: ver,
|
||||||
|
subnet: "10.1.2.0/24",
|
||||||
|
disableContIface: true,
|
||||||
|
}
|
||||||
|
args := tc.createCmdArgs(targetNS, dataDir)
|
||||||
|
Expect(cmdAdd(args)).To(HaveOccurred())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})).To(Succeed())
|
||||||
|
})
|
||||||
|
|
||||||
|
It(fmt.Sprintf("[%s] should set the container veth peer state down", ver), func() {
|
||||||
|
Expect(originalNS.Do(func(ns.NetNS) error {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
tc := testCase{
|
||||||
|
cniVersion: ver,
|
||||||
|
disableContIface: 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