From d09b18dac4f5ebf8e64e87c9ff18863cd7409a88 Mon Sep 17 00:00:00 2001 From: Lukasz Zajaczkowski Date: Fri, 29 Jul 2016 13:02:32 +0200 Subject: [PATCH] plugins: reconfigure bridge IP address 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 | 45 +++++++++++++++---- plugins/main/bridge/bridge_test.go | 70 ++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 9 deletions(-) diff --git a/plugins/main/bridge/bridge.go b/plugins/main/bridge/bridge.go index d4fc89c3..7309c403 100644 --- a/plugins/main/bridge/bridge.go +++ b/plugins/main/bridge/bridge.go @@ -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 } diff --git a/plugins/main/bridge/bridge_test.go b/plugins/main/bridge/bridge_test.go index 14fef56b..6fa45b3e 100644 --- a/plugins/main/bridge/bridge_test.go +++ b/plugins/main/bridge/bridge_test.go @@ -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()) + }) + })