Browse code

libnetwork vendoring

Vendoring libnetwork @ 9f0563ea8f430d8828553aac97161cbff4056436

Brings in:
* Support for overlay network driver in 3.10+ kernels
* Freebsd compilation fixes
* Remove .dockerinit dependency
* IPAM driver capability support
* Network internal mode support
* Misc. fixes

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

Jana Radhakrishnan authored on 2015/12/19 04:03:57
Showing 23 changed files
... ...
@@ -16,7 +16,6 @@ network. Docker Engine supports multi-host networking out-of-the-box through the
16 16
 `overlay` network driver.  Unlike `bridge` networks, overlay networks require
17 17
 some pre-existing conditions before you can create one. These conditions are:
18 18
 
19
-* A host with a 3.16 kernel version or higher.
20 19
 * Access to a key-value store. Docker supports Consul, Etcd, and ZooKeeper (Distributed store) key-value stores.
21 20
 * A cluster of hosts with connectivity to the key-value store.
22 21
 * A properly configured Engine `daemon` on each host in the cluster.
... ...
@@ -46,7 +45,7 @@ key-value stores. This example uses Consul.
46 46
 
47 47
 1. Log into a system prepared with the prerequisite Docker Engine, Docker Machine, and VirtualBox software.
48 48
 
49
-2. Provision a VirtualBox machine called `mh-keystore`.  
49
+2. Provision a VirtualBox machine called `mh-keystore`.
50 50
 
51 51
 		$ docker-machine create -d virtualbox mh-keystore
52 52
 
... ...
@@ -23,7 +23,7 @@ clone git golang.org/x/net 47990a1ba55743e6ef1affd3a14e5bac8553615d https://gith
23 23
 clone git github.com/docker/go-units v0.2.0
24 24
 
25 25
 #get libnetwork packages
26
-clone git github.com/docker/libnetwork bbd6e6d8ca1e7c9b42f6f53277b0bde72847ff90
26
+clone git github.com/docker/libnetwork 9f0563ea8f430d8828553aac97161cbff4056436
27 27
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
28 28
 clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
29 29
 clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
... ...
@@ -121,7 +121,8 @@ type driverData struct {
121 121
 }
122 122
 
123 123
 type ipamData struct {
124
-	driver ipamapi.Ipam
124
+	driver     ipamapi.Ipam
125
+	capability *ipamapi.Capability
125 126
 	// default address spaces are provided by ipam driver at registration time
126 127
 	defaultLocalAddressSpace, defaultGlobalAddressSpace string
127 128
 }
... ...
@@ -306,7 +307,7 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver,
306 306
 	return nil
307 307
 }
308 308
 
309
-func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error {
309
+func (c *controller) registerIpamDriver(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
310 310
 	if !config.IsValidName(name) {
311 311
 		return ErrInvalidName(name)
312 312
 	}
... ...
@@ -322,7 +323,7 @@ func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error
322 322
 		return types.InternalErrorf("ipam driver %q failed to return default address spaces: %v", name, err)
323 323
 	}
324 324
 	c.Lock()
325
-	c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS}
325
+	c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS, capability: caps}
326 326
 	c.Unlock()
327 327
 
328 328
 	log.Debugf("Registering ipam driver: %q", name)
... ...
@@ -330,6 +331,14 @@ func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error
330 330
 	return nil
331 331
 }
332 332
 
333
+func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error {
334
+	return c.registerIpamDriver(name, driver, &ipamapi.Capability{})
335
+}
336
+
337
+func (c *controller) RegisterIpamDriverWithCapabilities(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
338
+	return c.registerIpamDriver(name, driver, caps)
339
+}
340
+
333 341
 // NewNetwork creates a new network of the specified network type. The options
334 342
 // are network specific and modeled in a generic way.
335 343
 func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
... ...
@@ -103,6 +103,9 @@ func (sb *sandbox) needDefaultGW() bool {
103 103
 		if ep.getNetwork().Type() == "null" || ep.getNetwork().Type() == "host" {
104 104
 			continue
105 105
 		}
106
+		if ep.getNetwork().Internal() {
107
+			return false
108
+		}
106 109
 		if ep.joinInfo.disableGatewayService {
107 110
 			return false
108 111
 		}
... ...
@@ -490,6 +490,12 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati
490 490
 		config.EnableIPv6 = val.(bool)
491 491
 	}
492 492
 
493
+	if val, ok := option[netlabel.Internal]; ok {
494
+		if internal, ok := val.(bool); ok && internal {
495
+			return nil, &driverapi.ErrNotImplemented{}
496
+		}
497
+	}
498
+
493 499
 	// Finally validate the configuration
