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