github.com/cilium/cilium@v1.16.2/pkg/maps/lbmap/maglev_inner_map.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package lbmap
     5  
     6  import (
     7  	"fmt"
     8  	"unsafe"
     9  
    10  	"github.com/cilium/cilium/pkg/ebpf"
    11  	"github.com/cilium/cilium/pkg/loadbalancer"
    12  )
    13  
    14  // maglevBackendLen represents the length of a single backend ID
    15  // in a Maglev lookup table.
    16  var maglevBackendLen = uint32(unsafe.Sizeof(loadbalancer.BackendID(0)))
    17  
    18  // MaglevInnerMap represents a maglev inner map.
    19  type MaglevInnerMap ebpf.Map
    20  
    21  // TableSize returns the amount of backends this map can hold as a value.
    22  func (m *MaglevInnerMap) TableSize() uint32 {
    23  	return m.Map.ValueSize() / uint32(maglevBackendLen)
    24  }
    25  
    26  // UpdateBackends updates the maglev inner map's list of backends.
    27  func (m *MaglevInnerMap) UpdateBackends(backends []loadbalancer.BackendID) error {
    28  	// Backends are stored at inner map key zero.
    29  	var key MaglevInnerKey
    30  	return m.Map.Update(key, backends, 0)
    31  }
    32  
    33  // MaglevInnerKey is the key of a maglev inner map.
    34  type MaglevInnerKey struct {
    35  	Zero uint32
    36  }
    37  
    38  // MaglevInnerVal is the value of a maglev inner map.
    39  type MaglevInnerVal struct {
    40  	BackendIDs []loadbalancer.BackendID
    41  }
    42  
    43  // newMaglevInnerMapSpec returns the spec for a maglev inner map.
    44  func newMaglevInnerMapSpec(tableSize uint32) *ebpf.MapSpec {
    45  	return &ebpf.MapSpec{
    46  		Name:       "cilium_maglev_inner",
    47  		Type:       ebpf.Array,
    48  		KeySize:    uint32(unsafe.Sizeof(MaglevInnerKey{})),
    49  		ValueSize:  maglevBackendLen * tableSize,
    50  		MaxEntries: 1,
    51  	}
    52  }
    53  
    54  // createMaglevInnerMap creates a new Maglev inner map in the kernel
    55  // using the given table size.
    56  func createMaglevInnerMap(tableSize uint32) (*MaglevInnerMap, error) {
    57  	spec := newMaglevInnerMapSpec(tableSize)
    58  
    59  	m := ebpf.NewMap(spec)
    60  	if err := m.OpenOrCreate(); err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	return (*MaglevInnerMap)(m), nil
    65  }
    66  
    67  // MaglevInnerMapFromID returns a new object representing the maglev inner map
    68  // identified by an ID.
    69  func MaglevInnerMapFromID(id uint32) (*MaglevInnerMap, error) {
    70  	m, err := ebpf.MapFromID(int(id))
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	return (*MaglevInnerMap)(m), nil
    76  }
    77  
    78  // Lookup returns the value associated with a given key for a maglev inner map.
    79  func (m *MaglevInnerMap) Lookup(key *MaglevInnerKey) (*MaglevInnerVal, error) {
    80  	value := &MaglevInnerVal{
    81  		BackendIDs: make([]loadbalancer.BackendID, m.TableSize()),
    82  	}
    83  
    84  	if err := m.Map.Lookup(key, &value.BackendIDs); err != nil {
    85  		return nil, err
    86  	}
    87  
    88  	return value, nil
    89  }
    90  
    91  // DumpBackends returns the first key of the map as stringified ints for dumping purposes.
    92  func (m *MaglevInnerMap) DumpBackends() (string, error) {
    93  	// A service's backend array sits at the first key of the inner map.
    94  	var key MaglevInnerKey
    95  	val, err := m.Lookup(&key)
    96  	if err != nil {
    97  		return "", fmt.Errorf("lookup up first inner map key (backends): %w", err)
    98  	}
    99  
   100  	return fmt.Sprintf("%v", val.BackendIDs), nil
   101  }