Blame view

net/8021q/vlan_core.c 8.69 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
7750f403c   Patrick McHardy   vlan: uninline __...
2
3
4
  #include <linux/skbuff.h>
  #include <linux/netdevice.h>
  #include <linux/if_vlan.h>
4ead44316   Herbert Xu   netpoll: Add drop...
5
  #include <linux/netpoll.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
6
  #include <linux/export.h>
7750f403c   Patrick McHardy   vlan: uninline __...
7
  #include "vlan.h"
48cc32d38   Florian Zumbiehl   vlan: don't deliv...
8
  bool vlan_do_receive(struct sk_buff **skbp)
7750f403c   Patrick McHardy   vlan: uninline __...
9
  {
3701e5138   Jesse Gross   vlan: Centralize ...
10
  	struct sk_buff *skb = *skbp;
86a9bad3a   Patrick McHardy   net: vlan: add pr...
11
  	__be16 vlan_proto = skb->vlan_proto;
df8a39def   Jiri Pirko   net: rename vlan_...
12
  	u16 vlan_id = skb_vlan_tag_get_id(skb);
ad1afb003   Pedro Garcia   vlan_dev: VLAN 0 ...
13
  	struct net_device *vlan_dev;
4af429d29   Eric Dumazet   vlan: lockless tr...
14
  	struct vlan_pcpu_stats *rx_stats;
7750f403c   Patrick McHardy   vlan: uninline __...
15

86a9bad3a   Patrick McHardy   net: vlan: add pr...
16
  	vlan_dev = vlan_find_dev(skb->dev, vlan_proto, vlan_id);
48cc32d38   Florian Zumbiehl   vlan: don't deliv...
17
  	if (!vlan_dev)
3701e5138   Jesse Gross   vlan: Centralize ...
18
  		return false;
9b22ea560   Patrick McHardy   net: fix packet s...
19

3701e5138   Jesse Gross   vlan: Centralize ...
20
21
22
  	skb = *skbp = skb_share_check(skb, GFP_ATOMIC);
  	if (unlikely(!skb))
  		return false;
e769fcec6   Vishakha Narvekar   net: 8021q: skip ...
23
24
25
26
27
28
  
  	if (unlikely(!(vlan_dev->flags & IFF_UP))) {
  		kfree_skb(skb);
  		*skbp = NULL;
  		return false;
  	}
e1c096e25   Herbert Xu   vlan: Add GRO int...
29

3701e5138   Jesse Gross   vlan: Centralize ...
30
  	skb->dev = vlan_dev;
375f67df2   dingtianhong   vlan: slight opti...
31
  	if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) {
0b5c9db1b   Jiri Pirko   vlan: Fix the ing...
32
33
34
  		/* Our lower layer thinks this is not local, let's make sure.
  		 * This allows the VLAN to have a different MAC than the
  		 * underlying device, and still route correctly. */
be14cc98e   dingtianhong   vlan: use use eth...
35
  		if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, vlan_dev->dev_addr))
0b5c9db1b   Jiri Pirko   vlan: Fix the ing...
36
37
  			skb->pkt_type = PACKET_HOST;
  	}
28f9ee22b   Vlad Yasevich   vlan: Do not put ...
38
39
40
  	if (!(vlan_dev_priv(vlan_dev)->flags & VLAN_FLAG_REORDER_HDR) &&
  	    !netif_is_macvlan_port(vlan_dev) &&
  	    !netif_is_bridge_port(vlan_dev)) {
0b5c9db1b   Jiri Pirko   vlan: Fix the ing...
41
42
43
44
45
46
47
48
  		unsigned int offset = skb->data - skb_mac_header(skb);
  
  		/*
  		 * vlan_insert_tag expect skb->data pointing to mac header.
  		 * So change skb->data before calling it and change back to
  		 * original position later
  		 */
  		skb_push(skb, offset);
99ba9a972   Toshiaki Makita   vlan: Fix out of ...
49
50
  		skb = *skbp = vlan_insert_inner_tag(skb, skb->vlan_proto,
  						    skb->vlan_tci, skb->mac_len);
0b5c9db1b   Jiri Pirko   vlan: Fix the ing...
51
52
53
54
55
  		if (!skb)
  			return false;
  		skb_pull(skb, offset + VLAN_HLEN);
  		skb_reset_mac_len(skb);
  	}
