680-NET-skip-GRO-for-foreign-MAC-addresses.patch 3.96 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
From: Felix Fietkau <nbd@nbd.name>
Subject: net: replace GRO optimization patch with a new one that supports VLANs/bridges with different MAC addresses

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 include/linux/netdevice.h |  2 ++
 include/linux/skbuff.h    |  3 ++-
 net/core/dev.c            | 48 +++++++++++++++++++++++++++++++++++++++++++++++
 net/ethernet/eth.c        | 18 +++++++++++++++++-
 4 files changed, 69 insertions(+), 2 deletions(-)

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