new file mode 100644
@@ -0,0 +1,157 @@
+--- a/net/netfilter/nf_flow_table_ip.c
++++ b/net/netfilter/nf_flow_table_ip.c
+@@ -145,6 +145,7 @@ static void nf_flow_tuple_encap(struct s
+ struct vlan_ethhdr *veth;
+ struct pppoe_hdr *phdr;
+ int i = 0;
++ __be16 *proto_ptr;
+
+ if (skb_vlan_tag_present(skb)) {
+ tuple->encap[i].id = skb_vlan_tag_get(skb);
+@@ -156,6 +157,17 @@ static void nf_flow_tuple_encap(struct s
+ veth = (struct vlan_ethhdr *)skb_mac_header(skb);
+ tuple->encap[i].id = ntohs(veth->h_vlan_TCI);
+ tuple->encap[i].proto = skb->protocol;
++ i++;
++
++ proto_ptr = &veth->h_vlan_encapsulated_proto;
++ if (*proto_ptr == htons(ETH_P_8021Q)) {
++ tuple->encap[i].id = ntohs(*(proto_ptr + 1));
++ tuple->encap[i].proto = htons(ETH_P_8021Q);
++ } else if (*proto_ptr == htons(ETH_P_PPP_SES)) {
++ phdr = (struct pppoe_hdr *)(skb_mac_header(skb) + ETH_HLEN + VLAN_HLEN);
++ tuple->encap[i].id = ntohs(phdr->sid);
++ tuple->encap[i].proto = htons(ETH_P_PPP_SES);
++ }
+ break;
+ case htons(ETH_P_PPP_SES):
+ phdr = (struct pppoe_hdr *)(skb_mac_header(skb) + ETH_HLEN);
+@@ -248,11 +260,11 @@ static unsigned int nf_flow_xmit_xfrm(st
+ return NF_STOLEN;
+ }
+
+-static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb)
++static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb, u32 offset)
+ {
+ __be16 proto;
+
+- proto = *((__be16 *)(skb_mac_header(skb) + ETH_HLEN +
++ proto = *((__be16 *)(skb_mac_header(skb) + ETH_HLEN + offset +
+ sizeof(struct pppoe_hdr)));
+ switch (proto) {
+ case htons(PPP_IP):
+@@ -268,17 +280,29 @@ static bool nf_flow_skb_encap_protocol(c
+ u32 *offset)
+ {
+ struct vlan_ethhdr *veth;
++ __be16 *proto_ptr;
+
+ switch (skb->protocol) {
+ case htons(ETH_P_8021Q):
+ veth = (struct vlan_ethhdr *)skb_mac_header(skb);
+- if (veth->h_vlan_encapsulated_proto == proto) {
++ proto_ptr = &veth->h_vlan_encapsulated_proto;
++ *offset += VLAN_HLEN;
++
++ if (*proto_ptr == htons(ETH_P_PPP_SES))
++ goto pppoe;
++
++ if (*proto_ptr == htons(ETH_P_8021Q)) {
+ *offset += VLAN_HLEN;
+- return true;
++ proto_ptr += 2;
+ }
++
++ if (*proto_ptr == proto)
++ return true;
++
+ break;
+ case htons(ETH_P_PPP_SES):
+- if (nf_flow_pppoe_proto(skb) == proto) {
++pppoe:
++ if (nf_flow_pppoe_proto(skb, *offset) == proto) {
+ *offset += PPPOE_SES_HLEN;
+ return true;
+ }
+@@ -307,7 +331,7 @@ static void nf_flow_encap_pop(struct sk_
+ skb_reset_network_header(skb);
+ break;
+ case htons(ETH_P_PPP_SES):
+- skb->protocol = nf_flow_pppoe_proto(skb);
++ skb->protocol = nf_flow_pppoe_proto(skb, 0);
+ skb_pull(skb, PPPOE_SES_HLEN);
+ skb_reset_network_header(skb);
+ break;
+@@ -315,6 +339,62 @@ static void nf_flow_encap_pop(struct sk_
+ }
+ }
+
++static int nf_flow_encap_put(struct sk_buff *skb, unsigned short *type,
++ struct flow_offload_tuple_rhash *tuplehash)
++{
++ struct vlan_hdr *vlan_hdr = NULL;
++ struct pppoe_hdr *ph;
++ struct pppoe_tag *pt;
++ u16 data_len = skb->len;
++ int i;
++
++ if ((skb->data - PPPOE_SES_HLEN - VLAN_HLEN * 2) < skb->head)
++ if (skb_cow_head(skb, LL_RESERVED_SPACE(skb->dev) +
++ PPPOE_SES_HLEN + VLAN_HLEN * 2))
++ return -1;
++
++ /* Offset the pointer in the reverse direction */
++ tuplehash = (tuplehash->tuple.dir) ? (tuplehash - 1) : (tuplehash + 1);
++ for (i = tuplehash->tuple.encap_num - 1; i >= 0; i--) {
++ switch (tuplehash->tuple.encap[i].proto) {
++ case htons(ETH_P_8021Q):
++ vlan_hdr = __skb_push(skb, VLAN_HLEN);
++ vlan_hdr->h_vlan_TCI = htons(tuplehash->tuple.encap[i].id);
++ vlan_hdr->h_vlan_encapsulated_proto = htons(*type);
++
++ skb->protocol = htons(ETH_P_8021Q);
++ *type = ETH_P_8021Q;
++ break;
++ case htons(ETH_P_PPP_SES):
++ __skb_push(skb, PPPOE_SES_HLEN);
++ skb_reset_network_header(skb);
++
++ ph = pppoe_hdr(skb);
++ pt = ph->tag;
++ ph->ver = 1;
++ ph->type = 1;
++ ph->code = 0;
++ ph->sid = htons(tuplehash->tuple.encap[i].id);
++ ph->length = htons(data_len+2);
++
++ switch (*type) {
++ case ETH_P_IP:
++ pt->tag_type = htons(PPP_IP);
++ break;
++ case ETH_P_IPV6:
++ pt->tag_type = htons(PPP_IPV6);
++ break;
++ }
++
++ skb->protocol = htons(ETH_P_PPP_SES);
++ *type = ETH_P_PPP_SES;
++ break;
++ }
++ }
++
++ return 0;
++}
++
+ static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
+ const struct flow_offload_tuple_rhash *tuplehash,
+ unsigned short type)
+@@ -326,6 +406,9 @@ static unsigned int nf_flow_queue_xmit(s
+ return NF_DROP;
+
+ skb->dev = outdev;
++ if (nf_flow_encap_put(skb, &type, (void *)tuplehash))
++ return NF_DROP;
++
+ dev_hard_header(skb, skb->dev, type, tuplehash->tuple.out.h_dest,
+ tuplehash->tuple.out.h_source, skb->len);
+ dev_queue_xmit(skb);
Support (8021q + 8021q + pppoe) encap tuple. We need encap put to skb Before dev_hard_header(). Signed-off-by: LiXiong Liu <lxliu@ikuai8.com> --- ...ilter-flowtable-support-nf_flow_encap_put.patch | 157 +++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 target/linux/generic/pending-5.10/706-03-netfilter-flowtable-support-nf_flow_encap_put.patch