Blame view

drivers/net/macvlan.c 22.1 KB
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /*
   * Copyright (c) 2007 Patrick McHardy <kaber@trash.net>
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as
   * published by the Free Software Foundation; either version 2 of
   * the License, or (at your option) any later version.
   *
   * The code this is based on carried the following copyright notice:
   * ---
   * (C) Copyright 2001-2006
   * Alex Zeffertt, Cambridge Broadband Ltd, ajz@cambridgebroadband.com
   * Re-worked by Ben Greear <greearb@candelatech.com>
   * ---
   */
  #include <linux/kernel.h>
  #include <linux/types.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/errno.h>
  #include <linux/slab.h>
  #include <linux/string.h>
82524746c   Franck Bui-Huu   rcu: split list.h...
23
  #include <linux/rculist.h>
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
24
25
26
27
28
  #include <linux/notifier.h>
  #include <linux/netdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/ethtool.h>
  #include <linux/if_arp.h>
87002b03b   Jiri Pirko   net: introduce vl...
29
  #include <linux/if_vlan.h>
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
30
31
32
  #include <linux/if_link.h>
  #include <linux/if_macvlan.h>
  #include <net/rtnetlink.h>
618e1b748   Arnd Bergmann   macvlan: implemen...
33
  #include <net/xfrm.h>
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
34
35
36
37
38
39
40
  
  #define MACVLAN_HASH_SIZE	(1 << BITS_PER_BYTE)
  
  struct macvlan_port {
  	struct net_device	*dev;
  	struct hlist_head	vlan_hash[MACVLAN_HASH_SIZE];
  	struct list_head	vlans;
8b37ef0a1   Jiri Pirko   macvlan: use call...
41
  	struct rcu_head		rcu;
eb06acdc8   Sridhar Samudrala   macvlan: Introduc...
42
  	bool 			passthru;
d5cd92448   Eric W. Biederman   macvlan: Fix use ...
43
  	int			count;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
44
  };
d5cd92448   Eric W. Biederman   macvlan: Fix use ...
45
  static void macvlan_port_destroy(struct net_device *dev);
a35e2c1b6   Jiri Pirko   macvlan: use rx_h...
46
47
48
49
  #define macvlan_port_get_rcu(dev) \
  	((struct macvlan_port *) rcu_dereference(dev->rx_handler_data))
  #define macvlan_port_get(dev) ((struct macvlan_port *) dev->rx_handler_data)
  #define macvlan_port_exists(dev) (dev->priv_flags & IFF_MACVLAN_PORT)
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
50
51
52
53
54
55
56
  static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
  					       const unsigned char *addr)
  {
  	struct macvlan_dev *vlan;
  	struct hlist_node *n;
  
  	hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[addr[5]], hlist) {
ac06713d5   Eric Dumazet   macvlan: Use comp...
57
  		if (!compare_ether_addr_64bits(vlan->dev->dev_addr, addr))
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
58
59
60
61
  			return vlan;
  	}
  	return NULL;
  }
f9ac30f08   Eric Biederman   macvlan: Determin...
62
63
64
65
66
67
68
  static void macvlan_hash_add(struct macvlan_dev *vlan)
  {
  	struct macvlan_port *port = vlan->port;
  	const unsigned char *addr = vlan->dev->dev_addr;
  
  	hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]);
  }
449f45442   Eric Dumazet   macvlan: remove o...
69
  static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync)
f9ac30f08   Eric Biederman   macvlan: Determin...
70
71
  {
  	hlist_del_rcu(&vlan->hlist);
449f45442   Eric Dumazet   macvlan: remove o...
72
73
  	if (sync)
  		synchronize_rcu();
f9ac30f08   Eric Biederman   macvlan: Determin...
74
75
76
77
78
  }
  
  static void macvlan_hash_change_addr(struct macvlan_dev *vlan,
  					const unsigned char *addr)
  {
449f45442   Eric Dumazet   macvlan: remove o...
79
  	macvlan_hash_del(vlan, true);
f9ac30f08   Eric Biederman   macvlan: Determin...
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  	/* Now that we are unhashed it is safe to change the device
  	 * address without confusing packet delivery.
  	 */
  	memcpy(vlan->dev->dev_addr, addr, ETH_ALEN);
  	macvlan_hash_add(vlan);
  }
  
  static int macvlan_addr_busy(const struct macvlan_port *port,
  				const unsigned char *addr)
  {
  	/* Test to see if the specified multicast address is
  	 * currently in use by the underlying device or
  	 * another macvlan.
  	 */
ac06713d5   Eric Dumazet   macvlan: Use comp...
94
  	if (!compare_ether_addr_64bits(port->dev->dev_addr, addr))
f9ac30f08   Eric Biederman   macvlan: Determin...
95
96
97
98
99
100
101
  		return 1;
  
  	if (macvlan_hash_lookup(port, addr))
  		return 1;
  
  	return 0;
  }
a1e514c5d   Arnd Bergmann   macvlan: cleanup ...
102

fc0663d6b   Arnd Bergmann   macvlan: allow mu...
103
104
  static int macvlan_broadcast_one(struct sk_buff *skb,
  				 const struct macvlan_dev *vlan,
618e1b748   Arnd Bergmann   macvlan: implemen...
105
  				 const struct ethhdr *eth, bool local)
