diff -r -U 4 a/include/net/ip.h b/include/net/ip.h
--- a/include/net/ip.h  2013-08-27 17:15:42.952712200 +0300
+++ b/include/net/ip.h  2013-08-27 17:15:43.027698865 +0300
@@ -189,13 +189,20 @@
 #define IP_ADD_STATS(net, field, val)  
SNMP_ADD_STATS((net)->mib.ip_statistics, field, val)
 #define IP_ADD_STATS_BH(net, field, val) 
SNMP_ADD_STATS_BH((net)->mib.ip_statistics, field, val)
 #define IP_UPD_PO_STATS(net, field, val) 
SNMP_UPD_PO_STATS((net)->mib.ip_statistics, field, val)
 #define IP_UPD_PO_STATS_BH(net, field, val) 
SNMP_UPD_PO_STATS_BH((net)->mib.ip_statistics, field, val)
-#define NET_INC_STATS(net, field)      
SNMP_INC_STATS((net)->mib.net_statistics, field)
-#define NET_INC_STATS_BH(net, field)   
SNMP_INC_STATS_BH((net)->mib.net_statistics, field)
-#define NET_INC_STATS_USER(net, field)         
SNMP_INC_STATS_USER((net)->mib.net_statistics, field)
-#define NET_ADD_STATS_BH(net, field, adnd) 
SNMP_ADD_STATS_BH((net)->mib.net_statistics, field, adnd)
-#define NET_ADD_STATS_USER(net, field, adnd) 
SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd)
+
+#define __NET_INC_STATS(net, field)     
SNMP_INC_STATS((net)->mib.net_statistics, field)
+#define __NET_INC_STATS_BH(net, field)  
SNMP_INC_STATS_BH((net)->mib.net_statistics, field)
+#define __NET_INC_STATS_USER(net, field)        
SNMP_INC_STATS_USER((net)->mib.net_statistics, field)
+#define __NET_ADD_STATS_BH(net, field, adnd) 
SNMP_ADD_STATS_BH((net)->mib.net_statistics, field, adnd)
+#define __NET_ADD_STATS_USER(net, field, adnd) 
SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd)
+
+#define NET_INC_STATS(net, field) __NET_INC_STATS(net, field)
+#define NET_INC_STATS_BH(net, field)  __NET_INC_STATS_BH(net, field)
+#define NET_INC_STATS_USER(net, field) __NET_INC_STATS_USER(net, field)
+#define NET_ADD_STATS_BH(net, field, adnd) __NET_ADD_STATS_BH(net, field, adnd)
+#define NET_ADD_STATS_USER(net, field, adnd) __NET_ADD_STATS_USER(net, field, 
adnd)
 
 extern unsigned long snmp_fold_field(void *mib[], int offt);
 extern int snmp_mib_init(void *ptr[2], size_t mibsize);
 extern void snmp_mib_free(void *ptr[2]);
