diff --git a/plugins/main/bridge/README.md b/plugins/main/bridge/README.md index 3abe99fda..07eac591a 100644 --- a/plugins/main/bridge/README.md +++ b/plugins/main/bridge/README.md @@ -40,3 +40,4 @@ If the bridge is missing, the plugin will create one on first use and, if gatewa * `mtu` (integer, optional): explicitly set MTU to the specified value. Defaults to the value chosen by the kernel. * `hairpinMode` (boolean, optional): set hairpin mode for interfaces on the bridge. Defaults to false. * `ipam` (dictionary, required): IPAM configuration to be used for this network. +* `promiscMode` (boolean, optional): set promiscuous mode on the bridge. Defaults to false. diff --git a/plugins/main/bridge/bridge.go b/plugins/main/bridge/bridge.go index 4e5bb1e44..ef969bea8 100644 --- a/plugins/main/bridge/bridge.go +++ b/plugins/main/bridge/bridge.go @@ -46,6 +46,7 @@ type NetConf struct { IPMasq bool `json:"ipMasq"` MTU int `json:"mtu"` HairpinMode bool `json:"hairpinMode"` + PromiscMode bool `json:"promiscMode"` } type gwInfo struct { @@ -196,7 +197,7 @@ func bridgeByName(name string) (*netlink.Bridge, error) { return br, nil } -func ensureBridge(brName string, mtu int) (*netlink.Bridge, error) { +func ensureBridge(brName string, mtu int, promiscMode bool) (*netlink.Bridge, error) { br := &netlink.Bridge{ LinkAttrs: netlink.LinkAttrs{ Name: brName, @@ -214,6 +215,12 @@ func ensureBridge(brName string, mtu int) (*netlink.Bridge, error) { return nil, fmt.Errorf("could not add %q: %v", brName, err) } + if promiscMode { + if err := netlink.SetPromiscOn(br); err != nil { + return nil, fmt.Errorf("could not set promiscuous mode on %q: %v", brName, err) + } + } + // Re-fetch link to read all attributes and if it already existed, // ensure it's really a bridge with similar configuration br, err = bridgeByName(brName) @@ -275,7 +282,7 @@ func calcGatewayIP(ipn *net.IPNet) net.IP { func setupBridge(n *NetConf) (*netlink.Bridge, *current.Interface, error) { // create bridge if necessary - br, err := ensureBridge(n.BrName, n.MTU) + br, err := ensureBridge(n.BrName, n.MTU, n.PromiscMode) if err != nil { return nil, nil, fmt.Errorf("failed to create bridge %q: %v", n.BrName, err) } @@ -310,6 +317,10 @@ func cmdAdd(args *skel.CmdArgs) error { n.IsGW = true } + if n.HairpinMode && n.PromiscMode { + return fmt.Errorf("cannot set hairpin mode and promiscous mode at the same time.") + } + br, brInterface, err := setupBridge(n) if err != nil { return err diff --git a/plugins/main/bridge/bridge_test.go b/plugins/main/bridge/bridge_test.go index f97111970..2939b12c1 100644 --- a/plugins/main/bridge/bridge_test.go +++ b/plugins/main/bridge/bridge_test.go @@ -583,6 +583,7 @@ var _ = Describe("bridge Operations", func() { link, err := netlink.LinkByName(BRNAME) Expect(err).NotTo(HaveOccurred()) Expect(link.Attrs().Name).To(Equal(BRNAME)) + Expect(link.Attrs().Promisc).To(Equal(0)) return nil }) Expect(err).NotTo(HaveOccurred()) @@ -854,4 +855,41 @@ var _ = Describe("bridge Operations", func() { delBridgeAddrs(originalNS) } }) + It("ensure promiscuous mode on bridge", func() { + const IFNAME = "bridge0" + const EXPECTED_IP = "10.0.0.0/8" + const CHANGED_EXPECTED_IP = "10.1.2.3/16" + + conf := &NetConf{ + NetConf: types.NetConf{ + CNIVersion: "0.3.1", + Name: "testConfig", + Type: "bridge", + }, + BrName: IFNAME, + IsGW: true, + IPMasq: false, + HairpinMode: false, + PromiscMode: true, + MTU: 5000, + } + + err := originalNS.Do(func(ns.NetNS) error { + defer GinkgoRecover() + + _, _, err := setupBridge(conf) + Expect(err).NotTo(HaveOccurred()) + // Check if ForceAddress has default value + Expect(conf.ForceAddress).To(Equal(false)) + + //Check if promiscuous mode is set correctly + link, err := netlink.LinkByName("bridge0") + Expect(err).NotTo(HaveOccurred()) + + Expect(link.Attrs().Promisc).To(Equal(1)) + + return nil + }) + Expect(err).NotTo(HaveOccurred()) + }) })