aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/pending-5.10
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/pending-5.10')
-rw-r--r--target/linux/generic/pending-5.10/640-00-netfilter-flowtable-add-hash-offset-field-to-tuple.patch52
-rw-r--r--target/linux/generic/pending-5.10/640-01-netfilter-flowtable-add-xmit-path-types.patch188
-rw-r--r--target/linux/generic/pending-5.10/640-02-net-resolve-forwarding-path-from-virtual-netdevice-a.patch170
-rw-r--r--target/linux/generic/pending-5.10/640-03-net-8021q-resolve-forwarding-path-for-vlan-devices.patch80
-rw-r--r--target/linux/generic/pending-5.10/640-04-bridge-resolve-forwarding-path-for-bridge-devices.patch62
-rw-r--r--target/linux/generic/pending-5.10/640-05-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch191
-rw-r--r--target/linux/generic/pending-5.10/640-06-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch344
-rw-r--r--target/linux/generic/pending-5.10/640-07-netfilter-flowtable-add-vlan-support.patch391
-rw-r--r--target/linux/generic/pending-5.10/640-08-selftests-netfilter-flowtable-bridge-and-VLAN-suppor.patch107
-rw-r--r--target/linux/generic/pending-5.10/640-09-net-bridge-resolve-VLAN-tag-actions-in-forwarding-pa.patch207
-rw-r--r--target/linux/generic/pending-5.10/640-10-netfilter-nft_flow_offload-add-bridge-vlan-filtering.patch31
-rw-r--r--target/linux/generic/pending-5.10/640-11-net-ppp-resolve-forwarding-path-for-bridge-pppoe-dev.patch100
-rw-r--r--target/linux/generic/pending-5.10/640-12-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch60
-rw-r--r--target/linux/generic/pending-5.10/640-13-netfilter-flowtable-add-pppoe-support.patch263
-rw-r--r--target/linux/generic/pending-5.10/640-14-netfilter-nft_flow_offload-add-dsa-support.patch30
-rw-r--r--target/linux/generic/pending-5.10/640-15-netfilter-flowtable-add-offload-support-for-xmit-pat.patch308
-rw-r--r--target/linux/generic/pending-5.10/640-16-dsa-slave-add-support-for-TC_SETUP_FT.patch53
-rw-r--r--target/linux/generic/pending-5.10/640-17-netfilter-nft_flow_offload-use-direct-xmit-if-hardwa.patch108
-rw-r--r--target/linux/generic/pending-5.10/640-18-netfilter-nf_flow_table-fix-untagging-with-hardware-.patch122
-rw-r--r--target/linux/generic/pending-5.10/640-19-net-flow_offload-add-FLOW_ACTION_PPPOE_PUSH.patch26
-rw-r--r--target/linux/generic/pending-5.10/640-20-netfilter-flowtable-support-for-FLOW_ACTION_PPPOE_PU.patch31
-rw-r--r--target/linux/generic/pending-5.10/770-00-net-ethernet-mtk_eth_soc-use-napi_consume_skb.patch6
-rw-r--r--target/linux/generic/pending-5.10/770-01-net-ethernet-mtk_eth_soc-significantly-reduce-mdio-b.patch2
-rw-r--r--target/linux/generic/pending-5.10/770-02-net-ethernet-mtk_eth_soc-fix-rx-vlan-offload.patch2
-rw-r--r--target/linux/generic/pending-5.10/770-03-net-ethernet-mtk_eth_soc-fix-unnecessary-tx-queue-st.patch6
-rw-r--r--target/linux/generic/pending-5.10/770-04-net-ethernet-mtk_eth_soc-use-larger-burst-size-for-q.patch2
-rw-r--r--target/linux/generic/pending-5.10/770-05-net-ethernet-mtk_eth_soc-increase-DMA-ring-sizes.patch2
-rw-r--r--target/linux/generic/pending-5.10/770-06-net-ethernet-mtk_eth_soc-implement-dynamic-interrupt.patch26
-rw-r--r--target/linux/generic/pending-5.10/770-08-net-ethernet-mtk_eth_soc-cache-hardware-pointer-of-l.patch4
-rw-r--r--target/linux/generic/pending-5.10/770-09-net-ethernet-mtk_eth_soc-only-read-the-full-rx-descr.patch4
-rw-r--r--target/linux/generic/pending-5.10/770-13-net-ethernet-mtk_eth_soc-fix-parsing-packets-in-GDM.patch67
-rw-r--r--target/linux/generic/pending-5.10/770-15-net-ethernet-mtk_eth_soc-add-support-for-initializin.patch1307
-rw-r--r--target/linux/generic/pending-5.10/770-16-net-ethernet-mtk_eth_soc-add-flow-offloading-support.patch574
33 files changed, 27 insertions, 4899 deletions
diff --git a/target/linux/generic/pending-5.10/640-00-netfilter-flowtable-add-hash-offset-field-to-tuple.patch b/target/linux/generic/pending-5.10/640-00-netfilter-flowtable-add-hash-offset-field-to-tuple.patch
deleted file mode 100644
index c881ccfcb0..0000000000
--- a/target/linux/generic/pending-5.10/640-00-netfilter-flowtable-add-hash-offset-field-to-tuple.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Fri, 20 Nov 2020 13:49:13 +0100
-Subject: [PATCH] netfilter: flowtable: add hash offset field to tuple
-
-Add a placeholder field to calculate hash tuple offset. Similar to
-2c407aca6497 ("netfilter: conntrack: avoid gcc-10 zero-length-bounds
-warning").
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -107,6 +107,10 @@ struct flow_offload_tuple {
-
- u8 l3proto;
- u8 l4proto;
-+
-+ /* All members above are keys for lookups, see flow_offload_hash(). */
-+ struct { } __hash;
-+
- u8 dir;
-
- u16 mtu;
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -191,14 +191,14 @@ static u32 flow_offload_hash(const void
- {
- const struct flow_offload_tuple *tuple = data;
-
-- return jhash(tuple, offsetof(struct flow_offload_tuple, dir), seed);
-+ return jhash(tuple, offsetof(struct flow_offload_tuple, __hash), seed);
- }
-
- static u32 flow_offload_hash_obj(const void *data, u32 len, u32 seed)
- {
- const struct flow_offload_tuple_rhash *tuplehash = data;
-
-- return jhash(&tuplehash->tuple, offsetof(struct flow_offload_tuple, dir), seed);
-+ return jhash(&tuplehash->tuple, offsetof(struct flow_offload_tuple, __hash), seed);
- }
-
- static int flow_offload_hash_cmp(struct rhashtable_compare_arg *arg,
-@@ -207,7 +207,7 @@ static int flow_offload_hash_cmp(struct
- const struct flow_offload_tuple *tuple = arg->key;
- const struct flow_offload_tuple_rhash *x = ptr;
-
-- if (memcmp(&x->tuple, tuple, offsetof(struct flow_offload_tuple, dir)))
-+ if (memcmp(&x->tuple, tuple, offsetof(struct flow_offload_tuple, __hash)))
- return 1;
-
- return 0;
diff --git a/target/linux/generic/pending-5.10/640-01-netfilter-flowtable-add-xmit-path-types.patch b/target/linux/generic/pending-5.10/640-01-netfilter-flowtable-add-xmit-path-types.patch
deleted file mode 100644
index e47d03e48d..0000000000
--- a/target/linux/generic/pending-5.10/640-01-netfilter-flowtable-add-xmit-path-types.patch
+++ /dev/null
@@ -1,188 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Fri, 20 Nov 2020 13:49:14 +0100
-Subject: [PATCH] netfilter: flowtable: add xmit path types
-
-Add the xmit_type field that defines the two supported xmit paths in the
-flowtable data plane, which are the neighbour and the xfrm xmit paths.
-This patch prepares for new flowtable xmit path types to come.
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -89,6 +89,11 @@ enum flow_offload_tuple_dir {
- FLOW_OFFLOAD_DIR_MAX = IP_CT_DIR_MAX
- };
-
-+enum flow_offload_xmit_type {
-+ FLOW_OFFLOAD_XMIT_NEIGH = 0,
-+ FLOW_OFFLOAD_XMIT_XFRM,
-+};
-+
- struct flow_offload_tuple {
- union {
- struct in_addr src_v4;
-@@ -111,7 +116,8 @@ struct flow_offload_tuple {
- /* All members above are keys for lookups, see flow_offload_hash(). */
- struct { } __hash;
-
-- u8 dir;
-+ u8 dir:6,
-+ xmit_type:2;
-
- u16 mtu;
-
-@@ -158,7 +164,8 @@ static inline __s32 nf_flow_timeout_delt
-
- struct nf_flow_route {
- struct {
-- struct dst_entry *dst;
-+ struct dst_entry *dst;
-+ enum flow_offload_xmit_type xmit_type;
- } tuple[FLOW_OFFLOAD_DIR_MAX];
- };
-
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -95,6 +95,7 @@ static int flow_offload_fill_route(struc
- }
-
- flow_tuple->iifidx = other_dst->dev->ifindex;
-+ flow_tuple->xmit_type = route->tuple[dir].xmit_type;
- flow_tuple->dst_cache = dst;
-
- return 0;
---- a/net/netfilter/nf_flow_table_ip.c
-+++ b/net/netfilter/nf_flow_table_ip.c
-@@ -220,10 +220,20 @@ static bool nf_flow_exceeds_mtu(const st
- return true;
- }
-
--static int nf_flow_offload_dst_check(struct dst_entry *dst)
-+static inline struct dst_entry *
-+nft_flow_dst(struct flow_offload_tuple_rhash *tuplehash)
- {
-- if (unlikely(dst_xfrm(dst)))
-+ return tuplehash->tuple.dst_cache;
-+}
-+
-+static int nf_flow_offload_dst_check(struct flow_offload_tuple_rhash *tuplehash)
-+{
-+ struct dst_entry *dst;
-+
-+ if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
-+ dst = nft_flow_dst(tuplehash);
- return dst_check(dst, 0) ? 0 : -1;
-+ }
-
- return 0;
- }
-@@ -265,8 +275,6 @@ nf_flow_offload_ip_hook(void *priv, stru
-
- dir = tuplehash->tuple.dir;
- flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
-- rt = (struct rtable *)flow->tuplehash[dir].tuple.dst_cache;
-- outdev = rt->dst.dev;
-
- if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
- return NF_ACCEPT;
-@@ -280,7 +288,7 @@ nf_flow_offload_ip_hook(void *priv, stru
-
- flow_offload_refresh(flow_table, flow);
-
-- if (nf_flow_offload_dst_check(&rt->dst)) {
-+ if (nf_flow_offload_dst_check(tuplehash)) {
- flow_offload_teardown(flow);
- return NF_ACCEPT;
- }
-@@ -295,13 +303,16 @@ nf_flow_offload_ip_hook(void *priv, stru
- if (flow_table->flags & NF_FLOWTABLE_COUNTER)
- nf_ct_acct_update(flow->ct, tuplehash->tuple.dir, skb->len);
-
-- if (unlikely(dst_xfrm(&rt->dst))) {
-+ rt = (struct rtable *)tuplehash->tuple.dst_cache;
-+
-+ if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
- memset(skb->cb, 0, sizeof(struct inet_skb_parm));
- IPCB(skb)->iif = skb->dev->ifindex;
- IPCB(skb)->flags = IPSKB_FORWARDED;
- return nf_flow_xmit_xfrm(skb, state, &rt->dst);
- }
-
-+ outdev = rt->dst.dev;
- skb->dev = outdev;
- nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
- skb_dst_set_noref(skb, &rt->dst);
-@@ -506,8 +517,6 @@ nf_flow_offload_ipv6_hook(void *priv, st
-
- dir = tuplehash->tuple.dir;
- flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
-- rt = (struct rt6_info *)flow->tuplehash[dir].tuple.dst_cache;
-- outdev = rt->dst.dev;
-
- if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
- return NF_ACCEPT;
-@@ -518,7 +527,7 @@ nf_flow_offload_ipv6_hook(void *priv, st
-
- flow_offload_refresh(flow_table, flow);
-
-- if (nf_flow_offload_dst_check(&rt->dst)) {
-+ if (nf_flow_offload_dst_check(tuplehash)) {
- flow_offload_teardown(flow);
- return NF_ACCEPT;
- }
-@@ -536,13 +545,16 @@ nf_flow_offload_ipv6_hook(void *priv, st
- if (flow_table->flags & NF_FLOWTABLE_COUNTER)
- nf_ct_acct_update(flow->ct, tuplehash->tuple.dir, skb->len);
-
-- if (unlikely(dst_xfrm(&rt->dst))) {
-+ rt = (struct rt6_info *)tuplehash->tuple.dst_cache;
-+
-+ if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
- memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
- IP6CB(skb)->iif = skb->dev->ifindex;
- IP6CB(skb)->flags = IP6SKB_FORWARDED;
- return nf_flow_xmit_xfrm(skb, state, &rt->dst);
- }
-
-+ outdev = rt->dst.dev;
- skb->dev = outdev;
- nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
- skb_dst_set_noref(skb, &rt->dst);
---- a/net/netfilter/nft_flow_offload.c
-+++ b/net/netfilter/nft_flow_offload.c
-@@ -19,6 +19,22 @@ struct nft_flow_offload {
- struct nft_flowtable *flowtable;
- };
-
-+static enum flow_offload_xmit_type nft_xmit_type(struct dst_entry *dst)
-+{
-+ if (dst_xfrm(dst))
-+ return FLOW_OFFLOAD_XMIT_XFRM;
-+
-+ return FLOW_OFFLOAD_XMIT_NEIGH;
-+}
-+
-+static void nft_default_forward_path(struct nf_flow_route *route,
-+ struct dst_entry *dst_cache,
-+ enum ip_conntrack_dir dir)
-+{
-+ route->tuple[dir].dst = dst_cache;
-+ route->tuple[dir].xmit_type = nft_xmit_type(dst_cache);
-+}
-+
- static int nft_flow_route(const struct nft_pktinfo *pkt,
- const struct nf_conn *ct,
- struct nf_flow_route *route,
-@@ -44,8 +60,8 @@ static int nft_flow_route(const struct n
- if (!other_dst)
- return -ENOENT;
-
-- route->tuple[dir].dst = this_dst;
-- route->tuple[!dir].dst = other_dst;
-+ nft_default_forward_path(route, this_dst, dir);
-+ nft_default_forward_path(route, other_dst, !dir);
-
- return 0;
- }
diff --git a/target/linux/generic/pending-5.10/640-02-net-resolve-forwarding-path-from-virtual-netdevice-a.patch b/target/linux/generic/pending-5.10/640-02-net-resolve-forwarding-path-from-virtual-netdevice-a.patch
deleted file mode 100644
index 224831d593..0000000000
--- a/target/linux/generic/pending-5.10/640-02-net-resolve-forwarding-path-from-virtual-netdevice-a.patch
+++ /dev/null
@@ -1,170 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Thu, 4 Mar 2021 23:18:11 +0100
-Subject: [PATCH] net: resolve forwarding path from virtual netdevice and
- HW destination address
-
-This patch adds dev_fill_forward_path() which resolves the path to reach
-the real netdevice from the IP forwarding side. This function takes as
-input the netdevice and the destination hardware address and it walks
-down the devices calling .ndo_fill_forward_path() for each device until
-the real device is found.
-
-For instance, assuming the following topology:
-
- IP forwarding
- / \
- br0 eth0
- / \
- eth1 eth2
- .
- .
- .
- ethX
- ab:cd:ef:ab:cd:ef
-
-where eth1 and eth2 are bridge ports and eth0 provides WAN connectivity.
-ethX is the interface in another box which is connected to the eth1
-bridge port.
-
-For packets going through IP forwarding to br0 whose destination MAC
-address is ab:cd:ef:ab:cd:ef, dev_fill_forward_path() provides the
-following path:
-
- br0 -> eth1
-
-.ndo_fill_forward_path for br0 looks up at the FDB for the bridge port
-from the destination MAC address to get the bridge port eth1.
-
-This information allows to create a fast path that bypasses the classic
-bridge and IP forwarding paths, so packets go directly from the bridge
-port eth1 to eth0 (wan interface) and vice versa.
-
- fast path
- .------------------------.
- / \
- | IP forwarding |
- | / \ \/
- | br0 eth0
- . / \
- -> eth1 eth2
- .
- .
- .
- ethX
- ab:cd:ef:ab:cd:ef
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -827,6 +827,27 @@ typedef u16 (*select_queue_fallback_t)(s
- struct sk_buff *skb,
- struct net_device *sb_dev);
-
-+enum net_device_path_type {
-+ DEV_PATH_ETHERNET = 0,
-+};
-+
-+struct net_device_path {
-+ enum net_device_path_type type;
-+ const struct net_device *dev;
-+};
-+
-+#define NET_DEVICE_PATH_STACK_MAX 5
-+
-+struct net_device_path_stack {
-+ int num_paths;
-+ struct net_device_path path[NET_DEVICE_PATH_STACK_MAX];
-+};
-+
-+struct net_device_path_ctx {
-+ const struct net_device *dev;
-+ const u8 *daddr;
-+};
-+
- enum tc_setup_type {
- TC_SETUP_QDISC_MQPRIO,
- TC_SETUP_CLSU32,
-@@ -1273,6 +1294,8 @@ struct netdev_net_notifier {
- * struct net_device *(*ndo_get_peer_dev)(struct net_device *dev);
- * If a device is paired with a peer device, return the peer instance.
- * The caller must be under RCU read context.
-+ * int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx, struct net_device_path *path);
-+ * Get the forwarding path to reach the real device from the HW destination address
- */
- struct net_device_ops {
- int (*ndo_init)(struct net_device *dev);
-@@ -1481,6 +1504,8 @@ struct net_device_ops {
- int (*ndo_tunnel_ctl)(struct net_device *dev,
- struct ip_tunnel_parm *p, int cmd);
- struct net_device * (*ndo_get_peer_dev)(struct net_device *dev);
-+ int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx,
-+ struct net_device_path *path);
- };
-
- /**
-@@ -2795,6 +2820,8 @@ void dev_remove_offload(struct packet_of
-
- int dev_get_iflink(const struct net_device *dev);
- int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
-+int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
-+ struct net_device_path_stack *stack);
- struct net_device *__dev_get_by_flags(struct net *net, unsigned short flags,
- unsigned short mask);
- struct net_device *dev_get_by_name(struct net *net, const char *name);
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -847,6 +847,52 @@ int dev_fill_metadata_dst(struct net_dev
- }
- EXPORT_SYMBOL_GPL(dev_fill_metadata_dst);
-
-+static struct net_device_path *dev_fwd_path(struct net_device_path_stack *stack)
-+{
-+ int k = stack->num_paths++;
-+
-+ if (WARN_ON_ONCE(k >= NET_DEVICE_PATH_STACK_MAX))
-+ return NULL;
-+
-+ return &stack->path[k];
-+}
-+
-+int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
-+ struct net_device_path_stack *stack)
-+{
-+ const struct net_device *last_dev;
-+ struct net_device_path_ctx ctx = {
-+ .dev = dev,
-+ .daddr = daddr,
-+ };
-+ struct net_device_path *path;
-+ int ret = 0;
-+
-+ stack->num_paths = 0;
-+ while (ctx.dev && ctx.dev->netdev_ops->ndo_fill_forward_path) {
-+ last_dev = ctx.dev;
-+ path = dev_fwd_path(stack);
-+ if (!path)
-+ return -1;
-+
-+ memset(path, 0, sizeof(struct net_device_path));
-+ ret = ctx.dev->netdev_ops->ndo_fill_forward_path(&ctx, path);
-+ if (ret < 0)
-+ return -1;
-+
-+ if (WARN_ON_ONCE(last_dev == ctx.dev))
-+ return -1;
-+ }
-+ path = dev_fwd_path(stack);
-+ if (!path)
-+ return -1;
-+ path->type = DEV_PATH_ETHERNET;
-+ path->dev = ctx.dev;
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(dev_fill_forward_path);
-+
- /**
- * __dev_get_by_name - find a device by its name
- * @net: the applicable net namespace
diff --git a/target/linux/generic/pending-5.10/640-03-net-8021q-resolve-forwarding-path-for-vlan-devices.patch b/target/linux/generic/pending-5.10/640-03-net-8021q-resolve-forwarding-path-for-vlan-devices.patch
deleted file mode 100644
index 69e025be26..0000000000
--- a/target/linux/generic/pending-5.10/640-03-net-8021q-resolve-forwarding-path-for-vlan-devices.patch
+++ /dev/null
@@ -1,80 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Fri, 20 Nov 2020 13:49:16 +0100
-Subject: [PATCH] net: 8021q: resolve forwarding path for vlan devices
-
-Add .ndo_fill_forward_path for vlan devices.
-
-For instance, assuming the following topology:
-
- IP forwarding
- / \
- eth0.100 eth0
- |
- eth0
- .
- .
- .
- ethX
- ab:cd:ef:ab:cd:ef
-
-For packets going through IP forwarding to eth0.100 whose destination
-MAC address is ab:cd:ef:ab:cd:ef, dev_fill_forward_path() provides the
-following path:
-
- eth0.100 -> eth0
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -829,11 +829,18 @@ typedef u16 (*select_queue_fallback_t)(s
-
- enum net_device_path_type {
- DEV_PATH_ETHERNET = 0,
-+ DEV_PATH_VLAN,
- };
-
- struct net_device_path {
- enum net_device_path_type type;
- const struct net_device *dev;
-+ union {
-+ struct {
-+ u16 id;
-+ __be16 proto;
-+ } encap;
-+ };
- };
-
- #define NET_DEVICE_PATH_STACK_MAX 5
---- a/net/8021q/vlan_dev.c
-+++ b/net/8021q/vlan_dev.c
-@@ -767,6 +767,20 @@ static int vlan_dev_get_iflink(const str
- return real_dev->ifindex;
- }
-
-+static int vlan_dev_fill_forward_path(struct net_device_path_ctx *ctx,
-+ struct net_device_path *path)
-+{
-+ struct vlan_dev_priv *vlan = vlan_dev_priv(ctx->dev);
-+
-+ path->type = DEV_PATH_VLAN;
-+ path->encap.id = vlan->vlan_id;
-+ path->encap.proto = vlan->vlan_proto;
-+ path->dev = ctx->dev;
-+ ctx->dev = vlan->real_dev;
-+
-+ return 0;
-+}
-+
- static const struct ethtool_ops vlan_ethtool_ops = {
- .get_link_ksettings = vlan_ethtool_get_link_ksettings,
- .get_drvinfo = vlan_ethtool_get_drvinfo,
-@@ -805,6 +819,7 @@ static const struct net_device_ops vlan_
- #endif
- .ndo_fix_features = vlan_dev_fix_features,
- .ndo_get_iflink = vlan_dev_get_iflink,
-+ .ndo_fill_forward_path = vlan_dev_fill_forward_path,
- };
-
- static void vlan_dev_free(struct net_device *dev)
diff --git a/target/linux/generic/pending-5.10/640-04-bridge-resolve-forwarding-path-for-bridge-devices.patch b/target/linux/generic/pending-5.10/640-04-bridge-resolve-forwarding-path-for-bridge-devices.patch
deleted file mode 100644
index cfb817f20f..0000000000
--- a/target/linux/generic/pending-5.10/640-04-bridge-resolve-forwarding-path-for-bridge-devices.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Fri, 20 Nov 2020 13:49:17 +0100
-Subject: [PATCH] bridge: resolve forwarding path for bridge devices
-
-Add .ndo_fill_forward_path for bridge devices.
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -830,6 +830,7 @@ typedef u16 (*select_queue_fallback_t)(s
- enum net_device_path_type {
- DEV_PATH_ETHERNET = 0,
- DEV_PATH_VLAN,
-+ DEV_PATH_BRIDGE,
- };
-
- struct net_device_path {
---- a/net/bridge/br_device.c
-+++ b/net/bridge/br_device.c
-@@ -398,6 +398,32 @@ static int br_del_slave(struct net_devic
- return br_del_if(br, slave_dev);
- }
-
-+static int br_fill_forward_path(struct net_device_path_ctx *ctx,
-+ struct net_device_path *path)
-+{
-+ struct net_bridge_fdb_entry *f;
-+ struct net_bridge_port *dst;
-+ struct net_bridge *br;
-+
-+ if (netif_is_bridge_port(ctx->dev))
-+ return -1;
-+
-+ br = netdev_priv(ctx->dev);
-+ f = br_fdb_find_rcu(br, ctx->daddr, 0);
-+ if (!f || !f->dst)
-+ return -1;
-+
-+ dst = READ_ONCE(f->dst);
-+ if (!dst)
-+ return -1;
-+
-+ path->type = DEV_PATH_BRIDGE;
-+ path->dev = dst->br->dev;
-+ ctx->dev = dst->dev;
-+
-+ return 0;
-+}
-+
- static const struct ethtool_ops br_ethtool_ops = {
- .get_drvinfo = br_getinfo,
- .get_link = ethtool_op_get_link,
-@@ -432,6 +458,7 @@ static const struct net_device_ops br_ne
- .ndo_bridge_setlink = br_setlink,
- .ndo_bridge_dellink = br_dellink,
- .ndo_features_check = passthru_features_check,
-+ .ndo_fill_forward_path = br_fill_forward_path,
- };
-
- static struct device_type br_type = {
diff --git a/target/linux/generic/pending-5.10/640-05-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch b/target/linux/generic/pending-5.10/640-05-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch
deleted file mode 100644
index 1f61cff09d..0000000000
--- a/target/linux/generic/pending-5.10/640-05-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch
+++ /dev/null
@@ -1,191 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Fri, 20 Nov 2020 13:49:18 +0100
-Subject: [PATCH] netfilter: flowtable: use dev_fill_forward_path() to
- obtain ingress device
-
-Obtain the ingress device in the tuple from the route in the reply
-direction. Use dev_fill_forward_path() instead to get the real ingress
-device for this flow.
-
-Fall back to use the ingress device that the IP forwarding route
-provides if:
-
-- dev_fill_forward_path() finds no real ingress device.
-- the ingress device that is obtained is not part of the flowtable
- devices.
-- this route has a xfrm policy.
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -165,6 +165,9 @@ static inline __s32 nf_flow_timeout_delt
- struct nf_flow_route {
- struct {
- struct dst_entry *dst;
-+ struct {
-+ u32 ifindex;
-+ } in;
- enum flow_offload_xmit_type xmit_type;
- } tuple[FLOW_OFFLOAD_DIR_MAX];
- };
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -79,7 +79,6 @@ static int flow_offload_fill_route(struc
- enum flow_offload_tuple_dir dir)
- {
- struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
-- struct dst_entry *other_dst = route->tuple[!dir].dst;
- struct dst_entry *dst = route->tuple[dir].dst;
-
- if (!dst_hold_safe(route->tuple[dir].dst))
-@@ -94,7 +93,7 @@ static int flow_offload_fill_route(struc
- break;
- }
-
-- flow_tuple->iifidx = other_dst->dev->ifindex;
-+ flow_tuple->iifidx = route->tuple[dir].in.ifindex;
- flow_tuple->xmit_type = route->tuple[dir].xmit_type;
- flow_tuple->dst_cache = dst;
-
---- a/net/netfilter/nft_flow_offload.c
-+++ b/net/netfilter/nft_flow_offload.c
-@@ -31,14 +31,104 @@ static void nft_default_forward_path(str
- struct dst_entry *dst_cache,
- enum ip_conntrack_dir dir)
- {
-+ route->tuple[!dir].in.ifindex = dst_cache->dev->ifindex;
- route->tuple[dir].dst = dst_cache;
- route->tuple[dir].xmit_type = nft_xmit_type(dst_cache);
- }
-
-+static int nft_dev_fill_forward_path(const struct nf_flow_route *route,
-+ const struct dst_entry *dst_cache,
-+ const struct nf_conn *ct,
-+ enum ip_conntrack_dir dir,
-+ struct net_device_path_stack *stack)
-+{
-+ const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
-+ struct net_device *dev = dst_cache->dev;
-+ unsigned char ha[ETH_ALEN];
-+ struct neighbour *n;
-+ u8 nud_state;
-+
-+ n = dst_neigh_lookup(dst_cache, daddr);
-+ if (!n)
-+ return -1;
-+
-+ read_lock_bh(&n->lock);
-+ nud_state = n->nud_state;
-+ ether_addr_copy(ha, n->ha);
-+ read_unlock_bh(&n->lock);
-+ neigh_release(n);
-+
-+ if (!(nud_state & NUD_VALID))
-+ return -1;
-+
-+ return dev_fill_forward_path(dev, ha, stack);
-+}
-+
-+struct nft_forward_info {
-+ const struct net_device *indev;
-+};
-+
-+static void nft_dev_path_info(const struct net_device_path_stack *stack,
-+ struct nft_forward_info *info)
-+{
-+ const struct net_device_path *path;
-+ int i;
-+
-+ for (i = 0; i < stack->num_paths; i++) {
-+ path = &stack->path[i];
-+ switch (path->type) {
-+ case DEV_PATH_ETHERNET:
-+ info->indev = path->dev;
-+ break;
-+ case DEV_PATH_VLAN:
-+ case DEV_PATH_BRIDGE:
-+ default:
-+ info->indev = NULL;
-+ break;
-+ }
-+ }
-+}
-+
-+static bool nft_flowtable_find_dev(const struct net_device *dev,
-+ struct nft_flowtable *ft)
-+{
-+ struct nft_hook *hook;
-+ bool found = false;
-+
-+ list_for_each_entry_rcu(hook, &ft->hook_list, list) {
-+ if (hook->ops.dev != dev)
-+ continue;
-+
-+ found = true;
-+ break;
-+ }
-+
-+ return found;
-+}
-+
-+static void nft_dev_forward_path(struct nf_flow_route *route,
-+ const struct nf_conn *ct,
-+ enum ip_conntrack_dir dir,
-+ struct nft_flowtable *ft)
-+{
-+ const struct dst_entry *dst = route->tuple[dir].dst;
-+ struct net_device_path_stack stack;
-+ struct nft_forward_info info = {};
-+
-+ if (nft_dev_fill_forward_path(route, dst, ct, dir, &stack) >= 0)
-+ nft_dev_path_info(&stack, &info);
-+
-+ if (!info.indev || !nft_flowtable_find_dev(info.indev, ft))
-+ return;
-+
-+ route->tuple[!dir].in.ifindex = info.indev->ifindex;
-+}
-+
- static int nft_flow_route(const struct nft_pktinfo *pkt,
- const struct nf_conn *ct,
- struct nf_flow_route *route,
-- enum ip_conntrack_dir dir)
-+ enum ip_conntrack_dir dir,
-+ struct nft_flowtable *ft)
- {
- struct dst_entry *this_dst = skb_dst(pkt->skb);
- struct dst_entry *other_dst = NULL;
-@@ -63,6 +153,12 @@ static int nft_flow_route(const struct n
- nft_default_forward_path(route, this_dst, dir);
- nft_default_forward_path(route, other_dst, !dir);
-
-+ if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
-+ route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
-+ nft_dev_forward_path(route, ct, dir, ft);
-+ nft_dev_forward_path(route, ct, !dir, ft);
-+ }
-+
- return 0;
- }
-
-@@ -90,8 +186,8 @@ static void nft_flow_offload_eval(const
- struct nft_flow_offload *priv = nft_expr_priv(expr);
- struct nf_flowtable *flowtable = &priv->flowtable->data;
- struct tcphdr _tcph, *tcph = NULL;
-+ struct nf_flow_route route = {};
- enum ip_conntrack_info ctinfo;
-- struct nf_flow_route route;
- struct flow_offload *flow;
- enum ip_conntrack_dir dir;
- struct nf_conn *ct;
-@@ -128,7 +224,7 @@ static void nft_flow_offload_eval(const
- goto out;
-
- dir = CTINFO2DIR(ctinfo);
-- if (nft_flow_route(pkt, ct, &route, dir) < 0)
-+ if (nft_flow_route(pkt, ct, &route, dir, priv->flowtable) < 0)
- goto err_flow_route;
-
- flow = flow_offload_alloc(ct);
diff --git a/target/linux/generic/pending-5.10/640-06-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch b/target/linux/generic/pending-5.10/640-06-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch
deleted file mode 100644
index ada14e6c7a..0000000000
--- a/target/linux/generic/pending-5.10/640-06-netfilter-flowtable-use-dev_fill_forward_path-to-obt.patch
+++ /dev/null
@@ -1,344 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Thu, 4 Mar 2021 03:26:35 +0100
-Subject: [PATCH] netfilter: flowtable: use dev_fill_forward_path() to
- obtain egress device
-
-The egress device in the tuple is obtained from route. Use
-dev_fill_forward_path() instead to provide the real egress device for
-this flow whenever this is available.
-
-The new FLOW_OFFLOAD_XMIT_DIRECT type uses dev_queue_xmit() to transmit
-ethernet frames. Cache the source and destination hardware address to
-use dev_queue_xmit() to transfer packets.
-
-The FLOW_OFFLOAD_XMIT_DIRECT replaces FLOW_OFFLOAD_XMIT_NEIGH if
-dev_fill_forward_path() finds a direct transmit path.
-
-In case of topology updates, if peer is moved to different bridge port,
-the connection will time out, reconnect will result in a new entry with
-the correct path. Snooping fdb updates would allow for cleaning up stale
-flowtable entries.
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -92,6 +92,7 @@ enum flow_offload_tuple_dir {
- enum flow_offload_xmit_type {
- FLOW_OFFLOAD_XMIT_NEIGH = 0,
- FLOW_OFFLOAD_XMIT_XFRM,
-+ FLOW_OFFLOAD_XMIT_DIRECT,
- };
-
- struct flow_offload_tuple {
-@@ -120,8 +121,14 @@ struct flow_offload_tuple {
- xmit_type:2;
-
- u16 mtu;
--
-- struct dst_entry *dst_cache;
-+ union {
-+ struct dst_entry *dst_cache;
-+ struct {
-+ u32 ifidx;
-+ u8 h_source[ETH_ALEN];
-+ u8 h_dest[ETH_ALEN];
-+ } out;
-+ };
- };
-
- struct flow_offload_tuple_rhash {
-@@ -168,6 +175,11 @@ struct nf_flow_route {
- struct {
- u32 ifindex;
- } in;
-+ struct {
-+ u32 ifindex;
-+ u8 h_source[ETH_ALEN];
-+ u8 h_dest[ETH_ALEN];
-+ } out;
- enum flow_offload_xmit_type xmit_type;
- } tuple[FLOW_OFFLOAD_DIR_MAX];
- };
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -81,9 +81,6 @@ static int flow_offload_fill_route(struc
- struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
- struct dst_entry *dst = route->tuple[dir].dst;
-
-- if (!dst_hold_safe(route->tuple[dir].dst))
-- return -1;
--
- switch (flow_tuple->l3proto) {
- case NFPROTO_IPV4:
- flow_tuple->mtu = ip_dst_mtu_maybe_forward(dst, true);
-@@ -94,12 +91,36 @@ static int flow_offload_fill_route(struc
- }
-
- flow_tuple->iifidx = route->tuple[dir].in.ifindex;
-+
-+ switch (route->tuple[dir].xmit_type) {
-+ case FLOW_OFFLOAD_XMIT_DIRECT:
-+ memcpy(flow_tuple->out.h_dest, route->tuple[dir].out.h_dest,
-+ ETH_ALEN);
-+ memcpy(flow_tuple->out.h_source, route->tuple[dir].out.h_source,
-+ ETH_ALEN);
-+ flow_tuple->out.ifidx = route->tuple[dir].out.ifindex;
-+ break;
-+ case FLOW_OFFLOAD_XMIT_XFRM:
-+ case FLOW_OFFLOAD_XMIT_NEIGH:
-+ if (!dst_hold_safe(route->tuple[dir].dst))
-+ return -1;
-+
-+ flow_tuple->dst_cache = dst;
-+ break;
-+ }
- flow_tuple->xmit_type = route->tuple[dir].xmit_type;
-- flow_tuple->dst_cache = dst;
-
- return 0;
- }
-
-+static void nft_flow_dst_release(struct flow_offload *flow,
-+ enum flow_offload_tuple_dir dir)
-+{
-+ if (flow->tuplehash[dir].tuple.xmit_type == FLOW_OFFLOAD_XMIT_NEIGH ||
-+ flow->tuplehash[dir].tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)
-+ dst_release(flow->tuplehash[dir].tuple.dst_cache);
-+}
-+
- int flow_offload_route_init(struct flow_offload *flow,
- const struct nf_flow_route *route)
- {
-@@ -118,7 +139,7 @@ int flow_offload_route_init(struct flow_
- return 0;
-
- err_route_reply:
-- dst_release(route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst);
-+ nft_flow_dst_release(flow, FLOW_OFFLOAD_DIR_ORIGINAL);
-
- return err;
- }
-@@ -169,8 +190,8 @@ static void flow_offload_fixup_ct(struct
-
- static void flow_offload_route_release(struct flow_offload *flow)
- {
-- dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_cache);
-- dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_cache);
-+ nft_flow_dst_release(flow, FLOW_OFFLOAD_DIR_ORIGINAL);
-+ nft_flow_dst_release(flow, FLOW_OFFLOAD_DIR_REPLY);
- }
-
- void flow_offload_free(struct flow_offload *flow)
---- a/net/netfilter/nf_flow_table_ip.c
-+++ b/net/netfilter/nf_flow_table_ip.c
-@@ -248,6 +248,24 @@ static unsigned int nf_flow_xmit_xfrm(st
- return NF_STOLEN;
- }
-
-+static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
-+ const struct flow_offload_tuple_rhash *tuplehash,
-+ unsigned short type)
-+{
-+ struct net_device *outdev;
-+
-+ outdev = dev_get_by_index_rcu(net, tuplehash->tuple.out.ifidx);
-+ if (!outdev)
-+ return NF_DROP;
-+
-+ skb->dev = outdev;
-+ dev_hard_header(skb, skb->dev, type, tuplehash->tuple.out.h_dest,
-+ tuplehash->tuple.out.h_source, skb->len);
-+ dev_queue_xmit(skb);
-+
-+ return NF_STOLEN;
-+}
-+
- unsigned int
- nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
- const struct nf_hook_state *state)
-@@ -262,6 +280,7 @@ nf_flow_offload_ip_hook(void *priv, stru
- unsigned int thoff;
- struct iphdr *iph;
- __be32 nexthop;
-+ int ret;
-
- if (skb->protocol != htons(ETH_P_IP))
- return NF_ACCEPT;
-@@ -303,22 +322,32 @@ nf_flow_offload_ip_hook(void *priv, stru
- if (flow_table->flags & NF_FLOWTABLE_COUNTER)
- nf_ct_acct_update(flow->ct, tuplehash->tuple.dir, skb->len);
-
-- rt = (struct rtable *)tuplehash->tuple.dst_cache;
--
- if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
-+ rt = (struct rtable *)tuplehash->tuple.dst_cache;
- memset(skb->cb, 0, sizeof(struct inet_skb_parm));
- IPCB(skb)->iif = skb->dev->ifindex;
- IPCB(skb)->flags = IPSKB_FORWARDED;
- return nf_flow_xmit_xfrm(skb, state, &rt->dst);
- }
-
-- outdev = rt->dst.dev;
-- skb->dev = outdev;
-- nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
-- skb_dst_set_noref(skb, &rt->dst);
-- neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb);
-+ switch (tuplehash->tuple.xmit_type) {
-+ case FLOW_OFFLOAD_XMIT_NEIGH:
-+ rt = (struct rtable *)tuplehash->tuple.dst_cache;
-+ outdev = rt->dst.dev;
-+ skb->dev = outdev;
-+ nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
-+ skb_dst_set_noref(skb, &rt->dst);
-+ neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb);
-+ ret = NF_STOLEN;
-+ break;
-+ case FLOW_OFFLOAD_XMIT_DIRECT:
-+ ret = nf_flow_queue_xmit(state->net, skb, tuplehash, ETH_P_IP);
-+ if (ret == NF_DROP)
-+ flow_offload_teardown(flow);
-+ break;
-+ }
-
-- return NF_STOLEN;
-+ return ret;
- }
- EXPORT_SYMBOL_GPL(nf_flow_offload_ip_hook);
-
-@@ -504,6 +533,7 @@ nf_flow_offload_ipv6_hook(void *priv, st
- struct net_device *outdev;
- struct ipv6hdr *ip6h;
- struct rt6_info *rt;
-+ int ret;
-
- if (skb->protocol != htons(ETH_P_IPV6))
- return NF_ACCEPT;
-@@ -545,21 +575,31 @@ nf_flow_offload_ipv6_hook(void *priv, st
- if (flow_table->flags & NF_FLOWTABLE_COUNTER)
- nf_ct_acct_update(flow->ct, tuplehash->tuple.dir, skb->len);
-
-- rt = (struct rt6_info *)tuplehash->tuple.dst_cache;
--
- if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
-+ rt = (struct rt6_info *)tuplehash->tuple.dst_cache;
- memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
- IP6CB(skb)->iif = skb->dev->ifindex;
- IP6CB(skb)->flags = IP6SKB_FORWARDED;
- return nf_flow_xmit_xfrm(skb, state, &rt->dst);
- }
-
-- outdev = rt->dst.dev;
-- skb->dev = outdev;
-- nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
-- skb_dst_set_noref(skb, &rt->dst);
-- neigh_xmit(NEIGH_ND_TABLE, outdev, nexthop, skb);
-+ switch (tuplehash->tuple.xmit_type) {
-+ case FLOW_OFFLOAD_XMIT_NEIGH:
-+ rt = (struct rt6_info *)tuplehash->tuple.dst_cache;
-+ outdev = rt->dst.dev;
-+ skb->dev = outdev;
-+ nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
-+ skb_dst_set_noref(skb, &rt->dst);
-+ neigh_xmit(NEIGH_ND_TABLE, outdev, nexthop, skb);
-+ ret = NF_STOLEN;
-+ break;
-+ case FLOW_OFFLOAD_XMIT_DIRECT:
-+ ret = nf_flow_queue_xmit(state->net, skb, tuplehash, ETH_P_IPV6);
-+ if (ret == NF_DROP)
-+ flow_offload_teardown(flow);
-+ break;
-+ }
-
-- return NF_STOLEN;
-+ return ret;
- }
- EXPORT_SYMBOL_GPL(nf_flow_offload_ipv6_hook);
---- a/net/netfilter/nft_flow_offload.c
-+++ b/net/netfilter/nft_flow_offload.c
-@@ -39,12 +39,11 @@ static void nft_default_forward_path(str
- static int nft_dev_fill_forward_path(const struct nf_flow_route *route,
- const struct dst_entry *dst_cache,
- const struct nf_conn *ct,
-- enum ip_conntrack_dir dir,
-+ enum ip_conntrack_dir dir, u8 *ha,
- struct net_device_path_stack *stack)
- {
- const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
- struct net_device *dev = dst_cache->dev;
-- unsigned char ha[ETH_ALEN];
- struct neighbour *n;
- u8 nud_state;
-
-@@ -66,27 +65,43 @@ static int nft_dev_fill_forward_path(con
-
- struct nft_forward_info {
- const struct net_device *indev;
-+ const struct net_device *outdev;
-+ u8 h_source[ETH_ALEN];
-+ u8 h_dest[ETH_ALEN];
-+ enum flow_offload_xmit_type xmit_type;
- };
-
- static void nft_dev_path_info(const struct net_device_path_stack *stack,
-- struct nft_forward_info *info)
-+ struct nft_forward_info *info,
-+ unsigned char *ha)
- {
- const struct net_device_path *path;
- int i;
-
-+ memcpy(info->h_dest, ha, ETH_ALEN);
-+
- for (i = 0; i < stack->num_paths; i++) {
- path = &stack->path[i];
- switch (path->type) {
- case DEV_PATH_ETHERNET:
- info->indev = path->dev;
-+ if (is_zero_ether_addr(info->h_source))
-+ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
- break;
-- case DEV_PATH_VLAN:
- case DEV_PATH_BRIDGE:
-+ if (is_zero_ether_addr(info->h_source))
-+ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
-+
-+ info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
-+ break;
-+ case DEV_PATH_VLAN:
- default:
- info->indev = NULL;
- break;
- }
- }
-+ if (!info->outdev)
-+ info->outdev = info->indev;
- }
-
- static bool nft_flowtable_find_dev(const struct net_device *dev,
-@@ -114,14 +129,22 @@ static void nft_dev_forward_path(struct
- const struct dst_entry *dst = route->tuple[dir].dst;
- struct net_device_path_stack stack;
- struct nft_forward_info info = {};
-+ unsigned char ha[ETH_ALEN];
-
-- if (nft_dev_fill_forward_path(route, dst, ct, dir, &stack) >= 0)
-- nft_dev_path_info(&stack, &info);
-+ if (nft_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0)
-+ nft_dev_path_info(&stack, &info, ha);
-
- if (!info.indev || !nft_flowtable_find_dev(info.indev, ft))
- return;
-
- route->tuple[!dir].in.ifindex = info.indev->ifindex;
-+
-+ if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
-+ memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
-+ memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN);
-+ route->tuple[dir].out.ifindex = info.outdev->ifindex;
-+ route->tuple[dir].xmit_type = info.xmit_type;
-+ }
- }
-
- static int nft_flow_route(const struct nft_pktinfo *pkt,
diff --git a/target/linux/generic/pending-5.10/640-07-netfilter-flowtable-add-vlan-support.patch b/target/linux/generic/pending-5.10/640-07-netfilter-flowtable-add-vlan-support.patch
deleted file mode 100644
index fea1b59dc3..0000000000
--- a/target/linux/generic/pending-5.10/640-07-netfilter-flowtable-add-vlan-support.patch
+++ /dev/null
@@ -1,391 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Fri, 20 Nov 2020 13:49:20 +0100
-Subject: [PATCH] netfilter: flowtable: add vlan support
-
-Add the vlan id and protocol to the flow tuple to uniquely identify
-flows from the receive path. For the transmit path, dev_hard_header() on
-the vlan device push the headers. This patch includes support for two
-VLAN headers (QinQ) from the ingress path.
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -95,6 +95,8 @@ enum flow_offload_xmit_type {
- FLOW_OFFLOAD_XMIT_DIRECT,
- };
-
-+#define NF_FLOW_TABLE_ENCAP_MAX 2
-+
- struct flow_offload_tuple {
- union {
- struct in_addr src_v4;
-@@ -113,13 +115,17 @@ struct flow_offload_tuple {
-
- u8 l3proto;
- u8 l4proto;
-+ struct {
-+ u16 id;
-+ __be16 proto;
-+ } encap[NF_FLOW_TABLE_ENCAP_MAX];
-
- /* All members above are keys for lookups, see flow_offload_hash(). */
- struct { } __hash;
-
-- u8 dir:6,
-- xmit_type:2;
--
-+ u8 dir:4,
-+ xmit_type:2,
-+ encap_num:2;
- u16 mtu;
- union {
- struct dst_entry *dst_cache;
-@@ -174,6 +180,11 @@ struct nf_flow_route {
- struct dst_entry *dst;
- struct {
- u32 ifindex;
-+ struct {
-+ u16 id;
-+ __be16 proto;
-+ } encap[NF_FLOW_TABLE_ENCAP_MAX];
-+ u8 num_encaps;
- } in;
- struct {
- u32 ifindex;
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -80,6 +80,7 @@ static int flow_offload_fill_route(struc
- {
- struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
- struct dst_entry *dst = route->tuple[dir].dst;
-+ int i, j = 0;
-
- switch (flow_tuple->l3proto) {
- case NFPROTO_IPV4:
-@@ -91,6 +92,12 @@ static int flow_offload_fill_route(struc
- }
-
- flow_tuple->iifidx = route->tuple[dir].in.ifindex;
-+ for (i = route->tuple[dir].in.num_encaps - 1; i >= 0; i--) {
-+ flow_tuple->encap[j].id = route->tuple[dir].in.encap[i].id;
-+ flow_tuple->encap[j].proto = route->tuple[dir].in.encap[i].proto;
-+ j++;
-+ }
-+ flow_tuple->encap_num = route->tuple[dir].in.num_encaps;
-
- switch (route->tuple[dir].xmit_type) {
- case FLOW_OFFLOAD_XMIT_DIRECT:
---- a/net/netfilter/nf_flow_table_ip.c
-+++ b/net/netfilter/nf_flow_table_ip.c
-@@ -159,17 +159,38 @@ static bool ip_has_options(unsigned int
- return thoff != sizeof(struct iphdr);
- }
-
-+static void nf_flow_tuple_encap(struct sk_buff *skb,
-+ struct flow_offload_tuple *tuple)
-+{
-+ int i = 0;
-+
-+ if (skb_vlan_tag_present(skb)) {
-+ tuple->encap[i].id = skb_vlan_tag_get(skb);
-+ tuple->encap[i].proto = skb->vlan_proto;
-+ i++;
-+ }
-+ if (skb->protocol == htons(ETH_P_8021Q)) {
-+ struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
-+
-+ tuple->encap[i].id = ntohs(veth->h_vlan_TCI);
-+ tuple->encap[i].proto = skb->protocol;
-+ }
-+}
-+
- static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
- struct flow_offload_tuple *tuple)
- {
-- unsigned int thoff, hdrsize;
-+ unsigned int thoff, hdrsize, offset = 0;
- struct flow_ports *ports;
- struct iphdr *iph;
-
-- if (!pskb_may_pull(skb, sizeof(*iph)))
-+ if (skb->protocol == htons(ETH_P_8021Q))
-+ offset += VLAN_HLEN;
-+
-+ if (!pskb_may_pull(skb, sizeof(*iph) + offset))
- return -1;
-
-- iph = ip_hdr(skb);
-+ iph = (struct iphdr *)(skb_network_header(skb) + offset);
- thoff = iph->ihl * 4;
-
- if (ip_is_fragment(iph) ||
-@@ -191,11 +212,11 @@ static int nf_flow_tuple_ip(struct sk_bu
- return -1;
-
- thoff = iph->ihl * 4;
-- if (!pskb_may_pull(skb, thoff + hdrsize))
-+ if (!pskb_may_pull(skb, thoff + hdrsize + offset))
- return -1;
-
-- iph = ip_hdr(skb);
-- ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
-+ iph = (struct iphdr *)(skb_network_header(skb) + offset);
-+ ports = (struct flow_ports *)(skb_network_header(skb) + thoff + offset);
-
- tuple->src_v4.s_addr = iph->saddr;
- tuple->dst_v4.s_addr = iph->daddr;
-@@ -204,6 +225,7 @@ static int nf_flow_tuple_ip(struct sk_bu
- tuple->l3proto = AF_INET;
- tuple->l4proto = iph->protocol;
- tuple->iifidx = dev->ifindex;
-+ nf_flow_tuple_encap(skb, tuple);
-
- return 0;
- }
-@@ -248,6 +270,40 @@ static unsigned int nf_flow_xmit_xfrm(st
- return NF_STOLEN;
- }
-
-+static bool nf_flow_skb_encap_protocol(const struct sk_buff *skb, __be16 proto)
-+{
-+ if (skb->protocol == htons(ETH_P_8021Q)) {
-+ struct vlan_ethhdr *veth;
-+
-+ veth = (struct vlan_ethhdr *)skb_mac_header(skb);
-+ if (veth->h_vlan_encapsulated_proto == proto)
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+static void nf_flow_encap_pop(struct sk_buff *skb,
-+ struct flow_offload_tuple_rhash *tuplehash)
-+{
-+ struct vlan_hdr *vlan_hdr;
-+ int i;
-+
-+ for (i = 0; i < tuplehash->tuple.encap_num; i++) {
-+ if (skb_vlan_tag_present(skb)) {
-+ __vlan_hwaccel_clear_tag(skb);
-+ continue;
-+ }
-+ if (skb->protocol == htons(ETH_P_8021Q)) {
-+ vlan_hdr = (struct vlan_hdr *)skb->data;
-+ __skb_pull(skb, VLAN_HLEN);
-+ vlan_set_encap_proto(skb, vlan_hdr);
-+ skb_reset_network_header(skb);
-+ break;
-+ }
-+ }
-+}
-+
- static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
- const struct flow_offload_tuple_rhash *tuplehash,
- unsigned short type)
-@@ -276,13 +332,15 @@ nf_flow_offload_ip_hook(void *priv, stru
- enum flow_offload_tuple_dir dir;
- struct flow_offload *flow;
- struct net_device *outdev;
-+ unsigned int thoff, mtu;
- struct rtable *rt;
-- unsigned int thoff;
- struct iphdr *iph;
- __be32 nexthop;
-+ u32 offset = 0;
- int ret;
-
-- if (skb->protocol != htons(ETH_P_IP))
-+ if (skb->protocol != htons(ETH_P_IP) &&
-+ !nf_flow_skb_encap_protocol(skb, htons(ETH_P_IP)))
- return NF_ACCEPT;
-
- if (nf_flow_tuple_ip(skb, state->in, &tuple) < 0)
-@@ -295,14 +353,19 @@ nf_flow_offload_ip_hook(void *priv, stru
- dir = tuplehash->tuple.dir;
- flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
-
-- if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
-+ mtu = flow->tuplehash[dir].tuple.mtu + offset;
-+ if (unlikely(nf_flow_exceeds_mtu(skb, mtu)))
- return NF_ACCEPT;
-
-- if (skb_try_make_writable(skb, sizeof(*iph)))
-+ if (skb->protocol == htons(ETH_P_8021Q))
-+ offset += VLAN_HLEN;
-+
-+ if (skb_try_make_writable(skb, sizeof(*iph) + offset))
- return NF_DROP;
-
-- thoff = ip_hdr(skb)->ihl * 4;
-- if (nf_flow_state_check(flow, ip_hdr(skb)->protocol, skb, thoff))
-+ iph = (struct iphdr *)(skb_network_header(skb) + offset);
-+ thoff = (iph->ihl * 4) + offset;
-+ if (nf_flow_state_check(flow, iph->protocol, skb, thoff))
- return NF_ACCEPT;
-
- flow_offload_refresh(flow_table, flow);
-@@ -312,6 +375,9 @@ nf_flow_offload_ip_hook(void *priv, stru
- return NF_ACCEPT;
- }
-
-+ nf_flow_encap_pop(skb, tuplehash);
-+ thoff -= offset;
-+
- if (nf_flow_nat_ip(flow, skb, thoff, dir) < 0)
- return NF_DROP;
-
-@@ -479,14 +545,17 @@ static int nf_flow_nat_ipv6(const struct
- static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
- struct flow_offload_tuple *tuple)
- {
-- unsigned int thoff, hdrsize;
-+ unsigned int thoff, hdrsize, offset = 0;
- struct flow_ports *ports;
- struct ipv6hdr *ip6h;
-
-- if (!pskb_may_pull(skb, sizeof(*ip6h)))
-+ if (skb->protocol == htons(ETH_P_8021Q))
-+ offset += VLAN_HLEN;
-+
-+ if (!pskb_may_pull(skb, sizeof(*ip6h) + offset))
- return -1;
-
-- ip6h = ipv6_hdr(skb);
-+ ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
-
- switch (ip6h->nexthdr) {
- case IPPROTO_TCP:
-@@ -503,11 +572,11 @@ static int nf_flow_tuple_ipv6(struct sk_
- return -1;
-
- thoff = sizeof(*ip6h);
-- if (!pskb_may_pull(skb, thoff + hdrsize))
-+ if (!pskb_may_pull(skb, thoff + hdrsize + offset))
- return -1;
-
-- ip6h = ipv6_hdr(skb);
-- ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
-+ ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
-+ ports = (struct flow_ports *)(skb_network_header(skb) + thoff + offset);
-
- tuple->src_v6 = ip6h->saddr;
- tuple->dst_v6 = ip6h->daddr;
-@@ -516,6 +585,7 @@ static int nf_flow_tuple_ipv6(struct sk_
- tuple->l3proto = AF_INET6;
- tuple->l4proto = ip6h->nexthdr;
- tuple->iifidx = dev->ifindex;
-+ nf_flow_tuple_encap(skb, tuple);
-
- return 0;
- }
-@@ -533,9 +603,12 @@ nf_flow_offload_ipv6_hook(void *priv, st
- struct net_device *outdev;
- struct ipv6hdr *ip6h;
- struct rt6_info *rt;
-+ unsigned int mtu;
-+ u32 offset = 0;
- int ret;
-
-- if (skb->protocol != htons(ETH_P_IPV6))
-+ if (skb->protocol != htons(ETH_P_IPV6) &&
-+ !nf_flow_skb_encap_protocol(skb, htons(ETH_P_IPV6)))
- return NF_ACCEPT;
-
- if (nf_flow_tuple_ipv6(skb, state->in, &tuple) < 0)
-@@ -548,11 +621,15 @@ nf_flow_offload_ipv6_hook(void *priv, st
- dir = tuplehash->tuple.dir;
- flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
-
-- if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
-+ mtu = flow->tuplehash[dir].tuple.mtu + offset;
-+ if (unlikely(nf_flow_exceeds_mtu(skb, mtu)))
- return NF_ACCEPT;
-
-- if (nf_flow_state_check(flow, ipv6_hdr(skb)->nexthdr, skb,
-- sizeof(*ip6h)))
-+ if (skb->protocol == htons(ETH_P_8021Q))
-+ offset += VLAN_HLEN;
-+
-+ ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
-+ if (nf_flow_state_check(flow, ip6h->nexthdr, skb, sizeof(*ip6h)))
- return NF_ACCEPT;
-
- flow_offload_refresh(flow_table, flow);
-@@ -562,6 +639,8 @@ nf_flow_offload_ipv6_hook(void *priv, st
- return NF_ACCEPT;
- }
-
-+ nf_flow_encap_pop(skb, tuplehash);
-+
- if (skb_try_make_writable(skb, sizeof(*ip6h)))
- return NF_DROP;
-
---- a/net/netfilter/nft_flow_offload.c
-+++ b/net/netfilter/nft_flow_offload.c
-@@ -66,6 +66,11 @@ static int nft_dev_fill_forward_path(con
- struct nft_forward_info {
- const struct net_device *indev;
- const struct net_device *outdev;
-+ struct id {
-+ __u16 id;
-+ __be16 proto;
-+ } encap[NF_FLOW_TABLE_ENCAP_MAX];
-+ u8 num_encaps;
- u8 h_source[ETH_ALEN];
- u8 h_dest[ETH_ALEN];
- enum flow_offload_xmit_type xmit_type;
-@@ -84,9 +89,23 @@ static void nft_dev_path_info(const stru
- path = &stack->path[i];
- switch (path->type) {
- case DEV_PATH_ETHERNET:
-+ case DEV_PATH_VLAN:
- info->indev = path->dev;
- if (is_zero_ether_addr(info->h_source))
- memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
-+
-+ if (path->type == DEV_PATH_ETHERNET)
-+ break;
-+
-+ /* DEV_PATH_VLAN */
-+ if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) {
-+ info->indev = NULL;
-+ break;
-+ }
-+ 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++;
- break;
- case DEV_PATH_BRIDGE:
- if (is_zero_ether_addr(info->h_source))
-@@ -94,7 +113,6 @@ static void nft_dev_path_info(const stru
-
- info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
- break;
-- case DEV_PATH_VLAN:
- default:
- info->indev = NULL;
- break;
-@@ -130,6 +148,7 @@ static void nft_dev_forward_path(struct
- struct net_device_path_stack stack;
- struct nft_forward_info info = {};
- unsigned char ha[ETH_ALEN];
-+ int i;
-
- if (nft_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0)
- nft_dev_path_info(&stack, &info, ha);
-@@ -138,6 +157,11 @@ static void nft_dev_forward_path(struct
- return;
-
- route->tuple[!dir].in.ifindex = info.indev->ifindex;
-+ for (i = 0; i < info.num_encaps; i++) {
-+ route->tuple[!dir].in.encap[i].id = info.encap[i].id;
-+ route->tuple[!dir].in.encap[i].proto = info.encap[i].proto;
-+ }
-+ route->tuple[!dir].in.num_encaps = info.num_encaps;
-
- if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
- memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
diff --git a/target/linux/generic/pending-5.10/640-08-selftests-netfilter-flowtable-bridge-and-VLAN-suppor.patch b/target/linux/generic/pending-5.10/640-08-selftests-netfilter-flowtable-bridge-and-VLAN-suppor.patch
deleted file mode 100644
index 1ee015c6aa..0000000000
--- a/target/linux/generic/pending-5.10/640-08-selftests-netfilter-flowtable-bridge-and-VLAN-suppor.patch
+++ /dev/null
@@ -1,107 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Fri, 20 Nov 2020 13:49:21 +0100
-Subject: [PATCH] selftests: netfilter: flowtable bridge and VLAN support
-
-This patch adds two new tests to cover bridge and VLAN support:
-
-- Add a bridge device to the Router1 (nsr1) container and attach the
- veth0 device to the bridge. Set the IP address to the bridge device
- to exercise the bridge forwarding path.
-
-- Add VLAN encapsulation between to the bridge device in the Router1 and
- one of the sender containers (ns1).
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/tools/testing/selftests/netfilter/nft_flowtable.sh
-+++ b/tools/testing/selftests/netfilter/nft_flowtable.sh
-@@ -371,6 +371,88 @@ else
- ip netns exec nsr1 nft list ruleset
- fi
-
-+# Another test:
-+# Add bridge interface br0 to Router1, with NAT enabled.
-+ip -net nsr1 link add name br0 type bridge
-+ip -net nsr1 addr flush dev veth0
-+ip -net nsr1 link set up dev veth0
-+ip -net nsr1 link set veth0 master br0
-+ip -net nsr1 addr add 10.0.1.1/24 dev br0
-+ip -net nsr1 addr add dead:1::1/64 dev br0
-+ip -net nsr1 link set up dev br0
-+
-+ip netns exec nsr1 sysctl net.ipv4.conf.br0.forwarding=1 > /dev/null
-+
-+# br0 with NAT enabled.
-+ip netns exec nsr1 nft -f - <<EOF
-+flush table ip nat
-+table ip nat {
-+ chain prerouting {
-+ type nat hook prerouting priority 0; policy accept;
-+ meta iif "br0" ip daddr 10.6.6.6 tcp dport 1666 counter dnat ip to 10.0.2.99:12345
-+ }
-+
-+ chain postrouting {
-+ type nat hook postrouting priority 0; policy accept;
-+ meta oifname "veth1" counter masquerade
-+ }
-+}
-+EOF
-+
-+if test_tcp_forwarding_nat ns1 ns2; then
-+ echo "PASS: flow offloaded for ns1/ns2 with bridge NAT"
-+else
-+ echo "FAIL: flow offload for ns1/ns2 with bridge NAT" 1>&2
-+ ip netns exec nsr1 nft list ruleset
-+ ret=1
-+fi
-+
-+# Another test:
-+# Add bridge interface br0 to Router1, with NAT and VLAN.
-+ip -net nsr1 link set veth0 nomaster
-+ip -net nsr1 link set down dev veth0
-+ip -net nsr1 link add link veth0 name veth0.10 type vlan id 10
-+ip -net nsr1 link set up dev veth0
-+ip -net nsr1 link set up dev veth0.10
-+ip -net nsr1 link set veth0.10 master br0
-+
-+ip -net ns1 addr flush dev eth0
-+ip -net ns1 link add link eth0 name eth0.10 type vlan id 10
-+ip -net ns1 link set eth0 up
-+ip -net ns1 link set eth0.10 up
-+ip -net ns1 addr add 10.0.1.99/24 dev eth0.10
-+ip -net ns1 route add default via 10.0.1.1
-+ip -net ns1 addr add dead:1::99/64 dev eth0.10
-+
-+if test_tcp_forwarding_nat ns1 ns2; then
-+ echo "PASS: flow offloaded for ns1/ns2 with bridge NAT and VLAN"
-+else
-+ echo "FAIL: flow offload for ns1/ns2 with bridge NAT and VLAN" 1>&2
-+ ip netns exec nsr1 nft list ruleset
-+ ret=1
-+fi
-+
-+# restore test topology (remove bridge and VLAN)
-+ip -net nsr1 link set veth0 nomaster
-+ip -net nsr1 link set veth0 down
-+ip -net nsr1 link set veth0.10 down
-+ip -net nsr1 link delete veth0.10 type vlan
-+ip -net nsr1 link delete br0 type bridge
-+ip -net ns1 addr flush dev eth0.10
-+ip -net ns1 link set eth0.10 down
-+ip -net ns1 link set eth0 down
-+ip -net ns1 link delete eth0.10 type vlan
-+
-+# restore address in ns1 and nsr1
-+ip -net ns1 link set eth0 up
-+ip -net ns1 addr add 10.0.1.99/24 dev eth0
-+ip -net ns1 route add default via 10.0.1.1
-+ip -net ns1 addr add dead:1::99/64 dev eth0
-+ip -net ns1 route add default via dead:1::1
-+ip -net nsr1 addr add 10.0.1.1/24 dev veth0
-+ip -net nsr1 addr add dead:1::1/64 dev veth0
-+ip -net nsr1 link set up dev veth0
-+
- KEY_SHA="0x"$(ps -xaf | sha1sum | cut -d " " -f 1)
- KEY_AES="0x"$(ps -xaf | md5sum | cut -d " " -f 1)
- SPI1=$RANDOM
diff --git a/target/linux/generic/pending-5.10/640-09-net-bridge-resolve-VLAN-tag-actions-in-forwarding-pa.patch b/target/linux/generic/pending-5.10/640-09-net-bridge-resolve-VLAN-tag-actions-in-forwarding-pa.patch
deleted file mode 100644
index 8f8d58b299..0000000000
--- a/target/linux/generic/pending-5.10/640-09-net-bridge-resolve-VLAN-tag-actions-in-forwarding-pa.patch
+++ /dev/null
@@ -1,207 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Mon, 7 Dec 2020 20:31:45 +0100
-Subject: [PATCH] net: bridge: resolve VLAN tag actions in forwarding
- path for bridge devices
-
-Depending on the VLAN settings of the bridge and the port, the bridge can
-either add or remove a tag. When vlan filtering is enabled, the fdb lookup
-also needs to know the VLAN tag/proto for the destination address
-To provide this, keep track of the stack of VLAN tags for the path in the
-lookup context
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -841,10 +841,20 @@ struct net_device_path {
- u16 id;
- __be16 proto;
- } encap;
-+ struct {
-+ enum {
-+ DEV_PATH_BR_VLAN_KEEP,
-+ DEV_PATH_BR_VLAN_TAG,
-+ DEV_PATH_BR_VLAN_UNTAG,
-+ } vlan_mode;
-+ u16 vlan_id;
-+ __be16 vlan_proto;
-+ } bridge;
- };
- };
-
- #define NET_DEVICE_PATH_STACK_MAX 5
-+#define NET_DEVICE_PATH_VLAN_MAX 2
-
- struct net_device_path_stack {
- int num_paths;
-@@ -854,6 +864,12 @@ struct net_device_path_stack {
- struct net_device_path_ctx {
- const struct net_device *dev;
- const u8 *daddr;
-+
-+ int num_vlans;
-+ struct {
-+ u16 id;
-+ __be16 proto;
-+ } vlan[NET_DEVICE_PATH_VLAN_MAX];
- };
-
- enum tc_setup_type {
---- a/net/8021q/vlan_dev.c
-+++ b/net/8021q/vlan_dev.c
-@@ -777,6 +777,12 @@ static int vlan_dev_fill_forward_path(st
- path->encap.proto = vlan->vlan_proto;
- path->dev = ctx->dev;
- ctx->dev = vlan->real_dev;
-+ if (ctx->num_vlans >= ARRAY_SIZE(ctx->vlan))
-+ return -ENOSPC;
-+
-+ ctx->vlan[ctx->num_vlans].id = vlan->vlan_id;
-+ ctx->vlan[ctx->num_vlans].proto = vlan->vlan_proto;
-+ ctx->num_vlans++;
-
- return 0;
- }
---- a/net/bridge/br_device.c
-+++ b/net/bridge/br_device.c
-@@ -409,7 +409,10 @@ static int br_fill_forward_path(struct n
- return -1;
-
- br = netdev_priv(ctx->dev);
-- f = br_fdb_find_rcu(br, ctx->daddr, 0);
-+
-+ br_vlan_fill_forward_path_pvid(br, ctx, path);
-+
-+ f = br_fdb_find_rcu(br, ctx->daddr, path->bridge.vlan_id);
- if (!f || !f->dst)
- return -1;
-
-@@ -417,10 +420,28 @@ static int br_fill_forward_path(struct n
- if (!dst)
- return -1;
-
-+ if (br_vlan_fill_forward_path_mode(br, dst, path))
-+ return -1;
-+
- path->type = DEV_PATH_BRIDGE;
- path->dev = dst->br->dev;
- ctx->dev = dst->dev;
-
-+ switch (path->bridge.vlan_mode) {
-+ case DEV_PATH_BR_VLAN_TAG:
-+ if (ctx->num_vlans >= ARRAY_SIZE(ctx->vlan))
-+ return -ENOSPC;
-+ ctx->vlan[ctx->num_vlans].id = path->bridge.vlan_id;
-+ ctx->vlan[ctx->num_vlans].proto = path->bridge.vlan_proto;
-+ ctx->num_vlans++;
-+ break;
-+ case DEV_PATH_BR_VLAN_UNTAG:
-+ ctx->num_vlans--;
-+ break;
-+ case DEV_PATH_BR_VLAN_KEEP:
-+ break;
-+ }
-+
- return 0;
- }
-
---- a/net/bridge/br_private.h
-+++ b/net/bridge/br_private.h
-@@ -1095,6 +1095,13 @@ void br_vlan_notify(const struct net_bri
- bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
- const struct net_bridge_vlan *range_end);
-
-+void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
-+ struct net_device_path_ctx *ctx,
-+ struct net_device_path *path);
-+int br_vlan_fill_forward_path_mode(struct net_bridge *br,
-+ struct net_bridge_port *dst,
-+ struct net_device_path *path);
-+
- static inline struct net_bridge_vlan_group *br_vlan_group(
- const struct net_bridge *br)
- {
-@@ -1252,6 +1259,19 @@ static inline int nbp_get_num_vlan_infos
- {
- return 0;
- }
-+
-+static inline void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
-+ struct net_device_path_ctx *ctx,
-+ struct net_device_path *path)
-+{
-+}
-+
-+static inline int br_vlan_fill_forward_path_mode(struct net_bridge *br,
-+ struct net_bridge_port *dst,
-+ struct net_device_path *path)
-+{
-+ return 0;
-+}
-
- static inline struct net_bridge_vlan_group *br_vlan_group(
- const struct net_bridge *br)
---- a/net/bridge/br_vlan.c
-+++ b/net/bridge/br_vlan.c
-@@ -1327,6 +1327,59 @@ int br_vlan_get_pvid_rcu(const struct ne
- }
- EXPORT_SYMBOL_GPL(br_vlan_get_pvid_rcu);
-
-+void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
-+ struct net_device_path_ctx *ctx,
-+ struct net_device_path *path)
-+{
-+ struct net_bridge_vlan_group *vg;
-+ int idx = ctx->num_vlans - 1;
-+ u16 vid;
-+
-+ path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
-+
-+ if (!br_opt_get(br, BROPT_VLAN_ENABLED))
-+ return;
-+
-+ vg = br_vlan_group(br);
-+
-+ if (idx >= 0 &&
-+ ctx->vlan[idx].proto == br->vlan_proto) {
-+ vid = ctx->vlan[idx].id;
-+ } else {
-+ path->bridge.vlan_mode = DEV_PATH_BR_VLAN_TAG;
-+ vid = br_get_pvid(vg);
-+ }
-+
-+ path->bridge.vlan_id = vid;
-+ path->bridge.vlan_proto = br->vlan_proto;
-+}
-+
-+int br_vlan_fill_forward_path_mode(struct net_bridge *br,
-+ struct net_bridge_port *dst,
-+ struct net_device_path *path)
-+{
-+ struct net_bridge_vlan_group *vg;
-+ struct net_bridge_vlan *v;
-+
-+ if (!br_opt_get(br, BROPT_VLAN_ENABLED))
-+ return 0;
-+
-+ vg = nbp_vlan_group_rcu(dst);
-+ v = br_vlan_find(vg, path->bridge.vlan_id);
-+ if (!v || !br_vlan_should_use(v))
-+ return -EINVAL;
-+
-+ if (!(v->flags & BRIDGE_VLAN_INFO_UNTAGGED))
-+ return 0;
-+
-+ if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG)
-+ path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
-+ else
-+ path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG;
-+
-+ return 0;
-+}
-+
- int br_vlan_get_info(const struct net_device *dev, u16 vid,
- struct bridge_vlan_info *p_vinfo)
- {
diff --git a/target/linux/generic/pending-5.10/640-10-netfilter-nft_flow_offload-add-bridge-vlan-filtering.patch b/target/linux/generic/pending-5.10/640-10-netfilter-nft_flow_offload-add-bridge-vlan-filtering.patch
deleted file mode 100644
index 86fd6bf77b..0000000000
--- a/target/linux/generic/pending-5.10/640-10-netfilter-nft_flow_offload-add-bridge-vlan-filtering.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Sun, 24 Jan 2021 18:01:34 +0100
-Subject: [PATCH] netfilter: nft_flow_offload: add bridge vlan filtering
- support
-
-Add the vlan tag based when PVID is set on.
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/net/netfilter/nft_flow_offload.c
-+++ b/net/netfilter/nft_flow_offload.c
-@@ -111,6 +111,18 @@ static void nft_dev_path_info(const stru
- if (is_zero_ether_addr(info->h_source))
- memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
-
-+ switch (path->bridge.vlan_mode) {
-+ case DEV_PATH_BR_VLAN_TAG:
-+ info->encap[info->num_encaps].id = path->bridge.vlan_id;
-+ info->encap[info->num_encaps].proto = path->bridge.vlan_proto;
-+ info->num_encaps++;
-+ break;
-+ case DEV_PATH_BR_VLAN_UNTAG:
-+ info->num_encaps--;
-+ break;
-+ case DEV_PATH_BR_VLAN_KEEP:
-+ break;
-+ }
- info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
- break;
- default:
diff --git a/target/linux/generic/pending-5.10/640-11-net-ppp-resolve-forwarding-path-for-bridge-pppoe-dev.patch b/target/linux/generic/pending-5.10/640-11-net-ppp-resolve-forwarding-path-for-bridge-pppoe-dev.patch
deleted file mode 100644
index 88c89b27a0..0000000000
--- a/target/linux/generic/pending-5.10/640-11-net-ppp-resolve-forwarding-path-for-bridge-pppoe-dev.patch
+++ /dev/null
@@ -1,100 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Tue, 2 Mar 2021 21:45:16 +0100
-Subject: [PATCH] net: ppp: resolve forwarding path for bridge pppoe
- devices
-
-Pass on the PPPoE session ID and the real device.
----
-
---- a/drivers/net/ppp/ppp_generic.c
-+++ b/drivers/net/ppp/ppp_generic.c
-@@ -1450,12 +1450,34 @@ static void ppp_dev_priv_destructor(stru
- ppp_destroy_interface(ppp);
- }
-
-+static int ppp_fill_forward_path(struct net_device_path_ctx *ctx,
-+ struct net_device_path *path)
-+{
-+ struct ppp *ppp = netdev_priv(path->dev);
-+ struct ppp_channel *chan;
-+ struct channel *pch;
-+
-+ if (ppp->flags & SC_MULTILINK)
-+ return -EOPNOTSUPP;
-+
-+ if (list_empty(&ppp->channels))
-+ return -ENODEV;
-+
-+ pch = list_first_entry(&ppp->channels, struct channel, clist);
-+ chan = pch->chan;
-+ if (!chan->ops->fill_forward_path)
-+ return -EOPNOTSUPP;
-+
-+ return chan->ops->fill_forward_path(ctx, path, chan);
-+}
-+
- static const struct net_device_ops ppp_netdev_ops = {
- .ndo_init = ppp_dev_init,
- .ndo_uninit = ppp_dev_uninit,
- .ndo_start_xmit = ppp_start_xmit,
- .ndo_do_ioctl = ppp_net_ioctl,
- .ndo_get_stats64 = ppp_get_stats64,
-+ .ndo_fill_forward_path = ppp_fill_forward_path,
- };
-
- static struct device_type ppp_type = {
---- a/drivers/net/ppp/pppoe.c
-+++ b/drivers/net/ppp/pppoe.c
-@@ -972,8 +972,30 @@ static int pppoe_xmit(struct ppp_channel
- return __pppoe_xmit(sk, skb);
- }
-
-+static int pppoe_fill_forward_path(struct net_device_path_ctx *ctx,
-+ struct net_device_path *path,
-+ const struct ppp_channel *chan)
-+{
-+ struct sock *sk = (struct sock *)chan->private;
-+ struct pppox_sock *po = pppox_sk(sk);
-+ struct net_device *dev = po->pppoe_dev;
-+
-+ if (sock_flag(sk, SOCK_DEAD) ||
-+ !(sk->sk_state & PPPOX_CONNECTED) || !dev)
-+ return -1;
-+
-+ path->type = DEV_PATH_PPPOE;
-+ path->encap.proto = htons(ETH_P_PPP_SES);
-+ path->encap.id = be16_to_cpu(po->num);
-+ path->dev = ctx->dev;
-+ ctx->dev = dev;
-+
-+ return 0;
-+}
-+
- static const struct ppp_channel_ops pppoe_chan_ops = {
- .start_xmit = pppoe_xmit,
-+ .fill_forward_path = pppoe_fill_forward_path,
- };
-
- static int pppoe_recvmsg(struct socket *sock, struct msghdr *m,
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -831,6 +831,7 @@ enum net_device_path_type {
- DEV_PATH_ETHERNET = 0,
- DEV_PATH_VLAN,
- DEV_PATH_BRIDGE,
-+ DEV_PATH_PPPOE,
- };
-
- struct net_device_path {
---- a/include/linux/ppp_channel.h
-+++ b/include/linux/ppp_channel.h
-@@ -28,6 +28,9 @@ struct ppp_channel_ops {
- int (*start_xmit)(struct ppp_channel *, struct sk_buff *);
- /* Handle an ioctl call that has come in via /dev/ppp. */
- int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long);
-+ int (*fill_forward_path)(struct net_device_path_ctx *,
-+ struct net_device_path *,
-+ const struct ppp_channel *);
- };
-
- struct ppp_channel {
diff --git a/target/linux/generic/pending-5.10/640-12-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch b/target/linux/generic/pending-5.10/640-12-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch
deleted file mode 100644
index 0b85742290..0000000000
--- a/target/linux/generic/pending-5.10/640-12-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch
+++ /dev/null
@@ -1,60 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 4 Mar 2021 23:19:06 +0100
-Subject: [PATCH] net: dsa: resolve forwarding path for dsa slave ports
-
-Add .ndo_fill_forward_path for dsa slave port devices
----
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -832,6 +832,7 @@ enum net_device_path_type {
- DEV_PATH_VLAN,
- DEV_PATH_BRIDGE,
- DEV_PATH_PPPOE,
-+ DEV_PATH_DSA,
- };
-
- struct net_device_path {
-@@ -851,6 +852,10 @@ struct net_device_path {
- u16 vlan_id;
- __be16 vlan_proto;
- } bridge;
-+ struct {
-+ int port;
-+ u16 proto;
-+ } dsa;
- };
- };
-
---- a/net/dsa/slave.c
-+++ b/net/dsa/slave.c
-@@ -1617,6 +1617,21 @@ static struct devlink_port *dsa_slave_ge
- return dp->ds->devlink ? &dp->devlink_port : NULL;
- }
-
-+static int dsa_slave_fill_forward_path(struct net_device_path_ctx *ctx,
-+ struct net_device_path *path)
-+{
-+ struct dsa_port *dp = dsa_slave_to_port(ctx->dev);
-+ struct dsa_port *cpu_dp = dp->cpu_dp;
-+
-+ path->dev = ctx->dev;
-+ path->type = DEV_PATH_DSA;
-+ path->dsa.proto = cpu_dp->tag_ops->proto;
-+ path->dsa.port = dp->index;
-+ ctx->dev = cpu_dp->master;
-+
-+ return 0;
-+}
-+
- static const struct net_device_ops dsa_slave_netdev_ops = {
- .ndo_open = dsa_slave_open,
- .ndo_stop = dsa_slave_close,
-@@ -1642,6 +1657,7 @@ static const struct net_device_ops dsa_s
- .ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid,
- .ndo_get_devlink_port = dsa_slave_get_devlink_port,
- .ndo_change_mtu = dsa_slave_change_mtu,
-+ .ndo_fill_forward_path = dsa_slave_fill_forward_path,
- };
-
- static struct device_type dsa_type = {
diff --git a/target/linux/generic/pending-5.10/640-13-netfilter-flowtable-add-pppoe-support.patch b/target/linux/generic/pending-5.10/640-13-netfilter-flowtable-add-pppoe-support.patch
deleted file mode 100644
index 524f466bf9..0000000000
--- a/target/linux/generic/pending-5.10/640-13-netfilter-flowtable-add-pppoe-support.patch
+++ /dev/null
@@ -1,263 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Mon, 1 Mar 2021 23:52:49 +0100
-Subject: [PATCH] netfilter: flowtable: add pppoe support
-
----
-
---- a/drivers/net/ppp/ppp_generic.c
-+++ b/drivers/net/ppp/ppp_generic.c
-@@ -1453,7 +1453,7 @@ static void ppp_dev_priv_destructor(stru
- static int ppp_fill_forward_path(struct net_device_path_ctx *ctx,
- struct net_device_path *path)
- {
-- struct ppp *ppp = netdev_priv(path->dev);
-+ struct ppp *ppp = netdev_priv(ctx->dev);
- struct ppp_channel *chan;
- struct channel *pch;
-
---- a/drivers/net/ppp/pppoe.c
-+++ b/drivers/net/ppp/pppoe.c
-@@ -987,6 +987,7 @@ static int pppoe_fill_forward_path(struc
- path->type = DEV_PATH_PPPOE;
- path->encap.proto = htons(ETH_P_PPP_SES);
- path->encap.id = be16_to_cpu(po->num);
-+ memcpy(path->encap.h_dest, po->pppoe_pa.remote, ETH_ALEN);
- path->dev = ctx->dev;
- ctx->dev = dev;
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -842,6 +842,7 @@ struct net_device_path {
- struct {
- u16 id;
- __be16 proto;
-+ u8 h_dest[ETH_ALEN];
- } encap;
- struct {
- enum {
---- a/net/netfilter/nf_flow_table_ip.c
-+++ b/net/netfilter/nf_flow_table_ip.c
-@@ -7,6 +7,9 @@
- #include <linux/ip.h>
- #include <linux/ipv6.h>
- #include <linux/netdevice.h>
-+#include <linux/if_ether.h>
-+#include <linux/if_pppox.h>
-+#include <linux/ppp_defs.h>
- #include <net/ip.h>
- #include <net/ipv6.h>
- #include <net/ip6_route.h>
-@@ -162,6 +165,8 @@ static bool ip_has_options(unsigned int
- static void nf_flow_tuple_encap(struct sk_buff *skb,
- struct flow_offload_tuple *tuple)
- {
-+ struct vlan_ethhdr *veth;
-+ struct pppoe_hdr *phdr;
- int i = 0;
-
- if (skb_vlan_tag_present(skb)) {
-@@ -169,23 +174,35 @@ static void nf_flow_tuple_encap(struct s
- tuple->encap[i].proto = skb->vlan_proto;
- i++;
- }
-- if (skb->protocol == htons(ETH_P_8021Q)) {
-- struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
--
-+ switch (skb->protocol) {
-+ case htons(ETH_P_8021Q):
-+ veth = (struct vlan_ethhdr *)skb_mac_header(skb);
- tuple->encap[i].id = ntohs(veth->h_vlan_TCI);
- tuple->encap[i].proto = skb->protocol;
-+ break;
-+ case htons(ETH_P_PPP_SES):
-+ phdr = (struct pppoe_hdr *)skb_mac_header(skb);
-+ tuple->encap[i].id = ntohs(phdr->sid);
-+ tuple->encap[i].proto = skb->protocol;
-+ break;
- }
- }
-
- static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
-- struct flow_offload_tuple *tuple)
-+ struct flow_offload_tuple *tuple, u32 *nhoff)
- {
- unsigned int thoff, hdrsize, offset = 0;
- struct flow_ports *ports;
- struct iphdr *iph;
-
-- if (skb->protocol == htons(ETH_P_8021Q))
-+ switch (skb->protocol) {
-+ case htons(ETH_P_8021Q):
- offset += VLAN_HLEN;
-+ break;
-+ case htons(ETH_P_PPP_SES):
-+ offset += PPPOE_SES_HLEN;
-+ break;
-+ }
-
- if (!pskb_may_pull(skb, sizeof(*iph) + offset))
- return -1;
-@@ -226,6 +243,7 @@ static int nf_flow_tuple_ip(struct sk_bu
- tuple->l4proto = iph->protocol;
- tuple->iifidx = dev->ifindex;
- nf_flow_tuple_encap(skb, tuple);
-+ *nhoff = offset;
-
- return 0;
- }
-@@ -270,14 +288,36 @@ static unsigned int nf_flow_xmit_xfrm(st
- return NF_STOLEN;
- }
-
-+static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb)
-+{
-+ __be16 proto;
-+
-+ proto = *((__be16 *)(skb_mac_header(skb) + ETH_HLEN +
-+ sizeof(struct pppoe_hdr)));
-+ switch (proto) {
-+ case htons(PPP_IP):
-+ return htons(ETH_P_IP);
-+ case htons(PPP_IPV6):
-+ return htons(ETH_P_IPV6);
-+ }
-+
-+ return 0;
-+}
-+
- static bool nf_flow_skb_encap_protocol(const struct sk_buff *skb, __be16 proto)
- {
-- if (skb->protocol == htons(ETH_P_8021Q)) {
-- struct vlan_ethhdr *veth;
-+ struct vlan_ethhdr *veth;
-
-+ switch (skb->protocol) {
-+ case htons(ETH_P_8021Q):
- veth = (struct vlan_ethhdr *)skb_mac_header(skb);
- if (veth->h_vlan_encapsulated_proto == proto)
- return true;
-+ break;
-+ case htons(ETH_P_PPP_SES):
-+ if (nf_flow_pppoe_proto(skb) == proto)
-+ return true;
-+ break;
- }
-
- return false;
-@@ -294,12 +334,18 @@ static void nf_flow_encap_pop(struct sk_
- __vlan_hwaccel_clear_tag(skb);
- continue;
- }
-- if (skb->protocol == htons(ETH_P_8021Q)) {
-+ switch (skb->protocol) {
-+ case htons(ETH_P_8021Q):
- vlan_hdr = (struct vlan_hdr *)skb->data;
- __skb_pull(skb, VLAN_HLEN);
- vlan_set_encap_proto(skb, vlan_hdr);
- skb_reset_network_header(skb);
- break;
-+ case htons(ETH_P_PPP_SES):
-+ skb->protocol = nf_flow_pppoe_proto(skb);
-+ skb_pull(skb, PPPOE_SES_HLEN);
-+ skb_reset_network_header(skb);
-+ break;
- }
- }
- }
-@@ -343,7 +389,7 @@ nf_flow_offload_ip_hook(void *priv, stru
- !nf_flow_skb_encap_protocol(skb, htons(ETH_P_IP)))
- return NF_ACCEPT;
-
-- if (nf_flow_tuple_ip(skb, state->in, &tuple) < 0)
-+ if (nf_flow_tuple_ip(skb, state->in, &tuple, &offset) < 0)
- return NF_ACCEPT;
-
- tuplehash = flow_offload_lookup(flow_table, &tuple);
-@@ -357,9 +403,6 @@ nf_flow_offload_ip_hook(void *priv, stru
- if (unlikely(nf_flow_exceeds_mtu(skb, mtu)))
- return NF_ACCEPT;
-
-- if (skb->protocol == htons(ETH_P_8021Q))
-- offset += VLAN_HLEN;
--
- if (skb_try_make_writable(skb, sizeof(*iph) + offset))
- return NF_DROP;
-
-@@ -543,14 +586,20 @@ static int nf_flow_nat_ipv6(const struct
- }
-
- static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
-- struct flow_offload_tuple *tuple)
-+ struct flow_offload_tuple *tuple, u32 *nhoff)
- {
- unsigned int thoff, hdrsize, offset = 0;
- struct flow_ports *ports;
- struct ipv6hdr *ip6h;
-
-- if (skb->protocol == htons(ETH_P_8021Q))
-+ switch (skb->protocol) {
-+ case htons(ETH_P_8021Q):
- offset += VLAN_HLEN;
-+ break;
-+ case htons(ETH_P_PPP_SES):
-+ offset += PPPOE_SES_HLEN;
-+ break;
-+ }
-
- if (!pskb_may_pull(skb, sizeof(*ip6h) + offset))
- return -1;
-@@ -586,6 +635,7 @@ static int nf_flow_tuple_ipv6(struct sk_
- tuple->l4proto = ip6h->nexthdr;
- tuple->iifidx = dev->ifindex;
- nf_flow_tuple_encap(skb, tuple);
-+ *nhoff = offset;
-
- return 0;
- }
-@@ -611,7 +661,7 @@ nf_flow_offload_ipv6_hook(void *priv, st
- !nf_flow_skb_encap_protocol(skb, htons(ETH_P_IPV6)))
- return NF_ACCEPT;
-
-- if (nf_flow_tuple_ipv6(skb, state->in, &tuple) < 0)
-+ if (nf_flow_tuple_ipv6(skb, state->in, &tuple, &offset) < 0)
- return NF_ACCEPT;
-
- tuplehash = flow_offload_lookup(flow_table, &tuple);
-@@ -625,9 +675,6 @@ nf_flow_offload_ipv6_hook(void *priv, st
- if (unlikely(nf_flow_exceeds_mtu(skb, mtu)))
- return NF_ACCEPT;
-
-- if (skb->protocol == htons(ETH_P_8021Q))
-- offset += VLAN_HLEN;
--
- ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
- if (nf_flow_state_check(flow, ip6h->nexthdr, skb, sizeof(*ip6h)))
- return NF_ACCEPT;
---- a/net/netfilter/nft_flow_offload.c
-+++ b/net/netfilter/nft_flow_offload.c
-@@ -90,6 +90,7 @@ static void nft_dev_path_info(const stru
- switch (path->type) {
- case DEV_PATH_ETHERNET:
- case DEV_PATH_VLAN:
-+ case DEV_PATH_PPPOE:
- info->indev = path->dev;
- if (is_zero_ether_addr(info->h_source))
- memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
-@@ -97,7 +98,7 @@ static void nft_dev_path_info(const stru
- if (path->type == DEV_PATH_ETHERNET)
- break;
-
-- /* DEV_PATH_VLAN */
-+ /* DEV_PATH_VLAN and DEV_PATH_PPPOE */
- if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) {
- info->indev = NULL;
- break;
-@@ -106,6 +107,8 @@ static void nft_dev_path_info(const stru
- 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)
-+ memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
- break;
- case DEV_PATH_BRIDGE:
- if (is_zero_ether_addr(info->h_source))
diff --git a/target/linux/generic/pending-5.10/640-14-netfilter-nft_flow_offload-add-dsa-support.patch b/target/linux/generic/pending-5.10/640-14-netfilter-nft_flow_offload-add-dsa-support.patch
deleted file mode 100644
index 7ff5dad1f7..0000000000
--- a/target/linux/generic/pending-5.10/640-14-netfilter-nft_flow_offload-add-dsa-support.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Thu, 4 Mar 2021 19:22:55 +0100
-Subject: [PATCH] netfilter: nft_flow_offload: add dsa support
-
-Replace the master ethernet device by the dsa slave port.
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/net/netfilter/nft_flow_offload.c
-+++ b/net/netfilter/nft_flow_offload.c
-@@ -89,6 +89,7 @@ static void nft_dev_path_info(const stru
- path = &stack->path[i];
- switch (path->type) {
- case DEV_PATH_ETHERNET:
-+ case DEV_PATH_DSA:
- case DEV_PATH_VLAN:
- case DEV_PATH_PPPOE:
- info->indev = path->dev;
-@@ -97,6 +98,10 @@ static void nft_dev_path_info(const stru
-
- if (path->type == DEV_PATH_ETHERNET)
- break;
-+ if (path->type == DEV_PATH_DSA) {
-+ i = stack->num_paths;
-+ break;
-+ }
-
- /* DEV_PATH_VLAN and DEV_PATH_PPPOE */
- if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) {
diff --git a/target/linux/generic/pending-5.10/640-15-netfilter-flowtable-add-offload-support-for-xmit-pat.patch b/target/linux/generic/pending-5.10/640-15-netfilter-flowtable-add-offload-support-for-xmit-pat.patch
deleted file mode 100644
index 696ea03332..0000000000
--- a/target/linux/generic/pending-5.10/640-15-netfilter-flowtable-add-offload-support-for-xmit-pat.patch
+++ /dev/null
@@ -1,308 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Mon, 7 Dec 2020 20:31:44 +0100
-Subject: [PATCH] netfilter: flowtable: add offload support for xmit path
- types
-
-When the flow tuple xmit_type is set to FLOW_OFFLOAD_XMIT_DIRECT, the
-dst_cache pointer is not valid, and the h_source/h_dest/ifidx out fields
-need to be used.
-
-This patch also adds the FLOW_ACTION_VLAN_PUSH action to pass the VLAN
-tag to the driver.
----
-
---- a/net/netfilter/nf_flow_table_offload.c
-+++ b/net/netfilter/nf_flow_table_offload.c
-@@ -175,28 +175,45 @@ static int flow_offload_eth_src(struct n
- enum flow_offload_tuple_dir dir,
- struct nf_flow_rule *flow_rule)
- {
-- const struct flow_offload_tuple *tuple = &flow->tuplehash[!dir].tuple;
- struct flow_action_entry *entry0 = flow_action_entry_next(flow_rule);
- struct flow_action_entry *entry1 = flow_action_entry_next(flow_rule);
-- struct net_device *dev;
-+ const struct flow_offload_tuple *other_tuple, *this_tuple;
-+ struct net_device *dev = NULL;
-+ const unsigned char *addr;
- u32 mask, val;
- u16 val16;
-
-- dev = dev_get_by_index(net, tuple->iifidx);
-- if (!dev)
-- return -ENOENT;
-+ this_tuple = &flow->tuplehash[dir].tuple;
-+
-+ switch (this_tuple->xmit_type) {
-+ case FLOW_OFFLOAD_XMIT_DIRECT:
-+ addr = this_tuple->out.h_source;
-+ break;
-+ case FLOW_OFFLOAD_XMIT_NEIGH:
-+ other_tuple = &flow->tuplehash[!dir].tuple;
-+ dev = dev_get_by_index(net, other_tuple->iifidx);
-+ if (!dev)
-+ return -ENOENT;
-+
-+ addr = dev->dev_addr;
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-
- mask = ~0xffff0000;
-- memcpy(&val16, dev->dev_addr, 2);
-+ memcpy(&val16, addr, 2);
- val = val16 << 16;
- flow_offload_mangle(entry0, FLOW_ACT_MANGLE_HDR_TYPE_ETH, 4,
- &val, &mask);
-
- mask = ~0xffffffff;
-- memcpy(&val, dev->dev_addr + 2, 4);
-+ memcpy(&val, addr + 2, 4);
- flow_offload_mangle(entry1, FLOW_ACT_MANGLE_HDR_TYPE_ETH, 8,
- &val, &mask);
-- dev_put(dev);
-+
-+ if (dev)
-+ dev_put(dev);
-
- return 0;
- }
-@@ -208,27 +225,40 @@ static int flow_offload_eth_dst(struct n
- {
- struct flow_action_entry *entry0 = flow_action_entry_next(flow_rule);
- struct flow_action_entry *entry1 = flow_action_entry_next(flow_rule);
-- const void *daddr = &flow->tuplehash[!dir].tuple.src_v4;
-+ const struct flow_offload_tuple *other_tuple, *this_tuple;
- const struct dst_entry *dst_cache;
- unsigned char ha[ETH_ALEN];
- struct neighbour *n;
-+ const void *daddr;
- u32 mask, val;
- u8 nud_state;
- u16 val16;
-
-- dst_cache = flow->tuplehash[dir].tuple.dst_cache;
-- n = dst_neigh_lookup(dst_cache, daddr);
-- if (!n)
-- return -ENOENT;
--
-- read_lock_bh(&n->lock);
-- nud_state = n->nud_state;
-- ether_addr_copy(ha, n->ha);
-- read_unlock_bh(&n->lock);
-+ this_tuple = &flow->tuplehash[dir].tuple;
-
-- if (!(nud_state & NUD_VALID)) {
-+ switch (this_tuple->xmit_type) {
-+ case FLOW_OFFLOAD_XMIT_DIRECT:
-+ ether_addr_copy(ha, this_tuple->out.h_dest);
-+ break;
-+ case FLOW_OFFLOAD_XMIT_NEIGH:
-+ other_tuple = &flow->tuplehash[!dir].tuple;
-+ daddr = &other_tuple->src_v4;
-+ dst_cache = this_tuple->dst_cache;
-+ n = dst_neigh_lookup(dst_cache, daddr);
-+ if (!n)
-+ return -ENOENT;
-+
-+ read_lock_bh(&n->lock);
-+ nud_state = n->nud_state;
-+ ether_addr_copy(ha, n->ha);
-+ read_unlock_bh(&n->lock);
- neigh_release(n);
-- return -ENOENT;
-+
-+ if (!(nud_state & NUD_VALID))
-+ return -ENOENT;
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
- }
-
- mask = ~0xffffffff;
-@@ -241,7 +271,6 @@ static int flow_offload_eth_dst(struct n
- val = val16;
- flow_offload_mangle(entry1, FLOW_ACT_MANGLE_HDR_TYPE_ETH, 4,
- &val, &mask);
-- neigh_release(n);
-
- return 0;
- }
-@@ -463,27 +492,52 @@ static void flow_offload_ipv4_checksum(s
- }
- }
-
--static void flow_offload_redirect(const struct flow_offload *flow,
-+static void flow_offload_redirect(struct net *net,
-+ const struct flow_offload *flow,
- enum flow_offload_tuple_dir dir,
- struct nf_flow_rule *flow_rule)
- {
-- struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
-- struct rtable *rt;
-+ const struct flow_offload_tuple *this_tuple, *other_tuple;
-+ struct flow_action_entry *entry;
-+ struct net_device *dev;
-+ int ifindex;
-+
-+ this_tuple = &flow->tuplehash[dir].tuple;
-+ switch (this_tuple->xmit_type) {
-+ case FLOW_OFFLOAD_XMIT_DIRECT:
-+ this_tuple = &flow->tuplehash[dir].tuple;
-+ ifindex = this_tuple->out.ifidx;
-+ break;
-+ case FLOW_OFFLOAD_XMIT_NEIGH:
-+ other_tuple = &flow->tuplehash[!dir].tuple;
-+ ifindex = other_tuple->iifidx;
-+ break;
-+ default:
-+ return;
-+ }
-
-- rt = (struct rtable *)flow->tuplehash[dir].tuple.dst_cache;
-+ dev = dev_get_by_index(net, ifindex);
-+ if (!dev)
-+ return;
-+
-+ entry = flow_action_entry_next(flow_rule);
- entry->id = FLOW_ACTION_REDIRECT;
-- entry->dev = rt->dst.dev;
-- dev_hold(rt->dst.dev);
-+ entry->dev = dev;
- }
-
- static void flow_offload_encap_tunnel(const struct flow_offload *flow,
- enum flow_offload_tuple_dir dir,
- struct nf_flow_rule *flow_rule)
- {
-+ const struct flow_offload_tuple *this_tuple;
- struct flow_action_entry *entry;
- struct dst_entry *dst;
-
-- dst = flow->tuplehash[dir].tuple.dst_cache;
-+ this_tuple = &flow->tuplehash[dir].tuple;
-+ if (this_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
-+ return;
-+
-+ dst = this_tuple->dst_cache;
- if (dst && dst->lwtstate) {
- struct ip_tunnel_info *tun_info;
-
-@@ -500,10 +554,15 @@ static void flow_offload_decap_tunnel(co
- enum flow_offload_tuple_dir dir,
- struct nf_flow_rule *flow_rule)
- {
-+ const struct flow_offload_tuple *other_tuple;
- struct flow_action_entry *entry;
- struct dst_entry *dst;
-
-- dst = flow->tuplehash[!dir].tuple.dst_cache;
-+ other_tuple = &flow->tuplehash[!dir].tuple;
-+ if (other_tuple->xmit_type == FLOW_OFFLOAD_XMIT_DIRECT)
-+ return;
-+
-+ dst = other_tuple->dst_cache;
- if (dst && dst->lwtstate) {
- struct ip_tunnel_info *tun_info;
-
-@@ -515,10 +574,14 @@ static void flow_offload_decap_tunnel(co
- }
- }
-
--int nf_flow_rule_route_ipv4(struct net *net, const struct flow_offload *flow,
-- enum flow_offload_tuple_dir dir,
-- struct nf_flow_rule *flow_rule)
-+static int
-+nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
-+ enum flow_offload_tuple_dir dir,
-+ struct nf_flow_rule *flow_rule)
- {
-+ const struct flow_offload_tuple *other_tuple;
-+ int i;
-+
- flow_offload_decap_tunnel(flow, dir, flow_rule);
- flow_offload_encap_tunnel(flow, dir, flow_rule);
-
-@@ -526,6 +589,26 @@ int nf_flow_rule_route_ipv4(struct net *
- flow_offload_eth_dst(net, flow, dir, flow_rule) < 0)
- return -1;
-
-+ other_tuple = &flow->tuplehash[!dir].tuple;
-+
-+ for (i = 0; i < other_tuple->encap_num; i++) {
-+ struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
-+
-+ entry->id = FLOW_ACTION_VLAN_PUSH;
-+ entry->vlan.vid = other_tuple->encap[i].id;
-+ entry->vlan.proto = other_tuple->encap[i].proto;
-+ }
-+
-+ return 0;
-+}
-+
-+int nf_flow_rule_route_ipv4(struct net *net, const struct flow_offload *flow,
-+ enum flow_offload_tuple_dir dir,
-+ struct nf_flow_rule *flow_rule)
-+{
-+ if (nf_flow_rule_route_common(net, flow, dir, flow_rule) < 0)
-+ return -1;
-+
- if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
- flow_offload_ipv4_snat(net, flow, dir, flow_rule);
- flow_offload_port_snat(net, flow, dir, flow_rule);
-@@ -538,7 +621,7 @@ int nf_flow_rule_route_ipv4(struct net *
- test_bit(NF_FLOW_DNAT, &flow->flags))
- flow_offload_ipv4_checksum(net, flow, flow_rule);
-
-- flow_offload_redirect(flow, dir, flow_rule);
-+ flow_offload_redirect(net, flow, dir, flow_rule);
-
- return 0;
- }
-@@ -548,11 +631,7 @@ int nf_flow_rule_route_ipv6(struct net *
- enum flow_offload_tuple_dir dir,
- struct nf_flow_rule *flow_rule)
- {
-- flow_offload_decap_tunnel(flow, dir, flow_rule);
-- flow_offload_encap_tunnel(flow, dir, flow_rule);
--
-- if (flow_offload_eth_src(net, flow, dir, flow_rule) < 0 ||
-- flow_offload_eth_dst(net, flow, dir, flow_rule) < 0)
-+ if (nf_flow_rule_route_common(net, flow, dir, flow_rule) < 0)
- return -1;
-
- if (test_bit(NF_FLOW_SNAT, &flow->flags)) {
-@@ -564,7 +643,7 @@ int nf_flow_rule_route_ipv6(struct net *
- flow_offload_port_dnat(net, flow, dir, flow_rule);
- }
-
-- flow_offload_redirect(flow, dir, flow_rule);
-+ flow_offload_redirect(net, flow, dir, flow_rule);
-
- return 0;
- }
-@@ -578,10 +657,10 @@ nf_flow_offload_rule_alloc(struct net *n
- enum flow_offload_tuple_dir dir)
- {
- const struct nf_flowtable *flowtable = offload->flowtable;
-+ const struct flow_offload_tuple *tuple, *other_tuple;
- const struct flow_offload *flow = offload->flow;
-- const struct flow_offload_tuple *tuple;
-+ struct dst_entry *other_dst = NULL;
- struct nf_flow_rule *flow_rule;
-- struct dst_entry *other_dst;
- int err = -ENOMEM;
-
- flow_rule = kzalloc(sizeof(*flow_rule), GFP_KERNEL);
-@@ -597,7 +676,10 @@ nf_flow_offload_rule_alloc(struct net *n
- flow_rule->rule->match.key = &flow_rule->match.key;
-
- tuple = &flow->tuplehash[dir].tuple;
-- other_dst = flow->tuplehash[!dir].tuple.dst_cache;
-+ other_tuple = &flow->tuplehash[!dir].tuple;
-+ if (other_tuple->xmit_type == FLOW_OFFLOAD_XMIT_NEIGH)
-+ other_dst = other_tuple->dst_cache;
-+
- err = nf_flow_rule_match(&flow_rule->match, tuple, other_dst);
- if (err < 0)
- goto err_flow_match;
diff --git a/target/linux/generic/pending-5.10/640-16-dsa-slave-add-support-for-TC_SETUP_FT.patch b/target/linux/generic/pending-5.10/640-16-dsa-slave-add-support-for-TC_SETUP_FT.patch
deleted file mode 100644
index 4dade26f60..0000000000
--- a/target/linux/generic/pending-5.10/640-16-dsa-slave-add-support-for-TC_SETUP_FT.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Mon, 18 Jan 2021 22:39:17 +0100
-Subject: [PATCH] dsa: slave: add support for TC_SETUP_FT
-
-The dsa infrastructure provides a well-defined hierarchy of devices,
-pass up the call to set up the flow block to the master device. From the
-software dataplane, the netfilter infrastructure uses the dsa slave
-devices to refer to the input and output device for the given skbuff.
-Similarly, the flowtable definition in the ruleset refers to the dsa
-slave port devices.
-
-This patch adds the glue code to call ndo_setup_tc with TC_SETUP_FT
-with the master device via the dsa slave devices.
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
-
---- a/net/dsa/slave.c
-+++ b/net/dsa/slave.c
-@@ -1237,14 +1237,32 @@ static int dsa_slave_setup_tc_block(stru
- }
- }
-
-+static int dsa_slave_setup_ft_block(struct dsa_switch *ds, int port,
-+ void *type_data)
-+{
-+ struct dsa_port *cpu_dp = dsa_to_port(ds, port)->cpu_dp;
-+ struct net_device *master = cpu_dp->master;
-+
-+ if (!master->netdev_ops->ndo_setup_tc)
-+ return -EOPNOTSUPP;
-+
-+ return master->netdev_ops->ndo_setup_tc(master, TC_SETUP_FT, type_data);
-+}
-+
- static int dsa_slave_setup_tc(struct net_device *dev, enum tc_setup_type type,
- void *type_data)
- {
- struct dsa_port *dp = dsa_slave_to_port(dev);
- struct dsa_switch *ds = dp->ds;
-
-- if (type == TC_SETUP_BLOCK)
-+ switch (type) {
-+ case TC_SETUP_BLOCK:
- return dsa_slave_setup_tc_block(dev, type_data);
-+ case TC_SETUP_FT:
-+ return dsa_slave_setup_ft_block(ds, dp->index, type_data);
-+ default:
-+ break;
-+ }
-
- if (!ds->ops->port_setup_tc)
- return -EOPNOTSUPP;
diff --git a/target/linux/generic/pending-5.10/640-17-netfilter-nft_flow_offload-use-direct-xmit-if-hardwa.patch b/target/linux/generic/pending-5.10/640-17-netfilter-nft_flow_offload-use-direct-xmit-if-hardwa.patch
deleted file mode 100644
index 26d172bcf7..0000000000
--- a/target/linux/generic/pending-5.10/640-17-netfilter-nft_flow_offload-use-direct-xmit-if-hardwa.patch
+++ /dev/null
@@ -1,108 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Thu, 4 Mar 2021 19:24:11 +0100
-Subject: [PATCH] netfilter: nft_flow_offload: use direct xmit if
- hardware offload is enabled
-
-If there is a forward path to reach an ethernet device and hardware
-offload is enabled, then use the direct xmit path.
----
-
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -131,6 +131,7 @@ struct flow_offload_tuple {
- struct dst_entry *dst_cache;
- struct {
- u32 ifidx;
-+ u32 hw_ifidx;
- u8 h_source[ETH_ALEN];
- u8 h_dest[ETH_ALEN];
- } out;
-@@ -188,6 +189,7 @@ struct nf_flow_route {
- } in;
- struct {
- u32 ifindex;
-+ u32 hw_ifindex;
- u8 h_source[ETH_ALEN];
- u8 h_dest[ETH_ALEN];
- } out;
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -106,6 +106,7 @@ static int flow_offload_fill_route(struc
- memcpy(flow_tuple->out.h_source, route->tuple[dir].out.h_source,
- ETH_ALEN);
- flow_tuple->out.ifidx = route->tuple[dir].out.ifindex;
-+ flow_tuple->out.hw_ifidx = route->tuple[dir].out.hw_ifindex;
- break;
- case FLOW_OFFLOAD_XMIT_XFRM:
- case FLOW_OFFLOAD_XMIT_NEIGH:
---- a/net/netfilter/nf_flow_table_offload.c
-+++ b/net/netfilter/nf_flow_table_offload.c
-@@ -506,7 +506,7 @@ static void flow_offload_redirect(struct
- switch (this_tuple->xmit_type) {
- case FLOW_OFFLOAD_XMIT_DIRECT:
- this_tuple = &flow->tuplehash[dir].tuple;
-- ifindex = this_tuple->out.ifidx;
-+ ifindex = this_tuple->out.hw_ifidx;
- break;
- case FLOW_OFFLOAD_XMIT_NEIGH:
- other_tuple = &flow->tuplehash[!dir].tuple;
---- a/net/netfilter/nft_flow_offload.c
-+++ b/net/netfilter/nft_flow_offload.c
-@@ -66,6 +66,7 @@ static int nft_dev_fill_forward_path(con
- struct nft_forward_info {
- const struct net_device *indev;
- const struct net_device *outdev;
-+ const struct net_device *hw_outdev;
- struct id {
- __u16 id;
- __be16 proto;
-@@ -76,9 +77,18 @@ struct nft_forward_info {
- enum flow_offload_xmit_type xmit_type;
- };
-
-+static bool nft_is_valid_ether_device(const struct net_device *dev)
-+{
-+ if (!dev || (dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER ||
-+ dev->addr_len != ETH_ALEN || !is_valid_ether_addr(dev->dev_addr))
-+ return false;
-+
-+ return true;
-+}
-+
- static void nft_dev_path_info(const struct net_device_path_stack *stack,
- struct nft_forward_info *info,
-- unsigned char *ha)
-+ unsigned char *ha, struct nf_flowtable *flowtable)
- {
- const struct net_device_path *path;
- int i;
-@@ -140,6 +150,12 @@ static void nft_dev_path_info(const stru
- }
- if (!info->outdev)
- info->outdev = info->indev;
-+
-+ info->hw_outdev = info->indev;
-+
-+ if (nf_flowtable_hw_offload(flowtable) &&
-+ nft_is_valid_ether_device(info->indev))
-+ info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
- }
-
- static bool nft_flowtable_find_dev(const struct net_device *dev,
-@@ -171,7 +187,7 @@ static void nft_dev_forward_path(struct
- int i;
-
- if (nft_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0)
-- nft_dev_path_info(&stack, &info, ha);
-+ nft_dev_path_info(&stack, &info, ha, &ft->data);
-
- if (!info.indev || !nft_flowtable_find_dev(info.indev, ft))
- return;
-@@ -187,6 +203,7 @@ static void nft_dev_forward_path(struct
- memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
- memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN);
- route->tuple[dir].out.ifindex = info.outdev->ifindex;
-+ route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex;
- route->tuple[dir].xmit_type = info.xmit_type;
- }
- }
diff --git a/target/linux/generic/pending-5.10/640-18-netfilter-nf_flow_table-fix-untagging-with-hardware-.patch b/target/linux/generic/pending-5.10/640-18-netfilter-nf_flow_table-fix-untagging-with-hardware-.patch
deleted file mode 100644
index 18f43196eb..0000000000
--- a/target/linux/generic/pending-5.10/640-18-netfilter-nf_flow_table-fix-untagging-with-hardware-.patch
+++ /dev/null
@@ -1,122 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Mon, 8 Mar 2021 12:06:44 +0100
-Subject: [PATCH] netfilter: nf_flow_table: fix untagging with
- hardware-offloaded bridge vlan_filtering
-
-When switchdev offloading is enabled, treat an untagged VLAN as tagged for
-ingress only
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -849,6 +849,7 @@ struct net_device_path {
- DEV_PATH_BR_VLAN_KEEP,
- DEV_PATH_BR_VLAN_TAG,
- DEV_PATH_BR_VLAN_UNTAG,
-+ DEV_PATH_BR_VLAN_UNTAG_HW,
- } vlan_mode;
- u16 vlan_id;
- __be16 vlan_proto;
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -123,9 +123,10 @@ struct flow_offload_tuple {
- /* All members above are keys for lookups, see flow_offload_hash(). */
- struct { } __hash;
-
-- u8 dir:4,
-+ u8 dir:2,
- xmit_type:2,
-- encap_num:2;
-+ encap_num:2,
-+ in_vlan_ingress:2;
- u16 mtu;
- union {
- struct dst_entry *dst_cache;
-@@ -185,7 +186,8 @@ struct nf_flow_route {
- u16 id;
- __be16 proto;
- } encap[NF_FLOW_TABLE_ENCAP_MAX];
-- u8 num_encaps;
-+ u8 num_encaps:2,
-+ ingress_vlans:2;
- } in;
- struct {
- u32 ifindex;
---- a/net/bridge/br_device.c
-+++ b/net/bridge/br_device.c
-@@ -435,6 +435,7 @@ static int br_fill_forward_path(struct n
- ctx->vlan[ctx->num_vlans].proto = path->bridge.vlan_proto;
- ctx->num_vlans++;
- break;
-+ case DEV_PATH_BR_VLAN_UNTAG_HW:
- case DEV_PATH_BR_VLAN_UNTAG:
- ctx->num_vlans--;
- break;
---- a/net/bridge/br_vlan.c
-+++ b/net/bridge/br_vlan.c
-@@ -1374,6 +1374,8 @@ int br_vlan_fill_forward_path_mode(struc
-
- if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG)
- path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
-+ else if (v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
-+ path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG_HW;
- else
- path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG;
-
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -95,6 +95,8 @@ static int flow_offload_fill_route(struc
- for (i = route->tuple[dir].in.num_encaps - 1; i >= 0; i--) {
- flow_tuple->encap[j].id = route->tuple[dir].in.encap[i].id;
- flow_tuple->encap[j].proto = route->tuple[dir].in.encap[i].proto;
-+ if (route->tuple[dir].in.ingress_vlans & BIT(i))
-+ flow_tuple->in_vlan_ingress |= BIT(j);
- j++;
- }
- flow_tuple->encap_num = route->tuple[dir].in.num_encaps;
---- a/net/netfilter/nf_flow_table_offload.c
-+++ b/net/netfilter/nf_flow_table_offload.c
-@@ -592,8 +592,12 @@ nf_flow_rule_route_common(struct net *ne
- other_tuple = &flow->tuplehash[!dir].tuple;
-
- for (i = 0; i < other_tuple->encap_num; i++) {
-- struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
-+ struct flow_action_entry *entry;
-
-+ if (other_tuple->in_vlan_ingress & BIT(i))
-+ continue;
-+
-+ entry = flow_action_entry_next(flow_rule);
- entry->id = FLOW_ACTION_VLAN_PUSH;
- entry->vlan.vid = other_tuple->encap[i].id;
- entry->vlan.proto = other_tuple->encap[i].proto;
---- a/net/netfilter/nft_flow_offload.c
-+++ b/net/netfilter/nft_flow_offload.c
-@@ -72,6 +72,7 @@ struct nft_forward_info {
- __be16 proto;
- } encap[NF_FLOW_TABLE_ENCAP_MAX];
- u8 num_encaps;
-+ u8 ingress_vlans;
- u8 h_source[ETH_ALEN];
- u8 h_dest[ETH_ALEN];
- enum flow_offload_xmit_type xmit_type;
-@@ -130,6 +131,9 @@ static void nft_dev_path_info(const stru
- memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
-
- switch (path->bridge.vlan_mode) {
-+ case DEV_PATH_BR_VLAN_UNTAG_HW:
-+ info->ingress_vlans |= BIT(info->num_encaps - 1);
-+ break;
- case DEV_PATH_BR_VLAN_TAG:
- info->encap[info->num_encaps].id = path->bridge.vlan_id;
- info->encap[info->num_encaps].proto = path->bridge.vlan_proto;
-@@ -198,6 +202,7 @@ static void nft_dev_forward_path(struct
- route->tuple[!dir].in.encap[i].proto = info.encap[i].proto;
- }
- route->tuple[!dir].in.num_encaps = info.num_encaps;
-+ route->tuple[!dir].in.ingress_vlans = info.ingress_vlans;
-
- if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
- memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
diff --git a/target/linux/generic/pending-5.10/640-19-net-flow_offload-add-FLOW_ACTION_PPPOE_PUSH.patch b/target/linux/generic/pending-5.10/640-19-net-flow_offload-add-FLOW_ACTION_PPPOE_PUSH.patch
deleted file mode 100644
index 3eaad27cdf..0000000000
--- a/target/linux/generic/pending-5.10/640-19-net-flow_offload-add-FLOW_ACTION_PPPOE_PUSH.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Tue, 2 Mar 2021 00:51:31 +0100
-Subject: [PATCH] net: flow_offload: add FLOW_ACTION_PPPOE_PUSH
-
----
-
---- a/include/net/flow_offload.h
-+++ b/include/net/flow_offload.h
-@@ -147,6 +147,7 @@ enum flow_action_id {
- FLOW_ACTION_MPLS_POP,
- FLOW_ACTION_MPLS_MANGLE,
- FLOW_ACTION_GATE,
-+ FLOW_ACTION_PPPOE_PUSH,
- NUM_FLOW_ACTIONS,
- };
-
-@@ -271,6 +272,9 @@ struct flow_action_entry {
- u32 num_entries;
- struct action_gate_entry *entries;
- } gate;
-+ struct { /* FLOW_ACTION_PPPOE_PUSH */
-+ u16 sid;
-+ } pppoe;
- };
- struct flow_action_cookie *cookie; /* user defined action cookie */
- };
diff --git a/target/linux/generic/pending-5.10/640-20-netfilter-flowtable-support-for-FLOW_ACTION_PPPOE_PU.patch b/target/linux/generic/pending-5.10/640-20-netfilter-flowtable-support-for-FLOW_ACTION_PPPOE_PU.patch
deleted file mode 100644
index fcafff1fff..0000000000
--- a/target/linux/generic/pending-5.10/640-20-netfilter-flowtable-support-for-FLOW_ACTION_PPPOE_PU.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Tue, 2 Mar 2021 01:01:50 +0100
-Subject: [PATCH] netfilter: flowtable: support for
- FLOW_ACTION_PPPOE_PUSH
-
----
-
---- a/net/netfilter/nf_flow_table_offload.c
-+++ b/net/netfilter/nf_flow_table_offload.c
-@@ -598,9 +598,18 @@ nf_flow_rule_route_common(struct net *ne
- continue;
-
- entry = flow_action_entry_next(flow_rule);
-- entry->id = FLOW_ACTION_VLAN_PUSH;
-- entry->vlan.vid = other_tuple->encap[i].id;
-- entry->vlan.proto = other_tuple->encap[i].proto;
-+
-+ switch (other_tuple->encap[i].proto) {
-+ case htons(ETH_P_PPP_SES):
-+ entry->id = FLOW_ACTION_PPPOE_PUSH;
-+ entry->pppoe.sid = other_tuple->encap[i].id;
-+ break;
-+ case htons(ETH_P_8021Q):
-+ entry->id = FLOW_ACTION_VLAN_PUSH;
-+ entry->vlan.vid = other_tuple->encap[i].id;
-+ entry->vlan.proto = other_tuple->encap[i].proto;
-+ break;
-+ }
- }
-
- return 0;
diff --git a/target/linux/generic/pending-5.10/770-00-net-ethernet-mtk_eth_soc-use-napi_consume_skb.patch b/target/linux/generic/pending-5.10/770-00-net-ethernet-mtk_eth_soc-use-napi_consume_skb.patch
index 85c859b388..58cecb6026 100644
--- a/target/linux/generic/pending-5.10/770-00-net-ethernet-mtk_eth_soc-use-napi_consume_skb.patch
+++ b/target/linux/generic/pending-5.10/770-00-net-ethernet-mtk_eth_soc-use-napi_consume_skb.patch
@@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -857,7 +857,8 @@ static int txd_to_idx(struct mtk_tx_ring
+@@ -858,7 +858,8 @@ static int txd_to_idx(struct mtk_tx_ring
return ((void *)dma - (void *)ring->dma) / sizeof(*dma);
}
@@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
{
if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) {
-@@ -889,8 +890,12 @@ static void mtk_tx_unmap(struct mtk_eth
+@@ -890,8 +891,12 @@ static void mtk_tx_unmap(struct mtk_eth
tx_buf->flags = 0;
if (tx_buf->skb &&
@@ -34,7 +34,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
tx_buf->skb = NULL;
}
-@@ -1068,7 +1073,7 @@ err_dma:
+@@ -1069,7 +1074,7 @@ err_dma:
tx_buf = mtk_desc_to_tx_buf(ring, itxd);
/* unmap dma */
diff --git a/target/linux/generic/pending-5.10/770-01-net-ethernet-mtk_eth_soc-significantly-reduce-mdio-b.patch b/target/linux/generic/pending-5.10/770-01-net-ethernet-mtk_eth_soc-significantly-reduce-mdio-b.patch
index 922c35a3e4..577b2eda16 100644
--- a/target/linux/generic/pending-5.10/770-01-net-ethernet-mtk_eth_soc-significantly-reduce-mdio-b.patch
+++ b/target/linux/generic/pending-5.10/770-01-net-ethernet-mtk_eth_soc-significantly-reduce-mdio-b.patch
@@ -15,7 +15,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -85,7 +85,7 @@ static int mtk_mdio_busy_wait(struct mtk
+@@ -86,7 +86,7 @@ static int mtk_mdio_busy_wait(struct mtk
return 0;
if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT))
break;
diff --git a/target/linux/generic/pending-5.10/770-02-net-ethernet-mtk_eth_soc-fix-rx-vlan-offload.patch b/target/linux/generic/pending-5.10/770-02-net-ethernet-mtk_eth_soc-fix-rx-vlan-offload.patch
index cebfe32d95..9357e79c88 100644
--- a/target/linux/generic/pending-5.10/770-02-net-ethernet-mtk_eth_soc-fix-rx-vlan-offload.patch
+++ b/target/linux/generic/pending-5.10/770-02-net-ethernet-mtk_eth_soc-fix-rx-vlan-offload.patch
@@ -21,7 +21,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
skb_record_rx_queue(skb, 0);
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -295,6 +295,7 @@
+@@ -300,6 +300,7 @@
#define RX_DMA_LSO BIT(30)
#define RX_DMA_PLEN0(_x) (((_x) & 0x3fff) << 16)
#define RX_DMA_GET_PLEN0(_x) (((_x) >> 16) & 0x3fff)
diff --git a/target/linux/generic/pending-5.10/770-03-net-ethernet-mtk_eth_soc-fix-unnecessary-tx-queue-st.patch b/target/linux/generic/pending-5.10/770-03-net-ethernet-mtk_eth_soc-fix-unnecessary-tx-queue-st.patch
index 82bdb10eba..eda10a452e 100644
--- a/target/linux/generic/pending-5.10/770-03-net-ethernet-mtk_eth_soc-fix-unnecessary-tx-queue-st.patch
+++ b/target/linux/generic/pending-5.10/770-03-net-ethernet-mtk_eth_soc-fix-unnecessary-tx-queue-st.patch
@@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1130,17 +1130,6 @@ static void mtk_wake_queue(struct mtk_et
+@@ -1131,17 +1131,6 @@ static void mtk_wake_queue(struct mtk_et
}
}
@@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);
-@@ -1161,7 +1150,7 @@ static netdev_tx_t mtk_start_xmit(struct
+@@ -1162,7 +1151,7 @@ static netdev_tx_t mtk_start_xmit(struct
tx_num = mtk_cal_txd_req(skb);
if (unlikely(atomic_read(&ring->free_count) <= tx_num)) {
@@ -39,7 +39,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
netif_err(eth, tx_queued, dev,
"Tx Ring full when queue awake!\n");
spin_unlock(&eth->page_lock);
-@@ -1187,7 +1176,7 @@ static netdev_tx_t mtk_start_xmit(struct
+@@ -1188,7 +1177,7 @@ static netdev_tx_t mtk_start_xmit(struct
goto drop;
if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))
diff --git a/target/linux/generic/pending-5.10/770-04-net-ethernet-mtk_eth_soc-use-larger-burst-size-for-q.patch b/target/linux/generic/pending-5.10/770-04-net-ethernet-mtk_eth_soc-use-larger-burst-size-for-q.patch
index 94c0510257..24e069b8ae 100644
--- a/target/linux/generic/pending-5.10/770-04-net-ethernet-mtk_eth_soc-use-larger-burst-size-for-q.patch
+++ b/target/linux/generic/pending-5.10/770-04-net-ethernet-mtk_eth_soc-use-larger-burst-size-for-q.patch
@@ -21,7 +21,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
MTK_QDMA_GLO_CFG);
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -197,7 +197,7 @@
+@@ -202,7 +202,7 @@
#define MTK_RX_BT_32DWORDS (3 << 11)
#define MTK_NDP_CO_PRO BIT(10)
#define MTK_TX_WB_DDONE BIT(6)
diff --git a/target/linux/generic/pending-5.10/770-05-net-ethernet-mtk_eth_soc-increase-DMA-ring-sizes.patch b/target/linux/generic/pending-5.10/770-05-net-ethernet-mtk_eth_soc-increase-DMA-ring-sizes.patch
index f68cbc333c..201b70b65d 100644
--- a/target/linux/generic/pending-5.10/770-05-net-ethernet-mtk_eth_soc-increase-DMA-ring-sizes.patch
+++ b/target/linux/generic/pending-5.10/770-05-net-ethernet-mtk_eth_soc-increase-DMA-ring-sizes.patch
@@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -19,7 +19,7 @@
+@@ -21,7 +21,7 @@
#define MTK_QDMA_PAGE_SIZE 2048
#define MTK_MAX_RX_LENGTH 1536
#define MTK_TX_DMA_BUF_LEN 0x3fff
diff --git a/target/linux/generic/pending-5.10/770-06-net-ethernet-mtk_eth_soc-implement-dynamic-interrupt.patch b/target/linux/generic/pending-5.10/770-06-net-ethernet-mtk_eth_soc-implement-dynamic-interrupt.patch
index 61a51ba33b..be82637e6d 100644
--- a/target/linux/generic/pending-5.10/770-06-net-ethernet-mtk_eth_soc-implement-dynamic-interrupt.patch
+++ b/target/linux/generic/pending-5.10/770-06-net-ethernet-mtk_eth_soc-implement-dynamic-interrupt.patch
@@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
MediaTek SoC family.
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1232,12 +1232,13 @@ static void mtk_update_rx_cpu_idx(struct
+@@ -1233,12 +1233,13 @@ static void mtk_update_rx_cpu_idx(struct
static int mtk_poll_rx(struct napi_struct *napi, int budget,
struct mtk_eth *eth)
{
@@ -95,7 +95,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (likely(napi_schedule_prep(&eth->tx_napi))) {
__napi_schedule(&eth->tx_napi);
mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
-@@ -2315,6 +2332,9 @@ static int mtk_stop(struct net_device *d
+@@ -2323,6 +2340,9 @@ static int mtk_stop(struct net_device *d
napi_disable(&eth->tx_napi);
napi_disable(&eth->rx_napi);
@@ -105,7 +105,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
mtk_stop_dma(eth, MTK_QDMA_GLO_CFG);
mtk_stop_dma(eth, MTK_PDMA_GLO_CFG);
-@@ -2364,6 +2384,64 @@ err_disable_clks:
+@@ -2375,6 +2395,64 @@ err_disable_clks:
return ret;
}
@@ -170,7 +170,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
static int mtk_hw_init(struct mtk_eth *eth)
{
int i, val, ret;
-@@ -2385,9 +2463,6 @@ static int mtk_hw_init(struct mtk_eth *e
+@@ -2396,9 +2474,6 @@ static int mtk_hw_init(struct mtk_eth *e
goto err_disable_pm;
}
@@ -180,7 +180,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/* disable delay and normal interrupt */
mtk_tx_irq_disable(eth, ~0);
mtk_rx_irq_disable(eth, ~0);
-@@ -2426,11 +2501,10 @@ static int mtk_hw_init(struct mtk_eth *e
+@@ -2437,11 +2512,10 @@ static int mtk_hw_init(struct mtk_eth *e
/* Enable RX VLan Offloading */
mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
@@ -194,7 +194,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
mtk_tx_irq_disable(eth, ~0);
mtk_rx_irq_disable(eth, ~0);
-@@ -2934,6 +3008,13 @@ static int mtk_probe(struct platform_dev
+@@ -2946,6 +3020,13 @@ static int mtk_probe(struct platform_dev
spin_lock_init(&eth->page_lock);
spin_lock_init(&eth->tx_irq_lock);
spin_lock_init(&eth->rx_irq_lock);
@@ -210,15 +210,15 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -15,6 +15,7 @@
- #include <linux/u64_stats_sync.h>
+@@ -16,6 +16,7 @@
#include <linux/refcount.h>
#include <linux/phylink.h>
+ #include <linux/rhashtable.h>
+#include <linux/dim.h>
+ #include "mtk_ppe.h"
#define MTK_QDMA_PAGE_SIZE 2048
- #define MTK_MAX_RX_LENGTH 1536
-@@ -131,13 +132,18 @@
+@@ -136,13 +137,18 @@
/* PDMA Delay Interrupt Register */
#define MTK_PDMA_DELAY_INT 0xa0c
@@ -242,7 +242,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/* PDMA Interrupt Status Register */
#define MTK_PDMA_INT_STATUS 0xa20
-@@ -219,6 +225,7 @@
+@@ -224,6 +230,7 @@
/* QDMA Interrupt Status Register */
#define MTK_QDMA_INT_STATUS 0x1A18
#define MTK_RX_DONE_DLY BIT(30)
@@ -250,7 +250,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#define MTK_RX_DONE_INT3 BIT(19)
#define MTK_RX_DONE_INT2 BIT(18)
#define MTK_RX_DONE_INT1 BIT(17)
-@@ -228,8 +235,7 @@
+@@ -233,8 +240,7 @@
#define MTK_TX_DONE_INT1 BIT(1)
#define MTK_TX_DONE_INT0 BIT(0)
#define MTK_RX_DONE_INT MTK_RX_DONE_DLY
@@ -260,7 +260,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/* QDMA Interrupt grouping registers */
#define MTK_QDMA_INT_GRP1 0x1a20
-@@ -892,6 +898,18 @@ struct mtk_eth {
+@@ -905,6 +911,18 @@ struct mtk_eth {
const struct mtk_soc_data *soc;
diff --git a/target/linux/generic/pending-5.10/770-08-net-ethernet-mtk_eth_soc-cache-hardware-pointer-of-l.patch b/target/linux/generic/pending-5.10/770-08-net-ethernet-mtk_eth_soc-cache-hardware-pointer-of-l.patch
index 20181b8d12..b4ae8dc2e8 100644
--- a/target/linux/generic/pending-5.10/770-08-net-ethernet-mtk_eth_soc-cache-hardware-pointer-of-l.patch
+++ b/target/linux/generic/pending-5.10/770-08-net-ethernet-mtk_eth_soc-cache-hardware-pointer-of-l.patch
@@ -49,7 +49,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
} else {
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -624,6 +624,7 @@ struct mtk_tx_buf {
+@@ -636,6 +636,7 @@ struct mtk_tx_buf {
* @phys: The physical addr of tx_buf
* @next_free: Pointer to the next free descriptor
* @last_free: Pointer to the last free descriptor
@@ -57,7 +57,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
* @thresh: The threshold of minimum amount of free descriptors
* @free_count: QDMA uses a linked list. Track how many free descriptors
* are present
-@@ -634,6 +635,7 @@ struct mtk_tx_ring {
+@@ -646,6 +647,7 @@ struct mtk_tx_ring {
dma_addr_t phys;
struct mtk_tx_dma *next_free;
struct mtk_tx_dma *last_free;
diff --git a/target/linux/generic/pending-5.10/770-09-net-ethernet-mtk_eth_soc-only-read-the-full-rx-descr.patch b/target/linux/generic/pending-5.10/770-09-net-ethernet-mtk_eth_soc-only-read-the-full-rx-descr.patch
index bbd8ae7be4..b744ac643c 100644
--- a/target/linux/generic/pending-5.10/770-09-net-ethernet-mtk_eth_soc-only-read-the-full-rx-descr.patch
+++ b/target/linux/generic/pending-5.10/770-09-net-ethernet-mtk_eth_soc-only-read-the-full-rx-descr.patch
@@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -776,13 +776,18 @@ static inline int mtk_max_buf_size(int f
+@@ -777,13 +777,18 @@ static inline int mtk_max_buf_size(int f
return buf_size;
}
@@ -32,7 +32,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
}
/* the qdma core needs scratch memory to be setup */
-@@ -1254,8 +1259,7 @@ static int mtk_poll_rx(struct napi_struc
+@@ -1255,8 +1260,7 @@ static int mtk_poll_rx(struct napi_struc
rxd = &ring->dma[idx];
data = ring->data[idx];
diff --git a/target/linux/generic/pending-5.10/770-13-net-ethernet-mtk_eth_soc-fix-parsing-packets-in-GDM.patch b/target/linux/generic/pending-5.10/770-13-net-ethernet-mtk_eth_soc-fix-parsing-packets-in-GDM.patch
deleted file mode 100644
index d81d4bf5f4..0000000000
--- a/target/linux/generic/pending-5.10/770-13-net-ethernet-mtk_eth_soc-fix-parsing-packets-in-GDM.patch
+++ /dev/null
@@ -1,67 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sun, 13 Sep 2020 08:17:02 +0200
-Subject: [PATCH] net: ethernet: mtk_eth_soc: fix parsing packets in GDM
-
-When using DSA, set the special tag in GDM ingress control to allow the MAC
-to parse packets properly earlier. This affects rx DMA source port reporting.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -19,6 +19,7 @@
- #include <linux/interrupt.h>
- #include <linux/pinctrl/devinfo.h>
- #include <linux/phylink.h>
-+#include <net/dsa.h>
-
- #include "mtk_eth_soc.h"
-
-@@ -1263,13 +1264,12 @@ static int mtk_poll_rx(struct napi_struc
- break;
-
- /* find out which mac the packet come from. values start at 1 */
-- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
-+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) ||
-+ (trxd.rxd4 & RX_DMA_SPECIAL_TAG))
- mac = 0;
-- } else {
-- mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) &
-- RX_DMA_FPORT_MASK;
-- mac--;
-- }
-+ else
-+ mac = ((trxd.rxd4 >> RX_DMA_FPORT_SHIFT) &
-+ RX_DMA_FPORT_MASK) - 1;
-
- if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT ||
- !eth->netdev[mac]))
-@@ -2251,6 +2251,9 @@ static void mtk_gdm_config(struct mtk_et
-
- val |= config;
-
-+ if (!i && eth->netdev[0] && netdev_uses_dsa(eth->netdev[0]))
-+ val |= MTK_GDMA_SPECIAL_TAG;
-+
- mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
- }
- /* Reset and enable PSE */
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -82,6 +82,7 @@
-
- /* GDM Exgress Control Register */
- #define MTK_GDMA_FWD_CFG(x) (0x500 + (x * 0x1000))
-+#define MTK_GDMA_SPECIAL_TAG BIT(24)
- #define MTK_GDMA_ICS_EN BIT(22)
- #define MTK_GDMA_TCS_EN BIT(21)
- #define MTK_GDMA_UCS_EN BIT(20)
-@@ -311,6 +312,7 @@
- #define RX_DMA_L4_VALID_PDMA BIT(30) /* when PDMA is used */
- #define RX_DMA_FPORT_SHIFT 19
- #define RX_DMA_FPORT_MASK 0x7
-+#define RX_DMA_SPECIAL_TAG BIT(22)
-
- /* PHY Indirect Access Control registers */
- #define MTK_PHY_IAC 0x10004
diff --git a/target/linux/generic/pending-5.10/770-15-net-ethernet-mtk_eth_soc-add-support-for-initializin.patch b/target/linux/generic/pending-5.10/770-15-net-ethernet-mtk_eth_soc-add-support-for-initializin.patch
deleted file mode 100644
index 09282175b0..0000000000
--- a/target/linux/generic/pending-5.10/770-15-net-ethernet-mtk_eth_soc-add-support-for-initializin.patch
+++ /dev/null
@@ -1,1307 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sun, 11 Oct 2020 22:23:08 +0200
-Subject: [PATCH] ethernet: mediatek: mtk_eth_soc: add support for
- initializing the PPE
-
-The PPE (packet processing engine) is used to offload NAT/routed or even
-bridged flows. This patch brings up the PPE and uses it to get a packet
-hash. It also contains some functionality that will be used to bring up
-flow offloading.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
- create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe.c
- create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe.h
- create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
- create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe_regs.h
-
---- a/drivers/net/ethernet/mediatek/Makefile
-+++ b/drivers/net/ethernet/mediatek/Makefile
-@@ -4,5 +4,5 @@
- #
-
- obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
--mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o
-+mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o
- obj-$(CONFIG_NET_MEDIATEK_STAR_EMAC) += mtk_star_emac.o
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2284,12 +2284,17 @@ static int mtk_open(struct net_device *d
-
- /* we run 2 netdevs on the same dma ring so we only bring it up once */
- if (!refcount_read(&eth->dma_refcnt)) {
-- int err = mtk_start_dma(eth);
-+ u32 gdm_config = MTK_GDMA_TO_PDMA;
-+ int err;
-
-+ err = mtk_start_dma(eth);
- if (err)
- return err;
-
-- mtk_gdm_config(eth, MTK_GDMA_TO_PDMA);
-+ if (eth->soc->offload_version && mtk_ppe_start(&eth->ppe) == 0)
-+ gdm_config = MTK_GDMA_TO_PPE;
-+
-+ mtk_gdm_config(eth, gdm_config);
-
- napi_enable(&eth->tx_napi);
- napi_enable(&eth->rx_napi);
-@@ -2359,6 +2364,9 @@ static int mtk_stop(struct net_device *d
-
- mtk_dma_free(eth);
-
-+ if (eth->soc->offload_version)
-+ mtk_ppe_stop(&eth->ppe);
-+
- return 0;
- }
-
-@@ -3148,6 +3156,13 @@ static int mtk_probe(struct platform_dev
- goto err_free_dev;
- }
-
-+ if (eth->soc->offload_version) {
-+ err = mtk_ppe_init(&eth->ppe, eth->dev,
-+ eth->base + MTK_ETH_PPE_BASE, 2);
-+ if (err)
-+ goto err_free_dev;
-+ }
-+
- for (i = 0; i < MTK_MAX_DEVS; i++) {
- if (!eth->netdev[i])
- continue;
-@@ -3222,6 +3237,7 @@ static const struct mtk_soc_data mt7621_
- .hw_features = MTK_HW_FEATURES,
- .required_clks = MT7621_CLKS_BITMAP,
- .required_pctl = false,
-+ .offload_version = 2,
- };
-
- static const struct mtk_soc_data mt7622_data = {
-@@ -3230,6 +3246,7 @@ static const struct mtk_soc_data mt7622_
- .hw_features = MTK_HW_FEATURES,
- .required_clks = MT7622_CLKS_BITMAP,
- .required_pctl = false,
-+ .offload_version = 2,
- };
-
- static const struct mtk_soc_data mt7623_data = {
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -16,6 +16,7 @@
- #include <linux/refcount.h>
- #include <linux/phylink.h>
- #include <linux/dim.h>
-+#include "mtk_ppe.h"
-
- #define MTK_QDMA_PAGE_SIZE 2048
- #define MTK_MAX_RX_LENGTH 1536
-@@ -87,6 +88,7 @@
- #define MTK_GDMA_TCS_EN BIT(21)
- #define MTK_GDMA_UCS_EN BIT(20)
- #define MTK_GDMA_TO_PDMA 0x0
-+#define MTK_GDMA_TO_PPE 0x4444
- #define MTK_GDMA_DROP_ALL 0x7777
-
- /* Unicast Filter MAC Address Register - Low */
-@@ -308,6 +310,12 @@
- #define RX_DMA_VID(_x) ((_x) & 0xfff)
-
- /* QDMA descriptor rxd4 */
-+#define MTK_RXD4_FOE_ENTRY GENMASK(13, 0)
-+#define MTK_RXD4_PPE_CPU_REASON GENMASK(18, 14)
-+#define MTK_RXD4_SRC_PORT GENMASK(21, 19)
-+#define MTK_RXD4_ALG GENMASK(31, 22)
-+
-+/* QDMA descriptor rxd4 */
- #define RX_DMA_L4_VALID BIT(24)
- #define RX_DMA_L4_VALID_PDMA BIT(30) /* when PDMA is used */
- #define RX_DMA_FPORT_SHIFT 19
-@@ -807,6 +815,7 @@ struct mtk_soc_data {
- u32 caps;
- u32 required_clks;
- bool required_pctl;
-+ u8 offload_version;
- netdev_features_t hw_features;
- };
-
-@@ -918,6 +927,8 @@ struct mtk_eth {
- u32 tx_int_status_reg;
- u32 rx_dma_l4_valid;
- int ip_align;
-+
-+ struct mtk_ppe ppe;
- };
-
- /* struct mtk_mac - the structure that holds the info about the MACs of the
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -0,0 +1,511 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
-+
-+#include <linux/kernel.h>
-+#include <linux/jiffies.h>
-+#include <linux/delay.h>
-+#include <linux/io.h>
-+#include <linux/etherdevice.h>
-+#include <linux/platform_device.h>
-+#include "mtk_ppe.h"
-+#include "mtk_ppe_regs.h"
-+
-+static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val)
-+{
-+ writel(val, ppe->base + reg);
-+}
-+
-+static u32 ppe_r32(struct mtk_ppe *ppe, u32 reg)
-+{
-+ return readl(ppe->base + reg);
-+}
-+
-+static u32 ppe_m32(struct mtk_ppe *ppe, u32 reg, u32 mask, u32 set)
-+{
-+ u32 val;
-+
-+ val = ppe_r32(ppe, reg);
-+ val &= ~mask;
-+ val |= set;
-+ ppe_w32(ppe, reg, val);
-+
-+ return val;
-+}
-+
-+static u32 ppe_set(struct mtk_ppe *ppe, u32 reg, u32 val)
-+{
-+ return ppe_m32(ppe, reg, 0, val);
-+}
-+
-+static u32 ppe_clear(struct mtk_ppe *ppe, u32 reg, u32 val)
-+{
-+ return ppe_m32(ppe, reg, val, 0);
-+}
-+
-+static int mtk_ppe_wait_busy(struct mtk_ppe *ppe)
-+{
-+ unsigned long timeout = jiffies + HZ;
-+
-+ while (time_is_after_jiffies(timeout)) {
-+ if (!(ppe_r32(ppe, MTK_PPE_GLO_CFG) & MTK_PPE_GLO_CFG_BUSY))
-+ return 0;
-+
-+ usleep_range(10, 20);
-+ }
-+
-+ dev_err(ppe->dev, "PPE table busy");
-+
-+ return -ETIMEDOUT;
-+}
-+
-+static void mtk_ppe_cache_clear(struct mtk_ppe *ppe)
-+{
-+ ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR);
-+ ppe_clear(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR);
-+}
-+
-+static void mtk_ppe_cache_enable(struct mtk_ppe *ppe, bool enable)
-+{
-+ mtk_ppe_cache_clear(ppe);
-+
-+ ppe_m32(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_EN,
-+ enable * MTK_PPE_CACHE_CTL_EN);
-+}
-+
-+static u32 mtk_ppe_hash_entry(struct mtk_foe_entry *e)
-+{
-+ u32 hv1, hv2, hv3;
-+ u32 hash;
-+
-+ switch (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, e->ib1)) {
-+ case MTK_PPE_PKT_TYPE_BRIDGE:
-+ hv1 = e->bridge.src_mac_lo;
-+ hv1 ^= ((e->bridge.src_mac_hi & 0xffff) << 16);
-+ hv2 = e->bridge.src_mac_hi >> 16;
-+ hv2 ^= e->bridge.dest_mac_lo;
-+ hv3 = e->bridge.dest_mac_hi;
-+ break;
-+ case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
-+ case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
-+ hv1 = e->ipv4.orig.ports;
-+ hv2 = e->ipv4.orig.dest_ip;
-+ hv3 = e->ipv4.orig.src_ip;
-+ break;
-+ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
-+ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
-+ hv1 = e->ipv6.src_ip[3] ^ e->ipv6.dest_ip[3];
-+ hv1 ^= e->ipv6.ports;
-+
-+ hv2 = e->ipv6.src_ip[2] ^ e->ipv6.dest_ip[2];
-+ hv2 ^= e->ipv6.dest_ip[0];
-+
-+ hv3 = e->ipv6.src_ip[1] ^ e->ipv6.dest_ip[1];
-+ hv3 ^= e->ipv6.src_ip[0];
-+ break;
-+ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
-+ case MTK_PPE_PKT_TYPE_IPV6_6RD:
-+ default:
-+ WARN_ON_ONCE(1);
-+ return MTK_PPE_HASH_MASK;
-+ }
-+
-+ hash = (hv1 & hv2) | ((~hv1) & hv3);
-+ hash = (hash >> 24) | ((hash & 0xffffff) << 8);
-+ hash ^= hv1 ^ hv2 ^ hv3;
-+ hash ^= hash >> 16;
-+ hash <<= 1;
-+ hash &= MTK_PPE_ENTRIES - 1;
-+
-+ return hash;
-+}
-+
-+static inline struct mtk_foe_mac_info *
-+mtk_foe_entry_l2(struct mtk_foe_entry *entry)
-+{
-+ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
-+
-+ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE)
-+ return &entry->ipv6.l2;
-+
-+ return &entry->ipv4.l2;
-+}
-+
-+static inline u32 *
-+mtk_foe_entry_ib2(struct mtk_foe_entry *entry)
-+{
-+ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
-+
-+ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE)
-+ return &entry->ipv6.ib2;
-+
-+ return &entry->ipv4.ib2;
-+}
-+
-+int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto,
-+ u8 pse_port, u8 *src_mac, u8 *dest_mac)
-+{
-+ struct mtk_foe_mac_info *l2;
-+ u32 ports_pad, val;
-+
-+ memset(entry, 0, sizeof(*entry));
-+
-+ val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) |
-+ FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) |
-+ FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) |
-+ MTK_FOE_IB1_BIND_TTL |
-+ MTK_FOE_IB1_BIND_CACHE;
-+ entry->ib1 = val;
-+
-+ val = FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) |
-+ FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f) |
-+ FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port);
-+
-+ if (is_multicast_ether_addr(dest_mac))
-+ val |= MTK_FOE_IB2_MULTICAST;
-+
-+ ports_pad = 0xa5a5a500 | (l4proto & 0xff);
-+ if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE)
-+ entry->ipv4.orig.ports = ports_pad;
-+ if (type == MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T)
-+ entry->ipv6.ports = ports_pad;
-+
-+ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
-+ entry->ipv6.ib2 = val;
-+ l2 = &entry->ipv6.l2;
-+ } else {
-+ entry->ipv4.ib2 = val;
-+ l2 = &entry->ipv4.l2;
-+ }
-+
-+ l2->dest_mac_hi = get_unaligned_be32(dest_mac);
-+ l2->dest_mac_lo = get_unaligned_be16(dest_mac + 4);
-+ l2->src_mac_hi = get_unaligned_be32(src_mac);
-+ l2->src_mac_lo = get_unaligned_be16(src_mac + 4);
-+
-+ if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T)
-+ l2->etype = ETH_P_IPV6;
-+ else
-+ l2->etype = ETH_P_IP;
-+
-+ return 0;
-+}
-+
-+int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port)
-+{
-+ u32 *ib2 = mtk_foe_entry_ib2(entry);
-+ u32 val;
-+
-+ val = *ib2;
-+ val &= ~MTK_FOE_IB2_DEST_PORT;
-+ val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT, port);
-+ *ib2 = val;
-+
-+ return 0;
-+}
-+
-+int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool egress,
-+ __be32 src_addr, __be16 src_port,
-+ __be32 dest_addr, __be16 dest_port)
-+{
-+ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
-+ struct mtk_ipv4_tuple *t;
-+
-+ switch (type) {
-+ case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
-+ if (egress) {
-+ t = &entry->ipv4.new;
-+ break;
-+ }
-+ fallthrough;
-+ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
-+ case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
-+ t = &entry->ipv4.orig;
-+ break;
-+ case MTK_PPE_PKT_TYPE_IPV6_6RD:
-+ entry->ipv6_6rd.tunnel_src_ip = be32_to_cpu(src_addr);
-+ entry->ipv6_6rd.tunnel_dest_ip = be32_to_cpu(dest_addr);
-+ return 0;
-+ default:
-+ WARN_ON_ONCE(1);
-+ return -EINVAL;
-+ }
-+
-+ t->src_ip = be32_to_cpu(src_addr);
-+ t->dest_ip = be32_to_cpu(dest_addr);
-+
-+ if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE)
-+ return 0;
-+
-+ t->src_port = be16_to_cpu(src_port);
-+ t->dest_port = be16_to_cpu(dest_port);
-+
-+ return 0;
-+}
-+
-+int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry,
-+ __be32 *src_addr, __be16 src_port,
-+ __be32 *dest_addr, __be16 dest_port)
-+{
-+ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
-+ u32 *src, *dest;
-+ int i;
-+
-+ switch (type) {
-+ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
-+ src = entry->dslite.tunnel_src_ip;
-+ dest = entry->dslite.tunnel_dest_ip;
-+ break;
-+ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
-+ case MTK_PPE_PKT_TYPE_IPV6_6RD:
-+ entry->ipv6.src_port = be16_to_cpu(src_port);
-+ entry->ipv6.dest_port = be16_to_cpu(dest_port);
-+ fallthrough;
-+ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
-+ src = entry->ipv6.src_ip;
-+ dest = entry->ipv6.dest_ip;
-+ break;
-+ default:
-+ WARN_ON_ONCE(1);
-+ return -EINVAL;
-+ };
-+
-+ for (i = 0; i < 4; i++)
-+ src[i] = be32_to_cpu(src_addr[i]);
-+ for (i = 0; i < 4; i++)
-+ dest[i] = be32_to_cpu(dest_addr[i]);
-+
-+ return 0;
-+}
-+
-+int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port)
-+{
-+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
-+
-+ l2->etype = BIT(port);
-+
-+ if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER))
-+ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1);
-+ else
-+ l2->etype |= BIT(8);
-+
-+ entry->ib1 &= ~MTK_FOE_IB1_BIND_VLAN_TAG;
-+
-+ return 0;
-+}
-+
-+int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid)
-+{
-+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
-+
-+ switch (FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, entry->ib1)) {
-+ case 0:
-+ entry->ib1 |= MTK_FOE_IB1_BIND_VLAN_TAG |
-+ FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1);
-+ l2->vlan1 = vid;
-+ return 0;
-+ case 1:
-+ if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG)) {
-+ l2->vlan1 = vid;
-+ l2->etype |= BIT(8);
-+ } else {
-+ l2->vlan2 = vid;
-+ entry->ib1 += FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1);
-+ }
-+ return 0;
-+ default:
-+ return -ENOSPC;
-+ }
-+}
-+
-+int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid)
-+{
-+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
-+
-+ if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER) ||
-+ (entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG))
-+ l2->etype = ETH_P_PPP_SES;
-+
-+ entry->ib1 |= MTK_FOE_IB1_BIND_PPPOE;
-+ l2->pppoe_id = sid;
-+
-+ return 0;
-+}
-+
-+static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry)
-+{
-+ return !(entry->ib1 & MTK_FOE_IB1_STATIC) &&
-+ FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND;
-+}
-+
-+int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
-+ u16 timestamp)
-+{
-+ struct mtk_foe_entry *hwe;
-+ u32 hash;
-+
-+ timestamp &= MTK_FOE_IB1_BIND_TIMESTAMP;
-+ entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP;
-+ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp);
-+
-+ hash = mtk_ppe_hash_entry(entry);
-+ hwe = &ppe->foe_table[hash];
-+ if (!mtk_foe_entry_usable(hwe)) {
-+ hwe++;
-+ hash++;
-+
-+ if (!mtk_foe_entry_usable(hwe))
-+ return -ENOSPC;
-+ }
-+
-+ memcpy(&hwe->data, &entry->data, sizeof(hwe->data));
-+ wmb();
-+ hwe->ib1 = entry->ib1;
-+
-+ dma_wmb();
-+
-+ mtk_ppe_cache_clear(ppe);
-+
-+ return hash;
-+}
-+
-+int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base,
-+ int version)
-+{
-+ struct mtk_foe_entry *foe;
-+
-+ /* need to allocate a separate device, since it PPE DMA access is
-+ * not coherent.
-+ */
-+ ppe->base = base;
-+ ppe->dev = dev;
-+ ppe->version = version;
-+
-+ foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe),
-+ &ppe->foe_phys, GFP_KERNEL);
-+ if (!foe)
-+ return -ENOMEM;
-+
-+ ppe->foe_table = foe;
-+
-+ mtk_ppe_debugfs_init(ppe);
-+
-+ return 0;
-+}
-+
-+static void mtk_ppe_init_foe_table(struct mtk_ppe *ppe)
-+{
-+ static const u8 skip[] = { 12, 25, 38, 51, 76, 89, 102 };
-+ int i, k;
-+
-+ memset(ppe->foe_table, 0, MTK_PPE_ENTRIES * sizeof(ppe->foe_table));
-+
-+ if (!IS_ENABLED(CONFIG_SOC_MT7621))
-+ return;
-+
-+ /* skip all entries that cross the 1024 byte boundary */
-+ for (i = 0; i < MTK_PPE_ENTRIES; i += 128)
-+ for (k = 0; k < ARRAY_SIZE(skip); k++)
-+ ppe->foe_table[i + skip[k]].ib1 |= MTK_FOE_IB1_STATIC;
-+}
-+
-+int mtk_ppe_start(struct mtk_ppe *ppe)
-+{
-+ u32 val;
-+
-+ mtk_ppe_init_foe_table(ppe);
-+ ppe_w32(ppe, MTK_PPE_TB_BASE, ppe->foe_phys);
-+
-+ val = MTK_PPE_TB_CFG_ENTRY_80B |
-+ MTK_PPE_TB_CFG_AGE_NON_L4 |
-+ MTK_PPE_TB_CFG_AGE_UNBIND |
-+ MTK_PPE_TB_CFG_AGE_TCP |
-+ MTK_PPE_TB_CFG_AGE_UDP |
-+ MTK_PPE_TB_CFG_AGE_TCP_FIN |
-+ FIELD_PREP(MTK_PPE_TB_CFG_SEARCH_MISS,
-+ MTK_PPE_SEARCH_MISS_ACTION_FORWARD_BUILD) |
-+ FIELD_PREP(MTK_PPE_TB_CFG_KEEPALIVE,
-+ MTK_PPE_KEEPALIVE_DISABLE) |
-+ FIELD_PREP(MTK_PPE_TB_CFG_HASH_MODE, 1) |
-+ FIELD_PREP(MTK_PPE_TB_CFG_SCAN_MODE,
-+ MTK_PPE_SCAN_MODE_KEEPALIVE_AGE) |
-+ FIELD_PREP(MTK_PPE_TB_CFG_ENTRY_NUM,
-+ MTK_PPE_ENTRIES_SHIFT);
-+ ppe_w32(ppe, MTK_PPE_TB_CFG, val);
-+
-+ ppe_w32(ppe, MTK_PPE_IP_PROTO_CHK,
-+ MTK_PPE_IP_PROTO_CHK_IPV4 | MTK_PPE_IP_PROTO_CHK_IPV6);
-+
-+ mtk_ppe_cache_enable(ppe, true);
-+
-+ val = MTK_PPE_FLOW_CFG_IP4_TCP_FRAG |
-+ MTK_PPE_FLOW_CFG_IP4_UDP_FRAG |
-+ MTK_PPE_FLOW_CFG_IP6_3T_ROUTE |
-+ MTK_PPE_FLOW_CFG_IP6_5T_ROUTE |
-+ MTK_PPE_FLOW_CFG_IP6_6RD |
-+ MTK_PPE_FLOW_CFG_IP4_NAT |
-+ MTK_PPE_FLOW_CFG_IP4_NAPT |
-+ MTK_PPE_FLOW_CFG_IP4_DSLITE |
-+ MTK_PPE_FLOW_CFG_L2_BRIDGE |
-+ MTK_PPE_FLOW_CFG_IP4_NAT_FRAG;
-+ ppe_w32(ppe, MTK_PPE_FLOW_CFG, val);
-+
-+ val = FIELD_PREP(MTK_PPE_UNBIND_AGE_MIN_PACKETS, 1000) |
-+ FIELD_PREP(MTK_PPE_UNBIND_AGE_DELTA, 3);
-+ ppe_w32(ppe, MTK_PPE_UNBIND_AGE, val);
-+
-+ val = FIELD_PREP(MTK_PPE_BIND_AGE0_DELTA_UDP, 12) |
-+ FIELD_PREP(MTK_PPE_BIND_AGE0_DELTA_NON_L4, 1);
-+ ppe_w32(ppe, MTK_PPE_BIND_AGE0, val);
-+
-+ val = FIELD_PREP(MTK_PPE_BIND_AGE1_DELTA_TCP_FIN, 1) |
-+ FIELD_PREP(MTK_PPE_BIND_AGE1_DELTA_TCP, 7);
-+ ppe_w32(ppe, MTK_PPE_BIND_AGE1, val);
-+
-+ val = MTK_PPE_BIND_LIMIT0_QUARTER | MTK_PPE_BIND_LIMIT0_HALF;
-+ ppe_w32(ppe, MTK_PPE_BIND_LIMIT0, val);
-+
-+ val = MTK_PPE_BIND_LIMIT1_FULL |
-+ FIELD_PREP(MTK_PPE_BIND_LIMIT1_NON_L4, 1);
-+ ppe_w32(ppe, MTK_PPE_BIND_LIMIT1, val);
-+
-+ val = FIELD_PREP(MTK_PPE_BIND_RATE_BIND, 30) |
-+ FIELD_PREP(MTK_PPE_BIND_RATE_PREBIND, 1);
-+ ppe_w32(ppe, MTK_PPE_BIND_RATE, val);
-+
-+ /* enable PPE */
-+ val = MTK_PPE_GLO_CFG_EN |
-+ MTK_PPE_GLO_CFG_IP4_L4_CS_DROP |
-+ MTK_PPE_GLO_CFG_IP4_CS_DROP |
-+ MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE;
-+ ppe_w32(ppe, MTK_PPE_GLO_CFG, val);
-+
-+ ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0);
-+
-+ return 0;
-+}
-+
-+int mtk_ppe_stop(struct mtk_ppe *ppe)
-+{
-+ u32 val;
-+ int i;
-+
-+ for (i = 0; i < MTK_PPE_ENTRIES; i++)
-+ ppe->foe_table[i].ib1 = FIELD_PREP(MTK_FOE_IB1_STATE,
-+ MTK_FOE_STATE_INVALID);
-+
-+ mtk_ppe_cache_enable(ppe, false);
-+
-+ /* disable offload engine */
-+ ppe_clear(ppe, MTK_PPE_GLO_CFG, MTK_PPE_GLO_CFG_EN);
-+ ppe_w32(ppe, MTK_PPE_FLOW_CFG, 0);
-+
-+ /* disable aging */
-+ val = MTK_PPE_TB_CFG_AGE_NON_L4 |
-+ MTK_PPE_TB_CFG_AGE_UNBIND |
-+ MTK_PPE_TB_CFG_AGE_TCP |
-+ MTK_PPE_TB_CFG_AGE_UDP |
-+ MTK_PPE_TB_CFG_AGE_TCP_FIN;
-+ ppe_clear(ppe, MTK_PPE_TB_CFG, val);
-+
-+ return mtk_ppe_wait_busy(ppe);
-+}
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
-@@ -0,0 +1,287 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
-+
-+#ifndef __MTK_PPE_H
-+#define __MTK_PPE_H
-+
-+#include <linux/kernel.h>
-+#include <linux/bitfield.h>
-+
-+#define MTK_ETH_PPE_BASE 0xc00
-+
-+#define MTK_PPE_ENTRIES_SHIFT 3
-+#define MTK_PPE_ENTRIES (1024 << MTK_PPE_ENTRIES_SHIFT)
-+#define MTK_PPE_HASH_MASK (MTK_PPE_ENTRIES - 1)
-+
-+#define MTK_FOE_IB1_UNBIND_TIMESTAMP GENMASK(7, 0)
-+#define MTK_FOE_IB1_UNBIND_PACKETS GENMASK(23, 8)
-+#define MTK_FOE_IB1_UNBIND_PREBIND BIT(24)
-+
-+#define MTK_FOE_IB1_BIND_TIMESTAMP GENMASK(14, 0)
-+#define MTK_FOE_IB1_BIND_KEEPALIVE BIT(15)
-+#define MTK_FOE_IB1_BIND_VLAN_LAYER GENMASK(18, 16)
-+#define MTK_FOE_IB1_BIND_PPPOE BIT(19)
-+#define MTK_FOE_IB1_BIND_VLAN_TAG BIT(20)
-+#define MTK_FOE_IB1_BIND_PKT_SAMPLE BIT(21)
-+#define MTK_FOE_IB1_BIND_CACHE BIT(22)
-+#define MTK_FOE_IB1_BIND_TUNNEL_DECAP BIT(23)
-+#define MTK_FOE_IB1_BIND_TTL BIT(24)
-+
-+#define MTK_FOE_IB1_PACKET_TYPE GENMASK(27, 25)
-+#define MTK_FOE_IB1_STATE GENMASK(29, 28)
-+#define MTK_FOE_IB1_UDP BIT(30)
-+#define MTK_FOE_IB1_STATIC BIT(31)
-+
-+enum {
-+ MTK_PPE_PKT_TYPE_IPV4_HNAPT = 0,
-+ MTK_PPE_PKT_TYPE_IPV4_ROUTE = 1,
-+ MTK_PPE_PKT_TYPE_BRIDGE = 2,
-+ MTK_PPE_PKT_TYPE_IPV4_DSLITE = 3,
-+ MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T = 4,
-+ MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T = 5,
-+ MTK_PPE_PKT_TYPE_IPV6_6RD = 7,
-+};
-+
-+#define MTK_FOE_IB2_QID GENMASK(3, 0)
-+#define MTK_FOE_IB2_PSE_QOS BIT(4)
-+#define MTK_FOE_IB2_DEST_PORT GENMASK(7, 5)
-+#define MTK_FOE_IB2_MULTICAST BIT(8)
-+
-+#define MTK_FOE_IB2_WHNAT_QID2 GENMASK(13, 12)
-+#define MTK_FOE_IB2_WHNAT_DEVIDX BIT(16)
-+#define MTK_FOE_IB2_WHNAT_NAT BIT(17)
-+
-+#define MTK_FOE_IB2_PORT_MG GENMASK(17, 12)
-+
-+#define MTK_FOE_IB2_PORT_AG GENMASK(23, 18)
-+
-+#define MTK_FOE_IB2_DSCP GENMASK(31, 24)
-+
-+#define MTK_FOE_VLAN2_WHNAT_BSS GEMMASK(5, 0)
-+#define MTK_FOE_VLAN2_WHNAT_WCID GENMASK(13, 6)
-+#define MTK_FOE_VLAN2_WHNAT_RING GENMASK(15, 14)
-+
-+enum {
-+ MTK_FOE_STATE_INVALID,
-+ MTK_FOE_STATE_UNBIND,
-+ MTK_FOE_STATE_BIND,
-+ MTK_FOE_STATE_FIN
-+};
-+
-+struct mtk_foe_mac_info {
-+ u16 vlan1;
-+ u16 etype;
-+
-+ u32 dest_mac_hi;
-+
-+ u16 vlan2;
-+ u16 dest_mac_lo;
-+
-+ u32 src_mac_hi;
-+
-+ u16 pppoe_id;
-+ u16 src_mac_lo;
-+};
-+
-+struct mtk_foe_bridge {
-+ u32 dest_mac_hi;
-+
-+ u16 src_mac_lo;
-+ u16 dest_mac_lo;
-+
-+ u32 src_mac_hi;
-+
-+ u32 ib2;
-+
-+ u32 _rsv[5];
-+
-+ u32 udf_tsid;
-+ struct mtk_foe_mac_info l2;
-+};
-+
-+struct mtk_ipv4_tuple {
-+ u32 src_ip;
-+ u32 dest_ip;
-+ union {
-+ struct {
-+ u16 dest_port;
-+ u16 src_port;
-+ };
-+ struct {
-+ u8 protocol;
-+ u8 _pad[3]; /* fill with 0xa5a5a5 */
-+ };
-+ u32 ports;
-+ };
-+};
-+
-+struct mtk_foe_ipv4 {
-+ struct mtk_ipv4_tuple orig;
-+
-+ u32 ib2;
-+
-+ struct mtk_ipv4_tuple new;
-+
-+ u16 timestamp;
-+ u16 _rsv0[3];
-+
-+ u32 udf_tsid;
-+
-+ struct mtk_foe_mac_info l2;
-+};
-+
-+struct mtk_foe_ipv4_dslite {
-+ struct mtk_ipv4_tuple ip4;
-+
-+ u32 tunnel_src_ip[4];
-+ u32 tunnel_dest_ip[4];
-+
-+ u8 flow_label[3];
-+ u8 priority;
-+
-+ u32 udf_tsid;
-+
-+ u32 ib2;
-+
-+ struct mtk_foe_mac_info l2;
-+};
-+
-+struct mtk_foe_ipv6 {
-+ u32 src_ip[4];
-+ u32 dest_ip[4];
-+
-+ union {
-+ struct {
-+ u8 protocol;
-+ u8 _pad[3]; /* fill with 0xa5a5a5 */
-+ }; /* 3-tuple */
-+ struct {
-+ u16 dest_port;
-+ u16 src_port;
-+ }; /* 5-tuple */
-+ u32 ports;
-+ };
-+
-+ u32 _rsv[3];
-+
-+ u32 udf;
-+
-+ u32 ib2;
-+ struct mtk_foe_mac_info l2;
-+};
-+
-+struct mtk_foe_ipv6_6rd {
-+ u32 src_ip[4];
-+ u32 dest_ip[4];
-+ u16 dest_port;
-+ u16 src_port;
-+
-+ u32 tunnel_src_ip;
-+ u32 tunnel_dest_ip;
-+
-+ u16 hdr_csum;
-+ u8 dscp;
-+ u8 ttl;
-+
-+ u8 flag;
-+ u8 pad;
-+ u8 per_flow_6rd_id;
-+ u8 pad2;
-+
-+ u32 ib2;
-+ struct mtk_foe_mac_info l2;
-+};
-+
-+struct mtk_foe_entry {
-+ u32 ib1;
-+
-+ union {
-+ struct mtk_foe_bridge bridge;
-+ struct mtk_foe_ipv4 ipv4;
-+ struct mtk_foe_ipv4_dslite dslite;
-+ struct mtk_foe_ipv6 ipv6;
-+ struct mtk_foe_ipv6_6rd ipv6_6rd;
-+ u32 data[19];
-+ };
-+};
-+
-+enum {
-+ MTK_PPE_CPU_REASON_TTL_EXCEEDED = 0x02,
-+ MTK_PPE_CPU_REASON_OPTION_HEADER = 0x03,
-+ MTK_PPE_CPU_REASON_NO_FLOW = 0x07,
-+ MTK_PPE_CPU_REASON_IPV4_FRAG = 0x08,
-+ MTK_PPE_CPU_REASON_IPV4_DSLITE_FRAG = 0x09,
-+ MTK_PPE_CPU_REASON_IPV4_DSLITE_NO_TCP_UDP = 0x0a,
-+ MTK_PPE_CPU_REASON_IPV6_6RD_NO_TCP_UDP = 0x0b,
-+ MTK_PPE_CPU_REASON_TCP_FIN_SYN_RST = 0x0c,
-+ MTK_PPE_CPU_REASON_UN_HIT = 0x0d,
-+ MTK_PPE_CPU_REASON_HIT_UNBIND = 0x0e,
-+ MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED = 0x0f,
-+ MTK_PPE_CPU_REASON_HIT_BIND_TCP_FIN = 0x10,
-+ MTK_PPE_CPU_REASON_HIT_TTL_1 = 0x11,
-+ MTK_PPE_CPU_REASON_HIT_BIND_VLAN_VIOLATION = 0x12,
-+ MTK_PPE_CPU_REASON_KEEPALIVE_UC_OLD_HDR = 0x13,
-+ MTK_PPE_CPU_REASON_KEEPALIVE_MC_NEW_HDR = 0x14,
-+ MTK_PPE_CPU_REASON_KEEPALIVE_DUP_OLD_HDR = 0x15,
-+ MTK_PPE_CPU_REASON_HIT_BIND_FORCE_CPU = 0x16,
-+ MTK_PPE_CPU_REASON_TUNNEL_OPTION_HEADER = 0x17,
-+ MTK_PPE_CPU_REASON_MULTICAST_TO_CPU = 0x18,
-+ MTK_PPE_CPU_REASON_MULTICAST_TO_GMAC1_CPU = 0x19,
-+ MTK_PPE_CPU_REASON_HIT_PRE_BIND = 0x1a,
-+ MTK_PPE_CPU_REASON_PACKET_SAMPLING = 0x1b,
-+ MTK_PPE_CPU_REASON_EXCEED_MTU = 0x1c,
-+ MTK_PPE_CPU_REASON_PPE_BYPASS = 0x1e,
-+ MTK_PPE_CPU_REASON_INVALID = 0x1f,
-+};
-+
-+struct mtk_ppe {
-+ struct device *dev;
-+ void __iomem *base;
-+ int version;
-+
-+ struct mtk_foe_entry *foe_table;
-+ dma_addr_t foe_phys;
-+
-+ void *acct_table;
-+};
-+
-+int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base,
-+ int version);
-+int mtk_ppe_start(struct mtk_ppe *ppe);
-+int mtk_ppe_stop(struct mtk_ppe *ppe);
-+
-+static inline void
-+mtk_foe_entry_clear(struct mtk_ppe *ppe, u16 hash)
-+{
-+ ppe->foe_table[hash].ib1 = 0;
-+ dma_wmb();
-+}
-+
-+static inline int
-+mtk_foe_entry_timestamp(struct mtk_ppe *ppe, u16 hash)
-+{
-+ u32 ib1 = READ_ONCE(ppe->foe_table[hash].ib1);
-+
-+ if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND)
-+ return -1;
-+
-+ return FIELD_GET(MTK_FOE_IB1_BIND_TIMESTAMP, ib1);
-+}
-+
-+int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto,
-+ u8 pse_port, u8 *src_mac, u8 *dest_mac);
-+int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port);
-+int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool orig,
-+ __be32 src_addr, __be16 src_port,
-+ __be32 dest_addr, __be16 dest_port);
-+int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry,
-+ __be32 *src_addr, __be16 src_port,
-+ __be32 *dest_addr, __be16 dest_port);
-+int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port);
-+int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
-+int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
-+int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
-+ u16 timestamp);
-+int mtk_ppe_debugfs_init(struct mtk_ppe *ppe);
-+
-+#endif
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
-@@ -0,0 +1,217 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
-+
-+#include <linux/kernel.h>
-+#include <linux/debugfs.h>
-+#include "mtk_eth_soc.h"
-+
-+struct mtk_flow_addr_info
-+{
-+ void *src, *dest;
-+ u16 *src_port, *dest_port;
-+ bool ipv6;
-+};
-+
-+static const char *mtk_foe_entry_state_str(int state)
-+{
-+ static const char * const state_str[] = {
-+ [MTK_FOE_STATE_INVALID] = "INV",
-+ [MTK_FOE_STATE_UNBIND] = "UNB",
-+ [MTK_FOE_STATE_BIND] = "BND",
-+ [MTK_FOE_STATE_FIN] = "FIN",
-+ };
-+
-+ if (state >= ARRAY_SIZE(state_str) || !state_str[state])
-+ return "UNK";
-+
-+ return state_str[state];
-+}
-+
-+static const char *mtk_foe_pkt_type_str(int type)
-+{
-+ static const char * const type_str[] = {
-+ [MTK_PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T",
-+ [MTK_PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T",
-+ [MTK_PPE_PKT_TYPE_BRIDGE] = "L2",
-+ [MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE",
-+ [MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T",
-+ [MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T",
-+ [MTK_PPE_PKT_TYPE_IPV6_6RD] = "6RD",
-+ };
-+
-+ if (type >= ARRAY_SIZE(type_str) || !type_str[type])
-+ return "UNKNOWN";
-+
-+ return type_str[type];
-+}
-+
-+static void
-+mtk_print_addr(struct seq_file *m, u32 *addr, bool ipv6)
-+{
-+ u32 n_addr[4];
-+ int i;
-+
-+ if (!ipv6) {
-+ seq_printf(m, "%pI4h", addr);
-+ return;
-+ }
-+
-+ for (i = 0; i < ARRAY_SIZE(n_addr); i++)
-+ n_addr[i] = htonl(addr[i]);
-+ seq_printf(m, "%pI6", n_addr);
-+}
-+
-+static void
-+mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai)
-+{
-+ mtk_print_addr(m, ai->src, ai->ipv6);
-+ if (ai->src_port)
-+ seq_printf(m, ":%d", *ai->src_port);
-+ seq_printf(m, "->");
-+ mtk_print_addr(m, ai->dest, ai->ipv6);
-+ if (ai->dest_port)
-+ seq_printf(m, ":%d", *ai->dest_port);
-+}
-+
-+static int
-+mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
-+{
-+ struct mtk_ppe *ppe = m->private;
-+ int i, count;
-+
-+ for (i = 0, count = 0; i < MTK_PPE_ENTRIES; i++) {
-+ struct mtk_foe_entry *entry = &ppe->foe_table[i];
-+ struct mtk_foe_mac_info *l2;
-+ struct mtk_flow_addr_info ai = {};
-+ unsigned char h_source[ETH_ALEN];
-+ unsigned char h_dest[ETH_ALEN];
-+ int type, state;
-+ u32 ib2;
-+
-+
-+ state = FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1);
-+ if (!state)
-+ continue;
-+
-+ if (bind && state != MTK_FOE_STATE_BIND)
-+ continue;
-+
-+ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
-+ seq_printf(m, "%05x %s %7s", i,
-+ mtk_foe_entry_state_str(state),
-+ mtk_foe_pkt_type_str(type));
-+
-+ switch (type) {
-+ case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
-+ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
-+ ai.src_port = &entry->ipv4.orig.src_port;
-+ ai.dest_port = &entry->ipv4.orig.dest_port;
-+ fallthrough;
-+ case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
-+ ai.src = &entry->ipv4.orig.src_ip;
-+ ai.dest = &entry->ipv4.orig.dest_ip;
-+ break;
-+ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
-+ ai.src_port = &entry->ipv6.src_port;
-+ ai.dest_port = &entry->ipv6.dest_port;
-+ fallthrough;
-+ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
-+ case MTK_PPE_PKT_TYPE_IPV6_6RD:
-+ ai.src = &entry->ipv6.src_ip;
-+ ai.dest = &entry->ipv6.dest_ip;
-+ ai.ipv6 = true;
-+ break;
-+ }
-+
-+ seq_printf(m, " orig=");
-+ mtk_print_addr_info(m, &ai);
-+
-+ switch (type) {
-+ case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
-+ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
-+ ai.src_port = &entry->ipv4.new.src_port;
-+ ai.dest_port = &entry->ipv4.new.dest_port;
-+ fallthrough;
-+ case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
-+ ai.src = &entry->ipv4.new.src_ip;
-+ ai.dest = &entry->ipv4.new.dest_ip;
-+ seq_printf(m, " new=");
-+ mtk_print_addr_info(m, &ai);
-+ break;
-+ }
-+
-+ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
-+ l2 = &entry->ipv6.l2;
-+ ib2 = entry->ipv6.ib2;
-+ } else {
-+ l2 = &entry->ipv4.l2;
-+ ib2 = entry->ipv4.ib2;
-+ }
-+
-+ *((__be32 *)h_source) = htonl(l2->src_mac_hi);
-+ *((__be16 *)&h_source[4]) = htons(l2->src_mac_lo);
-+ *((__be32 *)h_dest) = htonl(l2->dest_mac_hi);
-+ *((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo);
-+
-+ seq_printf(m, " eth=%pM->%pM etype=%04x"
-+ " vlan=%d,%d ib1=%08x ib2=%08x\n",
-+ h_source, h_dest, ntohs(l2->etype),
-+ l2->vlan1, l2->vlan2, entry->ib1, ib2);
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+mtk_ppe_debugfs_foe_show_all(struct seq_file *m, void *private)
-+{
-+ return mtk_ppe_debugfs_foe_show(m, private, false);
-+}
-+
-+static int
-+mtk_ppe_debugfs_foe_show_bind(struct seq_file *m, void *private)
-+{
-+ return mtk_ppe_debugfs_foe_show(m, private, true);
-+}
-+
-+static int
-+mtk_ppe_debugfs_foe_open_all(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, mtk_ppe_debugfs_foe_show_all,
-+ inode->i_private);
-+}
-+
-+static int
-+mtk_ppe_debugfs_foe_open_bind(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, mtk_ppe_debugfs_foe_show_bind,
-+ inode->i_private);
-+}
-+
-+int mtk_ppe_debugfs_init(struct mtk_ppe *ppe)
-+{
-+ static const struct file_operations fops_all = {
-+ .open = mtk_ppe_debugfs_foe_open_all,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+ };
-+
-+ static const struct file_operations fops_bind = {
-+ .open = mtk_ppe_debugfs_foe_open_bind,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+ };
-+
-+ struct dentry *root;
-+
-+ root = debugfs_create_dir("mtk_ppe", NULL);
-+ if (!root)
-+ return -ENOMEM;
-+
-+ debugfs_create_file("entries", S_IRUGO, root, ppe, &fops_all);
-+ debugfs_create_file("bind", S_IRUGO, root, ppe, &fops_bind);
-+
-+ return 0;
-+}
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
-@@ -0,0 +1,144 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
-+
-+#ifndef __MTK_PPE_REGS_H
-+#define __MTK_PPE_REGS_H
-+
-+#define MTK_PPE_GLO_CFG 0x200
-+#define MTK_PPE_GLO_CFG_EN BIT(0)
-+#define MTK_PPE_GLO_CFG_TSID_EN BIT(1)
-+#define MTK_PPE_GLO_CFG_IP4_L4_CS_DROP BIT(2)
-+#define MTK_PPE_GLO_CFG_IP4_CS_DROP BIT(3)
-+#define MTK_PPE_GLO_CFG_TTL0_DROP BIT(4)
-+#define MTK_PPE_GLO_CFG_PPE_BSWAP BIT(5)
-+#define MTK_PPE_GLO_CFG_PSE_HASH_OFS BIT(6)
-+#define MTK_PPE_GLO_CFG_MCAST_TB_EN BIT(7)
-+#define MTK_PPE_GLO_CFG_FLOW_DROP_KA BIT(8)
-+#define MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE BIT(9)
-+#define MTK_PPE_GLO_CFG_UDP_LITE_EN BIT(10)
-+#define MTK_PPE_GLO_CFG_UDP_LEN_DROP BIT(11)
-+#define MTK_PPE_GLO_CFG_MCAST_ENTRIES GNEMASK(13, 12)
-+#define MTK_PPE_GLO_CFG_BUSY BIT(31)
-+
-+#define MTK_PPE_FLOW_CFG 0x204
-+#define MTK_PPE_FLOW_CFG_IP4_TCP_FRAG BIT(6)
-+#define MTK_PPE_FLOW_CFG_IP4_UDP_FRAG BIT(7)
-+#define MTK_PPE_FLOW_CFG_IP6_3T_ROUTE BIT(8)
-+#define MTK_PPE_FLOW_CFG_IP6_5T_ROUTE BIT(9)
-+#define MTK_PPE_FLOW_CFG_IP6_6RD BIT(10)
-+#define MTK_PPE_FLOW_CFG_IP4_NAT BIT(12)
-+#define MTK_PPE_FLOW_CFG_IP4_NAPT BIT(13)
-+#define MTK_PPE_FLOW_CFG_IP4_DSLITE BIT(14)
-+#define MTK_PPE_FLOW_CFG_L2_BRIDGE BIT(15)
-+#define MTK_PPE_FLOW_CFG_IP_PROTO_BLACKLIST BIT(16)
-+#define MTK_PPE_FLOW_CFG_IP4_NAT_FRAG BIT(17)
-+#define MTK_PPE_FLOW_CFG_IP4_HASH_FLOW_LABEL BIT(18)
-+#define MTK_PPE_FLOW_CFG_IP4_HASH_GRE_KEY BIT(19)
-+#define MTK_PPE_FLOW_CFG_IP6_HASH_GRE_KEY BIT(20)
-+
-+#define MTK_PPE_IP_PROTO_CHK 0x208
-+#define MTK_PPE_IP_PROTO_CHK_IPV4 GENMASK(15, 0)
-+#define MTK_PPE_IP_PROTO_CHK_IPV6 GENMASK(31, 16)
-+
-+#define MTK_PPE_TB_CFG 0x21c
-+#define MTK_PPE_TB_CFG_ENTRY_NUM GENMASK(2, 0)
-+#define MTK_PPE_TB_CFG_ENTRY_80B BIT(3)
-+#define MTK_PPE_TB_CFG_SEARCH_MISS GENMASK(5, 4)
-+#define MTK_PPE_TB_CFG_AGE_PREBIND BIT(6)
-+#define MTK_PPE_TB_CFG_AGE_NON_L4 BIT(7)
-+#define MTK_PPE_TB_CFG_AGE_UNBIND BIT(8)
-+#define MTK_PPE_TB_CFG_AGE_TCP BIT(9)
-+#define MTK_PPE_TB_CFG_AGE_UDP BIT(10)
-+#define MTK_PPE_TB_CFG_AGE_TCP_FIN BIT(11)
-+#define MTK_PPE_TB_CFG_KEEPALIVE GENMASK(13, 12)
-+#define MTK_PPE_TB_CFG_HASH_MODE GENMASK(15, 14)
-+#define MTK_PPE_TB_CFG_SCAN_MODE GENMASK(17, 16)
-+#define MTK_PPE_TB_CFG_HASH_DEBUG GENMASK(19, 18)
-+
-+enum {
-+ MTK_PPE_SCAN_MODE_DISABLED,
-+ MTK_PPE_SCAN_MODE_CHECK_AGE,
-+ MTK_PPE_SCAN_MODE_KEEPALIVE_AGE,
-+};
-+
-+enum {
-+ MTK_PPE_KEEPALIVE_DISABLE,
-+ MTK_PPE_KEEPALIVE_UNICAST_CPU,
-+ MTK_PPE_KEEPALIVE_DUP_CPU = 3,
-+};
-+
-+enum {
-+ MTK_PPE_SEARCH_MISS_ACTION_DROP,
-+ MTK_PPE_SEARCH_MISS_ACTION_FORWARD = 2,
-+ MTK_PPE_SEARCH_MISS_ACTION_FORWARD_BUILD = 3,
-+};
-+
-+#define MTK_PPE_TB_BASE 0x220
-+
-+#define MTK_PPE_TB_USED 0x224
-+#define MTK_PPE_TB_USED_NUM GENMASK(13, 0)
-+
-+#define MTK_PPE_BIND_RATE 0x228
-+#define MTK_PPE_BIND_RATE_BIND GENMASK(15, 0)
-+#define MTK_PPE_BIND_RATE_PREBIND GENMASK(31, 16)
-+
-+#define MTK_PPE_BIND_LIMIT0 0x22c
-+#define MTK_PPE_BIND_LIMIT0_QUARTER GENMASK(13, 0)
-+#define MTK_PPE_BIND_LIMIT0_HALF GENMASK(29, 16)
-+
-+#define MTK_PPE_BIND_LIMIT1 0x230
-+#define MTK_PPE_BIND_LIMIT1_FULL GENMASK(13, 0)
-+#define MTK_PPE_BIND_LIMIT1_NON_L4 GENMASK(23, 16)
-+
-+#define MTK_PPE_KEEPALIVE 0x234
-+#define MTK_PPE_KEEPALIVE_TIME GENMASK(15, 0)
-+#define MTK_PPE_KEEPALIVE_TIME_TCP GENMASK(23, 16)
-+#define MTK_PPE_KEEPALIVE_TIME_UDP GENMASK(31, 24)
-+
-+#define MTK_PPE_UNBIND_AGE 0x238
-+#define MTK_PPE_UNBIND_AGE_MIN_PACKETS GENMASK(31, 16)
-+#define MTK_PPE_UNBIND_AGE_DELTA GENMASK(7, 0)
-+
-+#define MTK_PPE_BIND_AGE0 0x23c
-+#define MTK_PPE_BIND_AGE0_DELTA_NON_L4 GENMASK(30, 16)
-+#define MTK_PPE_BIND_AGE0_DELTA_UDP GENMASK(14, 0)
-+
-+#define MTK_PPE_BIND_AGE1 0x240
-+#define MTK_PPE_BIND_AGE1_DELTA_TCP_FIN GENMASK(30, 16)
-+#define MTK_PPE_BIND_AGE1_DELTA_TCP GENMASK(14, 0)
-+
-+#define MTK_PPE_HASH_SEED 0x244
-+
-+#define MTK_PPE_DEFAULT_CPU_PORT 0x248
-+#define MTK_PPE_DEFAULT_CPU_PORT_MASK(_n) (GENMASK(2, 0) << ((_n) * 4))
-+
-+#define MTK_PPE_MTU_DROP 0x308
-+
-+#define MTK_PPE_VLAN_MTU0 0x30c
-+#define MTK_PPE_VLAN_MTU0_NONE GENMASK(13, 0)
-+#define MTK_PPE_VLAN_MTU0_1TAG GENMASK(29, 16)
-+
-+#define MTK_PPE_VLAN_MTU1 0x310
-+#define MTK_PPE_VLAN_MTU1_2TAG GENMASK(13, 0)
-+#define MTK_PPE_VLAN_MTU1_3TAG GENMASK(29, 16)
-+
-+#define MTK_PPE_VPM_TPID 0x318
-+
-+#define MTK_PPE_CACHE_CTL 0x320
-+#define MTK_PPE_CACHE_CTL_EN BIT(0)
-+#define MTK_PPE_CACHE_CTL_LOCK_CLR BIT(4)
-+#define MTK_PPE_CACHE_CTL_REQ BIT(8)
-+#define MTK_PPE_CACHE_CTL_CLEAR BIT(9)
-+#define MTK_PPE_CACHE_CTL_CMD GENMASK(13, 12)
-+
-+#define MTK_PPE_MIB_CFG 0x334
-+#define MTK_PPE_MIB_CFG_EN BIT(0)
-+#define MTK_PPE_MIB_CFG_RD_CLR BIT(1)
-+
-+#define MTK_PPE_MIB_TB_BASE 0x338
-+
-+#define MTK_PPE_MIB_CACHE_CTL 0x350
-+#define MTK_PPE_MIB_CACHE_CTL_EN BIT(0)
-+#define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2)
-+
-+#endif
diff --git a/target/linux/generic/pending-5.10/770-16-net-ethernet-mtk_eth_soc-add-flow-offloading-support.patch b/target/linux/generic/pending-5.10/770-16-net-ethernet-mtk_eth_soc-add-flow-offloading-support.patch
deleted file mode 100644
index 2f1ae6cde6..0000000000
--- a/target/linux/generic/pending-5.10/770-16-net-ethernet-mtk_eth_soc-add-flow-offloading-support.patch
+++ /dev/null
@@ -1,574 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 10 Dec 2020 12:19:18 +0100
-Subject: [PATCH] net: ethernet: mtk_eth_soc: add flow offloading support
-
-This adds support for offloading IPv4 routed flows, including SNAT/DNAT,
-one VLAN, and DSA.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
- create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-
---- a/drivers/net/ethernet/mediatek/Makefile
-+++ b/drivers/net/ethernet/mediatek/Makefile
-@@ -4,5 +4,5 @@
- #
-
- obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
--mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o
-+mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o
- obj-$(CONFIG_NET_MEDIATEK_STAR_EMAC) += mtk_star_emac.o
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2896,6 +2896,7 @@ static const struct net_device_ops mtk_n
- #ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = mtk_poll_controller,
- #endif
-+ .ndo_setup_tc = mtk_eth_setup_tc,
- };
-
- static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
-@@ -3161,6 +3162,10 @@ static int mtk_probe(struct platform_dev
- eth->base + MTK_ETH_PPE_BASE, 2);
- if (err)
- goto err_free_dev;
-+
-+ err = mtk_eth_offload_init(eth);
-+ if (err)
-+ goto err_free_dev;
- }
-
- for (i = 0; i < MTK_MAX_DEVS; i++) {
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -16,6 +16,7 @@
- #include <linux/refcount.h>
- #include <linux/phylink.h>
- #include <linux/dim.h>
-+#include <linux/rhashtable.h>
- #include "mtk_ppe.h"
-
- #define MTK_QDMA_PAGE_SIZE 2048
-@@ -41,7 +42,8 @@
- NETIF_F_HW_VLAN_CTAG_RX | \
- NETIF_F_SG | NETIF_F_TSO | \
- NETIF_F_TSO6 | \
-- NETIF_F_IPV6_CSUM)
-+ NETIF_F_IPV6_CSUM |\
-+ NETIF_F_HW_TC)
- #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM)
- #define NEXT_DESP_IDX(X, Y) (((X) + 1) & ((Y) - 1))
-
-@@ -929,6 +931,7 @@ struct mtk_eth {
- int ip_align;
-
- struct mtk_ppe ppe;
-+ struct rhashtable flow_table;
- };
-
- /* struct mtk_mac - the structure that holds the info about the MACs of the
-@@ -973,4 +976,9 @@ int mtk_gmac_sgmii_path_setup(struct mtk
- int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id);
- int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id);
-
-+int mtk_eth_offload_init(struct mtk_eth *eth);
-+int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
-+ void *type_data);
-+
-+
- #endif /* MTK_ETH_H */
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -0,0 +1,491 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * Copyright (C) 2020 Felix Fietkau <nbd@nbd.name>
-+ */
-+
-+#include <linux/if_ether.h>
-+#include <linux/rhashtable.h>
-+#include <linux/if_ether.h>
-+#include <linux/ip.h>
-+#include <net/flow_offload.h>
-+#include <net/pkt_cls.h>
-+#include <net/dsa.h>
-+#include "mtk_eth_soc.h"
-+
-+struct mtk_flow_data {
-+ struct ethhdr eth;
-+
-+ union {
-+ struct {
-+ __be32 src_addr;
-+ __be32 dst_addr;
-+ } v4;
-+ };
-+
-+ __be16 src_port;
-+ __be16 dst_port;
-+
-+ struct {
-+ u16 id;
-+ __be16 proto;
-+ u8 num;
-+ } vlan;
-+ struct {
-+ u16 sid;
-+ u8 num;
-+ } pppoe;
-+};
-+
-+struct mtk_flow_entry {
-+ struct rhash_head node;
-+ unsigned long cookie;
-+ u16 hash;
-+};
-+
-+static const struct rhashtable_params mtk_flow_ht_params = {
-+ .head_offset = offsetof(struct mtk_flow_entry, node),
-+ .head_offset = offsetof(struct mtk_flow_entry, cookie),
-+ .key_len = sizeof(unsigned long),
-+ .automatic_shrinking = true,
-+};
-+
-+static u32
-+mtk_eth_timestamp(struct mtk_eth *eth)
-+{
-+ return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP;
-+}
-+
-+static int
-+mtk_flow_set_ipv4_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data,
-+ bool egress)
-+{
-+ return mtk_foe_entry_set_ipv4_tuple(foe, egress,
-+ data->v4.src_addr, data->src_port,
-+ data->v4.dst_addr, data->dst_port);
-+}
-+
-+static void
-+mtk_flow_offload_mangle_eth(const struct flow_action_entry *act, void *eth)
-+{
-+ void *dest = eth + act->mangle.offset;
-+ const void *src = &act->mangle.val;
-+
-+ if (act->mangle.offset > 8)
-+ return;
-+
-+ if (act->mangle.mask == 0xffff) {
-+ src += 2;
-+ dest += 2;
-+ }
-+
-+ memcpy(dest, src, act->mangle.mask ? 2 : 4);
-+}
-+
-+
-+static int
-+mtk_flow_mangle_ports(const struct flow_action_entry *act,
-+ struct mtk_flow_data *data)
-+{
-+ u32 val = ntohl(act->mangle.val);
-+
-+ switch (act->mangle.offset) {
-+ case 0:
-+ if (act->mangle.mask == ~htonl(0xffff))
-+ data->dst_port = cpu_to_be16(val);
-+ else
-+ data->src_port = cpu_to_be16(val >> 16);
-+ break;
-+ case 2:
-+ data->dst_port = cpu_to_be16(val);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+mtk_flow_mangle_ipv4(const struct flow_action_entry *act,
-+ struct mtk_flow_data *data)
-+{
-+ __be32 *dest;
-+
-+ switch (act->mangle.offset) {
-+ case offsetof(struct iphdr, saddr):
-+ dest = &data->v4.src_addr;
-+ break;
-+ case offsetof(struct iphdr, daddr):
-+ dest = &data->v4.dst_addr;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ memcpy(dest, &act->mangle.val, sizeof(u32));
-+
-+ return 0;
-+}
-+
-+static int
-+mtk_flow_get_dsa_port(struct net_device **dev)
-+{
-+#if IS_ENABLED(CONFIG_NET_DSA)
-+ struct dsa_port *dp;
-+
-+ dp = dsa_port_from_netdev(*dev);
-+ if (IS_ERR(dp))
-+ return -ENODEV;
-+
-+ if (!dp->cpu_dp)
-+ return -ENODEV;
-+
-+ if (!dp->cpu_dp->tag_ops)
-+ return -ENODEV;
-+
-+ if (dp->cpu_dp->tag_ops->proto != DSA_TAG_PROTO_MTK)
-+ return -ENODEV;
-+
-+ *dev = dp->cpu_dp->master;
-+
-+ return dp->index;
-+#else
-+ return -ENODEV;
-+#endif
-+}
-+
-+static int
-+mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
-+ struct net_device *dev)
-+{
-+ int pse_port, dsa_port;
-+
-+ dsa_port = mtk_flow_get_dsa_port(&dev);
-+ if (dsa_port >= 0)
-+ mtk_foe_entry_set_dsa(foe, dsa_port);
-+
-+ if (dev == eth->netdev[0])
-+ pse_port = 1;
-+ else if (dev == eth->netdev[1])
-+ pse_port = 2;
-+ else
-+ return -EOPNOTSUPP;
-+
-+ mtk_foe_entry_set_pse_port(foe, pse_port);
-+
-+ return 0;
-+}
-+
-+static int
-+mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
-+{
-+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
-+ struct flow_action_entry *act;
-+ struct mtk_flow_data data = {};
-+ struct mtk_foe_entry foe;
-+ struct net_device *odev = NULL;
-+ struct mtk_flow_entry *entry;
-+ int offload_type = 0;
-+ u16 addr_type = 0;
-+ u32 timestamp;
-+ u8 l4proto = 0;
-+ int err = 0;
-+ int hash;
-+ int i;
-+
-+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META)) {
-+ struct flow_match_meta match;
-+
-+ flow_rule_match_meta(rule, &match);
-+ } else {
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
-+ struct flow_match_control match;
-+
-+ flow_rule_match_control(rule, &match);
-+ addr_type = match.key->addr_type;
-+ } else {
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
-+ struct flow_match_basic match;
-+
-+ flow_rule_match_basic(rule, &match);
-+ l4proto = match.key->ip_proto;
-+ } else {
-+ return -EOPNOTSUPP;
-+ }
-+
-+ flow_action_for_each(i, act, &rule->action) {
-+ switch (act->id) {
-+ case FLOW_ACTION_MANGLE:
-+ if (act->mangle.htype == FLOW_ACT_MANGLE_HDR_TYPE_ETH)
-+ mtk_flow_offload_mangle_eth(act, &data.eth);
-+ break;
-+ case FLOW_ACTION_REDIRECT:
-+ odev = act->dev;
-+ break;
-+ case FLOW_ACTION_CSUM:
-+ break;
-+ case FLOW_ACTION_VLAN_PUSH:
-+ if (data.vlan.num == 1 ||
-+ act->vlan.proto != htons(ETH_P_8021Q))
-+ return -EOPNOTSUPP;
-+
-+ data.vlan.id = act->vlan.vid;
-+ data.vlan.proto = act->vlan.proto;
-+ data.vlan.num++;
-+ break;
-+ case FLOW_ACTION_PPPOE_PUSH:
-+ if (data.pppoe.num == 1)
-+ return -EOPNOTSUPP;
-+
-+ data.pppoe.sid = act->pppoe.sid;
-+ data.pppoe.num++;
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+ }
-+
-+ switch (addr_type) {
-+ case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
-+ offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT;
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (!is_valid_ether_addr(data.eth.h_source) ||
-+ !is_valid_ether_addr(data.eth.h_dest))
-+ return -EINVAL;
-+
-+ err = mtk_foe_entry_prepare(&foe, offload_type, l4proto, 0,
-+ data.eth.h_source,
-+ data.eth.h_dest);
-+ if (err)
-+ return err;
-+
-+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
-+ struct flow_match_ports ports;
-+
-+ flow_rule_match_ports(rule, &ports);
-+ data.src_port = ports.key->src;
-+ data.dst_port = ports.key->dst;
-+ } else {
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
-+ struct flow_match_ipv4_addrs addrs;
-+
-+ flow_rule_match_ipv4_addrs(rule, &addrs);
-+
-+ data.v4.src_addr = addrs.key->src;
-+ data.v4.dst_addr = addrs.key->dst;
-+
-+ mtk_flow_set_ipv4_addr(&foe, &data, false);
-+ }
-+
-+ flow_action_for_each(i, act, &rule->action) {
-+ if (act->id != FLOW_ACTION_MANGLE)
-+ continue;
-+
-+ switch (act->mangle.htype) {
-+ case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
-+ case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
-+ err = mtk_flow_mangle_ports(act, &data);
-+ break;
-+ case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
-+ err = mtk_flow_mangle_ipv4(act, &data);
-+ break;
-+ case FLOW_ACT_MANGLE_HDR_TYPE_ETH:
-+ /* handled earlier */
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (err)
-+ return err;
-+ }
-+
-+ if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
-+ err = mtk_flow_set_ipv4_addr(&foe, &data, true);
-+ if (err)
-+ return err;
-+ }
-+
-+ if (data.vlan.num == 1) {
-+ if (data.vlan.proto != htons(ETH_P_8021Q))
-+ return -EOPNOTSUPP;
-+
-+ mtk_foe_entry_set_vlan(&foe, data.vlan.id);
-+ }
-+ if (data.pppoe.num == 1)
-+ mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
-+
-+ err = mtk_flow_set_output_device(eth, &foe, odev);
-+ if (err)
-+ return err;
-+
-+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-+ if (!entry)
-+ return -ENOMEM;
-+
-+ entry->cookie = f->cookie;
-+ timestamp = mtk_eth_timestamp(eth);
-+ hash = mtk_foe_entry_commit(&eth->ppe, &foe, timestamp);
-+ if (hash < 0) {
-+ err = hash;
-+ goto free;
-+ }
-+
-+ entry->hash = hash;
-+ err = rhashtable_insert_fast(&eth->flow_table, &entry->node,
-+ mtk_flow_ht_params);
-+ if (err < 0)
-+ goto clear_flow;
-+
-+ return 0;
-+clear_flow:
-+ mtk_foe_entry_clear(&eth->ppe, hash);
-+free:
-+ kfree(entry);
-+ return err;
-+}
-+
-+static int
-+mtk_flow_offload_destroy(struct mtk_eth *eth, struct flow_cls_offload *f)
-+{
-+ struct mtk_flow_entry *entry;
-+
-+ entry = rhashtable_lookup(&eth->flow_table, &f->cookie,
-+ mtk_flow_ht_params);
-+ if (!entry)
-+ return -ENOENT;
-+
-+ mtk_foe_entry_clear(&eth->ppe, entry->hash);
-+ rhashtable_remove_fast(&eth->flow_table, &entry->node,
-+ mtk_flow_ht_params);
-+ kfree(entry);
-+
-+ return 0;
-+}
-+
-+static int
-+mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
-+{
-+ struct mtk_flow_entry *entry;
-+ int timestamp;
-+ u32 idle;
-+
-+ entry = rhashtable_lookup(&eth->flow_table, &f->cookie,
-+ mtk_flow_ht_params);
-+ if (!entry)
-+ return -ENOENT;
-+
-+ timestamp = mtk_foe_entry_timestamp(&eth->ppe, entry->hash);
-+ if (timestamp < 0)
-+ return -ETIMEDOUT;
-+
-+ idle = mtk_eth_timestamp(eth) - timestamp;
-+ f->stats.lastused = jiffies - idle * HZ;
-+
-+ return 0;
-+}
-+
-+static int
-+mtk_eth_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
-+{
-+ struct flow_cls_offload *cls = type_data;
-+ struct net_device *dev = cb_priv;
-+ struct mtk_mac *mac = netdev_priv(dev);
-+ struct mtk_eth *eth = mac->hw;
-+
-+ if (!tc_can_offload(dev))
-+ return -EOPNOTSUPP;
-+
-+ if (type != TC_SETUP_CLSFLOWER)
-+ return -EOPNOTSUPP;
-+
-+ switch (cls->command) {
-+ case FLOW_CLS_REPLACE:
-+ return mtk_flow_offload_replace(eth, cls);
-+ case FLOW_CLS_DESTROY:
-+ return mtk_flow_offload_destroy(eth, cls);
-+ case FLOW_CLS_STATS:
-+ return mtk_flow_offload_stats(eth, cls);
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
-+{
-+ struct mtk_mac *mac = netdev_priv(dev);
-+ struct mtk_eth *eth = mac->hw;
-+ static LIST_HEAD(block_cb_list);
-+ struct flow_block_cb *block_cb;
-+ flow_setup_cb_t *cb;
-+
-+ if (!eth->ppe.foe_table)
-+ return -EOPNOTSUPP;
-+
-+ if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
-+ return -EOPNOTSUPP;
-+
-+ cb = mtk_eth_setup_tc_block_cb;
-+ f->driver_block_list = &block_cb_list;
-+
-+ switch (f->command) {
-+ case FLOW_BLOCK_BIND:
-+ block_cb = flow_block_cb_lookup(f->block, cb, dev);
-+ if (block_cb) {
-+ flow_block_cb_incref(block_cb);
-+ return 0;
-+ }
-+ block_cb = flow_block_cb_alloc(cb, dev, dev, NULL);
-+ if (IS_ERR(block_cb))
-+ return PTR_ERR(block_cb);
-+
-+ flow_block_cb_add(block_cb, f);
-+ list_add_tail(&block_cb->driver_list, &block_cb_list);
-+ return 0;
-+ case FLOW_BLOCK_UNBIND:
-+ block_cb = flow_block_cb_lookup(f->block, cb, dev);
-+ if (!block_cb)
-+ return -ENOENT;
-+
-+ if (flow_block_cb_decref(block_cb)) {
-+ flow_block_cb_remove(block_cb, f);
-+ list_del(&block_cb->driver_list);
-+ }
-+ return 0;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
-+ void *type_data)
-+{
-+ if (type == TC_SETUP_FT)
-+ return mtk_eth_setup_tc_block(dev, type_data);
-+
-+ return -EOPNOTSUPP;
-+}
-+
-+int mtk_eth_offload_init(struct mtk_eth *eth)
-+{
-+ if (!eth->ppe.foe_table)
-+ return 0;
-+
-+ return rhashtable_init(&eth->flow_table, &mtk_flow_ht_params);
-+}