diff options
Diffstat (limited to 'target/linux/generic/pending-4.19/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch')
-rw-r--r-- | target/linux/generic/pending-4.19/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch | 306 |
1 files changed, 0 insertions, 306 deletions
diff --git a/target/linux/generic/pending-4.19/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch b/target/linux/generic/pending-4.19/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch deleted file mode 100644 index 30819d47af..0000000000 --- a/target/linux/generic/pending-4.19/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch +++ /dev/null @@ -1,306 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Thu, 15 Mar 2018 20:46:31 +0100 -Subject: [PATCH] netfilter: nf_flow_table: support hw offload through - virtual interfaces - -There are hardware offload devices that support offloading VLANs and -PPPoE devices. Additionally, it is useful to be able to offload packets -routed through bridge interfaces as well. -Add support for finding the path to the offload device through these -virtual interfaces, while collecting useful parameters for the offload -device, like VLAN ID/protocol, PPPoE session and Ethernet MAC address. - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- - ---- a/include/linux/netdevice.h -+++ b/include/linux/netdevice.h -@@ -919,6 +919,7 @@ struct dev_ifalias { - }; - - struct flow_offload; -+struct flow_offload_hw_path; - - enum flow_offload_type { - FLOW_OFFLOAD_ADD = 0, -@@ -1157,8 +1158,15 @@ enum flow_offload_type { - * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh, - * u16 flags); - * -+ * int (*ndo_flow_offload_check)(struct flow_offload_hw_path *path); -+ * For virtual devices like bridges, vlan, and pppoe, fill in the -+ * underlying network device that can be used for offloading connections. -+ * Return an error if offloading is not supported. -+ * - * int (*ndo_flow_offload)(enum flow_offload_type type, -- * struct flow_offload *flow); -+ * struct flow_offload *flow, -+ * struct flow_offload_hw_path *src, -+ * struct flow_offload_hw_path *dest); - * Adds/deletes flow entry to/from net device flowtable. - * - * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier); -@@ -1388,8 +1396,11 @@ struct net_device_ops { - int (*ndo_bridge_dellink)(struct net_device *dev, - struct nlmsghdr *nlh, - u16 flags); -+ int (*ndo_flow_offload_check)(struct flow_offload_hw_path *path); - int (*ndo_flow_offload)(enum flow_offload_type type, -- struct flow_offload *flow); -+ struct flow_offload *flow, -+ struct flow_offload_hw_path *src, -+ struct flow_offload_hw_path *dest); - int (*ndo_change_carrier)(struct net_device *dev, - bool new_carrier); - int (*ndo_get_phys_port_id)(struct net_device *dev, ---- a/include/net/netfilter/nf_flow_table.h -+++ b/include/net/netfilter/nf_flow_table.h -@@ -86,6 +86,21 @@ struct flow_offload { - }; - }; - -+#define FLOW_OFFLOAD_PATH_ETHERNET BIT(0) -+#define FLOW_OFFLOAD_PATH_VLAN BIT(1) -+#define FLOW_OFFLOAD_PATH_PPPOE BIT(2) -+ -+struct flow_offload_hw_path { -+ struct net_device *dev; -+ u32 flags; -+ -+ u8 eth_src[ETH_ALEN]; -+ u8 eth_dest[ETH_ALEN]; -+ u16 vlan_proto; -+ u16 vlan_id; -+ u16 pppoe_sid; -+}; -+ - #define NF_FLOW_TIMEOUT (30 * HZ) - - struct nf_flow_route { ---- a/net/netfilter/nf_flow_table_hw.c -+++ b/net/netfilter/nf_flow_table_hw.c -@@ -19,48 +19,77 @@ struct flow_offload_hw { - enum flow_offload_type type; - struct flow_offload *flow; - struct nf_conn *ct; -- possible_net_t flow_hw_net; -+ -+ struct flow_offload_hw_path src; -+ struct flow_offload_hw_path dest; - }; - --static int do_flow_offload_hw(struct net *net, struct flow_offload *flow, -- int type) -+static void flow_offload_check_ethernet(struct flow_offload_tuple *tuple, -+ struct dst_entry *dst, -+ struct flow_offload_hw_path *path) - { -- struct net_device *indev; -- int ret, ifindex; -+ struct net_device *dev = path->dev; -+ struct neighbour *n; - -- ifindex = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx; -- indev = dev_get_by_index(net, ifindex); -- if (WARN_ON(!indev)) -- return 0; -- -- mutex_lock(&nf_flow_offload_hw_mutex); -- ret = indev->netdev_ops->ndo_flow_offload(type, flow); -- mutex_unlock(&nf_flow_offload_hw_mutex); -+ if (dev->type != ARPHRD_ETHER) -+ return; - -- dev_put(indev); -+ memcpy(path->eth_src, path->dev->dev_addr, ETH_ALEN); -+ n = dst_neigh_lookup(dst, &tuple->src_v4); -+ if (!n) -+ return; - -- return ret; -+ memcpy(path->eth_dest, n->ha, ETH_ALEN); -+ path->flags |= FLOW_OFFLOAD_PATH_ETHERNET; -+ neigh_release(n); - } - --static void flow_offload_hw_work_add(struct flow_offload_hw *offload) -+static int flow_offload_check_path(struct net *net, -+ struct flow_offload_tuple *tuple, -+ struct dst_entry *dst, -+ struct flow_offload_hw_path *path) - { -- struct net *net; -- int ret; -+ struct net_device *dev; - -- if (nf_ct_is_dying(offload->ct)) -- return; -+ dev = dev_get_by_index_rcu(net, tuple->iifidx); -+ if (!dev) -+ return -ENOENT; -+ -+ path->dev = dev; -+ flow_offload_check_ethernet(tuple, dst, path); - -- net = read_pnet(&offload->flow_hw_net); -- ret = do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_ADD); -- if (ret >= 0) -- offload->flow->flags |= FLOW_OFFLOAD_HW; -+ if (dev->netdev_ops->ndo_flow_offload_check) -+ return dev->netdev_ops->ndo_flow_offload_check(path); -+ -+ return 0; - } - --static void flow_offload_hw_work_del(struct flow_offload_hw *offload) -+static int do_flow_offload_hw(struct flow_offload_hw *offload) - { -- struct net *net = read_pnet(&offload->flow_hw_net); -+ struct net_device *src_dev = offload->src.dev; -+ struct net_device *dest_dev = offload->dest.dev; -+ int ret; -+ -+ ret = src_dev->netdev_ops->ndo_flow_offload(offload->type, -+ offload->flow, -+ &offload->src, -+ &offload->dest); -+ -+ /* restore devices in case the driver mangled them */ -+ offload->src.dev = src_dev; -+ offload->dest.dev = dest_dev; - -- do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_DEL); -+ return ret; -+} -+ -+static void flow_offload_hw_free(struct flow_offload_hw *offload) -+{ -+ dev_put(offload->src.dev); -+ dev_put(offload->dest.dev); -+ if (offload->ct) -+ nf_conntrack_put(&offload->ct->ct_general); -+ list_del(&offload->list); -+ kfree(offload); - } - - static void flow_offload_hw_work(struct work_struct *work) -@@ -73,18 +102,22 @@ static void flow_offload_hw_work(struct - spin_unlock_bh(&flow_offload_hw_pending_list_lock); - - list_for_each_entry_safe(offload, next, &hw_offload_pending, list) { -+ mutex_lock(&nf_flow_offload_hw_mutex); - switch (offload->type) { - case FLOW_OFFLOAD_ADD: -- flow_offload_hw_work_add(offload); -+ if (nf_ct_is_dying(offload->ct)) -+ break; -+ -+ if (do_flow_offload_hw(offload) >= 0) -+ offload->flow->flags |= FLOW_OFFLOAD_HW; - break; - case FLOW_OFFLOAD_DEL: -- flow_offload_hw_work_del(offload); -+ do_flow_offload_hw(offload); - break; - } -- if (offload->ct) -- nf_conntrack_put(&offload->ct->ct_general); -- list_del(&offload->list); -- kfree(offload); -+ mutex_unlock(&nf_flow_offload_hw_mutex); -+ -+ flow_offload_hw_free(offload); - } - } - -@@ -97,20 +130,56 @@ static void flow_offload_queue_work(stru - schedule_work(&nf_flow_offload_hw_work); - } - -+static struct flow_offload_hw * -+flow_offload_hw_prepare(struct net *net, struct flow_offload *flow) -+{ -+ struct flow_offload_hw_path src = {}; -+ struct flow_offload_hw_path dest = {}; -+ struct flow_offload_tuple *tuple_s, *tuple_d; -+ struct flow_offload_hw *offload = NULL; -+ -+ rcu_read_lock_bh(); -+ -+ tuple_s = &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple; -+ tuple_d = &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple; -+ -+ if (flow_offload_check_path(net, tuple_s, tuple_d->dst_cache, &src)) -+ goto out; -+ -+ if (flow_offload_check_path(net, tuple_d, tuple_s->dst_cache, &dest)) -+ goto out; -+ -+ if (!src.dev->netdev_ops->ndo_flow_offload) -+ goto out; -+ -+ offload = kzalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC); -+ if (!offload) -+ goto out; -+ -+ dev_hold(src.dev); -+ dev_hold(dest.dev); -+ offload->src = src; -+ offload->dest = dest; -+ offload->flow = flow; -+ -+out: -+ rcu_read_unlock_bh(); -+ -+ return offload; -+} -+ - static void flow_offload_hw_add(struct net *net, struct flow_offload *flow, - struct nf_conn *ct) - { - struct flow_offload_hw *offload; - -- offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC); -+ offload = flow_offload_hw_prepare(net, flow); - if (!offload) - return; - - nf_conntrack_get(&ct->ct_general); - offload->type = FLOW_OFFLOAD_ADD; - offload->ct = ct; -- offload->flow = flow; -- write_pnet(&offload->flow_hw_net, net); - - flow_offload_queue_work(offload); - } -@@ -119,14 +188,11 @@ static void flow_offload_hw_del(struct n - { - struct flow_offload_hw *offload; - -- offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC); -+ offload = flow_offload_hw_prepare(net, flow); - if (!offload) - return; - - offload->type = FLOW_OFFLOAD_DEL; -- offload->ct = NULL; -- offload->flow = flow; -- write_pnet(&offload->flow_hw_net, net); - - flow_offload_queue_work(offload); - } -@@ -153,12 +219,8 @@ static void __exit nf_flow_table_hw_modu - nf_flow_table_hw_unregister(&flow_offload_hw); - cancel_work_sync(&nf_flow_offload_hw_work); - -- list_for_each_entry_safe(offload, next, &hw_offload_pending, list) { -- if (offload->ct) -- nf_conntrack_put(&offload->ct->ct_general); -- list_del(&offload->list); -- kfree(offload); -- } -+ list_for_each_entry_safe(offload, next, &hw_offload_pending, list) -+ flow_offload_hw_free(offload); - } - - module_init(nf_flow_table_hw_module_init); |