a1e514c5d   Arnd Bergmann   macvlan: cleanup ...
106
  {
fc0663d6b   Arnd Bergmann   macvlan: allow mu...
107
  	struct net_device *dev = vlan->dev;
a1e514c5d   Arnd Bergmann   macvlan: cleanup ...
108
109
  	if (!skb)
  		return NET_RX_DROP;
618e1b748   Arnd Bergmann   macvlan: implemen...
110
  	if (local)
fc0663d6b   Arnd Bergmann   macvlan: allow mu...
111
  		return vlan->forward(dev, skb);
618e1b748   Arnd Bergmann   macvlan: implemen...
112

a1e514c5d   Arnd Bergmann   macvlan: cleanup ...
113
114
115
116
117
118
  	skb->dev = dev;
  	if (!compare_ether_addr_64bits(eth->h_dest,
  				       dev->broadcast))
  		skb->pkt_type = PACKET_BROADCAST;
  	else
  		skb->pkt_type = PACKET_MULTICAST;
fc0663d6b   Arnd Bergmann   macvlan: allow mu...
119
  	return vlan->receive(skb);
a1e514c5d   Arnd Bergmann   macvlan: cleanup ...
120
  }
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
121
  static void macvlan_broadcast(struct sk_buff *skb,
618e1b748   Arnd Bergmann   macvlan: implemen...
122
123
124
  			      const struct macvlan_port *port,
  			      struct net_device *src,
  			      enum macvlan_mode mode)
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
125
126
127
128
  {
  	const struct ethhdr *eth = eth_hdr(skb);
  	const struct macvlan_dev *vlan;
  	struct hlist_node *n;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
129
130
  	struct sk_buff *nskb;
  	unsigned int i;
a1e514c5d   Arnd Bergmann   macvlan: cleanup ...
131
  	int err;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
132

efbbced36   Patrick McHardy   macvlan: don't br...
133
134
  	if (skb->protocol == htons(ETH_P_PAUSE))
  		return;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
135
136
  	for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
  		hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) {
618e1b748   Arnd Bergmann   macvlan: implemen...
137
138
  			if (vlan->dev == src || !(vlan->mode & mode))
  				continue;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
139
  			nskb = skb_clone(skb, GFP_ATOMIC);
fc0663d6b   Arnd Bergmann   macvlan: allow mu...
140
  			err = macvlan_broadcast_one(nskb, vlan, eth,
618e1b748   Arnd Bergmann   macvlan: implemen...
141
  					 mode == MACVLAN_MODE_BRIDGE);
a1e514c5d   Arnd Bergmann   macvlan: cleanup ...
142
143
  			macvlan_count_rx(vlan, skb->len + ETH_HLEN,
  					 err == NET_RX_SUCCESS, 1);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
144
145
146
147
148
  		}
  	}
  }
  
  /* called under rcu_read_lock() from netif_receive_skb */
8a4eb5734   Jiri Pirko   net: introduce rx...
149
  static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
150
  {
ab95bfe01   Jiri Pirko   net: replace hook...
151
  	struct macvlan_port *port;
8a4eb5734   Jiri Pirko   net: introduce rx...
152
  	struct sk_buff *skb = *pskb;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
153
  	const struct ethhdr *eth = eth_hdr(skb);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
154
  	const struct macvlan_dev *vlan;
618e1b748   Arnd Bergmann   macvlan: implemen...
155
  	const struct macvlan_dev *src;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
156
  	struct net_device *dev;
ba01877f5   Sridhar Samudrala   macvlan: Fix rx c...
157
158
  	unsigned int len = 0;
  	int ret = NET_RX_DROP;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
159

a35e2c1b6   Jiri Pirko   macvlan: use rx_h...
160
  	port = macvlan_port_get_rcu(skb->dev);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
161
  	if (is_multicast_ether_addr(eth->h_dest)) {
bc416d976   Eric Dumazet   macvlan: handle f...
162
163
164
  		skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN);
  		if (!skb)
  			return RX_HANDLER_CONSUMED;
618e1b748   Arnd Bergmann   macvlan: implemen...
165
166
167
168
169
170
  		src = macvlan_hash_lookup(port, eth->h_source);
  		if (!src)
  			/* frame comes from an external address */
  			macvlan_broadcast(skb, port, NULL,
  					  MACVLAN_MODE_PRIVATE |
  					  MACVLAN_MODE_VEPA    |
eb06acdc8   Sridhar Samudrala   macvlan: Introduc...
171
  					  MACVLAN_MODE_PASSTHRU|
618e1b748   Arnd Bergmann   macvlan: implemen...
172
173
174
175
176
177
178
179
180
181
182
183
184
  					  MACVLAN_MODE_BRIDGE);
  		else if (src->mode == MACVLAN_MODE_VEPA)
  			/* flood to everyone except source */
  			macvlan_broadcast(skb, port, src->dev,
  					  MACVLAN_MODE_VEPA |
  					  MACVLAN_MODE_BRIDGE);
  		else if (src->mode == MACVLAN_MODE_BRIDGE)
  			/*
  			 * flood only to VEPA ports, bridge ports
  			 * already saw the frame on the way out.
  			 */
  			macvlan_broadcast(skb, port, src->dev,
  					  MACVLAN_MODE_VEPA);
729e72a10   stephen hemminger   macvlan: receive ...
185
186
187
188
189
190
  		else {
  			/* forward to original port. */
  			vlan = src;
  			ret = macvlan_broadcast_one(skb, vlan, eth, 0);
  			goto out;
  		}
8a4eb5734   Jiri Pirko   net: introduce rx...
191
  		return RX_HANDLER_PASS;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
192
  	}
eb06acdc8   Sridhar Samudrala   macvlan: Introduc...
193
194
195
196
  	if (port->passthru)
  		vlan = list_first_entry(&port->vlans, struct macvlan_dev, list);
  	else
  		vlan = macvlan_hash_lookup(port, eth->h_dest);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
197
  	if (vlan == NULL)
8a4eb5734   Jiri Pirko   net: introduce rx...
198
  		return RX_HANDLER_PASS;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
199
200
201
202
  
  	dev = vlan->dev;
  	if (unlikely(!(dev->flags & IFF_UP))) {
  		kfree_skb(skb);
8a4eb5734   Jiri Pirko   net: introduce rx...
203
  		return RX_HANDLER_CONSUMED;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
204
  	}
a1e514c5d   Arnd Bergmann   macvlan: cleanup ...
205
  	len = skb->len + ETH_HLEN;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
