Browse code

Updating IPAM config with results from HNS create network call. In windows HNS manages IPAM. If the user does not specify a subnet, HNS will choose one for them. However, in order for the IPAM to show up in the output of "docker inspect", we need to update the network IPAMv4Config field.

Signed-off-by: Pradip Dhara <pradipd@microsoft.com>

Pradip Dhara authored on 2019/08/08 06:28:54
Showing 4 changed files
... ...
@@ -95,6 +95,11 @@ type NetworkInfo interface {
95 95
 	// TableEventRegister registers driver interest in a given
96 96
 	// table name.
97 97
 	TableEventRegister(tableName string, objType ObjectType) error
98
+
99
+	// UpdateIPamConfig updates the networks IPAM configuration
100
+	// based on information from the driver.  In windows, the OS (HNS) chooses
101
+	// the IP address space if the user does not specify an address space.
102
+	UpdateIpamConfig(ipV4Data []IPAMData)
98 103
 }
99 104
 
100 105
 // InterfaceInfo provides a go interface for drivers to retrieve
... ...
@@ -255,7 +255,7 @@ func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (s
255 255
 	return "", nil
256 256
 }
257 257
 
258
-func (d *driver) createNetwork(config *networkConfiguration) error {
258
+func (d *driver) createNetwork(config *networkConfiguration) *hnsNetwork {
259 259
 	network := &hnsNetwork{
260 260
 		id:         config.ID,
261 261
 		endpoints:  make(map[string]*hnsEndpoint),
... ...
@@ -268,7 +268,7 @@ func (d *driver) createNetwork(config *networkConfiguration) error {
268 268
 	d.networks[config.ID] = network
269 269
 	d.Unlock()
270 270
 
271
-	return nil
271
+	return network
272 272
 }
273 273
 
274 274
 // Create a new network
... ...
@@ -293,11 +293,7 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
293 293
 		return err
294 294
 	}
295 295
 
296
-	err = d.createNetwork(config)
297
-
298
-	if err != nil {
299
-		return err
300
-	}
296
+	n := d.createNetwork(config)
301 297
 
302 298
 	// A non blank hnsid indicates that the network was discovered
303 299
 	// from HNS. No need to call HNS if this network was discovered
... ...
@@ -371,6 +367,36 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
371 371
 
372 372
 		config.HnsID = hnsresponse.Id
373 373
 		genData[HNSID] = config.HnsID
374
+		n.created = true
375
+
376
+		defer func() {
377
+			if err != nil {
378
+				d.DeleteNetwork(n.id)
379
+			}
380
+		}()
381
+
382
+		hnsIPv4Data := make([]driverapi.IPAMData, len(hnsresponse.Subnets))
383
+
384
+		for i, subnet := range hnsresponse.Subnets {
385
+			var gwIP, subnetIP *net.IPNet
386
+
387
+			//The gateway returned from HNS is an IPAddress.
388
+			//We need to convert it to an IPNet to use as the Gateway of driverapi.IPAMData struct
389
+			gwCIDR := subnet.GatewayAddress + "/32"
390
+			_, gwIP, err = net.ParseCIDR(gwCIDR)
391
+			if err != nil {
392
+				return err
393
+			}
394
+
395
+			hnsIPv4Data[i].Gateway = gwIP
396
+			_, subnetIP, err = net.ParseCIDR(subnet.AddressPrefix)
397
+			if err != nil {
398
+				return err
399
+			}
400
+			hnsIPv4Data[i].Pool = subnetIP
401
+		}
402
+
403
+		nInfo.UpdateIpamConfig(hnsIPv4Data)
374 404
 
375 405
 	} else {
376 406
 		// Delete any stale HNS endpoints for this network.
... ...
@@ -387,13 +413,10 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
387 387
 		} else {
388 388
 			logrus.Warnf("Error listing HNS endpoints for network %s", config.HnsID)
389 389
 		}
390
-	}
391 390
 
392
-	n, err := d.getNetwork(id)
393
-	if err != nil {
394
-		return err
391
+		n.created = true
395 392
 	}
396
-	n.created = true
393
+
397 394
 	return d.storeUpdate(config)
398 395
 }
399 396
 
... ...
@@ -61,9 +61,7 @@ func (d *driver) populateNetworks() error {
61 61
 		if ncfg.Type != d.name {
62 62
 			continue
63 63
 		}
64
-		if err = d.createNetwork(ncfg); err != nil {
65
-			logrus.Warnf("could not create windows network for id %s hnsid %s while booting up from persistent state: %v", ncfg.ID, ncfg.HnsID, err)
66
-		}
64
+		d.createNetwork(ncfg)
67 65
 		logrus.Debugf("Network  %v (%.7s) restored", d.name, ncfg.ID)
68 66
 	}
69 67
 
... ...
@@ -1938,6 +1938,22 @@ func (n *network) TableEventRegister(tableName string, objType driverapi.ObjectT
1938 1938
 	return nil
1939 1939
 }
1940 1940
 
1941
+func (n *network) UpdateIpamConfig(ipV4Data []driverapi.IPAMData) {
1942
+
1943
+	ipamV4Config := make([]*IpamConf, len(ipV4Data))
1944
+
1945
+	for i, data := range ipV4Data {
1946
+		ic := &IpamConf{}
1947
+		ic.PreferredPool = data.Pool.String()
1948
+		ic.Gateway = data.Gateway.IP.String()
1949
+		ipamV4Config[i] = ic
1950
+	}
1951
+
1952
+	n.Lock()
1953
+	defer n.Unlock()
1954
+	n.ipamV4Config = ipamV4Config
1955
+}
1956
+
1941 1957
 // Special drivers are ones which do not need to perform any network plumbing
1942 1958
 func (n *network) hasSpecialDriver() bool {
1943 1959
 	return n.Type() == "host" || n.Type() == "null"