diff -r -U 4 a/include/net/stat_sk_hashtable.h b/include/net/stat_sk_hashtable.h
--- a/include/net/stat_sk_hashtable.h   2013-08-27 17:15:42.958691937 +0300
+++ b/include/net/stat_sk_hashtable.h   2013-08-27 17:15:43.041673380 +0300
@@ -0,0 +1,664 @@
+/*
+ *             Per-ip statistics socket interface to hashtables
+ *
+ *             Menny Hamburger<menny_hambur...@dell.com>
+ */
+
+#ifndef _STAT_SK_HASHTABLE_H
+#define _STAT_SK_HASHTABLE_H
+
+#ifdef CONFIG_NET_IPV4_SOCK_STATS
+
+#include <net/ipv6.h>
+#include <net/stat_hashtable.h>
+
+#define STAT_NET_INITVAL(net) 0
+/* Not sure if we need an intival different than 0 - leave it here in case we 
do */
+//#define STAT_NET_INITVAL(net)        inet_ehash_secret + net_hash_mix(net)
+#define STAT_SOCK_INITVAL(sk)  STAT_NET_INITVAL(sock_net(sk))
+#define STAT_SK_INITVAL                STAT_SOCK_INITVAL(sk)
+
+/* This function is used to pass insert calls onto stat_hash_get_entry given a 
pointer to the cookie contained in sock. */
+extern int stat_hash_insert(u32 initval, struct stat_hash_addr *addr, bool 
existing, 
+                           int alloc_flag, struct stat_hash_cookie *cookie);
+
+#define STAT_SK_PREFIX "stat_sk_hash: "
+
+#ifdef CONFIG_NET_IPV4_STAT_HASHTABLE_DEBUG
+#define stat_sk_dprintk(level, format...) \
+       if ((stat_hash_debug_level) >= (level)) \
+               printk(KERN_DEBUG STAT_SK_PREFIX format)
+#else
+#define stat_sk_dprintk(level, format...)
+#endif
+
+
+/* Direction of data transfer - used when inserting a new entry into the hash 
*/
+enum {
+       STAT_HASH_SK_IN = 1,
+       STAT_HASH_SK_OUT,
+       STAT_HASH_SK_DONTCARE,
+       STAT_HASH_SK_INOUT,
+};
+
+/*
+ * Filter out addresses from entering the hashtable.
+ * The current filter code tests that the the remote address is not on the 
loopback.
+ * When the remote address is on the loopback, the address is filtered out by 
default because of the potential overhead 
+ * of updating their counters - specifically counters that are incremented 
each time a packet comes in or goes out.
+ * net_stat_hash_loopback can be toggled via sysctl to allow loopback remote 
addresses to enter the hash.
+ * The direction is needed in order to identify the remote address from the 
two addresses defined in struct stat_hash_addr.
+ */
+extern int stat_hash_filter_addr(struct stat_hash_addr *addr, u8 direction);
+
+/* Access the cookie contained in the socket */
+static inline struct stat_hash_cookie *
+sk_cookie(struct sock *sk)
+{
+       if (sk == NULL)
+               return NULL;
+
+       return &sk_extended(sk)->hash_cookie;
+}
+
+/* Clone the cookie from one socket to another */
+static inline void 
+sk_cookie_clone(struct sock *newsk, struct sock *sk)
+{
+       stat_hash_copy_cookie_atomic(sk_cookie(newsk), sk_cookie(sk));
+}
+
+static inline bool 
+sk_operation_allowed(u16 family)
+{
+       /* 
+        * We only start inserting into the hashtable when it is specifically 
requested by the user.
+        * Control is done using 
stat_hash_start_data_collection/stat_hash_stop_data_collection methods.
+        */
+        if (!stat_hash_data_collection_started) {
+                stat_sk_dprintk(STAT_HASH_MESSAGE_DEBUG, "data collection has 
not been started\n");
+                return false;
+        }
+
+       /* Data collection can be toggled on and off via sysctl */
+        if (!net_stat_hashtable) {
+                stat_sk_dprintk(STAT_HASH_MESSAGE_DEBUG, "hashing is 
disabled\n");
+                return false;
+        }
+
+       /* IPV6 support */
+       if (family == AF_INET6) {
+#ifdef CONFIG_IPV6_STAT_HASHTABLES
+               if (net_stat_hashtable_ipv6 == 0) {
+                       stat_sk_dprintk(STAT_HASH_MESSAGE_DEBUG, "disabled 
statistics hashing for address family %d\n", family);
+                       return false;
+               }
+#else
+               stat_sk_dprintk(STAT_HASH_MESSAGE_NOTICE, "unsupported family 
%d\n", family);
+               return false;
+#endif
+       }
+
+       return true;    
+}
+
+/* Process IPV4 address before inserting it into the hashtable, possibly 
filtering it out */
+static inline struct stat_hash_addr *
+sk_addr_ipv4(u16 family, __be32 saddr, __be32 daddr, struct stat_hash_addr 
*addr, u8 direction)
+{
+       if (!sk_operation_allowed(family)) 
+               return NULL;
+
+       addr->family = family;
+       addr->saddr.ip = saddr;
+       addr->daddr.ip = daddr;
+
+       if ((direction == STAT_HASH_SK_DONTCARE) || 
(stat_hash_filter_addr(addr, direction) == 0))
+               return addr;
+        
+
+       return NULL;
+}
+
+#ifdef CONFIG_IPV6_STAT_HASHTABLES
+/* Process IPV6 address before inserting it into the hashtable, possibly 
filtering out */
+static inline struct stat_hash_addr *
+sk_addr_ipv6(u16 family, struct in6_addr *saddr, struct in6_addr *daddr, 
struct stat_hash_addr *addr, u8 direction)
+{
+       if (!sk_operation_allowed(family))
+               return NULL;
+
+       addr->family = family;
+       ipv6_addr_copy(&addr->saddr.in6, saddr);
+       ipv6_addr_copy(&addr->daddr.in6, daddr);
+
+       if ((direction == STAT_HASH_SK_DONTCARE) || 
(stat_hash_filter_addr(addr, direction) == 0))
+               return addr;
+
+        return NULL;
+}
+#endif
+
+/* Pre-process address taken from inet_sk/inet6_sk of the socket */
+static inline struct stat_hash_addr *
+sk_addr_inet(struct sock *sk, struct stat_hash_addr *addr, u8 direction)
+{
+       struct stat_hash_addr *addr_out = NULL;
+
+       switch (sk->sk_family) {
+               case AF_INET:
+                       addr_out = sk_addr_ipv4(sk->sk_family, 
inet_sk(sk)->saddr, inet_sk(sk)->daddr, addr, direction);
+                       break;
+#ifdef CONFIG_IPV6_STAT_HASHTABLES
+               case AF_INET6:
+                       addr_out = sk_addr_ipv6(sk->sk_family, 
&inet6_sk(sk)->saddr, &inet6_sk(sk)->daddr, addr, direction);
+                       break;
+#endif
+               default:
+                       break;
+
+       }
+
+       return addr_out;
+}
+
+/* 
+ * Acquire address from socket buffer so we can use it to lookup the entry in 
the hash table.
+ * We use this when a a socket (and it's containing cookie) are not available.
+ */
+static inline struct stat_hash_addr *
+skb_addr(struct sk_buff *skb, struct stat_hash_addr *addr)
+{
+       if (skb == NULL)
+               return NULL;
+
+       if ((ntohs(skb->protocol) == ETH_P_IP) || (skb->protocol == ETH_P_IP)) {
+               addr->family = AF_INET;
+               addr->saddr.ip = ip_hdr(skb)->saddr;
+               addr->daddr.ip = ip_hdr(skb)->daddr;
+               return addr;
+       }
+#ifdef CONFIG_IPV6_STAT_HASHTABLES
+       if (net_stat_hashtable_ipv6 != 0) {
+               if ((ntohs(skb->protocol) == ETH_P_IPV6) || (skb->protocol == 
ETH_P_IPV6)) {
+                       addr->family = AF_INET6;
+                       ipv6_addr_copy(&addr->saddr.in6, &ipv6_hdr(skb)->saddr);
+                       ipv6_addr_copy(&addr->daddr.in6, &ipv6_hdr(skb)->daddr);
+                       return addr;
+               }
+       }
+#endif
+
+       return NULL;
+}
+
+/* Init the hash cookie contained in the socket */
+#define STAT_HASH_SK_INIT(sk)    STAT_INIT_COOKIE(sk_cookie(sk))       
+#define STAT_HASH_COOKIE_CLONE(newsk, sk)      \
+                       sk_cookie_clone((struct sock *) (newsk), (struct sock 
*) (sk))
+
+/*
+ * Basic macro used for acquiering a cookie of either an existing entry or a 
new entry in the hashtable.
+ * STAT_COOKIE_EMPTY makes sure that we do not operate on a socket that 
contains a non zero cookie 
+ * (non zero sequence number). This also ensures that when cookie is polluted 
we won't use it again during
+ * the lifetime of the socket.
+ */
+#define STAT_HASH_SK_INSERT_BASE(sk, direction, existing, alloc_flag)  \
+                       if (STAT_COOKIE_EMPTY(sk_cookie(sk))) \
+                               do { \
+                                       struct stat_hash_addr addr, *addr_in; \
+                                       addr_in = sk_addr_inet(sk, &addr, 
direction); \
+                                       if (addr_in) \
+                                               
stat_hash_insert(STAT_SK_INITVAL, (&addr), existing, \
+                                                                alloc_flag, 
sk_cookie(sk)); \
+                               }  while (0)
+
+
+
+/* 
+ * Insert a new address entry into the hash if it doesn't already exist, 
possibly
+ * allocating the per CPU counters in one or more of the mappings.
+ * Should not be called from within an atomic context or inside a spinlock.
+ */
+#define STAT_HASH_SK_INSERT_NONATOMIC(sk, direction) \
+       STAT_HASH_SK_INSERT_BASE(sk, direction, false, 
STAT_HASH_ALLOC_FLAG_ALLOC)
+
+
+/*
+ *  Insert a new address entry into the hash if it doesn't already exist, 
possibly 
+ *  allocating the per CPU counters in one or more of the mappings.
+ *  Should be used withing spinlocks or when we are sure we are in an atomic 
context.
+ */
+#define STAT_HASH_SK_INSERT_ATOMIC(sk, direction) \
+       STAT_HASH_SK_INSERT_BASE(sk, direction, false, 
STAT_HASH_ALLOC_FLAG_DELAYED_ALLOC) 
+
+/* 
+ * Insert a new address entry into the hash if it doesn't already exist, 
possibly
+ * allocating the per CPU counters in one or more of the mappings.
+ * If call is from is an atomic context, per CPU allocation is done in delayed 
work.
+ * Not intended to be used within spinlocks.
+ */
+#define STAT_HASH_SK_INSERT(sk, direction) \
+       STAT_HASH_SK_INSERT_BASE(sk, direction, false, \
+                        (in_atomic() ? STAT_HASH_ALLOC_FLAG_DELAYED_ALLOC : \
+                                       STAT_HASH_ALLOC_FLAG_ALLOC))
+
+
+/*
+ * Store cookie associated with an existing entry in the hashtable, possibly 
+ * allocating the per CPU counters in one or more of the mappings.
+ * Should not be called from within an atomic context or inside a spinlock.
+ */
+#define STAT_HASH_SK_INSERT_EXISTING_NONATOMIC(sk) \
+       STAT_HASH_SK_INSERT_BASE(sk, STAT_HASH_SK_DONTCARE, true, 
STAT_HASH_ALLOC_FLAG_ALLOC)   
+
+/*
+ * Store cookie associated with an existing entry in the hashtable, possibly
+ * allocating the per CPU counters in one or more of the mappings with delayed 
work.
+ * Should be used withing spinlocks or when we are sure we are in an atomic 
context.
+ */
+#define STAT_HASH_SK_INSERT_EXISTING_ATOMIC(sk) \
+       STAT_HASH_SK_INSERT_BASE(sk, STAT_HASH_SK_DONTCARE, true, 
STAT_HASH_ALLOC_FLAG_DELAYED_ALLOC)
+
+/*
+ * Store cookie associated with an existing entry in the hashtable, possibly
+ * allocating the per CPU counters in one or more of the mappings.
+ * If call is from is an atomic context, per CPU allocation is done in delayed 
work.
+ * Not intended to be used within spinlocks.
+ */
+#define STAT_HASH_SK_INSERT_EXISTING(sk) \
+       STAT_HASH_SK_INSERT_BASE(sk, STAT_HASH_SK_DONTCARE, true, \
+                        (in_atomic() ? STAT_HASH_ALLOC_FLAG_DELAYED_ALLOC : \
+                                       STAT_HASH_ALLOC_FLAG_ALLOC))
+
+/* 
+ * Store cookie associated with an existing entry in the hashtable without 
modifying
+ * the entry. This is used in those frequent and sensitive places where we 
want to make sure that the socket 
+ * contains a cookie, but we don't want any per CPU allocation to take place.
+ * It can be used several times on the same socket due to STAT_COOKIE_EMPTY 
test.
+ */
+#define STAT_HASH_SK_INSERT_EXISTING_NOALLOC(sk) \
+       STAT_HASH_SK_INSERT_BASE(sk, STAT_HASH_SK_DONTCARE, true, 
STAT_HASH_ALLOC_FLAG_NOALLOC)
+                                         
+
+/*************************************************************************************
+ * Replacement to NET_INC, NET_ADD macros to interract with hashed Linux MIB 
counters.
+ 
*************************************************************************************/
+
+/* Macros that interract with Linux MIB via cookie contained in struct sock */
+
+/* Update Linux MIB counter via a "struct sock *" of any name */
+#define __NET_INC_SOCK_STATS(sk, net, field)  \
+       if (snmp_map_allow_update(SNMP_LINUX_MIB, field)) \
+               SNMP_INC_STATS_HASH(sk_cookie(sk), lnx_stats, field)
+#define __NET_INC_SOCK_STATS_BH(sk, net, field)  \
+       if (snmp_map_allow_update(SNMP_LINUX_MIB, field)) \
+               SNMP_INC_STATS_HASH_BH(sk_cookie(sk), lnx_stats, field)
+#define __NET_INC_SOCK_STATS_USER(sk, net, field)  \
+       if (snmp_map_allow_update(SNMP_LINUX_MIB, field)) \
+               SNMP_INC_STATS_HASH_USER(sk_cookie(sk), lnx_stats, field)
+#define __NET_ADD_SOCK_STATS_BH(sk, net, field, adnd) \
+       if (snmp_map_allow_update(SNMP_LINUX_MIB, field)) \
+               SNMP_ADD_STATS_HASH_BH(sk_cookie(sk), lnx_stats, field, adnd)
+#define __NET_ADD_SOCK_STATS_USER(sk, net, field, adnd) \
+       if (snmp_map_allow_update(SNMP_LINUX_MIB, field)) \
+               SNMP_ADD_STATS_HASH_USER(sk_cookie(sk), lnx_stats, field, adnd)
+
+
+/* Update Linux MIB counter via a "struct sock *" of any name + update 
original counter */
+#define NET_INC_SOCK_STATS(sk, net, field)  \
+       do { \
+               __NET_INC_STATS(net, field); \
+               __NET_INC_SOCK_STATS((sk), net, field); \
+        } while (0)
+#define NET_INC_SOCK_STATS_BH(sk, net, field) \
+       do { \
+               __NET_INC_STATS_BH(net, field); \
+               __NET_INC_SOCK_STATS_BH((sk), net, field); \
+       } while (0)
+#define NET_INC_SOCK_STATS_USER(sk, net, field) \
+       do { \
+               __NET_INC_STATS_USER(net, field); \
+               __NET_INC_SOCK_STATS_USER((sk), net, field); \
+       } while (0)
+#define NET_ADD_SOCK_STATS_BH(sk, net, field, adnd) \
+       do { \
+               __NET_ADD_STATS_BH(net, field, adnd); \
+               __NET_ADD_SOCK_STATS_BH((sk), net, field, adnd); \
+       } while (0)
+#define NET_ADD_SOCK_STATS_USER(sk, net, field, adnd) \
+       do { \
+               __NET_ADD_STATS_USER(net, field, adnd); \
+               __NET_ADD_SOCK_STATS_USER((sk), net, field, adnd); \
+       } while (0)
+
+/*
+ * Update Linux MIB counter via a "struct sock *" named sk.
+ * This is the case in most situations so these macros are used for overriding 
the originals.
+ */
+#define NET_INC_SK_STATS(net, field)                 NET_INC_SOCK_STATS(sk, 
net, field)
+#define NET_INC_SK_STATS_BH(net, field)              NET_INC_SOCK_STATS_BH(sk, 
net, field)
+#define NET_INC_SK_STATS_USER(net, field)            
NET_INC_SOCK_STATS_USER(sk, net, field)
+#define NET_ADD_SK_STATS_BH(net, field, adnd)        NET_ADD_SOCK_STATS_BH(sk, 
net, field, adnd)
+#define NET_ADD_SK_STATS_USER(net, field, adnd)      
NET_ADD_SOCK_STATS_USER(sk, net, field, adnd)
+
+
+/* Macros that interract with Linux MIB via socket buffer */
+
+/* Update Linux MIB counter via a "struct sk_buff *" of any name */
+#define __NET_INC_SKBUFF_STATS(skb, net, field) \
+       do { \
+               if (snmp_map_allow_update(SNMP_LINUX_MIB, field))  { \
+                       struct stat_hash_addr addr, *addr_in; \
+                       addr_in = skb_addr((skb), &addr); \
+                       if (addr_in) \
+                               SNMP_INC_STATS_HASH_ADDR(STAT_NET_INITVAL(net), 
addr_in, lnx_stats, field); \
+               } \
+       } while (0)
+#define __NET_INC_SKBUFF_STATS_BH(skb, net, field) \
+       do { \
+               if (snmp_map_allow_update(SNMP_LINUX_MIB, field))  { \
+                       struct stat_hash_addr addr, *addr_in; \
+                       addr_in = skb_addr((skb), &addr); \
+                       if (addr_in) \
+                               
SNMP_INC_STATS_HASH_ADDR_BH(STAT_NET_INITVAL(net), addr_in, lnx_stats, field); \
+               } \
+       } while (0)
+#define __NET_INC_SKBUFF_STATS_USER(skb, net, field) \
+       do { \
+               if (snmp_map_allow_update(SNMP_LINUX_MIB, field))  { \
+                       struct stat_hash_addr addr, *addr_in; \
+                       addr_in = skb_addr((skb), &addr); \
+                       if (addr_in) \
+                               
SNMP_INC_STATS_HASH_ADDR_USER(STAT_NET_INITVAL(net), addr_in, lnx_stats, 
field); \
+               } \
+       } while (0)
+#define __NET_ADD_SKBUFF_STATS_BH(skb, net, field, adnd) \
+       do { \
+               if (snmp_map_allow_update(SNMP_LINUX_MIB, field))  { \
+                       struct stat_hash_addr addr, *addr_in; \
+                       addr_in = skb_addr((skb), &addr); \
+                       if (addr_in) \
+                               
SNMP_ADD_STATS_HASH_ADDR_BH(STAT_NET_INITVAL(net), addr_in, lnx_stats, field, 
adnd); \
+               } \
+       } while (0)
+#define __NET_ADD_SKBUFF_STATS_USER(skb, net, field, adnd) \
+       do { \
+               if (snmp_map_allow_update(SNMP_LINUX_MIB, field))  { \
+                       struct stat_hash_addr addr, *addr_in; \
+                       addr_in = skb_addr((skb), &addr); \
+                       if (addr_in) \
+                               
SNMP_ADD_STATS_HASH_ADDR_USER(STAT_NET_INITVAL(net), addr_in, lnx_stats, field, 
adnd); \
+               } \
+       } while (0)
+
+
+/* Update Linux MIB counter via a "struct sk_buff *" of any name + update 
original counter */
+#define NET_INC_SKBUFF_STATS(skb, field) \
+       do { \
+               __NET_INC_STATS(net, field); \
+               __NET_INC_SKBUFF_STATS((skb), net, field); \
+       } while (0)
+#define NET_INC_SKBUFF_STATS_BH(skb, net, field) \
+       do { \
+               __NET_INC_STATS_BH(net, field); \
+               __NET_INC_SKBUFF_STATS_BH((skb), net, field); \
+       } while (0)
+#define NET_INC_SKBUFF_STATS_USER(skb, net, field) \
+       do { \
+               __NET_INC_STATS_USER(net, field); \
+               __NET_INC_SKBUFF_STATS_USER((skb), net, field); \
+       } while (0)
+#define NET_ADD_SKBUFF_STATS_BH(skb, net, field, adnd) \
+       do { \
+               __NET_ADD_STATS_BH(net, field, adnd); \
+               __NET_ADD_SKBUFF_STATS_BH((skb), net, field, adnd); \
+       } while (0)
+#define NET_ADD_SKBUFF_STATS_USER(skb, net, field, adnd) \
+       do { \
+               __NET_ADD_STATS_USER(net, field, adnd); \
+               __NET_ADD_SKBUFF_STATS_USER((skb), net, field, adnd); \
+       } while (0)
+
+
+/* Update Linux MIB counter via a "struct sk_buff *" named skb. */
+#define NET_INC_SKB_STATS(net, field)                  
NET_INC_SKBUFF_STATS(skb, net, field)
+#define NET_INC_SKB_STATS_BH(net, field)               
NET_INC_SKBUFF_STATS_BH(skb, net, field)
+#define NET_INC_SKB_STATS_USER(net, field)             
NET_INC_SKBUFF_STATS_USER(skb, net, field)
+#define NET_ADD_SKB_STATS_BH(net, field, adnd)         
NET_ADD_SKBUFF_STATS_BH(skb, net, field, adnd)
+#define NET_ADD_SKB_STATS_USER(net, field, adnd)       
NET_ADD_SKBUFF_STATS_USER(skb, net, field, adnd)
+
+
+/*********************************************************************************************
+ * Replacement to TCP_INC, TCP_DEC, TCP__ADD macros to interract with hashed 
TCP MIB counters.
+ 
*********************************************************************************************/
+
+/* Macros that interract with TCP MIB via cookie contained in struct sock */
+
+/* Update TCP MIB counter via a "struct sock *" of any name */
+#define __TCP_INC_SOCK_STATS(sk, net, field)  \
+       if (snmp_map_allow_update(SNMP_TCP_MIB, field)) \
+               SNMP_INC_STATS_HASH(sk_cookie(sk), tcp_stats, field)
+#define __TCP_INC_SOCK_STATS_BH(sk, net, field)  \
+       if (snmp_map_allow_update(SNMP_TCP_MIB, field)) \
+               SNMP_INC_STATS_HASH_BH(sk_cookie(sk), tcp_stats, field)
+#define __TCP_INC_SOCK_STATS_USER(sk, net, field)  \
+       if (snmp_map_allow_update(SNMP_TCP_MIB, field)) \
+               SNMP_INC_STATS_HASH_USER(sk_cookie(sk), tcp_stats, field)
+#define __TCP_DEC_SOCK_STATS(sk, net, field)  \
+       if (snmp_map_allow_update(SNMP_TCP_MIB, field)) \
+               SNMP_DEC_STATS_HASH(sk_cookie(sk), tcp_stats, field)
+#define __TCP_ADD_SOCK_STATS_BH(sk, net, field, val)  \
+       if (snmp_map_allow_update(SNMP_TCP_MIB, field)) \
+               SNMP_ADD_STATS_HASH_BH(sk_cookie(sk), tcp_stats, field, val)
+#define __TCP_ADD_SOCK_STATS_USER(sk, net, field, val)  \
+       if (snmp_map_allow_update(SNMP_TCP_MIB, field)) \
+               SNMP_ADD_STATS_HASH_USER(sk_cookie(sk), tcp_stats, field, val)
+
+/* Update TCP MIB counter via a "struct sock *" of any name + update original 
counter */
+#define TCP_INC_SOCK_STATS(sk, net, field)  \
+       do { \
+               __TCP_INC_STATS(net, field); \
+               __TCP_INC_SOCK_STATS((sk), net, field); \
+       } while (0)
+#define TCP_INC_SOCK_STATS_BH(sk, net, field) \
+       do { \
+               __TCP_INC_STATS_BH(net, field); \
+               __TCP_INC_SOCK_STATS_BH((sk), net, field); \
+       } while (0)
+#define TCP_INC_SOCK_STATS_USER(sk, net, field) \
+       do { \
+               __TCP_INC_STATS_USER(net, field); \
+               __TCP_INC_SOCK_STATS_USER((sk), net, field); \
+       } while (0)
+#define TCP_DEC_SOCK_STATS(sk, net, field)  \
+       do { \
+               __TCP_DEC_STATS(net, field); \
+               __TCP_DEC_SOCK_STATS((sk), net, field); \
+       } while (0)
+#define TCP_ADD_SOCK_STATS_BH(sk, net, field, adnd) \
+       do { \
+               __TCP_ADD_STATS_BH(net, field, adnd); \
+               __TCP_ADD_SOCK_STATS_BH((sk), net, field, adnd); \
+       } while (0)
+#define TCP_ADD_SOCK_STATS_USER(sk, net, field, adnd) \
+       do { \
+               __TCP_ADD_STATS_USER(net, field, adnd); \
+               __TCP_ADD_SOCK_STATS_USER((sk), net, field, adnd); \
+       } while (0)
+
+/*
+ * Update TCP MIB counter via a "struct sock *" named sk.
+ * This is the case in most situations so these macros are used for overriding 
the originals.
+ */
+#define TCP_INC_SK_STATS(net, field)                   TCP_INC_SOCK_STATS(sk, 
net, field)
+#define TCP_INC_SK_STATS_BH(net, field)                        
TCP_INC_SOCK_STATS_BH(sk, net, field)
+#define TCP_INC_SK_STATS_USER(net, field)              
TCP_INC_SOCK_STATS_USER(sk, net, field)
+#define TCP_DEC_SK_STATS(net, field)                   TCP_DEC_SOCK_STATS(sk, 
net, field)
+#define TCP_ADD_SK_STATS_BH(net, field, adnd)          
TCP_ADD_SOCK_STATS_BH(sk, net, field, adnd)
+#define TCP_ADD_SK_STATS_USER(net, field, adnd)                
TCP_ADD_SOCK_STATS_USER(sk, net, field, adnd)
+
+/* Macros that interract with Linux TCP via socket buffer */
+
+/* Update TCP MIB counter via a "struct sk_buff *" of any name */
+#define __TCP_INC_SKBUFF_STATS(skb, net, field) \
+       do { \
+               if (snmp_map_allow_update(SNMP_TCP_MIB, field)) { \
+                       struct stat_hash_addr addr, *addr_in; \
+                       addr_in = skb_addr((skb), &addr); \
+                       if (addr_in) \
+                               SNMP_INC_STATS_HASH_ADDR(STAT_NET_INITVAL(net), 
addr_in, tcp_stats, field); \
+               } \
+       } while (0)
+#define __TCP_INC_SKBUFF_STATS_BH(skb, net, field) \
+       do { \
+               if (snmp_map_allow_update(SNMP_TCP_MIB, field)) { \
+                       struct stat_hash_addr addr, *addr_in; \
+                       addr_in = skb_addr((skb), &addr); \
+                       if (addr_in) \
+                               
SNMP_INC_STATS_HASH_ADDR_BH(STAT_NET_INITVAL(net), addr_in, tcp_stats, field); \
+               } \
+       } while (0)
+#define __TCP_INC_SKBUFF_STATS_USER(skb, net, field) \
+       do { \
+               if (snmp_map_allow_update(SNMP_TCP_MIB, field)) { \
+                       struct stat_hash_addr addr, *addr_in; \
+                       addr_in = skb_addr((skb), &addr); \
+                       if (addr_in) \
+                               
SNMP_INC_STATS_HASH_ADDR_USER(STAT_NET_INITVAL(net), addr_in, tcp_stats, 
field); \
+               } \
+       } while (0)
+#define __TCP_DEC_SKBUFF_STATS(skb, net, field) \
+       do { \
+               if (snmp_map_allow_update(SNMP_TCP_MIB, field)) { \
+                       struct stat_hash_addr addr, *addr_in; \
+                       addr_in = skb_addr((skb), &addr); \
+                       if (addr_in) \
+                               SNMP_DEC_STATS_HASH_ADDR(STAT_NET_INITVAL(net), 
addr_in, tcp_stats, field); \
+               } \
+       } while (0)
+#define __TCP_ADD_SKBUFF_STATS_BH(skb, net, field, adnd) \
+       do { \
+               if (snmp_map_allow_update(SNMP_TCP_MIB, field)) { \
+                       struct stat_hash_addr addr, *addr_in; \
+                       addr_in = skb_addr((skb), &addr); \
+                       if (addr_in) \
+                               
SNMP_ADD_STATS_HASH_ADDR_BH(STAT_NET_INITVAL(net), addr_in, tcp_stats, field, 
adnd); \
+               } \
+       } while (0)
+#define __TCP_ADD_SKBUFF_STATS_USER(skb, net, field, adnd) \
+       do { \
+               if (snmp_map_allow_update(SNMP_TCP_MIB, field)) { \
+                       struct stat_hash_addr addr, *addr_in; \
+                       addr_in = skb_addr((skb), &addr); \
+                       if (addr_in) \
+                               
SNMP_ADD_STATS_HASH_ADDR_USER(STAT_NET_INITVAL(net), addr_in, tcp_stats, field, 
adnd); \
+               } \
+       } while (0)
+
+
+/* Update TCP MIB counter via a "struct sk_buff *" of any name + update 
original counter */
+#define TCP_INC_SKBUFF_STATS(skb, net, field) \
+       do { \
+               __TCP_INC_STATS(net, field); \
+               __TCP_INC_SKBUFF_STATS((skb), net, field); \
+       } while (0)
+#define TCP_INC_SKBUFF_STATS_BH(skb, net, field) \
+       do { \
+               __TCP_INC_STATS_BH(net, field); \
+               __TCP_INC_SKBUFF_STATS_BH((skb), net, field); \
+       } while (0)
+#define TCP_INC_SKBUFF_STATS_USER(skb, net, field) \
+       do { \
+               __TCP_INC_STATS_USER(net, field); \
+               __TCP_INC_SKBUFF_STATS_USER((skb), net, field); \
+       } while (0)
+#define TCP_DEC_SKBUFF_STATS(skb, net, field) \
+       do { \
+               __TCP_DEC_STATS(net, field); \
+               __TCP_DEC_SKBUFF_STATS((skb), net, field); \
+       } while (0)
+#define TCP_ADD_SKBUFF_STATS_BH(skb, net, field, adnd) \
+       do { \
+               __TCP_ADD_STATS_BH(net, field, adnd); \
+               __TCP_ADD_SKBUFF_STATS_BH((skb), net, field, adnd); \
+       } while (0)
+#define TCP_ADD_SKBUFF_STATS_USER(skb, net, field, adnd) \
+       do { \
+               __TCP_ADD_STATS_USER(net, field, adnd); \
+               __TCP_ADD_SKBUFF_STATS_USER((skb), net, field, adnd); \
+       } while (0)
+
+
+/* Update TCP MIB counter via a "struct sk_buff *" named skb. */
+#define TCP_INC_SKB_STATS(net, field)                  
TCP_INC_SKBUFF_STATS(skb, net, field)
+#define TCP_INC_SKB_STATS_BH(net, field)               
TCP_INC_SKBUFF_STATS_BH(skb, net, field)
+#define TCP_INC_SKB_STATS_USER(net, field)             
TCP_INC_SKBUFF_STATS_USER(skb, net, field)
+#define TCP_DEC_SKB_STATS(net, field)                  
TCP_DEC_SKBUFF_STATS(skb, net, field)
+#define TCP_ADD_SKB_STATS_BH(net, field, adnd)         
TCP_ADD_SKBUFF_STATS_BH(skb, net, field, adnd)
+#define TCP_ADD_SKB_STATS_USER(net, field, adnd)       
TCP_ADD_SKBUFF_STATS_USER(skb, net, field, adnd)
+
+#else
+
+#define STAT_HASH_SK_INIT(sk) 
+#define STAT_HASH_COOKIE_CLONE(newsk, sk)                          
+#define STAT_HASH_SK_INSERT(sk, direction)
+#define STAT_HASH_SK_INSERT_ATOMIC(sk, direction)
+#define STAT_HASH_SK_INSERT_EXISTING(sk)
+#define STAT_HASH_SK_INSERT_EXISTING_NOALLOC(sk)
+
+#define NET_INC_SOCK_STATS(sk, net, field) __NET_INC_STATS(net, field)
+#define NET_INC_SOCK_STATS_BH(sk, net, field) __NET_INC_STATS_BH(net, field)
+#define NET_INC_SOCK_STATS_USER(sk, net, field) __NET_INC_STATS_USER(net, 
field)
+#define NET_ADD_SOCK_STATS_BH(sk, net, field, adnd) __NET_ADD_STATS_BH(net, 
field, adnd)
+#define NET_ADD_SOCK_STATS_USER(sk, net, field, adnd) 
__NET_ADD_STATS_USER(net, field, adnd)
+
+#define NET_INC_SK_STATS(net, field)  __NET_INC_STATS(net, field)
+#define NET_INC_SK_STATS_BH(net, field)  __NET_INC_STATS_BH(net, field)
+#define NET_INC_SK_STATS_USER(net, field)  __NET_INC_STATS_USER(net, field)
+#define NET_ADD_SK_STATS_BH(net, field, adnd)  __NET_ADD_STATS_BH(net, field, 
adnd)
+#define NET_ADD_SK_STATS_USER(net, field, adnd)  __NET_ADD_STATS_USER(net, 
field, adnd)
+
+#define NET_INC_SKBUFF_STATS(skb, net, field) __NET_INC_STATS(net, field)
+#define NET_INC_SKBUFF_STATS_BH(skb, net, field) __NET_INC_STATS_BH(net, field)
+#define NET_INC_SKBUFF_STATS_USER(skb, net, field) __NET_INC_STATS_USER(net, 
field)
+#define NET_ADD_SKBUFF_STATS_BH(skb, net, field, adnd) __NET_ADD_STATS_BH(net, 
field, adnd)
+#define NET_ADD_SKBUFF_STATS_USER(skb, net, field, adnd) 
__NET_ADD_STATS_USER(net, field, adnd)
+
+#define NET_INC_SKB_STATS(net, field)  __NET_INC_STATS(net, field)
+#define NET_INC_SKB_STATS_BH(net, field)   __NET_INC_STATS_BH(net, field)
+#define NET_INC_SKB_STATS_USER(net, field) __NET_INC_STATS_USER(net, field)
+#define NET_ADD_SKB_STATS_BH(net, field, adnd)  __NET_ADD_STATS_BH(net, field, 
adnd)
+#define NET_ADD_SKB_STATS_USER(net, field, adnd)  __NET_ADD_STATS_USER(net, 
field, adnd)
+
+#define TCP_INC_SOCK_STATS(sk, net, field) __TCP_INC_STATS(net, field)
+#define TCP_INC_SOCK_STATS_BH(sk, net, field) __TCP_INC_STATS_BH(net, field)
+#define TCP_INC_SOCK_STATS_USER(sk, net, field) __TCP_INC_STATS_USER(net, 
field)
+#define TCP_DEC_SOCK_STATS(sk, net, field) __TCP_DEC_STATS(net, field)
+#define TCP_ADD_SOCK_STATS_BH(sk, net, field, val) __TCP_ADD_STATS_BH(net, 
field, val)
+#define TCP_ADD_SOCK_STATS_USER(sk, net, field, val) __TCP_ADD_STATS_USER(net, 
field, val)
+
+#define TCP_INC_SK_STATS(net, field)  __TCP_INC_STATS(net, field)
+#define TCP_INC_SK_STATS_BH(net, field)  __TCP_INC_STATS_BH(net, field)
+#define TCP_INC_SK_STATS_USER(net, field)  __TCP_INC_STATS_USER(net, field)
+#define TCP_DEC_SK_STATS(net, field)  __TCP_DEC_STATS(net, field)
+#define TCP_ADD_SK_STATS_BH(net, field, val)  __TCP_ADD_STATS_BH(net, field, 
val)
+#define TCP_ADD_SK_STATS_USER(net, field, val)  __TCP_ADD_STATS_USER(net, 
field, val)
+
+#define TCP_INC_SKBUFF_STATS(skb, net, field) __TCP_INC_STATS(net, field)
+#define TCP_INC_SKBUFF_STATS_BH(skb, net, field) __TCP_INC_STATS_BH(net, field)
+#define TCP_INC_SKBUFF_STATS_USER(skb, net, field) __TCP_INC_STATS_USER(net, 
field)
+#define TCP_DEC_SKBUFF_STATS(skb, net, field) __TCP_DEC_STATS(net, field)
+#define TCP_ADD_SKBUFF_STATS_BH(skb, net, field, adnd) __TCP_ADD_STATS_BH(net, 
field, val)
+#define TCP_ADD_SKBUFF_STATS_USER(skb, net, field, adnd) 
__TCP_ADD_STATS_USER(net, field, val)
+
+#define TCP_INC_SKB_STATS(net, field)  __TCP_INC_STATS(net, field)
+#define TCP_INC_SKB_STATS_BH(net, field)  __TCP_INC_STATS_BH(net, field)
+#define TCP_INC_SKB_STATS_USER(net, field)  __TCP_INC_STATS_USER(net, field)
+#define TCP_DEC_SKB_STATS(net, field)  __TCP_DEC_STATS(net, field)
+#define TCP_ADD_SKB_STATS_BH(net, field, val)  __TCP_ADD_STATS_BH(net, field, 
val)
+#define TCP_ADD_SKB_STATS_USER(net, field, val)  __TCP_ADD_STATS_USER(net, 
field, val)
+
+#endif
+
+#endif
diff -r -U 4 a/include/net/stat_sk_hashtable_net_overrides.h 
b/include/net/stat_sk_hashtable_net_overrides.h
--- a/include/net/stat_sk_hashtable_net_overrides.h     2013-08-27 
17:15:42.965623755 +0300
+++ b/include/net/stat_sk_hashtable_net_overrides.h     2013-08-27 
17:15:43.055664650 +0300
@@ -0,0 +1,26 @@
+#ifndef _STAT_SK_HASHTABLE_NET_OVERRIDES_H
+#define _STAT_SK_HASHTABLE_NET_OVERRIDES_H
+
+#include <net/stat_sk_hashtable.h>
+
+#ifdef CONFIG_NET_IPV4_SOCK_STATS
+
+#undef NET_INC_STATS
+#define NET_INC_STATS(net, field) NET_INC_SK_STATS(net, field)
+
+#undef NET_INC_STATS_BH
+#define NET_INC_STATS_BH(net, field) NET_INC_SK_STATS_BH(net, field)
+
+#undef NET_INC_STATS_USER
+#define NET_INC_STATS_USER(net, field)  NET_INC_SK_STATS_USER(net, field)
+
+#undef NET_ADD_STATS_BH
+#define NET_ADD_STATS_BH(net, field, adnd) NET_ADD_SK_STATS_BH(net, field, 
adnd)
+
+#undef NET_ADD_STATS_USER
+#define NET_ADD_STATS_USER(net, field, adnd) NET_ADD_SK_STATS_USER(net, field, 
adnd)
+
+#endif
+
+#endif
+
diff -r -U 4 a/include/net/stat_sk_hashtable_tcp_overrides.h 
b/include/net/stat_sk_hashtable_tcp_overrides.h
--- a/include/net/stat_sk_hashtable_tcp_overrides.h     2013-08-27 
17:15:42.972623592 +0300
+++ b/include/net/stat_sk_hashtable_tcp_overrides.h     2013-08-27 
17:15:43.069671924 +0300
@@ -0,0 +1,29 @@
+#ifndef _STAT_SK_HASHTABLE_TCP_OVERRIDES_H
+#define _STAT_SK_HASHTABLE_TCP_OVERRIDES_H
+
+#include <net/stat_sk_hashtable.h>
+
+#ifdef CONFIG_NET_IPV4_SOCK_STATS
+
+#undef TCP_INC_STATS
+#define TCP_INC_STATS(net, field) TCP_INC_SK_STATS(net, field)
+
+#undef TCP_INC_STATS_BH
+#define TCP_INC_STATS_BH(net, field) TCP_INC_SK_STATS_BH(net, field)
+
+#undef TCP_INC_STATS_USER
+#define TCP_INC_STATS_USER(net, field) TCP_INC_SK_STATS_USER(net, field)
+
+#undef TCP_DEC_STATS
+#define TCP_DEC_STATS(net, field) TCP_DEC_SK_STATS(net, field)
+
+#undef TCP_ADD_STATS_BH
+#define TCP_ADD_STATS_BH(net, field, val) TCP_ADD_SK_STATS_BH(net, field, val)
+
+#undef TCP_ADD_STATS_USER
+#define TCP_ADD_STATS_USER(net, field, val) TCP_ADD_SK_STATS_USER(net, field, 
val)
+
+#endif
+
+#endif
+
diff -r -U 4 a/include/net/stat_sk_hashtable_undo_overrides.h 
b/include/net/stat_sk_hashtable_undo_overrides.h
--- a/include/net/stat_sk_hashtable_undo_overrides.h    2013-08-27 
17:15:42.979623650 +0300
+++ b/include/net/stat_sk_hashtable_undo_overrides.h    2013-08-27 
17:15:43.084645034 +0300
@@ -0,0 +1,49 @@
+#ifdef CONFIG_NET_IPV4_SOCK_STATS
+
+#undef NET_INC_STATS
+#undef NET_INC_STATS_BH
+#undef NET_INC_STATS_USER
+#undef NET_ADD_STATS_BH
+#undef NET_ADD_STATS_USER
+
+#define NET_INC_STATS(net, field) __NET_INC_STATS(net, field)
+#define NET_INC_STATS_BH(net, field) __NET_INC_STATS_BH(net, field)
+#define NET_INC_STATS_USER(net, field)  __NET_INC_STATS_USER(net, field)
+#define NET_ADD_STATS_BH(net, field, adnd) __NET_ADD_STATS_BH(net, field, adnd)
+#define NET_ADD_STATS_USER(net, field, adnd) __NET_ADD_STATS_USER(net, field, 
adnd)
+
+#undef TCP_INC_STATS
+#undef TCP_INC_STATS_BH
+#undef TCP_INC_STATS_USER
+#undef TCP_DEC_STATS
+#undef TCP_ADD_STATS_BH
+#undef TCP_ADD_STATS_USER
+
+#define TCP_INC_STATS(net, field) __TCP_INC_STATS(net, field)
+#define TCP_INC_STATS_BH(net, field) __TCP_INC_STATS_BH(net, field)
+#define TCP_INC_STATS_USER(net, field) __TCP_INC_STATS_USER(net, field)
+#define TCP_DEC_STATS(net, field) __TCP_DEC_STATS(net, field)
+#define TCP_ADD_STATS_BH(net, field, val) __TCP_ADD_STATS_BH(net, field, val)
+#define TCP_ADD_STATS_USER(net, field, val) __TCP_ADD_STATS_USER(net, field, 
val)
+
+#undef STAT_HASH_SK_INIT
+#undef STAT_HASH_COOKIE_CLONE
+#undef STAT_HASH_SK_INSERT_NONATOMIC
+#undef STAT_HASH_SK_INSERT_ATOMIC
+#undef STAT_HASH_SK_INSERT
+#undef STAT_HASH_SK_INSERT_EXISTING_NONATOMIC
+#undef STAT_HASH_SK_INSERT_EXISTING_ATOMIC
+#undef STAT_HASH_SK_INSERT_EXISTING
+#undef STAT_HASH_SK_INSERT_EXISTING_NOALLOC
+
+#define STAT_HASH_SK_INIT(sk)
+#define STAT_HASH_COOKIE_CLONE(newsk, sk)
+#define STAT_HASH_SK_INSERT_NONATOMIC(sk, direction) 
+#define STAT_HASH_SK_INSERT_ATOMIC(sk, direction) 
+#define STAT_HASH_SK_INSERT(sk, direction) 
+#define STAT_HASH_SK_INSERT_EXISTING_NONATOMIC(sk) 
+#define STAT_HASH_SK_INSERT_EXISTING_ATOMIC(sk) 
+#define STAT_HASH_SK_INSERT_EXISTING(sk) 
+#define STAT_HASH_SK_INSERT_EXISTING_NOALLOC(sk)
+
+#endif
diff -r -U 4 a/include/net/tcp.h b/include/net/tcp.h
--- a/include/net/tcp.h 2013-08-27 17:15:42.986623640 +0300
+++ b/include/net/tcp.h 2013-08-27 17:15:43.103606236 +0300
@@ -297,12 +297,17 @@
 }
 
 extern struct proto tcp_prot;
 
