We have our own netlink version of all the required calls now, so
we can just skip the /sbin/ip dependency.
| ... | ... |
@@ -6,12 +6,11 @@ import ( |
| 6 | 6 |
"fmt" |
| 7 | 7 |
"github.com/dotcloud/docker/iptables" |
| 8 | 8 |
"github.com/dotcloud/docker/proxy" |
| 9 |
+ "github.com/dotcloud/docker/netlink" |
|
| 9 | 10 |
"github.com/dotcloud/docker/utils" |
| 10 | 11 |
"log" |
| 11 | 12 |
"net" |
| 12 |
- "os/exec" |
|
| 13 | 13 |
"strconv" |
| 14 |
- "strings" |
|
| 15 | 14 |
"sync" |
| 16 | 15 |
) |
| 17 | 16 |
|
| ... | ... |
@@ -68,42 +67,10 @@ func networkSize(mask net.IPMask) int32 {
|
| 68 | 68 |
return int32(binary.BigEndian.Uint32(m)) + 1 |
| 69 | 69 |
} |
| 70 | 70 |
|
| 71 |
-//Wrapper around the ip command |
|
| 72 |
-func ip(args ...string) (string, error) {
|
|
| 73 |
- path, err := exec.LookPath("ip")
|
|
| 74 |
- if err != nil {
|
|
| 75 |
- return "", fmt.Errorf("command not found: ip")
|
|
| 76 |
- } |
|
| 77 |
- output, err := exec.Command(path, args...).CombinedOutput() |
|
| 78 |
- if err != nil {
|
|
| 79 |
- return "", fmt.Errorf("ip failed: ip %v", strings.Join(args, " "))
|
|
| 80 |
- } |
|
| 81 |
- return string(output), nil |
|
| 82 |
-} |
|
| 83 |
- |
|
| 84 |
-func checkRouteOverlaps(routes string, dockerNetwork *net.IPNet) error {
|
|
| 85 |
- utils.Debugf("Routes:\n\n%s", routes)
|
|
| 86 |
- for _, line := range strings.Split(routes, "\n") {
|
|
| 87 |
- if strings.Trim(line, "\r\n\t ") == "" || strings.Contains(line, "default") {
|
|
| 88 |
- continue |
|
| 89 |
- } |
|
| 90 |
- _, network, err := net.ParseCIDR(strings.Split(line, " ")[0]) |
|
| 91 |
- if err != nil {
|
|
| 92 |
- // is this a mask-less IP address? |
|
| 93 |
- if ip := net.ParseIP(strings.Split(line, " ")[0]); ip == nil {
|
|
| 94 |
- // fail only if it's neither a network nor a mask-less IP address |
|
| 95 |
- return fmt.Errorf("Unexpected ip route output: %s (%s)", err, line)
|
|
| 96 |
- } else {
|
|
| 97 |
- _, network, err = net.ParseCIDR(ip.String() + "/32") |
|
| 98 |
- if err != nil {
|
|
| 99 |
- return err |
|
| 100 |
- } |
|
| 101 |
- } |
|
| 102 |
- } |
|
| 103 |
- if err == nil && network != nil {
|
|
| 104 |
- if networkOverlaps(dockerNetwork, network) {
|
|
| 105 |
- return fmt.Errorf("Network %s is already routed: '%s'", dockerNetwork, line)
|
|
| 106 |
- } |
|
| 71 |
+func checkRouteOverlaps(networks []*net.IPNet, dockerNetwork *net.IPNet) error {
|
|
| 72 |
+ for _, network := range networks {
|
|
| 73 |
+ if networkOverlaps(dockerNetwork, network) {
|
|
| 74 |
+ return fmt.Errorf("Network %s is already routed: '%s'", dockerNetwork, network)
|
|
| 107 | 75 |
} |
| 108 | 76 |
} |
| 109 | 77 |
return nil |
| ... | ... |
@@ -139,7 +106,7 @@ func CreateBridgeIface(config *DaemonConfig) error {
|
| 139 | 139 |
if err != nil {
|
| 140 | 140 |
return err |
| 141 | 141 |
} |
| 142 |
- routes, err := ip("route")
|
|
| 142 |
+ routes, err := netlink.NetworkGetRoutes() |
|
| 143 | 143 |
if err != nil {
|
| 144 | 144 |
return err |
| 145 | 145 |
} |
| ... | ... |
@@ -155,15 +122,22 @@ func CreateBridgeIface(config *DaemonConfig) error {
|
| 155 | 155 |
} |
| 156 | 156 |
utils.Debugf("Creating bridge %s with network %s", config.BridgeIface, ifaceAddr)
|
| 157 | 157 |
|
| 158 |
- if output, err := ip("link", "add", config.BridgeIface, "type", "bridge"); err != nil {
|
|
| 159 |
- return fmt.Errorf("Error creating bridge: %s (output: %s)", err, output)
|
|
| 158 |
+ if err := netlink.NetworkLinkAdd(config.BridgeIface, "bridge"); err != nil {
|
|
| 159 |
+ return fmt.Errorf("Error creating bridge: %s", err)
|
|
| 160 | 160 |
} |
| 161 |
- |
|
| 162 |
- if output, err := ip("addr", "add", ifaceAddr, "dev", config.BridgeIface); err != nil {
|
|
| 163 |
- return fmt.Errorf("Unable to add private network: %s (%s)", err, output)
|
|
| 161 |
+ iface, err := net.InterfaceByName(config.BridgeIface) |
|
| 162 |
+ if err != nil {
|
|
| 163 |
+ return err |
|
| 164 |
+ } |
|
| 165 |
+ ipAddr, ipNet, err := net.ParseCIDR(ifaceAddr) |
|
| 166 |
+ if err != nil {
|
|
| 167 |
+ return err |
|
| 168 |
+ } |
|
| 169 |
+ if netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
|
|
| 170 |
+ return fmt.Errorf("Unable to add private network: %s", err)
|
|
| 164 | 171 |
} |
| 165 |
- if output, err := ip("link", "set", config.BridgeIface, "up"); err != nil {
|
|
| 166 |
- return fmt.Errorf("Unable to start network bridge: %s (%s)", err, output)
|
|
| 172 |
+ if err := netlink.NetworkLinkUp(iface); err != nil {
|
|
| 173 |
+ return fmt.Errorf("Unable to start network bridge: %s", err)
|
|
| 167 | 174 |
} |
| 168 | 175 |
|
| 169 | 176 |
if config.EnableIptables {
|
| ... | ... |
@@ -277,12 +277,13 @@ func TestNetworkOverlaps(t *testing.T) {
|
| 277 | 277 |
} |
| 278 | 278 |
|
| 279 | 279 |
func TestCheckRouteOverlaps(t *testing.T) {
|
| 280 |
- routes := `default via 10.0.2.2 dev eth0 |
|
| 281 |
-10.0.2.0 dev eth0 proto kernel scope link src 10.0.2.15 |
|
| 282 |
-10.0.3.0/24 dev lxcbr0 proto kernel scope link src 10.0.3.1 |
|
| 283 |
-10.0.42.0/24 dev testdockbr0 proto kernel scope link src 10.0.42.1 |
|
| 284 |
-172.16.42.0/24 dev docker0 proto kernel scope link src 172.16.42.1 |
|
| 285 |
-192.168.142.0/24 dev eth1 proto kernel scope link src 192.168.142.142` |
|
| 280 |
+ routesData := []string{"10.0.2.0/32", "10.0.3.0/24", "10.0.42.0/24", "172.16.42.0/24", "192.168.142.0/24"}
|
|
| 281 |
+ |
|
| 282 |
+ routes := []*net.IPNet{}
|
|
| 283 |
+ for _, addr := range routesData {
|
|
| 284 |
+ _, netX, _ := net.ParseCIDR(addr) |
|
| 285 |
+ routes = append(routes, netX) |
|
| 286 |
+ } |
|
| 286 | 287 |
|
| 287 | 288 |
_, netX, _ := net.ParseCIDR("172.16.0.1/24")
|
| 288 | 289 |
if err := checkRouteOverlaps(routes, netX); err != nil {
|