netfilter: flowtable: inline pppoe encapsulation in xmit path

Push the pppoe header from the flowtable xmit path, inlining is faster
than the original xmit path because it can avoid some locking.

This is based on a patch originally written by wenxu.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Pablo Neira Ayuso 2025-11-18 23:59:47 +01:00
parent c653d5a78f
commit 18d27bed08
2 changed files with 44 additions and 7 deletions

View File

@ -413,6 +413,44 @@ static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx,
return 1;
}
static int nf_flow_pppoe_push(struct sk_buff *skb, u16 id)
{
int data_len = skb->len + sizeof(__be16);
struct ppp_hdr {
struct pppoe_hdr hdr;
__be16 proto;
} *ph;
__be16 proto;
if (skb_cow_head(skb, PPPOE_SES_HLEN))
return -1;
switch (skb->protocol) {
case htons(ETH_P_IP):
proto = htons(PPP_IP);
break;
case htons(ETH_P_IPV6):
proto = htons(PPP_IPV6);
break;
default:
return -1;
}
__skb_push(skb, PPPOE_SES_HLEN);
skb_reset_network_header(skb);
ph = (struct ppp_hdr *)(skb->data);
ph->hdr.ver = 1;
ph->hdr.type = 1;
ph->hdr.code = 0;
ph->hdr.sid = htons(id);
ph->hdr.length = htons(data_len);
ph->proto = proto;
skb->protocol = htons(ETH_P_PPP_SES);
return 0;
}
static int nf_flow_encap_push(struct sk_buff *skb,
struct flow_offload_tuple *tuple)
{
@ -426,6 +464,10 @@ static int nf_flow_encap_push(struct sk_buff *skb,
tuple->encap[i].id) < 0)
return -1;
break;
case htons(ETH_P_PPP_SES):
if (nf_flow_pppoe_push(skb, tuple->encap[i].id) < 0)
return -1;
break;
}
}

View File

@ -122,11 +122,8 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
info->encap[info->num_encaps].id = path->encap.id;
info->encap[info->num_encaps].proto = path->encap.proto;
info->num_encaps++;
if (path->type == DEV_PATH_PPPOE) {
if (!info->outdev)
info->outdev = path->dev;
if (path->type == DEV_PATH_PPPOE)
memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
}
break;
case DEV_PATH_BRIDGE:
if (is_zero_ether_addr(info->h_source))
@ -161,9 +158,7 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
break;
}
}
if (!info->outdev)
info->outdev = info->indev;
info->outdev = info->indev;
info->hw_outdev = info->indev;
if (nf_flowtable_hw_offload(flowtable) &&