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