|
@@ -10,7 +10,6 @@ import (
|
|
|
|
|
|
"github.com/Microsoft/hcsshim"
|
|
|
"github.com/Sirupsen/logrus"
|
|
|
- "github.com/docker/libnetwork/datastore"
|
|
|
"github.com/docker/libnetwork/driverapi"
|
|
|
"github.com/docker/libnetwork/netlabel"
|
|
|
"github.com/docker/libnetwork/types"
|
|
@@ -25,9 +24,8 @@ type networkTable map[string]*network
|
|
|
|
|
|
type subnet struct {
|
|
|
vni uint32
|
|
|
- initErr error
|
|
|
subnetIP *net.IPNet
|
|
|
- gwIP *net.IPNet
|
|
|
+ gwIP *net.IP
|
|
|
}
|
|
|
|
|
|
type subnetJSON struct {
|
|
@@ -40,8 +38,6 @@ type network struct {
|
|
|
id string
|
|
|
name string
|
|
|
hnsId string
|
|
|
- dbIndex uint64
|
|
|
- dbExists bool
|
|
|
providerAddress string
|
|
|
interfaceName string
|
|
|
endpoints endpointTable
|
|
@@ -65,22 +61,31 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
|
|
|
var (
|
|
|
networkName string
|
|
|
interfaceName string
|
|
|
+ staleNetworks []string
|
|
|
)
|
|
|
|
|
|
if id == "" {
|
|
|
return fmt.Errorf("invalid network id")
|
|
|
}
|
|
|
|
|
|
+ if nInfo == nil {
|
|
|
+ return fmt.Errorf("invalid network info structure")
|
|
|
+ }
|
|
|
+
|
|
|
if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
|
|
|
return types.BadRequestErrorf("ipv4 pool is empty")
|
|
|
}
|
|
|
|
|
|
+ staleNetworks = make([]string, 0)
|
|
|
vnis := make([]uint32, 0, len(ipV4Data))
|
|
|
|
|
|
- // Since we perform lazy configuration make sure we try
|
|
|
- // configuring the driver when we enter CreateNetwork
|
|
|
- if err := d.configure(); err != nil {
|
|
|
- return err
|
|
|
+ existingNetwork := d.network(id)
|
|
|
+ if existingNetwork != nil {
|
|
|
+ logrus.Debugf("Network preexists. Deleting %s", id)
|
|
|
+ err := d.DeleteNetwork(id)
|
|
|
+ if err != nil {
|
|
|
+ logrus.Errorf("Error deleting stale network %s", err.Error())
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
n := &network{
|
|
@@ -119,23 +124,43 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
|
|
|
|
|
|
// If we are getting vnis from libnetwork, either we get for
|
|
|
// all subnets or none.
|
|
|
- if len(vnis) != 0 && len(vnis) < len(ipV4Data) {
|
|
|
- return fmt.Errorf("insufficient vnis(%d) passed to overlay", len(vnis))
|
|
|
+ if len(vnis) < len(ipV4Data) {
|
|
|
+ return fmt.Errorf("insufficient vnis(%d) passed to overlay. Windows driver requires VNIs to be prepopulated", len(vnis))
|
|
|
}
|
|
|
|
|
|
for i, ipd := range ipV4Data {
|
|
|
s := &subnet{
|
|
|
subnetIP: ipd.Pool,
|
|
|
- gwIP: ipd.Gateway,
|
|
|
+ gwIP: &ipd.Gateway.IP,
|
|
|
}
|
|
|
|
|
|
if len(vnis) != 0 {
|
|
|
s.vni = vnis[i]
|
|
|
}
|
|
|
|
|
|
+ d.Lock()
|
|
|
+ for _, network := range d.networks {
|
|
|
+ found := false
|
|
|
+ for _, sub := range network.subnets {
|
|
|
+ if sub.vni == s.vni {
|
|
|
+ staleNetworks = append(staleNetworks, network.id)
|
|
|
+ found = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if found {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ d.Unlock()
|
|
|
+
|
|
|
n.subnets = append(n.subnets, s)
|
|
|
}
|
|
|
|
|
|
+ for _, staleNetwork := range staleNetworks {
|
|
|
+ d.DeleteNetwork(staleNetwork)
|
|
|
+ }
|
|
|
+
|
|
|
n.name = networkName
|
|
|
if n.name == "" {
|
|
|
n.name = id
|
|
@@ -143,10 +168,6 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
|
|
|
|
|
|
n.interfaceName = interfaceName
|
|
|
|
|
|
- if err := n.writeToStore(); err != nil {
|
|
|
- return fmt.Errorf("failed to update data store for network %v: %v", n.id, err)
|
|
|
- }
|
|
|
-
|
|
|
if nInfo != nil {
|
|
|
if err := nInfo.TableEventRegister(ovPeerTable); err != nil {
|
|
|
return err
|
|
@@ -155,8 +176,13 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
|
|
|
|
|
|
d.addNetwork(n)
|
|
|
|
|
|
- err := d.findHnsNetwork(n)
|
|
|
- genData["com.docker.network.windowsshim.hnsid"] = n.hnsId
|
|
|
+ err := d.createHnsNetwork(n)
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ d.deleteNetwork(id)
|
|
|
+ } else {
|
|
|
+ genData["com.docker.network.windowsshim.hnsid"] = n.hnsId
|
|
|
+ }
|
|
|
|
|
|
return err
|
|
|
}
|
|
@@ -166,23 +192,17 @@ func (d *driver) DeleteNetwork(nid string) error {
|
|
|
return fmt.Errorf("invalid network id")
|
|
|
}
|
|
|
|
|
|
- // Make sure driver resources are initialized before proceeding
|
|
|
- if err := d.configure(); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
n := d.network(nid)
|
|
|
if n == nil {
|
|
|
- return fmt.Errorf("could not find network with id %s", nid)
|
|
|
+ return types.ForbiddenErrorf("could not find network with id %s", nid)
|
|
|
}
|
|
|
|
|
|
_, err := hcsshim.HNSNetworkRequest("DELETE", n.hnsId, "")
|
|
|
if err != nil {
|
|
|
- return err
|
|
|
+ return types.ForbiddenErrorf(err.Error())
|
|
|
}
|
|
|
|
|
|
d.deleteNetwork(nid)
|
|
|
- d.deleteLocalNetworkFromStore(n)
|
|
|
|
|
|
return nil
|
|
|
}
|
|
@@ -209,259 +229,107 @@ func (d *driver) deleteNetwork(nid string) {
|
|
|
|
|
|
func (d *driver) network(nid string) *network {
|
|
|
d.Lock()
|
|
|
- networks := d.networks
|
|
|
- d.Unlock()
|
|
|
-
|
|
|
- n, ok := networks[nid]
|
|
|
- if !ok {
|
|
|
- n = d.getNetworkFromStore(nid)
|
|
|
- if n != nil {
|
|
|
- n.driver = d
|
|
|
- n.endpoints = endpointTable{}
|
|
|
- networks[nid] = n
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return n
|
|
|
+ defer d.Unlock()
|
|
|
+ return d.networks[nid]
|
|
|
}
|
|
|
|
|
|
-func (d *driver) getNetworkFromStore(nid string) *network {
|
|
|
- if d.store == nil {
|
|
|
- return nil
|
|
|
- }
|
|
|
-
|
|
|
- n := &network{id: nid}
|
|
|
- if err := d.store.GetObject(datastore.Key(n.Key()...), n); err != nil {
|
|
|
- return nil
|
|
|
- }
|
|
|
-
|
|
|
- // As the network is being discovered from the global store, HNS may not be aware of it yet
|
|
|
- err := d.findHnsNetwork(n)
|
|
|
- if err != nil {
|
|
|
- logrus.Errorf("Failed to find hns network: %v", err)
|
|
|
- return nil
|
|
|
- }
|
|
|
+// func (n *network) restoreNetworkEndpoints() error {
|
|
|
+// logrus.Infof("Restoring endpoints for overlay network: %s", n.id)
|
|
|
|
|
|
- return n
|
|
|
-}
|
|
|
+// hnsresponse, err := hcsshim.HNSListEndpointRequest("GET", "", "")
|
|
|
+// if err != nil {
|
|
|
+// return err
|
|
|
+// }
|
|
|
|
|
|
-func (n *network) vxlanID(s *subnet) uint32 {
|
|
|
- n.Lock()
|
|
|
- defer n.Unlock()
|
|
|
+// for _, endpoint := range hnsresponse {
|
|
|
+// if endpoint.VirtualNetwork != n.hnsId {
|
|
|
+// continue
|
|
|
+// }
|
|
|
|
|
|
- return s.vni
|
|
|
-}
|
|
|
+// ep := n.convertToOverlayEndpoint(&endpoint)
|
|
|
|
|
|
-func (n *network) setVxlanID(s *subnet, vni uint32) {
|
|
|
- n.Lock()
|
|
|
- s.vni = vni
|
|
|
- n.Unlock()
|
|
|
-}
|
|
|
+// if ep != nil {
|
|
|
+// logrus.Debugf("Restored endpoint:%s Remote:%t", ep.id, ep.remote)
|
|
|
+// n.addEndpoint(ep)
|
|
|
+// }
|
|
|
+// }
|
|
|
|
|
|
-func (n *network) Key() []string {
|
|
|
- return []string{"overlay", "network", n.id}
|
|
|
-}
|
|
|
-
|
|
|
-func (n *network) KeyPrefix() []string {
|
|
|
- return []string{"overlay", "network"}
|
|
|
-}
|
|
|
+// return nil
|
|
|
+// }
|
|
|
|
|
|
-func (n *network) Value() []byte {
|
|
|
- m := map[string]interface{}{}
|
|
|
-
|
|
|
- netJSON := []*subnetJSON{}
|
|
|
-
|
|
|
- for _, s := range n.subnets {
|
|
|
- sj := &subnetJSON{
|
|
|
- SubnetIP: s.subnetIP.String(),
|
|
|
- GwIP: s.gwIP.String(),
|
|
|
- Vni: s.vni,
|
|
|
- }
|
|
|
- netJSON = append(netJSON, sj)
|
|
|
+func (n *network) convertToOverlayEndpoint(v *hcsshim.HNSEndpoint) *endpoint {
|
|
|
+ ep := &endpoint{
|
|
|
+ id: v.Name,
|
|
|
+ profileId: v.Id,
|
|
|
+ nid: n.id,
|
|
|
+ remote: v.IsRemoteEndpoint,
|
|
|
}
|
|
|
|
|
|
- b, err := json.Marshal(netJSON)
|
|
|
- if err != nil {
|
|
|
- return []byte{}
|
|
|
- }
|
|
|
+ mac, err := net.ParseMAC(v.MacAddress)
|
|
|
|
|
|
- m["secure"] = n.secure
|
|
|
- m["subnets"] = netJSON
|
|
|
- m["interfaceName"] = n.interfaceName
|
|
|
- m["providerAddress"] = n.providerAddress
|
|
|
- m["hnsId"] = n.hnsId
|
|
|
- m["name"] = n.name
|
|
|
- b, err = json.Marshal(m)
|
|
|
if err != nil {
|
|
|
- return []byte{}
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
- return b
|
|
|
-}
|
|
|
-
|
|
|
-func (n *network) Index() uint64 {
|
|
|
- return n.dbIndex
|
|
|
-}
|
|
|
+ ep.mac = mac
|
|
|
+ ep.addr = &net.IPNet{
|
|
|
+ IP: v.IPAddress,
|
|
|
+ Mask: net.CIDRMask(32, 32),
|
|
|
+ }
|
|
|
|
|
|
-func (n *network) SetIndex(index uint64) {
|
|
|
- n.dbIndex = index
|
|
|
- n.dbExists = true
|
|
|
+ return ep
|
|
|
}
|
|
|
|
|
|
-func (n *network) Exists() bool {
|
|
|
- return n.dbExists
|
|
|
-}
|
|
|
+func (d *driver) createHnsNetwork(n *network) error {
|
|
|
|
|
|
-func (n *network) Skip() bool {
|
|
|
- return false
|
|
|
-}
|
|
|
+ subnets := []hcsshim.Subnet{}
|
|
|
|
|
|
-func (n *network) SetValue(value []byte) error {
|
|
|
- var (
|
|
|
- m map[string]interface{}
|
|
|
- newNet bool
|
|
|
- isMap = true
|
|
|
- netJSON = []*subnetJSON{}
|
|
|
- )
|
|
|
+ for _, s := range n.subnets {
|
|
|
+ subnet := hcsshim.Subnet{
|
|
|
+ AddressPrefix: s.subnetIP.String(),
|
|
|
+ }
|
|
|
|
|
|
- if err := json.Unmarshal(value, &m); err != nil {
|
|
|
- err := json.Unmarshal(value, &netJSON)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
+ if s.gwIP != nil {
|
|
|
+ subnet.GatewayAddress = s.gwIP.String()
|
|
|
}
|
|
|
- isMap = false
|
|
|
- }
|
|
|
|
|
|
- if len(n.subnets) == 0 {
|
|
|
- newNet = true
|
|
|
- }
|
|
|
+ vsidPolicy, err := json.Marshal(hcsshim.VsidPolicy{
|
|
|
+ Type: "VSID",
|
|
|
+ VSID: uint(s.vni),
|
|
|
+ })
|
|
|
|
|
|
- if isMap {
|
|
|
- if val, ok := m["secure"]; ok {
|
|
|
- n.secure = val.(bool)
|
|
|
- }
|
|
|
- if val, ok := m["providerAddress"]; ok {
|
|
|
- n.providerAddress = val.(string)
|
|
|
- }
|
|
|
- if val, ok := m["interfaceName"]; ok {
|
|
|
- n.interfaceName = val.(string)
|
|
|
- }
|
|
|
- if val, ok := m["hnsId"]; ok {
|
|
|
- n.hnsId = val.(string)
|
|
|
- }
|
|
|
- if val, ok := m["name"]; ok {
|
|
|
- n.name = val.(string)
|
|
|
- }
|
|
|
- bytes, err := json.Marshal(m["subnets"])
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
- if err := json.Unmarshal(bytes, &netJSON); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for _, sj := range netJSON {
|
|
|
- subnetIPstr := sj.SubnetIP
|
|
|
- gwIPstr := sj.GwIP
|
|
|
- vni := sj.Vni
|
|
|
|
|
|
- subnetIP, _ := types.ParseCIDR(subnetIPstr)
|
|
|
- gwIP, _ := types.ParseCIDR(gwIPstr)
|
|
|
-
|
|
|
- if newNet {
|
|
|
- s := &subnet{
|
|
|
- subnetIP: subnetIP,
|
|
|
- gwIP: gwIP,
|
|
|
- vni: vni,
|
|
|
- }
|
|
|
- n.subnets = append(n.subnets, s)
|
|
|
- } else {
|
|
|
- sNet := n.getMatchingSubnet(subnetIP)
|
|
|
- if sNet != nil {
|
|
|
- sNet.vni = vni
|
|
|
- }
|
|
|
- }
|
|
|
+ subnet.Policies = append(subnet.Policies, vsidPolicy)
|
|
|
+ subnets = append(subnets, subnet)
|
|
|
}
|
|
|
- return nil
|
|
|
-}
|
|
|
|
|
|
-func (n *network) DataScope() string {
|
|
|
- return datastore.GlobalScope
|
|
|
-}
|
|
|
-
|
|
|
-func (n *network) writeToStore() error {
|
|
|
- if n.driver.store == nil {
|
|
|
- return nil
|
|
|
+ network := &hcsshim.HNSNetwork{
|
|
|
+ Name: n.name,
|
|
|
+ Type: d.Type(),
|
|
|
+ Subnets: subnets,
|
|
|
+ NetworkAdapterName: n.interfaceName,
|
|
|
}
|
|
|
|
|
|
- return n.driver.store.PutObjectAtomic(n)
|
|
|
-}
|
|
|
-
|
|
|
-func (n *network) releaseVxlanID() ([]uint32, error) {
|
|
|
- if len(n.subnets) == 0 {
|
|
|
- return nil, nil
|
|
|
- }
|
|
|
-
|
|
|
- if n.driver.store != nil {
|
|
|
- if err := n.driver.store.DeleteObjectAtomic(n); err != nil {
|
|
|
- if err == datastore.ErrKeyModified || err == datastore.ErrKeyNotFound {
|
|
|
- // In both the above cases we can safely assume that the key has been removed by some other
|
|
|
- // instance and so simply get out of here
|
|
|
- return nil, nil
|
|
|
- }
|
|
|
-
|
|
|
- return nil, fmt.Errorf("failed to delete network to vxlan id map: %v", err)
|
|
|
- }
|
|
|
- }
|
|
|
- var vnis []uint32
|
|
|
- for _, s := range n.subnets {
|
|
|
- if n.driver.vxlanIdm != nil {
|
|
|
- vni := n.vxlanID(s)
|
|
|
- vnis = append(vnis, vni)
|
|
|
- n.driver.vxlanIdm.Release(uint64(vni))
|
|
|
- }
|
|
|
-
|
|
|
- n.setVxlanID(s, 0)
|
|
|
+ configurationb, err := json.Marshal(network)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
}
|
|
|
|
|
|
- return vnis, nil
|
|
|
-}
|
|
|
+ configuration := string(configurationb)
|
|
|
+ logrus.Infof("HNSNetwork Request =%v", configuration)
|
|
|
|
|
|
-func (n *network) obtainVxlanID(s *subnet) error {
|
|
|
- //return if the subnet already has a vxlan id assigned
|
|
|
- if s.vni != 0 {
|
|
|
- return nil
|
|
|
- }
|
|
|
-
|
|
|
- if n.driver.store == nil {
|
|
|
- return fmt.Errorf("no valid vxlan id and no datastore configured, cannot obtain vxlan id")
|
|
|
+ hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
}
|
|
|
|
|
|
- for {
|
|
|
- if err := n.driver.store.GetObject(datastore.Key(n.Key()...), n); err != nil {
|
|
|
- return fmt.Errorf("getting network %q from datastore failed %v", n.id, err)
|
|
|
- }
|
|
|
-
|
|
|
- if s.vni == 0 {
|
|
|
- vxlanID, err := n.driver.vxlanIdm.GetID()
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf("failed to allocate vxlan id: %v", err)
|
|
|
- }
|
|
|
+ n.hnsId = hnsresponse.Id
|
|
|
+ n.providerAddress = hnsresponse.ManagementIP
|
|
|
|
|
|
- n.setVxlanID(s, uint32(vxlanID))
|
|
|
- if err := n.writeToStore(); err != nil {
|
|
|
- n.driver.vxlanIdm.Release(uint64(n.vxlanID(s)))
|
|
|
- n.setVxlanID(s, 0)
|
|
|
- if err == datastore.ErrKeyModified {
|
|
|
- continue
|
|
|
- }
|
|
|
- return fmt.Errorf("network %q failed to update data store: %v", n.id, err)
|
|
|
- }
|
|
|
- return nil
|
|
|
- }
|
|
|
- return nil
|
|
|
- }
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
// contains return true if the passed ip belongs to one the network's
|