-#define TCP_INC_STATS(net, field)      
SNMP_INC_STATS((net)->mib.tcp_statistics, field)
-#define TCP_INC_STATS_BH(net, field)   
SNMP_INC_STATS_BH((net)->mib.tcp_statistics, field)
-#define TCP_DEC_STATS(net, field)      
SNMP_DEC_STATS((net)->mib.tcp_statistics, field)
-#define TCP_ADD_STATS_USER(net, field, val) 
SNMP_ADD_STATS_USER((net)->mib.tcp_statistics, field, val)
+#define __TCP_INC_STATS(net, field)    
SNMP_INC_STATS((net)->mib.tcp_statistics, field)
+#define __TCP_INC_STATS_BH(net, field) 
SNMP_INC_STATS_BH((net)->mib.tcp_statistics, field)
+#define __TCP_DEC_STATS(net, field)    
SNMP_DEC_STATS((net)->mib.tcp_statistics, field)
+#define __TCP_ADD_STATS_USER(net, field, val) 
SNMP_ADD_STATS_USER((net)->mib.tcp_statistics, field, val)
+
+#define TCP_INC_STATS(net, field)       __TCP_INC_STATS(net, field)
+#define TCP_INC_STATS_BH(net, field)    __TCP_INC_STATS_BH(net, field)
+#define TCP_DEC_STATS(net, field)       __TCP_DEC_STATS(net, field)
+#define TCP_ADD_STATS_USER(net, field, val) __TCP_ADD_STATS_USER(net, field, 
val)
 
 extern void                    tcp_v4_err(struct sk_buff *skb, u32);
 
 extern void                    tcp_shutdown (struct sock *sk, int how);
