From 102b04d0ea404f0f130a30927b3585b02fb567ff Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sun, 26 Oct 2025 17:44:12 +0100 Subject: [PATCH] clat: pass the configuration as a BPF global variable The program only needs to know the local IPv4 address, the local IPv6 address and the PREF64. There is no need to create multiple maps for that, just pass a global configuration struct containing those 3 fields. --- src/core/bpf/clat.bpf.c | 78 +++++++++++----------------- src/core/bpf/clat.h | 16 +----- src/core/nm-l3cfg.c | 112 +++++----------------------------------- 3 files changed, 44 insertions(+), 162 deletions(-) diff --git a/src/core/bpf/clat.bpf.c b/src/core/bpf/clat.bpf.c index e297094f77..46e552583f 100644 --- a/src/core/bpf/clat.bpf.c +++ b/src/core/bpf/clat.bpf.c @@ -31,21 +31,7 @@ char _license[] SEC("license") = "GPL"; -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __type(key, struct clat_v4_config_key); - __type(value, struct clat_v4_config_value); - __uint(max_entries, 16); - __uint(map_flags, BPF_F_NO_PREALLOC); -} v4_config_map SEC(".maps"); - -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __type(key, struct clat_v6_config_key); - __type(value, struct clat_v6_config_value); - __uint(max_entries, 16); - __uint(map_flags, BPF_F_NO_PREALLOC); -} v6_config_map SEC(".maps"); +struct clat_config config; #ifdef DEBUG #define DBG(fmt, ...) \ @@ -307,25 +293,15 @@ clat_handle_v4(struct __sk_buff *skb) struct iphdr *iph; struct ethhdr *eth; - struct clat_v4_config_value *v4_config; - struct clat_v4_config_key v4_config_key; - iph = data + sizeof(struct ethhdr); if (iph + 1 > data_end) goto out; - v4_config_key.ifindex = skb->ifindex; - v4_config_key.local_v4.s_addr = iph->saddr; - - v4_config = bpf_map_lookup_elem(&v4_config_map, &v4_config_key); - if (!v4_config) { - DBG("-> v4: config for src_v4=%pI4 not found!\n", &v4_config_key.local_v4); + if (iph->saddr != config.local_v4.s_addr) goto out; - } - /* At this point we know the destination IP is within the configured - * subnet, so if we can't rewrite the packet it should be dropped (so as - * not to leak traffic in that subnet). + /* At this point we know the packet needs translation. If we can't + * rewrite it, it should be dropped. */ ret = TC_ACT_SHOT; @@ -345,8 +321,8 @@ clat_handle_v4(struct __sk_buff *skb) } /* src v4 as last octet of clat address */ - dst_hdr.saddr = v4_config->local_v6; - dst_hdr.daddr = v4_config->pref64; + dst_hdr.saddr = config.local_v6; + dst_hdr.daddr = config.pref64; dst_hdr.daddr.s6_addr32[3] = iph->daddr; dst_hdr.nexthdr = iph->protocol; dst_hdr.hop_limit = iph->ttl; @@ -402,6 +378,18 @@ csum_fold_helper(__u32 csum) return ~sum; } +static __always_inline bool +v6addr_equal(const struct in6_addr *a, const struct in6_addr *b) +{ + int i; + + for (i = 0; i < 4; i++) { + if (a->s6_addr32[i] != b->s6_addr32[i]) + return false; + } + return true; +} + static int rewrite_icmpv6(struct __sk_buff *skb) { @@ -514,6 +502,7 @@ clat_handle_v6(struct __sk_buff *skb) int ret = TC_ACT_OK; void *data_end = SKB_DATA_END(skb); void *data = SKB_DATA(skb); + struct in6_addr subnet_v6; struct ethhdr *eth; struct iphdr *iph; struct ipv6hdr *ip6h; @@ -523,30 +512,21 @@ clat_handle_v6(struct __sk_buff *skb) .frag_off = bpf_htons(1 << 14), /* set Don't Fragment bit */ }; - struct clat_v6_config_value *v6_config; - struct clat_v6_config_key v6_config_key; - ip6h = data + sizeof(struct ethhdr); if (ip6h + 1 > data_end) goto out; - v6_config_key.local_v6 = ip6h->daddr; - v6_config_key.pref64 = ip6h->saddr; - /* v6 pxlen is always 96 */ - v6_config_key.pref64.s6_addr32[3] = 0; - v6_config_key.ifindex = skb->ifindex; - - v6_config = bpf_map_lookup_elem(&v6_config_map, &v6_config_key); - if (!v6_config) { - DBG("<- v6: config for pref64=%pI6c, local_v6=%pI6c not found!\n", - &v6_config_key.pref64, - &v6_config_key.local_v6); + if (!v6addr_equal(&ip6h->daddr, &config.local_v6)) goto out; - } - /* At this point we know the destination IP is within the configured - * subnet, so if we can't rewrite the packet it should be dropped (so as - * not to leak traffic in that subnet). + subnet_v6 = ip6h->saddr; + subnet_v6.s6_addr32[3] = 0; /* prefix len is always 96 for now */ + + if (!v6addr_equal(&subnet_v6, &config.pref64)) + goto out; + + /* At this point we know the packet needs translation. If we can't + * rewrite it, it should be dropped. */ ret = TC_ACT_SHOT; @@ -555,7 +535,7 @@ clat_handle_v6(struct __sk_buff *skb) && ip6h->nexthdr != IPPROTO_ICMPV6) goto out; - dst_hdr.daddr = v6_config->local_v4.s_addr; + dst_hdr.daddr = config.local_v4.s_addr; dst_hdr.saddr = ip6h->saddr.s6_addr32[3]; dst_hdr.protocol = ip6h->nexthdr; dst_hdr.ttl = ip6h->hop_limit; diff --git a/src/core/bpf/clat.h b/src/core/bpf/clat.h index ee4763d5c7..2748946392 100644 --- a/src/core/bpf/clat.h +++ b/src/core/bpf/clat.h @@ -4,24 +4,10 @@ #include -struct clat_v6_config_key { +struct clat_config { struct in6_addr local_v6; struct in6_addr pref64; - __u32 ifindex; -}; - -struct clat_v6_config_value { struct in_addr local_v4; }; -struct clat_v4_config_key { - struct in_addr local_v4; - __u32 ifindex; -}; - -struct clat_v4_config_value { - struct in6_addr local_v6; - struct in6_addr pref64; -}; - #endif diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index 13cb73a496..e789be2fa1 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -310,9 +310,6 @@ typedef struct _NML3CfgPrivate { NMNetnsIPReservation *clat_address_4_committed; NMPlatformIP6Address clat_address_6_committed; - /* The NAT64 prefix discovered via RA */ - struct in6_addr clat_pref64; - /* If NULL, the BPF program hasn't been loaded or attached */ struct clat_bpf *clat_bpf; int clat_socket; @@ -387,7 +384,6 @@ typedef struct _NML3CfgPrivate { bool clat_address_6_valid : 1; bool clat_address_6_committed_valid : 1; - bool clat_pref64_valid : 1; } NML3CfgPrivate; struct _NML3CfgClass { @@ -5589,50 +5585,6 @@ _l3_commit_one(NML3Cfg *self, } #if HAVE_CLAT -static void -_l3_get_pref64_config(NML3Cfg *self, - struct clat_v4_config_key *v4_key, - struct clat_v4_config_value *v4_value, - struct clat_v6_config_key *v6_key, - struct clat_v6_config_value *v6_value, - gboolean committed) -{ - const NML3ConfigData *l3cd = self->priv.p->combined_l3cd_commited; - struct in6_addr pref64; - guint32 pref64_plen; - - memset(v4_key, 0, sizeof(*v4_key)); - memset(v6_key, 0, sizeof(*v6_key)); - memset(v4_value, 0, sizeof(*v4_value)); - memset(v6_value, 0, sizeof(*v6_value)); - - v4_key->ifindex = v6_key->ifindex = self->priv.ifindex; - - if (committed) { - if (self->priv.p->clat_address_4_committed) { - v6_value->local_v4.s_addr = v4_key->local_v4.s_addr = - self->priv.p->clat_address_4_committed->addr; - } - if (self->priv.p->clat_address_6_committed_valid) { - v4_value->local_v6 = v6_key->local_v6 = self->priv.p->clat_address_6_committed.address; - } - if (self->priv.p->clat_pref64_valid) { - v6_key->pref64 = v4_value->pref64 = self->priv.p->clat_pref64; - } - } else { - if (self->priv.p->clat_address_4) { - v6_value->local_v4.s_addr = v4_key->local_v4.s_addr = - self->priv.p->clat_address_4->addr; - } - if (self->priv.p->clat_address_6_valid) { - v4_value->local_v6 = v6_key->local_v6 = self->priv.p->clat_address_6.address; - } - if (nm_l3_config_data_get_pref64(l3cd, &pref64, &pref64_plen)) { - v6_key->pref64 = v4_value->pref64 = pref64; - } - } -} - static void _l3_clat_destroy(NML3Cfg *self) { @@ -5668,17 +5620,14 @@ _l3_clat_destroy(NML3Cfg *self) static void _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type) { - int err = 0; - const NML3ConfigData *l3cd = self->priv.p->combined_l3cd_commited; - struct in6_addr _l3cd_pref64_inner; - const struct in6_addr *l3cd_pref64 = NULL; - guint32 l3cd_pref64_plen; - char buf[100]; - struct clat_v6_config_key v6_key_committed, v6_key_new; - struct clat_v4_config_key v4_key_committed, v4_key_new; - struct clat_v6_config_value v6_value_committed, v6_value_new; - struct clat_v4_config_value v4_value_committed, v4_value_new; - gboolean v6_changed; + int err = 0; + const NML3ConfigData *l3cd = self->priv.p->combined_l3cd_commited; + struct in6_addr _l3cd_pref64_inner; + const struct in6_addr *l3cd_pref64 = NULL; + guint32 l3cd_pref64_plen; + char buf[100]; + struct clat_config clat_config; + gboolean v6_changed; DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, .attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS, @@ -5703,10 +5652,6 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type) return; } - /* Set up maps */ - bpf_map__set_max_entries(self->priv.p->clat_bpf->maps.v4_config_map, 16); - bpf_map__set_max_entries(self->priv.p->clat_bpf->maps.v6_config_map, 16); - err = clat_bpf__load(self->priv.p->clat_bpf); if (err) { libbpf_strerror(err, buf, sizeof(buf)); @@ -5764,41 +5709,12 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type) self->priv.p->clat_attach_egress = attach_egress; } - _l3_get_pref64_config(self, - &v4_key_committed, - &v4_value_committed, - &v6_key_committed, - &v6_value_committed, - TRUE); - _l3_get_pref64_config(self, &v4_key_new, &v4_value_new, &v6_key_new, &v6_value_new, FALSE); - - if (memcmp(&v4_key_committed, &v4_key_new, sizeof(v4_key_new))) { - bpf_map_delete_elem(bpf_map__fd(self->priv.p->clat_bpf->maps.v4_config_map), - &v4_key_committed); - } - if (memcmp(&v6_key_committed, &v6_key_new, sizeof(v6_key_new))) { - bpf_map_delete_elem(bpf_map__fd(self->priv.p->clat_bpf->maps.v6_config_map), - &v6_key_committed); - } - if (memcmp(&v4_value_committed, &v4_value_new, sizeof(v4_value_new))) { - bpf_map_update_elem(bpf_map__fd(self->priv.p->clat_bpf->maps.v4_config_map), - &v4_key_new, - &v4_value_new, - BPF_ANY); - } - if (memcmp(&v6_value_committed, &v6_value_new, sizeof(v6_value_new))) { - bpf_map_update_elem(bpf_map__fd(self->priv.p->clat_bpf->maps.v6_config_map), - &v6_key_new, - &v6_value_new, - BPF_ANY); - } - - if (l3cd_pref64) { - self->priv.p->clat_pref64_valid = TRUE; - self->priv.p->clat_pref64 = *l3cd_pref64; - } else { - self->priv.p->clat_pref64_valid = FALSE; - } + /* Pass configuration to the BPF program */ + memset(&clat_config, 0, sizeof(clat_config)); + clat_config.local_v4.s_addr = self->priv.p->clat_address_4->addr; + clat_config.local_v6 = self->priv.p->clat_address_6.address; + clat_config.pref64 = *l3cd_pref64; + self->priv.p->clat_bpf->bss->config = clat_config; if (self->priv.p->clat_socket < 0) { self->priv.p->clat_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);