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 filter->action.police_ena = true; 224 rate = a->police.rate_bytes_ps; 225 filter->action.pol.rate = div_u64(rate, 1000) * 8; 226 filter->action.pol.burst = a->police.burst; 227 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 228 break; 229 case FLOW_ACTION_REDIRECT: 230 if (filter->block_id != VCAP_IS2) { 231 NL_SET_ERR_MSG_MOD(extack, 232 "Redirect action can only be offloaded to VCAP IS2"); 233 return -EOPNOTSUPP; 234 } 235 if (filter->goto_target != -1) { 236 NL_SET_ERR_MSG_MOD(extack, 237 "Last action must be GOTO"); 238 return -EOPNOTSUPP; 239 } 240 egress_port = ocelot->ops->netdev_to_port(a->dev); 241 if (egress_port < 0) { 242 NL_SET_ERR_MSG_MOD(extack, 243 "Destination not an ocelot port"); 244 return -EOPNOTSUPP; 245 } 246 filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; 247 filter->action.port_mask = BIT(egress_port); 248 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 249 break; 250 case FLOW_ACTION_VLAN_POP: 251 if (filter->block_id != VCAP_IS1) { 252 NL_SET_ERR_MSG_MOD(extack, 253 "VLAN pop action can only be offloaded to VCAP IS1"); 254 return -EOPNOTSUPP; 255 } 256 if (filter->goto_target != -1) { 257 NL_SET_ERR_MSG_MOD(extack, 258 "Last action must be GOTO"); 259 return -EOPNOTSUPP; 260 } 261 filter->action.vlan_pop_cnt_ena = true; 262 filter->action.vlan_pop_cnt++; 263 if (filter->action.vlan_pop_cnt > 2) { 264 NL_SET_ERR_MSG_MOD(extack, 265 "Cannot pop more than 2 VLAN headers"); 266 return -EOPNOTSUPP; 267 } 268 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 269 break; 270 case FLOW_ACTION_VLAN_MANGLE: 271 if (filter->block_id != VCAP_IS1) { 272 NL_SET_ERR_MSG_MOD(extack, 273 "VLAN modify action can only be offloaded to VCAP IS1"); 274 return -EOPNOTSUPP; 275 } 276 if (filter->goto_target != -1) { 277 NL_SET_ERR_MSG_MOD(extack, 278 "Last action must be GOTO"); 279 return -EOPNOTSUPP; 280 } 281 if (!ocelot_port->vlan_aware) { 282 NL_SET_ERR_MSG_MOD(extack, 283 "Can only modify VLAN under VLAN aware bridge"); 284 return -EOPNOTSUPP; 285 } 286 filter->action.vid_replace_ena = true; 287 filter->action.pcp_dei_ena = true; 288 filter->action.vid = a->vlan.vid; 289 filter->action.pcp = a->vlan.prio; 290 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 291 break; 292 case FLOW_ACTION_PRIORITY: 293 if (filter->block_id != VCAP_IS1) { 294 NL_SET_ERR_MSG_MOD(extack, 295 "Priority action can only be offloaded to VCAP IS1"); 296 return -EOPNOTSUPP; 297 } 298 if (filter->goto_target != -1) { 299 NL_SET_ERR_MSG_MOD(extack, 300 "Last action must be GOTO"); 301 return -EOPNOTSUPP; 302 } 303 filter->action.qos_ena = true; 304 filter->action.qos_val = a->priority; 305 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 306 break; 307 case FLOW_ACTION_GOTO: 308 filter->goto_target = a->chain_index; 309 310 if (filter->block_id == VCAP_IS1 && filter->lookup == 2) { 311 int pag = ocelot_chain_to_pag(filter->goto_target); 312 313 filter->action.pag_override_mask = 0xff; 314 filter->action.pag_val = pag; 315 filter->type = OCELOT_VCAP_FILTER_PAG; 316 } 317 break; 318 case FLOW_ACTION_VLAN_PUSH: 319 if (filter->block_id != VCAP_ES0) { 320 NL_SET_ERR_MSG_MOD(extack, 321 "VLAN push action can only be offloaded to VCAP ES0"); 322 return -EOPNOTSUPP; 323 } 324 switch (ntohs(a->vlan.proto)) { 325 case ETH_P_8021Q: 326 tpid = OCELOT_TAG_TPID_SEL_8021Q; 327 break; 328 case ETH_P_8021AD: 329 tpid = OCELOT_TAG_TPID_SEL_8021AD; 330 break; 331 default: 332 NL_SET_ERR_MSG_MOD(extack, 333 "Cannot push custom TPID"); 334 return -EOPNOTSUPP; 335 } 336 filter->action.tag_a_tpid_sel = tpid; 337 filter->action.push_outer_tag = OCELOT_ES0_TAG; 338 filter->action.tag_a_vid_sel = 1; 339 filter->action.vid_a_val = a->vlan.vid; 340 filter->action.pcp_a_val = a->vlan.prio; 341 filter->type = OCELOT_VCAP_FILTER_OFFLOAD; 342 break; 343 default: 344 NL_SET_ERR_MSG_MOD(extack, "Cannot offload action"); 345 return -EOPNOTSUPP; 346 } 347 } 348 349 if (filter->goto_target == -1) { 350 if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) || 351 chain == 0) { 352 allow_missing_goto_target = true; 353 } else { 354 NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action"); 355 return -EOPNOTSUPP; 356 } 357 } 358 359 if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) && 360 !allow_missing_goto_target) { 361 NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target"); 362 return -EOPNOTSUPP; 363 } 364 365 return 0; 366 } 367 368 static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port, 369 struct flow_cls_offload *f, 370 struct ocelot_vcap_filter *filter) 371 { 372 struct flow_rule *rule = flow_cls_offload_flow_rule(f); 373 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0]; 374 int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length; 375 struct netlink_ext_ack *extack = f->common.extack; 376 struct net_device *dev, *indev; 377 struct flow_match_meta match; 378 int ingress_port; 379 380 flow_rule_match_meta(rule, &match); 381 382 if (!match.mask->ingress_ifindex) 383 return 0; 384 385 if (match.mask->ingress_ifindex != 0xFFFFFFFF) { 386 NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask"); 387 return -EOPNOTSUPP; 388 } 389 390 dev = ocelot->ops->port_to_netdev(ocelot, port); 391 if (!dev) 392 return -EINVAL; 393 394 indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex); 395 if (!indev) { 396 NL_SET_ERR_MSG_MOD(extack, 397 "Can't find the ingress port to match on"); 398 return -ENOENT; 399 } 400 401 ingress_port = ocelot->ops->netdev_to_port(indev); 402 if (ingress_port < 0) { 403 NL_SET_ERR_MSG_MOD(extack, 404 "Can only offload an ocelot ingress port"); 405 return -EOPNOTSUPP; 406 } 407 if (ingress_port == port) { 408 NL_SET_ERR_MSG_MOD(extack, 409 "Ingress port is equal to the egress port"); 410 return -EINVAL; 411 } 412 413 filter->ingress_port.value = ingress_port; 414 filter->ingress_port.mask = GENMASK(key_length - 1, 0); 415 416 return 0; 417 } 418 419 static int 420 ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress, 421 struct flow_cls_offload *f, 422 struct ocelot_vcap_filter *filter) 423 { 424 struct flow_rule *rule = flow_cls_offload_flow_rule(f); 425 struct flow_dissector *dissector = rule->match.dissector; 426 struct netlink_ext_ack *extack = f->common.extack; 427 u16 proto = ntohs(f->common.protocol); 428 bool match_protocol = true; 429 int ret; 430 431 if (dissector->used_keys & 432 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) | 433 BIT(FLOW_DISSECTOR_KEY_BASIC) | 434 BIT(FLOW_DISSECTOR_KEY_META) | 435 BIT(FLOW_DISSECTOR_KEY_PORTS) | 436 BIT(FLOW_DISSECTOR_KEY_VLAN) | 437 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | 438 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | 439 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) { 440 return -EOPNOTSUPP; 441 } 442 443 /* For VCAP ES0 (egress rewriter) we can match on the ingress port */ 444 if (!ingress) { 445 ret = ocelot_flower_parse_indev(ocelot, port, f, filter); 446 if (ret) 447 return ret; 448 } 449 450 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) { 451 struct flow_match_control match; 452 453 flow_rule_match_control(rule, &match); 454 } 455 456 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 457 struct flow_match_eth_addrs match; 458 459 if (filter->block_id == VCAP_ES0) { 460 NL_SET_ERR_MSG_MOD(extack, 461 "VCAP ES0 cannot match on MAC address"); 462 return -EOPNOTSUPP; 463 } 464 465 if (filter->block_id == VCAP_IS1 && 466 !is_zero_ether_addr(match.mask->dst)) { 467 NL_SET_ERR_MSG_MOD(extack, 468 "Key type S1_NORMAL cannot match on destination MAC"); 469 return -EOPNOTSUPP; 470 } 471 472 /* The hw support mac matches only for MAC_ETYPE key, 473 * therefore if other matches(port, tcp flags, etc) are added 474 * then just bail out 475 */ 476 if ((dissector->used_keys & 477 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 478 BIT(FLOW_DISSECTOR_KEY_BASIC) | 479 BIT(FLOW_DISSECTOR_KEY_CONTROL))) != 480 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 481 BIT(FLOW_DISSECTOR_KEY_BASIC) | 482 BIT(FLOW_DISSECTOR_KEY_CONTROL))) 483 return -EOPNOTSUPP; 484 485 flow_rule_match_eth_addrs(rule, &match); 486 filter->key_type = OCELOT_VCAP_KEY_ETYPE; 487 ether_addr_copy(filter->key.etype.dmac.value, 488 match.key->dst); 489 ether_addr_copy(filter->key.etype.smac.value, 490 match.key->src); 491 ether_addr_copy(filter->key.etype.dmac.mask, 492 match.mask->dst); 493 ether_addr_copy(filter->key.etype.smac.mask, 494 match.mask->src); 495 goto finished_key_parsing; 496 } 497 498 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) { 499 struct flow_match_basic match; 500 501 flow_rule_match_basic(rule, &match); 502 if (ntohs(match.key->n_proto) == ETH_P_IP) { 503 if (filter->block_id == VCAP_ES0) { 504 NL_SET_ERR_MSG_MOD(extack, 505 "VCAP ES0 cannot match on IP protocol"); 506 return -EOPNOTSUPP; 507 } 508 509 filter->key_type = OCELOT_VCAP_KEY_IPV4; 510 filter->key.ipv4.proto.value[0] = 511 match.key->ip_proto; 512 filter->key.ipv4.proto.mask[0] = 513 match.mask->ip_proto; 514 match_protocol = false; 515 } 516 if (ntohs(match.key->n_proto) == ETH_P_IPV6) { 517 if (filter->block_id == VCAP_ES0) { 518 NL_SET_ERR_MSG_MOD(extack, 519 "VCAP ES0 cannot match on IP protocol"); 520 return -EOPNOTSUPP; 521 } 522 523 filter->key_type = OCELOT_VCAP_KEY_IPV6; 524 filter->key.ipv6.proto.value[0] = 525 match.key->ip_proto; 526 filter->key.ipv6.proto.mask[0] = 527 match.mask->ip_proto; 528 match_protocol = false; 529 } 530 } 531 532 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) && 533 proto == ETH_P_IP) { 534 struct flow_match_ipv4_addrs match; 535 u8 *tmp; 536 537 if (filter->block_id == VCAP_ES0) { 538 NL_SET_ERR_MSG_MOD(extack, 539 "VCAP ES0 cannot match on IP address"); 540 return -EOPNOTSUPP; 541 } 542 543 if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) { 544 NL_SET_ERR_MSG_MOD(extack, 545 "Key type S1_NORMAL cannot match on destination IP"); 546 return -EOPNOTSUPP; 547 } 548 549 flow_rule_match_ipv4_addrs(rule, &match); 550 tmp = &filter->key.ipv4.sip.value.addr[0]; 551 memcpy(tmp, &match.key->src, 4); 552 553 tmp = &filter->key.ipv4.sip.mask.addr[0]; 554 memcpy(tmp, &match.mask->src, 4); 555 556 tmp = &filter->key.ipv4.dip.value.addr[0]; 557 memcpy(tmp, &match.key->dst, 4); 558 559 tmp = &filter->key.ipv4.dip.mask.addr[0]; 560 memcpy(tmp, &match.mask->dst, 4); 561 match_protocol = false; 562 } 563 564 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) && 565 proto == ETH_P_IPV6) { 566 return -EOPNOTSUPP; 567 } 568 569 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) { 570 struct flow_match_ports match; 571 572 if (filter->block_id == VCAP_ES0) { 573 NL_SET_ERR_MSG_MOD(extack, 574 "VCAP ES0 cannot match on L4 ports"); 575 return -EOPNOTSUPP; 576 } 577 578 flow_rule_match_ports(rule, &match); 579 filter->key.ipv4.sport.value = ntohs(match.key->src); 580 filter->key.ipv4.sport.mask = ntohs(match.mask->src); 581 filter->key.ipv4.dport.value = ntohs(match.key->dst); 582 filter->key.ipv4.dport.mask = ntohs(match.mask->dst); 583 match_protocol = false; 584 } 585 586 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { 587 struct flow_match_vlan match; 588 589 flow_rule_match_vlan(rule, &match); 590 filter->key_type = OCELOT_VCAP_KEY_ANY; 591 filter->vlan.vid.value = match.key->vlan_id; 592 filter->vlan.vid.mask = match.mask->vlan_id; 593 filter->vlan.pcp.value[0] = match.key->vlan_priority; 594 filter->vlan.pcp.mask[0] = match.mask->vlan_priority; 595 match_protocol = false; 596 } 597 598 finished_key_parsing: 599 if (match_protocol && proto != ETH_P_ALL) { 600 if (filter->block_id == VCAP_ES0) { 601 NL_SET_ERR_MSG_MOD(extack, 602 "VCAP ES0 cannot match on L2 proto"); 603 return -EOPNOTSUPP; 604 } 605 606 /* TODO: support SNAP, LLC etc */ 607 if (proto < ETH_P_802_3_MIN) 608 return -EOPNOTSUPP; 609 filter->key_type = OCELOT_VCAP_KEY_ETYPE; 610 *(__be16 *)filter->key.etype.etype.value = htons(proto); 611 *(__be16 *)filter->key.etype.etype.mask = htons(0xffff); 612 } 613 /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */ 614 615 return 0; 616 } 617 618 static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress, 619 struct flow_cls_offload *f, 620 struct ocelot_vcap_filter *filter) 621 { 622 int ret; 623 624 filter->prio = f->common.prio; 625 filter->id = f->cookie; 626 627 ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter); 628 if (ret) 629 return ret; 630 631 return ocelot_flower_parse_key(ocelot, port, ingress, f, filter); 632 } 633 634 static struct ocelot_vcap_filter 635 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress, 636 struct flow_cls_offload *f) 637 { 638 struct ocelot_vcap_filter *filter; 639 640 filter = kzalloc(sizeof(*filter), GFP_KERNEL); 641 if (!filter) 642 return NULL; 643 644 if (ingress) { 645 filter->ingress_port_mask = BIT(port); 646 } else { 647 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0]; 648 int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length; 649 650 filter->egress_port.value = port; 651 filter->egress_port.mask = GENMASK(key_length - 1, 0); 652 } 653 654 return filter; 655 } 656 657 static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot, 658 struct ocelot_vcap_filter *filter) 659 { 660 list_add(&filter->list, &ocelot->dummy_rules); 661 662 return 0; 663 } 664 665 static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot, 666 struct ocelot_vcap_filter *filter) 667 { 668 list_del(&filter->list); 669 kfree(filter); 670 671 return 0; 672 } 673 674 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port, 675 struct flow_cls_offload *f, bool ingress) 676 { 677 struct netlink_ext_ack *extack = f->common.extack; 678 struct ocelot_vcap_filter *filter; 679 int chain = f->common.chain_index; 680 int ret; 681 682 if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) { 683 NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain"); 684 return -EOPNOTSUPP; 685 } 686 687 filter = ocelot_vcap_filter_create(ocelot, port, ingress, f); 688 if (!filter) 689 return -ENOMEM; 690 691 ret = ocelot_flower_parse(ocelot, port, ingress, f, filter); 692 if (ret) { 693 kfree(filter); 694 return ret; 695 } 696 697 /* The non-optional GOTOs for the TCAM skeleton don't need 698 * to be actually offloaded. 699 */ 700 if (filter->type == OCELOT_VCAP_FILTER_DUMMY) 701 return ocelot_vcap_dummy_filter_add(ocelot, filter); 702 703 return ocelot_vcap_filter_add(ocelot, filter, f->common.extack); 704 } 705 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace); 706 707 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port, 708 struct flow_cls_offload *f, bool ingress) 709 { 710 struct ocelot_vcap_filter *filter; 711 struct ocelot_vcap_block *block; 712 int block_id; 713 714 block_id = ocelot_chain_to_block(f->common.chain_index, ingress); 715 if (block_id < 0) 716 return 0; 717 718 block = &ocelot->block[block_id]; 719 720 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie); 721 if (!filter) 722 return 0; 723 724 if (filter->type == OCELOT_VCAP_FILTER_DUMMY) 725 return ocelot_vcap_dummy_filter_del(ocelot, filter); 726 727 return ocelot_vcap_filter_del(ocelot, filter); 728 } 729 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy); 730 731 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port, 732 struct flow_cls_offload *f, bool ingress) 733 { 734 struct ocelot_vcap_filter *filter; 735 struct ocelot_vcap_block *block; 736 int block_id, ret; 737 738 block_id = ocelot_chain_to_block(f->common.chain_index, ingress); 739 if (block_id < 0) 740 return 0; 741 742 block = &ocelot->block[block_id]; 743 744 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie); 745 if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY) 746 return 0; 747 748 ret = ocelot_vcap_filter_stats_update(ocelot, filter); 749 if (ret) 750 return ret; 751 752 flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0, 753 FLOW_ACTION_HW_STATS_IMMEDIATE); 754 return 0; 755 } 756 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats); 757