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  }