206
  	skb = skb_share_check(skb, GFP_ATOMIC);
a1e514c5d   Arnd Bergmann   macvlan: cleanup ...
207
  	if (!skb)
ba01877f5   Sridhar Samudrala   macvlan: Fix rx c...
208
  		goto out;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
209
210
211
  
  	skb->dev = dev;
  	skb->pkt_type = PACKET_HOST;
ba01877f5   Sridhar Samudrala   macvlan: Fix rx c...
212
213
214
215
  	ret = vlan->receive(skb);
  
  out:
  	macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0);
8a4eb5734   Jiri Pirko   net: introduce rx...
216
  	return RX_HANDLER_CONSUMED;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
217
  }
618e1b748   Arnd Bergmann   macvlan: implemen...
218
219
220
221
222
  static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
  {
  	const struct macvlan_dev *vlan = netdev_priv(dev);
  	const struct macvlan_port *port = vlan->port;
  	const struct macvlan_dev *dest;
12a2856b6   Daniel Lezcano   macvlan : fix che...
223
  	__u8 ip_summed = skb->ip_summed;
618e1b748   Arnd Bergmann   macvlan: implemen...
224
225
226
  
  	if (vlan->mode == MACVLAN_MODE_BRIDGE) {
  		const struct ethhdr *eth = (void *)skb->data;
12a2856b6   Daniel Lezcano   macvlan : fix che...
227
  		skb->ip_summed = CHECKSUM_UNNECESSARY;
618e1b748   Arnd Bergmann   macvlan: implemen...
228
229
230
231
232
233
234
235
236
  
  		/* send to other bridge ports directly */
  		if (is_multicast_ether_addr(eth->h_dest)) {
  			macvlan_broadcast(skb, port, dev, MACVLAN_MODE_BRIDGE);
  			goto xmit_world;
  		}
  
  		dest = macvlan_hash_lookup(port, eth->h_dest);
  		if (dest && dest->mode == MACVLAN_MODE_BRIDGE) {
a37dd3332   David Ward   macvlan: Forward ...
237
  			/* send to lowerdev first for its network taps */
cb2d0f3e9   David Ward   macvlan/macvtap: ...
238
  			dev_forward_skb(vlan->lowerdev, skb);
618e1b748   Arnd Bergmann   macvlan: implemen...
239
240
241
242
243
244
  
  			return NET_XMIT_SUCCESS;
  		}
  	}
  
  xmit_world:
12a2856b6   Daniel Lezcano   macvlan : fix che...
245
  	skb->ip_summed = ip_summed;
8a83a00b0   Arnd Bergmann   net: maintain nam...
246
  	skb_set_dev(skb, vlan->lowerdev);
618e1b748   Arnd Bergmann   macvlan: implemen...
247
248
  	return dev_queue_xmit(skb);
  }
fc0663d6b   Arnd Bergmann   macvlan: allow mu...
249
250
  netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
  			       struct net_device *dev)
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
251
  {
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
252
253
  	unsigned int len = skb->len;
  	int ret;
8ffab51b3   Eric Dumazet   macvlan: lockless...
254
  	const struct macvlan_dev *vlan = netdev_priv(dev);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
255

618e1b748   Arnd Bergmann   macvlan: implemen...
256
  	ret = macvlan_queue_xmit(skb, dev);
2d6c9ffcc   Eric Dumazet   net: congestion n...
257
  	if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
8ffab51b3   Eric Dumazet   macvlan: lockless...
258
  		struct macvlan_pcpu_stats *pcpu_stats;
2c1145532   Eric Dumazet   macvlan: add mult...
259

8ffab51b3   Eric Dumazet   macvlan: lockless...
260
261
262
263
264
265
266
267
  		pcpu_stats = this_cpu_ptr(vlan->pcpu_stats);
  		u64_stats_update_begin(&pcpu_stats->syncp);
  		pcpu_stats->tx_packets++;
  		pcpu_stats->tx_bytes += len;
  		u64_stats_update_end(&pcpu_stats->syncp);
  	} else {
  		this_cpu_inc(vlan->pcpu_stats->tx_dropped);
  	}
cbbef5e18   Patrick McHardy   vlan/macvlan: pro...
268
  	return ret;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
269
  }
fc0663d6b   Arnd Bergmann   macvlan: allow mu...
270
  EXPORT_SYMBOL_GPL(macvlan_start_xmit);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
271
272
  
  static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev,
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
273
274
  			       unsigned short type, const void *daddr,
  			       const void *saddr, unsigned len)
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
275
276
277
  {
  	const struct macvlan_dev *vlan = netdev_priv(dev);
  	struct net_device *lowerdev = vlan->lowerdev;
0c4e85813   Stephen Hemminger   [NET]: Wrap netde...
278
279
  	return dev_hard_header(skb, lowerdev, type, daddr,
  			       saddr ? : dev->dev_addr, len);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
280
  }
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
281
282
283
284
  static const struct header_ops macvlan_hard_header_ops = {
  	.create  	= macvlan_hard_header,
  	.rebuild	= eth_rebuild_header,
  	.parse		= eth_header_parse,
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
285
286
287
  	.cache		= eth_header_cache,
  	.cache_update	= eth_header_cache_update,
  };
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
288
289
290
  static int macvlan_open(struct net_device *dev)
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
291
292
  	struct net_device *lowerdev = vlan->lowerdev;
  	int err;
eb06acdc8   Sridhar Samudrala   macvlan: Introduc...
293
294
295
296
  	if (vlan->port->passthru) {
  		dev_set_promiscuity(lowerdev, 1);
  		goto hash_add;
  	}
f9ac30f08   Eric Biederman   macvlan: Determin...
297
298
299
  	err = -EBUSY;
  	if (macvlan_addr_busy(vlan->port, dev->dev_addr))
  		goto out;
a748ee242   Jiri Pirko   net: move address...
300
  	err = dev_uc_add(lowerdev, dev->dev_addr);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
