]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - tc/f_rsvp.c
808310df3159c3a53cee58d0224401faabe8b7b4
[lisovros/iproute2_canprio.git] / tc / f_rsvp.c
1 /*
2  * q_rsvp.c             RSVP filter.
3  *
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.
8  *
9  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10  *
11  */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <syslog.h>
17 #include <fcntl.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <string.h>
22
23 #include "rt_names.h"
24 #include "utils.h"
25 #include "tc_util.h"
26
27 static void explain(void)
28 {
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");
38 }
39
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)
42 {
43         int argc = *argc_p;
44         char **argv = *argv_p;
45         char *p = strchr(*argv, '/');
46         struct tc_rsvp_gpi *pi = dir ? &pinfo->dpi : &pinfo->spi;
47
48         if (p) {
49                 __u16 tmp;
50
51                 if (get_u16(&tmp, p+1, 0))
52                         return -1;
53
54                 if (dir == 0) {
55                         /* Source port: u16 at offset 0 */
56                         pi->key = htonl(((__u32)tmp)<<16);
57                         pi->mask = htonl(0xFFFF0000);
58                 } else {
59                         /* Destination port: u16 at offset 2 */
60                         pi->key = htonl(((__u32)tmp));
61                         pi->mask = htonl(0x0000FFFF);
62                 }
63                 pi->offset = 0;
64                 *p = 0;
65         }
66         if (get_addr_1(addr, *argv, family))
67                 return -1;
68         if (p)
69                 *p = '/';
70
71         argc--; argv++;
72
73         if (pi->mask || argc <= 0)
74                 goto done;
75
76         if (strcmp(*argv, "spi/ah") == 0 ||
77             strcmp(*argv, "gpi/ah") == 0) {
78                 __u32 gpi;
79                 NEXT_ARG();
80                 if (get_u32(&gpi, *argv, 0))
81                         return -1;
82                 pi->mask = htonl(0xFFFFFFFF);
83                 pi->key = htonl(gpi);
84                 pi->offset = 4;
85                 if (pinfo->protocol == 0)
86                         pinfo->protocol = IPPROTO_AH;
87                 argc--; argv++;
88         } else if (strcmp(*argv, "spi/esp") == 0 ||
89                    strcmp(*argv, "gpi/esp") == 0) {
90                 __u32 gpi;
91                 NEXT_ARG();
92                 if (get_u32(&gpi, *argv, 0))
93                         return -1;
94                 pi->mask = htonl(0xFFFFFFFF);
95                 pi->key = htonl(gpi);
96                 pi->offset = 0;
97                 if (pinfo->protocol == 0)
98                         pinfo->protocol = IPPROTO_ESP;
99                 argc--; argv++;
100         } else if (strcmp(*argv, "flowlabel") == 0) {
101                 __u32 flabel;
102                 NEXT_ARG();
103                 if (get_u32(&flabel, *argv, 0))
104                         return -1;
105                 if (family != AF_INET6)
106                         return -1;
107                 pi->mask = htonl(0x000FFFFF);
108                 pi->key = htonl(flabel) & pi->mask;
109                 pi->offset = -40;
110                 argc--; argv++;
111         } else if (strcmp(*argv, "u32") == 0 ||
112                    strcmp(*argv, "u16") == 0 ||
113                    strcmp(*argv, "u8") == 0) {
114                 int sz = 1;
115                 __u32 tmp;
116                 __u32 mask = 0xff;
117                 if (strcmp(*argv, "u32") == 0) {
118                         sz = 4;
119                         mask = 0xffff;
120                 } else if (strcmp(*argv, "u16") == 0) {
121                         mask = 0xffffffff;
122                         sz = 2;
123                 }
124                 NEXT_ARG();
125                 if (get_u32(&tmp, *argv, 0))
126                         return -1;
127                 argc--; argv++;
128                 if (strcmp(*argv, "mask") == 0) {
129                         NEXT_ARG();
130                         if (get_u32(&mask, *argv, 16))
131                                 return -1;
132                         argc--; argv++;
133                 }
134                 if (strcmp(*argv, "at") == 0) {
135                         NEXT_ARG();
136                         if (get_integer(&pi->offset, *argv, 0))
137                                 return -1;
138                         argc--; argv++;
139                 }
140                 if (sz == 1) {
141                         if ((pi->offset & 3) == 0) {
142                                 mask <<= 24;
143                                 tmp <<= 24;
144                         } else if ((pi->offset & 3) == 1) {
145                                 mask <<= 16;
146                                 tmp <<= 16;
147                         } else if ((pi->offset & 3) == 3) {
148                                 mask <<= 8;
149                                 tmp <<= 8;
150                         }
151                 } else if (sz == 2) {
152                         if ((pi->offset & 3) == 0) {
153                                 mask <<= 16;
154                                 tmp <<= 16;
155                         }
156                 }
157                 pi->offset &= ~3;
158                 pi->mask = htonl(mask);
159                 pi->key = htonl(tmp) & pi->mask;
160         }
161
162 done:
163         *argc_p = argc;
164         *argv_p = argv;
165         return 0;
166 }
167
168
169 static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n)
170 {
171         int family = strcmp(qu->id, "rsvp") == 0 ? AF_INET : AF_INET6;
172         struct tc_rsvp_pinfo pinfo;
173         struct tc_police tp;
174         struct tcmsg *t = NLMSG_DATA(n);
175         int pinfo_ok = 0;
176         struct rtattr *tail;
177
178         memset(&pinfo, 0, sizeof(pinfo));
179         memset(&tp, 0, sizeof(tp));
180
181         if (handle) {
182                 if (get_u32(&t->tcm_handle, handle, 0)) {
183                         fprintf(stderr, "Illegal \"handle\"\n");
184                         return -1;
185                 }
186         }
187
188         if (argc == 0)
189                 return 0;
190
191         tail = NLMSG_TAIL(n);
192         addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
193
194         while (argc > 0) {
195                 if (matches(*argv, "session") == 0) {
196                         inet_prefix addr;
197                         NEXT_ARG();
198                         if (get_addr_and_pi(&argc, &argv, &addr, &pinfo, 1, family)) {
199                                 fprintf(stderr, "Illegal \"session\"\n");
200                                 return -1;
201                         }
202                         addattr_l(n, 4096, TCA_RSVP_DST, &addr.data, addr.bytelen);
203                         if (pinfo.dpi.mask || pinfo.protocol)
204                                 pinfo_ok++;
205                         continue;
206                 } else if (matches(*argv, "sender") == 0 ||
207                            matches(*argv, "flowspec") == 0) {
208                         inet_prefix addr;
209                         NEXT_ARG();
210                         if (get_addr_and_pi(&argc, &argv, &addr, &pinfo, 0, family)) {
211                                 fprintf(stderr, "Illegal \"sender\"\n");
212                                 return -1;
213                         }
214                         addattr_l(n, 4096, TCA_RSVP_SRC, &addr.data, addr.bytelen);
215                         if (pinfo.spi.mask || pinfo.protocol)
216                                 pinfo_ok++;
217                         continue;
218                 } else if (matches("ipproto", *argv) == 0) {
219                         int num;
220                         NEXT_ARG();
221                         num = inet_proto_a2n(*argv);
222                         if (num < 0) {
223                                 fprintf(stderr, "Illegal \"ipproto\"\n");
224                                 return -1;
225                         }
226                         pinfo.protocol = num;
227                         pinfo_ok++;
228                 } else if (matches(*argv, "classid") == 0 ||
229                            strcmp(*argv, "flowid") == 0) {
230                         unsigned handle;
231                         NEXT_ARG();
232                         if (get_tc_classid(&handle, *argv)) {
233                                 fprintf(stderr, "Illegal \"classid\"\n");
234                                 return -1;
235                         }
236                         addattr_l(n, 4096, TCA_RSVP_CLASSID, &handle, 4);
237                 } else if (strcmp(*argv, "tunnelid") == 0) {
238                         unsigned tid;
239                         NEXT_ARG();
240                         if (get_unsigned(&tid, *argv, 0)) {
241                                 fprintf(stderr, "Illegal \"tunnelid\"\n");
242                                 return -1;
243                         }
244                         pinfo.tunnelid = tid;
245                         pinfo_ok++;
246                 } else if (strcmp(*argv, "tunnel") == 0) {
247                         unsigned tid;
248                         NEXT_ARG();
249                         if (get_unsigned(&tid, *argv, 0)) {
250                                 fprintf(stderr, "Illegal \"tunnel\"\n");
251                                 return -1;
252                         }
253                         addattr_l(n, 4096, TCA_RSVP_CLASSID, &tid, 4);
254                         NEXT_ARG();
255                         if (strcmp(*argv, "skip") == 0) {
256                                 NEXT_ARG();
257                         }
258                         if (get_unsigned(&tid, *argv, 0)) {
259                                 fprintf(stderr, "Illegal \"skip\"\n");
260                                 return -1;
261                         }
262                         pinfo.tunnelhdr = tid;
263                         pinfo_ok++;
264                 } else if (matches(*argv, "police") == 0) {
265                         NEXT_ARG();
266                         if (parse_police(&argc, &argv, TCA_RSVP_POLICE, n)) {
267                                 fprintf(stderr, "Illegal \"police\"\n");
268                                 return -1;
269                         }
270                         continue;
271                 } else if (strcmp(*argv, "help") == 0) {
272                         explain();
273                         return -1;
274                 } else {
275                         fprintf(stderr, "What is \"%s\"?\n", *argv);
276                         explain();
277                         return -1;
278                 }
279                 argc--; argv++;
280         }
281
282         if (pinfo_ok)
283                 addattr_l(n, 4096, TCA_RSVP_PINFO, &pinfo, sizeof(pinfo));
284         tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
285         return 0;
286 }
287
288 static char * sprint_spi(struct tc_rsvp_gpi *pi, int dir, char *buf)
289 {
290         if (pi->offset == 0) {
291                 if (dir && pi->mask == htonl(0xFFFF)) {
292                         snprintf(buf, SPRINT_BSIZE-1, "/%d", htonl(pi->key));
293                         return buf;
294                 }
295                 if (!dir && pi->mask == htonl(0xFFFF0000)) {
296                         snprintf(buf, SPRINT_BSIZE-1, "/%d", htonl(pi->key)>>16);
297                         return buf;
298                 }
299                 if (pi->mask == htonl(0xFFFFFFFF)) {
300                         snprintf(buf, SPRINT_BSIZE-1, " spi/esp 0x%08x", htonl(pi->key));
301                         return buf;
302                 }
303         } else if (pi->offset == 4 && pi->mask == htonl(0xFFFFFFFF)) {
304                 snprintf(buf, SPRINT_BSIZE-1, " spi/ah 0x%08x", htonl(pi->key));
305                 return buf;
306         } else if (pi->offset == -40 && pi->mask == htonl(0x000FFFFF)) {
307                 snprintf(buf, SPRINT_BSIZE-1, " flowlabel 0x%05x", htonl(pi->key));
308                 return buf;
309         }
310         snprintf(buf, SPRINT_BSIZE-1, " u32 0x%08x mask %08x at %d",
311                  htonl(pi->key), htonl(pi->mask), pi->offset);
312         return buf;
313 }
314
315 static int rsvp_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle)
316 {
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;
320
321         if (opt == NULL)
322                 return 0;
323
324         parse_rtattr_nested(tb, TCA_RSVP_MAX, opt);
325
326         if (handle)
327                 fprintf(f, "fh 0x%08x ", handle);
328
329         if (tb[TCA_RSVP_PINFO]) {
330                 if (RTA_PAYLOAD(tb[TCA_RSVP_PINFO])  < sizeof(*pinfo))
331                         return -1;
332
333                 pinfo = RTA_DATA(tb[TCA_RSVP_PINFO]);
334         }
335
336         if (tb[TCA_RSVP_CLASSID]) {
337                 SPRINT_BUF(b1);
338                 if (!pinfo || pinfo->tunnelhdr == 0)
339                         fprintf(f, "flowid %s ", sprint_tc_classid(*(__u32*)RTA_DATA(tb[TCA_RSVP_CLASSID]), b1));
340                 else
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);
344
345         if (tb[TCA_RSVP_DST]) {
346                 char buf[128];
347                 fprintf(f, "session ");
348                 if (inet_ntop(family, RTA_DATA(tb[TCA_RSVP_DST]), buf, sizeof(buf)) == 0)
349                         fprintf(f, " [INVALID DADDR] ");
350                 else
351                         fprintf(f, "%s", buf);
352                 if (pinfo && pinfo->dpi.mask) {
353                         SPRINT_BUF(b2);
354                         fprintf(f, "%s ", sprint_spi(&pinfo->dpi, 1, b2));
355                 } else
356                         fprintf(f, " ");
357         } else {
358                 if (pinfo && pinfo->dpi.mask) {
359                         SPRINT_BUF(b2);
360                         fprintf(f, "session [NONE]%s ", sprint_spi(&pinfo->dpi, 1, b2));
361                 } else
362                         fprintf(f, "session NONE ");
363         }
364
365         if (pinfo && pinfo->protocol) {
366                 SPRINT_BUF(b1);
367                 fprintf(f, "ipproto %s ", inet_proto_n2a(pinfo->protocol, b1, sizeof(b1)));
368         }
369         if (pinfo && pinfo->tunnelid)
370                 fprintf(f, "tunnelid %d ", pinfo->tunnelid);
371         if (tb[TCA_RSVP_SRC]) {
372                 char buf[128];
373                 fprintf(f, "sender ");
374                 if (inet_ntop(family, RTA_DATA(tb[TCA_RSVP_SRC]), buf, sizeof(buf)) == 0) {
375                         fprintf(f, "[BAD]");
376                 } else {
377                         fprintf(f, " %s", buf);
378                 }
379                 if (pinfo && pinfo->spi.mask) {
380                         SPRINT_BUF(b2);
381                         fprintf(f, "%s ", sprint_spi(&pinfo->spi, 0, b2));
382                 } else
383                         fprintf(f, " ");
384         } else if (pinfo && pinfo->spi.mask) {
385                 SPRINT_BUF(b2);
386                 fprintf(f, "sender [NONE]%s ", sprint_spi(&pinfo->spi, 0, b2));
387         }
388         if (tb[TCA_RSVP_POLICE])
389                 tc_print_police(f, tb[TCA_RSVP_POLICE]);
390         return 0;
391 }
392
393 struct filter_util rsvp_filter_util = {
394         .id = "rsvp",
395         .parse_fopt = rsvp_parse_opt,
396         .print_fopt = rsvp_print_opt,
397 };
398
399 struct filter_util rsvp6_filter_util = {
400         .id = "rsvp6",
401         .parse_fopt = rsvp_parse_opt,
402         .print_fopt = rsvp_print_opt,
403 };