1/* 2 * q_htb.c HTB. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Martin Devera, devik@cdi.cz 10 * 11 */ 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <unistd.h> 16#include <syslog.h> 17#include <fcntl.h> 18#include <sys/socket.h> 19#include <netinet/in.h> 20#include <arpa/inet.h> 21#include <string.h> 22 23#include "utils.h" 24#include "tc_util.h" 25 26#define HTB_TC_VER 0x30003 27#if HTB_TC_VER >> 16 != TC_HTB_PROTOVER 28#error "Different kernel and TC HTB versions" 29#endif 30 31static void explain(void) 32{ 33 fprintf(stderr, "Usage: ... qdisc add ... htb [default N] [r2q N]\n" 34 " default minor id of class to which unclassified packets are sent {0}\n" 35 " r2q DRR quantums are computed as rate in Bps/r2q {10}\n" 36 " debug string of 16 numbers each 0-3 {0}\n\n" 37 "... class add ... htb rate R1 [burst B1] [mpu B] [overhead O]\n" 38 " [prio P] [slot S] [pslot PS]\n" 39 " [ceil R2] [cburst B2] [mtu MTU] [quantum Q]\n" 40 " rate rate allocated to this class (class can still borrow)\n" 41 " burst max bytes burst which can be accumulated during idle period {computed}\n" 42 " mpu minimum packet size used in rate computations\n" 43 " overhead per-packet size overhead used in rate computations\n" 44 45 " ceil definite upper class rate (no borrows) {rate}\n" 46 " cburst burst but for ceil {computed}\n" 47 " mtu max packet size we create rate map for {1600}\n" 48 " prio priority of leaf; lower are served first {0}\n" 49 " quantum how much bytes to serve from leaf at once {use r2q}\n" 50 "\nTC HTB version %d.%d\n",HTB_TC_VER>>16,HTB_TC_VER&0xffff 51 ); 52} 53 54static void explain1(char *arg) 55{ 56 fprintf(stderr, "Illegal \"%s\"\n", arg); 57 explain(); 58} 59 60 61#define usage() return(-1) 62 63static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) 64{ 65 struct tc_htb_glob opt; 66 struct rtattr *tail; 67 unsigned i; char *p; 68 memset(&opt,0,sizeof(opt)); 69 opt.rate2quantum = 10; 70 opt.version = 3; 71 72 while (argc > 0) { 73 if (matches(*argv, "r2q") == 0) { 74 NEXT_ARG(); 75 if (get_u32(&opt.rate2quantum, *argv, 10)) { 76 explain1("r2q"); return -1; 77 } 78 } else if (matches(*argv, "default") == 0) { 79 NEXT_ARG(); 80 if (get_u32(&opt.defcls, *argv, 16)) { 81 explain1("default"); return -1; 82 } 83 } else if (matches(*argv, "debug") == 0) { 84 NEXT_ARG(); p = *argv; 85 for (i=0; i<16; i++,p++) { 86 if (*p<'0' || *p>'3') break; 87 opt.debug |= (*p-'0')<<(2*i); 88 } 89 } else { 90 fprintf(stderr, "What is \"%s\"?\n", *argv); 91 explain(); 92 return -1; 93 } 94 argc--; argv++; 95 } 96 tail = NLMSG_TAIL(n); 97 addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); 98 addattr_l(n, 2024, TCA_HTB_INIT, &opt, NLMSG_ALIGN(sizeof(opt))); 99 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; 100 return 0; 101} 102 103static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) 104{ 105 int ok=0; 106 struct tc_htb_opt opt; 107 __u32 rtab[256],ctab[256]; 108 unsigned buffer=0,cbuffer=0; 109 int cell_log=-1,ccell_log = -1; 110 unsigned mtu, mpu; 111 unsigned char mpu8 = 0, overhead = 0; 112 struct rtattr *tail; 113 114 memset(&opt, 0, sizeof(opt)); mtu = 1600; /* eth packet len */ 115 116 while (argc > 0) { 117 if (matches(*argv, "prio") == 0) { 118 NEXT_ARG(); 119 if (get_u32(&opt.prio, *argv, 10)) { 120 explain1("prio"); return -1; 121 } 122 ok++; 123 } else if (matches(*argv, "mtu") == 0) { 124 NEXT_ARG(); 125 if (get_u32(&mtu, *argv, 10)) { 126 explain1("mtu"); return -1; 127 } 128 } else if (matches(*argv, "mpu") == 0) { 129 NEXT_ARG(); 130 if (get_u8(&mpu8, *argv, 10)) { 131 explain1("mpu"); return -1; 132 } 133 } else if (matches(*argv, "overhead") == 0) { 134 NEXT_ARG(); 135 if (get_u8(&overhead, *argv, 10)) { 136 explain1("overhead"); return -1; 137 } 138 } else if (matches(*argv, "quantum") == 0) { 139 NEXT_ARG(); 140 if (get_u32(&opt.quantum, *argv, 10)) { 141 explain1("quantum"); return -1; 142 } 143 } else if (matches(*argv, "burst") == 0 || 144 strcmp(*argv, "buffer") == 0 || 145 strcmp(*argv, "maxburst") == 0) { 146 NEXT_ARG(); 147 if (get_size_and_cell(&buffer, &cell_log, *argv) < 0) { 148 explain1("buffer"); 149 return -1; 150 } 151 ok++; 152 } else if (matches(*argv, "cburst") == 0 || 153 strcmp(*argv, "cbuffer") == 0 || 154 strcmp(*argv, "cmaxburst") == 0) { 155 NEXT_ARG(); 156 if (get_size_and_cell(&cbuffer, &ccell_log, *argv) < 0) { 157 explain1("cbuffer"); 158 return -1; 159 } 160 ok++; 161 } else if (strcmp(*argv, "ceil") == 0) { 162 NEXT_ARG(); 163 if (opt.ceil.rate) { 164 fprintf(stderr, "Double \"ceil\" spec\n"); 165 return -1; 166 } 167 if (get_rate(&opt.ceil.rate, *argv)) { 168 explain1("ceil"); 169 return -1; 170 } 171 ok++; 172 } else if (strcmp(*argv, "rate") == 0) { 173 NEXT_ARG(); 174 if (opt.rate.rate) { 175 fprintf(stderr, "Double \"rate\" spec\n"); 176 return -1; 177 } 178 if (get_rate(&opt.rate.rate, *argv)) { 179 explain1("rate"); 180 return -1; 181 } 182 ok++; 183 } else if (strcmp(*argv, "help") == 0) { 184 explain(); 185 return -1; 186 } else { 187 fprintf(stderr, "What is \"%s\"?\n", *argv); 188 explain(); 189 return -1; 190 } 191 argc--; argv++; 192 } 193 194/* if (!ok) 195 return 0;*/ 196 197 if (opt.rate.rate == 0) { 198 fprintf(stderr, "\"rate\" is required.\n"); 199 return -1; 200 } 201 /* if ceil params are missing, use the same as rate */ 202 if (!opt.ceil.rate) opt.ceil = opt.rate; 203 204 /* compute minimal allowed burst from rate; mtu is added here to make 205 sute that buffer is larger than mtu and to have some safeguard space */ 206 if (!buffer) buffer = opt.rate.rate / get_hz() + mtu; 207 if (!cbuffer) cbuffer = opt.ceil.rate / get_hz() + mtu; 208 209/* encode overhead and mpu, 8 bits each, into lower 16 bits */ 210 mpu = (unsigned)mpu8 | (unsigned)overhead << 8; 211 opt.ceil.mpu = mpu; opt.rate.mpu = mpu; 212 213 if ((cell_log = tc_calc_rtable(opt.rate.rate, rtab, cell_log, mtu, mpu)) < 0) { 214 fprintf(stderr, "htb: failed to calculate rate table.\n"); 215 return -1; 216 } 217 opt.buffer = tc_calc_xmittime(opt.rate.rate, buffer); 218 opt.rate.cell_log = cell_log; 219 220 if ((ccell_log = tc_calc_rtable(opt.ceil.rate, ctab, cell_log, mtu, mpu)) < 0) { 221 fprintf(stderr, "htb: failed to calculate ceil rate table.\n"); 222 return -1; 223 } 224 opt.cbuffer = tc_calc_xmittime(opt.ceil.rate, cbuffer); 225 opt.ceil.cell_log = ccell_log; 226 227 tail = NLMSG_TAIL(n); 228 addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); 229 addattr_l(n, 2024, TCA_HTB_PARMS, &opt, sizeof(opt)); 230 addattr_l(n, 3024, TCA_HTB_RTAB, rtab, 1024); 231 addattr_l(n, 4024, TCA_HTB_CTAB, ctab, 1024); 232 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; 233 return 0; 234} 235 236static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) 237{ 238 struct rtattr *tb[TCA_HTB_RTAB+1]; 239 struct tc_htb_opt *hopt; 240 struct tc_htb_glob *gopt; 241 double buffer,cbuffer; 242 SPRINT_BUF(b1); 243 SPRINT_BUF(b2); 244 SPRINT_BUF(b3); 245 246 if (opt == NULL) 247 return 0; 248 249 parse_rtattr_nested(tb, TCA_HTB_RTAB, opt); 250 251 if (tb[TCA_HTB_PARMS]) { 252 253 hopt = RTA_DATA(tb[TCA_HTB_PARMS]); 254 if (RTA_PAYLOAD(tb[TCA_HTB_PARMS]) < sizeof(*hopt)) return -1; 255 256 if (!hopt->level) { 257 fprintf(f, "prio %d ", (int)hopt->prio); 258 if (show_details) 259 fprintf(f, "quantum %d ", (int)hopt->quantum); 260 } 261 fprintf(f, "rate %s ", sprint_rate(hopt->rate.rate, b1)); 262 buffer = ((double)hopt->rate.rate*tc_core_tick2usec(hopt->buffer))/1000000; 263 fprintf(f, "ceil %s ", sprint_rate(hopt->ceil.rate, b1)); 264 cbuffer = ((double)hopt->ceil.rate*tc_core_tick2usec(hopt->cbuffer))/1000000; 265 if (show_details) { 266 fprintf(f, "burst %s/%u mpu %s overhead %s ", 267 sprint_size(buffer, b1), 268 1<<hopt->rate.cell_log, 269 sprint_size(hopt->rate.mpu&0xFF, b2), 270 sprint_size((hopt->rate.mpu>>8)&0xFF, b3)); 271 fprintf(f, "cburst %s/%u mpu %s overhead %s ", 272 sprint_size(cbuffer, b1), 273 1<<hopt->ceil.cell_log, 274 sprint_size(hopt->ceil.mpu&0xFF, b2), 275 sprint_size((hopt->ceil.mpu>>8)&0xFF, b3)); 276 fprintf(f, "level %d ", (int)hopt->level); 277 } else { 278 fprintf(f, "burst %s ", sprint_size(buffer, b1)); 279 fprintf(f, "cburst %s ", sprint_size(cbuffer, b1)); 280 } 281 if (show_raw) 282 fprintf(f, "buffer [%08x] cbuffer [%08x] ", 283 hopt->buffer,hopt->cbuffer); 284 } 285 if (tb[TCA_HTB_INIT]) { 286 gopt = RTA_DATA(tb[TCA_HTB_INIT]); 287 if (RTA_PAYLOAD(tb[TCA_HTB_INIT]) < sizeof(*gopt)) return -1; 288 289 fprintf(f, "r2q %d default %x direct_packets_stat %u", 290 gopt->rate2quantum,gopt->defcls,gopt->direct_pkts); 291 if (show_details) 292 fprintf(f," ver %d.%d",gopt->version >> 16,gopt->version & 0xffff); 293 } 294 return 0; 295} 296 297static int htb_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) 298{ 299 struct tc_htb_xstats *st; 300 if (xstats == NULL) 301 return 0; 302 303 if (RTA_PAYLOAD(xstats) < sizeof(*st)) 304 return -1; 305 306 st = RTA_DATA(xstats); 307 fprintf(f, " lended: %u borrowed: %u giants: %u\n", 308 st->lends,st->borrows,st->giants); 309 fprintf(f, " tokens: %d ctokens: %d\n", st->tokens,st->ctokens); 310 return 0; 311} 312 313struct qdisc_util htb_qdisc_util = { 314 .id = "htb", 315 .parse_qopt = htb_parse_opt, 316 .print_qopt = htb_print_opt, 317 .print_xstats = htb_print_xstats, 318 .parse_copt = htb_parse_class_opt, 319 .print_copt = htb_print_opt, 320}; 321 322/* for testing of old one */ 323struct qdisc_util htb2_qdisc_util = { 324 .id = "htb2", 325 .parse_qopt = htb_parse_opt, 326 .print_qopt = htb_print_opt, 327 .print_xstats = htb_print_xstats, 328 .parse_copt = htb_parse_class_opt, 329 .print_copt = htb_print_opt, 330}; 331