Browse code

libnetwork support for Solaris Signed-off-by: Puneet Pruthi <puneetpruthi@gmail.com>

Puneet Pruthi authored on 2016/05/21 05:23:53
Showing 27 changed files
... ...
@@ -8,6 +8,14 @@ ciargs = -e CIRCLECI -e "COVERALLS_TOKEN=$$COVERALLS_TOKEN" -e "INSIDECONTAINER=
8 8
 cidocker = docker run ${dockerargs} ${ciargs} $$EXTRA_ARGS ${container_env} ${build_image}
9 9
 CROSS_PLATFORMS = linux/amd64 linux/386 linux/arm windows/amd64
10 10
 export PATH := $(CURDIR)/bin:$(PATH)
11
+hostOS = ${shell go env GOHOSTOS}
12
+ifeq (${hostOS}, solaris)
13
+	gnufind=gfind
14
+	gnutail=gtail
15
+else
16
+	gnufind=find
17
+	gnutail=tail
18
+endif
11 19
 
12 20
 all: ${build_image}.created build check integration-tests clean
13 21
 
... ...
@@ -62,7 +70,40 @@ check-format:
62 62
 run-tests:
63 63
 	@echo "Running tests... "
64 64
 	@echo "mode: count" > coverage.coverprofile
65
-	@for dir in $$(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d); do \
65
+	@for dir in $$( ${gnufind} . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d); do \
66
+	    if [ ${hostOS} == solaris ]; then \
67
+	        case "$$dir" in \
68
+		    "./cmd/dnet" ) \
69
+		    ;& \
70
+		    "./cmd/ovrouter" ) \
71
+		    ;& \
72
+		    "./ns" ) \
73
+		    ;& \
74
+		    "./iptables" ) \
75
+		    ;& \
76
+		    "./ipvs" ) \
77
+		    ;& \
78
+		    "./drivers/bridge" ) \
79
+		    ;& \
80
+		    "./drivers/host" ) \
81
+		    ;& \
82
+		    "./drivers/ipvlan" ) \
83
+		    ;& \
84
+		    "./drivers/macvlan" ) \
85
+		    ;& \
86
+		    "./drivers/overlay" ) \
87
+		    ;& \
88
+		    "./drivers/remote" ) \
89
+		    ;& \
90
+		    "./drivers/windows" ) \
91
+			echo "Skipping $$dir on solaris host... "; \
92
+			continue; \
93
+			;; \
94
+		    * )\
95
+			echo "Entering $$dir ... "; \
96
+			;; \
97
+	        esac; \
98
+	    fi; \
66 99
 	    if ls $$dir/*.go &> /dev/null; then \
67 100
 		pushd . &> /dev/null ; \
68 101
 		cd $$dir ; \
... ...
@@ -71,7 +112,7 @@ run-tests:
71 71
 		if [ $$ret -ne 0 ]; then exit $$ret; fi ;\
72 72
 		popd &> /dev/null; \
73 73
 		if [ -f $$dir/profile.tmp ]; then \
74
-			cat $$dir/profile.tmp | tail -n +2 >> coverage.coverprofile ; \
74
+			cat $$dir/profile.tmp | ${gnutail} -n +2 >> coverage.coverprofile ; \
75 75
 				rm $$dir/profile.tmp ; \
76 76
 	    fi ; \
77 77
 	fi ; \
78 78
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+package api
1
+
2
+import (
3
+	"github.com/docker/libnetwork/drivers/bridge"
4
+	"github.com/docker/libnetwork/netlabel"
5
+)
6
+
7
+func GetOpsMap(bridgeName, defaultMTU string) map[string]string {
8
+	if defaultMTU == "" {
9
+		return map[string]string{
10
+			bridge.BridgeName: bridgeName,
11
+		}
12
+	}
13
+	return map[string]string{
14
+		bridge.BridgeName:  bridgeName,
15
+		netlabel.DriverMTU: defaultMTU,
16
+	}
17
+}
0 18
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+package api
1
+
2
+import (
3
+	"github.com/docker/libnetwork/drivers/solaris/bridge"
4
+	"github.com/docker/libnetwork/netlabel"
5
+)
6
+
7
+func GetOpsMap(bridgeName, defaultMTU string) map[string]string {
8
+	if defaultMTU == "" {
9
+		return map[string]string{
10
+			bridge.BridgeName: bridgeName,
11
+		}
12
+	}
13
+	return map[string]string{
14
+		bridge.BridgeName:  bridgeName,
15
+		netlabel.DriverMTU: defaultMTU,
16
+	}
17
+}
... ...
@@ -15,7 +15,6 @@ import (
15 15
 	"github.com/docker/docker/pkg/reexec"
16 16
 	"github.com/docker/libnetwork"
17 17
 	"github.com/docker/libnetwork/datastore"
18
-	"github.com/docker/libnetwork/drivers/bridge"
19 18
 	"github.com/docker/libnetwork/netlabel"
20 19
 	"github.com/docker/libnetwork/options"
21 20
 	"github.com/docker/libnetwork/testutils"
... ...
@@ -225,9 +224,7 @@ func TestCreateDeleteNetwork(t *testing.T) {
225 225
 		t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp)
226 226
 	}
227 227
 
228
-	dops := map[string]string{
229
-		bridge.BridgeName: "abc",
230
-	}
228
+	dops := GetOpsMap("abc", "")
231 229
 	nops := map[string]string{
232 230
 		netlabel.EnableIPv6: "true",
233 231
 	}
... ...
@@ -273,9 +270,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
273 273
 	}
274 274
 	defer c.Stop()
275 275
 
276
-	ops := map[string]string{
277
-		bridge.BridgeName: "api_test_nw",
278
-	}
276
+	ops := GetOpsMap("api_test_nw", "")
279 277
 	nc := networkCreate{Name: "sh", NetworkType: bridgeNetType, DriverOpts: ops}
280 278
 	body, err := json.Marshal(nc)
281 279
 	if err != nil {
... ...
@@ -544,7 +539,7 @@ func TestProcGetServices(t *testing.T) {
544 544
 		t.Fatal(err)
545 545
 	}
546 546
 
547
-	netName2 := "work-dev"
547
+	netName2 := "workdev"
548 548
 	netOption = options.Generic{
549 549
 		netlabel.GenericData: options.Generic{
550 550
 			"BridgeName": netName2,
... ...
@@ -1811,10 +1806,7 @@ func TestEndToEnd(t *testing.T) {
1811 1811
 
1812 1812
 	handleRequest := NewHTTPHandler(c)
1813 1813
 
1814
-	dops := map[string]string{
1815
-		bridge.BridgeName:  "cdef",
1816
-		netlabel.DriverMTU: "1460",
1817
-	}
1814
+	dops := GetOpsMap("cdef", "1460")
1818 1815
 	nops := map[string]string{
1819 1816
 		netlabel.EnableIPv6: "true",
1820 1817
 	}
1821 1818
new file mode 100644
... ...
@@ -0,0 +1,1254 @@
0
+// +build solaris
1
+
2
+package bridge
3
+
4
+import (
5
+	"bufio"
6
+	"errors"
7
+	"fmt"
8
+	"net"
9
+	"os"
10
+	"os/exec"
11
+	"strconv"
12
+	"strings"
13
+	"sync"
14
+
15
+	"github.com/Sirupsen/logrus"
16
+	"github.com/docker/libnetwork/datastore"
17
+	"github.com/docker/libnetwork/discoverapi"
18
+	"github.com/docker/libnetwork/driverapi"
19
+	"github.com/docker/libnetwork/iptables"
20
+	"github.com/docker/libnetwork/netlabel"
21
+	"github.com/docker/libnetwork/netutils"
22
+	"github.com/docker/libnetwork/options"
23
+	"github.com/docker/libnetwork/portmapper"
24
+	"github.com/docker/libnetwork/types"
25
+)
26
+
27
+const (
28
+	networkType = "bridge"
29
+
30
+	// DefaultBridgeName is the default name for the bridge interface managed
31
+	// by the driver when unspecified by the caller.
32
+	DefaultBridgeName = "docker0"
33
+
34
+	// BridgeName label for bridge driver
35
+	BridgeName = "com.docker.network.bridge.name"
36
+
37
+	// EnableIPMasquerade label for bridge driver
38
+	EnableIPMasquerade = "com.docker.network.bridge.enable_ip_masquerade"
39
+
40
+	// EnableICC label
41
+	EnableICC = "com.docker.network.bridge.enable_icc"
42
+
43
+	// DefaultBindingIP label
44
+	DefaultBindingIP = "com.docker.network.bridge.host_binding_ipv4"
45
+
46
+	// DefaultBridge label
47
+	DefaultBridge = "com.docker.network.bridge.default_bridge"
48
+
49
+	// DefaultGatewayV4AuxKey represents the default-gateway configured by the user
50
+	DefaultGatewayV4AuxKey = "DefaultGatewayIPv4"
51
+
52
+	// DefaultGatewayV6AuxKey represents the ipv6 default-gateway configured by the user
53
+	DefaultGatewayV6AuxKey = "DefaultGatewayIPv6"
54
+)
55
+
56
+// configuration info for the "bridge" driver.
57
+type configuration struct {
58
+	EnableIPForwarding  bool
59
+	EnableIPTables      bool
60
+	EnableUserlandProxy bool
61
+}
62
+
63
+// networkConfiguration for network specific configuration
64
+type networkConfiguration struct {
65
+	ID                 string
66
+	BridgeName         string
67
+	BridgeNameInternal string
68
+	EnableIPv6         bool
69
+	EnableIPMasquerade bool
70
+	EnableICC          bool
71
+	Mtu                int
72
+	DefaultBindingIntf string
73
+	DefaultBindingIP   net.IP
74
+	DefaultBridge      bool
75
+	// Internal fields set after ipam data parsing
76
+	AddressIPv4        *net.IPNet
77
+	AddressIPv6        *net.IPNet
78
+	DefaultGatewayIPv4 net.IP
79
+	DefaultGatewayIPv6 net.IP
80
+	dbIndex            uint64
81
+	dbExists           bool
82
+	Internal           bool
83
+}
84
+
85
+// endpointConfiguration represents the user specified configuration for the sandbox endpoint
86
+type endpointConfiguration struct {
87
+	MacAddress   net.HardwareAddr
88
+	PortBindings []types.PortBinding
89
+	ExposedPorts []types.TransportPort
90
+}
91
+
92
+// containerConfiguration represents the user specified configuration for a container
93
+type containerConfiguration struct {
94
+	ParentEndpoints []string
95
+	ChildEndpoints  []string
96
+}
97
+
98
+// cnnectivityConfiguration represents the user specified configuration regarding the external connectivity
99
+type connectivityConfiguration struct {
100
+	PortBindings []types.PortBinding
101
+	ExposedPorts []types.TransportPort
102
+}
103
+
104
+type bridgeEndpoint struct {
105
+	id              string
106
+	nid             string
107
+	srcName         string
108
+	addr            *net.IPNet
109
+	addrv6          *net.IPNet
110
+	macAddress      net.HardwareAddr
111
+	config          *endpointConfiguration // User specified parameters
112
+	containerConfig *containerConfiguration
113
+	extConnConfig   *connectivityConfiguration
114
+	portMapping     []types.PortBinding // Operation port bindings
115
+	dbIndex         uint64
116
+	dbExists        bool
117
+}
118
+
119
+type bridgeInterface struct {
120
+	bridgeIPv4  *net.IPNet
121
+	bridgeIPv6  *net.IPNet
122
+	gatewayIPv4 net.IP
123
+	gatewayIPv6 net.IP
124
+}
125
+
126
+type bridgeNetwork struct {
127
+	id         string
128
+	bridge     *bridgeInterface
129
+	config     *networkConfiguration
130
+	endpoints  map[string]*bridgeEndpoint // key: endpoint id
131
+	portMapper *portmapper.PortMapper
132
+	driver     *driver // The network's driver
133
+	sync.Mutex
134
+}
135
+
136
+type driver struct {
137
+	config         *configuration
138
+	network        *bridgeNetwork
139
+	natChain       *iptables.ChainInfo
140
+	filterChain    *iptables.ChainInfo
141
+	isolationChain *iptables.ChainInfo
142
+	networks       map[string]*bridgeNetwork
143
+	store          datastore.DataStore
144
+	sync.Mutex
145
+	defrouteIP net.IP
146
+}
147
+
148
+// New constructs a new bridge driver
149
+func newDriver() *driver {
150
+	return &driver{networks: map[string]*bridgeNetwork{}}
151
+}
152
+
153
+// Init registers a new instance of bridge driver
154
+func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
155
+	d := newDriver()
156
+	if err := d.configure(config); err != nil {
157
+		return err
158
+	}
159
+
160
+	c := driverapi.Capability{
161
+		DataScope: datastore.LocalScope,
162
+	}
163
+	return dc.RegisterDriver(networkType, d, c)
164
+}
165
+
166
+func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
167
+	return nil, types.NotImplementedErrorf("not implemented")
168
+}
169
+
170
+func (d *driver) NetworkFree(id string) error {
171
+	return types.NotImplementedErrorf("not implemented")
172
+}
173
+
174
+func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
175
+}
176
+
177
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
178
+	if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
179
+		return types.BadRequestErrorf("ipv4 pool is empty")
180
+	}
181
+	// Sanity checks
182
+	d.Lock()
183
+	if _, ok := d.networks[id]; ok {
184
+		d.Unlock()
185
+		return types.ForbiddenErrorf("network %s exists", id)
186
+	}
187
+	d.Unlock()
188
+
189
+	// Parse and validate the config. It should not conflict with existing networks' config
190
+	config, err := parseNetworkOptions(d, id, option)
191
+	if err != nil {
192
+		return err
193
+	}
194
+
195
+	err = config.processIPAM(id, ipV4Data, ipV6Data)
196
+	if err != nil {
197
+		return err
198
+	}
199
+
200
+	if err = d.createNetwork(config); err != nil {
201
+		return err
202
+	}
203
+
204
+	return d.storeUpdate(config)
205
+}
206
+
207
+func newInterface(config *networkConfiguration) *bridgeInterface {
208
+	i := &bridgeInterface{}
209
+
210
+	i.bridgeIPv4 = config.AddressIPv4
211
+	i.gatewayIPv4 = config.AddressIPv4.IP
212
+	if config.BridgeName == "" {
213
+		config.BridgeName = DefaultBridgeName
214
+	}
215
+	return i
216
+}
217
+
218
+// This function prunes the pf.conf for the firewall
219
+// that enable the service successfully.
220
+func fixPFConf() error {
221
+	conf := "/etc/firewall/pf.conf"
222
+	f, err := os.Open("/etc/firewall/pf.conf")
223
+	if err != nil {
224
+		return fmt.Errorf("cannot open %s: %v", conf, err)
225
+	}
226
+	defer f.Close()
227
+
228
+	// Look for line beginning with "REMOVE THIS LINE"
229
+	modify := false
230
+	lines := []string{}
231
+	scanner := bufio.NewScanner(f)
232
+	for scanner.Scan() {
233
+		l := scanner.Text()
234
+		if strings.Contains(l, "REMOVE THIS LINE") {
235
+			modify = true
236
+			continue
237
+		}
238
+		lines = append(lines, fmt.Sprintf("%s\n", l))
239
+	}
240
+	if err = scanner.Err(); err != nil {
241
+		return fmt.Errorf("cannot open %s: %v", conf, err)
242
+	}
243
+
244
+	// No changes needed to fix pf.conf
245
+	if !modify {
246
+		return nil
247
+	}
248
+
249
+	// Write back the file removing the line found above
250
+	tmpname := "/etc/firewall/pf.conf.tmp." + strconv.Itoa(os.Getpid())
251
+	tmp, err := os.OpenFile(tmpname,
252
+		os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_APPEND, 0644)
253
+	if err != nil {
254
+		return fmt.Errorf("cannot open %s: %v", tmpname, err)
255
+	}
256
+	defer tmp.Close()
257
+	for _, l := range lines {
258
+		_, err = tmp.WriteString(l)
259
+		if err != nil {
260
+			return fmt.Errorf("cannot write to %s: %v",
261
+				tmpname, err)
262
+		}
263
+	}
264
+	if err = tmp.Sync(); err != nil {
265
+		return fmt.Errorf("cannot sync %s: %v", tmpname, err)
266
+	}
267
+	if err = os.Rename(tmpname, conf); err != nil {
268
+		return fmt.Errorf("cannot rename %s to %s: %v",
269
+			tmpname, conf, err)
270
+	}
271
+	return nil
272
+}
273
+
274
+func (d *driver) initFirewall() error {
275
+	out, err := exec.Command("/usr/bin/svcs", "-Ho", "state",
276
+		"firewall").Output()
277
+	if err != nil {
278
+		return fmt.Errorf("cannot check firewall state: %v", err)
279
+	}
280
+	state := strings.TrimSpace(string(out))
281
+	if state != "online" {
282
+		if state != "disabled" {
283
+			return fmt.Errorf("firewall service is in %s state. "+
284
+				"please enable service manually.", state)
285
+		}
286
+		if err = fixPFConf(); err != nil {
287
+			return fmt.Errorf("cannot verify pf.conf: %v", err)
288
+		}
289
+		err = exec.Command("/usr/sbin/svcadm", "enable", "-ts",
290
+			"firewall").Run()
291
+		if err != nil {
292
+			return fmt.Errorf("cannot enable firewall service: %v", err)
293
+		}
294
+	}
295
+	out, err = exec.Command("/usr/sbin/pfctl", "-sr").Output()
296
+	if err != nil {
297
+		return fmt.Errorf("failed to list firewall rules: %v", err)
298
+	}
299
+	if strings.Contains(string(out), "anchor \"_auto/docker/*\" all") {
300
+		return nil
301
+	}
302
+	pfctlCmd := "(/usr/sbin/pfctl -sr; " +
303
+		"/usr/bin/echo \"anchor \\\"_auto/docker/*\\\"\") |" +
304
+		"/usr/sbin/pfctl -f -"
305
+	err = exec.Command("/usr/bin/bash", "-c", pfctlCmd).Run()
306
+	if err != nil {
307
+		return fmt.Errorf("failed to add docker firewall rules: %v", err)
308
+	}
309
+	return nil
310
+}
311
+
312
+func (d *driver) initRouting() error {
313
+	err := exec.Command("/usr/sbin/ipadm", "set-prop", "-t",
314
+		"-p", "forwarding=on", "ipv4").Run()
315
+	if err != nil {
316
+		return fmt.Errorf("cannot switch-on IP forwarding: %v", err)
317
+	}
318
+	routeCmd := "/usr/sbin/ipadm show-addr -p -o addr " +
319
+		"`/usr/sbin/route get default | /usr/bin/grep interface | " +
320
+		"/usr/bin/awk '{print $2}'`"
321
+	out, err := exec.Command("/usr/bin/bash", "-c", routeCmd).Output()
322
+	if err != nil {
323
+		return fmt.Errorf("cannot get default route: %v", err)
324
+	}
325
+	defroute := strings.SplitN(string(out), "/", 2)
326
+	d.defrouteIP = net.ParseIP(defroute[0])
327
+	if d.defrouteIP == nil {
328
+		return &ErrNoIPAddr{}
329
+	}
330
+	return nil
331
+}
332
+
333
+func (d *driver) configure(option map[string]interface{}) error {
334
+	var err error
335
+
336
+	if err = d.initFirewall(); err != nil {
337
+		return fmt.Errorf("failed to configure firewall: %v", err)
338
+	}
339
+	if err = d.initRouting(); err != nil {
340
+		return fmt.Errorf("failed to configure routing: %v", err)
341
+	}
342
+	if err = d.initStore(option); err != nil {
343
+		return fmt.Errorf("failed to initialize datastore: %v", err)
344
+	}
345
+
346
+	return nil
347
+}
348
+
349
+func (d *driver) getNetwork(id string) (*bridgeNetwork, error) {
350
+	d.Lock()
351
+	defer d.Unlock()
352
+
353
+	if id == "" {
354
+		return nil, types.BadRequestErrorf("invalid network id: %s", id)
355
+	}
356
+
357
+	if nw, ok := d.networks[id]; ok {
358
+		return nw, nil
359
+	}
360
+
361
+	return nil, types.NotFoundErrorf("network not found: %s", id)
362
+}
363
+
364
+// Return a slice of networks over which caller can iterate safely
365
+func (d *driver) getNetworks() []*bridgeNetwork {
366
+	d.Lock()
367
+	defer d.Unlock()
368
+
369
+	ls := make([]*bridgeNetwork, 0, len(d.networks))
370
+	for _, nw := range d.networks {
371
+		ls = append(ls, nw)
372
+	}
373
+	return ls
374
+}
375
+
376
+func bridgeSetup(config *networkConfiguration) error {
377
+	var err error
378
+	var bindingIntf string
379
+
380
+	bridgeName := config.BridgeName
381
+	gwName := fmt.Sprintf("%s_gw0", bridgeName)
382
+	gwIP := config.AddressIPv4.String()
383
+
384
+	if config.DefaultBindingIP == nil {
385
+		// Default to net0 if bindingIP is not provided.
386
+		bindingIntf = "net0"
387
+	} else {
388
+		ipadmCmd := "/usr/sbin/ipadm show-addr -p -o addrobj,addr |" +
389
+			"/usr/bin/grep " + config.DefaultBindingIP.String()
390
+		out, err := exec.Command("/usr/bin/bash", "-c", ipadmCmd).Output()
391
+		if err != nil {
392
+			logrus.Warnf("cannot find binding interface")
393
+			return err
394
+		}
395
+		bindingIntf = strings.SplitN(string(out), "/", 2)[0]
396
+		if bindingIntf == "" {
397
+			logrus.Warnf("cannot parse binding interface %s", string(out))
398
+			return &ErrNoIPAddr{}
399
+		}
400
+	}
401
+	config.DefaultBindingIntf = bindingIntf
402
+
403
+	err = exec.Command("/usr/sbin/dladm", "create-etherstub",
404
+		"-t", config.BridgeNameInternal).Run()
405
+	if err != nil {
406
+		logrus.Warnf("cannot create etherstub %s: %+v", config.BridgeNameInternal, err)
407
+		return err
408
+	}
409
+	err = exec.Command("/usr/sbin/dladm", "create-vnic",
410
+		"-t", "-l", config.BridgeNameInternal, gwName).Run()
411
+	if err != nil {
412
+		logrus.Warnf("cannot create vnic %s", gwName)
413
+		return err
414
+	}
415
+	err = exec.Command("/usr/sbin/ifconfig", gwName,
416
+		"plumb", gwIP, "up").Run()
417
+	if err != nil {
418
+		logrus.Warnf("cannot create gateway interface %s on %s",
419
+			gwIP, gwName)
420
+		return err
421
+	}
422
+
423
+	tableName := "bridge_nw_subnets"
424
+	pfAnchor := fmt.Sprintf("_auto/docker/%s", tableName)
425
+	err = exec.Command("/usr/sbin/pfctl", "-a", pfAnchor, "-t", tableName, "-T", "add", gwIP).Run()
426
+	if err != nil {
427
+		logrus.Warnf("cannot add bridge network '%s' to PF table", bridgeName)
428
+	}
429
+
430
+	pfCmd := fmt.Sprintf(
431
+		"/usr/bin/echo \"pass out on %s from %s:network to any nat-to (%s)\n"+
432
+			"block in quick from { <%s>, ! %s } to %s\" |"+
433
+			"/usr/sbin/pfctl -a _auto/docker/%s -f -",
434
+		bindingIntf, gwName, bindingIntf,
435
+		tableName, gwIP, gwIP,
436
+		bridgeName)
437
+	err = exec.Command("/usr/bin/bash", "-c", pfCmd).Run()
438
+	if err != nil {
439
+		logrus.Warnf("cannot add pf rule using: %s", pfCmd)
440
+		return err
441
+	}
442
+
443
+	return nil
444
+}
445
+
446
+func bridgeCleanup(config *networkConfiguration, logErr bool) {
447
+	var err error
448
+
449
+	bridgeName := config.BridgeName
450
+	tableName := "bridge_nw_subnets"
451
+	gwName := fmt.Sprintf("%s_gw0", bridgeName)
452
+	gwIP := config.AddressIPv4.String()
453
+	pfAnchor := fmt.Sprintf("_auto/docker/%s", bridgeName)
454
+	tableAnchor := fmt.Sprintf("_auto/docker/%s", tableName)
455
+
456
+	err = exec.Command("/usr/sbin/pfctl", "-a", pfAnchor, "-F", "all").Run()
457
+	if err != nil && logErr {
458
+		logrus.Warnf("cannot flush firewall rules")
459
+	}
460
+	err = exec.Command("/usr/sbin/ifconfig", gwName, "unplumb").Run()
461
+	if err != nil && logErr {
462
+		logrus.Warnf("cannot remove gateway interface")
463
+	}
464
+	err = exec.Command("/usr/sbin/dladm", "delete-vnic",
465
+		"-t", gwName).Run()
466
+	if err != nil && logErr {
467
+		logrus.Warnf("cannot delete vnic")
468
+	}
469
+	err = exec.Command("/usr/sbin/dladm", "delete-etherstub",
470
+		"-t", config.BridgeNameInternal).Run()
471
+	if err != nil && logErr {
472
+		logrus.Warnf("cannot delete etherstub")
473
+	}
474
+	err = exec.Command("/usr/sbin/pfctl", "-a", tableAnchor, "-t", tableName, "-T", "delete", gwIP).Run()
475
+	if err != nil && logErr {
476
+		logrus.Warnf("cannot remove bridge network '%s' from PF table", bridgeName)
477
+	}
478
+}
479
+
480
+func (d *driver) createNetwork(config *networkConfiguration) error {
481
+	var err error
482
+
483
+	logrus.Infof("Creating bridge network: %s %s %s", config.ID,
484
+		config.BridgeName, config.AddressIPv4)
485
+
486
+	networkList := d.getNetworks()
487
+	for i, nw := range networkList {
488
+		nw.Lock()
489
+		nwConfig := nw.config
490
+		nw.Unlock()
491
+		if err := nwConfig.Conflicts(config); err != nil {
492
+			if config.DefaultBridge {
493
+				// We encountered and identified a stale default network
494
+				// We must delete it as libnetwork is the source of thruth
495
+				// The default network being created must be the only one
496
+				// This can happen only from docker 1.12 on ward
497
+				logrus.Infof("Removing stale default bridge network %s (%s)", nwConfig.ID, nwConfig.BridgeName)
498
+				if err := d.DeleteNetwork(nwConfig.ID); err != nil {
499
+					logrus.Warnf("Failed to remove stale default network: %s (%s): %v. Will remove from store.", nwConfig.ID, nwConfig.BridgeName, err)
500
+					d.storeDelete(nwConfig)
501
+				}
502
+				networkList = append(networkList[:i], networkList[i+1:]...)
503
+			} else {
504
+				return types.ForbiddenErrorf(
505
+					"cannot create network %s (%s): "+
506
+						"conflicts with network %s (%s): %s",
507
+					nwConfig.BridgeName, config.ID, nw.id,
508
+					nw.config.BridgeName, err.Error())
509
+			}
510
+		}
511
+	}
512
+	if config.DefaultBindingIP == nil ||
513
+		config.DefaultBindingIP.IsUnspecified() {
514
+		config.DefaultBindingIP = d.defrouteIP
515
+	}
516
+
517
+	// Create and set network handler in driver
518
+	network := &bridgeNetwork{
519
+		id:         config.ID,
520
+		endpoints:  make(map[string]*bridgeEndpoint),
521
+		config:     config,
522
+		portMapper: portmapper.New(""),
523
+		driver:     d,
524
+	}
525
+
526
+	d.Lock()
527
+	d.networks[config.ID] = network
528
+	d.Unlock()
529
+
530
+	// On failure make sure to reset driver network handler to nil
531
+	defer func() {
532
+		if err != nil {
533
+			d.Lock()
534
+			delete(d.networks, config.ID)
535
+			d.Unlock()
536
+		}
537
+	}()
538
+
539
+	// Create or retrieve the bridge L3 interface
540
+	bridgeIface := newInterface(config)
541
+	network.bridge = bridgeIface
542
+
543
+	// Verify the network configuration does not conflict with previously installed
544
+	// networks. This step is needed now because driver might have now set the bridge
545
+	// name on this config struct. And because we need to check for possible address
546
+	// conflicts, so we need to check against operational networks.
547
+	if err = config.conflictsWithNetworks(config.ID, networkList); err != nil {
548
+		return err
549
+	}
550
+
551
+	// We only attempt to create the bridge when the requested device name is
552
+	// the default one.
553
+	if config.BridgeName != DefaultBridgeName && config.DefaultBridge {
554
+		return NonDefaultBridgeExistError(config.BridgeName)
555
+	}
556
+
557
+	bridgeCleanup(config, false)
558
+	err = bridgeSetup(config)
559
+	if err != nil {
560
+		return err
561
+	}
562
+	return nil
563
+}
564
+
565
+func (d *driver) DeleteNetwork(nid string) error {
566
+	var err error
567
+	// Get network handler and remove it from driver
568
+	d.Lock()
569
+	n, ok := d.networks[nid]
570
+	d.Unlock()
571
+
572
+	if !ok {
573
+		return types.InternalMaskableErrorf("network %s does not exist", nid)
574
+	}
575
+	d.Lock()
576
+	delete(d.networks, nid)
577
+	d.Unlock()
578
+
579
+	// On failure set network handler back in driver, but
580
+	// only if is not already taken over by some other thread
581
+	defer func() {
582
+		if err != nil {
583
+			d.Lock()
584
+			if _, ok := d.networks[nid]; !ok {
585
+				d.networks[nid] = n
586
+			}
587
+			d.Unlock()
588
+		}
589
+	}()
590
+
591
+	// Sanity check
592
+	if n == nil {
593
+		err = driverapi.ErrNoNetwork(nid)
594
+		return err
595
+	}
596
+
597
+	// Cannot remove network if endpoints are still present
598
+	if len(n.endpoints) != 0 {
599
+		err = ActiveEndpointsError(n.id)
600
+		return err
601
+	}
602
+	bridgeCleanup(n.config, true)
603
+	logrus.Infof("Deleting bridge network: %s", nid[:12])
604
+	return d.storeDelete(n.config)
605
+}
606
+
607
+func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
608
+	if ifInfo == nil {
609
+		return errors.New("invalid interface passed")
610
+	}
611
+
612
+	// Get the network handler and make sure it exists
613
+	d.Lock()
614
+	n, ok := d.networks[nid]
615
+	d.Unlock()
616
+
617
+	if !ok {
618
+		return types.NotFoundErrorf("network %s does not exist", nid)
619
+	}
620
+	if n == nil {
621
+		return driverapi.ErrNoNetwork(nid)
622
+	}
623
+
624
+	// Sanity check
625
+	n.Lock()
626
+	if n.id != nid {
627
+		n.Unlock()
628
+		return InvalidNetworkIDError(nid)
629
+	}
630
+	n.Unlock()
631
+
632
+	// Check if endpoint id is good and retrieve correspondent endpoint
633
+	ep, err := n.getEndpoint(eid)
634
+	if err != nil {
635
+		return err
636
+	}
637
+
638
+	// Endpoint with that id exists either on desired or other sandbox
639
+	if ep != nil {
640
+		return driverapi.ErrEndpointExists(eid)
641
+	}
642
+
643
+	// Try to convert the options to endpoint configuration
644
+	epConfig, err := parseEndpointOptions(epOptions)
645
+	if err != nil {
646
+		return err
647
+	}
648
+
649
+	// Create and add the endpoint
650
+	n.Lock()
651
+	endpoint := &bridgeEndpoint{id: eid, config: epConfig}
652
+	n.endpoints[eid] = endpoint
653
+	n.Unlock()
654
+
655
+	// On failure make sure to remove the endpoint
656
+	defer func() {
657
+		if err != nil {
658
+			n.Lock()
659
+			delete(n.endpoints, eid)
660
+			n.Unlock()
661
+		}
662
+	}()
663
+
664
+	// Create the sandbox side pipe interface
665
+	if ifInfo.MacAddress() == nil {
666
+		// No MAC address assigned to interface. Generate a random MAC to assign
667
+		endpoint.macAddress = netutils.GenerateRandomMAC()
668
+		if err := ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
669
+			logrus.Warnf("Unable to set mac address: %s to endpoint: %s",
670
+				endpoint.macAddress.String(), endpoint.id)
671
+			return err
672
+		}
673
+	} else {
674
+		endpoint.macAddress = ifInfo.MacAddress()
675
+	}
676
+	endpoint.addr = ifInfo.Address()
677
+	endpoint.addrv6 = ifInfo.AddressIPv6()
678
+	c := n.config
679
+
680
+	// Program any required port mapping and store them in the endpoint
681
+	endpoint.portMapping, err = n.allocatePorts(endpoint, c.DefaultBindingIntf, c.DefaultBindingIP, true)
682
+	if err != nil {
683
+		return err
684
+	}
685
+
686
+	return nil
687
+}
688
+
689
+func (d *driver) DeleteEndpoint(nid, eid string) error {
690
+	var err error
691
+
692
+	// Get the network handler and make sure it exists
693
+	d.Lock()
694
+	n, ok := d.networks[nid]
695
+	d.Unlock()
696
+
697
+	if !ok {
698
+		return types.InternalMaskableErrorf("network %s does not exist", nid)
699
+	}
700
+	if n == nil {
701
+		return driverapi.ErrNoNetwork(nid)
702
+	}
703
+
704
+	// Sanity Check
705
+	n.Lock()
706
+	if n.id != nid {
707
+		n.Unlock()
708
+		return InvalidNetworkIDError(nid)
709
+	}
710
+	n.Unlock()
711
+
712
+	// Check endpoint id and if an endpoint is actually there
713
+	ep, err := n.getEndpoint(eid)
714
+	if err != nil {
715
+		return err
716
+	}
717
+	if ep == nil {
718
+		return EndpointNotFoundError(eid)
719
+	}
720
+
721
+	// Remove it
722
+	n.Lock()
723
+	delete(n.endpoints, eid)
724
+	n.Unlock()
725
+
726
+	// On failure make sure to set back ep in n.endpoints, but only
727
+	// if it hasn't been taken over already by some other thread.
728
+	defer func() {
729
+		if err != nil {
730
+			n.Lock()
731
+			if _, ok := n.endpoints[eid]; !ok {
732
+				n.endpoints[eid] = ep
733
+			}
734
+			n.Unlock()
735
+		}
736
+	}()
737
+
738
+	err = n.releasePorts(ep)
739
+	if err != nil {
740
+		logrus.Warn(err)
741
+	}
742
+
743
+	return nil
744
+}
745
+
746
+func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
747
+	// Get the network handler and make sure it exists
748
+	d.Lock()
749
+	n, ok := d.networks[nid]
750
+	d.Unlock()
751
+	if !ok {
752
+		return nil, types.NotFoundErrorf("network %s does not exist", nid)
753
+	}
754
+	if n == nil {
755
+		return nil, driverapi.ErrNoNetwork(nid)
756
+	}
757
+
758
+	// Sanity check
759
+	n.Lock()
760
+	if n.id != nid {
761
+		n.Unlock()
762
+		return nil, InvalidNetworkIDError(nid)
763
+	}
764
+	n.Unlock()
765
+
766
+	// Check if endpoint id is good and retrieve correspondent endpoint
767
+	ep, err := n.getEndpoint(eid)
768
+	if err != nil {
769
+		return nil, err
770
+	}
771
+	if ep == nil {
772
+		return nil, driverapi.ErrNoEndpoint(eid)
773
+	}
774
+
775
+	m := make(map[string]interface{})
776
+
777
+	if ep.extConnConfig != nil && ep.extConnConfig.ExposedPorts != nil {
778
+		// Return a copy of the config data
779
+		epc := make([]types.TransportPort, 0, len(ep.extConnConfig.ExposedPorts))
780
+		for _, tp := range ep.extConnConfig.ExposedPorts {
781
+			epc = append(epc, tp.GetCopy())
782
+		}
783
+		m[netlabel.ExposedPorts] = epc
784
+	}
785
+
786
+	if ep.portMapping != nil {
787
+		// Return a copy of the operational data
788
+		pmc := make([]types.PortBinding, 0, len(ep.portMapping))
789
+		for _, pm := range ep.portMapping {
790
+			pmc = append(pmc, pm.GetCopy())
791
+		}
792
+		m[netlabel.PortMap] = pmc
793
+	}
794
+
795
+	if len(ep.macAddress) != 0 {
796
+		m[netlabel.MacAddress] = ep.macAddress
797
+	}
798
+	return m, nil
799
+}
800
+
801
+// Join method is invoked when a Sandbox is attached to an endpoint.
802
+func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
803
+	network, err := d.getNetwork(nid)
804
+	if err != nil {
805
+		return err
806
+	}
807
+
808
+	endpoint, err := network.getEndpoint(eid)
809
+	if err != nil {
810
+		return err
811
+	}
812
+
813
+	if endpoint == nil {
814
+		return EndpointNotFoundError(eid)
815
+	}
816
+
817
+	endpoint.containerConfig, err = parseContainerOptions(options)
818
+	if err != nil {
819
+		return err
820
+	}
821
+
822
+	err = jinfo.SetGateway(network.bridge.gatewayIPv4)
823
+	if err != nil {
824
+		return err
825
+	}
826
+
827
+	err = jinfo.SetGatewayIPv6(network.bridge.gatewayIPv6)
828
+	if err != nil {
829
+		return err
830
+	}
831
+
832
+	return nil
833
+}
834
+
835
+func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, enable bool) error {
836
+	return nil
837
+}
838
+
839
+// Leave method is invoked when a Sandbox detaches from an endpoint.
840
+func (d *driver) Leave(nid, eid string) error {
841
+	network, err := d.getNetwork(nid)
842
+	if err != nil {
843
+		return types.InternalMaskableErrorf("%s", err)
844
+	}
845
+
846
+	endpoint, err := network.getEndpoint(eid)
847
+	if err != nil {
848
+		return err
849
+	}
850
+
851
+	if endpoint == nil {
852
+		return EndpointNotFoundError(eid)
853
+	}
854
+
855
+	return nil
856
+}
857
+
858
+func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
859
+	network, err := d.getNetwork(nid)
860
+	if err != nil {
861
+		return err
862
+	}
863
+
864
+	endpoint, err := network.getEndpoint(eid)
865
+	if err != nil {
866
+		return err
867
+	}
868
+
869
+	if endpoint == nil {
870
+		return EndpointNotFoundError(eid)
871
+	}
872
+
873
+	endpoint.extConnConfig, err = parseConnectivityOptions(options)
874
+	if err != nil {
875
+		return err
876
+	}
877
+
878
+	// Program any required port mapping and store them in the endpoint
879
+	endpoint.portMapping, err = network.allocatePorts(endpoint, network.config.DefaultBindingIntf, network.config.DefaultBindingIP, true)
880
+	if err != nil {
881
+		return err
882
+	}
883
+
884
+	if !network.config.EnableICC {
885
+		return d.link(network, endpoint, true)
886
+	}
887
+
888
+	return nil
889
+}
890
+
891
+func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
892
+	network, err := d.getNetwork(nid)
893
+	if err != nil {
894
+		return err
895
+	}
896
+
897
+	endpoint, err := network.getEndpoint(eid)
898
+	if err != nil {
899
+		return err
900
+	}
901
+
902
+	if endpoint == nil {
903
+		return EndpointNotFoundError(eid)
904
+	}
905
+
906
+	err = network.releasePorts(endpoint)
907
+	if err != nil {
908
+		logrus.Warn(err)
909
+	}
910
+
911
+	return nil
912
+}
913
+
914
+func (d *driver) Type() string {
915
+	return networkType
916
+}
917
+
918
+// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
919
+func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
920
+	return nil
921
+}
922
+
923
+// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
924
+func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
925
+	return nil
926
+}
927
+
928
+// Validate performs a static validation on the network configuration parameters.
929
+// Whatever can be assessed a priori before attempting any programming.
930
+func (c *networkConfiguration) Validate() error {
931
+	if c.Mtu < 0 {
932
+		return ErrInvalidMtu(c.Mtu)
933
+	}
934
+
935
+	// If bridge v4 subnet is specified
936
+	if c.AddressIPv4 != nil {
937
+		// If default gw is specified, it must be part of bridge subnet
938
+		if c.DefaultGatewayIPv4 != nil {
939
+			if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) {
940
+				return &ErrInvalidGateway{}
941
+			}
942
+		}
943
+	}
944
+
945
+	// If default v6 gw is specified, AddressIPv6 must be specified and gw must belong to AddressIPv6 subnet
946
+	if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
947
+		if c.AddressIPv6 == nil || !c.AddressIPv6.Contains(c.DefaultGatewayIPv6) {
948
+			return &ErrInvalidGateway{}
949
+		}
950
+	}
951
+	return nil
952
+}
953
+
954
+// Checks whether this network's configuration for the network with this id conflicts with any of the passed networks
955
+func (c *networkConfiguration) conflictsWithNetworks(id string, others []*bridgeNetwork) error {
956
+	for _, nw := range others {
957
+
958
+		nw.Lock()
959
+		nwID := nw.id
960
+		nwConfig := nw.config
961
+		nwBridge := nw.bridge
962
+		nw.Unlock()
963
+
964
+		if nwID == id {
965
+			continue
966
+		}
967
+		// Verify the name (which may have been set by newInterface()) does not conflict with
968
+		// existing bridge interfaces. Ironically the system chosen name gets stored in the config...
969
+		// Basically we are checking if the two original configs were both empty.
970
+		if nwConfig.BridgeName == c.BridgeName {
971
+			return types.ForbiddenErrorf("conflicts with network %s (%s) by bridge name", nwID, nwConfig.BridgeName)
972
+		}
973
+		// If this network config specifies the AddressIPv4, we need
974
+		// to make sure it does not conflict with any previously allocated
975
+		// bridges. This could not be completely caught by the config conflict
976
+		// check, because networks which config does not specify the AddressIPv4
977
+		// get their address and subnet selected by the driver (see electBridgeIPv4())
978
+		if c.AddressIPv4 != nil {
979
+			if nwBridge.bridgeIPv4.Contains(c.AddressIPv4.IP) ||
980
+				c.AddressIPv4.Contains(nwBridge.bridgeIPv4.IP) {
981
+				return types.ForbiddenErrorf("conflicts with network %s (%s) by ip network", nwID, nwConfig.BridgeName)
982
+			}
983
+		}
984
+	}
985
+
986
+	return nil
987
+}
988
+
989
+// Conflicts check if two NetworkConfiguration objects overlap
990
+func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
991
+	if o == nil {
992
+		return fmt.Errorf("same configuration")
993
+	}
994
+
995
+	// Also empty, becasue only one network with empty name is allowed
996
+	if c.BridgeName == o.BridgeName {
997
+		return fmt.Errorf("networks have same bridge name")
998
+	}
999
+
1000
+	// They must be in different subnets
1001
+	if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) &&
1002
+		(c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) {
1003
+		return fmt.Errorf("networks have overlapping IPv4")
1004
+	}
1005
+
1006
+	// They must be in different v6 subnets
1007
+	if (c.AddressIPv6 != nil && o.AddressIPv6 != nil) &&
1008
+		(c.AddressIPv6.Contains(o.AddressIPv6.IP) || o.AddressIPv6.Contains(c.AddressIPv6.IP)) {
1009
+		return fmt.Errorf("networks have overlapping IPv6")
1010
+	}
1011
+
1012
+	return nil
1013
+}
1014
+
1015
+func (c *networkConfiguration) fromLabels(labels map[string]string) error {
1016
+	var err error
1017
+	for label, value := range labels {
1018
+		switch label {
1019
+		case BridgeName:
1020
+			c.BridgeName = value
1021
+		case netlabel.DriverMTU:
1022
+			if c.Mtu, err = strconv.Atoi(value); err != nil {
1023
+				return parseErr(label, value, err.Error())
1024
+			}
1025
+		case netlabel.EnableIPv6:
1026
+			if c.EnableIPv6, err = strconv.ParseBool(value); err != nil {
1027
+				return parseErr(label, value, err.Error())
1028
+			}
1029
+		case EnableIPMasquerade:
1030
+			if c.EnableIPMasquerade, err = strconv.ParseBool(value); err != nil {
1031
+				return parseErr(label, value, err.Error())
1032
+			}
1033
+		case EnableICC:
1034
+			if c.EnableICC, err = strconv.ParseBool(value); err != nil {
1035
+				return parseErr(label, value, err.Error())
1036
+			}
1037
+		case DefaultBridge:
1038
+			if c.DefaultBridge, err = strconv.ParseBool(value); err != nil {
1039
+				return parseErr(label, value, err.Error())
1040
+			}
1041
+		case DefaultBindingIP:
1042
+			if c.DefaultBindingIP = net.ParseIP(value); c.DefaultBindingIP == nil {
1043
+				return parseErr(label, value, "nil ip")
1044
+			}
1045
+		}
1046
+	}
1047
+
1048
+	return nil
1049
+}
1050
+
1051
+func parseErr(label, value, errString string) error {
1052
+	return types.BadRequestErrorf("failed to parse %s value: %v (%s)", label, value, errString)
1053
+}
1054
+
1055
+func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error) {
1056
+	var (
1057
+		err    error
1058
+		config *networkConfiguration
1059
+	)
1060
+
1061
+	switch opt := data.(type) {
1062
+	case *networkConfiguration:
1063
+		config = opt
1064
+	case map[string]string:
1065
+		config = &networkConfiguration{
1066
+			EnableICC:          true,
1067
+			EnableIPMasquerade: true,
1068
+		}
1069
+		err = config.fromLabels(opt)
1070
+	case options.Generic:
1071
+		var opaqueConfig interface{}
1072
+		if opaqueConfig, err = options.GenerateFromModel(opt, config); err == nil {
1073
+			config = opaqueConfig.(*networkConfiguration)
1074
+		}
1075
+	default:
1076
+		err = types.BadRequestErrorf("do not recognize network configuration format: %T", opt)
1077
+	}
1078
+
1079
+	return config, err
1080
+}
1081
+
1082
+func parseNetworkOptions(d *driver, id string, option options.Generic) (*networkConfiguration, error) {
1083
+	var (
1084
+		err    error
1085
+		config = &networkConfiguration{}
1086
+	)
1087
+
1088
+	// Parse generic label first, config will be re-assigned
1089
+	if genData, ok := option[netlabel.GenericData]; ok && genData != nil {
1090
+		if config, err = parseNetworkGenericOptions(genData); err != nil {
1091
+			return nil, err
1092
+		}
1093
+	}
1094
+
1095
+	// Process well-known labels next
1096
+	if val, ok := option[netlabel.EnableIPv6]; ok {
1097
+		config.EnableIPv6 = val.(bool)
1098
+	}
1099
+
1100
+	if val, ok := option[netlabel.Internal]; ok {
1101
+		if internal, ok := val.(bool); ok && internal {
1102
+			config.Internal = true
1103
+		}
1104
+	}
1105
+
1106
+	// Finally validate the configuration
1107
+	if err = config.Validate(); err != nil {
1108
+		return nil, err
1109
+	}
1110
+
1111
+	if config.BridgeName == "" && config.DefaultBridge == false {
1112
+		config.BridgeName = "br_" + id[:12] + "_0"
1113
+	}
1114
+
1115
+	lastChar := config.BridgeName[len(config.BridgeName)-1:]
1116
+	if _, err = strconv.Atoi(lastChar); err != nil {
1117
+		config.BridgeNameInternal = config.BridgeName + "_0"
1118
+	} else {
1119
+		config.BridgeNameInternal = config.BridgeName
1120
+	}
1121
+
1122
+	config.ID = id
1123
+	return config, nil
1124
+}
1125
+
1126
+func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
1127
+	if len(ipamV4Data) > 1 || len(ipamV6Data) > 1 {
1128
+		return types.ForbiddenErrorf("bridge driver doesnt support multiple subnets")
1129
+	}
1130
+
1131
+	if len(ipamV4Data) == 0 {
1132
+		return types.BadRequestErrorf("bridge network %s requires ipv4 configuration", id)
1133
+	}
1134
+
1135
+	if ipamV4Data[0].Gateway != nil {
1136
+		c.AddressIPv4 = types.GetIPNetCopy(ipamV4Data[0].Gateway)
1137
+	}
1138
+
1139
+	if gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey]; ok {
1140
+		c.DefaultGatewayIPv4 = gw.IP
1141
+	}
1142
+
1143
+	if len(ipamV6Data) > 0 {
1144
+		c.AddressIPv6 = ipamV6Data[0].Pool
1145
+
1146
+		if ipamV6Data[0].Gateway != nil {
1147
+			c.AddressIPv6 = types.GetIPNetCopy(ipamV6Data[0].Gateway)
1148
+		}
1149
+
1150
+		if gw, ok := ipamV6Data[0].AuxAddresses[DefaultGatewayV6AuxKey]; ok {
1151
+			c.DefaultGatewayIPv6 = gw.IP
1152
+		}
1153
+	}
1154
+
1155
+	return nil
1156
+}
1157
+
1158
+func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) {
1159
+	n.Lock()
1160
+	defer n.Unlock()
1161
+
1162
+	if eid == "" {
1163
+		return nil, InvalidEndpointIDError(eid)
1164
+	}
1165
+
1166
+	if ep, ok := n.endpoints[eid]; ok {
1167
+		return ep, nil
1168
+	}
1169
+
1170
+	return nil, nil
1171
+}
1172
+
1173
+func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) {
1174
+	if epOptions == nil {
1175
+		return nil, nil
1176
+	}
1177
+
1178
+	ec := &endpointConfiguration{}
1179
+
1180
+	if opt, ok := epOptions[netlabel.MacAddress]; ok {
1181
+		if mac, ok := opt.(net.HardwareAddr); ok {
1182
+			ec.MacAddress = mac
1183
+		} else {
1184
+			return nil, &ErrInvalidEndpointConfig{}
1185
+		}
1186
+	}
1187
+
1188
+	if opt, ok := epOptions[netlabel.PortMap]; ok {
1189
+		if bs, ok := opt.([]types.PortBinding); ok {
1190
+			ec.PortBindings = bs
1191
+		} else {
1192
+			return nil, &ErrInvalidEndpointConfig{}
1193
+		}
1194
+	}
1195
+
1196
+	if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
1197
+		if ports, ok := opt.([]types.TransportPort); ok {
1198
+			ec.ExposedPorts = ports
1199
+		} else {
1200
+			return nil, &ErrInvalidEndpointConfig{}
1201
+		}
1202
+	}
1203
+
1204
+	return ec, nil
1205
+}
1206
+
1207
+func parseContainerOptions(cOptions map[string]interface{}) (*containerConfiguration, error) {
1208
+	if cOptions == nil {
1209
+		return nil, nil
1210
+	}
1211
+	genericData := cOptions[netlabel.GenericData]
1212
+	if genericData == nil {
1213
+		return nil, nil
1214
+	}
1215
+	switch opt := genericData.(type) {
1216
+	case options.Generic:
1217
+		opaqueConfig, err := options.GenerateFromModel(opt, &containerConfiguration{})
1218
+		if err != nil {
1219
+			return nil, err
1220
+		}
1221
+		return opaqueConfig.(*containerConfiguration), nil
1222
+	case *containerConfiguration:
1223
+		return opt, nil
1224
+	default:
1225
+		return nil, nil
1226
+	}
1227
+}
1228
+
1229
+func parseConnectivityOptions(cOptions map[string]interface{}) (*connectivityConfiguration, error) {
1230
+	if cOptions == nil {
1231
+		return nil, nil
1232
+	}
1233
+
1234
+	cc := &connectivityConfiguration{}
1235
+
1236
+	if opt, ok := cOptions[netlabel.PortMap]; ok {
1237
+		if pb, ok := opt.([]types.PortBinding); ok {
1238
+			cc.PortBindings = pb
1239
+		} else {
1240
+			return nil, types.BadRequestErrorf("Invalid port mapping data in connectivity configuration: %v", opt)
1241
+		}
1242
+	}
1243
+
1244
+	if opt, ok := cOptions[netlabel.ExposedPorts]; ok {
1245
+		if ports, ok := opt.([]types.TransportPort); ok {
1246
+			cc.ExposedPorts = ports
1247
+		} else {
1248
+			return nil, types.BadRequestErrorf("Invalid exposed ports data in connectivity configuration: %v", opt)
1249
+		}
1250
+	}
1251
+
1252
+	return cc, nil
1253
+}
0 1254
new file mode 100644
... ...
@@ -0,0 +1,384 @@
0
+// +build solaris
1
+
2
+package bridge
3
+
4
+import (
5
+	"encoding/json"
6
+	"fmt"
7
+	"net"
8
+
9
+	"github.com/Sirupsen/logrus"
10
+	"github.com/docker/libnetwork/datastore"
11
+	"github.com/docker/libnetwork/discoverapi"
12
+	"github.com/docker/libnetwork/netlabel"
13
+	"github.com/docker/libnetwork/types"
14
+)
15
+
16
+const (
17
+	// network config prefix was not specific enough.
18
+	// To be backward compatible, need custom endpoint
19
+	// prefix with different root
20
+	bridgePrefix         = "bridge"
21
+	bridgeEndpointPrefix = "bridge-endpoint"
22
+)
23
+
24
+func (d *driver) initStore(option map[string]interface{}) error {
25
+	if data, ok := option[netlabel.LocalKVClient]; ok {
26
+		var err error
27
+		dsc, ok := data.(discoverapi.DatastoreConfigData)
28
+		if !ok {
29
+			return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
30
+		}
31
+		d.store, err = datastore.NewDataStoreFromConfig(dsc)
32
+		if err != nil {
33
+			return types.InternalErrorf("bridge driver failed to initialize data store: %v", err)
34
+		}
35
+
36
+		err = d.populateNetworks()
37
+		if err != nil {
38
+			return err
39
+		}
40
+
41
+		err = d.populateEndpoints()
42
+		if err != nil {
43
+			return err
44
+		}
45
+	}
46
+
47
+	return nil
48
+}
49
+
50
+func (d *driver) populateNetworks() error {
51
+	kvol, err := d.store.List(datastore.Key(bridgePrefix), &networkConfiguration{})
52
+	if err != nil && err != datastore.ErrKeyNotFound {
53
+		return fmt.Errorf("failed to get bridge network configurations from store: %v", err)
54
+	}
55
+
56
+	// It's normal for network configuration state to be empty. Just return.
57
+	if err == datastore.ErrKeyNotFound {
58
+		return nil
59
+	}
60
+
61
+	for _, kvo := range kvol {
62
+		ncfg := kvo.(*networkConfiguration)
63
+		if err = d.createNetwork(ncfg); err != nil {
64
+			logrus.Warnf("could not create bridge network for id %s bridge name %s while booting up from persistent state: %v", ncfg.ID, ncfg.BridgeName, err)
65
+		}
66
+		logrus.Debugf("Network (%s) restored", ncfg.ID[0:7])
67
+	}
68
+
69
+	return nil
70
+}
71
+
72
+func (d *driver) populateEndpoints() error {
73
+	kvol, err := d.store.List(datastore.Key(bridgeEndpointPrefix), &bridgeEndpoint{})
74
+	if err != nil && err != datastore.ErrKeyNotFound {
75
+		return fmt.Errorf("failed to get bridge endpoints from store: %v", err)
76
+	}
77
+
78
+	if err == datastore.ErrKeyNotFound {
79
+		return nil
80
+	}
81
+
82
+	for _, kvo := range kvol {
83
+		ep := kvo.(*bridgeEndpoint)
84
+		n, ok := d.networks[ep.nid]
85
+		if !ok {
86
+			logrus.Debugf("Network (%s) not found for restored bridge endpoint (%s)", ep.nid[0:7], ep.id[0:7])
87
+			logrus.Debugf("Deleting stale bridge endpoint (%s) from store", ep.nid[0:7])
88
+			if err := d.storeDelete(ep); err != nil {
89
+				logrus.Debugf("Failed to delete stale bridge endpoint (%s) from store", ep.nid[0:7])
90
+			}
91
+			continue
92
+		}
93
+		n.endpoints[ep.id] = ep
94
+		n.restorePortAllocations(ep)
95
+		logrus.Debugf("Endpoint (%s) restored to network (%s)", ep.id[0:7], ep.nid[0:7])
96
+	}
97
+
98
+	return nil
99
+}
100
+
101
+func (d *driver) storeUpdate(kvObject datastore.KVObject) error {
102
+	if d.store == nil {
103
+		logrus.Warnf("bridge store not initialized. kv object %s is not added to the store", datastore.Key(kvObject.Key()...))
104
+		return nil
105
+	}
106
+
107
+	if err := d.store.PutObjectAtomic(kvObject); err != nil {
108
+		return fmt.Errorf("failed to update bridge store for object type %T: %v", kvObject, err)
109
+	}
110
+
111
+	return nil
112
+}
113
+
114
+func (d *driver) storeDelete(kvObject datastore.KVObject) error {
115
+	if d.store == nil {
116
+		logrus.Debugf("bridge store not initialized. kv object %s is not deleted from store", datastore.Key(kvObject.Key()...))
117
+		return nil
118
+	}
119
+
120
+retry:
121
+	if err := d.store.DeleteObjectAtomic(kvObject); err != nil {
122
+		if err == datastore.ErrKeyModified {
123
+			if err := d.store.GetObject(datastore.Key(kvObject.Key()...), kvObject); err != nil {
124
+				return fmt.Errorf("could not update the kvobject to latest when trying to delete: %v", err)
125
+			}
126
+			goto retry
127
+		}
128
+		return err
129
+	}
130
+
131
+	return nil
132
+}
133
+
134
+func (ncfg *networkConfiguration) MarshalJSON() ([]byte, error) {
135
+	nMap := make(map[string]interface{})
136
+	nMap["ID"] = ncfg.ID
137
+	nMap["BridgeName"] = ncfg.BridgeName
138
+	nMap["BridgeNameInternal"] = ncfg.BridgeNameInternal
139
+	nMap["EnableIPv6"] = ncfg.EnableIPv6
140
+	nMap["EnableIPMasquerade"] = ncfg.EnableIPMasquerade
141
+	nMap["EnableICC"] = ncfg.EnableICC
142
+	nMap["Mtu"] = ncfg.Mtu
143
+	nMap["Internal"] = ncfg.Internal
144
+	nMap["DefaultBridge"] = ncfg.DefaultBridge
145
+	nMap["DefaultBindingIP"] = ncfg.DefaultBindingIP.String()
146
+	nMap["DefaultBindingIntf"] = ncfg.DefaultBindingIntf
147
+	nMap["DefaultGatewayIPv4"] = ncfg.DefaultGatewayIPv4.String()
148
+	nMap["DefaultGatewayIPv6"] = ncfg.DefaultGatewayIPv6.String()
149
+
150
+	if ncfg.AddressIPv4 != nil {
151
+		nMap["AddressIPv4"] = ncfg.AddressIPv4.String()
152
+	}
153
+
154
+	if ncfg.AddressIPv6 != nil {
155
+		nMap["AddressIPv6"] = ncfg.AddressIPv6.String()
156
+	}
157
+
158
+	return json.Marshal(nMap)
159
+}
160
+
161
+func (ncfg *networkConfiguration) UnmarshalJSON(b []byte) error {
162
+	var (
163
+		err  error
164
+		nMap map[string]interface{}
165
+	)
166
+
167
+	if err = json.Unmarshal(b, &nMap); err != nil {
168
+		return err
169
+	}
170
+
171
+	if v, ok := nMap["AddressIPv4"]; ok {
172
+		if ncfg.AddressIPv4, err = types.ParseCIDR(v.(string)); err != nil {
173
+			return types.InternalErrorf("failed to decode bridge network address IPv4 after json unmarshal: %s", v.(string))
174
+		}
175
+	}
176
+
177
+	if v, ok := nMap["AddressIPv6"]; ok {
178
+		if ncfg.AddressIPv6, err = types.ParseCIDR(v.(string)); err != nil {
179
+			return types.InternalErrorf("failed to decode bridge network address IPv6 after json unmarshal: %s", v.(string))
180
+		}
181
+	}
182
+
183
+	ncfg.DefaultBridge = nMap["DefaultBridge"].(bool)
184
+	ncfg.DefaultBindingIP = net.ParseIP(nMap["DefaultBindingIP"].(string))
185
+	ncfg.DefaultBindingIntf = nMap["DefaultBindingIntf"].(string)
186
+	ncfg.DefaultGatewayIPv4 = net.ParseIP(nMap["DefaultGatewayIPv4"].(string))
187
+	ncfg.DefaultGatewayIPv6 = net.ParseIP(nMap["DefaultGatewayIPv6"].(string))
188
+	ncfg.ID = nMap["ID"].(string)
189
+	ncfg.BridgeName = nMap["BridgeName"].(string)
190
+	ncfg.BridgeNameInternal = nMap["BridgeNameInternal"].(string)
191
+	ncfg.EnableIPv6 = nMap["EnableIPv6"].(bool)
192
+	ncfg.EnableIPMasquerade = nMap["EnableIPMasquerade"].(bool)
193
+	ncfg.EnableICC = nMap["EnableICC"].(bool)
194
+	ncfg.Mtu = int(nMap["Mtu"].(float64))
195
+	if v, ok := nMap["Internal"]; ok {
196
+		ncfg.Internal = v.(bool)
197
+	}
198
+
199
+	return nil
200
+}
201
+
202
+func (ncfg *networkConfiguration) Key() []string {
203
+	return []string{bridgePrefix, ncfg.ID}
204
+}
205
+
206
+func (ncfg *networkConfiguration) KeyPrefix() []string {
207
+	return []string{bridgePrefix}
208
+}
209
+
210
+func (ncfg *networkConfiguration) Value() []byte {
211
+	b, err := json.Marshal(ncfg)
212
+	if err != nil {
213
+		return nil
214
+	}
215
+	return b
216
+}
217
+
218
+func (ncfg *networkConfiguration) SetValue(value []byte) error {
219
+	return json.Unmarshal(value, ncfg)
220
+}
221
+
222
+func (ncfg *networkConfiguration) Index() uint64 {
223
+	return ncfg.dbIndex
224
+}
225
+
226
+func (ncfg *networkConfiguration) SetIndex(index uint64) {
227
+	ncfg.dbIndex = index
228
+	ncfg.dbExists = true
229
+}
230
+
231
+func (ncfg *networkConfiguration) Exists() bool {
232
+	return ncfg.dbExists
233
+}
234
+
235
+func (ncfg *networkConfiguration) Skip() bool {
236
+	return false
237
+}
238
+
239
+func (ncfg *networkConfiguration) New() datastore.KVObject {
240
+	return &networkConfiguration{}
241
+}
242
+
243
+func (ncfg *networkConfiguration) CopyTo(o datastore.KVObject) error {
244
+	dstNcfg := o.(*networkConfiguration)
245
+	*dstNcfg = *ncfg
246
+	return nil
247
+}
248
+
249
+func (ncfg *networkConfiguration) DataScope() string {
250
+	return datastore.LocalScope
251
+}
252
+
253
+func (ep *bridgeEndpoint) MarshalJSON() ([]byte, error) {
254
+	epMap := make(map[string]interface{})
255
+	epMap["id"] = ep.id
256
+	epMap["nid"] = ep.nid
257
+	epMap["SrcName"] = ep.srcName
258
+	epMap["MacAddress"] = ep.macAddress.String()
259
+	epMap["Addr"] = ep.addr.String()
260
+	if ep.addrv6 != nil {
261
+		epMap["Addrv6"] = ep.addrv6.String()
262
+	}
263
+	epMap["Config"] = ep.config
264
+	epMap["ContainerConfig"] = ep.containerConfig
265
+	epMap["ExternalConnConfig"] = ep.extConnConfig
266
+	epMap["PortMapping"] = ep.portMapping
267
+
268
+	return json.Marshal(epMap)
269
+}
270
+
271
+func (ep *bridgeEndpoint) UnmarshalJSON(b []byte) error {
272
+	var (
273
+		err   error
274
+		epMap map[string]interface{}
275
+	)
276
+
277
+	if err = json.Unmarshal(b, &epMap); err != nil {
278
+		return fmt.Errorf("Failed to unmarshal to bridge endpoint: %v", err)
279
+	}
280
+
281
+	if v, ok := epMap["MacAddress"]; ok {
282
+		if ep.macAddress, err = net.ParseMAC(v.(string)); err != nil {
283
+			return types.InternalErrorf("failed to decode bridge endpoint MAC address (%s) after json unmarshal: %v", v.(string), err)
284
+		}
285
+	}
286
+	if v, ok := epMap["Addr"]; ok {
287
+		if ep.addr, err = types.ParseCIDR(v.(string)); err != nil {
288
+			return types.InternalErrorf("failed to decode bridge endpoint IPv4 address (%s) after json unmarshal: %v", v.(string), err)
289
+		}
290
+	}
291
+	if v, ok := epMap["Addrv6"]; ok {
292
+		if ep.addrv6, err = types.ParseCIDR(v.(string)); err != nil {
293
+			return types.InternalErrorf("failed to decode bridge endpoint IPv6 address (%s) after json unmarshal: %v", v.(string), err)
294
+		}
295
+	}
296
+	ep.id = epMap["id"].(string)
297
+	ep.nid = epMap["nid"].(string)
298
+	ep.srcName = epMap["SrcName"].(string)
299
+	d, _ := json.Marshal(epMap["Config"])
300
+	if err := json.Unmarshal(d, &ep.config); err != nil {
301
+		logrus.Warnf("Failed to decode endpoint config %v", err)
302
+	}
303
+	d, _ = json.Marshal(epMap["ContainerConfig"])
304
+	if err := json.Unmarshal(d, &ep.containerConfig); err != nil {
305
+		logrus.Warnf("Failed to decode endpoint container config %v", err)
306
+	}
307
+	d, _ = json.Marshal(epMap["ExternalConnConfig"])
308
+	if err := json.Unmarshal(d, &ep.extConnConfig); err != nil {
309
+		logrus.Warnf("Failed to decode endpoint external connectivity configuration %v", err)
310
+	}
311
+	d, _ = json.Marshal(epMap["PortMapping"])
312
+	if err := json.Unmarshal(d, &ep.portMapping); err != nil {
313
+		logrus.Warnf("Failed to decode endpoint port mapping %v", err)
314
+	}
315
+
316
+	return nil
317
+}
318
+
319
+func (ep *bridgeEndpoint) Key() []string {
320
+	return []string{bridgeEndpointPrefix, ep.id}
321
+}
322
+
323
+func (ep *bridgeEndpoint) KeyPrefix() []string {
324
+	return []string{bridgeEndpointPrefix}
325
+}
326
+
327
+func (ep *bridgeEndpoint) Value() []byte {
328
+	b, err := json.Marshal(ep)
329
+	if err != nil {
330
+		return nil
331
+	}
332
+	return b
333
+}
334
+
335
+func (ep *bridgeEndpoint) SetValue(value []byte) error {
336
+	return json.Unmarshal(value, ep)
337
+}
338
+
339
+func (ep *bridgeEndpoint) Index() uint64 {
340
+	return ep.dbIndex
341
+}
342
+
343
+func (ep *bridgeEndpoint) SetIndex(index uint64) {
344
+	ep.dbIndex = index
345
+	ep.dbExists = true
346
+}
347
+
348
+func (ep *bridgeEndpoint) Exists() bool {
349
+	return ep.dbExists
350
+}
351
+
352
+func (ep *bridgeEndpoint) Skip() bool {
353
+	return false
354
+}
355
+
356
+func (ep *bridgeEndpoint) New() datastore.KVObject {
357
+	return &bridgeEndpoint{}
358
+}
359
+
360
+func (ep *bridgeEndpoint) CopyTo(o datastore.KVObject) error {
361
+	dstEp := o.(*bridgeEndpoint)
362
+	*dstEp = *ep
363
+	return nil
364
+}
365
+
366
+func (ep *bridgeEndpoint) DataScope() string {
367
+	return datastore.LocalScope
368
+}
369
+
370
+func (n *bridgeNetwork) restorePortAllocations(ep *bridgeEndpoint) {
371
+	if ep.extConnConfig == nil ||
372
+		ep.extConnConfig.ExposedPorts == nil ||
373
+		ep.extConnConfig.PortBindings == nil {
374
+		return
375
+	}
376
+	tmp := ep.extConnConfig.PortBindings
377
+	ep.extConnConfig.PortBindings = ep.portMapping
378
+	_, err := n.allocatePorts(ep, n.config.DefaultBindingIntf, n.config.DefaultBindingIP, n.driver.config.EnableUserlandProxy)
379
+	if err != nil {
380
+		logrus.Warnf("Failed to reserve existing port mapping for endpoint %s:%v", ep.id[0:7], err)
381
+	}
382
+	ep.extConnConfig.PortBindings = tmp
383
+}
0 384
new file mode 100644
... ...
@@ -0,0 +1,675 @@
0
+// +build solaris
1
+
2
+package bridge
3
+
4
+import (
5
+	"bytes"
6
+	"encoding/json"
7
+	"net"
8
+	"testing"
9
+
10
+	"github.com/docker/libnetwork/driverapi"
11
+	"github.com/docker/libnetwork/ipamutils"
12
+	"github.com/docker/libnetwork/netlabel"
13
+	"github.com/docker/libnetwork/netutils"
14
+	"github.com/docker/libnetwork/testutils"
15
+	"github.com/docker/libnetwork/types"
16
+)
17
+
18
+func init() {
19
+	ipamutils.InitNetworks()
20
+}
21
+
22
+func TestEndpointMarshalling(t *testing.T) {
23
+	ip1, _ := types.ParseCIDR("172.22.0.9/16")
24
+	ip2, _ := types.ParseCIDR("2001:db8::9")
25
+	mac, _ := net.ParseMAC("ac:bd:24:57:66:77")
26
+	e := &bridgeEndpoint{
27
+		id:         "d2c015a1fe5930650cbcd50493efba0500bcebd8ee1f4401a16319f8a567de33",
28
+		nid:        "ee33fbb43c323f1920b6b35a0101552ac22ede960d0e5245e9738bccc68b2415",
29
+		addr:       ip1,
30
+		addrv6:     ip2,
31
+		macAddress: mac,
32
+		srcName:    "veth123456",
33
+		config:     &endpointConfiguration{MacAddress: mac},
34
+		containerConfig: &containerConfiguration{
35
+			ParentEndpoints: []string{"one", "due", "three"},
36
+			ChildEndpoints:  []string{"four", "five", "six"},
37
+		},
38
+		extConnConfig: &connectivityConfiguration{
39
+			ExposedPorts: []types.TransportPort{
40
+				{
41
+					Proto: 6,
42
+					Port:  uint16(18),
43
+				},
44
+			},
45
+			PortBindings: []types.PortBinding{
46
+				{
47
+					Proto:       6,
48
+					IP:          net.ParseIP("17210.33.9.56"),
49
+					Port:        uint16(18),
50
+					HostPort:    uint16(3000),
51
+					HostPortEnd: uint16(14000),
52
+				},
53
+			},
54
+		},
55
+		portMapping: []types.PortBinding{
56
+			{
57
+				Proto:       17,
58
+				IP:          net.ParseIP("172.33.9.56"),
59
+				Port:        uint16(99),
60
+				HostIP:      net.ParseIP("10.10.100.2"),
61
+				HostPort:    uint16(9900),
62
+				HostPortEnd: uint16(10000),
63
+			},
64
+			{
65
+				Proto:       6,
66
+				IP:          net.ParseIP("171.33.9.56"),
67
+				Port:        uint16(55),
68
+				HostIP:      net.ParseIP("10.11.100.2"),
69
+				HostPort:    uint16(5500),
70
+				HostPortEnd: uint16(55000),
71
+			},
72
+		},
73
+	}
74
+
75
+	b, err := json.Marshal(e)
76
+	if err != nil {
77
+		t.Fatal(err)
78
+	}
79
+
80
+	ee := &bridgeEndpoint{}
81
+	err = json.Unmarshal(b, ee)
82
+	if err != nil {
83
+		t.Fatal(err)
84
+	}
85
+
86
+	if e.id != ee.id || e.nid != ee.nid || e.srcName != ee.srcName || !bytes.Equal(e.macAddress, ee.macAddress) ||
87
+		!types.CompareIPNet(e.addr, ee.addr) || !types.CompareIPNet(e.addrv6, ee.addrv6) ||
88
+		!compareEpConfig(e.config, ee.config) ||
89
+		!compareContainerConfig(e.containerConfig, ee.containerConfig) ||
90
+		!compareConnConfig(e.extConnConfig, ee.extConnConfig) ||
91
+		!compareBindings(e.portMapping, ee.portMapping) {
92
+		t.Fatalf("JSON marsh/unmarsh failed.\nOriginal:\n%#v\nDecoded:\n%#v", e, ee)
93
+	}
94
+}
95
+
96
+func compareEpConfig(a, b *endpointConfiguration) bool {
97
+	if a == b {
98
+		return true
99
+	}
100
+	if a == nil || b == nil {
101
+		return false
102
+	}
103
+	return bytes.Equal(a.MacAddress, b.MacAddress)
104
+}
105
+
106
+func compareContainerConfig(a, b *containerConfiguration) bool {
107
+	if a == b {
108
+		return true
109
+	}
110
+	if a == nil || b == nil {
111
+		return false
112
+	}
113
+	if len(a.ParentEndpoints) != len(b.ParentEndpoints) ||
114
+		len(a.ChildEndpoints) != len(b.ChildEndpoints) {
115
+		return false
116
+	}
117
+	for i := 0; i < len(a.ParentEndpoints); i++ {
118
+		if a.ParentEndpoints[i] != b.ParentEndpoints[i] {
119
+			return false
120
+		}
121
+	}
122
+	for i := 0; i < len(a.ChildEndpoints); i++ {
123
+		if a.ChildEndpoints[i] != b.ChildEndpoints[i] {
124
+			return false
125
+		}
126
+	}
127
+	return true
128
+}
129
+
130
+func compareConnConfig(a, b *connectivityConfiguration) bool {
131
+	if a == b {
132
+		return true
133
+	}
134
+	if a == nil || b == nil {
135
+		return false
136
+	}
137
+	if len(a.ExposedPorts) != len(b.ExposedPorts) ||
138
+		len(a.PortBindings) != len(b.PortBindings) {
139
+		return false
140
+	}
141
+	for i := 0; i < len(a.ExposedPorts); i++ {
142
+		if !a.ExposedPorts[i].Equal(&b.ExposedPorts[i]) {
143
+			return false
144
+		}
145
+	}
146
+	for i := 0; i < len(a.PortBindings); i++ {
147
+		if !a.PortBindings[i].Equal(&b.PortBindings[i]) {
148
+			return false
149
+		}
150
+	}
151
+	return true
152
+}
153
+
154
+func compareBindings(a, b []types.PortBinding) bool {
155
+	if len(a) != len(b) {
156
+		return false
157
+	}
158
+	for i := 0; i < len(a); i++ {
159
+		if !a[i].Equal(&b[i]) {
160
+			return false
161
+		}
162
+	}
163
+	return true
164
+}
165
+
166
+func getIPv4Data(t *testing.T) []driverapi.IPAMData {
167
+	ipd := driverapi.IPAMData{AddressSpace: "full"}
168
+	nw, _, err := netutils.ElectInterfaceAddresses("")
169
+	if err != nil {
170
+		t.Fatal(err)
171
+	}
172
+	ipd.Pool = nw
173
+	// Set network gateway to X.X.X.1
174
+	ipd.Gateway = types.GetIPNetCopy(nw)
175
+	ipd.Gateway.IP[len(ipd.Gateway.IP)-1] = 1
176
+	return []driverapi.IPAMData{ipd}
177
+}
178
+
179
+func TestCreateFullOptions(t *testing.T) {
180
+	defer testutils.SetupTestOSContext(t)()
181
+	d := newDriver()
182
+
183
+	config := &configuration{
184
+		EnableIPForwarding: true,
185
+		EnableIPTables:     true,
186
+	}
187
+
188
+	// Test this scenario: Default gw address does not belong to
189
+	// container network and it's greater than bridge address
190
+	cnw, _ := types.ParseCIDR("172.16.122.0/24")
191
+	bnw, _ := types.ParseCIDR("172.16.0.0/24")
192
+	br, _ := types.ParseCIDR("172.16.0.1/16")
193
+	defgw, _ := types.ParseCIDR("172.16.0.100/16")
194
+
195
+	genericOption := make(map[string]interface{})
196
+	genericOption[netlabel.GenericData] = config
197
+
198
+	if err := d.configure(genericOption); err != nil {
199
+		t.Fatalf("Failed to setup driver config: %v", err)
200
+	}
201
+
202
+	netOption := make(map[string]interface{})
203
+	netOption[netlabel.EnableIPv6] = true
204
+	netOption[netlabel.GenericData] = &networkConfiguration{
205
+		BridgeName: DefaultBridgeName,
206
+	}
207
+
208
+	ipdList := []driverapi.IPAMData{
209
+		{
210
+			Pool:         bnw,
211
+			Gateway:      br,
212
+			AuxAddresses: map[string]*net.IPNet{DefaultGatewayV4AuxKey: defgw},
213
+		},
214
+	}
215
+	err := d.CreateNetwork("dummy", netOption, nil, ipdList, nil)
216
+	if err != nil {
217
+		t.Fatalf("Failed to create bridge: %v", err)
218
+	}
219
+
220
+	// Verify the IP address allocated for the endpoint belongs to the container network
221
+	epOptions := make(map[string]interface{})
222
+	te := newTestEndpoint(cnw, 10)
223
+	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
224
+	if err != nil {
225
+		t.Fatalf("Failed to create an endpoint : %s", err.Error())
226
+	}
227
+
228
+	if !cnw.Contains(te.Interface().Address().IP) {
229
+		t.Fatalf("endpoint got assigned address outside of container network(%s): %s", cnw.String(), te.Interface().Address())
230
+	}
231
+}
232
+
233
+func TestCreateNoConfig(t *testing.T) {
234
+	if !testutils.IsRunningInContainer() {
235
+		defer testutils.SetupTestOSContext(t)()
236
+	}
237
+	d := newDriver()
238
+
239
+	netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
240
+	genericOption := make(map[string]interface{})
241
+	genericOption[netlabel.GenericData] = netconfig
242
+
243
+	if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil {
244
+		t.Fatalf("Failed to create bridge: %v", err)
245
+	}
246
+}
247
+
248
+func TestCreateFullOptionsLabels(t *testing.T) {
249
+	if !testutils.IsRunningInContainer() {
250
+		defer testutils.SetupTestOSContext(t)()
251
+	}
252
+	d := newDriver()
253
+
254
+	config := &configuration{
255
+		EnableIPForwarding: true,
256
+	}
257
+	genericOption := make(map[string]interface{})
258
+	genericOption[netlabel.GenericData] = config
259
+
260
+	if err := d.configure(genericOption); err != nil {
261
+		t.Fatalf("Failed to setup driver config: %v", err)
262
+	}
263
+
264
+	bndIPs := "127.0.0.1"
265
+	nwV6s := "2001:db8:2600:2700:2800::/80"
266
+	gwV6s := "2001:db8:2600:2700:2800::25/80"
267
+	nwV6, _ := types.ParseCIDR(nwV6s)
268
+	gwV6, _ := types.ParseCIDR(gwV6s)
269
+
270
+	labels := map[string]string{
271
+		BridgeName:         DefaultBridgeName,
272
+		DefaultBridge:      "true",
273
+		EnableICC:          "true",
274
+		EnableIPMasquerade: "true",
275
+		DefaultBindingIP:   bndIPs,
276
+	}
277
+
278
+	netOption := make(map[string]interface{})
279
+	netOption[netlabel.EnableIPv6] = true
280
+	netOption[netlabel.GenericData] = labels
281
+
282
+	ipdList := getIPv4Data(t)
283
+	ipd6List := []driverapi.IPAMData{
284
+		{
285
+			Pool: nwV6,
286
+			AuxAddresses: map[string]*net.IPNet{
287
+				DefaultGatewayV6AuxKey: gwV6,
288
+			},
289
+		},
290
+	}
291
+
292
+	err := d.CreateNetwork("dummy", netOption, nil, ipdList, ipd6List)
293
+	if err != nil {
294
+		t.Fatalf("Failed to create bridge: %v", err)
295
+	}
296
+
297
+	nw, ok := d.networks["dummy"]
298
+	if !ok {
299
+		t.Fatalf("Cannot find dummy network in bridge driver")
300
+	}
301
+
302
+	if nw.config.BridgeName != DefaultBridgeName {
303
+		t.Fatalf("incongruent name in bridge network")
304
+	}
305
+
306
+	if !nw.config.EnableIPv6 {
307
+		t.Fatalf("incongruent EnableIPv6 in bridge network")
308
+	}
309
+
310
+	if !nw.config.EnableICC {
311
+		t.Fatalf("incongruent EnableICC in bridge network")
312
+	}
313
+
314
+	if !nw.config.EnableIPMasquerade {
315
+		t.Fatalf("incongruent EnableIPMasquerade in bridge network")
316
+	}
317
+
318
+	bndIP := net.ParseIP(bndIPs)
319
+	if !bndIP.Equal(nw.config.DefaultBindingIP) {
320
+		t.Fatalf("Unexpected: %v", nw.config.DefaultBindingIP)
321
+	}
322
+
323
+	if !types.CompareIPNet(nw.config.AddressIPv6, nwV6) {
324
+		t.Fatalf("Unexpected: %v", nw.config.AddressIPv6)
325
+	}
326
+
327
+	if !gwV6.IP.Equal(nw.config.DefaultGatewayIPv6) {
328
+		t.Fatalf("Unexpected: %v", nw.config.DefaultGatewayIPv6)
329
+	}
330
+
331
+	// In short here we are testing --fixed-cidr-v6 daemon option
332
+	// plus --mac-address run option
333
+	mac, _ := net.ParseMAC("aa:bb:cc:dd:ee:ff")
334
+	epOptions := map[string]interface{}{netlabel.MacAddress: mac}
335
+	te := newTestEndpoint(ipdList[0].Pool, 20)
336
+	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
337
+	if err != nil {
338
+		t.Fatal(err)
339
+	}
340
+}
341
+
342
+func TestCreate(t *testing.T) {
343
+	if !testutils.IsRunningInContainer() {
344
+		defer testutils.SetupTestOSContext(t)()
345
+	}
346
+
347
+	d := newDriver()
348
+
349
+	if err := d.configure(nil); err != nil {
350
+		t.Fatalf("Failed to setup driver config: %v", err)
351
+	}
352
+
353
+	netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
354
+	genericOption := make(map[string]interface{})
355
+	genericOption[netlabel.GenericData] = netconfig
356
+
357
+	if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil {
358
+		t.Fatalf("Failed to create bridge: %v", err)
359
+	}
360
+
361
+	err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil)
362
+	if err == nil {
363
+		t.Fatalf("Expected bridge driver to refuse creation of second network with default name")
364
+	}
365
+	if _, ok := err.(types.ForbiddenError); !ok {
366
+		t.Fatalf("Creation of second network with default name failed with unexpected error type")
367
+	}
368
+}
369
+
370
+func TestCreateFail(t *testing.T) {
371
+	if !testutils.IsRunningInContainer() {
372
+		defer testutils.SetupTestOSContext(t)()
373
+	}
374
+
375
+	d := newDriver()
376
+
377
+	if err := d.configure(nil); err != nil {
378
+		t.Fatalf("Failed to setup driver config: %v", err)
379
+	}
380
+
381
+	netconfig := &networkConfiguration{BridgeName: "dummy0", DefaultBridge: true}
382
+	genericOption := make(map[string]interface{})
383
+	genericOption[netlabel.GenericData] = netconfig
384
+
385
+	if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err == nil {
386
+		t.Fatal("Bridge creation was expected to fail")
387
+	}
388
+}
389
+
390
+type testInterface struct {
391
+	mac     net.HardwareAddr
392
+	addr    *net.IPNet
393
+	addrv6  *net.IPNet
394
+	srcName string
395
+	dstName string
396
+}
397
+
398
+type testEndpoint struct {
399
+	iface          *testInterface
400
+	gw             net.IP
401
+	gw6            net.IP
402
+	hostsPath      string
403
+	resolvConfPath string
404
+	routes         []types.StaticRoute
405
+}
406
+
407
+func newTestEndpoint(nw *net.IPNet, ordinal byte) *testEndpoint {
408
+	addr := types.GetIPNetCopy(nw)
409
+	addr.IP[len(addr.IP)-1] = ordinal
410
+	return &testEndpoint{iface: &testInterface{addr: addr}}
411
+}
412
+
413
+func (te *testEndpoint) Interface() driverapi.InterfaceInfo {
414
+	if te.iface != nil {
415
+		return te.iface
416
+	}
417
+
418
+	return nil
419
+}
420
+
421
+func (i *testInterface) MacAddress() net.HardwareAddr {
422
+	return i.mac
423
+}
424
+
425
+func (i *testInterface) Address() *net.IPNet {
426
+	return i.addr
427
+}
428
+
429
+func (i *testInterface) AddressIPv6() *net.IPNet {
430
+	return i.addrv6
431
+}
432
+
433
+func (i *testInterface) SetMacAddress(mac net.HardwareAddr) error {
434
+	if i.mac != nil {
435
+		return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", i.mac, mac)
436
+	}
437
+	if mac == nil {
438
+		return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
439
+	}
440
+	i.mac = types.GetMacCopy(mac)
441
+	return nil
442
+}
443
+
444
+func (i *testInterface) SetIPAddress(address *net.IPNet) error {
445
+	if address.IP == nil {
446
+		return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
447
+	}
448
+	if address.IP.To4() == nil {
449
+		return setAddress(&i.addrv6, address)
450
+	}
451
+	return setAddress(&i.addr, address)
452
+}
453
+
454
+func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
455
+	if *ifaceAddr != nil {
456
+		return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
457
+	}
458
+	*ifaceAddr = types.GetIPNetCopy(address)
459
+	return nil
460
+}
461
+
462
+func (i *testInterface) SetNames(srcName string, dstName string) error {
463
+	i.srcName = srcName
464
+	i.dstName = dstName
465
+	return nil
466
+}
467
+
468
+func (te *testEndpoint) InterfaceName() driverapi.InterfaceNameInfo {
469
+	if te.iface != nil {
470
+		return te.iface
471
+	}
472
+
473
+	return nil
474
+}
475
+
476
+func (te *testEndpoint) SetGateway(gw net.IP) error {
477
+	te.gw = gw
478
+	return nil
479
+}
480
+
481
+func (te *testEndpoint) SetGatewayIPv6(gw6 net.IP) error {
482
+	te.gw6 = gw6
483
+	return nil
484
+}
485
+
486
+func (te *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
487
+	te.routes = append(te.routes, types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop})
488
+	return nil
489
+}
490
+
491
+func (te *testEndpoint) AddTableEntry(tableName string, key string, value []byte) error {
492
+	return nil
493
+}
494
+
495
+func (te *testEndpoint) DisableGatewayService() {}
496
+
497
+func TestQueryEndpointInfo(t *testing.T) {
498
+	testQueryEndpointInfo(t, true)
499
+}
500
+
501
+func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
502
+	defer testutils.SetupTestOSContext(t)()
503
+
504
+	d := newDriver()
505
+
506
+	config := &configuration{
507
+		EnableIPTables:      true,
508
+		EnableUserlandProxy: ulPxyEnabled,
509
+	}
510
+	genericOption := make(map[string]interface{})
511
+	genericOption[netlabel.GenericData] = config
512
+
513
+	if err := d.configure(genericOption); err != nil {
514
+		t.Fatalf("Failed to setup driver config: %v", err)
515
+	}
516
+
517
+	netconfig := &networkConfiguration{
518
+		BridgeName: DefaultBridgeName,
519
+		EnableICC:  false,
520
+	}
521
+	genericOption = make(map[string]interface{})
522
+	genericOption[netlabel.GenericData] = netconfig
523
+
524
+	ipdList := getIPv4Data(t)
525
+	err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil)
526
+	if err != nil {
527
+		t.Fatalf("Failed to create bridge: %v", err)
528
+	}
529
+
530
+	sbOptions := make(map[string]interface{})
531
+	sbOptions[netlabel.PortMap] = getPortMapping()
532
+
533
+	te := newTestEndpoint(ipdList[0].Pool, 11)
534
+	err = d.CreateEndpoint("net1", "ep1", te.Interface(), nil)
535
+	if err != nil {
536
+		t.Fatalf("Failed to create an endpoint : %s", err.Error())
537
+	}
538
+
539
+	err = d.Join("net1", "ep1", "sbox", te, sbOptions)
540
+	if err != nil {
541
+		t.Fatalf("Failed to join the endpoint: %v", err)
542
+	}
543
+
544
+	err = d.ProgramExternalConnectivity("net1", "ep1", sbOptions)
545
+	if err != nil {
546
+		t.Fatalf("Failed to program external connectivity: %v", err)
547
+	}
548
+
549
+	network, ok := d.networks["net1"]
550
+	if !ok {
551
+		t.Fatalf("Cannot find network %s inside driver", "net1")
552
+	}
553
+	ep, _ := network.endpoints["ep1"]
554
+	data, err := d.EndpointOperInfo(network.id, ep.id)
555
+	if err != nil {
556
+		t.Fatalf("Failed to ask for endpoint operational data:  %v", err)
557
+	}
558
+	pmd, ok := data[netlabel.PortMap]
559
+	if !ok {
560
+		t.Fatalf("Endpoint operational data does not contain port mapping data")
561
+	}
562
+	pm, ok := pmd.([]types.PortBinding)
563
+	if !ok {
564
+		t.Fatalf("Unexpected format for port mapping in endpoint operational data")
565
+	}
566
+	if len(ep.portMapping) != len(pm) {
567
+		t.Fatalf("Incomplete data for port mapping in endpoint operational data")
568
+	}
569
+	for i, pb := range ep.portMapping {
570
+		if !pb.Equal(&pm[i]) {
571
+			t.Fatalf("Unexpected data for port mapping in endpoint operational data")
572
+		}
573
+	}
574
+
575
+	err = d.RevokeExternalConnectivity("net1", "ep1")
576
+	if err != nil {
577
+		t.Fatal(err)
578
+	}
579
+
580
+	// release host mapped ports
581
+	err = d.Leave("net1", "ep1")
582
+	if err != nil {
583
+		t.Fatal(err)
584
+	}
585
+}
586
+
587
+func getExposedPorts() []types.TransportPort {
588
+	return []types.TransportPort{
589
+		{Proto: types.TCP, Port: uint16(5000)},
590
+		{Proto: types.UDP, Port: uint16(400)},
591
+		{Proto: types.TCP, Port: uint16(600)},
592
+	}
593
+}
594
+
595
+func getPortMapping() []types.PortBinding {
596
+	return []types.PortBinding{
597
+		{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
598
+		{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
599
+		{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
600
+	}
601
+}
602
+
603
+func TestValidateConfig(t *testing.T) {
604
+	if !testutils.IsRunningInContainer() {
605
+		defer testutils.SetupTestOSContext(t)()
606
+	}
607
+
608
+	// Test mtu
609
+	c := networkConfiguration{Mtu: -2}
610
+	err := c.Validate()
611
+	if err == nil {
612
+		t.Fatalf("Failed to detect invalid MTU number")
613
+	}
614
+
615
+	c.Mtu = 9000
616
+	err = c.Validate()
617
+	if err != nil {
618
+		t.Fatalf("unexpected validation error on MTU number")
619
+	}
620
+
621
+	// Bridge network
622
+	_, network, _ := net.ParseCIDR("172.28.0.0/16")
623
+	c = networkConfiguration{
624
+		AddressIPv4: network,
625
+	}
626
+
627
+	err = c.Validate()
628
+	if err != nil {
629
+		t.Fatal(err)
630
+	}
631
+
632
+	// Test v4 gw
633
+	c.DefaultGatewayIPv4 = net.ParseIP("172.27.30.234")
634
+	err = c.Validate()
635
+	if err == nil {
636
+		t.Fatalf("Failed to detect invalid default gateway")
637
+	}
638
+
639
+	c.DefaultGatewayIPv4 = net.ParseIP("172.28.30.234")
640
+	err = c.Validate()
641
+	if err != nil {
642
+		t.Fatalf("Unexpected validation error on default gateway")
643
+	}
644
+
645
+	// Test v6 gw
646
+	_, v6nw, _ := net.ParseCIDR("2001:db8:ae:b004::/64")
647
+	c = networkConfiguration{
648
+		EnableIPv6:         true,
649
+		AddressIPv6:        v6nw,
650
+		DefaultGatewayIPv6: net.ParseIP("2001:db8:ac:b004::bad:a55"),
651
+	}
652
+	err = c.Validate()
653
+	if err == nil {
654
+		t.Fatalf("Failed to detect invalid v6 default gateway")
655
+	}
656
+
657
+	c.DefaultGatewayIPv6 = net.ParseIP("2001:db8:ae:b004::bad:a55")
658
+	err = c.Validate()
659
+	if err != nil {
660
+		t.Fatalf("Unexpected validation error on v6 default gateway")
661
+	}
662
+
663
+	c.AddressIPv6 = nil
664
+	err = c.Validate()
665
+	if err == nil {
666
+		t.Fatalf("Failed to detect invalid v6 default gateway")
667
+	}
668
+
669
+	c.AddressIPv6 = nil
670
+	err = c.Validate()
671
+	if err == nil {
672
+		t.Fatalf("Failed to detect invalid v6 default gateway")
673
+	}
674
+}
0 675
new file mode 100644
... ...
@@ -0,0 +1,119 @@
0
+package bridge
1
+
2
+import "fmt"
3
+
4
+// ErrInvalidEndpointConfig error is returned when an endpoint create is attempted with an invalid endpoint configuration.
5
+type ErrInvalidEndpointConfig struct{}
6
+
7
+func (eiec *ErrInvalidEndpointConfig) Error() string {
8
+	return "trying to create an endpoint with an invalid endpoint configuration"
9
+}
10
+
11
+// BadRequest denotes the type of this error
12
+func (eiec *ErrInvalidEndpointConfig) BadRequest() {}
13
+
14
+// ErrNoIPAddr error is returned when bridge has no IPv4 address configured.
15
+type ErrNoIPAddr struct{}
16
+
17
+func (enip *ErrNoIPAddr) Error() string {
18
+	return "bridge has no IPv4 address configured"
19
+}
20
+
21
+// InternalError denotes the type of this error
22
+func (enip *ErrNoIPAddr) InternalError() {}
23
+
24
+// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid.
25
+type ErrInvalidGateway struct{}
26
+
27
+func (eig *ErrInvalidGateway) Error() string {
28
+	return "default gateway ip must be part of the network"
29
+}
30
+
31
+// BadRequest denotes the type of this error
32
+func (eig *ErrInvalidGateway) BadRequest() {}
33
+
34
+// ErrInvalidMtu is returned when the user provided MTU is not valid.
35
+type ErrInvalidMtu int
36
+
37
+func (eim ErrInvalidMtu) Error() string {
38
+	return fmt.Sprintf("invalid MTU number: %d", int(eim))
39
+}
40
+
41
+// BadRequest denotes the type of this error
42
+func (eim ErrInvalidMtu) BadRequest() {}
43
+
44
+// ErrUnsupportedAddressType is returned when the specified address type is not supported.
45
+type ErrUnsupportedAddressType string
46
+
47
+func (uat ErrUnsupportedAddressType) Error() string {
48
+	return fmt.Sprintf("unsupported address type: %s", string(uat))
49
+}
50
+
51
+// BadRequest denotes the type of this error
52
+func (uat ErrUnsupportedAddressType) BadRequest() {}
53
+
54
+// ActiveEndpointsError is returned when there are
55
+// still active endpoints in the network being deleted.
56
+type ActiveEndpointsError string
57
+
58
+func (aee ActiveEndpointsError) Error() string {
59
+	return fmt.Sprintf("network %s has active endpoint", string(aee))
60
+}
61
+
62
+// Forbidden denotes the type of this error
63
+func (aee ActiveEndpointsError) Forbidden() {}
64
+
65
+// InvalidNetworkIDError is returned when the passed
66
+// network id for an existing network is not a known id.
67
+type InvalidNetworkIDError string
68
+
69
+func (inie InvalidNetworkIDError) Error() string {
70
+	return fmt.Sprintf("invalid network id %s", string(inie))
71
+}
72
+
73
+// NotFound denotes the type of this error
74
+func (inie InvalidNetworkIDError) NotFound() {}
75
+
76
+// InvalidEndpointIDError is returned when the passed
77
+// endpoint id is not valid.
78
+type InvalidEndpointIDError string
79
+
80
+func (ieie InvalidEndpointIDError) Error() string {
81
+	return fmt.Sprintf("invalid endpoint id: %s", string(ieie))
82
+}
83
+
84
+// BadRequest denotes the type of this error
85
+func (ieie InvalidEndpointIDError) BadRequest() {}
86
+
87
+// EndpointNotFoundError is returned when the no endpoint
88
+// with the passed endpoint id is found.
89
+type EndpointNotFoundError string
90
+
91
+func (enfe EndpointNotFoundError) Error() string {
92
+	return fmt.Sprintf("endpoint not found: %s", string(enfe))
93
+}
94
+
95
+// NotFound denotes the type of this error
96
+func (enfe EndpointNotFoundError) NotFound() {}
97
+
98
+// NonDefaultBridgeExistError is returned when a non-default
99
+// bridge config is passed but it does not already exist.
100
+type NonDefaultBridgeExistError string
101
+
102
+func (ndbee NonDefaultBridgeExistError) Error() string {
103
+	return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee))
104
+}
105
+
106
+// Forbidden denotes the type of this error
107
+func (ndbee NonDefaultBridgeExistError) Forbidden() {}
108
+
109
+// NonDefaultBridgeNeedsIPError is returned when a non-default
110
+// bridge config is passed but it has no ip configured
111
+type NonDefaultBridgeNeedsIPError string
112
+
113
+func (ndbee NonDefaultBridgeNeedsIPError) Error() string {
114
+	return fmt.Sprintf("bridge device with non default name %s must have a valid IP address", string(ndbee))
115
+}
116
+
117
+// Forbidden denotes the type of this error
118
+func (ndbee NonDefaultBridgeNeedsIPError) Forbidden() {}
0 119
new file mode 100644
... ...
@@ -0,0 +1,225 @@
0
+// +build solaris
1
+
2
+package bridge
3
+
4
+import (
5
+	"bytes"
6
+	"errors"
7
+	"fmt"
8
+	"net"
9
+	"os"
10
+	"os/exec"
11
+
12
+	"github.com/Sirupsen/logrus"
13
+	"github.com/docker/libnetwork/types"
14
+)
15
+
16
+var (
17
+	defaultBindingIP = net.IPv4(0, 0, 0, 0)
18
+)
19
+
20
+const (
21
+	maxAllocatePortAttempts = 10
22
+)
23
+
24
+func addPFRules(epid, bindIntf string, bs []types.PortBinding) {
25
+	var id string
26
+
27
+	if len(epid) > 12 {
28
+		id = epid[:12]
29
+	} else {
30
+		id = epid
31
+	}
32
+
33
+	fname := "/var/lib/docker/network/files/pf." + id
34
+
35
+	f, err := os.OpenFile(fname,
36
+		os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
37
+	if err != nil {
38
+		logrus.Warnf("cannot open temp pf file")
39
+		return
40
+	}
41
+	for _, b := range bs {
42
+		r := fmt.Sprintf(
43
+			"pass in on %s proto %s from any to (%s) "+
44
+				"port %d rdr-to %s port %d\n", bindIntf,
45
+			b.Proto.String(), bindIntf, b.HostPort,
46
+			b.IP.String(), b.Port)
47
+		_, err = f.WriteString(r)
48
+		if err != nil {
49
+			logrus.Warnf("cannot write firewall rules to %s: %v", fname, err)
50
+		}
51
+	}
52
+	f.Close()
53
+
54
+	anchor := fmt.Sprintf("_auto/docker/ep%s", id)
55
+	err = exec.Command("/usr/sbin/pfctl", "-a", anchor, "-f", fname).Run()
56
+	if err != nil {
57
+		logrus.Warnf("failed to add firewall rules: %v", err)
58
+	}
59
+	os.Remove(fname)
60
+}
61
+
62
+func removePFRules(epid string) {
63
+	var id string
64
+
65
+	if len(epid) > 12 {
66
+		id = epid[:12]
67
+	} else {
68
+		id = epid
69
+	}
70
+
71
+	anchor := fmt.Sprintf("_auto/docker/ep%s", id)
72
+	err := exec.Command("/usr/sbin/pfctl", "-a", anchor, "-F", "all").Run()
73
+	if err != nil {
74
+		logrus.Warnf("failed to remove firewall rules: %v", err)
75
+	}
76
+}
77
+
78
+func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, bindIntf string, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
79
+	if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
80
+		return nil, nil
81
+	}
82
+
83
+	defHostIP := defaultBindingIP
84
+	if reqDefBindIP != nil {
85
+		defHostIP = reqDefBindIP
86
+	}
87
+
88
+	bs, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, bindIntf, ep.addr.IP, defHostIP, ulPxyEnabled)
89
+	if err != nil {
90
+		return nil, err
91
+	}
92
+
93
+	// Add PF rules for port bindings, if any
94
+	if len(bs) > 0 {
95
+		addPFRules(ep.id, bindIntf, bs)
96
+	}
97
+
98
+	return bs, err
99
+}
100
+
101
+func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, bindIntf string, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
102
+	bs := make([]types.PortBinding, 0, len(bindings))
103
+	for _, c := range bindings {
104
+		b := c.GetCopy()
105
+		if err := n.allocatePort(&b, containerIP, defHostIP); err != nil {
106
+			// On allocation failure,release previously
107
+			// allocated ports. On cleanup error, just log
108
+			// a warning message
109
+			if cuErr := n.releasePortsInternal(bs); cuErr != nil {
110
+				logrus.Warnf("Upon allocation failure "+
111
+					"for %v, failed to clear previously "+
112
+					"allocated port bindings: %v", b, cuErr)
113
+			}
114
+			return nil, err
115
+		}
116
+		bs = append(bs, b)
117
+	}
118
+	return bs, nil
119
+}
120
+
121
+func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP) error {
122
+	var (
123
+		host net.Addr
124
+		err  error
125
+	)
126
+
127
+	// Store the container interface address in the operational binding
128
+	bnd.IP = containerIP
129
+
130
+	// Adjust the host address in the operational binding
131
+	if len(bnd.HostIP) == 0 {
132
+		bnd.HostIP = defHostIP
133
+	}
134
+
135
+	// Adjust HostPortEnd if this is not a range.
136
+	if bnd.HostPortEnd == 0 {
137
+		bnd.HostPortEnd = bnd.HostPort
138
+	}
139
+
140
+	// Construct the container side transport address
141
+	container, err := bnd.ContainerAddr()
142
+	if err != nil {
143
+		return err
144
+	}
145
+
146
+	// Try up to maxAllocatePortAttempts times to get a port that's
147
+	// not already allocated.
148
+	for i := 0; i < maxAllocatePortAttempts; i++ {
149
+		if host, err = n.portMapper.MapRange(container, bnd.HostIP,
150
+			int(bnd.HostPort), int(bnd.HostPortEnd), false); err == nil {
151
+			break
152
+		}
153
+		// There is no point in immediately retrying to map an
154
+		// explicitly chosen port.
155
+		if bnd.HostPort != 0 {
156
+			logrus.Warnf(
157
+				"Failed to allocate and map port %d-%d: %s",
158
+				bnd.HostPort, bnd.HostPortEnd, err)
159
+			break
160
+		}
161
+		logrus.Warnf("Failed to allocate and map port: %s, retry: %d",
162
+			err, i+1)
163
+	}
164
+	if err != nil {
165
+		return err
166
+	}
167
+
168
+	// Save the host port (regardless it was or not specified in the
169
+	// binding)
170
+	switch netAddr := host.(type) {
171
+	case *net.TCPAddr:
172
+		bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
173
+		return nil
174
+	case *net.UDPAddr:
175
+		bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
176
+		return nil
177
+	default:
178
+		// For completeness
179
+		return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
180
+	}
181
+}
182
+
183
+func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
184
+	err := n.releasePortsInternal(ep.portMapping)
185
+	if err != nil {
186
+		return nil
187
+	}
188
+
189
+	// remove rules if there are any port mappings
190
+	if len(ep.portMapping) > 0 {
191
+		removePFRules(ep.id)
192
+	}
193
+
194
+	return nil
195
+
196
+}
197
+
198
+func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error {
199
+	var errorBuf bytes.Buffer
200
+
201
+	// Attempt to release all port bindings, do not stop on failure
202
+	for _, m := range bindings {
203
+		if err := n.releasePort(m); err != nil {
204
+			errorBuf.WriteString(
205
+				fmt.Sprintf(
206
+					"\ncould not release %v because of %v",
207
+					m, err))
208
+		}
209
+	}
210
+
211
+	if errorBuf.Len() != 0 {
212
+		return errors.New(errorBuf.String())
213
+	}
214
+	return nil
215
+}
216
+
217
+func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
218
+	// Construct the host side transport address
219
+	host, err := bnd.HostAddr()
220
+	if err != nil {
221
+		return err
222
+	}
223
+	return n.portMapper.Unmap(host)
224
+}
... ...
@@ -1,5 +1,13 @@
1 1
 package libnetwork
2 2
 
3
+import (
4
+	"github.com/docker/libnetwork/drivers/null"
5
+	"github.com/docker/libnetwork/drivers/solaris/bridge"
6
+)
7
+
3 8
 func getInitializers() []initializer {
4
-	return []initializer{}
9
+	return []initializer{
10
+		{bridge.Init, "bridge"},
11
+		{null.Init, "null"},
12
+	}
5 13
 }
6 14
new file mode 100644
... ...
@@ -0,0 +1,995 @@
0
+package libnetwork_test
1
+
2
+import (
3
+	"bytes"
4
+	"encoding/json"
5
+	"flag"
6
+	"fmt"
7
+	"io/ioutil"
8
+	"net"
9
+	"os"
10
+	"os/exec"
11
+	"runtime"
12
+	"strconv"
13
+	"strings"
14
+	"testing"
15
+
16
+	log "github.com/Sirupsen/logrus"
17
+	"github.com/docker/docker/pkg/reexec"
18
+	"github.com/docker/libnetwork"
19
+	"github.com/docker/libnetwork/ipamapi"
20
+	"github.com/docker/libnetwork/netlabel"
21
+	"github.com/docker/libnetwork/options"
22
+	"github.com/docker/libnetwork/osl"
23
+	"github.com/docker/libnetwork/testutils"
24
+	"github.com/docker/libnetwork/types"
25
+	"github.com/opencontainers/runc/libcontainer"
26
+	"github.com/opencontainers/runc/libcontainer/configs"
27
+	"github.com/vishvananda/netlink"
28
+	"github.com/vishvananda/netns"
29
+)
30
+
31
+func TestHost(t *testing.T) {
32
+	sbx1, err := controller.NewSandbox("host_c1",
33
+		libnetwork.OptionHostname("test1"),
34
+		libnetwork.OptionDomainname("docker.io"),
35
+		libnetwork.OptionExtraHost("web", "192.168.0.1"),
36
+		libnetwork.OptionUseDefaultSandbox())
37
+	if err != nil {
38
+		t.Fatal(err)
39
+	}
40
+	defer func() {
41
+		if err := sbx1.Delete(); err != nil {
42
+			t.Fatal(err)
43
+		}
44
+	}()
45
+
46
+	sbx2, err := controller.NewSandbox("host_c2",
47
+		libnetwork.OptionHostname("test2"),
48
+		libnetwork.OptionDomainname("docker.io"),
49
+		libnetwork.OptionExtraHost("web", "192.168.0.1"),
50
+		libnetwork.OptionUseDefaultSandbox())
51
+	if err != nil {
52
+		t.Fatal(err)
53
+	}
54
+	defer func() {
55
+		if err := sbx2.Delete(); err != nil {
56
+			t.Fatal(err)
57
+		}
58
+	}()
59
+
60
+	network, err := createTestNetwork("host", "testhost", options.Generic{}, nil, nil)
61
+	if err != nil {
62
+		t.Fatal(err)
63
+	}
64
+
65
+	ep1, err := network.CreateEndpoint("testep1")
66
+	if err != nil {
67
+		t.Fatal(err)
68
+	}
69
+
70
+	if err := ep1.Join(sbx1); err != nil {
71
+		t.Fatal(err)
72
+	}
73
+
74
+	ep2, err := network.CreateEndpoint("testep2")
75
+	if err != nil {
76
+		t.Fatal(err)
77
+	}
78
+
79
+	if err := ep2.Join(sbx2); err != nil {
80
+		t.Fatal(err)
81
+	}
82
+
83
+	if err := ep1.Leave(sbx1); err != nil {
84
+		t.Fatal(err)
85
+	}
86
+
87
+	if err := ep2.Leave(sbx2); err != nil {
88
+		t.Fatal(err)
89
+	}
90
+
91
+	if err := ep1.Delete(false); err != nil {
92
+		t.Fatal(err)
93
+	}
94
+
95
+	if err := ep2.Delete(false); err != nil {
96
+		t.Fatal(err)
97
+	}
98
+
99
+	// Try to create another host endpoint and join/leave that.
100
+	cnt3, err := controller.NewSandbox("host_c3",
101
+		libnetwork.OptionHostname("test3"),
102
+		libnetwork.OptionDomainname("docker.io"),
103
+		libnetwork.OptionExtraHost("web", "192.168.0.1"),
104
+		libnetwork.OptionUseDefaultSandbox())
105
+	if err != nil {
106
+		t.Fatal(err)
107
+	}
108
+	defer func() {
109
+		if err := cnt3.Delete(); err != nil {
110
+			t.Fatal(err)
111
+		}
112
+	}()
113
+
114
+	ep3, err := network.CreateEndpoint("testep3")
115
+	if err != nil {
116
+		t.Fatal(err)
117
+	}
118
+
119
+	if err := ep3.Join(sbx2); err != nil {
120
+		t.Fatal(err)
121
+	}
122
+
123
+	if err := ep3.Leave(sbx2); err != nil {
124
+		t.Fatal(err)
125
+	}
126
+
127
+	if err := ep3.Delete(false); err != nil {
128
+		t.Fatal(err)
129
+	}
130
+}
131
+
132
+// Testing IPV6 from MAC address
133
+func TestBridgeIpv6FromMac(t *testing.T) {
134
+	if !testutils.IsRunningInContainer() {
135
+		defer testutils.SetupTestOSContext(t)()
136
+	}
137
+
138
+	netOption := options.Generic{
139
+		netlabel.GenericData: options.Generic{
140
+			"BridgeName":         "testipv6mac",
141
+			"EnableICC":          true,
142
+			"EnableIPMasquerade": true,
143
+		},
144
+	}
145
+	ipamV4ConfList := []*libnetwork.IpamConf{{PreferredPool: "192.168.100.0/24", Gateway: "192.168.100.1"}}
146
+	ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}}
147
+
148
+	network, err := controller.NewNetwork(bridgeNetType, "testipv6mac", "",
149
+		libnetwork.NetworkOptionGeneric(netOption),
150
+		libnetwork.NetworkOptionEnableIPv6(true),
151
+		libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", ipamV4ConfList, ipamV6ConfList, nil),
152
+		libnetwork.NetworkOptionDeferIPv6Alloc(true))
153
+	if err != nil {
154
+		t.Fatal(err)
155
+	}
156
+
157
+	mac := net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}
158
+	epOption := options.Generic{netlabel.MacAddress: mac}
159
+
160
+	ep, err := network.CreateEndpoint("testep", libnetwork.EndpointOptionGeneric(epOption))
161
+	if err != nil {
162
+		t.Fatal(err)
163
+	}
164
+
165
+	iface := ep.Info().Iface()
166
+	if !bytes.Equal(iface.MacAddress(), mac) {
167
+		t.Fatalf("Unexpected mac address: %v", iface.MacAddress())
168
+	}
169
+
170
+	ip, expIP, _ := net.ParseCIDR("fe90::aabb:ccdd:eeff/64")
171
+	expIP.IP = ip
172
+	if !types.CompareIPNet(expIP, iface.AddressIPv6()) {
173
+		t.Fatalf("Expected %v. Got: %v", expIP, iface.AddressIPv6())
174
+	}
175
+
176
+	if err := ep.Delete(false); err != nil {
177
+		t.Fatal(err)
178
+	}
179
+
180
+	if err := network.Delete(); err != nil {
181
+		t.Fatal(err)
182
+	}
183
+}
184
+
185
+func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) {
186
+	key := info.Sandbox().Key()
187
+	sbNs, err := netns.GetFromPath(key)
188
+	if err != nil {
189
+		t.Fatalf("Failed to get network namespace path %q: %v", key, err)
190
+	}
191
+	defer sbNs.Close()
192
+
193
+	nh, err := netlink.NewHandleAt(sbNs)
194
+	if err != nil {
195
+		t.Fatal(err)
196
+	}
197
+
198
+	_, err = nh.LinkByName("eth0")
199
+	if err != nil {
200
+		t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err)
201
+	}
202
+
203
+	_, err = nh.LinkByName("eth1")
204
+	if err != nil {
205
+		t.Fatalf("Could not find the interface eth1 inside the sandbox: %v", err)
206
+	}
207
+}
208
+
209
+func TestEndpointJoin(t *testing.T) {
210
+	if !testutils.IsRunningInContainer() {
211
+		defer testutils.SetupTestOSContext(t)()
212
+	}
213
+
214
+	// Create network 1 and add 2 endpoint: ep11, ep12
215
+	netOption := options.Generic{
216
+		netlabel.GenericData: options.Generic{
217
+			"BridgeName":         "testnetwork1",
218
+			"EnableICC":          true,
219
+			"EnableIPMasquerade": true,
220
+		},
221
+	}
222
+	ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}}
223
+	n1, err := controller.NewNetwork(bridgeNetType, "testnetwork1", "",
224
+		libnetwork.NetworkOptionGeneric(netOption),
225
+		libnetwork.NetworkOptionEnableIPv6(true),
226
+		libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", nil, ipamV6ConfList, nil),
227
+		libnetwork.NetworkOptionDeferIPv6Alloc(true))
228
+	if err != nil {
229
+		t.Fatal(err)
230
+	}
231
+	defer func() {
232
+		if err := n1.Delete(); err != nil {
233
+			t.Fatal(err)
234
+		}
235
+	}()
236
+
237
+	ep1, err := n1.CreateEndpoint("ep1")
238
+	if err != nil {
239
+		t.Fatal(err)
240
+	}
241
+	defer func() {
242
+		if err := ep1.Delete(false); err != nil {
243
+			t.Fatal(err)
244
+		}
245
+	}()
246
+
247
+	// Validate if ep.Info() only gives me IP address info and not names and gateway during CreateEndpoint()
248
+	info := ep1.Info()
249
+	iface := info.Iface()
250
+	if iface.Address() != nil && iface.Address().IP.To4() == nil {
251
+		t.Fatalf("Invalid IP address returned: %v", iface.Address())
252
+	}
253
+	if iface.AddressIPv6() != nil && iface.AddressIPv6().IP == nil {
254
+		t.Fatalf("Invalid IPv6 address returned: %v", iface.Address())
255
+	}
256
+
257
+	if len(info.Gateway()) != 0 {
258
+		t.Fatalf("Expected empty gateway for an empty endpoint. Instead found a gateway: %v", info.Gateway())
259
+	}
260
+	if len(info.GatewayIPv6()) != 0 {
261
+		t.Fatalf("Expected empty gateway for an empty ipv6 endpoint. Instead found a gateway: %v", info.GatewayIPv6())
262
+	}
263
+
264
+	if info.Sandbox() != nil {
265
+		t.Fatalf("Expected an empty sandbox key for an empty endpoint. Instead found a non-empty sandbox key: %s", info.Sandbox().Key())
266
+	}
267
+
268
+	// test invalid joins
269
+	err = ep1.Join(nil)
270
+	if err == nil {
271
+		t.Fatalf("Expected to fail join with nil Sandbox")
272
+	}
273
+	if _, ok := err.(types.BadRequestError); !ok {
274
+		t.Fatalf("Unexpected error type returned: %T", err)
275
+	}
276
+
277
+	fsbx := &fakeSandbox{}
278
+	if err = ep1.Join(fsbx); err == nil {
279
+		t.Fatalf("Expected to fail join with invalid Sandbox")
280
+	}
281
+	if _, ok := err.(types.BadRequestError); !ok {
282
+		t.Fatalf("Unexpected error type returned: %T", err)
283
+	}
284
+
285
+	sb, err := controller.NewSandbox(containerID,
286
+		libnetwork.OptionHostname("test"),
287
+		libnetwork.OptionDomainname("docker.io"),
288
+		libnetwork.OptionExtraHost("web", "192.168.0.1"))
289
+	if err != nil {
290
+		t.Fatal(err)
291
+	}
292
+
293
+	defer func() {
294
+		if err := sb.Delete(); err != nil {
295
+			t.Fatal(err)
296
+		}
297
+	}()
298
+
299
+	err = ep1.Join(sb)
300
+	if err != nil {
301
+		t.Fatal(err)
302
+	}
303
+	defer func() {
304
+		err = ep1.Leave(sb)
305
+		if err != nil {
306
+			t.Fatal(err)
307
+		}
308
+	}()
309
+
310
+	// Validate if ep.Info() only gives valid gateway and sandbox key after has container has joined.
311
+	info = ep1.Info()
312
+	if len(info.Gateway()) == 0 {
313
+		t.Fatalf("Expected a valid gateway for a joined endpoint. Instead found an invalid gateway: %v", info.Gateway())
314
+	}
315
+	if len(info.GatewayIPv6()) == 0 {
316
+		t.Fatalf("Expected a valid ipv6 gateway for a joined endpoint. Instead found an invalid gateway: %v", info.GatewayIPv6())
317
+	}
318
+
319
+	if info.Sandbox() == nil {
320
+		t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key")
321
+	}
322
+
323
+	// Check endpoint provided container information
324
+	if ep1.Info().Sandbox().Key() != sb.Key() {
325
+		t.Fatalf("Endpoint Info returned unexpected sandbox key: %s", sb.Key())
326
+	}
327
+
328
+	// Attempt retrieval of endpoint interfaces statistics
329
+	stats, err := sb.Statistics()
330
+	if err != nil {
331
+		t.Fatal(err)
332
+	}
333
+	if _, ok := stats["eth0"]; !ok {
334
+		t.Fatalf("Did not find eth0 statistics")
335
+	}
336
+
337
+	// Now test the container joining another network
338
+	n2, err := createTestNetwork(bridgeNetType, "testnetwork2",
339
+		options.Generic{
340
+			netlabel.GenericData: options.Generic{
341
+				"BridgeName": "testnetwork2",
342
+			},
343
+		}, nil, nil)
344
+	if err != nil {
345
+		t.Fatal(err)
346
+	}
347
+	defer func() {
348
+		if err := n2.Delete(); err != nil {
349
+			t.Fatal(err)
350
+		}
351
+	}()
352
+
353
+	ep2, err := n2.CreateEndpoint("ep2")
354
+	if err != nil {
355
+		t.Fatal(err)
356
+	}
357
+	defer func() {
358
+		if err := ep2.Delete(false); err != nil {
359
+			t.Fatal(err)
360
+		}
361
+	}()
362
+
363
+	err = ep2.Join(sb)
364
+	if err != nil {
365
+		t.Fatal(err)
366
+	}
367
+	defer func() {
368
+		err = ep2.Leave(sb)
369
+		if err != nil {
370
+			t.Fatal(err)
371
+		}
372
+	}()
373
+
374
+	if ep1.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
375
+		t.Fatalf("ep1 and ep2 returned different container sandbox key")
376
+	}
377
+
378
+	checkSandbox(t, info)
379
+}
380
+
381
+func TestExternalKey(t *testing.T) {
382
+	externalKeyTest(t, false)
383
+}
384
+
385
+func externalKeyTest(t *testing.T, reexec bool) {
386
+	if !testutils.IsRunningInContainer() {
387
+		defer testutils.SetupTestOSContext(t)()
388
+	}
389
+
390
+	n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{
391
+		netlabel.GenericData: options.Generic{
392
+			"BridgeName": "testnetwork",
393
+		},
394
+	}, nil, nil)
395
+	if err != nil {
396
+		t.Fatal(err)
397
+	}
398
+	defer func() {
399
+		if err := n.Delete(); err != nil {
400
+			t.Fatal(err)
401
+		}
402
+	}()
403
+
404
+	ep, err := n.CreateEndpoint("ep1")
405
+	if err != nil {
406
+		t.Fatal(err)
407
+	}
408
+	defer func() {
409
+		err = ep.Delete(false)
410
+		if err != nil {
411
+			t.Fatal(err)
412
+		}
413
+	}()
414
+
415
+	ep2, err := n.CreateEndpoint("ep2")
416
+	if err != nil {
417
+		t.Fatal(err)
418
+	}
419
+	defer func() {
420
+		err = ep2.Delete(false)
421
+		if err != nil {
422
+			t.Fatal(err)
423
+		}
424
+	}()
425
+
426
+	cnt, err := controller.NewSandbox(containerID,
427
+		libnetwork.OptionHostname("test"),
428
+		libnetwork.OptionDomainname("docker.io"),
429
+		libnetwork.OptionUseExternalKey(),
430
+		libnetwork.OptionExtraHost("web", "192.168.0.1"))
431
+	defer func() {
432
+		if err := cnt.Delete(); err != nil {
433
+			t.Fatal(err)
434
+		}
435
+		osl.GC()
436
+	}()
437
+
438
+	// Join endpoint to sandbox before SetKey
439
+	err = ep.Join(cnt)
440
+	if err != nil {
441
+		t.Fatal(err)
442
+	}
443
+	defer func() {
444
+		err = ep.Leave(cnt)
445
+		if err != nil {
446
+			t.Fatal(err)
447
+		}
448
+	}()
449
+
450
+	sbox := ep.Info().Sandbox()
451
+	if sbox == nil {
452
+		t.Fatalf("Expected to have a valid Sandbox")
453
+	}
454
+
455
+	if reexec {
456
+		err := reexecSetKey("this-must-fail", containerID, controller.ID())
457
+		if err == nil {
458
+			t.Fatalf("SetExternalKey must fail if the corresponding namespace is not created")
459
+		}
460
+	} else {
461
+		// Setting an non-existing key (namespace) must fail
462
+		if err := sbox.SetKey("this-must-fail"); err == nil {
463
+			t.Fatalf("Setkey must fail if the corresponding namespace is not created")
464
+		}
465
+	}
466
+
467
+	// Create a new OS sandbox using the osl API before using it in SetKey
468
+	if extOsBox, err := osl.NewSandbox("ValidKey", true, false); err != nil {
469
+		t.Fatalf("Failed to create new osl sandbox")
470
+	} else {
471
+		defer func() {
472
+			if err := extOsBox.Destroy(); err != nil {
473
+				log.Warnf("Failed to remove os sandbox: %v", err)
474
+			}
475
+		}()
476
+	}
477
+
478
+	if reexec {
479
+		err := reexecSetKey("ValidKey", containerID, controller.ID())
480
+		if err != nil {
481
+			t.Fatalf("SetExternalKey failed with %v", err)
482
+		}
483
+	} else {
484
+		if err := sbox.SetKey("ValidKey"); err != nil {
485
+			t.Fatalf("Setkey failed with %v", err)
486
+		}
487
+	}
488
+
489
+	// Join endpoint to sandbox after SetKey
490
+	err = ep2.Join(sbox)
491
+	if err != nil {
492
+		t.Fatal(err)
493
+	}
494
+	defer func() {
495
+		err = ep2.Leave(sbox)
496
+		if err != nil {
497
+			t.Fatal(err)
498
+		}
499
+	}()
500
+
501
+	if ep.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
502
+		t.Fatalf("ep1 and ep2 returned different container sandbox key")
503
+	}
504
+
505
+	checkSandbox(t, ep.Info())
506
+}
507
+
508
+func reexecSetKey(key string, containerID string, controllerID string) error {
509
+	var (
510
+		state libcontainer.State
511
+		b     []byte
512
+		err   error
513
+	)
514
+
515
+	state.NamespacePaths = make(map[configs.NamespaceType]string)
516
+	state.NamespacePaths[configs.NamespaceType("NEWNET")] = key
517
+	if b, err = json.Marshal(state); err != nil {
518
+		return err
519
+	}
520
+	cmd := &exec.Cmd{
521
+		Path:   reexec.Self(),
522
+		Args:   append([]string{"libnetwork-setkey"}, containerID, controllerID),
523
+		Stdin:  strings.NewReader(string(b)),
524
+		Stdout: os.Stdout,
525
+		Stderr: os.Stderr,
526
+	}
527
+	return cmd.Run()
528
+}
529
+
530
+func TestEnableIPv6(t *testing.T) {
531
+	if !testutils.IsRunningInContainer() {
532
+		defer testutils.SetupTestOSContext(t)()
533
+	}
534
+
535
+	tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
536
+	expectedResolvConf := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\nnameserver 2001:4860:4860::8888\noptions ndots:0\n")
537
+	//take a copy of resolv.conf for restoring after test completes
538
+	resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
539
+	if err != nil {
540
+		t.Fatal(err)
541
+	}
542
+	//cleanup
543
+	defer func() {
544
+		if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
545
+			t.Fatal(err)
546
+		}
547
+	}()
548
+
549
+	netOption := options.Generic{
550
+		netlabel.EnableIPv6: true,
551
+		netlabel.GenericData: options.Generic{
552
+			"BridgeName": "testnetwork",
553
+		},
554
+	}
555
+	ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe99::/64", Gateway: "fe99::9"}}
556
+
557
+	n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, ipamV6ConfList)
558
+	if err != nil {
559
+		t.Fatal(err)
560
+	}
561
+	defer func() {
562
+		if err := n.Delete(); err != nil {
563
+			t.Fatal(err)
564
+		}
565
+	}()
566
+
567
+	ep1, err := n.CreateEndpoint("ep1")
568
+	if err != nil {
569
+		t.Fatal(err)
570
+	}
571
+
572
+	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
573
+		t.Fatal(err)
574
+	}
575
+
576
+	resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
577
+	defer os.Remove(resolvConfPath)
578
+
579
+	sb, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath))
580
+	if err != nil {
581
+		t.Fatal(err)
582
+	}
583
+	defer func() {
584
+		if err := sb.Delete(); err != nil {
585
+			t.Fatal(err)
586
+		}
587
+	}()
588
+
589
+	err = ep1.Join(sb)
590
+	if err != nil {
591
+		t.Fatal(err)
592
+	}
593
+
594
+	content, err := ioutil.ReadFile(resolvConfPath)
595
+	if err != nil {
596
+		t.Fatal(err)
597
+	}
598
+
599
+	if !bytes.Equal(content, expectedResolvConf) {
600
+		t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf), string(content))
601
+	}
602
+
603
+	if err != nil {
604
+		t.Fatal(err)
605
+	}
606
+}
607
+
608
+func TestResolvConfHost(t *testing.T) {
609
+	if !testutils.IsRunningInContainer() {
610
+		defer testutils.SetupTestOSContext(t)()
611
+	}
612
+
613
+	tmpResolvConf := []byte("search localhost.net\nnameserver 127.0.0.1\nnameserver 2001:4860:4860::8888\n")
614
+
615
+	//take a copy of resolv.conf for restoring after test completes
616
+	resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
617
+	if err != nil {
618
+		t.Fatal(err)
619
+	}
620
+	//cleanup
621
+	defer func() {
622
+		if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
623
+			t.Fatal(err)
624
+		}
625
+	}()
626
+
627
+	n, err := controller.NetworkByName("testhost")
628
+	if err != nil {
629
+		t.Fatal(err)
630
+	}
631
+
632
+	ep1, err := n.CreateEndpoint("ep1", libnetwork.CreateOptionDisableResolution())
633
+	if err != nil {
634
+		t.Fatal(err)
635
+	}
636
+
637
+	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
638
+		t.Fatal(err)
639
+	}
640
+
641
+	resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
642
+	defer os.Remove(resolvConfPath)
643
+
644
+	sb, err := controller.NewSandbox(containerID,
645
+		libnetwork.OptionResolvConfPath(resolvConfPath),
646
+		libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
647
+	if err != nil {
648
+		t.Fatal(err)
649
+	}
650
+	defer func() {
651
+		if err := sb.Delete(); err != nil {
652
+			t.Fatal(err)
653
+		}
654
+	}()
655
+
656
+	err = ep1.Join(sb)
657
+	if err != nil {
658
+		t.Fatal(err)
659
+	}
660
+	defer func() {
661
+		err = ep1.Leave(sb)
662
+		if err != nil {
663
+			t.Fatal(err)
664
+		}
665
+	}()
666
+
667
+	finfo, err := os.Stat(resolvConfPath)
668
+	if err != nil {
669
+		t.Fatal(err)
670
+	}
671
+
672
+	fmode := (os.FileMode)(0644)
673
+	if finfo.Mode() != fmode {
674
+		t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String())
675
+	}
676
+
677
+	content, err := ioutil.ReadFile(resolvConfPath)
678
+	if err != nil {
679
+		t.Fatal(err)
680
+	}
681
+
682
+	if !bytes.Equal(content, tmpResolvConf) {
683
+		t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf), string(content))
684
+	}
685
+}
686
+
687
+func TestResolvConf(t *testing.T) {
688
+	if !testutils.IsRunningInContainer() {
689
+		defer testutils.SetupTestOSContext(t)()
690
+	}
691
+
692
+	tmpResolvConf1 := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
693
+	tmpResolvConf2 := []byte("search pommesfrites.fr\nnameserver 112.34.56.78\nnameserver 2001:4860:4860::8888\n")
694
+	expectedResolvConf1 := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\noptions ndots:0\n")
695
+	tmpResolvConf3 := []byte("search pommesfrites.fr\nnameserver 113.34.56.78\n")
696
+
697
+	//take a copy of resolv.conf for restoring after test completes
698
+	resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
699
+	if err != nil {
700
+		t.Fatal(err)
701
+	}
702
+	//cleanup
703
+	defer func() {
704
+		if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
705
+			t.Fatal(err)
706
+		}
707
+	}()
708
+
709
+	netOption := options.Generic{
710
+		netlabel.GenericData: options.Generic{
711
+			"BridgeName": "testnetwork",
712
+		},
713
+	}
714
+	n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, nil)
715
+	if err != nil {
716
+		t.Fatal(err)
717
+	}
718
+	defer func() {
719
+		if err := n.Delete(); err != nil {
720
+			t.Fatal(err)
721
+		}
722
+	}()
723
+
724
+	ep, err := n.CreateEndpoint("ep")
725
+	if err != nil {
726
+		t.Fatal(err)
727
+	}
728
+
729
+	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf1, 0644); err != nil {
730
+		t.Fatal(err)
731
+	}
732
+
733
+	resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
734
+	defer os.Remove(resolvConfPath)
735
+
736
+	sb1, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath))
737
+	if err != nil {
738
+		t.Fatal(err)
739
+	}
740
+	defer func() {
741
+		if err := sb1.Delete(); err != nil {
742
+			t.Fatal(err)
743
+		}
744
+	}()
745
+
746
+	err = ep.Join(sb1)
747
+	if err != nil {
748
+		t.Fatal(err)
749
+	}
750
+
751
+	finfo, err := os.Stat(resolvConfPath)
752
+	if err != nil {
753
+		t.Fatal(err)
754
+	}
755
+
756
+	fmode := (os.FileMode)(0644)
757
+	if finfo.Mode() != fmode {
758
+		t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String())
759
+	}
760
+
761
+	content, err := ioutil.ReadFile(resolvConfPath)
762
+	if err != nil {
763
+		t.Fatal(err)
764
+	}
765
+
766
+	if !bytes.Equal(content, expectedResolvConf1) {
767
+		fmt.Printf("\n%v\n%v\n", expectedResolvConf1, content)
768
+		t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content))
769
+	}
770
+
771
+	err = ep.Leave(sb1)
772
+	if err != nil {
773
+		t.Fatal(err)
774
+	}
775
+
776
+	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf2, 0644); err != nil {
777
+		t.Fatal(err)
778
+	}
779
+
780
+	sb2, err := controller.NewSandbox(containerID+"_2", libnetwork.OptionResolvConfPath(resolvConfPath))
781
+	if err != nil {
782
+		t.Fatal(err)
783
+	}
784
+	defer func() {
785
+		if err := sb2.Delete(); err != nil {
786
+			t.Fatal(err)
787
+		}
788
+	}()
789
+
790
+	err = ep.Join(sb2)
791
+	if err != nil {
792
+		t.Fatal(err)
793
+	}
794
+
795
+	content, err = ioutil.ReadFile(resolvConfPath)
796
+	if err != nil {
797
+		t.Fatal(err)
798
+	}
799
+
800
+	if !bytes.Equal(content, expectedResolvConf1) {
801
+		t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content))
802
+	}
803
+
804
+	if err := ioutil.WriteFile(resolvConfPath, tmpResolvConf3, 0644); err != nil {
805
+		t.Fatal(err)
806
+	}
807
+
808
+	err = ep.Leave(sb2)
809
+	if err != nil {
810
+		t.Fatal(err)
811
+	}
812
+
813
+	err = ep.Join(sb2)
814
+	if err != nil {
815
+		t.Fatal(err)
816
+	}
817
+
818
+	content, err = ioutil.ReadFile(resolvConfPath)
819
+	if err != nil {
820
+		t.Fatal(err)
821
+	}
822
+
823
+	if !bytes.Equal(content, tmpResolvConf3) {
824
+		t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf3), string(content))
825
+	}
826
+}
827
+
828
+func parallelJoin(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) {
829
+	debugf("J%d.", thrNumber)
830
+	var err error
831
+
832
+	sb := sboxes[thrNumber-1]
833
+	err = ep.Join(sb)
834
+
835
+	runtime.LockOSThread()
836
+	if err != nil {
837
+		if _, ok := err.(types.ForbiddenError); !ok {
838
+			t.Fatalf("thread %d: %v", thrNumber, err)
839
+		}
840
+		debugf("JE%d(%v).", thrNumber, err)
841
+	}
842
+	debugf("JD%d.", thrNumber)
843
+}
844
+
845
+func parallelLeave(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) {
846
+	debugf("L%d.", thrNumber)
847
+	var err error
848
+
849
+	sb := sboxes[thrNumber-1]
850
+
851
+	err = ep.Leave(sb)
852
+	runtime.LockOSThread()
853
+	if err != nil {
854
+		if _, ok := err.(types.ForbiddenError); !ok {
855
+			t.Fatalf("thread %d: %v", thrNumber, err)
856
+		}
857
+		debugf("LE%d(%v).", thrNumber, err)
858
+	}
859
+	debugf("LD%d.", thrNumber)
860
+}
861
+
862
+func runParallelTests(t *testing.T, thrNumber int) {
863
+	var (
864
+		ep  libnetwork.Endpoint
865
+		sb  libnetwork.Sandbox
866
+		err error
867
+	)
868
+
869
+	t.Parallel()
870
+
871
+	pTest := flag.Lookup("test.parallel")
872
+	if pTest == nil {
873
+		t.Skip("Skipped because test.parallel flag not set;")
874
+	}
875
+	numParallel, err := strconv.Atoi(pTest.Value.String())
876
+	if err != nil {
877
+		t.Fatal(err)
878
+	}
879
+	if numParallel < numThreads {
880
+		t.Skip("Skipped because t.parallel was less than ", numThreads)
881
+	}
882
+
883
+	runtime.LockOSThread()
884
+	defer runtime.UnlockOSThread()
885
+
886
+	if thrNumber == first {
887
+		createGlobalInstance(t)
888
+	}
889
+
890
+	if thrNumber != first {
891
+		select {
892
+		case <-start:
893
+		}
894
+
895
+		thrdone := make(chan struct{})
896
+		done <- thrdone
897
+		defer close(thrdone)
898
+
899
+		if thrNumber == last {
900
+			defer close(done)
901
+		}
902
+
903
+		err = netns.Set(testns)
904
+		if err != nil {
905
+			t.Fatal(err)
906
+		}
907
+	}
908
+	defer netns.Set(origns)
909
+
910
+	net1, err := controller.NetworkByName("testhost")
911
+	if err != nil {
912
+		t.Fatal(err)
913
+	}
914
+	if net1 == nil {
915
+		t.Fatal("Could not find testhost")
916
+	}
917
+
918
+	net2, err := controller.NetworkByName("network2")
919
+	if err != nil {
920
+		t.Fatal(err)
921
+	}
922
+	if net2 == nil {
923
+		t.Fatal("Could not find network2")
924
+	}
925
+
926
+	epName := fmt.Sprintf("pep%d", thrNumber)
927
+
928
+	if thrNumber == first {
929
+		ep, err = net1.EndpointByName(epName)
930
+	} else {
931
+		ep, err = net2.EndpointByName(epName)
932
+	}
933
+
934
+	if err != nil {
935
+		t.Fatal(err)
936
+	}
937
+	if ep == nil {
938
+		t.Fatal("Got nil ep with no error")
939
+	}
940
+
941
+	cid := fmt.Sprintf("%drace", thrNumber)
942
+	controller.WalkSandboxes(libnetwork.SandboxContainerWalker(&sb, cid))
943
+	if sb == nil {
944
+		t.Fatalf("Got nil sandbox for container: %s", cid)
945
+	}
946
+
947
+	for i := 0; i < iterCnt; i++ {
948
+		parallelJoin(t, sb, ep, thrNumber)
949
+		parallelLeave(t, sb, ep, thrNumber)
950
+	}
951
+
952
+	debugf("\n")
953
+
954
+	err = sb.Delete()
955
+	if err != nil {
956
+		t.Fatal(err)
957
+	}
958
+	if thrNumber == first {
959
+		for thrdone := range done {
960
+			select {
961
+			case <-thrdone:
962
+			}
963
+		}
964
+
965
+		testns.Close()
966
+		if err := net2.Delete(); err != nil {
967
+			t.Fatal(err)
968
+		}
969
+	} else {
970
+		err = ep.Delete(false)
971
+		if err != nil {
972
+			t.Fatal(err)
973
+		}
974
+	}
975
+}
976
+
977
+func TestParallel1(t *testing.T) {
978
+	runParallelTests(t, 1)
979
+}
980
+
981
+func TestParallel2(t *testing.T) {
982
+	runParallelTests(t, 2)
983
+}
984
+
985
+func TestParallel3(t *testing.T) {
986
+	runParallelTests(t, 3)
987
+}
988
+
989
+func TestNullIpam(t *testing.T) {
990
+	_, err := controller.NewNetwork(bridgeNetType, "testnetworkinternal", "", libnetwork.NetworkOptionIpam(ipamapi.NullIPAM, "", nil, nil, nil))
991
+	if err == nil || err.Error() != "ipv4 pool is empty" {
992
+		t.Fatal("bridge network should complain empty pool")
993
+	}
994
+}
... ...
@@ -1,19 +1,12 @@
1 1
 package libnetwork_test
2 2
 
3 3
 import (
4
-	"bytes"
5
-	"encoding/json"
6
-	"flag"
7 4
 	"fmt"
8 5
 	"io/ioutil"
9 6
 	"net"
10 7
 	"net/http"
11 8
 	"net/http/httptest"
12 9
 	"os"
13
-	"os/exec"
14
-	"runtime"
15
-	"strconv"
16
-	"strings"
17 10
 	"sync"
18 11
 	"testing"
19 12
 
... ...
@@ -27,12 +20,8 @@ import (
27 27
 	"github.com/docker/libnetwork/ipamapi"
28 28
 	"github.com/docker/libnetwork/netlabel"
29 29
 	"github.com/docker/libnetwork/options"
30
-	"github.com/docker/libnetwork/osl"
31 30
 	"github.com/docker/libnetwork/testutils"
32 31
 	"github.com/docker/libnetwork/types"
33
-	"github.com/opencontainers/runc/libcontainer"
34
-	"github.com/opencontainers/runc/libcontainer/configs"
35
-	"github.com/vishvananda/netlink"
36 32
 	"github.com/vishvananda/netns"
37 33
 )
38 34
 
... ...
@@ -151,107 +140,6 @@ func TestNull(t *testing.T) {
151 151
 	}
152 152
 }
153 153
 
154
-func TestHost(t *testing.T) {
155
-	sbx1, err := controller.NewSandbox("host_c1",
156
-		libnetwork.OptionHostname("test1"),
157
-		libnetwork.OptionDomainname("docker.io"),
158
-		libnetwork.OptionExtraHost("web", "192.168.0.1"),
159
-		libnetwork.OptionUseDefaultSandbox())
160
-	if err != nil {
161
-		t.Fatal(err)
162
-	}
163
-	defer func() {
164
-		if err := sbx1.Delete(); err != nil {
165
-			t.Fatal(err)
166
-		}
167
-	}()
168
-
169
-	sbx2, err := controller.NewSandbox("host_c2",
170
-		libnetwork.OptionHostname("test2"),
171
-		libnetwork.OptionDomainname("docker.io"),
172
-		libnetwork.OptionExtraHost("web", "192.168.0.1"),
173
-		libnetwork.OptionUseDefaultSandbox())
174
-	if err != nil {
175
-		t.Fatal(err)
176
-	}
177
-	defer func() {
178
-		if err := sbx2.Delete(); err != nil {
179
-			t.Fatal(err)
180
-		}
181
-	}()
182
-
183
-	network, err := createTestNetwork("host", "testhost", options.Generic{}, nil, nil)
184
-	if err != nil {
185
-		t.Fatal(err)
186
-	}
187
-
188
-	ep1, err := network.CreateEndpoint("testep1")
189
-	if err != nil {
190
-		t.Fatal(err)
191
-	}
192
-
193
-	if err := ep1.Join(sbx1); err != nil {
194
-		t.Fatal(err)
195
-	}
196
-
197
-	ep2, err := network.CreateEndpoint("testep2")
198
-	if err != nil {
199
-		t.Fatal(err)
200
-	}
201
-
202
-	if err := ep2.Join(sbx2); err != nil {
203
-		t.Fatal(err)
204
-	}
205
-
206
-	if err := ep1.Leave(sbx1); err != nil {
207
-		t.Fatal(err)
208
-	}
209
-
210
-	if err := ep2.Leave(sbx2); err != nil {
211
-		t.Fatal(err)
212
-	}
213
-
214
-	if err := ep1.Delete(false); err != nil {
215
-		t.Fatal(err)
216
-	}
217
-
218
-	if err := ep2.Delete(false); err != nil {
219
-		t.Fatal(err)
220
-	}
221
-
222
-	// Try to create another host endpoint and join/leave that.
223
-	cnt3, err := controller.NewSandbox("host_c3",
224
-		libnetwork.OptionHostname("test3"),
225
-		libnetwork.OptionDomainname("docker.io"),
226
-		libnetwork.OptionExtraHost("web", "192.168.0.1"),
227
-		libnetwork.OptionUseDefaultSandbox())
228
-	if err != nil {
229
-		t.Fatal(err)
230
-	}
231
-	defer func() {
232
-		if err := cnt3.Delete(); err != nil {
233
-			t.Fatal(err)
234
-		}
235
-	}()
236
-
237
-	ep3, err := network.CreateEndpoint("testep3")
238
-	if err != nil {
239
-		t.Fatal(err)
240
-	}
241
-
242
-	if err := ep3.Join(sbx2); err != nil {
243
-		t.Fatal(err)
244
-	}
245
-
246
-	if err := ep3.Leave(sbx2); err != nil {
247
-		t.Fatal(err)
248
-	}
249
-
250
-	if err := ep3.Delete(false); err != nil {
251
-		t.Fatal(err)
252
-	}
253
-}
254
-
255 154
 func TestBridge(t *testing.T) {
256 155
 	if !testutils.IsRunningInContainer() {
257 156
 		defer testutils.SetupTestOSContext(t)()
... ...
@@ -315,59 +203,6 @@ func TestBridge(t *testing.T) {
315 315
 	}
316 316
 }
317 317
 
318
-// Testing IPV6 from MAC address
319
-func TestBridgeIpv6FromMac(t *testing.T) {
320
-	if !testutils.IsRunningInContainer() {
321
-		defer testutils.SetupTestOSContext(t)()
322
-	}
323
-
324
-	netOption := options.Generic{
325
-		netlabel.GenericData: options.Generic{
326
-			"BridgeName":         "testipv6mac",
327
-			"EnableICC":          true,
328
-			"EnableIPMasquerade": true,
329
-		},
330
-	}
331
-	ipamV4ConfList := []*libnetwork.IpamConf{{PreferredPool: "192.168.100.0/24", Gateway: "192.168.100.1"}}
332
-	ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}}
333
-
334
-	network, err := controller.NewNetwork(bridgeNetType, "testipv6mac", "",
335
-		libnetwork.NetworkOptionGeneric(netOption),
336
-		libnetwork.NetworkOptionEnableIPv6(true),
337
-		libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", ipamV4ConfList, ipamV6ConfList, nil),
338
-		libnetwork.NetworkOptionDeferIPv6Alloc(true))
339
-	if err != nil {
340
-		t.Fatal(err)
341
-	}
342
-
343
-	mac := net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}
344
-	epOption := options.Generic{netlabel.MacAddress: mac}
345
-
346
-	ep, err := network.CreateEndpoint("testep", libnetwork.EndpointOptionGeneric(epOption))
347
-	if err != nil {
348
-		t.Fatal(err)
349
-	}
350
-
351
-	iface := ep.Info().Iface()
352
-	if !bytes.Equal(iface.MacAddress(), mac) {
353
-		t.Fatalf("Unexpected mac address: %v", iface.MacAddress())
354
-	}
355
-
356
-	ip, expIP, _ := net.ParseCIDR("fe90::aabb:ccdd:eeff/64")
357
-	expIP.IP = ip
358
-	if !types.CompareIPNet(expIP, iface.AddressIPv6()) {
359
-		t.Fatalf("Expected %v. Got: %v", expIP, iface.AddressIPv6())
360
-	}
361
-
362
-	if err := ep.Delete(false); err != nil {
363
-		t.Fatal(err)
364
-	}
365
-
366
-	if err := network.Delete(); err != nil {
367
-		t.Fatal(err)
368
-	}
369
-}
370
-
371 318
 func TestUnknownDriver(t *testing.T) {
372 319
 	if !testutils.IsRunningInContainer() {
373 320
 		defer testutils.SetupTestOSContext(t)()
... ...
@@ -966,202 +801,6 @@ func TestNetworkQuery(t *testing.T) {
966 966
 
967 967
 const containerID = "valid_c"
968 968
 
969
-func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) {
970
-	key := info.Sandbox().Key()
971
-	sbNs, err := netns.GetFromPath(key)
972
-	if err != nil {
973
-		t.Fatalf("Failed to get network namespace path %q: %v", key, err)
974
-	}
975
-	defer sbNs.Close()
976
-
977
-	nh, err := netlink.NewHandleAt(sbNs)
978
-	if err != nil {
979
-		t.Fatal(err)
980
-	}
981
-
982
-	_, err = nh.LinkByName("eth0")
983
-	if err != nil {
984
-		t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err)
985
-	}
986
-
987
-	_, err = nh.LinkByName("eth1")
988
-	if err != nil {
989
-		t.Fatalf("Could not find the interface eth1 inside the sandbox: %v", err)
990
-	}
991
-}
992
-
993
-func TestEndpointJoin(t *testing.T) {
994
-	if !testutils.IsRunningInContainer() {
995
-		defer testutils.SetupTestOSContext(t)()
996
-	}
997
-
998
-	// Create network 1 and add 2 endpoint: ep11, ep12
999
-	netOption := options.Generic{
1000
-		netlabel.GenericData: options.Generic{
1001
-			"BridgeName":         "testnetwork1",
1002
-			"EnableICC":          true,
1003
-			"EnableIPMasquerade": true,
1004
-		},
1005
-	}
1006
-	ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}}
1007
-	n1, err := controller.NewNetwork(bridgeNetType, "testnetwork1", "",
1008
-		libnetwork.NetworkOptionGeneric(netOption),
1009
-		libnetwork.NetworkOptionEnableIPv6(true),
1010
-		libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", nil, ipamV6ConfList, nil),
1011
-		libnetwork.NetworkOptionDeferIPv6Alloc(true))
1012
-	if err != nil {
1013
-		t.Fatal(err)
1014
-	}
1015
-	defer func() {
1016
-		if err := n1.Delete(); err != nil {
1017
-			t.Fatal(err)
1018
-		}
1019
-	}()
1020
-
1021
-	ep1, err := n1.CreateEndpoint("ep1")
1022
-	if err != nil {
1023
-		t.Fatal(err)
1024
-	}
1025
-	defer func() {
1026
-		if err := ep1.Delete(false); err != nil {
1027
-			t.Fatal(err)
1028
-		}
1029
-	}()
1030
-
1031
-	// Validate if ep.Info() only gives me IP address info and not names and gateway during CreateEndpoint()
1032
-	info := ep1.Info()
1033
-	iface := info.Iface()
1034
-	if iface.Address() != nil && iface.Address().IP.To4() == nil {
1035
-		t.Fatalf("Invalid IP address returned: %v", iface.Address())
1036
-	}
1037
-	if iface.AddressIPv6() != nil && iface.AddressIPv6().IP == nil {
1038
-		t.Fatalf("Invalid IPv6 address returned: %v", iface.Address())
1039
-	}
1040
-
1041
-	if len(info.Gateway()) != 0 {
1042
-		t.Fatalf("Expected empty gateway for an empty endpoint. Instead found a gateway: %v", info.Gateway())
1043
-	}
1044
-	if len(info.GatewayIPv6()) != 0 {
1045
-		t.Fatalf("Expected empty gateway for an empty ipv6 endpoint. Instead found a gateway: %v", info.GatewayIPv6())
1046
-	}
1047
-
1048
-	if info.Sandbox() != nil {
1049
-		t.Fatalf("Expected an empty sandbox key for an empty endpoint. Instead found a non-empty sandbox key: %s", info.Sandbox().Key())
1050
-	}
1051
-
1052
-	// test invalid joins
1053
-	err = ep1.Join(nil)
1054
-	if err == nil {
1055
-		t.Fatalf("Expected to fail join with nil Sandbox")
1056
-	}
1057
-	if _, ok := err.(types.BadRequestError); !ok {
1058
-		t.Fatalf("Unexpected error type returned: %T", err)
1059
-	}
1060
-
1061
-	fsbx := &fakeSandbox{}
1062
-	if err = ep1.Join(fsbx); err == nil {
1063
-		t.Fatalf("Expected to fail join with invalid Sandbox")
1064
-	}
1065
-	if _, ok := err.(types.BadRequestError); !ok {
1066
-		t.Fatalf("Unexpected error type returned: %T", err)
1067
-	}
1068
-
1069
-	sb, err := controller.NewSandbox(containerID,
1070
-		libnetwork.OptionHostname("test"),
1071
-		libnetwork.OptionDomainname("docker.io"),
1072
-		libnetwork.OptionExtraHost("web", "192.168.0.1"))
1073
-	if err != nil {
1074
-		t.Fatal(err)
1075
-	}
1076
-
1077
-	defer func() {
1078
-		if err := sb.Delete(); err != nil {
1079
-			t.Fatal(err)
1080
-		}
1081
-	}()
1082
-
1083
-	err = ep1.Join(sb)
1084
-	if err != nil {
1085
-		t.Fatal(err)
1086
-	}
1087
-	defer func() {
1088
-		err = ep1.Leave(sb)
1089
-		if err != nil {
1090
-			t.Fatal(err)
1091
-		}
1092
-	}()
1093
-
1094
-	// Validate if ep.Info() only gives valid gateway and sandbox key after has container has joined.
1095
-	info = ep1.Info()
1096
-	if len(info.Gateway()) == 0 {
1097
-		t.Fatalf("Expected a valid gateway for a joined endpoint. Instead found an invalid gateway: %v", info.Gateway())
1098
-	}
1099
-	if len(info.GatewayIPv6()) == 0 {
1100
-		t.Fatalf("Expected a valid ipv6 gateway for a joined endpoint. Instead found an invalid gateway: %v", info.GatewayIPv6())
1101
-	}
1102
-
1103
-	if info.Sandbox() == nil {
1104
-		t.Fatalf("Expected a non-empty sandbox key for a joined endpoint. Instead found an empty sandbox key")
1105
-	}
1106
-
1107
-	// Check endpoint provided container information
1108
-	if ep1.Info().Sandbox().Key() != sb.Key() {
1109
-		t.Fatalf("Endpoint Info returned unexpected sandbox key: %s", sb.Key())
1110
-	}
1111
-
1112
-	// Attempt retrieval of endpoint interfaces statistics
1113
-	stats, err := sb.Statistics()
1114
-	if err != nil {
1115
-		t.Fatal(err)
1116
-	}
1117
-	if _, ok := stats["eth0"]; !ok {
1118
-		t.Fatalf("Did not find eth0 statistics")
1119
-	}
1120
-
1121
-	// Now test the container joining another network
1122
-	n2, err := createTestNetwork(bridgeNetType, "testnetwork2",
1123
-		options.Generic{
1124
-			netlabel.GenericData: options.Generic{
1125
-				"BridgeName": "testnetwork2",
1126
-			},
1127
-		}, nil, nil)
1128
-	if err != nil {
1129
-		t.Fatal(err)
1130
-	}
1131
-	defer func() {
1132
-		if err := n2.Delete(); err != nil {
1133
-			t.Fatal(err)
1134
-		}
1135
-	}()
1136
-
1137
-	ep2, err := n2.CreateEndpoint("ep2")
1138
-	if err != nil {
1139
-		t.Fatal(err)
1140
-	}
1141
-	defer func() {
1142
-		if err := ep2.Delete(false); err != nil {
1143
-			t.Fatal(err)
1144
-		}
1145
-	}()
1146
-
1147
-	err = ep2.Join(sb)
1148
-	if err != nil {
1149
-		t.Fatal(err)
1150
-	}
1151
-	defer func() {
1152
-		err = ep2.Leave(sb)
1153
-		if err != nil {
1154
-			t.Fatal(err)
1155
-		}
1156
-	}()
1157
-
1158
-	if ep1.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
1159
-		t.Fatalf("ep1 and ep2 returned different container sandbox key")
1160
-	}
1161
-
1162
-	checkSandbox(t, info)
1163
-}
1164
-
1165 969
 type fakeSandbox struct{}
1166 970
 
1167 971
 func (f *fakeSandbox) ID() string {
... ...
@@ -1216,155 +855,6 @@ func (f *fakeSandbox) Endpoints() []libnetwork.Endpoint {
1216 1216
 	return nil
1217 1217
 }
1218 1218
 
1219
-func TestExternalKey(t *testing.T) {
1220
-	externalKeyTest(t, false)
1221
-}
1222
-
1223
-func externalKeyTest(t *testing.T, reexec bool) {
1224
-	if !testutils.IsRunningInContainer() {
1225
-		defer testutils.SetupTestOSContext(t)()
1226
-	}
1227
-
1228
-	n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{
1229
-		netlabel.GenericData: options.Generic{
1230
-			"BridgeName": "testnetwork",
1231
-		},
1232
-	}, nil, nil)
1233
-	if err != nil {
1234
-		t.Fatal(err)
1235
-	}
1236
-	defer func() {
1237
-		if err := n.Delete(); err != nil {
1238
-			t.Fatal(err)
1239
-		}
1240
-	}()
1241
-
1242
-	ep, err := n.CreateEndpoint("ep1")
1243
-	if err != nil {
1244
-		t.Fatal(err)
1245
-	}
1246
-	defer func() {
1247
-		err = ep.Delete(false)
1248
-		if err != nil {
1249
-			t.Fatal(err)
1250
-		}
1251
-	}()
1252
-
1253
-	ep2, err := n.CreateEndpoint("ep2")
1254
-	if err != nil {
1255
-		t.Fatal(err)
1256
-	}
1257
-	defer func() {
1258
-		err = ep2.Delete(false)
1259
-		if err != nil {
1260
-			t.Fatal(err)
1261
-		}
1262
-	}()
1263
-
1264
-	cnt, err := controller.NewSandbox(containerID,
1265
-		libnetwork.OptionHostname("test"),
1266
-		libnetwork.OptionDomainname("docker.io"),
1267
-		libnetwork.OptionUseExternalKey(),
1268
-		libnetwork.OptionExtraHost("web", "192.168.0.1"))
1269
-	defer func() {
1270
-		if err := cnt.Delete(); err != nil {
1271
-			t.Fatal(err)
1272
-		}
1273
-		osl.GC()
1274
-	}()
1275
-
1276
-	// Join endpoint to sandbox before SetKey
1277
-	err = ep.Join(cnt)
1278
-	if err != nil {
1279
-		t.Fatal(err)
1280
-	}
1281
-	defer func() {
1282
-		err = ep.Leave(cnt)
1283
-		if err != nil {
1284
-			t.Fatal(err)
1285
-		}
1286
-	}()
1287
-
1288
-	sbox := ep.Info().Sandbox()
1289
-	if sbox == nil {
1290
-		t.Fatalf("Expected to have a valid Sandbox")
1291
-	}
1292
-
1293
-	if reexec {
1294
-		err := reexecSetKey("this-must-fail", containerID, controller.ID())
1295
-		if err == nil {
1296
-			t.Fatalf("SetExternalKey must fail if the corresponding namespace is not created")
1297
-		}
1298
-	} else {
1299
-		// Setting a non-existing key (namespace) must fail
1300
-		if err := sbox.SetKey("this-must-fail"); err == nil {
1301
-			t.Fatalf("Setkey must fail if the corresponding namespace is not created")
1302
-		}
1303
-	}
1304
-
1305
-	// Create a new OS sandbox using the osl API before using it in SetKey
1306
-	if extOsBox, err := osl.NewSandbox("ValidKey", true, false); err != nil {
1307
-		t.Fatalf("Failed to create new osl sandbox")
1308
-	} else {
1309
-		defer func() {
1310
-			if err := extOsBox.Destroy(); err != nil {
1311
-				log.Warnf("Failed to remove os sandbox: %v", err)
1312
-			}
1313
-		}()
1314
-	}
1315
-
1316
-	if reexec {
1317
-		err := reexecSetKey("ValidKey", containerID, controller.ID())
1318
-		if err != nil {
1319
-			t.Fatalf("SetExternalKey failed with %v", err)
1320
-		}
1321
-	} else {
1322
-		if err := sbox.SetKey("ValidKey"); err != nil {
1323
-			t.Fatalf("Setkey failed with %v", err)
1324
-		}
1325
-	}
1326
-
1327
-	// Join endpoint to sandbox after SetKey
1328
-	err = ep2.Join(sbox)
1329
-	if err != nil {
1330
-		t.Fatal(err)
1331
-	}
1332
-	defer func() {
1333
-		err = ep2.Leave(sbox)
1334
-		if err != nil {
1335
-			t.Fatal(err)
1336
-		}
1337
-	}()
1338
-
1339
-	if ep.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
1340
-		t.Fatalf("ep1 and ep2 returned different container sandbox key")
1341
-	}
1342
-
1343
-	checkSandbox(t, ep.Info())
1344
-}
1345
-
1346
-func reexecSetKey(key string, containerID string, controllerID string) error {
1347
-	var (
1348
-		state libcontainer.State
1349
-		b     []byte
1350
-		err   error
1351
-	)
1352
-
1353
-	state.NamespacePaths = make(map[configs.NamespaceType]string)
1354
-	state.NamespacePaths[configs.NamespaceType("NEWNET")] = key
1355
-	if b, err = json.Marshal(state); err != nil {
1356
-		return err
1357
-	}
1358
-	cmd := &exec.Cmd{
1359
-		Path:   reexec.Self(),
1360
-		Args:   append([]string{"libnetwork-setkey"}, containerID, controllerID),
1361
-		Stdin:  strings.NewReader(string(b)),
1362
-		Stdout: os.Stdout,
1363
-		Stderr: os.Stderr,
1364
-	}
1365
-	return cmd.Run()
1366
-}
1367
-
1368 1219
 func TestEndpointDeleteWithActiveContainer(t *testing.T) {
1369 1220
 	if !testutils.IsRunningInContainer() {
1370 1221
 		defer testutils.SetupTestOSContext(t)()
... ...
@@ -1678,304 +1168,6 @@ func TestEndpointUpdateParent(t *testing.T) {
1678 1678
 	}
1679 1679
 }
1680 1680
 
1681
-func TestEnableIPv6(t *testing.T) {
1682
-	if !testutils.IsRunningInContainer() {
1683
-		defer testutils.SetupTestOSContext(t)()
1684
-	}
1685
-
1686
-	tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
1687
-	expectedResolvConf := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\nnameserver 2001:4860:4860::8888\noptions ndots:0\n")
1688
-	//take a copy of resolv.conf for restoring after test completes
1689
-	resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
1690
-	if err != nil {
1691
-		t.Fatal(err)
1692
-	}
1693
-	//cleanup
1694
-	defer func() {
1695
-		if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
1696
-			t.Fatal(err)
1697
-		}
1698
-	}()
1699
-
1700
-	netOption := options.Generic{
1701
-		netlabel.EnableIPv6: true,
1702
-		netlabel.GenericData: options.Generic{
1703
-			"BridgeName": "testnetwork",
1704
-		},
1705
-	}
1706
-	ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe99::/64", Gateway: "fe99::9"}}
1707
-
1708
-	n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, ipamV6ConfList)
1709
-	if err != nil {
1710
-		t.Fatal(err)
1711
-	}
1712
-	defer func() {
1713
-		if err := n.Delete(); err != nil {
1714
-			t.Fatal(err)
1715
-		}
1716
-	}()
1717
-
1718
-	ep1, err := n.CreateEndpoint("ep1")
1719
-	if err != nil {
1720
-		t.Fatal(err)
1721
-	}
1722
-
1723
-	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
1724
-		t.Fatal(err)
1725
-	}
1726
-
1727
-	resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
1728
-	defer os.Remove(resolvConfPath)
1729
-
1730
-	sb, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath))
1731
-	if err != nil {
1732
-		t.Fatal(err)
1733
-	}
1734
-	defer func() {
1735
-		if err := sb.Delete(); err != nil {
1736
-			t.Fatal(err)
1737
-		}
1738
-	}()
1739
-
1740
-	err = ep1.Join(sb)
1741
-	if err != nil {
1742
-		t.Fatal(err)
1743
-	}
1744
-
1745
-	content, err := ioutil.ReadFile(resolvConfPath)
1746
-	if err != nil {
1747
-		t.Fatal(err)
1748
-	}
1749
-
1750
-	if !bytes.Equal(content, expectedResolvConf) {
1751
-		t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf), string(content))
1752
-	}
1753
-
1754
-	if err != nil {
1755
-		t.Fatal(err)
1756
-	}
1757
-}
1758
-
1759
-func TestResolvConfHost(t *testing.T) {
1760
-	if !testutils.IsRunningInContainer() {
1761
-		defer testutils.SetupTestOSContext(t)()
1762
-	}
1763
-
1764
-	tmpResolvConf := []byte("search localhost.net\nnameserver 127.0.0.1\nnameserver 2001:4860:4860::8888\n")
1765
-
1766
-	//take a copy of resolv.conf for restoring after test completes
1767
-	resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
1768
-	if err != nil {
1769
-		t.Fatal(err)
1770
-	}
1771
-	//cleanup
1772
-	defer func() {
1773
-		if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
1774
-			t.Fatal(err)
1775
-		}
1776
-	}()
1777
-
1778
-	n, err := controller.NetworkByName("testhost")
1779
-	if err != nil {
1780
-		t.Fatal(err)
1781
-	}
1782
-
1783
-	ep1, err := n.CreateEndpoint("ep1", libnetwork.CreateOptionDisableResolution())
1784
-	if err != nil {
1785
-		t.Fatal(err)
1786
-	}
1787
-
1788
-	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
1789
-		t.Fatal(err)
1790
-	}
1791
-
1792
-	resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
1793
-	defer os.Remove(resolvConfPath)
1794
-
1795
-	sb, err := controller.NewSandbox(containerID,
1796
-		libnetwork.OptionResolvConfPath(resolvConfPath),
1797
-		libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
1798
-	if err != nil {
1799
-		t.Fatal(err)
1800
-	}
1801
-	defer func() {
1802
-		if err := sb.Delete(); err != nil {
1803
-			t.Fatal(err)
1804
-		}
1805
-	}()
1806
-
1807
-	err = ep1.Join(sb)
1808
-	if err != nil {
1809
-		t.Fatal(err)
1810
-	}
1811
-	defer func() {
1812
-		err = ep1.Leave(sb)
1813
-		if err != nil {
1814
-			t.Fatal(err)
1815
-		}
1816
-	}()
1817
-
1818
-	finfo, err := os.Stat(resolvConfPath)
1819
-	if err != nil {
1820
-		t.Fatal(err)
1821
-	}
1822
-
1823
-	fmode := (os.FileMode)(0644)
1824
-	if finfo.Mode() != fmode {
1825
-		t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String())
1826
-	}
1827
-
1828
-	content, err := ioutil.ReadFile(resolvConfPath)
1829
-	if err != nil {
1830
-		t.Fatal(err)
1831
-	}
1832
-
1833
-	if !bytes.Equal(content, tmpResolvConf) {
1834
-		t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf), string(content))
1835
-	}
1836
-}
1837
-
1838
-func TestResolvConf(t *testing.T) {
1839
-	if !testutils.IsRunningInContainer() {
1840
-		defer testutils.SetupTestOSContext(t)()
1841
-	}
1842
-
1843
-	tmpResolvConf1 := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
1844
-	tmpResolvConf2 := []byte("search pommesfrites.fr\nnameserver 112.34.56.78\nnameserver 2001:4860:4860::8888\n")
1845
-	expectedResolvConf1 := []byte("search pommesfrites.fr\nnameserver 127.0.0.11\noptions ndots:0\n")
1846
-	tmpResolvConf3 := []byte("search pommesfrites.fr\nnameserver 113.34.56.78\n")
1847
-
1848
-	//take a copy of resolv.conf for restoring after test completes
1849
-	resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
1850
-	if err != nil {
1851
-		t.Fatal(err)
1852
-	}
1853
-	//cleanup
1854
-	defer func() {
1855
-		if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
1856
-			t.Fatal(err)
1857
-		}
1858
-	}()
1859
-
1860
-	netOption := options.Generic{
1861
-		netlabel.GenericData: options.Generic{
1862
-			"BridgeName": "testnetwork",
1863
-		},
1864
-	}
1865
-	n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, nil)
1866
-	if err != nil {
1867
-		t.Fatal(err)
1868
-	}
1869
-	defer func() {
1870
-		if err := n.Delete(); err != nil {
1871
-			t.Fatal(err)
1872
-		}
1873
-	}()
1874
-
1875
-	ep, err := n.CreateEndpoint("ep")
1876
-	if err != nil {
1877
-		t.Fatal(err)
1878
-	}
1879
-
1880
-	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf1, 0644); err != nil {
1881
-		t.Fatal(err)
1882
-	}
1883
-
1884
-	resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
1885
-	defer os.Remove(resolvConfPath)
1886
-
1887
-	sb1, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath))
1888
-	if err != nil {
1889
-		t.Fatal(err)
1890
-	}
1891
-	defer func() {
1892
-		if err := sb1.Delete(); err != nil {
1893
-			t.Fatal(err)
1894
-		}
1895
-	}()
1896
-
1897
-	err = ep.Join(sb1)
1898
-	if err != nil {
1899
-		t.Fatal(err)
1900
-	}
1901
-
1902
-	finfo, err := os.Stat(resolvConfPath)
1903
-	if err != nil {
1904
-		t.Fatal(err)
1905
-	}
1906
-
1907
-	fmode := (os.FileMode)(0644)
1908
-	if finfo.Mode() != fmode {
1909
-		t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String())
1910
-	}
1911
-
1912
-	content, err := ioutil.ReadFile(resolvConfPath)
1913
-	if err != nil {
1914
-		t.Fatal(err)
1915
-	}
1916
-
1917
-	if !bytes.Equal(content, expectedResolvConf1) {
1918
-		fmt.Printf("\n%v\n%v\n", expectedResolvConf1, content)
1919
-		t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content))
1920
-	}
1921
-
1922
-	err = ep.Leave(sb1)
1923
-	if err != nil {
1924
-		t.Fatal(err)
1925
-	}
1926
-
1927
-	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf2, 0644); err != nil {
1928
-		t.Fatal(err)
1929
-	}
1930
-
1931
-	sb2, err := controller.NewSandbox(containerID+"_2", libnetwork.OptionResolvConfPath(resolvConfPath))
1932
-	if err != nil {
1933
-		t.Fatal(err)
1934
-	}
1935
-	defer func() {
1936
-		if err := sb2.Delete(); err != nil {
1937
-			t.Fatal(err)
1938
-		}
1939
-	}()
1940
-
1941
-	err = ep.Join(sb2)
1942
-	if err != nil {
1943
-		t.Fatal(err)
1944
-	}
1945
-
1946
-	content, err = ioutil.ReadFile(resolvConfPath)
1947
-	if err != nil {
1948
-		t.Fatal(err)
1949
-	}
1950
-
1951
-	if !bytes.Equal(content, expectedResolvConf1) {
1952
-		t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content))
1953
-	}
1954
-
1955
-	if err := ioutil.WriteFile(resolvConfPath, tmpResolvConf3, 0644); err != nil {
1956
-		t.Fatal(err)
1957
-	}
1958
-
1959
-	err = ep.Leave(sb2)
1960
-	if err != nil {
1961
-		t.Fatal(err)
1962
-	}
1963
-
1964
-	err = ep.Join(sb2)
1965
-	if err != nil {
1966
-		t.Fatal(err)
1967
-	}
1968
-
1969
-	content, err = ioutil.ReadFile(resolvConfPath)
1970
-	if err != nil {
1971
-		t.Fatal(err)
1972
-	}
1973
-
1974
-	if !bytes.Equal(content, tmpResolvConf3) {
1975
-		t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf3), string(content))
1976
-	}
1977
-}
1978
-
1979 1681
 func TestInvalidRemoteDriver(t *testing.T) {
1980 1682
 	if !testutils.IsRunningInContainer() {
1981 1683
 		t.Skip("Skipping test when not running inside a Container")
... ...
@@ -2164,171 +1356,3 @@ func debugf(format string, a ...interface{}) (int, error) {
2164 2164
 
2165 2165
 	return 0, nil
2166 2166
 }
2167
-
2168
-func parallelJoin(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) {
2169
-	debugf("J%d.", thrNumber)
2170
-	var err error
2171
-
2172
-	sb := sboxes[thrNumber-1]
2173
-	err = ep.Join(sb)
2174
-
2175
-	runtime.LockOSThread()
2176
-	if err != nil {
2177
-		if _, ok := err.(types.ForbiddenError); !ok {
2178
-			t.Fatalf("thread %d: %v", thrNumber, err)
2179
-		}
2180
-		debugf("JE%d(%v).", thrNumber, err)
2181
-	}
2182
-	debugf("JD%d.", thrNumber)
2183
-}
2184
-
2185
-func parallelLeave(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) {
2186
-	debugf("L%d.", thrNumber)
2187
-	var err error
2188
-
2189
-	sb := sboxes[thrNumber-1]
2190
-
2191
-	err = ep.Leave(sb)
2192
-	runtime.LockOSThread()
2193
-	if err != nil {
2194
-		if _, ok := err.(types.ForbiddenError); !ok {
2195
-			t.Fatalf("thread %d: %v", thrNumber, err)
2196
-		}
2197
-		debugf("LE%d(%v).", thrNumber, err)
2198
-	}
2199
-	debugf("LD%d.", thrNumber)
2200
-}
2201
-
2202
-func runParallelTests(t *testing.T, thrNumber int) {
2203
-	var (
2204
-		ep  libnetwork.Endpoint
2205
-		sb  libnetwork.Sandbox
2206
-		err error
2207
-	)
2208
-
2209
-	t.Parallel()
2210
-
2211
-	pTest := flag.Lookup("test.parallel")
2212
-	if pTest == nil {
2213
-		t.Skip("Skipped because test.parallel flag not set;")
2214
-	}
2215
-	numParallel, err := strconv.Atoi(pTest.Value.String())
2216
-	if err != nil {
2217
-		t.Fatal(err)
2218
-	}
2219
-	if numParallel < numThreads {
2220
-		t.Skip("Skipped because t.parallel was less than ", numThreads)
2221
-	}
2222
-
2223
-	runtime.LockOSThread()
2224
-	defer runtime.UnlockOSThread()
2225
-
2226
-	if thrNumber == first {
2227
-		createGlobalInstance(t)
2228
-	}
2229
-
2230
-	if thrNumber != first {
2231
-		select {
2232
-		case <-start:
2233
-		}
2234
-
2235
-		thrdone := make(chan struct{})
2236
-		done <- thrdone
2237
-		defer close(thrdone)
2238
-
2239
-		if thrNumber == last {
2240
-			defer close(done)
2241
-		}
2242
-
2243
-		err = netns.Set(testns)
2244
-		if err != nil {
2245
-			t.Fatal(err)
2246
-		}
2247
-	}
2248
-	defer netns.Set(origns)
2249
-
2250
-	net1, err := controller.NetworkByName("testhost")
2251
-	if err != nil {
2252
-		t.Fatal(err)
2253
-	}
2254
-	if net1 == nil {
2255
-		t.Fatal("Could not find testhost")
2256
-	}
2257
-
2258
-	net2, err := controller.NetworkByName("network2")
2259
-	if err != nil {
2260
-		t.Fatal(err)
2261
-	}
2262
-	if net2 == nil {
2263
-		t.Fatal("Could not find network2")
2264
-	}
2265
-
2266
-	epName := fmt.Sprintf("pep%d", thrNumber)
2267
-
2268
-	if thrNumber == first {
2269
-		ep, err = net1.EndpointByName(epName)
2270
-	} else {
2271
-		ep, err = net2.EndpointByName(epName)
2272
-	}
2273
-
2274
-	if err != nil {
2275
-		t.Fatal(err)
2276
-	}
2277
-	if ep == nil {
2278
-		t.Fatal("Got nil ep with no error")
2279
-	}
2280
-
2281
-	cid := fmt.Sprintf("%drace", thrNumber)
2282
-	controller.WalkSandboxes(libnetwork.SandboxContainerWalker(&sb, cid))
2283
-	if sb == nil {
2284
-		t.Fatalf("Got nil sandbox for container: %s", cid)
2285
-	}
2286
-
2287
-	for i := 0; i < iterCnt; i++ {
2288
-		parallelJoin(t, sb, ep, thrNumber)
2289
-		parallelLeave(t, sb, ep, thrNumber)
2290
-	}
2291
-
2292
-	debugf("\n")
2293
-
2294
-	err = sb.Delete()
2295
-	if err != nil {
2296
-		t.Fatal(err)
2297
-	}
2298
-	if thrNumber == first {
2299
-		for thrdone := range done {
2300
-			select {
2301
-			case <-thrdone:
2302
-			}
2303
-		}
2304
-
2305
-		testns.Close()
2306
-		if err := net2.Delete(); err != nil {
2307
-			t.Fatal(err)
2308
-		}
2309
-	} else {
2310
-		err = ep.Delete(false)
2311
-		if err != nil {
2312
-			t.Fatal(err)
2313
-		}
2314
-	}
2315
-}
2316
-
2317
-func TestParallel1(t *testing.T) {
2318
-	runParallelTests(t, 1)
2319
-}
2320
-
2321
-func TestParallel2(t *testing.T) {
2322
-	runParallelTests(t, 2)
2323
-}
2324
-
2325
-func TestParallel3(t *testing.T) {
2326
-	runParallelTests(t, 3)
2327
-}
2328
-
2329
-func TestNullIpam(t *testing.T) {
2330
-	_, err := controller.NewNetwork(bridgeNetType, "testnetworkinternal", "", libnetwork.NetworkOptionIpam(ipamapi.NullIPAM, "", nil, nil, nil))
2331
-	if err == nil || err.Error() != "ipv4 pool is empty" {
2332
-		t.Fatal("bridge network should complain empty pool")
2333
-	}
2334
-}
... ...
@@ -1,13 +1,26 @@
1
-package netutils
1
+// +build solaris
2 2
 
3
-// Solaris: TODO
3
+package netutils
4 4
 
5 5
 import (
6
+	"fmt"
6 7
 	"net"
8
+	"os/exec"
9
+	"strings"
7 10
 
8 11
 	"github.com/docker/libnetwork/ipamutils"
12
+	"github.com/vishvananda/netlink"
13
+)
14
+
15
+var (
16
+	networkGetRoutesFct func(netlink.Link, int) ([]netlink.Route, error)
9 17
 )
10 18
 
19
+// CheckRouteOverlaps checks whether the passed network overlaps with any existing routes
20
+func CheckRouteOverlaps(toCheck *net.IPNet) error {
21
+	return nil
22
+}
23
+
11 24
 // ElectInterfaceAddresses looks for an interface on the OS with the specified name
12 25
 // and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist,
13 26
 // it chooses from a predifined list the first IPv4 address which does not conflict
... ...
@@ -15,18 +28,75 @@ import (
15 15
 func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
16 16
 	var (
17 17
 		v4Net *net.IPNet
18
-		err   error
19 18
 	)
20 19
 
21
-	v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks)
20
+	out, err := exec.Command("/usr/sbin/ipadm", "show-addr",
21
+		"-p", "-o", "addrobj,addr").Output()
22 22
 	if err != nil {
23
+		fmt.Println("failed to list interfaces on system")
23 24
 		return nil, nil, err
24 25
 	}
26
+	alist := strings.Fields(string(out))
27
+	for _, a := range alist {
28
+		linkandaddr := strings.SplitN(a, ":", 2)
29
+		if len(linkandaddr) != 2 {
30
+			fmt.Println("failed to check interfaces on system: ", a)
31
+			continue
32
+		}
33
+		gw := fmt.Sprintf("%s_gw0", name)
34
+		link := strings.Split(linkandaddr[0], "/")[0]
35
+		addr := linkandaddr[1]
36
+		if gw != link {
37
+			continue
38
+		}
39
+		_, ipnet, err := net.ParseCIDR(addr)
40
+		if err != nil {
41
+			fmt.Println("failed to parse address: ", addr)
42
+			continue
43
+		}
44
+		v4Net = ipnet
45
+		break
46
+	}
47
+	if v4Net == nil {
48
+		v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks)
49
+		if err != nil {
50
+			return nil, nil, err
51
+		}
52
+	}
25 53
 	return v4Net, nil, nil
26 54
 }
27 55
 
28 56
 // FindAvailableNetwork returns a network from the passed list which does not
29 57
 // overlap with existing interfaces in the system
30 58
 func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
31
-	return list[0], nil
59
+	out, err := exec.Command("/usr/sbin/ipadm", "show-addr",
60
+		"-p", "-o", "addr").Output()
61
+
62
+	if err != nil {
63
+		fmt.Println("failed to list interfaces on system")
64
+		return nil, err
65
+	}
66
+	ipaddrs := strings.Fields(string(out))
67
+	inuse := []*net.IPNet{}
68
+	for _, ip := range ipaddrs {
69
+		_, ipnet, err := net.ParseCIDR(ip)
70
+		if err != nil {
71
+			fmt.Println("failed to check interfaces on system: ", ip)
72
+			continue
73
+		}
74
+		inuse = append(inuse, ipnet)
75
+	}
76
+	for _, avail := range list {
77
+		is_avail := true
78
+		for _, ipnet := range inuse {
79
+			if NetworkOverlaps(avail, ipnet) {
80
+				is_avail = false
81
+				break
82
+			}
83
+		}
84
+		if is_avail {
85
+			return avail, nil
86
+		}
87
+	}
88
+	return nil, fmt.Errorf("no available network")
32 89
 }
... ...
@@ -1,3 +1,5 @@
1
+// +build !solaris
2
+
1 3
 package netutils
2 4
 
3 5
 import (
4 6
new file mode 100644
... ...
@@ -0,0 +1,24 @@
0
+package osl
1
+
2
+// NewSandbox provides a new sandbox instance created in an os specific way
3
+// provided a key which uniquely identifies the sandbox
4
+func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
5
+	return nil, nil
6
+}
7
+
8
+// GenerateKey generates a sandbox key based on the passed
9
+// container id.
10
+func GenerateKey(containerID string) string {
11
+	maxLen := 12
12
+
13
+	if len(containerID) < maxLen {
14
+		maxLen = len(containerID)
15
+	}
16
+
17
+	return containerID[:maxLen]
18
+}
19
+
20
+// InitOSContext initializes OS context while configuring network resources
21
+func InitOSContext() func() {
22
+	return func() {}
23
+}
... ...
@@ -1,3 +1,5 @@
1
+// +build !solaris
2
+
1 3
 package osl
2 4
 
3 5
 import (
... ...
@@ -1,4 +1,4 @@
1
-// +build !linux,!windows,!freebsd
1
+// +build !linux,!windows,!freebsd,!solaris
2 2
 
3 3
 package osl
4 4
 
... ...
@@ -1,4 +1,4 @@
1
-// +build !linux
1
+// +build !linux,!solaris
2 2
 
3 3
 package osl
4 4
 
... ...
@@ -1,11 +1,9 @@
1 1
 package portallocator
2 2
 
3 3
 import (
4
-	"bufio"
5 4
 	"errors"
6 5
 	"fmt"
7 6
 	"net"
8
-	"os"
9 7
 	"sync"
10 8
 )
11 9
 
... ...
@@ -106,26 +104,6 @@ func newInstance() *PortAllocator {
106 106
 	}
107 107
 }
108 108
 
109
-func getDynamicPortRange() (start int, end int, err error) {
110
-	const portRangeKernelParam = "/proc/sys/net/ipv4/ip_local_port_range"
111
-	portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd)
112
-	file, err := os.Open(portRangeKernelParam)
113
-	if err != nil {
114
-		return 0, 0, fmt.Errorf("port allocator - %s due to error: %v", portRangeFallback, err)
115
-	}
116
-
117
-	defer file.Close()
118
-
119
-	n, err := fmt.Fscanf(bufio.NewReader(file), "%d\t%d", &start, &end)
120
-	if n != 2 || err != nil {
121
-		if err == nil {
122
-			err = fmt.Errorf("unexpected count of parsed numbers (%d)", n)
123
-		}
124
-		return 0, 0, fmt.Errorf("port allocator - failed to parse system ephemeral port range from %s - %s: %v", portRangeKernelParam, portRangeFallback, err)
125
-	}
126
-	return start, end, nil
127
-}
128
-
129 109
 // RequestPort requests new port from global ports pool for specified ip and proto.
130 110
 // If port is 0 it returns first free port. Otherwise it checks port availability
131 111
 // in proto's pool and returns that port or error if port is already busy.
132 112
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+package portallocator
1
+
2
+import (
3
+	"bufio"
4
+	"fmt"
5
+	"os"
6
+)
7
+
8
+func getDynamicPortRange() (start int, end int, err error) {
9
+	const portRangeKernelParam = "/proc/sys/net/ipv4/ip_local_port_range"
10
+	portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd)
11
+	file, err := os.Open(portRangeKernelParam)
12
+	if err != nil {
13
+		return 0, 0, fmt.Errorf("port allocator - %s due to error: %v", portRangeFallback, err)
14
+	}
15
+
16
+	defer file.Close()
17
+
18
+	n, err := fmt.Fscanf(bufio.NewReader(file), "%d\t%d", &start, &end)
19
+	if n != 2 || err != nil {
20
+		if err == nil {
21
+			err = fmt.Errorf("unexpected count of parsed numbers (%d)", n)
22
+		}
23
+		return 0, 0, fmt.Errorf("port allocator - failed to parse system ephemeral port range from %s - %s: %v", portRangeKernelParam, portRangeFallback, err)
24
+	}
25
+	return start, end, nil
26
+}
0 27
new file mode 100644
... ...
@@ -0,0 +1,5 @@
0
+package portallocator
1
+
2
+func getDynamicPortRange() (start int, end int, err error) {
3
+	return 32768, 65535, nil
4
+}
... ...
@@ -7,8 +7,6 @@ import (
7 7
 	"net"
8 8
 	"os"
9 9
 	"os/exec"
10
-	"strconv"
11
-	"syscall"
12 10
 	"time"
13 11
 )
14 12
 
... ...
@@ -25,36 +23,6 @@ type proxyCommand struct {
25 25
 	cmd *exec.Cmd
26 26
 }
27 27
 
28
-func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
29
-	path := proxyPath
30
-	if proxyPath == "" {
31
-		cmd, err := exec.LookPath(userlandProxyCommandName)
32
-		if err != nil {
33
-			return nil, err
34
-		}
35
-		path = cmd
36
-	}
37
-
38
-	args := []string{
39
-		path,
40
-		"-proto", proto,
41
-		"-host-ip", hostIP.String(),
42
-		"-host-port", strconv.Itoa(hostPort),
43
-		"-container-ip", containerIP.String(),
44
-		"-container-port", strconv.Itoa(containerPort),
45
-	}
46
-
47
-	return &proxyCommand{
48
-		cmd: &exec.Cmd{
49
-			Path: path,
50
-			Args: args,
51
-			SysProcAttr: &syscall.SysProcAttr{
52
-				Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies
53
-			},
54
-		},
55
-	}, nil
56
-}
57
-
58 28
 func (p *proxyCommand) Start() error {
59 29
 	r, w, err := os.Pipe()
60 30
 	if err != nil {
61 31
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+package portmapper
1
+
2
+import (
3
+	"net"
4
+	"os/exec"
5
+	"strconv"
6
+	"syscall"
7
+)
8
+
9
+func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
10
+	path := proxyPath
11
+	if proxyPath == "" {
12
+		cmd, err := exec.LookPath(userlandProxyCommandName)
13
+		if err != nil {
14
+			return nil, err
15
+		}
16
+		path = cmd
17
+	}
18
+
19
+	args := []string{
20
+		path,
21
+		"-proto", proto,
22
+		"-host-ip", hostIP.String(),
23
+		"-host-port", strconv.Itoa(hostPort),
24
+		"-container-ip", containerIP.String(),
25
+		"-container-port", strconv.Itoa(containerPort),
26
+	}
27
+
28
+	return &proxyCommand{
29
+		cmd: &exec.Cmd{
30
+			Path: path,
31
+			Args: args,
32
+			SysProcAttr: &syscall.SysProcAttr{
33
+				Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies
34
+			},
35
+		},
36
+	}, nil
37
+}
0 38
new file mode 100644
... ...
@@ -0,0 +1,34 @@
0
+package portmapper
1
+
2
+import (
3
+	"net"
4
+	"os/exec"
5
+	"strconv"
6
+)
7
+
8
+func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
9
+	path := proxyPath
10
+	if proxyPath == "" {
11
+		cmd, err := exec.LookPath(userlandProxyCommandName)
12
+		if err != nil {
13
+			return nil, err
14
+		}
15
+		path = cmd
16
+	}
17
+
18
+	args := []string{
19
+		path,
20
+		"-proto", proto,
21
+		"-host-ip", hostIP.String(),
22
+		"-host-port", strconv.Itoa(hostPort),
23
+		"-container-ip", containerIP.String(),
24
+		"-container-port", strconv.Itoa(containerPort),
25
+	}
26
+
27
+	return &proxyCommand{
28
+		cmd: &exec.Cmd{
29
+			Path: path,
30
+			Args: args,
31
+		},
32
+	}, nil
33
+}
0 34
new file mode 100644
... ...
@@ -0,0 +1,45 @@
0
+package libnetwork
1
+
2
+import (
3
+	"os"
4
+	"testing"
5
+
6
+	"github.com/docker/libkv/store"
7
+	"github.com/docker/libnetwork/datastore"
8
+)
9
+
10
+func TestBoltdbBackend(t *testing.T) {
11
+	defer os.Remove(datastore.DefaultScopes("")[datastore.LocalScope].Client.Address)
12
+	testLocalBackend(t, "", "", nil)
13
+	defer os.Remove("/tmp/boltdb.db")
14
+	config := &store.Config{Bucket: "testBackend"}
15
+	testLocalBackend(t, "boltdb", "/tmp/boltdb.db", config)
16
+
17
+}
18
+
19
+func TestNoPersist(t *testing.T) {
20
+	cfgOptions, err := OptionBoltdbWithRandomDBFile()
21
+	if err != nil {
22
+		t.Fatalf("Error creating random boltdb file : %v", err)
23
+	}
24
+	ctrl, err := New(cfgOptions...)
25
+	if err != nil {
26
+		t.Fatalf("Error new controller: %v", err)
27
+	}
28
+	nw, err := ctrl.NewNetwork("host", "host", "", NetworkOptionPersist(false))
29
+	if err != nil {
30
+		t.Fatalf("Error creating default \"host\" network: %v", err)
31
+	}
32
+	ep, err := nw.CreateEndpoint("newendpoint", []EndpointOption{}...)
33
+	if err != nil {
34
+		t.Fatalf("Error creating endpoint: %v", err)
35
+	}
36
+	store := ctrl.(*controller).getStore(datastore.LocalScope).KVStore()
37
+	if exists, _ := store.Exists(datastore.Key(datastore.NetworkKeyPrefix, string(nw.ID()))); exists {
38
+		t.Fatalf("Network with persist=false should not be stored in KV Store")
39
+	}
40
+	if exists, _ := store.Exists(datastore.Key([]string{datastore.EndpointKeyPrefix, string(nw.ID()), string(ep.ID())}...)); exists {
41
+		t.Fatalf("Endpoint in Network with persist=false should not be stored in KV Store")
42
+	}
43
+	store.Close()
44
+}
... ...
@@ -3,7 +3,6 @@ package libnetwork
3 3
 import (
4 4
 	"fmt"
5 5
 	"io/ioutil"
6
-	"os"
7 6
 	"testing"
8 7
 
9 8
 	"github.com/docker/libkv/store"
... ...
@@ -31,15 +30,6 @@ func testNewController(t *testing.T, provider, url string) (NetworkController, e
31 31
 	return New(cfgOptions...)
32 32
 }
33 33
 
34
-func TestBoltdbBackend(t *testing.T) {
35
-	defer os.Remove(datastore.DefaultScopes("")[datastore.LocalScope].Client.Address)
36
-	testLocalBackend(t, "", "", nil)
37
-	defer os.Remove("/tmp/boltdb.db")
38
-	config := &store.Config{Bucket: "testBackend"}
39
-	testLocalBackend(t, "boltdb", "/tmp/boltdb.db", config)
40
-
41
-}
42
-
43 34
 func testLocalBackend(t *testing.T, provider, url string, storeConfig *store.Config) {
44 35
 	cfgOptions := []config.Option{}
45 36
 	cfgOptions = append(cfgOptions, config.OptionLocalKVProvider(provider))
... ...
@@ -82,33 +72,6 @@ func testLocalBackend(t *testing.T, provider, url string, storeConfig *store.Con
82 82
 	}
83 83
 }
84 84
 
85
-func TestNoPersist(t *testing.T) {
86
-	cfgOptions, err := OptionBoltdbWithRandomDBFile()
87
-	if err != nil {
88
-		t.Fatalf("Error creating random boltdb file : %v", err)
89
-	}
90
-	ctrl, err := New(cfgOptions...)
91
-	if err != nil {
92
-		t.Fatalf("Error new controller: %v", err)
93
-	}
94
-	nw, err := ctrl.NewNetwork("host", "host", "", NetworkOptionPersist(false))
95
-	if err != nil {
96
-		t.Fatalf("Error creating default \"host\" network: %v", err)
97
-	}
98
-	ep, err := nw.CreateEndpoint("newendpoint", []EndpointOption{}...)
99
-	if err != nil {
100
-		t.Fatalf("Error creating endpoint: %v", err)
101
-	}
102
-	store := ctrl.(*controller).getStore(datastore.LocalScope).KVStore()
103
-	if exists, _ := store.Exists(datastore.Key(datastore.NetworkKeyPrefix, string(nw.ID()))); exists {
104
-		t.Fatalf("Network with persist=false should not be stored in KV Store")
105
-	}
106
-	if exists, _ := store.Exists(datastore.Key([]string{datastore.EndpointKeyPrefix, string(nw.ID()), string(ep.ID())}...)); exists {
107
-		t.Fatalf("Endpoint in Network with persist=false should not be stored in KV Store")
108
-	}
109
-	store.Close()
110
-}
111
-
112 85
 // OptionBoltdbWithRandomDBFile function returns a random dir for local store backend
113 86
 func OptionBoltdbWithRandomDBFile() ([]config.Option, error) {
114 87
 	tmp, err := ioutil.TempFile("", "libnetwork-")
115 88
new file mode 100644
... ...
@@ -0,0 +1,25 @@
0
+// +build solaris
1
+
2
+package testutils
3
+
4
+import (
5
+	"os"
6
+	"testing"
7
+)
8
+
9
+// SetupTestOSContext joins a new network namespace, and returns its associated
10
+// teardown function.
11
+//
12
+// Example usage:
13
+//
14
+//     defer SetupTestOSContext(t)()
15
+//
16
+func SetupTestOSContext(t *testing.T) func() {
17
+	return func() {
18
+	}
19
+}
20
+
21
+// RunningOnCircleCI returns true if being executed on libnetwork Circle CI setup
22
+func RunningOnCircleCI() bool {
23
+	return os.Getenv("CIRCLECI") != ""
24
+}