1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2021 NVIDIA Corporation & Affiliates 3 */ 4 5 #include <stddef.h> 6 #include <stdint.h> 7 #include <stdio.h> 8 #include <errno.h> 9 #include <string.h> 10 11 #include <rte_common.h> 12 #include <rte_ethdev.h> 13 #include <cmdline_parse.h> 14 #include <cmdline_parse_string.h> 15 #include <cmdline_parse_num.h> 16 #include <rte_flow.h> 17 18 #include "testpmd.h" 19 20 struct flex_item *flex_items[RTE_MAX_ETHPORTS][FLEX_MAX_PARSERS_NUM]; 21 struct flex_pattern flex_patterns[FLEX_MAX_PATTERNS_NUM]; 22 23 static struct flex_item * 24 flex_parser_fetch(uint16_t port_id, uint16_t flex_id) 25 { 26 if (port_id >= RTE_MAX_ETHPORTS) { 27 printf("Invalid port_id: %u\n", port_id); 28 return FLEX_PARSER_ERR; 29 } 30 if (flex_id >= FLEX_MAX_PARSERS_NUM) { 31 printf("Invalid flex item flex_id: %u\n", flex_id); 32 return FLEX_PARSER_ERR; 33 } 34 return flex_items[port_id][flex_id]; 35 } 36 37 #ifdef RTE_HAS_JANSSON 38 static __rte_always_inline bool 39 match_strkey(const char *key, const char *pattern) 40 { 41 return strncmp(key, pattern, strlen(key)) == 0; 42 } 43 44 static int 45 flex_tunnel_parse(json_t *jtun, enum rte_flow_item_flex_tunnel_mode *tunnel) 46 { 47 int tun = -1; 48 49 if (json_is_integer(jtun)) 50 tun = (int)json_integer_value(jtun); 51 else if (json_is_real(jtun)) 52 tun = (int)json_real_value(jtun); 53 else if (json_is_string(jtun)) { 54 const char *mode = json_string_value(jtun); 55 56 if (match_strkey(mode, "FLEX_TUNNEL_MODE_SINGLE")) 57 tun = FLEX_TUNNEL_MODE_SINGLE; 58 else if (match_strkey(mode, "FLEX_TUNNEL_MODE_OUTER")) 59 tun = FLEX_TUNNEL_MODE_OUTER; 60 else if (match_strkey(mode, "FLEX_TUNNEL_MODE_INNER")) 61 tun = FLEX_TUNNEL_MODE_INNER; 62 else if (match_strkey(mode, "FLEX_TUNNEL_MODE_MULTI")) 63 tun = FLEX_TUNNEL_MODE_MULTI; 64 else if (match_strkey(mode, "FLEX_TUNNEL_MODE_TUNNEL")) 65 tun = FLEX_TUNNEL_MODE_TUNNEL; 66 else 67 return -EINVAL; 68 } else 69 return -EINVAL; 70 *tunnel = (enum rte_flow_item_flex_tunnel_mode)tun; 71 return 0; 72 } 73 74 static int 75 flex_field_parse(json_t *jfld, struct rte_flow_item_flex_field *fld) 76 { 77 const char *key; 78 json_t *je; 79 80 #define FLEX_FIELD_GET(fm, t) \ 81 do { \ 82 if (!strncmp(key, # fm, strlen(# fm))) { \ 83 if (json_is_real(je)) \ 84 fld->fm = (t) json_real_value(je); \ 85 else if (json_is_integer(je)) \ 86 fld->fm = (t) json_integer_value(je); \ 87 else \ 88 return -EINVAL; \ 89 } \ 90 } while (0) 91 92 json_object_foreach(jfld, key, je) { 93 FLEX_FIELD_GET(field_size, uint32_t); 94 FLEX_FIELD_GET(field_base, int32_t); 95 FLEX_FIELD_GET(offset_base, uint32_t); 96 FLEX_FIELD_GET(offset_mask, uint32_t); 97 FLEX_FIELD_GET(offset_shift, int32_t); 98 FLEX_FIELD_GET(field_id, uint16_t); 99 if (match_strkey(key, "field_mode")) { 100 const char *mode; 101 if (!json_is_string(je)) 102 return -EINVAL; 103 mode = json_string_value(je); 104 if (match_strkey(mode, "FIELD_MODE_DUMMY")) 105 fld->field_mode = FIELD_MODE_DUMMY; 106 else if (match_strkey(mode, "FIELD_MODE_FIXED")) 107 fld->field_mode = FIELD_MODE_FIXED; 108 else if (match_strkey(mode, "FIELD_MODE_OFFSET")) 109 fld->field_mode = FIELD_MODE_OFFSET; 110 else if (match_strkey(mode, "FIELD_MODE_BITMASK")) 111 fld->field_mode = FIELD_MODE_BITMASK; 112 else 113 return -EINVAL; 114 } 115 } 116 return 0; 117 } 118 119 enum flex_link_type { 120 FLEX_LINK_IN = 0, 121 FLEX_LINK_OUT = 1 122 }; 123 124 static int 125 flex_link_item_parse(const char *src, struct rte_flow_item *item) 126 { 127 #define FLEX_PARSE_DATA_SIZE 1024 128 129 int ret; 130 uint8_t *ptr, data[FLEX_PARSE_DATA_SIZE] = {0,}; 131 char flow_rule[256]; 132 struct rte_flow_attr *attr; 133 struct rte_flow_item *pattern; 134 struct rte_flow_action *actions; 135 136 sprintf(flow_rule, 137 "flow create 0 pattern %s / end actions drop / end", src); 138 src = flow_rule; 139 ret = flow_parse(src, (void *)data, sizeof(data), 140 &attr, &pattern, &actions); 141 if (ret) 142 return ret; 143 item->type = pattern->type; 144 if (pattern->spec) { 145 ptr = (void *)(uintptr_t)item->spec; 146 memcpy(ptr, pattern->spec, FLEX_MAX_FLOW_PATTERN_LENGTH); 147 } else { 148 item->spec = NULL; 149 } 150 if (pattern->mask) { 151 ptr = (void *)(uintptr_t)item->mask; 152 memcpy(ptr, pattern->mask, FLEX_MAX_FLOW_PATTERN_LENGTH); 153 } else { 154 item->mask = NULL; 155 } 156 if (pattern->last) { 157 ptr = (void *)(uintptr_t)item->last; 158 memcpy(ptr, pattern->last, FLEX_MAX_FLOW_PATTERN_LENGTH); 159 } else { 160 item->last = NULL; 161 } 162 return 0; 163 } 164 165 static int 166 flex_link_parse(json_t *jobj, struct rte_flow_item_flex_link *link, 167 enum flex_link_type link_type) 168 { 169 const char *key; 170 json_t *je; 171 int ret; 172 json_object_foreach(jobj, key, je) { 173 if (match_strkey(key, "item")) { 174 if (!json_is_string(je)) 175 return -EINVAL; 176 ret = flex_link_item_parse(json_string_value(je), 177 &link->item); 178 if (ret) 179 return -EINVAL; 180 if (link_type == FLEX_LINK_IN) { 181 if (!link->item.spec || !link->item.mask) 182 return -EINVAL; 183 if (link->item.last) 184 return -EINVAL; 185 } 186 } 187 if (match_strkey(key, "next")) { 188 if (json_is_integer(je)) 189 link->next = (typeof(link->next)) 190 json_integer_value(je); 191 else if (json_is_real(je)) 192 link->next = (typeof(link->next)) 193 json_real_value(je); 194 else 195 return -EINVAL; 196 } 197 } 198 return 0; 199 } 200 201 static int flex_item_config(json_t *jroot, 202 struct rte_flow_item_flex_conf *flex_conf) 203 { 204 const char *key; 205 json_t *jobj = NULL; 206 int ret = 0; 207 208 json_object_foreach(jroot, key, jobj) { 209 if (match_strkey(key, "tunnel")) { 210 ret = flex_tunnel_parse(jobj, &flex_conf->tunnel); 211 if (ret) { 212 printf("Can't parse tunnel value\n"); 213 goto out; 214 } 215 } else if (match_strkey(key, "next_header")) { 216 ret = flex_field_parse(jobj, &flex_conf->next_header); 217 if (ret) { 218 printf("Can't parse next_header field\n"); 219 goto out; 220 } 221 } else if (match_strkey(key, "next_protocol")) { 222 ret = flex_field_parse(jobj, 223 &flex_conf->next_protocol); 224 if (ret) { 225 printf("Can't parse next_protocol field\n"); 226 goto out; 227 } 228 } else if (match_strkey(key, "sample_data")) { 229 json_t *ji; 230 uint32_t i, size = json_array_size(jobj); 231 for (i = 0; i < size; i++) { 232 ji = json_array_get(jobj, i); 233 ret = flex_field_parse 234 (ji, flex_conf->sample_data + i); 235 if (ret) { 236 printf("Can't parse sample_data field(s)\n"); 237 goto out; 238 } 239 } 240 flex_conf->nb_samples = size; 241 } else if (match_strkey(key, "input_link")) { 242 json_t *ji; 243 uint32_t i, size = json_array_size(jobj); 244 for (i = 0; i < size; i++) { 245 ji = json_array_get(jobj, i); 246 ret = flex_link_parse(ji, 247 flex_conf->input_link + i, 248 FLEX_LINK_IN); 249 if (ret) { 250 printf("Can't parse input_link(s)\n"); 251 goto out; 252 } 253 } 254 flex_conf->nb_inputs = size; 255 } else if (match_strkey(key, "output_link")) { 256 json_t *ji; 257 uint32_t i, size = json_array_size(jobj); 258 for (i = 0; i < size; i++) { 259 ji = json_array_get(jobj, i); 260 ret = flex_link_parse 261 (ji, flex_conf->output_link + i, 262 FLEX_LINK_OUT); 263 if (ret) { 264 printf("Can't parse output_link(s)\n"); 265 goto out; 266 } 267 } 268 flex_conf->nb_outputs = size; 269 } 270 } 271 out: 272 return ret; 273 } 274 275 static struct flex_item * 276 flex_item_init(void) 277 { 278 size_t base_size, samples_size, links_size, spec_size; 279 struct rte_flow_item_flex_conf *conf; 280 struct flex_item *fp; 281 uint8_t (*pattern)[FLEX_MAX_FLOW_PATTERN_LENGTH]; 282 int i; 283 284 base_size = RTE_ALIGN(sizeof(*conf), sizeof(uintptr_t)); 285 samples_size = RTE_ALIGN(FLEX_ITEM_MAX_SAMPLES_NUM * 286 sizeof(conf->sample_data[0]), 287 sizeof(uintptr_t)); 288 links_size = RTE_ALIGN(FLEX_ITEM_MAX_LINKS_NUM * 289 sizeof(conf->input_link[0]), 290 sizeof(uintptr_t)); 291 /* spec & mask for all input links */ 292 spec_size = 2 * FLEX_MAX_FLOW_PATTERN_LENGTH * FLEX_ITEM_MAX_LINKS_NUM; 293 fp = calloc(1, base_size + samples_size + 2 * links_size + spec_size); 294 if (fp == NULL) { 295 printf("Can't allocate memory for flex item\n"); 296 return NULL; 297 } 298 conf = &fp->flex_conf; 299 conf->sample_data = (typeof(conf->sample_data)) 300 ((uint8_t *)fp + base_size); 301 conf->input_link = (typeof(conf->input_link)) 302 ((uint8_t *)conf->sample_data + samples_size); 303 conf->output_link = (typeof(conf->output_link)) 304 ((uint8_t *)conf->input_link + links_size); 305 pattern = (typeof(pattern))((uint8_t *)conf->output_link + links_size); 306 for (i = 0; i < FLEX_ITEM_MAX_LINKS_NUM; i++) { 307 struct rte_flow_item_flex_link *in = conf->input_link + i; 308 in->item.spec = pattern++; 309 in->item.mask = pattern++; 310 } 311 return fp; 312 } 313 314 static int 315 flex_item_build_config(struct flex_item *fp, const char *filename) 316 { 317 int ret; 318 json_error_t json_error; 319 json_t *jroot = json_load_file(filename, 0, &json_error); 320 321 if (!jroot) { 322 printf("Bad JSON file \"%s\": %s\n", filename, json_error.text); 323 return -1; 324 } 325 ret = flex_item_config(jroot, &fp->flex_conf); 326 json_decref(jroot); 327 return ret; 328 } 329 330 void 331 flex_item_create(portid_t port_id, uint16_t flex_id, const char *filename) 332 { 333 struct rte_flow_error flow_error; 334 struct flex_item *fp = flex_parser_fetch(port_id, flex_id); 335 int ret; 336 337 if (fp == FLEX_PARSER_ERR) { 338 printf("Bad parameters: port_id=%u flex_id=%u\n", 339 port_id, flex_id); 340 return; 341 } 342 if (fp) { 343 printf("port-%u: flex item #%u is already in use\n", 344 port_id, flex_id); 345 return; 346 } 347 fp = flex_item_init(); 348 if (!fp) { 349 printf("Could not allocate flex item\n"); 350 goto out; 351 } 352 ret = flex_item_build_config(fp, filename); 353 if (ret) 354 goto out; 355 fp->flex_handle = rte_flow_flex_item_create(port_id, 356 &fp->flex_conf, 357 &flow_error); 358 if (fp->flex_handle) { 359 flex_items[port_id][flex_id] = fp; 360 printf("port-%u: created flex item #%u\n", port_id, flex_id); 361 fp = NULL; 362 } else { 363 printf("port-%u: flex item #%u creation failed: %s\n", 364 port_id, flex_id, 365 flow_error.message ? flow_error.message : ""); 366 } 367 out: 368 free(fp); 369 } 370 371 #else /* RTE_HAS_JANSSON */ 372 void flex_item_create(__rte_unused portid_t port_id, 373 __rte_unused uint16_t flex_id, 374 __rte_unused const char *filename) 375 { 376 printf("cannot create flex item - no JSON library configured\n"); 377 } 378 #endif /* RTE_HAS_JANSSON */ 379 380 void 381 flex_item_destroy(portid_t port_id, uint16_t flex_id) 382 { 383 int ret; 384 struct rte_flow_error error; 385 struct flex_item *fp = flex_parser_fetch(port_id, flex_id); 386 if (!flex_id) 387 return; 388 if (fp == FLEX_PARSER_ERR) { 389 printf("Bad parameters: port_id=%u flex_id=%u\n", 390 port_id, flex_id); 391 return; 392 } 393 if (!fp) 394 return; 395 ret = rte_flow_flex_item_release(port_id, fp->flex_handle, &error); 396 if (!ret) { 397 free(fp); 398 flex_items[port_id][flex_id] = NULL; 399 printf("port-%u: released flex item #%u\n", 400 port_id, flex_id); 401 402 } else { 403 printf("port-%u: cannot release flex item #%u: %s\n", 404 port_id, flex_id, error.message); 405 } 406 } 407 408 void 409 port_flex_item_flush(portid_t port_id) 410 { 411 uint16_t i; 412 413 for (i = 0; i < FLEX_MAX_PARSERS_NUM; i++) { 414 if (flex_items[port_id][i] != NULL) { 415 flex_item_destroy(port_id, i); 416 flex_items[port_id][i] = NULL; 417 } 418 } 419 } 420 421 struct flex_pattern_set { 422 cmdline_fixed_string_t set, flex_pattern; 423 cmdline_fixed_string_t is_spec, mask; 424 cmdline_fixed_string_t spec_data, mask_data; 425 uint16_t id; 426 }; 427 428 static cmdline_parse_token_string_t flex_pattern_set_token = 429 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, set, "set"); 430 static cmdline_parse_token_string_t flex_pattern_token = 431 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, 432 flex_pattern, "flex_pattern"); 433 static cmdline_parse_token_string_t flex_pattern_is_token = 434 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, 435 is_spec, "is"); 436 static cmdline_parse_token_string_t flex_pattern_spec_token = 437 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, 438 is_spec, "spec"); 439 static cmdline_parse_token_string_t flex_pattern_mask_token = 440 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, mask, "mask"); 441 static cmdline_parse_token_string_t flex_pattern_spec_data_token = 442 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, spec_data, NULL); 443 static cmdline_parse_token_string_t flex_pattern_mask_data_token = 444 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, mask_data, NULL); 445 static cmdline_parse_token_num_t flex_pattern_id_token = 446 TOKEN_NUM_INITIALIZER(struct flex_pattern_set, id, RTE_UINT16); 447 448 /* 449 * flex pattern data - spec or mask is a string representation of byte array 450 * in hexadecimal format. Each byte in data string must have 2 characters: 451 * 0x15 - "15" 452 * 0x1 - "01" 453 * Bytes in data array are in network order. 454 */ 455 static uint32_t 456 flex_pattern_data(const char *str, uint8_t *data) 457 { 458 uint32_t i, len = strlen(str); 459 char b[3], *endptr; 460 461 if (len & 01) 462 return 0; 463 len /= 2; 464 if (len >= FLEX_MAX_FLOW_PATTERN_LENGTH) 465 return 0; 466 for (i = 0, b[2] = '\0'; i < len; i++) { 467 b[0] = str[2 * i]; 468 b[1] = str[2 * i + 1]; 469 data[i] = strtoul(b, &endptr, 16); 470 if (endptr != &b[2]) 471 return 0; 472 } 473 return len; 474 } 475 476 static void 477 flex_pattern_parsed_fn(void *parsed_result, 478 __rte_unused struct cmdline *cl, 479 __rte_unused void *data) 480 { 481 struct flex_pattern_set *res = parsed_result; 482 struct flex_pattern *fp; 483 bool full_spec; 484 485 if (res->id >= FLEX_MAX_PATTERNS_NUM) { 486 printf("Bad flex pattern id\n"); 487 return; 488 } 489 fp = flex_patterns + res->id; 490 memset(fp->spec_pattern, 0, sizeof(fp->spec_pattern)); 491 memset(fp->mask_pattern, 0, sizeof(fp->mask_pattern)); 492 fp->spec.length = flex_pattern_data(res->spec_data, fp->spec_pattern); 493 if (!fp->spec.length) { 494 printf("Bad flex pattern spec\n"); 495 return; 496 } 497 full_spec = strncmp(res->is_spec, "spec", strlen("spec")) == 0; 498 if (full_spec) { 499 fp->mask.length = flex_pattern_data(res->mask_data, 500 fp->mask_pattern); 501 if (!fp->mask.length) { 502 printf("Bad flex pattern mask\n"); 503 return; 504 } 505 } else { 506 memset(fp->mask_pattern, 0xFF, fp->spec.length); 507 fp->mask.length = fp->spec.length; 508 } 509 if (fp->mask.length != fp->spec.length) { 510 printf("Spec length do not match mask length\n"); 511 return; 512 } 513 fp->spec.pattern = fp->spec_pattern; 514 fp->mask.pattern = fp->mask_pattern; 515 printf("created pattern #%u\n", res->id); 516 } 517 518 cmdline_parse_inst_t cmd_set_flex_is_pattern = { 519 .f = flex_pattern_parsed_fn, 520 .data = NULL, 521 .help_str = "set flex_pattern <id> is <spec_data>", 522 .tokens = { 523 (void *)&flex_pattern_set_token, 524 (void *)&flex_pattern_token, 525 (void *)&flex_pattern_id_token, 526 (void *)&flex_pattern_is_token, 527 (void *)&flex_pattern_spec_data_token, 528 NULL, 529 } 530 }; 531 532 cmdline_parse_inst_t cmd_set_flex_spec_pattern = { 533 .f = flex_pattern_parsed_fn, 534 .data = NULL, 535 .help_str = "set flex_pattern <id> spec <spec_data> mask <mask_data>", 536 .tokens = { 537 (void *)&flex_pattern_set_token, 538 (void *)&flex_pattern_token, 539 (void *)&flex_pattern_id_token, 540 (void *)&flex_pattern_spec_token, 541 (void *)&flex_pattern_spec_data_token, 542 (void *)&flex_pattern_mask_token, 543 (void *)&flex_pattern_mask_data_token, 544 NULL, 545 } 546 }; 547