From 154de3f044549f8816b118c2902806842be4c9ce Mon Sep 17 00:00:00 2001 From: Mark Stansberry Date: Thu, 8 Aug 2024 18:40:17 -0400 Subject: [PATCH] BGPFilter: Add prefixLength to BGPFilter to match on min/max prefix length BGPFilter: Update PrefixLength to use pointers, add validators, and move to int32 BGPFilter: Update BGPFilter tests to duplicate and only use ipv6 in v6 rules BGPFilter: Add test confirming prefixLength is ignored when CIDR is not provided BGPFilter: Add error surfacing for failed ParseCIDR BGPFilter: Add kubebuilder validation for PrefixLength BGPFilter: Flatten validator functions for PrefixLength and add checks for empty CIDR --- api/pkg/apis/projectcalico/v3/bgpfilter.go | 22 +++++ .../projectcalico/v3/zz_generated.deepcopy.go | 78 ++++++++++++++- api/pkg/openapi/openapi_generated.go | 64 ++++++++++++ calicoctl/calicoctl/commands/crds/crds.go | 2 +- confd/pkg/resource/template/template_funcs.go | 98 ++++++++++++++----- .../resource/template/template_funcs_test.go | 34 +++++-- felix/dataplane/linux/bpf_ep_mgr.go | 2 +- .../crd/crd.projectcalico.org_bgpfilters.yaml | 52 ++++++++++ libcalico-go/lib/validator/v3/validator.go | 32 +++++- .../lib/validator/v3/validator_test.go | 66 +++++++++++++ manifests/calico-bpf.yaml | 52 ++++++++++ manifests/calico-policy-only.yaml | 52 ++++++++++ manifests/calico-typha.yaml | 52 ++++++++++ manifests/calico-vxlan.yaml | 52 ++++++++++ manifests/calico.yaml | 52 ++++++++++ manifests/canal.yaml | 52 ++++++++++ manifests/crds.yaml | 52 ++++++++++ manifests/flannel-migration/calico.yaml | 52 ++++++++++ .../ocp/crd.projectcalico.org_bgpfilters.yaml | 52 ++++++++++ manifests/operator-crds.yaml | 52 ++++++++++ manifests/tigera-operator.yaml | 52 ++++++++++ 21 files changed, 977 insertions(+), 45 deletions(-) diff --git a/api/pkg/apis/projectcalico/v3/bgpfilter.go b/api/pkg/apis/projectcalico/v3/bgpfilter.go index 21e70ce14ec..bf3538d1e57 100644 --- a/api/pkg/apis/projectcalico/v3/bgpfilter.go +++ b/api/pkg/apis/projectcalico/v3/bgpfilter.go @@ -64,6 +64,8 @@ type BGPFilterSpec struct { type BGPFilterRuleV4 struct { CIDR string `json:"cidr,omitempty" validate:"omitempty,netv4"` + PrefixLength *BGPFilterPrefixLengthV4 `json:"prefixLength,omitempty" validate:"omitempty"` + Source BGPFilterMatchSource `json:"source,omitempty" validate:"omitempty,oneof=RemotePeers"` Interface string `json:"interface,omitempty" validate:"omitempty,bgpFilterInterface"` @@ -77,6 +79,8 @@ type BGPFilterRuleV4 struct { type BGPFilterRuleV6 struct { CIDR string `json:"cidr,omitempty" validate:"omitempty,netv6"` + PrefixLength *BGPFilterPrefixLengthV6 `json:"prefixLength,omitempty" validate:"omitempty"` + Source BGPFilterMatchSource `json:"source,omitempty" validate:"omitempty,oneof=RemotePeers"` Interface string `json:"interface,omitempty" validate:"omitempty,bgpFilterInterface"` @@ -86,6 +90,24 @@ type BGPFilterRuleV6 struct { Action BGPFilterAction `json:"action" validate:"required,filterAction"` } +type BGPFilterPrefixLengthV4 struct { + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=32 + Min *int32 `json:"min,omitempty" validate:"omitempty,bgpFilterPrefixLengthV4"` + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=32 + Max *int32 `json:"max,omitempty" validate:"omitempty,bgpFilterPrefixLengthV4"` +} + +type BGPFilterPrefixLengthV6 struct { + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=128 + Min *int32 `json:"min,omitempty" validate:"omitempty,bgpFilterPrefixLengthV6"` + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=128 + Max *int32 `json:"max,omitempty" validate:"omitempty,bgpFilterPrefixLengthV6"` +} + type BGPFilterMatchSource string const ( diff --git a/api/pkg/apis/projectcalico/v3/zz_generated.deepcopy.go b/api/pkg/apis/projectcalico/v3/zz_generated.deepcopy.go index 35bdeda080d..5fe82c447d3 100644 --- a/api/pkg/apis/projectcalico/v3/zz_generated.deepcopy.go +++ b/api/pkg/apis/projectcalico/v3/zz_generated.deepcopy.go @@ -239,9 +239,66 @@ func (in *BGPFilterList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BGPFilterPrefixLengthV4) DeepCopyInto(out *BGPFilterPrefixLengthV4) { + *out = *in + if in.Min != nil { + in, out := &in.Min, &out.Min + *out = new(int32) + **out = **in + } + if in.Max != nil { + in, out := &in.Max, &out.Max + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BGPFilterPrefixLengthV4. +func (in *BGPFilterPrefixLengthV4) DeepCopy() *BGPFilterPrefixLengthV4 { + if in == nil { + return nil + } + out := new(BGPFilterPrefixLengthV4) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BGPFilterPrefixLengthV6) DeepCopyInto(out *BGPFilterPrefixLengthV6) { + *out = *in + if in.Min != nil { + in, out := &in.Min, &out.Min + *out = new(int32) + **out = **in + } + if in.Max != nil { + in, out := &in.Max, &out.Max + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BGPFilterPrefixLengthV6. +func (in *BGPFilterPrefixLengthV6) DeepCopy() *BGPFilterPrefixLengthV6 { + if in == nil { + return nil + } + out := new(BGPFilterPrefixLengthV6) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BGPFilterRuleV4) DeepCopyInto(out *BGPFilterRuleV4) { *out = *in + if in.PrefixLength != nil { + in, out := &in.PrefixLength, &out.PrefixLength + *out = new(BGPFilterPrefixLengthV4) + (*in).DeepCopyInto(*out) + } return } @@ -258,6 +315,11 @@ func (in *BGPFilterRuleV4) DeepCopy() *BGPFilterRuleV4 { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BGPFilterRuleV6) DeepCopyInto(out *BGPFilterRuleV6) { *out = *in + if in.PrefixLength != nil { + in, out := &in.PrefixLength, &out.PrefixLength + *out = new(BGPFilterPrefixLengthV6) + (*in).DeepCopyInto(*out) + } return } @@ -277,22 +339,30 @@ func (in *BGPFilterSpec) DeepCopyInto(out *BGPFilterSpec) { if in.ExportV4 != nil { in, out := &in.ExportV4, &out.ExportV4 *out = make([]BGPFilterRuleV4, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } if in.ImportV4 != nil { in, out := &in.ImportV4, &out.ImportV4 *out = make([]BGPFilterRuleV4, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } if in.ExportV6 != nil { in, out := &in.ExportV6, &out.ExportV6 *out = make([]BGPFilterRuleV6, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } if in.ImportV6 != nil { in, out := &in.ImportV6, &out.ImportV6 *out = make([]BGPFilterRuleV6, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } return } diff --git a/api/pkg/openapi/openapi_generated.go b/api/pkg/openapi/openapi_generated.go index 02c48d2f480..0df849c5992 100644 --- a/api/pkg/openapi/openapi_generated.go +++ b/api/pkg/openapi/openapi_generated.go @@ -26,6 +26,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/projectcalico/api/pkg/apis/projectcalico/v3.BGPDaemonStatus": schema_pkg_apis_projectcalico_v3_BGPDaemonStatus(ref), "github.com/projectcalico/api/pkg/apis/projectcalico/v3.BGPFilter": schema_pkg_apis_projectcalico_v3_BGPFilter(ref), "github.com/projectcalico/api/pkg/apis/projectcalico/v3.BGPFilterList": schema_pkg_apis_projectcalico_v3_BGPFilterList(ref), + "github.com/projectcalico/api/pkg/apis/projectcalico/v3.BGPFilterPrefixLengthV4": schema_pkg_apis_projectcalico_v3_BGPFilterPrefixLengthV4(ref), + "github.com/projectcalico/api/pkg/apis/projectcalico/v3.BGPFilterPrefixLengthV6": schema_pkg_apis_projectcalico_v3_BGPFilterPrefixLengthV6(ref), "github.com/projectcalico/api/pkg/apis/projectcalico/v3.BGPFilterRuleV4": schema_pkg_apis_projectcalico_v3_BGPFilterRuleV4(ref), "github.com/projectcalico/api/pkg/apis/projectcalico/v3.BGPFilterRuleV6": schema_pkg_apis_projectcalico_v3_BGPFilterRuleV6(ref), "github.com/projectcalico/api/pkg/apis/projectcalico/v3.BGPFilterSpec": schema_pkg_apis_projectcalico_v3_BGPFilterSpec(ref), @@ -802,6 +804,54 @@ func schema_pkg_apis_projectcalico_v3_BGPFilterList(ref common.ReferenceCallback } } +func schema_pkg_apis_projectcalico_v3_BGPFilterPrefixLengthV4(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "min": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, + "max": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_projectcalico_v3_BGPFilterPrefixLengthV6(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "min": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, + "max": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_projectcalico_v3_BGPFilterRuleV4(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -815,6 +865,11 @@ func schema_pkg_apis_projectcalico_v3_BGPFilterRuleV4(ref common.ReferenceCallba Format: "", }, }, + "prefixLength": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/projectcalico/api/pkg/apis/projectcalico/v3.BGPFilterPrefixLengthV4"), + }, + }, "source": { SchemaProps: spec.SchemaProps{ Type: []string{"string"}, @@ -844,6 +899,8 @@ func schema_pkg_apis_projectcalico_v3_BGPFilterRuleV4(ref common.ReferenceCallba Required: []string{"action"}, }, }, + Dependencies: []string{ + "github.com/projectcalico/api/pkg/apis/projectcalico/v3.BGPFilterPrefixLengthV4"}, } } @@ -860,6 +917,11 @@ func schema_pkg_apis_projectcalico_v3_BGPFilterRuleV6(ref common.ReferenceCallba Format: "", }, }, + "prefixLength": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/projectcalico/api/pkg/apis/projectcalico/v3.BGPFilterPrefixLengthV6"), + }, + }, "source": { SchemaProps: spec.SchemaProps{ Type: []string{"string"}, @@ -889,6 +951,8 @@ func schema_pkg_apis_projectcalico_v3_BGPFilterRuleV6(ref common.ReferenceCallba Required: []string{"action"}, }, }, + Dependencies: []string{ + "github.com/projectcalico/api/pkg/apis/projectcalico/v3.BGPFilterPrefixLengthV6"}, } } diff --git a/calicoctl/calicoctl/commands/crds/crds.go b/calicoctl/calicoctl/commands/crds/crds.go index c13dee4d970..a296157d9d5 100644 --- a/calicoctl/calicoctl/commands/crds/crds.go +++ b/calicoctl/calicoctl/commands/crds/crds.go @@ -18,7 +18,7 @@ package crds const ( bgpconfigurations = "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n name: bgpconfigurations.crd.projectcalico.org\nspec:\n group: crd.projectcalico.org\n names:\n kind: BGPConfiguration\n listKind: BGPConfigurationList\n plural: bgpconfigurations\n singular: bgpconfiguration\n preserveUnknownFields: false\n scope: Cluster\n versions:\n - name: v1\n schema:\n openAPIV3Schema:\n description: BGPConfiguration contains the configuration for any BGP routing.\n properties:\n apiVersion:\n description: 'APIVersion defines the versioned schema of this representation\n of an object. Servers should convert recognized schemas to the latest\n internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'\n type: string\n kind:\n description: 'Kind is a string value representing the REST resource this\n object represents. Servers may infer this from the endpoint the client\n submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'\n type: string\n metadata:\n type: object\n spec:\n description: BGPConfigurationSpec contains the values of the BGP configuration.\n properties:\n asNumber:\n description: 'ASNumber is the default AS number used by a node. [Default:\n 64512]'\n format: int32\n type: integer\n bindMode:\n description: BindMode indicates whether to listen for BGP connections\n on all addresses (None) or only on the node's canonical IP address\n Node.Spec.BGP.IPvXAddress (NodeIP). Default behaviour is to listen\n for BGP connections on all addresses.\n type: string\n communities:\n description: Communities is a list of BGP community values and their\n arbitrary names for tagging routes.\n items:\n description: Community contains standard or large community value\n and its name.\n properties:\n name:\n description: Name given to community value.\n type: string\n value:\n description: Value must be of format `aa:nn` or `aa:nn:mm`.\n For standard community use `aa:nn` format, where `aa` and\n `nn` are 16 bit number. For large community use `aa:nn:mm`\n format, where `aa`, `nn` and `mm` are 32 bit number. Where,\n `aa` is an AS Number, `nn` and `mm` are per-AS identifier.\n pattern: ^(\\d+):(\\d+)$|^(\\d+):(\\d+):(\\d+)$\n type: string\n type: object\n type: array\n ignoredInterfaces:\n description: IgnoredInterfaces indicates the network interfaces that\n needs to be excluded when reading device routes.\n items:\n type: string\n type: array\n listenPort:\n description: ListenPort is the port where BGP protocol should listen.\n Defaults to 179\n maximum: 65535\n minimum: 1\n type: integer\n logSeverityScreen:\n description: 'LogSeverityScreen is the log severity above which logs\n are sent to the stdout. [Default: INFO]'\n type: string\n nodeMeshMaxRestartTime:\n description: Time to allow for software restart for node-to-mesh peerings. When\n specified, this is configured as the graceful restart timeout. When\n not specified, the BIRD default of 120s is used. This field can\n only be set on the default BGPConfiguration instance and requires\n that NodeMesh is enabled\n type: string\n nodeMeshPassword:\n description: Optional BGP password for full node-to-mesh peerings.\n This field can only be set on the default BGPConfiguration instance\n and requires that NodeMesh is enabled\n properties:\n secretKeyRef:\n description: Selects a key of a secret in the node pod's namespace.\n properties:\n key:\n description: The key of the secret to select from. Must be\n a valid secret key.\n type: string\n name:\n description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n TODO: Add other useful fields. apiVersion, kind, uid?'\n type: string\n optional:\n description: Specify whether the Secret or its key must be\n defined\n type: boolean\n required:\n - key\n type: object\n type: object\n nodeToNodeMeshEnabled:\n description: 'NodeToNodeMeshEnabled sets whether full node to node\n BGP mesh is enabled. [Default: true]'\n type: boolean\n prefixAdvertisements:\n description: PrefixAdvertisements contains per-prefix advertisement\n configuration.\n items:\n description: PrefixAdvertisement configures advertisement properties\n for the specified CIDR.\n properties:\n cidr:\n description: CIDR for which properties should be advertised.\n type: string\n communities:\n description: Communities can be list of either community names\n already defined in `Specs.Communities` or community value\n of format `aa:nn` or `aa:nn:mm`. For standard community use\n `aa:nn` format, where `aa` and `nn` are 16 bit number. For\n large community use `aa:nn:mm` format, where `aa`, `nn` and\n `mm` are 32 bit number. Where,`aa` is an AS Number, `nn` and\n `mm` are per-AS identifier.\n items:\n type: string\n type: array\n type: object\n type: array\n serviceClusterIPs:\n description: ServiceClusterIPs are the CIDR blocks from which service\n cluster IPs are allocated. If specified, Calico will advertise these\n blocks, as well as any cluster IPs within them.\n items:\n description: ServiceClusterIPBlock represents a single allowed ClusterIP\n CIDR block.\n properties:\n cidr:\n type: string\n type: object\n type: array\n serviceExternalIPs:\n description: ServiceExternalIPs are the CIDR blocks for Kubernetes\n Service External IPs. Kubernetes Service ExternalIPs will only be\n advertised if they are within one of these blocks.\n items:\n description: ServiceExternalIPBlock represents a single allowed\n External IP CIDR block.\n properties:\n cidr:\n type: string\n type: object\n type: array\n serviceLoadBalancerIPs:\n description: ServiceLoadBalancerIPs are the CIDR blocks for Kubernetes\n Service LoadBalancer IPs. Kubernetes Service status.LoadBalancer.Ingress\n IPs will only be advertised if they are within one of these blocks.\n items:\n description: ServiceLoadBalancerIPBlock represents a single allowed\n LoadBalancer IP CIDR block.\n properties:\n cidr:\n type: string\n type: object\n type: array\n type: object\n type: object\n served: true\n storage: true\nstatus:\n acceptedNames:\n kind: \"\"\n plural: \"\"\n conditions: []\n storedVersions: []\n" - bgpfilters = "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n annotations:\n controller-gen.kubebuilder.io/version: (devel)\n creationTimestamp: null\n name: bgpfilters.crd.projectcalico.org\nspec:\n group: crd.projectcalico.org\n names:\n kind: BGPFilter\n listKind: BGPFilterList\n plural: bgpfilters\n singular: bgpfilter\n scope: Cluster\n versions:\n - name: v1\n schema:\n openAPIV3Schema:\n properties:\n apiVersion:\n description: 'APIVersion defines the versioned schema of this representation\n of an object. Servers should convert recognized schemas to the latest\n internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'\n type: string\n kind:\n description: 'Kind is a string value representing the REST resource this\n object represents. Servers may infer this from the endpoint the client\n submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'\n type: string\n metadata:\n type: object\n spec:\n description: BGPFilterSpec contains the IPv4 and IPv6 filter rules of\n the BGP Filter.\n properties:\n exportV4:\n description: The ordered set of IPv4 BGPFilter rules acting on exporting\n routes to a peer.\n items:\n description: BGPFilterRuleV4 defines a BGP filter rule consisting\n a single IPv4 CIDR block and a filter action for this CIDR.\n properties:\n action:\n type: string\n cidr:\n type: string\n interface:\n type: string\n matchOperator:\n type: string\n source:\n type: string\n required:\n - action\n type: object\n type: array\n exportV6:\n description: The ordered set of IPv6 BGPFilter rules acting on exporting\n routes to a peer.\n items:\n description: BGPFilterRuleV6 defines a BGP filter rule consisting\n a single IPv6 CIDR block and a filter action for this CIDR.\n properties:\n action:\n type: string\n cidr:\n type: string\n interface:\n type: string\n matchOperator:\n type: string\n source:\n type: string\n required:\n - action\n type: object\n type: array\n importV4:\n description: The ordered set of IPv4 BGPFilter rules acting on importing\n routes from a peer.\n items:\n description: BGPFilterRuleV4 defines a BGP filter rule consisting\n a single IPv4 CIDR block and a filter action for this CIDR.\n properties:\n action:\n type: string\n cidr:\n type: string\n interface:\n type: string\n matchOperator:\n type: string\n source:\n type: string\n required:\n - action\n type: object\n type: array\n importV6:\n description: The ordered set of IPv6 BGPFilter rules acting on importing\n routes from a peer.\n items:\n description: BGPFilterRuleV6 defines a BGP filter rule consisting\n a single IPv6 CIDR block and a filter action for this CIDR.\n properties:\n action:\n type: string\n cidr:\n type: string\n interface:\n type: string\n matchOperator:\n type: string\n source:\n type: string\n required:\n - action\n type: object\n type: array\n type: object\n type: object\n served: true\n storage: true\nstatus:\n acceptedNames:\n kind: \"\"\n plural: \"\"\n conditions: []\n storedVersions: []\n" + bgpfilters = "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n annotations:\n controller-gen.kubebuilder.io/version: (devel)\n creationTimestamp: null\n name: bgpfilters.crd.projectcalico.org\nspec:\n group: crd.projectcalico.org\n names:\n kind: BGPFilter\n listKind: BGPFilterList\n plural: bgpfilters\n singular: bgpfilter\n scope: Cluster\n versions:\n - name: v1\n schema:\n openAPIV3Schema:\n properties:\n apiVersion:\n description: 'APIVersion defines the versioned schema of this representation\n of an object. Servers should convert recognized schemas to the latest\n internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'\n type: string\n kind:\n description: 'Kind is a string value representing the REST resource this\n object represents. Servers may infer this from the endpoint the client\n submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'\n type: string\n metadata:\n type: object\n spec:\n description: BGPFilterSpec contains the IPv4 and IPv6 filter rules of\n the BGP Filter.\n properties:\n exportV4:\n description: The ordered set of IPv4 BGPFilter rules acting on exporting\n routes to a peer.\n items:\n description: BGPFilterRuleV4 defines a BGP filter rule consisting\n a single IPv4 CIDR block and a filter action for this CIDR.\n properties:\n action:\n type: string\n cidr:\n type: string\n interface:\n type: string\n matchOperator:\n type: string\n prefixLength:\n properties:\n max:\n format: int32\n maximum: 32\n minimum: 0\n type: integer\n min:\n format: int32\n maximum: 32\n minimum: 0\n type: integer\n type: object\n source:\n type: string\n required:\n - action\n type: object\n type: array\n exportV6:\n description: The ordered set of IPv6 BGPFilter rules acting on exporting\n routes to a peer.\n items:\n description: BGPFilterRuleV6 defines a BGP filter rule consisting\n a single IPv6 CIDR block and a filter action for this CIDR.\n properties:\n action:\n type: string\n cidr:\n type: string\n interface:\n type: string\n matchOperator:\n type: string\n prefixLength:\n properties:\n max:\n format: int32\n maximum: 128\n minimum: 0\n type: integer\n min:\n format: int32\n maximum: 128\n minimum: 0\n type: integer\n type: object\n source:\n type: string\n required:\n - action\n type: object\n type: array\n importV4:\n description: The ordered set of IPv4 BGPFilter rules acting on importing\n routes from a peer.\n items:\n description: BGPFilterRuleV4 defines a BGP filter rule consisting\n a single IPv4 CIDR block and a filter action for this CIDR.\n properties:\n action:\n type: string\n cidr:\n type: string\n interface:\n type: string\n matchOperator:\n type: string\n prefixLength:\n properties:\n max:\n format: int32\n maximum: 32\n minimum: 0\n type: integer\n min:\n format: int32\n maximum: 32\n minimum: 0\n type: integer\n type: object\n source:\n type: string\n required:\n - action\n type: object\n type: array\n importV6:\n description: The ordered set of IPv6 BGPFilter rules acting on importing\n routes from a peer.\n items:\n description: BGPFilterRuleV6 defines a BGP filter rule consisting\n a single IPv6 CIDR block and a filter action for this CIDR.\n properties:\n action:\n type: string\n cidr:\n type: string\n interface:\n type: string\n matchOperator:\n type: string\n prefixLength:\n properties:\n max:\n format: int32\n maximum: 128\n minimum: 0\n type: integer\n min:\n format: int32\n maximum: 128\n minimum: 0\n type: integer\n type: object\n source:\n type: string\n required:\n - action\n type: object\n type: array\n type: object\n type: object\n served: true\n storage: true\nstatus:\n acceptedNames:\n kind: \"\"\n plural: \"\"\n conditions: []\n storedVersions: []\n" bgppeers = "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n name: bgppeers.crd.projectcalico.org\nspec:\n group: crd.projectcalico.org\n names:\n kind: BGPPeer\n listKind: BGPPeerList\n plural: bgppeers\n singular: bgppeer\n preserveUnknownFields: false\n scope: Cluster\n versions:\n - name: v1\n schema:\n openAPIV3Schema:\n properties:\n apiVersion:\n description: 'APIVersion defines the versioned schema of this representation\n of an object. Servers should convert recognized schemas to the latest\n internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'\n type: string\n kind:\n description: 'Kind is a string value representing the REST resource this\n object represents. Servers may infer this from the endpoint the client\n submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'\n type: string\n metadata:\n type: object\n spec:\n description: BGPPeerSpec contains the specification for a BGPPeer resource.\n properties:\n asNumber:\n description: The AS Number of the peer.\n format: int32\n type: integer\n filters:\n description: The ordered set of BGPFilters applied on this BGP peer.\n items:\n type: string\n type: array\n keepOriginalNextHop:\n description: Option to keep the original nexthop field when routes\n are sent to a BGP Peer. Setting \"true\" configures the selected BGP\n Peers node to use the \"next hop keep;\" instead of \"next hop self;\"(default)\n in the specific branch of the Node on \"bird.cfg\".\n type: boolean\n maxRestartTime:\n description: Time to allow for software restart. When specified,\n this is configured as the graceful restart timeout. When not specified,\n the BIRD default of 120s is used.\n type: string\n node:\n description: The node name identifying the Calico node instance that\n is targeted by this peer. If this is not set, and no nodeSelector\n is specified, then this BGP peer selects all nodes in the cluster.\n type: string\n nodeSelector:\n description: Selector for the nodes that should have this peering. When\n this is set, the Node field must be empty.\n type: string\n numAllowedLocalASNumbers:\n description: Maximum number of local AS numbers that are allowed in\n the AS path for received routes. This removes BGP loop prevention\n and should only be used if absolutely necessary.\n format: int32\n type: integer\n password:\n description: Optional BGP password for the peerings generated by this\n BGPPeer resource.\n properties:\n secretKeyRef:\n description: Selects a key of a secret in the node pod's namespace.\n properties:\n key:\n description: The key of the secret to select from. Must be\n a valid secret key.\n type: string\n name:\n description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n TODO: Add other useful fields. apiVersion, kind, uid?'\n type: string\n optional:\n description: Specify whether the Secret or its key must be\n defined\n type: boolean\n required:\n - key\n type: object\n type: object\n peerIP:\n description: The IP address of the peer followed by an optional port\n number to peer with. If port number is given, format should be `[]:port`\n or `:` for IPv4. If optional port number is not set,\n and this peer IP and ASNumber belongs to a calico/node with ListenPort\n set in BGPConfiguration, then we use that port to peer.\n type: string\n peerSelector:\n description: Selector for the remote nodes to peer with. When this\n is set, the PeerIP and ASNumber fields must be empty. For each\n peering between the local node and selected remote nodes, we configure\n an IPv4 peering if both ends have NodeBGPSpec.IPv4Address specified,\n and an IPv6 peering if both ends have NodeBGPSpec.IPv6Address specified. The\n remote AS number comes from the remote node's NodeBGPSpec.ASNumber,\n or the global default if that is not set.\n type: string\n reachableBy:\n description: Add an exact, i.e. /32, static route toward peer IP in\n order to prevent route flapping. ReachableBy contains the address\n of the gateway which peer can be reached by.\n type: string\n sourceAddress:\n description: Specifies whether and how to configure a source address\n for the peerings generated by this BGPPeer resource. Default value\n \"UseNodeIP\" means to configure the node IP as the source address. \"None\"\n means not to configure a source address.\n type: string\n ttlSecurity:\n description: TTLSecurity enables the generalized TTL security mechanism\n (GTSM) which protects against spoofed packets by ignoring received\n packets with a smaller than expected TTL value. The provided value\n is the number of hops (edges) between the peers.\n type: integer\n type: object\n type: object\n served: true\n storage: true\nstatus:\n acceptedNames:\n kind: \"\"\n plural: \"\"\n conditions: []\n storedVersions: []\n" blockaffinities = "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n name: blockaffinities.crd.projectcalico.org\nspec:\n group: crd.projectcalico.org\n names:\n kind: BlockAffinity\n listKind: BlockAffinityList\n plural: blockaffinities\n singular: blockaffinity\n preserveUnknownFields: false\n scope: Cluster\n versions:\n - name: v1\n schema:\n openAPIV3Schema:\n properties:\n apiVersion:\n description: 'APIVersion defines the versioned schema of this representation\n of an object. Servers should convert recognized schemas to the latest\n internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'\n type: string\n kind:\n description: 'Kind is a string value representing the REST resource this\n object represents. Servers may infer this from the endpoint the client\n submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'\n type: string\n metadata:\n type: object\n spec:\n description: BlockAffinitySpec contains the specification for a BlockAffinity\n resource.\n properties:\n cidr:\n type: string\n deleted:\n description: Deleted indicates that this block affinity is being deleted.\n This field is a string for compatibility with older releases that\n mistakenly treat this field as a string.\n type: string\n node:\n type: string\n state:\n type: string\n required:\n - cidr\n - deleted\n - node\n - state\n type: object\n type: object\n served: true\n storage: true\nstatus:\n acceptedNames:\n kind: \"\"\n plural: \"\"\n conditions: []\n storedVersions: []\n" caliconodestatuses = "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n annotations:\n controller-gen.kubebuilder.io/version: (devel)\n creationTimestamp: null\n name: caliconodestatuses.crd.projectcalico.org\nspec:\n group: crd.projectcalico.org\n names:\n kind: CalicoNodeStatus\n listKind: CalicoNodeStatusList\n plural: caliconodestatuses\n singular: caliconodestatus\n preserveUnknownFields: false\n scope: Cluster\n versions:\n - name: v1\n schema:\n openAPIV3Schema:\n properties:\n apiVersion:\n description: 'APIVersion defines the versioned schema of this representation\n of an object. Servers should convert recognized schemas to the latest\n internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'\n type: string\n kind:\n description: 'Kind is a string value representing the REST resource this\n object represents. Servers may infer this from the endpoint the client\n submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'\n type: string\n metadata:\n type: object\n spec:\n description: CalicoNodeStatusSpec contains the specification for a CalicoNodeStatus\n resource.\n properties:\n classes:\n description: Classes declares the types of information to monitor\n for this calico/node, and allows for selective status reporting\n about certain subsets of information.\n items:\n type: string\n type: array\n node:\n description: The node name identifies the Calico node instance for\n node status.\n type: string\n updatePeriodSeconds:\n description: UpdatePeriodSeconds is the period at which CalicoNodeStatus\n should be updated. Set to 0 to disable CalicoNodeStatus refresh.\n Maximum update period is one day.\n format: int32\n type: integer\n type: object\n status:\n description: CalicoNodeStatusStatus defines the observed state of CalicoNodeStatus.\n No validation needed for status since it is updated by Calico.\n properties:\n agent:\n description: Agent holds agent status on the node.\n properties:\n birdV4:\n description: BIRDV4 represents the latest observed status of bird4.\n properties:\n lastBootTime:\n description: LastBootTime holds the value of lastBootTime\n from bird.ctl output.\n type: string\n lastReconfigurationTime:\n description: LastReconfigurationTime holds the value of lastReconfigTime\n from bird.ctl output.\n type: string\n routerID:\n description: Router ID used by bird.\n type: string\n state:\n description: The state of the BGP Daemon.\n type: string\n version:\n description: Version of the BGP daemon\n type: string\n type: object\n birdV6:\n description: BIRDV6 represents the latest observed status of bird6.\n properties:\n lastBootTime:\n description: LastBootTime holds the value of lastBootTime\n from bird.ctl output.\n type: string\n lastReconfigurationTime:\n description: LastReconfigurationTime holds the value of lastReconfigTime\n from bird.ctl output.\n type: string\n routerID:\n description: Router ID used by bird.\n type: string\n state:\n description: The state of the BGP Daemon.\n type: string\n version:\n description: Version of the BGP daemon\n type: string\n type: object\n type: object\n bgp:\n description: BGP holds node BGP status.\n properties:\n numberEstablishedV4:\n description: The total number of IPv4 established bgp sessions.\n type: integer\n numberEstablishedV6:\n description: The total number of IPv6 established bgp sessions.\n type: integer\n numberNotEstablishedV4:\n description: The total number of IPv4 non-established bgp sessions.\n type: integer\n numberNotEstablishedV6:\n description: The total number of IPv6 non-established bgp sessions.\n type: integer\n peersV4:\n description: PeersV4 represents IPv4 BGP peers status on the node.\n items:\n description: CalicoNodePeer contains the status of BGP peers\n on the node.\n properties:\n peerIP:\n description: IP address of the peer whose condition we are\n reporting.\n type: string\n since:\n description: Since the state or reason last changed.\n type: string\n state:\n description: State is the BGP session state.\n type: string\n type:\n description: Type indicates whether this peer is configured\n via the node-to-node mesh, or via en explicit global or\n per-node BGPPeer object.\n type: string\n type: object\n type: array\n peersV6:\n description: PeersV6 represents IPv6 BGP peers status on the node.\n items:\n description: CalicoNodePeer contains the status of BGP peers\n on the node.\n properties:\n peerIP:\n description: IP address of the peer whose condition we are\n reporting.\n type: string\n since:\n description: Since the state or reason last changed.\n type: string\n state:\n description: State is the BGP session state.\n type: string\n type:\n description: Type indicates whether this peer is configured\n via the node-to-node mesh, or via en explicit global or\n per-node BGPPeer object.\n type: string\n type: object\n type: array\n required:\n - numberEstablishedV4\n - numberEstablishedV6\n - numberNotEstablishedV4\n - numberNotEstablishedV6\n type: object\n lastUpdated:\n description: LastUpdated is a timestamp representing the server time\n when CalicoNodeStatus object last updated. It is represented in\n RFC3339 form and is in UTC.\n format: date-time\n nullable: true\n type: string\n routes:\n description: Routes reports routes known to the Calico BGP daemon\n on the node.\n properties:\n routesV4:\n description: RoutesV4 represents IPv4 routes on the node.\n items:\n description: CalicoNodeRoute contains the status of BGP routes\n on the node.\n properties:\n destination:\n description: Destination of the route.\n type: string\n gateway:\n description: Gateway for the destination.\n type: string\n interface:\n description: Interface for the destination\n type: string\n learnedFrom:\n description: LearnedFrom contains information regarding\n where this route originated.\n properties:\n peerIP:\n description: If sourceType is NodeMesh or BGPPeer, IP\n address of the router that sent us this route.\n type: string\n sourceType:\n description: Type of the source where a route is learned\n from.\n type: string\n type: object\n type:\n description: Type indicates if the route is being used for\n forwarding or not.\n type: string\n type: object\n type: array\n routesV6:\n description: RoutesV6 represents IPv6 routes on the node.\n items:\n description: CalicoNodeRoute contains the status of BGP routes\n on the node.\n properties:\n destination:\n description: Destination of the route.\n type: string\n gateway:\n description: Gateway for the destination.\n type: string\n interface:\n description: Interface for the destination\n type: string\n learnedFrom:\n description: LearnedFrom contains information regarding\n where this route originated.\n properties:\n peerIP:\n description: If sourceType is NodeMesh or BGPPeer, IP\n address of the router that sent us this route.\n type: string\n sourceType:\n description: Type of the source where a route is learned\n from.\n type: string\n type: object\n type:\n description: Type indicates if the route is being used for\n forwarding or not.\n type: string\n type: object\n type: array\n type: object\n type: object\n type: object\n served: true\n storage: true\nstatus:\n acceptedNames:\n kind: \"\"\n plural: \"\"\n conditions: []\n storedVersions: []\n" diff --git a/confd/pkg/resource/template/template_funcs.go b/confd/pkg/resource/template/template_funcs.go index 0012cbaa868..35aa387350d 100644 --- a/confd/pkg/resource/template/template_funcs.go +++ b/confd/pkg/resource/template/template_funcs.go @@ -65,7 +65,7 @@ func filterStatement(fields filterArgs) (string, error) { if fields.operator == "" { return "", fmt.Errorf("operator not included in BGPFilter") } - cidrCondition, err := filterMatchCIDR(fields.cidr, fields.operator) + cidrCondition, err := filterMatchCIDR(fields.cidr, fields.prefixLengthV4, fields.prefixLengthV6, fields.operator) if err != nil { return "", err } @@ -111,11 +111,49 @@ var ( } ) -func filterMatchCIDR(cidr string, operator v3.BGPFilterMatchOperator) (string, error) { +func filterMatchPrefixLength(cidr string, prefixMin, prefixMax *int32) (string, error) { + cidrIP, cidrNet, err := net.ParseCIDR(cidr) + if err != nil { + return "", fmt.Errorf("unexpected error when parsing cidr %s: %s", cidr, err) + } + + mask, _ := cidrNet.Mask.Size() + minLength := int32(mask) + // default for ipv4 + maxLength := int32(32) + + // check for ipv6 IP + if cidrIP.To4() == nil { + maxLength = 128 + } + + if prefixMin != nil { + minLength = max(minLength, *prefixMin) + } + if prefixMax != nil { + maxLength = min(maxLength, *prefixMax) + } + + return fmt.Sprintf("[ %s{%d,%d} ]", cidr, minLength, maxLength), nil +} + +func filterMatchCIDR(cidr string, prefixLengthV4 *v3.BGPFilterPrefixLengthV4, prefixLengthV6 *v3.BGPFilterPrefixLengthV6, operator v3.BGPFilterMatchOperator) (string, error) { op, ok := operatorLUT[operator] if !ok { return "", fmt.Errorf("unexpected operator found in BGPFilter: %s", operator) } + + var err error + if prefixLengthV4 != nil { + cidr, err = filterMatchPrefixLength(cidr, prefixLengthV4.Min, prefixLengthV4.Max) + } else if prefixLengthV6 != nil { + cidr, err = filterMatchPrefixLength(cidr, prefixLengthV6.Min, prefixLengthV6.Max) + } + + if err != nil { + return "", err + } + return fmt.Sprintf("(net %s %s)", op, cidr), nil } @@ -155,11 +193,13 @@ func BGPFilterFunctionName(filterName, direction, version string) (string, error } type filterArgs struct { - operator v3.BGPFilterMatchOperator - cidr string - source v3.BGPFilterMatchSource - iface string - action v3.BGPFilterAction + operator v3.BGPFilterMatchOperator + cidr string + prefixLengthV4 *v3.BGPFilterPrefixLengthV4 + prefixLengthV6 *v3.BGPFilterPrefixLengthV6 + source v3.BGPFilterMatchSource + iface string + action v3.BGPFilterAction } // BGPFilterBIRDFuncs generates a set of BIRD functions for BGPFilter resources that have been packaged into KVPairs. @@ -261,21 +301,23 @@ func BGPFilterBIRDFuncs(pairs memkv.KVPairs, version int) ([]string, error) { if v4Selected { for _, importV4 := range importFiltersV4 { ruleFields = append(ruleFields, filterArgs{ - operator: importV4.MatchOperator, - cidr: importV4.CIDR, - source: importV4.Source, - iface: importV4.Interface, - action: importV4.Action, + operator: importV4.MatchOperator, + cidr: importV4.CIDR, + prefixLengthV4: importV4.PrefixLength, + source: importV4.Source, + iface: importV4.Interface, + action: importV4.Action, }) } } else { for _, importV6 := range importFiltersV6 { ruleFields = append(ruleFields, filterArgs{ - operator: importV6.MatchOperator, - cidr: importV6.CIDR, - source: importV6.Source, - iface: importV6.Interface, - action: importV6.Action, + operator: importV6.MatchOperator, + cidr: importV6.CIDR, + prefixLengthV6: importV6.PrefixLength, + source: importV6.Source, + iface: importV6.Interface, + action: importV6.Action, }) } } @@ -306,21 +348,23 @@ func BGPFilterBIRDFuncs(pairs memkv.KVPairs, version int) ([]string, error) { if v4Selected { for _, exportV4 := range exportFiltersV4 { ruleFields = append(ruleFields, filterArgs{ - operator: exportV4.MatchOperator, - cidr: exportV4.CIDR, - source: exportV4.Source, - iface: exportV4.Interface, - action: exportV4.Action, + operator: exportV4.MatchOperator, + cidr: exportV4.CIDR, + prefixLengthV4: exportV4.PrefixLength, + source: exportV4.Source, + iface: exportV4.Interface, + action: exportV4.Action, }) } } else { for _, exportV6 := range exportFiltersV6 { ruleFields = append(ruleFields, filterArgs{ - operator: exportV6.MatchOperator, - cidr: exportV6.CIDR, - source: exportV6.Source, - iface: exportV6.Interface, - action: exportV6.Action, + operator: exportV6.MatchOperator, + cidr: exportV6.CIDR, + prefixLengthV6: exportV6.PrefixLength, + source: exportV6.Source, + iface: exportV6.Interface, + action: exportV6.Action, }) } } diff --git a/confd/pkg/resource/template/template_funcs_test.go b/confd/pkg/resource/template/template_funcs_test.go index e103f3f6639..cea00a6f6bd 100644 --- a/confd/pkg/resource/template/template_funcs_test.go +++ b/confd/pkg/resource/template/template_funcs_test.go @@ -59,8 +59,10 @@ func Test_BGPFilterBIRDFuncs(t *testing.T) { ImportV4: []v3.BGPFilterRuleV4{ {Action: "Accept", Source: "RemotePeers", Interface: "vxlan.calico", MatchOperator: "NotIn", CIDR: "55.4.0.0/16"}, {Action: "Reject", Source: "RemotePeers", MatchOperator: "NotIn", CIDR: "55.4.0.0/16"}, + {Action: "Reject", Source: "RemotePeers", MatchOperator: "NotIn", CIDR: "55.4.0.0/16", PrefixLength: &v3.BGPFilterPrefixLengthV4{Min: int32Helper(16), Max: int32Helper(24)}}, {Action: "Reject", Interface: "eth0", MatchOperator: "NotIn", CIDR: "55.4.0.0/16"}, {Action: "Accept", Interface: "eth0", Source: "RemotePeers"}, + {Action: "Reject", Interface: "eth0", Source: "RemotePeers", PrefixLength: &v3.BGPFilterPrefixLengthV4{Min: int32Helper(16), Max: int32Helper(24)}}, {Action: "Reject", MatchOperator: "Equal", CIDR: "44.4.0.0/16"}, {Action: "Accept", Source: "RemotePeers"}, {Action: "Reject", Interface: "extraiface"}, @@ -69,6 +71,7 @@ func Test_BGPFilterBIRDFuncs(t *testing.T) { ExportV4: []v3.BGPFilterRuleV4{ {Action: "Reject", Source: "RemotePeers", Interface: "vxlan.calico", MatchOperator: "NotIn", CIDR: "55.4.0.0/16"}, {Action: "Reject", Source: "RemotePeers", MatchOperator: "NotIn", CIDR: "88.7.0.0/16"}, + {Action: "Reject", Source: "RemotePeers", MatchOperator: "NotIn", CIDR: "88.7.0.0/16", PrefixLength: &v3.BGPFilterPrefixLengthV4{Max: int32Helper(24)}}, {Action: "Accept", Interface: "eth0", MatchOperator: "NotIn", CIDR: "55.4.0.0/16"}, {Action: "Reject", Interface: "eth0", Source: "RemotePeers"}, {Action: "Accept", MatchOperator: "In", CIDR: "77.7.0.0/16"}, @@ -77,21 +80,25 @@ func Test_BGPFilterBIRDFuncs(t *testing.T) { {Action: "Reject"}, }, ImportV6: []v3.BGPFilterRuleV6{ - {Action: "Reject", Source: "RemotePeers", Interface: "vxlan.calico", MatchOperator: "NotIn", CIDR: "55.4.0.0/16"}, + {Action: "Reject", Source: "RemotePeers", Interface: "vxlan.calico", MatchOperator: "NotIn", CIDR: "7000:1::0/64"}, {Action: "Reject", Source: "RemotePeers", MatchOperator: "NotEqual", CIDR: "8000:1::0/64"}, - {Action: "Accept", Interface: "eth0", MatchOperator: "NotIn", CIDR: "55.4.0.0/16"}, + {Action: "Accept", Interface: "eth0", MatchOperator: "NotIn", CIDR: "6000:1::0/64"}, + {Action: "Accept", Interface: "eth0", MatchOperator: "NotIn", CIDR: "6000:1::0/64", PrefixLength: &v3.BGPFilterPrefixLengthV6{Min: int32Helper(96)}}, {Action: "Reject", Interface: "eth0", Source: "RemotePeers"}, {Action: "Accept", MatchOperator: "NotEqual", CIDR: "7000:1::0/64"}, + {Action: "Accept", MatchOperator: "NotEqual", CIDR: "7000:1::0/64", PrefixLength: &v3.BGPFilterPrefixLengthV6{Max: int32Helper(96)}}, {Action: "Accept", Source: "RemotePeers"}, {Action: "Accept", Interface: "extraiface"}, {Action: "Reject"}, }, ExportV6: []v3.BGPFilterRuleV6{ - {Action: "Accept", Source: "RemotePeers", Interface: "vxlan.calico", MatchOperator: "NotIn", CIDR: "55.4.0.0/16"}, + {Action: "Accept", Source: "RemotePeers", Interface: "vxlan.calico", MatchOperator: "NotIn", CIDR: "b000:1::0/64"}, {Action: "Reject", Source: "RemotePeers", MatchOperator: "NotIn", CIDR: "a000:1::0/64"}, - {Action: "Reject", Interface: "eth0", MatchOperator: "NotIn", CIDR: "55.4.0.0/16"}, + {Action: "Reject", Interface: "eth0", MatchOperator: "NotIn", CIDR: "c000:1::0/64"}, + {Action: "Reject", Interface: "eth0", MatchOperator: "NotIn", CIDR: "c000:1::0/64", PrefixLength: &v3.BGPFilterPrefixLengthV6{Min: int32Helper(120), Max: int32Helper(128)}}, {Action: "Accept", Interface: "eth0", Source: "RemotePeers"}, {Action: "Accept", MatchOperator: "NotIn", CIDR: "9000:1::0/64"}, + {Action: "Accept", MatchOperator: "NotIn", CIDR: "9000:1::0/64", PrefixLength: &v3.BGPFilterPrefixLengthV6{Min: int32Helper(96), Max: int32Helper(120)}}, {Action: "Accept", Source: "RemotePeers"}, {Action: "Reject", Interface: "extraiface"}, {Action: "Reject"}, @@ -102,8 +109,10 @@ func Test_BGPFilterBIRDFuncs(t *testing.T) { "function 'bgp_test-bgpfilter_importFilterV4'() {", " if ((net !~ 55.4.0.0/16)&&((defined(source))&&(source ~ [ RTS_BGP ]))&&((defined(ifname))&&(ifname ~ \"vxlan.calico\"))) then { accept; }", " if ((net !~ 55.4.0.0/16)&&((defined(source))&&(source ~ [ RTS_BGP ]))) then { reject; }", + " if ((net !~ [ 55.4.0.0/16{16,24} ])&&((defined(source))&&(source ~ [ RTS_BGP ]))) then { reject; }", " if ((net !~ 55.4.0.0/16)&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { reject; }", " if (((defined(source))&&(source ~ [ RTS_BGP ]))&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { accept; }", + " if (((defined(source))&&(source ~ [ RTS_BGP ]))&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { reject; }", " if ((net = 44.4.0.0/16)) then { reject; }", " if (((defined(source))&&(source ~ [ RTS_BGP ]))) then { accept; }", " if (((defined(ifname))&&(ifname ~ \"extraiface\"))) then { reject; }", @@ -112,6 +121,7 @@ func Test_BGPFilterBIRDFuncs(t *testing.T) { "function 'bgp_test-bgpfilter_exportFilterV4'() {", " if ((net !~ 55.4.0.0/16)&&((defined(source))&&(source ~ [ RTS_BGP ]))&&((defined(ifname))&&(ifname ~ \"vxlan.calico\"))) then { reject; }", " if ((net !~ 88.7.0.0/16)&&((defined(source))&&(source ~ [ RTS_BGP ]))) then { reject; }", + " if ((net !~ [ 88.7.0.0/16{16,24} ])&&((defined(source))&&(source ~ [ RTS_BGP ]))) then { reject; }", " if ((net !~ 55.4.0.0/16)&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { accept; }", " if (((defined(source))&&(source ~ [ RTS_BGP ]))&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { reject; }", " if ((net ~ 77.7.0.0/16)) then { accept; }", @@ -123,21 +133,25 @@ func Test_BGPFilterBIRDFuncs(t *testing.T) { expectedBIRDCfgStrV6 := []string{ "# v6 BGPFilter test-bgpfilter", "function 'bgp_test-bgpfilter_importFilterV6'() {", - " if ((net !~ 55.4.0.0/16)&&((defined(source))&&(source ~ [ RTS_BGP ]))&&((defined(ifname))&&(ifname ~ \"vxlan.calico\"))) then { reject; }", + " if ((net !~ 7000:1::0/64)&&((defined(source))&&(source ~ [ RTS_BGP ]))&&((defined(ifname))&&(ifname ~ \"vxlan.calico\"))) then { reject; }", " if ((net != 8000:1::0/64)&&((defined(source))&&(source ~ [ RTS_BGP ]))) then { reject; }", - " if ((net !~ 55.4.0.0/16)&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { accept; }", + " if ((net !~ 6000:1::0/64)&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { accept; }", + " if ((net !~ [ 6000:1::0/64{96,128} ])&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { accept; }", " if (((defined(source))&&(source ~ [ RTS_BGP ]))&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { reject; }", " if ((net != 7000:1::0/64)) then { accept; }", + " if ((net != [ 7000:1::0/64{64,96} ])) then { accept; }", " if (((defined(source))&&(source ~ [ RTS_BGP ]))) then { accept; }", " if (((defined(ifname))&&(ifname ~ \"extraiface\"))) then { accept; }", " reject;", "}", "function 'bgp_test-bgpfilter_exportFilterV6'() {", - " if ((net !~ 55.4.0.0/16)&&((defined(source))&&(source ~ [ RTS_BGP ]))&&((defined(ifname))&&(ifname ~ \"vxlan.calico\"))) then { accept; }", + " if ((net !~ b000:1::0/64)&&((defined(source))&&(source ~ [ RTS_BGP ]))&&((defined(ifname))&&(ifname ~ \"vxlan.calico\"))) then { accept; }", " if ((net !~ a000:1::0/64)&&((defined(source))&&(source ~ [ RTS_BGP ]))) then { reject; }", - " if ((net !~ 55.4.0.0/16)&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { reject; }", + " if ((net !~ c000:1::0/64)&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { reject; }", + " if ((net !~ [ c000:1::0/64{120,128} ])&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { reject; }", " if (((defined(source))&&(source ~ [ RTS_BGP ]))&&((defined(ifname))&&(ifname ~ \"eth0\"))) then { accept; }", " if ((net !~ 9000:1::0/64)) then { accept; }", + " if ((net !~ [ 9000:1::0/64{96,120} ])) then { accept; }", " if (((defined(source))&&(source ~ [ RTS_BGP ]))) then { accept; }", " if (((defined(ifname))&&(ifname ~ \"extraiface\"))) then { reject; }", " reject;", @@ -186,3 +200,7 @@ func Test_ValidateHashToIpv4Method(t *testing.T) { t.Errorf("Expected %s to equal %s", expectedRouterId, actualRouterId) } } + +func int32Helper(i int32) *int32 { + return &i +} diff --git a/felix/dataplane/linux/bpf_ep_mgr.go b/felix/dataplane/linux/bpf_ep_mgr.go index 127d09cc98e..e9cca194f51 100644 --- a/felix/dataplane/linux/bpf_ep_mgr.go +++ b/felix/dataplane/linux/bpf_ep_mgr.go @@ -845,7 +845,7 @@ func (m *bpfEndpointManager) onRouteUpdate(update *proto.RouteUpdate) { if update.Type == proto.RouteType_LOCAL_TUNNEL { ip, _, err := net.ParseCIDR(update.Dst) if err != nil { - log.WithField("local tunnel cird", update.Dst).WithError(err).Warn("not parsable") + log.WithField("local tunnel cidr", update.Dst).WithError(err).Warn("not parsable") return } if m.v6 != nil { diff --git a/libcalico-go/config/crd/crd.projectcalico.org_bgpfilters.yaml b/libcalico-go/config/crd/crd.projectcalico.org_bgpfilters.yaml index 49dc53f8e80..09db5e3eff7 100644 --- a/libcalico-go/config/crd/crd.projectcalico.org_bgpfilters.yaml +++ b/libcalico-go/config/crd/crd.projectcalico.org_bgpfilters.yaml @@ -49,6 +49,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -70,6 +83,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: @@ -91,6 +117,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -112,6 +151,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: diff --git a/libcalico-go/lib/validator/v3/validator.go b/libcalico-go/lib/validator/v3/validator.go index c5671a99e05..e36fcf70949 100644 --- a/libcalico-go/lib/validator/v3/validator.go +++ b/libcalico-go/lib/validator/v3/validator.go @@ -80,6 +80,8 @@ var ( interfaceRegex = regexp.MustCompile("^[a-zA-Z0-9_.-]{1,15}$") bgpFilterInterfaceRegex = regexp.MustCompile("^[a-zA-Z0-9_.*-]{1,15}$") + bgpFilterPrefixLengthV4 = regexp.MustCompile("^([0-9]|[12][0-9]|3[0-2])$") + bgpFilterPrefixLengthV6 = regexp.MustCompile("^([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$") ignoredInterfaceRegex = regexp.MustCompile("^[a-zA-Z0-9_.*-]{1,15}$") ifaceFilterRegex = regexp.MustCompile("^[a-zA-Z0-9:._+-]{1,15}$") actionRegex = regexp.MustCompile("^(Allow|Deny|Log|Pass)$") @@ -163,6 +165,8 @@ func init() { registerFieldValidator("action", validateAction) registerFieldValidator("interface", validateInterface) registerFieldValidator("bgpFilterInterface", validateBGPFilterInterface) + registerFieldValidator("bgpFilterPrefixLengthV4", validateBGPFilterPrefixLengthV4) + registerFieldValidator("bgpFilterPrefixLengthV6", validateBGPFilterPrefixLengthV6) registerFieldValidator("ignoredInterface", validateIgnoredInterface) registerFieldValidator("datastoreType", validateDatastoreType) registerFieldValidator("name", validateName) @@ -302,6 +306,18 @@ func validateBGPFilterInterface(fl validator.FieldLevel) bool { return s == "*" || bgpFilterInterfaceRegex.MatchString(s) } +func validateBGPFilterPrefixLengthV4(fl validator.FieldLevel) bool { + s := fmt.Sprint(fl.Field()) + log.Debugf("Validate BGPFilter PrefixLength v4: %s", s) + return s == "*" || bgpFilterPrefixLengthV4.MatchString(s) +} + +func validateBGPFilterPrefixLengthV6(fl validator.FieldLevel) bool { + s := fmt.Sprint(fl.Field()) + log.Debugf("Validate BGPFilter PrefixLength v6: %s", s) + return s == "*" || bgpFilterPrefixLengthV6.MatchString(s) +} + func validateIgnoredInterface(fl validator.FieldLevel) bool { s := fl.Field().String() log.Debugf("Validate ignored interface name: %s", s) @@ -606,7 +622,7 @@ func ValidateIPv4Network(addr string) error { return fmt.Errorf("Invalid IPv4 network %s", addr) } -// validateIPv4Network validates the field is a valid (strictly masked) IPv6 network. +// validateIPv6Network validates the field is a valid (strictly masked) IPv6 network. // An IP address is valid, and assumed to be fully masked (i.e /128) func validateIPv6Network(fl validator.FieldLevel) bool { n := fl.Field().String() @@ -1395,15 +1411,15 @@ func validateReachableByField(fl validator.FieldLevel) bool { func validateBGPFilterRuleV4(structLevel validator.StructLevel) { fs := structLevel.Current().Interface().(api.BGPFilterRuleV4) - validateBGPFilterRule(structLevel, fs.CIDR, fs.MatchOperator) + validateBGPFilterRule(structLevel, fs.CIDR, fs.MatchOperator, fs.PrefixLength, nil) } func validateBGPFilterRuleV6(structLevel validator.StructLevel) { fs := structLevel.Current().Interface().(api.BGPFilterRuleV6) - validateBGPFilterRule(structLevel, fs.CIDR, fs.MatchOperator) + validateBGPFilterRule(structLevel, fs.CIDR, fs.MatchOperator, nil, fs.PrefixLength) } -func validateBGPFilterRule(structLevel validator.StructLevel, cidr string, op api.BGPFilterMatchOperator) { +func validateBGPFilterRule(structLevel validator.StructLevel, cidr string, op api.BGPFilterMatchOperator, prefixLengthV4 *api.BGPFilterPrefixLengthV4, prefixLengthV6 *api.BGPFilterPrefixLengthV6) { if cidr != "" && op == "" { structLevel.ReportError(cidr, "CIDR", "", reason("MatchOperator cannot be empty when CIDR is not"), "") @@ -1412,6 +1428,14 @@ func validateBGPFilterRule(structLevel validator.StructLevel, cidr string, op ap structLevel.ReportError(op, "MatchOperator", "", reason("CIDR cannot be empty when MatchOperator is not"), "") } + if cidr == "" && prefixLengthV4 != nil { + structLevel.ReportError(prefixLengthV4, "PrefixLength", "", + reason("CIDR cannot be empty when PrefixLength is not"), "") + } + if cidr == "" && prefixLengthV6 != nil { + structLevel.ReportError(prefixLengthV6, "PrefixLength", "", + reason("CIDR cannot be empty when PrefixLength is not"), "") + } } func validateEndpointPort(structLevel validator.StructLevel) { diff --git a/libcalico-go/lib/validator/v3/validator_test.go b/libcalico-go/lib/validator/v3/validator_test.go index f4d32dd6c0c..94641de0f20 100644 --- a/libcalico-go/lib/validator/v3/validator_test.go +++ b/libcalico-go/lib/validator/v3/validator_test.go @@ -1789,6 +1789,68 @@ func init() { Entry("should accept BGPFilter rule with just an action - 2", api.BGPFilterRuleV6{ Action: "Reject", }, true), + Entry("should accept BGPFilterV4 rule with PrefixLength Min set", api.BGPFilterRuleV4{ + CIDR: "10.0.10.0/24", + MatchOperator: "In", + Action: "Reject", + PrefixLength: &api.BGPFilterPrefixLengthV4{ + Min: int32Helper(25), + }, + }, true), + Entry("should accept BGPFilterV4 rule with PrefixLength Max set", api.BGPFilterRuleV4{ + CIDR: "10.0.10.0/24", + MatchOperator: "In", + Action: "Reject", + PrefixLength: &api.BGPFilterPrefixLengthV4{ + Max: int32Helper(30), + }, + }, true), + Entry("should reject BGPFilterV4 rule with PrefixLength Max is out-of-bounds", api.BGPFilterRuleV4{ + CIDR: "10.0.10.0/24", + MatchOperator: "In", + Action: "Reject", + PrefixLength: &api.BGPFilterPrefixLengthV4{ + Max: int32Helper(64), + }, + }, false), + Entry("should reject BGPFilterV4 rule with PrefixLength populated and CIDR missing", api.BGPFilterRuleV4{ + Interface: "ethx.", + Action: "Reject", + PrefixLength: &api.BGPFilterPrefixLengthV4{ + Min: int32Helper(16), + }, + }, false), + Entry("should accept BGPFilterV6 rule with PrefixLength Min set", api.BGPFilterRuleV6{ + CIDR: "ffff::/128", + MatchOperator: "In", + Action: "Reject", + PrefixLength: &api.BGPFilterPrefixLengthV6{ + Min: int32Helper(65), + }, + }, true), + Entry("should accept BGPFilterV6 rule with PrefixLength Max set", api.BGPFilterRuleV6{ + CIDR: "ffff::/128", + MatchOperator: "In", + Action: "Reject", + PrefixLength: &api.BGPFilterPrefixLengthV6{ + Max: int32Helper(96), + }, + }, true), + Entry("should reject BGPFilterV6 rule with PrefixLength Min is negative", api.BGPFilterRuleV6{ + CIDR: "ffff::/128", + MatchOperator: "In", + Action: "Reject", + PrefixLength: &api.BGPFilterPrefixLengthV6{ + Min: int32Helper(-16), + }, + }, false), + Entry("should reject BGPFilterV6 rule with PrefixLength populated and CIDR missing", api.BGPFilterRuleV6{ + Interface: "*.calico", + Action: "Reject", + PrefixLength: &api.BGPFilterPrefixLengthV6{ + Min: int32Helper(120), + }, + }, false), // (API) BGPPeerSpec Entry("should accept valid BGPPeerSpec", api.BGPPeerSpec{PeerIP: ipv4_1}, true), @@ -3141,3 +3203,7 @@ func mustParsePortRange(min, max uint16) numorstring.Port { } return p } + +func int32Helper(i int32) *int32 { + return &i +} diff --git a/manifests/calico-bpf.yaml b/manifests/calico-bpf.yaml index f0a75683318..9a08efd1bb0 100644 --- a/manifests/calico-bpf.yaml +++ b/manifests/calico-bpf.yaml @@ -334,6 +334,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -355,6 +368,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: @@ -376,6 +402,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -397,6 +436,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: diff --git a/manifests/calico-policy-only.yaml b/manifests/calico-policy-only.yaml index 0191364fae3..184f32577a2 100644 --- a/manifests/calico-policy-only.yaml +++ b/manifests/calico-policy-only.yaml @@ -344,6 +344,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -365,6 +378,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: @@ -386,6 +412,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -407,6 +446,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: diff --git a/manifests/calico-typha.yaml b/manifests/calico-typha.yaml index b122ea893dd..294c9eb465d 100644 --- a/manifests/calico-typha.yaml +++ b/manifests/calico-typha.yaml @@ -345,6 +345,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -366,6 +379,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: @@ -387,6 +413,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -408,6 +447,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: diff --git a/manifests/calico-vxlan.yaml b/manifests/calico-vxlan.yaml index 4ff859cee78..866d7324fe5 100644 --- a/manifests/calico-vxlan.yaml +++ b/manifests/calico-vxlan.yaml @@ -329,6 +329,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -350,6 +363,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: @@ -371,6 +397,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -392,6 +431,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: diff --git a/manifests/calico.yaml b/manifests/calico.yaml index 2c372c129e3..e1a7e23f523 100644 --- a/manifests/calico.yaml +++ b/manifests/calico.yaml @@ -329,6 +329,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -350,6 +363,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: @@ -371,6 +397,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -392,6 +431,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: diff --git a/manifests/canal.yaml b/manifests/canal.yaml index 0c824b32dff..a055b35f8e5 100644 --- a/manifests/canal.yaml +++ b/manifests/canal.yaml @@ -346,6 +346,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -367,6 +380,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: @@ -388,6 +414,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -409,6 +448,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: diff --git a/manifests/crds.yaml b/manifests/crds.yaml index fdfa5351670..687a0a547bc 100644 --- a/manifests/crds.yaml +++ b/manifests/crds.yaml @@ -239,6 +239,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -260,6 +273,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: @@ -281,6 +307,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -302,6 +341,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: diff --git a/manifests/flannel-migration/calico.yaml b/manifests/flannel-migration/calico.yaml index cebb3dc88a7..73b3a6a78ed 100644 --- a/manifests/flannel-migration/calico.yaml +++ b/manifests/flannel-migration/calico.yaml @@ -329,6 +329,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -350,6 +363,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: @@ -371,6 +397,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -392,6 +431,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: diff --git a/manifests/ocp/crd.projectcalico.org_bgpfilters.yaml b/manifests/ocp/crd.projectcalico.org_bgpfilters.yaml index 4cac7ae27a0..421273da9c0 100644 --- a/manifests/ocp/crd.projectcalico.org_bgpfilters.yaml +++ b/manifests/ocp/crd.projectcalico.org_bgpfilters.yaml @@ -49,6 +49,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -70,6 +83,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: @@ -91,6 +117,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -112,6 +151,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: diff --git a/manifests/operator-crds.yaml b/manifests/operator-crds.yaml index 7c5af336175..9aae1992cb4 100644 --- a/manifests/operator-crds.yaml +++ b/manifests/operator-crds.yaml @@ -16768,6 +16768,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -16789,6 +16802,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: @@ -16810,6 +16836,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -16831,6 +16870,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: diff --git a/manifests/tigera-operator.yaml b/manifests/tigera-operator.yaml index 581cffbcccc..df276cc142f 100644 --- a/manifests/tigera-operator.yaml +++ b/manifests/tigera-operator.yaml @@ -246,6 +246,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -267,6 +280,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: @@ -288,6 +314,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 32 + minimum: 0 + type: integer + min: + format: int32 + maximum: 32 + minimum: 0 + type: integer + type: object source: type: string required: @@ -309,6 +348,19 @@ spec: type: string matchOperator: type: string + prefixLength: + properties: + max: + format: int32 + maximum: 128 + minimum: 0 + type: integer + min: + format: int32 + maximum: 128 + minimum: 0 + type: integer + type: object source: type: string required: