@@ -15,13 +15,16 @@ import (
15
15
networkapi "github.com/openshift/origin/pkg/network/apis/network"
16
16
"github.com/openshift/origin/pkg/network/common"
17
17
networkinformers "github.com/openshift/origin/pkg/network/generated/informers/internalversion"
18
+ "github.com/openshift/origin/pkg/util/netutils"
18
19
19
20
"github.com/vishvananda/netlink"
20
21
)
21
22
22
23
type nodeEgress struct {
23
24
nodeIP string
25
+ sdnIP string
24
26
requestedIPs sets.String
27
+ offline bool
25
28
}
26
29
27
30
type namespaceEgress struct {
@@ -48,13 +51,14 @@ type egressIPWatcher struct {
48
51
49
52
networkInformers networkinformers.SharedInformerFactory
50
53
iptables * NodeIPTables
54
+ vxlanMonitor * egressVXLANMonitor
51
55
52
56
nodesByNodeIP map [string ]* nodeEgress
53
57
namespacesByVNID map [uint32 ]* namespaceEgress
54
58
egressIPs map [string ]* egressIPInfo
55
59
56
- changedEgressIPs [] * egressIPInfo
57
- changedNamespaces [] * namespaceEgress
60
+ changedEgressIPs map [ * egressIPInfo ] bool
61
+ changedNamespaces map [ * namespaceEgress ] bool
58
62
59
63
localEgressLink netlink.Link
60
64
localEgressNet * net.IPNet
@@ -70,6 +74,9 @@ func newEgressIPWatcher(oc *ovsController, localIP string, masqueradeBit *int32)
70
74
nodesByNodeIP : make (map [string ]* nodeEgress ),
71
75
namespacesByVNID : make (map [uint32 ]* namespaceEgress ),
72
76
egressIPs : make (map [string ]* egressIPInfo ),
77
+
78
+ changedEgressIPs : make (map [* egressIPInfo ]bool ),
79
+ changedNamespaces : make (map [* namespaceEgress ]bool ),
73
80
}
74
81
if masqueradeBit != nil {
75
82
eip .masqueradeBit = 1 << uint32 (* masqueradeBit )
@@ -87,6 +94,10 @@ func (eip *egressIPWatcher) Start(networkInformers networkinformers.SharedInform
87
94
eip .networkInformers = networkInformers
88
95
eip .iptables = iptables
89
96
97
+ updates := make (chan * egressVXLANNode )
98
+ eip .vxlanMonitor = newEgressVXLANMonitor (eip .oc .ovs , updates )
99
+ go eip .watchVXLAN (updates )
100
+
90
101
eip .watchHostSubnets ()
91
102
eip .watchNetNamespaces ()
92
103
return nil
@@ -114,19 +125,15 @@ func (eip *egressIPWatcher) ensureEgressIPInfo(egressIP string) *egressIPInfo {
114
125
}
115
126
116
127
func (eip * egressIPWatcher ) egressIPChanged (eg * egressIPInfo ) {
117
- eip .changedEgressIPs = append ( eip . changedEgressIPs , eg )
128
+ eip .changedEgressIPs [ eg ] = true
118
129
for _ , ns := range eg .namespaces {
119
- eip .changedNamespaces = append ( eip . changedNamespaces , ns )
130
+ eip .changedNamespaces [ ns ] = true
120
131
}
121
132
}
122
133
123
134
func (eip * egressIPWatcher ) addNode (egressIP string , node * nodeEgress ) {
124
135
eg := eip .ensureEgressIPInfo (egressIP )
125
- if len (eg .nodes ) != 0 {
126
- utilruntime .HandleError (fmt .Errorf ("Multiple nodes claiming EgressIP %q (nodes %q, %q)" , eg .ip , node .nodeIP , eg .nodes [0 ].nodeIP ))
127
- }
128
136
eg .nodes = append (eg .nodes , node )
129
-
130
137
eip .egressIPChanged (eg )
131
138
}
132
139
@@ -147,11 +154,7 @@ func (eip *egressIPWatcher) deleteNode(egressIP string, node *nodeEgress) {
147
154
148
155
func (eip * egressIPWatcher ) addNamespace (egressIP string , ns * namespaceEgress ) {
149
156
eg := eip .ensureEgressIPInfo (egressIP )
150
- if len (eg .namespaces ) != 0 {
151
- utilruntime .HandleError (fmt .Errorf ("Multiple namespaces claiming EgressIP %q (NetIDs %d, %d)" , eg .ip , ns .vnid , eg .namespaces [0 ].vnid ))
152
- }
153
157
eg .namespaces = append (eg .namespaces , ns )
154
-
155
158
eip .egressIPChanged (eg )
156
159
}
157
160
@@ -179,17 +182,23 @@ func (eip *egressIPWatcher) handleAddOrUpdateHostSubnet(obj, _ interface{}, even
179
182
hs := obj .(* networkapi.HostSubnet )
180
183
glog .V (5 ).Infof ("Watch %s event for HostSubnet %q" , eventType , hs .Name )
181
184
182
- eip .updateNodeEgress (hs .HostIP , hs .EgressIPs )
185
+ _ , cidr , err := net .ParseCIDR (hs .Subnet )
186
+ if err != nil {
187
+ utilruntime .HandleError (fmt .Errorf ("could not parse HostSubnet %q CIDR: %v" , hs .Name , err ))
188
+ }
189
+ sdnIP := netutils .GenerateDefaultGateway (cidr ).String ()
190
+
191
+ eip .updateNodeEgress (hs .HostIP , sdnIP , hs .EgressIPs )
183
192
}
184
193
185
194
func (eip * egressIPWatcher ) handleDeleteHostSubnet (obj interface {}) {
186
195
hs := obj .(* networkapi.HostSubnet )
187
196
glog .V (5 ).Infof ("Watch %s event for HostSubnet %q" , watch .Deleted , hs .Name )
188
197
189
- eip .updateNodeEgress (hs .HostIP , nil )
198
+ eip .updateNodeEgress (hs .HostIP , "" , nil )
190
199
}
191
200
192
- func (eip * egressIPWatcher ) updateNodeEgress (nodeIP string , nodeEgressIPs []string ) {
201
+ func (eip * egressIPWatcher ) updateNodeEgress (nodeIP , sdnIP string , nodeEgressIPs []string ) {
193
202
eip .Lock ()
194
203
defer eip .Unlock ()
195
204
@@ -200,11 +209,18 @@ func (eip *egressIPWatcher) updateNodeEgress(nodeIP string, nodeEgressIPs []stri
200
209
}
201
210
node = & nodeEgress {
202
211
nodeIP : nodeIP ,
212
+ sdnIP : sdnIP ,
203
213
requestedIPs : sets .NewString (),
204
214
}
205
215
eip .nodesByNodeIP [nodeIP ] = node
216
+ if eip .vxlanMonitor != nil && node .nodeIP != eip .localIP {
217
+ eip .vxlanMonitor .AddNode (node .nodeIP , node .sdnIP )
218
+ }
206
219
} else if len (nodeEgressIPs ) == 0 {
207
220
delete (eip .nodesByNodeIP , nodeIP )
221
+ if eip .vxlanMonitor != nil {
222
+ eip .vxlanMonitor .RemoveNode (node .nodeIP )
223
+ }
208
224
}
209
225
oldRequestedIPs := node .requestedIPs
210
226
node .requestedIPs = sets .NewString (nodeEgressIPs ... )
@@ -229,11 +245,6 @@ func (eip *egressIPWatcher) handleAddOrUpdateNetNamespace(obj, _ interface{}, ev
229
245
netns := obj .(* networkapi.NetNamespace )
230
246
glog .V (5 ).Infof ("Watch %s event for NetNamespace %q" , eventType , netns .Name )
231
247
232
- if len (netns .EgressIPs ) != 0 {
233
- if len (netns .EgressIPs ) > 1 {
234
- glog .Warningf ("Ignoring extra EgressIPs (%v) in NetNamespace %q" , netns .EgressIPs [1 :], netns .Name )
235
- }
236
- }
237
248
eip .updateNamespaceEgress (netns .NetID , netns .EgressIPs )
238
249
}
239
250
@@ -284,37 +295,46 @@ func (eip *egressIPWatcher) deleteNamespaceEgress(vnid uint32) {
284
295
eip .updateNamespaceEgress (vnid , nil )
285
296
}
286
297
287
- func (eip * egressIPWatcher ) syncEgressIPs () {
288
- changedEgressIPs := make (map [* egressIPInfo ]bool )
289
- for _ , eg := range eip .changedEgressIPs {
290
- changedEgressIPs [eg ] = true
298
+ func (eip * egressIPWatcher ) egressIPActive (eg * egressIPInfo ) (bool , error ) {
299
+ if len (eg .nodes ) == 0 || len (eg .namespaces ) == 0 {
300
+ return false , nil
291
301
}
292
- eip .changedEgressIPs = eip .changedEgressIPs [:0 ]
293
-
294
- changedNamespaces := make (map [* namespaceEgress ]bool )
295
- for _ , ns := range eip .changedNamespaces {
296
- changedNamespaces [ns ] = true
302
+ if len (eg .nodes ) > 1 {
303
+ return false , fmt .Errorf ("Multiple nodes (%s, %s) claiming EgressIP %s" , eg .nodes [0 ].nodeIP , eg .nodes [1 ].nodeIP , eg .ip )
297
304
}
298
- eip .changedNamespaces = eip .changedNamespaces [:0 ]
305
+ if len (eg .namespaces ) > 1 {
306
+ return false , fmt .Errorf ("Multiple namespaces (%d, %d) claiming EgressIP %s" , eg .namespaces [0 ].vnid , eg .namespaces [1 ].vnid , eg .ip )
307
+ }
308
+ for _ , ip := range eg .namespaces [0 ].requestedIPs {
309
+ eg2 := eip .egressIPs [ip ]
310
+ if eg2 != eg && len (eg2 .nodes ) == 1 && eg2 .nodes [0 ] == eg .nodes [0 ] {
311
+ return false , fmt .Errorf ("Multiple EgressIPs (%s, %s) for VNID %d on node %s" , eg .ip , eg2 .ip , eg .namespaces [0 ].vnid , eg .nodes [0 ].nodeIP )
312
+ }
313
+ }
314
+ return true , nil
315
+ }
299
316
300
- for eg := range changedEgressIPs {
301
- eip .syncEgressNodeState (eg )
317
+ func (eip * egressIPWatcher ) syncEgressIPs () {
318
+ for eg := range eip .changedEgressIPs {
319
+ active , err := eip .egressIPActive (eg )
320
+ if err != nil {
321
+ utilruntime .HandleError (err )
322
+ }
323
+ eip .syncEgressNodeState (eg , active )
302
324
}
325
+ eip .changedEgressIPs = make (map [* egressIPInfo ]bool )
303
326
304
- for ns := range changedNamespaces {
327
+ for ns := range eip . changedNamespaces {
305
328
err := eip .syncEgressNamespaceState (ns )
306
329
if err != nil {
307
330
utilruntime .HandleError (fmt .Errorf ("Error updating Namespace egress rules for VNID %d: %v" , ns .vnid , err ))
308
331
}
309
332
}
333
+ eip .changedNamespaces = make (map [* namespaceEgress ]bool )
310
334
}
311
335
312
- func (eip * egressIPWatcher ) syncEgressNodeState (eg * egressIPInfo ) {
313
- // The egressIPInfo should have an assigned node IP if and only if the
314
- // egress IP is active (ie, it is assigned to exactly 1 node and exactly
315
- // 1 namespace, and it's the first one for its namespace).
316
- egressIPActive := (len (eg .nodes ) == 1 && len (eg .namespaces ) == 1 && eg .ip == eg .namespaces [0 ].requestedIPs [0 ])
317
- if egressIPActive && eg .assignedNodeIP != eg .nodes [0 ].nodeIP {
336
+ func (eip * egressIPWatcher ) syncEgressNodeState (eg * egressIPInfo , active bool ) {
337
+ if active && eg .assignedNodeIP != eg .nodes [0 ].nodeIP {
318
338
glog .V (4 ).Infof ("Assigning egress IP %s to node %s" , eg .ip , eg .nodes [0 ].nodeIP )
319
339
eg .assignedNodeIP = eg .nodes [0 ].nodeIP
320
340
eg .assignedIPTablesMark = getMarkForVNID (eg .namespaces [0 ].vnid , eip .masqueradeBit )
@@ -324,7 +344,7 @@ func (eip *egressIPWatcher) syncEgressNodeState(eg *egressIPInfo) {
324
344
eg .assignedNodeIP = ""
325
345
}
326
346
}
327
- } else if ! egressIPActive && eg .assignedNodeIP != "" {
347
+ } else if ! active && eg .assignedNodeIP != "" {
328
348
glog .V (4 ).Infof ("Removing egress IP %s from node %s" , eg .ip , eg .assignedNodeIP )
329
349
if eg .assignedNodeIP == eip .localIP {
330
350
if err := eip .releaseEgressIP (eg .ip , eg .assignedIPTablesMark ); err != nil {
@@ -333,8 +353,6 @@ func (eip *egressIPWatcher) syncEgressNodeState(eg *egressIPInfo) {
333
353
}
334
354
eg .assignedNodeIP = ""
335
355
eg .assignedIPTablesMark = ""
336
- } else if ! egressIPActive {
337
- glog .V (4 ).Infof ("Egress IP %s is not assignable (%d namespaces, %d nodes)" , eg .ip , len (eg .namespaces ), len (eg .nodes ))
338
356
}
339
357
}
340
358
@@ -344,7 +362,7 @@ func (eip *egressIPWatcher) syncEgressNamespaceState(ns *namespaceEgress) error
344
362
}
345
363
346
364
var active * egressIPInfo
347
- for i , ip := range ns .requestedIPs {
365
+ for _ , ip := range ns .requestedIPs {
348
366
eg := eip .egressIPs [ip ]
349
367
if eg == nil {
350
368
continue
@@ -354,9 +372,11 @@ func (eip *egressIPWatcher) syncEgressNamespaceState(ns *namespaceEgress) error
354
372
glog .V (4 ).Infof ("VNID %d gets no egress due to multiply-assigned egress IP %s" , ns .vnid , eg .ip )
355
373
break
356
374
}
357
- if active == nil && i == 0 {
375
+ if active == nil {
358
376
if eg .assignedNodeIP == "" {
359
377
glog .V (4 ).Infof ("VNID %d cannot use unassigned egress IP %s" , ns .vnid , eg .ip )
378
+ } else if len (ns .requestedIPs ) > 1 && eg .nodes [0 ].offline {
379
+ glog .V (4 ).Infof ("VNID %d cannot use egress IP %s on offline node %s" , ns .vnid , eg .ip , eg .assignedNodeIP )
360
380
} else {
361
381
active = eg
362
382
}
@@ -436,3 +456,29 @@ func (eip *egressIPWatcher) releaseEgressIP(egressIP, mark string) error {
436
456
437
457
return nil
438
458
}
459
+
460
+ func (eip * egressIPWatcher ) watchVXLAN (updates chan * egressVXLANNode ) {
461
+ for node := range updates {
462
+ eip .updateNode (node .nodeIP , node .offline )
463
+ }
464
+ }
465
+
466
+ func (eip * egressIPWatcher ) updateNode (nodeIP string , offline bool ) {
467
+ eip .Lock ()
468
+ defer eip .Unlock ()
469
+
470
+ node := eip .nodesByNodeIP [nodeIP ]
471
+ if node == nil {
472
+ eip .vxlanMonitor .RemoveNode (nodeIP )
473
+ return
474
+ }
475
+
476
+ node .offline = offline
477
+ for _ , ip := range node .requestedIPs .UnsortedList () {
478
+ eg := eip .egressIPs [ip ]
479
+ if eg != nil {
480
+ eip .egressIPChanged (eg )
481
+ }
482
+ }
483
+ eip .syncEgressIPs ()
484
+ }
0 commit comments