1 // SPDX-License-Identifier: (GPL-2.0 OR MIT) 2 /* Microsemi Ocelot Switch driver 3 * Copyright (c) 2019 Microsemi Corporation 4 */ 5 6 #include <net/pkt_cls.h> 7 #include <net/tc_act/tc_gact.h> 8 #include <soc/mscc/ocelot_vcap.h> 9 #include "ocelot_vcap.h" 10 11 /* Arbitrarily chosen constants for encoding the VCAP block and lookup number 12 * into the chain number. This is UAPI. 13 */ 14 #define VCAP_BLOCK 10000 15 #define VCAP_LOOKUP 1000 16 #define VCAP_IS1_NUM_LOOKUPS 3 17 #define VCAP_IS2_NUM_LOOKUPS 2 18 #define VCAP_IS2_NUM_PAG 256 19 #define VCAP_IS1_CHAIN(lookup) \ 20 (1 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP) 21 #define VCAP_IS2_CHAIN(lookup, pag) \ 22 (2 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP + (pag)) 23 24 static int ocelot_chain_to_block(int chain, bool ingress) 25 { 26 int lookup, pag; 27 28 if (!ingress) { 29 if (chain == 0) 30 return VCAP_ES0; 31 return -EOPNOTSUPP; 32 } 33 34 /* Backwards compatibility with older, single-chain tc-flower 35 * offload support in Ocelot 36 */ 37 if (chain == 0) 38 return VCAP_IS2; 39 40 for (lookup = 0; lookup < VCAP_IS1_NUM_LOOKUPS; lookup++) 41 if (chain == VCAP_IS1_CHAIN(lookup)) 42 return VCAP_IS1; 43 44 for (lookup = 0; lookup < VCAP_IS2_NUM_LOOKUPS; lookup++) 45 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++) 46 if (chain == VCAP_IS2_CHAIN(lookup, pag)) 47 return VCAP_IS2; 48 49 return -EOPNOTSUPP; 50 } 51 52 /* Caller must ensure this is a valid IS1 or IS2 chain first, 53 * by calling ocelot_chain_to_block. 54 */ 55 static int ocelot_chain_to_lookup(int chain) 56 { 57 return (chain / VCAP_LOOKUP) % 10; 58 } 59 60 /* Caller must ensure this is a valid IS2 chain first, 61 * by calling ocelot_chain_to_block. 62 */ 63 static int ocelot_chain_to_pag(int chain) 64 { 65 int lookup = ocelot_chain_to_lookup(chain); 66 67 /* calculate PAG value as chain index relative to the first PAG */ 68 return chain - VCAP_IS2_CHAIN(lookup, 0); 69 } 70 71 static bool ocelot_is_goto_target_valid(int goto_target, int chain, 72 bool ingress) 73 { 74 int pag; 75 76 /* Can't offload GOTO in VCAP ES0 */ 77 if (!ingress) 78 return (goto_target < 0); 79 80 /* Non-optional GOTOs */ 81 if (chain == 0) 82 /* VCAP IS1 can be skipped, either partially or completely */ 83 return (goto_target == VCAP_IS1_CHAIN(0) || 84 goto_target == VCAP_IS1_CHAIN(1) || 85 goto_target == VCAP_IS1_CHAIN(2) || 86 goto_target == VCAP_IS2_CHAIN(0, 0) || 87 goto_target == VCAP_IS2_CHAIN(1, 0)); 88 89 if (chain == VCAP_IS1_CHAIN(0)) 90 return (goto_target == VCAP_IS1_CHAIN(1)); 91 92 if (chain == VCAP_IS1_CHAIN(1)) 93 return (goto_target == VCAP_IS1_CHAIN(2)); 94 95 /* Lookup 2 of VCAP IS1 can really support non-optional GOTOs, 96 * using a Policy Association Group (PAG) value, which is an 8-bit 97 * value encoding a VCAP IS2 target chain. 98 */ 99 if (chain == VCAP_IS1_CHAIN(2)) { 100 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++) 101 if (goto_target == VCAP_IS2_CHAIN(0, pag)) 102 return true; 103 104 return false; 105 } 106 107 /* Non-optional GOTO from VCAP IS2 lookup 0 to lookup 1. 108 * We cannot change the PAG at this point. 109 */ 110 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++) 111 if (chain == VCAP_IS2_CHAIN(0, pag)) 112 return (goto_target == VCAP_IS2_CHAIN(1, pag)); 113 114 /* VCAP IS2 lookup 1 cannot jump anywhere */ 115 return false; 116 } 117 118 static struct ocelot_vcap_filter * 119 ocelot_find_vcap_filter_that_points_at(struct ocelot *ocelot, int chain) 120 { 121 struct ocelot_vcap_filter *filter; 122 struct ocelot_vcap_block *block; 123 int block_id; 124 125 block_id = ocelot_chain_to_block(chain, true); 126 if (block_id < 0) 127 return NULL; 128 129 if (block_id == VCAP_IS2) { 130 block = &ocelot->block[VCAP_IS1]; 131 132 list_for_each_entry(filter, &block->rules, list) 133 if (filter->type == OCELOT_VCAP_FILTER_PAG && 134 filter->goto_target == chain) 135 return filter; 136 } 137 138 list_for_each_entry(filter, &ocelot->dummy_rules, list) 139 if (filter->goto_target == chain) 140 return filter; 141 142 return NULL; 143 } 144 145 static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, 146 bool ingress, struct flow_cls_offload *f, 147 struct ocelot_vcap_filter *filter) 148 { 149 struct ocelot_port *ocelot_port = ocelot->ports[port]; 150 struct netlink_ext_ack *extack = f->common.extack; 151 bool allow_missing_goto_target = false; 152 const struct flow_action_entry *a; 153 enum ocelot_tag_tpid_sel tpid; 154 int i, chain, egress_port; 155 u64 rate; 156 157 if (!flow_action_basic_hw_stats_check(&f->rule->action, 158 f->common.extack)) 159 return -EOPNOTSUPP; 160 161 chain = f->common.chain_index; 162 filter->block_id = ocelot_chain_to_block(chain, ingress); 163 if (filter->block_id < 0) { 164 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain"); 165 return -EOPNOTSUPP; 166 } 167 if (filter->block_id == VCAP_IS1 || filter->block_id == VCAP_IS2) 168 filter->lookup = ocelot_chain_to_lookup(chain); 169 if (filter->block_id == VCAP_IS2) 170 filter->pag = ocelot_chain_to_pag(chain); 171 172 filter->goto_target = -1; 173 filter->type = OCELOT_VCAP_FILTER_DUMMY; 174 175 flow_action_for_each(i, a, &f->rule->action) { 176 switch (a->id) { 177 case FLOW_ACTION_DROP: 178 if (filter->block_id != VCAP_IS2) { 179 NL_SET_ERR_MSG_MOD(extack, 180 "Drop action can only be offloaded to VCAP IS2"); 181 return -EOPNOTSUPP; 182 } 183 if (filter->goto_target != -1) { 184 NL_SET_ERR_MSG_MOD(extack, 185 "Last action must be GOTO"); 186 return -EOPNOTSUPP; 187 } 188 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; 189 filter->action.port_mask = 0; 190 filter->action.police_ena = true; 191 filter->action.pol_ix = OCELOT_POLICER_DISCARD; 192 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 193 break; 194 case FLOW_ACTION_TRAP: 195 if (filter->block_id != VCAP_IS2) { 196 NL_SET_ERR_MSG_MOD(extack, 197 "Trap action can only be offloaded to VCAP IS2"); 198 return -EOPNOTSUPP; 199 } 200 if (filter->goto_target != -1) { 201 NL_SET_ERR_MSG_MOD(extack, 202 "Last action must be GOTO"); 203 return -EOPNOTSUPP; 204 } 205 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY; 206 filter->action.port_mask = 0; 207 filter->action.cpu_copy_ena = true; 208 filter->action.cpu_qu_num = 0; 209 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 210 break; 211 case FLOW_ACTION_POLICE: 212 if (filter->block_id != VCAP_IS2 || 213 filter->lookup != 0) { 214 NL_SET_ERR_MSG_MOD(extack, 215 "Police action can only be offloaded to VCAP IS2 lookup 0"); 216 return -EOPNOTSUPP; 217 } 218 if (filter->goto_target != -1) { 219 NL_SET_ERR_MSG_MOD(extack, 220 "Last action must be GOTO"); 221 return -EOPNOTSUPP; 222 } 223 if (a->police.rate_pkt_ps) { 224 NL_SET_ERR_MSG_MOD(extack, 225 "QoS offload not support packets per second"); 226 return -EOPNOTSUPP; 227 } 228 filter->action.police_ena = true; 229 rate = a->police.rate_bytes_ps; 230 filter->action.pol.rate = div_u64(rate, 1000) * 8; 231 filter->action.pol.burst = a->police.burst; 232 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 233 break; 234 case FLOW_ACTION_REDIRECT: 235 if (filter->block_id != VCAP_IS2) { 236 NL_SET_ERR_MSG_MOD(extack, 237 "Redirect action can only be offloaded to VCAP IS2"); 238 return -EOPNOTSUPP; 239 } 240 if (filter->goto_target != -1) { 241 NL_SET_ERR_MSG_MOD(extack, 242 "Last action must be GOTO"); 243 return -EOPNOTSUPP; 244 } 245 egress_port = ocelot->ops->netdev_to_port(a->dev); 246 if (egress_port < 0) { 247 NL_SET_ERR_MSG_MOD(extack, 248 "Destination not an ocelot port"); 249 return -EOPNOTSUPP; 250 } 251 filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; 252 filter->action.port_mask = BIT(egress_port); 253 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 254 break; 255 case FLOW_ACTION_VLAN_POP: 256 if (filter->block_id != VCAP_IS1) { 257 NL_SET_ERR_MSG_MOD(extack, 258 "VLAN pop action can only be offloaded to VCAP IS1"); 259 return -EOPNOTSUPP; 260 } 261 if (filter->goto_target != -1) { 262 NL_SET_ERR_MSG_MOD(extack, 263 "Last action must be GOTO"); 264 return -EOPNOTSUPP; 265 } 266 filter->action.vlan_pop_cnt_ena = true; 267 filter->action.vlan_pop_cnt++; 268 if (filter->action.vlan_pop_cnt > 2) { 269 NL_SET_ERR_MSG_MOD(extack, 270 "Cannot pop more than 2 VLAN headers"); 271 return -EOPNOTSUPP; 272 } 273 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 274 break; 275 case FLOW_ACTION_VLAN_MANGLE: 276 if (filter->block_id != VCAP_IS1) { 277 NL_SET_ERR_MSG_MOD(extack, 278 "VLAN modify action can only be offloaded to VCAP IS1"); 279 return -EOPNOTSUPP; 280 } 281 if (filter->goto_target != -1) { 282 NL_SET_ERR_MSG_MOD(extack, 283 "Last action must be GOTO"); 284 return -EOPNOTSUPP; 285 } 286 if (!ocelot_port->vlan_aware) { 287 NL_SET_ERR_MSG_MOD(extack, 288 "Can only modify VLAN under VLAN aware bridge"); 289 return -EOPNOTSUPP; 290 } 291 filter->action.vid_replace_ena = true; 292 filter->action.pcp_dei_ena = true; 293 filter->action.vid = a->vlan.vid; 294 filter->action.pcp = a->vlan.prio; 295 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 296 break; 297 case FLOW_ACTION_PRIORITY: 298 if (filter->block_id != VCAP_IS1) { 299 NL_SET_ERR_MSG_MOD(extack, 300 "Priority action can only be offloaded to VCAP IS1"); 301 return -EOPNOTSUPP; 302 } 303 if (filter->goto_target != -1) { 304 NL_SET_ERR_MSG_MOD(extack, 305 "Last action must be GOTO"); 306 return -EOPNOTSUPP; 307 } 308 filter->action.qos_ena = true; 309 filter->action.qos_val = a->priority; 310 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 311 break; 312 case FLOW_ACTION_GOTO: 313 filter->goto_target = a->chain_index; 314 315 if (filter->block_id == VCAP_IS1 && filter->lookup == 2) { 316 int pag = ocelot_chain_to_pag(filter->goto_target); 317 318 filter->action.pag_override_mask = 0xff; 319 filter->action.pag_val = pag; 320 filter->type = OCELOT_VCAP_FILTER_PAG; 321 } 322 break; 323 case FLOW_ACTION_VLAN_PUSH: 324 if (filter->block_id != VCAP_ES0) { 325 NL_SET_ERR_MSG_MOD(extack, 326 "VLAN push action can only be offloaded to VCAP ES0"); 327 return -EOPNOTSUPP; 328 } 329 switch (ntohs(a->vlan.proto)) { 330 case ETH_P_8021Q: 331 tpid = OCELOT_TAG_TPID_SEL_8021Q; 332 break; 333 case ETH_P_8021AD: 334 tpid = OCELOT_TAG_TPID_SEL_8021AD; 335 break; 336 default: 337 NL_SET_ERR_MSG_MOD(extack, 338 "Cannot push custom TPID"); 339 return -EOPNOTSUPP; 340 } 341 filter->action.tag_a_tpid_sel = tpid; 342 filter->action.push_outer_tag = OCELOT_ES0_TAG; 343 filter->action.tag_a_vid_sel = 1; 344 filter->action.vid_a_val = a->vlan.vid; 345 filter->action.pcp_a_val = a->vlan.prio; 346 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 347 break; 348 default: 349 NL_SET_ERR_MSG_MOD(extack, "Cannot offload action"); 350 return -EOPNOTSUPP; 351 } 352 } 353 354 if (filter->goto_target == -1) { 355 if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) || 356 chain == 0) { 357 allow_missing_goto_target = true; 358 } else { 359 NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action"); 360 return -EOPNOTSUPP; 361 } 362 } 363 364 if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) && 365 !allow_missing_goto_target) { 366 NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target"); 367 return -EOPNOTSUPP; 368 } 369 370 return 0; 371 } 372 373 static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port, 374 struct flow_cls_offload *f, 375 struct ocelot_vcap_filter *filter) 376 { 377 struct flow_rule *rule = flow_cls_offload_flow_rule(f); 378 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0]; 379 int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length; 380 struct netlink_ext_ack *extack = f->common.extack; 381 struct net_device *dev, *indev; 382 struct flow_match_meta match; 383 int ingress_port; 384 385 flow_rule_match_meta(rule, &match); 386 387 if (!match.mask->ingress_ifindex) 388 return 0; 389 390 if (match.mask->ingress_ifindex != 0xFFFFFFFF) { 391 NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask"); 392 return -EOPNOTSUPP; 393 } 394 395 dev = ocelot->ops->port_to_netdev(ocelot, port); 396 if (!dev) 397 return -EINVAL; 398 399 indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex); 400 if (!indev) { 401 NL_SET_ERR_MSG_MOD(extack, 402 "Can't find the ingress port to match on"); 403 return -ENOENT; 404 } 405 406 ingress_port = ocelot->ops->netdev_to_port(indev); 407 if (ingress_port < 0) { 408 NL_SET_ERR_MSG_MOD(extack, 409 "Can only offload an ocelot ingress port"); 410 return -EOPNOTSUPP; 411 } 412 if (ingress_port == port) { 413 NL_SET_ERR_MSG_MOD(extack, 414 "Ingress port is equal to the egress port"); 415 return -EINVAL; 416 } 417 418 filter->ingress_port.value = ingress_port; 419 filter->ingress_port.mask = GENMASK(key_length - 1, 0); 420 421 return 0; 422 } 423 424 static int 425 ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress, 426 struct flow_cls_offload *f, 427 struct ocelot_vcap_filter *filter) 428 { 429 struct flow_rule *rule = flow_cls_offload_flow_rule(f); 430 struct flow_dissector *dissector = rule->match.dissector; 431 struct netlink_ext_ack *extack = f->common.extack; 432 u16 proto = ntohs(f->common.protocol); 433 bool match_protocol = true; 434 int ret; 435 436 if (dissector->used_keys & 437 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | 438 BIT(FLOW_DISSECTOR_KEY_BASIC) | 439 BIT(FLOW_DISSECTOR_KEY_META) | 440 BIT(FLOW_DISSECTOR_KEY_PORTS) | 441 BIT(FLOW_DISSECTOR_KEY_VLAN) | 442 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | 443 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | 444 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) { 445 return -EOPNOTSUPP; 446 } 447 448 /* For VCAP ES0 (egress rewriter) we can match on the ingress port */ 449 if (!ingress) { 450 ret = ocelot_flower_parse_indev(ocelot, port, f, filter); 451 if (ret) 452 return ret; 453 } 454 455 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) { 456 struct flow_match_control match; 457 458 flow_rule_match_control(rule, &match); 459 } 460 461 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 462 struct flow_match_eth_addrs match; 463 464 if (filter->block_id == VCAP_ES0) { 465 NL_SET_ERR_MSG_MOD(extack, 466 "VCAP ES0 cannot match on MAC address"); 467 return -EOPNOTSUPP; 468 } 469 470 if (filter->block_id == VCAP_IS1 && 471 !is_zero_ether_addr(match.mask->dst)) { 472 NL_SET_ERR_MSG_MOD(extack, 473 "Key type S1_NORMAL cannot match on destination MAC"); 474 return -EOPNOTSUPP; 475 } 476 477 /* The hw support mac matches only for MAC_ETYPE key, 478 * therefore if other matches(port, tcp flags, etc) are added 479 * then just bail out 480 */ 481 if ((dissector->used_keys & 482 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 483 BIT(FLOW_DISSECTOR_KEY_BASIC) | 484 BIT(FLOW_DISSECTOR_KEY_CONTROL))) != 485 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 486 BIT(FLOW_DISSECTOR_KEY_BASIC) | 487 BIT(FLOW_DISSECTOR_KEY_CONTROL))) 488 return -EOPNOTSUPP; 489 490 flow_rule_match_eth_addrs(rule, &match); 491 filter->key_type = OCELOT_VCAP_KEY_ETYPE; 492 ether_addr_copy(filter->key.etype.dmac.value, 493 match.key->dst); 494 ether_addr_copy(filter->key.etype.smac.value, 495 match.key->src); 496 ether_addr_copy(filter->key.etype.dmac.mask, 497 match.mask->dst); 498 ether_addr_copy(filter->key.etype.smac.mask, 499 match.mask->src); 500 goto finished_key_parsing; 501 } 502 503 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) { 504 struct flow_match_basic match; 505 506 flow_rule_match_basic(rule, &match); 507 if (ntohs(match.key->n_proto) == ETH_P_IP) { 508 if (filter->block_id == VCAP_ES0) { 509 NL_SET_ERR_MSG_MOD(extack, 510 "VCAP ES0 cannot match on IP protocol"); 511 return -EOPNOTSUPP; 512 } 513 514 filter->key_type = OCELOT_VCAP_KEY_IPV4; 515 filter->key.ipv4.proto.value[0] = 516 match.key->ip_proto; 517 filter->key.ipv4.proto.mask[0] = 518 match.mask->ip_proto; 519 match_protocol = false; 520 } 521 if (ntohs(match.key->n_proto) == ETH_P_IPV6) { 522 if (filter->block_id == VCAP_ES0) { 523 NL_SET_ERR_MSG_MOD(extack, 524 "VCAP ES0 cannot match on IP protocol"); 525 return -EOPNOTSUPP; 526 } 527 528 filter->key_type = OCELOT_VCAP_KEY_IPV6; 529 filter->key.ipv6.proto.value[0] = 530 match.key->ip_proto; 531 filter->key.ipv6.proto.mask[0] = 532 match.mask->ip_proto; 533 match_protocol = false; 534 } 535 } 536 537 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) && 538 proto == ETH_P_IP) { 539 struct flow_match_ipv4_addrs match; 540 u8 *tmp; 541 542 if (filter->block_id == VCAP_ES0) { 543 NL_SET_ERR_MSG_MOD(extack, 544 "VCAP ES0 cannot match on IP address"); 545 return -EOPNOTSUPP; 546 } 547 548 flow_rule_match_ipv4_addrs(rule, &match); 549 550 if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) { 551 NL_SET_ERR_MSG_MOD(extack, 552 "Key type S1_NORMAL cannot match on destination IP"); 553 return -EOPNOTSUPP; 554 } 555 556 tmp = &filter->key.ipv4.sip.value.addr[0]; 557 memcpy(tmp, &match.key->src, 4); 558 559 tmp = &filter->key.ipv4.sip.mask.addr[0]; 560 memcpy(tmp, &match.mask->src, 4); 561 562 tmp = &filter->key.ipv4.dip.value.addr[0]; 563 memcpy(tmp, &match.key->dst, 4); 564 565 tmp = &filter->key.ipv4.dip.mask.addr[0]; 566 memcpy(tmp, &match.mask->dst, 4); 567 match_protocol = false; 568 } 569 570 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) && 571 proto == ETH_P_IPV6) { 572 return -EOPNOTSUPP; 573 } 574 575 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) { 576 struct flow_match_ports match; 577 578 if (filter->block_id == VCAP_ES0) { 579 NL_SET_ERR_MSG_MOD(extack, 580 "VCAP ES0 cannot match on L4 ports"); 581 return -EOPNOTSUPP; 582 } 583 584 flow_rule_match_ports(rule, &match); 585 filter->key.ipv4.sport.value = ntohs(match.key->src); 586 filter->key.ipv4.sport.mask = ntohs(match.mask->src); 587 filter->key.ipv4.dport.value = ntohs(match.key->dst); 588 filter->key.ipv4.dport.mask = ntohs(match.mask->dst); 589 match_protocol = false; 590 } 591 592 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { 593 struct flow_match_vlan match; 594 595 flow_rule_match_vlan(rule, &match); 596 filter->key_type = OCELOT_VCAP_KEY_ANY; 597 filter->vlan.vid.value = match.key->vlan_id; 598 filter->vlan.vid.mask = match.mask->vlan_id; 599 filter->vlan.pcp.value[0] = match.key->vlan_priority; 600 filter->vlan.pcp.mask[0] = match.mask->vlan_priority; 601 match_protocol = false; 602 } 603 604 finished_key_parsing: 605 if (match_protocol && proto != ETH_P_ALL) { 606 if (filter->block_id == VCAP_ES0) { 607 NL_SET_ERR_MSG_MOD(extack, 608 "VCAP ES0 cannot match on L2 proto"); 609 return -EOPNOTSUPP; 610 } 611 612 /* TODO: support SNAP, LLC etc */ 613 if (proto < ETH_P_802_3_MIN) 614 return -EOPNOTSUPP; 615 filter->key_type = OCELOT_VCAP_KEY_ETYPE; 616 *(__be16 *)filter->key.etype.etype.value = htons(proto); 617 *(__be16 *)filter->key.etype.etype.mask = htons(0xffff); 618 } 619 /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */ 620 621 return 0; 622 } 623 624 static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress, 625 struct flow_cls_offload *f, 626 struct ocelot_vcap_filter *filter) 627 { 628 int ret; 629 630 filter->prio = f->common.prio; 631 filter->id.cookie = f->cookie; 632 filter->id.tc_offload = true; 633 634 ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter); 635 if (ret) 636 return ret; 637 638 return ocelot_flower_parse_key(ocelot, port, ingress, f, filter); 639 } 640 641 static struct ocelot_vcap_filter 642 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress, 643 struct flow_cls_offload *f) 644 { 645 struct ocelot_vcap_filter *filter; 646 647 filter = kzalloc(sizeof(*filter), GFP_KERNEL); 648 if (!filter) 649 return NULL; 650 651 if (ingress) { 652 filter->ingress_port_mask = BIT(port); 653 } else { 654 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0]; 655 int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length; 656 657 filter->egress_port.value = port; 658 filter->egress_port.mask = GENMASK(key_length - 1, 0); 659 } 660 661 return filter; 662 } 663 664 static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot, 665 struct ocelot_vcap_filter *filter) 666 { 667 list_add(&filter->list, &ocelot->dummy_rules); 668 669 return 0; 670 } 671 672 static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot, 673 struct ocelot_vcap_filter *filter) 674 { 675 list_del(&filter->list); 676 kfree(filter); 677 678 return 0; 679 } 680 681 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port, 682 struct flow_cls_offload *f, bool ingress) 683 { 684 struct netlink_ext_ack *extack = f->common.extack; 685 struct ocelot_vcap_filter *filter; 686 int chain = f->common.chain_index; 687 int ret; 688 689 if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) { 690 NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain"); 691 return -EOPNOTSUPP; 692 } 693 694 filter = ocelot_vcap_filter_create(ocelot, port, ingress, f); 695 if (!filter) 696 return -ENOMEM; 697 698 ret = ocelot_flower_parse(ocelot, port, ingress, f, filter); 699 if (ret) { 700 kfree(filter); 701 return ret; 702 } 703 704 /* The non-optional GOTOs for the TCAM skeleton don't need 705 * to be actually offloaded. 706 */ 707 if (filter->type == OCELOT_VCAP_FILTER_DUMMY) 708 return ocelot_vcap_dummy_filter_add(ocelot, filter); 709 710 return ocelot_vcap_filter_add(ocelot, filter, f->common.extack); 711 } 712 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace); 713 714 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port, 715 struct flow_cls_offload *f, bool ingress) 716 { 717 struct ocelot_vcap_filter *filter; 718 struct ocelot_vcap_block *block; 719 int block_id; 720 721 block_id = ocelot_chain_to_block(f->common.chain_index, ingress); 722 if (block_id < 0) 723 return 0; 724 725 block = &ocelot->block[block_id]; 726 727 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true); 728 if (!filter) 729 return 0; 730 731 if (filter->type == OCELOT_VCAP_FILTER_DUMMY) 732 return ocelot_vcap_dummy_filter_del(ocelot, filter); 733 734 return ocelot_vcap_filter_del(ocelot, filter); 735 } 736 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy); 737 738 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port, 739 struct flow_cls_offload *f, bool ingress) 740 { 741 struct ocelot_vcap_filter *filter; 742 struct ocelot_vcap_block *block; 743 int block_id, ret; 744 745 block_id = ocelot_chain_to_block(f->common.chain_index, ingress); 746 if (block_id < 0) 747 return 0; 748 749 block = &ocelot->block[block_id]; 750 751 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true); 752 if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY) 753 return 0; 754 755 ret = ocelot_vcap_filter_stats_update(ocelot, filter); 756 if (ret) 757 return ret; 758 759 flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0, 760 FLOW_ACTION_HW_STATS_IMMEDIATE); 761 return 0; 762 } 763 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats); 764