aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Borkmann <dborkman@redhat.com>2015-01-05 17:57:47 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-05 22:55:24 -0500
commitea697639992d96da98016b8934e68a73876a2264 (patch)
treec04b2007e7294668f40e16091b1a11647497c86e
parentc5c6a8ab45ec0f18733afb4aaade0d4a139d80b3 (diff)
net: tcp: add RTAX_CC_ALGO fib handling
This patch adds the minimum necessary for the RTAX_CC_ALGO congestion control metric to be set up and dumped back to user space. While the internal representation of RTAX_CC_ALGO is handled as a u32 key, we avoided to expose this implementation detail to user space, thus instead, we chose the netlink attribute that is being exchanged between user space to be the actual congestion control algorithm name, similarly as in the setsockopt(2) API in order to allow for maximum flexibility, even for 3rd party modules. It is a bit unfortunate that RTAX_QUICKACK used up a whole RTAX slot as it should have been stored in RTAX_FEATURES instead, we first thought about reusing it for the congestion control key, but it brings more complications and/or confusion than worth it. Joint work with Florian Westphal. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/tcp.h7
-rw-r--r--include/uapi/linux/rtnetlink.h2
-rw-r--r--net/core/rtnetlink.c15
-rw-r--r--net/decnet/dn_fib.c3
-rw-r--r--net/decnet/dn_table.c4
-rw-r--r--net/ipv4/fib_semantics.c14
-rw-r--r--net/ipv6/route.c17
7 files changed, 54 insertions, 8 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 135b70c9a734..95bb237152e0 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -846,7 +846,14 @@ extern struct tcp_congestion_ops tcp_reno;
846 846
847struct tcp_congestion_ops *tcp_ca_find_key(u32 key); 847struct tcp_congestion_ops *tcp_ca_find_key(u32 key);
848u32 tcp_ca_get_key_by_name(const char *name); 848u32 tcp_ca_get_key_by_name(const char *name);
849#ifdef CONFIG_INET
849char *tcp_ca_get_name_by_key(u32 key, char *buffer); 850char *tcp_ca_get_name_by_key(u32 key, char *buffer);
851#else
852static inline char *tcp_ca_get_name_by_key(u32 key, char *buffer)
853{
854 return NULL;
855}
856#endif
850 857
851static inline bool tcp_ca_needs_ecn(const struct sock *sk) 858static inline bool tcp_ca_needs_ecn(const struct sock *sk)
852{ 859{
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index 9c9b8b4480cd..d81f22d5b390 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -389,6 +389,8 @@ enum {
389#define RTAX_INITRWND RTAX_INITRWND 389#define RTAX_INITRWND RTAX_INITRWND
390 RTAX_QUICKACK, 390 RTAX_QUICKACK,
391#define RTAX_QUICKACK RTAX_QUICKACK 391#define RTAX_QUICKACK RTAX_QUICKACK
392 RTAX_CC_ALGO,
393#define RTAX_CC_ALGO RTAX_CC_ALGO
392 __RTAX_MAX 394 __RTAX_MAX
393}; 395};
394 396
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index da983d4bac02..6a6cdade1676 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -50,6 +50,7 @@
50#include <net/arp.h> 50#include <net/arp.h>
51#include <net/route.h> 51#include <net/route.h>
52#include <net/udp.h> 52#include <net/udp.h>
53#include <net/tcp.h>
53#include <net/sock.h> 54#include <net/sock.h>
54#include <net/pkt_sched.h> 55#include <net/pkt_sched.h>
55#include <net/fib_rules.h> 56#include <net/fib_rules.h>
@@ -669,9 +670,19 @@ int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics)
669 670
670 for (i = 0; i < RTAX_MAX; i++) { 671 for (i = 0; i < RTAX_MAX; i++) {
671 if (metrics[i]) { 672 if (metrics[i]) {
673 if (i == RTAX_CC_ALGO - 1) {
674 char tmp[TCP_CA_NAME_MAX], *name;
675
676 name = tcp_ca_get_name_by_key(metrics[i], tmp);
677 if (!name)
678 continue;
679 if (nla_put_string(skb, i + 1, name))
680 goto nla_put_failure;
681 } else {
682 if (nla_put_u32(skb, i + 1, metrics[i]))
683 goto nla_put_failure;
684 }
672 valid++; 685 valid++;
673 if (nla_put_u32(skb, i+1, metrics[i]))
674 goto nla_put_failure;
675 } 686 }
676 } 687 }
677 688
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
index d332aefb0846..df4803437888 100644
--- a/net/decnet/dn_fib.c
+++ b/net/decnet/dn_fib.c
@@ -298,7 +298,8 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct nlattr *att
298 int type = nla_type(attr); 298 int type = nla_type(attr);
299 299
300 if (type) { 300 if (type) {
301 if (type > RTAX_MAX || nla_len(attr) < 4) 301 if (type > RTAX_MAX || type == RTAX_CC_ALGO ||
302 nla_len(attr) < 4)
302 goto err_inval; 303 goto err_inval;
303 304
304 fi->fib_metrics[type-1] = nla_get_u32(attr); 305 fi->fib_metrics[type-1] = nla_get_u32(attr);
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index 86e3807052e9..3f19fcbf126d 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -29,6 +29,7 @@
29#include <linux/route.h> /* RTF_xxx */ 29#include <linux/route.h> /* RTF_xxx */
30#include <net/neighbour.h> 30#include <net/neighbour.h>
31#include <net/netlink.h> 31#include <net/netlink.h>
32#include <net/tcp.h>
32#include <net/dst.h> 33#include <net/dst.h>
33#include <net/flow.h> 34#include <net/flow.h>
34#include <net/fib_rules.h> 35#include <net/fib_rules.h>
@@ -273,7 +274,8 @@ static inline size_t dn_fib_nlmsg_size(struct dn_fib_info *fi)
273 size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg)) 274 size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg))
274 + nla_total_size(4) /* RTA_TABLE */ 275 + nla_total_size(4) /* RTA_TABLE */
275 + nla_total_size(2) /* RTA_DST */ 276 + nla_total_size(2) /* RTA_DST */
276 + nla_total_size(4); /* RTA_PRIORITY */ 277 + nla_total_size(4) /* RTA_PRIORITY */
278 + nla_total_size(TCP_CA_NAME_MAX); /* RTAX_CC_ALGO */
277 279
278 /* space for nested metrics */ 280 /* space for nested metrics */
279 payload += nla_total_size((RTAX_MAX * nla_total_size(4))); 281 payload += nla_total_size((RTAX_MAX * nla_total_size(4)));
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index f99f41bd15b8..d2b7b5521b1b 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -360,7 +360,8 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi)
360 + nla_total_size(4) /* RTA_TABLE */ 360 + nla_total_size(4) /* RTA_TABLE */
361 + nla_total_size(4) /* RTA_DST */ 361 + nla_total_size(4) /* RTA_DST */
362 + nla_total_size(4) /* RTA_PRIORITY */ 362 + nla_total_size(4) /* RTA_PRIORITY */
363 + nla_total_size(4); /* RTA_PREFSRC */ 363 + nla_total_size(4) /* RTA_PREFSRC */
364 + nla_total_size(TCP_CA_NAME_MAX); /* RTAX_CC_ALGO */
364 365
365 /* space for nested metrics */ 366 /* space for nested metrics */
366 payload += nla_total_size((RTAX_MAX * nla_total_size(4))); 367 payload += nla_total_size((RTAX_MAX * nla_total_size(4)));
@@ -859,7 +860,16 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
859 860
860 if (type > RTAX_MAX) 861 if (type > RTAX_MAX)
861 goto err_inval; 862 goto err_inval;
862 val = nla_get_u32(nla); 863 if (type == RTAX_CC_ALGO) {
864 char tmp[TCP_CA_NAME_MAX];
865
866 nla_strlcpy(tmp, nla, sizeof(tmp));
867 val = tcp_ca_get_key_by_name(tmp);
868 if (val == TCP_CA_UNSPEC)
869 goto err_inval;
870 } else {
871 val = nla_get_u32(nla);
872 }
863 if (type == RTAX_ADVMSS && val > 65535 - 40) 873 if (type == RTAX_ADVMSS && val > 65535 - 40)
864 val = 65535 - 40; 874 val = 65535 - 40;
865 if (type == RTAX_MTU && val > 65535 - 15) 875 if (type == RTAX_MTU && val > 65535 - 15)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 454771d20b21..34dcbb59df75 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1488,10 +1488,22 @@ static int ip6_convert_metrics(struct mx6_config *mxc,
1488 int type = nla_type(nla); 1488 int type = nla_type(nla);
1489 1489
1490 if (type) { 1490 if (type) {
1491 u32 val;
1492
1491 if (unlikely(type > RTAX_MAX)) 1493 if (unlikely(type > RTAX_MAX))
1492 goto err; 1494 goto err;
1495 if (type == RTAX_CC_ALGO) {
1496 char tmp[TCP_CA_NAME_MAX];
1497
1498 nla_strlcpy(tmp, nla, sizeof(tmp));
1499 val = tcp_ca_get_key_by_name(tmp);
1500 if (val == TCP_CA_UNSPEC)
1501 goto err;
1502 } else {
1503 val = nla_get_u32(nla);
1504 }
1493 1505
1494 mp[type - 1] = nla_get_u32(nla); 1506 mp[type - 1] = val;
1495 __set_bit(type - 1, mxc->mx_valid); 1507 __set_bit(type - 1, mxc->mx_valid);
1496 } 1508 }
1497 } 1509 }
@@ -2571,7 +2583,8 @@ static inline size_t rt6_nlmsg_size(void)
2571 + nla_total_size(4) /* RTA_OIF */ 2583 + nla_total_size(4) /* RTA_OIF */
2572 + nla_total_size(4) /* RTA_PRIORITY */ 2584 + nla_total_size(4) /* RTA_PRIORITY */
2573 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */ 2585 + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
2574 + nla_total_size(sizeof(struct rta_cacheinfo)); 2586 + nla_total_size(sizeof(struct rta_cacheinfo))
2587 + nla_total_size(TCP_CA_NAME_MAX); /* RTAX_CC_ALGO */
2575} 2588}
2576 2589
2577static int rt6_fill_node(struct net *net, 2590static int rt6_fill_node(struct net *net,