Linux Audio

Check our new training course

Loading...
v6.8
   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_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
 585	      BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
 586	      BIT_ULL(FLOW_DISSECTOR_KEY_META) |
 587	      BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
 588	      BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
 589	      BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
 590	      BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
 591	      BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
 592		return -EOPNOTSUPP;
 593	}
 594
 595	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META)) {
 596		struct flow_match_meta match;
 597
 598		flow_rule_match_meta(rule, &match);
 599		if (match.mask->l2_miss) {
 600			NL_SET_ERR_MSG_MOD(extack, "Can't match on \"l2_miss\"");
 601			return -EOPNOTSUPP;
 602		}
 603	}
 604
 605	/* For VCAP ES0 (egress rewriter) we can match on the ingress port */
 606	if (!ingress) {
 607		ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
 608		if (ret)
 609			return ret;
 610	}
 611
 612	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
 613		struct flow_match_control match;
 614
 615		flow_rule_match_control(rule, &match);
 616	}
 617
 618	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
 619		struct flow_match_vlan match;
 620
 621		flow_rule_match_vlan(rule, &match);
 622		filter->key_type = OCELOT_VCAP_KEY_ANY;
 623		filter->vlan.vid.value = match.key->vlan_id;
 624		filter->vlan.vid.mask = match.mask->vlan_id;
 625		filter->vlan.pcp.value[0] = match.key->vlan_priority;
 626		filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
 627		match_protocol = false;
 628	}
 629
 630	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
 631		struct flow_match_eth_addrs match;
 632
 633		if (filter->block_id == VCAP_ES0) {
 634			NL_SET_ERR_MSG_MOD(extack,
 635					   "VCAP ES0 cannot match on MAC address");
 636			return -EOPNOTSUPP;
 637		}
 638
 639		/* The hw support mac matches only for MAC_ETYPE key,
 640		 * therefore if other matches(port, tcp flags, etc) are added
 641		 * then just bail out
 642		 */
 643		if ((dissector->used_keys &
 644		    (BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
 645		     BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
 646		     BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL))) !=
 647		    (BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
 648		     BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
 649		     BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL)))
 650			return -EOPNOTSUPP;
 651
 652		flow_rule_match_eth_addrs(rule, &match);
 653
 654		if (filter->block_id == VCAP_IS1 &&
 655		    !is_zero_ether_addr(match.mask->dst)) {
 656			NL_SET_ERR_MSG_MOD(extack,
 657					   "Key type S1_NORMAL cannot match on destination MAC");
 658			return -EOPNOTSUPP;
 659		}
 660
 661		filter->key_type = OCELOT_VCAP_KEY_ETYPE;
 662		ether_addr_copy(filter->key.etype.dmac.value,
 
 663				match.key->dst);
 664		ether_addr_copy(filter->key.etype.smac.value,
 665				match.key->src);
 666		ether_addr_copy(filter->key.etype.dmac.mask,
 667				match.mask->dst);
 668		ether_addr_copy(filter->key.etype.smac.mask,
 669				match.mask->src);
 670		goto finished_key_parsing;
 671	}
 672
 673	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
 674		struct flow_match_basic match;
 675
 676		flow_rule_match_basic(rule, &match);
 677		if (ntohs(match.key->n_proto) == ETH_P_IP) {
 678			if (filter->block_id == VCAP_ES0) {
 679				NL_SET_ERR_MSG_MOD(extack,
 680						   "VCAP ES0 cannot match on IP protocol");
 681				return -EOPNOTSUPP;
 682			}
 683
 684			filter->key_type = OCELOT_VCAP_KEY_IPV4;
 685			filter->key.ipv4.proto.value[0] =
 686				match.key->ip_proto;
 687			filter->key.ipv4.proto.mask[0] =
 688				match.mask->ip_proto;
 689			match_protocol = false;
 690		}
 691		if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
 692			if (filter->block_id == VCAP_ES0) {
 693				NL_SET_ERR_MSG_MOD(extack,
 694						   "VCAP ES0 cannot match on IP protocol");
 695				return -EOPNOTSUPP;
 696			}
 697
 698			filter->key_type = OCELOT_VCAP_KEY_IPV6;
 699			filter->key.ipv6.proto.value[0] =
 700				match.key->ip_proto;
 701			filter->key.ipv6.proto.mask[0] =
 702				match.mask->ip_proto;
 703			match_protocol = false;
 704		}
 705	}
 706
 707	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
 708	    proto == ETH_P_IP) {
 709		struct flow_match_ipv4_addrs match;
 710		u8 *tmp;
 711
 712		if (filter->block_id == VCAP_ES0) {
 713			NL_SET_ERR_MSG_MOD(extack,
 714					   "VCAP ES0 cannot match on IP address");
 715			return -EOPNOTSUPP;
 716		}
 717
 718		flow_rule_match_ipv4_addrs(rule, &match);
 719
 720		if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
 721			NL_SET_ERR_MSG_MOD(extack,
 722					   "Key type S1_NORMAL cannot match on destination IP");
 723			return -EOPNOTSUPP;
 724		}
 725
 726		tmp = &filter->key.ipv4.sip.value.addr[0];
 727		memcpy(tmp, &match.key->src, 4);
 728
 729		tmp = &filter->key.ipv4.sip.mask.addr[0];
 730		memcpy(tmp, &match.mask->src, 4);
 731
 732		tmp = &filter->key.ipv4.dip.value.addr[0];
 733		memcpy(tmp, &match.key->dst, 4);
 734
 735		tmp = &filter->key.ipv4.dip.mask.addr[0];
 736		memcpy(tmp, &match.mask->dst, 4);
 737		match_protocol = false;
 738	}
 739
 740	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
 741	    proto == ETH_P_IPV6) {
 742		return -EOPNOTSUPP;
 743	}
 744
 745	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
 746		struct flow_match_ports match;
 747
 748		if (filter->block_id == VCAP_ES0) {
 749			NL_SET_ERR_MSG_MOD(extack,
 750					   "VCAP ES0 cannot match on L4 ports");
 751			return -EOPNOTSUPP;
 752		}
 753
 754		flow_rule_match_ports(rule, &match);
 755		filter->key.ipv4.sport.value = ntohs(match.key->src);
 756		filter->key.ipv4.sport.mask = ntohs(match.mask->src);
 757		filter->key.ipv4.dport.value = ntohs(match.key->dst);
 758		filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
 759		match_protocol = false;
 760	}
 761
 762finished_key_parsing:
 763	if (match_protocol && proto != ETH_P_ALL) {
 764		if (filter->block_id == VCAP_ES0) {
 765			NL_SET_ERR_MSG_MOD(extack,
 766					   "VCAP ES0 cannot match on L2 proto");
 767			return -EOPNOTSUPP;
 768		}
 769
 770		/* TODO: support SNAP, LLC etc */
 771		if (proto < ETH_P_802_3_MIN)
 772			return -EOPNOTSUPP;
 773		filter->key_type = OCELOT_VCAP_KEY_ETYPE;
 774		*(__be16 *)filter->key.etype.etype.value = htons(proto);
 775		*(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
 776	}
 777	/* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
 778
 779	return 0;
 
 
 
 780}
 781
 782static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
 783			       struct flow_cls_offload *f,
 784			       struct ocelot_vcap_filter *filter)
 785{
 786	int ret;
 787
 788	filter->prio = f->common.prio;
 789	filter->id.cookie = f->cookie;
 790	filter->id.tc_offload = true;
 791
 792	ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
 793	if (ret)
 794		return ret;
 795
 796	/* PSFP filter need to parse key by stream identification function. */
 797	if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD)
 798		return 0;
 799
 800	return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
 
 
 801}
 802
 803static struct ocelot_vcap_filter
 804*ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
 805			   struct flow_cls_offload *f)
 806{
 807	struct ocelot_vcap_filter *filter;
 808
 809	filter = kzalloc(sizeof(*filter), GFP_KERNEL);
 810	if (!filter)
 811		return NULL;
 812
 813	if (ingress) {
 814		filter->ingress_port_mask = BIT(port);
 815	} else {
 816		const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
 817		int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
 818
 819		filter->egress_port.value = port;
 820		filter->egress_port.mask = GENMASK(key_length - 1, 0);
 
 
 821	}
 822
 823	return filter;
 
 
 
 
 
 824}
 825
 826static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
 827					struct ocelot_vcap_filter *filter)
 828{
 829	list_add(&filter->list, &ocelot->dummy_rules);
 
 830
 
 
 
 
 
 
 
 
 
 831	return 0;
 832}
 833
 834static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
 835					struct ocelot_vcap_filter *filter)
 836{
 837	list_del(&filter->list);
 838	kfree(filter);
 
 
 
 
 
 
 
 839
 
 840	return 0;
 841}
 842
 843/* If we have an egress VLAN modification rule, we need to actually write the
 844 * delta between the input VLAN (from the key) and the output VLAN (from the
 845 * action), but the action was parsed first. So we need to patch the delta into
 846 * the action here.
 847 */
 848static int
 849ocelot_flower_patch_es0_vlan_modify(struct ocelot_vcap_filter *filter,
 850				    struct netlink_ext_ack *extack)
 851{
 852	if (filter->block_id != VCAP_ES0 ||
 853	    filter->action.tag_a_vid_sel != OCELOT_ES0_VID_PLUS_CLASSIFIED_VID)
 854		return 0;
 855
 856	if (filter->vlan.vid.mask != VLAN_VID_MASK) {
 857		NL_SET_ERR_MSG_MOD(extack,
 858				   "VCAP ES0 VLAN rewriting needs a full VLAN in the key");
 
 859		return -EOPNOTSUPP;
 860	}
 861
 862	filter->action.vid_a_val -= filter->vlan.vid.value;
 863	filter->action.vid_a_val &= VLAN_VID_MASK;
 864
 865	return 0;
 866}
 867
 868int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
 869			      struct flow_cls_offload *f, bool ingress)
 870{
 871	struct netlink_ext_ack *extack = f->common.extack;
 872	struct ocelot_vcap_filter *filter;
 873	int chain = f->common.chain_index;
 874	int block_id, ret;
 875
 876	if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
 877		NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
 878		return -EOPNOTSUPP;
 879	}
 880
 881	block_id = ocelot_chain_to_block(chain, ingress);
 882	if (block_id < 0) {
 883		NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
 
 
 
 884		return -EOPNOTSUPP;
 885	}
 
 886
 887	filter = ocelot_vcap_block_find_filter_by_id(&ocelot->block[block_id],
 888						     f->cookie, true);
 889	if (filter) {
 890		/* Filter already exists on other ports */
 891		if (!ingress) {
 892			NL_SET_ERR_MSG_MOD(extack, "VCAP ES0 does not support shared filters");
 893			return -EOPNOTSUPP;
 894		}
 895
 896		filter->ingress_port_mask |= BIT(port);
 897
 898		return ocelot_vcap_filter_replace(ocelot, filter);
 899	}
 900
 901	/* Filter didn't exist, create it now */
 902	filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
 903	if (!filter)
 904		return -ENOMEM;
 905
 906	ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
 907	if (ret) {
 908		kfree(filter);
 909		return ret;
 910	}
 911
 912	ret = ocelot_flower_patch_es0_vlan_modify(filter, extack);
 913	if (ret) {
 914		kfree(filter);
 915		return ret;
 916	}
 917
 918	/* The non-optional GOTOs for the TCAM skeleton don't need
 919	 * to be actually offloaded.
 920	 */
 921	if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
 922		return ocelot_vcap_dummy_filter_add(ocelot, filter);
 923
 924	if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD) {
 925		kfree(filter);
 926		if (ocelot->ops->psfp_filter_add)
 927			return ocelot->ops->psfp_filter_add(ocelot, port, f);
 928
 929		NL_SET_ERR_MSG_MOD(extack, "PSFP chain is not supported in HW");
 930		return -EOPNOTSUPP;
 931	}
 932
 933	return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
 
 
 934}
 935EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
 936
 937int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
 938			      struct flow_cls_offload *f, bool ingress)
 939{
 940	struct ocelot_vcap_filter *filter;
 941	struct ocelot_vcap_block *block;
 942	int block_id;
 943
 944	block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
 945	if (block_id < 0)
 946		return 0;
 947
 948	if (block_id == PSFP_BLOCK_ID) {
 949		if (ocelot->ops->psfp_filter_del)
 950			return ocelot->ops->psfp_filter_del(ocelot, f);
 
 
 
 951
 
 952		return -EOPNOTSUPP;
 953	}
 954
 955	block = &ocelot->block[block_id];
 956
 957	filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
 958	if (!filter)
 959		return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 960
 961	if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
 962		return ocelot_vcap_dummy_filter_del(ocelot, filter);
 963
 964	if (ingress) {
 965		filter->ingress_port_mask &= ~BIT(port);
 966		if (filter->ingress_port_mask)
 967			return ocelot_vcap_filter_replace(ocelot, filter);
 968	}
 969
 970	return ocelot_vcap_filter_del(ocelot, filter);
 971}
 972EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
 973
 974int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
 975			    struct flow_cls_offload *f, bool ingress)
 976{
 977	struct ocelot_vcap_filter *filter;
 978	struct ocelot_vcap_block *block;
 979	struct flow_stats stats = {0};
 980	int block_id, ret;
 981
 982	block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
 983	if (block_id < 0)
 984		return 0;
 
 985
 986	if (block_id == PSFP_BLOCK_ID) {
 987		if (ocelot->ops->psfp_stats_get) {
 988			ret = ocelot->ops->psfp_stats_get(ocelot, f, &stats);
 989			if (ret)
 990				return ret;
 991
 992			goto stats_update;
 993		}
 994
 995		return -EOPNOTSUPP;
 996	}
 997
 998	block = &ocelot->block[block_id];
 999
1000	filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
1001	if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
1002		return 0;
1003
1004	ret = ocelot_vcap_filter_stats_update(ocelot, filter);
1005	if (ret)
1006		return ret;
1007
1008	stats.pkts = filter->stats.pkts;
1009
1010stats_update:
1011	flow_stats_update(&f->stats, 0x0, stats.pkts, stats.drops, 0x0,
1012			  FLOW_ACTION_HW_STATS_IMMEDIATE);
1013	return 0;
1014}
1015EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);
v5.4
  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
  9#include "ocelot_ace.h"
 
 
 
 10
 11struct ocelot_port_block {
 12	struct ocelot_acl_block *block;
 13	struct ocelot_port *port;
 14};
 15
 16static int ocelot_flower_parse_action(struct flow_cls_offload *f,
 17				      struct ocelot_ace_rule *rule)
 18{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 19	const struct flow_action_entry *a;
 20	int i;
 
 
 
 
 
 
 
 
 21
 22	if (f->rule->action.num_entries != 1)
 
 
 
 23		return -EOPNOTSUPP;
 
 
 
 
 
 
 
 
 24
 25	flow_action_for_each(i, a, &f->rule->action) {
 26		switch (a->id) {
 27		case FLOW_ACTION_DROP:
 28			rule->action = OCELOT_ACL_ACTION_DROP;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 29			break;
 30		case FLOW_ACTION_TRAP:
 31			rule->action = OCELOT_ACL_ACTION_TRAP;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 32			break;
 33		default:
 
 34			return -EOPNOTSUPP;
 35		}
 36	}
 37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 38	return 0;
 39}
 40
 41static int ocelot_flower_parse(struct flow_cls_offload *f,
 42			       struct ocelot_ace_rule *ocelot_rule)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 43{
 44	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
 45	struct flow_dissector *dissector = rule->match.dissector;
 
 
 
 
 46
 47	if (dissector->used_keys &
 48	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
 49	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
 50	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
 51	      BIT(FLOW_DISSECTOR_KEY_VLAN) |
 52	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
 53	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
 54	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
 
 55		return -EOPNOTSUPP;
 56	}
 57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 58	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
 59		struct flow_match_control match;
 60
 61		flow_rule_match_control(rule, &match);
 62	}
 63
 
 
 
 
 
 
 
 
 
 
 
 
 64	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
 65		struct flow_match_eth_addrs match;
 66		u16 proto = ntohs(f->common.protocol);
 
 
 
 
 
 67
 68		/* The hw support mac matches only for MAC_ETYPE key,
 69		 * therefore if other matches(port, tcp flags, etc) are added
 70		 * then just bail out
 71		 */
 72		if ((dissector->used_keys &
 73		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
 74		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
 75		     BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
 76		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
 77		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
 78		     BIT(FLOW_DISSECTOR_KEY_CONTROL)))
 79			return -EOPNOTSUPP;
 80
 81		if (proto == ETH_P_IP ||
 82		    proto == ETH_P_IPV6 ||
 83		    proto == ETH_P_ARP)
 
 
 
 84			return -EOPNOTSUPP;
 
 85
 86		flow_rule_match_eth_addrs(rule, &match);
 87		ocelot_rule->type = OCELOT_ACE_TYPE_ETYPE;
 88		ether_addr_copy(ocelot_rule->frame.etype.dmac.value,
 89				match.key->dst);
 90		ether_addr_copy(ocelot_rule->frame.etype.smac.value,
 91				match.key->src);
 92		ether_addr_copy(ocelot_rule->frame.etype.dmac.mask,
 93				match.mask->dst);
 94		ether_addr_copy(ocelot_rule->frame.etype.smac.mask,
 95				match.mask->src);
 96		goto finished_key_parsing;
 97	}
 98
 99	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
