]>
Commit | Line | Data |
---|---|---|
1 | /* SPDX-License-Identifier: GPL-2.0 */ | |
2 | /* q_hhf.c Heavy-Hitter Filter (HHF) | |
3 | * | |
4 | * Copyright (C) 2013 Terry Lam <vtlam@google.com> | |
5 | */ | |
6 | #include <stdio.h> | |
7 | #include <stdlib.h> | |
8 | #include <unistd.h> | |
9 | #include <fcntl.h> | |
10 | #include <sys/socket.h> | |
11 | #include <netinet/in.h> | |
12 | #include <arpa/inet.h> | |
13 | #include <string.h> | |
14 | ||
15 | #include "utils.h" | |
16 | #include "tc_util.h" | |
17 | ||
18 | static void explain(void) | |
19 | { | |
20 | fprintf(stderr, "Usage: ... hhf [ limit PACKETS ] [ quantum BYTES]\n"); | |
21 | fprintf(stderr, " [ hh_limit NUMBER ]\n"); | |
22 | fprintf(stderr, " [ reset_timeout TIME ]\n"); | |
23 | fprintf(stderr, " [ admit_bytes BYTES ]\n"); | |
24 | fprintf(stderr, " [ evict_timeout TIME ]\n"); | |
25 | fprintf(stderr, " [ non_hh_weight NUMBER ]\n"); | |
26 | } | |
27 | ||
28 | static int hhf_parse_opt(struct qdisc_util *qu, int argc, char **argv, | |
29 | struct nlmsghdr *n, const char *dev) | |
30 | { | |
31 | unsigned int limit = 0; | |
32 | unsigned int quantum = 0; | |
33 | unsigned int hh_limit = 0; | |
34 | unsigned int reset_timeout = 0; | |
35 | unsigned int admit_bytes = 0; | |
36 | unsigned int evict_timeout = 0; | |
37 | unsigned int non_hh_weight = 0; | |
38 | struct rtattr *tail; | |
39 | ||
40 | while (argc > 0) { | |
41 | if (strcmp(*argv, "limit") == 0) { | |
42 | NEXT_ARG(); | |
43 | if (get_unsigned(&limit, *argv, 0)) { | |
44 | fprintf(stderr, "Illegal \"limit\"\n"); | |
45 | return -1; | |
46 | } | |
47 | } else if (strcmp(*argv, "quantum") == 0) { | |
48 | NEXT_ARG(); | |
49 | if (get_unsigned(&quantum, *argv, 0)) { | |
50 | fprintf(stderr, "Illegal \"quantum\"\n"); | |
51 | return -1; | |
52 | } | |
53 | } else if (strcmp(*argv, "hh_limit") == 0) { | |
54 | NEXT_ARG(); | |
55 | if (get_unsigned(&hh_limit, *argv, 0)) { | |
56 | fprintf(stderr, "Illegal \"hh_limit\"\n"); | |
57 | return -1; | |
58 | } | |
59 | } else if (strcmp(*argv, "reset_timeout") == 0) { | |
60 | NEXT_ARG(); | |
61 | if (get_time(&reset_timeout, *argv)) { | |
62 | fprintf(stderr, "Illegal \"reset_timeout\"\n"); | |
63 | return -1; | |
64 | } | |
65 | } else if (strcmp(*argv, "admit_bytes") == 0) { | |
66 | NEXT_ARG(); | |
67 | if (get_unsigned(&admit_bytes, *argv, 0)) { | |
68 | fprintf(stderr, "Illegal \"admit_bytes\"\n"); | |
69 | return -1; | |
70 | } | |
71 | } else if (strcmp(*argv, "evict_timeout") == 0) { | |
72 | NEXT_ARG(); | |
73 | if (get_time(&evict_timeout, *argv)) { | |
74 | fprintf(stderr, "Illegal \"evict_timeout\"\n"); | |
75 | return -1; | |
76 | } | |
77 | } else if (strcmp(*argv, "non_hh_weight") == 0) { | |
78 | NEXT_ARG(); | |
79 | if (get_unsigned(&non_hh_weight, *argv, 0)) { | |
80 | fprintf(stderr, "Illegal \"non_hh_weight\"\n"); | |
81 | return -1; | |
82 | } | |
83 | } else if (strcmp(*argv, "help") == 0) { | |
84 | explain(); | |
85 | return -1; | |
86 | } else { | |
87 | fprintf(stderr, "What is \"%s\"?\n", *argv); | |
88 | explain(); | |
89 | return -1; | |
90 | } | |
91 | argc--; argv++; | |
92 | } | |
93 | ||
94 | tail = addattr_nest(n, 1024, TCA_OPTIONS); | |
95 | if (limit) | |
96 | addattr_l(n, 1024, TCA_HHF_BACKLOG_LIMIT, &limit, | |
97 | sizeof(limit)); | |
98 | if (quantum) | |
99 | addattr_l(n, 1024, TCA_HHF_QUANTUM, &quantum, sizeof(quantum)); | |
100 | if (hh_limit) | |
101 | addattr_l(n, 1024, TCA_HHF_HH_FLOWS_LIMIT, &hh_limit, | |
102 | sizeof(hh_limit)); | |
103 | if (reset_timeout) | |
104 | addattr_l(n, 1024, TCA_HHF_RESET_TIMEOUT, &reset_timeout, | |
105 | sizeof(reset_timeout)); | |
106 | if (admit_bytes) | |
107 | addattr_l(n, 1024, TCA_HHF_ADMIT_BYTES, &admit_bytes, | |
108 | sizeof(admit_bytes)); | |
109 | if (evict_timeout) | |
110 | addattr_l(n, 1024, TCA_HHF_EVICT_TIMEOUT, &evict_timeout, | |
111 | sizeof(evict_timeout)); | |
112 | if (non_hh_weight) | |
113 | addattr_l(n, 1024, TCA_HHF_NON_HH_WEIGHT, &non_hh_weight, | |
114 | sizeof(non_hh_weight)); | |
115 | addattr_nest_end(n, tail); | |
116 | return 0; | |
117 | } | |
118 | ||
119 | static int hhf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) | |
120 | { | |
121 | struct rtattr *tb[TCA_HHF_MAX + 1]; | |
122 | unsigned int limit; | |
123 | unsigned int quantum; | |
124 | unsigned int hh_limit; | |
125 | unsigned int reset_timeout; | |
126 | unsigned int admit_bytes; | |
127 | unsigned int evict_timeout; | |
128 | unsigned int non_hh_weight; | |
129 | ||
130 | SPRINT_BUF(b1); | |
131 | ||
132 | if (opt == NULL) | |
133 | return 0; | |
134 | ||
135 | parse_rtattr_nested(tb, TCA_HHF_MAX, opt); | |
136 | ||
137 | if (tb[TCA_HHF_BACKLOG_LIMIT] && | |
138 | RTA_PAYLOAD(tb[TCA_HHF_BACKLOG_LIMIT]) >= sizeof(__u32)) { | |
139 | limit = rta_getattr_u32(tb[TCA_HHF_BACKLOG_LIMIT]); | |
140 | fprintf(f, "limit %up ", limit); | |
141 | } | |
142 | if (tb[TCA_HHF_QUANTUM] && | |
143 | RTA_PAYLOAD(tb[TCA_HHF_QUANTUM]) >= sizeof(__u32)) { | |
144 | quantum = rta_getattr_u32(tb[TCA_HHF_QUANTUM]); | |
145 | fprintf(f, "quantum %u ", quantum); | |
146 | } | |
147 | if (tb[TCA_HHF_HH_FLOWS_LIMIT] && | |
148 | RTA_PAYLOAD(tb[TCA_HHF_HH_FLOWS_LIMIT]) >= sizeof(__u32)) { | |
149 | hh_limit = rta_getattr_u32(tb[TCA_HHF_HH_FLOWS_LIMIT]); | |
150 | fprintf(f, "hh_limit %u ", hh_limit); | |
151 | } | |
152 | if (tb[TCA_HHF_RESET_TIMEOUT] && | |
153 | RTA_PAYLOAD(tb[TCA_HHF_RESET_TIMEOUT]) >= sizeof(__u32)) { | |
154 | reset_timeout = rta_getattr_u32(tb[TCA_HHF_RESET_TIMEOUT]); | |
155 | fprintf(f, "reset_timeout %s ", sprint_time(reset_timeout, b1)); | |
156 | } | |
157 | if (tb[TCA_HHF_ADMIT_BYTES] && | |
158 | RTA_PAYLOAD(tb[TCA_HHF_ADMIT_BYTES]) >= sizeof(__u32)) { | |
159 | admit_bytes = rta_getattr_u32(tb[TCA_HHF_ADMIT_BYTES]); | |
160 | fprintf(f, "admit_bytes %u ", admit_bytes); | |
161 | } | |
162 | if (tb[TCA_HHF_EVICT_TIMEOUT] && | |
163 | RTA_PAYLOAD(tb[TCA_HHF_EVICT_TIMEOUT]) >= sizeof(__u32)) { | |
164 | evict_timeout = rta_getattr_u32(tb[TCA_HHF_EVICT_TIMEOUT]); | |
165 | fprintf(f, "evict_timeout %s ", sprint_time(evict_timeout, b1)); | |
166 | } | |
167 | if (tb[TCA_HHF_NON_HH_WEIGHT] && | |
168 | RTA_PAYLOAD(tb[TCA_HHF_NON_HH_WEIGHT]) >= sizeof(__u32)) { | |
169 | non_hh_weight = rta_getattr_u32(tb[TCA_HHF_NON_HH_WEIGHT]); | |
170 | fprintf(f, "non_hh_weight %u ", non_hh_weight); | |
171 | } | |
172 | return 0; | |
173 | } | |
174 | ||
175 | static int hhf_print_xstats(struct qdisc_util *qu, FILE *f, | |
176 | struct rtattr *xstats) | |
177 | { | |
178 | struct tc_hhf_xstats *st; | |
179 | ||
180 | if (xstats == NULL) | |
181 | return 0; | |
182 | ||
183 | if (RTA_PAYLOAD(xstats) < sizeof(*st)) | |
184 | return -1; | |
185 | ||
186 | st = RTA_DATA(xstats); | |
187 | ||
188 | fprintf(f, " drop_overlimit %u hh_overlimit %u tot_hh %u cur_hh %u", | |
189 | st->drop_overlimit, st->hh_overlimit, | |
190 | st->hh_tot_count, st->hh_cur_count); | |
191 | return 0; | |
192 | } | |
193 | ||
194 | struct qdisc_util hhf_qdisc_util = { | |
195 | .id = "hhf", | |
196 | .parse_qopt = hhf_parse_opt, | |
197 | .print_qopt = hhf_print_opt, | |
198 | .print_xstats = hhf_print_xstats, | |
199 | }; |