Skip to content

Commit 9a63597

Browse files
author
Arko Dasgupta
committed
Support dockerd and system restarts for ipvlan and macvlan networks
This commit carries forward the work done in moby#2295 and fixes two things 1. Allows macvlan and ipvlan to be restored properly after dockerd or the system is restarted 2. Makes sure the refcount for the configOnly network is not incremented for the above case so this network can be deleted after all the associated ConfigFrom networks are deleted Signed-off-by: Arko Dasgupta <[email protected]>
1 parent 83d30db commit 9a63597

File tree

7 files changed

+150
-51
lines changed

7 files changed

+150
-51
lines changed

Diff for: controller.go

+12-5
Original file line numberDiff line numberDiff line change
@@ -706,9 +706,10 @@ const overlayDSROptionString = "dsr"
706706
// are network specific and modeled in a generic way.
707707
func (c *controller) NewNetwork(networkType, name string, id string, options ...NetworkOption) (Network, error) {
708708
var (
709-
cap *driverapi.Capability
710-
err error
711-
t *network
709+
cap *driverapi.Capability
710+
err error
711+
t *network
712+
skipCfgEpCount bool
712713
)
713714

714715
if id != "" {
@@ -802,7 +803,7 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
802803
return nil, types.InternalErrorf("Failed to apply configuration: %v", err)
803804
}
804805
defer func() {
805-
if err == nil {
806+
if err == nil && !skipCfgEpCount {
806807
if err := t.getEpCnt().IncEndpointCnt(); err != nil {
807808
logrus.Warnf("Failed to update reference count for configuration network %q on creation of network %q: %v",
808809
t.Name(), network.Name(), err)
@@ -823,7 +824,13 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
823824

824825
err = c.addNetwork(network)
825826
if err != nil {
826-
return nil, err
827+
if strings.Contains(err.Error(), "network exists") {
828+
// This error can be ignored and set this boolean
829+
// value to skip a refcount increment for configOnly networks
830+
skipCfgEpCount = true
831+
} else {
832+
return nil, nil
833+
}
827834
}
828835
defer func() {
829836
if err != nil {

Diff for: drivers/ipvlan/ipvlan_network.go

+38-21
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,14 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo
6060
// empty parent and --internal are handled the same. Set here to update k/v
6161
config.Internal = true
6262
}
63-
err = d.createNetwork(config)
63+
foundExisting, err := d.createNetwork(config)
6464
if err != nil {
6565
return err
6666
}
67+
68+
if foundExisting {
69+
return types.InternalMaskableErrorf("%s network exists", config.ID)
70+
}
6771
// update persistent db, rollback on fail
6872
err = d.storeUpdate(config)
6973
if err != nil {
@@ -76,22 +80,31 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo
7680
}
7781

7882
// createNetwork is used by new network callbacks and persistent network cache
79-
func (d *driver) createNetwork(config *configuration) error {
83+
func (d *driver) createNetwork(config *configuration) (bool, error) {
84+
foundExisting := false
8085
networkList := d.getNetworks()
8186
for _, nw := range networkList {
8287
if config.Parent == nw.config.Parent {
83-
return fmt.Errorf("network %s is already using parent interface %s",
84-
getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent)
88+
if config.ID != nw.config.ID {
89+
return false, fmt.Errorf("network %s is already using parent interface %s",
90+
getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent)
91+
}
92+
logrus.Debugf("Create Network for the same ID %s\n", config.ID)
93+
foundExisting = true
94+
break
8595
}
8696
}
8797
if !parentExists(config.Parent) {
8898
// if the --internal flag is set, create a dummy link
8999
if config.Internal {
90-
err := createDummyLink(config.Parent, getDummyName(stringid.TruncateID(config.ID)))
91-
if err != nil {
92-
return err
100+
if !dummyLinkExists(getDummyName(stringid.TruncateID(config.ID))) {
101+
err := createDummyLink(config.Parent, getDummyName(stringid.TruncateID(config.ID)))
102+
if err != nil {
103+
return false, err
104+
}
105+
config.CreatedSlaveLink = true
93106
}
94-
config.CreatedSlaveLink = true
107+
95108
// notify the user in logs they have limited communications
96109
if config.Parent == getDummyName(stringid.TruncateID(config.ID)) {
97110
logrus.Debugf("Empty -o parent= and --internal flags limit communications to other containers inside of network: %s",
@@ -100,24 +113,28 @@ func (d *driver) createNetwork(config *configuration) error {
100113
} else {
101114
// if the subinterface parent_iface.vlan_id checks do not pass, return err.
102115
// a valid example is 'eth0.10' for a parent iface 'eth0' with a vlan id '10'
103-
err := createVlanLink(config.Parent)
104-
if err != nil {
105-
return err
116+
if !vlanLinkExists(config.Parent) {
117+
err := createVlanLink(config.Parent)
118+
if err != nil {
119+
return false, err
120+
}
121+
// if driver created the networks slave link, record it for future deletion
122+
config.CreatedSlaveLink = true
106123
}
107-
// if driver created the networks slave link, record it for future deletion
108-
config.CreatedSlaveLink = true
109124
}
110125
}
111-
n := &network{
112-
id: config.ID,
113-
driver: d,
114-
endpoints: endpointTable{},
115-
config: config,
126+
if !foundExisting {
127+
n := &network{
128+
id: config.ID,
129+
driver: d,
130+
endpoints: endpointTable{},
131+
config: config,
132+
}
133+
// add the network
134+
d.addNetwork(n)
116135
}
117-
// add the *network
118-
d.addNetwork(n)
119136

120-
return nil
137+
return foundExisting, nil
121138
}
122139

123140
// DeleteNetwork the network for the specified driver type

Diff for: drivers/ipvlan/ipvlan_setup.go

+18
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ func parentExists(ifaceStr string) bool {
7070
return true
7171
}
7272

73+
// vlanLinkExists checks if specified vlan link exists in the default namespace
74+
func vlanLinkExists(linkStr string) bool {
75+
_, err := ns.NlHandle().LinkByName(linkStr)
76+
if err != nil {
77+
return false
78+
}
79+
return true
80+
}
81+
7382
// createVlanLink parses sub-interfaces and vlan id for creation
7483
func createVlanLink(parentName string) error {
7584
if strings.Contains(parentName, ".") {
@@ -156,6 +165,15 @@ func parseVlan(linkName string) (string, int, error) {
156165
return parent, vidInt, nil
157166
}
158167

168+
// dummyLinkExists checks if dummylink exists in the default namespace
169+
func dummyLinkExists(dummyName string) bool {
170+
_, err := ns.NlHandle().LinkByName(dummyName)
171+
if err != nil {
172+
return false
173+
}
174+
return true
175+
}
176+
159177
// createDummyLink creates a dummy0 parent link
160178
func createDummyLink(dummyName, truncNetID string) error {
161179
// create a parent interface since one was not specified

Diff for: drivers/ipvlan/ipvlan_store.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,14 @@ func (d *driver) initStore(option map[string]interface{}) error {
5555
return types.InternalErrorf("ipvlan driver failed to initialize data store: %v", err)
5656
}
5757

58-
return d.populateNetworks()
58+
err = d.populateNetworks()
59+
if err != nil {
60+
return err
61+
}
62+
err = d.populateEndpoints()
63+
if err != nil {
64+
return err
65+
}
5966
}
6067

6168
return nil
@@ -73,7 +80,7 @@ func (d *driver) populateNetworks() error {
7380
}
7481
for _, kvo := range kvol {
7582
config := kvo.(*configuration)
76-
if err = d.createNetwork(config); err != nil {
83+
if _, err = d.createNetwork(config); err != nil {
7784
logrus.Warnf("could not create ipvlan network for id %s from persistent state", config.ID)
7885
}
7986
}

Diff for: drivers/macvlan/macvlan_network.go

+45-21
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,15 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo
6464
// empty parent and --internal are handled the same. Set here to update k/v
6565
config.Internal = true
6666
}
67-
err = d.createNetwork(config)
67+
foundExisting, err := d.createNetwork(config)
6868
if err != nil {
6969
return err
7070
}
71+
72+
if foundExisting {
73+
return types.InternalMaskableErrorf("%s network exists", config.ID)
74+
}
75+
7176
// update persistent db, rollback on fail
7277
err = d.storeUpdate(config)
7378
if err != nil {
@@ -80,22 +85,32 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo
8085
}
8186

8287
// createNetwork is used by new network callbacks and persistent network cache
83-
func (d *driver) createNetwork(config *configuration) error {
88+
func (d *driver) createNetwork(config *configuration) (bool, error) {
89+
foundExisting := false
8490
networkList := d.getNetworks()
8591
for _, nw := range networkList {
8692
if config.Parent == nw.config.Parent {
87-
return fmt.Errorf("network %s is already using parent interface %s",
88-
getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent)
93+
if config.ID != nw.config.ID {
94+
return false, fmt.Errorf("network %s is already using parent interface %s",
95+
getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent)
96+
}
97+
logrus.Debugf("Create Network for the same ID %s\n", config.ID)
98+
foundExisting = true
99+
break
89100
}
90101
}
91102
if !parentExists(config.Parent) {
92103
// if the --internal flag is set, create a dummy link
93104
if config.Internal {
94-
err := createDummyLink(config.Parent, getDummyName(stringid.TruncateID(config.ID)))
95-
if err != nil {
96-
return err
105+
if !dummyLinkExists(getDummyName(stringid.TruncateID(config.ID))) {
106+
err := createDummyLink(config.Parent, getDummyName(stringid.TruncateID(config.ID)))
107+
if err != nil {
108+
return false, err
109+
}
110+
config.CreatedSlaveLink = true
111+
} else {
112+
logrus.Debugf("Dummy Link %s for Mac Vlan already exists", getDummyName(stringid.TruncateID(config.ID)))
97113
}
98-
config.CreatedSlaveLink = true
99114
// notify the user in logs they have limited communications
100115
if config.Parent == getDummyName(stringid.TruncateID(config.ID)) {
101116
logrus.Debugf("Empty -o parent= and --internal flags limit communications to other containers inside of network: %s",
@@ -104,24 +119,33 @@ func (d *driver) createNetwork(config *configuration) error {
104119
} else {
105120
// if the subinterface parent_iface.vlan_id checks do not pass, return err.
106121
// a valid example is 'eth0.10' for a parent iface 'eth0' with a vlan id '10'
107-
err := createVlanLink(config.Parent)
108-
if err != nil {
109-
return err
122+
123+
if !vlanLinkExists(config.Parent) {
124+
// if the subinterface parent_iface.vlan_id checks do not pass, return err.
125+
// a valid example is 'eth0.10' for a parent iface 'eth0' with a vlan id '10'
126+
err := createVlanLink(config.Parent)
127+
if err != nil {
128+
return false, err
129+
}
130+
// if driver created the networks slave link, record it for future deletion
131+
config.CreatedSlaveLink = true
132+
} else {
133+
logrus.Debugf("Parent Sub Interface %s already Exists NetID %s", config.Parent, config.ID)
110134
}
111-
// if driver created the networks slave link, record it for future deletion
112-
config.CreatedSlaveLink = true
113135
}
114136
}
115-
n := &network{
116-
id: config.ID,
117-
driver: d,
118-
endpoints: endpointTable{},
119-
config: config,
137+
if !foundExisting {
138+
n := &network{
139+
id: config.ID,
140+
driver: d,
141+
endpoints: endpointTable{},
142+
config: config,
143+
}
144+
// add the network
145+
d.addNetwork(n)
120146
}
121-
// add the *network
122-
d.addNetwork(n)
123147

124-
return nil
148+
return foundExisting, nil
125149
}
126150

127151
// DeleteNetwork deletes the network for the specified driver type

Diff for: drivers/macvlan/macvlan_setup.go

+18
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ func parentExists(ifaceStr string) bool {
7474
return true
7575
}
7676

77+
// vlanLinkExists checks if specified vlan link exists in the default namespace
78+
func vlanLinkExists(linkStr string) bool {
79+
_, err := ns.NlHandle().LinkByName(linkStr)
80+
if err != nil {
81+
return false
82+
}
83+
return true
84+
}
85+
7786
// createVlanLink parses sub-interfaces and vlan id for creation
7887
func createVlanLink(parentName string) error {
7988
if strings.Contains(parentName, ".") {
@@ -160,6 +169,15 @@ func parseVlan(linkName string) (string, int, error) {
160169
return parent, vidInt, nil
161170
}
162171

172+
// dummyLinkExists checks if dummylink exists in the default namespace
173+
func dummyLinkExists(dummyName string) bool {
174+
_, err := ns.NlHandle().LinkByName(dummyName)
175+
if err != nil {
176+
return false
177+
}
178+
return true
179+
}
180+
163181
// createDummyLink creates a dummy0 parent link
164182
func createDummyLink(dummyName, truncNetID string) error {
165183
// create a parent interface since one was not specified

Diff for: drivers/macvlan/macvlan_store.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,15 @@ func (d *driver) initStore(option map[string]interface{}) error {
5555
return types.InternalErrorf("macvlan driver failed to initialize data store: %v", err)
5656
}
5757

58-
return d.populateNetworks()
58+
err = d.populateNetworks()
59+
if err != nil {
60+
return err
61+
}
62+
err = d.populateEndpoints()
63+
if err != nil {
64+
return err
65+
}
66+
5967
}
6068

6169
return nil
@@ -73,7 +81,7 @@ func (d *driver) populateNetworks() error {
7381
}
7482
for _, kvo := range kvol {
7583
config := kvo.(*configuration)
76-
if err = d.createNetwork(config); err != nil {
84+
if _, err = d.createNetwork(config); err != nil {
7785
logrus.Warnf("Could not create macvlan network for id %s from persistent state", config.ID)
7886
}
7987
}

0 commit comments

Comments
 (0)