3701e5138   Jesse Gross   vlan: Centralize ...
56
  	skb->priority = vlan_get_ingress_priority(vlan_dev, skb->vlan_tci);
bc1d0411b   Patrick McHardy   vlan: deliver pac...
57
  	skb->vlan_tci = 0;
7750f403c   Patrick McHardy   vlan: uninline __...
58

7da82c06d   Jiri Pirko   vlan: rename vlan...
59
  	rx_stats = this_cpu_ptr(vlan_dev_priv(vlan_dev)->vlan_pcpu_stats);
9793241fe   Eric Dumazet   vlan: Precise RX ...
60

9618e2ffd   Eric Dumazet   vlan: 64 bit rx c...
61
  	u64_stats_update_begin(&rx_stats->syncp);
9793241fe   Eric Dumazet   vlan: Precise RX ...
62
63
  	rx_stats->rx_packets++;
  	rx_stats->rx_bytes += skb->len;
0b5c9db1b   Jiri Pirko   vlan: Fix the ing...
64
  	if (skb->pkt_type == PACKET_MULTICAST)
9618e2ffd   Eric Dumazet   vlan: 64 bit rx c...
65
  		rx_stats->rx_multicast++;
9618e2ffd   Eric Dumazet   vlan: 64 bit rx c...
66
  	u64_stats_update_end(&rx_stats->syncp);
3701e5138   Jesse Gross   vlan: Centralize ...
67
68
  
  	return true;
7750f403c   Patrick McHardy   vlan: uninline __...
69
  }
22d1ba74b   Patrick McHardy   vlan: move struct...
70

1cdfd72f7   Jiri Pirko   vlan: remove usag...
71
  /* Must be invoked with rcu_read_lock. */
f06c7f9f9   dingtianhong   vlan: rename __vl...
72
  struct net_device *__vlan_find_dev_deep_rcu(struct net_device *dev,
1fd9b1fc3   Patrick McHardy   net: vlan: prepar...
73
  					__be16 vlan_proto, u16 vlan_id)
cec9c1336   Jiri Pirko   vlan: introduce _...
74
  {
1cdfd72f7   Jiri Pirko   vlan: remove usag...
75
  	struct vlan_info *vlan_info = rcu_dereference(dev->vlan_info);
cec9c1336   Jiri Pirko   vlan: introduce _...
76

5b9ea6e02   Jiri Pirko   vlan: introduce v...
77
  	if (vlan_info) {
1fd9b1fc3   Patrick McHardy   net: vlan: prepar...
78
79
  		return vlan_group_get_device(&vlan_info->grp,
  					     vlan_proto, vlan_id);
cec9c1336   Jiri Pirko   vlan: introduce _...
80
81
  	} else {
  		/*
1cdfd72f7   Jiri Pirko   vlan: remove usag...
82
83
84
  		 * Lower devices of master uppers (bonding, team) do not have
  		 * grp assigned to themselves. Grp is assigned to upper device
  		 * instead.
cec9c1336   Jiri Pirko   vlan: introduce _...
85
  		 */
1cdfd72f7   Jiri Pirko   vlan: remove usag...
86
87
88
89
  		struct net_device *upper_dev;
  
  		upper_dev = netdev_master_upper_dev_get_rcu(dev);
  		if (upper_dev)
f06c7f9f9   dingtianhong   vlan: rename __vl...
90
  			return __vlan_find_dev_deep_rcu(upper_dev,
1fd9b1fc3   Patrick McHardy   net: vlan: prepar...
91
  						    vlan_proto, vlan_id);
cec9c1336   Jiri Pirko   vlan: introduce _...
92
93
94
95
  	}
  
  	return NULL;
  }
f06c7f9f9   dingtianhong   vlan: rename __vl...
96
  EXPORT_SYMBOL(__vlan_find_dev_deep_rcu);
