]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netfilter: flowtable: inline pppoe encapsulation in xmit path
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 18 Nov 2025 22:59:47 +0000 (23:59 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 28 Nov 2025 00:00:14 +0000 (00:00 +0000)
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>
net/netfilter/nf_flow_table_ip.c
net/netfilter/nf_flow_table_path.c

index aef799edca9f788cbc01316d016540afeb43c600..ee6ec63257d11967065935e54f9980aa772e29a5 100644 (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;
                }
        }
 
index 38ebda1afdceb8340ec015f9a1be643ef759e8e1..c51e310bb2ab23172bc60355292c515bd2bda286 100644 (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) &&