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

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package egressmap
     5  
     6  import (
     7  	"fmt"
     8  	"net/netip"
     9  	"unsafe"
    10  
    11  	"github.com/cilium/ebpf"
    12  	"github.com/cilium/hive/cell"
    13  	"github.com/spf13/pflag"
    14  	"go4.org/netipx"
    15  
    16  	"github.com/cilium/cilium/pkg/bpf"
    17  	"github.com/cilium/cilium/pkg/datapath/linux/config/defines"
    18  	"github.com/cilium/cilium/pkg/option"
    19  	"github.com/cilium/cilium/pkg/types"
    20  )
    21  
    22  const (
    23  	PolicyMapName = "cilium_egress_gw_policy_v4"
    24  	// PolicyStaticPrefixBits represents the size in bits of the static
    25  	// prefix part of an egress policy key (i.e. the source IP).
    26  	PolicyStaticPrefixBits = uint32(unsafe.Sizeof(types.IPv4{}) * 8)
    27  )
    28  
    29  // EgressPolicyKey4 is the key of an egress policy map.
    30  type EgressPolicyKey4 struct {
    31  	// PrefixLen is full 32 bits of SourceIP + DestCIDR's mask bits
    32  	PrefixLen uint32 `align:"lpm_key"`
    33  
    34  	SourceIP types.IPv4 `align:"saddr"`
    35  	DestCIDR types.IPv4 `align:"daddr"`
    36  }
    37  
    38  // EgressPolicyVal4 is the value of an egress policy map.
    39  type EgressPolicyVal4 struct {
    40  	EgressIP  types.IPv4 `align:"egress_ip"`
    41  	GatewayIP types.IPv4 `align:"gateway_ip"`
    42  }
    43  
    44  type PolicyConfig struct {
    45  	// EgressGatewayPolicyMapMax is the maximum number of entries
    46  	// allowed in the BPF egress gateway policy map.
    47  	EgressGatewayPolicyMapMax int
    48  }
    49  
    50  var DefaultPolicyConfig = PolicyConfig{
    51  	EgressGatewayPolicyMapMax: 1 << 14,
    52  }
    53  
    54  func (def PolicyConfig) Flags(flags *pflag.FlagSet) {
    55  	flags.Int("egress-gateway-policy-map-max", def.EgressGatewayPolicyMapMax, "Maximum number of entries in egress gateway policy map")
    56  }
    57  
    58  // PolicyMap is used to communicate EGW policies to the datapath.
    59  type PolicyMap interface {
    60  	Lookup(sourceIP netip.Addr, destCIDR netip.Prefix) (*EgressPolicyVal4, error)
    61  	Update(sourceIP netip.Addr, destCIDR netip.Prefix, egressIP, gatewayIP netip.Addr) error
    62  	Delete(sourceIP netip.Addr, destCIDR netip.Prefix) error
    63  	IterateWithCallback(EgressPolicyIterateCallback) error
    64  }
    65  
    66  // policyMap is the internal representation of an egress policy map.
    67  type policyMap struct {
    68  	m *bpf.Map
    69  }
    70  
    71  func createPolicyMapFromDaemonConfig(in struct {
    72  	cell.In
    73  
    74  	Lifecycle cell.Lifecycle
    75  	*option.DaemonConfig
    76  	PolicyConfig
    77  }) (out struct {
    78  	cell.Out
    79  
    80  	bpf.MapOut[PolicyMap]
    81  	defines.NodeOut
    82  }) {
    83  	out.NodeDefines = map[string]string{
    84  		"EGRESS_POLICY_MAP":      PolicyMapName,
    85  		"EGRESS_POLICY_MAP_SIZE": fmt.Sprint(in.EgressGatewayPolicyMapMax),
    86  	}
    87  
    88  	if !in.EnableIPv4EgressGateway {
    89  		return
    90  	}
    91  
    92  	out.MapOut = bpf.NewMapOut(PolicyMap(createPolicyMap(in.Lifecycle, in.PolicyConfig, ebpf.PinByName)))
    93  	return
    94  }
    95  
    96  // CreatePrivatePolicyMap creates an unpinned policy map.
    97  //
    98  // Useful for testing.
    99  func CreatePrivatePolicyMap(lc cell.Lifecycle, cfg PolicyConfig) PolicyMap {
   100  	return createPolicyMap(lc, cfg, ebpf.PinNone)
   101  }
   102  
   103  func createPolicyMap(lc cell.Lifecycle, cfg PolicyConfig, pinning ebpf.PinType) *policyMap {
   104  	m := bpf.NewMap(
   105  		PolicyMapName,
   106  		ebpf.LPMTrie,
   107  		&EgressPolicyKey4{},
   108  		&EgressPolicyVal4{},
   109  		cfg.EgressGatewayPolicyMapMax,
   110  		0,
   111  	).WithPressureMetric()
   112  
   113  	lc.Append(cell.Hook{
   114  		OnStart: func(cell.HookContext) error {
   115  			switch pinning {
   116  			case ebpf.PinNone:
   117  				return m.CreateUnpinned()
   118  			case ebpf.PinByName:
   119  				return m.OpenOrCreate()
   120  			}
   121  			return fmt.Errorf("received unexpected pin type: %d", pinning)
   122  		},
   123  		OnStop: func(cell.HookContext) error {
   124  			return m.Close()
   125  		},
   126  	})
   127  
   128  	return &policyMap{m}
   129  }
   130  
   131  func OpenPinnedPolicyMap() (PolicyMap, error) {
   132  	m, err := bpf.OpenMap(bpf.MapPath(PolicyMapName), &EgressPolicyKey4{}, &EgressPolicyVal4{})
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	return &policyMap{m}, nil
   138  }
   139  
   140  // NewEgressPolicyKey4 returns a new EgressPolicyKey4 object representing the
   141  // (source IP, destination CIDR) tuple.
   142  func NewEgressPolicyKey4(sourceIP netip.Addr, destPrefix netip.Prefix) EgressPolicyKey4 {
   143  	key := EgressPolicyKey4{}
   144  
   145  	ones := destPrefix.Bits()
   146  	key.SourceIP.FromAddr(sourceIP)
   147  	key.DestCIDR.FromAddr(destPrefix.Addr())
   148  	key.PrefixLen = PolicyStaticPrefixBits + uint32(ones)
   149  
   150  	return key
   151  }
   152  
   153  // NewEgressPolicyVal4 returns a new EgressPolicyVal4 object representing for
   154  // the given egress IP and gateway IPs
   155  func NewEgressPolicyVal4(egressIP, gatewayIP netip.Addr) EgressPolicyVal4 {
   156  	val := EgressPolicyVal4{}
   157  
   158  	val.EgressIP.FromAddr(egressIP)
   159  	val.GatewayIP.FromAddr(gatewayIP)
   160  
   161  	return val
   162  }
   163  
   164  // String returns the string representation of an egress policy key.
   165  func (k *EgressPolicyKey4) String() string {
   166  	return fmt.Sprintf("%s %s/%d", k.SourceIP, k.DestCIDR, k.PrefixLen-PolicyStaticPrefixBits)
   167  }
   168  
   169  // New returns an egress policy key
   170  func (k *EgressPolicyKey4) New() bpf.MapKey { return &EgressPolicyKey4{} }
   171  
   172  // Match returns true if the sourceIP and destCIDR parameters match the egress
   173  // policy key.
   174  func (k *EgressPolicyKey4) Match(sourceIP netip.Addr, destCIDR netip.Prefix) bool {
   175  	return k.GetSourceIP() == sourceIP &&
   176  		k.GetDestCIDR() == destCIDR
   177  }
   178  
   179  // GetSourceIP returns the egress policy key's source IP.
   180  func (k *EgressPolicyKey4) GetSourceIP() netip.Addr {
   181  	addr, _ := netipx.FromStdIP(k.SourceIP.IP())
   182  	return addr
   183  }
   184  
   185  // GetDestCIDR returns the egress policy key's destination CIDR.
   186  func (k *EgressPolicyKey4) GetDestCIDR() netip.Prefix {
   187  	addr, _ := netipx.FromStdIP(k.DestCIDR.IP())
   188  	return netip.PrefixFrom(addr, int(k.PrefixLen-PolicyStaticPrefixBits))
   189  }
   190  
   191  // New returns an egress policy value
   192  func (v *EgressPolicyVal4) New() bpf.MapValue { return &EgressPolicyVal4{} }
   193  
   194  // Match returns true if the egressIP and gatewayIP parameters match the egress
   195  // policy value.
   196  func (v *EgressPolicyVal4) Match(egressIP, gatewayIP netip.Addr) bool {
   197  	return v.GetEgressAddr() == egressIP &&
   198  		v.GetGatewayAddr() == gatewayIP
   199  }
   200  
   201  // GetEgressIP returns the egress policy value's egress IP.
   202  func (v *EgressPolicyVal4) GetEgressAddr() netip.Addr {
   203  	return v.EgressIP.Addr()
   204  }
   205  
   206  // GetGatewayIP returns the egress policy value's gateway IP.
   207  func (v *EgressPolicyVal4) GetGatewayAddr() netip.Addr {
   208  	return v.GatewayIP.Addr()
   209  }
   210  
   211  // String returns the string representation of an egress policy value.
   212  func (v *EgressPolicyVal4) String() string {
   213  	return fmt.Sprintf("%s %s", v.GetGatewayAddr(), v.GetEgressAddr())
   214  }
   215  
   216  // Lookup returns the egress policy object associated with the provided (source
   217  // IP, destination CIDR) tuple.
   218  func (m *policyMap) Lookup(sourceIP netip.Addr, destCIDR netip.Prefix) (*EgressPolicyVal4, error) {
   219  	key := NewEgressPolicyKey4(sourceIP, destCIDR)
   220  	val, err := m.m.Lookup(&key)
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  
   225  	return val.(*EgressPolicyVal4), err
   226  }
   227  
   228  // Update updates the (sourceIP, destCIDR) egress policy entry with the provided
   229  // egress and gateway IPs.
   230  func (m *policyMap) Update(sourceIP netip.Addr, destCIDR netip.Prefix, egressIP, gatewayIP netip.Addr) error {
   231  	key := NewEgressPolicyKey4(sourceIP, destCIDR)
   232  	val := NewEgressPolicyVal4(egressIP, gatewayIP)
   233  
   234  	return m.m.Update(&key, &val)
   235  }
   236  
   237  // Delete deletes the (sourceIP, destCIDR) egress policy entry.
   238  func (m *policyMap) Delete(sourceIP netip.Addr, destCIDR netip.Prefix) error {
   239  	key := NewEgressPolicyKey4(sourceIP, destCIDR)
   240  
   241  	return m.m.Delete(&key)
   242  }
   243  
   244  // EgressPolicyIterateCallback represents the signature of the callback function
   245  // expected by the IterateWithCallback method, which in turn is used to iterate
   246  // all the keys/values of an egress policy map.
   247  type EgressPolicyIterateCallback func(*EgressPolicyKey4, *EgressPolicyVal4)
   248  
   249  // IterateWithCallback iterates through all the keys/values of an egress policy
   250  // map, passing each key/value pair to the cb callback.
   251  func (m policyMap) IterateWithCallback(cb EgressPolicyIterateCallback) error {
   252  	return m.m.DumpWithCallback(func(k bpf.MapKey, v bpf.MapValue) {
   253  		key := k.(*EgressPolicyKey4)
   254  		value := v.(*EgressPolicyVal4)
   255  
   256  		cb(key, value)
   257  	})
   258  }