1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* q_hhf.c Heavy-Hitter Filter (HHF)
4 * Copyright (C) 2013 Terry Lam <vtlam@google.com>
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
18 static void explain(void)
21 "Usage: ... hhf [ limit PACKETS ] [ quantum BYTES]\n"
22 " [ hh_limit NUMBER ]\n"
23 " [ reset_timeout TIME ]\n"
24 " [ admit_bytes BYTES ]\n"
25 " [ evict_timeout TIME ]\n"
26 " [ non_hh_weight NUMBER ]\n");
29 static int hhf_parse_opt(struct qdisc_util
*qu
, int argc
, char **argv
,
30 struct nlmsghdr
*n
, const char *dev
)
32 unsigned int limit
= 0;
33 unsigned int quantum
= 0;
34 unsigned int hh_limit
= 0;
35 unsigned int reset_timeout
= 0;
36 unsigned int admit_bytes
= 0;
37 unsigned int evict_timeout
= 0;
38 unsigned int non_hh_weight
= 0;
42 if (strcmp(*argv
, "limit") == 0) {
44 if (get_unsigned(&limit
, *argv
, 0)) {
45 fprintf(stderr
, "Illegal \"limit\"\n");
48 } else if (strcmp(*argv
, "quantum") == 0) {
50 if (get_unsigned(&quantum
, *argv
, 0)) {
51 fprintf(stderr
, "Illegal \"quantum\"\n");
54 } else if (strcmp(*argv
, "hh_limit") == 0) {
56 if (get_unsigned(&hh_limit
, *argv
, 0)) {
57 fprintf(stderr
, "Illegal \"hh_limit\"\n");
60 } else if (strcmp(*argv
, "reset_timeout") == 0) {
62 if (get_time(&reset_timeout
, *argv
)) {
63 fprintf(stderr
, "Illegal \"reset_timeout\"\n");
66 } else if (strcmp(*argv
, "admit_bytes") == 0) {
68 if (get_unsigned(&admit_bytes
, *argv
, 0)) {
69 fprintf(stderr
, "Illegal \"admit_bytes\"\n");
72 } else if (strcmp(*argv
, "evict_timeout") == 0) {
74 if (get_time(&evict_timeout
, *argv
)) {
75 fprintf(stderr
, "Illegal \"evict_timeout\"\n");
78 } else if (strcmp(*argv
, "non_hh_weight") == 0) {
80 if (get_unsigned(&non_hh_weight
, *argv
, 0)) {
81 fprintf(stderr
, "Illegal \"non_hh_weight\"\n");
84 } else if (strcmp(*argv
, "help") == 0) {
88 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
95 tail
= addattr_nest(n
, 1024, TCA_OPTIONS
);
97 addattr_l(n
, 1024, TCA_HHF_BACKLOG_LIMIT
, &limit
,
100 addattr_l(n
, 1024, TCA_HHF_QUANTUM
, &quantum
, sizeof(quantum
));
102 addattr_l(n
, 1024, TCA_HHF_HH_FLOWS_LIMIT
, &hh_limit
,
105 addattr_l(n
, 1024, TCA_HHF_RESET_TIMEOUT
, &reset_timeout
,
106 sizeof(reset_timeout
));
108 addattr_l(n
, 1024, TCA_HHF_ADMIT_BYTES
, &admit_bytes
,
109 sizeof(admit_bytes
));
111 addattr_l(n
, 1024, TCA_HHF_EVICT_TIMEOUT
, &evict_timeout
,
112 sizeof(evict_timeout
));
114 addattr_l(n
, 1024, TCA_HHF_NON_HH_WEIGHT
, &non_hh_weight
,
115 sizeof(non_hh_weight
));
116 addattr_nest_end(n
, tail
);
120 static int hhf_print_opt(struct qdisc_util
*qu
, FILE *f
, struct rtattr
*opt
)
122 struct rtattr
*tb
[TCA_HHF_MAX
+ 1];
124 unsigned int quantum
;
125 unsigned int hh_limit
;
126 unsigned int reset_timeout
;
127 unsigned int admit_bytes
;
128 unsigned int evict_timeout
;
129 unsigned int non_hh_weight
;
136 parse_rtattr_nested(tb
, TCA_HHF_MAX
, opt
);
138 if (tb
[TCA_HHF_BACKLOG_LIMIT
] &&
139 RTA_PAYLOAD(tb
[TCA_HHF_BACKLOG_LIMIT
]) >= sizeof(__u32
)) {
140 limit
= rta_getattr_u32(tb
[TCA_HHF_BACKLOG_LIMIT
]);
141 print_uint(PRINT_ANY
, "limit", "limit %up ", limit
);
143 if (tb
[TCA_HHF_QUANTUM
] &&
144 RTA_PAYLOAD(tb
[TCA_HHF_QUANTUM
]) >= sizeof(__u32
)) {
145 quantum
= rta_getattr_u32(tb
[TCA_HHF_QUANTUM
]);
146 print_size(PRINT_ANY
, "quantum", "quantum %s ", quantum
);
148 if (tb
[TCA_HHF_HH_FLOWS_LIMIT
] &&
149 RTA_PAYLOAD(tb
[TCA_HHF_HH_FLOWS_LIMIT
]) >= sizeof(__u32
)) {
150 hh_limit
= rta_getattr_u32(tb
[TCA_HHF_HH_FLOWS_LIMIT
]);
151 print_uint(PRINT_ANY
, "hh_limit", "hh_limit %u ", hh_limit
);
153 if (tb
[TCA_HHF_RESET_TIMEOUT
] &&
154 RTA_PAYLOAD(tb
[TCA_HHF_RESET_TIMEOUT
]) >= sizeof(__u32
)) {
155 reset_timeout
= rta_getattr_u32(tb
[TCA_HHF_RESET_TIMEOUT
]);
156 print_uint(PRINT_JSON
, "reset_timeout", NULL
, reset_timeout
);
157 print_string(PRINT_FP
, NULL
, "reset_timeout %s ",
158 sprint_time(reset_timeout
, b1
));
160 if (tb
[TCA_HHF_ADMIT_BYTES
] &&
161 RTA_PAYLOAD(tb
[TCA_HHF_ADMIT_BYTES
]) >= sizeof(__u32
)) {
162 admit_bytes
= rta_getattr_u32(tb
[TCA_HHF_ADMIT_BYTES
]);
163 print_size(PRINT_ANY
, "admit_bytes", "admit_bytes %s ",
166 if (tb
[TCA_HHF_EVICT_TIMEOUT
] &&
167 RTA_PAYLOAD(tb
[TCA_HHF_EVICT_TIMEOUT
]) >= sizeof(__u32
)) {
168 evict_timeout
= rta_getattr_u32(tb
[TCA_HHF_EVICT_TIMEOUT
]);
169 print_uint(PRINT_JSON
, "evict_timeout", NULL
, evict_timeout
);
170 print_string(PRINT_FP
, NULL
, "evict_timeout %s ",
171 sprint_time(evict_timeout
, b1
));
173 if (tb
[TCA_HHF_NON_HH_WEIGHT
] &&
174 RTA_PAYLOAD(tb
[TCA_HHF_NON_HH_WEIGHT
]) >= sizeof(__u32
)) {
175 non_hh_weight
= rta_getattr_u32(tb
[TCA_HHF_NON_HH_WEIGHT
]);
176 print_uint(PRINT_ANY
, "non_hh_weight", "non_hh_weight %u ",
182 static int hhf_print_xstats(struct qdisc_util
*qu
, FILE *f
,
183 struct rtattr
*xstats
)
185 struct tc_hhf_xstats
*st
;
190 if (RTA_PAYLOAD(xstats
) < sizeof(*st
))
193 st
= RTA_DATA(xstats
);
195 print_uint(PRINT_ANY
, "drop_overlimit", " drop_overlimit %u",
197 print_uint(PRINT_ANY
, "hh_overlimit", " hh_overlimit %u",
199 print_uint(PRINT_ANY
, "tot_hh", " tot_hh %u", st
->hh_tot_count
);
200 print_uint(PRINT_ANY
, "cur_hh", " cur_hh %u", st
->hh_cur_count
);
205 struct qdisc_util hhf_qdisc_util
= {
207 .parse_qopt
= hhf_parse_opt
,
208 .print_qopt
= hhf_print_opt
,
209 .print_xstats
= hhf_print_xstats
,