diff options
Diffstat (limited to 'net/8021q')
-rw-r--r-- | net/8021q/vlan.c | 90 | ||||
-rw-r--r-- | net/8021q/vlan.h | 21 | ||||
-rw-r--r-- | net/8021q/vlan_core.c | 37 | ||||
-rw-r--r-- | net/8021q/vlan_dev.c | 72 | ||||
-rw-r--r-- | net/8021q/vlan_netlink.c | 7 | ||||
-rw-r--r-- | net/8021q/vlanproc.c | 13 |
6 files changed, 140 insertions, 100 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index a29c5ab5815c..33f90e7362cc 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -41,7 +41,7 @@ | |||
41 | 41 | ||
42 | /* Global VLAN variables */ | 42 | /* Global VLAN variables */ |
43 | 43 | ||
44 | int vlan_net_id; | 44 | int vlan_net_id __read_mostly; |
45 | 45 | ||
46 | /* Our listing of VLAN group(s) */ | 46 | /* Our listing of VLAN group(s) */ |
47 | static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE]; | 47 | static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE]; |
@@ -140,7 +140,7 @@ static void vlan_rcu_free(struct rcu_head *rcu) | |||
140 | vlan_group_free(container_of(rcu, struct vlan_group, rcu)); | 140 | vlan_group_free(container_of(rcu, struct vlan_group, rcu)); |
141 | } | 141 | } |
142 | 142 | ||
143 | void unregister_vlan_dev(struct net_device *dev) | 143 | void unregister_vlan_dev(struct net_device *dev, struct list_head *head) |
144 | { | 144 | { |
145 | struct vlan_dev_info *vlan = vlan_dev_info(dev); | 145 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
146 | struct net_device *real_dev = vlan->real_dev; | 146 | struct net_device *real_dev = vlan->real_dev; |
@@ -159,12 +159,13 @@ void unregister_vlan_dev(struct net_device *dev) | |||
159 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) | 159 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) |
160 | ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id); | 160 | ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id); |
161 | 161 | ||
162 | vlan_group_set_device(grp, vlan_id, NULL); | ||
163 | grp->nr_vlans--; | 162 | grp->nr_vlans--; |
164 | 163 | ||
165 | synchronize_net(); | 164 | vlan_group_set_device(grp, vlan_id, NULL); |
165 | if (!grp->killall) | ||
166 | synchronize_net(); | ||
166 | 167 | ||
167 | unregister_netdevice(dev); | 168 | unregister_netdevice_queue(dev, head); |
168 | 169 | ||
169 | /* If the group is now empty, kill off the group. */ | 170 | /* If the group is now empty, kill off the group. */ |
170 | if (grp->nr_vlans == 0) { | 171 | if (grp->nr_vlans == 0) { |
@@ -183,27 +184,6 @@ void unregister_vlan_dev(struct net_device *dev) | |||
183 | dev_put(real_dev); | 184 | dev_put(real_dev); |
184 | } | 185 | } |
185 | 186 | ||
186 | static void vlan_transfer_operstate(const struct net_device *dev, | ||
187 | struct net_device *vlandev) | ||
188 | { | ||
189 | /* Have to respect userspace enforced dormant state | ||
190 | * of real device, also must allow supplicant running | ||
191 | * on VLAN device | ||
192 | */ | ||
193 | if (dev->operstate == IF_OPER_DORMANT) | ||
194 | netif_dormant_on(vlandev); | ||
195 | else | ||
196 | netif_dormant_off(vlandev); | ||
197 | |||
198 | if (netif_carrier_ok(dev)) { | ||
199 | if (!netif_carrier_ok(vlandev)) | ||
200 | netif_carrier_on(vlandev); | ||
201 | } else { | ||
202 | if (netif_carrier_ok(vlandev)) | ||
203 | netif_carrier_off(vlandev); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) | 187 | int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) |
208 | { | 188 | { |
209 | const char *name = real_dev->name; | 189 | const char *name = real_dev->name; |
@@ -261,7 +241,7 @@ int register_vlan_dev(struct net_device *dev) | |||
261 | /* Account for reference in struct vlan_dev_info */ | 241 | /* Account for reference in struct vlan_dev_info */ |
262 | dev_hold(real_dev); | 242 | dev_hold(real_dev); |
263 | 243 | ||
264 | vlan_transfer_operstate(real_dev, dev); | 244 | netif_stacked_transfer_operstate(real_dev, dev); |
265 | linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */ | 245 | linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */ |
266 | 246 | ||
267 | /* So, got the sucker initialized, now lets place | 247 | /* So, got the sucker initialized, now lets place |
@@ -430,6 +410,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
430 | struct vlan_group *grp; | 410 | struct vlan_group *grp; |
431 | int i, flgs; | 411 | int i, flgs; |
432 | struct net_device *vlandev; | 412 | struct net_device *vlandev; |
413 | struct vlan_dev_info *vlan; | ||
414 | LIST_HEAD(list); | ||
433 | 415 | ||
434 | if (is_vlan_dev(dev)) | 416 | if (is_vlan_dev(dev)) |
435 | __vlan_device_event(dev, event); | 417 | __vlan_device_event(dev, event); |
@@ -450,7 +432,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
450 | if (!vlandev) | 432 | if (!vlandev) |
451 | continue; | 433 | continue; |
452 | 434 | ||
453 | vlan_transfer_operstate(dev, vlandev); | 435 | netif_stacked_transfer_operstate(dev, vlandev); |
454 | } | 436 | } |
455 | break; | 437 | break; |
456 | 438 | ||
@@ -505,8 +487,10 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
505 | if (!(flgs & IFF_UP)) | 487 | if (!(flgs & IFF_UP)) |
506 | continue; | 488 | continue; |
507 | 489 | ||
508 | dev_change_flags(vlandev, flgs & ~IFF_UP); | 490 | vlan = vlan_dev_info(vlandev); |
509 | vlan_transfer_operstate(dev, vlandev); | 491 | if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) |
492 | dev_change_flags(vlandev, flgs & ~IFF_UP); | ||
493 | netif_stacked_transfer_operstate(dev, vlandev); | ||
510 | } | 494 | } |
511 | break; | 495 | break; |
512 | 496 | ||
@@ -521,13 +505,17 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
521 | if (flgs & IFF_UP) | 505 | if (flgs & IFF_UP) |
522 | continue; | 506 | continue; |
523 | 507 | ||
524 | dev_change_flags(vlandev, flgs | IFF_UP); | 508 | vlan = vlan_dev_info(vlandev); |
525 | vlan_transfer_operstate(dev, vlandev); | 509 | if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) |
510 | dev_change_flags(vlandev, flgs | IFF_UP); | ||
511 | netif_stacked_transfer_operstate(dev, vlandev); | ||
526 | } | 512 | } |
527 | break; | 513 | break; |
528 | 514 | ||
529 | case NETDEV_UNREGISTER: | 515 | case NETDEV_UNREGISTER: |
530 | /* Delete all VLANs for this dev. */ | 516 | /* Delete all VLANs for this dev. */ |
517 | grp->killall = 1; | ||
518 | |||
531 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 519 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { |
532 | vlandev = vlan_group_get_device(grp, i); | 520 | vlandev = vlan_group_get_device(grp, i); |
533 | if (!vlandev) | 521 | if (!vlandev) |
@@ -538,8 +526,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
538 | if (grp->nr_vlans == 1) | 526 | if (grp->nr_vlans == 1) |
539 | i = VLAN_GROUP_ARRAY_LEN; | 527 | i = VLAN_GROUP_ARRAY_LEN; |
540 | 528 | ||
541 | unregister_vlan_dev(vlandev); | 529 | unregister_vlan_dev(vlandev, &list); |
542 | } | 530 | } |
531 | unregister_netdevice_many(&list); | ||
543 | break; | 532 | break; |
544 | } | 533 | } |
545 | 534 | ||
@@ -645,7 +634,7 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg) | |||
645 | err = -EPERM; | 634 | err = -EPERM; |
646 | if (!capable(CAP_NET_ADMIN)) | 635 | if (!capable(CAP_NET_ADMIN)) |
647 | break; | 636 | break; |
648 | unregister_vlan_dev(dev); | 637 | unregister_vlan_dev(dev, NULL); |
649 | err = 0; | 638 | err = 0; |
650 | break; | 639 | break; |
651 | 640 | ||
@@ -676,47 +665,26 @@ out: | |||
676 | 665 | ||
677 | static int vlan_init_net(struct net *net) | 666 | static int vlan_init_net(struct net *net) |
678 | { | 667 | { |
668 | struct vlan_net *vn = net_generic(net, vlan_net_id); | ||
679 | int err; | 669 | int err; |
680 | struct vlan_net *vn; | ||
681 | |||
682 | err = -ENOMEM; | ||
683 | vn = kzalloc(sizeof(struct vlan_net), GFP_KERNEL); | ||
684 | if (vn == NULL) | ||
685 | goto err_alloc; | ||
686 | |||
687 | err = net_assign_generic(net, vlan_net_id, vn); | ||
688 | if (err < 0) | ||
689 | goto err_assign; | ||
690 | 670 | ||
691 | vn->name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD; | 671 | vn->name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD; |
692 | 672 | ||
693 | err = vlan_proc_init(net); | 673 | err = vlan_proc_init(net); |
694 | if (err < 0) | ||
695 | goto err_proc; | ||
696 | |||
697 | return 0; | ||
698 | 674 | ||
699 | err_proc: | ||
700 | /* nothing */ | ||
701 | err_assign: | ||
702 | kfree(vn); | ||
703 | err_alloc: | ||
704 | return err; | 675 | return err; |
705 | } | 676 | } |
706 | 677 | ||
707 | static void vlan_exit_net(struct net *net) | 678 | static void vlan_exit_net(struct net *net) |
708 | { | 679 | { |
709 | struct vlan_net *vn; | ||
710 | |||
711 | vn = net_generic(net, vlan_net_id); | ||
712 | rtnl_kill_links(net, &vlan_link_ops); | ||
713 | vlan_proc_cleanup(net); | 680 | vlan_proc_cleanup(net); |
714 | kfree(vn); | ||
715 | } | 681 | } |
716 | 682 | ||
717 | static struct pernet_operations vlan_net_ops = { | 683 | static struct pernet_operations vlan_net_ops = { |
718 | .init = vlan_init_net, | 684 | .init = vlan_init_net, |
719 | .exit = vlan_exit_net, | 685 | .exit = vlan_exit_net, |
686 | .id = &vlan_net_id, | ||
687 | .size = sizeof(struct vlan_net), | ||
720 | }; | 688 | }; |
721 | 689 | ||
722 | static int __init vlan_proto_init(void) | 690 | static int __init vlan_proto_init(void) |
@@ -726,7 +694,7 @@ static int __init vlan_proto_init(void) | |||
726 | pr_info("%s v%s %s\n", vlan_fullname, vlan_version, vlan_copyright); | 694 | pr_info("%s v%s %s\n", vlan_fullname, vlan_version, vlan_copyright); |
727 | pr_info("All bugs added by %s\n", vlan_buggyright); | 695 | pr_info("All bugs added by %s\n", vlan_buggyright); |
728 | 696 | ||
729 | err = register_pernet_gen_device(&vlan_net_id, &vlan_net_ops); | 697 | err = register_pernet_subsys(&vlan_net_ops); |
730 | if (err < 0) | 698 | if (err < 0) |
731 | goto err0; | 699 | goto err0; |
732 | 700 | ||
@@ -751,7 +719,7 @@ err4: | |||
751 | err3: | 719 | err3: |
752 | unregister_netdevice_notifier(&vlan_notifier_block); | 720 | unregister_netdevice_notifier(&vlan_notifier_block); |
753 | err2: | 721 | err2: |
754 | unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); | 722 | unregister_pernet_subsys(&vlan_net_ops); |
755 | err0: | 723 | err0: |
756 | return err; | 724 | return err; |
757 | } | 725 | } |
@@ -771,7 +739,7 @@ static void __exit vlan_cleanup_module(void) | |||
771 | for (i = 0; i < VLAN_GRP_HASH_SIZE; i++) | 739 | for (i = 0; i < VLAN_GRP_HASH_SIZE; i++) |
772 | BUG_ON(!hlist_empty(&vlan_group_hash[i])); | 740 | BUG_ON(!hlist_empty(&vlan_group_hash[i])); |
773 | 741 | ||
774 | unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); | 742 | unregister_pernet_subsys(&vlan_net_ops); |
775 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | 743 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
776 | 744 | ||
777 | vlan_gvrp_uninit(); | 745 | vlan_gvrp_uninit(); |
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 82570bc2a180..5685296017e9 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h | |||
@@ -16,6 +16,21 @@ struct vlan_priority_tci_mapping { | |||
16 | struct vlan_priority_tci_mapping *next; | 16 | struct vlan_priority_tci_mapping *next; |
17 | }; | 17 | }; |
18 | 18 | ||
19 | |||
20 | /** | ||
21 | * struct vlan_rx_stats - VLAN percpu rx stats | ||
22 | * @rx_packets: number of received packets | ||
23 | * @rx_bytes: number of received bytes | ||
24 | * @multicast: number of received multicast packets | ||
25 | * @rx_errors: number of errors | ||
26 | */ | ||
27 | struct vlan_rx_stats { | ||
28 | unsigned long rx_packets; | ||
29 | unsigned long rx_bytes; | ||
30 | unsigned long multicast; | ||
31 | unsigned long rx_errors; | ||
32 | }; | ||
33 | |||
19 | /** | 34 | /** |
20 | * struct vlan_dev_info - VLAN private device data | 35 | * struct vlan_dev_info - VLAN private device data |
21 | * @nr_ingress_mappings: number of ingress priority mappings | 36 | * @nr_ingress_mappings: number of ingress priority mappings |
@@ -29,6 +44,7 @@ struct vlan_priority_tci_mapping { | |||
29 | * @dent: proc dir entry | 44 | * @dent: proc dir entry |
30 | * @cnt_inc_headroom_on_tx: statistic - number of skb expansions on TX | 45 | * @cnt_inc_headroom_on_tx: statistic - number of skb expansions on TX |
31 | * @cnt_encap_on_xmit: statistic - number of skb encapsulations on TX | 46 | * @cnt_encap_on_xmit: statistic - number of skb encapsulations on TX |
47 | * @vlan_rx_stats: ptr to percpu rx stats | ||
32 | */ | 48 | */ |
33 | struct vlan_dev_info { | 49 | struct vlan_dev_info { |
34 | unsigned int nr_ingress_mappings; | 50 | unsigned int nr_ingress_mappings; |
@@ -45,6 +61,7 @@ struct vlan_dev_info { | |||
45 | struct proc_dir_entry *dent; | 61 | struct proc_dir_entry *dent; |
46 | unsigned long cnt_inc_headroom_on_tx; | 62 | unsigned long cnt_inc_headroom_on_tx; |
47 | unsigned long cnt_encap_on_xmit; | 63 | unsigned long cnt_encap_on_xmit; |
64 | struct vlan_rx_stats *vlan_rx_stats; | ||
48 | }; | 65 | }; |
49 | 66 | ||
50 | static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev) | 67 | static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev) |
@@ -82,14 +99,14 @@ void vlan_dev_get_realdev_name(const struct net_device *dev, char *result); | |||
82 | int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id); | 99 | int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id); |
83 | void vlan_setup(struct net_device *dev); | 100 | void vlan_setup(struct net_device *dev); |
84 | int register_vlan_dev(struct net_device *dev); | 101 | int register_vlan_dev(struct net_device *dev); |
85 | void unregister_vlan_dev(struct net_device *dev); | 102 | void unregister_vlan_dev(struct net_device *dev, struct list_head *head); |
86 | 103 | ||
87 | static inline u32 vlan_get_ingress_priority(struct net_device *dev, | 104 | static inline u32 vlan_get_ingress_priority(struct net_device *dev, |
88 | u16 vlan_tci) | 105 | u16 vlan_tci) |
89 | { | 106 | { |
90 | struct vlan_dev_info *vip = vlan_dev_info(dev); | 107 | struct vlan_dev_info *vip = vlan_dev_info(dev); |
91 | 108 | ||
92 | return vip->ingress_priority_map[(vlan_tci >> 13) & 0x7]; | 109 | return vip->ingress_priority_map[(vlan_tci >> VLAN_PRIO_SHIFT) & 0x7]; |
93 | } | 110 | } |
94 | 111 | ||
95 | #ifdef CONFIG_VLAN_8021Q_GVRP | 112 | #ifdef CONFIG_VLAN_8021Q_GVRP |
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 7f7de1a04de6..e75a2f3b10af 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c | |||
@@ -14,7 +14,7 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, | |||
14 | if (skb_bond_should_drop(skb)) | 14 | if (skb_bond_should_drop(skb)) |
15 | goto drop; | 15 | goto drop; |
16 | 16 | ||
17 | skb->vlan_tci = vlan_tci; | 17 | __vlan_hwaccel_put_tag(skb, vlan_tci); |
18 | skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); | 18 | skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); |
19 | 19 | ||
20 | if (!skb->dev) | 20 | if (!skb->dev) |
@@ -31,7 +31,7 @@ EXPORT_SYMBOL(__vlan_hwaccel_rx); | |||
31 | int vlan_hwaccel_do_receive(struct sk_buff *skb) | 31 | int vlan_hwaccel_do_receive(struct sk_buff *skb) |
32 | { | 32 | { |
33 | struct net_device *dev = skb->dev; | 33 | struct net_device *dev = skb->dev; |
34 | struct net_device_stats *stats; | 34 | struct vlan_rx_stats *rx_stats; |
35 | 35 | ||
36 | skb->dev = vlan_dev_info(dev)->real_dev; | 36 | skb->dev = vlan_dev_info(dev)->real_dev; |
37 | netif_nit_deliver(skb); | 37 | netif_nit_deliver(skb); |
@@ -40,15 +40,17 @@ int vlan_hwaccel_do_receive(struct sk_buff *skb) | |||
40 | skb->priority = vlan_get_ingress_priority(dev, skb->vlan_tci); | 40 | skb->priority = vlan_get_ingress_priority(dev, skb->vlan_tci); |
41 | skb->vlan_tci = 0; | 41 | skb->vlan_tci = 0; |
42 | 42 | ||
43 | stats = &dev->stats; | 43 | rx_stats = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, |
44 | stats->rx_packets++; | 44 | smp_processor_id()); |
45 | stats->rx_bytes += skb->len; | 45 | |
46 | rx_stats->rx_packets++; | ||
47 | rx_stats->rx_bytes += skb->len; | ||
46 | 48 | ||
47 | switch (skb->pkt_type) { | 49 | switch (skb->pkt_type) { |
48 | case PACKET_BROADCAST: | 50 | case PACKET_BROADCAST: |
49 | break; | 51 | break; |
50 | case PACKET_MULTICAST: | 52 | case PACKET_MULTICAST: |
51 | stats->multicast++; | 53 | rx_stats->multicast++; |
52 | break; | 54 | break; |
53 | case PACKET_OTHERHOST: | 55 | case PACKET_OTHERHOST: |
54 | /* Our lower layer thinks this is not local, let's make sure. | 56 | /* Our lower layer thinks this is not local, let's make sure. |
@@ -74,15 +76,16 @@ u16 vlan_dev_vlan_id(const struct net_device *dev) | |||
74 | } | 76 | } |
75 | EXPORT_SYMBOL(vlan_dev_vlan_id); | 77 | EXPORT_SYMBOL(vlan_dev_vlan_id); |
76 | 78 | ||
77 | static int vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, | 79 | static gro_result_t |
78 | unsigned int vlan_tci, struct sk_buff *skb) | 80 | vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, |
81 | unsigned int vlan_tci, struct sk_buff *skb) | ||
79 | { | 82 | { |
80 | struct sk_buff *p; | 83 | struct sk_buff *p; |
81 | 84 | ||
82 | if (skb_bond_should_drop(skb)) | 85 | if (skb_bond_should_drop(skb)) |
83 | goto drop; | 86 | goto drop; |
84 | 87 | ||
85 | skb->vlan_tci = vlan_tci; | 88 | __vlan_hwaccel_put_tag(skb, vlan_tci); |
86 | skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); | 89 | skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK); |
87 | 90 | ||
88 | if (!skb->dev) | 91 | if (!skb->dev) |
@@ -101,11 +104,12 @@ drop: | |||
101 | return GRO_DROP; | 104 | return GRO_DROP; |
102 | } | 105 | } |
103 | 106 | ||
104 | int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, | 107 | gro_result_t vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, |
105 | unsigned int vlan_tci, struct sk_buff *skb) | 108 | unsigned int vlan_tci, struct sk_buff *skb) |
106 | { | 109 | { |
107 | if (netpoll_rx_on(skb)) | 110 | if (netpoll_rx_on(skb)) |
108 | return vlan_hwaccel_receive_skb(skb, grp, vlan_tci); | 111 | return vlan_hwaccel_receive_skb(skb, grp, vlan_tci) |
112 | ? GRO_DROP : GRO_NORMAL; | ||
109 | 113 | ||
110 | skb_gro_reset_offset(skb); | 114 | skb_gro_reset_offset(skb); |
111 | 115 | ||
@@ -113,17 +117,18 @@ int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, | |||
113 | } | 117 | } |
114 | EXPORT_SYMBOL(vlan_gro_receive); | 118 | EXPORT_SYMBOL(vlan_gro_receive); |
115 | 119 | ||
116 | int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, | 120 | gro_result_t vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, |
117 | unsigned int vlan_tci) | 121 | unsigned int vlan_tci) |
118 | { | 122 | { |
119 | struct sk_buff *skb = napi_frags_skb(napi); | 123 | struct sk_buff *skb = napi_frags_skb(napi); |
120 | 124 | ||
121 | if (!skb) | 125 | if (!skb) |
122 | return NET_RX_DROP; | 126 | return GRO_DROP; |
123 | 127 | ||
124 | if (netpoll_rx_on(skb)) { | 128 | if (netpoll_rx_on(skb)) { |
125 | skb->protocol = eth_type_trans(skb, skb->dev); | 129 | skb->protocol = eth_type_trans(skb, skb->dev); |
126 | return vlan_hwaccel_receive_skb(skb, grp, vlan_tci); | 130 | return vlan_hwaccel_receive_skb(skb, grp, vlan_tci) |
131 | ? GRO_DROP : GRO_NORMAL; | ||
127 | } | 132 | } |
128 | 133 | ||
129 | return napi_frags_finish(napi, skb, | 134 | return napi_frags_finish(napi, skb, |
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 4198ec5c8abc..b7889782047e 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -140,7 +140,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
140 | struct packet_type *ptype, struct net_device *orig_dev) | 140 | struct packet_type *ptype, struct net_device *orig_dev) |
141 | { | 141 | { |
142 | struct vlan_hdr *vhdr; | 142 | struct vlan_hdr *vhdr; |
143 | struct net_device_stats *stats; | 143 | struct vlan_rx_stats *rx_stats; |
144 | u16 vlan_id; | 144 | u16 vlan_id; |
145 | u16 vlan_tci; | 145 | u16 vlan_tci; |
146 | 146 | ||
@@ -163,9 +163,10 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
163 | goto err_unlock; | 163 | goto err_unlock; |
164 | } | 164 | } |
165 | 165 | ||
166 | stats = &skb->dev->stats; | 166 | rx_stats = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, |
167 | stats->rx_packets++; | 167 | smp_processor_id()); |
168 | stats->rx_bytes += skb->len; | 168 | rx_stats->rx_packets++; |
169 | rx_stats->rx_bytes += skb->len; | ||
169 | 170 | ||
170 | skb_pull_rcsum(skb, VLAN_HLEN); | 171 | skb_pull_rcsum(skb, VLAN_HLEN); |
171 | 172 | ||
@@ -180,7 +181,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
180 | break; | 181 | break; |
181 | 182 | ||
182 | case PACKET_MULTICAST: | 183 | case PACKET_MULTICAST: |
183 | stats->multicast++; | 184 | rx_stats->multicast++; |
184 | break; | 185 | break; |
185 | 186 | ||
186 | case PACKET_OTHERHOST: | 187 | case PACKET_OTHERHOST: |
@@ -200,7 +201,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
200 | 201 | ||
201 | skb = vlan_check_reorder_header(skb); | 202 | skb = vlan_check_reorder_header(skb); |
202 | if (!skb) { | 203 | if (!skb) { |
203 | stats->rx_errors++; | 204 | rx_stats->rx_errors++; |
204 | goto err_unlock; | 205 | goto err_unlock; |
205 | } | 206 | } |
206 | 207 | ||
@@ -332,7 +333,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, | |||
332 | } else | 333 | } else |
333 | txq->tx_dropped++; | 334 | txq->tx_dropped++; |
334 | 335 | ||
335 | return NETDEV_TX_OK; | 336 | return ret; |
336 | } | 337 | } |
337 | 338 | ||
338 | static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, | 339 | static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, |
@@ -358,7 +359,7 @@ static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, | |||
358 | } else | 359 | } else |
359 | txq->tx_dropped++; | 360 | txq->tx_dropped++; |
360 | 361 | ||
361 | return NETDEV_TX_OK; | 362 | return ret; |
362 | } | 363 | } |
363 | 364 | ||
364 | static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) | 365 | static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) |
@@ -393,7 +394,7 @@ int vlan_dev_set_egress_priority(const struct net_device *dev, | |||
393 | struct vlan_dev_info *vlan = vlan_dev_info(dev); | 394 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
394 | struct vlan_priority_tci_mapping *mp = NULL; | 395 | struct vlan_priority_tci_mapping *mp = NULL; |
395 | struct vlan_priority_tci_mapping *np; | 396 | struct vlan_priority_tci_mapping *np; |
396 | u32 vlan_qos = (vlan_prio << 13) & 0xE000; | 397 | u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK; |
397 | 398 | ||
398 | /* See if a priority mapping exists.. */ | 399 | /* See if a priority mapping exists.. */ |
399 | mp = vlan->egress_priority_map[skb_prio & 0xF]; | 400 | mp = vlan->egress_priority_map[skb_prio & 0xF]; |
@@ -430,7 +431,8 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask) | |||
430 | struct vlan_dev_info *vlan = vlan_dev_info(dev); | 431 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
431 | u32 old_flags = vlan->flags; | 432 | u32 old_flags = vlan->flags; |
432 | 433 | ||
433 | if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP)) | 434 | if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | |
435 | VLAN_FLAG_LOOSE_BINDING)) | ||
434 | return -EINVAL; | 436 | return -EINVAL; |
435 | 437 | ||
436 | vlan->flags = (old_flags & ~mask) | (flags & mask); | 438 | vlan->flags = (old_flags & ~mask) | (flags & mask); |
@@ -455,7 +457,8 @@ static int vlan_dev_open(struct net_device *dev) | |||
455 | struct net_device *real_dev = vlan->real_dev; | 457 | struct net_device *real_dev = vlan->real_dev; |
456 | int err; | 458 | int err; |
457 | 459 | ||
458 | if (!(real_dev->flags & IFF_UP)) | 460 | if (!(real_dev->flags & IFF_UP) && |
461 | !(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) | ||
459 | return -ENETDOWN; | 462 | return -ENETDOWN; |
460 | 463 | ||
461 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { | 464 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { |
@@ -626,6 +629,17 @@ static int vlan_dev_fcoe_disable(struct net_device *dev) | |||
626 | rc = ops->ndo_fcoe_disable(real_dev); | 629 | rc = ops->ndo_fcoe_disable(real_dev); |
627 | return rc; | 630 | return rc; |
628 | } | 631 | } |
632 | |||
633 | static int vlan_dev_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type) | ||
634 | { | ||
635 | struct net_device *real_dev = vlan_dev_info(dev)->real_dev; | ||
636 | const struct net_device_ops *ops = real_dev->netdev_ops; | ||
637 | int rc = -EINVAL; | ||
638 | |||
639 | if (ops->ndo_fcoe_get_wwn) | ||
640 | rc = ops->ndo_fcoe_get_wwn(real_dev, wwn, type); | ||
641 | return rc; | ||
642 | } | ||
629 | #endif | 643 | #endif |
630 | 644 | ||
631 | static void vlan_dev_change_rx_flags(struct net_device *dev, int change) | 645 | static void vlan_dev_change_rx_flags(struct net_device *dev, int change) |
@@ -720,6 +734,11 @@ static int vlan_dev_init(struct net_device *dev) | |||
720 | subclass = 1; | 734 | subclass = 1; |
721 | 735 | ||
722 | vlan_dev_set_lockdep_class(dev, subclass); | 736 | vlan_dev_set_lockdep_class(dev, subclass); |
737 | |||
738 | vlan_dev_info(dev)->vlan_rx_stats = alloc_percpu(struct vlan_rx_stats); | ||
739 | if (!vlan_dev_info(dev)->vlan_rx_stats) | ||
740 | return -ENOMEM; | ||
741 | |||
723 | return 0; | 742 | return 0; |
724 | } | 743 | } |
725 | 744 | ||
@@ -729,6 +748,8 @@ static void vlan_dev_uninit(struct net_device *dev) | |||
729 | struct vlan_dev_info *vlan = vlan_dev_info(dev); | 748 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
730 | int i; | 749 | int i; |
731 | 750 | ||
751 | free_percpu(vlan->vlan_rx_stats); | ||
752 | vlan->vlan_rx_stats = NULL; | ||
732 | for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { | 753 | for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { |
733 | while ((pm = vlan->egress_priority_map[i]) != NULL) { | 754 | while ((pm = vlan->egress_priority_map[i]) != NULL) { |
734 | vlan->egress_priority_map[i] = pm->next; | 755 | vlan->egress_priority_map[i] = pm->next; |
@@ -764,6 +785,31 @@ static u32 vlan_ethtool_get_flags(struct net_device *dev) | |||
764 | return dev_ethtool_get_flags(vlan->real_dev); | 785 | return dev_ethtool_get_flags(vlan->real_dev); |
765 | } | 786 | } |
766 | 787 | ||
788 | static struct net_device_stats *vlan_dev_get_stats(struct net_device *dev) | ||
789 | { | ||
790 | struct net_device_stats *stats = &dev->stats; | ||
791 | |||
792 | dev_txq_stats_fold(dev, stats); | ||
793 | |||
794 | if (vlan_dev_info(dev)->vlan_rx_stats) { | ||
795 | struct vlan_rx_stats *p, rx = {0}; | ||
796 | int i; | ||
797 | |||
798 | for_each_possible_cpu(i) { | ||
799 | p = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, i); | ||
800 | rx.rx_packets += p->rx_packets; | ||
801 | rx.rx_bytes += p->rx_bytes; | ||
802 | rx.rx_errors += p->rx_errors; | ||
803 | rx.multicast += p->multicast; | ||
804 | } | ||
805 | stats->rx_packets = rx.rx_packets; | ||
806 | stats->rx_bytes = rx.rx_bytes; | ||
807 | stats->rx_errors = rx.rx_errors; | ||
808 | stats->multicast = rx.multicast; | ||
809 | } | ||
810 | return stats; | ||
811 | } | ||
812 | |||
767 | static const struct ethtool_ops vlan_ethtool_ops = { | 813 | static const struct ethtool_ops vlan_ethtool_ops = { |
768 | .get_settings = vlan_ethtool_get_settings, | 814 | .get_settings = vlan_ethtool_get_settings, |
769 | .get_drvinfo = vlan_ethtool_get_drvinfo, | 815 | .get_drvinfo = vlan_ethtool_get_drvinfo, |
@@ -786,11 +832,13 @@ static const struct net_device_ops vlan_netdev_ops = { | |||
786 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, | 832 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, |
787 | .ndo_do_ioctl = vlan_dev_ioctl, | 833 | .ndo_do_ioctl = vlan_dev_ioctl, |
788 | .ndo_neigh_setup = vlan_dev_neigh_setup, | 834 | .ndo_neigh_setup = vlan_dev_neigh_setup, |
835 | .ndo_get_stats = vlan_dev_get_stats, | ||
789 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | 836 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) |
790 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, | 837 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, |
791 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, | 838 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, |
792 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, | 839 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, |
793 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, | 840 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, |
841 | .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, | ||
794 | #endif | 842 | #endif |
795 | }; | 843 | }; |
796 | 844 | ||
@@ -808,11 +856,13 @@ static const struct net_device_ops vlan_netdev_accel_ops = { | |||
808 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, | 856 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, |
809 | .ndo_do_ioctl = vlan_dev_ioctl, | 857 | .ndo_do_ioctl = vlan_dev_ioctl, |
810 | .ndo_neigh_setup = vlan_dev_neigh_setup, | 858 | .ndo_neigh_setup = vlan_dev_neigh_setup, |
859 | .ndo_get_stats = vlan_dev_get_stats, | ||
811 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | 860 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) |
812 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, | 861 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, |
813 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, | 862 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, |
814 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, | 863 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, |
815 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, | 864 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, |
865 | .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, | ||
816 | #endif | 866 | #endif |
817 | }; | 867 | }; |
818 | 868 | ||
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index a91504850195..ddc105734af7 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c | |||
@@ -60,7 +60,8 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
60 | if (data[IFLA_VLAN_FLAGS]) { | 60 | if (data[IFLA_VLAN_FLAGS]) { |
61 | flags = nla_data(data[IFLA_VLAN_FLAGS]); | 61 | flags = nla_data(data[IFLA_VLAN_FLAGS]); |
62 | if ((flags->flags & flags->mask) & | 62 | if ((flags->flags & flags->mask) & |
63 | ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP)) | 63 | ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | |
64 | VLAN_FLAG_LOOSE_BINDING)) | ||
64 | return -EINVAL; | 65 | return -EINVAL; |
65 | } | 66 | } |
66 | 67 | ||
@@ -119,7 +120,7 @@ static int vlan_get_tx_queues(struct net *net, | |||
119 | return 0; | 120 | return 0; |
120 | } | 121 | } |
121 | 122 | ||
122 | static int vlan_newlink(struct net_device *dev, | 123 | static int vlan_newlink(struct net *src_net, struct net_device *dev, |
123 | struct nlattr *tb[], struct nlattr *data[]) | 124 | struct nlattr *tb[], struct nlattr *data[]) |
124 | { | 125 | { |
125 | struct vlan_dev_info *vlan = vlan_dev_info(dev); | 126 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
@@ -131,7 +132,7 @@ static int vlan_newlink(struct net_device *dev, | |||
131 | 132 | ||
132 | if (!tb[IFLA_LINK]) | 133 | if (!tb[IFLA_LINK]) |
133 | return -EINVAL; | 134 | return -EINVAL; |
134 | real_dev = __dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK])); | 135 | real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); |
135 | if (!real_dev) | 136 | if (!real_dev) |
136 | return -ENODEV; | 137 | return -ENODEV; |
137 | 138 | ||
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 6262c335f3c2..9ec1f057c03a 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c | |||
@@ -201,18 +201,17 @@ int vlan_proc_rem_dev(struct net_device *vlandev) | |||
201 | 201 | ||
202 | /* start read of /proc/net/vlan/config */ | 202 | /* start read of /proc/net/vlan/config */ |
203 | static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) | 203 | static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) |
204 | __acquires(dev_base_lock) | 204 | __acquires(rcu) |
205 | { | 205 | { |
206 | struct net_device *dev; | 206 | struct net_device *dev; |
207 | struct net *net = seq_file_net(seq); | 207 | struct net *net = seq_file_net(seq); |
208 | loff_t i = 1; | 208 | loff_t i = 1; |
209 | 209 | ||
210 | read_lock(&dev_base_lock); | 210 | rcu_read_lock(); |
211 | |||
212 | if (*pos == 0) | 211 | if (*pos == 0) |
213 | return SEQ_START_TOKEN; | 212 | return SEQ_START_TOKEN; |
214 | 213 | ||
215 | for_each_netdev(net, dev) { | 214 | for_each_netdev_rcu(net, dev) { |
216 | if (!is_vlan_dev(dev)) | 215 | if (!is_vlan_dev(dev)) |
217 | continue; | 216 | continue; |
218 | 217 | ||
@@ -234,7 +233,7 @@ static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
234 | if (v == SEQ_START_TOKEN) | 233 | if (v == SEQ_START_TOKEN) |
235 | dev = net_device_entry(&net->dev_base_head); | 234 | dev = net_device_entry(&net->dev_base_head); |
236 | 235 | ||
237 | for_each_netdev_continue(net, dev) { | 236 | for_each_netdev_continue_rcu(net, dev) { |
238 | if (!is_vlan_dev(dev)) | 237 | if (!is_vlan_dev(dev)) |
239 | continue; | 238 | continue; |
240 | 239 | ||
@@ -245,9 +244,9 @@ static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
245 | } | 244 | } |
246 | 245 | ||
247 | static void vlan_seq_stop(struct seq_file *seq, void *v) | 246 | static void vlan_seq_stop(struct seq_file *seq, void *v) |
248 | __releases(dev_base_lock) | 247 | __releases(rcu) |
249 | { | 248 | { |
250 | read_unlock(&dev_base_lock); | 249 | rcu_read_unlock(); |
251 | } | 250 | } |
252 | 251 | ||
253 | static int vlan_seq_show(struct seq_file *seq, void *v) | 252 | static int vlan_seq_show(struct seq_file *seq, void *v) |