projectcalico / calico

Cloud native networking and network security
https://docs.tigera.io/calico/latest/about/
Apache License 2.0
6.03k stars 1.35k forks source link

BGPFilter: match on prefix length #8376

Closed defo89 closed 3 months ago

defo89 commented 10 months ago

Expected Behavior

In certain scenarios there might be a need to allow/deny prefixes with variable prefix length.

Example: Allow accepting prefixes within 77.0.0.0/16 but not /32 host routes, or more complex case: do not accept routes with prefix length greater than or equal /20 and less than or equal /24.

Another use case could be related to https://github.com/projectcalico/calico/issues/8374 (not yet sure if behaviour in the issue is intended): allow prefix advertisement within ClusterCIDR range but disable announcement of /32 prefixes.

If I understand bird filters correctly, that would look like this:

  exportV4:
    - action: Reject
      matchOperator: In
      cidr: 100.64.0.0/15{32}

From the above link:

Sets of prefixes are special: their literals does not allow ranges, but allows prefix patterns that are written as ipaddress/pxlen{low,high}. Prefix ip1/len1 matches prefix pattern ip2/len2{l,h} if the first min(len1, len2) bits of ip1 and ip2 are identical and len1 <= ip1 <= len2. A valid prefix pattern has to satisfy low <= high, but pxlen is not constrained by low or high. Obviously, a prefix matches a prefix set literal if it matches any prefix pattern in the prefix set literal.

There are also two shorthands for prefix patterns: address/len+ is a shorthand for address/len{len,maxlen} (where maxlen is 32 for IPv4 and 128 for IPv6), that means network prefix address/len and all its subnets. address/len- is a shorthand for address/len{0,len}, that means network prefix address/len and all its supernets (network prefixes that contain it).

For example, [ 1.0.0.0/8, 2.0.0.0/8+, 3.0.0.0/8-, 4.0.0.0/8{16,24} ] matches prefix 1.0.0.0/8, all subprefixes of 2.0.0.0/8, all superprefixes of 3.0.0.0/8 and prefixes 4.X.X.X whose prefix length is 16 to 24. [ 0.0.0.0/0{20,24} ] matches all prefixes (regardless of IP address) whose prefix length is 20 to 24, [ 1.2.3.4/32- ] matches any prefix that contains IP address 1.2.3.4. 1.2.0.0/16 ~ [ 1.0.0.0/8{15,17} ] is true, but 1.0.0.0/16 ~ [ 1.0.0.0/8- ] is false.

Cisco-style patterns like 10.0.0.0/8 ge 16 le 24 can be expressed in BIRD as 10.0.0.0/8{16,24}, 192.168.0.0/16 le 24 as 192.168.0.0/16{16,24} and 192.168.0.0/16 ge 24 as 192.168.0.0/16{24,32}.

Caveat: above works with cidr but I am not sure how the match would look like for communities.

caseydavenport commented 10 months ago

Seems like a reasonable enhancement to me, although potentially fairly niche outside of your linked issue (which it sounds like has been resolved through the use of USE_POD_CIDR).

Probably would look something like this in the Calico API:

  exportV4:
    - action: Accept
      matchOperator: In
      cidr: 77.0.0.0/16
      routePrefixLength: 32
mstansberry commented 10 months ago

would love to see this feature for more complete route control, especially for specific instances where we many only want to advertise service /32 and not the aggregate from all nodes

defo89 commented 10 months ago

@caseydavenport that API example would work for matching a specific prefix length within a given prefix. However it would not cover a range use case described in birds documentation which is usually used in routers prefix-list approach: match ≥16 and ≤24 at same time (separate usage is also possible of course).

Cisco-style patterns like 10.0.0.0/8 ge 16 le 24 can be expressed in BIRD as 10.0.0.0/8{16,24}
caseydavenport commented 10 months ago

Right, IIUC that's basically the union of "route within 10.0.0.0/8" and "route prefix >= 16" and "route prefix <= 24".

So we might want a more expressive prefix match section. e.g.,

# Match a specific prefix length
cidr: 77.0.0.0/16
prefix:
  length: 32

or

# Match a range of prefix lengths
cidr: 77.0.0.0/16
prefix:
  min: 16
  max: 24
defo89 commented 10 months ago

Spot on, whereas min and max could also be used separately:

# Match prefixes lengths until 24 (included)
cidr: 77.0.0.0/16
prefix:
  max: 24

or

# Match prefixes lengths from 20
cidr: 77.0.0.0/16
prefix:
  min: 20
mstansberry commented 9 months ago

Just checking if there is a planned ETA for this feature on the roadmap? Thanks a lot.

caseydavenport commented 8 months ago

I think this one is still on the backlog. Would be happy to review PRs for it, though!