github.com/cilium/cilium@v1.16.2/pkg/bgpv1/types/utils.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package types 5 6 import ( 7 "net/netip" 8 "slices" 9 10 "github.com/osrg/gobgp/v3/pkg/packet/bgp" 11 12 ipamOption "github.com/cilium/cilium/pkg/ipam/option" 13 ) 14 15 // CanAdvertisePodCIDR returns true if the provided IPAM mode is supported for 16 // advertising PodCIDR 17 func CanAdvertisePodCIDR(ipam string) bool { 18 supportedIPAMs := []string{ 19 ipamOption.IPAMKubernetes, 20 ipamOption.IPAMClusterPool, 21 } 22 return slices.Contains(supportedIPAMs, ipam) 23 } 24 25 // NewPathForPrefix returns a Path that can be used to advertise the provided 26 // IP prefix by the underlying BGP implementation. 27 // 28 // The prefix can be either IPv4 or IPv6 and this function will handle the differences 29 // between MP BGP and BGP. 30 // 31 // The next hop of the path will always be set to "0.0.0.0" for IPv4 and "::" for IPv6, 32 // so the underlying BGP implementation selects appropriate actual nexthop address when advertising it. 33 func NewPathForPrefix(prefix netip.Prefix) (path *Path) { 34 originAttr := bgp.NewPathAttributeOrigin(0) 35 36 // Currently, we only support advertising locally originated paths (the paths generated in Cilium 37 // node itself, not the paths received from another BGP Peer or redistributed from another routing 38 // protocol. In this case, the nexthop address should be the address used for peering. That means 39 // the nexthop address can be changed depending on the neighbor. 40 // 41 // For example, when the Cilium node is connected to two subnets 10.0.0.0/24 and 10.0.1.0/24 with 42 // local address 10.0.0.1 and 10.0.1.1 respectively, the nexthop should be advertised for 10.0.0.0/24 43 // peers is 10.0.0.1. On the other hand, we should advertise 10.0.1.1 as a nexthop for 10.0.1.0/24. 44 // 45 // Fortunately, GoBGP takes care of resolving appropriate nexthop address for each peers when we 46 // specify an zero IP address (0.0.0.0 for IPv4 and :: for IPv6). So, we can just rely on that. 47 // 48 // References: 49 // - RFC4271 Section 5.1.3 (NEXT_HOP) 50 // - RFC4760 Section 3 (Multiprotocol Reachable NLRI - MP_REACH_NLRI (Type Code 14)) 51 52 switch { 53 case prefix.Addr().Is4(): 54 nlri := bgp.NewIPAddrPrefix(uint8(prefix.Bits()), prefix.Addr().String()) 55 nextHopAttr := bgp.NewPathAttributeNextHop("0.0.0.0") 56 path = &Path{ 57 NLRI: nlri, 58 PathAttributes: []bgp.PathAttributeInterface{ 59 originAttr, 60 nextHopAttr, 61 }, 62 } 63 case prefix.Addr().Is6(): 64 nlri := bgp.NewIPv6AddrPrefix(uint8(prefix.Bits()), prefix.Addr().String()) 65 mpReachNLRIAttr := bgp.NewPathAttributeMpReachNLRI("::", []bgp.AddrPrefixInterface{nlri}) 66 path = &Path{ 67 NLRI: nlri, 68 PathAttributes: []bgp.PathAttributeInterface{ 69 originAttr, 70 mpReachNLRIAttr, 71 }, 72 } 73 } 74 75 return 76 } 77 78 // DeepEqual is a manually created deepequal function, deeply comparing the receiver with another. 79 // It compares fields with types that do not implement the `DeepEqual` method 80 // and calls the generated private `deepEqual` method which compares the rest of the fields. 81 func (m *RoutePolicyPrefixMatch) DeepEqual(other *RoutePolicyPrefixMatch) bool { 82 // Compare netip.Prefix field (does not implement the `DeepEqual` method) 83 if m.CIDR != other.CIDR { 84 return false 85 } 86 // Call generated `deepEqual` method which compares all fields except 'CIDR' 87 return m.deepEqual(other) 88 } 89 90 type PolicyPrefixMatchList []*RoutePolicyPrefixMatch 91 92 // Less is a comparator of two RoutePolicyPrefixMatch rules to be used for sorting purposes 93 func (l PolicyPrefixMatchList) Less(i, j int) bool { 94 return l[i].CIDR.Bits() < l[j].CIDR.Bits() || l[i].CIDR.Addr().Less(l[j].CIDR.Addr()) || 95 l[i].PrefixLenMin < l[j].PrefixLenMin || l[i].PrefixLenMax < l[j].PrefixLenMax 96 }