Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
   1// SPDX-License-Identifier: GPL-2.0+
   2/* Microchip VCAP API
   3 *
   4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
   5 */
   6
   7#include <net/tcp.h>
   8
   9#include "sparx5_tc.h"
  10#include "vcap_api.h"
  11#include "vcap_api_client.h"
  12#include "sparx5_main.h"
  13#include "sparx5_vcap_impl.h"
  14
  15#define SPX5_MAX_RULE_SIZE 13 /* allows X1, X2, X4, X6 and X12 rules */
  16
  17/* Collect keysets and type ids for multiple rules per size */
  18struct sparx5_wildcard_rule {
  19	bool selected;
  20	u8 value;
  21	u8 mask;
  22	enum vcap_keyfield_set keyset;
  23};
  24
  25struct sparx5_multiple_rules {
  26	struct sparx5_wildcard_rule rule[SPX5_MAX_RULE_SIZE];
  27};
  28
  29struct sparx5_tc_flower_parse_usage {
  30	struct flow_cls_offload *fco;
  31	struct flow_rule *frule;
  32	struct vcap_rule *vrule;
  33	u16 l3_proto;
  34	u8 l4_proto;
  35	unsigned int used_keys;
  36};
  37
  38struct sparx5_tc_rule_pkt_cnt {
  39	u64 cookie;
  40	u32 pkts;
  41};
  42
  43/* These protocols have dedicated keysets in IS2 and a TC dissector
  44 * ETH_P_ARP does not have a TC dissector
  45 */
  46static u16 sparx5_tc_known_etypes[] = {
  47	ETH_P_ALL,
  48	ETH_P_ARP,
  49	ETH_P_IP,
  50	ETH_P_IPV6,
  51};
  52
  53enum sparx5_is2_arp_opcode {
  54	SPX5_IS2_ARP_REQUEST,
  55	SPX5_IS2_ARP_REPLY,
  56	SPX5_IS2_RARP_REQUEST,
  57	SPX5_IS2_RARP_REPLY,
  58};
  59
  60enum tc_arp_opcode {
  61	TC_ARP_OP_RESERVED,
  62	TC_ARP_OP_REQUEST,
  63	TC_ARP_OP_REPLY,
  64};
  65
  66static bool sparx5_tc_is_known_etype(u16 etype)
  67{
  68	int idx;
  69
  70	/* For now this only knows about IS2 traffic classification */
  71	for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_known_etypes); ++idx)
  72		if (sparx5_tc_known_etypes[idx] == etype)
  73			return true;
  74
  75	return false;
  76}
  77
  78static int sparx5_tc_flower_handler_ethaddr_usage(struct sparx5_tc_flower_parse_usage *st)
  79{
  80	enum vcap_key_field smac_key = VCAP_KF_L2_SMAC;
  81	enum vcap_key_field dmac_key = VCAP_KF_L2_DMAC;
  82	struct flow_match_eth_addrs match;
  83	struct vcap_u48_key smac, dmac;
  84	int err = 0;
  85
  86	flow_rule_match_eth_addrs(st->frule, &match);
  87
  88	if (!is_zero_ether_addr(match.mask->src)) {
  89		vcap_netbytes_copy(smac.value, match.key->src, ETH_ALEN);
  90		vcap_netbytes_copy(smac.mask, match.mask->src, ETH_ALEN);
  91		err = vcap_rule_add_key_u48(st->vrule, smac_key, &smac);
  92		if (err)
  93			goto out;
  94	}
  95
  96	if (!is_zero_ether_addr(match.mask->dst)) {
  97		vcap_netbytes_copy(dmac.value, match.key->dst, ETH_ALEN);
  98		vcap_netbytes_copy(dmac.mask, match.mask->dst, ETH_ALEN);
  99		err = vcap_rule_add_key_u48(st->vrule, dmac_key, &dmac);
 100		if (err)
 101			goto out;
 102	}
 103
 104	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS);
 105
 106	return err;
 107
 108out:
 109	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error");
 110	return err;
 111}
 112
 113static int
 114sparx5_tc_flower_handler_ipv4_usage(struct sparx5_tc_flower_parse_usage *st)
 115{
 116	int err = 0;
 117
 118	if (st->l3_proto == ETH_P_IP) {
 119		struct flow_match_ipv4_addrs mt;
 120
 121		flow_rule_match_ipv4_addrs(st->frule, &mt);
 122		if (mt.mask->src) {
 123			err = vcap_rule_add_key_u32(st->vrule,
 124						    VCAP_KF_L3_IP4_SIP,
 125						    be32_to_cpu(mt.key->src),
 126						    be32_to_cpu(mt.mask->src));
 127			if (err)
 128				goto out;
 129		}
 130		if (mt.mask->dst) {
 131			err = vcap_rule_add_key_u32(st->vrule,
 132						    VCAP_KF_L3_IP4_DIP,
 133						    be32_to_cpu(mt.key->dst),
 134						    be32_to_cpu(mt.mask->dst));
 135			if (err)
 136				goto out;
 137		}
 138	}
 139
 140	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS);
 141
 142	return err;
 143
 144out:
 145	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv4_addr parse error");
 146	return err;
 147}
 148
 149static int
 150sparx5_tc_flower_handler_ipv6_usage(struct sparx5_tc_flower_parse_usage *st)
 151{
 152	int err = 0;
 153
 154	if (st->l3_proto == ETH_P_IPV6) {
 155		struct flow_match_ipv6_addrs mt;
 156		struct vcap_u128_key sip;
 157		struct vcap_u128_key dip;
 158
 159		flow_rule_match_ipv6_addrs(st->frule, &mt);
 160		/* Check if address masks are non-zero */
 161		if (!ipv6_addr_any(&mt.mask->src)) {
 162			vcap_netbytes_copy(sip.value, mt.key->src.s6_addr, 16);
 163			vcap_netbytes_copy(sip.mask, mt.mask->src.s6_addr, 16);
 164			err = vcap_rule_add_key_u128(st->vrule,
 165						     VCAP_KF_L3_IP6_SIP, &sip);
 166			if (err)
 167				goto out;
 168		}
 169		if (!ipv6_addr_any(&mt.mask->dst)) {
 170			vcap_netbytes_copy(dip.value, mt.key->dst.s6_addr, 16);
 171			vcap_netbytes_copy(dip.mask, mt.mask->dst.s6_addr, 16);
 172			err = vcap_rule_add_key_u128(st->vrule,
 173						     VCAP_KF_L3_IP6_DIP, &dip);
 174			if (err)
 175				goto out;
 176		}
 177	}
 178	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS);
 179	return err;
 180out:
 181	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv6_addr parse error");
 182	return err;
 183}
 184
 185static int
 186sparx5_tc_flower_handler_control_usage(struct sparx5_tc_flower_parse_usage *st)
 187{
 188	struct flow_match_control mt;
 189	u32 value, mask;
 190	int err = 0;
 191
 192	flow_rule_match_control(st->frule, &mt);
 193
 194	if (mt.mask->flags) {
 195		if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) {
 196			if (mt.key->flags & FLOW_DIS_FIRST_FRAG) {
 197				value = 1; /* initial fragment */
 198				mask = 0x3;
 199			} else {
 200				if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
 201					value = 3; /* follow up fragment */
 202					mask = 0x3;
 203				} else {
 204					value = 0; /* no fragment */
 205					mask = 0x3;
 206				}
 207			}
 208		} else {
 209			if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
 210				value = 3; /* follow up fragment */
 211				mask = 0x3;
 212			} else {
 213				value = 0; /* no fragment */
 214				mask = 0x3;
 215			}
 216		}
 217
 218		err = vcap_rule_add_key_u32(st->vrule,
 219					    VCAP_KF_L3_FRAGMENT_TYPE,
 220					    value, mask);
 221		if (err)
 222			goto out;
 223	}
 224
 225	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL);
 226
 227	return err;
 228
 229out:
 230	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error");
 231	return err;
 232}
 233
 234static int
 235sparx5_tc_flower_handler_portnum_usage(struct sparx5_tc_flower_parse_usage *st)
 236{
 237	struct flow_match_ports mt;
 238	u16 value, mask;
 239	int err = 0;
 240
 241	flow_rule_match_ports(st->frule, &mt);
 242
 243	if (mt.mask->src) {
 244		value = be16_to_cpu(mt.key->src);
 245		mask = be16_to_cpu(mt.mask->src);
 246		err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_SPORT, value,
 247					    mask);
 248		if (err)
 249			goto out;
 250	}
 251
 252	if (mt.mask->dst) {
 253		value = be16_to_cpu(mt.key->dst);
 254		mask = be16_to_cpu(mt.mask->dst);
 255		err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_DPORT, value,
 256					    mask);
 257		if (err)
 258			goto out;
 259	}
 260
 261	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_PORTS);
 262
 263	return err;
 264
 265out:
 266	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "port parse error");
 267	return err;
 268}
 269
 270static int
 271sparx5_tc_flower_handler_basic_usage(struct sparx5_tc_flower_parse_usage *st)
 272{
 273	struct flow_match_basic mt;
 274	int err = 0;
 275
 276	flow_rule_match_basic(st->frule, &mt);
 277
 278	if (mt.mask->n_proto) {
 279		st->l3_proto = be16_to_cpu(mt.key->n_proto);
 280		if (!sparx5_tc_is_known_etype(st->l3_proto)) {
 281			err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
 282						    st->l3_proto, ~0);
 283			if (err)
 284				goto out;
 285		} else if (st->l3_proto == ETH_P_IP) {
 286			err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
 287						    VCAP_BIT_1);
 288			if (err)
 289				goto out;
 290		} else if (st->l3_proto == ETH_P_IPV6) {
 291			err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
 292						    VCAP_BIT_0);
 293			if (err)
 294				goto out;
 295		}
 296	}
 297
 298	if (mt.mask->ip_proto) {
 299		st->l4_proto = mt.key->ip_proto;
 300		if (st->l4_proto == IPPROTO_TCP) {
 301			err = vcap_rule_add_key_bit(st->vrule,
 302						    VCAP_KF_TCP_IS,
 303						    VCAP_BIT_1);
 304			if (err)
 305				goto out;
 306		} else if (st->l4_proto == IPPROTO_UDP) {
 307			err = vcap_rule_add_key_bit(st->vrule,
 308						    VCAP_KF_TCP_IS,
 309						    VCAP_BIT_0);
 310			if (err)
 311				goto out;
 312		} else {
 313			err = vcap_rule_add_key_u32(st->vrule,
 314						    VCAP_KF_L3_IP_PROTO,
 315						    st->l4_proto, ~0);
 316			if (err)
 317				goto out;
 318		}
 319	}
 320
 321	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC);
 322
 323	return err;
 324
 325out:
 326	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");
 327	return err;
 328}
 329
 330static int
 331sparx5_tc_flower_handler_vlan_usage(struct sparx5_tc_flower_parse_usage *st)
 332{
 333	enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS;
 334	enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS;
 335	struct flow_match_vlan mt;
 336	int err;
 337
 338	flow_rule_match_vlan(st->frule, &mt);
 339
 340	if (mt.mask->vlan_id) {
 341		err = vcap_rule_add_key_u32(st->vrule, vid_key,
 342					    mt.key->vlan_id,
 343					    mt.mask->vlan_id);
 344		if (err)
 345			goto out;
 346	}
 347
 348	if (mt.mask->vlan_priority) {
 349		err = vcap_rule_add_key_u32(st->vrule, pcp_key,
 350					    mt.key->vlan_priority,
 351					    mt.mask->vlan_priority);
 352		if (err)
 353			goto out;
 354	}
 355
 356	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_VLAN);
 357
 358	return 0;
 359out:
 360	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "vlan parse error");
 361	return err;
 362}
 363
 364static int
 365sparx5_tc_flower_handler_tcp_usage(struct sparx5_tc_flower_parse_usage *st)
 366{
 367	struct flow_match_tcp mt;
 368	u16 tcp_flags_mask;
 369	u16 tcp_flags_key;
 370	enum vcap_bit val;
 371	int err = 0;
 372
 373	flow_rule_match_tcp(st->frule, &mt);
 374	tcp_flags_key = be16_to_cpu(mt.key->flags);
 375	tcp_flags_mask = be16_to_cpu(mt.mask->flags);
 376
 377	if (tcp_flags_mask & TCPHDR_FIN) {
 378		val = VCAP_BIT_0;
 379		if (tcp_flags_key & TCPHDR_FIN)
 380			val = VCAP_BIT_1;
 381		err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_FIN, val);
 382		if (err)
 383			goto out;
 384	}
 385
 386	if (tcp_flags_mask & TCPHDR_SYN) {
 387		val = VCAP_BIT_0;
 388		if (tcp_flags_key & TCPHDR_SYN)
 389			val = VCAP_BIT_1;
 390		err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_SYN, val);
 391		if (err)
 392			goto out;
 393	}
 394
 395	if (tcp_flags_mask & TCPHDR_RST) {
 396		val = VCAP_BIT_0;
 397		if (tcp_flags_key & TCPHDR_RST)
 398			val = VCAP_BIT_1;
 399		err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_RST, val);
 400		if (err)
 401			goto out;
 402	}
 403
 404	if (tcp_flags_mask & TCPHDR_PSH) {
 405		val = VCAP_BIT_0;
 406		if (tcp_flags_key & TCPHDR_PSH)
 407			val = VCAP_BIT_1;
 408		err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_PSH, val);
 409		if (err)
 410			goto out;
 411	}
 412
 413	if (tcp_flags_mask & TCPHDR_ACK) {
 414		val = VCAP_BIT_0;
 415		if (tcp_flags_key & TCPHDR_ACK)
 416			val = VCAP_BIT_1;
 417		err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_ACK, val);
 418		if (err)
 419			goto out;
 420	}
 421
 422	if (tcp_flags_mask & TCPHDR_URG) {
 423		val = VCAP_BIT_0;
 424		if (tcp_flags_key & TCPHDR_URG)
 425			val = VCAP_BIT_1;
 426		err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_URG, val);
 427		if (err)
 428			goto out;
 429	}
 430
 431	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_TCP);
 432
 433	return err;
 434
 435out:
 436	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "tcp_flags parse error");
 437	return err;
 438}
 439
 440static int
 441sparx5_tc_flower_handler_arp_usage(struct sparx5_tc_flower_parse_usage *st)
 442{
 443	struct flow_match_arp mt;
 444	u16 value, mask;
 445	u32 ipval, ipmsk;
 446	int err;
 447
 448	flow_rule_match_arp(st->frule, &mt);
 449
 450	if (mt.mask->op) {
 451		mask = 0x3;
 452		if (st->l3_proto == ETH_P_ARP) {
 453			value = mt.key->op == TC_ARP_OP_REQUEST ?
 454					SPX5_IS2_ARP_REQUEST :
 455					SPX5_IS2_ARP_REPLY;
 456		} else { /* RARP */
 457			value = mt.key->op == TC_ARP_OP_REQUEST ?
 458					SPX5_IS2_RARP_REQUEST :
 459					SPX5_IS2_RARP_REPLY;
 460		}
 461		err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ARP_OPCODE,
 462					    value, mask);
 463		if (err)
 464			goto out;
 465	}
 466
 467	/* The IS2 ARP keyset does not support ARP hardware addresses */
 468	if (!is_zero_ether_addr(mt.mask->sha) ||
 469	    !is_zero_ether_addr(mt.mask->tha)) {
 470		err = -EINVAL;
 471		goto out;
 472	}
 473
 474	if (mt.mask->sip) {
 475		ipval = be32_to_cpu((__force __be32)mt.key->sip);
 476		ipmsk = be32_to_cpu((__force __be32)mt.mask->sip);
 477
 478		err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_SIP,
 479					    ipval, ipmsk);
 480		if (err)
 481			goto out;
 482	}
 483
 484	if (mt.mask->tip) {
 485		ipval = be32_to_cpu((__force __be32)mt.key->tip);
 486		ipmsk = be32_to_cpu((__force __be32)mt.mask->tip);
 487
 488		err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_DIP,
 489					    ipval, ipmsk);
 490		if (err)
 491			goto out;
 492	}
 493
 494	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ARP);
 495
 496	return 0;
 497
 498out:
 499	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "arp parse error");
 500	return err;
 501}
 502
 503static int
 504sparx5_tc_flower_handler_ip_usage(struct sparx5_tc_flower_parse_usage *st)
 505{
 506	struct flow_match_ip mt;
 507	int err = 0;
 508
 509	flow_rule_match_ip(st->frule, &mt);
 510
 511	if (mt.mask->tos) {
 512		err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_TOS,
 513					    mt.key->tos,
 514					    mt.mask->tos);
 515		if (err)
 516			goto out;
 517	}
 518
 519	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_IP);
 520
 521	return err;
 522
 523out:
 524	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_tos parse error");
 525	return err;
 526}
 527
 528static int (*sparx5_tc_flower_usage_handlers[])(struct sparx5_tc_flower_parse_usage *st) = {
 529	[FLOW_DISSECTOR_KEY_ETH_ADDRS] = sparx5_tc_flower_handler_ethaddr_usage,
 530	[FLOW_DISSECTOR_KEY_IPV4_ADDRS] = sparx5_tc_flower_handler_ipv4_usage,
 531	[FLOW_DISSECTOR_KEY_IPV6_ADDRS] = sparx5_tc_flower_handler_ipv6_usage,
 532	[FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage,
 533	[FLOW_DISSECTOR_KEY_PORTS] = sparx5_tc_flower_handler_portnum_usage,
 534	[FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage,
 535	[FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage,
 536	[FLOW_DISSECTOR_KEY_TCP] = sparx5_tc_flower_handler_tcp_usage,
 537	[FLOW_DISSECTOR_KEY_ARP] = sparx5_tc_flower_handler_arp_usage,
 538	[FLOW_DISSECTOR_KEY_IP] = sparx5_tc_flower_handler_ip_usage,
 539};
 540
 541static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco,
 542				    struct vcap_admin *admin,
 543				    struct vcap_rule *vrule,
 544				    u16 *l3_proto)
 545{
 546	struct sparx5_tc_flower_parse_usage state = {
 547		.fco = fco,
 548		.vrule = vrule,
 549		.l3_proto = ETH_P_ALL,
 550	};
 551	int idx, err = 0;
 552
 553	state.frule = flow_cls_offload_flow_rule(fco);
 554	for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) {
 555		if (!flow_rule_match_key(state.frule, idx))
 556			continue;
 557		if (!sparx5_tc_flower_usage_handlers[idx])
 558			continue;
 559		err = sparx5_tc_flower_usage_handlers[idx](&state);
 560		if (err)
 561			return err;
 562	}
 563
 564	if (state.frule->match.dissector->used_keys ^ state.used_keys) {
 565		NL_SET_ERR_MSG_MOD(fco->common.extack,
 566				   "Unsupported match item");
 567		return -ENOENT;
 568	}
 569
 570	if (l3_proto)
 571		*l3_proto = state.l3_proto;
 572	return err;
 573}
 574
 575static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
 576					 struct flow_cls_offload *fco,
 577					 struct vcap_admin *admin)
 578{
 579	struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
 580	struct flow_action_entry *actent, *last_actent = NULL;
 581	struct flow_action *act = &rule->action;
 582	u64 action_mask = 0;
 583	int idx;
 584
 585	if (!flow_action_has_entries(act)) {
 586		NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
 587		return -EINVAL;
 588	}
 589
 590	if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
 591		return -EOPNOTSUPP;
 592
 593	flow_action_for_each(idx, actent, act) {
 594		if (action_mask & BIT(actent->id)) {
 595			NL_SET_ERR_MSG_MOD(fco->common.extack,
 596					   "More actions of the same type");
 597			return -EINVAL;
 598		}
 599		action_mask |= BIT(actent->id);
 600		last_actent = actent; /* Save last action for later check */
 601	}
 602
 603	/* Check that last action is a goto */
 604	if (last_actent->id != FLOW_ACTION_GOTO) {
 605		NL_SET_ERR_MSG_MOD(fco->common.extack,
 606				   "Last action must be 'goto'");
 607		return -EINVAL;
 608	}
 609
 610	/* Check if the goto chain is in the next lookup */
 611	if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
 612				 last_actent->chain_index)) {
 613		NL_SET_ERR_MSG_MOD(fco->common.extack,
 614				   "Invalid goto chain");
 615		return -EINVAL;
 616	}
 617
 618	/* Catch unsupported combinations of actions */
 619	if (action_mask & BIT(FLOW_ACTION_TRAP) &&
 620	    action_mask & BIT(FLOW_ACTION_ACCEPT)) {
 621		NL_SET_ERR_MSG_MOD(fco->common.extack,
 622				   "Cannot combine pass and trap action");
 623		return -EOPNOTSUPP;
 624	}
 625
 626	return 0;
 627}
 628
 629/* Add a rule counter action - only IS2 is considered for now */
 630static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
 631				      struct vcap_rule *vrule)
 632{
 633	int err;
 634
 635	err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID, vrule->id);
 636	if (err)
 637		return err;
 638
 639	vcap_rule_set_counter_id(vrule, vrule->id);
 640	return err;
 641}
 642
 643/* Collect all port keysets and apply the first of them, possibly wildcarded */
 644static int sparx5_tc_select_protocol_keyset(struct net_device *ndev,
 645					    struct vcap_rule *vrule,
 646					    struct vcap_admin *admin,
 647					    u16 l3_proto,
 648					    struct sparx5_multiple_rules *multi)
 649{
 650	struct sparx5_port *port = netdev_priv(ndev);
 651	struct vcap_keyset_list portkeysetlist = {};
 652	enum vcap_keyfield_set portkeysets[10] = {};
 653	struct vcap_keyset_list matches = {};
 654	enum vcap_keyfield_set keysets[10];
 655	int idx, jdx, err = 0, count = 0;
 656	struct sparx5_wildcard_rule *mru;
 657	const struct vcap_set *kinfo;
 658	struct vcap_control *vctrl;
 659
 660	vctrl = port->sparx5->vcap_ctrl;
 661
 662	/* Find the keysets that the rule can use */
 663	matches.keysets = keysets;
 664	matches.max = ARRAY_SIZE(keysets);
 665	if (vcap_rule_find_keysets(vrule, &matches) == 0)
 666		return -EINVAL;
 667
 668	/* Find the keysets that the port configuration supports */
 669	portkeysetlist.max = ARRAY_SIZE(portkeysets);
 670	portkeysetlist.keysets = portkeysets;
 671	err = sparx5_vcap_get_port_keyset(ndev,
 672					  admin, vrule->vcap_chain_id,
 673					  l3_proto,
 674					  &portkeysetlist);
 675	if (err)
 676		return err;
 677
 678	/* Find the intersection of the two sets of keyset */
 679	for (idx = 0; idx < portkeysetlist.cnt; ++idx) {
 680		kinfo = vcap_keyfieldset(vctrl, admin->vtype,
 681					 portkeysetlist.keysets[idx]);
 682		if (!kinfo)
 683			continue;
 684
 685		/* Find a port keyset that matches the required keys
 686		 * If there are multiple keysets then compose a type id mask
 687		 */
 688		for (jdx = 0; jdx < matches.cnt; ++jdx) {
 689			if (portkeysetlist.keysets[idx] != matches.keysets[jdx])
 690				continue;
 691
 692			mru = &multi->rule[kinfo->sw_per_item];
 693			if (!mru->selected) {
 694				mru->selected = true;
 695				mru->keyset = portkeysetlist.keysets[idx];
 696				mru->value = kinfo->type_id;
 697			}
 698			mru->value &= kinfo->type_id;
 699			mru->mask |= kinfo->type_id;
 700			++count;
 701		}
 702	}
 703	if (count == 0)
 704		return -EPROTO;
 705
 706	if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt)
 707		return -ENOENT;
 708
 709	for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
 710		mru = &multi->rule[idx];
 711		if (!mru->selected)
 712			continue;
 713
 714		/* Align the mask to the combined value */
 715		mru->mask ^= mru->value;
 716	}
 717
 718	/* Set the chosen keyset on the rule and set a wildcarded type if there
 719	 * are more than one keyset
 720	 */
 721	for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
 722		mru = &multi->rule[idx];
 723		if (!mru->selected)
 724			continue;
 725
 726		vcap_set_rule_set_keyset(vrule, mru->keyset);
 727		if (count > 1)
 728			/* Some keysets do not have a type field */
 729			vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE,
 730					      mru->value,
 731					      ~mru->mask);
 732		mru->selected = false; /* mark as done */
 733		break; /* Stop here and add more rules later */
 734	}
 735	return err;
 736}
 737
 738static int sparx5_tc_add_rule_copy(struct vcap_control *vctrl,
 739				   struct flow_cls_offload *fco,
 740				   struct vcap_rule *erule,
 741				   struct vcap_admin *admin,
 742				   struct sparx5_wildcard_rule *rule)
 743{
 744	enum vcap_key_field keylist[] = {
 745		VCAP_KF_IF_IGR_PORT_MASK,
 746		VCAP_KF_IF_IGR_PORT_MASK_SEL,
 747		VCAP_KF_IF_IGR_PORT_MASK_RNG,
 748		VCAP_KF_LOOKUP_FIRST_IS,
 749		VCAP_KF_TYPE,
 750	};
 751	struct vcap_rule *vrule;
 752	int err;
 753
 754	/* Add an extra rule with a special user and the new keyset */
 755	erule->user = VCAP_USER_TC_EXTRA;
 756	vrule = vcap_copy_rule(erule);
 757	if (IS_ERR(vrule))
 758		return PTR_ERR(vrule);
 759
 760	/* Link the new rule to the existing rule with the cookie */
 761	vrule->cookie = erule->cookie;
 762	vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true);
 763	err = vcap_set_rule_set_keyset(vrule, rule->keyset);
 764	if (err) {
 765		pr_err("%s:%d: could not set keyset %s in rule: %u\n",
 766		       __func__, __LINE__,
 767		       vcap_keyset_name(vctrl, rule->keyset),
 768		       vrule->id);
 769		goto out;
 770	}
 771
 772	/* Some keysets do not have a type field, so ignore return value */
 773	vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask);
 774
 775	err = vcap_set_rule_set_actionset(vrule, erule->actionset);
 776	if (err)
 777		goto out;
 778
 779	err = sparx5_tc_add_rule_counter(admin, vrule);
 780	if (err)
 781		goto out;
 782
 783	err = vcap_val_rule(vrule, ETH_P_ALL);
 784	if (err) {
 785		pr_err("%s:%d: could not validate rule: %u\n",
 786		       __func__, __LINE__, vrule->id);
 787		vcap_set_tc_exterr(fco, vrule);
 788		goto out;
 789	}
 790	err = vcap_add_rule(vrule);
 791	if (err) {
 792		pr_err("%s:%d: could not add rule: %u\n",
 793		       __func__, __LINE__, vrule->id);
 794		goto out;
 795	}
 796out:
 797	vcap_free_rule(vrule);
 798	return err;
 799}
 800
 801static int sparx5_tc_add_remaining_rules(struct vcap_control *vctrl,
 802					 struct flow_cls_offload *fco,
 803					 struct vcap_rule *erule,
 804					 struct vcap_admin *admin,
 805					 struct sparx5_multiple_rules *multi)
 806{
 807	int idx, err = 0;
 808
 809	for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
 810		if (!multi->rule[idx].selected)
 811			continue;
 812
 813		err = sparx5_tc_add_rule_copy(vctrl, fco, erule, admin,
 814					      &multi->rule[idx]);
 815		if (err)
 816			break;
 817	}
 818	return err;
 819}
 820
 821static int sparx5_tc_flower_replace(struct net_device *ndev,
 822				    struct flow_cls_offload *fco,
 823				    struct vcap_admin *admin)
 824{
 825	struct sparx5_port *port = netdev_priv(ndev);
 826	struct sparx5_multiple_rules multi = {};
 827	struct flow_action_entry *act;
 828	struct vcap_control *vctrl;
 829	struct flow_rule *frule;
 830	struct vcap_rule *vrule;
 831	u16 l3_proto;
 832	int err, idx;
 833
 834	vctrl = port->sparx5->vcap_ctrl;
 835
 836	err = sparx5_tc_flower_action_check(vctrl, fco, admin);
 837	if (err)
 838		return err;
 839
 840	vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC,
 841				fco->common.prio, 0);
 842	if (IS_ERR(vrule))
 843		return PTR_ERR(vrule);
 844
 845	vrule->cookie = fco->cookie;
 846
 847	l3_proto = ETH_P_ALL;
 848	err = sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto);
 849	if (err)
 850		goto out;
 851
 852	err = sparx5_tc_add_rule_counter(admin, vrule);
 853	if (err)
 854		goto out;
 855
 856	frule = flow_cls_offload_flow_rule(fco);
 857	flow_action_for_each(idx, act, &frule->action) {
 858		switch (act->id) {
 859		case FLOW_ACTION_TRAP:
 860			err = vcap_rule_add_action_bit(vrule,
 861						       VCAP_AF_CPU_COPY_ENA,
 862						       VCAP_BIT_1);
 863			if (err)
 864				goto out;
 865			err = vcap_rule_add_action_u32(vrule,
 866						       VCAP_AF_CPU_QUEUE_NUM, 0);
 867			if (err)
 868				goto out;
 869			err = vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE,
 870						       SPX5_PMM_REPLACE_ALL);
 871			if (err)
 872				goto out;
 873			/* For now the actionset is hardcoded */
 874			err = vcap_set_rule_set_actionset(vrule,
 875							  VCAP_AFS_BASE_TYPE);
 876			if (err)
 877				goto out;
 878			break;
 879		case FLOW_ACTION_ACCEPT:
 880			/* For now the actionset is hardcoded */
 881			err = vcap_set_rule_set_actionset(vrule,
 882							  VCAP_AFS_BASE_TYPE);
 883			if (err)
 884				goto out;
 885			break;
 886		case FLOW_ACTION_GOTO:
 887			/* Links between VCAPs will be added later */
 888			break;
 889		default:
 890			NL_SET_ERR_MSG_MOD(fco->common.extack,
 891					   "Unsupported TC action");
 892			err = -EOPNOTSUPP;
 893			goto out;
 894		}
 895	}
 896
 897	err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin, l3_proto,
 898					       &multi);
 899	if (err) {
 900		NL_SET_ERR_MSG_MOD(fco->common.extack,
 901				   "No matching port keyset for filter protocol and keys");
 902		goto out;
 903	}
 904
 905	/* provide the l3 protocol to guide the keyset selection */
 906	err = vcap_val_rule(vrule, l3_proto);
 907	if (err) {
 908		vcap_set_tc_exterr(fco, vrule);
 909		goto out;
 910	}
 911	err = vcap_add_rule(vrule);
 912	if (err)
 913		NL_SET_ERR_MSG_MOD(fco->common.extack,
 914				   "Could not add the filter");
 915
 916	if (l3_proto == ETH_P_ALL)
 917		err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin,
 918						    &multi);
 919
 920out:
 921	vcap_free_rule(vrule);
 922	return err;
 923}
 924
 925static int sparx5_tc_flower_destroy(struct net_device *ndev,
 926				    struct flow_cls_offload *fco,
 927				    struct vcap_admin *admin)
 928{
 929	struct sparx5_port *port = netdev_priv(ndev);
 930	struct vcap_control *vctrl;
 931	int err = -ENOENT, rule_id;
 932
 933	vctrl = port->sparx5->vcap_ctrl;
 934	while (true) {
 935		rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie);
 936		if (rule_id <= 0)
 937			break;
 938		err = vcap_del_rule(vctrl, ndev, rule_id);
 939		if (err) {
 940			pr_err("%s:%d: could not delete rule %d\n",
 941			       __func__, __LINE__, rule_id);
 942			break;
 943		}
 944	}
 945	return err;
 946}
 947
 948/* Collect packet counts from all rules with the same cookie */
 949static int sparx5_tc_rule_counter_cb(void *arg, struct vcap_rule *rule)
 950{
 951	struct sparx5_tc_rule_pkt_cnt *rinfo = arg;
 952	struct vcap_counter counter;
 953	int err = 0;
 954
 955	if (rule->cookie == rinfo->cookie) {
 956		err = vcap_rule_get_counter(rule, &counter);
 957		if (err)
 958			return err;
 959		rinfo->pkts += counter.value;
 960		/* Reset the rule counter */
 961		counter.value = 0;
 962		vcap_rule_set_counter(rule, &counter);
 963	}
 964	return err;
 965}
 966
 967static int sparx5_tc_flower_stats(struct net_device *ndev,
 968				  struct flow_cls_offload *fco,
 969				  struct vcap_admin *admin)
 970{
 971	struct sparx5_port *port = netdev_priv(ndev);
 972	struct sparx5_tc_rule_pkt_cnt rinfo = {};
 973	struct vcap_control *vctrl;
 974	ulong lastused = 0;
 975	u64 drops = 0;
 976	u32 pkts = 0;
 977	int err;
 978
 979	rinfo.cookie = fco->cookie;
 980	vctrl = port->sparx5->vcap_ctrl;
 981	err = vcap_rule_iter(vctrl, sparx5_tc_rule_counter_cb, &rinfo);
 982	if (err)
 983		return err;
 984	pkts = rinfo.pkts;
 985	flow_stats_update(&fco->stats, 0x0, pkts, drops, lastused,
 986			  FLOW_ACTION_HW_STATS_IMMEDIATE);
 987	return err;
 988}
 989
 990int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
 991		     bool ingress)
 992{
 993	struct sparx5_port *port = netdev_priv(ndev);
 994	struct vcap_control *vctrl;
 995	struct vcap_admin *admin;
 996	int err = -EINVAL;
 997
 998	/* Get vcap instance from the chain id */
 999	vctrl = port->sparx5->vcap_ctrl;
1000	admin = vcap_find_admin(vctrl, fco->common.chain_index);
1001	if (!admin) {
1002		NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain");
1003		return err;
1004	}
1005
1006	switch (fco->command) {
1007	case FLOW_CLS_REPLACE:
1008		return sparx5_tc_flower_replace(ndev, fco, admin);
1009	case FLOW_CLS_DESTROY:
1010		return sparx5_tc_flower_destroy(ndev, fco, admin);
1011	case FLOW_CLS_STATS:
1012		return sparx5_tc_flower_stats(ndev, fco, admin);
1013	default:
1014		return -EOPNOTSUPP;
1015	}
1016}