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