@@ -17,16 +17,16 @@ import (
17
17
"github.com/cilium/hive/job"
18
18
"github.com/cilium/statedb"
19
19
"github.com/cilium/statedb/index"
20
- "github.com/cilium/stream"
21
20
"github.com/spf13/pflag"
22
21
"k8s.io/apimachinery/pkg/util/sets"
23
22
24
23
"github.com/cilium/cilium/pkg/defaults"
25
24
"github.com/cilium/cilium/pkg/ip"
26
25
"github.com/cilium/cilium/pkg/logging/logfields"
27
26
"github.com/cilium/cilium/pkg/node"
27
+ "github.com/cilium/cilium/pkg/node/addressing"
28
+ nodeTypes "github.com/cilium/cilium/pkg/node/types"
28
29
"github.com/cilium/cilium/pkg/option"
29
- "github.com/cilium/cilium/pkg/rate"
30
30
"github.com/cilium/cilium/pkg/time"
31
31
)
32
32
@@ -155,7 +155,7 @@ var (
155
155
//
156
156
// The Table[NodeAddress] contains the actual assigned addresses on the node,
157
157
// but not for example external Kubernetes node addresses that may be merely
158
- // NATd to a private address. Those can be queried through [ node.LocalNodeStore ].
158
+ // NATd to a private address. Those can be queried through Table[* node.LocalNode ].
159
159
NodeAddressCell = cell .Module (
160
160
"node-address" ,
161
161
"Table of node addresses derived from system network devices" ,
@@ -216,13 +216,12 @@ type nodeAddressControllerParams struct {
216
216
Routes statedb.Table [* Route ]
217
217
NodeAddresses statedb.RWTable [NodeAddress ]
218
218
AddressScopeMax AddressScopeMax
219
- LocalNode * node.LocalNodeStore
219
+ Nodes statedb. Table [ * node.LocalNode ]
220
220
}
221
221
222
222
type nodeAddressController struct {
223
223
nodeAddressControllerParams
224
224
225
- k8sIPv4 , k8sIPv6 netip.Addr
226
225
fallbackAddresses fallbackAddresses
227
226
}
228
227
@@ -241,88 +240,52 @@ func (n *nodeAddressController) register() {
241
240
n .Lifecycle .Append (
242
241
cell.Hook {
243
242
OnStart : func (ctx cell.HookContext ) error {
244
- if node , err := n .LocalNode .Get (ctx ); err == nil {
245
- n .updateK8sNodeIPs (node )
246
- }
247
-
248
243
// Perform an initial synchronous reconciliation to populate the table.
249
244
// This ensures that dependent cells see the initial state when they start.
250
245
// The watch channels returned here will be the initial channels for the run loop.
251
- initialDevicesWatch , initialRoutesWatch := n .reconcile ()
246
+ ws := n .reconcile ()
252
247
253
248
// Start the background job for continuous reconciliation.
254
249
n .Jobs .Add (job .OneShot ("node-address-update" , func (ctx context.Context , reporter cell.Health ) error {
255
- return n .run (ctx , reporter , initialDevicesWatch , initialRoutesWatch )
250
+ return n .run (ctx , reporter , ws )
256
251
}))
257
252
return nil
258
253
},
259
254
})
260
255
}
261
256
262
- func (n * nodeAddressController ) updateK8sNodeIPs (node node.LocalNode ) (updated bool ) {
263
- if ip := node .GetNodeIP (true ); ip != nil {
264
- if newIP , ok := netip .AddrFromSlice (ip ); ok {
265
- if newIP != n .k8sIPv6 {
266
- n .k8sIPv6 = newIP
267
- updated = true
268
- }
269
- }
270
- }
271
- if ip := node .GetNodeIP (false ); ip != nil {
272
- if newIP , ok := netip .AddrFromSlice (ip ); ok {
273
- if newIP != n .k8sIPv4 {
274
- n .k8sIPv4 = newIP
275
- updated = true
276
- }
277
- }
278
- }
279
- return
280
- }
281
-
282
- func (n * nodeAddressController ) run (ctx context.Context , reporter cell.Health , initialDevicesWatch , initialRoutesWatch <- chan struct {}) error {
283
- localNodeChanges := stream .ToChannel (ctx , stream .Debounce (n .LocalNode , nodeAddressControllerMinInterval ))
284
- limiter := rate .NewLimiter (nodeAddressControllerMinInterval , 1 )
285
-
286
- // Use the initial watch channels provided from the OnStart hook.
287
- devicesWatch := initialDevicesWatch
288
- routesWatch := initialRoutesWatch
289
-
257
+ func (n * nodeAddressController ) run (ctx context.Context , reporter cell.Health , ws * statedb.WatchSet ) error {
290
258
for {
291
- // Rate-limit to batch multiple updates together.
292
- if err := limiter .Wait (ctx ); err != nil {
293
- return err
294
- }
295
-
296
- // Wait for changes from any input source.
297
- select {
298
- case <- ctx .Done ():
259
+ // Wait for changes
260
+ if _ , err := ws .Wait (ctx , nodeAddressControllerMinInterval ); err != nil {
299
261
return nil
300
- case <- devicesWatch :
301
- // A device has changed.
302
- case <- routesWatch :
303
- // A route has changed.
304
- case localNode , ok := <- localNodeChanges :
305
- if ! ok {
306
- localNodeChanges = nil
307
- continue
308
- }
309
- // Update Kubernetes node IPs. Reconciliation will happen after rate-limiting.
310
- n .updateK8sNodeIPs (localNode )
311
262
}
312
263
313
- // Perform the full reconciliation and get new watch channels for the next iteration.
314
- devicesWatch , routesWatch = n .reconcile ()
264
+ // Perform the full reconciliation and get new watch set
265
+ ws = n .reconcile ()
315
266
}
316
267
}
317
268
318
269
// reconcile performs a full reconciliation of the NodeAddress table. It computes
319
270
// the desired state from the Devices table and updates the NodeAddress table
320
271
// to match it. It returns the read transaction and new watch channels for Devices and Routes.
321
- func (n * nodeAddressController ) reconcile () (<- chan struct {}, <- chan struct {}) {
272
+ func (n * nodeAddressController ) reconcile () * statedb.WatchSet {
273
+ ws := statedb .NewWatchSet ()
274
+
322
275
rtxn := n .DB .ReadTxn ()
276
+
277
+ var k8sIPv4 , k8sIPv6 netip.Addr
278
+ if localNode , _ , watch , found := n .Nodes .GetWatch (rtxn , node .LocalNodeQuery ); found {
279
+ k8sIPv4 , _ = netip .AddrFromSlice (addressing .ExtractNodeIP [nodeTypes.Address ](localNode .IPAddresses , false ))
280
+ k8sIPv6 , _ = netip .AddrFromSlice (addressing .ExtractNodeIP [nodeTypes.Address ](localNode .IPAddresses , true ))
281
+ ws .Add (watch )
282
+ }
283
+
323
284
// Get iterators for the current state and new watch channels.
324
285
allDevices , devicesWatch := n .Devices .AllWatch (rtxn )
286
+ ws .Add (devicesWatch )
325
287
localRoutes , routesWatch := n .Routes .PrefixWatch (rtxn , RouteIDIndex .Query (RouteID {Table : RT_TABLE_LOCAL }))
288
+ ws .Add (routesWatch )
326
289
327
290
// A map to hold the desired state of node addresses, keyed by device name.
328
291
newAddrsByDevice := make (map [string ][]NodeAddress )
@@ -331,7 +294,7 @@ func (n *nodeAddressController) reconcile() (<-chan struct{}, <-chan struct{}) {
331
294
// Get addresses from devices
332
295
n .fallbackAddresses .clear ()
333
296
for dev := range allDevices {
334
- deviceAddrs := n .getAddressesFromDevice (dev )
297
+ deviceAddrs := n .getAddressesFromDevice (dev , k8sIPv4 , k8sIPv6 )
335
298
if deviceAddrs == nil {
336
299
continue
337
300
}
@@ -427,7 +390,7 @@ func (n *nodeAddressController) reconcile() (<-chan struct{}, <-chan struct{}) {
427
390
n .update (wtxn , nil , n .Health , deletedDevName )
428
391
}
429
392
wtxn .Commit ()
430
- return devicesWatch , routesWatch
393
+ return ws
431
394
}
432
395
433
396
// updates the node addresses of a single device.
@@ -497,7 +460,7 @@ func (n *nodeAddressController) shouldUseDeviceForNodeAddress(dev *Device) bool
497
460
return true
498
461
}
499
462
500
- func (n * nodeAddressController ) getAddressesFromDevice (dev * Device ) []NodeAddress {
463
+ func (n * nodeAddressController ) getAddressesFromDevice (dev * Device , k8sIPv4 , k8sIPv6 netip. Addr ) []NodeAddress {
501
464
if ! n .shouldUseDeviceForNodeAddress (dev ) {
502
465
return nil
503
466
}
@@ -527,7 +490,7 @@ func (n *nodeAddressController) getAddressesFromDevice(dev *Device) []NodeAddres
527
490
index := len (addrs )
528
491
isPublic := ip .IsPublicAddr (addr .Addr .AsSlice ())
529
492
if addr .Addr .Is4 () {
530
- if addr .Addr .Unmap () == n . k8sIPv4 .Unmap () {
493
+ if addr .Addr .Unmap () == k8sIPv4 .Unmap () {
531
494
// Address matches the K8s Node IP. Force this to be picked.
532
495
ipv4PublicIndex = index
533
496
ipv4PrivateIndex = index
@@ -541,7 +504,7 @@ func (n *nodeAddressController) getAddressesFromDevice(dev *Device) []NodeAddres
541
504
}
542
505
543
506
if addr .Addr .Is6 () {
544
- if addr .Addr == n . k8sIPv6 {
507
+ if addr .Addr == k8sIPv6 {
545
508
// Address matches the K8s Node IP. Force this to be picked.
546
509
ipv6PublicIndex = index
547
510
ipv6PrivateIndex = index
0 commit comments