Browse code

- Added support for Join/Leave methods to Endpoint. - Removed sandbox key argument for CreateEndpoint. - Refactored bridge driver code to remove sandbox key. - Fixed bridge driver code for gaps in ipv6 behavior observed during docker integration. - Updated test code, readme code, README.md according api change. - Fixed some sandbox issues while testing docker ipv6 integration.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>

Jana Radhakrishnan authored on 2015/04/28 14:57:36
Showing 14 changed files
... ...
@@ -19,54 +19,33 @@ Please refer to the [roadmap](ROADMAP.md) for more information.
19 19
 
20 20
 There are many networking solutions available to suit a broad range of use-cases. libnetwork uses a driver / plugin model to support all of these solutions while abstracting the complexity of the driver implementations by exposing a simple and consistent Network Model to users.
21 21
 
22
+
22 23
 ```go
23
- // Create a new controller instance
24
- controller := libnetwork.New()
25
-
26
- // This option is only needed for in-tree drivers. Plugins(in future) will get
27
- // their options through plugin infrastructure.
28
- option := options.Generic{}
29
- driver, err := controller.NewNetworkDriver("bridge", option)
30
- if err != nil {
31
-    return
32
- }
33
-
34
- netOptions := options.Generic{}
35
- // Create a network for containers to join.
36
- network, err := controller.NewNetwork(driver, "network1", netOptions)
37
- if err != nil {
38
-    return
39
- }
40
-
41
- // For a new container: create a sandbox instance (providing a unique key).
42
- // For linux it is a filesystem path
43
- networkPath := "/var/lib/docker/.../4d23e"
44
- networkNamespace, err := sandbox.NewSandbox(networkPath)
45
- if err != nil {
46
-    return
47
- }
48
-
49
- // For each new container: allocate IP and interfaces. The returned network
50
- // settings will be used for container infos (inspect and such), as well as
51
- // iptables rules for port publishing. This info is contained or accessible
52
- // from the returned endpoint.
53
- ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
54
- if err != nil {
55
-    return
56
- }
57
-
58
- // Add interfaces to the namespace.
59
- sinfo := ep.SandboxInfo()
60
- for _, iface := range sinfo.Interfaces {
61
-     if err := networkNamespace.AddInterface(iface); err != nil {
62
-     	    return
63
-     }
64
- }
65
-
66
- // Set the gateway IP
67
- if err := networkNamespace.SetGateway(sinfo.Gateway); err != nil {
68
-    return
69
- }
24
+    // Create a new controller instance
25
+    controller := libnetwork.New()
26
+
27
+    // This option is only needed for in-tree drivers. Plugins(in future) will get
28
+    // their options through plugin infrastructure.
29
+    option := options.Generic{}
30
+    err := controller.NewNetworkDriver("bridge", option)
31
+    if err != nil {
32
+        return
33
+    }
34
+
35
+    netOptions := options.Generic{}
36
+    // Create a network for containers to join.
37
+    network, err := controller.NewNetwork("bridge", "network1", netOptions)
38
+    if err != nil {
39
+    	return
40
+    }
41
+
42
+    // For each new container: allocate IP and interfaces. The returned network
43
+    // settings will be used for container infos (inspect and such), as well as
44
+    // iptables rules for port publishing.
45
+    ep, err := network.CreateEndpoint("Endpoint1", nil)
46
+    if err != nil {
47
+	    return
48
+    }
70 49
 ```
71 50
 
72 51
 ## Future
... ...
@@ -12,7 +12,7 @@ To suggest changes to the roadmap, including additions, please write the change
12 12
 #### Concepts
13 13
 
14 14
 1. Sandbox: An isolated environment. This is more or less a standard docker container.
15
-2. Endpoint: An addressable endpoint used for communication over a specific network. Endpoints join exactly one network and are expected to create a method of network communication for a container. Endpoints are garbage collected when they no longer belong to any Sandboxes. Example : veth pair
15
+2. Endpoint: An addressable endpoint used for communication over a specific network. Endpoints join exactly one network and are expected to create a method of network communication for a container. Example : veth pair
16 16
 3. Network: A collection of endpoints that are able to communicate to each other. Networks are intended to be isolated from each other and to not cross communicate.
17 17
 
18 18
 #### axioms
... ...
@@ -3,7 +3,6 @@ package main
3 3
 import (
4 4
 	"github.com/docker/libnetwork"
5 5
 	"github.com/docker/libnetwork/pkg/options"
6
-	"github.com/docker/libnetwork/sandbox"
7 6
 )
8 7
 
9 8
 func main() {
... ...
@@ -25,33 +24,20 @@ func main() {
25 25
 		return
26 26
 	}
27 27
 
28
-	// For a new container: create a sandbox instance (providing a unique key).
29
-	// For linux it is a filesystem path
30
-	networkPath := "/var/lib/docker/.../4d23e"
31
-	networkNamespace, err := sandbox.NewSandbox(networkPath)
32
-	if err != nil {
33
-		return
34
-	}
35
-
36 28
 	// For each new container: allocate IP and interfaces. The returned network
37 29
 	// settings will be used for container infos (inspect and such), as well as
38 30
 	// iptables rules for port publishing. This info is contained or accessible
39 31
 	// from the returned endpoint.
40
-	ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), nil)
32
+	ep, err := network.CreateEndpoint("Endpoint1", nil)
41 33
 	if err != nil {
42 34
 		return
43 35
 	}
44 36
 
