[PATCH-22.03 3/4] kernel: support nf_flow_encap_put and more encap

LiXiong Liu lxliu at ikuai8.com
Thu Nov 24 03:24:07 PST 2022


Support (8021q + 8021q + pppoe) encap tuple.
We need encap put to skb Before dev_hard_header().

Signed-off-by: LiXiong Liu <lxliu at 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

diff --git a/target/linux/generic/pending-5.10/706-03-netfilter-flowtable-support-nf_flow_encap_put.patch b/target/linux/generic/pending-5.10/706-03-netfilter-flowtable-support-nf_flow_encap_put.patch
new file mode 100644
index 0000000..545a956
--- /dev/null
+++ b/target/linux/generic/pending-5.10/706-03-netfilter-flowtable-support-nf_flow_encap_put.patch
@@ -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);
-- 
2.7.4




More information about the openwrt-devel mailing list