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");
39 #define usage() return(-1)
41 int get_addr_and_pi(int *argc_p
, char ***argv_p
, inet_prefix
* addr
,
42 struct tc_rsvp_pinfo
*pinfo
, int dir
, int family
)
45 char **argv
= *argv_p
;
46 char *p
= strchr(*argv
, '/');
47 struct tc_rsvp_gpi
*pi
= dir
? &pinfo
->dpi
: &pinfo
->spi
;
52 if (get_u16(&tmp
, p
+1, 0))
56 /* Source port: u16 at offset 0 */
57 pi
->key
= htonl(((__u32
)tmp
)<<16);
58 pi
->mask
= htonl(0xFFFF0000);
60 /* Destination port: u16 at offset 2 */
61 pi
->key
= htonl(((__u32
)tmp
));
62 pi
->mask
= htonl(0x0000FFFF);
67 if (get_addr_1(addr
, *argv
, family
))
74 if (pi
->mask
|| argc
<= 0)
77 if (strcmp(*argv
, "spi/ah") == 0 ||
78 strcmp(*argv
, "gpi/ah") == 0) {
81 if (get_u32(&gpi
, *argv
, 0))
83 pi
->mask
= htonl(0xFFFFFFFF);
86 if (pinfo
->protocol
== 0)
87 pinfo
->protocol
= IPPROTO_AH
;
89 } else if (strcmp(*argv
, "spi/esp") == 0 ||
90 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) {
104 if (get_u32(&flabel
, *argv
, 0))
106 if (family
!= AF_INET6
)
108 pi
->mask
= htonl(0x000FFFFF);
109 pi
->key
= htonl(flabel
) & pi
->mask
;
112 } else if (strcmp(*argv
, "u32") == 0 ||
113 strcmp(*argv
, "u16") == 0 ||
114 strcmp(*argv
, "u8") == 0) {
118 if (strcmp(*argv
, "u32") == 0) {
121 } else if (strcmp(*argv
, "u16") == 0) {
126 if (get_u32(&tmp
, *argv
, 0))
129 if (strcmp(*argv
, "mask") == 0) {
131 if (get_u32(&mask
, *argv
, 16))
135 if (strcmp(*argv
, "at") == 0) {
137 if (get_integer(&pi
->offset
, *argv
, 0))
142 if ((pi
->offset
& 3) == 0) {
145 } else if ((pi
->offset
& 3) == 1) {
148 } else if ((pi
->offset
& 3) == 3) {
152 } else if (sz
== 2) {
153 if ((pi
->offset
& 3) == 0) {
159 pi
->mask
= htonl(mask
);
160 pi
->key
= htonl(tmp
) & pi
->mask
;
170 static int rsvp_parse_opt(struct filter_util
*qu
, char *handle
, int argc
, char **argv
, struct nlmsghdr
*n
)
172 int family
= strcmp(qu
->id
, "rsvp") == 0 ? AF_INET
: AF_INET6
;
173 struct tc_rsvp_pinfo pinfo
;
175 struct tcmsg
*t
= NLMSG_DATA(n
);
179 memset(&pinfo
, 0, sizeof(pinfo
));
180 memset(&tp
, 0, sizeof(tp
));
183 if (get_u32(&t
->tcm_handle
, handle
, 0)) {
184 fprintf(stderr
, "Illegal \"handle\"\n");
192 tail
= NLMSG_TAIL(n
);
193 addattr_l(n
, 4096, TCA_OPTIONS
, NULL
, 0);
196 if (matches(*argv
, "session") == 0) {
199 if (get_addr_and_pi(&argc
, &argv
, &addr
, &pinfo
, 1, family
)) {
200 fprintf(stderr
, "Illegal \"session\"\n");
203 addattr_l(n
, 4096, TCA_RSVP_DST
, &addr
.data
, addr
.bytelen
);
204 if (pinfo
.dpi
.mask
|| pinfo
.protocol
)
207 } else if (matches(*argv
, "sender") == 0 ||
208 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) {
222 num
= inet_proto_a2n(*argv
);
224 fprintf(stderr
, "Illegal \"ipproto\"\n");
227 pinfo
.protocol
= num
;
229 } else if (matches(*argv
, "classid") == 0 ||
230 strcmp(*argv
, "flowid") == 0) {
233 if (get_tc_classid(&handle
, *argv
)) {
234 fprintf(stderr
, "Illegal \"classid\"\n");
237 addattr_l(n
, 4096, TCA_RSVP_CLASSID
, &handle
, 4);
238 } else if (strcmp(*argv
, "tunnelid") == 0) {
241 if (get_unsigned(&tid
, *argv
, 0)) {
242 fprintf(stderr
, "Illegal \"tunnelid\"\n");
245 pinfo
.tunnelid
= tid
;
247 } else if (strcmp(*argv
, "tunnel") == 0) {
250 if (get_unsigned(&tid
, *argv
, 0)) {
251 fprintf(stderr
, "Illegal \"tunnel\"\n");
254 addattr_l(n
, 4096, TCA_RSVP_CLASSID
, &tid
, 4);
256 if (strcmp(*argv
, "skip") == 0) {
259 if (get_unsigned(&tid
, *argv
, 0)) {
260 fprintf(stderr
, "Illegal \"skip\"\n");
263 pinfo
.tunnelhdr
= tid
;
265 } else if (matches(*argv
, "police") == 0) {
267 if (parse_police(&argc
, &argv
, TCA_RSVP_POLICE
, n
)) {
268 fprintf(stderr
, "Illegal \"police\"\n");
272 } else if (strcmp(*argv
, "help") == 0) {
276 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
284 addattr_l(n
, 4096, TCA_RSVP_PINFO
, &pinfo
, sizeof(pinfo
));
285 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
289 static char * sprint_spi(struct tc_rsvp_gpi
*pi
, int dir
, char *buf
)
291 if (pi
->offset
== 0) {
292 if (dir
&& pi
->mask
== htonl(0xFFFF)) {
293 snprintf(buf
, SPRINT_BSIZE
-1, "/%d", htonl(pi
->key
));
296 if (!dir
&& pi
->mask
== htonl(0xFFFF0000)) {
297 snprintf(buf
, SPRINT_BSIZE
-1, "/%d", htonl(pi
->key
)>>16);
300 if (pi
->mask
== htonl(0xFFFFFFFF)) {
301 snprintf(buf
, SPRINT_BSIZE
-1, " spi/esp 0x%08x", htonl(pi
->key
));
304 } else if (pi
->offset
== 4 && pi
->mask
== htonl(0xFFFFFFFF)) {
305 snprintf(buf
, SPRINT_BSIZE
-1, " spi/ah 0x%08x", htonl(pi
->key
));
307 } else if (pi
->offset
== -40 && pi
->mask
== htonl(0x000FFFFF)) {
308 snprintf(buf
, SPRINT_BSIZE
-1, " flowlabel 0x%05x", htonl(pi
->key
));
311 snprintf(buf
, SPRINT_BSIZE
-1, " u32 0x%08x mask %08x at %d",
312 htonl(pi
->key
), htonl(pi
->mask
), pi
->offset
);
316 static int rsvp_print_opt(struct filter_util
*qu
, FILE *f
, struct rtattr
*opt
, __u32 handle
)
318 int family
= strcmp(qu
->id
, "rsvp") == 0 ? AF_INET
: AF_INET6
;
319 struct rtattr
*tb
[TCA_RSVP_MAX
+1];
320 struct tc_rsvp_pinfo
*pinfo
= NULL
;
325 parse_rtattr_nested(tb
, TCA_RSVP_MAX
, opt
);
328 fprintf(f
, "fh 0x%08x ", handle
);
330 if (tb
[TCA_RSVP_PINFO
]) {
331 if (RTA_PAYLOAD(tb
[TCA_RSVP_PINFO
]) < sizeof(*pinfo
))
334 pinfo
= RTA_DATA(tb
[TCA_RSVP_PINFO
]);
337 if (tb
[TCA_RSVP_CLASSID
]) {
339 if (!pinfo
|| pinfo
->tunnelhdr
== 0)
340 fprintf(f
, "flowid %s ", sprint_tc_classid(*(__u32
*)RTA_DATA(tb
[TCA_RSVP_CLASSID
]), b1
));
342 fprintf(f
, "tunnel %d skip %d ", *(__u32
*)RTA_DATA(tb
[TCA_RSVP_CLASSID
]), pinfo
->tunnelhdr
);
343 } else if (pinfo
&& pinfo
->tunnelhdr
)
344 fprintf(f
, "tunnel [BAD] skip %d ", pinfo
->tunnelhdr
);
346 if (tb
[TCA_RSVP_DST
]) {
348 fprintf(f
, "session ");
349 if (inet_ntop(family
, RTA_DATA(tb
[TCA_RSVP_DST
]), buf
, sizeof(buf
)) == 0)
350 fprintf(f
, " [INVALID DADDR] ");
352 fprintf(f
, "%s", buf
);
353 if (pinfo
&& pinfo
->dpi
.mask
) {
355 fprintf(f
, "%s ", sprint_spi(&pinfo
->dpi
, 1, b2
));
359 if (pinfo
&& pinfo
->dpi
.mask
) {
361 fprintf(f
, "session [NONE]%s ", sprint_spi(&pinfo
->dpi
, 1, b2
));
363 fprintf(f
, "session NONE ");
366 if (pinfo
&& pinfo
->protocol
) {
368 fprintf(f
, "ipproto %s ", inet_proto_n2a(pinfo
->protocol
, b1
, sizeof(b1
)));
370 if (pinfo
&& pinfo
->tunnelid
)
371 fprintf(f
, "tunnelid %d ", pinfo
->tunnelid
);
372 if (tb
[TCA_RSVP_SRC
]) {
374 fprintf(f
, "sender ");
375 if (inet_ntop(family
, RTA_DATA(tb
[TCA_RSVP_SRC
]), buf
, sizeof(buf
)) == 0) {
378 fprintf(f
, " %s", buf
);
380 if (pinfo
&& pinfo
->spi
.mask
) {
382 fprintf(f
, "%s ", sprint_spi(&pinfo
->spi
, 0, b2
));
385 } else if (pinfo
&& pinfo
->spi
.mask
) {
387 fprintf(f
, "sender [NONE]%s ", sprint_spi(&pinfo
->spi
, 0, b2
));
389 if (tb
[TCA_RSVP_POLICE
])
390 tc_print_police(f
, tb
[TCA_RSVP_POLICE
]);
394 struct filter_util rsvp_filter_util
= {
396 .parse_fopt
= rsvp_parse_opt
,
397 .print_fopt
= rsvp_print_opt
,
400 struct filter_util rsvp6_filter_util
= {
402 .parse_fopt
= rsvp_parse_opt
,
403 .print_fopt
= rsvp_print_opt
,