bridge: add support for promiscuous mode
authorDaniel Nardo <dnardo@google.com>
Sat, 1 Jul 2017 00:08:30 +0000 (17:08 -0700)
committerDaniel Nardo <dnardo@google.com>
Wed, 5 Jul 2017 16:51:10 +0000 (09:51 -0700)
plugins/main/bridge/README.md
plugins/main/bridge/bridge.go
plugins/main/bridge/bridge_test.go

index 3abe99f..07eac59 100644 (file)
@@ -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.
index 4e5bb1e..ef969be 100644 (file)
@@ -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
index f971119..2939b12 100644 (file)
@@ -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())
+       })
 })