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_flow_tunnel_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_SUPPORTED); 25 } 26 27 bool 28 sfc_flow_tunnel_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_flow_tunnel * 37 sfc_flow_tunnel_pick(struct sfc_adapter *sa, uint32_t ft_mark) 38 { 39 uint32_t tunnel_mark = SFC_FT_GET_TUNNEL_MARK(ft_mark); 40 41 SFC_ASSERT(sfc_adapter_is_locked(sa)); 42 43 if (tunnel_mark != SFC_FT_TUNNEL_MARK_INVALID) { 44 sfc_ft_id_t ft_id = SFC_FT_TUNNEL_MARK_TO_ID(tunnel_mark); 45 struct sfc_flow_tunnel *ft = &sa->flow_tunnels[ft_id]; 46 47 ft->id = ft_id; 48 49 return ft; 50 } 51 52 return NULL; 53 } 54 55 int 56 sfc_flow_tunnel_detect_jump_rule(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_flow_tunnel *ft; 64 uint32_t ft_mark = 0; 65 int rc = 0; 66 67 SFC_ASSERT(sfc_adapter_is_locked(sa)); 68 69 if (!sfc_flow_tunnel_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 ft_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 = sfc_flow_tunnel_pick(sa, ft_mark); 117 if (ft != NULL && action_jump != 0) { 118 sfc_dbg(sa, "tunnel offload: JUMP: detected"); 119 120 if (rc != 0) { 121 /* The loop above might have spotted wrong actions. */ 122 sfc_err(sa, "tunnel offload: JUMP: invalid actions: %s", 123 strerror(rc)); 124 goto fail; 125 } 126 127 if (ft->refcnt == 0) { 128 sfc_err(sa, "tunnel offload: JUMP: tunnel=%u does not exist", 129 ft->id); 130 rc = ENOENT; 131 goto fail; 132 } 133 134 if (ft->jump_rule_is_set) { 135 sfc_err(sa, "tunnel offload: JUMP: already exists in tunnel=%u", 136 ft->id); 137 rc = EEXIST; 138 goto fail; 139 } 140 141 spec->ft_rule_type = SFC_FT_RULE_JUMP; 142 spec->ft = ft; 143 } 144 145 return 0; 146 147 fail: 148 return rte_flow_error_set(error, rc, 149 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 150 "tunnel offload: JUMP: preparsing failed"); 151 } 152 153 static int 154 sfc_flow_tunnel_attach(struct sfc_adapter *sa, 155 struct rte_flow_tunnel *tunnel, 156 struct sfc_flow_tunnel **ftp) 157 { 158 struct sfc_flow_tunnel *ft; 159 const char *ft_status; 160 int ft_id_free = -1; 161 sfc_ft_id_t ft_id; 162 int rc; 163 164 SFC_ASSERT(sfc_adapter_is_locked(sa)); 165 166 rc = sfc_dp_ft_id_register(); 167 if (rc != 0) 168 return rc; 169 170 if (tunnel->type != RTE_FLOW_ITEM_TYPE_VXLAN) { 171 sfc_err(sa, "tunnel offload: unsupported tunnel (encapsulation) type"); 172 return ENOTSUP; 173 } 174 175 for (ft_id = 0; ft_id < SFC_FT_MAX_NTUNNELS; ++ft_id) { 176 ft = &sa->flow_tunnels[ft_id]; 177 178 if (ft->refcnt == 0) { 179 if (ft_id_free == -1) 180 ft_id_free = ft_id; 181 182 continue; 183 } 184 185 if (memcmp(tunnel, &ft->rte_tunnel, sizeof(*tunnel)) == 0) { 186 ft_status = "existing"; 187 goto attach; 188 } 189 } 190 191 if (ft_id_free == -1) { 192 sfc_err(sa, "tunnel offload: no free slot for the new tunnel"); 193 return ENOBUFS; 194 } 195 196 ft_id = ft_id_free; 197 ft = &sa->flow_tunnels[ft_id]; 198 199 memcpy(&ft->rte_tunnel, tunnel, sizeof(*tunnel)); 200 201 ft->encap_type = EFX_TUNNEL_PROTOCOL_VXLAN; 202 203 ft->action_mark.id = SFC_FT_ID_TO_MARK(ft_id_free); 204 ft->action.type = RTE_FLOW_ACTION_TYPE_MARK; 205 ft->action.conf = &ft->action_mark; 206 207 ft->item.type = RTE_FLOW_ITEM_TYPE_MARK; 208 ft->item_mark_v.id = ft->action_mark.id; 209 ft->item.spec = &ft->item_mark_v; 210 ft->item.mask = &ft->item_mark_m; 211 ft->item_mark_m.id = UINT32_MAX; 212 213 ft->jump_rule_is_set = B_FALSE; 214 215 ft->refcnt = 0; 216 217 ft_status = "newly added"; 218 219 attach: 220 sfc_dbg(sa, "tunnel offload: attaching to %s tunnel=%u", 221 ft_status, ft_id); 222 223 ++(ft->refcnt); 224 *ftp = ft; 225 226 return 0; 227 } 228 229 static int 230 sfc_flow_tunnel_detach(struct sfc_adapter *sa, 231 uint32_t ft_mark) 232 { 233 struct sfc_flow_tunnel *ft; 234 235 SFC_ASSERT(sfc_adapter_is_locked(sa)); 236 237 ft = sfc_flow_tunnel_pick(sa, ft_mark); 238 if (ft == NULL) { 239 sfc_err(sa, "tunnel offload: invalid tunnel"); 240 return EINVAL; 241 } 242 243 if (ft->refcnt == 0) { 244 sfc_err(sa, "tunnel offload: tunnel=%u does not exist", ft->id); 245 return ENOENT; 246 } 247 248 --(ft->refcnt); 249 250 return 0; 251 } 252 253 int 254 sfc_flow_tunnel_decap_set(struct rte_eth_dev *dev, 255 struct rte_flow_tunnel *tunnel, 256 struct rte_flow_action **pmd_actions, 257 uint32_t *num_of_actions, 258 struct rte_flow_error *err) 259 { 260 struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); 261 struct sfc_flow_tunnel *ft; 262 int rc; 263 264 sfc_adapter_lock(sa); 265 266 if (!sfc_flow_tunnel_is_active(sa)) { 267 rc = ENOTSUP; 268 goto fail; 269 } 270 271 rc = sfc_flow_tunnel_attach(sa, tunnel, &ft); 272 if (rc != 0) 273 goto fail; 274 275 *pmd_actions = &ft->action; 276 *num_of_actions = 1; 277 278 sfc_adapter_unlock(sa); 279 280 return 0; 281 282 fail: 283 sfc_adapter_unlock(sa); 284 285 return rte_flow_error_set(err, rc, 286 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 287 "tunnel offload: decap_set failed"); 288 } 289 290 int 291 sfc_flow_tunnel_match(struct rte_eth_dev *dev, 292 struct rte_flow_tunnel *tunnel, 293 struct rte_flow_item **pmd_items, 294 uint32_t *num_of_items, 295 struct rte_flow_error *err) 296 { 297 struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); 298 struct sfc_flow_tunnel *ft; 299 int rc; 300 301 sfc_adapter_lock(sa); 302 303 if (!sfc_flow_tunnel_is_active(sa)) { 304 rc = ENOTSUP; 305 goto fail; 306 } 307 308 rc = sfc_flow_tunnel_attach(sa, tunnel, &ft); 309 if (rc != 0) 310 goto fail; 311 312 *pmd_items = &ft->item; 313 *num_of_items = 1; 314 315 sfc_adapter_unlock(sa); 316 317 return 0; 318 319 fail: 320 sfc_adapter_unlock(sa); 321 322 return rte_flow_error_set(err, rc, 323 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 324 "tunnel offload: tunnel_match failed"); 325 } 326 327 int 328 sfc_flow_tunnel_item_release(struct rte_eth_dev *dev, 329 struct rte_flow_item *pmd_items, 330 uint32_t num_items, 331 struct rte_flow_error *err) 332 { 333 struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); 334 const struct rte_flow_item_mark *item_mark; 335 struct rte_flow_item *item = pmd_items; 336 int rc; 337 338 sfc_adapter_lock(sa); 339 340 if (!sfc_flow_tunnel_is_active(sa)) { 341 rc = ENOTSUP; 342 goto fail; 343 } 344 345 if (num_items != 1 || item == NULL || item->spec == NULL || 346 item->type != RTE_FLOW_ITEM_TYPE_MARK) { 347 sfc_err(sa, "tunnel offload: item_release: wrong input"); 348 rc = EINVAL; 349 goto fail; 350 } 351 352 item_mark = item->spec; 353 354 rc = sfc_flow_tunnel_detach(sa, item_mark->id); 355 if (rc != 0) 356 goto fail; 357 358 sfc_adapter_unlock(sa); 359 360 return 0; 361 362 fail: 363 sfc_adapter_unlock(sa); 364 365 return rte_flow_error_set(err, rc, 366 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 367 "tunnel offload: item_release failed"); 368 } 369 370 int 371 sfc_flow_tunnel_action_decap_release(struct rte_eth_dev *dev, 372 struct rte_flow_action *pmd_actions, 373 uint32_t num_actions, 374 struct rte_flow_error *err) 375 { 376 struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); 377 const struct rte_flow_action_mark *action_mark; 378 struct rte_flow_action *action = pmd_actions; 379 int rc; 380 381 sfc_adapter_lock(sa); 382 383 if (!sfc_flow_tunnel_is_active(sa)) { 384 rc = ENOTSUP; 385 goto fail; 386 } 387 388 if (num_actions != 1 || action == NULL || action->conf == NULL || 389 action->type != RTE_FLOW_ACTION_TYPE_MARK) { 390 sfc_err(sa, "tunnel offload: action_decap_release: wrong input"); 391 rc = EINVAL; 392 goto fail; 393 } 394 395 action_mark = action->conf; 396 397 rc = sfc_flow_tunnel_detach(sa, action_mark->id); 398 if (rc != 0) 399 goto fail; 400 401 sfc_adapter_unlock(sa); 402 403 return 0; 404 405 fail: 406 sfc_adapter_unlock(sa); 407 408 return rte_flow_error_set(err, rc, 409 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 410 "tunnel offload: item_release failed"); 411 } 412 413 int 414 sfc_flow_tunnel_get_restore_info(struct rte_eth_dev *dev, 415 struct rte_mbuf *m, 416 struct rte_flow_restore_info *info, 417 struct rte_flow_error *err) 418 { 419 struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); 420 const struct sfc_flow_tunnel *ft; 421 sfc_ft_id_t ft_id; 422 int rc; 423 424 sfc_adapter_lock(sa); 425 426 if ((m->ol_flags & sfc_dp_ft_id_valid) == 0) { 427 sfc_dbg(sa, "tunnel offload: get_restore_info: no tunnel mark in the packet"); 428 rc = EINVAL; 429 goto fail; 430 } 431 432 ft_id = *RTE_MBUF_DYNFIELD(m, sfc_dp_ft_id_offset, sfc_ft_id_t *); 433 ft = &sa->flow_tunnels[ft_id]; 434 435 if (ft->refcnt == 0) { 436 sfc_err(sa, "tunnel offload: get_restore_info: tunnel=%u does not exist", 437 ft_id); 438 rc = ENOENT; 439 goto fail; 440 } 441 442 memcpy(&info->tunnel, &ft->rte_tunnel, sizeof(info->tunnel)); 443 444 /* 445 * The packet still has encapsulation header; JUMP rules never 446 * strip it. Therefore, set RTE_FLOW_RESTORE_INFO_ENCAPSULATED. 447 */ 448 info->flags = RTE_FLOW_RESTORE_INFO_ENCAPSULATED | 449 RTE_FLOW_RESTORE_INFO_GROUP_ID | 450 RTE_FLOW_RESTORE_INFO_TUNNEL; 451 452 info->group_id = 0; 453 454 sfc_adapter_unlock(sa); 455 456 return 0; 457 458 fail: 459 sfc_adapter_unlock(sa); 460 461 return rte_flow_error_set(err, rc, 462 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 463 "tunnel offload: get_restore_info failed"); 464 } 465 466 void 467 sfc_flow_tunnel_reset_hit_counters(struct sfc_adapter *sa) 468 { 469 unsigned int i; 470 471 SFC_ASSERT(sfc_adapter_is_locked(sa)); 472 SFC_ASSERT(sa->state != SFC_ETHDEV_STARTED); 473 474 for (i = 0; i < RTE_DIM(sa->flow_tunnels); ++i) { 475 struct sfc_flow_tunnel *ft = &sa->flow_tunnels[i]; 476 477 ft->reset_jump_hit_counter = 0; 478 ft->group_hit_counter = 0; 479 } 480 } 481