2 * q_rsvp.c RSVP filter.
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
27 static void explain(void)
29 fprintf(stderr
, "Usage: ... rsvp ipproto PROTOCOL session DST[/PORT | GPI ]\n");
30 fprintf(stderr
, " [ sender SRC[/PORT | GPI ]\n");
31 fprintf(stderr
, " [ classid CLASSID ] [ police POLICE_SPEC ]\n");
32 fprintf(stderr
, " [ tunnelid ID ] [ tunnel ID skip NUMBER ]\n");
33 fprintf(stderr
, "Where: GPI := { flowlabel NUMBER | spi/ah SPI | spi/esp SPI |\n");
34 fprintf(stderr
, " u{8|16|32} NUMBER mask MASK at OFFSET}\n");
35 fprintf(stderr
, " POLICE_SPEC := ... look at TBF\n");
36 fprintf(stderr
, " FILTERID := X:Y\n");
37 fprintf(stderr
, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
40 int get_addr_and_pi(int *argc_p
, char ***argv_p
, inet_prefix
* addr
,
41 struct tc_rsvp_pinfo
*pinfo
, int dir
, int family
)
44 char **argv
= *argv_p
;
45 char *p
= strchr(*argv
, '/');
46 struct tc_rsvp_gpi
*pi
= dir
? &pinfo
->dpi
: &pinfo
->spi
;
51 if (get_u16(&tmp
, p
+1, 0))
55 /* Source port: u16 at offset 0 */
56 pi
->key
= htonl(((__u32
)tmp
)<<16);
57 pi
->mask
= htonl(0xFFFF0000);
59 /* Destination port: u16 at offset 2 */
60 pi
->key
= htonl(((__u32
)tmp
));
61 pi
->mask
= htonl(0x0000FFFF);
66 if (get_addr_1(addr
, *argv
, family
))
73 if (pi
->mask
|| argc
<= 0)
76 if (strcmp(*argv
, "spi/ah") == 0 ||
77 strcmp(*argv
, "gpi/ah") == 0) {
80 if (get_u32(&gpi
, *argv
, 0))
82 pi
->mask
= htonl(0xFFFFFFFF);
85 if (pinfo
->protocol
== 0)
86 pinfo
->protocol
= IPPROTO_AH
;
88 } else if (strcmp(*argv
, "spi/esp") == 0 ||
89 strcmp(*argv
, "gpi/esp") == 0) {
92 if (get_u32(&gpi
, *argv
, 0))
94 pi
->mask
= htonl(0xFFFFFFFF);
97 if (pinfo
->protocol
== 0)
98 pinfo
->protocol
= IPPROTO_ESP
;
100 } else if (strcmp(*argv
, "flowlabel") == 0) {
103 if (get_u32(&flabel
, *argv
, 0))
105 if (family
!= AF_INET6
)
107 pi
->mask
= htonl(0x000FFFFF);
108 pi
->key
= htonl(flabel
) & pi
->mask
;
111 } else if (strcmp(*argv
, "u32") == 0 ||
112 strcmp(*argv
, "u16") == 0 ||
113 strcmp(*argv
, "u8") == 0) {
117 if (strcmp(*argv
, "u32") == 0) {
120 } else if (strcmp(*argv
, "u16") == 0) {
125 if (get_u32(&tmp
, *argv
, 0))
128 if (strcmp(*argv
, "mask") == 0) {
130 if (get_u32(&mask
, *argv
, 16))
134 if (strcmp(*argv
, "at") == 0) {
136 if (get_integer(&pi
->offset
, *argv
, 0))
141 if ((pi
->offset
& 3) == 0) {
144 } else if ((pi
->offset
& 3) == 1) {
147 } else if ((pi
->offset
& 3) == 3) {
151 } else if (sz
== 2) {
152 if ((pi
->offset
& 3) == 0) {
158 pi
->mask
= htonl(mask
);
159 pi
->key
= htonl(tmp
) & pi
->mask
;
169 static int rsvp_parse_opt(struct filter_util
*qu
, char *handle
, int argc
, char **argv
, struct nlmsghdr
*n
)
171 int family
= strcmp(qu
->id
, "rsvp") == 0 ? AF_INET
: AF_INET6
;
172 struct tc_rsvp_pinfo pinfo
;
174 struct tcmsg
*t
= NLMSG_DATA(n
);
178 memset(&pinfo
, 0, sizeof(pinfo
));
179 memset(&tp
, 0, sizeof(tp
));
182 if (get_u32(&t
->tcm_handle
, handle
, 0)) {
183 fprintf(stderr
, "Illegal \"handle\"\n");
191 tail
= NLMSG_TAIL(n
);
192 addattr_l(n
, 4096, TCA_OPTIONS
, NULL
, 0);
195 if (matches(*argv
, "session") == 0) {
198 if (get_addr_and_pi(&argc
, &argv
, &addr
, &pinfo
, 1, family
)) {
199 fprintf(stderr
, "Illegal \"session\"\n");
202 addattr_l(n
, 4096, TCA_RSVP_DST
, &addr
.data
, addr
.bytelen
);
203 if (pinfo
.dpi
.mask
|| pinfo
.protocol
)
206 } else if (matches(*argv
, "sender") == 0 ||
207 matches(*argv
, "flowspec") == 0) {
210 if (get_addr_and_pi(&argc
, &argv
, &addr
, &pinfo
, 0, family
)) {
211 fprintf(stderr
, "Illegal \"sender\"\n");
214 addattr_l(n
, 4096, TCA_RSVP_SRC
, &addr
.data
, addr
.bytelen
);
215 if (pinfo
.spi
.mask
|| pinfo
.protocol
)
218 } else if (matches("ipproto", *argv
) == 0) {
221 num
= inet_proto_a2n(*argv
);
223 fprintf(stderr
, "Illegal \"ipproto\"\n");
226 pinfo
.protocol
= num
;
228 } else if (matches(*argv
, "classid") == 0 ||
229 strcmp(*argv
, "flowid") == 0) {
232 if (get_tc_classid(&handle
, *argv
)) {
233 fprintf(stderr
, "Illegal \"classid\"\n");
236 addattr_l(n
, 4096, TCA_RSVP_CLASSID
, &handle
, 4);
237 } else if (strcmp(*argv
, "tunnelid") == 0) {
240 if (get_unsigned(&tid
, *argv
, 0)) {
241 fprintf(stderr
, "Illegal \"tunnelid\"\n");
244 pinfo
.tunnelid
= tid
;
246 } else if (strcmp(*argv
, "tunnel") == 0) {
249 if (get_unsigned(&tid
, *argv
, 0)) {
250 fprintf(stderr
, "Illegal \"tunnel\"\n");
253 addattr_l(n
, 4096, TCA_RSVP_CLASSID
, &tid
, 4);
255 if (strcmp(*argv
, "skip") == 0) {
258 if (get_unsigned(&tid
, *argv
, 0)) {
259 fprintf(stderr
, "Illegal \"skip\"\n");
262 pinfo
.tunnelhdr
= tid
;
264 } else if (matches(*argv
, "police") == 0) {
266 if (parse_police(&argc
, &argv
, TCA_RSVP_POLICE
, n
)) {
267 fprintf(stderr
, "Illegal \"police\"\n");
271 } else if (strcmp(*argv
, "help") == 0) {
275 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
283 addattr_l(n
, 4096, TCA_RSVP_PINFO
, &pinfo
, sizeof(pinfo
));
284 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
288 static char * sprint_spi(struct tc_rsvp_gpi
*pi
, int dir
, char *buf
)
290 if (pi
->offset
== 0) {
291 if (dir
&& pi
->mask
== htonl(0xFFFF)) {
292 snprintf(buf
, SPRINT_BSIZE
-1, "/%d", htonl(pi
->key
));
295 if (!dir
&& pi
->mask
== htonl(0xFFFF0000)) {
296 snprintf(buf
, SPRINT_BSIZE
-1, "/%d", htonl(pi
->key
)>>16);
299 if (pi
->mask
== htonl(0xFFFFFFFF)) {
300 snprintf(buf
, SPRINT_BSIZE
-1, " spi/esp 0x%08x", htonl(pi
->key
));
303 } else if (pi
->offset
== 4 && pi
->mask
== htonl(0xFFFFFFFF)) {
304 snprintf(buf
, SPRINT_BSIZE
-1, " spi/ah 0x%08x", htonl(pi
->key
));
306 } else if (pi
->offset
== -40 && pi
->mask
== htonl(0x000FFFFF)) {
307 snprintf(buf
, SPRINT_BSIZE
-1, " flowlabel 0x%05x", htonl(pi
->key
));
310 snprintf(buf
, SPRINT_BSIZE
-1, " u32 0x%08x mask %08x at %d",
311 htonl(pi
->key
), htonl(pi
->mask
), pi
->offset
);
315 static int rsvp_print_opt(struct filter_util
*qu
, FILE *f
, struct rtattr
*opt
, __u32 handle
)
317 int family
= strcmp(qu
->id
, "rsvp") == 0 ? AF_INET
: AF_INET6
;
318 struct rtattr
*tb
[TCA_RSVP_MAX
+1];
319 struct tc_rsvp_pinfo
*pinfo
= NULL
;
324 parse_rtattr_nested(tb
, TCA_RSVP_MAX
, opt
);
327 fprintf(f
, "fh 0x%08x ", handle
);
329 if (tb
[TCA_RSVP_PINFO
]) {
330 if (RTA_PAYLOAD(tb
[TCA_RSVP_PINFO
]) < sizeof(*pinfo
))
333 pinfo
= RTA_DATA(tb
[TCA_RSVP_PINFO
]);
336 if (tb
[TCA_RSVP_CLASSID
]) {
338 if (!pinfo
|| pinfo
->tunnelhdr
== 0)
339 fprintf(f
, "flowid %s ", sprint_tc_classid(*(__u32
*)RTA_DATA(tb
[TCA_RSVP_CLASSID
]), b1
));
341 fprintf(f
, "tunnel %d skip %d ", *(__u32
*)RTA_DATA(tb
[TCA_RSVP_CLASSID
]), pinfo
->tunnelhdr
);
342 } else if (pinfo
&& pinfo
->tunnelhdr
)
343 fprintf(f
, "tunnel [BAD] skip %d ", pinfo
->tunnelhdr
);
345 if (tb
[TCA_RSVP_DST
]) {
347 fprintf(f
, "session ");
348 if (inet_ntop(family
, RTA_DATA(tb
[TCA_RSVP_DST
]), buf
, sizeof(buf
)) == 0)
349 fprintf(f
, " [INVALID DADDR] ");
351 fprintf(f
, "%s", buf
);
352 if (pinfo
&& pinfo
->dpi
.mask
) {
354 fprintf(f
, "%s ", sprint_spi(&pinfo
->dpi
, 1, b2
));
358 if (pinfo
&& pinfo
->dpi
.mask
) {
360 fprintf(f
, "session [NONE]%s ", sprint_spi(&pinfo
->dpi
, 1, b2
));
362 fprintf(f
, "session NONE ");
365 if (pinfo
&& pinfo
->protocol
) {
367 fprintf(f
, "ipproto %s ", inet_proto_n2a(pinfo
->protocol
, b1
, sizeof(b1
)));
369 if (pinfo
&& pinfo
->tunnelid
)
370 fprintf(f
, "tunnelid %d ", pinfo
->tunnelid
);
371 if (tb
[TCA_RSVP_SRC
]) {
373 fprintf(f
, "sender ");
374 if (inet_ntop(family
, RTA_DATA(tb
[TCA_RSVP_SRC
]), buf
, sizeof(buf
)) == 0) {
377 fprintf(f
, " %s", buf
);
379 if (pinfo
&& pinfo
->spi
.mask
) {
381 fprintf(f
, "%s ", sprint_spi(&pinfo
->spi
, 0, b2
));
384 } else if (pinfo
&& pinfo
->spi
.mask
) {
386 fprintf(f
, "sender [NONE]%s ", sprint_spi(&pinfo
->spi
, 0, b2
));
388 if (tb
[TCA_RSVP_POLICE
])
389 tc_print_police(f
, tb
[TCA_RSVP_POLICE
]);
393 struct filter_util rsvp_filter_util
= {
395 .parse_fopt
= rsvp_parse_opt
,
396 .print_fopt
= rsvp_print_opt
,
399 struct filter_util rsvp6_filter_util
= {
401 .parse_fopt
= rsvp_parse_opt
,
402 .print_fopt
= rsvp_print_opt
,