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