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