plugins: reconfigure bridge IP address
authorLukasz Zajaczkowski <Lukasz.Zajaczkowski@ts.fujitsu.com>
Fri, 29 Jul 2016 11:02:32 +0000 (13:02 +0200)
committerLukasz Zajaczkowski <Lukasz.Zajaczkowski@ts.fujitsu.com>
Tue, 2 Aug 2016 05:33:17 +0000 (07:33 +0200)
Add possibility to reconfigure bridge IP address when there is a new value.
New boolean flag added to net configuration to force IP change if it is need.
Otherwise code behaves as previously and throws error

plugins/main/bridge/bridge.go
plugins/main/bridge/bridge_test.go

index d4fc89c..7309c40 100644 (file)
@@ -35,12 +35,13 @@ const defaultBrName = "cni0"
 
 type NetConf struct {
        types.NetConf
-       BrName      string `json:"bridge"`
-       IsGW        bool   `json:"isGateway"`
-       IsDefaultGW bool   `json:"isDefaultGateway"`
-       IPMasq      bool   `json:"ipMasq"`
-       MTU         int    `json:"mtu"`
-       HairpinMode bool   `json:"hairpinMode"`
+       BrName       string `json:"bridge"`
+       IsGW         bool   `json:"isGateway"`
+       IsDefaultGW  bool   `json:"isDefaultGateway"`
+       ForceAddress bool   `json:"forceAddress"`
+       IPMasq       bool   `json:"ipMasq"`
+       MTU          int    `json:"mtu"`
+       HairpinMode  bool   `json:"hairpinMode"`
 }
 
 func init() {
@@ -60,7 +61,7 @@ func loadNetConf(bytes []byte) (*NetConf, error) {
        return n, nil
 }
 
-func ensureBridgeAddr(br *netlink.Bridge, ipn *net.IPNet) error {
+func ensureBridgeAddr(br *netlink.Bridge, ipn *net.IPNet, forceAddress bool) error {
        addrs, err := netlink.AddrList(br, syscall.AF_INET)
        if err != nil && err != syscall.ENOENT {
                return fmt.Errorf("could not get list of IP addresses: %v", err)
@@ -74,8 +75,16 @@ func ensureBridgeAddr(br *netlink.Bridge, ipn *net.IPNet) error {
                        if a.IPNet.String() == ipnStr {
                                return nil
                        }
+
+                       // If forceAddress is set to true then reconfigure IP address otherwise throw error
+                       if forceAddress {
+                               if err = deleteBridgeAddr(br, a.IPNet); err != nil {
+                                       return err
+                               }
+                       } else {
+                               return fmt.Errorf("%q already has an IP address different from %v", br.Name, ipn.String())
+                       }
                }
-               return fmt.Errorf("%q already has an IP address different from %v", br.Name, ipn.String())
        }
 
        addr := &netlink.Addr{IPNet: ipn, Label: ""}
@@ -85,6 +94,24 @@ func ensureBridgeAddr(br *netlink.Bridge, ipn *net.IPNet) error {
        return nil
 }
 
+func deleteBridgeAddr(br *netlink.Bridge, ipn *net.IPNet) error {
+       addr := &netlink.Addr{IPNet: ipn, Label: ""}
+
+       if err := netlink.LinkSetDown(br); err != nil {
+               return fmt.Errorf("could not set down bridge %q: %v", br.Name, err)
+       }
+
+       if err := netlink.AddrDel(br, addr); err != nil {
+               return fmt.Errorf("could not remove IP address from %q: %v", br.Name, err)
+       }
+
+       if err := netlink.LinkSetUp(br); err != nil {
+               return fmt.Errorf("could not set up bridge %q: %v", br.Name, err)
+       }
+
+       return nil
+}
+
 func bridgeByName(name string) (*netlink.Bridge, error) {
        l, err := netlink.LinkByName(name)
        if err != nil {
@@ -258,7 +285,7 @@ func cmdAdd(args *skel.CmdArgs) error {
                        Mask: result.IP4.IP.Mask,
                }
 
-               if err = ensureBridgeAddr(br, gwn); err != nil {
+               if err = ensureBridgeAddr(br, gwn, n.ForceAddress); err != nil {
                        return err
                }
 
index 14fef56..6fa45b3 100644 (file)
@@ -236,4 +236,74 @@ var _ = Describe("bridge Operations", func() {
                })
                Expect(err).NotTo(HaveOccurred())
        })
+
+       It("ensure bridge address", 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{
+                               Name: "testConfig",
+                               Type: "bridge",
+                       },
+                       BrName: IFNAME,
+                       IsGW:   true,
+                       IPMasq: false,
+                       MTU:    5000,
+               }
+
+               gwnFirst := &net.IPNet{
+                       IP:   net.IPv4(10, 0, 0, 0),
+                       Mask: net.CIDRMask(8, 32),
+               }
+
+               gwnSecond := &net.IPNet{
+                       IP:   net.IPv4(10, 1, 2, 3),
+                       Mask: net.CIDRMask(16, 32),
+               }
+
+               err := originalNS.Do(func(ns.NetNS) error {
+                       defer GinkgoRecover()
+
+                       bridge, err := setupBridge(conf)
+                       Expect(err).NotTo(HaveOccurred())
+                       // Check if ForceAddress has default value
+                       Expect(conf.ForceAddress).To(Equal(false))
+
+                       err = ensureBridgeAddr(bridge, gwnFirst, conf.ForceAddress)
+                       Expect(err).NotTo(HaveOccurred())
+
+                       //Check if IP address is set correctly
+                       addrs, err := netlink.AddrList(bridge, syscall.AF_INET)
+                       Expect(len(addrs)).To(Equal(1))
+                       addr := addrs[0].IPNet.String()
+                       Expect(addr).To(Equal(EXPECTED_IP))
+
+                       //The bridge IP address has been changed. Error expected when ForceAddress is set to false.
+                       err = ensureBridgeAddr(bridge, gwnSecond, false)
+                       Expect(err).To(HaveOccurred())
+
+                       //The IP address should stay the same.
+                       addrs, err = netlink.AddrList(bridge, syscall.AF_INET)
+                       Expect(len(addrs)).To(Equal(1))
+                       addr = addrs[0].IPNet.String()
+                       Expect(addr).To(Equal(EXPECTED_IP))
+
+                       //Reconfigure IP when ForceAddress is set to true and IP address has been changed.
+                       err = ensureBridgeAddr(bridge, gwnSecond, true)
+                       Expect(err).NotTo(HaveOccurred())
+
+                       //Retrieve the IP address after reconfiguration
+                       addrs, err = netlink.AddrList(bridge, syscall.AF_INET)
+                       Expect(len(addrs)).To(Equal(1))
+                       addr = addrs[0].IPNet.String()
+                       Expect(addr).To(Equal(CHANGED_EXPECTED_IP))
+
+                       return nil
+               })
+               Expect(err).NotTo(HaveOccurred())
+       })
+
 })