net: tcp: add RTAX_CC_ALGO fib handling
authorDaniel Borkmann <dborkman@redhat.com>
Mon, 5 Jan 2015 22:57:47 +0000 (23:57 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 6 Jan 2015 03:55:24 +0000 (22:55 -0500)
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>
include/net/tcp.h
include/uapi/linux/rtnetlink.h
net/core/rtnetlink.c
net/decnet/dn_fib.c
net/decnet/dn_table.c
net/ipv4/fib_semantics.c
net/ipv6/route.c

index 135b70c9a734c4dc211bac0dc71168db24d2ce5b..95bb237152e0467f33b31831be0789151015f693 100644 (file)
@@ -846,7 +846,14 @@ extern struct tcp_congestion_ops tcp_reno;
 
 struct tcp_congestion_ops *tcp_ca_find_key(u32 key);
 u32 tcp_ca_get_key_by_name(const char *name);
+#ifdef CONFIG_INET
 char *tcp_ca_get_name_by_key(u32 key, char *buffer);
+#else
+static inline char *tcp_ca_get_name_by_key(u32 key, char *buffer)
+{
+       return NULL;
+}
+#endif
 
 static inline bool tcp_ca_needs_ecn(const struct sock *sk)
 {
index 9c9b8b4480cd4608d783318b7dbac4c060db210a..d81f22d5b39090aa109edb07c24f51517b7828fa 100644 (file)
@@ -389,6 +389,8 @@ enum {
 #define RTAX_INITRWND RTAX_INITRWND
        RTAX_QUICKACK,
 #define RTAX_QUICKACK RTAX_QUICKACK
+       RTAX_CC_ALGO,
+#define RTAX_CC_ALGO RTAX_CC_ALGO
        __RTAX_MAX
 };
 
index da983d4bac0267d3be1568ad53367a6e6bc0f0ea..6a6cdade167661ee5286adab67083572376a1780 100644 (file)
@@ -50,6 +50,7 @@
 #include <net/arp.h>
 #include <net/route.h>
 #include <net/udp.h>
+#include <net/tcp.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
 #include <net/fib_rules.h>
@@ -669,9 +670,19 @@ int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics)
 
        for (i = 0; i < RTAX_MAX; i++) {
                if (metrics[i]) {
+                       if (i == RTAX_CC_ALGO - 1) {
+                               char tmp[TCP_CA_NAME_MAX], *name;
+
+                               name = tcp_ca_get_name_by_key(metrics[i], tmp);
+                               if (!name)
+                                       continue;
+                               if (nla_put_string(skb, i + 1, name))
+                                       goto nla_put_failure;
+                       } else {
+                               if (nla_put_u32(skb, i + 1, metrics[i]))
+                                       goto nla_put_failure;
+                       }
                        valid++;
-                       if (nla_put_u32(skb, i+1, metrics[i]))
-                               goto nla_put_failure;
                }
        }
 
index d332aefb0846f86a11d924e3e1e7ad23e279dda2..df48034378889eac83c6b262a76a32028202efb4 100644 (file)
@@ -298,7 +298,8 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct nlattr *att
                        int type = nla_type(attr);
 
                        if (type) {
-                               if (type > RTAX_MAX || nla_len(attr) < 4)
+                               if (type > RTAX_MAX || type == RTAX_CC_ALGO ||
+                                   nla_len(attr) < 4)
                                        goto err_inval;
 
                                fi->fib_metrics[type-1] = nla_get_u32(attr);
index 86e3807052e9ab4feb56fcf88a06391c18f1472e..3f19fcbf126d0395acc69f2ec51fc7e2ea486c76 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/route.h> /* RTF_xxx */
 #include <net/neighbour.h>
 #include <net/netlink.h>
+#include <net/tcp.h>
 #include <net/dst.h>
 #include <net/flow.h>
 #include <net/fib_rules.h>
@@ -273,7 +274,8 @@ static inline size_t dn_fib_nlmsg_size(struct dn_fib_info *fi)
        size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg))
                         + nla_total_size(4) /* RTA_TABLE */
                         + nla_total_size(2) /* RTA_DST */
-                        + nla_total_size(4); /* RTA_PRIORITY */
+                        + nla_total_size(4) /* RTA_PRIORITY */
+                        + nla_total_size(TCP_CA_NAME_MAX); /* RTAX_CC_ALGO */
 
        /* space for nested metrics */
        payload += nla_total_size((RTAX_MAX * nla_total_size(4)));
index f99f41bd15b83072d7a67cd452a29ce550e0593e..d2b7b5521b1b5cc44074868f1f032ae8f96ae878 100644 (file)
@@ -360,7 +360,8 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi)
                         + nla_total_size(4) /* RTA_TABLE */
                         + nla_total_size(4) /* RTA_DST */
                         + nla_total_size(4) /* RTA_PRIORITY */
-                        + nla_total_size(4); /* RTA_PREFSRC */
+                        + nla_total_size(4) /* RTA_PREFSRC */
+                        + nla_total_size(TCP_CA_NAME_MAX); /* RTAX_CC_ALGO */
 
        /* space for nested metrics */
        payload += nla_total_size((RTAX_MAX * nla_total_size(4)));
@@ -859,7 +860,16 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
 
                                if (type > RTAX_MAX)
                                        goto err_inval;
-                               val = nla_get_u32(nla);
+                               if (type == RTAX_CC_ALGO) {
+                                       char tmp[TCP_CA_NAME_MAX];
+
+                                       nla_strlcpy(tmp, nla, sizeof(tmp));
+                                       val = tcp_ca_get_key_by_name(tmp);
+                                       if (val == TCP_CA_UNSPEC)
+                                               goto err_inval;
+                               } else {
+                                       val = nla_get_u32(nla);
+                               }
                                if (type == RTAX_ADVMSS && val > 65535 - 40)
                                        val = 65535 - 40;
                                if (type == RTAX_MTU && val > 65535 - 15)
index 454771d20b214c9a6c3c2c061f3e0826fa9be70e..34dcbb59df7514afd0163e1a737e14aba014b030 100644 (file)
@@ -1488,10 +1488,22 @@ static int ip6_convert_metrics(struct mx6_config *mxc,
                int type = nla_type(nla);
 
                if (type) {
+                       u32 val;
+
                        if (unlikely(type > RTAX_MAX))
                                goto err;
+                       if (type == RTAX_CC_ALGO) {
+                               char tmp[TCP_CA_NAME_MAX];
+
+                               nla_strlcpy(tmp, nla, sizeof(tmp));
+                               val = tcp_ca_get_key_by_name(tmp);
+                               if (val == TCP_CA_UNSPEC)
+                                       goto err;
+                       } else {
+                               val = nla_get_u32(nla);
+                       }
 
-                       mp[type - 1] = nla_get_u32(nla);
+                       mp[type - 1] = val;
                        __set_bit(type - 1, mxc->mx_valid);
                }
        }
@@ -2571,7 +2583,8 @@ static inline size_t rt6_nlmsg_size(void)
               + nla_total_size(4) /* RTA_OIF */
               + nla_total_size(4) /* RTA_PRIORITY */
               + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */
-              + nla_total_size(sizeof(struct rta_cacheinfo));
+              + nla_total_size(sizeof(struct rta_cacheinfo))
+              + nla_total_size(TCP_CA_NAME_MAX); /* RTAX_CC_ALGO */
 }
 
 static int rt6_fill_node(struct net *net,