Add support for CLAT to l3cfg (fixes)

This commit is contained in:
Beniamino Galvani 2025-09-08 21:51:40 +02:00
parent 79a2b5599f
commit b31d3e1eae
4 changed files with 126 additions and 103 deletions

View file

@ -304,6 +304,7 @@ typedef enum {
NM_UTILS_STABLE_TYPE_STABLE_ID = 1,
NM_UTILS_STABLE_TYPE_GENERATED = 2,
NM_UTILS_STABLE_TYPE_RANDOM = 3,
NM_UTILS_STABLE_TYPE_CLAT = 4,
} NMUtilsStableType;
#define NM_UTILS_STABLE_TYPE_NONE ((NMUtilsStableType) - 1)

View file

@ -2001,12 +2001,11 @@ nm_l3_config_data_set_pref64_valid(NML3ConfigData *self, gboolean val)
}
gboolean
nm_l3_config_data_get_pref64_valid(const NML3ConfigData *self, gboolean *out_val)
nm_l3_config_data_get_pref64_valid(const NML3ConfigData *self)
{
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
NM_SET_OUT(out_val, self->pref64_valid);
return TRUE;
return self->pref64_valid;
}
gboolean

View file

@ -500,7 +500,7 @@ const char *nm_l3_config_data_get_network_id(const NML3ConfigData *self);
gboolean nm_l3_config_data_set_pref64_valid(NML3ConfigData *self, gboolean val);
gboolean nm_l3_config_data_get_pref64_valid(const NML3ConfigData *self, gboolean *out_val);
gboolean nm_l3_config_data_get_pref64_valid(const NML3ConfigData *self);
gboolean nm_l3_config_data_get_pref64(const NML3ConfigData *self,
struct in6_addr *out_prefix,

View file

@ -11,7 +11,7 @@
#include <linux/if_ether.h>
#include <linux/rtnetlink.h>
#include <linux/fib_rules.h>
#ifdef HAVE_CLAT
#if HAVE_CLAT
#include <bpf/libbpf.h>
#include <bpf/bpf.h>
#endif /* HAVE_CLAT */
@ -27,7 +27,7 @@
#include "nm-l3-ipv4ll.h"
#include "nm-ip-config.h"
#include "nm-core-utils.h"
#ifdef HAVE_CLAT
#if HAVE_CLAT
#include "bpf/clat.h"
NM_PRAGMA_WARNING_DISABLE("-Wcast-align")
#include "bpf/clat.skel.h"
@ -300,12 +300,19 @@ typedef struct _NML3CfgPrivate {
NMIPConfig *ipconfig_x[2];
};
#ifdef HAVE_CLAT
NMNetnsIPRange *clat_address_4_commited;
NMPlatformIP6Address clat_address_6_commited;
NMNetnsIPRange *clat_address_4;
#if HAVE_CLAT
/* The reserved IPv4 address for CLAT in the 192.0.0.0/28 range */
NMNetnsIPReservation *clat_address_4;
/* The IPv6 address for sending and receiving translated packets */
NMPlatformIP6Address clat_address_6;
struct in6_addr clat_pref64;
/* The same addresses as above, but already committed previously */
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;
@ -379,7 +386,7 @@ typedef struct _NML3CfgPrivate {
bool rp_filter_set : 1;
bool clat_address_6_valid : 1;
bool clat_address_6_commited_valid : 1;
bool clat_address_6_committed_valid : 1;
bool clat_pref64_valid : 1;
} NML3CfgPrivate;
@ -4151,9 +4158,10 @@ _l3cfg_update_combined_config(NML3Cfg *self,
guint i;
gboolean merged_changed = FALSE;
gboolean commited_changed = FALSE;
gboolean pref64_valid = FALSE;
struct in6_addr pref64;
guint32 pref64_plen;
#if HAVE_CLAT
struct in6_addr pref64;
guint32 pref64_plen;
#endif
nm_assert(NM_IS_L3CFG(self));
nm_assert(!out_old || !*out_old);
@ -4252,32 +4260,42 @@ _l3cfg_update_combined_config(NML3Cfg *self,
}
#if HAVE_CLAT
nm_assert(nm_l3_config_data_get_pref64_valid(l3cd, &pref64_valid));
if (pref64_valid) {
nm_assert(nm_l3_config_data_get_pref64(l3cd, &pref64, &pref64_plen));
}
if (pref64_valid) {
NMPlatformIPXRoute rx;
NMIPAddrTyped best_v6_gateway;
struct in6_addr ip6;
NMDedupMultiIter iter;
if (nm_l3_config_data_get_pref64_valid(l3cd)) {
NMPlatformIPXRoute rx;
NMIPAddrTyped best_v6_gateway;
NMDedupMultiIter iter;
const NMPlatformIP6Route *best_v6_route;
const NMPlatformIP6Address *ip6_entry;
struct in6_addr ip6;
const char *network_id;
char buf[512];
/* We need to assign an additional v6 /64 address for ourselves, according
to the spec: https://www.rfc-editor.org/rfc/rfc6877#section-6.3 */
if (!self->priv.p->clat_address_6_valid) {
/* If we have a valid NAT64 prefix, configure in kernel:
*
* - a CLAT IPv4 address (192.0.0.x)
* - a IPv4 default route via the best IPv6 gateway
*
* We also set clat_address_6 as an additional /64 IPv6 address
* determined according to https://www.rfc-editor.org/rfc/rfc6877#section-6.3 .
* This address is used for sending and receiving translated packets,
* but is not configured in kernel to avoid that it gets used by applications.
* Later in _l3_commit_pref64() we use IPV6_JOIN_ANYCAST to let the kernel
* handle ND for the address.
*/
nm_l3_config_data_get_pref64(l3cd, &pref64, &pref64_plen);
network_id = nm_l3_config_data_get_network_id(l3cd);
if (!self->priv.p->clat_address_6_valid && network_id) {
nm_l3_config_data_iter_ip6_address_for_each (&iter, l3cd, &ip6_entry) {
if (ip6_entry->addr_source == NM_IP_CONFIG_SOURCE_NDISC
&& ip6_entry->plen == 64) {
ip6 = ip6_entry->address;
nm_utils_ipv6_addr_set_stable_privacy(NM_UTILS_STABLE_TYPE_RANDOM,
nm_utils_ipv6_addr_set_stable_privacy(NM_UTILS_STABLE_TYPE_CLAT,
&ip6,
nm_l3cfg_get_ifname(self, TRUE),
"TODO: Mary fixme",
network_id,
0);
self->priv.p->clat_address_6 = (NMPlatformIP6Address) {
.ifindex = self->priv.ifindex,
@ -4286,6 +4304,9 @@ _l3cfg_update_combined_config(NML3Cfg *self,
.addr_source = NM_IP_CONFIG_SOURCE_CLAT,
.plen = ip6_entry->plen,
};
_LOGT("clat: using IPv6 address %s", nm_inet6_ntop(&ip6, buf));
self->priv.p->clat_address_6_valid = TRUE;
break;
}
@ -4296,16 +4317,18 @@ _l3cfg_update_combined_config(NML3Cfg *self,
potentially create broken v4 connectivity) */
if (!self->priv.p->clat_address_6_valid) {
_LOGW("CLAT is currently only supported when SLAAC is in use.");
/* Deallocate the v4 address unless it's the commited one */
if (self->priv.p->clat_address_4 != self->priv.p->clat_address_4_commited) {
nm_clear_pointer(&self->priv.p->clat_address_4, nm_netns_ip_range_release);
/* Deallocate the v4 address unless it's the committed one */
if (self->priv.p->clat_address_4 != self->priv.p->clat_address_4_committed) {
nm_clear_pointer(&self->priv.p->clat_address_4,
nm_netns_ip_reservation_release);
} else {
self->priv.p->clat_address_4 = NULL;
}
} else if (!self->priv.p->clat_address_4) {
/* We need a v4 /32 */
self->priv.p->clat_address_4 =
nm_netns_ip_range_allocate(self->priv.netns, NM_NETNS_IP_RANGE_TYPE_CLAT);
nm_netns_ip_reservation_get(self->priv.netns,
NM_NETNS_IP_RESERVATION_TYPE_CLAT);
}
if (self->priv.p->clat_address_4) {
@ -4357,6 +4380,10 @@ _l3cfg_update_combined_config(NML3Cfg *self,
if (!nm_l3_config_data_lookup_route(l3cd, AF_INET, &rx.rx)) {
nm_l3_config_data_add_route_4(l3cd, &rx.r4);
}
_LOGT("clat: route %s",
nm_platform_ip4_route_to_string(&rx.r4, buf, sizeof(buf)));
nm_l3_config_data_add_address_4(l3cd, &addr);
} else {
_LOGW("Couldn't find a good ipv6 route! Unable to set up CLAT!");
@ -4425,15 +4452,17 @@ _l3cfg_update_combined_config(NML3Cfg *self,
if (nm_l3_config_data_equal(l3cd, self->priv.p->combined_l3cd_merged))
goto out;
#if HAVE_CLAT
if (!l3cd) {
self->priv.p->clat_address_6_valid = FALSE;
/* Deallocate the v4 address unless it's the commited one */
if (self->priv.p->clat_address_4 != self->priv.p->clat_address_4_commited) {
nm_clear_pointer(&self->priv.p->clat_address_4, nm_netns_ip_range_release);
if (self->priv.p->clat_address_4 != self->priv.p->clat_address_4_committed) {
nm_clear_pointer(&self->priv.p->clat_address_4, nm_netns_ip_reservation_release);
} else {
self->priv.p->clat_address_4 = NULL;
}
}
#endif /* HAVE_CLAT */
l3cd_old = g_steal_pointer(&self->priv.p->combined_l3cd_merged);
self->priv.p->combined_l3cd_merged = nm_l3_config_data_seal(g_steal_pointer(&l3cd));
@ -5534,14 +5563,14 @@ _l3_commit_one(NML3Cfg *self,
_failedobj_handle_routes(self, addr_family, routes_failed);
}
#ifdef HAVE_CLAT
#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 commited)
gboolean committed)
{
const NML3ConfigData *l3cd = self->priv.p->combined_l3cd_commited;
struct in6_addr pref64;
@ -5554,13 +5583,13 @@ _l3_get_pref64_config(NML3Cfg *self,
v4_key->ifindex = v6_key->ifindex = self->priv.ifindex;
if (commited) {
if (self->priv.p->clat_address_4_commited) {
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_commited->addr;
self->priv.p->clat_address_4_committed->addr;
}
if (self->priv.p->clat_address_6_commited_valid) {
v4_value->local_v6 = v6_key->local_v6 = self->priv.p->clat_address_6_commited.address;
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;
@ -5605,6 +5634,9 @@ _l3_clat_destroy(NML3Cfg *self)
libbpf_strerror(err, buf, sizeof(buf));
_LOGW("failed to tear down CLAT BPF egress hook: %s", buf);
}
bpf_tc_hook_destroy(&hook);
nm_clear_pointer(&self->priv.p->clat_bpf, clat_bpf__destroy);
}
@ -5617,10 +5649,10 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
const struct in6_addr *l3cd_pref64 = NULL;
guint32 l3cd_pref64_plen;
char buf[100];
struct clat_v6_config_key v6_key_commited, v6_key_new;
struct clat_v4_config_key v4_key_commited, v4_key_new;
struct clat_v6_config_value v6_value_commited, v6_value_new;
struct clat_v4_config_value v4_value_commited, v4_value_new;
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;
DECLARE_LIBBPF_OPTS(bpf_tc_hook,
hook,
@ -5635,12 +5667,12 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
if (l3cd_pref64 && self->priv.p->clat_address_4 && self->priv.p->clat_address_6_valid) {
if (!self->priv.p->clat_bpf) {
/* Bring up the CLAT */
_LOGT("clat: attaching the BPF program");
self->priv.p->clat_bpf = clat_bpf__open();
err = libbpf_get_error(self->priv.p->clat_bpf);
if (err) {
libbpf_strerror(err, buf, sizeof(buf));
_LOGW("failed to load CLAT BPF: %s", buf);
_LOGW("clat: failed to open the BPF program: %s", buf);
clat_bpf__destroy(self->priv.p->clat_bpf);
self->priv.p->clat_bpf = NULL;
return;
@ -5653,7 +5685,7 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
err = clat_bpf__load(self->priv.p->clat_bpf);
if (err) {
libbpf_strerror(err, buf, sizeof(buf));
_LOGW("failed to open CLAT BPF: %s", buf);
_LOGW("clat: failed to load the BPF program: %s", buf);
clat_bpf__destroy(self->priv.p->clat_bpf);
self->priv.p->clat_bpf = NULL;
return;
@ -5662,7 +5694,7 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
err = bpf_tc_hook_create(&hook);
if (err && err != -EEXIST) {
libbpf_strerror(err, buf, sizeof(buf));
_LOGW("failed to create CLAT BPF hook: %s", buf);
_LOGW("clat: failed to create the BPF hook: %s", buf);
clat_bpf__destroy(self->priv.p->clat_bpf);
self->priv.p->clat_bpf = NULL;
return;
@ -5670,7 +5702,7 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
attach_ingress.prog_fd = bpf_program__fd(self->priv.p->clat_bpf->progs.clat_ingress);
if (attach_ingress.prog_fd < 0) {
_LOGW("couldn't find CLAT BPF ingress!");
_LOGW("clat: couldn't find the BPF ingress");
clat_bpf__destroy(self->priv.p->clat_bpf);
self->priv.p->clat_bpf = NULL;
return;
@ -5678,7 +5710,7 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
attach_egress.prog_fd = bpf_program__fd(self->priv.p->clat_bpf->progs.clat_egress);
if (attach_egress.prog_fd < 0) {
_LOGW("couldn't find CLAT BPF egress!");
_LOGW("clat: couldn't find the BPF egress");
clat_bpf__destroy(self->priv.p->clat_bpf);
self->priv.p->clat_bpf = NULL;
return;
@ -5688,7 +5720,7 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
err = bpf_tc_attach(&hook, &attach_ingress);
if (err) {
libbpf_strerror(err, buf, sizeof(buf));
_LOGW("failed to attach ingress to CLAT BPF hook: %s", buf);
_LOGW("clat: failed to attach ingress to BPF hook: %s", buf);
clat_bpf__destroy(self->priv.p->clat_bpf);
self->priv.p->clat_bpf = NULL;
return;
@ -5699,7 +5731,7 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
err = bpf_tc_attach(&hook, &attach_egress);
if (err) {
libbpf_strerror(err, buf, sizeof(buf));
_LOGW("failed to attach ingress to CLAT BPF hook: %s", buf);
_LOGW("clat: failed to attach ingress to BPF hook: %s", buf);
clat_bpf__destroy(self->priv.p->clat_bpf);
self->priv.p->clat_bpf = NULL;
return;
@ -5708,28 +5740,28 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
}
_l3_get_pref64_config(self,
&v4_key_commited,
&v4_value_commited,
&v6_key_commited,
&v6_value_commited,
&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_commited, &v4_key_new, sizeof(v4_key_new))) {
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_commited);
&v4_key_committed);
}
if (memcmp(&v6_key_commited, &v6_key_new, sizeof(v6_key_new))) {
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_commited);
&v6_key_committed);
}
if (memcmp(&v4_value_commited, &v4_value_new, sizeof(v4_value_new))) {
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_commited, &v6_value_new, sizeof(v6_value_new))) {
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,
@ -5746,9 +5778,7 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
if (self->priv.p->clat_socket < 0) {
self->priv.p->clat_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (self->priv.p->clat_socket < 0) {
_LOGW("Couldn't create CLAT socket for %d! %s",
self->priv.ifindex,
nm_strerror_native(errno));
_LOGW("clat: couldn't create the socket: %s", nm_strerror_native(errno));
}
}
if (self->priv.p->clat_socket >= 0) {
@ -5757,35 +5787,31 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
SO_BINDTOIFINDEX,
&self->priv.ifindex,
sizeof(self->priv.ifindex));
if (err) {
_LOGW("Couldn't bind CLAT socket to interface %d! %s",
self->priv.ifindex,
nm_strerror_native(errno));
if (err < 0) {
_LOGW("clat: couldn't bind the socket: %s", nm_strerror_native(errno));
}
}
v6_changed =
(self->priv.p->clat_address_6_valid != self->priv.p->clat_address_6_commited_valid)
|| (self->priv.p->clat_address_6_valid && self->priv.p->clat_address_6_commited_valid
(self->priv.p->clat_address_6_valid != self->priv.p->clat_address_6_committed_valid)
|| (self->priv.p->clat_address_6_valid && self->priv.p->clat_address_6_committed_valid
&& memcmp(&self->priv.p->clat_address_6.address,
&self->priv.p->clat_address_6_commited.address,
sizeof(self->priv.p->clat_address_6_commited.address)));
&self->priv.p->clat_address_6_committed.address,
sizeof(self->priv.p->clat_address_6_committed.address)));
if (self->priv.p->clat_socket > 0 && v6_changed) {
struct ipv6_mreq mreq = {.ipv6mr_interface = self->priv.ifindex};
if (self->priv.p->clat_address_6_commited_valid) {
mreq.ipv6mr_multiaddr = self->priv.p->clat_address_6_commited.address;
if (self->priv.p->clat_address_6_committed_valid) {
mreq.ipv6mr_multiaddr = self->priv.p->clat_address_6_committed.address;
err = setsockopt(self->priv.p->clat_socket,
SOL_IPV6,
IPV6_LEAVE_ANYCAST,
&mreq,
sizeof(mreq));
if (err) {
_LOGW("Couldn't leave CLAT anycast group on interface %d! %s",
self->priv.ifindex,
nm_strerror_native(errno));
if (err < 0) {
_LOGW("clat: couldn't leave the anycast group: %s", nm_strerror_native(errno));
}
}
@ -5797,10 +5823,8 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
IPV6_JOIN_ANYCAST,
&mreq,
sizeof(mreq));
if (err) {
_LOGW("Couldn't join CLAT anycast group on interface %d! %s",
self->priv.ifindex,
nm_strerror_native(errno));
if (err < 0) {
_LOGW("clat: couldn't join the anycast group: %s", nm_strerror_native(errno));
}
}
}
@ -5809,27 +5833,27 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
_l3_clat_destroy(self);
}
/* Commited will get cleaned up below */
/* Committed will get cleaned up below */
self->priv.p->clat_address_6_valid = FALSE;
nm_clear_fd(&self->priv.p->clat_socket);
/* Deallocate the v4 address. Commited address will get cleaned up below,
/* Deallocate the v4 address. Committed address will get cleaned up below,
but we need to make sure there's no double-free */
if (self->priv.p->clat_address_4 != self->priv.p->clat_address_4_commited) {
nm_clear_pointer(&self->priv.p->clat_address_4, nm_netns_ip_range_release);
if (self->priv.p->clat_address_4 != self->priv.p->clat_address_4_committed) {
nm_clear_pointer(&self->priv.p->clat_address_4, nm_netns_ip_reservation_release);
} else {
self->priv.p->clat_address_4 = NULL;
}
}
/* Record the new state */
if (self->priv.p->clat_address_4_commited != self->priv.p->clat_address_4) {
nm_clear_pointer(&self->priv.p->clat_address_4_commited, nm_netns_ip_range_release);
self->priv.p->clat_address_4_commited = self->priv.p->clat_address_4;
if (self->priv.p->clat_address_4_committed != self->priv.p->clat_address_4) {
nm_clear_pointer(&self->priv.p->clat_address_4_committed, nm_netns_ip_reservation_release);
self->priv.p->clat_address_4_committed = self->priv.p->clat_address_4;
}
self->priv.p->clat_address_6_commited = self->priv.p->clat_address_6;
self->priv.p->clat_address_6_commited_valid = self->priv.p->clat_address_6_valid;
self->priv.p->clat_address_6_committed = self->priv.p->clat_address_6;
self->priv.p->clat_address_6_committed_valid = self->priv.p->clat_address_6_valid;
}
#endif /* HAVE_CLAT */
@ -5915,7 +5939,7 @@ _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle)
_l3_acd_data_process_changes(self);
#ifdef HAVE_CLAT
#if HAVE_CLAT
_l3_commit_pref64(self, commit_type);
#endif /* HAVE_CLAT */
@ -6300,7 +6324,9 @@ nm_l3cfg_init(NML3Cfg *self)
{
self->priv.p = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_L3CFG, NML3CfgPrivate);
#if HAVE_CLAT
self->priv.p->clat_socket = -1;
#endif /* HAVE_CLAT */
c_list_init(&self->priv.p->acd_lst_head);
c_list_init(&self->priv.p->acd_event_notify_lst_head);
@ -6356,9 +6382,6 @@ finalize(GObject *object)
{
NML3Cfg *self = NM_L3CFG(object);
gboolean changed;
#ifdef HAVE_CLAT
DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, .attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS);
#endif /* HAVE_CLAT */
if (self->priv.netns) {
nm_netns_watcher_remove_all(self->priv.netns, _NETNS_WATCHER_IP_ADDR_TAG(self, AF_INET));
@ -6413,9 +6436,9 @@ finalize(GObject *object)
if (changed)
nmp_global_tracker_sync_mptcp_addrs(self->priv.global_tracker, FALSE);
#ifdef HAVE_CLAT
self->priv.p->clat_address_4_commited = NULL;
nm_clear_pointer(&self->priv.p->clat_address_4, nm_netns_ip_range_release);
#if HAVE_CLAT
self->priv.p->clat_address_4_committed = NULL;
nm_clear_pointer(&self->priv.p->clat_address_4, nm_netns_ip_reservation_release);
nm_clear_fd(&self->priv.p->clat_socket);
if (self->priv.p->clat_bpf) {
_l3_clat_destroy(self);