301
  	if (err < 0)
b89fb7da2   Wang Chen   macvlan: Check re...
302
303
304
305
306
307
  		goto out;
  	if (dev->flags & IFF_ALLMULTI) {
  		err = dev_set_allmulti(lowerdev, 1);
  		if (err < 0)
  			goto del_unicast;
  	}
eb06acdc8   Sridhar Samudrala   macvlan: Introduc...
308
309
  
  hash_add:
f9ac30f08   Eric Biederman   macvlan: Determin...
310
  	macvlan_hash_add(vlan);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
311
  	return 0;
b89fb7da2   Wang Chen   macvlan: Check re...
312
313
  
  del_unicast:
a748ee242   Jiri Pirko   net: move address...
314
  	dev_uc_del(lowerdev, dev->dev_addr);
b89fb7da2   Wang Chen   macvlan: Check re...
315
316
  out:
  	return err;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
317
318
319
320
321
322
  }
  
  static int macvlan_stop(struct net_device *dev)
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
  	struct net_device *lowerdev = vlan->lowerdev;
eb06acdc8   Sridhar Samudrala   macvlan: Introduc...
323
324
325
326
  	if (vlan->port->passthru) {
  		dev_set_promiscuity(lowerdev, -1);
  		goto hash_del;
  	}
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
327
328
329
  	dev_mc_unsync(lowerdev, dev);
  	if (dev->flags & IFF_ALLMULTI)
  		dev_set_allmulti(lowerdev, -1);
a748ee242   Jiri Pirko   net: move address...
330
  	dev_uc_del(lowerdev, dev->dev_addr);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
331

eb06acdc8   Sridhar Samudrala   macvlan: Introduc...
332
  hash_del:
449f45442   Eric Dumazet   macvlan: remove o...
333
  	macvlan_hash_del(vlan, !dev->dismantle);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
334
335
  	return 0;
  }
ad5d20a63   Patrick McHardy   [MACVLAN]: Allow ...
336
337
338
339
340
341
342
343
344
  static int macvlan_set_mac_address(struct net_device *dev, void *p)
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
  	struct net_device *lowerdev = vlan->lowerdev;
  	struct sockaddr *addr = p;
  	int err;
  
  	if (!is_valid_ether_addr(addr->sa_data))
  		return -EADDRNOTAVAIL;
f9ac30f08   Eric Biederman   macvlan: Determin...
345
346
347
348
349
350
351
  	if (!(dev->flags & IFF_UP)) {
  		/* Just copy in the new address */
  		memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
  	} else {
  		/* Rehash and update the device filters */
  		if (macvlan_addr_busy(vlan->port, addr->sa_data))
  			return -EBUSY;
ad5d20a63   Patrick McHardy   [MACVLAN]: Allow ...
352

a748ee242   Jiri Pirko   net: move address...
353
  		err = dev_uc_add(lowerdev, addr->sa_data);
ccffad25b   Jiri Pirko   net: convert unic...
354
  		if (err)
f9ac30f08   Eric Biederman   macvlan: Determin...
355
  			return err;
ad5d20a63   Patrick McHardy   [MACVLAN]: Allow ...
356

a748ee242   Jiri Pirko   net: move address...
357
  		dev_uc_del(lowerdev, dev->dev_addr);
f9ac30f08   Eric Biederman   macvlan: Determin...
358
359
360
  
  		macvlan_hash_change_addr(vlan, addr->sa_data);
  	}
ad5d20a63   Patrick McHardy   [MACVLAN]: Allow ...
361
362
  	return 0;
  }
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  static void macvlan_change_rx_flags(struct net_device *dev, int change)
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
  	struct net_device *lowerdev = vlan->lowerdev;
  
  	if (change & IFF_ALLMULTI)
  		dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1);
  }
  
  static void macvlan_set_multicast_list(struct net_device *dev)
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
  
  	dev_mc_sync(vlan->lowerdev, dev);
  }
  
  static int macvlan_change_mtu(struct net_device *dev, int new_mtu)
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
  
  	if (new_mtu < 68 || vlan->lowerdev->mtu < new_mtu)
  		return -EINVAL;
  	dev->mtu = new_mtu;
  	return 0;
  }
  
  /*
   * macvlan network devices have devices nesting below it and are a special
   * "super class" of normal network devices; split their locks off into a
   * separate class since they always nest.
   */
  static struct lock_class_key macvlan_netdev_xmit_lock_key;
cf508b121   David S. Miller   netdev: Handle ->...
395
  static struct lock_class_key macvlan_netdev_addr_lock_key;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