cec9c1336   Jiri Pirko   vlan: introduce _...
97

22d1ba74b   Patrick McHardy   vlan: move struct...
98
99
  struct net_device *vlan_dev_real_dev(const struct net_device *dev)
  {
0369722f0   nikolay@redhat.com   vlan: make vlan_d...
100
101
102
103
104
105
  	struct net_device *ret = vlan_dev_priv(dev)->real_dev;
  
  	while (is_vlan_dev(ret))
  		ret = vlan_dev_priv(ret)->real_dev;
  
  	return ret;
22d1ba74b   Patrick McHardy   vlan: move struct...
106
  }
116cb4285   Ben Greear   vlan: Export symb...
107
  EXPORT_SYMBOL(vlan_dev_real_dev);
22d1ba74b   Patrick McHardy   vlan: move struct...
108
109
110
  
  u16 vlan_dev_vlan_id(const struct net_device *dev)
  {
7da82c06d   Jiri Pirko   vlan: rename vlan...
111
  	return vlan_dev_priv(dev)->vlan_id;
22d1ba74b   Patrick McHardy   vlan: move struct...
112
  }
116cb4285   Ben Greear   vlan: Export symb...
113
  EXPORT_SYMBOL(vlan_dev_vlan_id);
e1c096e25   Herbert Xu   vlan: Add GRO int...
114

71e415e44   dingtianhong   vlan: make a new ...
115
116
117
118
119
  __be16 vlan_dev_vlan_proto(const struct net_device *dev)
  {
  	return vlan_dev_priv(dev)->vlan_proto;
  }
  EXPORT_SYMBOL(vlan_dev_vlan_proto);
5b9ea6e02   Jiri Pirko   vlan: introduce v...
120
121
122
123
124
125
  /*
   * vlan info and vid list
   */
  
  static void vlan_group_free(struct vlan_group *grp)
  {
cf2c014ad   Patrick McHardy   net: vlan: fix me...
126
  	int i, j;
5b9ea6e02   Jiri Pirko   vlan: introduce v...
127

cf2c014ad   Patrick McHardy   net: vlan: fix me...
128
129
130
  	for (i = 0; i < VLAN_PROTO_NUM; i++)
  		for (j = 0; j < VLAN_GROUP_ARRAY_SPLIT_PARTS; j++)
  			kfree(grp->vlan_devices_arrays[i][j]);
5b9ea6e02   Jiri Pirko   vlan: introduce v...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  }
  
  static void vlan_info_free(struct vlan_info *vlan_info)
  {
  	vlan_group_free(&vlan_info->grp);
  	kfree(vlan_info);
  }
  
  static void vlan_info_rcu_free(struct rcu_head *rcu)
  {
  	vlan_info_free(container_of(rcu, struct vlan_info, rcu));
  }
  
  static struct vlan_info *vlan_info_alloc(struct net_device *dev)
  {
  	struct vlan_info *vlan_info;
  
  	vlan_info = kzalloc(sizeof(struct vlan_info), GFP_KERNEL);
  	if (!vlan_info)
  		return NULL;
  
  	vlan_info->real_dev = dev;
  	INIT_LIST_HEAD(&vlan_info->vid_list);
  	return vlan_info;
  }
  
  struct vlan_vid_info {
  	struct list_head list;
80d5c3689   Patrick McHardy   net: vlan: prepar...
159
160
  	__be16 proto;
  	u16 vid;
5b9ea6e02   Jiri Pirko   vlan: introduce v...
161
162
  	int refcount;
  };