100		struct flow_match_basic match;
101
102		flow_rule_match_basic(rule, &match);
103		if (ntohs(match.key->n_proto) == ETH_P_IP) {
104			ocelot_rule->type = OCELOT_ACE_TYPE_IPV4;
105			ocelot_rule->frame.ipv4.proto.value[0] =
 
 
 
 
 
 
106				match.key->ip_proto;
107			ocelot_rule->frame.ipv4.proto.mask[0] =
108				match.mask->ip_proto;
 
109		}
110		if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
111			ocelot_rule->type = OCELOT_ACE_TYPE_IPV6;
112			ocelot_rule->frame.ipv6.proto.value[0] =
 
 
 
 
 
 
113				match.key->ip_proto;
114			ocelot_rule->frame.ipv6.proto.mask[0] =
115				match.mask->ip_proto;
 
116		}
117	}
118
119	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
120	    ntohs(f->common.protocol) == ETH_P_IP) {
121		struct flow_match_ipv4_addrs match;
122		u8 *tmp;
123
 
 
 
 
 
 
124		flow_rule_match_ipv4_addrs(rule, &match);
125		tmp = &ocelot_rule->frame.ipv4.sip.value.addr[0];
 
 
 
 
 
 
 
126		memcpy(tmp, &match.key->src, 4);
127
128		tmp = &ocelot_rule->frame.ipv4.sip.mask.addr[0];
129		memcpy(tmp, &match.mask->src, 4);
130
131		tmp = &ocelot_rule->frame.ipv4.dip.value.addr[0];
132		memcpy(tmp, &match.key->dst, 4);
133
134		tmp = &ocelot_rule->frame.ipv4.dip.mask.addr[0];
135		memcpy(tmp, &match.mask->dst, 4);
 
136	}
137
138	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
139	    ntohs(f->common.protocol) == ETH_P_IPV6) {
140		return -EOPNOTSUPP;
141	}
142
143	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
144		struct flow_match_ports match;
145
 
 
 
 
 
 
146		flow_rule_match_ports(rule, &match);
147		ocelot_rule->frame.ipv4.sport.value = ntohs(match.key->src);
148		ocelot_rule->frame.ipv4.sport.mask = ntohs(match.mask->src);
149		ocelot_rule->frame.ipv4.dport.value = ntohs(match.key->dst);
150		ocelot_rule->frame.ipv4.dport.mask = ntohs(match.mask->dst);
 