396
397
398
399
  
  #define MACVLAN_FEATURES \
  	(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
  	 NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
8d13e670d   John Fastabend   macvlan: add VLAN...
400
401
  	 NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM | \
  	 NETIF_F_HW_VLAN_FILTER)
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
402
403
404
  
  #define MACVLAN_STATE_MASK \
  	((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
e8a0464cc   David S. Miller   netdev: Allocate ...
405
406
407
  static void macvlan_set_lockdep_class_one(struct net_device *dev,
  					  struct netdev_queue *txq,
  					  void *_unused)
c773e847e   David S. Miller   netdev: Move _xmi...
408
409
410
411
412
413
414
  {
  	lockdep_set_class(&txq->_xmit_lock,
  			  &macvlan_netdev_xmit_lock_key);
  }
  
  static void macvlan_set_lockdep_class(struct net_device *dev)
  {
cf508b121   David S. Miller   netdev: Handle ->...
415
416
  	lockdep_set_class(&dev->addr_list_lock,
  			  &macvlan_netdev_addr_lock_key);
e8a0464cc   David S. Miller   netdev: Allocate ...
417
  	netdev_for_each_tx_queue(dev, macvlan_set_lockdep_class_one, NULL);
c773e847e   David S. Miller   netdev: Move _xmi...
418
  }
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
419
420
421
422
423
424
425
426
  static int macvlan_init(struct net_device *dev)
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
  	const struct net_device *lowerdev = vlan->lowerdev;
  
  	dev->state		= (dev->state & ~MACVLAN_STATE_MASK) |
  				  (lowerdev->state & MACVLAN_STATE_MASK);
  	dev->features 		= lowerdev->features & MACVLAN_FEATURES;
8ffab51b3   Eric Dumazet   macvlan: lockless...
427
  	dev->features		|= NETIF_F_LLTX;
8c2acc53f   Patrick McHardy   macvlan: fix gso_...
428
  	dev->gso_max_size	= lowerdev->gso_max_size;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
429
  	dev->iflink		= lowerdev->ifindex;
ef5c89967   sg.tweak@gmail.com   drivers/net/macvl...
430
  	dev->hard_header_len	= lowerdev->hard_header_len;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
431

c773e847e   David S. Miller   netdev: Move _xmi...
432
  	macvlan_set_lockdep_class(dev);
8ffab51b3   Eric Dumazet   macvlan: lockless...
433
434
  	vlan->pcpu_stats = alloc_percpu(struct macvlan_pcpu_stats);
  	if (!vlan->pcpu_stats)
fccaf7101   Eric Dumazet   macvlan: Precise ...
435
  		return -ENOMEM;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
436
437
  	return 0;
  }
fccaf7101   Eric Dumazet   macvlan: Precise ...
438
439
440
  static void macvlan_uninit(struct net_device *dev)
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
d5cd92448   Eric W. Biederman   macvlan: Fix use ...
441
  	struct macvlan_port *port = vlan->port;
fccaf7101   Eric Dumazet   macvlan: Precise ...
442

8ffab51b3   Eric Dumazet   macvlan: lockless...
443
  	free_percpu(vlan->pcpu_stats);
d5cd92448   Eric W. Biederman   macvlan: Fix use ...
444
445
446
447
  
  	port->count -= 1;
  	if (!port->count)
  		macvlan_port_destroy(port->dev);
fccaf7101   Eric Dumazet   macvlan: Precise ...
448
  }
28172739f   Eric Dumazet   net: fix 64 bit c...
449
450
  static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
  							 struct rtnl_link_stats64 *stats)
fccaf7101   Eric Dumazet   macvlan: Precise ...
451
  {
fccaf7101   Eric Dumazet   macvlan: Precise ...
452
  	struct macvlan_dev *vlan = netdev_priv(dev);
8ffab51b3   Eric Dumazet   macvlan: lockless...
453
454
455
456
  	if (vlan->pcpu_stats) {
  		struct macvlan_pcpu_stats *p;
  		u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes;
  		u32 rx_errors = 0, tx_dropped = 0;
bc66154ef   Eric Dumazet   macvlan: 64 bit r...
457
  		unsigned int start;
fccaf7101   Eric Dumazet   macvlan: Precise ...
458
459
460
  		int i;
  
  		for_each_possible_cpu(i) {
8ffab51b3   Eric Dumazet   macvlan: lockless...
461
  			p = per_cpu_ptr(vlan->pcpu_stats, i);
bc66154ef   Eric Dumazet   macvlan: 64 bit r...
462
463
464
465
466
  			do {
  				start = u64_stats_fetch_begin_bh(&p->syncp);
  				rx_packets	= p->rx_packets;
  				rx_bytes	= p->rx_bytes;
  				rx_multicast	= p->rx_multicast;
8ffab51b3   Eric Dumazet   macvlan: lockless...
467
468
  				tx_packets	= p->tx_packets;
  				tx_bytes	= p->tx_bytes;
bc66154ef   Eric Dumazet   macvlan: 64 bit r...
469
  			} while (u64_stats_fetch_retry_bh(&p->syncp, start));
8ffab51b3   Eric Dumazet   macvlan: lockless...
470
471
472
473
474
475
476
477
478
479
480
  
  			stats->rx_packets	+= rx_packets;
  			stats->rx_bytes		+= rx_bytes;
  			stats->multicast	+= rx_multicast;
  			stats->tx_packets	+= tx_packets;
  			stats->tx_bytes		+= tx_bytes;
  			/* rx_errors & tx_dropped are u32, updated
  			 * without syncp protection.
  			 */
  			rx_errors	+= p->rx_errors;
  			tx_dropped	+= p->tx_dropped;
fccaf7101   Eric Dumazet   macvlan: Precise ...
481
  		}
8ffab51b3   Eric Dumazet   macvlan: lockless...
482
483
484
  		stats->rx_errors	= rx_errors;
  		stats->rx_dropped	= rx_errors;
  		stats->tx_dropped	= tx_dropped;
fccaf7101   Eric Dumazet   macvlan: Precise ...
485
486
487
  	}
  	return stats;
  }
8e586137e   Jiri Pirko   net: make vlan nd...
488
  static int macvlan_vlan_rx_add_vid(struct net_device *dev,
8d13e670d   John Fastabend   macvlan: add VLAN...
489
490
491
492
  				    unsigned short vid)
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
  	struct net_device *lowerdev = vlan->lowerdev;
8d13e670d   John Fastabend   macvlan: add VLAN...
493

87002b03b   Jiri Pirko   net: introduce vl...
494
  	return vlan_vid_add(lowerdev, vid);
8d13e670d   John Fastabend   macvlan: add VLAN...
495
  }
8e586137e   Jiri Pirko   net: make vlan nd...
496
  static int macvlan_vlan_rx_kill_vid(struct net_device *dev,
8d13e670d   John Fastabend   macvlan: add VLAN...
497
498
499
500
  				     unsigned short vid)
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
  	struct net_device *lowerdev = vlan->lowerdev;
8d13e670d   John Fastabend   macvlan: add VLAN...
501

87002b03b   Jiri Pirko   net: introduce vl...
502
  	vlan_vid_del(lowerdev, vid);
8e586137e   Jiri Pirko   net: make vlan nd...
503
  	return 0;