8ad227ff8   Patrick McHardy   net: vlan: add 80...
163
164
165
166
167
168
169
170
171
172
173
  static bool vlan_hw_filter_capable(const struct net_device *dev,
  				     const struct vlan_vid_info *vid_info)
  {
  	if (vid_info->proto == htons(ETH_P_8021Q) &&
  	    dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
  		return true;
  	if (vid_info->proto == htons(ETH_P_8021AD) &&
  	    dev->features & NETIF_F_HW_VLAN_STAG_FILTER)
  		return true;
  	return false;
  }
5b9ea6e02   Jiri Pirko   vlan: introduce v...
174
  static struct vlan_vid_info *vlan_vid_info_get(struct vlan_info *vlan_info,
80d5c3689   Patrick McHardy   net: vlan: prepar...
175
  					       __be16 proto, u16 vid)
5b9ea6e02   Jiri Pirko   vlan: introduce v...
176
177
178
179
  {
  	struct vlan_vid_info *vid_info;
  
  	list_for_each_entry(vid_info, &vlan_info->vid_list, list) {
80d5c3689   Patrick McHardy   net: vlan: prepar...
180
  		if (vid_info->proto == proto && vid_info->vid == vid)
5b9ea6e02   Jiri Pirko   vlan: introduce v...
181
182
183
184
  			return vid_info;
  	}
  	return NULL;
  }
80d5c3689   Patrick McHardy   net: vlan: prepar...
185
  static struct vlan_vid_info *vlan_vid_info_alloc(__be16 proto, u16 vid)
5b9ea6e02   Jiri Pirko   vlan: introduce v...
186
187
188
189
190
191
  {
  	struct vlan_vid_info *vid_info;
  
  	vid_info = kzalloc(sizeof(struct vlan_vid_info), GFP_KERNEL);
  	if (!vid_info)
  		return NULL;
80d5c3689   Patrick McHardy   net: vlan: prepar...
192
  	vid_info->proto = proto;
5b9ea6e02   Jiri Pirko   vlan: introduce v...
193
194
195
196
  	vid_info->vid = vid;
  
  	return vid_info;
  }
80d5c3689   Patrick McHardy   net: vlan: prepar...
197
  static int __vlan_vid_add(struct vlan_info *vlan_info, __be16 proto, u16 vid,
5b9ea6e02   Jiri Pirko   vlan: introduce v...
198
  			  struct vlan_vid_info **pvid_info)
87002b03b   Jiri Pirko   net: introduce vl...
199
  {
5b9ea6e02   Jiri Pirko   vlan: introduce v...
200
  	struct net_device *dev = vlan_info->real_dev;
87002b03b   Jiri Pirko   net: introduce vl...
201
  	const struct net_device_ops *ops = dev->netdev_ops;
5b9ea6e02   Jiri Pirko   vlan: introduce v...
202
203
  	struct vlan_vid_info *vid_info;
  	int err;
80d5c3689   Patrick McHardy   net: vlan: prepar...
204
  	vid_info = vlan_vid_info_alloc(proto, vid);
5b9ea6e02   Jiri Pirko   vlan: introduce v...
205
206
  	if (!vid_info)
  		return -ENOMEM;
87002b03b   Jiri Pirko   net: introduce vl...
207

8ad227ff8   Patrick McHardy   net: vlan: add 80...
208
  	if (vlan_hw_filter_capable(dev, vid_info)) {
74f2d19ca   Padmanabh Ratnakar   vlan: Invoke driv...
209
210
211
212
  		if (netif_device_present(dev))
  			err = ops->ndo_vlan_rx_add_vid(dev, proto, vid);
  		else
  			err = -ENODEV;
5b9ea6e02   Jiri Pirko   vlan: introduce v...
213
214
215
216
  		if (err) {
  			kfree(vid_info);
  			return err;
  		}
87002b03b   Jiri Pirko   net: introduce vl...
217
  	}
5b9ea6e02   Jiri Pirko   vlan: introduce v...
218
219
220
  	list_add(&vid_info->list, &vlan_info->vid_list);
  	vlan_info->nr_vids++;
  	*pvid_info = vid_info;
87002b03b   Jiri Pirko   net: introduce vl...
221
222
  	return 0;
  }
5b9ea6e02   Jiri Pirko   vlan: introduce v...
223

80d5c3689   Patrick McHardy   net: vlan: prepar...
224
  int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid)
