Fix packet count when using vlan/macvlan drivers with gso. Without this it
is not possible to reconcile packet counts between underlying devices and
these virtual devices. Additionally, the output looks wrong in a standalone
way i.e. device MTU of 1500, 1 packet sent, 31856 bytes sent.

There are many other drivers that likely have a similar problem, although
it is not clear how many of those could be used with gso. Perhaps all
packet counting should be wrapped in a helper fn.

v2: bytes were also incorrect for gso skb's, fix tx as that is readily
available. Fix rx packets for macvlan.

Signed-off-by: Debabrata Banerjee <dbane...@akamai.com>
---
 drivers/net/ethernet/intel/fm10k/fm10k_main.c |  4 ++--
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |  4 ++--
 drivers/net/macvlan.c                         | 13 ++++++++-----
 drivers/net/macvtap.c                         |  2 +-
 include/linux/if_macvlan.h                    |  6 +++---
 net/8021q/vlan_core.c                         |  3 ++-
 net/8021q/vlan_dev.c                          |  4 ++--
 7 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c 
b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
index 6fd15a734324..e39fad2d888f 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
@@ -431,8 +431,8 @@ static void fm10k_type_trans(struct fm10k_ring *rx_ring,
        if (!l2_accel)
                skb_record_rx_queue(skb, rx_ring->queue_index);
        else
-               macvlan_count_rx(netdev_priv(dev), skb->len + ETH_HLEN, true,
-                                false);
+               macvlan_count_rx(netdev_priv(dev), skb_shinfo(skb)->gso_segs ?: 
1,
+                                skb->len + ETH_HLEN, true, false);
 
        skb->protocol = eth_type_trans(skb, dev);
 }
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c 
b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 49a4ea38eb07..474e72ec68b0 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1704,8 +1704,8 @@ void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
        if (netif_is_ixgbe(dev))
                skb_record_rx_queue(skb, rx_ring->queue_index);
        else
-               macvlan_count_rx(netdev_priv(dev), skb->len + ETH_HLEN, true,
-                                false);
+               macvlan_count_rx(netdev_priv(dev), skb_shinfo(skb)->gso_segs ?: 
1,
+                                skb->len + ETH_HLEN, true, false);
 
        skb->protocol = eth_type_trans(skb, dev);
 }
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index fc8d5f1ee1ad..ab8743777897 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -289,7 +289,8 @@ static void macvlan_broadcast(struct sk_buff *skb,
                                        nskb, vlan, eth,
                                        mode == MACVLAN_MODE_BRIDGE) ?:
                                      netif_rx_ni(nskb);
-                       macvlan_count_rx(vlan, skb->len + ETH_HLEN,
+                       macvlan_count_rx(vlan, skb_shinfo(skb)->gso_segs ?: 1,
+                                        skb->len + ETH_HLEN,
                                         err == NET_RX_SUCCESS, true);
                }
        }
@@ -418,7 +419,8 @@ static void macvlan_forward_source_one(struct sk_buff *skb,
                nskb->pkt_type = PACKET_HOST;
 
        ret = netif_rx(nskb);
-       macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false);
+       macvlan_count_rx(vlan, skb_shinfo(skb)->gso_segs ?: 1, len,
+                        ret == NET_RX_SUCCESS, false);
 }
 
 static void macvlan_forward_source(struct sk_buff *skb,
@@ -505,7 +507,8 @@ static rx_handler_result_t macvlan_handle_frame(struct 
sk_buff **pskb)
        ret = NET_RX_SUCCESS;
        handle_res = RX_HANDLER_ANOTHER;
 out:
-       macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false);
+       macvlan_count_rx(vlan, skb_shinfo(skb)->gso_segs ?: 1, len,
+                        ret == NET_RX_SUCCESS, false);
        return handle_res;
 }
 
@@ -553,7 +556,7 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
                                      struct net_device *dev)
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
-       unsigned int len = skb->len;
+       unsigned int len = qdisc_skb_cb(skb)->pkt_len;
        int ret;
 
        if (unlikely(netpoll_tx_running(dev)))
@@ -566,7 +569,7 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
 
                pcpu_stats = this_cpu_ptr(vlan->pcpu_stats);
                u64_stats_update_begin(&pcpu_stats->syncp);
-               pcpu_stats->tx_packets++;
+               pcpu_stats->tx_packets += skb_shinfo(skb)->gso_segs ?: 1;
                pcpu_stats->tx_bytes += len;
                u64_stats_update_end(&pcpu_stats->syncp);
        } else {
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 9a10029caf83..06880a61cab9 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -64,7 +64,7 @@ static void macvtap_count_rx_dropped(struct tap_dev *tap)
        struct macvtap_dev *vlantap = container_of(tap, struct macvtap_dev, 
tap);
        struct macvlan_dev *vlan = &vlantap->vlan;
 
-       macvlan_count_rx(vlan, 0, 0, 0);
+       macvlan_count_rx(vlan, 1, 0, 0, 0);
 }
 
 static void macvtap_update_features(struct tap_dev *tap,
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
index 2e55e4cdbd8a..0f592925c559 100644
--- a/include/linux/if_macvlan.h
+++ b/include/linux/if_macvlan.h
@@ -37,15 +37,15 @@ struct macvlan_dev {
 };
 
 static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
-                                   unsigned int len, bool success,
-                                   bool multicast)
+                                   unsigned int packets, unsigned int len,
+                                   bool success, bool multicast)
 {
        if (likely(success)) {
                struct vlan_pcpu_stats *pcpu_stats;
 
                pcpu_stats = this_cpu_ptr(vlan->pcpu_stats);
                u64_stats_update_begin(&pcpu_stats->syncp);
-               pcpu_stats->rx_packets++;
+               pcpu_stats->rx_packets += packets;
                pcpu_stats->rx_bytes += len;
                if (multicast)
                        pcpu_stats->rx_multicast++;
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index a313165e7a67..3297eac36541 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -4,6 +4,7 @@
 #include <linux/if_vlan.h>
 #include <linux/netpoll.h>
 #include <linux/export.h>
+#include <net/sch_generic.h>
 #include "vlan.h"
 
 bool vlan_do_receive(struct sk_buff **skbp)
@@ -62,7 +63,7 @@ bool vlan_do_receive(struct sk_buff **skbp)
        rx_stats = this_cpu_ptr(vlan_dev_priv(vlan_dev)->vlan_pcpu_stats);
 
        u64_stats_update_begin(&rx_stats->syncp);
-       rx_stats->rx_packets++;
+       rx_stats->rx_packets += skb_shinfo(skb)->gso_segs ?: 1;
        rx_stats->rx_bytes += skb->len;
        if (skb->pkt_type == PACKET_MULTICAST)
                rx_stats->rx_multicast++;
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index b2d9c8f27cd7..0e4aca7d594f 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -124,7 +124,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff 
*skb,
        }
 
        skb->dev = vlan->real_dev;
-       len = skb->len;
+       len = qdisc_skb_cb(skb)->pkt_len;
        if (unlikely(netpoll_tx_running(dev)))
                return vlan_netpoll_send_skb(vlan, skb);
 
@@ -135,7 +135,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff 
*skb,
 
                stats = this_cpu_ptr(vlan->vlan_pcpu_stats);
                u64_stats_update_begin(&stats->syncp);
-               stats->tx_packets++;
+               stats->tx_packets += skb_shinfo(skb)->gso_segs ?: 1;
                stats->tx_bytes += len;
                u64_stats_update_end(&stats->syncp);
        } else {
-- 
2.19.2

Reply via email to