diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/macvlan.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r-- | drivers/net/macvlan.c | 303 |
1 files changed, 223 insertions, 80 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 2490aa39804c..40faa368b07a 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/if_link.h> | 29 | #include <linux/if_link.h> |
30 | #include <linux/if_macvlan.h> | 30 | #include <linux/if_macvlan.h> |
31 | #include <net/rtnetlink.h> | 31 | #include <net/rtnetlink.h> |
32 | #include <net/xfrm.h> | ||
32 | 33 | ||
33 | #define MACVLAN_HASH_SIZE (1 << BITS_PER_BYTE) | 34 | #define MACVLAN_HASH_SIZE (1 << BITS_PER_BYTE) |
34 | 35 | ||
@@ -38,15 +39,6 @@ struct macvlan_port { | |||
38 | struct list_head vlans; | 39 | struct list_head vlans; |
39 | }; | 40 | }; |
40 | 41 | ||
41 | struct macvlan_dev { | ||
42 | struct net_device *dev; | ||
43 | struct list_head list; | ||
44 | struct hlist_node hlist; | ||
45 | struct macvlan_port *port; | ||
46 | struct net_device *lowerdev; | ||
47 | }; | ||
48 | |||
49 | |||
50 | static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port, | 42 | static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port, |
51 | const unsigned char *addr) | 43 | const unsigned char *addr) |
52 | { | 44 | { |
@@ -101,41 +93,53 @@ static int macvlan_addr_busy(const struct macvlan_port *port, | |||
101 | return 0; | 93 | return 0; |
102 | } | 94 | } |
103 | 95 | ||
96 | |||
97 | static int macvlan_broadcast_one(struct sk_buff *skb, | ||
98 | const struct macvlan_dev *vlan, | ||
99 | const struct ethhdr *eth, bool local) | ||
100 | { | ||
101 | struct net_device *dev = vlan->dev; | ||
102 | if (!skb) | ||
103 | return NET_RX_DROP; | ||
104 | |||
105 | if (local) | ||
106 | return vlan->forward(dev, skb); | ||
107 | |||
108 | skb->dev = dev; | ||
109 | if (!compare_ether_addr_64bits(eth->h_dest, | ||
110 | dev->broadcast)) | ||
111 | skb->pkt_type = PACKET_BROADCAST; | ||
112 | else | ||
113 | skb->pkt_type = PACKET_MULTICAST; | ||
114 | |||
115 | return vlan->receive(skb); | ||
116 | } | ||
117 | |||
104 | static void macvlan_broadcast(struct sk_buff *skb, | 118 | static void macvlan_broadcast(struct sk_buff *skb, |
105 | const struct macvlan_port *port) | 119 | const struct macvlan_port *port, |
120 | struct net_device *src, | ||
121 | enum macvlan_mode mode) | ||
106 | { | 122 | { |
107 | const struct ethhdr *eth = eth_hdr(skb); | 123 | const struct ethhdr *eth = eth_hdr(skb); |
108 | const struct macvlan_dev *vlan; | 124 | const struct macvlan_dev *vlan; |
109 | struct hlist_node *n; | 125 | struct hlist_node *n; |
110 | struct net_device *dev; | ||
111 | struct sk_buff *nskb; | 126 | struct sk_buff *nskb; |
112 | unsigned int i; | 127 | unsigned int i; |
128 | int err; | ||
113 | 129 | ||
114 | if (skb->protocol == htons(ETH_P_PAUSE)) | 130 | if (skb->protocol == htons(ETH_P_PAUSE)) |
115 | return; | 131 | return; |
116 | 132 | ||
117 | for (i = 0; i < MACVLAN_HASH_SIZE; i++) { | 133 | for (i = 0; i < MACVLAN_HASH_SIZE; i++) { |
118 | hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) { | 134 | hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) { |
119 | dev = vlan->dev; | 135 | if (vlan->dev == src || !(vlan->mode & mode)) |
120 | |||
121 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
122 | if (nskb == NULL) { | ||
123 | dev->stats.rx_errors++; | ||
124 | dev->stats.rx_dropped++; | ||
125 | continue; | 136 | continue; |
126 | } | ||
127 | |||
128 | dev->stats.rx_bytes += skb->len + ETH_HLEN; | ||
129 | dev->stats.rx_packets++; | ||
130 | dev->stats.multicast++; | ||
131 | 137 | ||
132 | nskb->dev = dev; | 138 | nskb = skb_clone(skb, GFP_ATOMIC); |
133 | if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast)) | 139 | err = macvlan_broadcast_one(nskb, vlan, eth, |
134 | nskb->pkt_type = PACKET_BROADCAST; | 140 | mode == MACVLAN_MODE_BRIDGE); |
135 | else | 141 | macvlan_count_rx(vlan, skb->len + ETH_HLEN, |
136 | nskb->pkt_type = PACKET_MULTICAST; | 142 | err == NET_RX_SUCCESS, 1); |
137 | |||
138 | netif_rx(nskb); | ||
139 | } | 143 | } |
140 | } | 144 | } |
141 | } | 145 | } |
@@ -146,14 +150,34 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) | |||
146 | const struct ethhdr *eth = eth_hdr(skb); | 150 | const struct ethhdr *eth = eth_hdr(skb); |
147 | const struct macvlan_port *port; | 151 | const struct macvlan_port *port; |
148 | const struct macvlan_dev *vlan; | 152 | const struct macvlan_dev *vlan; |
153 | const struct macvlan_dev *src; | ||
149 | struct net_device *dev; | 154 | struct net_device *dev; |
155 | unsigned int len; | ||
150 | 156 | ||
151 | port = rcu_dereference(skb->dev->macvlan_port); | 157 | port = rcu_dereference(skb->dev->macvlan_port); |
152 | if (port == NULL) | 158 | if (port == NULL) |
153 | return skb; | 159 | return skb; |
154 | 160 | ||
155 | if (is_multicast_ether_addr(eth->h_dest)) { | 161 | if (is_multicast_ether_addr(eth->h_dest)) { |
156 | macvlan_broadcast(skb, port); | 162 | src = macvlan_hash_lookup(port, eth->h_source); |
163 | if (!src) | ||
164 | /* frame comes from an external address */ | ||
165 | macvlan_broadcast(skb, port, NULL, | ||
166 | MACVLAN_MODE_PRIVATE | | ||
167 | MACVLAN_MODE_VEPA | | ||
168 | MACVLAN_MODE_BRIDGE); | ||
169 | else if (src->mode == MACVLAN_MODE_VEPA) | ||
170 | /* flood to everyone except source */ | ||
171 | macvlan_broadcast(skb, port, src->dev, | ||
172 | MACVLAN_MODE_VEPA | | ||
173 | MACVLAN_MODE_BRIDGE); | ||
174 | else if (src->mode == MACVLAN_MODE_BRIDGE) | ||
175 | /* | ||
176 | * flood only to VEPA ports, bridge ports | ||
177 | * already saw the frame on the way out. | ||
178 | */ | ||
179 | macvlan_broadcast(skb, port, src->dev, | ||
180 | MACVLAN_MODE_VEPA); | ||
157 | return skb; | 181 | return skb; |
158 | } | 182 | } |
159 | 183 | ||
@@ -166,44 +190,68 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) | |||
166 | kfree_skb(skb); | 190 | kfree_skb(skb); |
167 | return NULL; | 191 | return NULL; |
168 | } | 192 | } |
169 | 193 | len = skb->len + ETH_HLEN; | |
170 | skb = skb_share_check(skb, GFP_ATOMIC); | 194 | skb = skb_share_check(skb, GFP_ATOMIC); |
171 | if (skb == NULL) { | 195 | macvlan_count_rx(vlan, len, skb != NULL, 0); |
172 | dev->stats.rx_errors++; | 196 | if (!skb) |
173 | dev->stats.rx_dropped++; | ||
174 | return NULL; | 197 | return NULL; |
175 | } | ||
176 | |||
177 | dev->stats.rx_bytes += skb->len + ETH_HLEN; | ||
178 | dev->stats.rx_packets++; | ||
179 | 198 | ||
180 | skb->dev = dev; | 199 | skb->dev = dev; |
181 | skb->pkt_type = PACKET_HOST; | 200 | skb->pkt_type = PACKET_HOST; |
182 | 201 | ||
183 | netif_rx(skb); | 202 | vlan->receive(skb); |
184 | return NULL; | 203 | return NULL; |
185 | } | 204 | } |
186 | 205 | ||
187 | static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, | 206 | static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) |
188 | struct net_device *dev) | 207 | { |
208 | const struct macvlan_dev *vlan = netdev_priv(dev); | ||
209 | const struct macvlan_port *port = vlan->port; | ||
210 | const struct macvlan_dev *dest; | ||
211 | |||
212 | if (vlan->mode == MACVLAN_MODE_BRIDGE) { | ||
213 | const struct ethhdr *eth = (void *)skb->data; | ||
214 | |||
215 | /* send to other bridge ports directly */ | ||
216 | if (is_multicast_ether_addr(eth->h_dest)) { | ||
217 | macvlan_broadcast(skb, port, dev, MACVLAN_MODE_BRIDGE); | ||
218 | goto xmit_world; | ||
219 | } | ||
220 | |||
221 | dest = macvlan_hash_lookup(port, eth->h_dest); | ||
222 | if (dest && dest->mode == MACVLAN_MODE_BRIDGE) { | ||
223 | unsigned int length = skb->len + ETH_HLEN; | ||
224 | int ret = dest->forward(dest->dev, skb); | ||
225 | macvlan_count_rx(dest, length, | ||
226 | ret == NET_RX_SUCCESS, 0); | ||
227 | |||
228 | return NET_XMIT_SUCCESS; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | xmit_world: | ||
233 | skb_set_dev(skb, vlan->lowerdev); | ||
234 | return dev_queue_xmit(skb); | ||
235 | } | ||
236 | |||
237 | netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, | ||
238 | struct net_device *dev) | ||
189 | { | 239 | { |
190 | int i = skb_get_queue_mapping(skb); | 240 | int i = skb_get_queue_mapping(skb); |
191 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); | 241 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); |
192 | const struct macvlan_dev *vlan = netdev_priv(dev); | ||
193 | unsigned int len = skb->len; | 242 | unsigned int len = skb->len; |
194 | int ret; | 243 | int ret; |
195 | 244 | ||
196 | skb->dev = vlan->lowerdev; | 245 | ret = macvlan_queue_xmit(skb, dev); |
197 | ret = dev_queue_xmit(skb); | ||
198 | |||
199 | if (likely(ret == NET_XMIT_SUCCESS)) { | 246 | if (likely(ret == NET_XMIT_SUCCESS)) { |
200 | txq->tx_packets++; | 247 | txq->tx_packets++; |
201 | txq->tx_bytes += len; | 248 | txq->tx_bytes += len; |
202 | } else | 249 | } else |
203 | txq->tx_dropped++; | 250 | txq->tx_dropped++; |
204 | 251 | ||
205 | return NETDEV_TX_OK; | 252 | return ret; |
206 | } | 253 | } |
254 | EXPORT_SYMBOL_GPL(macvlan_start_xmit); | ||
207 | 255 | ||
208 | static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev, | 256 | static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev, |
209 | unsigned short type, const void *daddr, | 257 | unsigned short type, const void *daddr, |
@@ -332,7 +380,7 @@ static struct lock_class_key macvlan_netdev_addr_lock_key; | |||
332 | #define MACVLAN_FEATURES \ | 380 | #define MACVLAN_FEATURES \ |
333 | (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ | 381 | (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ |
334 | NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \ | 382 | NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \ |
335 | NETIF_F_TSO_ECN | NETIF_F_TSO6) | 383 | NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO) |
336 | 384 | ||
337 | #define MACVLAN_STATE_MASK \ | 385 | #define MACVLAN_STATE_MASK \ |
338 | ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT)) | 386 | ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT)) |
@@ -366,9 +414,47 @@ static int macvlan_init(struct net_device *dev) | |||
366 | 414 | ||
367 | macvlan_set_lockdep_class(dev); | 415 | macvlan_set_lockdep_class(dev); |
368 | 416 | ||
417 | vlan->rx_stats = alloc_percpu(struct macvlan_rx_stats); | ||
418 | if (!vlan->rx_stats) | ||
419 | return -ENOMEM; | ||
420 | |||
369 | return 0; | 421 | return 0; |
370 | } | 422 | } |
371 | 423 | ||
424 | static void macvlan_uninit(struct net_device *dev) | ||
425 | { | ||
426 | struct macvlan_dev *vlan = netdev_priv(dev); | ||
427 | |||
428 | free_percpu(vlan->rx_stats); | ||
429 | } | ||
430 | |||
431 | static struct net_device_stats *macvlan_dev_get_stats(struct net_device *dev) | ||
432 | { | ||
433 | struct net_device_stats *stats = &dev->stats; | ||
434 | struct macvlan_dev *vlan = netdev_priv(dev); | ||
435 | |||
436 | dev_txq_stats_fold(dev, stats); | ||
437 | |||
438 | if (vlan->rx_stats) { | ||
439 | struct macvlan_rx_stats *p, rx = {0}; | ||
440 | int i; | ||
441 | |||
442 | for_each_possible_cpu(i) { | ||
443 | p = per_cpu_ptr(vlan->rx_stats, i); | ||
444 | rx.rx_packets += p->rx_packets; | ||
445 | rx.rx_bytes += p->rx_bytes; | ||
446 | rx.rx_errors += p->rx_errors; | ||
447 | rx.multicast += p->multicast; | ||
448 | } | ||
449 | stats->rx_packets = rx.rx_packets; | ||
450 | stats->rx_bytes = rx.rx_bytes; | ||
451 | stats->rx_errors = rx.rx_errors; | ||
452 | stats->rx_dropped = rx.rx_errors; | ||
453 | stats->multicast = rx.multicast; | ||
454 | } | ||
455 | return stats; | ||
456 | } | ||
457 | |||
372 | static void macvlan_ethtool_get_drvinfo(struct net_device *dev, | 458 | static void macvlan_ethtool_get_drvinfo(struct net_device *dev, |
373 | struct ethtool_drvinfo *drvinfo) | 459 | struct ethtool_drvinfo *drvinfo) |
374 | { | 460 | { |
@@ -405,6 +491,7 @@ static const struct ethtool_ops macvlan_ethtool_ops = { | |||
405 | 491 | ||
406 | static const struct net_device_ops macvlan_netdev_ops = { | 492 | static const struct net_device_ops macvlan_netdev_ops = { |
407 | .ndo_init = macvlan_init, | 493 | .ndo_init = macvlan_init, |
494 | .ndo_uninit = macvlan_uninit, | ||
408 | .ndo_open = macvlan_open, | 495 | .ndo_open = macvlan_open, |
409 | .ndo_stop = macvlan_stop, | 496 | .ndo_stop = macvlan_stop, |
410 | .ndo_start_xmit = macvlan_start_xmit, | 497 | .ndo_start_xmit = macvlan_start_xmit, |
@@ -412,6 +499,7 @@ static const struct net_device_ops macvlan_netdev_ops = { | |||
412 | .ndo_change_rx_flags = macvlan_change_rx_flags, | 499 | .ndo_change_rx_flags = macvlan_change_rx_flags, |
413 | .ndo_set_mac_address = macvlan_set_mac_address, | 500 | .ndo_set_mac_address = macvlan_set_mac_address, |
414 | .ndo_set_multicast_list = macvlan_set_multicast_list, | 501 | .ndo_set_multicast_list = macvlan_set_multicast_list, |
502 | .ndo_get_stats = macvlan_dev_get_stats, | ||
415 | .ndo_validate_addr = eth_validate_addr, | 503 | .ndo_validate_addr = eth_validate_addr, |
416 | }; | 504 | }; |
417 | 505 | ||
@@ -456,25 +544,6 @@ static void macvlan_port_destroy(struct net_device *dev) | |||
456 | kfree(port); | 544 | kfree(port); |
457 | } | 545 | } |
458 | 546 | ||
459 | static void macvlan_transfer_operstate(struct net_device *dev) | ||
460 | { | ||
461 | struct macvlan_dev *vlan = netdev_priv(dev); | ||
462 | const struct net_device *lowerdev = vlan->lowerdev; | ||
463 | |||
464 | if (lowerdev->operstate == IF_OPER_DORMANT) | ||
465 | netif_dormant_on(dev); | ||
466 | else | ||
467 | netif_dormant_off(dev); | ||
468 | |||
469 | if (netif_carrier_ok(lowerdev)) { | ||
470 | if (!netif_carrier_ok(dev)) | ||
471 | netif_carrier_on(dev); | ||
472 | } else { | ||
473 | if (netif_carrier_ok(dev)) | ||
474 | netif_carrier_off(dev); | ||
475 | } | ||
476 | } | ||
477 | |||
478 | static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) | 547 | static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) |
479 | { | 548 | { |
480 | if (tb[IFLA_ADDRESS]) { | 549 | if (tb[IFLA_ADDRESS]) { |
@@ -483,6 +552,17 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
483 | if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) | 552 | if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) |
484 | return -EADDRNOTAVAIL; | 553 | return -EADDRNOTAVAIL; |
485 | } | 554 | } |
555 | |||
556 | if (data && data[IFLA_MACVLAN_MODE]) { | ||
557 | switch (nla_get_u32(data[IFLA_MACVLAN_MODE])) { | ||
558 | case MACVLAN_MODE_PRIVATE: | ||
559 | case MACVLAN_MODE_VEPA: | ||
560 | case MACVLAN_MODE_BRIDGE: | ||
561 | break; | ||
562 | default: | ||
563 | return -EINVAL; | ||
564 | } | ||
565 | } | ||
486 | return 0; | 566 | return 0; |
487 | } | 567 | } |
488 | 568 | ||
@@ -505,8 +585,11 @@ static int macvlan_get_tx_queues(struct net *net, | |||
505 | return 0; | 585 | return 0; |
506 | } | 586 | } |
507 | 587 | ||
508 | static int macvlan_newlink(struct net_device *dev, | 588 | int macvlan_common_newlink(struct net *src_net, struct net_device *dev, |
509 | struct nlattr *tb[], struct nlattr *data[]) | 589 | struct nlattr *tb[], struct nlattr *data[], |
590 | int (*receive)(struct sk_buff *skb), | ||
591 | int (*forward)(struct net_device *dev, | ||
592 | struct sk_buff *skb)) | ||
510 | { | 593 | { |
511 | struct macvlan_dev *vlan = netdev_priv(dev); | 594 | struct macvlan_dev *vlan = netdev_priv(dev); |
512 | struct macvlan_port *port; | 595 | struct macvlan_port *port; |
@@ -516,7 +599,7 @@ static int macvlan_newlink(struct net_device *dev, | |||
516 | if (!tb[IFLA_LINK]) | 599 | if (!tb[IFLA_LINK]) |
517 | return -EINVAL; | 600 | return -EINVAL; |
518 | 601 | ||
519 | lowerdev = __dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK])); | 602 | lowerdev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); |
520 | if (lowerdev == NULL) | 603 | if (lowerdev == NULL) |
521 | return -ENODEV; | 604 | return -ENODEV; |
522 | 605 | ||
@@ -546,34 +629,93 @@ static int macvlan_newlink(struct net_device *dev, | |||
546 | vlan->lowerdev = lowerdev; | 629 | vlan->lowerdev = lowerdev; |
547 | vlan->dev = dev; | 630 | vlan->dev = dev; |
548 | vlan->port = port; | 631 | vlan->port = port; |
632 | vlan->receive = receive; | ||
633 | vlan->forward = forward; | ||
634 | |||
635 | vlan->mode = MACVLAN_MODE_VEPA; | ||
636 | if (data && data[IFLA_MACVLAN_MODE]) | ||
637 | vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); | ||
549 | 638 | ||
550 | err = register_netdevice(dev); | 639 | err = register_netdevice(dev); |
551 | if (err < 0) | 640 | if (err < 0) |
552 | return err; | 641 | return err; |
553 | 642 | ||
554 | list_add_tail(&vlan->list, &port->vlans); | 643 | list_add_tail(&vlan->list, &port->vlans); |
555 | macvlan_transfer_operstate(dev); | 644 | netif_stacked_transfer_operstate(lowerdev, dev); |
556 | return 0; | 645 | return 0; |
557 | } | 646 | } |
647 | EXPORT_SYMBOL_GPL(macvlan_common_newlink); | ||
558 | 648 | ||
559 | static void macvlan_dellink(struct net_device *dev) | 649 | static int macvlan_newlink(struct net *src_net, struct net_device *dev, |
650 | struct nlattr *tb[], struct nlattr *data[]) | ||
651 | { | ||
652 | return macvlan_common_newlink(src_net, dev, tb, data, | ||
653 | netif_rx, | ||
654 | dev_forward_skb); | ||
655 | } | ||
656 | |||
657 | void macvlan_dellink(struct net_device *dev, struct list_head *head) | ||
560 | { | 658 | { |
561 | struct macvlan_dev *vlan = netdev_priv(dev); | 659 | struct macvlan_dev *vlan = netdev_priv(dev); |
562 | struct macvlan_port *port = vlan->port; | 660 | struct macvlan_port *port = vlan->port; |
563 | 661 | ||
564 | list_del(&vlan->list); | 662 | list_del(&vlan->list); |
565 | unregister_netdevice(dev); | 663 | unregister_netdevice_queue(dev, head); |
566 | 664 | ||
567 | if (list_empty(&port->vlans)) | 665 | if (list_empty(&port->vlans)) |
568 | macvlan_port_destroy(port->dev); | 666 | macvlan_port_destroy(port->dev); |
569 | } | 667 | } |
668 | EXPORT_SYMBOL_GPL(macvlan_dellink); | ||
669 | |||
670 | static int macvlan_changelink(struct net_device *dev, | ||
671 | struct nlattr *tb[], struct nlattr *data[]) | ||
672 | { | ||
673 | struct macvlan_dev *vlan = netdev_priv(dev); | ||
674 | if (data && data[IFLA_MACVLAN_MODE]) | ||
675 | vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static size_t macvlan_get_size(const struct net_device *dev) | ||
680 | { | ||
681 | return nla_total_size(4); | ||
682 | } | ||
683 | |||
684 | static int macvlan_fill_info(struct sk_buff *skb, | ||
685 | const struct net_device *dev) | ||
686 | { | ||
687 | struct macvlan_dev *vlan = netdev_priv(dev); | ||
688 | |||
689 | NLA_PUT_U32(skb, IFLA_MACVLAN_MODE, vlan->mode); | ||
690 | return 0; | ||
691 | |||
692 | nla_put_failure: | ||
693 | return -EMSGSIZE; | ||
694 | } | ||
695 | |||
696 | static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { | ||
697 | [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, | ||
698 | }; | ||
699 | |||
700 | int macvlan_link_register(struct rtnl_link_ops *ops) | ||
701 | { | ||
702 | /* common fields */ | ||
703 | ops->priv_size = sizeof(struct macvlan_dev); | ||
704 | ops->get_tx_queues = macvlan_get_tx_queues; | ||
705 | ops->setup = macvlan_setup; | ||
706 | ops->validate = macvlan_validate; | ||
707 | ops->maxtype = IFLA_MACVLAN_MAX; | ||
708 | ops->policy = macvlan_policy; | ||
709 | ops->changelink = macvlan_changelink; | ||
710 | ops->get_size = macvlan_get_size; | ||
711 | ops->fill_info = macvlan_fill_info; | ||
712 | |||
713 | return rtnl_link_register(ops); | ||
714 | }; | ||
715 | EXPORT_SYMBOL_GPL(macvlan_link_register); | ||
570 | 716 | ||
571 | static struct rtnl_link_ops macvlan_link_ops __read_mostly = { | 717 | static struct rtnl_link_ops macvlan_link_ops = { |
572 | .kind = "macvlan", | 718 | .kind = "macvlan", |
573 | .priv_size = sizeof(struct macvlan_dev), | ||
574 | .get_tx_queues = macvlan_get_tx_queues, | ||
575 | .setup = macvlan_setup, | ||
576 | .validate = macvlan_validate, | ||
577 | .newlink = macvlan_newlink, | 719 | .newlink = macvlan_newlink, |
578 | .dellink = macvlan_dellink, | 720 | .dellink = macvlan_dellink, |
579 | }; | 721 | }; |
@@ -592,7 +734,8 @@ static int macvlan_device_event(struct notifier_block *unused, | |||
592 | switch (event) { | 734 | switch (event) { |
593 | case NETDEV_CHANGE: | 735 | case NETDEV_CHANGE: |
594 | list_for_each_entry(vlan, &port->vlans, list) | 736 | list_for_each_entry(vlan, &port->vlans, list) |
595 | macvlan_transfer_operstate(vlan->dev); | 737 | netif_stacked_transfer_operstate(vlan->lowerdev, |
738 | vlan->dev); | ||
596 | break; | 739 | break; |
597 | case NETDEV_FEAT_CHANGE: | 740 | case NETDEV_FEAT_CHANGE: |
598 | list_for_each_entry(vlan, &port->vlans, list) { | 741 | list_for_each_entry(vlan, &port->vlans, list) { |
@@ -603,7 +746,7 @@ static int macvlan_device_event(struct notifier_block *unused, | |||
603 | break; | 746 | break; |
604 | case NETDEV_UNREGISTER: | 747 | case NETDEV_UNREGISTER: |
605 | list_for_each_entry_safe(vlan, next, &port->vlans, list) | 748 | list_for_each_entry_safe(vlan, next, &port->vlans, list) |
606 | macvlan_dellink(vlan->dev); | 749 | vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL); |
607 | break; | 750 | break; |
608 | } | 751 | } |
609 | return NOTIFY_DONE; | 752 | return NOTIFY_DONE; |
@@ -620,7 +763,7 @@ static int __init macvlan_init_module(void) | |||
620 | register_netdevice_notifier(&macvlan_notifier_block); | 763 | register_netdevice_notifier(&macvlan_notifier_block); |
621 | macvlan_handle_frame_hook = macvlan_handle_frame; | 764 | macvlan_handle_frame_hook = macvlan_handle_frame; |
622 | 765 | ||
623 | err = rtnl_link_register(&macvlan_link_ops); | 766 | err = macvlan_link_register(&macvlan_link_ops); |
624 | if (err < 0) | 767 | if (err < 0) |
625 | goto err1; | 768 | goto err1; |
626 | return 0; | 769 | return 0; |