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 }