Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'prestera-matchall'

Maksym Glubokiy says:

====================
net: prestera: matchall features

This patch series extracts matchall rules management out of SPAN API
implementation and adds 2 features on top of that:
- support for egress traffic (mirred egress action)
- proper rule priorities management between matchall and flower
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+291 -78
+1 -1
drivers/net/ethernet/marvell/prestera/Makefile
··· 4 4 prestera_rxtx.o prestera_devlink.o prestera_ethtool.o \ 5 5 prestera_switchdev.o prestera_acl.o prestera_flow.o \ 6 6 prestera_flower.o prestera_span.o prestera_counter.o \ 7 - prestera_router.o prestera_router_hw.o 7 + prestera_router.o prestera_router_hw.o prestera_matchall.o 8 8 9 9 obj-$(CONFIG_PRESTERA_PCI) += prestera_pci.o
+43
drivers/net/ethernet/marvell/prestera/prestera_acl.c
··· 54 54 struct prestera_acl_ruleset_ht_key ht_key; 55 55 struct rhashtable rule_ht; 56 56 struct prestera_acl *acl; 57 + struct { 58 + u32 min; 59 + u32 max; 60 + } prio; 57 61 unsigned long rule_count; 58 62 refcount_t refcount; 59 63 void *keymask; ··· 165 161 /* make pcl-id based on uid */ 166 162 ruleset->pcl_id = PRESTERA_ACL_PCL_ID_MAKE((u8)uid, chain_index); 167 163 ruleset->index = uid; 164 + 165 + ruleset->prio.min = UINT_MAX; 166 + ruleset->prio.max = 0; 168 167 169 168 err = rhashtable_insert_fast(&acl->ruleset_ht, &ruleset->ht_node, 170 169 prestera_acl_ruleset_ht_params); ··· 372 365 block->ruleset_zero = NULL; 373 366 } 374 367 368 + static void 369 + prestera_acl_ruleset_prio_refresh(struct prestera_acl *acl, 370 + struct prestera_acl_ruleset *ruleset) 371 + { 372 + struct prestera_acl_rule *rule; 373 + 374 + ruleset->prio.min = UINT_MAX; 375 + ruleset->prio.max = 0; 376 + 377 + list_for_each_entry(rule, &acl->rules, list) { 378 + if (ruleset->ingress != rule->ruleset->ingress) 379 + continue; 380 + if (ruleset->ht_key.chain_index != rule->chain_index) 381 + continue; 382 + 383 + ruleset->prio.min = min(ruleset->prio.min, rule->priority); 384 + ruleset->prio.max = max(ruleset->prio.max, rule->priority); 385 + } 386 + } 387 + 375 388 void 376 389 prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule, u16 pcl_id) 377 390 { ··· 414 387 u32 prestera_acl_ruleset_index_get(const struct prestera_acl_ruleset *ruleset) 415 388 { 416 389 return ruleset->index; 390 + } 391 + 392 + void prestera_acl_ruleset_prio_get(struct prestera_acl_ruleset *ruleset, 393 + u32 *prio_min, u32 *prio_max) 394 + { 395 + *prio_min = ruleset->prio.min; 396 + *prio_max = ruleset->prio.max; 417 397 } 418 398 419 399 bool prestera_acl_ruleset_is_offload(struct prestera_acl_ruleset *ruleset) ··· 463 429 kfree(rule); 464 430 } 465 431 432 + static void prestera_acl_ruleset_prio_update(struct prestera_acl_ruleset *ruleset, 433 + u32 prio) 434 + { 435 + ruleset->prio.min = min(ruleset->prio.min, prio); 436 + ruleset->prio.max = max(ruleset->prio.max, prio); 437 + } 438 + 466 439 int prestera_acl_rule_add(struct prestera_switch *sw, 467 440 struct prestera_acl_rule *rule) 468 441 { ··· 509 468 510 469 list_add_tail(&rule->list, &sw->acl->rules); 511 470 ruleset->rule_count++; 471 + prestera_acl_ruleset_prio_update(ruleset, rule->priority); 512 472 return 0; 513 473 514 474 err_acl_block_bind: ··· 534 492 list_del(&rule->list); 535 493 536 494 prestera_acl_rule_entry_destroy(sw->acl, rule->re); 495 + prestera_acl_ruleset_prio_refresh(sw->acl, ruleset); 537 496 538 497 /* unbind block (all ports) */ 539 498 if (!ruleset->ht_key.chain_index && !ruleset->rule_count)
+2
drivers/net/ethernet/marvell/prestera/prestera_acl.h
··· 195 195 int prestera_acl_ruleset_unbind(struct prestera_acl_ruleset *ruleset, 196 196 struct prestera_port *port); 197 197 u32 prestera_acl_ruleset_index_get(const struct prestera_acl_ruleset *ruleset); 198 + void prestera_acl_ruleset_prio_get(struct prestera_acl_ruleset *ruleset, 199 + u32 *prio_min, u32 *prio_max); 198 200 void 199 201 prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule, 200 202 u16 pcl_id);
+8 -4
drivers/net/ethernet/marvell/prestera/prestera_flow.c
··· 7 7 #include "prestera.h" 8 8 #include "prestera_acl.h" 9 9 #include "prestera_flow.h" 10 - #include "prestera_span.h" 11 10 #include "prestera_flower.h" 11 + #include "prestera_matchall.h" 12 + #include "prestera_span.h" 12 13 13 14 static LIST_HEAD(prestera_block_cb_list); 14 15 ··· 18 17 { 19 18 switch (f->command) { 20 19 case TC_CLSMATCHALL_REPLACE: 21 - return prestera_span_replace(block, f); 20 + return prestera_mall_replace(block, f); 22 21 case TC_CLSMATCHALL_DESTROY: 23 - prestera_span_destroy(block); 22 + prestera_mall_destroy(block); 24 23 return 0; 25 24 default: 26 25 return -EOPNOTSUPP; ··· 90 89 INIT_LIST_HEAD(&block->template_list); 91 90 block->net = net; 92 91 block->sw = sw; 92 + block->mall.prio_min = UINT_MAX; 93 + block->mall.prio_max = 0; 94 + block->mall.bound = false; 93 95 block->ingress = ingress; 94 96 95 97 return block; ··· 267 263 268 264 block = flow_block_cb_priv(block_cb); 269 265 270 - prestera_span_destroy(block); 266 + prestera_mall_destroy(block); 271 267 272 268 err = prestera_flow_block_unbind(block, port); 273 269 if (err)
+5
drivers/net/ethernet/marvell/prestera/prestera_flow.h
··· 22 22 struct prestera_acl_ruleset *ruleset_zero; 23 23 struct flow_block_cb *block_cb; 24 24 struct list_head template_list; 25 + struct { 26 + u32 prio_min; 27 + u32 prio_max; 28 + bool bound; 29 + } mall; 25 30 unsigned int rule_count; 26 31 bool ingress; 27 32 };
+48
drivers/net/ethernet/marvell/prestera/prestera_flower.c
··· 5 5 #include "prestera_acl.h" 6 6 #include "prestera_flow.h" 7 7 #include "prestera_flower.h" 8 + #include "prestera_matchall.h" 8 9 9 10 struct prestera_flower_template { 10 11 struct prestera_acl_ruleset *ruleset; ··· 361 360 f->common.extack); 362 361 } 363 362 363 + static int prestera_flower_prio_check(struct prestera_flow_block *block, 364 + struct flow_cls_offload *f) 365 + { 366 + u32 mall_prio_min; 367 + u32 mall_prio_max; 368 + int err; 369 + 370 + err = prestera_mall_prio_get(block, &mall_prio_min, &mall_prio_max); 371 + if (err == -ENOENT) 372 + /* No matchall filters installed on this chain. */ 373 + return 0; 374 + 375 + if (err) { 376 + NL_SET_ERR_MSG(f->common.extack, "Failed to get matchall priorities"); 377 + return err; 378 + } 379 + 380 + if (f->common.prio <= mall_prio_max && block->ingress) { 381 + NL_SET_ERR_MSG(f->common.extack, 382 + "Failed to add in front of existing matchall rules"); 383 + return -EOPNOTSUPP; 384 + } 385 + if (f->common.prio >= mall_prio_min && !block->ingress) { 386 + NL_SET_ERR_MSG(f->common.extack, "Failed to add behind of existing matchall rules"); 387 + return -EOPNOTSUPP; 388 + } 389 + 390 + return 0; 391 + } 392 + 393 + int prestera_flower_prio_get(struct prestera_flow_block *block, u32 chain_index, 394 + u32 *prio_min, u32 *prio_max) 395 + { 396 + struct prestera_acl_ruleset *ruleset; 397 + 398 + ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block, chain_index); 399 + if (IS_ERR(ruleset)) 400 + return PTR_ERR(ruleset); 401 + 402 + prestera_acl_ruleset_prio_get(ruleset, prio_min, prio_max); 403 + return 0; 404 + } 405 + 364 406 int prestera_flower_replace(struct prestera_flow_block *block, 365 407 struct flow_cls_offload *f) 366 408 { ··· 411 367 struct prestera_acl *acl = block->sw->acl; 412 368 struct prestera_acl_rule *rule; 413 369 int err; 370 + 371 + err = prestera_flower_prio_check(block, f); 372 + if (err) 373 + return err; 414 374 415 375 ruleset = prestera_acl_ruleset_get(acl, block, f->common.chain_index); 416 376 if (IS_ERR(ruleset))
+2
drivers/net/ethernet/marvell/prestera/prestera_flower.h
··· 19 19 void prestera_flower_tmplt_destroy(struct prestera_flow_block *block, 20 20 struct flow_cls_offload *f); 21 21 void prestera_flower_template_cleanup(struct prestera_flow_block *block); 22 + int prestera_flower_prio_get(struct prestera_flow_block *block, u32 chain_index, 23 + u32 *prio_min, u32 *prio_max); 22 24 23 25 #endif /* _PRESTERA_FLOWER_H_ */
+22 -8
drivers/net/ethernet/marvell/prestera/prestera_hw.c
··· 78 78 PRESTERA_CMD_TYPE_STP_PORT_SET = 0x1000, 79 79 80 80 PRESTERA_CMD_TYPE_SPAN_GET = 0x1100, 81 - PRESTERA_CMD_TYPE_SPAN_BIND = 0x1101, 82 - PRESTERA_CMD_TYPE_SPAN_UNBIND = 0x1102, 81 + PRESTERA_CMD_TYPE_SPAN_INGRESS_BIND = 0x1101, 82 + PRESTERA_CMD_TYPE_SPAN_INGRESS_UNBIND = 0x1102, 83 83 PRESTERA_CMD_TYPE_SPAN_RELEASE = 0x1103, 84 + PRESTERA_CMD_TYPE_SPAN_EGRESS_BIND = 0x1104, 85 + PRESTERA_CMD_TYPE_SPAN_EGRESS_UNBIND = 0x1105, 84 86 85 87 PRESTERA_CMD_TYPE_POLICER_CREATE = 0x1500, 86 88 PRESTERA_CMD_TYPE_POLICER_RELEASE = 0x1501, ··· 1436 1434 return 0; 1437 1435 } 1438 1436 1439 - int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id) 1437 + int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id, 1438 + bool ingress) 1440 1439 { 1441 1440 struct prestera_msg_span_req req = { 1442 1441 .port = __cpu_to_le32(port->hw_id), 1443 1442 .dev = __cpu_to_le32(port->dev_id), 1444 1443 .id = span_id, 1445 1444 }; 1445 + enum prestera_cmd_type_t cmd_type; 1446 1446 1447 - return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_SPAN_BIND, 1448 - &req.cmd, sizeof(req)); 1447 + if (ingress) 1448 + cmd_type = PRESTERA_CMD_TYPE_SPAN_INGRESS_BIND; 1449 + else 1450 + cmd_type = PRESTERA_CMD_TYPE_SPAN_EGRESS_BIND; 1451 + 1452 + return prestera_cmd(port->sw, cmd_type, &req.cmd, sizeof(req)); 1453 + 1449 1454 } 1450 1455 1451 - int prestera_hw_span_unbind(const struct prestera_port *port) 1456 + int prestera_hw_span_unbind(const struct prestera_port *port, bool ingress) 1452 1457 { 1453 1458 struct prestera_msg_span_req req = { 1454 1459 .port = __cpu_to_le32(port->hw_id), 1455 1460 .dev = __cpu_to_le32(port->dev_id), 1456 1461 }; 1462 + enum prestera_cmd_type_t cmd_type; 1457 1463 1458 - return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_SPAN_UNBIND, 1459 - &req.cmd, sizeof(req)); 1464 + if (ingress) 1465 + cmd_type = PRESTERA_CMD_TYPE_SPAN_INGRESS_UNBIND; 1466 + else 1467 + cmd_type = PRESTERA_CMD_TYPE_SPAN_EGRESS_UNBIND; 1468 + 1469 + return prestera_cmd(port->sw, cmd_type, &req.cmd, sizeof(req)); 1460 1470 } 1461 1471 1462 1472 int prestera_hw_span_release(struct prestera_switch *sw, u8 span_id)
+3 -2
drivers/net/ethernet/marvell/prestera/prestera_hw.h
··· 245 245 246 246 /* SPAN API */ 247 247 int prestera_hw_span_get(const struct prestera_port *port, u8 *span_id); 248 - int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id); 249 - int prestera_hw_span_unbind(const struct prestera_port *port); 248 + int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id, 249 + bool ingress); 250 + int prestera_hw_span_unbind(const struct prestera_port *port, bool ingress); 250 251 int prestera_hw_span_release(struct prestera_switch *sw, u8 span_id); 251 252 252 253 /* Router API */
+125
drivers/net/ethernet/marvell/prestera/prestera_matchall.c
··· 1 + // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 + /* Copyright (c) 2019-2022 Marvell International Ltd. All rights reserved */ 3 + 4 + #include <linux/kernel.h> 5 + #include <linux/list.h> 6 + 7 + #include "prestera.h" 8 + #include "prestera_hw.h" 9 + #include "prestera_flow.h" 10 + #include "prestera_flower.h" 11 + #include "prestera_matchall.h" 12 + #include "prestera_span.h" 13 + 14 + static int prestera_mall_prio_check(struct prestera_flow_block *block, 15 + struct tc_cls_matchall_offload *f) 16 + { 17 + u32 flower_prio_min; 18 + u32 flower_prio_max; 19 + int err; 20 + 21 + err = prestera_flower_prio_get(block, f->common.chain_index, 22 + &flower_prio_min, &flower_prio_max); 23 + if (err == -ENOENT) 24 + /* No flower filters installed on this chain. */ 25 + return 0; 26 + 27 + if (err) { 28 + NL_SET_ERR_MSG(f->common.extack, "Failed to get flower priorities"); 29 + return err; 30 + } 31 + 32 + if (f->common.prio <= flower_prio_max && !block->ingress) { 33 + NL_SET_ERR_MSG(f->common.extack, "Failed to add in front of existing flower rules"); 34 + return -EOPNOTSUPP; 35 + } 36 + if (f->common.prio >= flower_prio_min && block->ingress) { 37 + NL_SET_ERR_MSG(f->common.extack, "Failed to add behind of existing flower rules"); 38 + return -EOPNOTSUPP; 39 + } 40 + 41 + return 0; 42 + } 43 + 44 + int prestera_mall_prio_get(struct prestera_flow_block *block, 45 + u32 *prio_min, u32 *prio_max) 46 + { 47 + if (!block->mall.bound) 48 + return -ENOENT; 49 + 50 + *prio_min = block->mall.prio_min; 51 + *prio_max = block->mall.prio_max; 52 + return 0; 53 + } 54 + 55 + static void prestera_mall_prio_update(struct prestera_flow_block *block, 56 + struct tc_cls_matchall_offload *f) 57 + { 58 + block->mall.prio_min = min(block->mall.prio_min, f->common.prio); 59 + block->mall.prio_max = max(block->mall.prio_max, f->common.prio); 60 + } 61 + 62 + int prestera_mall_replace(struct prestera_flow_block *block, 63 + struct tc_cls_matchall_offload *f) 64 + { 65 + struct prestera_flow_block_binding *binding; 66 + __be16 protocol = f->common.protocol; 67 + struct flow_action_entry *act; 68 + struct prestera_port *port; 69 + int err; 70 + 71 + if (!flow_offload_has_one_action(&f->rule->action)) { 72 + NL_SET_ERR_MSG(f->common.extack, 73 + "Only singular actions are supported"); 74 + return -EOPNOTSUPP; 75 + } 76 + 77 + act = &f->rule->action.entries[0]; 78 + 79 + if (!prestera_netdev_check(act->dev)) { 80 + NL_SET_ERR_MSG(f->common.extack, 81 + "Only Marvell Prestera port is supported"); 82 + return -EINVAL; 83 + } 84 + if (!tc_cls_can_offload_and_chain0(act->dev, &f->common)) 85 + return -EOPNOTSUPP; 86 + if (act->id != FLOW_ACTION_MIRRED) 87 + return -EOPNOTSUPP; 88 + if (protocol != htons(ETH_P_ALL)) 89 + return -EOPNOTSUPP; 90 + 91 + err = prestera_mall_prio_check(block, f); 92 + if (err) 93 + return err; 94 + 95 + port = netdev_priv(act->dev); 96 + 97 + list_for_each_entry(binding, &block->binding_list, list) { 98 + err = prestera_span_rule_add(binding, port, block->ingress); 99 + if (err) 100 + goto rollback; 101 + } 102 + 103 + prestera_mall_prio_update(block, f); 104 + 105 + block->mall.bound = true; 106 + return 0; 107 + 108 + rollback: 109 + list_for_each_entry_continue_reverse(binding, 110 + &block->binding_list, list) 111 + prestera_span_rule_del(binding, block->ingress); 112 + return err; 113 + } 114 + 115 + void prestera_mall_destroy(struct prestera_flow_block *block) 116 + { 117 + struct prestera_flow_block_binding *binding; 118 + 119 + list_for_each_entry(binding, &block->binding_list, list) 120 + prestera_span_rule_del(binding, block->ingress); 121 + 122 + block->mall.prio_min = UINT_MAX; 123 + block->mall.prio_max = 0; 124 + block->mall.bound = false; 125 + }
+17
drivers/net/ethernet/marvell/prestera/prestera_matchall.h
··· 1 + /* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ 2 + /* Copyright (c) 2022 Marvell International Ltd. All rights reserved. */ 3 + 4 + #ifndef _PRESTERA_MATCHALL_H_ 5 + #define _PRESTERA_MATCHALL_H_ 6 + 7 + #include <net/pkt_cls.h> 8 + 9 + struct prestera_flow_block; 10 + 11 + int prestera_mall_replace(struct prestera_flow_block *block, 12 + struct tc_cls_matchall_offload *f); 13 + void prestera_mall_destroy(struct prestera_flow_block *block); 14 + int prestera_mall_prio_get(struct prestera_flow_block *block, 15 + u32 *prio_min, u32 *prio_max); 16 + 17 + #endif /* _PRESTERA_MATCHALL_H_ */
+7 -59
drivers/net/ethernet/marvell/prestera/prestera_span.c
··· 120 120 return 0; 121 121 } 122 122 123 - static int prestera_span_rule_add(struct prestera_flow_block_binding *binding, 124 - struct prestera_port *to_port) 123 + int prestera_span_rule_add(struct prestera_flow_block_binding *binding, 124 + struct prestera_port *to_port, 125 + bool ingress) 125 126 { 126 127 struct prestera_switch *sw = binding->port->sw; 127 128 u8 span_id; ··· 136 135 if (err) 137 136 return err; 138 137 139 - err = prestera_hw_span_bind(binding->port, span_id); 138 + err = prestera_hw_span_bind(binding->port, span_id, ingress); 140 139 if (err) { 141 140 prestera_span_put(sw, span_id); 142 141 return err; ··· 146 145 return 0; 147 146 } 148 147 149 - static int prestera_span_rule_del(struct prestera_flow_block_binding *binding) 148 + int prestera_span_rule_del(struct prestera_flow_block_binding *binding, 149 + bool ingress) 150 150 { 151 151 int err; 152 152 153 - err = prestera_hw_span_unbind(binding->port); 153 + err = prestera_hw_span_unbind(binding->port, ingress); 154 154 if (err) 155 155 return err; 156 156 ··· 161 159 162 160 binding->span_id = PRESTERA_SPAN_INVALID_ID; 163 161 return 0; 164 - } 165 - 166 - int prestera_span_replace(struct prestera_flow_block *block, 167 - struct tc_cls_matchall_offload *f) 168 - { 169 - struct prestera_flow_block_binding *binding; 170 - __be16 protocol = f->common.protocol; 171 - struct flow_action_entry *act; 172 - struct prestera_port *port; 173 - int err; 174 - 175 - if (!flow_offload_has_one_action(&f->rule->action)) { 176 - NL_SET_ERR_MSG(f->common.extack, 177 - "Only singular actions are supported"); 178 - return -EOPNOTSUPP; 179 - } 180 - 181 - act = &f->rule->action.entries[0]; 182 - 183 - if (!prestera_netdev_check(act->dev)) { 184 - NL_SET_ERR_MSG(f->common.extack, 185 - "Only Marvell Prestera port is supported"); 186 - return -EINVAL; 187 - } 188 - if (!tc_cls_can_offload_and_chain0(act->dev, &f->common)) 189 - return -EOPNOTSUPP; 190 - if (act->id != FLOW_ACTION_MIRRED) 191 - return -EOPNOTSUPP; 192 - if (protocol != htons(ETH_P_ALL)) 193 - return -EOPNOTSUPP; 194 - 195 - port = netdev_priv(act->dev); 196 - 197 - list_for_each_entry(binding, &block->binding_list, list) { 198 - err = prestera_span_rule_add(binding, port); 199 - if (err) 200 - goto rollback; 201 - } 202 - 203 - return 0; 204 - 205 - rollback: 206 - list_for_each_entry_continue_reverse(binding, 207 - &block->binding_list, list) 208 - prestera_span_rule_del(binding); 209 - return err; 210 - } 211 - 212 - void prestera_span_destroy(struct prestera_flow_block *block) 213 - { 214 - struct prestera_flow_block_binding *binding; 215 - 216 - list_for_each_entry(binding, &block->binding_list, list) 217 - prestera_span_rule_del(binding); 218 162 } 219 163 220 164 int prestera_span_init(struct prestera_switch *sw)
+8 -4
drivers/net/ethernet/marvell/prestera/prestera_span.h
··· 8 8 9 9 #define PRESTERA_SPAN_INVALID_ID -1 10 10 11 + struct prestera_port; 11 12 struct prestera_switch; 12 - struct prestera_flow_block; 13 + struct prestera_flow_block_binding; 13 14 14 15 int prestera_span_init(struct prestera_switch *sw); 15 16 void prestera_span_fini(struct prestera_switch *sw); 16 - int prestera_span_replace(struct prestera_flow_block *block, 17 - struct tc_cls_matchall_offload *f); 18 - void prestera_span_destroy(struct prestera_flow_block *block); 17 + 18 + int prestera_span_rule_add(struct prestera_flow_block_binding *binding, 19 + struct prestera_port *to_port, 20 + bool ingress); 21 + int prestera_span_rule_del(struct prestera_flow_block_binding *binding, 22 + bool ingress); 19 23 20 24 #endif /* _PRESTERA_SPAN_H_ */