1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2020 Marvell International Ltd. All rights reserved */ 3 4 #include "prestera.h" 5 #include "prestera_acl.h" 6 #include "prestera_flow.h" 7 #include "prestera_flower.h" 8 9 struct prestera_flower_template { 10 struct prestera_acl_ruleset *ruleset; 11 struct list_head list; 12 u32 chain_index; 13 }; 14 15 static void 16 prestera_flower_template_free(struct prestera_flower_template *template) 17 { 18 prestera_acl_ruleset_put(template->ruleset); 19 list_del(&template->list); 20 kfree(template); 21 } 22 23 void prestera_flower_template_cleanup(struct prestera_flow_block *block) 24 { 25 struct prestera_flower_template *template, *tmp; 26 27 /* put the reference to all rulesets kept in tmpl create */ 28 list_for_each_entry_safe(template, tmp, &block->template_list, list) 29 prestera_flower_template_free(template); 30 } 31 32 static int 33 prestera_flower_parse_goto_action(struct prestera_flow_block *block, 34 struct prestera_acl_rule *rule, 35 u32 chain_index, 36 const struct flow_action_entry *act) 37 { 38 struct prestera_acl_ruleset *ruleset; 39 40 if (act->chain_index <= chain_index) 41 /* we can jump only forward */ 42 return -EINVAL; 43 44 if (rule->re_arg.jump.valid) 45 return -EEXIST; 46 47 ruleset = prestera_acl_ruleset_get(block->sw->acl, block, 48 act->chain_index); 49 if (IS_ERR(ruleset)) 50 return PTR_ERR(ruleset); 51 52 rule->re_arg.jump.valid = 1; 53 rule->re_arg.jump.i.index = prestera_acl_ruleset_index_get(ruleset); 54 55 rule->jump_ruleset = ruleset; 56 57 return 0; 58 } 59 60 static int prestera_flower_parse_actions(struct prestera_flow_block *block, 61 struct prestera_acl_rule *rule, 62 struct flow_action *flow_action, 63 u32 chain_index, 64 struct netlink_ext_ack *extack) 65 { 66 const struct flow_action_entry *act; 67 int err, i; 68 69 /* whole struct (rule->re_arg) must be initialized with 0 */ 70 if (!flow_action_has_entries(flow_action)) 71 return 0; 72 73 if (!flow_action_mixed_hw_stats_check(flow_action, extack)) 74 return -EOPNOTSUPP; 75 76 act = flow_action_first_entry_get(flow_action); 77 if (act->hw_stats & FLOW_ACTION_HW_STATS_DISABLED) { 78 /* Nothing to do */ 79 } else if (act->hw_stats & FLOW_ACTION_HW_STATS_DELAYED) { 80 /* setup counter first */ 81 rule->re_arg.count.valid = true; 82 err = prestera_acl_chain_to_client(chain_index, block->ingress, 83 &rule->re_arg.count.client); 84 if (err) 85 return err; 86 } else { 87 NL_SET_ERR_MSG_MOD(extack, "Unsupported action HW stats type"); 88 return -EOPNOTSUPP; 89 } 90 91 flow_action_for_each(i, act, flow_action) { 92 switch (act->id) { 93 case FLOW_ACTION_ACCEPT: 94 if (rule->re_arg.accept.valid) 95 return -EEXIST; 96 97 rule->re_arg.accept.valid = 1; 98 break; 99 case FLOW_ACTION_DROP: 100 if (rule->re_arg.drop.valid) 101 return -EEXIST; 102 103 rule->re_arg.drop.valid = 1; 104 break; 105 case FLOW_ACTION_TRAP: 106 if (rule->re_arg.trap.valid) 107 return -EEXIST; 108 109 rule->re_arg.trap.valid = 1; 110 break; 111 case FLOW_ACTION_POLICE: 112 if (rule->re_arg.police.valid) 113 return -EEXIST; 114 115 rule->re_arg.police.valid = 1; 116 rule->re_arg.police.rate = 117 act->police.rate_bytes_ps; 118 rule->re_arg.police.burst = act->police.burst; 119 rule->re_arg.police.ingress = block->ingress; 120 break; 121 case FLOW_ACTION_GOTO: 122 err = prestera_flower_parse_goto_action(block, rule, 123 chain_index, 124 act); 125 if (err) 126 return err; 127 break; 128 default: 129 NL_SET_ERR_MSG_MOD(extack, "Unsupported action"); 130 pr_err("Unsupported action\n"); 131 return -EOPNOTSUPP; 132 } 133 } 134 135 return 0; 136 } 137 138 static int prestera_flower_parse_meta(struct prestera_acl_rule *rule, 139 struct flow_cls_offload *f, 140 struct prestera_flow_block *block) 141 { 142 struct flow_rule *f_rule = flow_cls_offload_flow_rule(f); 143 struct prestera_acl_match *r_match = &rule->re_key.match; 144 struct prestera_port *port; 145 struct net_device *ingress_dev; 146 struct flow_match_meta match; 147 __be16 key, mask; 148 149 flow_rule_match_meta(f_rule, &match); 150 if (match.mask->ingress_ifindex != 0xFFFFFFFF) { 151 NL_SET_ERR_MSG_MOD(f->common.extack, 152 "Unsupported ingress ifindex mask"); 153 return -EINVAL; 154 } 155 156 ingress_dev = __dev_get_by_index(block->net, 157 match.key->ingress_ifindex); 158 if (!ingress_dev) { 159 NL_SET_ERR_MSG_MOD(f->common.extack, 160 "Can't find specified ingress port to match on"); 161 return -EINVAL; 162 } 163 164 if (!prestera_netdev_check(ingress_dev)) { 165 NL_SET_ERR_MSG_MOD(f->common.extack, 166 "Can't match on switchdev ingress port"); 167 return -EINVAL; 168 } 169 port = netdev_priv(ingress_dev); 170 171 mask = htons(0x1FFF << 3); 172 key = htons(port->hw_id << 3); 173 rule_match_set(r_match->key, SYS_PORT, key); 174 rule_match_set(r_match->mask, SYS_PORT, mask); 175 176 mask = htons(0x3FF); 177 key = htons(port->dev_id); 178 rule_match_set(r_match->key, SYS_DEV, key); 179 rule_match_set(r_match->mask, SYS_DEV, mask); 180 181 return 0; 182 } 183 184 static int prestera_flower_parse(struct prestera_flow_block *block, 185 struct prestera_acl_rule *rule, 186 struct flow_cls_offload *f) 187 { 188 struct flow_rule *f_rule = flow_cls_offload_flow_rule(f); 189 struct flow_dissector *dissector = f_rule->match.dissector; 190 struct prestera_acl_match *r_match = &rule->re_key.match; 191 __be16 n_proto_mask = 0; 192 __be16 n_proto_key = 0; 193 u16 addr_type = 0; 194 u8 ip_proto = 0; 195 int err; 196 197 if (dissector->used_keys & 198 ~(BIT(FLOW_DISSECTOR_KEY_META) | 199 BIT(FLOW_DISSECTOR_KEY_CONTROL) | 200 BIT(FLOW_DISSECTOR_KEY_BASIC) | 201 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) | 202 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | 203 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | 204 BIT(FLOW_DISSECTOR_KEY_ICMP) | 205 BIT(FLOW_DISSECTOR_KEY_PORTS) | 206 BIT(FLOW_DISSECTOR_KEY_PORTS_RANGE) | 207 BIT(FLOW_DISSECTOR_KEY_VLAN))) { 208 NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported key"); 209 return -EOPNOTSUPP; 210 } 211 212 prestera_acl_rule_priority_set(rule, f->common.prio); 213 214 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_META)) { 215 err = prestera_flower_parse_meta(rule, f, block); 216 if (err) 217 return err; 218 } 219 220 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_CONTROL)) { 221 struct flow_match_control match; 222 223 flow_rule_match_control(f_rule, &match); 224 addr_type = match.key->addr_type; 225 } 226 227 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_BASIC)) { 228 struct flow_match_basic match; 229 230 flow_rule_match_basic(f_rule, &match); 231 n_proto_key = match.key->n_proto; 232 n_proto_mask = match.mask->n_proto; 233 234 if (ntohs(match.key->n_proto) == ETH_P_ALL) { 235 n_proto_key = 0; 236 n_proto_mask = 0; 237 } 238 239 rule_match_set(r_match->key, ETH_TYPE, n_proto_key); 240 rule_match_set(r_match->mask, ETH_TYPE, n_proto_mask); 241 242 rule_match_set(r_match->key, IP_PROTO, match.key->ip_proto); 243 rule_match_set(r_match->mask, IP_PROTO, match.mask->ip_proto); 244 ip_proto = match.key->ip_proto; 245 } 246 247 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 248 struct flow_match_eth_addrs match; 249 250 flow_rule_match_eth_addrs(f_rule, &match); 251 252 /* DA key, mask */ 253 rule_match_set_n(r_match->key, 254 ETH_DMAC_0, &match.key->dst[0], 4); 255 rule_match_set_n(r_match->key, 256 ETH_DMAC_1, &match.key->dst[4], 2); 257 258 rule_match_set_n(r_match->mask, 259 ETH_DMAC_0, &match.mask->dst[0], 4); 260 rule_match_set_n(r_match->mask, 261 ETH_DMAC_1, &match.mask->dst[4], 2); 262 263 /* SA key, mask */ 264 rule_match_set_n(r_match->key, 265 ETH_SMAC_0, &match.key->src[0], 4); 266 rule_match_set_n(r_match->key, 267 ETH_SMAC_1, &match.key->src[4], 2); 268 269 rule_match_set_n(r_match->mask, 270 ETH_SMAC_0, &match.mask->src[0], 4); 271 rule_match_set_n(r_match->mask, 272 ETH_SMAC_1, &match.mask->src[4], 2); 273 } 274 275 if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { 276 struct flow_match_ipv4_addrs match; 277 278 flow_rule_match_ipv4_addrs(f_rule, &match); 279 280 rule_match_set(r_match->key, IP_SRC, match.key->src); 281 rule_match_set(r_match->mask, IP_SRC, match.mask->src); 282 283 rule_match_set(r_match->key, IP_DST, match.key->dst); 284 rule_match_set(r_match->mask, IP_DST, match.mask->dst); 285 } 286 287 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS)) { 288 struct flow_match_ports match; 289 290 if (ip_proto != IPPROTO_TCP && ip_proto != IPPROTO_UDP) { 291 NL_SET_ERR_MSG_MOD 292 (f->common.extack, 293 "Only UDP and TCP keys are supported"); 294 return -EINVAL; 295 } 296 297 flow_rule_match_ports(f_rule, &match); 298 299 rule_match_set(r_match->key, L4_PORT_SRC, match.key->src); 300 rule_match_set(r_match->mask, L4_PORT_SRC, match.mask->src); 301 302 rule_match_set(r_match->key, L4_PORT_DST, match.key->dst); 303 rule_match_set(r_match->mask, L4_PORT_DST, match.mask->dst); 304 } 305 306 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS_RANGE)) { 307 struct flow_match_ports_range match; 308 __be32 tp_key, tp_mask; 309 310 flow_rule_match_ports_range(f_rule, &match); 311 312 /* src port range (min, max) */ 313 tp_key = htonl(ntohs(match.key->tp_min.src) | 314 (ntohs(match.key->tp_max.src) << 16)); 315 tp_mask = htonl(ntohs(match.mask->tp_min.src) | 316 (ntohs(match.mask->tp_max.src) << 16)); 317 rule_match_set(r_match->key, L4_PORT_RANGE_SRC, tp_key); 318 rule_match_set(r_match->mask, L4_PORT_RANGE_SRC, tp_mask); 319 320 /* dst port range (min, max) */ 321 tp_key = htonl(ntohs(match.key->tp_min.dst) | 322 (ntohs(match.key->tp_max.dst) << 16)); 323 tp_mask = htonl(ntohs(match.mask->tp_min.dst) | 324 (ntohs(match.mask->tp_max.dst) << 16)); 325 rule_match_set(r_match->key, L4_PORT_RANGE_DST, tp_key); 326 rule_match_set(r_match->mask, L4_PORT_RANGE_DST, tp_mask); 327 } 328 329 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_VLAN)) { 330 struct flow_match_vlan match; 331 332 flow_rule_match_vlan(f_rule, &match); 333 334 if (match.mask->vlan_id != 0) { 335 __be16 key = cpu_to_be16(match.key->vlan_id); 336 __be16 mask = cpu_to_be16(match.mask->vlan_id); 337 338 rule_match_set(r_match->key, VLAN_ID, key); 339 rule_match_set(r_match->mask, VLAN_ID, mask); 340 } 341 342 rule_match_set(r_match->key, VLAN_TPID, match.key->vlan_tpid); 343 rule_match_set(r_match->mask, VLAN_TPID, match.mask->vlan_tpid); 344 } 345 346 if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ICMP)) { 347 struct flow_match_icmp match; 348 349 flow_rule_match_icmp(f_rule, &match); 350 351 rule_match_set(r_match->key, ICMP_TYPE, match.key->type); 352 rule_match_set(r_match->mask, ICMP_TYPE, match.mask->type); 353 354 rule_match_set(r_match->key, ICMP_CODE, match.key->code); 355 rule_match_set(r_match->mask, ICMP_CODE, match.mask->code); 356 } 357 358 return prestera_flower_parse_actions(block, rule, &f->rule->action, 359 f->common.chain_index, 360 f->common.extack); 361 } 362 363 int prestera_flower_replace(struct prestera_flow_block *block, 364 struct flow_cls_offload *f) 365 { 366 struct prestera_acl_ruleset *ruleset; 367 struct prestera_acl *acl = block->sw->acl; 368 struct prestera_acl_rule *rule; 369 int err; 370 371 ruleset = prestera_acl_ruleset_get(acl, block, f->common.chain_index); 372 if (IS_ERR(ruleset)) 373 return PTR_ERR(ruleset); 374 375 /* increments the ruleset reference */ 376 rule = prestera_acl_rule_create(ruleset, f->cookie, 377 f->common.chain_index); 378 if (IS_ERR(rule)) { 379 err = PTR_ERR(rule); 380 goto err_rule_create; 381 } 382 383 err = prestera_flower_parse(block, rule, f); 384 if (err) 385 goto err_rule_add; 386 387 if (!prestera_acl_ruleset_is_offload(ruleset)) { 388 err = prestera_acl_ruleset_offload(ruleset); 389 if (err) 390 goto err_ruleset_offload; 391 } 392 393 err = prestera_acl_rule_add(block->sw, rule); 394 if (err) 395 goto err_rule_add; 396 397 prestera_acl_ruleset_put(ruleset); 398 return 0; 399 400 err_ruleset_offload: 401 err_rule_add: 402 prestera_acl_rule_destroy(rule); 403 err_rule_create: 404 prestera_acl_ruleset_put(ruleset); 405 return err; 406 } 407 408 void prestera_flower_destroy(struct prestera_flow_block *block, 409 struct flow_cls_offload *f) 410 { 411 struct prestera_acl_ruleset *ruleset; 412 struct prestera_acl_rule *rule; 413 414 ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block, 415 f->common.chain_index); 416 if (IS_ERR(ruleset)) 417 return; 418 419 rule = prestera_acl_rule_lookup(ruleset, f->cookie); 420 if (rule) { 421 prestera_acl_rule_del(block->sw, rule); 422 prestera_acl_rule_destroy(rule); 423 } 424 prestera_acl_ruleset_put(ruleset); 425 } 426 427 int prestera_flower_tmplt_create(struct prestera_flow_block *block, 428 struct flow_cls_offload *f) 429 { 430 struct prestera_flower_template *template; 431 struct prestera_acl_ruleset *ruleset; 432 struct prestera_acl_rule rule; 433 int err; 434 435 memset(&rule, 0, sizeof(rule)); 436 err = prestera_flower_parse(block, &rule, f); 437 if (err) 438 return err; 439 440 template = kmalloc(sizeof(*template), GFP_KERNEL); 441 if (!template) { 442 err = -ENOMEM; 443 goto err_malloc; 444 } 445 446 prestera_acl_rule_keymask_pcl_id_set(&rule, 0); 447 ruleset = prestera_acl_ruleset_get(block->sw->acl, block, 448 f->common.chain_index); 449 if (IS_ERR_OR_NULL(ruleset)) { 450 err = -EINVAL; 451 goto err_ruleset_get; 452 } 453 454 /* preserve keymask/template to this ruleset */ 455 prestera_acl_ruleset_keymask_set(ruleset, rule.re_key.match.mask); 456 457 /* skip error, as it is not possible to reject template operation, 458 * so, keep the reference to the ruleset for rules to be added 459 * to that ruleset later. In case of offload fail, the ruleset 460 * will be offloaded again during adding a new rule. Also, 461 * unlikly possble that ruleset is already offloaded at this staage. 462 */ 463 prestera_acl_ruleset_offload(ruleset); 464 465 /* keep the reference to the ruleset */ 466 template->ruleset = ruleset; 467 template->chain_index = f->common.chain_index; 468 list_add_rcu(&template->list, &block->template_list); 469 return 0; 470 471 err_ruleset_get: 472 kfree(template); 473 err_malloc: 474 NL_SET_ERR_MSG_MOD(f->common.extack, "Create chain template failed"); 475 return err; 476 } 477 478 void prestera_flower_tmplt_destroy(struct prestera_flow_block *block, 479 struct flow_cls_offload *f) 480 { 481 struct prestera_flower_template *template, *tmp; 482 483 list_for_each_entry_safe(template, tmp, &block->template_list, list) 484 if (template->chain_index == f->common.chain_index) { 485 /* put the reference to the ruleset kept in create */ 486 prestera_flower_template_free(template); 487 return; 488 } 489 } 490 491 int prestera_flower_stats(struct prestera_flow_block *block, 492 struct flow_cls_offload *f) 493 { 494 struct prestera_acl_ruleset *ruleset; 495 struct prestera_acl_rule *rule; 496 u64 packets; 497 u64 lastuse; 498 u64 bytes; 499 int err; 500 501 ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block, 502 f->common.chain_index); 503 if (IS_ERR(ruleset)) 504 return PTR_ERR(ruleset); 505 506 rule = prestera_acl_rule_lookup(ruleset, f->cookie); 507 if (!rule) { 508 err = -EINVAL; 509 goto err_rule_get_stats; 510 } 511 512 err = prestera_acl_rule_get_stats(block->sw->acl, rule, &packets, 513 &bytes, &lastuse); 514 if (err) 515 goto err_rule_get_stats; 516 517 flow_stats_update(&f->stats, bytes, packets, 0, lastuse, 518 FLOW_ACTION_HW_STATS_DELAYED); 519 520 err_rule_get_stats: 521 prestera_acl_ruleset_put(ruleset); 522 return err; 523 } 524