diff --git a/libnetwork/controller.go b/libnetwork/controller.go index ff7b36947a..dc33ded09e 100644 --- a/libnetwork/controller.go +++ b/libnetwork/controller.go @@ -706,9 +706,10 @@ const overlayDSROptionString = "dsr" // are network specific and modeled in a generic way. func (c *controller) NewNetwork(networkType, name string, id string, options ...NetworkOption) (Network, error) { var ( - cap *driverapi.Capability - err error - t *network + cap *driverapi.Capability + err error + t *network + skipCfgEpCount bool ) if id != "" { @@ -803,7 +804,7 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... } network.generic[netlabel.Internal] = network.internal defer func() { - if err == nil { + if err == nil && !skipCfgEpCount { if err := t.getEpCnt().IncEndpointCnt(); err != nil { logrus.Warnf("Failed to update reference count for configuration network %q on creation of network %q: %v", t.Name(), network.Name(), err) @@ -824,7 +825,13 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... err = c.addNetwork(network) if err != nil { - return nil, err + if strings.Contains(err.Error(), "restoring existing network") { + // This error can be ignored and set this boolean + // value to skip a refcount increment for configOnly networks + skipCfgEpCount = true + } else { + return nil, err + } } defer func() { if err != nil { diff --git a/libnetwork/drivers/ipvlan/ipvlan_network.go b/libnetwork/drivers/ipvlan/ipvlan_network.go index 39980fb316..3d2b822301 100644 --- a/libnetwork/drivers/ipvlan/ipvlan_network.go +++ b/libnetwork/drivers/ipvlan/ipvlan_network.go @@ -60,10 +60,14 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo // empty parent and --internal are handled the same. Set here to update k/v config.Internal = true } - err = d.createNetwork(config) + foundExisting, err := d.createNetwork(config) if err != nil { return err } + + if foundExisting { + return types.InternalMaskableErrorf("restoring existing network %s", config.ID) + } // update persistent db, rollback on fail err = d.storeUpdate(config) if err != nil { @@ -76,12 +80,18 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo } // createNetwork is used by new network callbacks and persistent network cache -func (d *driver) createNetwork(config *configuration) error { +func (d *driver) createNetwork(config *configuration) (bool, error) { + foundExisting := false networkList := d.getNetworks() for _, nw := range networkList { if config.Parent == nw.config.Parent { - return fmt.Errorf("network %s is already using parent interface %s", - getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent) + if config.ID != nw.config.ID { + return false, fmt.Errorf("network %s is already using parent interface %s", + getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent) + } + logrus.Debugf("Create Network for the same ID %s\n", config.ID) + foundExisting = true + break } } if !parentExists(config.Parent) { @@ -89,9 +99,10 @@ func (d *driver) createNetwork(config *configuration) error { if config.Internal { err := createDummyLink(config.Parent, getDummyName(stringid.TruncateID(config.ID))) if err != nil { - return err + return false, err } config.CreatedSlaveLink = true + // notify the user in logs they have limited communications if config.Parent == getDummyName(stringid.TruncateID(config.ID)) { logrus.Debugf("Empty -o parent= and --internal flags limit communications to other containers inside of network: %s", @@ -102,22 +113,24 @@ func (d *driver) createNetwork(config *configuration) error { // a valid example is 'eth0.10' for a parent iface 'eth0' with a vlan id '10' err := createVlanLink(config.Parent) if err != nil { - return err + return false, err } // if driver created the networks slave link, record it for future deletion config.CreatedSlaveLink = true } } - n := &network{ - id: config.ID, - driver: d, - endpoints: endpointTable{}, - config: config, + if !foundExisting { + n := &network{ + id: config.ID, + driver: d, + endpoints: endpointTable{}, + config: config, + } + // add the network + d.addNetwork(n) } - // add the *network - d.addNetwork(n) - return nil + return foundExisting, nil } // DeleteNetwork the network for the specified driver type diff --git a/libnetwork/drivers/ipvlan/ipvlan_store.go b/libnetwork/drivers/ipvlan/ipvlan_store.go index 72eb3fc4ff..cf9d324292 100644 --- a/libnetwork/drivers/ipvlan/ipvlan_store.go +++ b/libnetwork/drivers/ipvlan/ipvlan_store.go @@ -55,7 +55,14 @@ func (d *driver) initStore(option map[string]interface{}) error { return types.InternalErrorf("ipvlan driver failed to initialize data store: %v", err) } - return d.populateNetworks() + err = d.populateNetworks() + if err != nil { + return err + } + err = d.populateEndpoints() + if err != nil { + return err + } } return nil @@ -73,7 +80,7 @@ func (d *driver) populateNetworks() error { } for _, kvo := range kvol { config := kvo.(*configuration) - if err = d.createNetwork(config); err != nil { + if _, err = d.createNetwork(config); err != nil { logrus.Warnf("could not create ipvlan network for id %s from persistent state", config.ID) } } diff --git a/libnetwork/drivers/macvlan/macvlan_network.go b/libnetwork/drivers/macvlan/macvlan_network.go index 8c515bb2f4..99eae86f35 100644 --- a/libnetwork/drivers/macvlan/macvlan_network.go +++ b/libnetwork/drivers/macvlan/macvlan_network.go @@ -64,10 +64,15 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo // empty parent and --internal are handled the same. Set here to update k/v config.Internal = true } - err = d.createNetwork(config) + foundExisting, err := d.createNetwork(config) if err != nil { return err } + + if foundExisting { + return types.InternalMaskableErrorf("restoring existing network %s", config.ID) + } + // update persistent db, rollback on fail err = d.storeUpdate(config) if err != nil { @@ -80,12 +85,18 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo } // createNetwork is used by new network callbacks and persistent network cache -func (d *driver) createNetwork(config *configuration) error { +func (d *driver) createNetwork(config *configuration) (bool, error) { + foundExisting := false networkList := d.getNetworks() for _, nw := range networkList { if config.Parent == nw.config.Parent { - return fmt.Errorf("network %s is already using parent interface %s", - getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent) + if config.ID != nw.config.ID { + return false, fmt.Errorf("network %s is already using parent interface %s", + getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent) + } + logrus.Debugf("Create Network for the same ID %s\n", config.ID) + foundExisting = true + break } } if !parentExists(config.Parent) { @@ -93,7 +104,7 @@ func (d *driver) createNetwork(config *configuration) error { if config.Internal { err := createDummyLink(config.Parent, getDummyName(stringid.TruncateID(config.ID))) if err != nil { - return err + return false, err } config.CreatedSlaveLink = true // notify the user in logs they have limited communications @@ -106,22 +117,24 @@ func (d *driver) createNetwork(config *configuration) error { // a valid example is 'eth0.10' for a parent iface 'eth0' with a vlan id '10' err := createVlanLink(config.Parent) if err != nil { - return err + return false, err } // if driver created the networks slave link, record it for future deletion config.CreatedSlaveLink = true } } - n := &network{ - id: config.ID, - driver: d, - endpoints: endpointTable{}, - config: config, + if !foundExisting { + n := &network{ + id: config.ID, + driver: d, + endpoints: endpointTable{}, + config: config, + } + // add the network + d.addNetwork(n) } - // add the *network - d.addNetwork(n) - return nil + return foundExisting, nil } // DeleteNetwork deletes the network for the specified driver type diff --git a/libnetwork/drivers/macvlan/macvlan_store.go b/libnetwork/drivers/macvlan/macvlan_store.go index 8683cacd02..184e3da957 100644 --- a/libnetwork/drivers/macvlan/macvlan_store.go +++ b/libnetwork/drivers/macvlan/macvlan_store.go @@ -55,7 +55,15 @@ func (d *driver) initStore(option map[string]interface{}) error { return types.InternalErrorf("macvlan driver failed to initialize data store: %v", err) } - return d.populateNetworks() + err = d.populateNetworks() + if err != nil { + return err + } + err = d.populateEndpoints() + if err != nil { + return err + } + } return nil @@ -73,7 +81,7 @@ func (d *driver) populateNetworks() error { } for _, kvo := range kvol { config := kvo.(*configuration) - if err = d.createNetwork(config); err != nil { + if _, err = d.createNetwork(config); err != nil { logrus.Warnf("Could not create macvlan network for id %s from persistent state", config.ID) } }