b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From: Felix Fietkau <nbd@nbd.name> |
| 2 | Subject: net: replace GRO optimization patch with a new one that supports VLANs/bridges with different MAC addresses |
| 3 | |
| 4 | Signed-off-by: Felix Fietkau <nbd@nbd.name> |
| 5 | --- |
| 6 | include/linux/netdevice.h | 2 ++ |
| 7 | include/linux/skbuff.h | 3 ++- |
| 8 | net/core/dev.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ |
| 9 | net/ethernet/eth.c | 18 +++++++++++++++++- |
| 10 | 4 files changed, 69 insertions(+), 2 deletions(-) |
| 11 | |
| 12 | --- a/include/linux/netdevice.h |
| 13 | +++ b/include/linux/netdevice.h |
| 14 | @@ -1936,6 +1936,8 @@ struct net_device { |
| 15 | struct netdev_hw_addr_list mc; |
| 16 | struct netdev_hw_addr_list dev_addrs; |
| 17 | |
| 18 | + unsigned char local_addr_mask[MAX_ADDR_LEN]; |
| 19 | + |
| 20 | #ifdef CONFIG_SYSFS |
| 21 | struct kset *queues_kset; |
| 22 | #endif |
| 23 | --- a/include/linux/skbuff.h |
| 24 | +++ b/include/linux/skbuff.h |
| 25 | @@ -826,6 +826,7 @@ struct sk_buff { |
| 26 | __u8 decrypted:1; |
| 27 | #endif |
| 28 | __u8 scm_io_uring:1; |
| 29 | + __u8 gro_skip:1; |
| 30 | |
| 31 | #ifdef CONFIG_NET_SCHED |
| 32 | __u16 tc_index; /* traffic control index */ |
| 33 | --- a/net/core/dev.c |
| 34 | +++ b/net/core/dev.c |
| 35 | @@ -5544,6 +5544,9 @@ static enum gro_result dev_gro_receive(s |
| 36 | int same_flow; |
| 37 | int grow; |
| 38 | |
| 39 | + if (skb->gro_skip) |
| 40 | + goto normal; |
| 41 | + |
| 42 | if (netif_elide_gro(skb->dev)) |
| 43 | goto normal; |
| 44 | |
| 45 | @@ -7487,6 +7490,48 @@ static void __netdev_adjacent_dev_unlink |
| 46 | &upper_dev->adj_list.lower); |
| 47 | } |
| 48 | |
| 49 | +static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr, |
| 50 | + struct net_device *dev) |
| 51 | +{ |
| 52 | + int i; |
| 53 | + |
| 54 | + for (i = 0; i < dev->addr_len; i++) |
| 55 | + mask[i] |= addr[i] ^ dev->dev_addr[i]; |
| 56 | +} |
| 57 | + |
| 58 | +static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev, |
| 59 | + struct net_device *lower) |
| 60 | +{ |
| 61 | + struct net_device *cur; |
| 62 | + struct list_head *iter; |
| 63 | + |
| 64 | + netdev_for_each_upper_dev_rcu(dev, cur, iter) { |
| 65 | + __netdev_addr_mask(mask, cur->dev_addr, lower); |
| 66 | + __netdev_upper_mask(mask, cur, lower); |
| 67 | + } |
| 68 | +} |
| 69 | + |
| 70 | +static void __netdev_update_addr_mask(struct net_device *dev) |
| 71 | +{ |
| 72 | + unsigned char mask[MAX_ADDR_LEN]; |
| 73 | + struct net_device *cur; |
| 74 | + struct list_head *iter; |
| 75 | + |
| 76 | + memset(mask, 0, sizeof(mask)); |
| 77 | + __netdev_upper_mask(mask, dev, dev); |
| 78 | + memcpy(dev->local_addr_mask, mask, dev->addr_len); |
| 79 | + |
| 80 | + netdev_for_each_lower_dev(dev, cur, iter) |
| 81 | + __netdev_update_addr_mask(cur); |
| 82 | +} |
| 83 | + |
| 84 | +static void netdev_update_addr_mask(struct net_device *dev) |
| 85 | +{ |
| 86 | + rcu_read_lock(); |
| 87 | + __netdev_update_addr_mask(dev); |
| 88 | + rcu_read_unlock(); |
| 89 | +} |
| 90 | + |
| 91 | static int __netdev_upper_dev_link(struct net_device *dev, |
| 92 | struct net_device *upper_dev, bool master, |
| 93 | void *upper_priv, void *upper_info, |
| 94 | @@ -7537,6 +7582,7 @@ static int __netdev_upper_dev_link(struc |
| 95 | if (ret) |
| 96 | return ret; |
| 97 | |
| 98 | + netdev_update_addr_mask(dev); |
| 99 | ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, |
| 100 | &changeupper_info.info); |
| 101 | ret = notifier_to_errno(ret); |
| 102 | @@ -7630,6 +7676,7 @@ void netdev_upper_dev_unlink(struct net_ |
| 103 | |
| 104 | __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); |
| 105 | |
| 106 | + netdev_update_addr_mask(dev); |
| 107 | call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, |
| 108 | &changeupper_info.info); |
| 109 | |
| 110 | @@ -8360,6 +8407,7 @@ int dev_set_mac_address(struct net_devic |
| 111 | if (err) |
| 112 | return err; |
| 113 | dev->addr_assign_type = NET_ADDR_SET; |
| 114 | + netdev_update_addr_mask(dev); |
| 115 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); |
| 116 | add_device_randomness(dev->dev_addr, dev->addr_len); |
| 117 | return 0; |
| 118 | --- a/net/ethernet/eth.c |
| 119 | +++ b/net/ethernet/eth.c |
| 120 | @@ -143,6 +143,18 @@ u32 eth_get_headlen(const struct net_dev |
| 121 | } |
| 122 | EXPORT_SYMBOL(eth_get_headlen); |
| 123 | |
| 124 | +static inline bool |
| 125 | +eth_check_local_mask(const void *addr1, const void *addr2, const void *mask) |
| 126 | +{ |
| 127 | + const u16 *a1 = addr1; |
| 128 | + const u16 *a2 = addr2; |
| 129 | + const u16 *m = mask; |
| 130 | + |
| 131 | + return (((a1[0] ^ a2[0]) & ~m[0]) | |
| 132 | + ((a1[1] ^ a2[1]) & ~m[1]) | |
| 133 | + ((a1[2] ^ a2[2]) & ~m[2])); |
| 134 | +} |
| 135 | + |
| 136 | /** |
| 137 | * eth_type_trans - determine the packet's protocol ID. |
| 138 | * @skb: received socket data |
| 139 | @@ -174,6 +186,10 @@ __be16 eth_type_trans(struct sk_buff *sk |
| 140 | } else { |
| 141 | skb->pkt_type = PACKET_OTHERHOST; |
| 142 | } |
| 143 | + |
| 144 | + if (eth_check_local_mask(eth->h_dest, dev->dev_addr, |
| 145 | + dev->local_addr_mask)) |
| 146 | + skb->gro_skip = 1; |
| 147 | } |
| 148 | |
| 149 | /* |