From aa4bf4284b4d18874544368349cb9575d8412de8 Mon Sep 17 00:00:00 2001 From: "Guillaume J. Charmes" Date: Wed, 3 Apr 2013 15:57:57 -0700 Subject: [PATCH] If bridge does not exists, try to create it --- network.go | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/network.go b/network.go index d6b7537c2b..cde78e7aa6 100644 --- a/network.go +++ b/network.go @@ -64,6 +64,19 @@ func networkSize(mask net.IPMask) int32 { return int32(binary.BigEndian.Uint32(m)) + 1 } +//Wrapper around the ip command +func ip(args ...string) (string, error) { + path, err := exec.LookPath("ip") + if err != nil { + return "", fmt.Errorf("command not found: ip") + } + output, err := exec.Command(path, args...).CombinedOutput() + if err != nil { + return "", fmt.Errorf("ip failed: ip %v", strings.Join(args, " ")) + } + return string(output), nil +} + // Wrapper around the iptables command func iptables(args ...string) error { path, err := exec.LookPath("iptables") @@ -76,6 +89,64 @@ func iptables(args ...string) error { return nil } +func checkRouteOverlaps(dockerNetwork *net.IPNet) error { + output, err := ip("route") + if err != nil { + return err + } + Debugf("Routes:\n\n%s", output) + for _, line := range strings.Split(output, "\n") { + if strings.Trim(line, "\r\n\t ") == "" || strings.Contains(line, "default") { + continue + } + if _, network, err := net.ParseCIDR(strings.Split(line, " ")[0]); err != nil { + return fmt.Errorf("Unexpected ip route output: %s (%s)", err, line) + } else if networkOverlaps(dockerNetwork, network) { + return fmt.Errorf("Network %s is already routed: '%s'", dockerNetwork.String(), line) + } + } + return nil +} + +func CreateBridgeIface(ifaceName string) error { + addrs := []string{"172.16.42.1/24", "10.0.42.1/24", "192.168.42.1/24"} + + var ifaceAddr string + for _, addr := range addrs { + _, dockerNetwork, err := net.ParseCIDR(addr) + if err != nil { + return err + } + if err := checkRouteOverlaps(dockerNetwork); err == nil { + ifaceAddr = addr + break + } else { + Debugf("%s: %s", addr, err) + } + } + if ifaceAddr == "" { + return fmt.Errorf("Impossible to create a bridge. Please create a bridge manually and restart docker with -br ") + } else { + Debugf("Creating bridge %s with network %s", ifaceName, ifaceAddr) + } + + if output, err := ip("link", "add", ifaceName, "type", "bridge"); err != nil { + return fmt.Errorf("Error creating bridge: %s (output: %s)", err, output) + } + + if output, err := ip("addr", "add", ifaceAddr, "dev", ifaceName); err != nil { + return fmt.Errorf("Unable to add private network: %s (%s)", err, output) + } + if output, err := ip("link", "set", ifaceName, "up"); err != nil { + return fmt.Errorf("Unable to start network bridge: %s (%s)", err, output) + } + if err := iptables("-t", "nat", "-A", "POSTROUTING", "-s", ifaceAddr, + "!", "-d", ifaceAddr, "-j", "MASQUERADE"); err != nil { + return fmt.Errorf("Unable to enable network bridge NAT: %s", err) + } + return nil +} + // Return the IPv4 address of a network interface func getIfaceAddr(name string) (net.Addr, error) { iface, err := net.InterfaceByName(name) @@ -371,7 +442,14 @@ func (manager *NetworkManager) Allocate() (*NetworkInterface, error) { func newNetworkManager(bridgeIface string) (*NetworkManager, error) { addr, err := getIfaceAddr(bridgeIface) if err != nil { - return nil, fmt.Errorf("Couldn't find bridge interface %s (%s).\nPlease create it with 'ip link add lxcbr0 type bridge; ip addr add ADDRESS/MASK dev lxcbr0'", bridgeIface, err) + // If the iface is not found, try to create it + if err := CreateBridgeIface(bridgeIface); err != nil { + return nil, err + } + addr, err = getIfaceAddr(bridgeIface) + if err != nil { + return nil, err + } } network := addr.(*net.IPNet)