github.com/cilium/cilium@v1.16.2/pkg/datapath/linux/config/config.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package config 5 6 import ( 7 "bufio" 8 "bytes" 9 "encoding/base64" 10 "encoding/json" 11 "errors" 12 "fmt" 13 "io" 14 "log/slog" 15 "net" 16 "net/netip" 17 "slices" 18 "sort" 19 "strconv" 20 "strings" 21 "text/template" 22 23 "github.com/vishvananda/netlink" 24 25 "github.com/cilium/cilium/pkg/bpf" 26 "github.com/cilium/cilium/pkg/byteorder" 27 "github.com/cilium/cilium/pkg/cidr" 28 "github.com/cilium/cilium/pkg/datapath/link" 29 dpdef "github.com/cilium/cilium/pkg/datapath/linux/config/defines" 30 "github.com/cilium/cilium/pkg/datapath/linux/sysctl" 31 datapathOption "github.com/cilium/cilium/pkg/datapath/option" 32 "github.com/cilium/cilium/pkg/datapath/tables" 33 datapath "github.com/cilium/cilium/pkg/datapath/types" 34 "github.com/cilium/cilium/pkg/defaults" 35 "github.com/cilium/cilium/pkg/identity" 36 "github.com/cilium/cilium/pkg/labels" 37 "github.com/cilium/cilium/pkg/mac" 38 "github.com/cilium/cilium/pkg/maglev" 39 "github.com/cilium/cilium/pkg/maps/authmap" 40 "github.com/cilium/cilium/pkg/maps/callsmap" 41 "github.com/cilium/cilium/pkg/maps/configmap" 42 "github.com/cilium/cilium/pkg/maps/ctmap" 43 "github.com/cilium/cilium/pkg/maps/encrypt" 44 "github.com/cilium/cilium/pkg/maps/eventsmap" 45 "github.com/cilium/cilium/pkg/maps/fragmap" 46 ipcachemap "github.com/cilium/cilium/pkg/maps/ipcache" 47 "github.com/cilium/cilium/pkg/maps/ipmasq" 48 "github.com/cilium/cilium/pkg/maps/l2respondermap" 49 "github.com/cilium/cilium/pkg/maps/lbmap" 50 "github.com/cilium/cilium/pkg/maps/lxcmap" 51 "github.com/cilium/cilium/pkg/maps/metricsmap" 52 "github.com/cilium/cilium/pkg/maps/nat" 53 "github.com/cilium/cilium/pkg/maps/neighborsmap" 54 "github.com/cilium/cilium/pkg/maps/nodemap" 55 "github.com/cilium/cilium/pkg/maps/policymap" 56 "github.com/cilium/cilium/pkg/maps/recorder" 57 "github.com/cilium/cilium/pkg/maps/signalmap" 58 "github.com/cilium/cilium/pkg/maps/tunnel" 59 "github.com/cilium/cilium/pkg/maps/vtep" 60 "github.com/cilium/cilium/pkg/maps/worldcidrsmap" 61 "github.com/cilium/cilium/pkg/netns" 62 "github.com/cilium/cilium/pkg/option" 63 wgtypes "github.com/cilium/cilium/pkg/wireguard/types" 64 ) 65 66 const NodePortMaxNAT = 65535 67 68 // HeaderfileWriter is a wrapper type which implements datapath.ConfigWriter. 69 // It manages writing of configuration of datapath program headerfiles. 70 type HeaderfileWriter struct { 71 log *slog.Logger 72 nodeMap nodemap.MapV2 73 nodeAddressing datapath.NodeAddressing 74 nodeExtraDefines dpdef.Map 75 nodeExtraDefineFns []dpdef.Fn 76 sysctl sysctl.Sysctl 77 } 78 79 func NewHeaderfileWriter(p WriterParams) (datapath.ConfigWriter, error) { 80 merged := make(dpdef.Map) 81 for _, defines := range p.NodeExtraDefines { 82 if err := merged.Merge(defines); err != nil { 83 return nil, err 84 } 85 } 86 return &HeaderfileWriter{ 87 nodeMap: p.NodeMap, 88 nodeAddressing: p.NodeAddressing, 89 nodeExtraDefines: merged, 90 nodeExtraDefineFns: p.NodeExtraDefineFns, 91 log: p.Log, 92 sysctl: p.Sysctl, 93 }, nil 94 } 95 96 func writeIncludes(w io.Writer) (int, error) { 97 return fmt.Fprintf(w, "#include \"lib/utils.h\"\n\n") 98 } 99 100 // WriteNodeConfig writes the local node configuration to the specified writer. 101 func (h *HeaderfileWriter) WriteNodeConfig(w io.Writer, cfg *datapath.LocalNodeConfiguration) error { 102 extraMacrosMap := make(dpdef.Map) 103 cDefinesMap := make(dpdef.Map) 104 105 nativeDevices := cfg.Devices 106 107 fw := bufio.NewWriter(w) 108 109 writeIncludes(w) 110 111 routerIP := cfg.CiliumInternalIPv6 112 hostIP := cfg.NodeIPv6 113 114 var ipv4NodePortAddrs, ipv6NodePortAddrs []netip.Addr 115 for _, addr := range cfg.NodeAddresses { 116 if !addr.NodePort { 117 continue 118 } 119 if addr.Addr.Is4() { 120 ipv4NodePortAddrs = append(ipv4NodePortAddrs, addr.Addr) 121 } else { 122 ipv6NodePortAddrs = append(ipv6NodePortAddrs, addr.Addr) 123 } 124 } 125 126 fmt.Fprintf(fw, "/*\n") 127 if option.Config.EnableIPv6 { 128 fmt.Fprintf(fw, " cilium.v6.external.str %s\n", cfg.NodeIPv6.String()) 129 fmt.Fprintf(fw, " cilium.v6.internal.str %s\n", cfg.CiliumInternalIPv6.String()) 130 fmt.Fprintf(fw, " cilium.v6.nodeport.str %v\n", ipv6NodePortAddrs) 131 fmt.Fprintf(fw, "\n") 132 } 133 fmt.Fprintf(fw, " cilium.v4.external.str %s\n", cfg.NodeIPv4.String()) 134 fmt.Fprintf(fw, " cilium.v4.internal.str %s\n", cfg.CiliumInternalIPv4.String()) 135 fmt.Fprintf(fw, " cilium.v4.nodeport.str %v\n", ipv4NodePortAddrs) 136 fmt.Fprintf(fw, "\n") 137 if option.Config.EnableIPv6 { 138 fw.WriteString(dumpRaw(defaults.RestoreV6Addr, cfg.CiliumInternalIPv6)) 139 } 140 fw.WriteString(dumpRaw(defaults.RestoreV4Addr, cfg.CiliumInternalIPv4)) 141 fmt.Fprintf(fw, " */\n\n") 142 143 cDefinesMap["KERNEL_HZ"] = fmt.Sprintf("%d", option.Config.KernelHz) 144 145 if option.Config.EnableIPv6 { 146 extraMacrosMap["ROUTER_IP"] = routerIP.String() 147 fw.WriteString(defineIPv6("ROUTER_IP", routerIP)) 148 } 149 150 if option.Config.EnableIPv4 { 151 ipv4GW := cfg.CiliumInternalIPv4 152 loopbackIPv4 := cfg.LoopbackIPv4 153 ipv4Range := cfg.AllocCIDRIPv4 154 cDefinesMap["IPV4_GATEWAY"] = fmt.Sprintf("%#x", byteorder.NetIPv4ToHost32(ipv4GW)) 155 cDefinesMap["IPV4_LOOPBACK"] = fmt.Sprintf("%#x", byteorder.NetIPv4ToHost32(loopbackIPv4)) 156 cDefinesMap["IPV4_MASK"] = fmt.Sprintf("%#x", byteorder.NetIPv4ToHost32(net.IP(ipv4Range.Mask))) 157 158 if option.Config.EnableIPv4FragmentsTracking { 159 cDefinesMap["ENABLE_IPV4_FRAGMENTS"] = "1" 160 cDefinesMap["IPV4_FRAG_DATAGRAMS_MAP"] = fragmap.MapName 161 cDefinesMap["CILIUM_IPV4_FRAG_MAP_MAX_ENTRIES"] = fmt.Sprintf("%d", option.Config.FragmentsMapEntries) 162 } 163 } 164 165 if option.Config.EnableIPv6 { 166 extraMacrosMap["HOST_IP"] = hostIP.String() 167 fw.WriteString(defineIPv6("HOST_IP", hostIP)) 168 } 169 170 cDefinesMap["UNKNOWN_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameUnknown)) 171 cDefinesMap["HOST_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameHost)) 172 cDefinesMap["WORLD_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameWorld)) 173 if option.Config.IsDualStack() { 174 cDefinesMap["WORLD_IPV4_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameWorldIPv4)) 175 cDefinesMap["WORLD_IPV6_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameWorldIPv6)) 176 } else { 177 worldID := identity.GetReservedID(labels.IDNameWorld) 178 cDefinesMap["WORLD_IPV4_ID"] = fmt.Sprintf("%d", worldID) 179 cDefinesMap["WORLD_IPV6_ID"] = fmt.Sprintf("%d", worldID) 180 } 181 cDefinesMap["HEALTH_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameHealth)) 182 cDefinesMap["UNMANAGED_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameUnmanaged)) 183 cDefinesMap["INIT_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameInit)) 184 cDefinesMap["LOCAL_NODE_ID"] = fmt.Sprintf("%d", identity.GetLocalNodeID()) 185 cDefinesMap["REMOTE_NODE_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameRemoteNode)) 186 cDefinesMap["KUBE_APISERVER_NODE_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameKubeAPIServer)) 187 cDefinesMap["ENCRYPTED_OVERLAY_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameEncryptedOverlay)) 188 cDefinesMap["CILIUM_LB_SERVICE_MAP_MAX_ENTRIES"] = fmt.Sprintf("%d", lbmap.ServiceMapMaxEntries) 189 cDefinesMap["CILIUM_LB_BACKENDS_MAP_MAX_ENTRIES"] = fmt.Sprintf("%d", lbmap.ServiceBackEndMapMaxEntries) 190 cDefinesMap["CILIUM_LB_REV_NAT_MAP_MAX_ENTRIES"] = fmt.Sprintf("%d", lbmap.RevNatMapMaxEntries) 191 cDefinesMap["CILIUM_LB_AFFINITY_MAP_MAX_ENTRIES"] = fmt.Sprintf("%d", lbmap.AffinityMapMaxEntries) 192 cDefinesMap["CILIUM_LB_SOURCE_RANGE_MAP_MAX_ENTRIES"] = fmt.Sprintf("%d", lbmap.SourceRangeMapMaxEntries) 193 cDefinesMap["CILIUM_LB_MAGLEV_MAP_MAX_ENTRIES"] = fmt.Sprintf("%d", lbmap.MaglevMapMaxEntries) 194 cDefinesMap["CILIUM_LB_SKIP_MAP_MAX_ENTRIES"] = fmt.Sprintf("%d", lbmap.SkipLBMapMaxEntries) 195 196 cDefinesMap["TUNNEL_MAP"] = tunnel.MapName 197 cDefinesMap["TUNNEL_ENDPOINT_MAP_SIZE"] = fmt.Sprintf("%d", tunnel.MaxEntries) 198 cDefinesMap["ENDPOINTS_MAP"] = lxcmap.MapName 199 cDefinesMap["ENDPOINTS_MAP_SIZE"] = fmt.Sprintf("%d", lxcmap.MaxEntries) 200 cDefinesMap["METRICS_MAP"] = metricsmap.MapName 201 cDefinesMap["METRICS_MAP_SIZE"] = fmt.Sprintf("%d", metricsmap.MaxEntries) 202 cDefinesMap["POLICY_MAP_SIZE"] = fmt.Sprintf("%d", policymap.MaxEntries) 203 cDefinesMap["AUTH_MAP"] = authmap.MapName 204 cDefinesMap["AUTH_MAP_SIZE"] = fmt.Sprintf("%d", option.Config.AuthMapEntries) 205 cDefinesMap["CONFIG_MAP"] = configmap.MapName 206 cDefinesMap["CONFIG_MAP_SIZE"] = fmt.Sprintf("%d", configmap.MaxEntries) 207 cDefinesMap["IPCACHE_MAP"] = ipcachemap.Name 208 cDefinesMap["IPCACHE_MAP_SIZE"] = fmt.Sprintf("%d", ipcachemap.MaxEntries) 209 cDefinesMap["NODE_MAP"] = nodemap.MapName 210 cDefinesMap["NODE_MAP_V2"] = nodemap.MapNameV2 211 cDefinesMap["NODE_MAP_SIZE"] = fmt.Sprintf("%d", h.nodeMap.Size()) 212 cDefinesMap["WORLD_CIDRS4_MAP"] = worldcidrsmap.MapName4 213 cDefinesMap["WORLD_CIDRS4_MAP_SIZE"] = fmt.Sprintf("%d", worldcidrsmap.MapMaxEntries) 214 cDefinesMap["POLICY_PROG_MAP_SIZE"] = fmt.Sprintf("%d", policymap.PolicyCallMaxEntries) 215 cDefinesMap["L2_RESPONSER_MAP4_SIZE"] = fmt.Sprintf("%d", l2respondermap.DefaultMaxEntries) 216 217 if option.Config.EnableIPSec { 218 cDefinesMap["ENCRYPT_MAP"] = encrypt.MapName 219 } 220 221 cDefinesMap["L2_RESPONDER_MAP4"] = l2respondermap.MapName 222 cDefinesMap["CT_CONNECTION_LIFETIME_TCP"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutTCP.Seconds())) 223 cDefinesMap["CT_CONNECTION_LIFETIME_NONTCP"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutAny.Seconds())) 224 cDefinesMap["CT_SERVICE_LIFETIME_TCP"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutSVCTCP.Seconds())) 225 cDefinesMap["CT_SERVICE_LIFETIME_NONTCP"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutSVCAny.Seconds())) 226 cDefinesMap["CT_SERVICE_CLOSE_REBALANCE"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutSVCTCPGrace.Seconds())) 227 cDefinesMap["CT_SYN_TIMEOUT"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutSYN.Seconds())) 228 cDefinesMap["CT_CLOSE_TIMEOUT"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutFIN.Seconds())) 229 cDefinesMap["CT_REPORT_INTERVAL"] = fmt.Sprintf("%d", int64(option.Config.MonitorAggregationInterval.Seconds())) 230 cDefinesMap["CT_REPORT_FLAGS"] = fmt.Sprintf("%#04x", int64(option.Config.MonitorAggregationFlags)) 231 cDefinesMap["RATELIMIT_MAP"] = "cilium_ratelimit" 232 cDefinesMap["CT_TAIL_CALL_BUFFER4"] = "cilium_tail_call_buffer4" 233 cDefinesMap["CT_TAIL_CALL_BUFFER6"] = "cilium_tail_call_buffer6" 234 cDefinesMap["PER_CLUSTER_CT_TCP4"] = "cilium_per_cluster_ct_tcp4" 235 cDefinesMap["PER_CLUSTER_CT_TCP6"] = "cilium_per_cluster_ct_tcp6" 236 cDefinesMap["PER_CLUSTER_CT_ANY4"] = "cilium_per_cluster_ct_any4" 237 cDefinesMap["PER_CLUSTER_CT_ANY6"] = "cilium_per_cluster_ct_any6" 238 cDefinesMap["PER_CLUSTER_SNAT_MAPPING_IPV4"] = "cilium_per_cluster_snat_v4_external" 239 cDefinesMap["PER_CLUSTER_SNAT_MAPPING_IPV6"] = "cilium_per_cluster_snat_v6_external" 240 241 if option.Config.PreAllocateMaps { 242 cDefinesMap["PREALLOCATE_MAPS"] = "1" 243 } 244 245 cDefinesMap["EVENTS_MAP"] = eventsmap.MapName 246 cDefinesMap["SIGNAL_MAP"] = signalmap.MapName 247 cDefinesMap["POLICY_CALL_MAP"] = policymap.PolicyCallMapName 248 if option.Config.EnableEnvoyConfig { 249 cDefinesMap["POLICY_EGRESSCALL_MAP"] = policymap.PolicyEgressCallMapName 250 } 251 cDefinesMap["LB6_REVERSE_NAT_MAP"] = "cilium_lb6_reverse_nat" 252 cDefinesMap["LB6_SERVICES_MAP_V2"] = "cilium_lb6_services_v2" 253 cDefinesMap["LB6_BACKEND_MAP"] = "cilium_lb6_backends_v3" 254 cDefinesMap["LB6_REVERSE_NAT_SK_MAP"] = lbmap.SockRevNat6MapName 255 cDefinesMap["LB6_REVERSE_NAT_SK_MAP_SIZE"] = fmt.Sprintf("%d", lbmap.MaxSockRevNat6MapEntries) 256 cDefinesMap["LB4_REVERSE_NAT_MAP"] = "cilium_lb4_reverse_nat" 257 cDefinesMap["LB4_SERVICES_MAP_V2"] = "cilium_lb4_services_v2" 258 cDefinesMap["LB4_BACKEND_MAP"] = "cilium_lb4_backends_v3" 259 cDefinesMap["LB4_REVERSE_NAT_SK_MAP"] = lbmap.SockRevNat4MapName 260 cDefinesMap["LB4_REVERSE_NAT_SK_MAP_SIZE"] = fmt.Sprintf("%d", lbmap.MaxSockRevNat4MapEntries) 261 cDefinesMap["LB4_SKIP_MAP"] = lbmap.SkipLB4MapName 262 cDefinesMap["LB6_SKIP_MAP"] = lbmap.SkipLB6MapName 263 264 if option.Config.EnableSessionAffinity { 265 cDefinesMap["ENABLE_SESSION_AFFINITY"] = "1" 266 cDefinesMap["LB_AFFINITY_MATCH_MAP"] = lbmap.AffinityMatchMapName 267 if option.Config.EnableIPv4 { 268 cDefinesMap["LB4_AFFINITY_MAP"] = lbmap.Affinity4MapName 269 } 270 if option.Config.EnableIPv6 { 271 cDefinesMap["LB6_AFFINITY_MAP"] = lbmap.Affinity6MapName 272 } 273 } 274 275 cDefinesMap["TRACE_PAYLOAD_LEN"] = fmt.Sprintf("%dULL", option.Config.TracePayloadlen) 276 cDefinesMap["MTU"] = fmt.Sprintf("%d", cfg.DeviceMTU) 277 278 if option.Config.EnableIPv4 { 279 cDefinesMap["ENABLE_IPV4"] = "1" 280 } 281 282 if option.Config.EnableIPv6 { 283 cDefinesMap["ENABLE_IPV6"] = "1" 284 } 285 286 if option.Config.EnableSRv6 { 287 cDefinesMap["ENABLE_SRV6"] = "1" 288 if option.Config.SRv6EncapMode != "reduced" { 289 cDefinesMap["ENABLE_SRV6_SRH_ENCAP"] = "1" 290 } 291 } 292 293 if option.Config.EnableSCTP { 294 cDefinesMap["ENABLE_SCTP"] = "1" 295 } 296 297 if option.Config.EnableIPSec { 298 cDefinesMap["ENABLE_IPSEC"] = "1" 299 300 if option.Config.EnableIPSecEncryptedOverlay { 301 cDefinesMap["ENABLE_ENCRYPTED_OVERLAY"] = "1" 302 } 303 } 304 305 if option.Config.EnableWireguard { 306 cDefinesMap["ENABLE_WIREGUARD"] = "1" 307 ifindex, err := link.GetIfIndex(wgtypes.IfaceName) 308 if err != nil { 309 return err 310 } 311 cDefinesMap["WG_IFINDEX"] = fmt.Sprintf("%d", ifindex) 312 313 if option.Config.EncryptNode { 314 cDefinesMap["ENABLE_NODE_ENCRYPTION"] = "1" 315 } 316 } 317 318 if option.Config.ServiceNoBackendResponse == option.ServiceNoBackendResponseReject { 319 cDefinesMap["SERVICE_NO_BACKEND_RESPONSE"] = "1" 320 } 321 322 if option.Config.EnableL2Announcements { 323 cDefinesMap["ENABLE_L2_ANNOUNCEMENTS"] = "1" 324 // If the agent is down for longer than the lease duration, stop responding 325 cDefinesMap["L2_ANNOUNCEMENTS_MAX_LIVENESS"] = fmt.Sprintf("%dULL", option.Config.L2AnnouncerLeaseDuration.Nanoseconds()) 326 } 327 328 if option.Config.EnableEncryptionStrictMode { 329 cDefinesMap["ENCRYPTION_STRICT_MODE"] = "1" 330 331 // when parsing the user input we only accept ipv4 addresses 332 cDefinesMap["STRICT_IPV4_NET"] = fmt.Sprintf("%#x", byteorder.NetIPAddrToHost32(option.Config.EncryptionStrictModeCIDR.Addr())) 333 cDefinesMap["STRICT_IPV4_NET_SIZE"] = fmt.Sprintf("%d", option.Config.EncryptionStrictModeCIDR.Bits()) 334 335 cDefinesMap["IPV4_ENCRYPT_IFACE"] = fmt.Sprintf("%#x", byteorder.NetIPv4ToHost32(cfg.NodeIPv4)) 336 337 ipv4Interface, ok := netip.AddrFromSlice(cfg.NodeIPv4.To4()) 338 if !ok { 339 return fmt.Errorf("unable to parse node IPv4 address %s", cfg.NodeIPv4) 340 } 341 342 if option.Config.EncryptionStrictModeCIDR.Contains(ipv4Interface) { 343 if !option.Config.EncryptionStrictModeAllowRemoteNodeIdentities { 344 return fmt.Errorf(`encryption strict mode is enabled but the node's IPv4 address is within the strict CIDR range. 345 This will cause the node to drop all traffic. 346 Please either disable encryption or set --encryption-strict-mode-allow-dynamic-lookup=true`) 347 } 348 cDefinesMap["STRICT_IPV4_OVERLAPPING_CIDR"] = "1" 349 } 350 } 351 352 if option.Config.EnableBPFTProxy { 353 cDefinesMap["ENABLE_TPROXY"] = "1" 354 } 355 356 if option.Config.EnableXDPPrefilter { 357 cDefinesMap["ENABLE_PREFILTER"] = "1" 358 } 359 360 if option.Config.EnableEndpointRoutes { 361 cDefinesMap["ENABLE_ENDPOINT_ROUTES"] = "1" 362 } 363 364 if option.Config.EnableEnvoyConfig { 365 cDefinesMap["ENABLE_L7_LB"] = "1" 366 } 367 368 if option.Config.EnableSocketLB { 369 if option.Config.BPFSocketLBHostnsOnly { 370 cDefinesMap["ENABLE_SOCKET_LB_HOST_ONLY"] = "1" 371 } else { 372 cDefinesMap["ENABLE_SOCKET_LB_FULL"] = "1" 373 } 374 if option.Config.EnableSocketLBPeer { 375 cDefinesMap["ENABLE_SOCKET_LB_PEER"] = "1" 376 } 377 if option.Config.EnableSocketLBTracing { 378 cDefinesMap["TRACE_SOCK_NOTIFY"] = "1" 379 } 380 381 if cookie, err := netns.GetNetNSCookie(); err == nil { 382 // When running in nested environments (e.g. Kind), cilium-agent does 383 // not run in the host netns. So, in such cases the cookie comparison 384 // based on bpf_get_netns_cookie(NULL) for checking whether a socket 385 // belongs to a host netns does not work. 386 // 387 // To fix this, we derive the cookie of the netns in which cilium-agent 388 // runs via getsockopt(...SO_NETNS_COOKIE...) and then use it in the 389 // check above. This is based on an assumption that cilium-agent 390 // always runs with "hostNetwork: true". 391 cDefinesMap["HOST_NETNS_COOKIE"] = fmt.Sprintf("%d", cookie) 392 } 393 394 if option.Config.EnableLocalRedirectPolicy { 395 cDefinesMap["ENABLE_LOCAL_REDIRECT_POLICY"] = "1" 396 } 397 } 398 399 cDefinesMap["NAT_46X64_PREFIX_0"] = "0" 400 cDefinesMap["NAT_46X64_PREFIX_1"] = "0" 401 cDefinesMap["NAT_46X64_PREFIX_2"] = "0" 402 cDefinesMap["NAT_46X64_PREFIX_3"] = "0" 403 404 if option.Config.EnableNodePort { 405 if option.Config.EnableHealthDatapath { 406 cDefinesMap["ENABLE_HEALTH_CHECK"] = "1" 407 } 408 if option.Config.EnableMKE && option.Config.EnableSocketLB { 409 cDefinesMap["ENABLE_MKE"] = "1" 410 cDefinesMap["MKE_HOST"] = fmt.Sprintf("%d", option.HostExtensionMKE) 411 } 412 if option.Config.EnableRecorder { 413 cDefinesMap["ENABLE_CAPTURE"] = "1" 414 if option.Config.EnableIPv4 { 415 cDefinesMap["CAPTURE4_RULES"] = recorder.MapNameWcard4 416 cDefinesMap["CAPTURE4_SIZE"] = fmt.Sprintf("%d", recorder.MapSize) 417 } 418 if option.Config.EnableIPv6 { 419 cDefinesMap["CAPTURE6_RULES"] = recorder.MapNameWcard6 420 cDefinesMap["CAPTURE6_SIZE"] = fmt.Sprintf("%d", recorder.MapSize) 421 } 422 } 423 cDefinesMap["ENABLE_NODEPORT"] = "1" 424 if option.Config.EnableIPv4 { 425 cDefinesMap["NODEPORT_NEIGH4"] = neighborsmap.Map4Name 426 cDefinesMap["NODEPORT_NEIGH4_SIZE"] = fmt.Sprintf("%d", option.Config.NeighMapEntriesGlobal) 427 if option.Config.EnableHealthDatapath { 428 cDefinesMap["LB4_HEALTH_MAP"] = lbmap.HealthProbe4MapName 429 } 430 } 431 if option.Config.EnableIPv6 { 432 cDefinesMap["NODEPORT_NEIGH6"] = neighborsmap.Map6Name 433 cDefinesMap["NODEPORT_NEIGH6_SIZE"] = fmt.Sprintf("%d", option.Config.NeighMapEntriesGlobal) 434 if option.Config.EnableHealthDatapath { 435 cDefinesMap["LB6_HEALTH_MAP"] = lbmap.HealthProbe6MapName 436 } 437 } 438 if option.Config.EnableNat46X64Gateway { 439 cDefinesMap["ENABLE_NAT_46X64_GATEWAY"] = "1" 440 base := option.Config.IPv6NAT46x64CIDRBase.AsSlice() 441 cDefinesMap["NAT_46X64_PREFIX_0"] = fmt.Sprintf("%d", base[0]) 442 cDefinesMap["NAT_46X64_PREFIX_1"] = fmt.Sprintf("%d", base[1]) 443 cDefinesMap["NAT_46X64_PREFIX_2"] = fmt.Sprintf("%d", base[2]) 444 cDefinesMap["NAT_46X64_PREFIX_3"] = fmt.Sprintf("%d", base[3]) 445 } 446 if option.Config.NodePortNat46X64 { 447 cDefinesMap["ENABLE_NAT_46X64"] = "1" 448 } 449 const ( 450 dsrEncapInv = iota 451 dsrEncapNone 452 dsrEncapIPIP 453 dsrEncapGeneve 454 ) 455 const ( 456 dsrL4XlateInv = iota 457 dsrL4XlateFrontend 458 dsrL4XlateBackend 459 ) 460 cDefinesMap["DSR_ENCAP_IPIP"] = fmt.Sprintf("%d", dsrEncapIPIP) 461 cDefinesMap["DSR_ENCAP_GENEVE"] = fmt.Sprintf("%d", dsrEncapGeneve) 462 cDefinesMap["DSR_ENCAP_NONE"] = fmt.Sprintf("%d", dsrEncapNone) 463 cDefinesMap["DSR_XLATE_FRONTEND"] = fmt.Sprintf("%d", dsrL4XlateFrontend) 464 cDefinesMap["DSR_XLATE_BACKEND"] = fmt.Sprintf("%d", dsrL4XlateBackend) 465 if option.Config.LoadBalancerUsesDSR() { 466 cDefinesMap["ENABLE_DSR"] = "1" 467 if option.Config.EnablePMTUDiscovery { 468 cDefinesMap["ENABLE_DSR_ICMP_ERRORS"] = "1" 469 } 470 if option.Config.NodePortMode == option.NodePortModeHybrid { 471 cDefinesMap["ENABLE_DSR_HYBRID"] = "1" 472 } 473 if option.Config.LoadBalancerDSRDispatch == option.DSRDispatchOption { 474 cDefinesMap["DSR_ENCAP_MODE"] = fmt.Sprintf("%d", dsrEncapNone) 475 } else if option.Config.LoadBalancerDSRDispatch == option.DSRDispatchIPIP { 476 cDefinesMap["DSR_ENCAP_MODE"] = fmt.Sprintf("%d", dsrEncapIPIP) 477 } else if option.Config.LoadBalancerDSRDispatch == option.DSRDispatchGeneve { 478 cDefinesMap["DSR_ENCAP_MODE"] = fmt.Sprintf("%d", dsrEncapGeneve) 479 } 480 if option.Config.LoadBalancerDSRDispatch == option.DSRDispatchIPIP { 481 if option.Config.LoadBalancerDSRL4Xlate == option.DSRL4XlateFrontend { 482 cDefinesMap["DSR_XLATE_MODE"] = fmt.Sprintf("%d", dsrL4XlateFrontend) 483 } else if option.Config.LoadBalancerDSRL4Xlate == option.DSRL4XlateBackend { 484 cDefinesMap["DSR_XLATE_MODE"] = fmt.Sprintf("%d", dsrL4XlateBackend) 485 } 486 } else { 487 cDefinesMap["DSR_XLATE_MODE"] = fmt.Sprintf("%d", dsrL4XlateInv) 488 } 489 } else { 490 cDefinesMap["DSR_ENCAP_MODE"] = fmt.Sprintf("%d", dsrEncapInv) 491 cDefinesMap["DSR_XLATE_MODE"] = fmt.Sprintf("%d", dsrL4XlateInv) 492 } 493 if option.Config.EnableIPv4 { 494 if option.Config.LoadBalancerRSSv4CIDR != "" { 495 ipv4 := byteorder.NetIPv4ToHost32(option.Config.LoadBalancerRSSv4.IP) 496 ones, _ := option.Config.LoadBalancerRSSv4.Mask.Size() 497 cDefinesMap["IPV4_RSS_PREFIX"] = fmt.Sprintf("%d", ipv4) 498 cDefinesMap["IPV4_RSS_PREFIX_BITS"] = fmt.Sprintf("%d", ones) 499 } else { 500 cDefinesMap["IPV4_RSS_PREFIX"] = "IPV4_DIRECT_ROUTING" 501 cDefinesMap["IPV4_RSS_PREFIX_BITS"] = "32" 502 } 503 } 504 if option.Config.EnableIPv6 { 505 if option.Config.LoadBalancerRSSv6CIDR != "" { 506 ipv6 := option.Config.LoadBalancerRSSv6.IP 507 ones, _ := option.Config.LoadBalancerRSSv6.Mask.Size() 508 extraMacrosMap["IPV6_RSS_PREFIX"] = ipv6.String() 509 fw.WriteString(FmtDefineAddress("IPV6_RSS_PREFIX", ipv6)) 510 cDefinesMap["IPV6_RSS_PREFIX_BITS"] = fmt.Sprintf("%d", ones) 511 } else { 512 cDefinesMap["IPV6_RSS_PREFIX"] = "IPV6_DIRECT_ROUTING" 513 cDefinesMap["IPV6_RSS_PREFIX_BITS"] = "128" 514 } 515 } 516 if option.Config.NodePortAcceleration != option.NodePortAccelerationDisabled { 517 cDefinesMap["ENABLE_NODEPORT_ACCELERATION"] = "1" 518 } 519 if !option.Config.EnableHostLegacyRouting { 520 cDefinesMap["ENABLE_HOST_ROUTING"] = "1" 521 } 522 if option.Config.EnableSVCSourceRangeCheck { 523 cDefinesMap["ENABLE_SRC_RANGE_CHECK"] = "1" 524 if option.Config.EnableIPv4 { 525 cDefinesMap["LB4_SRC_RANGE_MAP"] = lbmap.SourceRange4MapName 526 cDefinesMap["LB4_SRC_RANGE_MAP_SIZE"] = 527 fmt.Sprintf("%d", lbmap.SourceRange4Map.MaxEntries()) 528 } 529 if option.Config.EnableIPv6 { 530 cDefinesMap["LB6_SRC_RANGE_MAP"] = lbmap.SourceRange6MapName 531 cDefinesMap["LB6_SRC_RANGE_MAP_SIZE"] = 532 fmt.Sprintf("%d", lbmap.SourceRange6Map.MaxEntries()) 533 } 534 } 535 536 cDefinesMap["NODEPORT_PORT_MIN"] = fmt.Sprintf("%d", option.Config.NodePortMin) 537 cDefinesMap["NODEPORT_PORT_MAX"] = fmt.Sprintf("%d", option.Config.NodePortMax) 538 cDefinesMap["NODEPORT_PORT_MIN_NAT"] = fmt.Sprintf("%d", option.Config.NodePortMax+1) 539 cDefinesMap["NODEPORT_PORT_MAX_NAT"] = strconv.Itoa(NodePortMaxNAT) 540 } 541 542 macByIfIndexMacro, isL3DevMacro, err := devMacros(nativeDevices) 543 if err != nil { 544 return err 545 } 546 cDefinesMap["NATIVE_DEV_MAC_BY_IFINDEX(IFINDEX)"] = macByIfIndexMacro 547 cDefinesMap["IS_L3_DEV(ifindex)"] = isL3DevMacro 548 549 const ( 550 selectionRandom = iota + 1 551 selectionMaglev 552 ) 553 cDefinesMap["LB_SELECTION_RANDOM"] = fmt.Sprintf("%d", selectionRandom) 554 cDefinesMap["LB_SELECTION_MAGLEV"] = fmt.Sprintf("%d", selectionMaglev) 555 if option.Config.NodePortAlg == option.NodePortAlgRandom { 556 cDefinesMap["LB_SELECTION"] = fmt.Sprintf("%d", selectionRandom) 557 } else if option.Config.NodePortAlg == option.NodePortAlgMaglev { 558 cDefinesMap["LB_SELECTION"] = fmt.Sprintf("%d", selectionMaglev) 559 cDefinesMap["LB_MAGLEV_LUT_SIZE"] = fmt.Sprintf("%d", option.Config.MaglevTableSize) 560 if option.Config.EnableIPv6 { 561 cDefinesMap["LB6_MAGLEV_MAP_OUTER"] = lbmap.MaglevOuter6MapName 562 } 563 if option.Config.EnableIPv4 { 564 cDefinesMap["LB4_MAGLEV_MAP_OUTER"] = lbmap.MaglevOuter4MapName 565 } 566 } 567 cDefinesMap["HASH_INIT4_SEED"] = fmt.Sprintf("%d", maglev.SeedJhash0) 568 cDefinesMap["HASH_INIT6_SEED"] = fmt.Sprintf("%d", maglev.SeedJhash1) 569 570 if option.Config.DirectRoutingDeviceRequired() { 571 if option.Config.EnableIPv4 { 572 ifindex, ip, ok := h.nodeAddressing.IPv4().DirectRouting() 573 if !ok { 574 return fmt.Errorf("IPv4 direct routing device not found") 575 } 576 ipv4 := byteorder.NetIPv4ToHost32(ip) 577 cDefinesMap["IPV4_DIRECT_ROUTING"] = fmt.Sprintf("%d", ipv4) 578 cDefinesMap["DIRECT_ROUTING_DEV_IFINDEX"] = fmt.Sprintf("%d", ifindex) 579 } 580 if option.Config.EnableIPv6 { 581 ifindex, ip, ok := h.nodeAddressing.IPv6().DirectRouting() 582 if !ok { 583 return fmt.Errorf("IPv6 direct routing device not found") 584 } 585 extraMacrosMap["IPV6_DIRECT_ROUTING"] = ip.String() 586 fw.WriteString(FmtDefineAddress("IPV6_DIRECT_ROUTING", ip)) 587 cDefinesMap["DIRECT_ROUTING_DEV_IFINDEX"] = fmt.Sprintf("%d", ifindex) 588 } 589 } else { 590 var directRoutingIPv6 net.IP 591 cDefinesMap["DIRECT_ROUTING_DEV_IFINDEX"] = "0" 592 if option.Config.EnableIPv4 { 593 cDefinesMap["IPV4_DIRECT_ROUTING"] = "0" 594 } 595 if option.Config.EnableIPv6 { 596 extraMacrosMap["IPV6_DIRECT_ROUTING"] = directRoutingIPv6.String() 597 fw.WriteString(FmtDefineAddress("IPV6_DIRECT_ROUTING", directRoutingIPv6)) 598 } 599 } 600 601 if option.Config.EnableHostFirewall { 602 cDefinesMap["ENABLE_HOST_FIREWALL"] = "1" 603 } 604 605 if option.Config.EnableIPSec { 606 nodeAddress := cfg.NodeIPv4 607 if nodeAddress == nil { 608 return errors.New("external IPv4 node address is required when IPSec is enabled, but none found") 609 } 610 611 a := byteorder.NetIPv4ToHost32(nodeAddress) 612 cDefinesMap["IPV4_ENCRYPT_IFACE"] = fmt.Sprintf("%d", a) 613 } 614 615 if option.Config.EnableNodePort { 616 if option.Config.EnableIPv4 { 617 cDefinesMap["SNAT_MAPPING_IPV4"] = nat.MapNameSnat4Global 618 cDefinesMap["SNAT_MAPPING_IPV4_SIZE"] = fmt.Sprintf("%d", option.Config.NATMapEntriesGlobal) 619 } 620 621 if option.Config.EnableIPv6 { 622 cDefinesMap["SNAT_MAPPING_IPV6"] = nat.MapNameSnat6Global 623 cDefinesMap["SNAT_MAPPING_IPV6_SIZE"] = fmt.Sprintf("%d", option.Config.NATMapEntriesGlobal) 624 } 625 626 if option.Config.EnableBPFMasquerade { 627 if option.Config.EnableIPv4Masquerade { 628 cDefinesMap["ENABLE_MASQUERADE_IPV4"] = "1" 629 630 // ip-masq-agent depends on bpf-masq 631 var excludeCIDR *cidr.CIDR 632 if option.Config.EnableIPMasqAgent { 633 cDefinesMap["ENABLE_IP_MASQ_AGENT_IPV4"] = "1" 634 cDefinesMap["IP_MASQ_AGENT_IPV4"] = ipmasq.MapNameIPv4 635 636 // native-routing-cidr is optional with ip-masq-agent and may be nil 637 excludeCIDR = option.Config.GetIPv4NativeRoutingCIDR() 638 } else { 639 excludeCIDR = datapath.RemoteSNATDstAddrExclusionCIDRv4() 640 } 641 642 if excludeCIDR != nil { 643 cDefinesMap["IPV4_SNAT_EXCLUSION_DST_CIDR"] = 644 fmt.Sprintf("%#x", byteorder.NetIPv4ToHost32(excludeCIDR.IP)) 645 ones, _ := excludeCIDR.Mask.Size() 646 cDefinesMap["IPV4_SNAT_EXCLUSION_DST_CIDR_LEN"] = fmt.Sprintf("%d", ones) 647 } 648 } 649 if option.Config.EnableIPv6Masquerade { 650 cDefinesMap["ENABLE_MASQUERADE_IPV6"] = "1" 651 652 var excludeCIDR *cidr.CIDR 653 if option.Config.EnableIPMasqAgent { 654 cDefinesMap["ENABLE_IP_MASQ_AGENT_IPV6"] = "1" 655 cDefinesMap["IP_MASQ_AGENT_IPV6"] = ipmasq.MapNameIPv6 656 657 excludeCIDR = option.Config.GetIPv6NativeRoutingCIDR() 658 } else { 659 excludeCIDR = datapath.RemoteSNATDstAddrExclusionCIDRv6() 660 } 661 662 if excludeCIDR != nil { 663 extraMacrosMap["IPV6_SNAT_EXCLUSION_DST_CIDR"] = excludeCIDR.IP.String() 664 fw.WriteString(FmtDefineAddress("IPV6_SNAT_EXCLUSION_DST_CIDR", excludeCIDR.IP)) 665 extraMacrosMap["IPV6_SNAT_EXCLUSION_DST_CIDR_MASK"] = excludeCIDR.Mask.String() 666 fw.WriteString(FmtDefineAddress("IPV6_SNAT_EXCLUSION_DST_CIDR_MASK", excludeCIDR.Mask)) 667 } 668 } 669 } 670 671 ctmap.WriteBPFMacros(fw, nil) 672 } 673 674 if option.Config.AllowICMPFragNeeded { 675 cDefinesMap["ALLOW_ICMP_FRAG_NEEDED"] = "1" 676 } 677 678 if option.Config.ClockSource == option.ClockSourceJiffies { 679 cDefinesMap["ENABLE_JIFFIES"] = "1" 680 } 681 682 if option.Config.EnableIdentityMark { 683 cDefinesMap["ENABLE_IDENTITY_MARK"] = "1" 684 } 685 686 if option.Config.EnableHighScaleIPcache { 687 cDefinesMap["ENABLE_HIGH_SCALE_IPCACHE"] = "1" 688 } 689 690 if option.Config.EnableCustomCalls { 691 cDefinesMap["ENABLE_CUSTOM_CALLS"] = "1" 692 } 693 694 if option.Config.EnableVTEP { 695 cDefinesMap["ENABLE_VTEP"] = "1" 696 cDefinesMap["VTEP_MAP"] = vtep.Name 697 cDefinesMap["VTEP_MAP_SIZE"] = fmt.Sprintf("%d", vtep.MaxEntries) 698 cDefinesMap["VTEP_MASK"] = fmt.Sprintf("%#x", byteorder.NetIPv4ToHost32(net.IP(option.Config.VtepCidrMask))) 699 700 } 701 702 vlanFilter, err := vlanFilterMacros(nativeDevices) 703 if err != nil { 704 return err 705 } 706 cDefinesMap["VLAN_FILTER(ifindex, vlan_id)"] = vlanFilter 707 708 if option.Config.DisableExternalIPMitigation { 709 cDefinesMap["DISABLE_EXTERNAL_IP_MITIGATION"] = "1" 710 } 711 712 if option.Config.EnableICMPRules { 713 cDefinesMap["ENABLE_ICMP_RULE"] = "1" 714 } 715 716 cDefinesMap["CIDR_IDENTITY_RANGE_START"] = fmt.Sprintf("%d", identity.MinLocalIdentity) 717 cDefinesMap["CIDR_IDENTITY_RANGE_END"] = fmt.Sprintf("%d", identity.MaxLocalIdentity) 718 719 if option.Config.TunnelingEnabled() { 720 cDefinesMap["TUNNEL_MODE"] = "1" 721 } 722 723 ciliumNetLink, err := netlink.LinkByName(defaults.SecondHostDevice) 724 if err != nil { 725 return fmt.Errorf("failed to look up link '%s': %w", defaults.SecondHostDevice, err) 726 } 727 cDefinesMap["CILIUM_NET_MAC"] = fmt.Sprintf("{.addr=%s}", mac.CArrayString(ciliumNetLink.Attrs().HardwareAddr)) 728 cDefinesMap["HOST_IFINDEX"] = fmt.Sprintf("%d", ciliumNetLink.Attrs().Index) 729 730 ciliumHostLink, err := netlink.LinkByName(defaults.HostDevice) 731 if err != nil { 732 return fmt.Errorf("failed to look up link '%s': %w", defaults.HostDevice, err) 733 } 734 cDefinesMap["HOST_IFINDEX_MAC"] = fmt.Sprintf("{.addr=%s}", mac.CArrayString(ciliumHostLink.Attrs().HardwareAddr)) 735 cDefinesMap["CILIUM_IFINDEX"] = fmt.Sprintf("%d", ciliumHostLink.Attrs().Index) 736 737 ephemeralMin, err := getEphemeralPortRangeMin(h.sysctl) 738 if err != nil { 739 return err 740 } 741 cDefinesMap["EPHEMERAL_MIN"] = fmt.Sprintf("%d", ephemeralMin) 742 743 if err := cDefinesMap.Merge(h.nodeExtraDefines); err != nil { 744 return err 745 } 746 747 for _, fn := range h.nodeExtraDefineFns { 748 defines, err := fn() 749 if err != nil { 750 return err 751 } 752 753 if err := cDefinesMap.Merge(defines); err != nil { 754 return err 755 } 756 } 757 758 if option.Config.EnableHealthDatapath { 759 if option.Config.IPv4Enabled() { 760 ipip4, err := netlink.LinkByName(defaults.IPIPv4Device) 761 if err != nil { 762 return err 763 } 764 cDefinesMap["ENCAP4_IFINDEX"] = fmt.Sprintf("%d", ipip4.Attrs().Index) 765 } 766 if option.Config.IPv6Enabled() { 767 ipip6, err := netlink.LinkByName(defaults.IPIPv6Device) 768 if err != nil { 769 return err 770 } 771 cDefinesMap["ENCAP6_IFINDEX"] = fmt.Sprintf("%d", ipip6.Attrs().Index) 772 } 773 } 774 775 // Write Identity and ClusterID related macros. 776 cDefinesMap["CLUSTER_ID_MAX"] = fmt.Sprintf("%d", option.Config.MaxConnectedClusters) 777 778 fmt.Fprint(fw, declareConfig("identity_length", identity.GetClusterIDShift(), "Identity length in bits")) 779 fmt.Fprint(fw, assignConfig("identity_length", identity.GetClusterIDShift())) 780 781 // Since golang maps are unordered, we sort the keys in the map 782 // to get a consistent written format to the writer. This maintains 783 // the consistency when we try to calculate hash for a datapath after 784 // writing the config. 785 keys := make([]string, 0, len(cDefinesMap)) 786 for key := range cDefinesMap { 787 keys = append(keys, key) 788 } 789 sort.Strings(keys) 790 791 for _, key := range keys { 792 fmt.Fprintf(fw, "#define %s %s\n", key, cDefinesMap[key]) 793 } 794 795 // Populate cDefinesMap with extraMacrosMap to get all the configuration 796 // in the cDefinesMap itself. 797 for key, value := range extraMacrosMap { 798 cDefinesMap[key] = value 799 } 800 801 // Write the JSON encoded config as base64 encoded commented string to 802 // the header file. 803 jsonBytes, err := json.Marshal(cDefinesMap) 804 if err == nil { 805 // We don't care if some error occurs while marshaling the map. 806 // In such cases we skip embedding the base64 encoded JSON configuration 807 // to the writer. 808 encodedConfig := base64.StdEncoding.EncodeToString(jsonBytes) 809 fmt.Fprintf(fw, "\n// JSON_OUTPUT: %s\n", encodedConfig) 810 } 811 812 return fw.Flush() 813 } 814 815 func getEphemeralPortRangeMin(sysctl sysctl.Sysctl) (int, error) { 816 ephemeralPortRangeStr, err := sysctl.Read([]string{"net", "ipv4", "ip_local_port_range"}) 817 if err != nil { 818 return 0, fmt.Errorf("unable to read net.ipv4.ip_local_port_range: %w", err) 819 } 820 ephemeralPortRange := strings.Split(ephemeralPortRangeStr, "\t") 821 if len(ephemeralPortRange) != 2 { 822 return 0, fmt.Errorf("invalid ephemeral port range: %s", ephemeralPortRangeStr) 823 } 824 ephemeralPortMin, err := strconv.Atoi(ephemeralPortRange[0]) 825 if err != nil { 826 return 0, fmt.Errorf("unable to parse min port value %s for ephemeral range: %w", 827 ephemeralPortRange[0], err) 828 } 829 830 return ephemeralPortMin, nil 831 } 832 833 // vlanFilterMacros generates VLAN_FILTER macros which 834 // are written to node_config.h 835 func vlanFilterMacros(nativeDevices []*tables.Device) (string, error) { 836 devices := make(map[int]bool) 837 for _, device := range nativeDevices { 838 devices[device.Index] = true 839 } 840 841 allowedVlans := make(map[int]bool) 842 for _, vlanId := range option.Config.VLANBPFBypass { 843 allowedVlans[vlanId] = true 844 } 845 846 // allow all vlan id's 847 if allowedVlans[0] { 848 return "return true", nil 849 } 850 851 vlansByIfIndex := make(map[int][]int) 852 853 links, err := netlink.LinkList() 854 if err != nil { 855 return "", err 856 } 857 858 for _, l := range links { 859 vlan, ok := l.(*netlink.Vlan) 860 // if it's vlan device and we're controlling vlan main device 861 // and either all vlans are allowed, or we're controlling vlan device or vlan is explicitly allowed 862 if ok && devices[vlan.ParentIndex] && (devices[vlan.Index] || allowedVlans[vlan.VlanId]) { 863 vlansByIfIndex[vlan.ParentIndex] = append(vlansByIfIndex[vlan.ParentIndex], vlan.VlanId) 864 } 865 } 866 867 vlansCount := 0 868 for _, v := range vlansByIfIndex { 869 vlansCount += len(v) 870 sort.Ints(v) // sort Vlanids in-place since netlink.LinkList() may return them in any order 871 } 872 873 if vlansCount == 0 { 874 return "return false", nil 875 } else if vlansCount > 5 { 876 return "", fmt.Errorf("allowed VLAN list is too big - %d entries, please use '--vlan-bpf-bypass 0' in order to allow all available VLANs", vlansCount) 877 } else { 878 vlanFilterTmpl := template.Must(template.New("vlanFilter").Parse( 879 `switch (ifindex) { \ 880 {{range $ifindex,$vlans := . -}} case {{$ifindex}}: \ 881 switch (vlan_id) { \ 882 {{range $vlan := $vlans -}} case {{$vlan}}: \ 883 {{end}}return true; \ 884 } \ 885 break; \ 886 {{end}}} \ 887 return false;`)) 888 889 var vlanFilterMacro bytes.Buffer 890 if err := vlanFilterTmpl.Execute(&vlanFilterMacro, vlansByIfIndex); err != nil { 891 return "", fmt.Errorf("failed to execute template: %w", err) 892 } 893 894 return vlanFilterMacro.String(), nil 895 } 896 } 897 898 // devMacros generates NATIVE_DEV_MAC_BY_IFINDEX and IS_L3_DEV macros which 899 // are written to node_config.h. 900 func devMacros(devs []*tables.Device) (string, string, error) { 901 var ( 902 macByIfIndexMacro, isL3DevMacroBuf bytes.Buffer 903 isL3DevMacro string 904 ) 905 macByIfIndex := make(map[int]string) 906 l3DevIfIndices := make([]int, 0) 907 908 for _, dev := range devs { 909 if len(dev.HardwareAddr) != 6 { 910 l3DevIfIndices = append(l3DevIfIndices, dev.Index) 911 } 912 macByIfIndex[dev.Index] = mac.CArrayString(net.HardwareAddr(dev.HardwareAddr)) 913 } 914 915 macByIfindexTmpl := template.Must(template.New("macByIfIndex").Parse( 916 `({ \ 917 union macaddr __mac = {.addr = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; \ 918 switch (IFINDEX) { \ 919 {{range $idx,$mac := .}} case {{$idx}}: {union macaddr __tmp = {.addr = {{$mac}}}; __mac=__tmp;} break; \ 920 {{end}}} \ 921 __mac; })`)) 922 923 if err := macByIfindexTmpl.Execute(&macByIfIndexMacro, macByIfIndex); err != nil { 924 return "", "", fmt.Errorf("failed to execute template: %w", err) 925 } 926 927 if len(l3DevIfIndices) == 0 { 928 isL3DevMacro = "false" 929 } else { 930 isL3DevTmpl := template.Must(template.New("isL3Dev").Parse( 931 `({ \ 932 bool is_l3 = false; \ 933 switch (ifindex) { \ 934 {{range $idx := .}} case {{$idx}}: is_l3 = true; break; \ 935 {{end}}} \ 936 is_l3; })`)) 937 if err := isL3DevTmpl.Execute(&isL3DevMacroBuf, l3DevIfIndices); err != nil { 938 return "", "", fmt.Errorf("failed to execute template: %w", err) 939 } 940 isL3DevMacro = isL3DevMacroBuf.String() 941 } 942 943 return macByIfIndexMacro.String(), isL3DevMacro, nil 944 } 945 946 func (h *HeaderfileWriter) writeNetdevConfig(w io.Writer, opts *option.IntOptions) { 947 fmt.Fprint(w, opts.GetFmtList()) 948 949 if option.Config.EnableEndpointRoutes { 950 fmt.Fprint(w, "#define USE_BPF_PROG_FOR_INGRESS_POLICY 1\n") 951 } 952 } 953 954 // WriteNetdevConfig writes the BPF configuration for the endpoint to a writer. 955 func (h *HeaderfileWriter) WriteNetdevConfig(w io.Writer, opts *option.IntOptions) error { 956 fw := bufio.NewWriter(w) 957 h.writeNetdevConfig(fw, opts) 958 return fw.Flush() 959 } 960 961 // writeStaticData writes the endpoint-specific static data defines to the 962 // specified writer. This must be kept in sync with loader.ELFSubstitutions(). 963 func (h *HeaderfileWriter) writeStaticData(devices []string, fw io.Writer, e datapath.EndpointConfiguration) { 964 if e.IsHost() { 965 // Values defined here are for the host datapath attached to the 966 // host device and therefore won't be used. We however need to set 967 // non-zero values to prevent the compiler from optimizing them 968 // out, because we need to substitute them for host datapaths 969 // attached to native devices. 970 // When substituting symbols in the object file, we will replace 971 // these values with zero for the host device and with the actual 972 // values for the native devices. 973 fmt.Fprint(fw, "/* Fake values, replaced by 0 for host device and by actual values for native devices. */\n") 974 fmt.Fprint(fw, defineUint32("NATIVE_DEV_IFINDEX", 1)) 975 fmt.Fprint(fw, "\n") 976 977 if option.Config.EnableBPFMasquerade { 978 if option.Config.EnableIPv4Masquerade { 979 // NodePort comment above applies to IPV4_MASQUERADE too 980 placeholderIPv4 := []byte{1, 1, 1, 1} 981 fmt.Fprint(fw, defineIPv4("IPV4_MASQUERADE", placeholderIPv4)) 982 } 983 if option.Config.EnableIPv6Masquerade { 984 // NodePort comment above applies to IPV6_MASQUERADE too 985 placeholderIPv6 := []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} 986 fmt.Fprint(fw, defineIPv6("IPV6_MASQUERADE", placeholderIPv6)) 987 } 988 } 989 // Dummy value to avoid being optimized when 0 990 fmt.Fprint(fw, defineUint32("SECCTX_FROM_IPCACHE", 1)) 991 992 // Use templating for ETH_HLEN only if there is any L2-less device 993 if !mac.HaveMACAddrs(devices) { 994 // L2 hdr len (for L2-less devices it will be replaced with "0") 995 fmt.Fprint(fw, defineUint16("ETH_HLEN", mac.EthHdrLen)) 996 } 997 } else { 998 // We want to ensure that the template BPF program always has "LXC_IP" 999 // defined and present as a symbol in the resulting object file after 1000 // compilation, regardless of whether IPv6 is disabled. Because the type 1001 // templateCfg hardcodes a dummy IPv6 address (and adheres to the 1002 // datapath.EndpointConfiguration interface), we can rely on it always 1003 // having an IPv6 addr. Endpoints however may not have IPv6 addrs if IPv6 1004 // is disabled. Hence this check prevents us from omitting the "LXC_IP" 1005 // symbol from the template BPF program. Without this, the following 1006 // scenario is possible: 1007 // 1) Enable IPv6 in cilium 1008 // 2) Create an endpoint (ensure endpoint has an IPv6 addr) 1009 // 3) Disable IPv6 and restart cilium 1010 // This results in a template BPF object without an "LXC_IP" defined, 1011 // __but__ the endpoint still has "LXC_IP" defined. This causes a later 1012 // call to loader.ELFSubstitutions() to fail on missing a symbol "LXC_IP". 1013 if ipv6 := e.IPv6Address(); ipv6.IsValid() { 1014 fmt.Fprint(fw, defineIPv6("LXC_IP", ipv6.AsSlice())) 1015 } 1016 1017 fmt.Fprint(fw, defineIPv4("LXC_IPV4", e.IPv4Address().AsSlice())) 1018 fmt.Fprint(fw, defineUint16("LXC_ID", uint16(e.GetID()))) 1019 } 1020 1021 fmt.Fprint(fw, defineMAC("THIS_INTERFACE_MAC", e.GetNodeMAC())) 1022 fmt.Fprint(fw, defineUint32("THIS_INTERFACE_IFINDEX", uint32(e.GetIfIndex()))) 1023 1024 secID := e.GetIdentityLocked().Uint32() 1025 fmt.Fprint(fw, defineUint32("SECLABEL", secID)) 1026 fmt.Fprint(fw, defineUint32("SECLABEL_IPV4", secID)) 1027 fmt.Fprint(fw, defineUint32("SECLABEL_IPV6", secID)) 1028 fmt.Fprint(fw, defineUint32("POLICY_VERDICT_LOG_FILTER", e.GetPolicyVerdictLogFilter())) 1029 1030 epID := uint16(e.GetID()) 1031 fmt.Fprintf(fw, "#define POLICY_MAP %s\n", bpf.LocalMapName(policymap.MapName, epID)) 1032 callsMapName := callsmap.MapName 1033 if e.IsHost() { 1034 callsMapName = callsmap.HostMapName 1035 } 1036 fmt.Fprintf(fw, "#define CALLS_MAP %s\n", bpf.LocalMapName(callsMapName, epID)) 1037 if option.Config.EnableCustomCalls && !e.IsHost() { 1038 fmt.Fprintf(fw, "#define CUSTOM_CALLS_MAP %s\n", bpf.LocalMapName(callsmap.CustomCallsMapName, epID)) 1039 } 1040 } 1041 1042 // WriteEndpointConfig writes the BPF configuration for the endpoint to a writer. 1043 func (h *HeaderfileWriter) WriteEndpointConfig(w io.Writer, cfg *datapath.LocalNodeConfiguration, e datapath.EndpointConfiguration) error { 1044 fw := bufio.NewWriter(w) 1045 1046 deviceNames := cfg.DeviceNames() 1047 1048 // Add cilium_wg0 if necessary. 1049 if option.Config.NeedBPFHostOnWireGuardDevice() { 1050 deviceNames = append(slices.Clone(deviceNames), wgtypes.IfaceName) 1051 } 1052 1053 writeIncludes(w) 1054 h.writeStaticData(deviceNames, fw, e) 1055 1056 return h.writeTemplateConfig(fw, deviceNames, cfg.HostEndpointID, e) 1057 } 1058 1059 func (h *HeaderfileWriter) writeTemplateConfig(fw *bufio.Writer, devices []string, hostEndpointID uint64, e datapath.EndpointConfiguration) error { 1060 if e.RequireEgressProg() { 1061 fmt.Fprintf(fw, "#define USE_BPF_PROG_FOR_INGRESS_POLICY 1\n") 1062 } 1063 1064 if e.RequireRouting() { 1065 fmt.Fprintf(fw, "#define ENABLE_ROUTING 1\n") 1066 } 1067 1068 if !option.Config.EnableHostLegacyRouting && option.Config.DirectRoutingDevice != "" { 1069 directRoutingIface := option.Config.DirectRoutingDevice 1070 directRoutingIfIndex, err := link.GetIfIndex(directRoutingIface) 1071 if err != nil { 1072 return err 1073 } 1074 fmt.Fprintf(fw, "#define DIRECT_ROUTING_DEV_IFINDEX %d\n", directRoutingIfIndex) 1075 if len(devices) == 1 { 1076 if e.IsHost() || !option.Config.EnforceLXCFibLookup() { 1077 fmt.Fprintf(fw, "#define ENABLE_SKIP_FIB 1\n") 1078 } 1079 } 1080 } 1081 1082 if e.IsHost() { 1083 // Only used to differentiate between host endpoint template and other templates. 1084 fmt.Fprintf(fw, "#define HOST_ENDPOINT 1\n") 1085 if option.Config.EnableNodePort { 1086 fmt.Fprintf(fw, "#define DISABLE_LOOPBACK_LB 1\n") 1087 } 1088 } 1089 1090 fmt.Fprintf(fw, "#define HOST_EP_ID %d\n", uint32(hostEndpointID)) 1091 1092 if option.Config.DatapathMode != datapathOption.DatapathModeNetkit { 1093 if e.RequireARPPassthrough() { 1094 fmt.Fprint(fw, "#define ENABLE_ARP_PASSTHROUGH 1\n") 1095 } else { 1096 fmt.Fprint(fw, "#define ENABLE_ARP_RESPONDER 1\n") 1097 } 1098 } 1099 1100 if e.ConntrackLocalLocked() { 1101 ctmap.WriteBPFMacros(fw, e) 1102 } else { 1103 ctmap.WriteBPFMacros(fw, nil) 1104 } 1105 1106 // Local delivery metrics should always be set for endpoint programs. 1107 fmt.Fprint(fw, "#define LOCAL_DELIVERY_METRICS 1\n") 1108 1109 h.writeNetdevConfig(fw, e.GetOptions()) 1110 1111 return fw.Flush() 1112 } 1113 1114 // WriteTemplateConfig writes the BPF configuration for the template to a writer. 1115 func (h *HeaderfileWriter) WriteTemplateConfig(w io.Writer, cfg *datapath.LocalNodeConfiguration, e datapath.EndpointConfiguration) error { 1116 fw := bufio.NewWriter(w) 1117 return h.writeTemplateConfig(fw, cfg.DeviceNames(), cfg.HostEndpointID, e) 1118 }