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, "flow create 0 pattern %s / end", src); 137 src = flow_rule; 138 ret = flow_parse(src, (void *)data, sizeof(data), 139 &attr, &pattern, &actions); 140 if (ret) 141 return ret; 142 item->type = pattern->type; 143 if (pattern->spec) { 144 ptr = (void *)(uintptr_t)item->spec; 145 memcpy(ptr, pattern->spec, FLEX_MAX_FLOW_PATTERN_LENGTH); 146 } else { 147 item->spec = NULL; 148 } 149 if (pattern->mask) { 150 ptr = (void *)(uintptr_t)item->mask; 151 memcpy(ptr, pattern->mask, FLEX_MAX_FLOW_PATTERN_LENGTH); 152 } else { 153 item->mask = NULL; 154 } 155 if (pattern->last) { 156 ptr = (void *)(uintptr_t)item->last; 157 memcpy(ptr, pattern->last, FLEX_MAX_FLOW_PATTERN_LENGTH); 158 } else { 159 item->last = NULL; 160 } 161 return 0; 162 } 163 164 static int 165 flex_link_parse(json_t *jobj, struct rte_flow_item_flex_link *link, 166 enum flex_link_type link_type) 167 { 168 const char *key; 169 json_t *je; 170 int ret; 171 json_object_foreach(jobj, key, je) { 172 if (match_strkey(key, "item")) { 173 if (!json_is_string(je)) 174 return -EINVAL; 175 ret = flex_link_item_parse(json_string_value(je), 176 &link->item); 177 if (ret) 178 return -EINVAL; 179 if (link_type == FLEX_LINK_IN) { 180 if (!link->item.spec || !link->item.mask) 181 return -EINVAL; 182 if (link->item.last) 183 return -EINVAL; 184 } 185 } 186 if (match_strkey(key, "next")) { 187 if (json_is_integer(je)) 188 link->next = (typeof(link->next)) 189 json_integer_value(je); 190 else if (json_is_real(je)) 191 link->next = (typeof(link->next)) 192 json_real_value(je); 193 else 194 return -EINVAL; 195 } 196 } 197 return 0; 198 } 199 200 static int flex_item_config(json_t *jroot, 201 struct rte_flow_item_flex_conf *flex_conf) 202 { 203 const char *key; 204 json_t *jobj = NULL; 205 int ret = 0; 206 207 json_object_foreach(jroot, key, jobj) { 208 if (match_strkey(key, "tunnel")) { 209 ret = flex_tunnel_parse(jobj, &flex_conf->tunnel); 210 if (ret) { 211 printf("Can't parse tunnel value\n"); 212 goto out; 213 } 214 } else if (match_strkey(key, "next_header")) { 215 ret = flex_field_parse(jobj, &flex_conf->next_header); 216 if (ret) { 217 printf("Can't parse next_header field\n"); 218 goto out; 219 } 220 } else if (match_strkey(key, "next_protocol")) { 221 ret = flex_field_parse(jobj, 222 &flex_conf->next_protocol); 223 if (ret) { 224 printf("Can't parse next_protocol field\n"); 225 goto out; 226 } 227 } else if (match_strkey(key, "sample_data")) { 228 json_t *ji; 229 uint32_t i, size = json_array_size(jobj); 230 for (i = 0; i < size; i++) { 231 ji = json_array_get(jobj, i); 232 ret = flex_field_parse 233 (ji, flex_conf->sample_data + i); 234 if (ret) { 235 printf("Can't parse sample_data field(s)\n"); 236 goto out; 237 } 238 } 239 flex_conf->nb_samples = size; 240 } else if (match_strkey(key, "input_link")) { 241 json_t *ji; 242 uint32_t i, size = json_array_size(jobj); 243 for (i = 0; i < size; i++) { 244 ji = json_array_get(jobj, i); 245 ret = flex_link_parse(ji, 246 flex_conf->input_link + i, 247 FLEX_LINK_IN); 248 if (ret) { 249 printf("Can't parse input_link(s)\n"); 250 goto out; 251 } 252 } 253 flex_conf->nb_inputs = size; 254 } else if (match_strkey(key, "output_link")) { 255 json_t *ji; 256 uint32_t i, size = json_array_size(jobj); 257 for (i = 0; i < size; i++) { 258 ji = json_array_get(jobj, i); 259 ret = flex_link_parse 260 (ji, flex_conf->output_link + i, 261 FLEX_LINK_OUT); 262 if (ret) { 263 printf("Can't parse output_link(s)\n"); 264 goto out; 265 } 266 } 267 flex_conf->nb_outputs = size; 268 } 269 } 270 out: 271 return ret; 272 } 273 274 static struct flex_item * 275 flex_item_init(void) 276 { 277 size_t base_size, samples_size, links_size, spec_size; 278 struct rte_flow_item_flex_conf *conf; 279 struct flex_item *fp; 280 uint8_t (*pattern)[FLEX_MAX_FLOW_PATTERN_LENGTH]; 281 int i; 282 283 base_size = RTE_ALIGN(sizeof(*conf), sizeof(uintptr_t)); 284 samples_size = RTE_ALIGN(FLEX_ITEM_MAX_SAMPLES_NUM * 285 sizeof(conf->sample_data[0]), 286 sizeof(uintptr_t)); 287 links_size = RTE_ALIGN(FLEX_ITEM_MAX_LINKS_NUM * 288 sizeof(conf->input_link[0]), 289 sizeof(uintptr_t)); 290 /* spec & mask for all input links */ 291 spec_size = 2 * FLEX_MAX_FLOW_PATTERN_LENGTH * FLEX_ITEM_MAX_LINKS_NUM; 292 fp = calloc(1, base_size + samples_size + 2 * links_size + spec_size); 293 if (fp == NULL) { 294 printf("Can't allocate memory for flex item\n"); 295 return NULL; 296 } 297 conf = &fp->flex_conf; 298 conf->sample_data = (typeof(conf->sample_data)) 299 ((uint8_t *)fp + base_size); 300 conf->input_link = (typeof(conf->input_link)) 301 ((uint8_t *)conf->sample_data + samples_size); 302 conf->output_link = (typeof(conf->output_link)) 303 ((uint8_t *)conf->input_link + links_size); 304 pattern = (typeof(pattern))((uint8_t *)conf->output_link + links_size); 305 for (i = 0; i < FLEX_ITEM_MAX_LINKS_NUM; i++) { 306 struct rte_flow_item_flex_link *in = conf->input_link + i; 307 in->item.spec = pattern++; 308 in->item.mask = pattern++; 309 } 310 return fp; 311 } 312 313 static int 314 flex_item_build_config(struct flex_item *fp, const char *filename) 315 { 316 int ret; 317 json_error_t json_error; 318 json_t *jroot = json_load_file(filename, 0, &json_error); 319 320 if (!jroot) { 321 printf("Bad JSON file \"%s\": %s\n", filename, json_error.text); 322 return -1; 323 } 324 ret = flex_item_config(jroot, &fp->flex_conf); 325 json_decref(jroot); 326 return ret; 327 } 328 329 void 330 flex_item_create(portid_t port_id, uint16_t flex_id, const char *filename) 331 { 332 struct rte_flow_error flow_error; 333 struct flex_item *fp = flex_parser_fetch(port_id, flex_id); 334 int ret; 335 336 if (fp == FLEX_PARSER_ERR) { 337 printf("Bad parameters: port_id=%u flex_id=%u\n", 338 port_id, flex_id); 339 return; 340 } 341 if (fp) { 342 printf("port-%u: flex item #%u is already in use\n", 343 port_id, flex_id); 344 return; 345 } 346 fp = flex_item_init(); 347 if (!fp) { 348 printf("Could not allocate flex item\n"); 349 goto out; 350 } 351 ret = flex_item_build_config(fp, filename); 352 if (ret) 353 goto out; 354 fp->flex_handle = rte_flow_flex_item_create(port_id, 355 &fp->flex_conf, 356 &flow_error); 357 if (fp->flex_handle) { 358 flex_items[port_id][flex_id] = fp; 359 printf("port-%u: created flex item #%u\n", port_id, flex_id); 360 fp = NULL; 361 } else { 362 printf("port-%u: flex item #%u creation failed: %s\n", 363 port_id, flex_id, 364 flow_error.message ? flow_error.message : ""); 365 } 366 out: 367 free(fp); 368 } 369 370 #else /* RTE_HAS_JANSSON */ 371 void flex_item_create(__rte_unused portid_t port_id, 372 __rte_unused uint16_t flex_id, 373 __rte_unused const char *filename) 374 { 375 printf("cannot create flex item - no JSON library configured\n"); 376 } 377 #endif /* RTE_HAS_JANSSON */ 378 379 void 380 flex_item_destroy(portid_t port_id, uint16_t flex_id) 381 { 382 int ret; 383 struct rte_flow_error error; 384 struct flex_item *fp = flex_parser_fetch(port_id, flex_id); 385 if (!flex_id) 386 return; 387 if (fp == FLEX_PARSER_ERR) { 388 printf("Bad parameters: port_id=%u flex_id=%u\n", 389 port_id, flex_id); 390 return; 391 } 392 if (!fp) 393 return; 394 ret = rte_flow_flex_item_release(port_id, fp->flex_handle, &error); 395 if (!ret) { 396 free(fp); 397 flex_items[port_id][flex_id] = NULL; 398 printf("port-%u: released flex item #%u\n", 399 port_id, flex_id); 400 401 } else { 402 printf("port-%u: cannot release flex item #%u: %s\n", 403 port_id, flex_id, error.message); 404 } 405 } 406 407 void 408 port_flex_item_flush(portid_t port_id) 409 { 410 uint16_t i; 411 412 for (i = 0; i < FLEX_MAX_PARSERS_NUM; i++) { 413 if (flex_items[port_id][i] != NULL) { 414 flex_item_destroy(port_id, i); 415 flex_items[port_id][i] = NULL; 416 } 417 } 418 } 419 420 struct flex_pattern_set { 421 cmdline_fixed_string_t set, flex_pattern; 422 cmdline_fixed_string_t is_spec, mask; 423 cmdline_fixed_string_t spec_data, mask_data; 424 uint16_t id; 425 }; 426 427 static cmdline_parse_token_string_t flex_pattern_set_token = 428 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, set, "set"); 429 static cmdline_parse_token_string_t flex_pattern_token = 430 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, 431 flex_pattern, "flex_pattern"); 432 static cmdline_parse_token_string_t flex_pattern_is_token = 433 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, 434 is_spec, "is"); 435 static cmdline_parse_token_string_t flex_pattern_spec_token = 436 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, 437 is_spec, "spec"); 438 static cmdline_parse_token_string_t flex_pattern_mask_token = 439 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, mask, "mask"); 440 static cmdline_parse_token_string_t flex_pattern_spec_data_token = 441 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, spec_data, NULL); 442 static cmdline_parse_token_string_t flex_pattern_mask_data_token = 443 TOKEN_STRING_INITIALIZER(struct flex_pattern_set, mask_data, NULL); 444 static cmdline_parse_token_num_t flex_pattern_id_token = 445 TOKEN_NUM_INITIALIZER(struct flex_pattern_set, id, RTE_UINT16); 446 447 /* 448 * flex pattern data - spec or mask is a string representation of byte array 449 * in hexadecimal format. Each byte in data string must have 2 characters: 450 * 0x15 - "15" 451 * 0x1 - "01" 452 * Bytes in data array are in network order. 453 */ 454 static uint32_t 455 flex_pattern_data(const char *str, uint8_t *data) 456 { 457 uint32_t i, len = strlen(str); 458 char b[3], *endptr; 459 460 if (len & 01) 461 return 0; 462 len /= 2; 463 if (len >= FLEX_MAX_FLOW_PATTERN_LENGTH) 464 return 0; 465 for (i = 0, b[2] = '\0'; i < len; i++) { 466 b[0] = str[2 * i]; 467 b[1] = str[2 * i + 1]; 468 data[i] = strtoul(b, &endptr, 16); 469 if (endptr != &b[2]) 470 return 0; 471 } 472 return len; 473 } 474 475 static void 476 flex_pattern_parsed_fn(void *parsed_result, 477 __rte_unused struct cmdline *cl, 478 __rte_unused void *data) 479 { 480 struct flex_pattern_set *res = parsed_result; 481 struct flex_pattern *fp; 482 bool full_spec; 483 484 if (res->id >= FLEX_MAX_PATTERNS_NUM) { 485 printf("Bad flex pattern id\n"); 486 return; 487 } 488 fp = flex_patterns + res->id; 489 memset(fp->spec_pattern, 0, sizeof(fp->spec_pattern)); 490 memset(fp->mask_pattern, 0, sizeof(fp->mask_pattern)); 491 fp->spec.length = flex_pattern_data(res->spec_data, fp->spec_pattern); 492 if (!fp->spec.length) { 493 printf("Bad flex pattern spec\n"); 494 return; 495 } 496 full_spec = strncmp(res->is_spec, "spec", strlen("spec")) == 0; 497 if (full_spec) { 498 fp->mask.length = flex_pattern_data(res->mask_data, 499 fp->mask_pattern); 500 if (!fp->mask.length) { 501 printf("Bad flex pattern mask\n"); 502 return; 503 } 504 } else { 505 memset(fp->mask_pattern, 0xFF, fp->spec.length); 506 fp->mask.length = fp->spec.length; 507 } 508 if (fp->mask.length != fp->spec.length) { 509 printf("Spec length do not match mask length\n"); 510 return; 511 } 512 fp->spec.pattern = fp->spec_pattern; 513 fp->mask.pattern = fp->mask_pattern; 514 printf("created pattern #%u\n", res->id); 515 } 516 517 cmdline_parse_inst_t cmd_set_flex_is_pattern = { 518 .f = flex_pattern_parsed_fn, 519 .data = NULL, 520 .help_str = "set flex_pattern <id> is <spec_data>", 521 .tokens = { 522 (void *)&flex_pattern_set_token, 523 (void *)&flex_pattern_token, 524 (void *)&flex_pattern_id_token, 525 (void *)&flex_pattern_is_token, 526 (void *)&flex_pattern_spec_data_token, 527 NULL, 528 } 529 }; 530 531 cmdline_parse_inst_t cmd_set_flex_spec_pattern = { 532 .f = flex_pattern_parsed_fn, 533 .data = NULL, 534 .help_str = "set flex_pattern <id> spec <spec_data> mask <mask_data>", 535 .tokens = { 536 (void *)&flex_pattern_set_token, 537 (void *)&flex_pattern_token, 538 (void *)&flex_pattern_id_token, 539 (void *)&flex_pattern_spec_token, 540 (void *)&flex_pattern_spec_data_token, 541 (void *)&flex_pattern_mask_token, 542 (void *)&flex_pattern_mask_data_token, 543 NULL, 544 } 545 }; 546