@@ -1108,12 +1113,12 @@
 
 static inline void tcp_mib_init(struct net *net)
 {
        /* See RFC 2012 */
-       TCP_ADD_STATS_USER(net, TCP_MIB_RTOALGORITHM, 1);
-       TCP_ADD_STATS_USER(net, TCP_MIB_RTOMIN, TCP_RTO_MIN*1000/HZ);
-       TCP_ADD_STATS_USER(net, TCP_MIB_RTOMAX, TCP_RTO_MAX*1000/HZ);
-       TCP_ADD_STATS_USER(net, TCP_MIB_MAXCONN, -1);
+       __TCP_ADD_STATS_USER(net, TCP_MIB_RTOALGORITHM, 1);
+       __TCP_ADD_STATS_USER(net, TCP_MIB_RTOMIN, TCP_RTO_MIN*1000/HZ);
+       __TCP_ADD_STATS_USER(net, TCP_MIB_RTOMAX, TCP_RTO_MAX*1000/HZ);
+       __TCP_ADD_STATS_USER(net, TCP_MIB_MAXCONN, -1);
 }
 
 /* from STCP */
 static inline void tcp_clear_retrans_hints_partial(struct tcp_sock *tp)
diff -r -U 4 a/net/ipv4/Kconfig b/net/ipv4/Kconfig
--- a/net/ipv4/Kconfig  2013-08-27 17:15:42.993704555 +0300
+++ b/net/ipv4/Kconfig  2013-08-27 17:15:43.129606087 +0300
@@ -669,4 +669,13 @@
        default n
        ---help---
        Debug statistics hash table functionality
 
