File Index
Files and directories
Sign in
FILE

prestera_matchall.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/marvell/prestera/prestera_matchall.c 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
 14static 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
 44int 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
 55static 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
 62int 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 == -EEXIST)
100			return err;
101		if (err)
102			goto rollback;
103	}
104
105	prestera_mall_prio_update(block, f);
106
107	block->mall.bound = true;
108	return 0;
109
110rollback:
111	list_for_each_entry_continue_reverse(binding,
112					     &block->binding_list, list)
113		prestera_span_rule_del(binding, block->ingress);
114	return err;
115}
116
117void prestera_mall_destroy(struct prestera_flow_block *block)
118{
119	struct prestera_flow_block_binding *binding;
120
121	list_for_each_entry(binding, &block->binding_list, list)
122		prestera_span_rule_del(binding, block->ingress);
123
124	block->mall.prio_min = UINT_MAX;
125	block->mall.prio_max = 0;
126	block->mall.bound = false;
127}
~/ Read-only file preview.