From cca9e1afce16375b2e2d49a51b905068e504a417 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 struct 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 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 3d2edc44ab..6c852a5f33 100644 --- a/src/core/bpf/clat.bpf.c +++ b/src/core/bpf/clat.bpf.c @@ -34,21 +34,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, ...) \ @@ -305,25 +291,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; @@ -343,8 +319,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; @@ -499,6 +475,18 @@ rewrite_icmpv6(struct ipv6hdr *ip6h, struct __sk_buff *skb) return 0; } +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; +} + /* ipv6 traffic from the PLAT, to be translated into ipv4 and sent to an application */ static int clat_handle_v6(struct __sk_buff *skb) @@ -506,6 +494,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; @@ -515,30 +504,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; @@ -547,7 +527,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 6da877a976..5c3f92080f 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 { @@ -5564,50 +5560,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) { @@ -5643,17 +5595,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, @@ -5678,10 +5627,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)); @@ -5739,41 +5684,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);