494 500
 	if err = config.Validate(); err != nil {
495 501
 		return nil, err
... ...
@@ -157,6 +157,6 @@ func isPacketForwardingEnabled(ipVer ipVersion, iface string) (bool, error) {
157 157
 }
158 158
 
159 159
 func isRunningInContainer() bool {
160
-	_, err := os.Stat("/.dockerinit")
160
+	_, err := os.Stat("/.dockerenv")
161 161
 	return !os.IsNotExist(err)
162 162
 }
... ...
@@ -62,6 +62,13 @@ func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
62 62
 		return nil
63 63
 	}
64 64
 
65
+	// Store and program user specified bridge network and network gateway
66
+	i.bridgeIPv6 = config.AddressIPv6
67
+	i.gatewayIPv6 = config.AddressIPv6.IP
68
+	if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: i.bridgeIPv6}); err != nil {
69
+		return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: err}
70
+	}
71
+
65 72
 	// Setting route to global IPv6 subnet
66 73
 	logrus.Debugf("Adding route to IPv6 network %s via device %s", config.AddressIPv6.String(), config.BridgeName)
67 74
 	err = netlink.RouteAdd(&netlink.Route{
68 75
new file mode 100644
... ...
@@ -0,0 +1,131 @@
0
+package overlay
1
+
2
+import (
3
+	"fmt"
4
+	"sync"
5
+
6
+	"github.com/Sirupsen/logrus"
7
+	"github.com/docker/libnetwork/iptables"
8
+)
9
+
10
+const globalChain = "DOCKER-OVERLAY"
11
+
12
+var filterOnce sync.Once
13
+
14
+func rawIPTables(args ...string) error {
15
+	if output, err := iptables.Raw(args...); err != nil {
16
+		return fmt.Errorf("unable to add overlay filter: %v", err)
17
+	} else if len(output) != 0 {
18
+		return fmt.Errorf("unable to add overlay filter: %s", string(output))
19
+	}
20
+
21
+	return nil
22
+}
23
+
24
+func chainExists(cname string) bool {
25
+	if _, err := iptables.Raw("-L", cname); err != nil {
26
+		return false
27
+	}
28
+
29
+	return true
30
+}
31
+
32
+func setupGlobalChain() {
33
+	if err := rawIPTables("-N", globalChain); err != nil {
34
+		logrus.Debugf("could not create global overlay chain: %v", err)
35
+	}
36
+
37
+	if err := rawIPTables("-A", globalChain, "-j", "RETURN"); err != nil {
38
+		logrus.Debugf("could not install default return chain in the overlay global chain: %v", err)
39
+	}
40
+}
41
+
42
+func setNetworkChain(cname string, remove bool) error {
43
+	// Initialize the onetime global overlay chain
44
+	filterOnce.Do(setupGlobalChain)
45
+
46
+	exists := chainExists(cname)
47
+
48
+	opt := "-N"
49
+	// In case of remove, make sure to flush the rules in the chain
50
+	if remove && exists {
51
+		if err := rawIPTables("-F", cname); err != nil {
52
+			return fmt.Errorf("failed to flush overlay network chain %s rules: %v", cname, err)
53
+		}
54
+		opt = "-X"
55
+	}
56
+
57
+	if (!remove && !exists) || (remove && exists) {
58
+		if err := rawIPTables(opt, cname); err != nil {
59
+			return fmt.Errorf("failed network chain operation %q for chain %s: %v", opt, cname, err)
60
+		}
61
+	}
62
+
63
+	if !remove {
64
+		if !iptables.Exists(iptables.Filter, cname, "-j", "DROP") {
65
+			if err := rawIPTables("-A", cname, "-j", "DROP"); err != nil {
66
+				return fmt.Errorf("failed adding default drop rule to overlay network chain %s: %v", cname, err)
67
+			}
68
+		}
69
+	}
70
+
71
+	return nil
72
+}
73
+
74
+func addNetworkChain(cname string) error {
75
+	return setNetworkChain(cname, false)
76
+}
77
+
78
+func removeNetworkChain(cname string) error {
79
+	return setNetworkChain(cname, true)
80
+}
81
+
82
+func setFilters(cname, brName string, remove bool) error {
83
+	opt := "-I"
84
+	if remove {
85
+		opt = "-D"
86
+	}
87
+
88
+	// Everytime we set filters for a new subnet make sure to move the global overlay hook to the top of the both the OUTPUT and forward chains
89
+	if !remove {
90
+		for _, chain := range []string{"OUTPUT", "FORWARD"} {
91
+			exists := iptables.Exists(iptables.Filter, chain, "-j", globalChain)
92
+			if exists {
93
+				if err := rawIPTables("-D", chain, "-j", globalChain); err != nil {
94
+					return fmt.Errorf("failed to delete overlay hook in chain %s while moving the hook: %v", chain, err)
95
+				}
96
+			}
97
+
98
+			if err := rawIPTables("-I", chain, "-j", globalChain); err != nil {
99
+				return fmt.Errorf("failed to insert overlay hook in chain %s: %v", chain, err)
100
+			}
101
+		}
102
+	}
103
+
104
+	// Insert/Delete the rule to jump to per-bridge chain
105
+	exists := iptables.Exists(iptables.Filter, globalChain, "-o", brName, "-j", cname)
106
+	if (!remove && !exists) || (remove && exists) {
107
+		if err := rawIPTables(opt, globalChain, "-o", brName, "-j", cname); err != nil {
108
+			return fmt.Errorf("failed to add per-bridge filter rule for bridge %s, network chain %s: %v", brName, cname, err)
109
+		}
110
+	}
111
+
112
+	exists = iptables.Exists(iptables.Filter, cname, "-i", brName, "-j", "ACCEPT")
113
+	if (!remove && exists) || (remove && !exists) {
114
+		return nil
115
+	}
116
+
117
+	if err := rawIPTables(opt, cname, "-i", brName, "-j", "ACCEPT"); err != nil {
118
+		return fmt.Errorf("failed to add overlay filter rile for network chain %s, bridge %s: %v", cname, brName, err)
119
+	}
120
+
121
+	return nil
122
+}
123
+
124
+func addFilters(cname, brName string) error {
125
+	return setFilters(cname, brName, false)
126
+}
127
+
128
+func removeFilters(cname, brName string) error {
129
+	return setFilters(cname, brName, true)
130
+}
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"encoding/json"
5 5
 	"fmt"
6 6
 	"net"
7
+	"os"
7 8
 	"sync"
8 9
 	"syscall"
9 10
 
... ...
@@ -12,11 +13,17 @@ import (
12 12
 	"github.com/docker/libnetwork/driverapi"
13 13
 	"github.com/docker/libnetwork/netutils"
14 14
 	"github.com/docker/libnetwork/osl"
15
+	"github.com/docker/libnetwork/resolvconf"
15 16
 	"github.com/docker/libnetwork/types"
16 17
 	"github.com/vishvananda/netlink"
17 18
 	"github.com/vishvananda/netlink/nl"
18 19
 )
19 20
 
21
+var (
22
+	hostMode     bool
23
+	hostModeOnce sync.Once
24
+)
25
+
20 26
 type networkTable map[string]*network
21 27
 
22 28
 type subnet struct {
... ...
@@ -87,22 +94,6 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat
87 87
 	return nil
88 88
 }
89 89
 
90
-/* func (d *driver) createNetworkfromStore(nid string) (*network, error) {
91
-	n := &network{
92
-		id:        nid,
93
-		driver:    d,
94
-		endpoints: endpointTable{},
95
-		once:      &sync.Once{},
96
-		subnets:   []*subnet{},
97
-	}
98
-
99
-	err := d.store.GetObject(datastore.Key(n.Key()...), n)
100
-	if err != nil {
101
-		return nil, fmt.Errorf("unable to get network %q from data store, %v", nid, err)
102
-	}
103
-	return n, nil
104
-}*/
105
-
106 90
 func (d *driver) DeleteNetwork(nid string) error {
107 91
 	if nid == "" {
108 92
 		return fmt.Errorf("invalid network id")
... ...
@@ -171,24 +162,110 @@ func (n *network) destroySandbox() {
171 171
 		}
172 172
 
173 173
 		for _, s := range n.subnets {
174
+			if hostMode {
175
+				if err := removeFilters(n.id[:12], s.brName); err != nil {
176
+					logrus.Warnf("Could not remove overlay filters: %v", err)
177
+				}
178
+			}
179
+
174 180
 			if s.vxlanName != "" {
175
-				err := deleteVxlan(s.vxlanName)
181
+				err := deleteInterface(s.vxlanName)
176 182
 				if err != nil {
177 183
 					logrus.Warnf("could not cleanup sandbox properly: %v", err)
178 184
 				}
179 185
 			}
180 186
 		}
187
+
188
+		if hostMode {
189
+			if err := removeNetworkChain(n.id[:12]); err != nil {
190
+				logrus.Warnf("could not remove network chain: %v", err)
191
+			}
192
+		}
193
+
181 194
 		sbox.Destroy()
182 195
 		n.setSandbox(nil)
183 196
 	}
184 197
 }
185 198
 
186
-func (n *network) initSubnetSandbox(s *subnet) error {
187
-	// create a bridge and vxlan device for this subnet and move it to the sandbox
188
-	brName, err := netutils.GenerateIfaceName("bridge", 7)
199
+func setHostMode() {
200
+	if os.Getenv("_OVERLAY_HOST_MODE") != "" {
201
+		hostMode = true
202
+		return
203
+	}
204
+
205
+	err := createVxlan("testvxlan", 1)
189 206
 	if err != nil {
190
-		return err
207
+		logrus.Errorf("Failed to create testvxlan interface: %v", err)
208
+		return
209
+	}
210
+
211
+	defer deleteInterface("testvxlan")
212
+
213
+	path := "/proc/self/ns/net"
214
+	f, err := os.OpenFile(path, os.O_RDONLY, 0)
215
+	if err != nil {
216
+		logrus.Errorf("Failed to open path %s for network namespace for setting host mode: %v", path, err)
217
+		return
218
+	}
219
+	defer f.Close()
220
+
221
+	nsFD := f.Fd()
222
+
223
+	iface, err := netlink.LinkByName("testvxlan")
224
+	if err != nil {
225
+		logrus.Errorf("Failed to get link testvxlan: %v", err)
226
+		return
227
+	}
228
+
229
+	// If we are not able to move the vxlan interface to a namespace
230
+	// then fallback to host mode
231
+	if err := netlink.LinkSetNsFd(iface, int(nsFD)); err != nil {
232
+		hostMode = true
233
+	}
234
+}
235
+
236
+func (n *network) generateVxlanName(s *subnet) string {
237
+	return "vx-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + n.id[:5]
238
+}
239
+
240
+func (n *network) generateBridgeName(s *subnet) string {
241
+	return "ov-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + n.id[:5]
242
+}
243
+
244
+func isOverlap(nw *net.IPNet) bool {
245
+	var nameservers []string
246
+
247
+	if rc, err := resolvconf.Get(); err == nil {
248
+		nameservers = resolvconf.GetNameserversAsCIDR(rc.Content)
249
+	}
250
+
251
+	if err := netutils.CheckNameserverOverlaps(nameservers, nw); err != nil {
252
+		return true
253
+	}
254
+
255
+	if err := netutils.CheckRouteOverlaps(nw); err != nil {
256
+		return true
257
+	}
258
+
259
+	return false
260
+}
261
+
262
+func (n *network) initSubnetSandbox(s *subnet) error {
263
+	brName := n.generateBridgeName(s)
264
+	vxlanName := n.generateVxlanName(s)
265
+
266
+	if hostMode {
267
+		// Try to delete stale bridge interface if it exists
268
+		deleteInterface(brName)
269
+		// Try to delete the vxlan interface by vni if already present
270
+		deleteVxlanByVNI(n.vxlanID(s))
271
+
272
+		if isOverlap(s.subnetIP) {
273
+			return fmt.Errorf("overlay subnet %s has conflicts in the host while running in host mode", s.subnetIP.String())
274
+		}
191 275
 	}
276
+
277
+	// create a bridge and vxlan device for this subnet and move it to the sandbox
192 278
 	sbox := n.sandbox()
193 279
 
194 280
 	if err := sbox.AddInterface(brName, "br",
... ...
@@ -197,7 +274,7 @@ func (n *network) initSubnetSandbox(s *subnet) error {
197 197
 		return fmt.Errorf("bridge creation in sandbox failed for subnet %q: %v", s.subnetIP.String(), err)
198 198
 	}
199 199
 
200
-	vxlanName, err := createVxlan(n.vxlanID(s))
200
+	err := createVxlan(vxlanName, n.vxlanID(s))
201 201
 	if err != nil {
202 202
 		return err
203 203
 	}
... ...
@@ -207,6 +284,12 @@ func (n *network) initSubnetSandbox(s *subnet) error {
207 207
 		return fmt.Errorf("vxlan interface creation failed for subnet %q: %v", s.subnetIP.String(), err)
208 208
 	}
209 209
 
210
+	if hostMode {
211
+		if err := addFilters(n.id[:12], brName); err != nil {
212
+			return err
213
+		}
214
+	}
215
+
210 216
 	n.Lock()
211 217
 	s.vxlanName = vxlanName
212 218
 	s.brName = brName
... ...
@@ -220,8 +303,16 @@ func (n *network) initSandbox() error {
220 220
 	n.initEpoch++
221 221
 	n.Unlock()
222 222
 
223
+	hostModeOnce.Do(setHostMode)
224
+
225
+	if hostMode {
226
+		if err := addNetworkChain(n.id[:12]); err != nil {
227
+			return err
228
+		}
229
+	}
230
+
223 231
 	sbox, err := osl.NewSandbox(
224
-		osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), true)
232
+		osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), !hostMode)
225 233
 	if err != nil {
226 234
 		return fmt.Errorf("could not create network sandbox: %v", err)
227 235
 	}
... ...
@@ -47,14 +47,9 @@ func createVethPair() (string, string, error) {
47 47
 	return name1, name2, nil
48 48
 }
49 49
 
50
-func createVxlan(vni uint32) (string, error) {
50
+func createVxlan(name string, vni uint32) error {
51 51
 	defer osl.InitOSContext()()
52 52
 
53
-	name, err := netutils.GenerateIfaceName("vxlan", 7)
54
-	if err != nil {
55
-		return "", fmt.Errorf("error generating vxlan name: %v", err)
56
-	}
57
-
58 53
 	vxlan := &netlink.Vxlan{
59 54
 		LinkAttrs: netlink.LinkAttrs{Name: name},
60 55
 		VxlanId:   int(vni),
... ...
@@ -66,23 +61,45 @@ func createVxlan(vni uint32) (string, error) {
66 66
 	}
67 67
 
68 68
 	if err := netlink.LinkAdd(vxlan); err != nil {
69
-		return "", fmt.Errorf("error creating vxlan interface: %v", err)
69
+		return fmt.Errorf("error creating vxlan interface: %v", err)
70 70
 	}
71 71
 
72
-	return name, nil
72
+	return nil
73 73
 }
74 74
 
75
-func deleteVxlan(name string) error {
75
+func deleteInterface(name string) error {
76 76
 	defer osl.InitOSContext()()
77 77
 
78 78
 	link, err := netlink.LinkByName(name)
79 79
 	if err != nil {
80
-		return fmt.Errorf("failed to find vxlan interface with name %s: %v", name, err)
80
+		return fmt.Errorf("failed to find interface with name %s: %v", name, err)
81 81
 	}
82 82
 
83 83
 	if err := netlink.LinkDel(link); err != nil {
84
-		return fmt.Errorf("error deleting vxlan interface: %v", err)
84
+		return fmt.Errorf("error deleting interface with name %s: %v", name, err)
85 85
 	}
86 86
 
87 87
 	return nil
88 88
 }
89
+
90
+func deleteVxlanByVNI(vni uint32) error {
91
+	defer osl.InitOSContext()()
92
+
93
+	links, err := netlink.LinkList()
94
+	if err != nil {
95
+		return fmt.Errorf("failed to list interfaces while deleting vxlan interface by vni: %v", err)
96
+	}
97
+
98
+	for _, l := range links {
99
+		if l.Type() == "vxlan" && l.(*netlink.Vxlan).VxlanId == int(vni) {
100
+			err = netlink.LinkDel(l)
101
+			if err != nil {
102
+				return fmt.Errorf("error deleting vxlan interface with id %d: %v", vni, err)
103
+			}
104
+
105
+			return nil
106
+		}
107
+	}
108
+
109
+	return fmt.Errorf("could not find a vxlan interface to delete with id %d", vni)
110
+}
... ...
@@ -51,7 +51,7 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
51 51
 	d := &driver{
52 52
 		networks: networkTable{},
53 53
 		peerDb: peerNetworkMap{
54
-			mp: map[string]peerMap{},
54
+			mp: map[string]*peerMap{},
55 55
 		},
56 56
 		config: config,
57 57
 	}
... ...
@@ -26,7 +26,7 @@ type peerMap struct {
26 26
 }
27 27
 
28 28
 type peerNetworkMap struct {
29
-	mp map[string]peerMap
29
+	mp map[string]*peerMap
30 30
 	sync.Mutex
31 31
 }
32 32
 
... ...
@@ -138,7 +138,7 @@ func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask
138 138
 	d.peerDb.Lock()
139 139
 	pMap, ok := d.peerDb.mp[nid]
140 140
 	if !ok {
141
-		d.peerDb.mp[nid] = peerMap{
141
+		d.peerDb.mp[nid] = &peerMap{
142 142
 			mp: make(map[string]peerEntry),
143 143
 		}
144 144
 
... ...
@@ -748,11 +748,8 @@ func (ep *endpoint) DataScope() string {
748 748
 	return ep.getNetwork().DataScope()
749 749
 }
750 750
 
751
-func (ep *endpoint) assignAddress(assignIPv4, assignIPv6 bool) error {
752
-	var (
753
-		ipam ipamapi.Ipam
754
-		err  error
755
-	)
751
+func (ep *endpoint) assignAddress(ipam ipamapi.Ipam, assignIPv4, assignIPv6 bool) error {
752
+	var err error
756 753
 
757 754
 	n := ep.getNetwork()
758 755
 	if n.Type() == "host" || n.Type() == "null" {
... ...
@@ -761,11 +758,6 @@ func (ep *endpoint) assignAddress(assignIPv4, assignIPv6 bool) error {
761 761
 
762 762
 	log.Debugf("Assigning addresses for endpoint %s's interface on network %s", ep.Name(), n.Name())
763 763
 
764
-	ipam, err = n.getController().getIpamDriver(n.ipamType)
765
-	if err != nil {
766
-		return err
767
-	}
768
-
769 764
 	if assignIPv4 {
770 765
 		if err = ep.assignAddressVersion(4, ipam); err != nil {
771 766
 			return err
... ...
@@ -486,21 +486,28 @@ func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddres
486 486
 // DumpDatabase dumps the internal info
487 487
 func (a *Allocator) DumpDatabase() string {
488 488
 	a.Lock()
489
-	defer a.Unlock()
489
+	aspaces := make(map[string]*addrSpace, len(a.addrSpaces))
490
+	for as, aSpace := range a.addrSpaces {
491
+		aspaces[as] = aSpace
492
+	}
493
+	a.Unlock()
490 494
 
491 495
 	var s string
492
-	for as, aSpace := range a.addrSpaces {
496
+	for as, aSpace := range aspaces {
493 497
 		s = fmt.Sprintf("\n\n%s Config", as)
494 498
 		aSpace.Lock()
495 499
 		for k, config := range aSpace.subnets {
496 500
 			s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
501
+			if config.Range == nil {
502
+				a.retrieveBitmask(k, config.Pool)
503
+			}
497 504
 		}
498 505
 		aSpace.Unlock()
499 506
 	}
500 507
 
501 508
 	s = fmt.Sprintf("%s\n\nBitmasks", s)
502 509
 	for k, bm := range a.addresses {
503
-		s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n\t%s: %s\n\t%d", k, bm, bm.Unselected()))
510
+		s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%s: %s", k, bm))
504 511
 	}
505 512
 
506 513
 	return s
... ...
@@ -22,8 +22,10 @@ const (
22 22
 
23 23
 // Callback provides a Callback interface for registering an IPAM instance into LibNetwork
24 24
 type Callback interface {
25
-	// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a ipam instance
25
+	// RegisterIpamDriver provides a way for Remote drivers to dynamically register with libnetwork
26 26
 	RegisterIpamDriver(name string, driver Ipam) error
27
+	// RegisterIpamDriverWithCapabilities provides a way for Remote drivers to dynamically register with libnetwork and specify cpaabilities
28
+	RegisterIpamDriverWithCapabilities(name string, driver Ipam, capability *Capability) error
27 29
 }
28 30
 
29 31
 /**************
... ...
@@ -70,3 +72,8 @@ type Ipam interface {
70 70
 	// Release the address from the specified pool ID
71 71
 	ReleaseAddress(string, net.IP) error
72 72
 }
73
+
74
+// Capability represents the requirements and capabilities of the IPAM driver
75
+type Capability struct {
76
+	RequiresMACAddress bool
77
+}
... ...
@@ -2,6 +2,8 @@
2 2
 // messages between libnetwork and the remote ipam plugin
3 3
 package api
4 4
 
5
+import "github.com/docker/libnetwork/ipamapi"
6
+
5 7
 // Response is the basic response structure used in all responses
6 8
 type Response struct {
7 9
 	Error string
... ...
@@ -17,6 +19,17 @@ func (r *Response) GetError() string {
17 17
 	return r.Error
18 18
 }
19 19
 
20
+// GetCapabilityResponse is the response of GetCapability request
21
+type GetCapabilityResponse struct {
22
+	Response
23
+	RequiresMACAddress bool
24
+}
25
+
26
+// ToCapability converts the capability response into the internal ipam driver capaility structure
27
+func (capRes GetCapabilityResponse) ToCapability() *ipamapi.Capability {
28
+	return &ipamapi.Capability{RequiresMACAddress: capRes.RequiresMACAddress}
29
+}
30
+
20 31
 // GetAddressSpacesResponse is the response to the ``get default address spaces`` request message
21 32
 type GetAddressSpacesResponse struct {
22 33
 	Response
... ...
@@ -30,8 +30,17 @@ func newAllocator(name string, client *plugins.Client) ipamapi.Ipam {
30 30
 // Init registers a remote ipam when its plugin is activated
31 31
 func Init(cb ipamapi.Callback, l, g interface{}) error {
32 32
 	plugins.Handle(ipamapi.PluginEndpointType, func(name string, client *plugins.Client) {
33
-		if err := cb.RegisterIpamDriver(name, newAllocator(name, client)); err != nil {
34
-			log.Errorf("error registering remote ipam %s due to %v", name, err)
33
+		a := newAllocator(name, client)
34
+		if cps, err := a.(*allocator).getCapabilities(); err == nil {
35
+			if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil {
36
+				log.Errorf("error registering remote ipam driver %s due to %v", name, err)
37
+			}
38
+		} else {
39
+			log.Infof("remote ipam driver %s does not support capabilities", name)
40
+			log.Debug(err)
41
+			if err := cb.RegisterIpamDriver(name, a); err != nil {
42
+				log.Errorf("error registering remote ipam driver %s due to %v", name, err)
43
+			}
35 44
 		}
36 45
 	})
37 46
 	return nil
... ...
@@ -49,6 +58,14 @@ func (a *allocator) call(methodName string, arg interface{}, retVal PluginRespon
49 49
 	return nil
50 50
 }
51 51
 
52
+func (a *allocator) getCapabilities() (*ipamapi.Capability, error) {
53
+	var res api.GetCapabilityResponse
54
+	if err := a.call("GetCapabilities", nil, &res); err != nil {
55
+		return nil, err
56
+	}
57
+	return res.ToCapability(), nil
58
+}
59
+
52 60
 // GetDefaultAddressSpaces returns the local and global default address spaces
53 61
 func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
54 62
 	res := &api.GetAddressSpacesResponse{}
55 63
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+// Package ipamutils provides utililty functions for ipam management
1
+package ipamutils
2
+
3
+import (
4
+	"net"
5
+
6
+	"github.com/docker/libnetwork/types"
7
+)
8
+
9
+// ElectInterfaceAddresses looks for an interface on the OS with the specified name
10
+// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist,
11
+// it chooses from a predifined list the first IPv4 address which does not conflict
12
+// with other interfaces on the system.
13
+func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
14
+	return nil, nil, types.NotImplementedErrorf("not supported on freebsd")
15
+}
16
+
17
+// FindAvailableNetwork returns a network from the passed list which does not
18
+// overlap with existing interfaces in the system
19
+func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
20
+	return nil, types.NotImplementedErrorf("not supported on freebsd")
21
+}
... ...
@@ -41,6 +41,9 @@ const (
41 41
 
42 42
 	// Gateway represents the gateway for the network
43 43
 	Gateway = Prefix + ".gateway"
44
+
45
+	// Internal constant represents that the network is internal which disables default gateway service
46
+	Internal = Prefix + ".internal"
44 47
 )
45 48
 
46 49
 var (
... ...
@@ -16,6 +16,7 @@ import (
16 16
 	"github.com/docker/libnetwork/etchosts"
17 17
 	"github.com/docker/libnetwork/ipamapi"
18 18
 	"github.com/docker/libnetwork/netlabel"
19
+	"github.com/docker/libnetwork/netutils"
19 20
 	"github.com/docker/libnetwork/options"
20 21
 	"github.com/docker/libnetwork/types"
21 22
 )
... ...
@@ -58,6 +59,7 @@ type Network interface {
58 58
 // NetworkInfo returns some configuration and operational information about the network
59 59
 type NetworkInfo interface {
60 60
 	IpamConfig() (string, []*IpamConf, []*IpamConf)
61
+	IpamInfo() ([]*IpamInfo, []*IpamInfo)
61 62
 	DriverOptions() map[string]string
62 63
 	Scope() string
63 64
 }
... ...
@@ -161,6 +163,7 @@ type network struct {
161 161
 	persist      bool
162 162
 	stopWatchCh  chan struct{}
163 163
 	drvOnce      *sync.Once
164
+	internal     bool
164 165
 	sync.Mutex
165 166
 }
166 167
 
... ...
@@ -303,6 +306,7 @@ func (n *network) CopyTo(o datastore.KVObject) error {
303 303
 	dstN.dbIndex = n.dbIndex
304 304
 	dstN.dbExists = n.dbExists
305 305
 	dstN.drvOnce = n.drvOnce
306
+	dstN.internal = n.internal
306 307
 
307 308
 	for _, v4conf := range n.ipamV4Config {
308 309
 		dstV4Conf := &IpamConf{}
... ...
@@ -389,6 +393,7 @@ func (n *network) MarshalJSON() ([]byte, error) {
389 389
 		}
390 390
 		netMap["ipamV6Info"] = string(iis)
391 391
 	}
392
+	netMap["internal"] = n.internal
392 393
 	return json.Marshal(netMap)
393 394
 }
394 395
 
... ...
@@ -452,6 +457,9 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
452 452
 			return err
453 453
 		}
454 454
 	}
455
+	if v, ok := netMap["internal"]; ok {
456
+		n.internal = v.(bool)
457
+	}
455 458
 	return nil
456 459
 }
457 460
 
... ...
@@ -478,6 +486,18 @@ func NetworkOptionPersist(persist bool) NetworkOption {
478 478
 	}
479 479
 }
480 480
 
481
+// NetworkOptionInternalNetwork returns an option setter to config the network
482
+// to be internal which disables default gateway service
483
+func NetworkOptionInternalNetwork() NetworkOption {
484
+	return func(n *network) {
485
+		n.internal = true
486
+		if n.generic == nil {
487
+			n.generic = make(map[string]interface{})
488
+		}
489
+		n.generic[netlabel.Internal] = true
490
+	}
491
+}
492
+
481 493
 // NetworkOptionIpam function returns an option setter for the ipam configuration for this network
482 494
 func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ipV6 []*IpamConf) NetworkOption {
483 495
 	return func(n *network) {
... ...
@@ -678,7 +698,22 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
678 678
 		}
679 679
 	}
680 680
 
681
-	if err = ep.assignAddress(true, !n.postIPv6); err != nil {
681
+	ipam, err := n.getController().getIPAM(n.ipamType)
682
+	if err != nil {
683
+		return nil, err
684
+	}
685
+
686
+	if ipam.capability.RequiresMACAddress {
687
+		if ep.iface.mac == nil {
688
+			ep.iface.mac = netutils.GenerateRandomMAC()
689
+		}
690
+		if ep.ipamOptions == nil {
691
+			ep.ipamOptions = make(map[string]string)
692
+		}
693
+		ep.ipamOptions[netlabel.MacAddress] = ep.iface.mac.String()
694
+	}
695
+
696
+	if err = ep.assignAddress(ipam.driver, true, !n.postIPv6); err != nil {
682 697
 		return nil, err
683 698
 	}
684 699
 	defer func() {
... ...
@@ -698,7 +733,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
698 698
 		}
699 699
 	}()
700 700
 
701
-	if err = ep.assignAddress(false, n.postIPv6); err != nil {
701
+	if err = ep.assignAddress(ipam.driver, false, n.postIPv6); err != nil {
702 702
 		return nil, err
703 703
 	}
704 704
 
... ...
@@ -1148,3 +1183,32 @@ func (n *network) IpamConfig() (string, []*IpamConf, []*IpamConf) {
1148 1148
 
1149 1149
 	return n.ipamType, v4L, v6L
1150 1150
 }
1151
+
1152
+func (n *network) IpamInfo() ([]*IpamInfo, []*IpamInfo) {
1153
+	n.Lock()
1154
+	defer n.Unlock()
1155
+
1156
+	v4Info := make([]*IpamInfo, len(n.ipamV4Info))
1157
+	v6Info := make([]*IpamInfo, len(n.ipamV6Info))
1158
+
1159
+	for i, info := range n.ipamV4Info {
1160
+		ic := &IpamInfo{}
1161
+		info.CopyTo(ic)
1162
+		v4Info[i] = ic
1163
+	}
1164
+
1165
+	for i, info := range n.ipamV6Info {
1166
+		ic := &IpamInfo{}
1167
+		info.CopyTo(ic)
1168
+		v6Info[i] = ic
1169
+	}
1170
+
1171
+	return v4Info, v6Info
1172
+}
1173
+
1174
+func (n *network) Internal() bool {
1175
+	n.Lock()
1176
+	defer n.Unlock()
1177
+
1178
+	return n.internal
1179
+}
... ...
@@ -109,6 +109,7 @@ func (i *nwIface) Remove() error {
109 109
 
110 110
 	n.Lock()
111 111
 	path := n.path
112
+	isDefault := n.isDefault
112 113
 	n.Unlock()
113 114
 
114 115
 	return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
... ...
@@ -134,7 +135,7 @@ func (i *nwIface) Remove() error {
134 134
 			if err := netlink.LinkDel(iface); err != nil {
135 135
 				return fmt.Errorf("failed deleting bridge %q: %v", i.SrcName(), err)
136 136
 			}
137
-		} else {
137
+		} else if !isDefault {
138 138
 			// Move the network interface to caller namespace.
139 139
 			if err := netlink.LinkSetNsFd(iface, callerFD); err != nil {
140 140
 				fmt.Println("LinkSetNsPid failed: ", err)
... ...
@@ -213,9 +214,15 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
213 213
 	}
214 214
 
215 215
 	n.Lock()
216
-	i.dstName = fmt.Sprintf("%s%d", i.dstName, n.nextIfIndex)
217
-	n.nextIfIndex++
216
+	if n.isDefault {
217
+		i.dstName = i.srcName
218
+	} else {
219
+		i.dstName = fmt.Sprintf("%s%d", i.dstName, n.nextIfIndex)
220
+		n.nextIfIndex++
221
+	}
222
+
218 223
 	path := n.path
224
+	isDefault := n.isDefault
219 225
 	n.Unlock()
220 226
 
221 227
 	return nsInvoke(path, func(nsFD int) error {
... ...
@@ -231,9 +238,13 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
231 231
 			return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
232 232
 		}
233 233
 
234
-		// Move the network interface to the destination namespace.
235
-		if err := netlink.LinkSetNsFd(iface, nsFD); err != nil {
236
-			return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err)
234
+		// Move the network interface to the destination
235
+		// namespace only if the namespace is not a default
236
+		// type
237
+		if !isDefault {
238
+			if err := netlink.LinkSetNsFd(iface, nsFD); err != nil {
239
+				return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err)
240
+			}
237 241
 		}
238 242
 
239 243
 		return nil
... ...
@@ -41,6 +41,7 @@ type networkNamespace struct {
41 41
 	staticRoutes []*types.StaticRoute
42 42
 	neighbors    []*neigh
43 43
 	nextIfIndex  int
44
+	isDefault    bool
44 45
 	sync.Mutex
45 46
 }
46 47
 
... ...
@@ -146,7 +147,7 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
146 146
 		return nil, err
147 147
 	}
148 148
 
149
-	return &networkNamespace{path: key}, nil
149
+	return &networkNamespace{path: key, isDefault: !osCreate}, nil
150 150
 }
151 151
 
152 152
 func (n *networkNamespace) InterfaceOptions() IfaceOptionSetter {
... ...
@@ -19,6 +19,11 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
19 19
 	return nil, nil
20 20
 }
21 21
 
22
+// GetSandboxForExternalKey returns sandbox object for the supplied path
23
+func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
24
+	return nil, nil
25
+}
26
+
22 27
 // GC triggers garbage collection of namespace path right away
23 28
 // and waits for it.
24 29
 func GC() {