1dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat/* 2dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * q_red.c RED. 3dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * 4dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * This program is free software; you can redistribute it and/or 5dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * modify it under the terms of the GNU General Public License 6dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * as published by the Free Software Foundation; either version 7dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * 2 of the License, or (at your option) any later version. 8dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * 9dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 10dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * 11dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat */ 12dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 13dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <stdio.h> 14dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <stdlib.h> 15dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <unistd.h> 16dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <syslog.h> 17dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <fcntl.h> 18dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <sys/socket.h> 19dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <netinet/in.h> 20dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <arpa/inet.h> 21dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <string.h> 22dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 23dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "utils.h" 24dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "tc_util.h" 25dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 26dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "tc_red.h" 27dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 28dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic void explain(void) 29dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{ 30dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "Usage: ... red limit BYTES min BYTES max BYTES avpkt BYTES burst PACKETS\n"); 31dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, " probability PROBABILITY bandwidth KBPS [ ecn ]\n"); 32dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat} 33dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 34dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) 35dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{ 36dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat struct tc_red_qopt opt; 37dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat unsigned burst = 0; 38dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat unsigned avpkt = 0; 39dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat double probability = 0.02; 40dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat unsigned rate = 0; 41dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat int ecn_ok = 0; 42dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat int wlog; 43dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat __u8 sbuf[256]; 44dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat struct rtattr *tail; 45dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 46dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat memset(&opt, 0, sizeof(opt)); 47dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 48dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat while (argc > 0) { 49dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (strcmp(*argv, "limit") == 0) { 50dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat NEXT_ARG(); 51dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (get_size(&opt.limit, *argv)) { 52dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "Illegal \"limit\"\n"); 53dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 54dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 55dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } else if (strcmp(*argv, "min") == 0) { 56dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat NEXT_ARG(); 57dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (get_size(&opt.qth_min, *argv)) { 58dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "Illegal \"min\"\n"); 59dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 60dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 61dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } else if (strcmp(*argv, "max") == 0) { 62dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat NEXT_ARG(); 63dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (get_size(&opt.qth_max, *argv)) { 64dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "Illegal \"max\"\n"); 65dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 66dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 67dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } else if (strcmp(*argv, "burst") == 0) { 68dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat NEXT_ARG(); 69dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (get_unsigned(&burst, *argv, 0)) { 70dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "Illegal \"burst\"\n"); 71dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 72dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 73dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } else if (strcmp(*argv, "avpkt") == 0) { 74dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat NEXT_ARG(); 75dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (get_size(&avpkt, *argv)) { 76dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "Illegal \"avpkt\"\n"); 77dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 78dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 79dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } else if (strcmp(*argv, "probability") == 0) { 80dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat NEXT_ARG(); 81dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (sscanf(*argv, "%lg", &probability) != 1) { 82dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "Illegal \"probability\"\n"); 83dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 84dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 85dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } else if (strcmp(*argv, "bandwidth") == 0) { 86dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat NEXT_ARG(); 87dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (get_rate(&rate, *argv)) { 88dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "Illegal \"bandwidth\"\n"); 89dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 90dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 91dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } else if (strcmp(*argv, "ecn") == 0) { 92dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat ecn_ok = 1; 93dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } else if (strcmp(*argv, "help") == 0) { 94dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat explain(); 95dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 96dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } else { 97dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "What is \"%s\"?\n", *argv); 98dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat explain(); 99dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 100dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 101dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat argc--; argv++; 102dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 103dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 104dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (rate == 0) 105dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat get_rate(&rate, "10Mbit"); 106dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 107dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (!opt.qth_min || !opt.qth_max || !burst || !opt.limit || !avpkt) { 1081a441f49ec87ef74b978d7ae17da2a9b2ca6e811Dmitry Shmidt fprintf(stderr, "Required parameter (min, max, burst, limit, avpkt) is missing\n"); 109dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 110dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 111dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 112dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if ((wlog = tc_red_eval_ewma(opt.qth_min, burst, avpkt)) < 0) { 113dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "RED: failed to calculate EWMA constant.\n"); 114dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 115dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 116dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (wlog >= 10) 117dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "RED: WARNING. Burst %d seems to be to large.\n", burst); 118dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat opt.Wlog = wlog; 119dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if ((wlog = tc_red_eval_P(opt.qth_min, opt.qth_max, probability)) < 0) { 120dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "RED: failed to calculate probability.\n"); 121dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 122dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 123dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat opt.Plog = wlog; 124dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if ((wlog = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf)) < 0) { 125dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "RED: failed to calculate idle damping table.\n"); 126dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 127dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 128dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat opt.Scell_log = wlog; 129dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (ecn_ok) { 130dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#ifdef TC_RED_ECN 131dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat opt.flags |= TC_RED_ECN; 132dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#else 133dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(stderr, "RED: ECN support is missing in this binary.\n"); 134dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 135dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#endif 136dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 137dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 138dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat tail = NLMSG_TAIL(n); 139dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); 140dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat addattr_l(n, 1024, TCA_RED_PARMS, &opt, sizeof(opt)); 141dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat addattr_l(n, 1024, TCA_RED_STAB, sbuf, 256); 142dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; 143dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return 0; 144dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat} 145dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 146dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int red_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) 147dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{ 148dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat struct rtattr *tb[TCA_RED_STAB+1]; 149dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat struct tc_red_qopt *qopt; 150dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat SPRINT_BUF(b1); 151dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat SPRINT_BUF(b2); 152dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat SPRINT_BUF(b3); 153dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 154dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (opt == NULL) 155dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return 0; 156dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 157dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat parse_rtattr_nested(tb, TCA_RED_STAB, opt); 158dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 159dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (tb[TCA_RED_PARMS] == NULL) 160dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 161dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat qopt = RTA_DATA(tb[TCA_RED_PARMS]); 162dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (RTA_PAYLOAD(tb[TCA_RED_PARMS]) < sizeof(*qopt)) 163dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 164dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(f, "limit %s min %s max %s ", 165dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat sprint_size(qopt->limit, b1), 166dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat sprint_size(qopt->qth_min, b2), 167dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat sprint_size(qopt->qth_max, b3)); 168dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#ifdef TC_RED_ECN 169dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (qopt->flags & TC_RED_ECN) 170dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(f, "ecn "); 171dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#endif 172dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (show_details) { 173dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(f, "ewma %u Plog %u Scell_log %u", 174dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat qopt->Wlog, qopt->Plog, qopt->Scell_log); 175dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat } 176dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return 0; 177dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat} 178dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 179dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int red_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) 180dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{ 181dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#ifdef TC_RED_ECN 182dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat struct tc_red_xstats *st; 183dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 184dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (xstats == NULL) 185dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return 0; 186dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 187dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat if (RTA_PAYLOAD(xstats) < sizeof(*st)) 188dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return -1; 189dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 190dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat st = RTA_DATA(xstats); 191dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat fprintf(f, " marked %u early %u pdrop %u other %u", 192dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat st->marked, st->early, st->pdrop, st->other); 193dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return 0; 194dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 195dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#endif 196dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat return 0; 197dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat} 198dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 199dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat 200dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstruct qdisc_util red_qdisc_util = { 201dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat .id = "red", 202dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat .parse_qopt = red_parse_opt, 203dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat .print_qopt = red_print_opt, 204dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat .print_xstats = red_print_xstats, 205dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}; 206