diff options
author | Eric Dumazet <edumazet@google.com> | 2015-04-28 19:23:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-04-29 17:10:38 -0400 |
commit | 6e9250f59ef9efb932c84850cd221f22c2a03c4a (patch) | |
tree | 8492e1b4724aa12b31675b45e3bb681f860213f0 | |
parent | 64f40ff5bbdb1b679fb3c4dbc8230d6517d2b8dc (diff) |
tcp: add TCP_CC_INFO socket option
Some Congestion Control modules can provide per flow information,
but current way to get this information is to use netlink.
Like TCP_INFO, let's add TCP_CC_INFO so that applications can
issue a getsockopt() if they have a socket file descriptor,
instead of playing complex netlink games.
Sample usage would be :
union tcp_cc_info info;
socklen_t len = sizeof(info);
if (getsockopt(fd, SOL_TCP, TCP_CC_INFO, &info, &len) == -1)
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
Acked-by: Neal Cardwell <ncardwell@google.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Yuchung Cheng <ycheng@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/uapi/linux/tcp.h | 1 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 21 |
2 files changed, 22 insertions, 0 deletions
diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h index a48f93f3207b..faa72f4fa547 100644 --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h | |||
@@ -112,6 +112,7 @@ enum { | |||
112 | #define TCP_FASTOPEN 23 /* Enable FastOpen on listeners */ | 112 | #define TCP_FASTOPEN 23 /* Enable FastOpen on listeners */ |
113 | #define TCP_TIMESTAMP 24 | 113 | #define TCP_TIMESTAMP 24 |
114 | #define TCP_NOTSENT_LOWAT 25 /* limit number of unsent bytes in write queue */ | 114 | #define TCP_NOTSENT_LOWAT 25 /* limit number of unsent bytes in write queue */ |
115 | #define TCP_CC_INFO 26 /* Get Congestion Control (optional) info */ | ||
115 | 116 | ||
116 | struct tcp_repair_opt { | 117 | struct tcp_repair_opt { |
117 | __u32 opt_code; | 118 | __u32 opt_code; |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 99fcc0b22c92..46efa03d2b11 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -252,6 +252,7 @@ | |||
252 | #include <linux/types.h> | 252 | #include <linux/types.h> |
253 | #include <linux/fcntl.h> | 253 | #include <linux/fcntl.h> |
254 | #include <linux/poll.h> | 254 | #include <linux/poll.h> |
255 | #include <linux/inet_diag.h> | ||
255 | #include <linux/init.h> | 256 | #include <linux/init.h> |
256 | #include <linux/fs.h> | 257 | #include <linux/fs.h> |
257 | #include <linux/skbuff.h> | 258 | #include <linux/skbuff.h> |
@@ -2739,6 +2740,26 @@ static int do_tcp_getsockopt(struct sock *sk, int level, | |||
2739 | return -EFAULT; | 2740 | return -EFAULT; |
2740 | return 0; | 2741 | return 0; |
2741 | } | 2742 | } |
2743 | case TCP_CC_INFO: { | ||
2744 | const struct tcp_congestion_ops *ca_ops; | ||
2745 | union tcp_cc_info info; | ||
2746 | size_t sz = 0; | ||
2747 | int attr; | ||
2748 | |||
2749 | if (get_user(len, optlen)) | ||
2750 | return -EFAULT; | ||
2751 | |||
2752 | ca_ops = icsk->icsk_ca_ops; | ||
2753 | if (ca_ops && ca_ops->get_info) | ||
2754 | sz = ca_ops->get_info(sk, ~0U, &attr, &info); | ||
2755 | |||
2756 | len = min_t(unsigned int, len, sz); | ||
2757 | if (put_user(len, optlen)) | ||
2758 | return -EFAULT; | ||
2759 | if (copy_to_user(optval, &info, len)) | ||
2760 | return -EFAULT; | ||
2761 | return 0; | ||
2762 | } | ||
2742 | case TCP_QUICKACK: | 2763 | case TCP_QUICKACK: |
2743 | val = !icsk->icsk_ack.pingpong; | 2764 | val = !icsk->icsk_ack.pingpong; |
2744 | break; | 2765 | break; |