8d13e670d   John Fastabend   macvlan: add VLAN...
504
  }
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
505
506
507
508
509
510
  static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
  					struct ethtool_drvinfo *drvinfo)
  {
  	snprintf(drvinfo->driver, 32, "macvlan");
  	snprintf(drvinfo->version, 32, "0.1");
  }
9edb8bb68   Stephen Hemminger   macvlan: add supp...
511
512
513
514
  static int macvlan_ethtool_get_settings(struct net_device *dev,
  					struct ethtool_cmd *cmd)
  {
  	const struct macvlan_dev *vlan = netdev_priv(dev);
4bc71cb98   Jiri Pirko   net: consolidate ...
515
516
  
  	return __ethtool_get_settings(vlan->lowerdev, cmd);
9edb8bb68   Stephen Hemminger   macvlan: add supp...
517
  }
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
518
519
  static const struct ethtool_ops macvlan_ethtool_ops = {
  	.get_link		= ethtool_op_get_link,
9edb8bb68   Stephen Hemminger   macvlan: add supp...
520
  	.get_settings		= macvlan_ethtool_get_settings,
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
521
522
  	.get_drvinfo		= macvlan_ethtool_get_drvinfo,
  };
54a30c975   Stephen Hemminger   macvlan: convert ...
523
524
  static const struct net_device_ops macvlan_netdev_ops = {
  	.ndo_init		= macvlan_init,
fccaf7101   Eric Dumazet   macvlan: Precise ...
525
  	.ndo_uninit		= macvlan_uninit,
54a30c975   Stephen Hemminger   macvlan: convert ...
526
527
  	.ndo_open		= macvlan_open,
  	.ndo_stop		= macvlan_stop,
008298231   Stephen Hemminger   netdev: add more ...
528
  	.ndo_start_xmit		= macvlan_start_xmit,
54a30c975   Stephen Hemminger   macvlan: convert ...
529
530
531
  	.ndo_change_mtu		= macvlan_change_mtu,
  	.ndo_change_rx_flags	= macvlan_change_rx_flags,
  	.ndo_set_mac_address	= macvlan_set_mac_address,
afc4b13df   Jiri Pirko   net: remove use o...
532
  	.ndo_set_rx_mode	= macvlan_set_multicast_list,
bc66154ef   Eric Dumazet   macvlan: 64 bit r...
533
  	.ndo_get_stats64	= macvlan_dev_get_stats64,
54a30c975   Stephen Hemminger   macvlan: convert ...
534
  	.ndo_validate_addr	= eth_validate_addr,
8d13e670d   John Fastabend   macvlan: add VLAN...
535
536
  	.ndo_vlan_rx_add_vid	= macvlan_vlan_rx_add_vid,
  	.ndo_vlan_rx_kill_vid	= macvlan_vlan_rx_kill_vid,
54a30c975   Stephen Hemminger   macvlan: convert ...
537
  };
8a35747a5   Herbert Xu   macvtap: Limit pa...
538
  void macvlan_common_setup(struct net_device *dev)
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
539
540
  {
  	ether_setup(dev);
550fd08c2   Neil Horman   net: Audit driver...
541
  	dev->priv_flags	       &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
54a30c975   Stephen Hemminger   macvlan: convert ...
542
  	dev->netdev_ops		= &macvlan_netdev_ops;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
543
  	dev->destructor		= free_netdev;
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
544
  	dev->header_ops		= &macvlan_hard_header_ops,
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
545
  	dev->ethtool_ops	= &macvlan_ethtool_ops;
8a35747a5   Herbert Xu   macvtap: Limit pa...
546
547
548
549
550
551
  }
  EXPORT_SYMBOL_GPL(macvlan_common_setup);
  
  static void macvlan_setup(struct net_device *dev)
  {
  	macvlan_common_setup(dev);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
552
553
554
555
556
557
558
  	dev->tx_queue_len	= 0;
  }
  
  static int macvlan_port_create(struct net_device *dev)
  {
  	struct macvlan_port *port;
  	unsigned int i;
ab95bfe01   Jiri Pirko   net: replace hook...
559
  	int err;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
560
561
562
563
564
565
566
  
  	if (dev->type != ARPHRD_ETHER || dev->flags & IFF_LOOPBACK)
  		return -EINVAL;
  
  	port = kzalloc(sizeof(*port), GFP_KERNEL);
  	if (port == NULL)
  		return -ENOMEM;
eb06acdc8   Sridhar Samudrala   macvlan: Introduc...
567
  	port->passthru = false;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
568
569
570
571
  	port->dev = dev;
  	INIT_LIST_HEAD(&port->vlans);
  	for (i = 0; i < MACVLAN_HASH_SIZE; i++)
  		INIT_HLIST_HEAD(&port->vlan_hash[i]);
ab95bfe01   Jiri Pirko   net: replace hook...
572

a35e2c1b6   Jiri Pirko   macvlan: use rx_h...
573
574
  	err = netdev_rx_handler_register(dev, macvlan_handle_frame, port);
  	if (err)
ab95bfe01   Jiri Pirko   net: replace hook...
575
  		kfree(port);
d93515611   Eric Dumazet   macvlan: fix pani...
576
577
  	else
  		dev->priv_flags |= IFF_MACVLAN_PORT;
ab95bfe01   Jiri Pirko   net: replace hook...
578
  	return err;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
579
580
581
582
  }
  
  static void macvlan_port_destroy(struct net_device *dev)
  {
a35e2c1b6   Jiri Pirko   macvlan: use rx_h...
583
  	struct macvlan_port *port = macvlan_port_get(dev);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
584

a35e2c1b6   Jiri Pirko   macvlan: use rx_h...
585
  	dev->priv_flags &= ~IFF_MACVLAN_PORT;
ab95bfe01   Jiri Pirko   net: replace hook...
586
  	netdev_rx_handler_unregister(dev);
6e070aecd   Lai Jiangshan   macvlan,rcu: conv...
587
  	kfree_rcu(port, rcu);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
588
  }
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
589
590
591
592
593
594
595
596
  static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
  {
  	if (tb[IFLA_ADDRESS]) {
  		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
  			return -EINVAL;
  		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
  			return -EADDRNOTAVAIL;
  	}
27c0b1a85   Arnd Bergmann   macvlan: export m...
597
598
599
600
601
602
  
  	if (data && data[IFLA_MACVLAN_MODE]) {
  		switch (nla_get_u32(data[IFLA_MACVLAN_MODE])) {
  		case MACVLAN_MODE_PRIVATE:
  		case MACVLAN_MODE_VEPA:
  		case MACVLAN_MODE_BRIDGE:
eb06acdc8   Sridhar Samudrala   macvlan: Introduc...
603
  		case MACVLAN_MODE_PASSTHRU:
27c0b1a85   Arnd Bergmann   macvlan: export m...
604
605
606
607
608
  			break;
  		default:
  			return -EINVAL;
  		}
  	}
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
609
610
  	return 0;
  }
