github.com/cilium/cilium@v1.16.2/pkg/maps/l2respondermap/l2_responder_map4.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package l2respondermap
     5  
     6  import (
     7  	"fmt"
     8  	"net"
     9  	"net/netip"
    10  	"unsafe"
    11  
    12  	"github.com/cilium/hive/cell"
    13  	"golang.org/x/sys/unix"
    14  
    15  	"github.com/cilium/cilium/pkg/ebpf"
    16  	"github.com/cilium/cilium/pkg/types"
    17  )
    18  
    19  const (
    20  	MapName           = "cilium_l2_responder_v4"
    21  	DefaultMaxEntries = 4096
    22  )
    23  
    24  var Cell = cell.Provide(NewMap)
    25  
    26  type Map interface {
    27  	Create(ip netip.Addr, ifIndex uint32) error
    28  	Lookup(ip netip.Addr, ifIndex uint32) (*L2ResponderStats, error)
    29  	Delete(ip netip.Addr, ifIndex uint32) error
    30  	IterateWithCallback(cb IterateCallback) error
    31  }
    32  
    33  func NewMap(lifecycle cell.Lifecycle) (Map, error) {
    34  	return newMap(lifecycle, DefaultMaxEntries)
    35  }
    36  
    37  type l2ResponderMap struct {
    38  	*ebpf.Map
    39  }
    40  
    41  func newMap(lifecycle cell.Lifecycle, maxEntries int) (*l2ResponderMap, error) {
    42  	outerMap := &l2ResponderMap{}
    43  
    44  	lifecycle.Append(cell.Hook{
    45  		OnStart: func(hc cell.HookContext) error {
    46  			var (
    47  				m   *ebpf.Map
    48  				err error
    49  			)
    50  
    51  			if m, err = ebpf.LoadRegisterMap(MapName); err != nil {
    52  				m = ebpf.NewMap(&ebpf.MapSpec{
    53  					Name:       MapName,
    54  					Type:       ebpf.Hash,
    55  					KeySize:    uint32(unsafe.Sizeof(L2ResponderKey{})),
    56  					ValueSize:  uint32(unsafe.Sizeof(L2ResponderStats{})),
    57  					MaxEntries: uint32(maxEntries),
    58  					Flags:      unix.BPF_F_NO_PREALLOC,
    59  					Pinning:    ebpf.PinByName,
    60  				})
    61  				if err := m.OpenOrCreate(); err != nil {
    62  					return err
    63  				}
    64  			}
    65  
    66  			outerMap.Map = m
    67  
    68  			return nil
    69  		},
    70  	})
    71  
    72  	return outerMap, nil
    73  }
    74  
    75  // Create creates a new entry for the given IP and IfIndex tuple.
    76  func (m *l2ResponderMap) Create(ip netip.Addr, ifIndex uint32) error {
    77  	key := newL2ResponderKey(ip, ifIndex)
    78  	return m.Map.Put(key, L2ResponderStats{})
    79  }
    80  
    81  // Delete deletes the entry associated with the provided IP and IfIndex tuple.
    82  func (m *l2ResponderMap) Delete(ip netip.Addr, ifIndex uint32) error {
    83  	key := newL2ResponderKey(ip, ifIndex)
    84  	return m.Map.Delete(key)
    85  }
    86  
    87  // Lookup returns the stats object associated with the provided IP and IfIndex tuple.
    88  func (m *l2ResponderMap) Lookup(ip netip.Addr, ifIndex uint32) (*L2ResponderStats, error) {
    89  	key := newL2ResponderKey(ip, ifIndex)
    90  	val := L2ResponderStats{}
    91  
    92  	err := m.Map.Lookup(&key, &val)
    93  
    94  	return &val, err
    95  }
    96  
    97  // IterateCallback represents the signature of the callback function
    98  // expected by the IterateWithCallback method, which in turn is used to iterate
    99  // all the keys/values of a L2 responder map.
   100  type IterateCallback func(*L2ResponderKey, *L2ResponderStats)
   101  
   102  // IterateWithCallback iterates through all the keys/values of a L2 responder map,
   103  // passing each key/value pair to the cb callback.
   104  func (m *l2ResponderMap) IterateWithCallback(cb IterateCallback) error {
   105  	return m.Map.IterateWithCallback(&L2ResponderKey{}, &L2ResponderStats{},
   106  		func(k, v interface{}) {
   107  			key := k.(*L2ResponderKey)
   108  			value := v.(*L2ResponderStats)
   109  			cb(key, value)
   110  		},
   111  	)
   112  }
   113  
   114  // L2ResponderKey implements the bpf.MapKey interface.
   115  //
   116  // Must be in sync with struct l2_responder_v4_key in <bpf/lib/maps.h>
   117  type L2ResponderKey struct {
   118  	IP      types.IPv4 `align:"ip"`
   119  	IfIndex uint32     `align:"ifindex"`
   120  }
   121  
   122  func (k *L2ResponderKey) String() string {
   123  	return fmt.Sprintf("ip=%s, ifIndex=%d", net.IP(k.IP[:]), k.IfIndex)
   124  }
   125  
   126  func newL2ResponderKey(ip netip.Addr, ifIndex uint32) L2ResponderKey {
   127  	return L2ResponderKey{
   128  		IP:      types.IPv4(ip.As4()),
   129  		IfIndex: ifIndex,
   130  	}
   131  }
   132  
   133  // L2ResponderStats implements the bpf.MapValue interface.
   134  //
   135  // Must be in sync with struct l2_responder_v4_stats in <bpf/lib/maps.h>
   136  type L2ResponderStats struct {
   137  	ResponsesSent uint64 `align:"responses_sent"`
   138  }
   139  
   140  func (s *L2ResponderStats) String() string {
   141  	return fmt.Sprintf("responses_sent=%q", s.ResponsesSent)
   142  }