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