diff options
Diffstat (limited to 'net/8021q/vlan_dev.c')
-rw-r--r-- | net/8021q/vlan_dev.c | 72 |
1 files changed, 61 insertions, 11 deletions
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 | ||