diff --git a/ip/iproute.c b/ip/iproute.c index 32847c69..5a496a91 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -80,6 +80,7 @@ static void usage(void) fprintf(stderr, " [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n"); fprintf(stderr, " [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]\n"); fprintf(stderr, " [ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]\n"); + fprintf(stderr, " [ features FEATURES ]\n"); fprintf(stderr, " [ quickack BOOL ]\n"); fprintf(stderr, "TYPE := [ unicast | local | broadcast | multicast | throw |\n"); fprintf(stderr, " unreachable | prohibit | blackhole | nat ]\n"); @@ -89,6 +90,7 @@ static void usage(void) fprintf(stderr, "RTPROTO := [ kernel | boot | static | NUMBER ]\n"); fprintf(stderr, "TIME := NUMBER[s|ms]\n"); fprintf(stderr, "BOOL := [1|0]\n"); + fprintf(stderr, "FEATURES := ecn\n"); exit(-1); } @@ -280,6 +282,19 @@ static int calc_host_len(const struct rtmsg *r) return -1; } +static void print_rtax_features(FILE *fp, unsigned int features) +{ + unsigned int of = features; + + if (features & RTAX_FEATURE_ECN) { + fprintf(fp, " ecn"); + features &= ~RTAX_FEATURE_ECN; + } + + if (features) + fprintf(fp, " 0x%x", of); +} + int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; @@ -535,6 +550,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) val = *(unsigned*)RTA_DATA(mxrta[i]); switch (i) { + case RTAX_FEATURES: + print_rtax_features(fp, val); + break; case RTAX_HOPLIMIT: if ((int)val == -1) val = 0; @@ -885,6 +903,20 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) if (get_unsigned(&win, *argv, 0)) invarg("\"initrwnd\" value is invalid\n", *argv); rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITRWND, win); + } else if (matches(*argv, "features") == 0) { + unsigned int features = 0; + + while (argc > 0) { + NEXT_ARG(); + + if (strcmp(*argv, "ecn") == 0) + features |= RTAX_FEATURE_ECN; + else + invarg("\"features\" value not valid\n", *argv); + break; + } + + rta_addattr32(mxrta, sizeof(mxbuf), RTAX_FEATURES, features); } else if (matches(*argv, "quickack") == 0) { unsigned quickack; NEXT_ARG(); diff --git a/man/man8/ip-route.8.in b/man/man8/ip-route.8.in index 79bc7f10..89960c14 100644 --- a/man/man8/ip-route.8.in +++ b/man/man8/ip-route.8.in @@ -113,6 +113,8 @@ replace " } " .IR NUMBER " ] [ " .B initrwnd .IR NUMBER " ] [ " +.B features +.IR FEATURES " ] [ " .B quickack .IR BOOL " ]" @@ -140,6 +142,10 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]" .BR kernel " | " boot " | " static " |" .IR NUMBER " ]" +.ti -8 +.IR FEATURES " := [ " +.BR ecn " | ]" + .SH DESCRIPTION .B ip route @@ -410,6 +416,18 @@ the initial receive window size for connections to this destination. Actual window size is this value multiplied by the MSS of the connection. The default value is zero, meaning to use Slow Start value. +.TP +.BI features " FEATURES " (3.18+ only) +Enable or disable per-route features. Only available feature at this +time is +.B ecn +to enable explicit congestion notification when initiating connections to the +given destination network. +When responding to a connection request from the given network, ecn will +also be used even if the +.B net.ipv4.tcp_ecn +sysctl is set to 0. + .TP .BI quickack " BOOL " "(3.11+ only)" Enable or disable quick ack for connections to this destination.