github.com/cilium/cilium@v1.16.2/pkg/maps/srv6map/policy.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package srv6map
     5  
     6  import (
     7  	"fmt"
     8  	"net/netip"
     9  	"strconv"
    10  	"unsafe"
    11  
    12  	"github.com/cilium/ebpf"
    13  	"github.com/cilium/hive/cell"
    14  
    15  	"github.com/cilium/cilium/pkg/bpf"
    16  	"github.com/cilium/cilium/pkg/datapath/linux/config/defines"
    17  	"github.com/cilium/cilium/pkg/option"
    18  	"github.com/cilium/cilium/pkg/types"
    19  )
    20  
    21  const (
    22  	policyMapName4   = "cilium_srv6_policy_v4"
    23  	policyMapName6   = "cilium_srv6_policy_v6"
    24  	maxPolicyEntries = 16384
    25  
    26  	// policyStaticPrefixBits represents the size in bits of the static
    27  	// prefix part of an policy key (i.e. the VRF ID).
    28  	policyStaticPrefixBits = uint32(unsafe.Sizeof(uint32(0)) * 8)
    29  )
    30  
    31  // PolicyKey4 is a key for the PolicyMap4. Implements bpf.MapKey.
    32  type PolicyKey4 struct {
    33  	// PrefixLen is full 32 bits of VRF ID + DestCIDR's mask bits
    34  	PrefixLen uint32     `align:"lpm"`
    35  	VRFID     uint32     `align:"vrf_id"`
    36  	DestCIDR  types.IPv4 `align:"dst_cidr"`
    37  }
    38  
    39  func (k *PolicyKey4) New() bpf.MapKey {
    40  	return &PolicyKey4{}
    41  }
    42  
    43  func (k *PolicyKey4) String() string {
    44  	return fmt.Sprintf("vrfid=%d, destCIDR=%s", k.VRFID, k.getDestCIDR())
    45  }
    46  
    47  func (k *PolicyKey4) getDestCIDR() netip.Prefix {
    48  	return netip.PrefixFrom(
    49  		k.DestCIDR.Addr(),
    50  		int(k.PrefixLen-policyStaticPrefixBits),
    51  	)
    52  }
    53  
    54  // PolicyKey6 is a key for the PolicyMap6. Implements bpf.MapKey.
    55  type PolicyKey6 struct {
    56  	// PrefixLen is full 32 bits of VRF ID + DestCIDR's mask bits
    57  	PrefixLen uint32     `align:"lpm"`
    58  	VRFID     uint32     `align:"vrf_id"`
    59  	DestCIDR  types.IPv6 `align:"dst_cidr"`
    60  }
    61  
    62  func (k *PolicyKey6) New() bpf.MapKey {
    63  	return &PolicyKey6{}
    64  }
    65  
    66  func (k *PolicyKey6) String() string {
    67  	return fmt.Sprintf("vrfid=%d, destCIDR=%s", k.VRFID, k.getDestCIDR())
    68  }
    69  
    70  func (k *PolicyKey6) getDestCIDR() netip.Prefix {
    71  	return netip.PrefixFrom(
    72  		k.DestCIDR.Addr(),
    73  		int(k.PrefixLen-policyStaticPrefixBits),
    74  	)
    75  }
    76  
    77  // PolicyKey abstracts away the differences between PolicyKey4 and PolicyKey6.
    78  type PolicyKey struct {
    79  	VRFID    uint32
    80  	DestCIDR netip.Prefix
    81  }
    82  
    83  // PolicyValue is a value for the PolicyMap4/6. Implements bpf.MapValue.
    84  type PolicyValue struct {
    85  	SID types.IPv6
    86  }
    87  
    88  func (k *PolicyValue) New() bpf.MapValue {
    89  	return &PolicyValue{}
    90  }
    91  
    92  func (v *PolicyValue) String() string {
    93  	return fmt.Sprintf("sid=%s", v.SID.String())
    94  }
    95  
    96  // SRv6PolicyIterateCallback represents the signature of the callback function
    97  // expected by the IterateWithCallback method, which in turn is used to iterate
    98  // all the keys/values of an SRv6 policy map.
    99  type SRv6PolicyIterateCallback func(*PolicyKey, *PolicyValue)
   100  
   101  // Define different types for IPv4 and IPv6 maps for DI
   102  type PolicyMap4 srv6PolicyMap
   103  type PolicyMap6 srv6PolicyMap
   104  
   105  // IterateWithCallback4 iterates through the IPv4 keys/values of an egress
   106  // policy map, passing each key/value pair to the cb callback.
   107  func (m *PolicyMap4) IterateWithCallback(cb SRv6PolicyIterateCallback) error {
   108  	return m.DumpWithCallback(func(k bpf.MapKey, v bpf.MapValue) {
   109  		k4 := k.(*PolicyKey4)
   110  		key := &PolicyKey{
   111  			VRFID:    k4.VRFID,
   112  			DestCIDR: k4.getDestCIDR(),
   113  		}
   114  		value := v.(*PolicyValue)
   115  		cb(key, value)
   116  	})
   117  }
   118  
   119  // IterateWithCallback iterates through the IPv6 keys/values of an egress
   120  // policy map, passing each key/value pair to the cb callback.
   121  func (m *PolicyMap6) IterateWithCallback(cb SRv6PolicyIterateCallback) error {
   122  	return m.DumpWithCallback(func(k bpf.MapKey, v bpf.MapValue) {
   123  		k6 := k.(*PolicyKey6)
   124  		key := &PolicyKey{
   125  			VRFID:    k6.VRFID,
   126  			DestCIDR: k6.getDestCIDR(),
   127  		}
   128  		value := v.(*PolicyValue)
   129  		cb(key, value)
   130  	})
   131  }
   132  
   133  // srv6PolicyMap is the internal representation of an SRv6 policy map.
   134  type srv6PolicyMap struct {
   135  	*bpf.Map
   136  }
   137  
   138  func newPolicyMaps(dc *option.DaemonConfig, lc cell.Lifecycle) (bpf.MapOut[*PolicyMap4], bpf.MapOut[*PolicyMap6], defines.NodeOut) {
   139  	if !dc.EnableSRv6 {
   140  		return bpf.MapOut[*PolicyMap4]{}, bpf.MapOut[*PolicyMap6]{}, defines.NodeOut{}
   141  	}
   142  
   143  	m4 := bpf.NewMap(
   144  		policyMapName4,
   145  		ebpf.LPMTrie,
   146  		&PolicyKey4{},
   147  		&PolicyValue{},
   148  		maxPolicyEntries,
   149  		bpf.BPF_F_NO_PREALLOC,
   150  	)
   151  
   152  	m6 := bpf.NewMap(
   153  		policyMapName6,
   154  		ebpf.LPMTrie,
   155  		&PolicyKey6{},
   156  		&PolicyValue{},
   157  		maxPolicyEntries,
   158  		bpf.BPF_F_NO_PREALLOC,
   159  	)
   160  
   161  	lc.Append(cell.Hook{
   162  		OnStart: func(ctx cell.HookContext) error {
   163  			if err := m4.OpenOrCreate(); err != nil {
   164  				return err
   165  			}
   166  			if err := m6.OpenOrCreate(); err != nil {
   167  				return err
   168  			}
   169  			return nil
   170  		},
   171  		OnStop: func(ctx cell.HookContext) error {
   172  			m4.Close()
   173  			m6.Close()
   174  			return nil
   175  		},
   176  	})
   177  
   178  	nodeOut := defines.NodeOut{
   179  		NodeDefines: defines.Map{
   180  			"SRV6_POLICY_MAP4":     policyMapName4,
   181  			"SRV6_POLICY_MAP6":     policyMapName6,
   182  			"SRV6_POLICY_MAP_SIZE": strconv.FormatUint(maxPolicyEntries, 10),
   183  		},
   184  	}
   185  
   186  	return bpf.NewMapOut(&PolicyMap4{m4}), bpf.NewMapOut(&PolicyMap6{m6}), nodeOut
   187  }
   188  
   189  // OpenPolicyMaps opens the SRv6 policy maps on bpffs
   190  func OpenPolicyMaps() (*PolicyMap4, *PolicyMap6, error) {
   191  	m4, err := bpf.OpenMap(bpf.MapPath(policyMapName4), &PolicyKey4{}, &PolicyValue{})
   192  	if err != nil {
   193  		return nil, nil, err
   194  	}
   195  	m6, err := bpf.OpenMap(bpf.MapPath(policyMapName6), &PolicyKey6{}, &PolicyValue{})
   196  	if err != nil {
   197  		return nil, nil, err
   198  	}
   199  	return &PolicyMap4{m4}, &PolicyMap6{m6}, nil
   200  }