l3cfg: use the tcx attachment for the clat program

The TCX attachment type was added in kernel 6.6 (October 2023) and it
replaces the Traffic Control (TC) BPF attachment, providing better
usability. Convert the l3cfg code to use it.
This commit is contained in:
Beniamino Galvani 2026-01-07 15:05:21 +01:00
parent bd67cefaaa
commit 6ec321d21b

View file

@ -312,9 +312,10 @@ typedef struct _NML3CfgPrivate {
/* If NULL, the BPF program hasn't been loaded or attached */ /* If NULL, the BPF program hasn't been loaded or attached */
struct clat_bpf *clat_bpf; struct clat_bpf *clat_bpf;
struct bpf_link *clat_ingress_link;
struct bpf_link *clat_egress_link;
int clat_socket; int clat_socket;
struct bpf_tc_opts clat_attach_ingress;
struct bpf_tc_opts clat_attach_egress;
#endif /* HAVE_CLAT */ #endif /* HAVE_CLAT */
/* Whether we earlier configured MPTCP endpoints for the interface. */ /* Whether we earlier configured MPTCP endpoints for the interface. */
@ -5588,31 +5589,26 @@ _l3_commit_one(NML3Cfg *self,
static void static void
_l3_clat_destroy(NML3Cfg *self) _l3_clat_destroy(NML3Cfg *self)
{ {
DECLARE_LIBBPF_OPTS(bpf_tc_hook,
hook,
.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS,
.ifindex = self->priv.ifindex);
int err = 0;
char buf[100]; char buf[100];
int err;
hook.attach_point = BPF_TC_INGRESS; if (self->priv.p->clat_ingress_link) {
self->priv.p->clat_attach_ingress.prog_fd = 0; err = bpf_link__destroy(self->priv.p->clat_ingress_link);
self->priv.p->clat_attach_ingress.prog_id = 0; if (err != 0) {
err = bpf_tc_detach(&hook, &self->priv.p->clat_attach_ingress);
if (err) {
libbpf_strerror(err, buf, sizeof(buf)); libbpf_strerror(err, buf, sizeof(buf));
_LOGW("failed to tear down CLAT BPF ingress hook: %s", buf); _LOGD("clat: failed to destroy the ingress link");
} }
hook.attach_point = BPF_TC_EGRESS; self->priv.p->clat_ingress_link = NULL;
self->priv.p->clat_attach_egress.prog_fd = 0;
self->priv.p->clat_attach_egress.prog_id = 0;
err = bpf_tc_detach(&hook, &self->priv.p->clat_attach_egress);
if (err) {
libbpf_strerror(err, buf, sizeof(buf));
_LOGW("failed to tear down CLAT BPF egress hook: %s", buf);
} }
bpf_tc_hook_destroy(&hook); if (self->priv.p->clat_egress_link) {
err = bpf_link__destroy(self->priv.p->clat_egress_link);
if (err != 0) {
libbpf_strerror(err, buf, sizeof(buf));
_LOGD("clat: failed to destroy the egress link");
}
self->priv.p->clat_egress_link = NULL;
}
nm_clear_pointer(&self->priv.p->clat_bpf, clat_bpf__destroy); nm_clear_pointer(&self->priv.p->clat_bpf, clat_bpf__destroy);
} }
@ -5628,12 +5624,6 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
char buf[100]; char buf[100];
struct clat_config clat_config; struct clat_config clat_config;
gboolean v6_changed; gboolean v6_changed;
DECLARE_LIBBPF_OPTS(bpf_tc_hook,
hook,
.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS,
.ifindex = self->priv.ifindex);
DECLARE_LIBBPF_OPTS(bpf_tc_opts, attach_egress);
DECLARE_LIBBPF_OPTS(bpf_tc_opts, attach_ingress);
if (l3cd && nm_l3_config_data_get_pref64(l3cd, &_l3cd_pref64_inner, &l3cd_pref64_plen)) { if (l3cd && nm_l3_config_data_get_pref64(l3cd, &_l3cd_pref64_inner, &l3cd_pref64_plen)) {
l3cd_pref64 = &_l3cd_pref64_inner; l3cd_pref64 = &_l3cd_pref64_inner;
@ -5642,71 +5632,35 @@ _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 (l3cd_pref64 && self->priv.p->clat_address_4 && self->priv.p->clat_address_6_valid) {
if (!self->priv.p->clat_bpf) { if (!self->priv.p->clat_bpf) {
_LOGT("clat: attaching the BPF program"); _LOGT("clat: attaching the BPF program");
self->priv.p->clat_bpf = clat_bpf__open();
err = libbpf_get_error(self->priv.p->clat_bpf); self->priv.p->clat_bpf = clat_bpf__open_and_load();
if (err) { if (!self->priv.p->clat_bpf) {
libbpf_strerror(err, buf, sizeof(buf)); libbpf_strerror(errno, buf, sizeof(buf));
_LOGW("clat: failed to open the BPF program: %s", buf); _LOGW("clat: failed to open and load the BPF program: %s", buf);
clat_bpf__destroy(self->priv.p->clat_bpf);
self->priv.p->clat_bpf = NULL;
return; return;
} }
err = clat_bpf__load(self->priv.p->clat_bpf); self->priv.p->clat_ingress_link =
if (err) { bpf_program__attach_tcx(self->priv.p->clat_bpf->progs.clat_ingress,
libbpf_strerror(err, buf, sizeof(buf)); self->priv.ifindex,
_LOGW("clat: failed to load the BPF program: %s", buf); NULL);
clat_bpf__destroy(self->priv.p->clat_bpf); if (!self->priv.p->clat_ingress_link) {
self->priv.p->clat_bpf = NULL; libbpf_strerror(errno, buf, sizeof(buf));
_LOGW("clat: failed to attach the ingress program: %s", buf);
return; return;
} }
err = bpf_tc_hook_create(&hook); self->priv.p->clat_egress_link =
if (err && err != -EEXIST) { bpf_program__attach_tcx(self->priv.p->clat_bpf->progs.clat_egress,
libbpf_strerror(err, buf, sizeof(buf)); self->priv.ifindex,
_LOGW("clat: failed to create the BPF hook: %s", buf); NULL);
clat_bpf__destroy(self->priv.p->clat_bpf); if (!self->priv.p->clat_egress_link) {
self->priv.p->clat_bpf = NULL; libbpf_strerror(errno, buf, sizeof(buf));
_LOGW("clat: failed to attach the egress program: %s", buf);
return; return;
} }
attach_ingress.prog_fd = bpf_program__fd(self->priv.p->clat_bpf->progs.clat_ingress); _LOGT("clat: program attached successfully");
if (attach_ingress.prog_fd < 0) {
_LOGW("clat: couldn't find the BPF ingress");
clat_bpf__destroy(self->priv.p->clat_bpf);
self->priv.p->clat_bpf = NULL;
return;
}
attach_egress.prog_fd = bpf_program__fd(self->priv.p->clat_bpf->progs.clat_egress);
if (attach_egress.prog_fd < 0) {
_LOGW("clat: couldn't find the BPF egress");
clat_bpf__destroy(self->priv.p->clat_bpf);
self->priv.p->clat_bpf = NULL;
return;
}
hook.attach_point = BPF_TC_INGRESS;
err = bpf_tc_attach(&hook, &attach_ingress);
if (err) {
libbpf_strerror(err, buf, sizeof(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;
}
self->priv.p->clat_attach_ingress = attach_ingress;
hook.attach_point = BPF_TC_EGRESS;
err = bpf_tc_attach(&hook, &attach_egress);
if (err) {
libbpf_strerror(err, buf, sizeof(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;
}
self->priv.p->clat_attach_egress = attach_egress;
} }
/* Pass configuration to the BPF program */ /* Pass configuration to the BPF program */