+config NET_IPV4_SOCK_STATS
+       boolean "Access stat hashtable from socket structure"
+       depends on NET_IPV4_STAT_HASHTABLES
+       default y
+       ---help---
+       Stores the cookie for accessing the statistics hash in the socket 
structure.
+
+
+
diff -r -U 4 a/net/ipv4/Makefile b/net/ipv4/Makefile
--- a/net/ipv4/Makefile 2013-08-27 17:15:42.999718205 +0300
+++ b/net/ipv4/Makefile 2013-08-27 17:15:43.151652445 +0300
@@ -53,5 +53,6 @@
 obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
                      xfrm4_output.o
 obj-$(CONFIG_NET_IPV4_SNMP_MAPPING) += snmp_map.o
 obj-$(CONFIG_NET_IPV4_STAT_HASHTABLES) += stat_hashtable.o
+obj-$(CONFIG_NET_IPV4_SOCK_STATS) += stat_sk_hashtable.o
 
diff -r -U 4 a/net/ipv4/stat_sk_hashtable.c b/net/ipv4/stat_sk_hashtable.c
--- a/net/ipv4/stat_sk_hashtable.c      2013-08-27 17:15:43.005707986 +0300
+++ b/net/ipv4/stat_sk_hashtable.c      2013-08-27 17:15:43.165606451 +0300
@@ -0,0 +1,148 @@
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include <net/inet_connection_sock.h>
+#include <net/inet_hashtables.h>
+#include <net/secure_seq.h>
+#include <net/ip.h>
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+#include <linux/in6.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#endif
+
+#include <net/snmp_map.h>
+#include <net/stat_hashtable.h>
+#include <net/stat_sk_hashtable.h>
+
+static inline bool 
+ipv4_addr_loopback(__be32 addr)
+{
+       return (addr & htonl(0xff000000)) == htonl(0x7f000000);
+}
+
+static int
+stat4_hash_filter_addr(struct stat_hash_addr *addr, u8 direction)
+{
+       __be32 local_addr;
+       __be32 remote_addr;
+
+       if (direction == STAT_HASH_SK_IN) {
+               local_addr = addr->daddr.ip;
+               remote_addr = addr->saddr.ip;
+       } else {        /* STAT_HASH_SK_OUT + STAT_HASH_SK_INOUT */
+               local_addr = addr->saddr.ip;
+               remote_addr = addr->daddr.ip;
+       }
+
+       if (remote_addr == 0) {
+               stat_sk_dprintk(STAT_HASH_MESSAGE_DEBUG, "zero IPV4 address\n");
+               return -EINVAL;
+       }
+
+       if (net_stat_hash_loopback == 0) {
+               if (local_addr == remote_addr) {
+                       stat_sk_dprintk(STAT_HASH_MESSAGE_DEBUG, "local and 
remote IPV4 addresses are the same\n");
+                       return -EINVAL;
+               }
+
+               if (ipv4_addr_loopback(remote_addr)) {
+                       stat_sk_dprintk(STAT_HASH_MESSAGE_DEBUG, "IPV4 address 
is on the loopback\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+       
+static int 
+stat6_hash_filter_address(struct stat_hash_addr *addr, u8 direction)
+{
+       struct in6_addr local_addr;
+       struct in6_addr remote_addr;
+       struct in6_addr zero_addr;
+
+       if (net_stat_hashtable_ipv6 == 0) {
+               stat_sk_dprintk(STAT_HASH_MESSAGE_DEBUG_VERBOSE, "disabled 
hashing for address family %d\n", addr->family);
+               return -EINVAL;
+       }
+
+       memset(&zero_addr, 0, sizeof(zero_addr));
+       if (direction == STAT_HASH_SK_IN) {
+               ipv6_addr_copy(&local_addr, &addr->daddr.in6);
+               ipv6_addr_copy(&remote_addr, &addr->saddr.in6);
+       } else {        /* STAT_HASH_SK_OUT + STAT_HASH_SK_INOUT */
+               ipv6_addr_copy(&local_addr, &addr->saddr.in6);
+               ipv6_addr_copy(&remote_addr, &addr->daddr.in6);
+       }
+
+       if (!memcmp(&zero_addr, &remote_addr, sizeof(zero_addr)))  {
+               stat_sk_dprintk(STAT_HASH_MESSAGE_DEBUG, "zero IPV6 address\n");
+               return -EINVAL;
+       }
+
+       if (net_stat_hash_loopback == 0) {
+               if (ipv6_addr_equal(&local_addr, &remote_addr)) {
+                       stat_sk_dprintk(STAT_HASH_MESSAGE_DEBUG, "local and 
remote IPV6 addresses are the same\n");
+                       return -EINVAL;
+               }
+
+               if (ipv6_addr_loopback(&remote_addr)) {
+                       stat_sk_dprintk(STAT_HASH_MESSAGE_DEBUG, "IPV6 address 
is on the loopback\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+int
+stat_hash_filter_addr(struct stat_hash_addr *addr, u8 direction)
+{
+       int rc = -EINVAL;
+
+       switch (addr->family) {
+                case AF_INET:
+                       rc = stat4_hash_filter_addr(addr, direction);
+                        break;
+#ifdef CONFIG_IPV6_STAT_HASHTABLES
+               case AF_INET6:
+                       rc = stat6_hash_filter_address(addr, direction);
+                       break;
+#endif
+                default:
+                       break;
+        }
+
+#ifdef CONFIG_NET_IPV4_STAT_HASHTABLE_DEBUG
+       if (stat_hash_debug_level >= STAT_HASH_MESSAGE_DEBUG_VERBOSE) {
+               printk("%s address: ", (rc == 0) ? "accepted" : "rejected");
+               stat_hash_dump_address(addr);
+       }
+#endif
+
+       return rc;
+}
+EXPORT_SYMBOL(stat_hash_filter_addr);
+
+int 
+stat_hash_insert(u32 initval, struct stat_hash_addr *addr, bool existing, 
+                int alloc_flag, struct stat_hash_cookie *cookie)
+{
+       struct stat_hash_entry *entry = NULL;
+       struct stat_hash_cookie ck;
+       int err = -EFAULT;
+
+       STAT_INIT_COOKIE(&ck);
+       if ((entry = stat_hash_get_entry(initval, addr, existing, alloc_flag, 
&ck)) != NULL) {
+               stat_hash_copy_cookie_atomic(cookie, &ck);
+               err = 0;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(stat_hash_insert);
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to