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