aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-11-16 23:53:09 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-18 02:51:55 -0500
commit9793241fe92f7d9303fb221e43fc598eb065f267 (patch)
tree5f7a347c3a6b32a49e54f1f6ead1c96f2351208c
parentd83345adf96bc13a5e360f4649a2e68ef968dec0 (diff)
vlan: Precise RX stats accounting
With multi queue devices, its possible that several cpus call vlan RX routines simultaneously for the same vlan device. We update RX stats counter without any locking, so we can get slightly wrong counters. One possible fix is to use percpu counters, to get precise accounting and also get guarantee of no cache line ping pongs between cpus. Note: this adds 16 bytes (32 bytes on 64bit arches) of percpu data per vlan device. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/8021q/vlan.h17
-rw-r--r--net/8021q/vlan_core.c12
-rw-r--r--net/8021q/vlan_dev.c47
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 */
27struct 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 */
33struct vlan_dev_info { 49struct 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
50static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev) 67static 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);
31int vlan_hwaccel_do_receive(struct sk_buff *skb) 31int 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
786static 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
778static const struct ethtool_ops vlan_ethtool_ops = { 811static 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,