1 /* 2 * Codel - The Controlled-Delay Active Queue Management algorithm 3 * 4 * Copyright (C) 2011-2012 Kathleen Nichols <nichols (at) pollere.com> 5 * Copyright (C) 2011-2012 Van Jacobson <van (at) pollere.com> 6 * Copyright (C) 2012 Michael D. Taht <dave.taht (at) bufferbloat.net> 7 * Copyright (C) 2012,2015 Eric Dumazet <edumazet (at) google.com> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions, and the following disclaimer, 14 * without modification. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The names of the authors may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * Alternatively, provided that this notice is retained in full, this 22 * software may be distributed under the terms of the GNU General 23 * Public License ("GPL") version 2, in which case the provisions of the 24 * GPL apply INSTEAD OF those given above. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 37 * DAMAGE. 38 * 39 */ 40 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <unistd.h> 44 #include <syslog.h> 45 #include <fcntl.h> 46 #include <sys/socket.h> 47 #include <netinet/in.h> 48 #include <arpa/inet.h> 49 #include <string.h> 50 51 #include "utils.h" 52 #include "tc_util.h" 53 54 static void explain(void) 55 { 56 fprintf(stderr, "Usage: ... codel [ limit PACKETS ] [ target TIME]\n"); 57 fprintf(stderr, " [ interval TIME ] [ ecn | noecn ]\n"); 58 fprintf(stderr, " [ ce_threshold TIME ]\n"); 59 } 60 61 static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, 62 struct nlmsghdr *n) 63 { 64 unsigned limit = 0; 65 unsigned target = 0; 66 unsigned interval = 0; 67 unsigned ce_threshold = ~0U; 68 int ecn = -1; 69 struct rtattr *tail; 70 71 while (argc > 0) { 72 if (strcmp(*argv, "limit") == 0) { 73 NEXT_ARG(); 74 if (get_unsigned(&limit, *argv, 0)) { 75 fprintf(stderr, "Illegal \"limit\"\n"); 76 return -1; 77 } 78 } else if (strcmp(*argv, "target") == 0) { 79 NEXT_ARG(); 80 if (get_time(&target, *argv)) { 81 fprintf(stderr, "Illegal \"target\"\n"); 82 return -1; 83 } 84 } else if (strcmp(*argv, "ce_threshold") == 0) { 85 NEXT_ARG(); 86 if (get_time(&ce_threshold, *argv)) { 87 fprintf(stderr, "Illegal \"ce_threshold\"\n"); 88 return -1; 89 } 90 } else if (strcmp(*argv, "interval") == 0) { 91 NEXT_ARG(); 92 if (get_time(&interval, *argv)) { 93 fprintf(stderr, "Illegal \"interval\"\n"); 94 return -1; 95 } 96 } else if (strcmp(*argv, "ecn") == 0) { 97 ecn = 1; 98 } else if (strcmp(*argv, "noecn") == 0) { 99 ecn = 0; 100 } else if (strcmp(*argv, "help") == 0) { 101 explain(); 102 return -1; 103 } else { 104 fprintf(stderr, "What is \"%s\"?\n", *argv); 105 explain(); 106 return -1; 107 } 108 argc--; argv++; 109 } 110 111 tail = NLMSG_TAIL(n); 112 addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); 113 if (limit) 114 addattr_l(n, 1024, TCA_CODEL_LIMIT, &limit, sizeof(limit)); 115 if (interval) 116 addattr_l(n, 1024, TCA_CODEL_INTERVAL, &interval, sizeof(interval)); 117 if (target) 118 addattr_l(n, 1024, TCA_CODEL_TARGET, &target, sizeof(target)); 119 if (ecn != -1) 120 addattr_l(n, 1024, TCA_CODEL_ECN, &ecn, sizeof(ecn)); 121 if (ce_threshold != ~0U) 122 addattr_l(n, 1024, TCA_CODEL_CE_THRESHOLD, 123 &ce_threshold, sizeof(ce_threshold)); 124 125 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; 126 return 0; 127 } 128 129 static int codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) 130 { 131 struct rtattr *tb[TCA_CODEL_MAX + 1]; 132 unsigned limit; 133 unsigned interval; 134 unsigned target; 135 unsigned ecn; 136 unsigned ce_threshold; 137 SPRINT_BUF(b1); 138 139 if (opt == NULL) 140 return 0; 141 142 parse_rtattr_nested(tb, TCA_CODEL_MAX, opt); 143 144 if (tb[TCA_CODEL_LIMIT] && 145 RTA_PAYLOAD(tb[TCA_CODEL_LIMIT]) >= sizeof(__u32)) { 146 limit = rta_getattr_u32(tb[TCA_CODEL_LIMIT]); 147 fprintf(f, "limit %up ", limit); 148 } 149 if (tb[TCA_CODEL_TARGET] && 150 RTA_PAYLOAD(tb[TCA_CODEL_TARGET]) >= sizeof(__u32)) { 151 target = rta_getattr_u32(tb[TCA_CODEL_TARGET]); 152 fprintf(f, "target %s ", sprint_time(target, b1)); 153 } 154 if (tb[TCA_CODEL_CE_THRESHOLD] && 155 RTA_PAYLOAD(tb[TCA_CODEL_CE_THRESHOLD]) >= sizeof(__u32)) { 156 ce_threshold = rta_getattr_u32(tb[TCA_CODEL_CE_THRESHOLD]); 157 fprintf(f, "ce_threshold %s ", sprint_time(ce_threshold, b1)); 158 } 159 if (tb[TCA_CODEL_INTERVAL] && 160 RTA_PAYLOAD(tb[TCA_CODEL_INTERVAL]) >= sizeof(__u32)) { 161 interval = rta_getattr_u32(tb[TCA_CODEL_INTERVAL]); 162 fprintf(f, "interval %s ", sprint_time(interval, b1)); 163 } 164 if (tb[TCA_CODEL_ECN] && 165 RTA_PAYLOAD(tb[TCA_CODEL_ECN]) >= sizeof(__u32)) { 166 ecn = rta_getattr_u32(tb[TCA_CODEL_ECN]); 167 if (ecn) 168 fprintf(f, "ecn "); 169 } 170 171 return 0; 172 } 173 174 static int codel_print_xstats(struct qdisc_util *qu, FILE *f, 175 struct rtattr *xstats) 176 { 177 struct tc_codel_xstats _st, *st; 178 SPRINT_BUF(b1); 179 180 if (xstats == NULL) 181 return 0; 182 183 st = RTA_DATA(xstats); 184 if (RTA_PAYLOAD(xstats) < sizeof(*st)) { 185 memset(&_st, 0, sizeof(_st)); 186 memcpy(&_st, st, RTA_PAYLOAD(xstats)); 187 st = &_st; 188 } 189 190 fprintf(f, " count %u lastcount %u ldelay %s", 191 st->count, st->lastcount, sprint_time(st->ldelay, b1)); 192 if (st->dropping) 193 fprintf(f, " dropping"); 194 if (st->drop_next < 0) 195 fprintf(f, " drop_next -%s", sprint_time(-st->drop_next, b1)); 196 else 197 fprintf(f, " drop_next %s", sprint_time(st->drop_next, b1)); 198 fprintf(f, "\n maxpacket %u ecn_mark %u drop_overlimit %u", 199 st->maxpacket, st->ecn_mark, st->drop_overlimit); 200 if (st->ce_mark) 201 fprintf(f, " ce_mark %u", st->ce_mark); 202 return 0; 203 204 } 205 206 struct qdisc_util codel_qdisc_util = { 207 .id = "codel", 208 .parse_qopt = codel_parse_opt, 209 .print_qopt = codel_print_opt, 210 .print_xstats = codel_print_xstats, 211 }; 212