2 * em_meta.c Metadata Ematch
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.
9 * Authors: Thomas Graf <tgraf@suug.ch>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
25 #include <linux/tc_ematch/tc_em_meta.h>
27 extern struct ematch_util meta_ematch_util
;
29 static void meta_print_usage(FILE *fd
)
32 "Usage: meta(OBJECT { eq | lt | gt } OBJECT)\n" \
33 "where: OBJECT := { META_ID | VALUE }\n" \
34 " META_ID := id [ shift SHIFT ] [ mask MASK ]\n" \
36 "Example: meta(nfmark gt 24)\n" \
37 " meta(indev shift 1 eq \"ppp\")\n" \
38 " meta(tcindex mask 0xf0 eq 0xf0)\n" \
40 "For a list of meta identifiers, use meta(list).\n");
49 #define TCF_META_ID_SECTION 0
50 #define __A(id, name, mask, desc) { TCF_META_ID_##id, name, mask, desc }
51 __A(SECTION
, "Generic", "", ""),
52 __A(RANDOM
, "random", "i",
53 "Random value (32 bit)"),
54 __A(LOADAVG_0
, "loadavg_1", "i",
55 "Load average in last minute"),
56 __A(LOADAVG_1
, "loadavg_5", "i",
57 "Load average in last 5 minutes"),
58 __A(LOADAVG_2
, "loadavg_15", "i",
59 "Load average in last 15 minutes"),
61 __A(SECTION
, "Interfaces", "", ""),
63 "Device the packet is on"),
64 __A(SECTION
, "Packet attributes", "", ""),
65 __A(PRIORITY
, "priority", "i",
66 "Priority of packet"),
67 __A(PROTOCOL
, "protocol", "i",
68 "Link layer protocol"),
69 __A(PKTTYPE
, "pkt_type", "i",
70 "Packet type (uni|multi|broad|...)cast"),
71 __A(PKTLEN
, "pkt_len", "i",
73 __A(DATALEN
, "data_len", "i",
74 "Length of data in packet"),
75 __A(MACLEN
, "mac_len", "i",
76 "Length of link layer header"),
78 __A(SECTION
, "Netfilter", "", ""),
79 __A(NFMARK
, "nf_mark", "i",
81 __A(NFMARK
, "fwmark", "i",
84 __A(SECTION
, "Traffic Control", "", ""),
85 __A(TCINDEX
, "tc_index", "i", "TC Index"),
86 __A(SECTION
, "Routing", "", ""),
87 __A(RTCLASSID
, "rt_classid", "i",
88 "Routing ClassID (cls_route)"),
89 __A(RTIIF
, "rt_iif", "i",
90 "Incoming interface index"),
91 __A(VLAN_TAG
, "vlan", "i", "Vlan tag"),
93 __A(SECTION
, "Sockets", "", ""),
94 __A(SK_FAMILY
, "sk_family", "i", "Address family"),
95 __A(SK_STATE
, "sk_state", "i", "State"),
96 __A(SK_REUSE
, "sk_reuse", "i", "Reuse Flag"),
97 __A(SK_BOUND_IF
, "sk_bind_if", "iv", "Bound interface"),
98 __A(SK_REFCNT
, "sk_refcnt", "i", "Reference counter"),
99 __A(SK_SHUTDOWN
, "sk_shutdown", "i", "Shutdown mask"),
100 __A(SK_PROTO
, "sk_proto", "i", "Protocol"),
101 __A(SK_TYPE
, "sk_type", "i", "Type"),
102 __A(SK_RCVBUF
, "sk_rcvbuf", "i", "Receive buffer size"),
103 __A(SK_RMEM_ALLOC
, "sk_rmem", "i", "RMEM"),
104 __A(SK_WMEM_ALLOC
, "sk_wmem", "i", "WMEM"),
105 __A(SK_OMEM_ALLOC
, "sk_omem", "i", "OMEM"),
106 __A(SK_WMEM_QUEUED
, "sk_wmem_queue","i", "WMEM queue"),
107 __A(SK_SND_QLEN
, "sk_snd_queue", "i", "Send queue length"),
108 __A(SK_RCV_QLEN
, "sk_rcv_queue", "i", "Receive queue length"),
109 __A(SK_ERR_QLEN
, "sk_err_queue", "i", "Error queue length"),
110 __A(SK_FORWARD_ALLOCS
, "sk_fwd_alloc", "i", "Forward allocations"),
111 __A(SK_SNDBUF
, "sk_sndbuf", "i", "Send buffer size"),
115 static inline int map_type(char k
)
118 case 'i': return TCF_META_TYPE_INT
;
119 case 'v': return TCF_META_TYPE_VAR
;
122 fprintf(stderr
, "BUG: Unknown map character '%c'\n", k
);
126 static struct meta_entry
* lookup_meta_entry(struct bstr
*kind
)
130 for (i
= 0; i
< (sizeof(meta_table
)/sizeof(meta_table
[0])); i
++)
131 if (!bstrcmp(kind
, meta_table
[i
].kind
) &&
132 meta_table
[i
].id
!= 0)
133 return &meta_table
[i
];
138 static struct meta_entry
* lookup_meta_entry_byid(int id
)
142 for (i
= 0; i
< (sizeof(meta_table
)/sizeof(meta_table
[0])); i
++)
143 if (meta_table
[i
].id
== id
)
144 return &meta_table
[i
];
149 static inline void dump_value(struct nlmsghdr
*n
, int tlv
, unsigned long val
,
150 struct tcf_meta_val
*hdr
)
154 switch (TCF_META_TYPE(hdr
->kind
)) {
155 case TCF_META_TYPE_INT
:
157 addattr_l(n
, MAX_MSG
, tlv
, &t
, sizeof(t
));
160 case TCF_META_TYPE_VAR
:
161 if (TCF_META_ID(hdr
->kind
) == TCF_META_ID_VALUE
) {
162 struct bstr
*a
= (struct bstr
*) val
;
163 addattr_l(n
, MAX_MSG
, tlv
, a
->data
, a
->len
);
169 static inline int is_compatible(struct tcf_meta_val
*what
,
170 struct tcf_meta_val
*needed
)
173 struct meta_entry
*entry
;
175 entry
= lookup_meta_entry_byid(TCF_META_ID(what
->kind
));
180 for (p
= entry
->mask
; p
; p
++)
181 if (map_type(*p
) == TCF_META_TYPE(needed
->kind
))
187 static void list_meta_ids(FILE *fd
)
192 "--------------------------------------------------------\n" \
193 " ID Type Description\n" \
194 "--------------------------------------------------------");
196 for (i
= 0; i
< (sizeof(meta_table
)/sizeof(meta_table
[0])); i
++) {
197 if (meta_table
[i
].id
== TCF_META_ID_SECTION
) {
198 fprintf(fd
, "\n%s:\n", meta_table
[i
].kind
);
200 char *p
= meta_table
[i
].mask
;
203 fprintf(fd
, " %-16s ", meta_table
[i
].kind
);
206 int type
= map_type(*p
);
209 case TCF_META_TYPE_INT
:
213 case TCF_META_TYPE_VAR
:
222 fprintf(fd
, "%-10s %s\n", buf
, meta_table
[i
].desc
);
227 "--------------------------------------------------------\n");
230 #undef TCF_META_ID_SECTION
232 #define PARSE_FAILURE ((void *) (-1))
234 #define PARSE_ERR(CARG, FMT, ARGS...) \
235 em_parse_error(EINVAL, args, CARG, &meta_ematch_util, FMT ,##ARGS)
237 static inline int can_adopt(struct tcf_meta_val
*val
)
239 return !!TCF_META_ID(val
->kind
);
242 static inline int overwrite_type(struct tcf_meta_val
*src
,
243 struct tcf_meta_val
*dst
)
245 return (TCF_META_TYPE(dst
->kind
) << 12) | TCF_META_ID(src
->kind
);
249 static inline struct bstr
*
250 parse_object(struct bstr
*args
, struct bstr
*arg
, struct tcf_meta_val
*obj
,
251 unsigned long *dst
, struct tcf_meta_val
*left
)
253 struct meta_entry
*entry
;
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
);
265 if (num
!= ULONG_MAX
) {
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
);
272 entry
= lookup_meta_entry(arg
);
275 PARSE_ERR(arg
, "meta: unknown meta id\n");
276 return PARSE_FAILURE
;
279 obj
->kind
= entry
->id
| (map_type(entry
->mask
[0]) << 12);
282 struct tcf_meta_val
*right
= obj
;
284 if (TCF_META_TYPE(right
->kind
) == TCF_META_TYPE(left
->kind
))
287 if (can_adopt(left
) && !can_adopt(right
)) {
288 if (is_compatible(left
, right
))
289 left
->kind
= overwrite_type(left
, right
);
292 } else if (can_adopt(right
) && !can_adopt(left
)) {
293 if (is_compatible(right
, left
))
294 right
->kind
= overwrite_type(right
, left
);
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
);
313 if (!bstrcmp(a
, "shift")) {
316 if (a
->next
== NULL
) {
317 PARSE_ERR(a
, "meta: missing argument");
318 return PARSE_FAILURE
;
323 if (shift
== ULONG_MAX
) {
324 PARSE_ERR(a
, "meta: invalid shift, must " \
326 return PARSE_FAILURE
;
329 obj
->shift
= (__u8
) shift
;
331 } else if (!bstrcmp(a
, "mask")) {
334 if (a
->next
== NULL
) {
335 PARSE_ERR(a
, "meta: missing argument");
336 return PARSE_FAILURE
;
341 if (mask
== ULONG_MAX
) {
342 PARSE_ERR(a
, "meta: invalid mask, must be " \
344 return PARSE_FAILURE
;
346 *dst
= (unsigned long) mask
;
355 PARSE_ERR(arg
, "lvalue and rvalue are not compatible.");
356 return PARSE_FAILURE
;
359 static int meta_parse_eopt(struct nlmsghdr
*n
, struct tcf_ematch_hdr
*hdr
,
364 struct tcf_meta_hdr meta_hdr
;
365 unsigned long lvalue
= 0, rvalue
= 0;
367 memset(&meta_hdr
, 0, sizeof(meta_hdr
));
370 return PARSE_ERR(args
, "meta: missing arguments");
372 if (!bstrcmp(args
, "list")) {
373 list_meta_ids(stderr
);
377 a
= parse_object(args
, args
, &meta_hdr
.left
, &lvalue
, NULL
);
378 if (a
== PARSE_FAILURE
)
381 return PARSE_ERR(args
, "meta: missing operand");
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
;
390 return PARSE_ERR(a
, "meta: invalid operand");
392 meta_hdr
.left
.op
= (__u8
) opnd
;
395 return PARSE_ERR(args
, "meta: missing rvalue");
398 a
= parse_object(args
, a
, &meta_hdr
.right
, &rvalue
, &meta_hdr
.left
);
399 if (a
== PARSE_FAILURE
)
402 return PARSE_ERR(a
, "meta: unexpected trailer");
405 addraw_l(n
, MAX_MSG
, hdr
, sizeof(*hdr
));
407 addattr_l(n
, MAX_MSG
, TCA_EM_META_HDR
, &meta_hdr
, sizeof(meta_hdr
));
409 dump_value(n
, TCA_EM_META_LVALUE
, lvalue
, &meta_hdr
.left
);
410 dump_value(n
, TCA_EM_META_RVALUE
, rvalue
, &meta_hdr
.right
);
416 static inline void print_binary(FILE *fd
, unsigned char *str
, int len
)
420 for (i
= 0; i
< len
; i
++)
421 if (!isprint(str
[i
]))
424 for (i
= 0; i
< len
; i
++)
425 fprintf(fd
, "%c", str
[i
]);
429 for (i
= 0; i
< len
; i
++)
430 fprintf(fd
, "%02x ", str
[i
]);
433 for (i
= 0; i
< len
; i
++)
434 fprintf(fd
, "%c", isprint(str
[i
]) ? str
[i
] : '.');
438 static inline int print_value(FILE *fd
, int type
, struct rtattr
*rta
)
441 fprintf(stderr
, "Missing value TLV\n");
446 case TCF_META_TYPE_INT
:
447 if (RTA_PAYLOAD(rta
) < sizeof(__u32
)) {
448 fprintf(stderr
, "meta int type value TLV " \
452 fprintf(fd
, "%d", *(__u32
*) RTA_DATA(rta
));
455 case TCF_META_TYPE_VAR
:
456 print_binary(fd
, RTA_DATA(rta
), RTA_PAYLOAD(rta
));
463 static int print_object(FILE *fd
, struct tcf_meta_val
*obj
, struct rtattr
*rta
)
465 int id
= TCF_META_ID(obj
->kind
);
466 int type
= TCF_META_TYPE(obj
->kind
);
467 struct meta_entry
*entry
;
469 if (id
== TCF_META_ID_VALUE
)
470 return print_value(fd
, type
, rta
);
472 entry
= lookup_meta_entry_byid(id
);
475 fprintf(fd
, "[unknown meta id %d]", id
);
477 fprintf(fd
, "%s", entry
->kind
);
480 fprintf(fd
, " shift %d", obj
->shift
);
483 case TCF_META_TYPE_INT
:
485 if (RTA_PAYLOAD(rta
) < sizeof(__u32
))
488 fprintf(fd
, " mask 0x%08x",
489 *(__u32
*) RTA_DATA(rta
));
497 fprintf(stderr
, "meta int type mask TLV size mismatch\n");
502 static int meta_print_eopt(FILE *fd
, struct tcf_ematch_hdr
*hdr
, void *data
,
505 struct rtattr
*tb
[TCA_EM_META_MAX
+1];
506 struct tcf_meta_hdr
*meta_hdr
;
508 if (parse_rtattr(tb
, TCA_EM_META_MAX
, data
, data_len
) < 0)
511 if (tb
[TCA_EM_META_HDR
] == NULL
) {
512 fprintf(stderr
, "Missing meta header\n");
516 if (RTA_PAYLOAD(tb
[TCA_EM_META_HDR
]) < sizeof(*meta_hdr
)) {
517 fprintf(stderr
, "Meta header size mismatch\n");
521 meta_hdr
= RTA_DATA(tb
[TCA_EM_META_HDR
]);
523 if (print_object(fd
, &meta_hdr
->left
, tb
[TCA_EM_META_LVALUE
]) < 0)
526 switch (meta_hdr
->left
.op
) {
538 return print_object(fd
, &meta_hdr
->right
, tb
[TCA_EM_META_RVALUE
]);
541 struct ematch_util meta_ematch_util
= {
543 .kind_num
= TCF_EM_META
,
544 .parse_eopt
= meta_parse_eopt
,
545 .print_eopt
= meta_print_eopt
,
546 .print_usage
= meta_print_usage