@@ -25,8 +25,8 @@ type nodeEgress struct {
25
25
}
26
26
27
27
type namespaceEgress struct {
28
- vnid uint32
29
- requestedIP string
28
+ vnid uint32
29
+ requestedIPs [] string
30
30
}
31
31
32
32
type egressIPInfo struct {
@@ -37,8 +37,6 @@ type egressIPInfo struct {
37
37
38
38
assignedNodeIP string
39
39
assignedIPTablesMark string
40
- assignedVNID uint32
41
- blockedVNIDs map [uint32 ]bool
42
40
}
43
41
44
42
type egressIPWatcher struct {
@@ -55,6 +53,9 @@ type egressIPWatcher struct {
55
53
namespacesByVNID map [uint32 ]* namespaceEgress
56
54
egressIPs map [string ]* egressIPInfo
57
55
56
+ changedEgressIPs []* egressIPInfo
57
+ changedNamespaces []* namespaceEgress
58
+
58
59
localEgressLink netlink.Link
59
60
localEgressNet * net.IPNet
60
61
@@ -112,32 +113,57 @@ func (eip *egressIPWatcher) ensureEgressIPInfo(egressIP string) *egressIPInfo {
112
113
return eg
113
114
}
114
115
115
- func (eg * egressIPInfo ) addNode (node * nodeEgress ) {
116
+ func (eip * egressIPWatcher ) egressIPChanged (eg * egressIPInfo ) {
117
+ eip .changedEgressIPs = append (eip .changedEgressIPs , eg )
118
+ for _ , ns := range eg .namespaces {
119
+ eip .changedNamespaces = append (eip .changedNamespaces , ns )
120
+ }
121
+ }
122
+
123
+ func (eip * egressIPWatcher ) addNode (egressIP string , node * nodeEgress ) {
124
+ eg := eip .ensureEgressIPInfo (egressIP )
116
125
if len (eg .nodes ) != 0 {
117
126
utilruntime .HandleError (fmt .Errorf ("Multiple nodes claiming EgressIP %q (nodes %q, %q)" , eg .ip , node .nodeIP , eg .nodes [0 ].nodeIP ))
118
127
}
119
128
eg .nodes = append (eg .nodes , node )
129
+
130
+ eip .egressIPChanged (eg )
120
131
}
121
132
122
- func (eg * egressIPInfo ) deleteNode (node * nodeEgress ) {
133
+ func (eip * egressIPWatcher ) deleteNode (egressIP string , node * nodeEgress ) {
134
+ eg := eip .egressIPs [egressIP ]
135
+ if eg == nil {
136
+ return
137
+ }
138
+
123
139
for i := range eg .nodes {
124
140
if eg .nodes [i ] == node {
141
+ eip .egressIPChanged (eg )
125
142
eg .nodes = append (eg .nodes [:i ], eg .nodes [i + 1 :]... )
126
143
return
127
144
}
128
145
}
129
146
}
130
147
131
- func (eg * egressIPInfo ) addNamespace (ns * namespaceEgress ) {
148
+ func (eip * egressIPWatcher ) addNamespace (egressIP string , ns * namespaceEgress ) {
149
+ eg := eip .ensureEgressIPInfo (egressIP )
132
150
if len (eg .namespaces ) != 0 {
133
151
utilruntime .HandleError (fmt .Errorf ("Multiple namespaces claiming EgressIP %q (NetIDs %d, %d)" , eg .ip , ns .vnid , eg .namespaces [0 ].vnid ))
134
152
}
135
153
eg .namespaces = append (eg .namespaces , ns )
154
+
155
+ eip .egressIPChanged (eg )
136
156
}
137
157
138
- func (eg * egressIPInfo ) deleteNamespace (ns * namespaceEgress ) {
158
+ func (eip * egressIPWatcher ) deleteNamespace (egressIP string , ns * namespaceEgress ) {
159
+ eg := eip .egressIPs [egressIP ]
160
+ if eg == nil {
161
+ return
162
+ }
163
+
139
164
for i := range eg .namespaces {
140
165
if eg .namespaces [i ] == ns {
166
+ eip .egressIPChanged (eg )
141
167
eg .namespaces = append (eg .namespaces [:i ], eg .namespaces [i + 1 :]... )
142
168
return
143
169
}
@@ -183,22 +209,15 @@ func (eip *egressIPWatcher) updateNodeEgress(nodeIP string, nodeEgressIPs []stri
183
209
oldRequestedIPs := node .requestedIPs
184
210
node .requestedIPs = sets .NewString (nodeEgressIPs ... )
185
211
186
- // Process new EgressIPs
212
+ // Process new and removed EgressIPs
187
213
for _ , ip := range node .requestedIPs .Difference (oldRequestedIPs ).UnsortedList () {
188
- eg := eip .ensureEgressIPInfo (ip )
189
- eg .addNode (node )
190
- eip .syncEgressIP (eg )
214
+ eip .addNode (ip , node )
191
215
}
192
-
193
- // Process removed EgressIPs
194
216
for _ , ip := range oldRequestedIPs .Difference (node .requestedIPs ).UnsortedList () {
195
- eg := eip .egressIPs [ip ]
196
- if eg == nil {
197
- continue
198
- }
199
- eg .deleteNode (node )
200
- eip .syncEgressIP (eg )
217
+ eip .deleteNode (ip , node )
201
218
}
219
+
220
+ eip .syncEgressIPs ()
202
221
}
203
222
204
223
func (eip * egressIPWatcher ) watchNetNamespaces () {
@@ -214,10 +233,8 @@ func (eip *egressIPWatcher) handleAddOrUpdateNetNamespace(obj, _ interface{}, ev
214
233
if len (netns .EgressIPs ) > 1 {
215
234
glog .Warningf ("Ignoring extra EgressIPs (%v) in NetNamespace %q" , netns .EgressIPs [1 :], netns .Name )
216
235
}
217
- eip .updateNamespaceEgress (netns .NetID , netns .EgressIPs [0 ])
218
- } else {
219
- eip .deleteNamespaceEgress (netns .NetID )
220
236
}
237
+ eip .updateNamespaceEgress (netns .NetID , netns .EgressIPs )
221
238
}
222
239
223
240
func (eip * egressIPWatcher ) handleDeleteNetNamespace (obj interface {}) {
@@ -227,126 +244,128 @@ func (eip *egressIPWatcher) handleDeleteNetNamespace(obj interface{}) {
227
244
eip .deleteNamespaceEgress (netns .NetID )
228
245
}
229
246
230
- func (eip * egressIPWatcher ) updateNamespaceEgress (vnid uint32 , egressIP string ) {
247
+ func (eip * egressIPWatcher ) updateNamespaceEgress (vnid uint32 , egressIPs [] string ) {
231
248
eip .Lock ()
232
249
defer eip .Unlock ()
233
250
234
251
ns := eip .namespacesByVNID [vnid ]
235
252
if ns == nil {
236
- if egressIP == "" {
253
+ if len ( egressIPs ) == 0 {
237
254
return
238
255
}
239
256
ns = & namespaceEgress {vnid : vnid }
240
257
eip .namespacesByVNID [vnid ] = ns
241
- } else if egressIP == "" {
258
+ } else if len ( egressIPs ) == 0 {
242
259
delete (eip .namespacesByVNID , vnid )
243
260
}
244
261
245
- if ns . requestedIP == egressIP {
246
- return
247
- }
262
+ oldRequestedIPs := sets . NewString ( ns . requestedIPs ... )
263
+ newRequestedIPs := sets . NewString ( egressIPs ... )
264
+ ns . requestedIPs = egressIPs
248
265
249
- if ns .requestedIP != "" {
250
- eg := eip .egressIPs [ns .requestedIP ]
251
- if eg != nil {
252
- eg .deleteNamespace (ns )
253
- eip .syncEgressIP (eg )
254
- }
266
+ // Process new and removed EgressIPs
267
+ for _ , ip := range newRequestedIPs .Difference (oldRequestedIPs ).UnsortedList () {
268
+ eip .addNamespace (ip , ns )
255
269
}
256
-
257
- ns .requestedIP = egressIP
258
- if egressIP == "" {
259
- return
270
+ for _ , ip := range oldRequestedIPs .Difference (newRequestedIPs ).UnsortedList () {
271
+ eip .deleteNamespace (ip , ns )
260
272
}
261
273
262
- eg := eip .ensureEgressIPInfo (egressIP )
263
- eg .addNamespace (ns )
264
- eip .syncEgressIP (eg )
274
+ // Make sure we update OVS even if nothing was added or removed; the order might
275
+ // have changed
276
+ eip .changedNamespaces = append (eip .changedNamespaces , ns )
277
+
278
+ eip .syncEgressIPs ()
265
279
}
266
280
267
281
func (eip * egressIPWatcher ) deleteNamespaceEgress (vnid uint32 ) {
268
- eip .updateNamespaceEgress (vnid , "" )
282
+ eip .updateNamespaceEgress (vnid , nil )
269
283
}
270
284
271
- func (eip * egressIPWatcher ) syncEgressIP (eg * egressIPInfo ) {
272
- assignedNodeIPChanged := eip .syncEgressIPTablesState (eg )
273
- eip .syncEgressOVSState (eg , assignedNodeIPChanged )
285
+ func (eip * egressIPWatcher ) syncEgressIPs () {
286
+ changedEgressIPs := make (map [* egressIPInfo ]bool )
287
+ for _ , eg := range eip .changedEgressIPs {
288
+ changedEgressIPs [eg ] = true
289
+ }
290
+ eip .changedEgressIPs = eip .changedEgressIPs [:0 ]
291
+
292
+ changedNamespaces := make (map [* namespaceEgress ]bool )
293
+ for _ , ns := range eip .changedNamespaces {
294
+ changedNamespaces [ns ] = true
295
+ }
296
+ eip .changedNamespaces = eip .changedNamespaces [:0 ]
297
+
298
+ for eg := range changedEgressIPs {
299
+ eip .syncEgressNodeState (eg )
300
+ }
301
+
302
+ for ns := range changedNamespaces {
303
+ err := eip .syncEgressNamespaceState (ns )
304
+ if err != nil {
305
+ utilruntime .HandleError (fmt .Errorf ("Error updating Namespace egress rules for VNID %d: %v" , ns .vnid , err ))
306
+ }
307
+ }
274
308
}
275
309
276
- func (eip * egressIPWatcher ) syncEgressIPTablesState (eg * egressIPInfo ) bool {
310
+ func (eip * egressIPWatcher ) syncEgressNodeState (eg * egressIPInfo ) {
277
311
// The egressIPInfo should have an assigned node IP if and only if the
278
312
// egress IP is active (ie, it is assigned to exactly 1 node and exactly
279
313
// 1 namespace).
280
314
egressIPActive := (len (eg .nodes ) == 1 && len (eg .namespaces ) == 1 )
281
- assignedNodeIPChanged := false
282
315
if egressIPActive && eg .assignedNodeIP != eg .nodes [0 ].nodeIP {
316
+ glog .V (4 ).Infof ("Assigning egress IP %s to node %s" , eg .ip , eg .nodes [0 ].nodeIP )
283
317
eg .assignedNodeIP = eg .nodes [0 ].nodeIP
284
318
eg .assignedIPTablesMark = getMarkForVNID (eg .namespaces [0 ].vnid , eip .masqueradeBit )
285
- assignedNodeIPChanged = true
286
319
if eg .assignedNodeIP == eip .localIP {
287
320
if err := eip .assignEgressIP (eg .ip , eg .assignedIPTablesMark ); err != nil {
288
321
utilruntime .HandleError (fmt .Errorf ("Error assigning Egress IP %q: %v" , eg .ip , err ))
289
322
eg .assignedNodeIP = ""
290
323
}
291
324
}
292
325
} else if ! egressIPActive && eg .assignedNodeIP != "" {
326
+ glog .V (4 ).Infof ("Removing egress IP %s from node %s" , eg .ip , eg .assignedNodeIP )
293
327
if eg .assignedNodeIP == eip .localIP {
294
328
if err := eip .releaseEgressIP (eg .ip , eg .assignedIPTablesMark ); err != nil {
295
329
utilruntime .HandleError (fmt .Errorf ("Error releasing Egress IP %q: %v" , eg .ip , err ))
296
330
}
297
331
}
298
332
eg .assignedNodeIP = ""
299
333
eg .assignedIPTablesMark = ""
300
- assignedNodeIPChanged = true
334
+ } else if ! egressIPActive {
335
+ glog .V (4 ).Infof ("Egress IP %s is not assignable (%d namespaces, %d nodes)" , eg .ip , len (eg .namespaces ), len (eg .nodes ))
301
336
}
302
- return assignedNodeIPChanged
303
337
}
304
338
305
- func (eip * egressIPWatcher ) syncEgressOVSState (eg * egressIPInfo , assignedNodeIPChanged bool ) {
306
- var blockedVNIDs map [uint32 ]bool
307
-
308
- // If multiple namespaces are assigned to the same EgressIP, we need to block
309
- // outgoing traffic from all of them.
310
- if len (eg .namespaces ) > 1 {
311
- eg .assignedVNID = 0
312
- blockedVNIDs = make (map [uint32 ]bool )
313
- for _ , ns := range eg .namespaces {
314
- blockedVNIDs [ns .vnid ] = true
315
- if ! eg .blockedVNIDs [ns .vnid ] {
316
- err := eip .oc .SetNamespaceEgressDropped (ns .vnid )
317
- if err != nil {
318
- utilruntime .HandleError (fmt .Errorf ("Error updating Namespace egress rules: %v" , err ))
319
- }
320
- }
321
- }
339
+ func (eip * egressIPWatcher ) syncEgressNamespaceState (ns * namespaceEgress ) error {
340
+ if len (ns .requestedIPs ) == 0 {
341
+ return eip .oc .SetNamespaceEgressNormal (ns .vnid )
322
342
}
323
343
324
- // If we have, or had, a single egress namespace, then update the OVS flows if
325
- // something has changed
326
- var err error
327
- if len (eg .namespaces ) == 1 && (eg .assignedVNID != eg .namespaces [0 ].vnid || assignedNodeIPChanged ) {
328
- eg .assignedVNID = eg .namespaces [0 ].vnid
329
- delete (eg .blockedVNIDs , eg .assignedVNID )
330
- err = eip .oc .SetNamespaceEgressViaEgressIP (eg .assignedVNID , eg .assignedNodeIP , getMarkForVNID (eg .assignedVNID , eip .masqueradeBit ))
331
- } else if len (eg .namespaces ) == 0 && eg .assignedVNID != 0 {
332
- err = eip .oc .SetNamespaceEgressNormal (eg .assignedVNID )
333
- eg .assignedVNID = 0
334
- }
335
- if err != nil {
336
- utilruntime .HandleError (fmt .Errorf ("Error updating Namespace egress rules: %v" , err ))
337
- }
338
-
339
- // If we previously had blocked VNIDs, we need to unblock any that have been removed
340
- // from the duplicates list
341
- for vnid := range eg .blockedVNIDs {
342
- if ! blockedVNIDs [vnid ] {
343
- err := eip .oc .SetNamespaceEgressNormal (vnid )
344
- if err != nil {
345
- utilruntime .HandleError (fmt .Errorf ("Error updating Namespace egress rules: %v" , err ))
344
+ var active * egressIPInfo
345
+ for i , ip := range ns .requestedIPs {
346
+ eg := eip .egressIPs [ip ]
347
+ if eg == nil {
348
+ continue
349
+ }
350
+ if len (eg .namespaces ) > 1 {
351
+ active = nil
352
+ glog .V (4 ).Infof ("VNID %d gets no egress due to multiply-assigned egress IP %s" , ns .vnid , eg .ip )
353
+ break
354
+ }
355
+ if active == nil && i == 0 {
356
+ if eg .assignedNodeIP == "" {
357
+ glog .V (4 ).Infof ("VNID %d cannot use unassigned egress IP %s" , ns .vnid , eg .ip )
358
+ } else {
359
+ active = eg
346
360
}
347
361
}
348
362
}
349
- eg .blockedVNIDs = blockedVNIDs
363
+
364
+ if active != nil {
365
+ return eip .oc .SetNamespaceEgressViaEgressIP (ns .vnid , active .assignedNodeIP , active .assignedIPTablesMark )
366
+ } else {
367
+ return eip .oc .SetNamespaceEgressDropped (ns .vnid )
368
+ }
350
369
}
351
370
352
371
func (eip * egressIPWatcher ) assignEgressIP (egressIP , mark string ) error {
0 commit comments