diff options
-rw-r--r-- | net/8021q/vlan.h | 17 | ||||
-rw-r--r-- | net/8021q/vlan_core.c | 12 | ||||
-rw-r--r-- | net/8021q/vlan_dev.c | 47 |
3 files changed, 65 insertions, 11 deletions
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 68f9290e6837..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) |
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 971d3755ae87..e75a2f3b10af 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c | |||
@@ -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. |
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 915965942139..de0dc6bacbe8 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 | ||
@@ -731,6 +732,11 @@ static int vlan_dev_init(struct net_device *dev) | |||
731 | subclass = 1; | 732 | subclass = 1; |
732 | 733 | ||
733 | vlan_dev_set_lockdep_class(dev, subclass); | 734 | vlan_dev_set_lockdep_class(dev, subclass); |
735 | |||
736 | vlan_dev_info(dev)->vlan_rx_stats = alloc_percpu(struct vlan_rx_stats); | ||
737 | if (!vlan_dev_info(dev)->vlan_rx_stats) | ||
738 | return -ENOMEM; | ||
739 | |||
734 | return 0; | 740 | return 0; |
735 | } | 741 | } |
736 | 742 | ||
@@ -740,6 +746,8 @@ static void vlan_dev_uninit(struct net_device *dev) | |||
740 | struct vlan_dev_info *vlan = vlan_dev_info(dev); | 746 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
741 | int i; | 747 | int i; |
742 | 748 | ||
749 | free_percpu(vlan->vlan_rx_stats); | ||
750 | vlan->vlan_rx_stats = NULL; | ||
743 | for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { | 751 | for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { |
744 | while ((pm = vlan->egress_priority_map[i]) != NULL) { | 752 | while ((pm = vlan->egress_priority_map[i]) != NULL) { |
745 | vlan->egress_priority_map[i] = pm->next; | 753 | vlan->egress_priority_map[i] = pm->next; |
@@ -775,6 +783,31 @@ static u32 vlan_ethtool_get_flags(struct net_device *dev) | |||
775 | return dev_ethtool_get_flags(vlan->real_dev); | 783 | return dev_ethtool_get_flags(vlan->real_dev); |
776 | } | 784 | } |
777 | 785 | ||
786 | static struct net_device_stats *vlan_dev_get_stats(struct net_device *dev) | ||
787 | { | ||
788 | struct net_device_stats *stats = &dev->stats; | ||
789 | |||
790 | dev_txq_stats_fold(dev, stats); | ||
791 | |||
792 | if (vlan_dev_info(dev)->vlan_rx_stats) { | ||
793 | struct vlan_rx_stats *p, rx = {0}; | ||
794 | int i; | ||
795 | |||
796 | for_each_possible_cpu(i) { | ||
797 | p = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, i); | ||
798 | rx.rx_packets += p->rx_packets; | ||
799 | rx.rx_bytes += p->rx_bytes; | ||
800 | rx.rx_errors += p->rx_errors; | ||
801 | rx.multicast += p->multicast; | ||
802 | } | ||
803 | stats->rx_packets = rx.rx_packets; | ||
804 | stats->rx_bytes = rx.rx_bytes; | ||
805 | stats->rx_errors = rx.rx_errors; | ||
806 | stats->multicast = rx.multicast; | ||
807 | } | ||
808 | return stats; | ||
809 | } | ||
810 | |||
778 | static const struct ethtool_ops vlan_ethtool_ops = { | 811 | static const struct ethtool_ops vlan_ethtool_ops = { |
779 | .get_settings = vlan_ethtool_get_settings, | 812 | .get_settings = vlan_ethtool_get_settings, |
780 | .get_drvinfo = vlan_ethtool_get_drvinfo, | 813 | .get_drvinfo = vlan_ethtool_get_drvinfo, |
@@ -797,6 +830,7 @@ static const struct net_device_ops vlan_netdev_ops = { | |||
797 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, | 830 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, |
798 | .ndo_do_ioctl = vlan_dev_ioctl, | 831 | .ndo_do_ioctl = vlan_dev_ioctl, |
799 | .ndo_neigh_setup = vlan_dev_neigh_setup, | 832 | .ndo_neigh_setup = vlan_dev_neigh_setup, |
833 | .ndo_get_stats = vlan_dev_get_stats, | ||
800 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | 834 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) |
801 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, | 835 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, |
802 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, | 836 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, |
@@ -820,6 +854,7 @@ static const struct net_device_ops vlan_netdev_accel_ops = { | |||
820 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, | 854 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, |
821 | .ndo_do_ioctl = vlan_dev_ioctl, | 855 | .ndo_do_ioctl = vlan_dev_ioctl, |
822 | .ndo_neigh_setup = vlan_dev_neigh_setup, | 856 | .ndo_neigh_setup = vlan_dev_neigh_setup, |
857 | .ndo_get_stats = vlan_dev_get_stats, | ||
823 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | 858 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) |
824 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, | 859 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, |
825 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, | 860 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, |