45
-	// Add interfaces to the namespace.
46
-	sinfo := ep.SandboxInfo()
47
-	for _, iface := range sinfo.Interfaces {
48
-		if err := networkNamespace.AddInterface(iface); err != nil {
49
-			return
50
-		}
51
-	}
52
-
53
-	// Set the gateway IP
54
-	if err := networkNamespace.SetGateway(sinfo.Gateway); err != nil {
37
+	// A container can join the endpoint by providing the container ID to the join
38
+	// api which returns the sandbox key which can be used to access the sandbox
39
+	// created for the container during join.
40
+	_, err = ep.Join("container1")
41
+	if err != nil {
55 42
 		return
56 43
 	}
57 44
 }
... ...
@@ -31,10 +31,10 @@ type Driver interface {
31 31
 	DeleteNetwork(nid types.UUID) error
32 32
 
33 33
 	// CreateEndpoint invokes the driver method to create an endpoint
34
-	// passing the network id, endpoint id, sandbox key and driver
34
+	// passing the network id, endpoint id and driver
35 35
 	// specific config. The config mechanism will eventually be replaced
36 36
 	// with labels which are yet to be introduced.
37
-	CreateEndpoint(nid, eid types.UUID, key string, config interface{}) (*sandbox.Info, error)
37
+	CreateEndpoint(nid, eid types.UUID, config interface{}) (*sandbox.Info, error)
38 38
 
39 39
 	// DeleteEndpoint invokes the driver method to delete an endpoint
40 40
 	// passing the network id and endpoint id.
... ...
@@ -57,8 +57,8 @@ type bridgeEndpoint struct {
57 57
 
58 58
 type bridgeNetwork struct {
59 59
 	id        types.UUID
60
-	bridge    *bridgeInterface           // The bridge's L3 interface
61
-	endpoints map[string]*bridgeEndpoint // key: sandbox id
60
+	bridge    *bridgeInterface               // The bridge's L3 interface
61
+	endpoints map[types.UUID]*bridgeEndpoint // key: endpoint id
62 62
 	sync.Mutex
63 63
 }
64 64
 
... ...
@@ -118,21 +118,19 @@ func (c *Configuration) Validate() error {
118 118
 	return nil
119 119
 }
120 120
 
121
-func (n *bridgeNetwork) getEndpoint(eid types.UUID) (string, *bridgeEndpoint, error) {
121
+func (n *bridgeNetwork) getEndpoint(eid types.UUID) (*bridgeEndpoint, error) {
122 122
 	n.Lock()
123 123
 	defer n.Unlock()
124 124
 
125 125
 	if eid == "" {
126
-		return "", nil, InvalidEndpointIDError(eid)
126
+		return nil, InvalidEndpointIDError(eid)
127 127
 	}
128 128
 
129
-	for sk, ep := range n.endpoints {
130
-		if ep.id == eid {
131
-			return sk, ep, nil
132
-		}
129
+	if ep, ok := n.endpoints[eid]; ok {
130
+		return ep, nil
133 131
 	}
134 132
 
135
-	return "", nil, nil
133
+	return nil, nil
136 134
 }
137 135
 
138 136
 func (d *driver) Config(option interface{}) error {
... ...
@@ -184,7 +182,7 @@ func (d *driver) CreateNetwork(id types.UUID, option interface{}) error {
184 184
 	}
185 185
 
186 186
 	// Create and set network handler in driver
187
-	d.network = &bridgeNetwork{id: id, endpoints: make(map[string]*bridgeEndpoint)}
187
+	d.network = &bridgeNetwork{id: id, endpoints: make(map[types.UUID]*bridgeEndpoint)}
188 188
 	d.Unlock()
189 189
 
190 190
 	// On failure make sure to reset driver network handler to nil
... ...
@@ -299,7 +297,7 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
299 299
 	return err
300 300
 }
301 301
 
302
-func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOptions interface{}) (*sandbox.Info, error) {
302
+func (d *driver) CreateEndpoint(nid, eid types.UUID, epOptions interface{}) (*sandbox.Info, error) {
303 303
 	var (
304 304
 		ipv6Addr *net.IPNet
305 305
 		err      error
... ...
@@ -323,7 +321,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOptions i
323 323
 	n.Unlock()
324 324
 
325 325
 	// Check if endpoint id is good and retrieve correspondent endpoint
326
-	_, ep, err := n.getEndpoint(eid)
326
+	ep, err := n.getEndpoint(eid)
327 327
 	if err != nil {
328 328
 		return nil, err
329 329
 	}
... ...
@@ -333,18 +331,6 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOptions i
333 333
 		return nil, driverapi.ErrEndpointExists
334 334
 	}
335 335
 
336
-	// Check if valid sandbox key
337
-	if sboxKey == "" {
338
-		return nil, InvalidSandboxIDError(sboxKey)
339
-	}
340
-
341
-	// Check if endpoint already exists for this sandbox
342
-	n.Lock()
343
-	if _, ok := n.endpoints[sboxKey]; ok {
344
-		n.Unlock()
345
-		return nil, driverapi.ErrEndpointExists
346
-	}
347
-
348 336
 	// Try to convert the options to endpoint configuration
349 337
 	epConfig, err := parseEndpointOptions(epOptions)
350 338
 	if err != nil {
... ...
@@ -353,15 +339,16 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOptions i
353 353
 	}
354 354
 
355 355
 	// Create and add the endpoint
356
+	n.Lock()
356 357
 	endpoint := &bridgeEndpoint{id: eid, config: epConfig}
357
-	n.endpoints[sboxKey] = endpoint
358
+	n.endpoints[eid] = endpoint
358 359
 	n.Unlock()
359 360
 
360 361
 	// On failure make sure to remove the endpoint
361 362
 	defer func() {
362 363
 		if err != nil {
363 364
 			n.Lock()
364
-			delete(n.endpoints, sboxKey)
365
+			delete(n.endpoints, eid)
365 366
 			n.Unlock()
366 367
 		}
367 368
 	}()
... ...
@@ -408,12 +395,15 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOptions i
408 408
 		}
409 409
 	}()
410 410
 
411
+	mac := netutils.GenerateRandomMAC()
411 412
 	// Add user specified attributes
412 413
 	if epConfig != nil && epConfig.MacAddress != nil {
413
-		err = netlink.LinkSetHardwareAddr(sbox, epConfig.MacAddress)
414
-		if err != nil {
415
-			return nil, err
416
-		}
414
+		mac = epConfig.MacAddress
415
+	}
416
+
417
+	err = netlink.LinkSetHardwareAddr(sbox, mac)
418
+	if err != nil {
419
+		return nil, err
417 420
 	}
418 421
 
419 422
 	// Add bridge inherited attributes to pipe interfaces
... ...
@@ -443,11 +433,28 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, sboxKey string, epOptions i
443 443
 
444 444
 	// v6 address for the sandbox side pipe interface
445 445
 	if config.EnableIPv6 {
446
-		ip6, err := ipAllocator.RequestIP(n.bridge.bridgeIPv6, nil)
446
+		var ip6 net.IP
447
+
448
+		network := n.bridge.bridgeIPv6
449
+		if config.FixedCIDRv6 != nil {
450
+			network = config.FixedCIDRv6
451
+		}
452
+
453
+		ones, _ := network.Mask.Size()
454
+		if ones <= 80 {
455
+			ip6 = make(net.IP, len(network.IP))
456
+			copy(ip6, network.IP)
457
+			for i, h := range mac {
458
+				ip6[i+10] = h
459
+			}
460
+		}
461
+
462
+		ip6, err := ipAllocator.RequestIP(network, ip6)
447 463
 		if err != nil {
448 464
 			return nil, err
449 465
 		}
450
-		ipv6Addr = &net.IPNet{IP: ip6, Mask: n.bridge.bridgeIPv6.Mask}
466
+
467
+		ipv6Addr = &net.IPNet{IP: ip6, Mask: network.Mask}
451 468
 	}
452 469
 
453 470
 	// Store the sandbox side pipe interface
... ...
@@ -494,7 +501,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
494 494
 	n.Unlock()
495 495
 
496 496
 	// Check endpoint id and if an endpoint is actually there
497
-	sboxKey, ep, err := n.getEndpoint(eid)
497
+	ep, err := n.getEndpoint(eid)
498 498
 	if err != nil {
499 499
 		return err
500 500
 	}
... ...
@@ -504,7 +511,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
504 504
 
505 505
 	// Remove it
506 506
 	n.Lock()
507
-	delete(n.endpoints, sboxKey)
507
+	delete(n.endpoints, eid)
508 508
 	n.Unlock()
509 509
 
510 510
 	// On failure make sure to set back ep in n.endpoints, but only
... ...
@@ -512,8 +519,8 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
512 512
 	defer func() {
513 513
 		if err != nil {
514 514
 			n.Lock()
515
-			if _, ok := n.endpoints[sboxKey]; !ok {
516
-				n.endpoints[sboxKey] = ep
515
+			if _, ok := n.endpoints[eid]; !ok {
516
+				n.endpoints[eid] = ep
517 517
 			}
518 518
 			n.Unlock()
519 519
 		}
... ...
@@ -76,7 +76,7 @@ func TestCreateLinkWithOptions(t *testing.T) {
76 76
 	mac := net.HardwareAddr([]byte{0x1e, 0x67, 0x66, 0x44, 0x55, 0x66})
77 77
 	epConf := &EndpointConfiguration{MacAddress: mac}
78 78
 
79
-	sinfo, err := d.CreateEndpoint("net1", "ep", "s1", epConf)
79
+	sinfo, err := d.CreateEndpoint("net1", "ep", epConf)
80 80
 	if err != nil {
81 81
 		t.Fatalf("Failed to create a link: %s", err.Error())
82 82
 	}
... ...
@@ -207,7 +207,7 @@ func TestSetDefaultGw(t *testing.T) {
207 207
 		t.Fatalf("Failed to create bridge: %v", err)
208 208
 	}
209 209
 
210
-	sinfo, err := d.CreateEndpoint("dummy", "ep", "sb2", nil)
210
+	sinfo, err := d.CreateEndpoint("dummy", "ep", nil)
211 211
 	if err != nil {
212 212
 		t.Fatalf("Failed to create endpoint: %v", err)
213 213
 	}
... ...
@@ -28,7 +28,7 @@ func TestLinkCreate(t *testing.T) {
28 28
 		t.Fatalf("Failed to create bridge: %v", err)
29 29
 	}
30 30
 
31
-	sinfo, err := d.CreateEndpoint("dummy", "", "sb1", nil)
31
+	sinfo, err := d.CreateEndpoint("dummy", "", nil)
32 32
 	if err != nil {
33 33
 		if _, ok := err.(InvalidEndpointIDError); !ok {
34 34
 			t.Fatalf("Failed with a wrong error :%s", err.Error())
... ...
@@ -37,17 +37,8 @@ func TestLinkCreate(t *testing.T) {
37 37
 		t.Fatalf("Failed to detect invalid config")
38 38
 	}
39 39
 
40
-	sinfo, err = d.CreateEndpoint("dummy", "ep", "", nil)
41
-	if err != nil {
42
-		if _, ok := err.(InvalidSandboxIDError); !ok {
43
-			t.Fatalf("Failed with a wrong error :%s", err.Error())
44
-		}
45
-	} else {
46
-		t.Fatalf("Failed to detect invalid config")
47
-	}
48
-
49 40
 	// Good endpoint creation
50
-	sinfo, err = d.CreateEndpoint("dummy", "ep", "cc", nil)
41
+	sinfo, err = d.CreateEndpoint("dummy", "ep", nil)
51 42
 	if err != nil {
52 43
 		t.Fatalf("Failed to create a link: %s", err.Error())
53 44
 	}
... ...
@@ -63,16 +54,11 @@ func TestLinkCreate(t *testing.T) {
63 63
 	// TODO: if we could get peer name from (sboxLnk.(*netlink.Veth)).PeerName
64 64
 	// then we could check the MTU on hostLnk as well.
65 65
 
66
-	_, err = d.CreateEndpoint("dummy", "ep", "cc2", nil)
66
+	_, err = d.CreateEndpoint("dummy", "ep", nil)
67 67
 	if err == nil {
68 68
 		t.Fatalf("Failed to detect duplicate endpoint id on same network")
69 69
 	}
70 70
 
71
-	_, err = d.CreateEndpoint("dummy", "ep2", "cc", nil)
72
-	if err == nil {
73
-		t.Fatalf("Failed to detect addition of more than one endpoint to same sandbox")
74
-	}
75
-
76 71
 	interfaces := sinfo.Interfaces
77 72
 	if len(interfaces) != 1 {
78 73
 		t.Fatalf("Expected exactly one interface. Instead got %d interface(s)", len(interfaces))
... ...
@@ -125,12 +111,12 @@ func TestLinkCreateTwo(t *testing.T) {
125 125
 		t.Fatalf("Failed to create bridge: %v", err)
126 126
 	}
127 127
 
128
-	_, err = d.CreateEndpoint("dummy", "ep", "s1", nil)
128
+	_, err = d.CreateEndpoint("dummy", "ep", nil)
129 129
 	if err != nil {
130 130
 		t.Fatalf("Failed to create a link: %s", err.Error())
131 131
 	}
132 132
 
133
-	_, err = d.CreateEndpoint("dummy", "ep", "s1", nil)
133
+	_, err = d.CreateEndpoint("dummy", "ep", nil)
134 134
 	if err != nil {
135 135
 		if err != driverapi.ErrEndpointExists {
136 136
 			t.Fatalf("Failed with a wrong error :%s", err.Error())
... ...
@@ -155,7 +141,7 @@ func TestLinkCreateNoEnableIPv6(t *testing.T) {
155 155
 		t.Fatalf("Failed to create bridge: %v", err)
156 156
 	}
157 157
 
158
-	sinfo, err := d.CreateEndpoint("dummy", "ep", "sb2", nil)
158
+	sinfo, err := d.CreateEndpoint("dummy", "ep", nil)
159 159
 	if err != nil {
160 160
 		t.Fatalf("Failed to create a link: %s", err.Error())
161 161
 	}
... ...
@@ -186,7 +172,7 @@ func TestLinkDelete(t *testing.T) {
186 186
 		t.Fatalf("Failed to create bridge: %v", err)
187 187
 	}
188 188
 
189
-	_, err = d.CreateEndpoint("dummy", "ep1", "s1", nil)
189
+	_, err = d.CreateEndpoint("dummy", "ep1", nil)
190 190
 	if err != nil {
191 191
 		t.Fatalf("Failed to create a link: %s", err.Error())
192 192
 	}
... ...
@@ -29,8 +29,15 @@ func setupBridgeIPv6(config *Configuration, i *bridgeInterface) error {
29 29
 		return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
30 30
 	}
31 31
 
32
-	if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
33
-		return &IPv6AddrAddError{ip: bridgeIPv6, err: err}
32
+	_, addrsv6, err := i.addresses()
33
+	if err != nil {
34
+		return err
35
+	}
36
+
37
+	if len(addrsv6) == 0 {
38
+		if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
39
+			return &IPv6AddrAddError{ip: bridgeIPv6, err: err}
40
+		}
34 41
 	}
35 42
 
36 43
 	// Store bridge network and default gateway
... ...
@@ -12,6 +12,9 @@ var (
12 12
 	// ErrInvalidNetworkDriver is returned if an invalid driver
13 13
 	// instance is passed.
14 14
 	ErrInvalidNetworkDriver = errors.New("invalid driver bound to network")
15
+	// ErrInvalidJoin is returned if a join is attempted on an endpoint
16
+	// which already has a container joined.
17
+	ErrInvalidJoin = errors.New("A container has already joined the endpoint")
15 18
 )
16 19
 
17 20
 // NetworkTypeError type is returned when the network type string is not
... ...
@@ -61,3 +64,11 @@ type UnknownEndpointError struct {
61 61
 func (uee *UnknownEndpointError) Error() string {
62 62
 	return fmt.Sprintf("unknown endpoint %s id %s", uee.name, uee.id)
63 63
 }
64
+
65
+// InvalidContainerIDError is returned when an invalid container id is passed
66
+// in Join/Leave
67
+type InvalidContainerIDError string
68
+
69
+func (id InvalidContainerIDError) Error() string {
70
+	return fmt.Sprintf("invalid container id %s", string(id))
71
+}
... ...
@@ -69,7 +69,7 @@ func TestBridge(t *testing.T) {
69 69
 		t.Fatal(err)
70 70
 	}
71 71
 
72
-	ep, err := network.CreateEndpoint("testep", "sb1", nil)
72
+	ep, err := network.CreateEndpoint("testep", nil)
73 73
 	if err != nil {
74 74
 		t.Fatal(err)
75 75
 	}
... ...
@@ -199,7 +199,7 @@ func TestDeleteNetworkWithActiveEndpoints(t *testing.T) {
199 199
 		t.Fatal(err)
200 200
 	}
201 201
 
202
-	ep, err := network.CreateEndpoint("testep", "sb2", nil)
202
+	ep, err := network.CreateEndpoint("testep", nil)
203 203
 	if err != nil {
204 204
 		t.Fatal(err)
205 205
 	}
... ...
@@ -267,7 +267,7 @@ func TestUnknownEndpoint(t *testing.T) {
267 267
 		t.Fatal(err)
268 268
 	}
269 269
 
270
-	ep, err := network.CreateEndpoint("testep", "sb1", nil)
270
+	ep, err := network.CreateEndpoint("testep", nil)
271 271
 	if err != nil {
272 272
 		t.Fatal(err)
273 273
 	}
... ...
@@ -308,11 +308,11 @@ func TestNetworkEndpointsWalkers(t *testing.T) {
308 308
 	if err != nil {
309 309
 		t.Fatal(err)
310 310
 	}
311
-	ep11, err := net1.CreateEndpoint("ep11", "sbox1", nil)
311
+	ep11, err := net1.CreateEndpoint("ep11", nil)
312 312
 	if err != nil {
313 313
 		t.Fatal(err)
314 314
 	}
315
-	ep12, err := net1.CreateEndpoint("ep12", "sbox2", nil)
315
+	ep12, err := net1.CreateEndpoint("ep12", nil)
316 316
 	if err != nil {
317 317
 		t.Fatal(err)
318 318
 	}
... ...
@@ -434,11 +434,11 @@ func TestNetworkQuery(t *testing.T) {
434 434
 	if err != nil {
435 435
 		t.Fatal(err)
436 436
 	}
437
-	ep11, err := net1.CreateEndpoint("ep11", "sbox1", nil)
437
+	ep11, err := net1.CreateEndpoint("ep11", nil)
438 438
 	if err != nil {
439 439
 		t.Fatal(err)
440 440
 	}
441
-	ep12, err := net1.CreateEndpoint("ep12", "sbox2", nil)
441
+	ep12, err := net1.CreateEndpoint("ep12", nil)
442 442
 	if err != nil {
443 443
 		t.Fatal(err)
444 444
 	}
... ...
@@ -469,3 +469,136 @@ func TestNetworkQuery(t *testing.T) {
469 469
 	}
470 470
 
471 471
 }
472
+
473
+const containerID = "valid_container"
474
+
475
+func TestEndpointJoin(t *testing.T) {
476
+	defer netutils.SetupTestNetNS(t)()
477
+
478
+	n, err := createTestNetwork("bridge", "testnetwork", options.Generic{})
479
+	if err != nil {
480
+		t.Fatal(err)
481
+	}
482
+
483
+	ep, err := n.CreateEndpoint("ep1", nil)
484
+	if err != nil {
485
+		t.Fatal(err)
486
+	}
487
+
488
+	_, err = ep.Join(containerID)
489
+	if err != nil {
490
+		t.Fatal(err)
491
+	}
492
+
493
+	err = ep.Leave(containerID)
494
+	if err != nil {
495
+		t.Fatal(err)
496
+	}
497
+}
498
+
499
+func TestEndpointJoinInvalidContainerId(t *testing.T) {
500
+	defer netutils.SetupTestNetNS(t)()
501
+
502
+	n, err := createTestNetwork("bridge", "testnetwork", options.Generic{})
503
+	if err != nil {
504
+		t.Fatal(err)
505
+	}
506
+
507
+	ep, err := n.CreateEndpoint("ep1", nil)
508
+	if err != nil {
509
+		t.Fatal(err)
510
+	}
511
+
512
+	_, err = ep.Join("")
513
+	if err == nil {
514
+		t.Fatal("Expected to fail join with empty container id string")
515
+	}
516
+
517
+	if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
518
+		t.Fatalf("Failed for unexpected reason: %v", err)
519
+	}
520
+}
521
+
522
+func TestEndpointMultipleJoins(t *testing.T) {
523
+	defer netutils.SetupTestNetNS(t)()
524
+
525
+	n, err := createTestNetwork("bridge", "testnetwork", options.Generic{})
526
+	if err != nil {
527
+		t.Fatal(err)
528
+	}
529
+
530
+	ep, err := n.CreateEndpoint("ep1", nil)
531
+	if err != nil {
532
+		t.Fatal(err)
533
+	}
534
+
535
+	_, err = ep.Join(containerID)
536
+	if err != nil {
537
+		t.Fatal(err)
538
+	}
539
+
540
+	_, err = ep.Join("container2")
541
+	if err == nil {
542
+		t.Fatal("Expected to fail multiple joins for the same endpoint")
543
+	}
544
+
545
+	if err != libnetwork.ErrInvalidJoin {
546
+		t.Fatalf("Failed for unexpected reason: %v", err)
547
+	}
548
+
549
+	err = ep.Leave(containerID)
550
+	if err != nil {
551
+		t.Fatal(err)
552
+	}
553
+}
554
+
555
+func TestEndpointInvalidLeave(t *testing.T) {
556
+	defer netutils.SetupTestNetNS(t)()
557
+
558
+	n, err := createTestNetwork("bridge", "testnetwork", options.Generic{})
559
+	if err != nil {
560
+		t.Fatal(err)
561
+	}
562
+
563
+	ep, err := n.CreateEndpoint("ep1", nil)
564
+	if err != nil {
565
+		t.Fatal(err)
566
+	}
567
+
568
+	err = ep.Leave(containerID)
569
+	if err == nil {
570
+		t.Fatal("Expected to fail leave from an endpoint which has no active join")
571
+	}
572
+
573
+	if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
574
+		t.Fatalf("Failed for unexpected reason: %v", err)
575
+	}
576
+
577
+	_, err = ep.Join(containerID)
578
+	if err != nil {
579
+		t.Fatal(err)
580
+	}
581
+
582
+	err = ep.Leave("")
583
+	if err == nil {
584
+		t.Fatal("Expected to fail leave with empty container id")
585
+	}
586
+
587
+	if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
588
+		t.Fatalf("Failed for unexpected reason: %v", err)
589
+	}
590
+
591
+	err = ep.Leave("container2")
592
+	if err == nil {
593
+		t.Fatal("Expected to fail leave with wrong container id")
594
+	}
595
+
596
+	if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
597
+		t.Fatalf("Failed for unexpected reason: %v", err)
598
+	}
599
+
600
+	err = ep.Leave(containerID)
601
+	if err != nil {
602
+		t.Fatal(err)
603
+	}
604
+}
... ...
@@ -2,39 +2,40 @@
2 2
 Package libnetwork provides the basic functionality and extension points to
3 3
 create network namespaces and allocate interfaces for containers to use.
4 4
 
5
-    // Create a new controller instance
6
-    controller := libnetwork.New()
7
-
8
-    // This option is only needed for in-tree drivers. Plugins(in future) will get
9
-    // their options through plugin infrastructure.
10
-    option := options.Generic{}
11
-    err := controller.NewNetworkDriver("bridge", option)
12
-    if err != nil {
13
-        return
14
-    }
15
-
16
-    netOptions := options.Generic{}
17
-    // Create a network for containers to join.
18
-    network, err := controller.NewNetwork("bridge", "network1", netOptions)
19
-    if err != nil {
20
-    	return
21
-    }
22
-
23
-    // For a new container: create a sandbox instance (providing a unique key).
24
-    // For linux it is a filesystem path
25
-    networkPath := "/var/lib/docker/.../4d23e"
26
-    networkNamespace, err := sandbox.NewSandbox(networkPath)
27
-    if err != nil {
28
-	    return
29
-    }
30
-
31
-    // For each new container: allocate IP and interfaces. The returned network
32
-    // settings will be used for container infos (inspect and such), as well as
33
-    // iptables rules for port publishing.
34
-    ep, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), nil)
35
-    if err != nil {
36
-	    return
37
-    }
5
+	// Create a new controller instance
6
+	controller := libnetwork.New()
7
+
8
+	// Select and configure the network driver
9
+	networkType := "bridge"
10
+	option := options.Generic{}
11
+	err := controller.ConfigureNetworkDriver(networkType, option)
12
+	if err != nil {
13
+		return
14
+	}
15
+
16
+	netOptions := options.Generic{}
17
+	// Create a network for containers to join.
18
+	network, err := controller.NewNetwork(networkType, "network1", netOptions)
19
+	if err != nil {
20
+		return
21
+	}
22
+
23
+	// For each new container: allocate IP and interfaces. The returned network
24
+	// settings will be used for container infos (inspect and such), as well as
25
+	// iptables rules for port publishing. This info is contained or accessible
26
+	// from the returned endpoint.
27
+	ep, err := network.CreateEndpoint("Endpoint1", nil)
28
+	if err != nil {
29
+		return
30
+	}
31
+
32
+	// A container can join the endpoint by providing the container ID to the join
33
+	// api which returns the sandbox key which can be used to access the sandbox
34
+	// created for the container during join.
35
+	_, err = ep.Join("container1")
36
+	if err != nil {
37
+		return
38
+	}
38 39
 */
39 40
 package libnetwork
40 41
 
... ...
@@ -85,7 +86,7 @@ type Network interface {
85 85
 	// Create a new endpoint to this network symbolically identified by the
86 86
 	// specified unique name. The options parameter carry driver specific options.
87 87
 	// Labels support will be added in the near future.
88
-	CreateEndpoint(name string, sboxKey string, options interface{}) (Endpoint, error)
88
+	CreateEndpoint(name string, options interface{}) (Endpoint, error)
89 89
 
90 90
 	// Delete the network.
91 91
 	Delete() error
... ...
@@ -118,6 +119,15 @@ type Endpoint interface {
118 118
 	// Network returns the name of the network to which this endpoint is attached.
119 119
 	Network() string
120 120
 
121
+	// Join creates a new sandbox for the given container ID and populates the
122
+	// network resources allocated for the endpoint and joins the sandbox to
123
+	// the endpoint. It returns the sandbox key to the caller
124
+	Join(containerID string) (string, error)
125
+
126
+	// Leave removes the sandbox associated with  container ID and detaches
127
+	// the network resources populated in the sandbox
128
+	Leave(containerID string) error
129
+
121 130
 	// SandboxInfo returns the sandbox information for this endpoint.
122 131
 	SandboxInfo() *sandbox.Info
123 132
 
... ...
@@ -144,20 +154,29 @@ type endpoint struct {
144 144
 	id          types.UUID
145 145
 	network     *network
146 146
 	sandboxInfo *sandbox.Info
147
+	sandBox     sandbox.Sandbox
148
+	containerID string
149
+}
150
+
151
+type sandboxData struct {
152
+	sandbox sandbox.Sandbox
153
+	refCnt  int
147 154
 }
148 155
 
149 156
 type networkTable map[types.UUID]*network
150 157
 type endpointTable map[types.UUID]*endpoint
158
+type sandboxTable map[string]sandboxData
151 159
 
152 160
 type controller struct {
153
-	networks networkTable
154
-	drivers  driverTable
161
+	networks  networkTable
162
+	drivers   driverTable
163
+	sandboxes sandboxTable
155 164
 	sync.Mutex
156 165
 }
157 166
 
158 167
 // New creates a new instance of network controller.
159 168
 func New() NetworkController {
160
-	return &controller{networkTable{}, enumerateDrivers(), sync.Mutex{}}
169
+	return &controller{networkTable{}, enumerateDrivers(), sandboxTable{}, sync.Mutex{}}
161 170
 }
162 171
 
163 172
 func (c *controller) ConfigureNetworkDriver(networkType string, options interface{}) error {
... ...
@@ -256,6 +275,51 @@ func (c *controller) NetworkByID(id string) Network {
256 256
 	return nil
257 257
 }
258 258
 
259
+func (c *controller) sandboxAdd(key string) (sandbox.Sandbox, error) {
260
+	c.Lock()
261
+	defer c.Unlock()
262
+
263
+	sData, ok := c.sandboxes[key]
264
+	if !ok {
265
+		sb, err := sandbox.NewSandbox(key)
266
+		if err != nil {
267
+			return nil, err
268
+		}
269
+
270
+		sData = sandboxData{sandbox: sb, refCnt: 1}
271
+		c.sandboxes[key] = sData
272
+		return sData.sandbox, nil
273
+	}
274
+
275
+	sData.refCnt++
276
+	return sData.sandbox, nil
277
+}
278
+
279
+func (c *controller) sandboxRm(key string) {
280
+	c.Lock()
281
+	defer c.Unlock()
282
+
283
+	sData := c.sandboxes[key]
284
+	sData.refCnt--
285
+
286
+	if sData.refCnt == 0 {
287
+		sData.sandbox.Destroy()
288
+		delete(c.sandboxes, key)
289
+	}
290
+}
291
+
292
+func (c *controller) sandboxGet(key string) sandbox.Sandbox {
293
+	c.Lock()
294
+	defer c.Unlock()
295
+
296
+	sData, ok := c.sandboxes[key]
297
+	if !ok {
298
+		return nil
299
+	}
300
+
301
+	return sData.sandbox
302
+}
303
+
259 304
 func (n *network) Name() string {
260 305
 	return n.name
261 306
 }
... ...
@@ -304,13 +368,13 @@ func (n *network) Delete() error {
304 304
 	return err
305 305
 }
306 306
 
307
-func (n *network) CreateEndpoint(name string, sboxKey string, options interface{}) (Endpoint, error) {
307
+func (n *network) CreateEndpoint(name string, options interface{}) (Endpoint, error) {
308 308
 	ep := &endpoint{name: name}
309 309
 	ep.id = types.UUID(stringid.GenerateRandomID())
310 310
 	ep.network = n
311 311
 
312 312
 	d := n.driver
313
-	sinfo, err := d.CreateEndpoint(n.id, ep.id, sboxKey, options)
313
+	sinfo, err := d.CreateEndpoint(n.id, ep.id, options)
314 314
 	if err != nil {
315 315
 		return nil, err
316 316
 	}
... ...
@@ -387,6 +451,60 @@ func (ep *endpoint) SandboxInfo() *sandbox.Info {
387 387
 	return ep.sandboxInfo.GetCopy()
388 388
 }
389 389
 
390
+func (ep *endpoint) Join(containerID string) (string, error) {
391
+	if containerID == "" {
392
+		return "", InvalidContainerIDError(containerID)
393
+	}
394
+
395
+	if ep.containerID != "" {
396
+		return "", ErrInvalidJoin
397
+	}
398
+
399
+	sboxKey := sandbox.GenerateKey(containerID)
400
+	sb, err := ep.network.ctrlr.sandboxAdd(sboxKey)
401
+	if err != nil {
402
+		return "", err
403
+	}
404
+	defer func() {
405
+		if err != nil {
406
+			ep.network.ctrlr.sandboxRm(sboxKey)
407
+		}
408
+	}()
409
+
410
+	sinfo := ep.SandboxInfo()
411
+	if sinfo != nil {
412
+		for _, i := range sinfo.Interfaces {
413
+			err = sb.AddInterface(i)
414
+			if err != nil {
415
+				return "", err
416
+			}
417
+		}
418
+
419
+		err = sb.SetGateway(sinfo.Gateway)
420
+		if err != nil {
421
+			return "", err
422
+		}
423
+
424
+		err = sb.SetGatewayIPv6(sinfo.GatewayIPv6)
425
+		if err != nil {
426
+			return "", err
427
+		}
428
+	}
429
+
430
+	ep.containerID = containerID
431
+	return sb.Key(), nil
432
+}
433
+
434
+func (ep *endpoint) Leave(containerID string) error {
435
+	if ep.containerID == "" || containerID == "" || ep.containerID != containerID {
436
+		return InvalidContainerIDError(containerID)
437
+	}
438
+
439
+	ep.network.ctrlr.sandboxRm(sandbox.GenerateKey(containerID))
440
+	ep.containerID = ""
441
+	return nil
442
+}
443
+
390 444
 func (ep *endpoint) Delete() error {
391 445
 	var err error
392 446
 
... ...
@@ -51,9 +51,15 @@ func programGateway(path string, gw net.IP) error {
51 51
 	}
52 52
 	defer netns.Set(origns)
53 53
 
54
+	gwRoutes, err := netlink.RouteGet(gw)
55
+	if err != nil {
56
+		return fmt.Errorf("route for the gateway could not be found: %v", err)
57
+	}
58
+
54 59
 	return netlink.RouteAdd(&netlink.Route{
55
-		Scope: netlink.SCOPE_UNIVERSE,
56
-		Gw:    gw,
60
+		Scope:     netlink.SCOPE_UNIVERSE,
61
+		LinkIndex: gwRoutes[0].LinkIndex,
62
+		Gw:        gw,
57 63
 	})
58 64
 }
59 65
 
... ...
@@ -5,12 +5,17 @@ import (
5 5
 	"net"
6 6
 	"os"
7 7
 	"runtime"
8
+	"sync"
8 9
 	"syscall"
9 10
 
10 11
 	"github.com/vishvananda/netlink"
11 12
 	"github.com/vishvananda/netns"
12 13
 )
13 14
 
15
+const prefix = "/var/lib/docker/network"
16
+
17
+var once sync.Once
18
+
14 19
 // The networkNamespace type is the linux implementation of the Sandbox
15 20
 // interface. It represents a linux network namespace, and moves an interface
16 21
 // into it when called on method AddInterface or sets the gateway etc.
... ...
@@ -19,6 +24,24 @@ type networkNamespace struct {
19 19
 	sinfo *Info
20 20
 }
21 21
 
22
+func creatBasePath() {
23
+	err := os.MkdirAll(prefix, 0644)
24
+	if err != nil && !os.IsExist(err) {
25
+		panic("Could not create net namespace path directory")
26
+	}
27
+}
28
+
29
+// GenerateKey generates a sandbox key based on the passed
30
+// container id.
31
+func GenerateKey(containerID string) string {
32
+	maxLen := 12
33
+	if len(containerID) < maxLen {
34
+		maxLen = len(containerID)
35
+	}
36
+
37
+	return prefix + "/" + containerID[:maxLen]
38
+}
39
+
22 40
 // NewSandbox provides a new sandbox instance created in an os specific way
23 41
 // provided a key which uniquely identifies the sandbox
24 42
 func NewSandbox(key string) (Sandbox, error) {
... ...
@@ -63,6 +86,8 @@ func createNetworkNamespace(path string) (Sandbox, error) {
63 63
 
64 64
 func createNamespaceFile(path string) (err error) {
65 65
 	var f *os.File
66
+
67
+	once.Do(creatBasePath)
66 68
 	if f, err = os.Create(path); err == nil {
67 69
 		f.Close()
68 70
 	}
... ...
@@ -130,6 +155,10 @@ func (n *networkNamespace) AddInterface(i *Interface) error {
130 130
 }
131 131
 
132 132
 func (n *networkNamespace) SetGateway(gw net.IP) error {
133
+	if len(gw) == 0 {
134
+		return nil
135
+	}
136
+
133 137
 	err := programGateway(n.path, gw)
134 138
 	if err == nil {
135 139
 		n.sinfo.Gateway = gw
... ...
@@ -162,5 +191,9 @@ func (n *networkNamespace) Key() string {
162 162
 func (n *networkNamespace) Destroy() error {
163 163
 	// Assuming no running process is executing in this network namespace,
164 164
 	// unmounting is sufficient to destroy it.
165
-	return syscall.Unmount(n.path, syscall.MNT_DETACH)
165
+	if err := syscall.Unmount(n.path, syscall.MNT_DETACH); err != nil {
166
+		return err
167
+	}
168
+
169
+	return os.Remove(n.path)
166 170
 }
... ...
@@ -54,7 +54,8 @@ func newInfo(t *testing.T) (*Info, error) {
54 54
 	intf.Address = addr
55 55
 	intf.Address.IP = ip4
56 56
 
57
-	ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
57
+	// ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
58
+	ip6, addrv6, err := net.ParseCIDR("fe80::2/64")
58 59
 	if err != nil {
59 60
 		return nil, err
60 61
 	}
... ...
@@ -63,7 +64,8 @@ func newInfo(t *testing.T) (*Info, error) {
63 63
 
64 64
 	sinfo := &Info{Interfaces: []*Interface{intf}}
65 65
 	sinfo.Gateway = net.ParseIP("192.168.1.1")
66
-	sinfo.GatewayIPv6 = net.ParseIP("2001:DB8::1")
66
+	// sinfo.GatewayIPv6 = net.ParseIP("2001:DB8::1")
67
+	sinfo.GatewayIPv6 = net.ParseIP("fe80::1")
67 68
 
68 69
 	return sinfo, nil
69 70
 }