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