151	}
152
153	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
154		struct flow_match_vlan match;
 
 
 
 
 
155
156		flow_rule_match_vlan(rule, &match);
157		ocelot_rule->type = OCELOT_ACE_TYPE_ANY;
158		ocelot_rule->vlan.vid.value = match.key->vlan_id;
159		ocelot_rule->vlan.vid.mask = match.mask->vlan_id;
160		ocelot_rule->vlan.pcp.value[0] = match.key->vlan_priority;
161		ocelot_rule->vlan.pcp.mask[0] = match.mask->vlan_priority;
162	}
 
163
164finished_key_parsing:
165	ocelot_rule->prio = f->common.prio;
166	ocelot_rule->id = f->cookie;
167	return ocelot_flower_parse_action(f, ocelot_rule);
168}
169
170static
171struct ocelot_ace_rule *ocelot_ace_rule_create(struct flow_cls_offload *f,
172					       struct ocelot_port_block *block)
173{
174	struct ocelot_ace_rule *rule;
175
176	rule = kzalloc(sizeof(*rule), GFP_KERNEL);
177	if (!rule)
178		return NULL;
 
 
 
 
 
 
 
 
179
180	rule->port = block->port;
181	rule->chip_port = block->port->chip_port;
182	return rule;
183}
184
185static int ocelot_flower_replace(struct flow_cls_offload *f,
186				 struct ocelot_port_block *port_block)
 
