1 // SPDX-License-Identifier: GPL-2.0+ 2 3 #include "lan966x_main.h" 4 #include "vcap_api.h" 5 #include "vcap_api_client.h" 6 #include "vcap_tc.h" 7 8 #define LAN966X_FORCE_UNTAGED 3 9 10 static bool lan966x_tc_is_known_etype(struct vcap_tc_flower_parse_usage *st, 11 u16 etype) 12 { 13 switch (st->admin->vtype) { 14 case VCAP_TYPE_IS1: 15 switch (etype) { 16 case ETH_P_ALL: 17 case ETH_P_ARP: 18 case ETH_P_IP: 19 case ETH_P_IPV6: 20 return true; 21 } 22 break; 23 case VCAP_TYPE_IS2: 24 switch (etype) { 25 case ETH_P_ALL: 26 case ETH_P_ARP: 27 case ETH_P_IP: 28 case ETH_P_IPV6: 29 case ETH_P_SNAP: 30 case ETH_P_802_2: 31 return true; 32 } 33 break; 34 case VCAP_TYPE_ES0: 35 return true; 36 default: 37 NL_SET_ERR_MSG_MOD(st->fco->common.extack, 38 "VCAP type not supported"); 39 return false; 40 } 41 42 return false; 43 } 44 45 static int 46 lan966x_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st) 47 { 48 struct flow_match_control match; 49 int err = 0; 50 51 flow_rule_match_control(st->frule, &match); 52 if (match.mask->flags & FLOW_DIS_IS_FRAGMENT) { 53 if (match.key->flags & FLOW_DIS_IS_FRAGMENT) 54 err = vcap_rule_add_key_bit(st->vrule, 55 VCAP_KF_L3_FRAGMENT, 56 VCAP_BIT_1); 57 else 58 err = vcap_rule_add_key_bit(st->vrule, 59 VCAP_KF_L3_FRAGMENT, 60 VCAP_BIT_0); 61 if (err) 62 goto out; 63 } 64 65 if (match.mask->flags & FLOW_DIS_FIRST_FRAG) { 66 if (match.key->flags & FLOW_DIS_FIRST_FRAG) 67 err = vcap_rule_add_key_bit(st->vrule, 68 VCAP_KF_L3_FRAG_OFS_GT0, 69 VCAP_BIT_0); 70 else 71 err = vcap_rule_add_key_bit(st->vrule, 72 VCAP_KF_L3_FRAG_OFS_GT0, 73 VCAP_BIT_1); 74 if (err) 75 goto out; 76 } 77 78 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL); 79 80 return err; 81 82 out: 83 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error"); 84 return err; 85 } 86 87 static int 88 lan966x_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st) 89 { 90 struct flow_match_basic match; 91 int err = 0; 92 93 flow_rule_match_basic(st->frule, &match); 94 if (match.mask->n_proto) { 95 st->l3_proto = be16_to_cpu(match.key->n_proto); 96 if (!lan966x_tc_is_known_etype(st, st->l3_proto)) { 97 err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE, 98 st->l3_proto, ~0); 99 if (err) 100 goto out; 101 } else if (st->l3_proto == ETH_P_IP) { 102 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, 103 VCAP_BIT_1); 104 if (err) 105 goto out; 106 } else if (st->l3_proto == ETH_P_IPV6 && 107 st->admin->vtype == VCAP_TYPE_IS1) { 108 /* Don't set any keys in this case */ 109 } else if (st->l3_proto == ETH_P_SNAP && 110 st->admin->vtype == VCAP_TYPE_IS1) { 111 err = vcap_rule_add_key_bit(st->vrule, 112 VCAP_KF_ETYPE_LEN_IS, 113 VCAP_BIT_0); 114 if (err) 115 goto out; 116 117 err = vcap_rule_add_key_bit(st->vrule, 118 VCAP_KF_IP_SNAP_IS, 119 VCAP_BIT_1); 120 if (err) 121 goto out; 122 } else if (st->admin->vtype == VCAP_TYPE_IS1) { 123 err = vcap_rule_add_key_bit(st->vrule, 124 VCAP_KF_ETYPE_LEN_IS, 125 VCAP_BIT_1); 126 if (err) 127 goto out; 128 129 err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE, 130 st->l3_proto, ~0); 131 if (err) 132 goto out; 133 } 134 } 135 if (match.mask->ip_proto) { 136 st->l4_proto = match.key->ip_proto; 137 138 if (st->l4_proto == IPPROTO_TCP) { 139 if (st->admin->vtype == VCAP_TYPE_IS1) { 140 err = vcap_rule_add_key_bit(st->vrule, 141 VCAP_KF_TCP_UDP_IS, 142 VCAP_BIT_1); 143 if (err) 144 goto out; 145 } 146 147 err = vcap_rule_add_key_bit(st->vrule, 148 VCAP_KF_TCP_IS, 149 VCAP_BIT_1); 150 if (err) 151 goto out; 152 } else if (st->l4_proto == IPPROTO_UDP) { 153 if (st->admin->vtype == VCAP_TYPE_IS1) { 154 err = vcap_rule_add_key_bit(st->vrule, 155 VCAP_KF_TCP_UDP_IS, 156 VCAP_BIT_1); 157 if (err) 158 goto out; 159 } 160 161 err = vcap_rule_add_key_bit(st->vrule, 162 VCAP_KF_TCP_IS, 163 VCAP_BIT_0); 164 if (err) 165 goto out; 166 } else { 167 err = vcap_rule_add_key_u32(st->vrule, 168 VCAP_KF_L3_IP_PROTO, 169 st->l4_proto, ~0); 170 if (err) 171 goto out; 172 } 173 } 174 175 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC); 176 return err; 177 out: 178 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error"); 179 return err; 180 } 181 182 static int 183 lan966x_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st) 184 { 185 if (st->admin->vtype != VCAP_TYPE_IS1) { 186 NL_SET_ERR_MSG_MOD(st->fco->common.extack, 187 "cvlan not supported in this VCAP"); 188 return -EINVAL; 189 } 190 191 return vcap_tc_flower_handler_cvlan_usage(st); 192 } 193 194 static int 195 lan966x_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st) 196 { 197 enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS; 198 enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS; 199 200 if (st->admin->vtype == VCAP_TYPE_IS1) { 201 vid_key = VCAP_KF_8021Q_VID0; 202 pcp_key = VCAP_KF_8021Q_PCP0; 203 } 204 205 return vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key); 206 } 207 208 static int 209 (*lan966x_tc_flower_handlers_usage[])(struct vcap_tc_flower_parse_usage *st) = { 210 [FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage, 211 [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage, 212 [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage, 213 [FLOW_DISSECTOR_KEY_CONTROL] = lan966x_tc_flower_handler_control_usage, 214 [FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage, 215 [FLOW_DISSECTOR_KEY_BASIC] = lan966x_tc_flower_handler_basic_usage, 216 [FLOW_DISSECTOR_KEY_CVLAN] = lan966x_tc_flower_handler_cvlan_usage, 217 [FLOW_DISSECTOR_KEY_VLAN] = lan966x_tc_flower_handler_vlan_usage, 218 [FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage, 219 [FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage, 220 [FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage, 221 }; 222 223 static int lan966x_tc_flower_use_dissectors(struct flow_cls_offload *f, 224 struct vcap_admin *admin, 225 struct vcap_rule *vrule, 226 u16 *l3_proto) 227 { 228 struct vcap_tc_flower_parse_usage state = { 229 .fco = f, 230 .vrule = vrule, 231 .l3_proto = ETH_P_ALL, 232 .admin = admin, 233 }; 234 int err = 0; 235 236 state.frule = flow_cls_offload_flow_rule(f); 237 for (int i = 0; i < ARRAY_SIZE(lan966x_tc_flower_handlers_usage); ++i) { 238 if (!flow_rule_match_key(state.frule, i) || 239 !lan966x_tc_flower_handlers_usage[i]) 240 continue; 241 242 err = lan966x_tc_flower_handlers_usage[i](&state); 243 if (err) 244 return err; 245 } 246 247 if (l3_proto) 248 *l3_proto = state.l3_proto; 249 250 return err; 251 } 252 253 static int lan966x_tc_flower_action_check(struct vcap_control *vctrl, 254 struct net_device *dev, 255 struct flow_cls_offload *fco, 256 bool ingress) 257 { 258 struct flow_rule *rule = flow_cls_offload_flow_rule(fco); 259 struct flow_action_entry *actent, *last_actent = NULL; 260 struct flow_action *act = &rule->action; 261 u64 action_mask = 0; 262 int idx; 263 264 if (!flow_action_has_entries(act)) { 265 NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions"); 266 return -EINVAL; 267 } 268 269 if (!flow_action_basic_hw_stats_check(act, fco->common.extack)) 270 return -EOPNOTSUPP; 271 272 flow_action_for_each(idx, actent, act) { 273 if (action_mask & BIT(actent->id)) { 274 NL_SET_ERR_MSG_MOD(fco->common.extack, 275 "More actions of the same type"); 276 return -EINVAL; 277 } 278 action_mask |= BIT(actent->id); 279 last_actent = actent; /* Save last action for later check */ 280 } 281 282 /* Check that last action is a goto 283 * The last chain/lookup does not need to have goto action 284 */ 285 if (last_actent->id == FLOW_ACTION_GOTO) { 286 /* Check if the destination chain is in one of the VCAPs */ 287 if (!vcap_is_next_lookup(vctrl, fco->common.chain_index, 288 last_actent->chain_index)) { 289 NL_SET_ERR_MSG_MOD(fco->common.extack, 290 "Invalid goto chain"); 291 return -EINVAL; 292 } 293 } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index, 294 ingress)) { 295 NL_SET_ERR_MSG_MOD(fco->common.extack, 296 "Last action must be 'goto'"); 297 return -EINVAL; 298 } 299 300 /* Catch unsupported combinations of actions */ 301 if (action_mask & BIT(FLOW_ACTION_TRAP) && 302 action_mask & BIT(FLOW_ACTION_ACCEPT)) { 303 NL_SET_ERR_MSG_MOD(fco->common.extack, 304 "Cannot combine pass and trap action"); 305 return -EOPNOTSUPP; 306 } 307 308 return 0; 309 } 310 311 /* Add the actionset that is the default for the VCAP type */ 312 static int lan966x_tc_set_actionset(struct vcap_admin *admin, 313 struct vcap_rule *vrule) 314 { 315 enum vcap_actionfield_set aset; 316 int err = 0; 317 318 switch (admin->vtype) { 319 case VCAP_TYPE_IS1: 320 aset = VCAP_AFS_S1; 321 break; 322 case VCAP_TYPE_IS2: 323 aset = VCAP_AFS_BASE_TYPE; 324 break; 325 case VCAP_TYPE_ES0: 326 aset = VCAP_AFS_VID; 327 break; 328 default: 329 return -EINVAL; 330 } 331 332 /* Do not overwrite any current actionset */ 333 if (vrule->actionset == VCAP_AFS_NO_VALUE) 334 err = vcap_set_rule_set_actionset(vrule, aset); 335 336 return err; 337 } 338 339 static int lan966x_tc_add_rule_link_target(struct vcap_admin *admin, 340 struct vcap_rule *vrule, 341 int target_cid) 342 { 343 int link_val = target_cid % VCAP_CID_LOOKUP_SIZE; 344 int err; 345 346 if (!link_val) 347 return 0; 348 349 switch (admin->vtype) { 350 case VCAP_TYPE_IS1: 351 /* Choose IS1 specific NXT_IDX key (for chaining rules from IS1) */ 352 err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL, 353 1, ~0); 354 if (err) 355 return err; 356 357 return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX, 358 link_val, ~0); 359 case VCAP_TYPE_IS2: 360 /* Add IS2 specific PAG key (for chaining rules from IS1) */ 361 return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG, 362 link_val, ~0); 363 case VCAP_TYPE_ES0: 364 /* Add ES0 specific ISDX key (for chaining rules from IS1) */ 365 return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, 366 link_val, ~0); 367 default: 368 break; 369 } 370 return 0; 371 } 372 373 static int lan966x_tc_add_rule_link(struct vcap_control *vctrl, 374 struct vcap_admin *admin, 375 struct vcap_rule *vrule, 376 struct flow_cls_offload *f, 377 int to_cid) 378 { 379 struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid); 380 int diff, err = 0; 381 382 if (!to_admin) { 383 NL_SET_ERR_MSG_MOD(f->common.extack, 384 "Unknown destination chain"); 385 return -EINVAL; 386 } 387 388 diff = vcap_chain_offset(vctrl, f->common.chain_index, to_cid); 389 if (!diff) 390 return 0; 391 392 /* Between IS1 and IS2 the PAG value is used */ 393 if (admin->vtype == VCAP_TYPE_IS1 && to_admin->vtype == VCAP_TYPE_IS2) { 394 /* This works for IS1->IS2 */ 395 err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff); 396 if (err) 397 return err; 398 399 err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_OVERRIDE_MASK, 400 0xff); 401 if (err) 402 return err; 403 } else if (admin->vtype == VCAP_TYPE_IS1 && 404 to_admin->vtype == VCAP_TYPE_ES0) { 405 /* This works for IS1->ES0 */ 406 err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_ADD_VAL, 407 diff); 408 if (err) 409 return err; 410 411 err = vcap_rule_add_action_bit(vrule, VCAP_AF_ISDX_REPLACE_ENA, 412 VCAP_BIT_1); 413 if (err) 414 return err; 415 } else { 416 NL_SET_ERR_MSG_MOD(f->common.extack, 417 "Unsupported chain destination"); 418 return -EOPNOTSUPP; 419 } 420 421 return err; 422 } 423 424 static int lan966x_tc_add_rule_counter(struct vcap_admin *admin, 425 struct vcap_rule *vrule) 426 { 427 int err = 0; 428 429 switch (admin->vtype) { 430 case VCAP_TYPE_ES0: 431 err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX, 432 vrule->id); 433 break; 434 default: 435 break; 436 } 437 438 return err; 439 } 440 441 static int lan966x_tc_flower_add(struct lan966x_port *port, 442 struct flow_cls_offload *f, 443 struct vcap_admin *admin, 444 bool ingress) 445 { 446 struct flow_action_entry *act; 447 u16 l3_proto = ETH_P_ALL; 448 struct flow_rule *frule; 449 struct vcap_rule *vrule; 450 int err, idx; 451 452 err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl, 453 port->dev, f, ingress); 454 if (err) 455 return err; 456 457 vrule = vcap_alloc_rule(port->lan966x->vcap_ctrl, port->dev, 458 f->common.chain_index, VCAP_USER_TC, 459 f->common.prio, 0); 460 if (IS_ERR(vrule)) 461 return PTR_ERR(vrule); 462 463 vrule->cookie = f->cookie; 464 err = lan966x_tc_flower_use_dissectors(f, admin, vrule, &l3_proto); 465 if (err) 466 goto out; 467 468 err = lan966x_tc_add_rule_link_target(admin, vrule, 469 f->common.chain_index); 470 if (err) 471 goto out; 472 473 frule = flow_cls_offload_flow_rule(f); 474 475 flow_action_for_each(idx, act, &frule->action) { 476 switch (act->id) { 477 case FLOW_ACTION_TRAP: 478 if (admin->vtype != VCAP_TYPE_IS2) { 479 NL_SET_ERR_MSG_MOD(f->common.extack, 480 "Trap action not supported in this VCAP"); 481 err = -EOPNOTSUPP; 482 goto out; 483 } 484 485 err = vcap_rule_add_action_bit(vrule, 486 VCAP_AF_CPU_COPY_ENA, 487 VCAP_BIT_1); 488 err |= vcap_rule_add_action_u32(vrule, 489 VCAP_AF_CPU_QUEUE_NUM, 490 0); 491 err |= vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE, 492 LAN966X_PMM_REPLACE); 493 if (err) 494 goto out; 495 496 break; 497 case FLOW_ACTION_GOTO: 498 err = lan966x_tc_set_actionset(admin, vrule); 499 if (err) 500 goto out; 501 502 err = lan966x_tc_add_rule_link(port->lan966x->vcap_ctrl, 503 admin, vrule, 504 f, act->chain_index); 505 if (err) 506 goto out; 507 508 break; 509 case FLOW_ACTION_VLAN_POP: 510 if (admin->vtype != VCAP_TYPE_ES0) { 511 NL_SET_ERR_MSG_MOD(f->common.extack, 512 "Cannot use vlan pop on non es0"); 513 err = -EOPNOTSUPP; 514 goto out; 515 } 516 517 /* Force untag */ 518 err = vcap_rule_add_action_u32(vrule, VCAP_AF_PUSH_OUTER_TAG, 519 LAN966X_FORCE_UNTAGED); 520 if (err) 521 goto out; 522 523 break; 524 default: 525 NL_SET_ERR_MSG_MOD(f->common.extack, 526 "Unsupported TC action"); 527 err = -EOPNOTSUPP; 528 goto out; 529 } 530 } 531 532 err = lan966x_tc_add_rule_counter(admin, vrule); 533 if (err) { 534 vcap_set_tc_exterr(f, vrule); 535 goto out; 536 } 537 538 err = vcap_val_rule(vrule, l3_proto); 539 if (err) { 540 vcap_set_tc_exterr(f, vrule); 541 goto out; 542 } 543 544 err = vcap_add_rule(vrule); 545 if (err) 546 NL_SET_ERR_MSG_MOD(f->common.extack, 547 "Could not add the filter"); 548 out: 549 vcap_free_rule(vrule); 550 return err; 551 } 552 553 static int lan966x_tc_flower_del(struct lan966x_port *port, 554 struct flow_cls_offload *f, 555 struct vcap_admin *admin) 556 { 557 struct vcap_control *vctrl; 558 int err = -ENOENT, rule_id; 559 560 vctrl = port->lan966x->vcap_ctrl; 561 while (true) { 562 rule_id = vcap_lookup_rule_by_cookie(vctrl, f->cookie); 563 if (rule_id <= 0) 564 break; 565 566 err = vcap_del_rule(vctrl, port->dev, rule_id); 567 if (err) { 568 NL_SET_ERR_MSG_MOD(f->common.extack, 569 "Cannot delete rule"); 570 break; 571 } 572 } 573 574 return err; 575 } 576 577 static int lan966x_tc_flower_stats(struct lan966x_port *port, 578 struct flow_cls_offload *f, 579 struct vcap_admin *admin) 580 { 581 struct vcap_counter count = {}; 582 int err; 583 584 err = vcap_get_rule_count_by_cookie(port->lan966x->vcap_ctrl, 585 &count, f->cookie); 586 if (err) 587 return err; 588 589 flow_stats_update(&f->stats, 0x0, count.value, 0, 0, 590 FLOW_ACTION_HW_STATS_IMMEDIATE); 591 592 return err; 593 } 594 595 int lan966x_tc_flower(struct lan966x_port *port, 596 struct flow_cls_offload *f, 597 bool ingress) 598 { 599 struct vcap_admin *admin; 600 601 admin = vcap_find_admin(port->lan966x->vcap_ctrl, 602 f->common.chain_index); 603 if (!admin) { 604 NL_SET_ERR_MSG_MOD(f->common.extack, "Invalid chain"); 605 return -EINVAL; 606 } 607 608 switch (f->command) { 609 case FLOW_CLS_REPLACE: 610 return lan966x_tc_flower_add(port, f, admin, ingress); 611 case FLOW_CLS_DESTROY: 612 return lan966x_tc_flower_del(port, f, admin); 613 case FLOW_CLS_STATS: 614 return lan966x_tc_flower_stats(port, f, admin); 615 default: 616 return -EOPNOTSUPP; 617 } 618 619 return 0; 620 } 621