1/* 2 * q_netem.c NETEM. 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: Stephen Hemminger <shemminger@osdl.org> 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#include <errno.h> 23 24#include "utils.h" 25#include "tc_util.h" 26#include "tc_common.h" 27 28static void explain(void) 29{ 30 fprintf(stderr, 31"Usage: ... netem [ limit PACKETS ] \n" \ 32" [ delay TIME [ JITTER [CORRELATION]]]\n" \ 33" [ distribution {uniform|normal|pareto|paretonormal} ]\n" \ 34" [ drop PERCENT [CORRELATION]] \n" \ 35" [ duplicate PERCENT [CORRELATION]]\n" \ 36" [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n"); 37} 38 39static void explain1(const char *arg) 40{ 41 fprintf(stderr, "Illegal \"%s\"\n", arg); 42} 43 44#define usage() return(-1) 45 46/* 47 * Simplistic file parser for distrbution data. 48 * Format is: 49 * # comment line(s) 50 * data0 data1 51 */ 52#define MAXDIST 65536 53static int get_distribution(const char *type, __s16 *data) 54{ 55 FILE *f; 56 int n; 57 long x; 58 size_t len; 59 char *line = NULL; 60 char name[128]; 61 62 snprintf(name, sizeof(name), "/usr/lib/tc/%s.dist", type); 63 if ((f = fopen(name, "r")) == NULL) { 64 fprintf(stderr, "No distribution data for %s (%s: %s)\n", 65 type, name, strerror(errno)); 66 return -1; 67 } 68 69 n = 0; 70 while (getline(&line, &len, f) != -1) { 71 char *p, *endp; 72 if (*line == '\n' || *line == '#') 73 continue; 74 75 for (p = line; ; p = endp) { 76 x = strtol(p, &endp, 0); 77 if (endp == p) 78 break; 79 80 if (n >= MAXDIST) { 81 fprintf(stderr, "%s: too much data\n", 82 name); 83 n = -1; 84 goto error; 85 } 86 data[n++] = x; 87 } 88 } 89 error: 90 free(line); 91 fclose(f); 92 return n; 93} 94 95static int isnumber(const char *arg) 96{ 97 char *p; 98 (void) strtod(arg, &p); 99 return (p != arg); 100} 101 102#define NEXT_IS_NUMBER() (NEXT_ARG_OK() && isnumber(argv[1])) 103 104/* Adjust for the fact that psched_ticks aren't always usecs 105 (based on kernel PSCHED_CLOCK configuration */ 106static int get_ticks(__u32 *ticks, const char *str) 107{ 108 unsigned t; 109 110 if(get_usecs(&t, str)) 111 return -1; 112 113 *ticks = tc_core_usec2tick(t); 114 return 0; 115} 116 117static char *sprint_ticks(__u32 ticks, char *buf) 118{ 119 return sprint_usecs(tc_core_tick2usec(ticks), buf); 120} 121 122 123static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, 124 struct nlmsghdr *n) 125{ 126 size_t dist_size = 0; 127 struct rtattr *tail; 128 struct tc_netem_qopt opt; 129 struct tc_netem_corr cor; 130 struct tc_netem_reorder reorder; 131 __s16 dist_data[MAXDIST]; 132 133 memset(&opt, 0, sizeof(opt)); 134 opt.limit = 1000; 135 memset(&cor, 0, sizeof(cor)); 136 memset(&reorder, 0, sizeof(reorder)); 137 138 while (argc > 0) { 139 if (matches(*argv, "limit") == 0) { 140 NEXT_ARG(); 141 if (get_size(&opt.limit, *argv)) { 142 explain1("limit"); 143 return -1; 144 } 145 } else if (matches(*argv, "latency") == 0 || 146 matches(*argv, "delay") == 0) { 147 NEXT_ARG(); 148 if (get_ticks(&opt.latency, *argv)) { 149 explain1("latency"); 150 return -1; 151 } 152 153 if (NEXT_IS_NUMBER()) { 154 NEXT_ARG(); 155 if (get_ticks(&opt.jitter, *argv)) { 156 explain1("latency"); 157 return -1; 158 } 159 160 if (NEXT_IS_NUMBER()) { 161 NEXT_ARG(); 162 if (get_percent(&cor.delay_corr, 163 *argv)) { 164 explain1("latency"); 165 return -1; 166 } 167 } 168 } 169 } else if (matches(*argv, "loss") == 0 || 170 matches(*argv, "drop") == 0) { 171 NEXT_ARG(); 172 if (get_percent(&opt.loss, *argv)) { 173 explain1("loss"); 174 return -1; 175 } 176 if (NEXT_IS_NUMBER()) { 177 NEXT_ARG(); 178 if (get_percent(&cor.loss_corr, *argv)) { 179 explain1("loss"); 180 return -1; 181 } 182 } 183 } else if (matches(*argv, "reorder") == 0) { 184 NEXT_ARG(); 185 if (get_percent(&reorder.probability, *argv)) { 186 explain1("reorder"); 187 return -1; 188 } 189 if (NEXT_IS_NUMBER()) { 190 NEXT_ARG(); 191 if (get_percent(&reorder.correlation, *argv)) { 192 explain1("reorder"); 193 return -1; 194 } 195 } 196 } else if (matches(*argv, "gap") == 0) { 197 NEXT_ARG(); 198 if (get_u32(&opt.gap, *argv, 0)) { 199 explain1("gap"); 200 return -1; 201 } 202 } else if (matches(*argv, "duplicate") == 0) { 203 NEXT_ARG(); 204 if (get_percent(&opt.duplicate, *argv)) { 205 explain1("duplicate"); 206 return -1; 207 } 208 if (NEXT_IS_NUMBER()) { 209 NEXT_ARG(); 210 if (get_percent(&cor.dup_corr, *argv)) { 211 explain1("duplicate"); 212 return -1; 213 } 214 } 215 } else if (matches(*argv, "distribution") == 0) { 216 NEXT_ARG(); 217 dist_size = get_distribution(*argv, dist_data); 218 if (dist_size < 0) 219 return -1; 220 } else if (strcmp(*argv, "help") == 0) { 221 explain(); 222 return -1; 223 } else { 224 fprintf(stderr, "What is \"%s\"?\n", *argv); 225 explain(); 226 return -1; 227 } 228 argc--; argv++; 229 } 230 231 tail = NLMSG_TAIL(n); 232 233 if (reorder.probability) { 234 if (opt.latency == 0) { 235 fprintf(stderr, "reordering not possible without specifying some delay\n"); 236 } 237 if (opt.gap == 0) 238 opt.gap = 1; 239 } else if (opt.gap > 0) { 240 fprintf(stderr, "gap specified without reorder probability\n"); 241 explain(); 242 return -1; 243 } 244 245 if (dist_size > 0 && (opt.latency == 0 || opt.jitter == 0)) { 246 fprintf(stderr, "distribution specified but no latency and jitter values\n"); 247 explain(); 248 return -1; 249 } 250 251 addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)); 252 addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)); 253 addattr_l(n, 1024, TCA_NETEM_REORDER, &reorder, sizeof(reorder)); 254 255 if (dist_size > 0) { 256 addattr_l(n, 32768, TCA_NETEM_DELAY_DIST, 257 dist_data, dist_size*sizeof(dist_data[0])); 258 } 259 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; 260 return 0; 261} 262 263static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) 264{ 265 const struct tc_netem_corr *cor = NULL; 266 const struct tc_netem_reorder *reorder = NULL; 267 struct tc_netem_qopt qopt; 268 int len = RTA_PAYLOAD(opt) - sizeof(qopt); 269 SPRINT_BUF(b1); 270 271 if (opt == NULL) 272 return 0; 273 274 if (len < 0) { 275 fprintf(stderr, "options size error\n"); 276 return -1; 277 } 278 memcpy(&qopt, RTA_DATA(opt), sizeof(qopt)); 279 280 if (len > 0) { 281 struct rtattr *tb[TCA_NETEM_MAX+1]; 282 parse_rtattr(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(qopt), 283 len); 284 285 if (tb[TCA_NETEM_CORR]) { 286 if (RTA_PAYLOAD(tb[TCA_NETEM_CORR]) < sizeof(*cor)) 287 return -1; 288 cor = RTA_DATA(tb[TCA_NETEM_CORR]); 289 } 290 if (tb[TCA_NETEM_REORDER]) { 291 if (RTA_PAYLOAD(tb[TCA_NETEM_REORDER]) < sizeof(*reorder)) 292 return -1; 293 reorder = RTA_DATA(tb[TCA_NETEM_REORDER]); 294 } 295 } 296 297 fprintf(f, "limit %d", qopt.limit); 298 299 if (qopt.latency) { 300 fprintf(f, " delay %s", sprint_ticks(qopt.latency, b1)); 301 302 if (qopt.jitter) { 303 fprintf(f, " %s", sprint_ticks(qopt.jitter, b1)); 304 if (cor && cor->delay_corr) 305 fprintf(f, " %s", sprint_percent(cor->delay_corr, b1)); 306 } 307 } 308 309 if (qopt.loss) { 310 fprintf(f, " loss %s", sprint_percent(qopt.loss, b1)); 311 if (cor && cor->loss_corr) 312 fprintf(f, " %s", sprint_percent(cor->loss_corr, b1)); 313 } 314 315 if (qopt.duplicate) { 316 fprintf(f, " duplicate %s", 317 sprint_percent(qopt.duplicate, b1)); 318 if (cor && cor->dup_corr) 319 fprintf(f, " %s", sprint_percent(cor->dup_corr, b1)); 320 } 321 322 if (reorder && reorder->probability) { 323 fprintf(f, " reorder %s", 324 sprint_percent(reorder->probability, b1)); 325 if (reorder->correlation) 326 fprintf(f, " %s", 327 sprint_percent(reorder->correlation, b1)); 328 } 329 330 if (qopt.gap) 331 fprintf(f, " gap %lu", (unsigned long)qopt.gap); 332 333 return 0; 334} 335 336struct qdisc_util netem_qdisc_util = { 337 .id = "netem", 338 .parse_qopt = netem_parse_opt, 339 .print_qopt = netem_print_opt, 340}; 341 342