187{
188	struct ocelot_ace_rule *rule;
189	int ret;
 
 
 
190
191	rule = ocelot_ace_rule_create(f, port_block);
192	if (!rule)
193		return -ENOMEM;
 
 
194
195	ret = ocelot_flower_parse(f, rule);
196	if (ret) {
197		kfree(rule);
198		return ret;
199	}
200
201	ret = ocelot_ace_rule_offload_add(rule);
202	if (ret)
203		return ret;
204
205	port_block->port->tc.offload_cnt++;
206	return 0;
207}
208
209static int ocelot_flower_destroy(struct flow_cls_offload *f,
210				 struct ocelot_port_block *port_block)
211{
212	struct ocelot_ace_rule rule;
213	int ret;
214
215	rule.prio = f->common.prio;
216	rule.port = port_block->port;
217	rule.id = f->cookie;
218
219	ret = ocelot_ace_rule_offload_del(&rule);
220	if (ret)
221		return ret;
222
223	port_block->port->tc.offload_cnt--;
224	return 0;
225}
226
227static int ocelot_flower_stats_update(struct flow_cls_offload *f,
228				      struct ocelot_port_block *port_block)
229{
230	struct ocelot_ace_rule rule;
231	int ret;
232
233	rule.prio = f->common.prio;
234	rule.port = port_block->port;
235	rule.id = f->cookie;
236	ret = ocelot_ace_rule_stats_update(&rule);
237	if (ret)
238		return ret;
239
240	flow_stats_update(&f->stats, 0x0, rule.stats.pkts, 0x0);
241	return 0;
242}
243
244static int ocelot_setup_tc_cls_flower(struct flow_cls_offload *f,
245				      struct ocelot_port_block *port_block)
 
 
 
 
 
 
246{
247	switch (f->command) {
248	case FLOW_CLS_REPLACE:
249		return ocelot_flower_replace(f, port_block);
250	case FLOW_CLS_DESTROY:
251		return ocelot_flower_destroy(f, port_block);
252	case FLOW_CLS_STATS:
253		return ocelot_flower_stats_update(f, port_block);
254	default:
255		return -EOPNOTSUPP;
256	}
 
 
 
 
 
257}
258
259static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type,
260					   void *type_data, void *cb_priv)
261{
262	struct ocelot_port_block *port_block = cb_priv;
 
 
 
263
264	if (!tc_cls_can_offload_and_chain0(port_block->port->dev, type_data))
 
265		return -EOPNOTSUPP;
 
266
267	switch (type) {
268	case TC_SETUP_CLSFLOWER:
269		return ocelot_setup_tc_cls_flower(type_data, cb_priv);
270	case TC_SETUP_CLSMATCHALL:
271		return 0;
272	default:
273		return -EOPNOTSUPP;
274	}
275}
276
277static struct ocelot_port_block*
278ocelot_port_block_create(struct ocelot_port *port)
279{
280	struct ocelot_port_block *port_block;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
282	port_block = kzalloc(sizeof(*port_block), GFP_KERNEL);
283	if (!port_block)
284		return NULL;
 
 
285
286	port_block->port = port;
 
 
 
 
 
 
 
 
 
287
288	return port_block;
289}
 
