1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2021 NVIDIA Corporation & Affiliates 3 */ 4 #include <rte_malloc.h> 5 #include <mlx5_devx_cmds.h> 6 #include <mlx5_malloc.h> 7 #include "mlx5.h" 8 #include "mlx5_flow.h" 9 10 static_assert(sizeof(uint32_t) * CHAR_BIT >= MLX5_PORT_FLEX_ITEM_NUM, 11 "Flex item maximal number exceeds uint32_t bit width"); 12 13 /** 14 * Routine called once on port initialization to init flex item 15 * related infrastructure initialization 16 * 17 * @param dev 18 * Ethernet device to perform flex item initialization 19 * 20 * @return 21 * 0 on success, a negative errno value otherwise and rte_errno is set. 22 */ 23 int 24 mlx5_flex_item_port_init(struct rte_eth_dev *dev) 25 { 26 struct mlx5_priv *priv = dev->data->dev_private; 27 28 rte_spinlock_init(&priv->flex_item_sl); 29 MLX5_ASSERT(!priv->flex_item_map); 30 return 0; 31 } 32 33 /** 34 * Routine called once on port close to perform flex item 35 * related infrastructure cleanup. 36 * 37 * @param dev 38 * Ethernet device to perform cleanup 39 */ 40 void 41 mlx5_flex_item_port_cleanup(struct rte_eth_dev *dev) 42 { 43 struct mlx5_priv *priv = dev->data->dev_private; 44 uint32_t i; 45 46 for (i = 0; i < MLX5_PORT_FLEX_ITEM_NUM && priv->flex_item_map ; i++) { 47 if (priv->flex_item_map & (1 << i)) { 48 struct mlx5_flex_item *flex = &priv->flex_item[i]; 49 50 claim_zero(mlx5_list_unregister 51 (priv->sh->flex_parsers_dv, 52 &flex->devx_fp->entry)); 53 flex->devx_fp = NULL; 54 flex->refcnt = 0; 55 priv->flex_item_map &= ~(1 << i); 56 } 57 } 58 } 59 60 static int 61 mlx5_flex_index(struct mlx5_priv *priv, struct mlx5_flex_item *item) 62 { 63 uintptr_t start = (uintptr_t)&priv->flex_item[0]; 64 uintptr_t entry = (uintptr_t)item; 65 uintptr_t idx = (entry - start) / sizeof(struct mlx5_flex_item); 66 67 if (entry < start || 68 idx >= MLX5_PORT_FLEX_ITEM_NUM || 69 (entry - start) % sizeof(struct mlx5_flex_item) || 70 !(priv->flex_item_map & (1u << idx))) 71 return -1; 72 return (int)idx; 73 } 74 75 static struct mlx5_flex_item * 76 mlx5_flex_alloc(struct mlx5_priv *priv) 77 { 78 struct mlx5_flex_item *item = NULL; 79 80 rte_spinlock_lock(&priv->flex_item_sl); 81 if (~priv->flex_item_map) { 82 uint32_t idx = rte_bsf32(~priv->flex_item_map); 83 84 if (idx < MLX5_PORT_FLEX_ITEM_NUM) { 85 item = &priv->flex_item[idx]; 86 MLX5_ASSERT(!item->refcnt); 87 MLX5_ASSERT(!item->devx_fp); 88 item->devx_fp = NULL; 89 rte_atomic_store_explicit(&item->refcnt, 0, rte_memory_order_release); 90 priv->flex_item_map |= 1u << idx; 91 } 92 } 93 rte_spinlock_unlock(&priv->flex_item_sl); 94 return item; 95 } 96 97 static void 98 mlx5_flex_free(struct mlx5_priv *priv, struct mlx5_flex_item *item) 99 { 100 int idx = mlx5_flex_index(priv, item); 101 102 MLX5_ASSERT(idx >= 0 && 103 idx < MLX5_PORT_FLEX_ITEM_NUM && 104 (priv->flex_item_map & (1u << idx))); 105 if (idx >= 0) { 106 rte_spinlock_lock(&priv->flex_item_sl); 107 MLX5_ASSERT(!item->refcnt); 108 MLX5_ASSERT(!item->devx_fp); 109 item->devx_fp = NULL; 110 rte_atomic_store_explicit(&item->refcnt, 0, rte_memory_order_release); 111 priv->flex_item_map &= ~(1u << idx); 112 rte_spinlock_unlock(&priv->flex_item_sl); 113 } 114 } 115 116 static uint32_t 117 mlx5_flex_get_bitfield(const struct rte_flow_item_flex *item, 118 uint32_t pos, uint32_t width, uint32_t shift) 119 { 120 const uint8_t *ptr = item->pattern + pos / CHAR_BIT; 121 uint32_t val, vbits, skip = pos % CHAR_BIT; 122 123 /* Proceed the bitfield start byte. */ 124 MLX5_ASSERT(width <= sizeof(uint32_t) * CHAR_BIT && width); 125 MLX5_ASSERT(width + shift <= sizeof(uint32_t) * CHAR_BIT); 126 if (item->length <= pos / CHAR_BIT) 127 return 0; 128 /* Bits are enumerated in byte in network order: 01234567 */ 129 val = *ptr++; 130 vbits = CHAR_BIT - pos % CHAR_BIT; 131 pos = RTE_ALIGN_CEIL(pos, CHAR_BIT) / CHAR_BIT; 132 vbits = RTE_MIN(vbits, width); 133 /* Load bytes to cover the field width, checking pattern boundary */ 134 while (vbits < width && pos < item->length) { 135 uint32_t part = RTE_MIN(width - vbits, (uint32_t)CHAR_BIT); 136 uint32_t tmp = *ptr++; 137 138 val |= tmp << RTE_ALIGN_CEIL(vbits, CHAR_BIT); 139 vbits += part; 140 pos++; 141 } 142 val = rte_cpu_to_be_32(val); 143 val <<= skip; 144 val >>= shift; 145 val &= (RTE_BIT64(width) - 1) << (sizeof(uint32_t) * CHAR_BIT - shift - width); 146 return val; 147 } 148 149 #define SET_FP_MATCH_SAMPLE_ID(x, def, msk, val, sid) \ 150 do { \ 151 uint32_t tmp, out = (def); \ 152 tmp = MLX5_GET(fte_match_set_misc4, misc4_v, \ 153 prog_sample_field_value_##x); \ 154 tmp = (tmp & ~out) | (val); \ 155 MLX5_SET(fte_match_set_misc4, misc4_v, \ 156 prog_sample_field_value_##x, tmp); \ 157 tmp = MLX5_GET(fte_match_set_misc4, misc4_m, \ 158 prog_sample_field_value_##x); \ 159 tmp = (tmp & ~out) | (msk); \ 160 MLX5_SET(fte_match_set_misc4, misc4_m, \ 161 prog_sample_field_value_##x, tmp); \ 162 tmp = tmp ? (sid) : 0; \ 163 MLX5_SET(fte_match_set_misc4, misc4_v, \ 164 prog_sample_field_id_##x, tmp);\ 165 MLX5_SET(fte_match_set_misc4, misc4_m, \ 166 prog_sample_field_id_##x, tmp); \ 167 } while (0) 168 169 __rte_always_inline static void 170 mlx5_flex_set_match_sample(void *misc4_m, void *misc4_v, 171 uint32_t def, uint32_t mask, uint32_t value, 172 uint32_t sample_id, uint32_t id) 173 { 174 switch (id) { 175 case 0: 176 SET_FP_MATCH_SAMPLE_ID(0, def, mask, value, sample_id); 177 break; 178 case 1: 179 SET_FP_MATCH_SAMPLE_ID(1, def, mask, value, sample_id); 180 break; 181 case 2: 182 SET_FP_MATCH_SAMPLE_ID(2, def, mask, value, sample_id); 183 break; 184 case 3: 185 SET_FP_MATCH_SAMPLE_ID(3, def, mask, value, sample_id); 186 break; 187 case 4: 188 SET_FP_MATCH_SAMPLE_ID(4, def, mask, value, sample_id); 189 break; 190 case 5: 191 SET_FP_MATCH_SAMPLE_ID(5, def, mask, value, sample_id); 192 break; 193 case 6: 194 SET_FP_MATCH_SAMPLE_ID(6, def, mask, value, sample_id); 195 break; 196 case 7: 197 SET_FP_MATCH_SAMPLE_ID(7, def, mask, value, sample_id); 198 break; 199 default: 200 MLX5_ASSERT(false); 201 break; 202 } 203 #undef SET_FP_MATCH_SAMPLE_ID 204 } 205 206 /** 207 * Get the flex parser sample id and corresponding mask 208 * per shift and width information. 209 * 210 * @param[in] tp 211 * Mlx5 flex item sample mapping handle. 212 * @param[in] idx 213 * Mapping index. 214 * @param[in, out] pos 215 * Where to search the value and mask. 216 * @param[in] is_inner 217 * For inner matching or not. 218 * 219 * @return 220 * 0 on success, -1 to ignore. 221 */ 222 int 223 mlx5_flex_get_sample_id(const struct mlx5_flex_item *tp, 224 uint32_t idx, uint32_t *pos, bool is_inner) 225 { 226 const struct mlx5_flex_pattern_field *map = tp->map + idx; 227 uint32_t id = map->reg_id; 228 229 /* Skip placeholders for DUMMY fields. */ 230 if (id == MLX5_INVALID_SAMPLE_REG_ID) { 231 *pos += map->width; 232 return -1; 233 } 234 MLX5_ASSERT(map->width); 235 MLX5_ASSERT(id < tp->devx_fp->num_samples); 236 if (tp->tunnel_mode == FLEX_TUNNEL_MODE_MULTI && is_inner) { 237 uint32_t num_samples = tp->devx_fp->num_samples / 2; 238 239 MLX5_ASSERT(tp->devx_fp->num_samples % 2 == 0); 240 MLX5_ASSERT(id < num_samples); 241 id += num_samples; 242 } 243 return id; 244 } 245 246 /** 247 * Get the flex parser mapping value per definer format_select_dw. 248 * 249 * @param[in] item 250 * Rte flex item pointer. 251 * @param[in] flex 252 * Mlx5 flex item sample mapping handle. 253 * @param[in] byte_off 254 * Mlx5 flex item format_select_dw. 255 * @param[in] tunnel 256 * Tunnel mode or not. 257 * @param[in, def] value 258 * Value calculated for this flex parser, either spec or mask. 259 * 260 * @return 261 * 0 on success, -1 for error. 262 */ 263 int 264 mlx5_flex_get_parser_value_per_byte_off(const struct rte_flow_item_flex *item, 265 void *flex, uint32_t byte_off, 266 bool tunnel, uint32_t *value) 267 { 268 struct mlx5_flex_pattern_field *map; 269 struct mlx5_flex_item *tp = flex; 270 uint32_t i, pos, val; 271 int id; 272 273 *value = 0; 274 for (i = 0, pos = 0; i < tp->mapnum && pos < item->length * CHAR_BIT; i++) { 275 map = tp->map + i; 276 id = mlx5_flex_get_sample_id(tp, i, &pos, tunnel); 277 if (id == -1) 278 continue; 279 if (id >= (int)tp->devx_fp->num_samples || id >= MLX5_GRAPH_NODE_SAMPLE_NUM) 280 return -1; 281 if (byte_off == tp->devx_fp->sample_info[id].sample_dw_data * sizeof(uint32_t)) { 282 val = mlx5_flex_get_bitfield(item, pos, map->width, map->shift); 283 *value |= val; 284 } 285 pos += map->width; 286 } 287 return 0; 288 } 289 290 /** 291 * Get the flex parser tunnel mode. 292 * 293 * @param[in] item 294 * RTE Flex item. 295 * @param[in, out] tunnel_mode 296 * Pointer to return tunnel mode. 297 * 298 * @return 299 * 0 on success, otherwise negative error code. 300 */ 301 int 302 mlx5_flex_get_tunnel_mode(const struct rte_flow_item *item, 303 enum rte_flow_item_flex_tunnel_mode *tunnel_mode) 304 { 305 if (item && item->spec && tunnel_mode) { 306 const struct rte_flow_item_flex *spec = item->spec; 307 struct mlx5_flex_item *flex = (struct mlx5_flex_item *)spec->handle; 308 309 if (flex) { 310 *tunnel_mode = flex->tunnel_mode; 311 return 0; 312 } 313 } 314 return -EINVAL; 315 } 316 317 /** 318 * Translate item pattern into matcher fields according to translation 319 * array. 320 * 321 * @param dev 322 * Ethernet device to translate flex item on. 323 * @param[in, out] matcher 324 * Flow matcher to configure 325 * @param[in, out] key 326 * Flow matcher value. 327 * @param[in] item 328 * Flow pattern to translate. 329 * @param[in] is_inner 330 * Inner Flex Item (follows after tunnel header). 331 * 332 * @return 333 * 0 on success, a negative errno value otherwise and rte_errno is set. 334 */ 335 void 336 mlx5_flex_flow_translate_item(struct rte_eth_dev *dev, 337 void *matcher, void *key, 338 const struct rte_flow_item *item, 339 bool is_inner) 340 { 341 const struct rte_flow_item_flex *spec, *mask; 342 void *misc4_m = MLX5_ADDR_OF(fte_match_param, matcher, 343 misc_parameters_4); 344 void *misc4_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_4); 345 struct mlx5_flex_item *tp; 346 uint32_t i, pos = 0; 347 uint32_t sample_id; 348 349 RTE_SET_USED(dev); 350 MLX5_ASSERT(item->spec && item->mask); 351 spec = item->spec; 352 mask = item->mask; 353 tp = (struct mlx5_flex_item *)spec->handle; 354 for (i = 0; i < tp->mapnum && pos < (spec->length * CHAR_BIT); i++) { 355 struct mlx5_flex_pattern_field *map = tp->map + i; 356 uint32_t val, msk, def; 357 int id = mlx5_flex_get_sample_id(tp, i, &pos, is_inner); 358 359 if (id == -1) 360 continue; 361 MLX5_ASSERT(id < (int)tp->devx_fp->num_samples); 362 if (id >= (int)tp->devx_fp->num_samples || 363 id >= MLX5_GRAPH_NODE_SAMPLE_NUM) 364 return; 365 def = (uint32_t)(RTE_BIT64(map->width) - 1); 366 def <<= (sizeof(uint32_t) * CHAR_BIT - map->shift - map->width); 367 val = mlx5_flex_get_bitfield(spec, pos, map->width, map->shift); 368 msk = pos < (mask->length * CHAR_BIT) ? 369 mlx5_flex_get_bitfield(mask, pos, map->width, map->shift) : def; 370 sample_id = tp->devx_fp->sample_ids[id]; 371 mlx5_flex_set_match_sample(misc4_m, misc4_v, 372 def, msk, val & msk, 373 sample_id, id); 374 pos += map->width; 375 } 376 } 377 378 /** 379 * Convert flex item handle (from the RTE flow) to flex item index on port. 380 * Optionally can increment flex item object reference count. 381 * 382 * @param dev 383 * Ethernet device to acquire flex item on. 384 * @param[in] handle 385 * Flow item handle from item spec. 386 * @param[in] acquire 387 * If set - increment reference counter. 388 * 389 * @return 390 * >=0 - index on success, a negative errno value otherwise 391 * and rte_errno is set. 392 */ 393 int 394 mlx5_flex_acquire_index(struct rte_eth_dev *dev, 395 struct rte_flow_item_flex_handle *handle, 396 bool acquire) 397 { 398 struct mlx5_priv *priv = dev->data->dev_private; 399 struct mlx5_flex_item *flex = (struct mlx5_flex_item *)handle; 400 int ret = mlx5_flex_index(priv, flex); 401 402 if (ret < 0) { 403 errno = -EINVAL; 404 rte_errno = EINVAL; 405 return ret; 406 } 407 if (acquire) 408 rte_atomic_fetch_add_explicit(&flex->refcnt, 1, rte_memory_order_release); 409 return ret; 410 } 411 412 /** 413 * Release flex item index on port - decrements reference counter by index. 414 * 415 * @param dev 416 * Ethernet device to acquire flex item on. 417 * @param[in] index 418 * Flow item index. 419 * 420 * @return 421 * 0 - on success, a negative errno value otherwise and rte_errno is set. 422 */ 423 int 424 mlx5_flex_release_index(struct rte_eth_dev *dev, 425 int index) 426 { 427 struct mlx5_priv *priv = dev->data->dev_private; 428 struct mlx5_flex_item *flex; 429 430 if (index >= MLX5_PORT_FLEX_ITEM_NUM || 431 !(priv->flex_item_map & (1u << index))) { 432 errno = EINVAL; 433 rte_errno = -EINVAL; 434 return -EINVAL; 435 } 436 flex = priv->flex_item + index; 437 if (flex->refcnt <= 1) { 438 MLX5_ASSERT(false); 439 errno = EINVAL; 440 rte_errno = -EINVAL; 441 return -EINVAL; 442 } 443 rte_atomic_fetch_sub_explicit(&flex->refcnt, 1, rte_memory_order_release); 444 return 0; 445 } 446 447 /* 448 * Calculate largest mask value for a given shift. 449 * 450 * shift mask 451 * ------- --------------- 452 * 0 b11111100 0x3C 453 * 1 b01111110 0x3E 454 * 2 b00111111 0x3F 455 * 3 b00011111 0x1F 456 * 4 b00001111 0x0F 457 * 5 b00000111 0x07 458 * 6 b00000011 0x03 459 * 7 b00000001 0x01 460 */ 461 static uint8_t 462 mlx5_flex_hdr_len_mask(uint8_t shift, 463 const struct mlx5_hca_flex_attr *attr) 464 { 465 uint32_t base_mask; 466 int diff = shift - MLX5_PARSE_GRAPH_NODE_HDR_LEN_SHIFT_DWORD; 467 468 base_mask = mlx5_hca_parse_graph_node_base_hdr_len_mask(attr); 469 return diff < 0 ? base_mask << -diff : base_mask >> diff; 470 } 471 472 static int 473 mlx5_flex_translate_length(struct mlx5_hca_flex_attr *attr, 474 const struct rte_flow_item_flex_conf *conf, 475 struct mlx5_flex_parser_devx *devx, 476 struct rte_flow_error *error) 477 { 478 const struct rte_flow_item_flex_field *field = &conf->next_header; 479 struct mlx5_devx_graph_node_attr *node = &devx->devx_conf; 480 481 if (field->field_base % CHAR_BIT) 482 return rte_flow_error_set 483 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 484 "not byte aligned header length field"); 485 switch (field->field_mode) { 486 case FIELD_MODE_DUMMY: 487 return rte_flow_error_set 488 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 489 "invalid header length field mode (DUMMY)"); 490 case FIELD_MODE_FIXED: 491 if (!(attr->header_length_mode & 492 RTE_BIT32(MLX5_GRAPH_NODE_LEN_FIXED))) 493 return rte_flow_error_set 494 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 495 "unsupported header length field mode (FIXED)"); 496 if (field->field_size || 497 field->offset_mask || field->offset_shift) 498 return rte_flow_error_set 499 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 500 "invalid fields for fixed mode"); 501 if (field->field_base < 0) 502 return rte_flow_error_set 503 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 504 "negative header length field base (FIXED)"); 505 node->header_length_mode = MLX5_GRAPH_NODE_LEN_FIXED; 506 break; 507 case FIELD_MODE_OFFSET: { 508 uint32_t msb, lsb; 509 int32_t shift = field->offset_shift; 510 uint32_t offset = field->offset_base; 511 uint32_t mask = field->offset_mask; 512 uint32_t wmax = attr->header_length_mask_width + 513 MLX5_PARSE_GRAPH_NODE_HDR_LEN_SHIFT_DWORD; 514 515 if (!(attr->header_length_mode & 516 RTE_BIT32(MLX5_GRAPH_NODE_LEN_FIELD))) 517 return rte_flow_error_set 518 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 519 "unsupported header length field mode (OFFSET)"); 520 if (!field->field_size) 521 return rte_flow_error_set 522 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 523 "field size is a must for offset mode"); 524 if ((offset ^ (field->field_size + offset)) >> 5) 525 return rte_flow_error_set 526 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 527 "field crosses the 32-bit word boundary"); 528 /* Hardware counts in dwords, all shifts done by offset within mask */ 529 if (shift < 0 || (uint32_t)shift >= wmax) 530 return rte_flow_error_set 531 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 532 "header length field shift exceeds limits (OFFSET)"); 533 if (!mask) 534 return rte_flow_error_set 535 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 536 "zero length field offset mask (OFFSET)"); 537 msb = rte_fls_u32(mask) - 1; 538 lsb = rte_bsf32(mask); 539 if (!rte_is_power_of_2((mask >> lsb) + 1)) 540 return rte_flow_error_set 541 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 542 "length field offset mask not contiguous (OFFSET)"); 543 if (msb >= field->field_size) 544 return rte_flow_error_set 545 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 546 "length field offset mask exceeds field size (OFFSET)"); 547 if (msb >= wmax) 548 return rte_flow_error_set 549 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 550 "length field offset mask exceeds supported width (OFFSET)"); 551 if (mask & ~mlx5_flex_hdr_len_mask(shift, attr)) 552 return rte_flow_error_set 553 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 554 "mask and shift combination not supported (OFFSET)"); 555 msb++; 556 offset += field->field_size - msb; 557 if (msb < attr->header_length_mask_width) { 558 if (attr->header_length_mask_width - msb > offset) 559 return rte_flow_error_set 560 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 561 "field size plus offset_base is too small"); 562 offset += msb; 563 /* 564 * Here we can move to preceding dword. Hardware does 565 * cyclic left shift so we should avoid this and stay 566 * at current dword offset. 567 */ 568 offset = (offset & ~0x1Fu) | 569 ((offset - attr->header_length_mask_width) & 0x1F); 570 } 571 node->header_length_mode = MLX5_GRAPH_NODE_LEN_FIELD; 572 node->header_length_field_mask = mask; 573 node->header_length_field_shift = shift; 574 node->header_length_field_offset = offset; 575 break; 576 } 577 case FIELD_MODE_BITMASK: 578 if (!(attr->header_length_mode & 579 RTE_BIT32(MLX5_GRAPH_NODE_LEN_BITMASK))) 580 return rte_flow_error_set 581 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 582 "unsupported header length field mode (BITMASK)"); 583 if (field->offset_shift > 15 || field->offset_shift < 0) 584 return rte_flow_error_set 585 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 586 "header length field shift exceeds limit (BITMASK)"); 587 node->header_length_mode = MLX5_GRAPH_NODE_LEN_BITMASK; 588 node->header_length_field_mask = field->offset_mask; 589 node->header_length_field_shift = field->offset_shift; 590 node->header_length_field_offset = field->offset_base; 591 break; 592 default: 593 return rte_flow_error_set 594 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 595 "unknown header length field mode"); 596 } 597 if (field->field_base / CHAR_BIT >= 0 && 598 field->field_base / CHAR_BIT > attr->max_base_header_length) 599 return rte_flow_error_set 600 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 601 "header length field base exceeds limit"); 602 node->header_length_base_value = field->field_base / CHAR_BIT; 603 return 0; 604 } 605 606 static int 607 mlx5_flex_translate_next(struct mlx5_hca_flex_attr *attr, 608 const struct rte_flow_item_flex_conf *conf, 609 struct mlx5_flex_parser_devx *devx, 610 struct rte_flow_error *error) 611 { 612 const struct rte_flow_item_flex_field *field = &conf->next_protocol; 613 struct mlx5_devx_graph_node_attr *node = &devx->devx_conf; 614 615 switch (field->field_mode) { 616 case FIELD_MODE_DUMMY: 617 if (conf->nb_outputs) 618 return rte_flow_error_set 619 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 620 "next protocol field is required (DUMMY)"); 621 return 0; 622 case FIELD_MODE_FIXED: 623 break; 624 case FIELD_MODE_OFFSET: 625 return rte_flow_error_set 626 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 627 "unsupported next protocol field mode (OFFSET)"); 628 break; 629 case FIELD_MODE_BITMASK: 630 return rte_flow_error_set 631 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 632 "unsupported next protocol field mode (BITMASK)"); 633 default: 634 return rte_flow_error_set 635 (error, EINVAL, 636 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 637 "unknown next protocol field mode"); 638 } 639 MLX5_ASSERT(field->field_mode == FIELD_MODE_FIXED); 640 if (!conf->nb_outputs) 641 return rte_flow_error_set 642 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 643 "out link(s) is required if next field present"); 644 if (attr->max_next_header_offset < field->field_base) 645 return rte_flow_error_set 646 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 647 "next protocol field base exceeds limit"); 648 if (field->offset_shift) 649 return rte_flow_error_set 650 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 651 "unsupported next protocol field shift"); 652 node->next_header_field_offset = field->field_base; 653 node->next_header_field_size = field->field_size; 654 return 0; 655 } 656 657 /* Helper structure to handle field bit intervals. */ 658 struct mlx5_flex_field_cover { 659 uint16_t num; 660 int32_t start[MLX5_FLEX_ITEM_MAPPING_NUM]; 661 int32_t end[MLX5_FLEX_ITEM_MAPPING_NUM]; 662 uint8_t mapped[MLX5_FLEX_ITEM_MAPPING_NUM / CHAR_BIT + 1]; 663 }; 664 665 static void 666 mlx5_flex_insert_field(struct mlx5_flex_field_cover *cover, 667 uint16_t num, int32_t start, int32_t end) 668 { 669 MLX5_ASSERT(num < MLX5_FLEX_ITEM_MAPPING_NUM); 670 MLX5_ASSERT(num <= cover->num); 671 if (num < cover->num) { 672 memmove(&cover->start[num + 1], &cover->start[num], 673 (cover->num - num) * sizeof(int32_t)); 674 memmove(&cover->end[num + 1], &cover->end[num], 675 (cover->num - num) * sizeof(int32_t)); 676 } 677 cover->start[num] = start; 678 cover->end[num] = end; 679 cover->num++; 680 } 681 682 static void 683 mlx5_flex_merge_field(struct mlx5_flex_field_cover *cover, uint16_t num) 684 { 685 uint32_t i, del = 0; 686 int32_t end; 687 688 MLX5_ASSERT(num < MLX5_FLEX_ITEM_MAPPING_NUM); 689 MLX5_ASSERT(num < (cover->num - 1)); 690 end = cover->end[num]; 691 for (i = num + 1; i < cover->num; i++) { 692 if (end < cover->start[i]) 693 break; 694 del++; 695 if (end <= cover->end[i]) { 696 cover->end[num] = cover->end[i]; 697 break; 698 } 699 } 700 if (del) { 701 MLX5_ASSERT(del < (cover->num - 1u - num)); 702 cover->num -= del; 703 MLX5_ASSERT(cover->num > num); 704 if ((cover->num - num) > 1) { 705 memmove(&cover->start[num + 1], 706 &cover->start[num + 1 + del], 707 (cover->num - num - 1) * sizeof(int32_t)); 708 memmove(&cover->end[num + 1], 709 &cover->end[num + 1 + del], 710 (cover->num - num - 1) * sizeof(int32_t)); 711 } 712 } 713 } 714 715 /* 716 * Validate the sample field and update interval array 717 * if parameters match with the 'match" field. 718 * Returns: 719 * < 0 - error 720 * == 0 - no match, interval array not updated 721 * > 0 - match, interval array updated 722 */ 723 static int 724 mlx5_flex_cover_sample(struct mlx5_flex_field_cover *cover, 725 struct rte_flow_item_flex_field *field, 726 struct rte_flow_item_flex_field *match, 727 struct mlx5_hca_flex_attr *attr, 728 struct rte_flow_error *error) 729 { 730 int32_t start, end; 731 uint32_t i; 732 733 switch (field->field_mode) { 734 case FIELD_MODE_DUMMY: 735 return 0; 736 case FIELD_MODE_FIXED: 737 if (!(attr->sample_offset_mode & 738 RTE_BIT32(MLX5_GRAPH_SAMPLE_OFFSET_FIXED))) 739 return rte_flow_error_set 740 (error, EINVAL, 741 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 742 "unsupported sample field mode (FIXED)"); 743 if (field->offset_shift) 744 return rte_flow_error_set 745 (error, EINVAL, 746 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 747 "invalid sample field shift (FIXED"); 748 if (field->field_base < 0) 749 return rte_flow_error_set 750 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 751 "invalid sample field base (FIXED)"); 752 if (field->field_base / CHAR_BIT > attr->max_sample_base_offset) 753 return rte_flow_error_set 754 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 755 "sample field base exceeds limit (FIXED)"); 756 break; 757 case FIELD_MODE_OFFSET: 758 if (!(attr->sample_offset_mode & 759 RTE_BIT32(MLX5_GRAPH_SAMPLE_OFFSET_FIELD))) 760 return rte_flow_error_set 761 (error, EINVAL, 762 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 763 "unsupported sample field mode (OFFSET)"); 764 if (field->field_base / CHAR_BIT >= 0 && 765 field->field_base / CHAR_BIT > attr->max_sample_base_offset) 766 return rte_flow_error_set 767 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 768 "sample field base exceeds limit"); 769 break; 770 case FIELD_MODE_BITMASK: 771 if (!(attr->sample_offset_mode & 772 RTE_BIT32(MLX5_GRAPH_SAMPLE_OFFSET_BITMASK))) 773 return rte_flow_error_set 774 (error, EINVAL, 775 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 776 "unsupported sample field mode (BITMASK)"); 777 if (field->field_base / CHAR_BIT >= 0 && 778 field->field_base / CHAR_BIT > attr->max_sample_base_offset) 779 return rte_flow_error_set 780 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 781 "sample field base exceeds limit"); 782 break; 783 default: 784 return rte_flow_error_set 785 (error, EINVAL, 786 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 787 "unknown data sample field mode"); 788 } 789 if (!match) { 790 if (!field->field_size) 791 return rte_flow_error_set 792 (error, EINVAL, 793 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 794 "zero sample field width"); 795 if (field->field_id) 796 DRV_LOG(DEBUG, "sample field id hint ignored"); 797 } else { 798 if (field->field_mode != match->field_mode || 799 field->offset_base | match->offset_base || 800 field->offset_mask | match->offset_mask || 801 field->offset_shift | match->offset_shift) 802 return 0; 803 } 804 start = field->field_base; 805 end = start + field->field_size; 806 /* Add the new or similar field to interval array. */ 807 if (!cover->num) { 808 cover->start[cover->num] = start; 809 cover->end[cover->num] = end; 810 cover->num = 1; 811 return 1; 812 } 813 for (i = 0; i < cover->num; i++) { 814 if (start > cover->end[i]) { 815 if (i >= (cover->num - 1u)) { 816 mlx5_flex_insert_field(cover, cover->num, 817 start, end); 818 break; 819 } 820 continue; 821 } 822 if (end < cover->start[i]) { 823 mlx5_flex_insert_field(cover, i, start, end); 824 break; 825 } 826 if (start < cover->start[i]) 827 cover->start[i] = start; 828 if (end > cover->end[i]) { 829 cover->end[i] = end; 830 if (i < (cover->num - 1u)) 831 mlx5_flex_merge_field(cover, i); 832 } 833 break; 834 } 835 return 1; 836 } 837 838 static void 839 mlx5_flex_config_sample(struct mlx5_devx_match_sample_attr *na, 840 struct rte_flow_item_flex_field *field, 841 enum rte_flow_item_flex_tunnel_mode tunnel_mode) 842 { 843 memset(na, 0, sizeof(struct mlx5_devx_match_sample_attr)); 844 na->flow_match_sample_en = 1; 845 switch (field->field_mode) { 846 case FIELD_MODE_FIXED: 847 na->flow_match_sample_offset_mode = 848 MLX5_GRAPH_SAMPLE_OFFSET_FIXED; 849 break; 850 case FIELD_MODE_OFFSET: 851 na->flow_match_sample_offset_mode = 852 MLX5_GRAPH_SAMPLE_OFFSET_FIELD; 853 na->flow_match_sample_field_offset = field->offset_base; 854 na->flow_match_sample_field_offset_mask = field->offset_mask; 855 na->flow_match_sample_field_offset_shift = field->offset_shift; 856 break; 857 case FIELD_MODE_BITMASK: 858 na->flow_match_sample_offset_mode = 859 MLX5_GRAPH_SAMPLE_OFFSET_BITMASK; 860 na->flow_match_sample_field_offset = field->offset_base; 861 na->flow_match_sample_field_offset_mask = field->offset_mask; 862 na->flow_match_sample_field_offset_shift = field->offset_shift; 863 break; 864 default: 865 MLX5_ASSERT(false); 866 break; 867 } 868 switch (tunnel_mode) { 869 case FLEX_TUNNEL_MODE_SINGLE: 870 /* Fallthrough */ 871 case FLEX_TUNNEL_MODE_TUNNEL: 872 na->flow_match_sample_tunnel_mode = 873 MLX5_GRAPH_SAMPLE_TUNNEL_FIRST; 874 break; 875 case FLEX_TUNNEL_MODE_MULTI: 876 /* Fallthrough */ 877 case FLEX_TUNNEL_MODE_OUTER: 878 na->flow_match_sample_tunnel_mode = 879 MLX5_GRAPH_SAMPLE_TUNNEL_OUTER; 880 break; 881 case FLEX_TUNNEL_MODE_INNER: 882 na->flow_match_sample_tunnel_mode = 883 MLX5_GRAPH_SAMPLE_TUNNEL_INNER; 884 break; 885 default: 886 MLX5_ASSERT(false); 887 break; 888 } 889 } 890 891 /* Map specified field to set/subset of allocated sample registers. */ 892 static int 893 mlx5_flex_map_sample(struct rte_flow_item_flex_field *field, 894 struct mlx5_flex_parser_devx *parser, 895 struct mlx5_flex_item *item, 896 struct rte_flow_error *error) 897 { 898 struct mlx5_devx_match_sample_attr node; 899 int32_t start = field->field_base; 900 int32_t end = start + field->field_size; 901 struct mlx5_flex_pattern_field *trans; 902 uint32_t i, done_bits = 0; 903 904 if (field->field_mode == FIELD_MODE_DUMMY) { 905 done_bits = field->field_size; 906 while (done_bits) { 907 uint32_t part = RTE_MIN(done_bits, 908 sizeof(uint32_t) * CHAR_BIT); 909 if (item->mapnum >= MLX5_FLEX_ITEM_MAPPING_NUM) 910 return rte_flow_error_set 911 (error, 912 EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 913 "too many flex item pattern translations"); 914 trans = &item->map[item->mapnum]; 915 trans->reg_id = MLX5_INVALID_SAMPLE_REG_ID; 916 trans->shift = 0; 917 trans->width = part; 918 item->mapnum++; 919 done_bits -= part; 920 } 921 return 0; 922 } 923 mlx5_flex_config_sample(&node, field, item->tunnel_mode); 924 for (i = 0; i < parser->num_samples; i++) { 925 struct mlx5_devx_match_sample_attr *sample = 926 &parser->devx_conf.sample[i]; 927 int32_t reg_start, reg_end; 928 int32_t cov_start, cov_end; 929 930 MLX5_ASSERT(sample->flow_match_sample_en); 931 if (!sample->flow_match_sample_en) 932 break; 933 node.flow_match_sample_field_base_offset = 934 sample->flow_match_sample_field_base_offset; 935 if (memcmp(&node, sample, sizeof(node))) 936 continue; 937 reg_start = (int8_t)sample->flow_match_sample_field_base_offset; 938 reg_start *= CHAR_BIT; 939 reg_end = reg_start + 32; 940 if (end <= reg_start || start >= reg_end) 941 continue; 942 cov_start = RTE_MAX(reg_start, start); 943 cov_end = RTE_MIN(reg_end, end); 944 MLX5_ASSERT(cov_end > cov_start); 945 done_bits += cov_end - cov_start; 946 if (item->mapnum >= MLX5_FLEX_ITEM_MAPPING_NUM) 947 return rte_flow_error_set 948 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 949 "too many flex item pattern translations"); 950 trans = &item->map[item->mapnum]; 951 item->mapnum++; 952 trans->reg_id = i; 953 trans->shift = cov_start - reg_start; 954 trans->width = cov_end - cov_start; 955 } 956 if (done_bits != field->field_size) { 957 MLX5_ASSERT(false); 958 return rte_flow_error_set 959 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 960 "failed to map field to sample register"); 961 } 962 return 0; 963 } 964 965 /* Allocate sample registers for the specified field type and interval array. */ 966 static int 967 mlx5_flex_alloc_sample(struct mlx5_flex_field_cover *cover, 968 struct mlx5_flex_parser_devx *parser, 969 struct mlx5_flex_item *item, 970 struct rte_flow_item_flex_field *field, 971 struct mlx5_hca_flex_attr *attr, 972 struct rte_flow_error *error) 973 { 974 struct mlx5_devx_match_sample_attr node; 975 uint32_t idx = 0; 976 977 mlx5_flex_config_sample(&node, field, item->tunnel_mode); 978 while (idx < cover->num) { 979 int32_t start, end; 980 981 /* 982 * Sample base offsets are in bytes, should be aligned 983 * to 32-bit as required by firmware for samples. 984 */ 985 start = RTE_ALIGN_FLOOR(cover->start[idx], 986 sizeof(uint32_t) * CHAR_BIT); 987 node.flow_match_sample_field_base_offset = 988 (start / CHAR_BIT) & 0xFF; 989 /* Allocate sample register. */ 990 if (parser->num_samples >= MLX5_GRAPH_NODE_SAMPLE_NUM || 991 parser->num_samples >= attr->max_num_sample || 992 parser->num_samples >= attr->max_num_prog_sample) 993 return rte_flow_error_set 994 (error, EINVAL, 995 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 996 "no sample registers to handle all flex item fields"); 997 parser->devx_conf.sample[parser->num_samples] = node; 998 parser->num_samples++; 999 /* Remove or update covered intervals. */ 1000 end = start + 32; 1001 while (idx < cover->num) { 1002 if (end >= cover->end[idx]) { 1003 idx++; 1004 continue; 1005 } 1006 if (end > cover->start[idx]) 1007 cover->start[idx] = end; 1008 break; 1009 } 1010 } 1011 return 0; 1012 } 1013 1014 static int 1015 mlx5_flex_translate_sample(struct mlx5_hca_flex_attr *attr, 1016 const struct rte_flow_item_flex_conf *conf, 1017 struct mlx5_flex_parser_devx *parser, 1018 struct mlx5_flex_item *item, 1019 struct rte_flow_error *error) 1020 { 1021 struct mlx5_flex_field_cover cover; 1022 uint32_t i, j; 1023 int ret; 1024 1025 switch (conf->tunnel) { 1026 case FLEX_TUNNEL_MODE_SINGLE: 1027 /* Fallthrough */ 1028 case FLEX_TUNNEL_MODE_OUTER: 1029 /* Fallthrough */ 1030 case FLEX_TUNNEL_MODE_INNER: 1031 /* Fallthrough */ 1032 case FLEX_TUNNEL_MODE_MULTI: 1033 /* Fallthrough */ 1034 case FLEX_TUNNEL_MODE_TUNNEL: 1035 break; 1036 default: 1037 return rte_flow_error_set 1038 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1039 "unrecognized tunnel mode"); 1040 } 1041 item->tunnel_mode = conf->tunnel; 1042 if (conf->nb_samples > MLX5_FLEX_ITEM_MAPPING_NUM) 1043 return rte_flow_error_set 1044 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1045 "sample field number exceeds limit"); 1046 /* 1047 * The application can specify fields smaller or bigger than 32 bits 1048 * covered with single sample register and it can specify field 1049 * offsets in any order. 1050 * 1051 * Gather all similar fields together, build array of bit intervals 1052 * in ascending order and try to cover with the smallest set of sample 1053 * registers. 1054 */ 1055 memset(&cover, 0, sizeof(cover)); 1056 for (i = 0; i < conf->nb_samples; i++) { 1057 struct rte_flow_item_flex_field *fl = conf->sample_data + i; 1058 1059 /* Check whether field was covered in the previous iteration. */ 1060 if (cover.mapped[i / CHAR_BIT] & (1u << (i % CHAR_BIT))) 1061 continue; 1062 if (fl->field_mode == FIELD_MODE_DUMMY) 1063 continue; 1064 /* Build an interval array for the field and similar ones */ 1065 cover.num = 0; 1066 /* Add the first field to array unconditionally. */ 1067 ret = mlx5_flex_cover_sample(&cover, fl, NULL, attr, error); 1068 if (ret < 0) 1069 return ret; 1070 MLX5_ASSERT(ret > 0); 1071 cover.mapped[i / CHAR_BIT] |= 1u << (i % CHAR_BIT); 1072 for (j = i + 1; j < conf->nb_samples; j++) { 1073 struct rte_flow_item_flex_field *ft; 1074 1075 /* Add field to array if its type matches. */ 1076 ft = conf->sample_data + j; 1077 ret = mlx5_flex_cover_sample(&cover, ft, fl, 1078 attr, error); 1079 if (ret < 0) 1080 return ret; 1081 if (!ret) 1082 continue; 1083 cover.mapped[j / CHAR_BIT] |= 1u << (j % CHAR_BIT); 1084 } 1085 /* Allocate sample registers to cover array of intervals. */ 1086 ret = mlx5_flex_alloc_sample(&cover, parser, item, 1087 fl, attr, error); 1088 if (ret) 1089 return ret; 1090 } 1091 /* Build the item pattern translating data on flow creation. */ 1092 item->mapnum = 0; 1093 memset(&item->map, 0, sizeof(item->map)); 1094 for (i = 0; i < conf->nb_samples; i++) { 1095 struct rte_flow_item_flex_field *fl = conf->sample_data + i; 1096 1097 ret = mlx5_flex_map_sample(fl, parser, item, error); 1098 if (ret) { 1099 MLX5_ASSERT(false); 1100 return ret; 1101 } 1102 } 1103 if (conf->tunnel == FLEX_TUNNEL_MODE_MULTI) { 1104 /* 1105 * In FLEX_TUNNEL_MODE_MULTI tunnel mode PMD creates 2 sets 1106 * of samples. The first set is for outer and the second set 1107 * for inner flex flow item. Outer and inner samples differ 1108 * only in tunnel_mode. 1109 */ 1110 if (parser->num_samples > MLX5_GRAPH_NODE_SAMPLE_NUM / 2) 1111 return rte_flow_error_set 1112 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1113 "no sample registers for inner"); 1114 rte_memcpy(parser->devx_conf.sample + parser->num_samples, 1115 parser->devx_conf.sample, 1116 parser->num_samples * 1117 sizeof(parser->devx_conf.sample[0])); 1118 for (i = 0; i < parser->num_samples; i++) { 1119 struct mlx5_devx_match_sample_attr *sm = i + 1120 parser->devx_conf.sample + parser->num_samples; 1121 1122 sm->flow_match_sample_tunnel_mode = 1123 MLX5_GRAPH_SAMPLE_TUNNEL_INNER; 1124 } 1125 parser->num_samples *= 2; 1126 } 1127 return 0; 1128 } 1129 1130 static int 1131 mlx5_flex_arc_type(enum rte_flow_item_type type, int in) 1132 { 1133 switch (type) { 1134 case RTE_FLOW_ITEM_TYPE_ETH: 1135 return MLX5_GRAPH_ARC_NODE_MAC; 1136 case RTE_FLOW_ITEM_TYPE_IPV4: 1137 return in ? MLX5_GRAPH_ARC_NODE_IP : MLX5_GRAPH_ARC_NODE_IPV4; 1138 case RTE_FLOW_ITEM_TYPE_IPV6: 1139 return in ? MLX5_GRAPH_ARC_NODE_IP : MLX5_GRAPH_ARC_NODE_IPV6; 1140 case RTE_FLOW_ITEM_TYPE_UDP: 1141 return MLX5_GRAPH_ARC_NODE_UDP; 1142 case RTE_FLOW_ITEM_TYPE_TCP: 1143 return MLX5_GRAPH_ARC_NODE_TCP; 1144 case RTE_FLOW_ITEM_TYPE_MPLS: 1145 return MLX5_GRAPH_ARC_NODE_MPLS; 1146 case RTE_FLOW_ITEM_TYPE_GRE: 1147 return MLX5_GRAPH_ARC_NODE_GRE; 1148 case RTE_FLOW_ITEM_TYPE_GENEVE: 1149 return MLX5_GRAPH_ARC_NODE_GENEVE; 1150 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: 1151 return MLX5_GRAPH_ARC_NODE_VXLAN_GPE; 1152 case RTE_FLOW_ITEM_TYPE_ESP: 1153 return MLX5_GRAPH_ARC_NODE_IPSEC_ESP; 1154 default: 1155 return -EINVAL; 1156 } 1157 } 1158 1159 static int 1160 mlx5_flex_arc_in_eth(const struct rte_flow_item *item, 1161 struct rte_flow_error *error) 1162 { 1163 const struct rte_flow_item_eth *spec = item->spec; 1164 const struct rte_flow_item_eth *mask = item->mask; 1165 struct rte_flow_item_eth eth = { .hdr.ether_type = RTE_BE16(0xFFFF) }; 1166 1167 if (memcmp(mask, ð, sizeof(struct rte_flow_item_eth))) { 1168 return rte_flow_error_set 1169 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, 1170 "invalid eth item mask"); 1171 } 1172 return rte_be_to_cpu_16(spec->hdr.ether_type); 1173 } 1174 1175 static int 1176 mlx5_flex_arc_in_udp(const struct rte_flow_item *item, 1177 struct rte_flow_error *error) 1178 { 1179 const struct rte_flow_item_udp *spec = item->spec; 1180 const struct rte_flow_item_udp *mask = item->mask; 1181 struct rte_flow_item_udp udp = { .hdr.dst_port = RTE_BE16(0xFFFF) }; 1182 1183 if (memcmp(mask, &udp, sizeof(struct rte_flow_item_udp))) { 1184 return rte_flow_error_set 1185 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, 1186 "invalid eth item mask"); 1187 } 1188 return rte_be_to_cpu_16(spec->hdr.dst_port); 1189 } 1190 1191 static int 1192 mlx5_flex_arc_in_ipv4(const struct rte_flow_item *item, 1193 struct rte_flow_error *error) 1194 { 1195 const struct rte_flow_item_ipv4 *spec = item->spec; 1196 const struct rte_flow_item_ipv4 *mask = item->mask; 1197 struct rte_flow_item_ipv4 ip = { .hdr.next_proto_id = 0xff }; 1198 1199 if (memcmp(mask, &ip, sizeof(struct rte_flow_item_ipv4))) { 1200 return rte_flow_error_set 1201 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, 1202 "invalid ipv4 item mask, full mask is desired"); 1203 } 1204 return spec->hdr.next_proto_id; 1205 } 1206 1207 static int 1208 mlx5_flex_arc_in_ipv6(const struct rte_flow_item *item, 1209 struct rte_flow_error *error) 1210 { 1211 const struct rte_flow_item_ipv6 *spec = item->spec; 1212 const struct rte_flow_item_ipv6 *mask = item->mask; 1213 struct rte_flow_item_ipv6 ip = { .hdr.proto = 0xff }; 1214 1215 if (memcmp(mask, &ip, sizeof(struct rte_flow_item_ipv6))) { 1216 return rte_flow_error_set 1217 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, 1218 "invalid ipv6 item mask, full mask is desired"); 1219 } 1220 return spec->hdr.proto; 1221 } 1222 1223 static int 1224 mlx5_flex_translate_arc_in(struct mlx5_hca_flex_attr *attr, 1225 const struct rte_flow_item_flex_conf *conf, 1226 struct mlx5_flex_parser_devx *devx, 1227 struct mlx5_flex_item *item, 1228 struct rte_flow_error *error) 1229 { 1230 struct mlx5_devx_graph_node_attr *node = &devx->devx_conf; 1231 uint32_t i; 1232 1233 RTE_SET_USED(item); 1234 if (conf->nb_inputs > attr->max_num_arc_in) 1235 return rte_flow_error_set 1236 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1237 "too many input links"); 1238 for (i = 0; i < conf->nb_inputs; i++) { 1239 struct mlx5_devx_graph_arc_attr *arc = node->in + i; 1240 struct rte_flow_item_flex_link *link = conf->input_link + i; 1241 const struct rte_flow_item *rte_item = &link->item; 1242 int arc_type; 1243 int ret; 1244 1245 if (!rte_item->spec || !rte_item->mask || rte_item->last) 1246 return rte_flow_error_set 1247 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1248 "invalid flex item IN arc format"); 1249 arc_type = mlx5_flex_arc_type(rte_item->type, true); 1250 if (arc_type < 0 || !(attr->node_in & RTE_BIT32(arc_type))) 1251 return rte_flow_error_set 1252 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1253 "unsupported flex item IN arc type"); 1254 arc->arc_parse_graph_node = arc_type; 1255 arc->start_inner_tunnel = 0; 1256 /* 1257 * Configure arc IN condition value. The value location depends 1258 * on protocol. Current FW version supports IP & UDP for IN 1259 * arcs only, and locations for these protocols are defined. 1260 * Add more protocols when available. 1261 */ 1262 switch (rte_item->type) { 1263 case RTE_FLOW_ITEM_TYPE_ETH: 1264 ret = mlx5_flex_arc_in_eth(rte_item, error); 1265 break; 1266 case RTE_FLOW_ITEM_TYPE_UDP: 1267 ret = mlx5_flex_arc_in_udp(rte_item, error); 1268 break; 1269 case RTE_FLOW_ITEM_TYPE_IPV4: 1270 ret = mlx5_flex_arc_in_ipv4(rte_item, error); 1271 break; 1272 case RTE_FLOW_ITEM_TYPE_IPV6: 1273 ret = mlx5_flex_arc_in_ipv6(rte_item, error); 1274 break; 1275 default: 1276 MLX5_ASSERT(false); 1277 return rte_flow_error_set 1278 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1279 "unsupported flex item IN arc type"); 1280 } 1281 if (ret < 0) 1282 return ret; 1283 arc->compare_condition_value = (uint16_t)ret; 1284 } 1285 return 0; 1286 } 1287 1288 static int 1289 mlx5_flex_translate_arc_out(struct mlx5_hca_flex_attr *attr, 1290 const struct rte_flow_item_flex_conf *conf, 1291 struct mlx5_flex_parser_devx *devx, 1292 struct mlx5_flex_item *item, 1293 struct rte_flow_error *error) 1294 { 1295 struct mlx5_devx_graph_node_attr *node = &devx->devx_conf; 1296 bool is_tunnel = conf->tunnel == FLEX_TUNNEL_MODE_TUNNEL; 1297 uint32_t i; 1298 1299 RTE_SET_USED(item); 1300 if (conf->nb_outputs > attr->max_num_arc_out) 1301 return rte_flow_error_set 1302 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1303 "too many output links"); 1304 for (i = 0; i < conf->nb_outputs; i++) { 1305 struct mlx5_devx_graph_arc_attr *arc = node->out + i; 1306 struct rte_flow_item_flex_link *link = conf->output_link + i; 1307 const struct rte_flow_item *rte_item = &link->item; 1308 int arc_type; 1309 1310 if (rte_item->spec || rte_item->mask || rte_item->last) 1311 return rte_flow_error_set 1312 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1313 "flex node: invalid OUT arc format"); 1314 arc_type = mlx5_flex_arc_type(rte_item->type, false); 1315 if (arc_type < 0 || !(attr->node_out & RTE_BIT32(arc_type))) 1316 return rte_flow_error_set 1317 (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1318 "unsupported flex item OUT arc type"); 1319 arc->arc_parse_graph_node = arc_type; 1320 arc->start_inner_tunnel = !!is_tunnel; 1321 arc->compare_condition_value = link->next; 1322 } 1323 return 0; 1324 } 1325 1326 /* Translate RTE flex item API configuration into flaex parser settings. */ 1327 static int 1328 mlx5_flex_translate_conf(struct rte_eth_dev *dev, 1329 const struct rte_flow_item_flex_conf *conf, 1330 struct mlx5_flex_parser_devx *devx, 1331 struct mlx5_flex_item *item, 1332 struct rte_flow_error *error) 1333 { 1334 struct mlx5_priv *priv = dev->data->dev_private; 1335 struct mlx5_hca_flex_attr *attr = &priv->sh->cdev->config.hca_attr.flex; 1336 int ret; 1337 1338 ret = mlx5_flex_translate_length(attr, conf, devx, error); 1339 if (ret) 1340 return ret; 1341 ret = mlx5_flex_translate_next(attr, conf, devx, error); 1342 if (ret) 1343 return ret; 1344 ret = mlx5_flex_translate_sample(attr, conf, devx, item, error); 1345 if (ret) 1346 return ret; 1347 ret = mlx5_flex_translate_arc_in(attr, conf, devx, item, error); 1348 if (ret) 1349 return ret; 1350 ret = mlx5_flex_translate_arc_out(attr, conf, devx, item, error); 1351 if (ret) 1352 return ret; 1353 return 0; 1354 } 1355 1356 /** 1357 * Create the flex item with specified configuration over the Ethernet device. 1358 * 1359 * @param dev 1360 * Ethernet device to create flex item on. 1361 * @param[in] conf 1362 * Flex item configuration. 1363 * @param[out] error 1364 * Perform verbose error reporting if not NULL. PMDs initialize this 1365 * structure in case of error only. 1366 * 1367 * @return 1368 * Non-NULL opaque pointer on success, NULL otherwise and rte_errno is set. 1369 */ 1370 struct rte_flow_item_flex_handle * 1371 flow_dv_item_create(struct rte_eth_dev *dev, 1372 const struct rte_flow_item_flex_conf *conf, 1373 struct rte_flow_error *error) 1374 { 1375 struct mlx5_priv *priv = dev->data->dev_private; 1376 struct mlx5_flex_parser_devx devx_config = { .devx_obj = NULL }; 1377 struct mlx5_flex_item *flex; 1378 struct mlx5_list_entry *ent; 1379 1380 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); 1381 flex = mlx5_flex_alloc(priv); 1382 if (!flex) { 1383 rte_flow_error_set(error, ENOMEM, 1384 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 1385 "too many flex items created on the port"); 1386 return NULL; 1387 } 1388 if (mlx5_flex_translate_conf(dev, conf, &devx_config, flex, error)) 1389 goto error; 1390 ent = mlx5_list_register(priv->sh->flex_parsers_dv, &devx_config); 1391 if (!ent) { 1392 rte_flow_error_set(error, ENOMEM, 1393 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 1394 "flex item creation failure"); 1395 goto error; 1396 } 1397 flex->devx_fp = container_of(ent, struct mlx5_flex_parser_devx, entry); 1398 /* Mark initialized flex item valid. */ 1399 rte_atomic_fetch_add_explicit(&flex->refcnt, 1, rte_memory_order_release); 1400 return (struct rte_flow_item_flex_handle *)flex; 1401 1402 error: 1403 mlx5_flex_free(priv, flex); 1404 return NULL; 1405 } 1406 1407 /** 1408 * Release the flex item on the specified Ethernet device. 1409 * 1410 * @param dev 1411 * Ethernet device to destroy flex item on. 1412 * @param[in] handle 1413 * Handle of the item existing on the specified device. 1414 * @param[out] error 1415 * Perform verbose error reporting if not NULL. PMDs initialize this 1416 * structure in case of error only. 1417 * 1418 * @return 1419 * 0 on success, a negative errno value otherwise and rte_errno is set. 1420 */ 1421 int 1422 flow_dv_item_release(struct rte_eth_dev *dev, 1423 const struct rte_flow_item_flex_handle *handle, 1424 struct rte_flow_error *error) 1425 { 1426 struct mlx5_priv *priv = dev->data->dev_private; 1427 struct mlx5_flex_item *flex = 1428 (struct mlx5_flex_item *)(uintptr_t)handle; 1429 uint32_t old_refcnt = 1; 1430 int rc; 1431 1432 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); 1433 rte_spinlock_lock(&priv->flex_item_sl); 1434 if (mlx5_flex_index(priv, flex) < 0) { 1435 rte_spinlock_unlock(&priv->flex_item_sl); 1436 return rte_flow_error_set(error, EINVAL, 1437 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1438 "invalid flex item handle value"); 1439 } 1440 if (!rte_atomic_compare_exchange_strong_explicit(&flex->refcnt, &old_refcnt, 0, 1441 rte_memory_order_acquire, rte_memory_order_relaxed)) { 1442 rte_spinlock_unlock(&priv->flex_item_sl); 1443 return rte_flow_error_set(error, EBUSY, 1444 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1445 "flex item has flow references"); 1446 } 1447 /* Flex item is marked as invalid, we can leave locked section. */ 1448 rte_spinlock_unlock(&priv->flex_item_sl); 1449 MLX5_ASSERT(flex->devx_fp); 1450 rc = mlx5_list_unregister(priv->sh->flex_parsers_dv, 1451 &flex->devx_fp->entry); 1452 flex->devx_fp = NULL; 1453 mlx5_flex_free(priv, flex); 1454 if (rc < 0) 1455 return rte_flow_error_set(error, EBUSY, 1456 RTE_FLOW_ERROR_TYPE_ITEM, NULL, 1457 "flex item release failure"); 1458 return 0; 1459 } 1460 1461 /* DevX flex parser list callbacks. */ 1462 struct mlx5_list_entry * 1463 mlx5_flex_parser_create_cb(void *list_ctx, void *ctx) 1464 { 1465 struct mlx5_dev_ctx_shared *sh = list_ctx; 1466 struct mlx5_flex_parser_devx *fp, *conf = ctx; 1467 uint32_t i; 1468 uint8_t sample_info = sh->cdev->config.hca_attr.flex.query_match_sample_info; 1469 int ret; 1470 1471 fp = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_flex_parser_devx), 1472 0, SOCKET_ID_ANY); 1473 if (!fp) 1474 return NULL; 1475 /* Copy the requested configurations. */ 1476 fp->num_samples = conf->num_samples; 1477 memcpy(&fp->devx_conf, &conf->devx_conf, sizeof(fp->devx_conf)); 1478 /* Create DevX flex parser. */ 1479 fp->devx_obj = mlx5_devx_cmd_create_flex_parser(sh->cdev->ctx, 1480 &fp->devx_conf); 1481 if (!fp->devx_obj) 1482 goto error; 1483 /* Query the firmware assigned sample ids. */ 1484 ret = mlx5_devx_cmd_query_parse_samples(fp->devx_obj, 1485 fp->sample_ids, 1486 fp->num_samples, 1487 &fp->anchor_id); 1488 if (ret) 1489 goto error; 1490 /* Query sample information per ID. */ 1491 for (i = 0; i < fp->num_samples && sample_info; i++) { 1492 ret = mlx5_devx_cmd_match_sample_info_query(sh->cdev->ctx, fp->sample_ids[i], 1493 &fp->sample_info[i]); 1494 if (ret) 1495 goto error; 1496 } 1497 DRV_LOG(DEBUG, "DEVx flex parser %p created, samples num: %u", 1498 (const void *)fp, fp->num_samples); 1499 return &fp->entry; 1500 error: 1501 if (fp->devx_obj) 1502 mlx5_devx_cmd_destroy((void *)(uintptr_t)fp->devx_obj); 1503 if (fp) 1504 mlx5_free(fp); 1505 return NULL; 1506 } 1507 1508 int 1509 mlx5_flex_parser_match_cb(void *list_ctx, 1510 struct mlx5_list_entry *iter, void *ctx) 1511 { 1512 struct mlx5_flex_parser_devx *fp = 1513 container_of(iter, struct mlx5_flex_parser_devx, entry); 1514 struct mlx5_flex_parser_devx *org = 1515 container_of(ctx, struct mlx5_flex_parser_devx, entry); 1516 1517 RTE_SET_USED(list_ctx); 1518 return !iter || !ctx || memcmp(&fp->devx_conf, 1519 &org->devx_conf, 1520 sizeof(fp->devx_conf)); 1521 } 1522 1523 void 1524 mlx5_flex_parser_remove_cb(void *list_ctx, struct mlx5_list_entry *entry) 1525 { 1526 struct mlx5_flex_parser_devx *fp = 1527 container_of(entry, struct mlx5_flex_parser_devx, entry); 1528 1529 RTE_SET_USED(list_ctx); 1530 MLX5_ASSERT(fp->devx_obj); 1531 claim_zero(mlx5_devx_cmd_destroy(fp->devx_obj)); 1532 DRV_LOG(DEBUG, "DEVx flex parser %p destroyed", (const void *)fp); 1533 mlx5_free(entry); 1534 } 1535 1536 struct mlx5_list_entry * 1537 mlx5_flex_parser_clone_cb(void *list_ctx, 1538 struct mlx5_list_entry *entry, void *ctx) 1539 { 1540 struct mlx5_flex_parser_devx *fp; 1541 1542 RTE_SET_USED(list_ctx); 1543 RTE_SET_USED(entry); 1544 fp = mlx5_malloc(0, sizeof(struct mlx5_flex_parser_devx), 1545 0, SOCKET_ID_ANY); 1546 if (!fp) 1547 return NULL; 1548 memcpy(fp, ctx, sizeof(struct mlx5_flex_parser_devx)); 1549 return &fp->entry; 1550 } 1551 1552 void 1553 mlx5_flex_parser_clone_free_cb(void *list_ctx, struct mlx5_list_entry *entry) 1554 { 1555 struct mlx5_flex_parser_devx *fp = 1556 container_of(entry, struct mlx5_flex_parser_devx, entry); 1557 RTE_SET_USED(list_ctx); 1558 mlx5_free(fp); 1559 } 1560