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>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
26 static void explain(void)
28 fprintf(stderr
, "Usage: ... rsvp ipproto PROTOCOL session DST[/PORT | GPI ]\n");
29 fprintf(stderr
, " [ sender SRC[/PORT | GPI ] ]\n");
30 fprintf(stderr
, " [ classid CLASSID ] [ action ACTION_SPEC ]\n");
31 fprintf(stderr
, " [ tunnelid ID ] [ tunnel ID skip NUMBER ]\n");
32 fprintf(stderr
, "Where: GPI := { flowlabel NUMBER | spi/ah SPI | spi/esp SPI |\n");
33 fprintf(stderr
, " u{8|16|32} NUMBER mask MASK at OFFSET}\n");
34 fprintf(stderr
, " ACTION_SPEC := ... look at individual actions\n");
35 fprintf(stderr
, " FILTERID := X:Y\n");
36 fprintf(stderr
, "\nNOTE: CLASSID is parsed as hexadecimal input.\n");
39 static int get_addr_and_pi(int *argc_p
, char ***argv_p
, inet_prefix
*addr
,
40 struct tc_rsvp_pinfo
*pinfo
, int dir
, int family
)
43 char **argv
= *argv_p
;
44 char *p
= strchr(*argv
, '/');
45 struct tc_rsvp_gpi
*pi
= dir
? &pinfo
->dpi
: &pinfo
->spi
;
50 if (get_u16(&tmp
, p
+1, 0))
54 /* Source port: u16 at offset 0 */
55 pi
->key
= htonl(((__u32
)tmp
)<<16);
56 pi
->mask
= htonl(0xFFFF0000);
58 /* Destination port: u16 at offset 2 */
59 pi
->key
= htonl(((__u32
)tmp
));
60 pi
->mask
= htonl(0x0000FFFF);
65 if (get_addr_1(addr
, *argv
, family
))
72 if (pi
->mask
|| argc
<= 0)
75 if (strcmp(*argv
, "spi/ah") == 0 ||
76 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) {
93 if (get_u32(&gpi
, *argv
, 0))
95 pi
->mask
= htonl(0xFFFFFFFF);
98 if (pinfo
->protocol
== 0)
99 pinfo
->protocol
= IPPROTO_ESP
;
101 } else if (strcmp(*argv
, "flowlabel") == 0) {
105 if (get_u32(&flabel
, *argv
, 0))
107 if (family
!= AF_INET6
)
109 pi
->mask
= htonl(0x000FFFFF);
110 pi
->key
= htonl(flabel
) & pi
->mask
;
113 } else if (strcmp(*argv
, "u32") == 0 ||
114 strcmp(*argv
, "u16") == 0 ||
115 strcmp(*argv
, "u8") == 0) {
120 if (strcmp(*argv
, "u32") == 0) {
123 } else if (strcmp(*argv
, "u16") == 0) {
128 if (get_u32(&tmp
, *argv
, 0))
131 if (strcmp(*argv
, "mask") == 0) {
133 if (get_u32(&mask
, *argv
, 16))
137 if (strcmp(*argv
, "at") == 0) {
139 if (get_integer(&pi
->offset
, *argv
, 0))
144 if ((pi
->offset
& 3) == 0) {
147 } else if ((pi
->offset
& 3) == 1) {
150 } else if ((pi
->offset
& 3) == 3) {
154 } else if (sz
== 2) {
155 if ((pi
->offset
& 3) == 0) {
161 pi
->mask
= htonl(mask
);
162 pi
->key
= htonl(tmp
) & pi
->mask
;
172 static int rsvp_parse_opt(struct filter_util
*qu
, char *handle
, int argc
,
173 char **argv
, struct nlmsghdr
*n
)
175 int family
= strcmp(qu
->id
, "rsvp") == 0 ? AF_INET
: AF_INET6
;
176 struct tc_rsvp_pinfo pinfo
= {};
177 struct tcmsg
*t
= NLMSG_DATA(n
);
182 if (get_u32(&t
->tcm_handle
, handle
, 0)) {
183 fprintf(stderr
, "Illegal \"handle\"\n");
191 tail
= addattr_nest(n
, 4096, TCA_OPTIONS
);
194 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) {
211 if (get_addr_and_pi(&argc
, &argv
, &addr
, &pinfo
, 0, family
)) {
212 fprintf(stderr
, "Illegal \"sender\"\n");
215 addattr_l(n
, 4096, TCA_RSVP_SRC
, &addr
.data
, addr
.bytelen
);
216 if (pinfo
.spi
.mask
|| pinfo
.protocol
)
219 } else if (matches("ipproto", *argv
) == 0) {
223 num
= inet_proto_a2n(*argv
);
225 fprintf(stderr
, "Illegal \"ipproto\"\n");
228 pinfo
.protocol
= num
;
230 } else if (matches(*argv
, "classid") == 0 ||
231 strcmp(*argv
, "flowid") == 0) {
235 if (get_tc_classid(&handle
, *argv
)) {
236 fprintf(stderr
, "Illegal \"classid\"\n");
239 addattr_l(n
, 4096, TCA_RSVP_CLASSID
, &handle
, 4);
240 } else if (strcmp(*argv
, "tunnelid") == 0) {
244 if (get_unsigned(&tid
, *argv
, 0)) {
245 fprintf(stderr
, "Illegal \"tunnelid\"\n");
248 pinfo
.tunnelid
= tid
;
250 } else if (strcmp(*argv
, "tunnel") == 0) {
254 if (get_unsigned(&tid
, *argv
, 0)) {
255 fprintf(stderr
, "Illegal \"tunnel\"\n");
258 addattr_l(n
, 4096, TCA_RSVP_CLASSID
, &tid
, 4);
260 if (strcmp(*argv
, "skip") == 0) {
263 if (get_unsigned(&tid
, *argv
, 0)) {
264 fprintf(stderr
, "Illegal \"skip\"\n");
267 pinfo
.tunnelhdr
= tid
;
269 } else if (matches(*argv
, "action") == 0) {
271 if (parse_action(&argc
, &argv
, TCA_RSVP_ACT
, n
)) {
272 fprintf(stderr
, "Illegal \"action\"\n");
276 } else if (matches(*argv
, "police") == 0) {
278 if (parse_police(&argc
, &argv
, TCA_RSVP_POLICE
, n
)) {
279 fprintf(stderr
, "Illegal \"police\"\n");
283 } else if (strcmp(*argv
, "help") == 0) {
287 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
295 addattr_l(n
, 4096, TCA_RSVP_PINFO
, &pinfo
, sizeof(pinfo
));
296 addattr_nest_end(n
, tail
);
300 static char *sprint_spi(struct tc_rsvp_gpi
*pi
, int dir
, char *buf
)
302 if (pi
->offset
== 0) {
303 if (dir
&& pi
->mask
== htonl(0xFFFF)) {
304 snprintf(buf
, SPRINT_BSIZE
-1, "/%d", htonl(pi
->key
));
307 if (!dir
&& pi
->mask
== htonl(0xFFFF0000)) {
308 snprintf(buf
, SPRINT_BSIZE
-1, "/%d", htonl(pi
->key
)>>16);
311 if (pi
->mask
== htonl(0xFFFFFFFF)) {
312 snprintf(buf
, SPRINT_BSIZE
-1, " spi/esp 0x%08x", htonl(pi
->key
));
315 } else if (pi
->offset
== 4 && pi
->mask
== htonl(0xFFFFFFFF)) {
316 snprintf(buf
, SPRINT_BSIZE
-1, " spi/ah 0x%08x", htonl(pi
->key
));
318 } else if (pi
->offset
== -40 && pi
->mask
== htonl(0x000FFFFF)) {
319 snprintf(buf
, SPRINT_BSIZE
-1, " flowlabel 0x%05x", htonl(pi
->key
));
322 snprintf(buf
, SPRINT_BSIZE
-1, " u32 0x%08x mask %08x at %d",
323 htonl(pi
->key
), htonl(pi
->mask
), pi
->offset
);
327 static int rsvp_print_opt(struct filter_util
*qu
, FILE *f
, struct rtattr
*opt
, __u32 handle
)
329 int family
= strcmp(qu
->id
, "rsvp") == 0 ? AF_INET
: AF_INET6
;
330 struct rtattr
*tb
[TCA_RSVP_MAX
+1];
331 struct tc_rsvp_pinfo
*pinfo
= NULL
;
336 parse_rtattr_nested(tb
, TCA_RSVP_MAX
, opt
);
339 fprintf(f
, "fh 0x%08x ", handle
);
341 if (tb
[TCA_RSVP_PINFO
]) {
342 if (RTA_PAYLOAD(tb
[TCA_RSVP_PINFO
]) < sizeof(*pinfo
))
345 pinfo
= RTA_DATA(tb
[TCA_RSVP_PINFO
]);
348 if (tb
[TCA_RSVP_CLASSID
]) {
350 if (!pinfo
|| pinfo
->tunnelhdr
== 0)
351 fprintf(f
, "flowid %s ", sprint_tc_classid(rta_getattr_u32(tb
[TCA_RSVP_CLASSID
]), b1
));
353 fprintf(f
, "tunnel %d skip %d ", rta_getattr_u32(tb
[TCA_RSVP_CLASSID
]), pinfo
->tunnelhdr
);
354 } else if (pinfo
&& pinfo
->tunnelhdr
)
355 fprintf(f
, "tunnel [BAD] skip %d ", pinfo
->tunnelhdr
);
357 if (tb
[TCA_RSVP_DST
]) {
360 fprintf(f
, "session ");
361 if (inet_ntop(family
, RTA_DATA(tb
[TCA_RSVP_DST
]), buf
, sizeof(buf
)) == 0)
362 fprintf(f
, " [INVALID DADDR] ");
364 fprintf(f
, "%s", buf
);
365 if (pinfo
&& pinfo
->dpi
.mask
) {
367 fprintf(f
, "%s ", sprint_spi(&pinfo
->dpi
, 1, b2
));
371 if (pinfo
&& pinfo
->dpi
.mask
) {
373 fprintf(f
, "session [NONE]%s ", sprint_spi(&pinfo
->dpi
, 1, b2
));
375 fprintf(f
, "session NONE ");
378 if (pinfo
&& pinfo
->protocol
) {
380 fprintf(f
, "ipproto %s ", inet_proto_n2a(pinfo
->protocol
, b1
, sizeof(b1
)));
382 if (pinfo
&& pinfo
->tunnelid
)
383 fprintf(f
, "tunnelid %d ", pinfo
->tunnelid
);
384 if (tb
[TCA_RSVP_SRC
]) {
387 fprintf(f
, "sender ");
388 if (inet_ntop(family
, RTA_DATA(tb
[TCA_RSVP_SRC
]), buf
, sizeof(buf
)) == 0) {
391 fprintf(f
, " %s", buf
);
393 if (pinfo
&& pinfo
->spi
.mask
) {
395 fprintf(f
, "%s ", sprint_spi(&pinfo
->spi
, 0, b2
));
398 } else if (pinfo
&& pinfo
->spi
.mask
) {
400 fprintf(f
, "sender [NONE]%s ", sprint_spi(&pinfo
->spi
, 0, b2
));
403 if (tb
[TCA_RSVP_ACT
]) {
404 tc_print_action(f
, tb
[TCA_RSVP_ACT
], 0);
406 if (tb
[TCA_RSVP_POLICE
])
407 tc_print_police(f
, tb
[TCA_RSVP_POLICE
]);
411 struct filter_util rsvp_filter_util
= {
413 .parse_fopt
= rsvp_parse_opt
,
414 .print_fopt
= rsvp_print_opt
,
417 struct filter_util rsvp6_filter_util
= {
419 .parse_fopt
= rsvp_parse_opt
,
420 .print_fopt
= rsvp_print_opt
,