5b9ea6e02   Jiri Pirko   vlan: introduce v...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  {
  	struct vlan_info *vlan_info;
  	struct vlan_vid_info *vid_info;
  	bool vlan_info_created = false;
  	int err;
  
  	ASSERT_RTNL();
  
  	vlan_info = rtnl_dereference(dev->vlan_info);
  	if (!vlan_info) {
  		vlan_info = vlan_info_alloc(dev);
  		if (!vlan_info)
  			return -ENOMEM;
  		vlan_info_created = true;
  	}
80d5c3689   Patrick McHardy   net: vlan: prepar...
240
  	vid_info = vlan_vid_info_get(vlan_info, proto, vid);
5b9ea6e02   Jiri Pirko   vlan: introduce v...
241
  	if (!vid_info) {
80d5c3689   Patrick McHardy   net: vlan: prepar...
242
  		err = __vlan_vid_add(vlan_info, proto, vid, &vid_info);
5b9ea6e02   Jiri Pirko   vlan: introduce v...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  		if (err)
  			goto out_free_vlan_info;
  	}
  	vid_info->refcount++;
  
  	if (vlan_info_created)
  		rcu_assign_pointer(dev->vlan_info, vlan_info);
  
  	return 0;
  
  out_free_vlan_info:
  	if (vlan_info_created)
  		kfree(vlan_info);
  	return err;
  }
87002b03b   Jiri Pirko   net: introduce vl...
258
  EXPORT_SYMBOL(vlan_vid_add);
5b9ea6e02   Jiri Pirko   vlan: introduce v...
259
260
  static void __vlan_vid_del(struct vlan_info *vlan_info,
  			   struct vlan_vid_info *vid_info)
87002b03b   Jiri Pirko   net: introduce vl...
261
  {
5b9ea6e02   Jiri Pirko   vlan: introduce v...
262
  	struct net_device *dev = vlan_info->real_dev;
87002b03b   Jiri Pirko   net: introduce vl...
263
  	const struct net_device_ops *ops = dev->netdev_ops;
80d5c3689   Patrick McHardy   net: vlan: prepar...
264
265
  	__be16 proto = vid_info->proto;
  	u16 vid = vid_info->vid;
5b9ea6e02   Jiri Pirko   vlan: introduce v...
266
  	int err;
87002b03b   Jiri Pirko   net: introduce vl...
267

8ad227ff8   Patrick McHardy   net: vlan: add 80...
268
  	if (vlan_hw_filter_capable(dev, vid_info)) {
74f2d19ca   Padmanabh Ratnakar   vlan: Invoke driv...
269
270
271
272
  		if (netif_device_present(dev))
  			err = ops->ndo_vlan_rx_kill_vid(dev, proto, vid);
  		else
  			err = -ENODEV;
5b9ea6e02   Jiri Pirko   vlan: introduce v...
273
  		if (err) {
80d5c3689   Patrick McHardy   net: vlan: prepar...
274
275
276
  			pr_warn("failed to kill vid %04x/%d for device %s
  ",
  				proto, vid, dev->name);
5b9ea6e02   Jiri Pirko   vlan: introduce v...
277
278
279
280
281
282
  		}
  	}
  	list_del(&vid_info->list);
  	kfree(vid_info);
  	vlan_info->nr_vids--;
  }
80d5c3689   Patrick McHardy   net: vlan: prepar...
283
  void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid)
5b9ea6e02   Jiri Pirko   vlan: introduce v...
284
285
286
287
288
289
290
291
292
  {
  	struct vlan_info *vlan_info;
  	struct vlan_vid_info *vid_info;
  
  	ASSERT_RTNL();
  
  	vlan_info = rtnl_dereference(dev->vlan_info);
  	if (!vlan_info)
  		return;
80d5c3689   Patrick McHardy   net: vlan: prepar...
293
  	vid_info = vlan_vid_info_get(vlan_info, proto, vid);
5b9ea6e02   Jiri Pirko   vlan: introduce v...
294
295
296
297
298
299
300
301
302
  	if (!vid_info)
  		return;
  	vid_info->refcount--;
  	if (vid_info->refcount == 0) {
  		__vlan_vid_del(vlan_info, vid_info);
  		if (vlan_info->nr_vids == 0) {
  			RCU_INIT_POINTER(dev->vlan_info, NULL);
  			call_rcu(&vlan_info->rcu, vlan_info_rcu_free);
  		}
87002b03b   Jiri Pirko   net: introduce vl...
303
304
305
  	}
  }
  EXPORT_SYMBOL(vlan_vid_del);
