diff options
Diffstat (limited to 'net/8021q/vlan_dev.c')
-rw-r--r-- | net/8021q/vlan_dev.c | 153 |
1 files changed, 134 insertions, 19 deletions
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 4198ec5c8abc..29b6348c8d4d 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -21,6 +21,7 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/slab.h> | ||
24 | #include <linux/skbuff.h> | 25 | #include <linux/skbuff.h> |
25 | #include <linux/netdevice.h> | 26 | #include <linux/netdevice.h> |
26 | #include <linux/etherdevice.h> | 27 | #include <linux/etherdevice.h> |
@@ -140,7 +141,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
140 | struct packet_type *ptype, struct net_device *orig_dev) | 141 | struct packet_type *ptype, struct net_device *orig_dev) |
141 | { | 142 | { |
142 | struct vlan_hdr *vhdr; | 143 | struct vlan_hdr *vhdr; |
143 | struct net_device_stats *stats; | 144 | struct vlan_rx_stats *rx_stats; |
144 | u16 vlan_id; | 145 | u16 vlan_id; |
145 | u16 vlan_tci; | 146 | u16 vlan_tci; |
146 | 147 | ||
@@ -163,9 +164,10 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
163 | goto err_unlock; | 164 | goto err_unlock; |
164 | } | 165 | } |
165 | 166 | ||
166 | stats = &skb->dev->stats; | 167 | rx_stats = per_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats, |
167 | stats->rx_packets++; | 168 | smp_processor_id()); |
168 | stats->rx_bytes += skb->len; | 169 | rx_stats->rx_packets++; |
170 | rx_stats->rx_bytes += skb->len; | ||
169 | 171 | ||
170 | skb_pull_rcsum(skb, VLAN_HLEN); | 172 | skb_pull_rcsum(skb, VLAN_HLEN); |
171 | 173 | ||
@@ -180,7 +182,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
180 | break; | 182 | break; |
181 | 183 | ||
182 | case PACKET_MULTICAST: | 184 | case PACKET_MULTICAST: |
183 | stats->multicast++; | 185 | rx_stats->multicast++; |
184 | break; | 186 | break; |
185 | 187 | ||
186 | case PACKET_OTHERHOST: | 188 | case PACKET_OTHERHOST: |
@@ -200,7 +202,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
200 | 202 | ||
201 | skb = vlan_check_reorder_header(skb); | 203 | skb = vlan_check_reorder_header(skb); |
202 | if (!skb) { | 204 | if (!skb) { |
203 | stats->rx_errors++; | 205 | rx_stats->rx_errors++; |
204 | goto err_unlock; | 206 | goto err_unlock; |
205 | } | 207 | } |
206 | 208 | ||
@@ -262,11 +264,10 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, | |||
262 | vhdr->h_vlan_TCI = htons(vlan_tci); | 264 | vhdr->h_vlan_TCI = htons(vlan_tci); |
263 | 265 | ||
264 | /* | 266 | /* |
265 | * Set the protocol type. For a packet of type ETH_P_802_3 we | 267 | * Set the protocol type. For a packet of type ETH_P_802_3/2 we |
266 | * put the length in here instead. It is up to the 802.2 | 268 | * put the length in here instead. |
267 | * layer to carry protocol information. | ||
268 | */ | 269 | */ |
269 | if (type != ETH_P_802_3) | 270 | if (type != ETH_P_802_3 && type != ETH_P_802_2) |
270 | vhdr->h_vlan_encapsulated_proto = htons(type); | 271 | vhdr->h_vlan_encapsulated_proto = htons(type); |
271 | else | 272 | else |
272 | vhdr->h_vlan_encapsulated_proto = htons(len); | 273 | vhdr->h_vlan_encapsulated_proto = htons(len); |
@@ -322,7 +323,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, | |||
322 | } | 323 | } |
323 | 324 | ||
324 | 325 | ||
325 | skb->dev = vlan_dev_info(dev)->real_dev; | 326 | skb_set_dev(skb, vlan_dev_info(dev)->real_dev); |
326 | len = skb->len; | 327 | len = skb->len; |
327 | ret = dev_queue_xmit(skb); | 328 | ret = dev_queue_xmit(skb); |
328 | 329 | ||
@@ -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,15 @@ 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; |
363 | } | ||
364 | |||
365 | static u16 vlan_dev_select_queue(struct net_device *dev, struct sk_buff *skb) | ||
366 | { | ||
367 | struct net_device *rdev = vlan_dev_info(dev)->real_dev; | ||
368 | const struct net_device_ops *ops = rdev->netdev_ops; | ||
369 | |||
370 | return ops->ndo_select_queue(rdev, skb); | ||
362 | } | 371 | } |
363 | 372 | ||
364 | static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) | 373 | static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) |
@@ -393,7 +402,7 @@ int vlan_dev_set_egress_priority(const struct net_device *dev, | |||
393 | struct vlan_dev_info *vlan = vlan_dev_info(dev); | 402 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
394 | struct vlan_priority_tci_mapping *mp = NULL; | 403 | struct vlan_priority_tci_mapping *mp = NULL; |
395 | struct vlan_priority_tci_mapping *np; | 404 | struct vlan_priority_tci_mapping *np; |
396 | u32 vlan_qos = (vlan_prio << 13) & 0xE000; | 405 | u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK; |
397 | 406 | ||
398 | /* See if a priority mapping exists.. */ | 407 | /* See if a priority mapping exists.. */ |
399 | mp = vlan->egress_priority_map[skb_prio & 0xF]; | 408 | mp = vlan->egress_priority_map[skb_prio & 0xF]; |
@@ -430,7 +439,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); | 439 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
431 | u32 old_flags = vlan->flags; | 440 | u32 old_flags = vlan->flags; |
432 | 441 | ||
433 | if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP)) | 442 | if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | |
443 | VLAN_FLAG_LOOSE_BINDING)) | ||
434 | return -EINVAL; | 444 | return -EINVAL; |
435 | 445 | ||
436 | vlan->flags = (old_flags & ~mask) | (flags & mask); | 446 | vlan->flags = (old_flags & ~mask) | (flags & mask); |
@@ -455,7 +465,8 @@ static int vlan_dev_open(struct net_device *dev) | |||
455 | struct net_device *real_dev = vlan->real_dev; | 465 | struct net_device *real_dev = vlan->real_dev; |
456 | int err; | 466 | int err; |
457 | 467 | ||
458 | if (!(real_dev->flags & IFF_UP)) | 468 | if (!(real_dev->flags & IFF_UP) && |
469 | !(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) | ||
459 | return -ENETDOWN; | 470 | return -ENETDOWN; |
460 | 471 | ||
461 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { | 472 | if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { |
@@ -626,6 +637,17 @@ static int vlan_dev_fcoe_disable(struct net_device *dev) | |||
626 | rc = ops->ndo_fcoe_disable(real_dev); | 637 | rc = ops->ndo_fcoe_disable(real_dev); |
627 | return rc; | 638 | return rc; |
628 | } | 639 | } |
640 | |||
641 | static int vlan_dev_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type) | ||
642 | { | ||
643 | struct net_device *real_dev = vlan_dev_info(dev)->real_dev; | ||
644 | const struct net_device_ops *ops = real_dev->netdev_ops; | ||
645 | int rc = -EINVAL; | ||
646 | |||
647 | if (ops->ndo_fcoe_get_wwn) | ||
648 | rc = ops->ndo_fcoe_get_wwn(real_dev, wwn, type); | ||
649 | return rc; | ||
650 | } | ||
629 | #endif | 651 | #endif |
630 | 652 | ||
631 | static void vlan_dev_change_rx_flags(struct net_device *dev, int change) | 653 | static void vlan_dev_change_rx_flags(struct net_device *dev, int change) |
@@ -675,7 +697,8 @@ static const struct header_ops vlan_header_ops = { | |||
675 | .parse = eth_header_parse, | 697 | .parse = eth_header_parse, |
676 | }; | 698 | }; |
677 | 699 | ||
678 | static const struct net_device_ops vlan_netdev_ops, vlan_netdev_accel_ops; | 700 | static const struct net_device_ops vlan_netdev_ops, vlan_netdev_accel_ops, |
701 | vlan_netdev_ops_sq, vlan_netdev_accel_ops_sq; | ||
679 | 702 | ||
680 | static int vlan_dev_init(struct net_device *dev) | 703 | static int vlan_dev_init(struct net_device *dev) |
681 | { | 704 | { |
@@ -709,17 +732,28 @@ static int vlan_dev_init(struct net_device *dev) | |||
709 | if (real_dev->features & NETIF_F_HW_VLAN_TX) { | 732 | if (real_dev->features & NETIF_F_HW_VLAN_TX) { |
710 | dev->header_ops = real_dev->header_ops; | 733 | dev->header_ops = real_dev->header_ops; |
711 | dev->hard_header_len = real_dev->hard_header_len; | 734 | dev->hard_header_len = real_dev->hard_header_len; |
712 | dev->netdev_ops = &vlan_netdev_accel_ops; | 735 | if (real_dev->netdev_ops->ndo_select_queue) |
736 | dev->netdev_ops = &vlan_netdev_accel_ops_sq; | ||
737 | else | ||
738 | dev->netdev_ops = &vlan_netdev_accel_ops; | ||
713 | } else { | 739 | } else { |
714 | dev->header_ops = &vlan_header_ops; | 740 | dev->header_ops = &vlan_header_ops; |
715 | dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN; | 741 | dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN; |
716 | dev->netdev_ops = &vlan_netdev_ops; | 742 | if (real_dev->netdev_ops->ndo_select_queue) |
743 | dev->netdev_ops = &vlan_netdev_ops_sq; | ||
744 | else | ||
745 | dev->netdev_ops = &vlan_netdev_ops; | ||
717 | } | 746 | } |
718 | 747 | ||
719 | if (is_vlan_dev(real_dev)) | 748 | if (is_vlan_dev(real_dev)) |
720 | subclass = 1; | 749 | subclass = 1; |
721 | 750 | ||
722 | vlan_dev_set_lockdep_class(dev, subclass); | 751 | vlan_dev_set_lockdep_class(dev, subclass); |
752 | |||
753 | vlan_dev_info(dev)->vlan_rx_stats = alloc_percpu(struct vlan_rx_stats); | ||
754 | if (!vlan_dev_info(dev)->vlan_rx_stats) | ||
755 | return -ENOMEM; | ||
756 | |||
723 | return 0; | 757 | return 0; |
724 | } | 758 | } |
725 | 759 | ||
@@ -729,6 +763,8 @@ static void vlan_dev_uninit(struct net_device *dev) | |||
729 | struct vlan_dev_info *vlan = vlan_dev_info(dev); | 763 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
730 | int i; | 764 | int i; |
731 | 765 | ||
766 | free_percpu(vlan->vlan_rx_stats); | ||
767 | vlan->vlan_rx_stats = NULL; | ||
732 | for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { | 768 | for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { |
733 | while ((pm = vlan->egress_priority_map[i]) != NULL) { | 769 | while ((pm = vlan->egress_priority_map[i]) != NULL) { |
734 | vlan->egress_priority_map[i] = pm->next; | 770 | vlan->egress_priority_map[i] = pm->next; |
@@ -764,6 +800,31 @@ static u32 vlan_ethtool_get_flags(struct net_device *dev) | |||
764 | return dev_ethtool_get_flags(vlan->real_dev); | 800 | return dev_ethtool_get_flags(vlan->real_dev); |
765 | } | 801 | } |
766 | 802 | ||
803 | static struct net_device_stats *vlan_dev_get_stats(struct net_device *dev) | ||
804 | { | ||
805 | struct net_device_stats *stats = &dev->stats; | ||
806 | |||
807 | dev_txq_stats_fold(dev, stats); | ||
808 | |||
809 | if (vlan_dev_info(dev)->vlan_rx_stats) { | ||
810 | struct vlan_rx_stats *p, rx = {0}; | ||
811 | int i; | ||
812 | |||
813 | for_each_possible_cpu(i) { | ||
814 | p = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, i); | ||
815 | rx.rx_packets += p->rx_packets; | ||
816 | rx.rx_bytes += p->rx_bytes; | ||
817 | rx.rx_errors += p->rx_errors; | ||
818 | rx.multicast += p->multicast; | ||
819 | } | ||
820 | stats->rx_packets = rx.rx_packets; | ||
821 | stats->rx_bytes = rx.rx_bytes; | ||
822 | stats->rx_errors = rx.rx_errors; | ||
823 | stats->multicast = rx.multicast; | ||
824 | } | ||
825 | return stats; | ||
826 | } | ||
827 | |||
767 | static const struct ethtool_ops vlan_ethtool_ops = { | 828 | static const struct ethtool_ops vlan_ethtool_ops = { |
768 | .get_settings = vlan_ethtool_get_settings, | 829 | .get_settings = vlan_ethtool_get_settings, |
769 | .get_drvinfo = vlan_ethtool_get_drvinfo, | 830 | .get_drvinfo = vlan_ethtool_get_drvinfo, |
@@ -786,11 +847,13 @@ static const struct net_device_ops vlan_netdev_ops = { | |||
786 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, | 847 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, |
787 | .ndo_do_ioctl = vlan_dev_ioctl, | 848 | .ndo_do_ioctl = vlan_dev_ioctl, |
788 | .ndo_neigh_setup = vlan_dev_neigh_setup, | 849 | .ndo_neigh_setup = vlan_dev_neigh_setup, |
850 | .ndo_get_stats = vlan_dev_get_stats, | ||
789 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | 851 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) |
790 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, | 852 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, |
791 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, | 853 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, |
792 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, | 854 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, |
793 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, | 855 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, |
856 | .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, | ||
794 | #endif | 857 | #endif |
795 | }; | 858 | }; |
796 | 859 | ||
@@ -808,11 +871,63 @@ static const struct net_device_ops vlan_netdev_accel_ops = { | |||
808 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, | 871 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, |
809 | .ndo_do_ioctl = vlan_dev_ioctl, | 872 | .ndo_do_ioctl = vlan_dev_ioctl, |
810 | .ndo_neigh_setup = vlan_dev_neigh_setup, | 873 | .ndo_neigh_setup = vlan_dev_neigh_setup, |
874 | .ndo_get_stats = vlan_dev_get_stats, | ||
875 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | ||
876 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, | ||
877 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, | ||
878 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, | ||
879 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, | ||
880 | .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, | ||
881 | #endif | ||
882 | }; | ||
883 | |||
884 | static const struct net_device_ops vlan_netdev_ops_sq = { | ||
885 | .ndo_select_queue = vlan_dev_select_queue, | ||
886 | .ndo_change_mtu = vlan_dev_change_mtu, | ||
887 | .ndo_init = vlan_dev_init, | ||
888 | .ndo_uninit = vlan_dev_uninit, | ||
889 | .ndo_open = vlan_dev_open, | ||
890 | .ndo_stop = vlan_dev_stop, | ||
891 | .ndo_start_xmit = vlan_dev_hard_start_xmit, | ||
892 | .ndo_validate_addr = eth_validate_addr, | ||
893 | .ndo_set_mac_address = vlan_dev_set_mac_address, | ||
894 | .ndo_set_rx_mode = vlan_dev_set_rx_mode, | ||
895 | .ndo_set_multicast_list = vlan_dev_set_rx_mode, | ||
896 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, | ||
897 | .ndo_do_ioctl = vlan_dev_ioctl, | ||
898 | .ndo_neigh_setup = vlan_dev_neigh_setup, | ||
899 | .ndo_get_stats = vlan_dev_get_stats, | ||
900 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | ||
901 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, | ||
902 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, | ||
903 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, | ||
904 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, | ||
905 | .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, | ||
906 | #endif | ||
907 | }; | ||
908 | |||
909 | static const struct net_device_ops vlan_netdev_accel_ops_sq = { | ||
910 | .ndo_select_queue = vlan_dev_select_queue, | ||
911 | .ndo_change_mtu = vlan_dev_change_mtu, | ||
912 | .ndo_init = vlan_dev_init, | ||
913 | .ndo_uninit = vlan_dev_uninit, | ||
914 | .ndo_open = vlan_dev_open, | ||
915 | .ndo_stop = vlan_dev_stop, | ||
916 | .ndo_start_xmit = vlan_dev_hwaccel_hard_start_xmit, | ||
917 | .ndo_validate_addr = eth_validate_addr, | ||
918 | .ndo_set_mac_address = vlan_dev_set_mac_address, | ||
919 | .ndo_set_rx_mode = vlan_dev_set_rx_mode, | ||
920 | .ndo_set_multicast_list = vlan_dev_set_rx_mode, | ||
921 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, | ||
922 | .ndo_do_ioctl = vlan_dev_ioctl, | ||
923 | .ndo_neigh_setup = vlan_dev_neigh_setup, | ||
924 | .ndo_get_stats = vlan_dev_get_stats, | ||
811 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | 925 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) |
812 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, | 926 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, |
813 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, | 927 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, |
814 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, | 928 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, |
815 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, | 929 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, |
930 | .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, | ||
816 | #endif | 931 | #endif |
817 | }; | 932 | }; |
818 | 933 | ||