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