|
@@ -140,7 +140,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
|
|
|
struct packet_type *ptype, struct net_device *orig_dev)
|
|
|
{
|
|
|
struct vlan_hdr *vhdr;
|
|
|
- struct net_device_stats *stats;
|
|
|
+ struct vlan_rx_stats *rx_stats;
|
|
|
u16 vlan_id;
|
|
|
u16 vlan_tci;
|
|
|
|
|
@@ -163,9 +163,10 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
|
|
|
goto err_unlock;
|
|
|
}
|
|
|
|
|
|
- stats = &skb->dev->stats;
|
|
|
- stats->rx_packets++;
|
|
|
- stats->rx_bytes += skb->len;
|
|
|
+ rx_stats = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats,
|
|
|
+ smp_processor_id());
|
|
|
+ rx_stats->rx_packets++;
|
|
|
+ rx_stats->rx_bytes += skb->len;
|
|
|
|
|
|
skb_pull_rcsum(skb, VLAN_HLEN);
|
|
|
|
|
@@ -180,7 +181,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
|
|
|
break;
|
|
|
|
|
|
case PACKET_MULTICAST:
|
|
|
- stats->multicast++;
|
|
|
+ rx_stats->multicast++;
|
|
|
break;
|
|
|
|
|
|
case PACKET_OTHERHOST:
|
|
@@ -200,7 +201,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
|
|
|
|
|
|
skb = vlan_check_reorder_header(skb);
|
|
|
if (!skb) {
|
|
|
- stats->rx_errors++;
|
|
|
+ rx_stats->rx_errors++;
|
|
|
goto err_unlock;
|
|
|
}
|
|
|
|
|
@@ -731,6 +732,11 @@ static int vlan_dev_init(struct net_device *dev)
|
|
|
subclass = 1;
|
|
|
|
|
|
vlan_dev_set_lockdep_class(dev, subclass);
|
|
|
+
|
|
|
+ vlan_dev_info(dev)->vlan_rx_stats = alloc_percpu(struct vlan_rx_stats);
|
|
|
+ if (!vlan_dev_info(dev)->vlan_rx_stats)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -740,6 +746,8 @@ static void vlan_dev_uninit(struct net_device *dev)
|
|
|
struct vlan_dev_info *vlan = vlan_dev_info(dev);
|
|
|
int i;
|
|
|
|
|
|
+ free_percpu(vlan->vlan_rx_stats);
|
|
|
+ vlan->vlan_rx_stats = NULL;
|
|
|
for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
|
|
|
while ((pm = vlan->egress_priority_map[i]) != NULL) {
|
|
|
vlan->egress_priority_map[i] = pm->next;
|
|
@@ -775,6 +783,31 @@ static u32 vlan_ethtool_get_flags(struct net_device *dev)
|
|
|
return dev_ethtool_get_flags(vlan->real_dev);
|
|
|
}
|
|
|
|
|
|
+static struct net_device_stats *vlan_dev_get_stats(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct net_device_stats *stats = &dev->stats;
|
|
|
+
|
|
|
+ dev_txq_stats_fold(dev, stats);
|
|
|
+
|
|
|
+ if (vlan_dev_info(dev)->vlan_rx_stats) {
|
|
|
+ struct vlan_rx_stats *p, rx = {0};
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for_each_possible_cpu(i) {
|
|
|
+ p = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, i);
|
|
|
+ rx.rx_packets += p->rx_packets;
|
|
|
+ rx.rx_bytes += p->rx_bytes;
|
|
|
+ rx.rx_errors += p->rx_errors;
|
|
|
+ rx.multicast += p->multicast;
|
|
|
+ }
|
|
|
+ stats->rx_packets = rx.rx_packets;
|
|
|
+ stats->rx_bytes = rx.rx_bytes;
|
|
|
+ stats->rx_errors = rx.rx_errors;
|
|
|
+ stats->multicast = rx.multicast;
|
|
|
+ }
|
|
|
+ return stats;
|
|
|
+}
|
|
|
+
|
|
|
static const struct ethtool_ops vlan_ethtool_ops = {
|
|
|
.get_settings = vlan_ethtool_get_settings,
|
|
|
.get_drvinfo = vlan_ethtool_get_drvinfo,
|
|
@@ -797,6 +830,7 @@ static const struct net_device_ops vlan_netdev_ops = {
|
|
|
.ndo_change_rx_flags = vlan_dev_change_rx_flags,
|
|
|
.ndo_do_ioctl = vlan_dev_ioctl,
|
|
|
.ndo_neigh_setup = vlan_dev_neigh_setup,
|
|
|
+ .ndo_get_stats = vlan_dev_get_stats,
|
|
|
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
|
|
|
.ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup,
|
|
|
.ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done,
|
|
@@ -820,6 +854,7 @@ static const struct net_device_ops vlan_netdev_accel_ops = {
|
|
|
.ndo_change_rx_flags = vlan_dev_change_rx_flags,
|
|
|
.ndo_do_ioctl = vlan_dev_ioctl,
|
|
|
.ndo_neigh_setup = vlan_dev_neigh_setup,
|
|
|
+ .ndo_get_stats = vlan_dev_get_stats,
|
|
|
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
|
|
|
.ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup,
|
|
|
.ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done,
|