]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/em_meta.c
tc: m_action: Improve conversion to C99 style initializers
[mirror_iproute2.git] / tc / em_meta.c
CommitLineData
311b4145
SH
1/*
2 * em_meta.c Metadata Ematch
3 *
4 * This program is free software; you can distribute 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: Thomas Graf <tgraf@suug.ch>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <syslog.h>
16#include <fcntl.h>
17#include <sys/socket.h>
18#include <netinet/in.h>
19#include <arpa/inet.h>
20#include <string.h>
311b4145
SH
21#include <errno.h>
22
23#include "m_ematch.h"
24#include <linux/tc_ematch/tc_em_meta.h>
25
26extern struct ematch_util meta_ematch_util;
27
28static void meta_print_usage(FILE *fd)
29{
30 fprintf(fd,
31 "Usage: meta(OBJECT { eq | lt | gt } OBJECT)\n" \
32 "where: OBJECT := { META_ID | VALUE }\n" \
33 " META_ID := id [ shift SHIFT ] [ mask MASK ]\n" \
34 "\n" \
a07c6d61 35 "Example: meta(nf_mark gt 24)\n" \
ba26a6e8 36 " meta(indev shift 1 eq \"ppp\")\n" \
311b4145 37 " meta(tcindex mask 0xf0 eq 0xf0)\n" \
311b4145
SH
38 "\n" \
39 "For a list of meta identifiers, use meta(list).\n");
40}
41
42struct meta_entry {
43 int id;
32a121cb
SH
44 char *kind;
45 char *mask;
46 char *desc;
311b4145
SH
47} meta_table[] = {
48#define TCF_META_ID_SECTION 0
49#define __A(id, name, mask, desc) { TCF_META_ID_##id, name, mask, desc }
50 __A(SECTION, "Generic", "", ""),
51 __A(RANDOM, "random", "i",
52 "Random value (32 bit)"),
53 __A(LOADAVG_0, "loadavg_1", "i",
54 "Load average in last minute"),
55 __A(LOADAVG_1, "loadavg_5", "i",
56 "Load average in last 5 minutes"),
57 __A(LOADAVG_2, "loadavg_15", "i",
58 "Load average in last 15 minutes"),
59
60 __A(SECTION, "Interfaces", "", ""),
61 __A(DEV, "dev", "iv",
62 "Device the packet is on"),
311b4145
SH
63 __A(SECTION, "Packet attributes", "", ""),
64 __A(PRIORITY, "priority", "i",
65 "Priority of packet"),
66 __A(PROTOCOL, "protocol", "i",
67 "Link layer protocol"),
311b4145
SH
68 __A(PKTTYPE, "pkt_type", "i",
69 "Packet type (uni|multi|broad|...)cast"),
70 __A(PKTLEN, "pkt_len", "i",
71 "Length of packet"),
72 __A(DATALEN, "data_len", "i",
73 "Length of data in packet"),
74 __A(MACLEN, "mac_len", "i",
75 "Length of link layer header"),
76
77 __A(SECTION, "Netfilter", "", ""),
78 __A(NFMARK, "nf_mark", "i",
79 "Netfilter mark"),
80 __A(NFMARK, "fwmark", "i",
81 "Alias for nf_mark"),
82
83 __A(SECTION, "Traffic Control", "", ""),
84 __A(TCINDEX, "tc_index", "i", "TC Index"),
311b4145
SH
85 __A(SECTION, "Routing", "", ""),
86 __A(RTCLASSID, "rt_classid", "i",
87 "Routing ClassID (cls_route)"),
88 __A(RTIIF, "rt_iif", "i",
89 "Incoming interface index"),
5e76a87d 90 __A(VLAN_TAG, "vlan", "i", "Vlan tag"),
311b4145
SH
91
92 __A(SECTION, "Sockets", "", ""),
93 __A(SK_FAMILY, "sk_family", "i", "Address family"),
94 __A(SK_STATE, "sk_state", "i", "State"),
95 __A(SK_REUSE, "sk_reuse", "i", "Reuse Flag"),
96 __A(SK_BOUND_IF, "sk_bind_if", "iv", "Bound interface"),
97 __A(SK_REFCNT, "sk_refcnt", "i", "Reference counter"),
98 __A(SK_SHUTDOWN, "sk_shutdown", "i", "Shutdown mask"),
99 __A(SK_PROTO, "sk_proto", "i", "Protocol"),
100 __A(SK_TYPE, "sk_type", "i", "Type"),
101 __A(SK_RCVBUF, "sk_rcvbuf", "i", "Receive buffer size"),
102 __A(SK_RMEM_ALLOC, "sk_rmem", "i", "RMEM"),
103 __A(SK_WMEM_ALLOC, "sk_wmem", "i", "WMEM"),
104 __A(SK_OMEM_ALLOC, "sk_omem", "i", "OMEM"),
32a121cb 105 __A(SK_WMEM_QUEUED, "sk_wmem_queue", "i", "WMEM queue"),
311b4145
SH
106 __A(SK_SND_QLEN, "sk_snd_queue", "i", "Send queue length"),
107 __A(SK_RCV_QLEN, "sk_rcv_queue", "i", "Receive queue length"),
108 __A(SK_ERR_QLEN, "sk_err_queue", "i", "Error queue length"),
109 __A(SK_FORWARD_ALLOCS, "sk_fwd_alloc", "i", "Forward allocations"),
110 __A(SK_SNDBUF, "sk_sndbuf", "i", "Send buffer size"),
111#undef __A
112};
113
114static inline int map_type(char k)
115{
116 switch (k) {
117 case 'i': return TCF_META_TYPE_INT;
118 case 'v': return TCF_META_TYPE_VAR;
119 }
120
121 fprintf(stderr, "BUG: Unknown map character '%c'\n", k);
122 return INT_MAX;
123}
124
32a121cb 125static struct meta_entry *lookup_meta_entry(struct bstr *kind)
311b4145
SH
126{
127 int i;
128
32a121cb 129 for (i = 0; i < ARRAY_SIZE(meta_table); i++)
311b4145
SH
130 if (!bstrcmp(kind, meta_table[i].kind) &&
131 meta_table[i].id != 0)
132 return &meta_table[i];
ae665a52 133
311b4145
SH
134 return NULL;
135}
136
32a121cb 137static struct meta_entry *lookup_meta_entry_byid(int id)
311b4145
SH
138{
139 int i;
140
32a121cb 141 for (i = 0; i < ARRAY_SIZE(meta_table); i++)
311b4145
SH
142 if (meta_table[i].id == id)
143 return &meta_table[i];
ae665a52 144
311b4145
SH
145 return NULL;
146}
147
148static inline void dump_value(struct nlmsghdr *n, int tlv, unsigned long val,
149 struct tcf_meta_val *hdr)
150{
151 __u32 t;
152
153 switch (TCF_META_TYPE(hdr->kind)) {
154 case TCF_META_TYPE_INT:
155 t = val;
156 addattr_l(n, MAX_MSG, tlv, &t, sizeof(t));
157 break;
158
159 case TCF_META_TYPE_VAR:
160 if (TCF_META_ID(hdr->kind) == TCF_META_ID_VALUE) {
161 struct bstr *a = (struct bstr *) val;
32a121cb 162
311b4145
SH
163 addattr_l(n, MAX_MSG, tlv, a->data, a->len);
164 }
165 break;
166 }
167}
168
169static inline int is_compatible(struct tcf_meta_val *what,
170 struct tcf_meta_val *needed)
171{
172 char *p;
173 struct meta_entry *entry;
ae665a52 174
311b4145
SH
175 entry = lookup_meta_entry_byid(TCF_META_ID(what->kind));
176
177 if (entry == NULL)
178 return 0;
ae665a52 179
311b4145
SH
180 for (p = entry->mask; p; p++)
181 if (map_type(*p) == TCF_META_TYPE(needed->kind))
182 return 1;
183
184 return 0;
185}
186
187static void list_meta_ids(FILE *fd)
188{
189 int i;
190
191 fprintf(fd,
192 "--------------------------------------------------------\n" \
193 " ID Type Description\n" \
194 "--------------------------------------------------------");
195
32a121cb 196 for (i = 0; i < ARRAY_SIZE(meta_table); i++) {
311b4145
SH
197 if (meta_table[i].id == TCF_META_ID_SECTION) {
198 fprintf(fd, "\n%s:\n", meta_table[i].kind);
199 } else {
200 char *p = meta_table[i].mask;
201 char buf[64] = {0};
202
203 fprintf(fd, " %-16s ", meta_table[i].kind);
204
205 while (*p) {
206 int type = map_type(*p);
207
208 switch (type) {
209 case TCF_META_TYPE_INT:
210 strcat(buf, "INT");
211 break;
212
213 case TCF_META_TYPE_VAR:
214 strcat(buf, "VAR");
215 break;
216 }
217
218 if (*(++p))
219 strcat(buf, ",");
220 }
221
222 fprintf(fd, "%-10s %s\n", buf, meta_table[i].desc);
223 }
224 }
225
226 fprintf(fd,
227 "--------------------------------------------------------\n");
228}
229
230#undef TCF_META_ID_SECTION
231
232#define PARSE_FAILURE ((void *) (-1))
233
234#define PARSE_ERR(CARG, FMT, ARGS...) \
32a121cb 235 em_parse_error(EINVAL, args, CARG, &meta_ematch_util, FMT, ##ARGS)
311b4145
SH
236
237static inline int can_adopt(struct tcf_meta_val *val)
238{
239 return !!TCF_META_ID(val->kind);
240}
241
242static inline int overwrite_type(struct tcf_meta_val *src,
243 struct tcf_meta_val *dst)
244{
245 return (TCF_META_TYPE(dst->kind) << 12) | TCF_META_ID(src->kind);
246}
ae665a52 247
311b4145
SH
248
249static inline struct bstr *
250parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj,
251 unsigned long *dst, struct tcf_meta_val *left)
252{
253 struct meta_entry *entry;
254 unsigned long num;
255 struct bstr *a;
256
257 if (arg->quoted) {
258 obj->kind = TCF_META_TYPE_VAR << 12;
259 obj->kind |= TCF_META_ID_VALUE;
260 *dst = (unsigned long) arg;
261 return bstr_next(arg);
262 }
263
264 num = bstrtoul(arg);
11bbe7fd 265 if (num != ULONG_MAX) {
311b4145
SH
266 obj->kind = TCF_META_TYPE_INT << 12;
267 obj->kind |= TCF_META_ID_VALUE;
268 *dst = (unsigned long) num;
269 return bstr_next(arg);
270 }
271
272 entry = lookup_meta_entry(arg);
273
274 if (entry == NULL) {
275 PARSE_ERR(arg, "meta: unknown meta id\n");
276 return PARSE_FAILURE;
277 }
278
279 obj->kind = entry->id | (map_type(entry->mask[0]) << 12);
280
281 if (left) {
282 struct tcf_meta_val *right = obj;
ae665a52 283
311b4145
SH
284 if (TCF_META_TYPE(right->kind) == TCF_META_TYPE(left->kind))
285 goto compatible;
286
287 if (can_adopt(left) && !can_adopt(right)) {
288 if (is_compatible(left, right))
289 left->kind = overwrite_type(left, right);
290 else
291 goto not_compatible;
292 } else if (can_adopt(right) && !can_adopt(left)) {
293 if (is_compatible(right, left))
294 right->kind = overwrite_type(right, left);
295 else
296 goto not_compatible;
297 } else if (can_adopt(left) && can_adopt(right)) {
298 if (is_compatible(left, right))
299 left->kind = overwrite_type(left, right);
300 else if (is_compatible(right, left))
301 right->kind = overwrite_type(right, left);
302 else
303 goto not_compatible;
ae665a52 304 } else
311b4145
SH
305 goto not_compatible;
306 }
307
308compatible:
309
310 a = bstr_next(arg);
311
32a121cb 312 while (a) {
311b4145
SH
313 if (!bstrcmp(a, "shift")) {
314 unsigned long shift;
315
316 if (a->next == NULL) {
317 PARSE_ERR(a, "meta: missing argument");
318 return PARSE_FAILURE;
319 }
320 a = bstr_next(a);
ae665a52 321
311b4145 322 shift = bstrtoul(a);
11bbe7fd 323 if (shift == ULONG_MAX) {
311b4145
SH
324 PARSE_ERR(a, "meta: invalid shift, must " \
325 "be numeric");
326 return PARSE_FAILURE;
327 }
328
329 obj->shift = (__u8) shift;
330 a = bstr_next(a);
331 } else if (!bstrcmp(a, "mask")) {
332 unsigned long mask;
333
334 if (a->next == NULL) {
335 PARSE_ERR(a, "meta: missing argument");
336 return PARSE_FAILURE;
337 }
338 a = bstr_next(a);
ae665a52 339
311b4145 340 mask = bstrtoul(a);
11bbe7fd 341 if (mask == ULONG_MAX) {
311b4145
SH
342 PARSE_ERR(a, "meta: invalid mask, must be " \
343 "numeric");
344 return PARSE_FAILURE;
345 }
346 *dst = (unsigned long) mask;
347 a = bstr_next(a);
348 } else
349 break;
350 }
351
352 return a;
353
354not_compatible:
355 PARSE_ERR(arg, "lvalue and rvalue are not compatible.");
356 return PARSE_FAILURE;
357}
358
359static int meta_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
360 struct bstr *args)
361{
362 int opnd;
363 struct bstr *a;
364 struct tcf_meta_hdr meta_hdr;
365 unsigned long lvalue = 0, rvalue = 0;
366
367 memset(&meta_hdr, 0, sizeof(meta_hdr));
368
369 if (args == NULL)
370 return PARSE_ERR(args, "meta: missing arguments");
371
372 if (!bstrcmp(args, "list")) {
373 list_meta_ids(stderr);
374 return -1;
375 }
376
377 a = parse_object(args, args, &meta_hdr.left, &lvalue, NULL);
378 if (a == PARSE_FAILURE)
379 return -1;
380 else if (a == NULL)
381 return PARSE_ERR(args, "meta: missing operand");
382
383 if (!bstrcmp(a, "eq"))
384 opnd = TCF_EM_OPND_EQ;
385 else if (!bstrcmp(a, "gt"))
386 opnd = TCF_EM_OPND_GT;
387 else if (!bstrcmp(a, "lt"))
388 opnd = TCF_EM_OPND_LT;
389 else
390 return PARSE_ERR(a, "meta: invalid operand");
391
392 meta_hdr.left.op = (__u8) opnd;
393
394 if (a->next == NULL)
395 return PARSE_ERR(args, "meta: missing rvalue");
396 a = bstr_next(a);
397
398 a = parse_object(args, a, &meta_hdr.right, &rvalue, &meta_hdr.left);
399 if (a == PARSE_FAILURE)
400 return -1;
401 else if (a != NULL)
402 return PARSE_ERR(a, "meta: unexpected trailer");
ae665a52 403
311b4145
SH
404
405 addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
406
407 addattr_l(n, MAX_MSG, TCA_EM_META_HDR, &meta_hdr, sizeof(meta_hdr));
408
61407852
PM
409 dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left);
410 dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right);
311b4145
SH
411
412 return 0;
413}
414#undef PARSE_ERR
415
416static inline void print_binary(FILE *fd, unsigned char *str, int len)
417{
418 int i;
419
420 for (i = 0; i < len; i++)
421 if (!isprint(str[i]))
422 goto binary;
423
424 for (i = 0; i < len; i++)
425 fprintf(fd, "%c", str[i]);
426 return;
427
428binary:
429 for (i = 0; i < len; i++)
430 fprintf(fd, "%02x ", str[i]);
431
432 fprintf(fd, "\"");
433 for (i = 0; i < len; i++)
434 fprintf(fd, "%c", isprint(str[i]) ? str[i] : '.');
435 fprintf(fd, "\"");
436}
437
438static inline int print_value(FILE *fd, int type, struct rtattr *rta)
439{
440 if (rta == NULL) {
441 fprintf(stderr, "Missing value TLV\n");
442 return -1;
443 }
444
32a121cb 445 switch (type) {
311b4145
SH
446 case TCF_META_TYPE_INT:
447 if (RTA_PAYLOAD(rta) < sizeof(__u32)) {
448 fprintf(stderr, "meta int type value TLV " \
449 "size mismatch.\n");
450 return -1;
451 }
ff24746c 452 fprintf(fd, "%d", rta_getattr_u32(rta));
311b4145
SH
453 break;
454
455 case TCF_META_TYPE_VAR:
456 print_binary(fd, RTA_DATA(rta), RTA_PAYLOAD(rta));
457 break;
458 }
459
460 return 0;
461}
462
463static int print_object(FILE *fd, struct tcf_meta_val *obj, struct rtattr *rta)
464{
465 int id = TCF_META_ID(obj->kind);
466 int type = TCF_META_TYPE(obj->kind);
467 struct meta_entry *entry;
468
469 if (id == TCF_META_ID_VALUE)
470 return print_value(fd, type, rta);
471
472 entry = lookup_meta_entry_byid(id);
473
474 if (entry == NULL)
475 fprintf(fd, "[unknown meta id %d]", id);
476 else
477 fprintf(fd, "%s", entry->kind);
478
479 if (obj->shift)
480 fprintf(fd, " shift %d", obj->shift);
481
482 switch (type) {
483 case TCF_META_TYPE_INT:
484 if (rta) {
485 if (RTA_PAYLOAD(rta) < sizeof(__u32))
486 goto size_mismatch;
487
488 fprintf(fd, " mask 0x%08x",
ff24746c 489 rta_getattr_u32(rta));
311b4145
SH
490 }
491 break;
492 }
493
494 return 0;
495
496size_mismatch:
497 fprintf(stderr, "meta int type mask TLV size mismatch\n");
498 return -1;
499}
500
501
502static int meta_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
503 int data_len)
504{
505 struct rtattr *tb[TCA_EM_META_MAX+1];
506 struct tcf_meta_hdr *meta_hdr;
507
508 if (parse_rtattr(tb, TCA_EM_META_MAX, data, data_len) < 0)
509 return -1;
510
511 if (tb[TCA_EM_META_HDR] == NULL) {
512 fprintf(stderr, "Missing meta header\n");
513 return -1;
514 }
515
516 if (RTA_PAYLOAD(tb[TCA_EM_META_HDR]) < sizeof(*meta_hdr)) {
517 fprintf(stderr, "Meta header size mismatch\n");
518 return -1;
519 }
520
521 meta_hdr = RTA_DATA(tb[TCA_EM_META_HDR]);
522
523 if (print_object(fd, &meta_hdr->left, tb[TCA_EM_META_LVALUE]) < 0)
524 return -1;
525
526 switch (meta_hdr->left.op) {
527 case TCF_EM_OPND_EQ:
528 fprintf(fd, " eq ");
529 break;
530 case TCF_EM_OPND_LT:
531 fprintf(fd, " lt ");
532 break;
533 case TCF_EM_OPND_GT:
534 fprintf(fd, " gt ");
535 break;
536 }
537
538 return print_object(fd, &meta_hdr->right, tb[TCA_EM_META_RVALUE]);
539}
540
541struct ematch_util meta_ematch_util = {
542 .kind = "meta",
543 .kind_num = TCF_EM_META,
544 .parse_eopt = meta_parse_eopt,
545 .print_eopt = meta_print_eopt,
546 .print_usage = meta_print_usage
547};