@@ -57,11 +57,14 @@ var (
5757
5858// Controller reconciles RouteAdvertisements
5959type Controller struct {
60- eipLister egressiplisters.EgressIPLister
61- frrLister frrlisters.FRRConfigurationLister
62- nadLister nadlisters.NetworkAttachmentDefinitionLister
63- nodeLister corelisters.NodeLister
64- raLister ralisters.RouteAdvertisementsLister
60+ wf * factory.WatchFactory
61+
62+ eipLister egressiplisters.EgressIPLister
63+ frrLister frrlisters.FRRConfigurationLister
64+ nadLister nadlisters.NetworkAttachmentDefinitionLister
65+ nodeLister corelisters.NodeLister
66+ raLister ralisters.RouteAdvertisementsLister
67+ namespaceLister corelisters.NamespaceLister
6568
6669 frrClient frrclientset.Interface
6770 nadClient nadclientset.Interface
@@ -72,6 +75,7 @@ type Controller struct {
7275 nadController controllerutil.Controller
7376 nodeController controllerutil.Controller
7477 raController controllerutil.Controller
78+ nsController controllerutil.Controller
7579
7680 nm networkmanager.Interface
7781}
@@ -83,15 +87,17 @@ func NewController(
8387 ovnClient * util.OVNClusterManagerClientset ,
8488) * Controller {
8589 c := & Controller {
86- eipLister : wf .EgressIPInformer ().Lister (),
87- frrLister : wf .FRRConfigurationsInformer ().Lister (),
88- nadLister : wf .NADInformer ().Lister (),
89- nodeLister : wf .NodeCoreInformer ().Lister (),
90- raLister : wf .RouteAdvertisementsInformer ().Lister (),
91- frrClient : ovnClient .FRRClient ,
92- nadClient : ovnClient .NetworkAttchDefClient ,
93- raClient : ovnClient .RouteAdvertisementsClient ,
94- nm : nm ,
90+ wf : wf ,
91+ eipLister : wf .EgressIPInformer ().Lister (),
92+ frrLister : wf .FRRConfigurationsInformer ().Lister (),
93+ nadLister : wf .NADInformer ().Lister (),
94+ nodeLister : wf .NodeCoreInformer ().Lister (),
95+ raLister : wf .RouteAdvertisementsInformer ().Lister (),
96+ namespaceLister : wf .NamespaceInformer ().Lister (),
97+ frrClient : ovnClient .FRRClient ,
98+ nadClient : ovnClient .NetworkAttchDefClient ,
99+ raClient : ovnClient .RouteAdvertisementsClient ,
100+ nm : nm ,
95101 }
96102
97103 handleError := func (key string , errorstatus error ) error {
@@ -153,14 +159,24 @@ func NewController(
153159
154160 eipConfig := & controllerutil.ControllerConfig [eiptypes.EgressIP ]{
155161 RateLimiter : workqueue .DefaultTypedControllerRateLimiter [string ](),
156- Reconcile : c .reconcileEgressIP ,
162+ Reconcile : c .reconcileEgressIPs ,
157163 Threadiness : 1 ,
158164 Informer : wf .EgressIPInformer ().Informer (),
159165 Lister : wf .EgressIPInformer ().Lister ().List ,
160166 ObjNeedsUpdate : egressIPNeedsUpdate ,
161167 }
162168 c .eipController = controllerutil .NewController ("clustermanager routeadvertisements egressip controller" , eipConfig )
163169
170+ nsConfig := & controllerutil.ControllerConfig [corev1.Namespace ]{
171+ RateLimiter : workqueue .DefaultTypedControllerRateLimiter [string ](),
172+ Reconcile : c .reconcileEgressIPs ,
173+ Threadiness : 1 ,
174+ Informer : wf .NamespaceInformer ().Informer (),
175+ Lister : wf .NamespaceInformer ().Lister ().List ,
176+ ObjNeedsUpdate : nsNeedsUpdate ,
177+ }
178+ c .nsController = controllerutil .NewController ("clustermanager routeadvertisements namespace controller" , nsConfig )
179+
164180 return c
165181}
166182
@@ -171,6 +187,7 @@ func (c *Controller) Start() error {
171187 c .frrController ,
172188 c .nadController ,
173189 c .nodeController ,
190+ c .nsController ,
174191 c .raController ,
175192 )
176193}
@@ -181,20 +198,33 @@ func (c *Controller) Stop() {
181198 c .frrController ,
182199 c .nadController ,
183200 c .nodeController ,
201+ c .nsController ,
184202 c .raController ,
185203 )
186- klog .Infof ("Cluster manager routeadvertisements stoppedu " )
204+ klog .Infof ("Cluster manager routeadvertisements stopped " )
187205}
188206
189207func (c * Controller ) ReconcileNetwork (_ string , old , new util.NetInfo ) {
190- // This controller already listens on NAD events however we skip NADs
191- // pointing to networks that network manager is still not aware of; so we
192- // only need to signal the reconciliation of new networks. Reconcile one of
193- // the NADs of the network to do s
194- if new == nil || old != nil {
195- return
196- }
197- c .nadController .Reconcile (new .GetNADs ()[0 ])
208+ // This controller already listens on NAD events but there is two additional
209+ // scenarios we need to cover for:
210+ // - for newly created networks, we need to wait until network manager is
211+ // aware of them.
212+ // - if the namespaces served by a network change.
213+ oldNamespaces , newNamespaces := sets .New [string ](), sets .New [string ]()
214+ if old != nil {
215+ oldNamespaces .Insert (old .GetNADNamespaces ()... )
216+ }
217+ if new != nil {
218+ newNamespaces .Insert (new .GetNADNamespaces ()... )
219+ }
220+ if new != nil && ! newNamespaces .Equal (oldNamespaces ) {
221+ // we use one of the NADs of the network to reconcile it
222+ c .nadController .Reconcile (new .GetNADs ()[0 ])
223+ // if the namespaces served by a network changed, it is possible that
224+ // those namespaces are served or no longer served by the default
225+ // network, so reconcile it as well
226+ c .nadController .Reconcile (config .Kubernetes .OVNConfigNamespace + "/" + types .DefaultNetworkName )
227+ }
198228}
199229
200230// Reconcile RouteAdvertisements. For each selected FRRConfiguration and node,
@@ -206,7 +236,8 @@ func (c *Controller) ReconcileNetwork(_ string, old, new util.NetInfo) {
206236//
207237// - If EgressIP advertisements are enabled, the generated FRRConfiguration will
208238// announce from the node the EgressIPs allocated to it on the matching target
209- // VRFs.
239+ // VRFs. Selected EgressIP are those that serve the same namespaces as the
240+ // selected networks. Target VRF `auto` is not supported for EgressIPs.
210241//
211242// - If pod network advertisements are enabled, the generated FRRConfiguration
212243// will import the target VRFs on the selected networks as required.
@@ -222,7 +253,7 @@ func (c *Controller) ReconcileNetwork(_ string, old, new util.NetInfo) {
222253// Finally, it will update the status of the RouteAdvertisements.
223254//
224255// The controller processes selected events of RouteAdvertisements,
225- // FRRConfigurations, Nodes, EgressIPs and NADs .
256+ // FRRConfigurations, Nodes, EgressIPs, NADs and namespaces .
226257func (c * Controller ) reconcile (name string ) error {
227258 startTime := time .Now ()
228259 klog .V (5 ).Infof ("Syncing routeadvertisements %q" , name )
@@ -294,6 +325,11 @@ func (c *Controller) generateFRRConfigurations(ra *ratypes.RouteAdvertisements)
294325 return nil , nil , nil
295326 }
296327
328+ advertisements := sets .New (ra .Spec .Advertisements ... )
329+ if advertisements .Has (ratypes .EgressIP ) && ra .Spec .TargetVRF == "auto" {
330+ return nil , nil , fmt .Errorf ("%w: advertising EgressIP not supported with TargetVRF set to 'auto'" , errConfig )
331+ }
332+
297333 // if we are matching on the well known default network label, create an
298334 // internal nad for it if it doesn't exist
299335 if matchesDefaultNetworkLabel (ra .Spec .NetworkSelector ) {
@@ -369,7 +405,6 @@ func (c *Controller) generateFRRConfigurations(ra *ratypes.RouteAdvertisements)
369405 if err != nil {
370406 return nil , nil , err
371407 }
372- advertisements := sets .New (ra .Spec .Advertisements ... )
373408 if ! nodeSelector .Empty () && advertisements .Has (ratypes .PodNetwork ) {
374409 return nil , nil , fmt .Errorf ("%w: node selector cannot be specified if pod network is advertised" , errConfig )
375410 }
@@ -444,15 +479,15 @@ func (c *Controller) generateFRRConfigurations(ra *ratypes.RouteAdvertisements)
444479
445480 // helper to gather egress ips and cache during reconcile
446481 // TODO perhaps cache across reconciles as well
447- var nodeEgressIPs map [string ][] string
448- getEgressIPs := func (nodeName string ) ([] string , error ) {
449- if nodeEgressIPs == nil {
450- nodeEgressIPs , err = c .getEgressIPsByNode ( )
482+ var eipsByNodesByNetworks map [string ]map [ string ]sets. Set [ string ]
483+ getEgressIPsByNode := func (nodeName string ) (map [ string ]sets. Set [ string ] , error ) {
484+ if eipsByNodesByNetworks == nil {
485+ eipsByNodesByNetworks , err = c .getEgressIPsByNodesByNetworks ( networkSet )
451486 if err != nil {
452487 return nil , err
453488 }
454489 }
455- return nodeEgressIPs [nodeName ], nil
490+ return eipsByNodesByNetworks [nodeName ], nil
456491 }
457492
458493 // helper to gather host subnets and egress ips as prefixes
@@ -469,13 +504,11 @@ func (c *Controller) generateFRRConfigurations(ra *ratypes.RouteAdvertisements)
469504 // gather EgressIPs
470505 var eips []string
471506 if advertisements .Has (ratypes .EgressIP ) {
472- if network != types .DefaultNetworkName {
473- return nil , fmt .Errorf ("%w: can't advertise EgressIP in selected non default network %q: %w" , errConfig , network , err )
474- }
475- eips , err = getEgressIPs (nodeName )
507+ eipsByNode , err := getEgressIPsByNode (nodeName )
476508 if err != nil {
477509 return nil , err
478510 }
511+ eips = eipsByNode [network ].UnsortedList ()
479512 }
480513
481514 prefixes := make ([]string , 0 , len (subnets )+ len (eips ))
@@ -500,8 +533,13 @@ func (c *Controller) generateFRRConfigurations(ra *ratypes.RouteAdvertisements)
500533 // ordered
501534 slices .Sort (selectedNetworks .hostNetworkSubnets [network ])
502535 }
503- // ordered
504- slices .Sort (selectedNetworks .hostSubnets )
536+ // order, dedup
537+ selectedNetworks .hostSubnets = sets .List (sets .New (selectedNetworks .hostSubnets ... ))
538+
539+ // if there is no prefixes to advertise for this node, skip it
540+ if len (selectedNetworks .hostSubnets ) == 0 {
541+ continue
542+ }
505543
506544 matchedNetworks := sets .New [string ]()
507545 for _ , frrConfig := range frrConfigs {
@@ -985,26 +1023,69 @@ func (c *Controller) getOrCreateDefaultNetworkNAD() (*nadtypes.NetworkAttachment
9851023 )
9861024}
9871025
988- // getEgressIPsByNode iterates all existing egress IPs and returns them indexed
989- // by node
990- func (c * Controller ) getEgressIPsByNode () (map [string ][]string , error ) {
1026+ // getEgressIPsByNodesByNetworks iterates all existing egress IPs that apply to
1027+ // any of the provided networks and returns a "node -> network -> eips"
1028+ // map.
1029+ func (c * Controller ) getEgressIPsByNodesByNetworks (networks sets.Set [string ]) (map [string ]map [string ]sets.Set [string ], error ) {
1030+ eipsByNodesByNetworks := map [string ]map [string ]sets.Set [string ]{}
1031+ addEgressIPsByNodesByNetwork := func (eipsByNodes map [string ]string , network string ) {
1032+ for node , eip := range eipsByNodes {
1033+ if eipsByNodesByNetworks [node ] == nil {
1034+ eipsByNodesByNetworks [node ] = map [string ]sets.Set [string ]{}
1035+ }
1036+ if eipsByNodesByNetworks [node ][network ] == nil {
1037+ eipsByNodesByNetworks [node ][network ] = sets .New [string ]()
1038+ }
1039+ eipsByNodesByNetworks [node ][network ].Insert (eip )
1040+ }
1041+ }
1042+
1043+ addEgressIPsByNodesByNetworkSelector := func (eipsByNodes map [string ]string , namespaceSelector * metav1.LabelSelector ) error {
1044+ nsSelector , err := metav1 .LabelSelectorAsSelector (namespaceSelector )
1045+ if err != nil {
1046+ return err
1047+ }
1048+ selected , err := c .namespaceLister .List (nsSelector )
1049+ if err != nil {
1050+ return err
1051+ }
1052+ for _ , namespace := range selected {
1053+ namespaceNetwork := c .nm .GetActiveNetworkForNamespaceFast (namespace .Name )
1054+ networkName := namespaceNetwork .GetNetworkName ()
1055+ if networks .Has (networkName ) {
1056+ addEgressIPsByNodesByNetwork (eipsByNodes , networkName )
1057+ }
1058+ }
1059+ return nil
1060+ }
1061+
9911062 eips , err := c .eipLister .List (labels .Everything ())
9921063 if err != nil {
9931064 return nil , err
9941065 }
9951066
996- eipsByNode := map [string ][]string {}
9971067 for _ , eip := range eips {
1068+ eipsByNodes := make (map [string ]string , len (eip .Status .Items ))
9981069 for _ , item := range eip .Status .Items {
999- if item .EgressIP == "" {
1070+ // skip unassigned EIPs
1071+ if item .EgressIP == "" || item .Node == "" {
10001072 continue
10011073 }
1074+
10021075 ip := item .EgressIP + util .GetIPFullMaskString (item .EgressIP )
1003- eipsByNode [item .Node ] = append (eipsByNode [item .Node ], ip )
1076+ eipsByNodes [item .Node ] = ip
1077+ }
1078+ if len (eipsByNodes ) == 0 {
1079+ continue
1080+ }
1081+
1082+ err = addEgressIPsByNodesByNetworkSelector (eipsByNodes , & eip .Spec .NamespaceSelector )
1083+ if err != nil {
1084+ return nil , err
10041085 }
10051086 }
10061087
1007- return eipsByNode , nil
1088+ return eipsByNodesByNetworks , nil
10081089}
10091090
10101091// isOwnUpdate checks if an object was updated by us last, as indicated by its
@@ -1055,12 +1136,13 @@ func nadNeedsUpdate(oldObj, newObj *nadtypes.NetworkAttachmentDefinition) bool {
10551136func nodeNeedsUpdate (oldObj , newObj * corev1.Node ) bool {
10561137 return oldObj == nil || newObj == nil ||
10571138 ! reflect .DeepEqual (oldObj .Labels , newObj .Labels ) ||
1058- util .NodeSubnetAnnotationChanged (oldObj , newObj )
1139+ util .NodeSubnetAnnotationChanged (oldObj , newObj ) ||
1140+ oldObj .Annotations [util .OvnNodeIfAddr ] != newObj .Annotations [util .OvnNodeIfAddr ]
10591141}
10601142
10611143func egressIPNeedsUpdate (oldObj , newObj * eiptypes.EgressIP ) bool {
1062- if oldObj != nil && newObj != nil && reflect . DeepEqual ( oldObj . Status , newObj . Status ) {
1063- return false
1144+ if oldObj != nil && newObj != nil {
1145+ return ! reflect . DeepEqual ( oldObj . Status , newObj . Status ) || ! reflect . DeepEqual ( oldObj . Spec . NamespaceSelector , newObj . Spec . NamespaceSelector )
10641146 }
10651147 if oldObj != nil && len (oldObj .Status .Items ) > 0 {
10661148 return true
@@ -1071,6 +1153,12 @@ func egressIPNeedsUpdate(oldObj, newObj *eiptypes.EgressIP) bool {
10711153 return false
10721154}
10731155
1156+ func nsNeedsUpdate (oldObj , newObj * corev1.Namespace ) bool {
1157+ // we only care about label changes, added/deleted namespaces served by a
1158+ // UDN will already be reflected in a network update
1159+ return oldObj != nil && newObj != nil && ! reflect .DeepEqual (oldObj .Labels , newObj .Labels )
1160+ }
1161+
10741162func (c * Controller ) reconcileFRRConfiguration (key string ) error {
10751163 namespace , name , err := cache .SplitMetaNamespaceKey (key )
10761164 if err != nil {
@@ -1133,7 +1221,7 @@ func (c *Controller) reconcileNAD(key string) error {
11331221 return nil
11341222}
11351223
1136- func (c * Controller ) reconcileEgressIP ( _ string ) error {
1224+ func (c * Controller ) reconcileEgressIPs ( string ) error {
11371225 // reconcile RAs that advertise EIPs
11381226 ras , err := c .raLister .List (labels .Everything ())
11391227 if err != nil {
0 commit comments