Home | History | Annotate | Download | only in cls
      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 (at) 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