• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lib/route/cls/ematch_syntax.y	ematch expression syntax
3  *
4  *	This library is free software; you can redistribute it and/or
5  *	modify it under the terms of the GNU Lesser General Public
6  *	License as published by the Free Software Foundation version 2.1
7  *	of the License.
8  *
9  * Copyright (c) 2010-2013 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 %{
13 #include <netlink-private/netlink.h>
14 #include <netlink-private/tc.h>
15 #include <netlink/netlink.h>
16 #include <netlink/utils.h>
17 #include <netlink/route/pktloc.h>
18 #include <netlink/route/cls/ematch.h>
19 #include <netlink/route/cls/ematch/cmp.h>
20 #include <netlink/route/cls/ematch/nbyte.h>
21 #include <netlink/route/cls/ematch/text.h>
22 #include <netlink/route/cls/ematch/meta.h>
23 
24 #define META_ALLOC rtnl_meta_value_alloc_id
25 #define META_ID(name) TCF_META_ID_##name
26 #define META_INT TCF_META_TYPE_INT
27 #define META_VAR TCF_META_TYPE_VAR
28 %}
29 
30 %error-verbose
31 %define api.pure
32 %name-prefix "ematch_"
33 
34 %parse-param {void *scanner}
35 %parse-param {char **errp}
36 %parse-param {struct nl_list_head *root}
37 %lex-param {void *scanner}
38 
39 %union {
40 	struct tcf_em_cmp	cmp;
41 	struct ematch_quoted	q;
42 	struct rtnl_ematch *	e;
43 	struct rtnl_pktloc *	loc;
44 	struct rtnl_meta_value *mv;
45 	uint32_t		i;
46 	uint64_t		i64;
47 	char *			s;
48 }
49 
50 %{
51 extern int ematch_lex(YYSTYPE *, void *);
52 
53 static void yyerror(void *scanner, char **errp, struct nl_list_head *root, const char *msg)
54 {
55 	if (msg)
56             *errp = strdup(msg);
57         else
58 	    *errp = NULL;
59 }
60 %}
61 
62 %token <i> ERROR LOGIC NOT OPERAND NUMBER ALIGN LAYER
63 %token <i> KW_OPEN "("
64 %token <i> KW_CLOSE ")"
65 %token <i> KW_PLUS "+"
66 %token <i> KW_MASK "mask"
67 %token <i> KW_SHIFT ">>"
68 %token <i> KW_AT "at"
69 %token <i> EMATCH_CMP "cmp"
70 %token <i> EMATCH_NBYTE "pattern"
71 %token <i> EMATCH_TEXT "text"
72 %token <i> EMATCH_META "meta"
73 %token <i> KW_EQ "="
74 %token <i> KW_GT ">"
75 %token <i> KW_LT "<"
76 %token <i> KW_FROM "from"
77 %token <i> KW_TO "to"
78 
79 %token <i> META_RANDOM "random"
80 %token <i> META_LOADAVG_0 "loadavg_0"
81 %token <i> META_LOADAVG_1 "loadavg_1"
82 %token <i> META_LOADAVG_2 "loadavg_2"
83 %token <i> META_DEV "dev"
84 %token <i> META_PRIO "prio"
85 %token <i> META_PROTO "proto"
86 %token <i> META_PKTTYPE "pkttype"
87 %token <i> META_PKTLEN "pktlen"
88 %token <i> META_DATALEN "datalen"
89 %token <i> META_MACLEN "maclen"
90 %token <i> META_MARK "mark"
91 %token <i> META_TCINDEX "tcindex"
92 %token <i> META_RTCLASSID "rtclassid"
93 %token <i> META_RTIIF "rtiif"
94 %token <i> META_SK_FAMILY "sk_family"
95 %token <i> META_SK_STATE "sk_state"
96 %token <i> META_SK_REUSE "sk_reuse"
97 %token <i> META_SK_REFCNT "sk_refcnt"
98 %token <i> META_SK_RCVBUF "sk_rcvbuf"
99 %token <i> META_SK_SNDBUF "sk_sndbuf"
100 %token <i> META_SK_SHUTDOWN "sk_shutdown"
101 %token <i> META_SK_PROTO "sk_proto"
102 %token <i> META_SK_TYPE "sk_type"
103 %token <i> META_SK_RMEM_ALLOC "sk_rmem_alloc"
104 %token <i> META_SK_WMEM_ALLOC "sk_wmem_alloc"
105 %token <i> META_SK_WMEM_QUEUED "sk_wmem_queued"
106 %token <i> META_SK_RCV_QLEN "sk_rcv_qlen"
107 %token <i> META_SK_SND_QLEN "sk_snd_qlen"
108 %token <i> META_SK_ERR_QLEN "sk_err_qlen"
109 %token <i> META_SK_FORWARD_ALLOCS "sk_forward_allocs"
110 %token <i> META_SK_ALLOCS "sk_allocs"
111 %token <i> META_SK_ROUTE_CAPS "sk_route_caps"
112 %token <i> META_SK_HASH "sk_hash"
113 %token <i> META_SK_LINGERTIME "sk_lingertime"
114 %token <i> META_SK_ACK_BACKLOG "sk_ack_backlog"
115 %token <i> META_SK_MAX_ACK_BACKLOG "sk_max_ack_backlog"
116 %token <i> META_SK_PRIO "sk_prio"
117 %token <i> META_SK_RCVLOWAT "sk_rcvlowat"
118 %token <i> META_SK_RCVTIMEO "sk_rcvtimeo"
119 %token <i> META_SK_SNDTIMEO "sk_sndtimeo"
120 %token <i> META_SK_SENDMSG_OFF "sk_sendmsg_off"
121 %token <i> META_SK_WRITE_PENDING "sk_write_pending"
122 %token <i> META_VLAN "vlan"
123 %token <i> META_RXHASH "rxhash"
124 %token <i> META_DEVNAME "devname"
125 %token <i> META_SK_BOUND_IF "sk_bound_if"
126 
127 %token <s> STR
128 
129 %token <q> QUOTED
130 
131 %type <i> align operand shift meta_int_id meta_var_id
132 %type <i64> mask
133 %type <e> expr match ematch
134 %type <cmp> cmp_expr cmp_match
135 %type <loc> pktloc text_from text_to
136 %type <q> pattern
137 %type <mv> meta_value
138 
139 %destructor { free($$); NL_DBG(2, "string destructor\n"); } <s>
140 %destructor { rtnl_pktloc_put($$); NL_DBG(2, "pktloc destructor\n"); } <loc>
141 %destructor { free($$.data); NL_DBG(2, "quoted destructor\n"); } <q>
142 %destructor { rtnl_meta_value_put($$); NL_DBG(2, "meta value destructor\n"); } <mv>
143 
144 %start input
145 
146 %%
147 
148 input:
149 	/* empty */
150 	| expr
151 		{
152 			nl_list_add_tail(root, &$1->e_list);
153 		}
154 	;
155 
156 expr:
157 	match
158 		{
159 			$$ = $1;
160 		}
161 	| match LOGIC expr
162 		{
163 			rtnl_ematch_set_flags($1, $2);
164 
165 			/* make ematch new head */
166 			nl_list_add_tail(&$1->e_list, &$3->e_list);
167 
168 			$$ = $1;
169 		}
170 	;
171 
172 match:
173 	NOT ematch
174 		{
175 			rtnl_ematch_set_flags($2, TCF_EM_INVERT);
176 			$$ = $2;
177 		}
178 	| ematch
179 		{
180 			$$ = $1;
181 		}
182 	;
183 
184 ematch:
185 	/* CMP */
186 	cmp_match
187 		{
188 			struct rtnl_ematch *e;
189 
190 			if (!(e = rtnl_ematch_alloc())) {
191 				*errp = strdup("Unable to allocate ematch object");
192 				YYABORT;
193 			}
194 
195 			if (rtnl_ematch_set_kind(e, TCF_EM_CMP) < 0)
196 				BUG();
197 
198 			rtnl_ematch_cmp_set(e, &$1);
199 			$$ = e;
200 		}
201 	| EMATCH_NBYTE "(" pktloc KW_EQ pattern ")"
202 		{
203 			struct rtnl_ematch *e;
204 
205 			if (!(e = rtnl_ematch_alloc())) {
206 				*errp = strdup("Unable to allocate ematch object");
207 				YYABORT;
208 			}
209 
210 			if (rtnl_ematch_set_kind(e, TCF_EM_NBYTE) < 0)
211 				BUG();
212 
213 			rtnl_ematch_nbyte_set_offset(e, $3->layer, $3->offset);
214 			rtnl_pktloc_put($3);
215 			rtnl_ematch_nbyte_set_pattern(e, (uint8_t *) $5.data, $5.index);
216 
217 			$$ = e;
218 		}
219 	| EMATCH_TEXT "(" STR QUOTED text_from text_to ")"
220 		{
221 			struct rtnl_ematch *e;
222 
223 			if (!(e = rtnl_ematch_alloc())) {
224 				*errp = strdup("Unable to allocate ematch object");
225 				YYABORT;
226 			}
227 
228 			if (rtnl_ematch_set_kind(e, TCF_EM_TEXT) < 0)
229 				BUG();
230 
231 			rtnl_ematch_text_set_algo(e, $3);
232 			rtnl_ematch_text_set_pattern(e, $4.data, $4.index);
233 
234 			if ($5) {
235 				rtnl_ematch_text_set_from(e, $5->layer, $5->offset);
236 				rtnl_pktloc_put($5);
237 			}
238 
239 			if ($6) {
240 				rtnl_ematch_text_set_to(e, $6->layer, $6->offset);
241 				rtnl_pktloc_put($6);
242 			}
243 
244 			$$ = e;
245 		}
246 	| EMATCH_META "(" meta_value operand meta_value ")"
247 		{
248 			struct rtnl_ematch *e;
249 
250 			if (!(e = rtnl_ematch_alloc())) {
251 				*errp = strdup("Unable to allocate ematch object");
252 				YYABORT;
253 			}
254 
255 			if (rtnl_ematch_set_kind(e, TCF_EM_META) < 0)
256 				BUG();
257 
258 			rtnl_ematch_meta_set_lvalue(e, $3);
259 			rtnl_ematch_meta_set_rvalue(e, $5);
260 			rtnl_ematch_meta_set_operand(e, $4);
261 
262 			$$ = e;
263 		}
264 	/* CONTAINER */
265 	| "(" expr ")"
266 		{
267 			struct rtnl_ematch *e;
268 
269 			if (!(e = rtnl_ematch_alloc())) {
270 				*errp = strdup("Unable to allocate ematch object");
271 				YYABORT;
272 			}
273 
274 			if (rtnl_ematch_set_kind(e, TCF_EM_CONTAINER) < 0)
275 				BUG();
276 
277 			/* Make e->childs the list head of a the ematch sequence */
278 			nl_list_add_tail(&e->e_childs, &$2->e_list);
279 
280 			$$ = e;
281 		}
282 	;
283 
284 /*
285  * CMP match
286  *
287  * match  := cmp(expr) | expr
288  * expr   := pktloc (=|>|<) NUMBER
289  * pktloc := alias | definition
290  *
291  */
292 cmp_match:
293 	EMATCH_CMP "(" cmp_expr ")"
294 		{ $$ = $3; }
295 	| cmp_expr
296 		{ $$ = $1; }
297 	;
298 
299 cmp_expr:
300 	pktloc operand NUMBER
301 		{
302 			if ($1->align == TCF_EM_ALIGN_U16 ||
303 			    $1->align == TCF_EM_ALIGN_U32)
304 				$$.flags = TCF_EM_CMP_TRANS;
305 
306 			memset(&$$, 0, sizeof($$));
307 
308 			$$.mask = $1->mask;
309 			$$.off = $1->offset;
310 			$$.align = $1->align;
311 			$$.layer = $1->layer;
312 			$$.opnd = $2;
313 			$$.val = $3;
314 
315 			rtnl_pktloc_put($1);
316 		}
317 	;
318 
319 text_from:
320 	/* empty */
321 		{ $$ = NULL; }
322 	| "from" pktloc
323 		{ $$ = $2; }
324 	;
325 
326 text_to:
327 	/* empty */
328 		{ $$ = NULL; }
329 	| "to" pktloc
330 		{ $$ = $2; }
331 	;
332 
333 meta_value:
334 	QUOTED
335 		{ $$ = rtnl_meta_value_alloc_var($1.data, $1.len); }
336 	| NUMBER
337 		{ $$ = rtnl_meta_value_alloc_int($1); }
338 	| meta_int_id shift mask
339 		{ $$ = META_ALLOC(META_INT, $1, $2, $3); }
340 	| meta_var_id shift
341 		{ $$ = META_ALLOC(META_VAR, $1, $2, 0); }
342 	;
343 
344 meta_int_id:
345 	META_RANDOM			{ $$ = META_ID(RANDOM); }
346 	|META_LOADAVG_0			{ $$ = META_ID(LOADAVG_0); }
347 	|META_LOADAVG_1			{ $$ = META_ID(LOADAVG_1); }
348 	|META_LOADAVG_2			{ $$ = META_ID(LOADAVG_2); }
349 	| META_DEV			{ $$ = META_ID(DEV); }
350 	| META_PRIO			{ $$ = META_ID(PRIORITY); }
351 	| META_PROTO			{ $$ = META_ID(PROTOCOL); }
352 	| META_PKTTYPE			{ $$ = META_ID(PKTTYPE); }
353 	| META_PKTLEN			{ $$ = META_ID(PKTLEN); }
354 	| META_DATALEN			{ $$ = META_ID(DATALEN); }
355 	| META_MACLEN			{ $$ = META_ID(MACLEN); }
356 	| META_MARK			{ $$ = META_ID(NFMARK); }
357 	| META_TCINDEX			{ $$ = META_ID(TCINDEX); }
358 	| META_RTCLASSID		{ $$ = META_ID(RTCLASSID); }
359 	| META_RTIIF			{ $$ = META_ID(RTIIF); }
360 	| META_SK_FAMILY		{ $$ = META_ID(SK_FAMILY); }
361 	| META_SK_STATE			{ $$ = META_ID(SK_STATE); }
362 	| META_SK_REUSE			{ $$ = META_ID(SK_REUSE); }
363 	| META_SK_REFCNT		{ $$ = META_ID(SK_REFCNT); }
364 	| META_SK_RCVBUF		{ $$ = META_ID(SK_RCVBUF); }
365 	| META_SK_SNDBUF		{ $$ = META_ID(SK_SNDBUF); }
366 	| META_SK_SHUTDOWN		{ $$ = META_ID(SK_SHUTDOWN); }
367 	| META_SK_PROTO			{ $$ = META_ID(SK_PROTO); }
368 	| META_SK_TYPE			{ $$ = META_ID(SK_TYPE); }
369 	| META_SK_RMEM_ALLOC		{ $$ = META_ID(SK_RMEM_ALLOC); }
370 	| META_SK_WMEM_ALLOC		{ $$ = META_ID(SK_WMEM_ALLOC); }
371 	| META_SK_WMEM_QUEUED		{ $$ = META_ID(SK_WMEM_QUEUED); }
372 	| META_SK_RCV_QLEN		{ $$ = META_ID(SK_RCV_QLEN); }
373 	| META_SK_SND_QLEN		{ $$ = META_ID(SK_SND_QLEN); }
374 	| META_SK_ERR_QLEN		{ $$ = META_ID(SK_ERR_QLEN); }
375 	| META_SK_FORWARD_ALLOCS	{ $$ = META_ID(SK_FORWARD_ALLOCS); }
376 	| META_SK_ALLOCS		{ $$ = META_ID(SK_ALLOCS); }
377 	| META_SK_ROUTE_CAPS		{ $$ = META_ID(SK_ROUTE_CAPS); }
378 	| META_SK_HASH			{ $$ = META_ID(SK_HASH); }
379 	| META_SK_LINGERTIME		{ $$ = META_ID(SK_LINGERTIME); }
380 	| META_SK_ACK_BACKLOG		{ $$ = META_ID(SK_ACK_BACKLOG); }
381 	| META_SK_MAX_ACK_BACKLOG	{ $$ = META_ID(SK_MAX_ACK_BACKLOG); }
382 	| META_SK_PRIO			{ $$ = META_ID(SK_PRIO); }
383 	| META_SK_RCVLOWAT		{ $$ = META_ID(SK_RCVLOWAT); }
384 	| META_SK_RCVTIMEO		{ $$ = META_ID(SK_RCVTIMEO); }
385 	| META_SK_SNDTIMEO		{ $$ = META_ID(SK_SNDTIMEO); }
386 	| META_SK_SENDMSG_OFF		{ $$ = META_ID(SK_SENDMSG_OFF); }
387 	| META_SK_WRITE_PENDING		{ $$ = META_ID(SK_WRITE_PENDING); }
388 	| META_VLAN			{ $$ = META_ID(VLAN_TAG); }
389 	| META_RXHASH			{ $$ = META_ID(RXHASH); }
390 	;
391 
392 meta_var_id:
393 	META_DEVNAME		{ $$ = META_ID(DEV); }
394 	| META_SK_BOUND_IF	{ $$ = META_ID(SK_BOUND_IF); }
395 	;
396 
397 /*
398  * pattern
399  */
400 pattern:
401 	QUOTED
402 		{
403 			$$ = $1;
404 		}
405 	| STR
406 		{
407 			struct nl_addr *addr;
408 
409 			if (nl_addr_parse($1, AF_UNSPEC, &addr) == 0) {
410 				$$.len = nl_addr_get_len(addr);
411 
412 				$$.index = min_t(int, $$.len, nl_addr_get_prefixlen(addr)/8);
413 
414 				if (!($$.data = calloc(1, $$.len))) {
415 					nl_addr_put(addr);
416 					YYABORT;
417 				}
418 
419 				memcpy($$.data, nl_addr_get_binary_addr(addr), $$.len);
420 				nl_addr_put(addr);
421 			} else {
422 				if (asprintf(errp, "invalid pattern \"%s\"", $1) == -1)
423 					*errp = NULL;
424 				YYABORT;
425 			}
426 		}
427 	;
428 
429 /*
430  * packet location
431  */
432 
433 pktloc:
434 	STR
435 		{
436 			struct rtnl_pktloc *loc;
437 
438 			if (rtnl_pktloc_lookup($1, &loc) < 0) {
439 				if (asprintf(errp, "Packet location \"%s\" not found", $1) == -1)
440 					*errp = NULL;
441 				YYABORT;
442 			}
443 
444 			$$ = loc;
445 		}
446 	/* [u8|u16|u32|NUM at] LAYER + OFFSET [mask MASK] */
447 	| align LAYER "+" NUMBER mask
448 		{
449 			struct rtnl_pktloc *loc;
450 
451 			if ($5 && (!$1 || $1 > TCF_EM_ALIGN_U32)) {
452 				*errp = strdup("mask only allowed for alignments u8|u16|u32");
453 				YYABORT;
454 			}
455 
456 			if (!(loc = rtnl_pktloc_alloc())) {
457 				*errp = strdup("Unable to allocate packet location object");
458 				YYABORT;
459 			}
460 
461 			loc->name = strdup("<USER-DEFINED>");
462 			loc->align = $1;
463 			loc->layer = $2;
464 			loc->offset = $4;
465 			loc->mask = $5;
466 
467 			$$ = loc;
468 		}
469 	;
470 
471 align:
472 	/* empty */
473 		{ $$ = 0; }
474 	| ALIGN "at"
475 		{ $$ = $1; }
476 	| NUMBER "at"
477 		{ $$ = $1; }
478 	;
479 
480 mask:
481 	/* empty */
482 		{ $$ = 0; }
483 	| KW_MASK NUMBER
484 		{ $$ = $2; }
485 	;
486 
487 shift:
488 	/* empty */
489 		{ $$ = 0; }
490 	| KW_SHIFT NUMBER
491 		{ $$ = $2; }
492 	;
493 
494 operand:
495 	KW_EQ
496 		{ $$ = TCF_EM_OPND_EQ; }
497 	| KW_GT
498 		{ $$ = TCF_EM_OPND_GT; }
499 	| KW_LT
500 		{ $$ = TCF_EM_OPND_LT; }
501 	;
502