brintos

brintos / linux-shallow public Read only

0
0
Text · 3.2 KiB · 1da9c1b Raw
128 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* 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}128