b1b166a194a1ebd09aed8cd6fd841742675e1588
[oweals/openwrt.git] / target / linux / generic / pending-5.4 / 680-NET-skip-GRO-for-foreign-MAC-addresses.patch
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 @@ -1922,6 +1922,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 @@ -822,6 +822,7 @@ struct sk_buff {
26  #ifdef CONFIG_TLS_DEVICE
27         __u8                    decrypted:1;
28  #endif
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 @@ -5477,6 +5477,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 @@ -7269,6 +7272,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 @@ -7319,6 +7364,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 @@ -7412,6 +7458,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 @@ -8142,6 +8189,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         /*