290
291static void ocelot_port_block_destroy(struct ocelot_port_block *block)
292{
293	kfree(block);
294}
 
295
296static void ocelot_tc_block_unbind(void *cb_priv)
 
297{
298	struct ocelot_port_block *port_block = cb_priv;
 
 
299
300	ocelot_port_block_destroy(port_block);
301}
 
302
303int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
304				      struct flow_block_offload *f)
305{
306	struct ocelot_port_block *port_block;
307	struct flow_block_cb *block_cb;
308	int ret;
309
310	if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
311		return -EOPNOTSUPP;
 
 
 
312
313	block_cb = flow_block_cb_lookup(f->block,
314					ocelot_setup_tc_block_cb_flower, port);
315	if (!block_cb) {
316		port_block = ocelot_port_block_create(port);
317		if (!port_block)
318			return -ENOMEM;
319
320		block_cb = flow_block_cb_alloc(ocelot_setup_tc_block_cb_flower,
321					       port, port_block,
322					       ocelot_tc_block_unbind);
323		if (IS_ERR(block_cb)) {
324			ret = PTR_ERR(block_cb);
325			goto err_cb_register;
326		}
327		flow_block_cb_add(block_cb, f);
328		list_add_tail(&block_cb->driver_list, f->driver_block_list);
329	} else {
330		port_block = flow_block_cb_priv(block_cb);
331	}
332
333	flow_block_cb_incref(block_cb);
334	return 0;
335
336err_cb_register:
337	ocelot_port_block_destroy(port_block);
 
 
 
338
339	return ret;
340}
 
341
342void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
343					 struct flow_block_offload *f)
344{
345	struct flow_block_cb *block_cb;
 
 
 
346
347	block_cb = flow_block_cb_lookup(f->block,
348					ocelot_setup_tc_block_cb_flower, port);
349	if (!block_cb)
350		return;
351
352	if (!flow_block_cb_decref(block_cb)) {
353		flow_block_cb_remove(block_cb, f);
354		list_del(&block_cb->driver_list);
 
 
 
 
 
 
 
355	}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356}