With GRO/LRO processing, there is a problem because Ip[6]InReceives SNMP
counters do not count the number of frames, but number of aggregated
segments.
Its probably too late to change this now.
This patch adds four new counters, tracking number of frames, regardless
of LRO/GRO, and on a per ECN status basis, for IPv4 and IPv6.
Ip[6]NoECTPkts : Number of packets received with NOECT
Ip[6]ECT1Pkts  : Number of packets received with ECT(1)
Ip[6]ECT0Pkts  : Number of packets received with ECT(0)
Ip[6]CEPkts    : Number of packets received with Congestion Experienced
lph37:~# nstat | egrep "Pkts|InReceive"
IpInReceives                    
1634137            0.0
Ip6InReceives                   
3714107            0.0
Ip6InNoECTPkts                  19205              0.0
Ip6InECT0Pkts                   
52651828           0.0
IpExtInNoECTPkts                33630              0.0
IpExtInECT0Pkts                 
15581379           0.0
IpExtInCEPkts                   6                  0.0
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
        IPSTATS_MIB_INBCASTOCTETS,              /* InBcastOctets */
        IPSTATS_MIB_OUTBCASTOCTETS,             /* OutBcastOctets */
        IPSTATS_MIB_CSUMERRORS,                 /* InCsumErrors */
+       IPSTATS_MIB_NOECTPKTS,                  /* InNoECTPkts */
+       IPSTATS_MIB_ECT1PKTS,                   /* InECT1Pkts */
+       IPSTATS_MIB_ECT0PKTS,                   /* InECT0Pkts */
+       IPSTATS_MIB_CEPKTS,                     /* InCEPkts */
        __IPSTATS_MIB_MAX
 };
 
 
 #include <net/icmp.h>
 #include <net/raw.h>
 #include <net/checksum.h>
+#include <net/inet_ecn.h>
 #include <linux/netfilter_ipv4.h>
 #include <net/xfrm.h>
 #include <linux/mroute.h>
        if (iph->ihl < 5 || iph->version != 4)
                goto inhdr_error;
 
+       BUILD_BUG_ON(IPSTATS_MIB_ECT1PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_1);
+       BUILD_BUG_ON(IPSTATS_MIB_ECT0PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_0);
+       BUILD_BUG_ON(IPSTATS_MIB_CEPKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_CE);
+       IP_ADD_STATS_BH(dev_net(dev),
+                       IPSTATS_MIB_NOECTPKTS + (iph->tos & INET_ECN_MASK),
+                       max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs));
+
        if (!pskb_may_pull(skb, iph->ihl*4))
                goto inhdr_error;
 
 
        SNMP_MIB_SENTINEL
 };
 
-/* Following RFC4293 items are displayed in /proc/net/netstat */
+/* Following items are displayed in /proc/net/netstat */
 static const struct snmp_mib snmp4_ipextstats_list[] = {
        SNMP_MIB_ITEM("InNoRoutes", IPSTATS_MIB_INNOROUTES),
        SNMP_MIB_ITEM("InTruncatedPkts", IPSTATS_MIB_INTRUNCATEDPKTS),
        SNMP_MIB_ITEM("OutMcastOctets", IPSTATS_MIB_OUTMCASTOCTETS),
        SNMP_MIB_ITEM("InBcastOctets", IPSTATS_MIB_INBCASTOCTETS),
        SNMP_MIB_ITEM("OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS),
+       /* Non RFC4293 fields */
        SNMP_MIB_ITEM("InCsumErrors", IPSTATS_MIB_CSUMERRORS),
+       SNMP_MIB_ITEM("InNoECTPkts", IPSTATS_MIB_NOECTPKTS),
+       SNMP_MIB_ITEM("InECT1Pkts", IPSTATS_MIB_ECT1PKTS),
+       SNMP_MIB_ITEM("InECT0Pkts", IPSTATS_MIB_ECT0PKTS),
+       SNMP_MIB_ITEM("InCEPkts", IPSTATS_MIB_CEPKTS),
        SNMP_MIB_SENTINEL
 };
 
 
 #include <net/ip6_route.h>
 #include <net/addrconf.h>
 #include <net/xfrm.h>
-
+#include <net/inet_ecn.h>
 
 
 int ip6_rcv_finish(struct sk_buff *skb)
        if (hdr->version != 6)
                goto err;
 
+       IP6_ADD_STATS_BH(dev_net(dev), idev,
+                        IPSTATS_MIB_NOECTPKTS +
+                               (ipv6_get_dsfield(hdr) & INET_ECN_MASK),
+                        max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs));
        /*
         * RFC4291 2.5.3
         * A packet received on an interface with a destination address
 
        SNMP_MIB_ITEM("Ip6InBcastOctets", IPSTATS_MIB_INBCASTOCTETS),
        SNMP_MIB_ITEM("Ip6OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS),
        /* IPSTATS_MIB_CSUMERRORS is not relevant in IPv6 (no checksum) */
+       SNMP_MIB_ITEM("Ip6InNoECTPkts", IPSTATS_MIB_NOECTPKTS),
+       SNMP_MIB_ITEM("Ip6InECT1Pkts", IPSTATS_MIB_ECT1PKTS),
+       SNMP_MIB_ITEM("Ip6InECT0Pkts", IPSTATS_MIB_ECT0PKTS),
+       SNMP_MIB_ITEM("Ip6InCEPkts", IPSTATS_MIB_CEPKTS),
        SNMP_MIB_SENTINEL
 };