kernel: remove support for kernel 4.14
[openwrt/staging/dedeckeh.git] / target / linux / generic / pending-4.14 / 641-netfilter-nf_flow_table-support-hw-offload-through-v.patch
diff --git a/target/linux/generic/pending-4.14/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch b/target/linux/generic/pending-4.14/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch
deleted file mode 100644 (file)
index e1b13a1..0000000
+++ /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
-@@ -827,6 +827,7 @@ struct xfrmdev_ops {
- #endif
- struct flow_offload;
-+struct flow_offload_hw_path;
- enum flow_offload_type {
-       FLOW_OFFLOAD_ADD        = 0,
-@@ -1064,8 +1065,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);
-@@ -1292,8 +1300,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);