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