netfilter: flowtable: inline vlan encapsulation in xmit path

Push the vlan header from the flowtable xmit path, instead of passing
the packet to the vlan device.

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-10-10 12:39:15 +02:00
parent b5964aac51
commit c653d5a78f
2 changed files with 29 additions and 3 deletions

View File

@ -413,6 +413,25 @@ static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx,
return 1;
}
static int nf_flow_encap_push(struct sk_buff *skb,
struct flow_offload_tuple *tuple)
{
int i;
for (i = 0; i < tuple->encap_num; i++) {
switch (tuple->encap[i].proto) {
case htons(ETH_P_8021Q):
case htons(ETH_P_8021AD):
if (skb_vlan_push(skb, tuple->encap[i].proto,
tuple->encap[i].id) < 0)
return -1;
break;
}
}
return 0;
}
unsigned int
nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
@ -450,6 +469,9 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
dir = tuplehash->tuple.dir;
flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
if (nf_flow_encap_push(skb, &flow->tuplehash[!dir].tuple) < 0)
return NF_DROP;
switch (tuplehash->tuple.xmit_type) {
case FLOW_OFFLOAD_XMIT_NEIGH:
rt = dst_rtable(tuplehash->tuple.dst_cache);
@ -754,6 +776,9 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
dir = tuplehash->tuple.dir;
flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
if (nf_flow_encap_push(skb, &flow->tuplehash[!dir].tuple) < 0)
return NF_DROP;
switch (tuplehash->tuple.xmit_type) {
case FLOW_OFFLOAD_XMIT_NEIGH:
rt = dst_rt6_info(tuplehash->tuple.dst_cache);

View File

@ -119,13 +119,14 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
info->indev = NULL;
break;
}
if (!info->outdev)
info->outdev = path->dev;
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 (path->type == DEV_PATH_PPPOE) {
if (!info->outdev)
info->outdev = path->dev;
memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
}
break;
case DEV_PATH_BRIDGE:
if (is_zero_ether_addr(info->h_source))