mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-10 18:40:22 +01:00
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.
This commit is contained in:
parent
195d6e5561
commit
cca9e1afce
3 changed files with 44 additions and 162 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -4,24 +4,10 @@
|
|||
|
||||
#include <linux/in6.h>
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue