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