Skip to content

Commit 65188ad

Browse files
committed
RouteAdvertisements: update API to use universal NetworkSelector
Signed-off-by: Jaime Caamaño Ruiz <[email protected]>
1 parent 58e5d3f commit 65188ad

File tree

9 files changed

+491
-104
lines changed

9 files changed

+491
-104
lines changed

dist/templates/k8s.ovn.org_routeadvertisements.yaml.j2

Lines changed: 372 additions & 40 deletions
Large diffs are not rendered by default.

dist/templates/ovn-setup.yaml.j2

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,8 @@ kind: RouteAdvertisements
8686
metadata:
8787
name: default
8888
spec:
89-
networkSelector:
90-
matchLabels:
91-
k8s.ovn.org/default-network: ""
89+
networkSelectors:
90+
- networkSelectionType: DefaultNetwork
9291
advertisements:
9392
- "PodNetwork"
9493
{%- endif %}

go-controller/pkg/clustermanager/routeadvertisements/controller.go

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ import (
3838
raapply "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/routeadvertisements/v1/apis/applyconfiguration/routeadvertisements/v1"
3939
raclientset "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/routeadvertisements/v1/apis/clientset/versioned"
4040
ralisters "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/routeadvertisements/v1/apis/listers/routeadvertisements/v1"
41+
apitypes "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/types"
42+
userdefinednetworkv1 "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/userdefinednetwork/v1"
4143
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/factory"
4244
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/kube"
4345
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/networkmanager"
@@ -51,8 +53,9 @@ const (
5153
)
5254

5355
var (
54-
errConfig = errors.New("configuration error")
55-
errPending = errors.New("configuration pending")
56+
errConfig = errors.New("configuration error")
57+
errPending = errors.New("configuration pending")
58+
cudnController = userdefinednetworkv1.SchemeGroupVersion.WithKind("ClusterUserDefinedNetwork")
5659
)
5760

5861
// Controller reconciles RouteAdvertisements
@@ -332,20 +335,7 @@ func (c *Controller) generateFRRConfigurations(ra *ratypes.RouteAdvertisements)
332335

333336
// if we are matching on the well known default network label, create an
334337
// internal nad for it if it doesn't exist
335-
if matchesDefaultNetworkLabel(ra.Spec.NetworkSelector) {
336-
_, err := c.getOrCreateDefaultNetworkNAD()
337-
if err != nil {
338-
return nil, nil, fmt.Errorf("failed to get/create default network NAD: %w", err)
339-
}
340-
}
341-
342-
// gather selected networks
343-
var nads []*nadtypes.NetworkAttachmentDefinition
344-
nadSelector, err := metav1.LabelSelectorAsSelector(&ra.Spec.NetworkSelector)
345-
if err != nil {
346-
return nil, nil, err
347-
}
348-
nads, err = c.nadLister.List(nadSelector)
338+
nads, err := c.getSelectedNADs(ra.Spec.NetworkSelectors)
349339
if err != nil {
350340
return nil, nil, err
351341
}
@@ -994,6 +984,44 @@ func (c *Controller) updateRAStatus(ra *ratypes.RouteAdvertisements, hadUpdates
994984
return nil
995985
}
996986

987+
func (c *Controller) getSelectedNADs(networkSelectors apitypes.NetworkSelectors) ([]*nadtypes.NetworkAttachmentDefinition, error) {
988+
var selected []*nadtypes.NetworkAttachmentDefinition
989+
for _, networkSelector := range networkSelectors {
990+
switch networkSelector.NetworkSelectionType {
991+
case apitypes.DefaultNetwork:
992+
// if we are selecting the default networkdefault network label,
993+
// make sure a NAD exists for it
994+
nad, err := c.getOrCreateDefaultNetworkNAD()
995+
if err != nil {
996+
return nil, fmt.Errorf("failed to get/create default network NAD: %w", err)
997+
}
998+
selected = append(selected, nad)
999+
case apitypes.ClusterUserDefinedNetworks:
1000+
nadSelector, err := metav1.LabelSelectorAsSelector(&networkSelector.ClusterUserDefinedNetworkSelector.NetworkSelector)
1001+
if err != nil {
1002+
return nil, err
1003+
}
1004+
nads, err := c.nadLister.List(nadSelector)
1005+
if err != nil {
1006+
return nil, err
1007+
}
1008+
for _, nad := range nads {
1009+
// check this NAD is controlled by a CUDN
1010+
controller := metav1.GetControllerOfNoCopy(nad)
1011+
isCUDN := controller != nil && controller.Kind == cudnController.Kind && controller.APIVersion == cudnController.GroupVersion().String()
1012+
if !isCUDN {
1013+
continue
1014+
}
1015+
selected = append(selected, nad)
1016+
}
1017+
default:
1018+
return nil, fmt.Errorf("%w: unsupported network selection type %s", errConfig, networkSelector.NetworkSelectionType)
1019+
}
1020+
}
1021+
1022+
return selected, nil
1023+
}
1024+
9971025
// getOrCreateDefaultNetworkNAD ensure that a well-known NAD exists for the
9981026
// default network in ovn-k namespace.
9991027
func (c *Controller) getOrCreateDefaultNetworkNAD() (*nadtypes.NetworkAttachmentDefinition, error) {
@@ -1010,7 +1038,6 @@ func (c *Controller) getOrCreateDefaultNetworkNAD() (*nadtypes.NetworkAttachment
10101038
ObjectMeta: metav1.ObjectMeta{
10111039
Name: types.DefaultNetworkName,
10121040
Namespace: config.Kubernetes.OVNConfigNamespace,
1013-
Labels: map[string]string{types.DefaultNetworkLabelSelector: ""},
10141041
},
10151042
Spec: nadtypes.NetworkAttachmentDefinitionSpec{
10161043
Config: fmt.Sprintf("{\"cniVersion\": \"0.4.0\", \"name\": \"ovn-kubernetes\", \"type\": \"%s\"}", config.CNI.Plugin),
@@ -1236,16 +1263,3 @@ func (c *Controller) reconcileEgressIPs(string) error {
12361263

12371264
return nil
12381265
}
1239-
1240-
func matchesDefaultNetworkLabel(selector metav1.LabelSelector) bool {
1241-
_, matchesLabel := selector.MatchLabels[types.DefaultNetworkLabelSelector]
1242-
if matchesLabel {
1243-
return true
1244-
}
1245-
for _, expr := range selector.MatchExpressions {
1246-
if expr.Key == types.DefaultNetworkLabelSelector {
1247-
return true
1248-
}
1249-
}
1250-
return false
1251-
}

go-controller/pkg/clustermanager/routeadvertisements/controller_test.go

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import (
2828
controllerutil "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/controller"
2929
eiptypes "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/egressip/v1"
3030
ratypes "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/routeadvertisements/v1"
31+
apitypes "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/types"
32+
userdefinednetworkv1 "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/userdefinednetwork/v1"
3133
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/factory"
3234
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/networkmanager"
3335
ovntest "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/testing"
@@ -42,6 +44,7 @@ type testRA struct {
4244
NetworkSelector map[string]string
4345
NodeSelector map[string]string
4446
FRRConfigurationSelector map[string]string
47+
SelectsDefault bool
4548
AdvertisePods bool
4649
AdvertiseEgressIPs bool
4750
}
@@ -63,9 +66,19 @@ func (tra testRA) RouteAdvertisements() *ratypes.RouteAdvertisements {
6366
ra.Spec.Advertisements = append(ra.Spec.Advertisements, ratypes.EgressIP)
6467
}
6568
if tra.NetworkSelector != nil {
66-
ra.Spec.NetworkSelector = metav1.LabelSelector{
67-
MatchLabels: tra.NetworkSelector,
68-
}
69+
ra.Spec.NetworkSelectors = append(ra.Spec.NetworkSelectors, apitypes.NetworkSelector{
70+
NetworkSelectionType: apitypes.ClusterUserDefinedNetworks,
71+
ClusterUserDefinedNetworkSelector: &apitypes.ClusterUserDefinedNetworkSelector{
72+
NetworkSelector: metav1.LabelSelector{
73+
MatchLabels: tra.NetworkSelector,
74+
},
75+
},
76+
})
77+
}
78+
if tra.SelectsDefault {
79+
ra.Spec.NetworkSelectors = append(ra.Spec.NetworkSelectors, apitypes.NetworkSelector{
80+
NetworkSelectionType: apitypes.DefaultNetwork,
81+
})
6982
}
7083
if tra.NodeSelector != nil {
7184
ra.Spec.NodeSelector = metav1.LabelSelector{
@@ -291,6 +304,13 @@ func (tn testNAD) NAD() *nadtypes.NetworkAttachmentDefinition {
291304
Annotations: tn.Annotations,
292305
},
293306
}
307+
if strings.HasPrefix(tn.Network, types.CUDNPrefix) {
308+
ownerRef := *metav1.NewControllerRef(
309+
&metav1.ObjectMeta{Name: tn.Network},
310+
userdefinednetworkv1.SchemeGroupVersion.WithKind("ClusterUserDefinedNetwork"),
311+
)
312+
nad.ObjectMeta.OwnerReferences = []metav1.OwnerReference{ownerRef}
313+
}
294314
topology := tn.Topology
295315
if topology == "" {
296316
topology = "layer3"
@@ -378,7 +398,7 @@ func TestController_reconcile(t *testing.T) {
378398
}{
379399
{
380400
name: "reconciles pod+eip RouteAdvertisement for a single FRR config, node and default network and target VRF",
381-
ra: &testRA{Name: "ra", AdvertisePods: true, AdvertiseEgressIPs: true},
401+
ra: &testRA{Name: "ra", AdvertisePods: true, AdvertiseEgressIPs: true, SelectsDefault: true},
382402
frrConfigs: []*testFRRConfig{
383403
{
384404
Name: "frrConfig",
@@ -409,7 +429,7 @@ func TestController_reconcile(t *testing.T) {
409429
},
410430
{
411431
name: "reconciles dual-stack pod+eip RouteAdvertisement for a single FRR config, node and default network and target VRF",
412-
ra: &testRA{Name: "ra", AdvertisePods: true, AdvertiseEgressIPs: true},
432+
ra: &testRA{Name: "ra", AdvertisePods: true, AdvertiseEgressIPs: true, SelectsDefault: true},
413433
frrConfigs: []*testFRRConfig{
414434
{
415435
Name: "frrConfig",
@@ -455,8 +475,8 @@ func TestController_reconcile(t *testing.T) {
455475
},
456476
},
457477
nads: []*testNAD{
458-
{Name: "red", Namespace: "red", Network: util.GenerateCUDNNetworkName("red"), Topology: "layer3", Subnet: "1.2.0.0/16", Labels: map[string]string{"selected": "true"}},
459-
{Name: "blue", Namespace: "blue", Network: util.GenerateCUDNNetworkName("blue"), Topology: "layer3", Subnet: "1.3.0.0/16", Labels: map[string]string{"selected": "true"}},
478+
{Name: "red", Namespace: "red", Network: "cluster_udn_red", Topology: "layer3", Subnet: "1.2.0.0/16", Labels: map[string]string{"selected": "true"}},
479+
{Name: "blue", Namespace: "blue", Network: "cluster_udn_blue", Topology: "layer3", Subnet: "1.3.0.0/16", Labels: map[string]string{"selected": "true"}},
460480
},
461481
nodes: []*testNode{{Name: "node", SubnetsAnnotation: "{\"default\":\"1.1.0.0/24\", \"cluster_udn_red\":\"1.2.0.0/24\", \"cluster_udn_blue\":\"1.3.0.0/24\"}"}},
462482
eips: []*testEIP{{Name: "eip", EIPs: map[string]string{"node": "1.0.1.1"}}},
@@ -493,11 +513,11 @@ func TestController_reconcile(t *testing.T) {
493513
},
494514
nads: []*testNAD{
495515
{Name: "default", Namespace: "ovn-kubernetes", Network: "default"},
496-
{Name: "red", Namespace: "red", Network: "cluster.udn.red", Topology: "layer3", Subnet: "1.2.0.0/16"},
497-
{Name: "blue", Namespace: "blue", Network: "cluster.udn.blue", Topology: "layer3", Subnet: "1.3.0.0/16", Labels: map[string]string{"selected": "true"}},
516+
{Name: "red", Namespace: "red", Network: "cluster_udn_red", Topology: "layer3", Subnet: "1.2.0.0/16"},
517+
{Name: "blue", Namespace: "blue", Network: "cluster_udn_blue", Topology: "layer3", Subnet: "1.3.0.0/16", Labels: map[string]string{"selected": "true"}},
498518
},
499519
nodes: []*testNode{
500-
{Name: "node", SubnetsAnnotation: "{\"default\":\"1.1.1.0/24\", \"cluster.udn.red\":\"1.2.1.0/24\", \"cluster.udn.blue\":\"1.3.1.0/24\"}"},
520+
{Name: "node", SubnetsAnnotation: "{\"default\":\"1.1.1.0/24\", \"cluster_udn_red\":\"1.2.1.0/24\", \"cluster_udn_blue\":\"1.3.1.0/24\"}"},
501521
},
502522
namespaces: []*testNamespace{
503523
{Name: "default", Labels: map[string]string{"selected": "default"}},
@@ -526,7 +546,7 @@ func TestController_reconcile(t *testing.T) {
526546
},
527547
{
528548
name: "reconciles a RouteAdvertisement updating the generated FRRConfigurations if needed",
529-
ra: &testRA{Name: "ra", AdvertisePods: true, AdvertiseEgressIPs: true},
549+
ra: &testRA{Name: "ra", AdvertisePods: true, AdvertiseEgressIPs: true, SelectsDefault: true},
530550
frrConfigs: []*testFRRConfig{
531551
{
532552
Name: "frrConfig",
@@ -594,11 +614,12 @@ func TestController_reconcile(t *testing.T) {
594614
TargetVRF: "auto",
595615
FRRConfigurationSelector: map[string]string{"selected": "true"},
596616
NetworkSelector: map[string]string{"selected": "true"},
617+
SelectsDefault: true,
597618
},
598619
nads: []*testNAD{
599620
{Name: "default", Namespace: "ovn-kubernetes", Network: "default", Labels: map[string]string{"selected": "true"}},
600-
{Name: "red", Namespace: "red", Network: util.GenerateCUDNNetworkName("red"), Topology: "layer3", Subnet: "1.2.0.0/16", Labels: map[string]string{"selected": "true"}},
601-
{Name: "blue", Namespace: "blue", Network: util.GenerateCUDNNetworkName("blue"), Topology: "layer3"}, // not selected
621+
{Name: "red", Namespace: "red", Network: "cluster_udn_red", Topology: "layer3", Subnet: "1.2.0.0/16", Labels: map[string]string{"selected": "true"}},
622+
{Name: "blue", Namespace: "blue", Network: "cluster_udn_blue", Topology: "layer3"}, // not selected
602623
},
603624
frrConfigs: []*testFRRConfig{
604625
{
@@ -708,6 +729,15 @@ func TestController_reconcile(t *testing.T) {
708729
reconcile: "ra",
709730
expectAcceptedStatus: metav1.ConditionFalse,
710731
},
732+
{
733+
name: "fails to reconcile an non-cluster UDN",
734+
ra: &testRA{Name: "ra", AdvertisePods: true, NetworkSelector: map[string]string{"selected": "true"}},
735+
nads: []*testNAD{
736+
{Name: "red", Namespace: "red", Network: "red", Topology: "layer3", Subnet: "1.2.0.0/16", Labels: map[string]string{"selected": "true"}},
737+
},
738+
reconcile: "ra",
739+
expectAcceptedStatus: metav1.ConditionFalse,
740+
},
711741
{
712742
name: "fails to reconcile pod network if node selector is not empty",
713743
ra: &testRA{Name: "ra", AdvertisePods: true, NodeSelector: map[string]string{"selected": "true"}},
@@ -794,8 +824,8 @@ func TestController_reconcile(t *testing.T) {
794824
name: "fails to reconcile if not all VRFs were matched with 'auto' target VRF",
795825
ra: &testRA{Name: "ra", TargetVRF: "auto", AdvertisePods: true, NetworkSelector: map[string]string{"selected": "true"}},
796826
nads: []*testNAD{
797-
{Name: "red", Namespace: "red", Network: "red", Topology: "layer3", Labels: map[string]string{"selected": "true"}},
798-
{Name: "blue", Namespace: "blue", Network: "blue", Topology: "layer3", Labels: map[string]string{"selected": "true"}},
827+
{Name: "red", Namespace: "red", Network: "cluster_udn_red", Topology: "layer3", Labels: map[string]string{"selected": "true"}},
828+
{Name: "blue", Namespace: "blue", Network: "cluster_udn_blue", Topology: "layer3", Labels: map[string]string{"selected": "true"}},
799829
},
800830
frrConfigs: []*testFRRConfig{
801831
{
@@ -808,7 +838,7 @@ func TestController_reconcile(t *testing.T) {
808838
},
809839
},
810840
},
811-
nodes: []*testNode{{Name: "node", SubnetsAnnotation: "{\"red\":\"1.1.0.0/24\", \"blue\":\"1.2.0.0/24\"}"}},
841+
nodes: []*testNode{{Name: "node", SubnetsAnnotation: "{\"cluster_udn_red\":\"1.1.0.0/24\", \"cluster_udn_blue\":\"1.2.0.0/24\"}"}},
812842
reconcile: "ra",
813843
expectAcceptedStatus: metav1.ConditionFalse,
814844
},

go-controller/pkg/crd/routeadvertisements/v1/apis/applyconfiguration/routeadvertisements/v1/routeadvertisementsspec.go

Lines changed: 6 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go-controller/pkg/crd/routeadvertisements/v1/types.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package v1
22

33
import (
44
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5+
6+
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/crd/types"
57
)
68

79
// +genclient
@@ -24,14 +26,16 @@ type RouteAdvertisements struct {
2426

2527
// RouteAdvertisementsSpec defines the desired state of RouteAdvertisements
2628
// +kubebuilder:validation:XValidation:rule="!has(self.nodeSelector) || !('PodNetwork' in self.advertisements)",message="If 'PodNetwork' is selected for advertisement, a 'nodeSelector' can't be specified as it needs to be advertised on all nodes"
29+
// +kubebuilder:validation:XValidation:rule="!self.networkSelectors.exists(i, i.networkSelectionType != 'DefaultNetwork' && i.networkSelectionType != 'ClusterUserDefinedNetworks')",message="Only DefaultNetwork or ClusterUserDefinedNetworks can be selected"
2730
type RouteAdvertisementsSpec struct {
2831
// targetVRF determines which VRF the routes should be advertised in.
2932
// +kubebuilder:validation:Optional
3033
TargetVRF string `json:"targetVRF,omitempty"`
3134

32-
// networkSelector determines which network routes should be advertised. To
33-
// select the default network, match on label 'k8s.ovn.org/default-network'.
34-
NetworkSelector metav1.LabelSelector `json:"networkSelector,omitempty"`
35+
// networkSelectors determines which network routes should be advertised.
36+
// Only ClusterUserDefinedNetworks and the default network can be selected.
37+
// +kubebuilder:validation:Required
38+
NetworkSelectors types.NetworkSelectors `json:"networkSelectors"`
3539

3640
// nodeSelector limits the advertisements to selected nodes.
3741
// When omitted, all nodes are selected.

go-controller/pkg/crd/routeadvertisements/v1/zz_generated.deepcopy.go

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go-controller/pkg/types/const.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,6 @@ const (
157157
// OVN-K8S annotation & taint constants
158158
OvnK8sPrefix = "k8s.ovn.org"
159159

160-
// DefaultNetworkLabelSelector is the label that needs to be matched on a
161-
// selector to select the default network
162-
DefaultNetworkLabelSelector = OvnK8sPrefix + "/default-network"
163160
// OvnNetworkNameAnnotation is the name of the network annotated on the NAD
164161
// by cluster manager nad controller
165162
OvnNetworkNameAnnotation = OvnK8sPrefix + "/network-name"

test/e2e/route_advertisements.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,9 +466,12 @@ kind: RouteAdvertisements
466466
metadata:
467467
name: ` + name + `
468468
spec:
469-
networkSelector:
470-
matchLabels:
471-
k8s.ovn.org/bgp-network: ""
469+
networkSelectors:
470+
- networkSelectionType: ClusterUserDefinedNetworks
471+
clusterUserDefinedNetworkSelector:
472+
networkSelector:
473+
matchLabels:
474+
k8s.ovn.org/bgp-network: ""
472475
advertisements:
473476
- "PodNetwork"`
474477
}

0 commit comments

Comments
 (0)