From b10d6044599d8c1fa7fbb2374bcbf30118d39db1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 24 Oct 2020 21:14:16 +0200 Subject: kernel: add linux 5.10 support Signed-off-by: Felix Fietkau --- ...-forwarding-path-from-virtual-netdevice-a.patch | 170 +++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 target/linux/generic/pending-5.10/640-02-net-resolve-forwarding-path-from-virtual-netdevice-a.patch (limited to 'target/linux/generic/pending-5.10/640-02-net-resolve-forwarding-path-from-virtual-netdevice-a.patch') 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 new file mode 100644 index 0000000000..953446baab --- /dev/null +++ b/target/linux/generic/pending-5.10/640-02-net-resolve-forwarding-path-from-virtual-netdevice-a.patch @@ -0,0 +1,170 @@ +From: Pablo Neira Ayuso +Date: Sun, 10 Jan 2021 15:53:58 +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 +--- + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -833,6 +833,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, +@@ -1279,6 +1300,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); +@@ -1487,6 +1510,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); + }; + + /** +@@ -2798,6 +2823,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 +@@ -846,6 +846,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 -- cgit v1.2.3