Browse code

network: Stop shelling out to /sbin/ip

We have our own netlink version of all the required calls now, so
we can just skip the /sbin/ip dependency.

Alexander Larsson authored on 2013/09/19 17:57:11
Showing 2 changed files
... ...
@@ -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 {