1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2021 Xilinx, Inc. 4 */ 5 6 #include <stdbool.h> 7 #include <stdint.h> 8 9 #include <rte_flow.h> 10 11 #include "sfc.h" 12 #include "sfc_dp.h" 13 #include "sfc_flow.h" 14 #include "sfc_dp_rx.h" 15 #include "sfc_flow_tunnel.h" 16 #include "sfc_mae.h" 17 18 bool 19 sfc_ft_is_supported(struct sfc_adapter *sa) 20 { 21 SFC_ASSERT(sfc_adapter_is_locked(sa)); 22 23 return ((sa->priv.dp_rx->features & SFC_DP_RX_FEAT_FLOW_MARK) != 0 && 24 sa->mae.status == SFC_MAE_STATUS_ADMIN); 25 } 26 27 bool 28 sfc_ft_is_active(struct sfc_adapter *sa) 29 { 30 SFC_ASSERT(sfc_adapter_is_locked(sa)); 31 32 return ((sa->negotiated_rx_metadata & 33 RTE_ETH_RX_METADATA_TUNNEL_ID) != 0); 34 } 35 36 struct sfc_ft_ctx * 37 sfc_ft_ctx_pick(struct sfc_adapter *sa, uint32_t flow_mark) 38 { 39 uint8_t ft_ctx_mark = SFC_FT_FLOW_MARK_TO_CTX_MARK(flow_mark); 40 41 SFC_ASSERT(sfc_adapter_is_locked(sa)); 42 43 if (ft_ctx_mark != SFC_FT_CTX_MARK_INVALID) { 44 sfc_ft_ctx_id_t ft_ctx_id = SFC_FT_CTX_MARK_TO_CTX_ID(ft_ctx_mark); 45 struct sfc_ft_ctx *ft_ctx = &sa->ft_ctx_pool[ft_ctx_id]; 46 47 ft_ctx->id = ft_ctx_id; 48 49 return ft_ctx; 50 } 51 52 return NULL; 53 } 54 55 int 56 sfc_ft_tunnel_rule_detect(struct sfc_adapter *sa, 57 const struct rte_flow_action *actions, 58 struct sfc_flow_spec_mae *spec, 59 struct rte_flow_error *error) 60 { 61 const struct rte_flow_action_mark *action_mark = NULL; 62 const struct rte_flow_action_jump *action_jump = NULL; 63 struct sfc_ft_ctx *ft_ctx; 64 uint32_t flow_mark = 0; 65 int rc = 0; 66 67 SFC_ASSERT(sfc_adapter_is_locked(sa)); 68 69 if (!sfc_ft_is_active(sa)) { 70 /* Tunnel-related actions (if any) will be turned down later. */ 71 return 0; 72 } 73 74 if (actions == NULL) { 75 rte_flow_error_set(error, EINVAL, 76 RTE_FLOW_ERROR_TYPE_ACTION_NUM, NULL, 77 "NULL actions"); 78 return -rte_errno; 79 } 80 81 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) { 82 if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) 83 continue; 84 85 if (actions->conf == NULL) { 86 rc = EINVAL; 87 continue; 88 } 89 90 switch (actions->type) { 91 case RTE_FLOW_ACTION_TYPE_COUNT: 92 break; 93 case RTE_FLOW_ACTION_TYPE_MARK: 94 if (action_mark == NULL) { 95 action_mark = actions->conf; 96 flow_mark = action_mark->id; 97 } else { 98 rc = EINVAL; 99 } 100 break; 101 case RTE_FLOW_ACTION_TYPE_JUMP: 102 if (action_jump == NULL) { 103 action_jump = actions->conf; 104 if (action_jump->group != 0) 105 rc = EINVAL; 106 } else { 107 rc = EINVAL; 108 } 109 break; 110 default: 111 rc = ENOTSUP; 112 break; 113 } 114 } 115 116 ft_ctx = sfc_ft_ctx_pick(sa, flow_mark); 117 if (ft_ctx != NULL && action_jump != 0) { 118 sfc_dbg(sa, "FT: TUNNEL: detected"); 119 120 if (rc != 0) { 121 /* The loop above might have spotted wrong actions. */ 122 sfc_err(sa, "FT: TUNNEL: invalid actions: %s", 123 strerror(rc)); 124 goto fail; 125 } 126 127 if (ft_ctx->refcnt == 0) { 128 sfc_err(sa, "FT: TUNNEL: inactive context (ID=%u)", 129 ft_ctx->id); 130 rc = ENOENT; 131 goto fail; 132 } 133 134 if (ft_ctx->tunnel_rule_is_set) { 135 sfc_err(sa, "FT: TUNNEL: already setup context (ID=%u)", 136 ft_ctx->id); 137 rc = EEXIST; 138 goto fail; 139 } 140 141 spec->ft_rule_type = SFC_FT_RULE_TUNNEL; 142 spec->ft_ctx = ft_ctx; 143 } 144 145 return 0; 146 147 fail: 148 return rte_flow_error_set(error, rc, 149 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 150 "FT: TUNNEL: preparsing failed"); 151 } 152 153 static int 154 sfc_ft_ctx_attach(struct sfc_adapter *sa, const struct rte_flow_tunnel *tunnel, 155 struct sfc_ft_ctx **ft_ctxp) 156 { 157 sfc_ft_ctx_id_t ft_ctx_id; 158 struct sfc_ft_ctx *ft_ctx; 159 const char *ft_ctx_status; 160 int ft_ctx_id_free = -1; 161 int rc; 162 163 SFC_ASSERT(sfc_adapter_is_locked(sa)); 164 165 rc = sfc_dp_ft_ctx_id_register(); 166 if (rc != 0) 167 return rc; 168 169 if (tunnel->type != RTE_FLOW_ITEM_TYPE_VXLAN) { 170 sfc_err(sa, "FT: unsupported tunnel (encapsulation) type"); 171 return ENOTSUP; 172 } 173 174 for (ft_ctx_id = 0; ft_ctx_id < SFC_FT_MAX_NTUNNELS; ++ft_ctx_id) { 175 ft_ctx = &sa->ft_ctx_pool[ft_ctx_id]; 176 177 if (ft_ctx->refcnt == 0) { 178 if (ft_ctx_id_free == -1) 179 ft_ctx_id_free = ft_ctx_id; 180 181 continue; 182 } 183 184 if (memcmp(tunnel, &ft_ctx->tunnel, sizeof(*tunnel)) == 0) { 185 ft_ctx_status = "existing"; 186 goto attach; 187 } 188 } 189 190 if (ft_ctx_id_free == -1) { 191 sfc_err(sa, "FT: no free slot for the new context"); 192 return ENOBUFS; 193 } 194 195 ft_ctx_id = ft_ctx_id_free; 196 ft_ctx = &sa->ft_ctx_pool[ft_ctx_id]; 197 198 memcpy(&ft_ctx->tunnel, tunnel, sizeof(*tunnel)); 199 200 ft_ctx->encap_type = EFX_TUNNEL_PROTOCOL_VXLAN; 201 202 ft_ctx->action_mark.id = SFC_FT_CTX_ID_TO_FLOW_MARK(ft_ctx_id); 203 ft_ctx->action.type = RTE_FLOW_ACTION_TYPE_MARK; 204 ft_ctx->action.conf = &ft_ctx->action_mark; 205 206 ft_ctx->item_mark_v.id = ft_ctx->action_mark.id; 207 ft_ctx->item.type = RTE_FLOW_ITEM_TYPE_MARK; 208 ft_ctx->item.spec = &ft_ctx->item_mark_v; 209 ft_ctx->item.mask = &ft_ctx->item_mark_m; 210 ft_ctx->item_mark_m.id = UINT32_MAX; 211 212 ft_ctx->tunnel_rule_is_set = B_FALSE; 213 214 ft_ctx->refcnt = 0; 215 216 ft_ctx_status = "newly added"; 217 218 attach: 219 sfc_dbg(sa, "FT: attaching to %s context (ID=%u)", 220 ft_ctx_status, ft_ctx_id); 221 222 ++(ft_ctx->refcnt); 223 *ft_ctxp = ft_ctx; 224 225 return 0; 226 } 227 228 static int 229 sfc_ft_ctx_detach(struct sfc_adapter *sa, uint32_t flow_mark) 230 { 231 struct sfc_ft_ctx *ft_ctx; 232 233 SFC_ASSERT(sfc_adapter_is_locked(sa)); 234 235 ft_ctx = sfc_ft_ctx_pick(sa, flow_mark); 236 if (ft_ctx == NULL) { 237 sfc_err(sa, "FT: invalid context"); 238 return EINVAL; 239 } 240 241 if (ft_ctx->refcnt == 0) { 242 sfc_err(sa, "FT: inactive context (ID=%u)", ft_ctx->id); 243 return ENOENT; 244 } 245 246 --(ft_ctx->refcnt); 247 248 return 0; 249 } 250 251 int 252 sfc_ft_decap_set(struct rte_eth_dev *dev, struct rte_flow_tunnel *tunnel, 253 struct rte_flow_action **pmd_actions, uint32_t *num_of_actions, 254 struct rte_flow_error *err) 255 { 256 struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); 257 struct sfc_ft_ctx *ft_ctx; 258 int rc; 259 260 sfc_adapter_lock(sa); 261 262 if (!sfc_ft_is_active(sa)) { 263 rc = ENOTSUP; 264 goto fail; 265 } 266 267 rc = sfc_ft_ctx_attach(sa, tunnel, &ft_ctx); 268 if (rc != 0) 269 goto fail; 270 271 *pmd_actions = &ft_ctx->action; 272 *num_of_actions = 1; 273 274 sfc_adapter_unlock(sa); 275 276 return 0; 277 278 fail: 279 sfc_adapter_unlock(sa); 280 281 return rte_flow_error_set(err, rc, 282 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 283 "FT: decap_set failed"); 284 } 285 286 int 287 sfc_ft_match(struct rte_eth_dev *dev, struct rte_flow_tunnel *tunnel, 288 struct rte_flow_item **pmd_items, uint32_t *num_of_items, 289 struct rte_flow_error *err) 290 { 291 struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); 292 struct sfc_ft_ctx *ft_ctx; 293 int rc; 294 295 sfc_adapter_lock(sa); 296 297 if (!sfc_ft_is_active(sa)) { 298 rc = ENOTSUP; 299 goto fail; 300 } 301 302 rc = sfc_ft_ctx_attach(sa, tunnel, &ft_ctx); 303 if (rc != 0) 304 goto fail; 305 306 *pmd_items = &ft_ctx->item; 307 *num_of_items = 1; 308 309 sfc_adapter_unlock(sa); 310 311 return 0; 312 313 fail: 314 sfc_adapter_unlock(sa); 315 316 return rte_flow_error_set(err, rc, 317 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 318 "FT: tunnel_match failed"); 319 } 320 321 int 322 sfc_ft_item_release(struct rte_eth_dev *dev, struct rte_flow_item *pmd_items, 323 uint32_t num_items, struct rte_flow_error *err) 324 { 325 struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); 326 const struct rte_flow_item_mark *item_mark; 327 struct rte_flow_item *item = pmd_items; 328 int rc; 329 330 sfc_adapter_lock(sa); 331 332 if (!sfc_ft_is_active(sa)) { 333 rc = ENOTSUP; 334 goto fail; 335 } 336 337 if (num_items != 1 || item == NULL || item->spec == NULL || 338 item->type != RTE_FLOW_ITEM_TYPE_MARK) { 339 sfc_err(sa, "FT: item_release: wrong input"); 340 rc = EINVAL; 341 goto fail; 342 } 343 344 item_mark = item->spec; 345 346 rc = sfc_ft_ctx_detach(sa, item_mark->id); 347 if (rc != 0) 348 goto fail; 349 350 sfc_adapter_unlock(sa); 351 352 return 0; 353 354 fail: 355 sfc_adapter_unlock(sa); 356 357 return rte_flow_error_set(err, rc, 358 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 359 "FT: item_release failed"); 360 } 361 362 int 363 sfc_ft_action_decap_release(struct rte_eth_dev *dev, 364 struct rte_flow_action *pmd_actions, 365 uint32_t num_actions, struct rte_flow_error *err) 366 { 367 struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); 368 const struct rte_flow_action_mark *action_mark; 369 struct rte_flow_action *action = pmd_actions; 370 int rc; 371 372 sfc_adapter_lock(sa); 373 374 if (!sfc_ft_is_active(sa)) { 375 rc = ENOTSUP; 376 goto fail; 377 } 378 379 if (num_actions != 1 || action == NULL || action->conf == NULL || 380 action->type != RTE_FLOW_ACTION_TYPE_MARK) { 381 sfc_err(sa, "FT: action_decap_release: wrong input"); 382 rc = EINVAL; 383 goto fail; 384 } 385 386 action_mark = action->conf; 387 388 rc = sfc_ft_ctx_detach(sa, action_mark->id); 389 if (rc != 0) 390 goto fail; 391 392 sfc_adapter_unlock(sa); 393 394 return 0; 395 396 fail: 397 sfc_adapter_unlock(sa); 398 399 return rte_flow_error_set(err, rc, 400 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 401 "FT: item_release failed"); 402 } 403 404 int 405 sfc_ft_get_restore_info(struct rte_eth_dev *dev, struct rte_mbuf *m, 406 struct rte_flow_restore_info *info, 407 struct rte_flow_error *err) 408 { 409 struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); 410 const struct sfc_ft_ctx *ft_ctx; 411 sfc_ft_ctx_id_t ft_ctx_id; 412 int rc; 413 414 sfc_adapter_lock(sa); 415 416 if ((m->ol_flags & sfc_dp_ft_ctx_id_valid) == 0) { 417 sfc_dbg(sa, "FT: get_restore_info: no FT context mark in the packet"); 418 rc = EINVAL; 419 goto fail; 420 } 421 422 ft_ctx_id = *RTE_MBUF_DYNFIELD(m, sfc_dp_ft_ctx_id_offset, 423 sfc_ft_ctx_id_t *); 424 ft_ctx = &sa->ft_ctx_pool[ft_ctx_id]; 425 426 if (ft_ctx->refcnt == 0) { 427 sfc_dbg(sa, "FT: get_restore_info: inactive context (ID=%u)", 428 ft_ctx_id); 429 rc = ENOENT; 430 goto fail; 431 } 432 433 memcpy(&info->tunnel, &ft_ctx->tunnel, sizeof(info->tunnel)); 434 435 /* 436 * The packet still has encapsulation header; TUNNEL rules never 437 * strip it. Therefore, set RTE_FLOW_RESTORE_INFO_ENCAPSULATED. 438 */ 439 info->flags = RTE_FLOW_RESTORE_INFO_ENCAPSULATED | 440 RTE_FLOW_RESTORE_INFO_GROUP_ID | 441 RTE_FLOW_RESTORE_INFO_TUNNEL; 442 443 info->group_id = 0; 444 445 sfc_adapter_unlock(sa); 446 447 return 0; 448 449 fail: 450 sfc_adapter_unlock(sa); 451 452 return rte_flow_error_set(err, rc, 453 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 454 "FT: get_restore_info failed"); 455 } 456 457 void 458 sfc_ft_counters_reset(struct sfc_adapter *sa) 459 { 460 unsigned int i; 461 462 SFC_ASSERT(sfc_adapter_is_locked(sa)); 463 SFC_ASSERT(sa->state != SFC_ETHDEV_STARTED); 464 465 for (i = 0; i < RTE_DIM(sa->ft_ctx_pool); ++i) { 466 struct sfc_ft_ctx *ft_ctx = &sa->ft_ctx_pool[i]; 467 468 ft_ctx->reset_tunnel_hit_counter = 0; 469 ft_ctx->switch_hit_counter = 0; 470 } 471 } 472