fc0663d6b   Arnd Bergmann   macvlan: allow mu...
611
612
613
614
615
  int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
  			   struct nlattr *tb[], struct nlattr *data[],
  			   int (*receive)(struct sk_buff *skb),
  			   int (*forward)(struct net_device *dev,
  					  struct sk_buff *skb))
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
616
617
618
619
620
621
622
623
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
  	struct macvlan_port *port;
  	struct net_device *lowerdev;
  	int err;
  
  	if (!tb[IFLA_LINK])
  		return -EINVAL;
81adee47d   Eric W. Biederman   net: Support spec...
624
  	lowerdev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
625
626
  	if (lowerdev == NULL)
  		return -ENODEV;
b0832a296   Eric Biederman   macvlan: Support ...
627
628
  	/* When creating macvlans on top of other macvlans - use
  	 * the real device as the lowerdev.
a6ca5f1db   Patrick McHardy   [MACVLAN]: Preven...
629
  	 */
b0832a296   Eric Biederman   macvlan: Support ...
630
631
632
633
  	if (lowerdev->rtnl_link_ops == dev->rtnl_link_ops) {
  		struct macvlan_dev *lowervlan = netdev_priv(lowerdev);
  		lowerdev = lowervlan->lowerdev;
  	}
a6ca5f1db   Patrick McHardy   [MACVLAN]: Preven...
634

b863ceb7d   Patrick McHardy   [NET]: Add macvla...
635
636
637
638
639
640
641
  	if (!tb[IFLA_MTU])
  		dev->mtu = lowerdev->mtu;
  	else if (dev->mtu > lowerdev->mtu)
  		return -EINVAL;
  
  	if (!tb[IFLA_ADDRESS])
  		random_ether_addr(dev->dev_addr);
a35e2c1b6   Jiri Pirko   macvlan: use rx_h...
642
  	if (!macvlan_port_exists(lowerdev)) {
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
643
644
645
646
  		err = macvlan_port_create(lowerdev);
  		if (err < 0)
  			return err;
  	}
a35e2c1b6   Jiri Pirko   macvlan: use rx_h...
647
  	port = macvlan_port_get(lowerdev);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
648

eb06acdc8   Sridhar Samudrala   macvlan: Introduc...
649
650
651
  	/* Only 1 macvlan device can be created in passthru mode */
  	if (port->passthru)
  		return -EINVAL;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
652
653
654
  	vlan->lowerdev = lowerdev;
  	vlan->dev      = dev;
  	vlan->port     = port;
fc0663d6b   Arnd Bergmann   macvlan: allow mu...
655
656
  	vlan->receive  = receive;
  	vlan->forward  = forward;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
657

27c0b1a85   Arnd Bergmann   macvlan: export m...
658
659
660
  	vlan->mode     = MACVLAN_MODE_VEPA;
  	if (data && data[IFLA_MACVLAN_MODE])
  		vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
eb06acdc8   Sridhar Samudrala   macvlan: Introduc...
661
  	if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
d5cd92448   Eric W. Biederman   macvlan: Fix use ...
662
  		if (port->count)
eb06acdc8   Sridhar Samudrala   macvlan: Introduc...
663
664
665
666
  			return -EINVAL;
  		port->passthru = true;
  		memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN);
  	}
d5cd92448   Eric W. Biederman   macvlan: Fix use ...
667
  	port->count += 1;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
668
669
  	err = register_netdevice(dev);
  	if (err < 0)
f16d3d574   Jiri Pirko   macvlan: do prope...
670
  		goto destroy_port;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
671
672
  
  	list_add_tail(&vlan->list, &port->vlans);
fc4a74896   Patrick Mullaney   netdevice: provid...
673
  	netif_stacked_transfer_operstate(lowerdev, dev);
f16d3d574   Jiri Pirko   macvlan: do prope...
674

b863ceb7d   Patrick McHardy   [NET]: Add macvla...
675
  	return 0;
f16d3d574   Jiri Pirko   macvlan: do prope...
676
677
  
  destroy_port:
d5cd92448   Eric W. Biederman   macvlan: Fix use ...
678
679
  	port->count -= 1;
  	if (!port->count)
f16d3d574   Jiri Pirko   macvlan: do prope...
680
681
682
  		macvlan_port_destroy(lowerdev);
  
  	return err;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
683
  }
fc0663d6b   Arnd Bergmann   macvlan: allow mu...
684
  EXPORT_SYMBOL_GPL(macvlan_common_newlink);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
685

fc0663d6b   Arnd Bergmann   macvlan: allow mu...
686
687
688
689
690
691
692
693
694
  static int macvlan_newlink(struct net *src_net, struct net_device *dev,
  			   struct nlattr *tb[], struct nlattr *data[])
  {
  	return macvlan_common_newlink(src_net, dev, tb, data,
  				      netif_rx,
  				      dev_forward_skb);
  }
  
  void macvlan_dellink(struct net_device *dev, struct list_head *head)
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
695
696
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
697
698
  
  	list_del(&vlan->list);
