cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ocelot_flower.c (27890B)


      1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
      2/* Microsemi Ocelot Switch driver
      3 * Copyright (c) 2019 Microsemi Corporation
      4 */
      5
      6#include <net/pkt_cls.h>
      7#include <net/tc_act/tc_gact.h>
      8#include <soc/mscc/ocelot_vcap.h>
      9#include "ocelot_police.h"
     10#include "ocelot_vcap.h"
     11
     12/* Arbitrarily chosen constants for encoding the VCAP block and lookup number
     13 * into the chain number. This is UAPI.
     14 */
     15#define VCAP_BLOCK			10000
     16#define VCAP_LOOKUP			1000
     17#define VCAP_IS1_NUM_LOOKUPS		3
     18#define VCAP_IS2_NUM_LOOKUPS		2
     19#define VCAP_IS2_NUM_PAG		256
     20#define VCAP_IS1_CHAIN(lookup)		\
     21	(1 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP)
     22#define VCAP_IS2_CHAIN(lookup, pag)	\
     23	(2 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP + (pag))
     24/* PSFP chain and block ID */
     25#define PSFP_BLOCK_ID			OCELOT_NUM_VCAP_BLOCKS
     26#define OCELOT_PSFP_CHAIN		(3 * VCAP_BLOCK)
     27
     28static int ocelot_chain_to_block(int chain, bool ingress)
     29{
     30	int lookup, pag;
     31
     32	if (!ingress) {
     33		if (chain == 0)
     34			return VCAP_ES0;
     35		return -EOPNOTSUPP;
     36	}
     37
     38	/* Backwards compatibility with older, single-chain tc-flower
     39	 * offload support in Ocelot
     40	 */
     41	if (chain == 0)
     42		return VCAP_IS2;
     43
     44	for (lookup = 0; lookup < VCAP_IS1_NUM_LOOKUPS; lookup++)
     45		if (chain == VCAP_IS1_CHAIN(lookup))
     46			return VCAP_IS1;
     47
     48	for (lookup = 0; lookup < VCAP_IS2_NUM_LOOKUPS; lookup++)
     49		for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
     50			if (chain == VCAP_IS2_CHAIN(lookup, pag))
     51				return VCAP_IS2;
     52
     53	if (chain == OCELOT_PSFP_CHAIN)
     54		return PSFP_BLOCK_ID;
     55
     56	return -EOPNOTSUPP;
     57}
     58
     59/* Caller must ensure this is a valid IS1 or IS2 chain first,
     60 * by calling ocelot_chain_to_block.
     61 */
     62static int ocelot_chain_to_lookup(int chain)
     63{
     64	/* Backwards compatibility with older, single-chain tc-flower
     65	 * offload support in Ocelot
     66	 */
     67	if (chain == 0)
     68		return 0;
     69
     70	return (chain / VCAP_LOOKUP) % 10;
     71}
     72
     73/* Caller must ensure this is a valid IS2 chain first,
     74 * by calling ocelot_chain_to_block.
     75 */
     76static int ocelot_chain_to_pag(int chain)
     77{
     78	int lookup;
     79
     80	/* Backwards compatibility with older, single-chain tc-flower
     81	 * offload support in Ocelot
     82	 */
     83	if (chain == 0)
     84		return 0;
     85
     86	lookup = ocelot_chain_to_lookup(chain);
     87
     88	/* calculate PAG value as chain index relative to the first PAG */
     89	return chain - VCAP_IS2_CHAIN(lookup, 0);
     90}
     91
     92static bool ocelot_is_goto_target_valid(int goto_target, int chain,
     93					bool ingress)
     94{
     95	int pag;
     96
     97	/* Can't offload GOTO in VCAP ES0 */
     98	if (!ingress)
     99		return (goto_target < 0);
    100
    101	/* Non-optional GOTOs */
    102	if (chain == 0)
    103		/* VCAP IS1 can be skipped, either partially or completely */
    104		return (goto_target == VCAP_IS1_CHAIN(0) ||
    105			goto_target == VCAP_IS1_CHAIN(1) ||
    106			goto_target == VCAP_IS1_CHAIN(2) ||
    107			goto_target == VCAP_IS2_CHAIN(0, 0) ||
    108			goto_target == VCAP_IS2_CHAIN(1, 0) ||
    109			goto_target == OCELOT_PSFP_CHAIN);
    110
    111	if (chain == VCAP_IS1_CHAIN(0))
    112		return (goto_target == VCAP_IS1_CHAIN(1));
    113
    114	if (chain == VCAP_IS1_CHAIN(1))
    115		return (goto_target == VCAP_IS1_CHAIN(2));
    116
    117	/* Lookup 2 of VCAP IS1 can really support non-optional GOTOs,
    118	 * using a Policy Association Group (PAG) value, which is an 8-bit
    119	 * value encoding a VCAP IS2 target chain.
    120	 */
    121	if (chain == VCAP_IS1_CHAIN(2)) {
    122		for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
    123			if (goto_target == VCAP_IS2_CHAIN(0, pag))
    124				return true;
    125
    126		return false;
    127	}
    128
    129	/* Non-optional GOTO from VCAP IS2 lookup 0 to lookup 1.
    130	 * We cannot change the PAG at this point.
    131	 */
    132	for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
    133		if (chain == VCAP_IS2_CHAIN(0, pag))
    134			return (goto_target == VCAP_IS2_CHAIN(1, pag));
    135
    136	/* VCAP IS2 lookup 1 can goto to PSFP block if hardware support */
    137	for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
    138		if (chain == VCAP_IS2_CHAIN(1, pag))
    139			return (goto_target == OCELOT_PSFP_CHAIN);
    140
    141	return false;
    142}
    143
    144static struct ocelot_vcap_filter *
    145ocelot_find_vcap_filter_that_points_at(struct ocelot *ocelot, int chain)
    146{
    147	struct ocelot_vcap_filter *filter;
    148	struct ocelot_vcap_block *block;
    149	int block_id;
    150
    151	block_id = ocelot_chain_to_block(chain, true);
    152	if (block_id < 0)
    153		return NULL;
    154
    155	if (block_id == VCAP_IS2) {
    156		block = &ocelot->block[VCAP_IS1];
    157
    158		list_for_each_entry(filter, &block->rules, list)
    159			if (filter->type == OCELOT_VCAP_FILTER_PAG &&
    160			    filter->goto_target == chain)
    161				return filter;
    162	}
    163
    164	list_for_each_entry(filter, &ocelot->dummy_rules, list)
    165		if (filter->goto_target == chain)
    166			return filter;
    167
    168	return NULL;
    169}
    170
    171static int
    172ocelot_flower_parse_ingress_vlan_modify(struct ocelot *ocelot, int port,
    173					struct ocelot_vcap_filter *filter,
    174					const struct flow_action_entry *a,
    175					struct netlink_ext_ack *extack)
    176{
    177	struct ocelot_port *ocelot_port = ocelot->ports[port];
    178
    179	if (filter->goto_target != -1) {
    180		NL_SET_ERR_MSG_MOD(extack,
    181				   "Last action must be GOTO");
    182		return -EOPNOTSUPP;
    183	}
    184
    185	if (!ocelot_port->vlan_aware) {
    186		NL_SET_ERR_MSG_MOD(extack,
    187				   "Can only modify VLAN under VLAN aware bridge");
    188		return -EOPNOTSUPP;
    189	}
    190
    191	filter->action.vid_replace_ena = true;
    192	filter->action.pcp_dei_ena = true;
    193	filter->action.vid = a->vlan.vid;
    194	filter->action.pcp = a->vlan.prio;
    195	filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
    196
    197	return 0;
    198}
    199
    200static int
    201ocelot_flower_parse_egress_vlan_modify(struct ocelot_vcap_filter *filter,
    202				       const struct flow_action_entry *a,
    203				       struct netlink_ext_ack *extack)
    204{
    205	enum ocelot_tag_tpid_sel tpid;
    206
    207	switch (ntohs(a->vlan.proto)) {
    208	case ETH_P_8021Q:
    209		tpid = OCELOT_TAG_TPID_SEL_8021Q;
    210		break;
    211	case ETH_P_8021AD:
    212		tpid = OCELOT_TAG_TPID_SEL_8021AD;
    213		break;
    214	default:
    215		NL_SET_ERR_MSG_MOD(extack,
    216				   "Cannot modify custom TPID");
    217		return -EOPNOTSUPP;
    218	}
    219
    220	filter->action.tag_a_tpid_sel = tpid;
    221	filter->action.push_outer_tag = OCELOT_ES0_TAG;
    222	filter->action.tag_a_vid_sel = OCELOT_ES0_VID_PLUS_CLASSIFIED_VID;
    223	filter->action.vid_a_val = a->vlan.vid;
    224	filter->action.pcp_a_val = a->vlan.prio;
    225	filter->action.tag_a_pcp_sel = OCELOT_ES0_PCP;
    226	filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
    227
    228	return 0;
    229}
    230
    231static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
    232				      bool ingress, struct flow_cls_offload *f,
    233				      struct ocelot_vcap_filter *filter)
    234{
    235	const struct flow_action *action = &f->rule->action;
    236	struct netlink_ext_ack *extack = f->common.extack;
    237	bool allow_missing_goto_target = false;
    238	const struct flow_action_entry *a;
    239	enum ocelot_tag_tpid_sel tpid;
    240	int i, chain, egress_port;
    241	u32 pol_ix, pol_max;
    242	u64 rate;
    243	int err;
    244
    245	if (!flow_action_basic_hw_stats_check(&f->rule->action,
    246					      f->common.extack))
    247		return -EOPNOTSUPP;
    248
    249	chain = f->common.chain_index;
    250	filter->block_id = ocelot_chain_to_block(chain, ingress);
    251	if (filter->block_id < 0) {
    252		NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
    253		return -EOPNOTSUPP;
    254	}
    255	if (filter->block_id == VCAP_IS1 || filter->block_id == VCAP_IS2)
    256		filter->lookup = ocelot_chain_to_lookup(chain);
    257	if (filter->block_id == VCAP_IS2)
    258		filter->pag = ocelot_chain_to_pag(chain);
    259
    260	filter->goto_target = -1;
    261	filter->type = OCELOT_VCAP_FILTER_DUMMY;
    262
    263	flow_action_for_each(i, a, action) {
    264		switch (a->id) {
    265		case FLOW_ACTION_DROP:
    266			if (filter->block_id != VCAP_IS2) {
    267				NL_SET_ERR_MSG_MOD(extack,
    268						   "Drop action can only be offloaded to VCAP IS2");
    269				return -EOPNOTSUPP;
    270			}
    271			if (filter->goto_target != -1) {
    272				NL_SET_ERR_MSG_MOD(extack,
    273						   "Last action must be GOTO");
    274				return -EOPNOTSUPP;
    275			}
    276			filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
    277			filter->action.port_mask = 0;
    278			filter->action.police_ena = true;
    279			filter->action.pol_ix = OCELOT_POLICER_DISCARD;
    280			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
    281			break;
    282		case FLOW_ACTION_ACCEPT:
    283			if (filter->block_id != VCAP_ES0 &&
    284			    filter->block_id != VCAP_IS1 &&
    285			    filter->block_id != VCAP_IS2) {
    286				NL_SET_ERR_MSG_MOD(extack,
    287						   "Accept action can only be offloaded to VCAP chains");
    288				return -EOPNOTSUPP;
    289			}
    290			if (filter->block_id != VCAP_ES0 &&
    291			    filter->goto_target != -1) {
    292				NL_SET_ERR_MSG_MOD(extack,
    293						   "Last action must be GOTO");
    294				return -EOPNOTSUPP;
    295			}
    296			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
    297			break;
    298		case FLOW_ACTION_TRAP:
    299			if (filter->block_id != VCAP_IS2 ||
    300			    filter->lookup != 0) {
    301				NL_SET_ERR_MSG_MOD(extack,
    302						   "Trap action can only be offloaded to VCAP IS2 lookup 0");
    303				return -EOPNOTSUPP;
    304			}
    305			if (filter->goto_target != -1) {
    306				NL_SET_ERR_MSG_MOD(extack,
    307						   "Last action must be GOTO");
    308				return -EOPNOTSUPP;
    309			}
    310			filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
    311			filter->action.port_mask = 0;
    312			filter->action.cpu_copy_ena = true;
    313			filter->action.cpu_qu_num = 0;
    314			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
    315			filter->is_trap = true;
    316			break;
    317		case FLOW_ACTION_POLICE:
    318			if (filter->block_id == PSFP_BLOCK_ID) {
    319				filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
    320				break;
    321			}
    322			if (filter->block_id != VCAP_IS2 ||
    323			    filter->lookup != 0) {
    324				NL_SET_ERR_MSG_MOD(extack,
    325						   "Police action can only be offloaded to VCAP IS2 lookup 0 or PSFP");
    326				return -EOPNOTSUPP;
    327			}
    328			if (filter->goto_target != -1) {
    329				NL_SET_ERR_MSG_MOD(extack,
    330						   "Last action must be GOTO");
    331				return -EOPNOTSUPP;
    332			}
    333
    334			err = ocelot_policer_validate(action, a, extack);
    335			if (err)
    336				return err;
    337
    338			filter->action.police_ena = true;
    339
    340			pol_ix = a->hw_index + ocelot->vcap_pol.base;
    341			pol_max = ocelot->vcap_pol.max;
    342
    343			if (ocelot->vcap_pol.max2 && pol_ix > pol_max) {
    344				pol_ix += ocelot->vcap_pol.base2 - pol_max - 1;
    345				pol_max = ocelot->vcap_pol.max2;
    346			}
    347
    348			if (pol_ix >= pol_max)
    349				return -EINVAL;
    350
    351			filter->action.pol_ix = pol_ix;
    352
    353			rate = a->police.rate_bytes_ps;
    354			filter->action.pol.rate = div_u64(rate, 1000) * 8;
    355			filter->action.pol.burst = a->police.burst;
    356			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
    357			break;
    358		case FLOW_ACTION_REDIRECT:
    359			if (filter->block_id != VCAP_IS2) {
    360				NL_SET_ERR_MSG_MOD(extack,
    361						   "Redirect action can only be offloaded to VCAP IS2");
    362				return -EOPNOTSUPP;
    363			}
    364			if (filter->goto_target != -1) {
    365				NL_SET_ERR_MSG_MOD(extack,
    366						   "Last action must be GOTO");
    367				return -EOPNOTSUPP;
    368			}
    369			egress_port = ocelot->ops->netdev_to_port(a->dev);
    370			if (egress_port < 0) {
    371				NL_SET_ERR_MSG_MOD(extack,
    372						   "Destination not an ocelot port");
    373				return -EOPNOTSUPP;
    374			}
    375			filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
    376			filter->action.port_mask = BIT(egress_port);
    377			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
    378			break;
    379		case FLOW_ACTION_MIRRED:
    380			if (filter->block_id != VCAP_IS2) {
    381				NL_SET_ERR_MSG_MOD(extack,
    382						   "Mirror action can only be offloaded to VCAP IS2");
    383				return -EOPNOTSUPP;
    384			}
    385			if (filter->goto_target != -1) {
    386				NL_SET_ERR_MSG_MOD(extack,
    387						   "Last action must be GOTO");
    388				return -EOPNOTSUPP;
    389			}
    390			egress_port = ocelot->ops->netdev_to_port(a->dev);
    391			if (egress_port < 0) {
    392				NL_SET_ERR_MSG_MOD(extack,
    393						   "Destination not an ocelot port");
    394				return -EOPNOTSUPP;
    395			}
    396			filter->egress_port.value = egress_port;
    397			filter->action.mirror_ena = true;
    398			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
    399			break;
    400		case FLOW_ACTION_VLAN_POP:
    401			if (filter->block_id != VCAP_IS1) {
    402				NL_SET_ERR_MSG_MOD(extack,
    403						   "VLAN pop action can only be offloaded to VCAP IS1");
    404				return -EOPNOTSUPP;
    405			}
    406			if (filter->goto_target != -1) {
    407				NL_SET_ERR_MSG_MOD(extack,
    408						   "Last action must be GOTO");
    409				return -EOPNOTSUPP;
    410			}
    411			filter->action.vlan_pop_cnt_ena = true;
    412			filter->action.vlan_pop_cnt++;
    413			if (filter->action.vlan_pop_cnt > 2) {
    414				NL_SET_ERR_MSG_MOD(extack,
    415						   "Cannot pop more than 2 VLAN headers");
    416				return -EOPNOTSUPP;
    417			}
    418			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
    419			break;
    420		case FLOW_ACTION_VLAN_MANGLE:
    421			if (filter->block_id == VCAP_IS1) {
    422				err = ocelot_flower_parse_ingress_vlan_modify(ocelot, port,
    423									      filter, a,
    424									      extack);
    425			} else if (filter->block_id == VCAP_ES0) {
    426				err = ocelot_flower_parse_egress_vlan_modify(filter, a,
    427									     extack);
    428			} else {
    429				NL_SET_ERR_MSG_MOD(extack,
    430						   "VLAN modify action can only be offloaded to VCAP IS1 or ES0");
    431				err = -EOPNOTSUPP;
    432			}
    433			if (err)
    434				return err;
    435			break;
    436		case FLOW_ACTION_PRIORITY:
    437			if (filter->block_id != VCAP_IS1) {
    438				NL_SET_ERR_MSG_MOD(extack,
    439						   "Priority action can only be offloaded to VCAP IS1");
    440				return -EOPNOTSUPP;
    441			}
    442			if (filter->goto_target != -1) {
    443				NL_SET_ERR_MSG_MOD(extack,
    444						   "Last action must be GOTO");
    445				return -EOPNOTSUPP;
    446			}
    447			filter->action.qos_ena = true;
    448			filter->action.qos_val = a->priority;
    449			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
    450			break;
    451		case FLOW_ACTION_GOTO:
    452			filter->goto_target = a->chain_index;
    453
    454			if (filter->block_id == VCAP_IS1 && filter->lookup == 2) {
    455				int pag = ocelot_chain_to_pag(filter->goto_target);
    456
    457				filter->action.pag_override_mask = 0xff;
    458				filter->action.pag_val = pag;
    459				filter->type = OCELOT_VCAP_FILTER_PAG;
    460			}
    461			break;
    462		case FLOW_ACTION_VLAN_PUSH:
    463			if (filter->block_id != VCAP_ES0) {
    464				NL_SET_ERR_MSG_MOD(extack,
    465						   "VLAN push action can only be offloaded to VCAP ES0");
    466				return -EOPNOTSUPP;
    467			}
    468			switch (ntohs(a->vlan.proto)) {
    469			case ETH_P_8021Q:
    470				tpid = OCELOT_TAG_TPID_SEL_8021Q;
    471				break;
    472			case ETH_P_8021AD:
    473				tpid = OCELOT_TAG_TPID_SEL_8021AD;
    474				break;
    475			default:
    476				NL_SET_ERR_MSG_MOD(extack,
    477						   "Cannot push custom TPID");
    478				return -EOPNOTSUPP;
    479			}
    480			filter->action.tag_a_tpid_sel = tpid;
    481			filter->action.push_outer_tag = OCELOT_ES0_TAG;
    482			filter->action.tag_a_vid_sel = OCELOT_ES0_VID;
    483			filter->action.vid_a_val = a->vlan.vid;
    484			filter->action.pcp_a_val = a->vlan.prio;
    485			filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
    486			break;
    487		case FLOW_ACTION_GATE:
    488			if (filter->block_id != PSFP_BLOCK_ID) {
    489				NL_SET_ERR_MSG_MOD(extack,
    490						   "Gate action can only be offloaded to PSFP chain");
    491				return -EOPNOTSUPP;
    492			}
    493			filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
    494			break;
    495		default:
    496			NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
    497			return -EOPNOTSUPP;
    498		}
    499	}
    500
    501	if (filter->goto_target == -1) {
    502		if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
    503		    chain == 0 || filter->block_id == PSFP_BLOCK_ID) {
    504			allow_missing_goto_target = true;
    505		} else {
    506			NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
    507			return -EOPNOTSUPP;
    508		}
    509	}
    510
    511	if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) &&
    512	    !allow_missing_goto_target) {
    513		NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target");
    514		return -EOPNOTSUPP;
    515	}
    516
    517	return 0;
    518}
    519
    520static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
    521				     struct flow_cls_offload *f,
    522				     struct ocelot_vcap_filter *filter)
    523{
    524	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
    525	const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
    526	int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length;
    527	struct netlink_ext_ack *extack = f->common.extack;
    528	struct net_device *dev, *indev;
    529	struct flow_match_meta match;
    530	int ingress_port;
    531
    532	flow_rule_match_meta(rule, &match);
    533
    534	if (!match.mask->ingress_ifindex)
    535		return 0;
    536
    537	if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
    538		NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask");
    539		return -EOPNOTSUPP;
    540	}
    541
    542	dev = ocelot->ops->port_to_netdev(ocelot, port);
    543	if (!dev)
    544		return -EINVAL;
    545
    546	indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex);
    547	if (!indev) {
    548		NL_SET_ERR_MSG_MOD(extack,
    549				   "Can't find the ingress port to match on");
    550		return -ENOENT;
    551	}
    552
    553	ingress_port = ocelot->ops->netdev_to_port(indev);
    554	if (ingress_port < 0) {
    555		NL_SET_ERR_MSG_MOD(extack,
    556				   "Can only offload an ocelot ingress port");
    557		return -EOPNOTSUPP;
    558	}
    559	if (ingress_port == port) {
    560		NL_SET_ERR_MSG_MOD(extack,
    561				   "Ingress port is equal to the egress port");
    562		return -EINVAL;
    563	}
    564
    565	filter->ingress_port.value = ingress_port;
    566	filter->ingress_port.mask = GENMASK(key_length - 1, 0);
    567
    568	return 0;
    569}
    570
    571static int
    572ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
    573			struct flow_cls_offload *f,
    574			struct ocelot_vcap_filter *filter)
    575{
    576	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
    577	struct flow_dissector *dissector = rule->match.dissector;
    578	struct netlink_ext_ack *extack = f->common.extack;
    579	u16 proto = ntohs(f->common.protocol);
    580	bool match_protocol = true;
    581	int ret;
    582
    583	if (dissector->used_keys &
    584	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
    585	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
    586	      BIT(FLOW_DISSECTOR_KEY_META) |
    587	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
    588	      BIT(FLOW_DISSECTOR_KEY_VLAN) |
    589	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
    590	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
    591	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
    592		return -EOPNOTSUPP;
    593	}
    594
    595	/* For VCAP ES0 (egress rewriter) we can match on the ingress port */
    596	if (!ingress) {
    597		ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
    598		if (ret)
    599			return ret;
    600	}
    601
    602	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
    603		struct flow_match_control match;
    604
    605		flow_rule_match_control(rule, &match);
    606	}
    607
    608	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
    609		struct flow_match_eth_addrs match;
    610
    611		if (filter->block_id == VCAP_ES0) {
    612			NL_SET_ERR_MSG_MOD(extack,
    613					   "VCAP ES0 cannot match on MAC address");
    614			return -EOPNOTSUPP;
    615		}
    616
    617		/* The hw support mac matches only for MAC_ETYPE key,
    618		 * therefore if other matches(port, tcp flags, etc) are added
    619		 * then just bail out
    620		 */
    621		if ((dissector->used_keys &
    622		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
    623		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
    624		     BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
    625		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
    626		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
    627		     BIT(FLOW_DISSECTOR_KEY_CONTROL)))
    628			return -EOPNOTSUPP;
    629
    630		flow_rule_match_eth_addrs(rule, &match);
    631
    632		if (filter->block_id == VCAP_IS1 &&
    633		    !is_zero_ether_addr(match.mask->dst)) {
    634			NL_SET_ERR_MSG_MOD(extack,
    635					   "Key type S1_NORMAL cannot match on destination MAC");
    636			return -EOPNOTSUPP;
    637		}
    638
    639		filter->key_type = OCELOT_VCAP_KEY_ETYPE;
    640		ether_addr_copy(filter->key.etype.dmac.value,
    641				match.key->dst);
    642		ether_addr_copy(filter->key.etype.smac.value,
    643				match.key->src);
    644		ether_addr_copy(filter->key.etype.dmac.mask,
    645				match.mask->dst);
    646		ether_addr_copy(filter->key.etype.smac.mask,
    647				match.mask->src);
    648		goto finished_key_parsing;
    649	}
    650
    651	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
    652		struct flow_match_basic match;
    653
    654		flow_rule_match_basic(rule, &match);
    655		if (ntohs(match.key->n_proto) == ETH_P_IP) {
    656			if (filter->block_id == VCAP_ES0) {
    657				NL_SET_ERR_MSG_MOD(extack,
    658						   "VCAP ES0 cannot match on IP protocol");
    659				return -EOPNOTSUPP;
    660			}
    661
    662			filter->key_type = OCELOT_VCAP_KEY_IPV4;
    663			filter->key.ipv4.proto.value[0] =
    664				match.key->ip_proto;
    665			filter->key.ipv4.proto.mask[0] =
    666				match.mask->ip_proto;
    667			match_protocol = false;
    668		}
    669		if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
    670			if (filter->block_id == VCAP_ES0) {
    671				NL_SET_ERR_MSG_MOD(extack,
    672						   "VCAP ES0 cannot match on IP protocol");
    673				return -EOPNOTSUPP;
    674			}
    675
    676			filter->key_type = OCELOT_VCAP_KEY_IPV6;
    677			filter->key.ipv6.proto.value[0] =
    678				match.key->ip_proto;
    679			filter->key.ipv6.proto.mask[0] =
    680				match.mask->ip_proto;
    681			match_protocol = false;
    682		}
    683	}
    684
    685	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
    686	    proto == ETH_P_IP) {
    687		struct flow_match_ipv4_addrs match;
    688		u8 *tmp;
    689
    690		if (filter->block_id == VCAP_ES0) {
    691			NL_SET_ERR_MSG_MOD(extack,
    692					   "VCAP ES0 cannot match on IP address");
    693			return -EOPNOTSUPP;
    694		}
    695
    696		flow_rule_match_ipv4_addrs(rule, &match);
    697
    698		if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
    699			NL_SET_ERR_MSG_MOD(extack,
    700					   "Key type S1_NORMAL cannot match on destination IP");
    701			return -EOPNOTSUPP;
    702		}
    703
    704		tmp = &filter->key.ipv4.sip.value.addr[0];
    705		memcpy(tmp, &match.key->src, 4);
    706
    707		tmp = &filter->key.ipv4.sip.mask.addr[0];
    708		memcpy(tmp, &match.mask->src, 4);
    709
    710		tmp = &filter->key.ipv4.dip.value.addr[0];
    711		memcpy(tmp, &match.key->dst, 4);
    712
    713		tmp = &filter->key.ipv4.dip.mask.addr[0];
    714		memcpy(tmp, &match.mask->dst, 4);
    715		match_protocol = false;
    716	}
    717
    718	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
    719	    proto == ETH_P_IPV6) {
    720		return -EOPNOTSUPP;
    721	}
    722
    723	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
    724		struct flow_match_ports match;
    725
    726		if (filter->block_id == VCAP_ES0) {
    727			NL_SET_ERR_MSG_MOD(extack,
    728					   "VCAP ES0 cannot match on L4 ports");
    729			return -EOPNOTSUPP;
    730		}
    731
    732		flow_rule_match_ports(rule, &match);
    733		filter->key.ipv4.sport.value = ntohs(match.key->src);
    734		filter->key.ipv4.sport.mask = ntohs(match.mask->src);
    735		filter->key.ipv4.dport.value = ntohs(match.key->dst);
    736		filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
    737		match_protocol = false;
    738	}
    739
    740	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
    741		struct flow_match_vlan match;
    742
    743		flow_rule_match_vlan(rule, &match);
    744		filter->key_type = OCELOT_VCAP_KEY_ANY;
    745		filter->vlan.vid.value = match.key->vlan_id;
    746		filter->vlan.vid.mask = match.mask->vlan_id;
    747		filter->vlan.pcp.value[0] = match.key->vlan_priority;
    748		filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
    749		match_protocol = false;
    750	}
    751
    752finished_key_parsing:
    753	if (match_protocol && proto != ETH_P_ALL) {
    754		if (filter->block_id == VCAP_ES0) {
    755			NL_SET_ERR_MSG_MOD(extack,
    756					   "VCAP ES0 cannot match on L2 proto");
    757			return -EOPNOTSUPP;
    758		}
    759
    760		/* TODO: support SNAP, LLC etc */
    761		if (proto < ETH_P_802_3_MIN)
    762			return -EOPNOTSUPP;
    763		filter->key_type = OCELOT_VCAP_KEY_ETYPE;
    764		*(__be16 *)filter->key.etype.etype.value = htons(proto);
    765		*(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
    766	}
    767	/* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
    768
    769	return 0;
    770}
    771
    772static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
    773			       struct flow_cls_offload *f,
    774			       struct ocelot_vcap_filter *filter)
    775{
    776	int ret;
    777
    778	filter->prio = f->common.prio;
    779	filter->id.cookie = f->cookie;
    780	filter->id.tc_offload = true;
    781
    782	ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
    783	if (ret)
    784		return ret;
    785
    786	/* PSFP filter need to parse key by stream identification function. */
    787	if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD)
    788		return 0;
    789
    790	return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
    791}
    792
    793static struct ocelot_vcap_filter
    794*ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
    795			   struct flow_cls_offload *f)
    796{
    797	struct ocelot_vcap_filter *filter;
    798
    799	filter = kzalloc(sizeof(*filter), GFP_KERNEL);
    800	if (!filter)
    801		return NULL;
    802
    803	if (ingress) {
    804		filter->ingress_port_mask = BIT(port);
    805	} else {
    806		const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
    807		int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
    808
    809		filter->egress_port.value = port;
    810		filter->egress_port.mask = GENMASK(key_length - 1, 0);
    811	}
    812
    813	return filter;
    814}
    815
    816static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
    817					struct ocelot_vcap_filter *filter)
    818{
    819	list_add(&filter->list, &ocelot->dummy_rules);
    820
    821	return 0;
    822}
    823
    824static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
    825					struct ocelot_vcap_filter *filter)
    826{
    827	list_del(&filter->list);
    828	kfree(filter);
    829
    830	return 0;
    831}
    832
    833/* If we have an egress VLAN modification rule, we need to actually write the
    834 * delta between the input VLAN (from the key) and the output VLAN (from the
    835 * action), but the action was parsed first. So we need to patch the delta into
    836 * the action here.
    837 */
    838static int
    839ocelot_flower_patch_es0_vlan_modify(struct ocelot_vcap_filter *filter,
    840				    struct netlink_ext_ack *extack)
    841{
    842	if (filter->block_id != VCAP_ES0 ||
    843	    filter->action.tag_a_vid_sel != OCELOT_ES0_VID_PLUS_CLASSIFIED_VID)
    844		return 0;
    845
    846	if (filter->vlan.vid.mask != VLAN_VID_MASK) {
    847		NL_SET_ERR_MSG_MOD(extack,
    848				   "VCAP ES0 VLAN rewriting needs a full VLAN in the key");
    849		return -EOPNOTSUPP;
    850	}
    851
    852	filter->action.vid_a_val -= filter->vlan.vid.value;
    853	filter->action.vid_a_val &= VLAN_VID_MASK;
    854
    855	return 0;
    856}
    857
    858int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
    859			      struct flow_cls_offload *f, bool ingress)
    860{
    861	struct netlink_ext_ack *extack = f->common.extack;
    862	struct ocelot_vcap_filter *filter;
    863	int chain = f->common.chain_index;
    864	int block_id, ret;
    865
    866	if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
    867		NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
    868		return -EOPNOTSUPP;
    869	}
    870
    871	block_id = ocelot_chain_to_block(chain, ingress);
    872	if (block_id < 0) {
    873		NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
    874		return -EOPNOTSUPP;
    875	}
    876
    877	filter = ocelot_vcap_block_find_filter_by_id(&ocelot->block[block_id],
    878						     f->cookie, true);
    879	if (filter) {
    880		/* Filter already exists on other ports */
    881		if (!ingress) {
    882			NL_SET_ERR_MSG_MOD(extack, "VCAP ES0 does not support shared filters");
    883			return -EOPNOTSUPP;
    884		}
    885
    886		filter->ingress_port_mask |= BIT(port);
    887
    888		return ocelot_vcap_filter_replace(ocelot, filter);
    889	}
    890
    891	/* Filter didn't exist, create it now */
    892	filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
    893	if (!filter)
    894		return -ENOMEM;
    895
    896	ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
    897	if (ret) {
    898		kfree(filter);
    899		return ret;
    900	}
    901
    902	ret = ocelot_flower_patch_es0_vlan_modify(filter, extack);
    903	if (ret) {
    904		kfree(filter);
    905		return ret;
    906	}
    907
    908	/* The non-optional GOTOs for the TCAM skeleton don't need
    909	 * to be actually offloaded.
    910	 */
    911	if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
    912		return ocelot_vcap_dummy_filter_add(ocelot, filter);
    913
    914	if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD) {
    915		kfree(filter);
    916		if (ocelot->ops->psfp_filter_add)
    917			return ocelot->ops->psfp_filter_add(ocelot, port, f);
    918
    919		NL_SET_ERR_MSG_MOD(extack, "PSFP chain is not supported in HW");
    920		return -EOPNOTSUPP;
    921	}
    922
    923	return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
    924}
    925EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
    926
    927int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
    928			      struct flow_cls_offload *f, bool ingress)
    929{
    930	struct ocelot_vcap_filter *filter;
    931	struct ocelot_vcap_block *block;
    932	int block_id;
    933
    934	block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
    935	if (block_id < 0)
    936		return 0;
    937
    938	if (block_id == PSFP_BLOCK_ID) {
    939		if (ocelot->ops->psfp_filter_del)
    940			return ocelot->ops->psfp_filter_del(ocelot, f);
    941
    942		return -EOPNOTSUPP;
    943	}
    944
    945	block = &ocelot->block[block_id];
    946
    947	filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
    948	if (!filter)
    949		return 0;
    950
    951	if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
    952		return ocelot_vcap_dummy_filter_del(ocelot, filter);
    953
    954	if (ingress) {
    955		filter->ingress_port_mask &= ~BIT(port);
    956		if (filter->ingress_port_mask)
    957			return ocelot_vcap_filter_replace(ocelot, filter);
    958	}
    959
    960	return ocelot_vcap_filter_del(ocelot, filter);
    961}
    962EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
    963
    964int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
    965			    struct flow_cls_offload *f, bool ingress)
    966{
    967	struct ocelot_vcap_filter *filter;
    968	struct ocelot_vcap_block *block;
    969	struct flow_stats stats = {0};
    970	int block_id, ret;
    971
    972	block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
    973	if (block_id < 0)
    974		return 0;
    975
    976	if (block_id == PSFP_BLOCK_ID) {
    977		if (ocelot->ops->psfp_stats_get) {
    978			ret = ocelot->ops->psfp_stats_get(ocelot, f, &stats);
    979			if (ret)
    980				return ret;
    981
    982			goto stats_update;
    983		}
    984
    985		return -EOPNOTSUPP;
    986	}
    987
    988	block = &ocelot->block[block_id];
    989
    990	filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
    991	if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
    992		return 0;
    993
    994	ret = ocelot_vcap_filter_stats_update(ocelot, filter);
    995	if (ret)
    996		return ret;
    997
    998	stats.pkts = filter->stats.pkts;
    999
   1000stats_update:
   1001	flow_stats_update(&f->stats, 0x0, stats.pkts, stats.drops, 0x0,
   1002			  FLOW_ACTION_HW_STATS_IMMEDIATE);
   1003	return 0;
   1004}
   1005EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);