osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 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 | * |
Stephen Hemminger | 59a935d | 2011-03-23 12:29:06 -0700 | [diff] [blame] | 9 | * Authors: Stephen Hemminger <shemminger@linux-foundation.org> |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 10 | * |
| 11 | */ |
| 12 | |
| 13 | #include <stdio.h> |
| 14 | #include <stdlib.h> |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 15 | #include <math.h> |
| 16 | #include <ctype.h> |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 17 | #include <unistd.h> |
| 18 | #include <syslog.h> |
| 19 | #include <fcntl.h> |
| 20 | #include <sys/socket.h> |
| 21 | #include <netinet/in.h> |
| 22 | #include <arpa/inet.h> |
| 23 | #include <string.h> |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 24 | #include <errno.h> |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 25 | |
| 26 | #include "utils.h" |
| 27 | #include "tc_util.h" |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 28 | #include "tc_common.h" |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 29 | |
| 30 | static void explain(void) |
| 31 | { |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 32 | fprintf(stderr, |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 33 | "Usage: ... netem [ limit PACKETS ] \n" \ |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 34 | " [ delay TIME [ JITTER [CORRELATION]]]\n" \ |
| 35 | " [ distribution {uniform|normal|pareto|paretonormal} ]\n" \ |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 36 | " [ corrupt PERCENT [CORRELATION]] \n" \ |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 37 | " [ duplicate PERCENT [CORRELATION]]\n" \ |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 38 | " [ loss random PERCENT [CORRELATION]]\n" \ |
| 39 | " [ loss state P13 [P31 [P32 [P23 P14]]]\n" \ |
| 40 | " [ loss gemodel PERCENT [R [1-H [1-K]]]\n" \ |
Vijay Subramanian | 1070205 | 2012-05-16 13:51:58 +0000 | [diff] [blame] | 41 | " [ ecn ]\n" \ |
Hagen Paul Pfeifer | 6b8dc4d | 2012-01-19 14:28:27 -0800 | [diff] [blame] | 42 | " [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n" \ |
| 43 | " [ rate RATE [PACKETOVERHEAD] [CELLSIZE] [CELLOVERHEAD]]\n"); |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 44 | } |
| 45 | |
| 46 | static void explain1(const char *arg) |
| 47 | { |
| 48 | fprintf(stderr, "Illegal \"%s\"\n", arg); |
| 49 | } |
| 50 | |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 51 | /* Upper bound on size of distribution |
Stephen Hemminger | c1b81cb | 2007-12-12 15:02:51 -0800 | [diff] [blame] | 52 | * really (TCA_BUF_MAX - other headers) / sizeof (__s16) |
| 53 | */ |
| 54 | #define MAX_DIST (16*1024) |
| 55 | |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 56 | static const double max_percent_value = 0xffffffff; |
| 57 | |
| 58 | /* scaled value used to percent of maximum. */ |
| 59 | static void set_percent(__u32 *percent, double per) |
| 60 | { |
| 61 | *percent = (unsigned) rint(per * max_percent_value); |
| 62 | } |
| 63 | |
| 64 | |
| 65 | /* Parse either a fraction '.3' or percent '30% |
| 66 | * return: 0 = ok, -1 = error, 1 = out of range |
| 67 | */ |
| 68 | static int parse_percent(double *val, const char *str) |
| 69 | { |
| 70 | char *p; |
| 71 | |
| 72 | *val = strtod(str, &p) / 100.; |
| 73 | if (*p && strcmp(p, "%") ) |
| 74 | return -1; |
| 75 | |
| 76 | return 0; |
| 77 | } |
| 78 | |
| 79 | static int get_percent(__u32 *percent, const char *str) |
| 80 | { |
| 81 | double per; |
| 82 | |
| 83 | if (parse_percent(&per, str)) |
| 84 | return -1; |
| 85 | |
| 86 | set_percent(percent, per); |
| 87 | return 0; |
| 88 | } |
| 89 | |
Stephen Hemminger | d1f28cf | 2013-02-12 11:09:03 -0800 | [diff] [blame] | 90 | static void print_percent(char *buf, int len, __u32 per) |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 91 | { |
| 92 | snprintf(buf, len, "%g%%", 100. * (double) per / max_percent_value); |
| 93 | } |
| 94 | |
Stephen Hemminger | d1f28cf | 2013-02-12 11:09:03 -0800 | [diff] [blame] | 95 | static char * sprint_percent(__u32 per, char *buf) |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 96 | { |
| 97 | print_percent(buf, SPRINT_BSIZE-1, per); |
| 98 | return buf; |
| 99 | } |
| 100 | |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 101 | /* |
| 102 | * Simplistic file parser for distrbution data. |
| 103 | * Format is: |
| 104 | * # comment line(s) |
Stephen Hemminger | c1b81cb | 2007-12-12 15:02:51 -0800 | [diff] [blame] | 105 | * data0 data1 ... |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 106 | */ |
Stephen Hemminger | c1b81cb | 2007-12-12 15:02:51 -0800 | [diff] [blame] | 107 | static int get_distribution(const char *type, __s16 *data, int maxdata) |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 108 | { |
| 109 | FILE *f; |
| 110 | int n; |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 111 | long x; |
| 112 | size_t len; |
osdl.net!shemminger | fb9b1d0 | 2005-02-07 18:15:04 +0000 | [diff] [blame] | 113 | char *line = NULL; |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 114 | char name[128]; |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 115 | |
Stephen Hemminger | aa27f88 | 2007-06-20 15:27:22 -0700 | [diff] [blame] | 116 | snprintf(name, sizeof(name), "%s/%s.dist", get_tc_lib(), type); |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 117 | if ((f = fopen(name, "r")) == NULL) { |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 118 | fprintf(stderr, "No distribution data for %s (%s: %s)\n", |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 119 | type, name, strerror(errno)); |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 120 | return -1; |
| 121 | } |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 122 | |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 123 | n = 0; |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 124 | while (getline(&line, &len, f) != -1) { |
| 125 | char *p, *endp; |
| 126 | if (*line == '\n' || *line == '#') |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 127 | continue; |
| 128 | |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 129 | for (p = line; ; p = endp) { |
| 130 | x = strtol(p, &endp, 0); |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 131 | if (endp == p) |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 132 | break; |
| 133 | |
Stephen Hemminger | c1b81cb | 2007-12-12 15:02:51 -0800 | [diff] [blame] | 134 | if (n >= maxdata) { |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 135 | fprintf(stderr, "%s: too much data\n", |
| 136 | name); |
| 137 | n = -1; |
| 138 | goto error; |
| 139 | } |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 140 | data[n++] = x; |
| 141 | } |
| 142 | } |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 143 | error: |
| 144 | free(line); |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 145 | fclose(f); |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 146 | return n; |
| 147 | } |
| 148 | |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 149 | #define NEXT_IS_NUMBER() (NEXT_ARG_OK() && isdigit(argv[1][0])) |
Johannes Naab | e72ca3f | 2013-01-23 11:38:19 +0000 | [diff] [blame] | 150 | #define NEXT_IS_SIGNED_NUMBER() \ |
| 151 | (NEXT_ARG_OK() && (isdigit(argv[1][0]) || argv[1][0] == '-')) |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 152 | |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 153 | /* Adjust for the fact that psched_ticks aren't always usecs |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 154 | (based on kernel PSCHED_CLOCK configuration */ |
| 155 | static int get_ticks(__u32 *ticks, const char *str) |
| 156 | { |
| 157 | unsigned t; |
| 158 | |
Patrick McHardy | 8f34caa | 2007-03-04 20:15:00 +0100 | [diff] [blame] | 159 | if(get_time(&t, str)) |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 160 | return -1; |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 161 | |
Patrick McHardy | 8f34caa | 2007-03-04 20:15:00 +0100 | [diff] [blame] | 162 | if (tc_core_time2big(t)) { |
| 163 | fprintf(stderr, "Illegal %u time (too large)\n", t); |
Stephen Hemminger | fa56513 | 2006-10-19 13:10:26 -0700 | [diff] [blame] | 164 | return -1; |
| 165 | } |
| 166 | |
Patrick McHardy | 8f34caa | 2007-03-04 20:15:00 +0100 | [diff] [blame] | 167 | *ticks = tc_core_time2tick(t); |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 168 | return 0; |
| 169 | } |
| 170 | |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 171 | static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 172 | struct nlmsghdr *n) |
| 173 | { |
Thomas Jarosch | fcbd016 | 2011-11-23 22:15:19 +0100 | [diff] [blame] | 174 | int dist_size = 0; |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 175 | struct rtattr *tail; |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 176 | struct tc_netem_qopt opt = { .limit = 1000 }; |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 177 | struct tc_netem_corr cor; |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 178 | struct tc_netem_reorder reorder; |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 179 | struct tc_netem_corrupt corrupt; |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 180 | struct tc_netem_gimodel gimodel; |
| 181 | struct tc_netem_gemodel gemodel; |
Hagen Paul Pfeifer | 6b8dc4d | 2012-01-19 14:28:27 -0800 | [diff] [blame] | 182 | struct tc_netem_rate rate; |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 183 | __s16 *dist_data = NULL; |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 184 | __u16 loss_type = NETEM_LOSS_UNSPEC; |
Stephen Hemminger | 40076f6 | 2007-01-09 15:46:55 -0800 | [diff] [blame] | 185 | int present[__TCA_NETEM_MAX]; |
Yang Yingliang | dad2f72 | 2014-01-16 11:09:14 +0800 | [diff] [blame] | 186 | __u64 rate64 = 0; |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 187 | |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 188 | memset(&cor, 0, sizeof(cor)); |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 189 | memset(&reorder, 0, sizeof(reorder)); |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 190 | memset(&corrupt, 0, sizeof(corrupt)); |
Hagen Paul Pfeifer | 6b8dc4d | 2012-01-19 14:28:27 -0800 | [diff] [blame] | 191 | memset(&rate, 0, sizeof(rate)); |
Stephen Hemminger | 40076f6 | 2007-01-09 15:46:55 -0800 | [diff] [blame] | 192 | memset(present, 0, sizeof(present)); |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 193 | |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 194 | for( ; argc > 0; --argc, ++argv) { |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 195 | if (matches(*argv, "limit") == 0) { |
| 196 | NEXT_ARG(); |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 197 | if (get_size(&opt.limit, *argv)) { |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 198 | explain1("limit"); |
| 199 | return -1; |
| 200 | } |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 201 | } else if (matches(*argv, "latency") == 0 || |
| 202 | matches(*argv, "delay") == 0) { |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 203 | NEXT_ARG(); |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 204 | if (get_ticks(&opt.latency, *argv)) { |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 205 | explain1("latency"); |
| 206 | return -1; |
| 207 | } |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 208 | |
| 209 | if (NEXT_IS_NUMBER()) { |
| 210 | NEXT_ARG(); |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 211 | if (get_ticks(&opt.jitter, *argv)) { |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 212 | explain1("latency"); |
| 213 | return -1; |
| 214 | } |
| 215 | |
| 216 | if (NEXT_IS_NUMBER()) { |
| 217 | NEXT_ARG(); |
Stephen Hemminger | 40076f6 | 2007-01-09 15:46:55 -0800 | [diff] [blame] | 218 | ++present[TCA_NETEM_CORR]; |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 219 | if (get_percent(&cor.delay_corr, *argv)) { |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 220 | explain1("latency"); |
| 221 | return -1; |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | } else if (matches(*argv, "loss") == 0 || |
| 226 | matches(*argv, "drop") == 0) { |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 227 | if (opt.loss > 0 || loss_type != NETEM_LOSS_UNSPEC) { |
| 228 | explain1("duplicate loss argument\n"); |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 229 | return -1; |
| 230 | } |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 231 | |
| 232 | NEXT_ARG(); |
| 233 | /* Old (deprecated) random loss model syntax */ |
| 234 | if (isdigit(argv[0][0])) |
| 235 | goto random_loss_model; |
| 236 | |
| 237 | if (!strcmp(*argv, "random")) { |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 238 | NEXT_ARG(); |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 239 | random_loss_model: |
| 240 | if (get_percent(&opt.loss, *argv)) { |
| 241 | explain1("loss percent"); |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 242 | return -1; |
| 243 | } |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 244 | if (NEXT_IS_NUMBER()) { |
| 245 | NEXT_ARG(); |
| 246 | ++present[TCA_NETEM_CORR]; |
| 247 | if (get_percent(&cor.loss_corr, *argv)) { |
| 248 | explain1("loss correllation"); |
| 249 | return -1; |
| 250 | } |
| 251 | } |
| 252 | } else if (!strcmp(*argv, "state")) { |
| 253 | double p13; |
| 254 | |
| 255 | NEXT_ARG(); |
| 256 | if (parse_percent(&p13, *argv)) { |
| 257 | explain1("loss p13"); |
| 258 | return -1; |
| 259 | } |
| 260 | |
| 261 | /* set defaults */ |
| 262 | set_percent(&gimodel.p13, p13); |
| 263 | set_percent(&gimodel.p31, 1. - p13); |
| 264 | set_percent(&gimodel.p32, 0); |
| 265 | set_percent(&gimodel.p23, 1.); |
Jay Vosburgh | 8f9672a | 2014-05-08 19:02:20 -0700 | [diff] [blame] | 266 | set_percent(&gimodel.p14, 0); |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 267 | loss_type = NETEM_LOSS_GI; |
| 268 | |
| 269 | if (!NEXT_IS_NUMBER()) |
| 270 | continue; |
| 271 | NEXT_ARG(); |
| 272 | if (get_percent(&gimodel.p31, *argv)) { |
| 273 | explain1("loss p31"); |
| 274 | return -1; |
| 275 | } |
| 276 | |
| 277 | if (!NEXT_IS_NUMBER()) |
| 278 | continue; |
| 279 | NEXT_ARG(); |
| 280 | if (get_percent(&gimodel.p32, *argv)) { |
| 281 | explain1("loss p32"); |
| 282 | return -1; |
| 283 | } |
| 284 | |
| 285 | if (!NEXT_IS_NUMBER()) |
| 286 | continue; |
| 287 | NEXT_ARG(); |
| 288 | if (get_percent(&gimodel.p23, *argv)) { |
| 289 | explain1("loss p23"); |
| 290 | return -1; |
| 291 | } |
Jay Vosburgh | 8f9672a | 2014-05-08 19:02:20 -0700 | [diff] [blame] | 292 | if (!NEXT_IS_NUMBER()) |
| 293 | continue; |
| 294 | NEXT_ARG(); |
| 295 | if (get_percent(&gimodel.p14, *argv)) { |
| 296 | explain1("loss p14"); |
| 297 | return -1; |
| 298 | } |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 299 | |
| 300 | } else if (!strcmp(*argv, "gemodel")) { |
| 301 | NEXT_ARG(); |
| 302 | if (get_percent(&gemodel.p, *argv)) { |
| 303 | explain1("loss gemodel p"); |
| 304 | return -1; |
| 305 | } |
| 306 | |
| 307 | /* set defaults */ |
| 308 | set_percent(&gemodel.r, 1.); |
| 309 | set_percent(&gemodel.h, 0); |
Jay Vosburgh | 3757185 | 2014-05-10 13:34:58 -0700 | [diff] [blame] | 310 | set_percent(&gemodel.k1, 0); |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 311 | loss_type = NETEM_LOSS_GE; |
| 312 | |
| 313 | if (!NEXT_IS_NUMBER()) |
| 314 | continue; |
| 315 | NEXT_ARG(); |
| 316 | if (get_percent(&gemodel.r, *argv)) { |
| 317 | explain1("loss gemodel r"); |
| 318 | return -1; |
| 319 | } |
| 320 | |
| 321 | if (!NEXT_IS_NUMBER()) |
| 322 | continue; |
| 323 | NEXT_ARG(); |
| 324 | if (get_percent(&gemodel.h, *argv)) { |
| 325 | explain1("loss gemodel h"); |
| 326 | return -1; |
| 327 | } |
Jay Vosburgh | 3757185 | 2014-05-10 13:34:58 -0700 | [diff] [blame] | 328 | /* netem option is "1-h" but kernel |
| 329 | * expects "h". |
| 330 | */ |
| 331 | gemodel.h = max_percent_value - gemodel.h; |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 332 | |
| 333 | if (!NEXT_IS_NUMBER()) |
| 334 | continue; |
| 335 | NEXT_ARG(); |
| 336 | if (get_percent(&gemodel.k1, *argv)) { |
| 337 | explain1("loss gemodel k"); |
| 338 | return -1; |
| 339 | } |
| 340 | } else { |
| 341 | fprintf(stderr, "Unknown loss parameter: %s\n", |
| 342 | *argv); |
| 343 | return -1; |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 344 | } |
Vijay Subramanian | 1070205 | 2012-05-16 13:51:58 +0000 | [diff] [blame] | 345 | } else if (matches(*argv, "ecn") == 0) { |
| 346 | present[TCA_NETEM_ECN] = 1; |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 347 | } else if (matches(*argv, "reorder") == 0) { |
| 348 | NEXT_ARG(); |
Stephen Hemminger | 40076f6 | 2007-01-09 15:46:55 -0800 | [diff] [blame] | 349 | present[TCA_NETEM_REORDER] = 1; |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 350 | if (get_percent(&reorder.probability, *argv)) { |
| 351 | explain1("reorder"); |
| 352 | return -1; |
| 353 | } |
| 354 | if (NEXT_IS_NUMBER()) { |
| 355 | NEXT_ARG(); |
Stephen Hemminger | 40076f6 | 2007-01-09 15:46:55 -0800 | [diff] [blame] | 356 | ++present[TCA_NETEM_CORR]; |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 357 | if (get_percent(&reorder.correlation, *argv)) { |
| 358 | explain1("reorder"); |
| 359 | return -1; |
| 360 | } |
| 361 | } |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 362 | } else if (matches(*argv, "corrupt") == 0) { |
| 363 | NEXT_ARG(); |
Stephen Hemminger | 40076f6 | 2007-01-09 15:46:55 -0800 | [diff] [blame] | 364 | present[TCA_NETEM_CORRUPT] = 1; |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 365 | if (get_percent(&corrupt.probability, *argv)) { |
| 366 | explain1("corrupt"); |
| 367 | return -1; |
| 368 | } |
| 369 | if (NEXT_IS_NUMBER()) { |
| 370 | NEXT_ARG(); |
Stephen Hemminger | 40076f6 | 2007-01-09 15:46:55 -0800 | [diff] [blame] | 371 | ++present[TCA_NETEM_CORR]; |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 372 | if (get_percent(&corrupt.correlation, *argv)) { |
| 373 | explain1("corrupt"); |
| 374 | return -1; |
| 375 | } |
| 376 | } |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 377 | } else if (matches(*argv, "gap") == 0) { |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 378 | NEXT_ARG(); |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 379 | if (get_u32(&opt.gap, *argv, 0)) { |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 380 | explain1("gap"); |
| 381 | return -1; |
| 382 | } |
osdl.net!shemminger | ffb79d0 | 2004-07-01 11:02:04 +0000 | [diff] [blame] | 383 | } else if (matches(*argv, "duplicate") == 0) { |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 384 | NEXT_ARG(); |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 385 | if (get_percent(&opt.duplicate, *argv)) { |
osdl.net!shemminger | ffb79d0 | 2004-07-01 11:02:04 +0000 | [diff] [blame] | 386 | explain1("duplicate"); |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 387 | return -1; |
| 388 | } |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 389 | if (NEXT_IS_NUMBER()) { |
| 390 | NEXT_ARG(); |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 391 | if (get_percent(&cor.dup_corr, *argv)) { |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 392 | explain1("duplicate"); |
| 393 | return -1; |
| 394 | } |
| 395 | } |
| 396 | } else if (matches(*argv, "distribution") == 0) { |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 397 | NEXT_ARG(); |
Stephen Hemminger | c1b81cb | 2007-12-12 15:02:51 -0800 | [diff] [blame] | 398 | dist_data = calloc(sizeof(dist_data[0]), MAX_DIST); |
| 399 | dist_size = get_distribution(*argv, dist_data, MAX_DIST); |
| 400 | if (dist_size <= 0) { |
| 401 | free(dist_data); |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 402 | return -1; |
Stephen Hemminger | c1b81cb | 2007-12-12 15:02:51 -0800 | [diff] [blame] | 403 | } |
Hagen Paul Pfeifer | 6b8dc4d | 2012-01-19 14:28:27 -0800 | [diff] [blame] | 404 | } else if (matches(*argv, "rate") == 0) { |
| 405 | ++present[TCA_NETEM_RATE]; |
| 406 | NEXT_ARG(); |
Yang Yingliang | dad2f72 | 2014-01-16 11:09:14 +0800 | [diff] [blame] | 407 | if (get_rate64(&rate64, *argv)) { |
Hagen Paul Pfeifer | 6b8dc4d | 2012-01-19 14:28:27 -0800 | [diff] [blame] | 408 | explain1("rate"); |
| 409 | return -1; |
| 410 | } |
Johannes Naab | e72ca3f | 2013-01-23 11:38:19 +0000 | [diff] [blame] | 411 | if (NEXT_IS_SIGNED_NUMBER()) { |
Hagen Paul Pfeifer | 6b8dc4d | 2012-01-19 14:28:27 -0800 | [diff] [blame] | 412 | NEXT_ARG(); |
| 413 | if (get_s32(&rate.packet_overhead, *argv, 0)) { |
| 414 | explain1("rate"); |
| 415 | return -1; |
| 416 | } |
| 417 | } |
| 418 | if (NEXT_IS_NUMBER()) { |
| 419 | NEXT_ARG(); |
| 420 | if (get_u32(&rate.cell_size, *argv, 0)) { |
| 421 | explain1("rate"); |
| 422 | return -1; |
| 423 | } |
| 424 | } |
Johannes Naab | e72ca3f | 2013-01-23 11:38:19 +0000 | [diff] [blame] | 425 | if (NEXT_IS_SIGNED_NUMBER()) { |
Hagen Paul Pfeifer | 6b8dc4d | 2012-01-19 14:28:27 -0800 | [diff] [blame] | 426 | NEXT_ARG(); |
| 427 | if (get_s32(&rate.cell_overhead, *argv, 0)) { |
| 428 | explain1("rate"); |
| 429 | return -1; |
| 430 | } |
| 431 | } |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 432 | } else if (strcmp(*argv, "help") == 0) { |
| 433 | explain(); |
| 434 | return -1; |
| 435 | } else { |
| 436 | fprintf(stderr, "What is \"%s\"?\n", *argv); |
| 437 | explain(); |
| 438 | return -1; |
| 439 | } |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 440 | } |
| 441 | |
17!tgraf | 1a1d22a | 2005-01-18 01:24:18 +0000 | [diff] [blame] | 442 | tail = NLMSG_TAIL(n); |
osdl.net!shemminger | 025dc69 | 2004-08-09 17:12:23 +0000 | [diff] [blame] | 443 | |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 444 | if (reorder.probability) { |
| 445 | if (opt.latency == 0) { |
| 446 | fprintf(stderr, "reordering not possible without specifying some delay\n"); |
Vijay Subramanian | 14a1c16 | 2012-01-20 09:50:25 -0800 | [diff] [blame] | 447 | explain(); |
| 448 | return -1; |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 449 | } |
| 450 | if (opt.gap == 0) |
| 451 | opt.gap = 1; |
| 452 | } else if (opt.gap > 0) { |
| 453 | fprintf(stderr, "gap specified without reorder probability\n"); |
| 454 | explain(); |
| 455 | return -1; |
| 456 | } |
| 457 | |
Vijay Subramanian | 1070205 | 2012-05-16 13:51:58 +0000 | [diff] [blame] | 458 | if (present[TCA_NETEM_ECN]) { |
| 459 | if (opt.loss <= 0 && loss_type == NETEM_LOSS_UNSPEC) { |
| 460 | fprintf(stderr, "ecn requested without loss model\n"); |
| 461 | explain(); |
| 462 | return -1; |
| 463 | } |
| 464 | } |
| 465 | |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 466 | if (dist_data && (opt.latency == 0 || opt.jitter == 0)) { |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 467 | fprintf(stderr, "distribution specified but no latency and jitter values\n"); |
| 468 | explain(); |
| 469 | return -1; |
| 470 | } |
| 471 | |
Stephen Hemminger | c1b81cb | 2007-12-12 15:02:51 -0800 | [diff] [blame] | 472 | if (addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)) < 0) |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 473 | return -1; |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 474 | |
Stephen Hemminger | 40076f6 | 2007-01-09 15:46:55 -0800 | [diff] [blame] | 475 | if (present[TCA_NETEM_CORR] && |
Stephen Hemminger | c1b81cb | 2007-12-12 15:02:51 -0800 | [diff] [blame] | 476 | addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0) |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 477 | return -1; |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 478 | |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 479 | if (present[TCA_NETEM_REORDER] && |
Stephen Hemminger | c1b81cb | 2007-12-12 15:02:51 -0800 | [diff] [blame] | 480 | addattr_l(n, 1024, TCA_NETEM_REORDER, &reorder, sizeof(reorder)) < 0) |
shemminger | e9bc3c4 | 2005-12-10 00:01:02 +0000 | [diff] [blame] | 481 | return -1; |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 482 | |
Vijay Subramanian | 1070205 | 2012-05-16 13:51:58 +0000 | [diff] [blame] | 483 | if (present[TCA_NETEM_ECN] && |
| 484 | addattr_l(n, 1024, TCA_NETEM_ECN, &present[TCA_NETEM_ECN], |
| 485 | sizeof(present[TCA_NETEM_ECN])) < 0) |
| 486 | return -1; |
| 487 | |
Stephen Hemminger | 40076f6 | 2007-01-09 15:46:55 -0800 | [diff] [blame] | 488 | if (present[TCA_NETEM_CORRUPT] && |
Stephen Hemminger | c1b81cb | 2007-12-12 15:02:51 -0800 | [diff] [blame] | 489 | addattr_l(n, 1024, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0) |
Stephen Hemminger | 40076f6 | 2007-01-09 15:46:55 -0800 | [diff] [blame] | 490 | return -1; |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 491 | |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 492 | if (loss_type != NETEM_LOSS_UNSPEC) { |
| 493 | struct rtattr *start; |
| 494 | |
| 495 | start = addattr_nest(n, 1024, TCA_NETEM_LOSS | NLA_F_NESTED); |
| 496 | if (loss_type == NETEM_LOSS_GI) { |
| 497 | if (addattr_l(n, 1024, NETEM_LOSS_GI, |
| 498 | &gimodel, sizeof(gimodel)) < 0) |
| 499 | return -1; |
| 500 | } else if (loss_type == NETEM_LOSS_GE) { |
| 501 | if (addattr_l(n, 1024, NETEM_LOSS_GE, |
| 502 | &gemodel, sizeof(gemodel)) < 0) |
| 503 | return -1; |
| 504 | } else { |
| 505 | fprintf(stderr, "loss in the weeds!\n"); |
| 506 | return -1; |
| 507 | } |
Stephen Hemminger | 3d0b743 | 2014-12-20 15:47:17 -0800 | [diff] [blame] | 508 | |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 509 | addattr_nest_end(n, start); |
| 510 | } |
| 511 | |
Yang Yingliang | dad2f72 | 2014-01-16 11:09:14 +0800 | [diff] [blame] | 512 | if (present[TCA_NETEM_RATE]) { |
| 513 | if (rate64 >= (1ULL << 32)) { |
| 514 | if (addattr_l(n, 1024, |
| 515 | TCA_NETEM_RATE64, &rate64, sizeof(rate64)) < 0) |
| 516 | return -1; |
| 517 | rate.rate = ~0U; |
| 518 | } else { |
| 519 | rate.rate = rate64; |
| 520 | } |
| 521 | if (addattr_l(n, 1024, TCA_NETEM_RATE, &rate, sizeof(rate)) < 0) |
| 522 | return -1; |
| 523 | } |
Hagen Paul Pfeifer | 6b8dc4d | 2012-01-19 14:28:27 -0800 | [diff] [blame] | 524 | |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 525 | if (dist_data) { |
Stephen Hemminger | c1b81cb | 2007-12-12 15:02:51 -0800 | [diff] [blame] | 526 | if (addattr_l(n, MAX_DIST * sizeof(dist_data[0]), |
| 527 | TCA_NETEM_DELAY_DIST, |
| 528 | dist_data, dist_size * sizeof(dist_data[0])) < 0) |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 529 | return -1; |
Stephen Hemminger | c1b81cb | 2007-12-12 15:02:51 -0800 | [diff] [blame] | 530 | free(dist_data); |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 531 | } |
17!tgraf | 1a1d22a | 2005-01-18 01:24:18 +0000 | [diff] [blame] | 532 | tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 533 | return 0; |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 534 | } |
| 535 | |
| 536 | static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) |
| 537 | { |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 538 | const struct tc_netem_corr *cor = NULL; |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 539 | const struct tc_netem_reorder *reorder = NULL; |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 540 | const struct tc_netem_corrupt *corrupt = NULL; |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 541 | const struct tc_netem_gimodel *gimodel = NULL; |
| 542 | const struct tc_netem_gemodel *gemodel = NULL; |
Vijay Subramanian | 1070205 | 2012-05-16 13:51:58 +0000 | [diff] [blame] | 543 | int *ecn = NULL; |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 544 | struct tc_netem_qopt qopt; |
Hagen Paul Pfeifer | 6b8dc4d | 2012-01-19 14:28:27 -0800 | [diff] [blame] | 545 | const struct tc_netem_rate *rate = NULL; |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 546 | int len = RTA_PAYLOAD(opt) - sizeof(qopt); |
Yang Yingliang | dad2f72 | 2014-01-16 11:09:14 +0800 | [diff] [blame] | 547 | __u64 rate64 = 0; |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 548 | SPRINT_BUF(b1); |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 549 | |
| 550 | if (opt == NULL) |
| 551 | return 0; |
| 552 | |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 553 | if (len < 0) { |
| 554 | fprintf(stderr, "options size error\n"); |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 555 | return -1; |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 556 | } |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 557 | memcpy(&qopt, RTA_DATA(opt), sizeof(qopt)); |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 558 | |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 559 | if (len > 0) { |
net[shemminger]!shemminger | 1d2d1cb | 2005-03-10 19:00:42 +0000 | [diff] [blame] | 560 | struct rtattr *tb[TCA_NETEM_MAX+1]; |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 561 | parse_rtattr(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(qopt), |
| 562 | len); |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 563 | |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 564 | if (tb[TCA_NETEM_CORR]) { |
| 565 | if (RTA_PAYLOAD(tb[TCA_NETEM_CORR]) < sizeof(*cor)) |
| 566 | return -1; |
| 567 | cor = RTA_DATA(tb[TCA_NETEM_CORR]); |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 568 | } |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 569 | if (tb[TCA_NETEM_REORDER]) { |
| 570 | if (RTA_PAYLOAD(tb[TCA_NETEM_REORDER]) < sizeof(*reorder)) |
| 571 | return -1; |
| 572 | reorder = RTA_DATA(tb[TCA_NETEM_REORDER]); |
| 573 | } |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 574 | if (tb[TCA_NETEM_CORRUPT]) { |
| 575 | if (RTA_PAYLOAD(tb[TCA_NETEM_CORRUPT]) < sizeof(*corrupt)) |
| 576 | return -1; |
shemminger | e9bc3c4 | 2005-12-10 00:01:02 +0000 | [diff] [blame] | 577 | corrupt = RTA_DATA(tb[TCA_NETEM_CORRUPT]); |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 578 | } |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 579 | if (tb[TCA_NETEM_LOSS]) { |
| 580 | struct rtattr *lb[NETEM_LOSS_MAX + 1]; |
| 581 | |
| 582 | parse_rtattr_nested(lb, NETEM_LOSS_MAX, tb[TCA_NETEM_LOSS]); |
| 583 | if (lb[NETEM_LOSS_GI]) |
Jay Vosburgh | 8f9672a | 2014-05-08 19:02:20 -0700 | [diff] [blame] | 584 | gimodel = RTA_DATA(lb[NETEM_LOSS_GI]); |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 585 | if (lb[NETEM_LOSS_GE]) |
| 586 | gemodel = RTA_DATA(lb[NETEM_LOSS_GE]); |
Stephen Hemminger | 3d0b743 | 2014-12-20 15:47:17 -0800 | [diff] [blame] | 587 | } |
Hagen Paul Pfeifer | 6b8dc4d | 2012-01-19 14:28:27 -0800 | [diff] [blame] | 588 | if (tb[TCA_NETEM_RATE]) { |
| 589 | if (RTA_PAYLOAD(tb[TCA_NETEM_RATE]) < sizeof(*rate)) |
| 590 | return -1; |
| 591 | rate = RTA_DATA(tb[TCA_NETEM_RATE]); |
| 592 | } |
Vijay Subramanian | 1070205 | 2012-05-16 13:51:58 +0000 | [diff] [blame] | 593 | if (tb[TCA_NETEM_ECN]) { |
| 594 | if (RTA_PAYLOAD(tb[TCA_NETEM_ECN]) < sizeof(*ecn)) |
| 595 | return -1; |
| 596 | ecn = RTA_DATA(tb[TCA_NETEM_ECN]); |
| 597 | } |
Yang Yingliang | dad2f72 | 2014-01-16 11:09:14 +0800 | [diff] [blame] | 598 | if (tb[TCA_NETEM_RATE64]) { |
| 599 | if (RTA_PAYLOAD(tb[TCA_NETEM_RATE64]) < sizeof(rate64)) |
| 600 | return -1; |
| 601 | rate64 = rta_getattr_u64(tb[TCA_NETEM_RATE64]); |
| 602 | } |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 603 | } |
| 604 | |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 605 | fprintf(f, "limit %d", qopt.limit); |
| 606 | |
| 607 | if (qopt.latency) { |
| 608 | fprintf(f, " delay %s", sprint_ticks(qopt.latency, b1)); |
| 609 | |
| 610 | if (qopt.jitter) { |
| 611 | fprintf(f, " %s", sprint_ticks(qopt.jitter, b1)); |
| 612 | if (cor && cor->delay_corr) |
| 613 | fprintf(f, " %s", sprint_percent(cor->delay_corr, b1)); |
| 614 | } |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 615 | } |
| 616 | |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 617 | if (qopt.loss) { |
| 618 | fprintf(f, " loss %s", sprint_percent(qopt.loss, b1)); |
| 619 | if (cor && cor->loss_corr) |
| 620 | fprintf(f, " %s", sprint_percent(cor->loss_corr, b1)); |
| 621 | } |
| 622 | |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 623 | if (gimodel) { |
| 624 | fprintf(f, " loss state p13 %s", sprint_percent(gimodel->p13, b1)); |
| 625 | fprintf(f, " p31 %s", sprint_percent(gimodel->p31, b1)); |
| 626 | fprintf(f, " p32 %s", sprint_percent(gimodel->p32, b1)); |
| 627 | fprintf(f, " p23 %s", sprint_percent(gimodel->p23, b1)); |
| 628 | fprintf(f, " p14 %s", sprint_percent(gimodel->p14, b1)); |
| 629 | } |
| 630 | |
| 631 | if (gemodel) { |
Jay Vosburgh | 3757185 | 2014-05-10 13:34:58 -0700 | [diff] [blame] | 632 | fprintf(f, " loss gemodel p %s", |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 633 | sprint_percent(gemodel->p, b1)); |
| 634 | fprintf(f, " r %s", sprint_percent(gemodel->r, b1)); |
Jay Vosburgh | 3757185 | 2014-05-10 13:34:58 -0700 | [diff] [blame] | 635 | fprintf(f, " 1-h %s", sprint_percent(max_percent_value - |
| 636 | gemodel->h, b1)); |
Stephen Hemminger | 3c7950a | 2011-12-22 17:08:11 -0800 | [diff] [blame] | 637 | fprintf(f, " 1-k %s", sprint_percent(gemodel->k1, b1)); |
| 638 | } |
| 639 | |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 640 | if (qopt.duplicate) { |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 641 | fprintf(f, " duplicate %s", |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 642 | sprint_percent(qopt.duplicate, b1)); |
| 643 | if (cor && cor->dup_corr) |
| 644 | fprintf(f, " %s", sprint_percent(cor->dup_corr, b1)); |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 645 | } |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 646 | |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 647 | if (reorder && reorder->probability) { |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 648 | fprintf(f, " reorder %s", |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 649 | sprint_percent(reorder->probability, b1)); |
| 650 | if (reorder->correlation) |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 651 | fprintf(f, " %s", |
shemminger | ea8fc10 | 2005-06-22 18:27:49 +0000 | [diff] [blame] | 652 | sprint_percent(reorder->correlation, b1)); |
| 653 | } |
osdl.net!shemminger | b7be3d0 | 2004-08-23 20:21:21 +0000 | [diff] [blame] | 654 | |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 655 | if (corrupt && corrupt->probability) { |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 656 | fprintf(f, " corrupt %s", |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 657 | sprint_percent(corrupt->probability, b1)); |
| 658 | if (corrupt->correlation) |
Stephen Hemminger | ae665a5 | 2006-12-05 10:10:22 -0800 | [diff] [blame] | 659 | fprintf(f, " %s", |
shemminger | a31a5d5 | 2005-12-09 23:27:44 +0000 | [diff] [blame] | 660 | sprint_percent(corrupt->correlation, b1)); |
| 661 | } |
| 662 | |
Hagen Paul Pfeifer | 6b8dc4d | 2012-01-19 14:28:27 -0800 | [diff] [blame] | 663 | if (rate && rate->rate) { |
Yang Yingliang | dad2f72 | 2014-01-16 11:09:14 +0800 | [diff] [blame] | 664 | if (rate64) |
| 665 | fprintf(f, " rate %s", sprint_rate(rate64, b1)); |
| 666 | else |
| 667 | fprintf(f, " rate %s", sprint_rate(rate->rate, b1)); |
Hagen Paul Pfeifer | 6b8dc4d | 2012-01-19 14:28:27 -0800 | [diff] [blame] | 668 | if (rate->packet_overhead) |
| 669 | fprintf(f, " packetoverhead %d", rate->packet_overhead); |
| 670 | if (rate->cell_size) |
| 671 | fprintf(f, " cellsize %u", rate->cell_size); |
| 672 | if (rate->cell_overhead) |
| 673 | fprintf(f, " celloverhead %d", rate->cell_overhead); |
| 674 | } |
| 675 | |
Vijay Subramanian | 1070205 | 2012-05-16 13:51:58 +0000 | [diff] [blame] | 676 | if (ecn) |
| 677 | fprintf(f, " ecn "); |
| 678 | |
osdl.net!shemminger | 2e21655 | 2004-08-30 20:54:46 +0000 | [diff] [blame] | 679 | if (qopt.gap) |
| 680 | fprintf(f, " gap %lu", (unsigned long)qopt.gap); |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 681 | |
Vijay Subramanian | 1070205 | 2012-05-16 13:51:58 +0000 | [diff] [blame] | 682 | |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 683 | return 0; |
| 684 | } |
| 685 | |
net[shemminger]!kaber | 95812b5 | 2004-09-28 18:35:49 +0000 | [diff] [blame] | 686 | struct qdisc_util netem_qdisc_util = { |
osdl.net!shemminger | 31fa60e | 2004-07-12 21:03:29 +0000 | [diff] [blame] | 687 | .id = "netem", |
| 688 | .parse_qopt = netem_parse_opt, |
| 689 | .print_qopt = netem_print_opt, |
osdl.net!shemminger | 309a4c9 | 2004-06-28 20:41:55 +0000 | [diff] [blame] | 690 | }; |