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  }