github.com/cilium/cilium@v1.16.2/pkg/maps/ipcache/ipcache.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package ipcache 5 6 import ( 7 "fmt" 8 "net" 9 "net/netip" 10 "sync" 11 "unsafe" 12 13 "github.com/cilium/cilium/pkg/bpf" 14 cmtypes "github.com/cilium/cilium/pkg/clustermesh/types" 15 "github.com/cilium/cilium/pkg/ebpf" 16 "github.com/cilium/cilium/pkg/option" 17 "github.com/cilium/cilium/pkg/types" 18 ) 19 20 const ( 21 // MaxEntries is the maximum number of keys that can be present in the 22 // RemoteEndpointMap. 23 MaxEntries = 512000 24 25 // Name is the canonical name for the IPCache map on the filesystem. 26 Name = "cilium_ipcache" 27 ) 28 29 // Key implements the bpf.MapKey interface. 30 // 31 // Must be in sync with struct ipcache_key in <bpf/lib/maps.h> 32 type Key struct { 33 Prefixlen uint32 `align:"lpm_key"` 34 ClusterID uint16 `align:"cluster_id"` 35 Pad1 uint8 `align:"pad1"` 36 Family uint8 `align:"family"` 37 // represents both IPv6 and IPv4 (in the lowest four bytes) 38 IP types.IPv6 `align:"$union0"` 39 } 40 41 func getStaticPrefixBits() uint32 { 42 staticMatchSize := unsafe.Sizeof(Key{}) 43 staticMatchSize -= unsafe.Sizeof(Key{}.Prefixlen) 44 staticMatchSize -= unsafe.Sizeof(Key{}.IP) 45 return uint32(staticMatchSize) * 8 46 } 47 48 func (k Key) String() string { 49 var ( 50 addr netip.Addr 51 ok bool 52 ) 53 54 switch k.Family { 55 case bpf.EndpointKeyIPv4: 56 addr, ok = netip.AddrFromSlice(k.IP[:net.IPv4len]) 57 if !ok { 58 return "<unknown>" 59 } 60 case bpf.EndpointKeyIPv6: 61 addr = netip.AddrFrom16(k.IP) 62 default: 63 return "<unknown>" 64 } 65 66 prefixLen := int(k.Prefixlen - getStaticPrefixBits()) 67 clusterID := uint32(k.ClusterID) 68 69 return cmtypes.PrefixClusterFrom(addr, prefixLen, cmtypes.WithClusterID(clusterID)).String() 70 } 71 72 func (k *Key) New() bpf.MapKey { return &Key{} } 73 74 func (k Key) Prefix() netip.Prefix { 75 var addr netip.Addr 76 prefixLen := int(k.Prefixlen - getStaticPrefixBits()) 77 switch k.Family { 78 case bpf.EndpointKeyIPv4: 79 addr = netip.AddrFrom4(*(*[4]byte)(k.IP[:4])) 80 case bpf.EndpointKeyIPv6: 81 addr = netip.AddrFrom16(k.IP) 82 } 83 return netip.PrefixFrom(addr, prefixLen) 84 } 85 86 // getPrefixLen determines the length that should be set inside the Key so that 87 // the lookup prefix is correct in the BPF map key. The specified 'prefixBits' 88 // indicates the number of bits in the IP that must match to match the entry in 89 // the BPF ipcache. 90 func getPrefixLen(prefixBits int) uint32 { 91 return getStaticPrefixBits() + uint32(prefixBits) 92 } 93 94 // NewKey returns an Key based on the provided IP address, mask, and ClusterID. 95 // The address family is automatically detected 96 func NewKey(ip net.IP, mask net.IPMask, clusterID uint16) Key { 97 result := Key{} 98 99 ones, _ := mask.Size() 100 if ip4 := ip.To4(); ip4 != nil { 101 if mask == nil { 102 ones = net.IPv4len * 8 103 } 104 result.Prefixlen = getPrefixLen(ones) 105 result.Family = bpf.EndpointKeyIPv4 106 copy(result.IP[:], ip4) 107 } else { 108 if mask == nil { 109 ones = net.IPv6len * 8 110 } 111 result.Prefixlen = getPrefixLen(ones) 112 result.Family = bpf.EndpointKeyIPv6 113 copy(result.IP[:], ip) 114 } 115 116 result.ClusterID = clusterID 117 118 return result 119 } 120 121 // RemoteEndpointInfoFlags represents various flags that can be attached to 122 // remote endpoints in the IPCache. 123 type RemoteEndpointInfoFlags uint8 124 125 // String returns a human-readable representation of the flags present in the 126 // RemoteEndpointInfoFlags. 127 // The output format is the string name of each flag contained in the flag set, 128 // separated by a comma. If no flags are set, then "<none>" is returned. 129 func (f RemoteEndpointInfoFlags) String() string { 130 // If more flags are added in the future, then this method will need 131 // a re-work to support multiple flags. 132 // Right now, it only supports checking for FlagSkipTunnel. 133 if f&FlagSkipTunnel == FlagSkipTunnel { 134 return "skiptunnel" 135 } 136 137 return "<none>" 138 } 139 140 const ( 141 // FlagSkipTunnel can be applied to a remote endpoint to signal that 142 // packets destined for said endpoint shall not be forwarded through 143 // a VXLAN/Geneve tunnel, regardless of Cilium's configuration. 144 FlagSkipTunnel RemoteEndpointInfoFlags = 1 << iota 145 ) 146 147 // RemoteEndpointInfo implements the bpf.MapValue interface. It contains the 148 // security identity of a remote endpoint. 149 type RemoteEndpointInfo struct { 150 SecurityIdentity uint32 `align:"sec_identity"` 151 TunnelEndpoint types.IPv4 `align:"tunnel_endpoint"` 152 _ uint16 153 Key uint8 `align:"key"` 154 Flags RemoteEndpointInfoFlags `align:"flag_skip_tunnel"` 155 } 156 157 func (v *RemoteEndpointInfo) String() string { 158 return fmt.Sprintf("identity=%d encryptkey=%d tunnelendpoint=%s, flags=%s", 159 v.SecurityIdentity, v.Key, v.TunnelEndpoint, v.Flags) 160 } 161 162 func (v *RemoteEndpointInfo) New() bpf.MapValue { return &RemoteEndpointInfo{} } 163 164 // Map represents an IPCache BPF map. 165 type Map struct { 166 bpf.Map 167 } 168 169 func newIPCacheMap(name string) *bpf.Map { 170 return bpf.NewMap( 171 name, 172 ebpf.LPMTrie, 173 &Key{}, 174 &RemoteEndpointInfo{}, 175 MaxEntries, 176 bpf.BPF_F_NO_PREALLOC) 177 } 178 179 // NewMap instantiates a Map. 180 func NewMap(name string) *Map { 181 return &Map{ 182 Map: *newIPCacheMap(name).WithCache().WithPressureMetric(). 183 WithEvents(option.Config.GetEventBufferConfig(name)), 184 } 185 } 186 187 var ( 188 // IPCache is a mapping of all endpoint IPs in the cluster which this 189 // Cilium agent is a part of to their corresponding security identities. 190 // It is a singleton; there is only one such map per agent. 191 ipcache *Map 192 once = &sync.Once{} 193 ) 194 195 // IPCacheMap gets the ipcache Map singleton. If it has not already been done, 196 // this also initializes the Map. 197 func IPCacheMap() *Map { 198 once.Do(func() { 199 ipcache = NewMap(Name) 200 }) 201 return ipcache 202 }