]> git.proxmox.com Git - mirror_iproute2.git/blob - tc/q_netem.c
Fix errors in netem scheduler when using PSCHED_CLOCK_CPU,
[mirror_iproute2.git] / tc / q_netem.c
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
23 #include "utils.h"
24 #include "tc_util.h"
25
26 static void explain(void)
27 {
28 fprintf(stderr,
29 "Usage: ... netem latency TIME [ jitter TIME ] [ limit PACKETS] \n" \
30 " [ loss PERCENT ] [ duplicate PERCENT ]\n" \
31 " [ gap PACKETS]\n");
32 }
33
34 static void explain1(const char *arg)
35 {
36 fprintf(stderr, "Illegal \"%s\"\n", arg);
37 }
38
39 #define usage() return(-1)
40
41 static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
42 struct nlmsghdr *n)
43 {
44 struct tc_netem_qopt opt;
45 unsigned latency = 0;
46 int ok = 0;
47
48 memset(&opt, 0, sizeof(opt));
49 opt.limit = 1000;
50
51 while (argc > 0) {
52 if (matches(*argv, "limit") == 0) {
53 NEXT_ARG();
54 if (get_size(&opt.limit, *argv)) {
55 explain1("limit");
56 return -1;
57 }
58 ok++;
59 } else if (matches(*argv, "latency") == 0) {
60 NEXT_ARG();
61 if (get_usecs(&latency, *argv)) {
62 explain1("latency");
63 return -1;
64 }
65 ok++;
66 } else if (matches(*argv, "loss") == 0) {
67 NEXT_ARG();
68 if (get_percent(&opt.loss, *argv)) {
69 explain1("loss");
70 return -1;
71 }
72 ok++;
73 } else if (matches(*argv, "gap") == 0) {
74 NEXT_ARG();
75 if (get_u32(&opt.gap, *argv, 0)) {
76 explain1("gap");
77 return -1;
78 }
79 ok++;
80 } else if (matches(*argv, "duplicate") == 0) {
81 NEXT_ARG();
82 if (get_percent(&opt.duplicate, *argv)) {
83 explain1("duplicate");
84 return -1;
85 }
86 ok++;
87 } else if (matches(*argv, "jitter") == 0) {
88 NEXT_ARG();
89 if (get_usecs(&opt.jitter, *argv)) {
90 explain1("jitter");
91 return -1;
92 }
93 ok++;
94 } else if (strcmp(*argv, "help") == 0) {
95 explain();
96 return -1;
97 } else {
98 fprintf(stderr, "What is \"%s\"?\n", *argv);
99 explain();
100 return -1;
101 }
102 argc--; argv++;
103 }
104
105 opt.latency = tc_core_usec2tick(latency);
106
107 return ok ? addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)) : 0;
108 }
109
110 static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
111 {
112 struct tc_netem_qopt *qopt;
113 SPRINT_BUF(b1);
114
115 if (opt == NULL)
116 return 0;
117
118 if (RTA_PAYLOAD(opt) < sizeof(*qopt))
119 return -1;
120
121 qopt = RTA_DATA(opt);
122
123 fprintf(f, "limit %d", qopt->limit);
124 if (qopt->latency)
125 fprintf(f, " latency %s",
126 sprint_usecs(tc_core_tick2usec(qopt->latency), b1));
127 if (qopt->jitter)
128 fprintf(f, " jitter %s", sprint_usecs(qopt->jitter, b1));
129
130 if (qopt->loss)
131 fprintf(f, " loss %s",
132 sprint_percent(qopt->loss, b1));
133 if (qopt->gap)
134 fprintf(f, " gap %lu", (unsigned long)qopt->gap);
135
136
137 return 0;
138 }
139
140 static int netem_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats)
141 {
142 return 0;
143 }
144
145 struct qdisc_util netem_util = {
146 .id = "netem",
147 .parse_qopt = netem_parse_opt,
148 .print_qopt = netem_print_opt,
149 .print_xstats = netem_print_xstats,
150 };