tcp: account SYN-ACK timeouts & retransmissions
authorOctavian Purdila <opurdila@ixiacom.com>
Mon, 18 Jan 2010 03:09:39 +0000 (19:09 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 18 Jan 2010 03:09:39 +0000 (19:09 -0800)
Currently we don't increment SYN-ACK timeouts & retransmissions
although we do increment the same stats for SYN. We seem to have lost
the SYN-ACK accounting with the introduction of tcp_syn_recv_timer
(commit 2248761e in the netdev-vger-cvs tree).

This patch fixes this issue. In the process we also rename the v4/v6
syn/ack retransmit functions for clarity. We also add a new
request_socket operations (syn_ack_timeout) so we can keep code in
inet_connection_sock.c protocol agnostic.

Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/request_sock.h
include/net/tcp.h
net/ipv4/inet_connection_sock.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_timer.c
net/ipv6/tcp_ipv6.c

index c9b50ebd9ce9ea3cab54d14411a899b7df524150..99e6e19b57c2188ed0a592789e68e00c2d0a55f8 100644 (file)
@@ -45,6 +45,8 @@ struct request_sock_ops {
        void            (*send_reset)(struct sock *sk,
                                      struct sk_buff *skb);
        void            (*destructor)(struct request_sock *req);
+       void            (*syn_ack_timeout)(struct sock *sk,
+                                          struct request_sock *req);
 };
 
 /* struct request_sock - mini sock to represent a connection request
index 788c99f98597d6e59b900951b18e6089e2ba0a69..87d164b9bd8f63784c4db0731297697cc06aafea 100644 (file)
@@ -400,6 +400,8 @@ extern int                  compat_tcp_setsockopt(struct sock *sk,
                                        int level, int optname,
                                        char __user *optval, unsigned int optlen);
 extern void                    tcp_set_keepalive(struct sock *sk, int val);
+extern void                    tcp_syn_ack_timeout(struct sock *sk,
+                                                   struct request_sock *req);
 extern int                     tcp_recvmsg(struct kiocb *iocb, struct sock *sk,
                                            struct msghdr *msg,
                                            size_t len, int nonblock, 
index ee16475f8fc33619eea9c9e247f06501e6aad45b..8da6429269dddd922f9c3fb4eda2b86a7bffe0d2 100644 (file)
@@ -529,6 +529,8 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
                                syn_ack_recalc(req, thresh, max_retries,
                                               queue->rskq_defer_accept,
                                               &expire, &resend);
+                               if (req->rsk_ops->syn_ack_timeout)
+                                       req->rsk_ops->syn_ack_timeout(parent, req);
                                if (!expire &&
                                    (!resend ||
                                     !req->rsk_ops->rtx_syn_ack(parent, req, NULL) ||
index 382f667238ecec4361829c7158445e85e48b373c..356f544c4c10e18b25060b6af39ba7eec1d07f76 100644 (file)
@@ -742,9 +742,9 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
  *     This still operates on a request_sock only, not on a big
  *     socket.
  */
-static int __tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
-                               struct request_sock *req,
-                               struct request_values *rvp)
+static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
+                             struct request_sock *req,
+                             struct request_values *rvp)
 {
        const struct inet_request_sock *ireq = inet_rsk(req);
        int err = -1;
@@ -775,10 +775,11 @@ static int __tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
        return err;
 }
 
-static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
+static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req,
                              struct request_values *rvp)
 {
-       return __tcp_v4_send_synack(sk, NULL, req, rvp);
+       TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
+       return tcp_v4_send_synack(sk, NULL, req, rvp);
 }
 
 /*
@@ -1192,10 +1193,11 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
 struct request_sock_ops tcp_request_sock_ops __read_mostly = {
        .family         =       PF_INET,
        .obj_size       =       sizeof(struct tcp_request_sock),
-       .rtx_syn_ack    =       tcp_v4_send_synack,
+       .rtx_syn_ack    =       tcp_v4_rtx_synack,
        .send_ack       =       tcp_v4_reqsk_send_ack,
        .destructor     =       tcp_v4_reqsk_destructor,
        .send_reset     =       tcp_v4_send_reset,
+       .syn_ack_timeout =      tcp_syn_ack_timeout,
 };
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -1373,8 +1375,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        }
        tcp_rsk(req)->snt_isn = isn;
 
-       if (__tcp_v4_send_synack(sk, dst, req,
-                                (struct request_values *)&tmp_ext) ||
+       if (tcp_v4_send_synack(sk, dst, req,
+                              (struct request_values *)&tmp_ext) ||
            want_cookie)
                goto drop_and_free;
 
index 8816a20c25970ad4fe9ae172a4890af74ee928ce..de7d1bf9114fe6d3bf6475be2f9031460c618e95 100644 (file)
@@ -474,6 +474,12 @@ static void tcp_synack_timer(struct sock *sk)
                                   TCP_TIMEOUT_INIT, TCP_RTO_MAX);
 }
 
+void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req)
+{
+       NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPTIMEOUTS);
+}
+EXPORT_SYMBOL(tcp_syn_ack_timeout);
+
 void tcp_set_keepalive(struct sock *sk, int val)
 {
        if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))
index 1c832bf198b3473a4bd8070a528f0de383537271..82f2dea0e39eed580d48adeeaef5f1878a4e5cb3 100644 (file)
@@ -520,6 +520,13 @@ done:
        return err;
 }
 
+static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
+                            struct request_values *rvp)
+{
+       TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
+       return tcp_v6_send_synack(sk, req, rvp);
+}
+
 static inline void syn_flood_warning(struct sk_buff *skb)
 {
 #ifdef CONFIG_SYN_COOKIES
@@ -890,10 +897,11 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
 struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
        .family         =       AF_INET6,
        .obj_size       =       sizeof(struct tcp6_request_sock),
-       .rtx_syn_ack    =       tcp_v6_send_synack,
+       .rtx_syn_ack    =       tcp_v6_rtx_synack,
        .send_ack       =       tcp_v6_reqsk_send_ack,
        .destructor     =       tcp_v6_reqsk_destructor,
-       .send_reset     =       tcp_v6_send_reset
+       .send_reset     =       tcp_v6_send_reset,
+       .syn_ack_timeout =      tcp_syn_ack_timeout,
 };
 
 #ifdef CONFIG_TCP_MD5SIG