brintos

brintos / linux-shallow public Read only

0
0
Text · 5.0 KiB · 6b4d1d7 Raw
205 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/* Microchip VCAP API3 *4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.5 */6 7#include "sparx5_tc.h"8#include "vcap_api.h"9#include "vcap_api_client.h"10#include "sparx5_main_regs.h"11#include "sparx5_main.h"12#include "sparx5_vcap_impl.h"13 14static struct sparx5_mall_entry *15sparx5_tc_matchall_entry_find(struct list_head *entries, unsigned long cookie)16{17	struct sparx5_mall_entry *entry;18 19	list_for_each_entry(entry, entries, list) {20		if (entry->cookie == cookie)21			return entry;22	}23 24	return NULL;25}26 27static void sparx5_tc_matchall_parse_action(struct sparx5_port *port,28					    struct sparx5_mall_entry *entry,29					    struct flow_action_entry *action,30					    bool ingress,31					    unsigned long cookie)32{33	entry->port = port;34	entry->type = action->id;35	entry->ingress = ingress;36	entry->cookie = cookie;37}38 39static void40sparx5_tc_matchall_parse_mirror_action(struct sparx5_mall_entry *entry,41				       struct flow_action_entry *action)42{43	entry->mirror.port = netdev_priv(action->dev);44}45 46static int sparx5_tc_matchall_replace(struct net_device *ndev,47				      struct tc_cls_matchall_offload *tmo,48				      bool ingress)49{50	struct sparx5_port *port = netdev_priv(ndev);51	struct sparx5_mall_entry *mall_entry;52	struct flow_action_entry *action;53	struct sparx5 *sparx5;54	int err;55 56	if (!flow_offload_has_one_action(&tmo->rule->action)) {57		NL_SET_ERR_MSG_MOD(tmo->common.extack,58				   "Only one action per filter is supported");59		return -EOPNOTSUPP;60	}61	action = &tmo->rule->action.entries[0];62 63	mall_entry = kzalloc(sizeof(*mall_entry), GFP_KERNEL);64	if (!mall_entry)65		return -ENOMEM;66 67	sparx5_tc_matchall_parse_action(port,68					mall_entry,69					action,70					ingress,71					tmo->cookie);72 73	sparx5 = port->sparx5;74	switch (action->id) {75	case FLOW_ACTION_MIRRED:76		sparx5_tc_matchall_parse_mirror_action(mall_entry, action);77		err = sparx5_mirror_add(mall_entry);78		if (err) {79			switch (err) {80			case -EEXIST:81				NL_SET_ERR_MSG_MOD(tmo->common.extack,82						   "Mirroring already exists");83				break;84			case -EINVAL:85				NL_SET_ERR_MSG_MOD(tmo->common.extack,86						   "Cannot mirror a monitor port");87				break;88			case -ENOENT:89				NL_SET_ERR_MSG_MOD(tmo->common.extack,90						   "No more mirror probes available");91				break;92			default:93				NL_SET_ERR_MSG_MOD(tmo->common.extack,94						   "Unknown error");95				break;96			}97			return err;98		}99		/* Get baseline stats for this port */100		sparx5_mirror_stats(mall_entry, &tmo->stats);101		break;102	case FLOW_ACTION_GOTO:103		err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,104					  tmo->common.chain_index,105					  action->chain_index, tmo->cookie,106					  true);107		if (err == -EFAULT) {108			NL_SET_ERR_MSG_MOD(tmo->common.extack,109					   "Unsupported goto chain");110			return -EOPNOTSUPP;111		}112		if (err == -EADDRINUSE) {113			NL_SET_ERR_MSG_MOD(tmo->common.extack,114					   "VCAP already enabled");115			return -EOPNOTSUPP;116		}117		if (err == -EADDRNOTAVAIL) {118			NL_SET_ERR_MSG_MOD(tmo->common.extack,119					   "Already matching this chain");120			return -EOPNOTSUPP;121		}122		if (err) {123			NL_SET_ERR_MSG_MOD(tmo->common.extack,124					   "Could not enable VCAP lookups");125			return err;126		}127		break;128	default:129		NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");130		return -EOPNOTSUPP;131	}132 133	list_add_tail(&mall_entry->list, &sparx5->mall_entries);134 135	return 0;136}137 138static int sparx5_tc_matchall_destroy(struct net_device *ndev,139				      struct tc_cls_matchall_offload *tmo,140				      bool ingress)141{142	struct sparx5_port *port = netdev_priv(ndev);143	struct sparx5 *sparx5 = port->sparx5;144	struct sparx5_mall_entry *entry;145	int err = 0;146 147	entry = sparx5_tc_matchall_entry_find(&sparx5->mall_entries,148					      tmo->cookie);149	if (!entry)150		return -ENOENT;151 152	if (entry->type == FLOW_ACTION_MIRRED) {153		sparx5_mirror_del(entry);154	} else if (entry->type == FLOW_ACTION_GOTO) {155		err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,156					  0, 0, tmo->cookie, false);157	} else {158		NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");159		err = -EOPNOTSUPP;160	}161 162	list_del(&entry->list);163 164	return err;165}166 167static int sparx5_tc_matchall_stats(struct net_device *ndev,168				    struct tc_cls_matchall_offload *tmo,169				    bool ingress)170{171	struct sparx5_port *port = netdev_priv(ndev);172	struct sparx5 *sparx5 = port->sparx5;173	struct sparx5_mall_entry *entry;174 175	entry = sparx5_tc_matchall_entry_find(&sparx5->mall_entries,176					      tmo->cookie);177	if (!entry)178		return -ENOENT;179 180	if (entry->type == FLOW_ACTION_MIRRED) {181		sparx5_mirror_stats(entry, &tmo->stats);182	} else {183		NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");184		return -EOPNOTSUPP;185	}186 187	return 0;188}189 190int sparx5_tc_matchall(struct net_device *ndev,191		       struct tc_cls_matchall_offload *tmo,192		       bool ingress)193{194	switch (tmo->command) {195	case TC_CLSMATCHALL_REPLACE:196		return sparx5_tc_matchall_replace(ndev, tmo, ingress);197	case TC_CLSMATCHALL_DESTROY:198		return sparx5_tc_matchall_destroy(ndev, tmo, ingress);199	case TC_CLSMATCHALL_STATS:200		return sparx5_tc_matchall_stats(ndev, tmo, ingress);201	default:202		return -EOPNOTSUPP;203	}204}205