23289a37e   Eric Dumazet   net: add a list_h...
699
  	unregister_netdevice_queue(dev, head);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
700
  }
fc0663d6b   Arnd Bergmann   macvlan: allow mu...
701
  EXPORT_SYMBOL_GPL(macvlan_dellink);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
702

27c0b1a85   Arnd Bergmann   macvlan: export m...
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
  static int macvlan_changelink(struct net_device *dev,
  		struct nlattr *tb[], struct nlattr *data[])
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
  	if (data && data[IFLA_MACVLAN_MODE])
  		vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
  	return 0;
  }
  
  static size_t macvlan_get_size(const struct net_device *dev)
  {
  	return nla_total_size(4);
  }
  
  static int macvlan_fill_info(struct sk_buff *skb,
  				const struct net_device *dev)
  {
  	struct macvlan_dev *vlan = netdev_priv(dev);
  
  	NLA_PUT_U32(skb, IFLA_MACVLAN_MODE, vlan->mode);
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
  
  static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = {
  	[IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
  };
fc0663d6b   Arnd Bergmann   macvlan: allow mu...
732
733
734
735
  int macvlan_link_register(struct rtnl_link_ops *ops)
  {
  	/* common fields */
  	ops->priv_size		= sizeof(struct macvlan_dev);
fc0663d6b   Arnd Bergmann   macvlan: allow mu...
736
737
738
739
740
741
742
743
744
745
746
747
  	ops->validate		= macvlan_validate;
  	ops->maxtype		= IFLA_MACVLAN_MAX;
  	ops->policy		= macvlan_policy;
  	ops->changelink		= macvlan_changelink;
  	ops->get_size		= macvlan_get_size;
  	ops->fill_info		= macvlan_fill_info;
  
  	return rtnl_link_register(ops);
  };
  EXPORT_SYMBOL_GPL(macvlan_link_register);
  
  static struct rtnl_link_ops macvlan_link_ops = {
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
748
  	.kind		= "macvlan",
8a35747a5   Herbert Xu   macvtap: Limit pa...
749
  	.setup		= macvlan_setup,
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
750
751
752
753
754
755
756
757
758
759
  	.newlink	= macvlan_newlink,
  	.dellink	= macvlan_dellink,
  };
  
  static int macvlan_device_event(struct notifier_block *unused,
  				unsigned long event, void *ptr)
  {
  	struct net_device *dev = ptr;
  	struct macvlan_dev *vlan, *next;
  	struct macvlan_port *port;
226bd3411   Eric Dumazet   net: use batched ...
760
  	LIST_HEAD(list_kill);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
761

a35e2c1b6   Jiri Pirko   macvlan: use rx_h...
762
  	if (!macvlan_port_exists(dev))
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
763
  		return NOTIFY_DONE;
a35e2c1b6   Jiri Pirko   macvlan: use rx_h...
764
  	port = macvlan_port_get(dev);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
765
766
767
  	switch (event) {
  	case NETDEV_CHANGE:
  		list_for_each_entry(vlan, &port->vlans, list)
fc4a74896   Patrick Mullaney   netdevice: provid...
768
769
  			netif_stacked_transfer_operstate(vlan->lowerdev,
  							 vlan->dev);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
770
771
772
773
  		break;
  	case NETDEV_FEAT_CHANGE:
  		list_for_each_entry(vlan, &port->vlans, list) {
  			vlan->dev->features = dev->features & MACVLAN_FEATURES;
8c2acc53f   Patrick McHardy   macvlan: fix gso_...
774
  			vlan->dev->gso_max_size = dev->gso_max_size;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
775
776
777
778
  			netdev_features_change(vlan->dev);
  		}
  		break;
  	case NETDEV_UNREGISTER:
3b27e1055   David Lamparter   netns: keep vlan ...
779
780
781
  		/* twiddle thumbs on netns device moves */
  		if (dev->reg_state != NETREG_UNREGISTERING)
  			break;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
782
  		list_for_each_entry_safe(vlan, next, &port->vlans, list)
226bd3411   Eric Dumazet   net: use batched ...
783
784
785
  			vlan->dev->rtnl_link_ops->dellink(vlan->dev, &list_kill);
  		unregister_netdevice_many(&list_kill);
  		list_del(&list_kill);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
786
  		break;
1c01fe14a   Jiri Pirko   net: forbid under...
787
788
789
  	case NETDEV_PRE_TYPE_CHANGE:
  		/* Forbid underlaying device to change its type. */
  		return NOTIFY_BAD;
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
790
791
792
793
794
795
796
797
798
799
800
801
802
  	}
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block macvlan_notifier_block __read_mostly = {
  	.notifier_call	= macvlan_device_event,
  };
  
  static int __init macvlan_init_module(void)
  {
  	int err;
  
  	register_netdevice_notifier(&macvlan_notifier_block);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
803

fc0663d6b   Arnd Bergmann   macvlan: allow mu...
804
  	err = macvlan_link_register(&macvlan_link_ops);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
805
806
807
808
  	if (err < 0)
  		goto err1;
  	return 0;
  err1:
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
809
810
811
812
813
814
815
  	unregister_netdevice_notifier(&macvlan_notifier_block);
  	return err;
  }
  
  static void __exit macvlan_cleanup_module(void)
  {
  	rtnl_link_unregister(&macvlan_link_ops);
b863ceb7d   Patrick McHardy   [NET]: Add macvla...
816
817
818
819
820
821
822
823
824
825
  	unregister_netdevice_notifier(&macvlan_notifier_block);
  }
  
  module_init(macvlan_init_module);
  module_exit(macvlan_cleanup_module);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
  MODULE_DESCRIPTION("Driver for MAC address based VLANs");
  MODULE_ALIAS_RTNL_LINK("macvlan");