348a1443c   Jiri Pirko   vlan: introduce f...
306
307
308
309
310
  
  int vlan_vids_add_by_dev(struct net_device *dev,
  			 const struct net_device *by_dev)
  {
  	struct vlan_vid_info *vid_info;
f9586f79b   Dan Carpenter   vlan: add rtnl_de...
311
  	struct vlan_info *vlan_info;
348a1443c   Jiri Pirko   vlan: introduce f...
312
313
314
  	int err;
  
  	ASSERT_RTNL();
f9586f79b   Dan Carpenter   vlan: add rtnl_de...
315
316
  	vlan_info = rtnl_dereference(by_dev->vlan_info);
  	if (!vlan_info)
348a1443c   Jiri Pirko   vlan: introduce f...
317
  		return 0;
f9586f79b   Dan Carpenter   vlan: add rtnl_de...
318
  	list_for_each_entry(vid_info, &vlan_info->vid_list, list) {
80d5c3689   Patrick McHardy   net: vlan: prepar...
319
  		err = vlan_vid_add(dev, vid_info->proto, vid_info->vid);
348a1443c   Jiri Pirko   vlan: introduce f...
320
321
322
323
324
325
326
  		if (err)
  			goto unwind;
  	}
  	return 0;
  
  unwind:
  	list_for_each_entry_continue_reverse(vid_info,
f9586f79b   Dan Carpenter   vlan: add rtnl_de...
327
  					     &vlan_info->vid_list,
348a1443c   Jiri Pirko   vlan: introduce f...
328
  					     list) {
80d5c3689   Patrick McHardy   net: vlan: prepar...
329
  		vlan_vid_del(dev, vid_info->proto, vid_info->vid);
348a1443c   Jiri Pirko   vlan: introduce f...
330
331
332
333
334
335
336
337
338
339
  	}
  
  	return err;
  }
  EXPORT_SYMBOL(vlan_vids_add_by_dev);
  
  void vlan_vids_del_by_dev(struct net_device *dev,
  			  const struct net_device *by_dev)
  {
  	struct vlan_vid_info *vid_info;
f9586f79b   Dan Carpenter   vlan: add rtnl_de...
340
  	struct vlan_info *vlan_info;
348a1443c   Jiri Pirko   vlan: introduce f...
341
342
  
  	ASSERT_RTNL();
f9586f79b   Dan Carpenter   vlan: add rtnl_de...
343
344
  	vlan_info = rtnl_dereference(by_dev->vlan_info);
  	if (!vlan_info)
348a1443c   Jiri Pirko   vlan: introduce f...
345
  		return;
f9586f79b   Dan Carpenter   vlan: add rtnl_de...
346
  	list_for_each_entry(vid_info, &vlan_info->vid_list, list)
80d5c3689   Patrick McHardy   net: vlan: prepar...
347
  		vlan_vid_del(dev, vid_info->proto, vid_info->vid);
348a1443c   Jiri Pirko   vlan: introduce f...
348
349
  }
  EXPORT_SYMBOL(vlan_vids_del_by_dev);
9b361c13c   Jiri Pirko   vlan: add helper ...
350
351
352
  
  bool vlan_uses_dev(const struct net_device *dev)
  {
55462cf30   Jiri Pirko   vlan: fix bond/te...
353
354
355
356
357
358
359
360
  	struct vlan_info *vlan_info;
  
  	ASSERT_RTNL();
  
  	vlan_info = rtnl_dereference(dev->vlan_info);
  	if (!vlan_info)
  		return false;
  	return vlan_info->grp.nr_vlan_devs ? true : false;
9b361c13c   Jiri Pirko   vlan: add helper ...
361
362
  }
  EXPORT_SYMBOL(vlan_uses_dev);