diff --git a/network/mode/bridge/bridge.go b/network/mode/bridge/bridge.go index dd29e82b1..ea20c699d 100644 --- a/network/mode/bridge/bridge.go +++ b/network/mode/bridge/bridge.go @@ -11,6 +11,7 @@ import ( "github.com/alibaba/pouch/daemon/mgr" "github.com/alibaba/pouch/network" "github.com/alibaba/pouch/pkg/errtypes" + "github.com/alibaba/pouch/pkg/utils" "github.com/docker/libnetwork/drivers/bridge" "github.com/docker/libnetwork/netlabel" @@ -30,55 +31,39 @@ func New(ctx context.Context, config network.BridgeConfig, manager mgr.NetworkMg } } - // set bridge name + // get bridge name bridgeName := DefaultBridge if config.Name != "" { bridgeName = config.Name } - // init host bridge network. - br, err := initBridgeDevice(bridgeName) + // get bridge ip + bridgeIP := utils.StringDefault(config.IP, DefaultIPNet) + ipNet, err := netlink.ParseIPNet(bridgeIP) if err != nil { - return err + return fmt.Errorf("failed to parse ip %v", bridgeIP) } + logrus.Debugf("initialize bridge network, bridge ip: %s.", ipNet) - var ( - bridgeIPv4Address string - ) - Addrs, err := netlink.AddrList(br, netlink.FAMILY_V4) + // init host bridge network. + _, err = initBridgeDevice(bridgeName, ipNet) if err != nil { - return errors.Wrap(err, "failed to get bridge addr") - } - for _, addr := range Addrs { - cidr := addr.String() - if strings.Contains(cidr, ":") { - continue - } - - parts := strings.Split(cidr, " ") - if len(parts) != 2 { - continue - } - - bridgeIPv4Address = parts[0] - break + return err } - // get subnet - subnet := DefaultSubnet - if config.IP != "" { - subnet = config.IP - } else if bridgeIPv4Address != "" { - subnet = bridgeIPv4Address + // get bridge subnet + _, subnet, err := net.ParseCIDR(bridgeIP) + if err != nil { + return fmt.Errorf("failted to parse subnet %v", bridgeIP) } - logrus.Debugf("initialize bridge network, subnet: %s", subnet) + logrus.Debugf("initialize bridge network, bridge network: %s", subnet) // get ip range ipRange := DefaultIPRange if config.FixedCIDR != "" { ipRange = config.FixedCIDR } else { - ipRange = subnet + ipRange = subnet.String() } logrus.Debugf("initialize bridge network, bridge ip range in subnet: %s", ipRange) @@ -86,30 +71,12 @@ func New(ctx context.Context, config network.BridgeConfig, manager mgr.NetworkMg gateway := DefaultGateway if config.GatewayIPv4 != "" { gateway = config.GatewayIPv4 - } else { - // get the default route set as gateway. - routes, err := netlink.RouteList(br, netlink.FAMILY_V4) - if err != nil { - return errors.Wrap(err, "failed to get route list") - } - for _, route := range routes { - gw := route.Gw.String() - if gw != "" && gw != "" { - gateway = gw - break - } - } - - // nat mode bridge have no default route, so let the bridge ip as gateway. - if bridgeIPv4Address != "" { - gateway = strings.Split(bridgeIPv4Address, "/")[0] - } } logrus.Debugf("initialize bridge network, gateway: %s", gateway) ipamV4Conf := types.IPAMConfig{ AuxAddress: make(map[string]string), - Subnet: subnet, + Subnet: subnet.String(), IPRange: ipRange, Gateway: gateway, } @@ -148,15 +115,49 @@ func New(ctx context.Context, config network.BridgeConfig, manager mgr.NetworkMg return err } -func initBridgeDevice(name string) (netlink.Link, error) { +func containIP(ip net.IPNet, br netlink.Link) bool { + addrs, err := netlink.AddrList(br, netlink.FAMILY_V4) + if err == nil { + for _, addr := range addrs { + if ip.IP.Equal(addr.IP) { + sizea, _ := ip.Mask.Size() + sizeb, _ := addr.Mask.Size() + if sizea == sizeb { + return true + } + } + } + } + return false +} + +func existVethPair(br netlink.Link) bool { + allLinks, err := netlink.LinkList() + if err == nil { + for _, l := range allLinks { + if l.Type() == "veth" && l.Attrs().MasterIndex == br.Attrs().Index { + return true + } + } + } + return false +} + +func initBridgeDevice(name string, ipNet *net.IPNet) (netlink.Link, error) { br, err := netlink.LinkByName(name) if err == nil && br != nil { - return br, nil + if containIP(*ipNet, br) { // do nothing if ip exists + return br, nil + } + if existVethPair(br) { + return nil, fmt.Errorf("failed to remove old bridge device due to existing veth pair") + } + netlink.LinkDel(br) } // generate mac address for bridge. var ip []int - for _, v := range strings.Split(DefaultBridgeIP, ".") { + for _, v := range strings.Split(ipNet.IP.String(), ".") { tmp, _ := strconv.Atoi(v) ip = append(ip, tmp) } @@ -184,7 +185,7 @@ func initBridgeDevice(name string) (netlink.Link, error) { } }() - addr, err := netlink.ParseAddr(DefaultSubnet) + addr, err := netlink.ParseAddr(ipNet.String()) if err != nil { return nil, errors.Wrap(err, "failed to parse ip address") } diff --git a/network/mode/bridge/vars.go b/network/mode/bridge/vars.go index ba9997367..907e4dfd6 100644 --- a/network/mode/bridge/vars.go +++ b/network/mode/bridge/vars.go @@ -4,11 +4,8 @@ const ( // DefaultBridge defines the default bridge name. DefaultBridge = "p0" - // DefaultBridgeIP defines the default bridge ip. - DefaultBridgeIP = "192.168.5.1" - - // DefaultSubnet defines the default bridge subnet. - DefaultSubnet = "192.168.5.1/24" + // DefaultIPNet defines the default bridge ip. + DefaultIPNet = "192.168.5.1/24" // DefaultIPRange defines the default bridge ip range in ipam. DefaultIPRange = "192.168.5.1/24" diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 7b9a1b9b2..3305886e9 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -353,3 +353,11 @@ func MergeMap(m1 map[string]interface{}, m2 map[string]interface{}) (map[string] return m1, nil } + +// StringDefault return default value if s is empty, otherwise return s. +func StringDefault(s string, val string) string { + if s != "" { + return s + } + return val +}