162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/* Microchip VCAP TC
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (c) 2023 Microchip Technology Inc. and its subsidiaries.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <net/flow_offload.h>
862306a36Sopenharmony_ci#include <net/ipv6.h>
962306a36Sopenharmony_ci#include <net/tcp.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "vcap_api_client.h"
1262306a36Sopenharmony_ci#include "vcap_tc.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cienum vcap_is2_arp_opcode {
1562306a36Sopenharmony_ci	VCAP_IS2_ARP_REQUEST,
1662306a36Sopenharmony_ci	VCAP_IS2_ARP_REPLY,
1762306a36Sopenharmony_ci	VCAP_IS2_RARP_REQUEST,
1862306a36Sopenharmony_ci	VCAP_IS2_RARP_REPLY,
1962306a36Sopenharmony_ci};
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cienum vcap_arp_opcode {
2262306a36Sopenharmony_ci	VCAP_ARP_OP_RESERVED,
2362306a36Sopenharmony_ci	VCAP_ARP_OP_REQUEST,
2462306a36Sopenharmony_ci	VCAP_ARP_OP_REPLY,
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciint vcap_tc_flower_handler_ethaddr_usage(struct vcap_tc_flower_parse_usage *st)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	enum vcap_key_field smac_key = VCAP_KF_L2_SMAC;
3062306a36Sopenharmony_ci	enum vcap_key_field dmac_key = VCAP_KF_L2_DMAC;
3162306a36Sopenharmony_ci	struct flow_match_eth_addrs match;
3262306a36Sopenharmony_ci	struct vcap_u48_key smac, dmac;
3362306a36Sopenharmony_ci	int err = 0;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	flow_rule_match_eth_addrs(st->frule, &match);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (!is_zero_ether_addr(match.mask->src)) {
3862306a36Sopenharmony_ci		vcap_netbytes_copy(smac.value, match.key->src, ETH_ALEN);
3962306a36Sopenharmony_ci		vcap_netbytes_copy(smac.mask, match.mask->src, ETH_ALEN);
4062306a36Sopenharmony_ci		err = vcap_rule_add_key_u48(st->vrule, smac_key, &smac);
4162306a36Sopenharmony_ci		if (err)
4262306a36Sopenharmony_ci			goto out;
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	if (!is_zero_ether_addr(match.mask->dst)) {
4662306a36Sopenharmony_ci		vcap_netbytes_copy(dmac.value, match.key->dst, ETH_ALEN);
4762306a36Sopenharmony_ci		vcap_netbytes_copy(dmac.mask, match.mask->dst, ETH_ALEN);
4862306a36Sopenharmony_ci		err = vcap_rule_add_key_u48(st->vrule, dmac_key, &dmac);
4962306a36Sopenharmony_ci		if (err)
5062306a36Sopenharmony_ci			goto out;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	return err;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ciout:
5862306a36Sopenharmony_ci	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error");
5962306a36Sopenharmony_ci	return err;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ethaddr_usage);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ciint vcap_tc_flower_handler_ipv4_usage(struct vcap_tc_flower_parse_usage *st)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	int err = 0;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (st->l3_proto == ETH_P_IP) {
6862306a36Sopenharmony_ci		struct flow_match_ipv4_addrs mt;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci		flow_rule_match_ipv4_addrs(st->frule, &mt);
7162306a36Sopenharmony_ci		if (mt.mask->src) {
7262306a36Sopenharmony_ci			err = vcap_rule_add_key_u32(st->vrule,
7362306a36Sopenharmony_ci						    VCAP_KF_L3_IP4_SIP,
7462306a36Sopenharmony_ci						    be32_to_cpu(mt.key->src),
7562306a36Sopenharmony_ci						    be32_to_cpu(mt.mask->src));
7662306a36Sopenharmony_ci			if (err)
7762306a36Sopenharmony_ci				goto out;
7862306a36Sopenharmony_ci		}
7962306a36Sopenharmony_ci		if (mt.mask->dst) {
8062306a36Sopenharmony_ci			err = vcap_rule_add_key_u32(st->vrule,
8162306a36Sopenharmony_ci						    VCAP_KF_L3_IP4_DIP,
8262306a36Sopenharmony_ci						    be32_to_cpu(mt.key->dst),
8362306a36Sopenharmony_ci						    be32_to_cpu(mt.mask->dst));
8462306a36Sopenharmony_ci			if (err)
8562306a36Sopenharmony_ci				goto out;
8662306a36Sopenharmony_ci		}
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return err;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciout:
9462306a36Sopenharmony_ci	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv4_addr parse error");
9562306a36Sopenharmony_ci	return err;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ipv4_usage);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciint vcap_tc_flower_handler_ipv6_usage(struct vcap_tc_flower_parse_usage *st)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	int err = 0;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (st->l3_proto == ETH_P_IPV6) {
10462306a36Sopenharmony_ci		struct flow_match_ipv6_addrs mt;
10562306a36Sopenharmony_ci		struct vcap_u128_key sip;
10662306a36Sopenharmony_ci		struct vcap_u128_key dip;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		flow_rule_match_ipv6_addrs(st->frule, &mt);
10962306a36Sopenharmony_ci		/* Check if address masks are non-zero */
11062306a36Sopenharmony_ci		if (!ipv6_addr_any(&mt.mask->src)) {
11162306a36Sopenharmony_ci			vcap_netbytes_copy(sip.value, mt.key->src.s6_addr, 16);
11262306a36Sopenharmony_ci			vcap_netbytes_copy(sip.mask, mt.mask->src.s6_addr, 16);
11362306a36Sopenharmony_ci			err = vcap_rule_add_key_u128(st->vrule,
11462306a36Sopenharmony_ci						     VCAP_KF_L3_IP6_SIP, &sip);
11562306a36Sopenharmony_ci			if (err)
11662306a36Sopenharmony_ci				goto out;
11762306a36Sopenharmony_ci		}
11862306a36Sopenharmony_ci		if (!ipv6_addr_any(&mt.mask->dst)) {
11962306a36Sopenharmony_ci			vcap_netbytes_copy(dip.value, mt.key->dst.s6_addr, 16);
12062306a36Sopenharmony_ci			vcap_netbytes_copy(dip.mask, mt.mask->dst.s6_addr, 16);
12162306a36Sopenharmony_ci			err = vcap_rule_add_key_u128(st->vrule,
12262306a36Sopenharmony_ci						     VCAP_KF_L3_IP6_DIP, &dip);
12362306a36Sopenharmony_ci			if (err)
12462306a36Sopenharmony_ci				goto out;
12562306a36Sopenharmony_ci		}
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci	st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS);
12862306a36Sopenharmony_ci	return err;
12962306a36Sopenharmony_ciout:
13062306a36Sopenharmony_ci	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv6_addr parse error");
13162306a36Sopenharmony_ci	return err;
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ipv6_usage);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ciint vcap_tc_flower_handler_portnum_usage(struct vcap_tc_flower_parse_usage *st)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct flow_match_ports mt;
13862306a36Sopenharmony_ci	u16 value, mask;
13962306a36Sopenharmony_ci	int err = 0;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	flow_rule_match_ports(st->frule, &mt);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (mt.mask->src) {
14462306a36Sopenharmony_ci		value = be16_to_cpu(mt.key->src);
14562306a36Sopenharmony_ci		mask = be16_to_cpu(mt.mask->src);
14662306a36Sopenharmony_ci		err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_SPORT, value,
14762306a36Sopenharmony_ci					    mask);
14862306a36Sopenharmony_ci		if (err)
14962306a36Sopenharmony_ci			goto out;
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (mt.mask->dst) {
15362306a36Sopenharmony_ci		value = be16_to_cpu(mt.key->dst);
15462306a36Sopenharmony_ci		mask = be16_to_cpu(mt.mask->dst);
15562306a36Sopenharmony_ci		err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_DPORT, value,
15662306a36Sopenharmony_ci					    mask);
15762306a36Sopenharmony_ci		if (err)
15862306a36Sopenharmony_ci			goto out;
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_PORTS);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	return err;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ciout:
16662306a36Sopenharmony_ci	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "port parse error");
16762306a36Sopenharmony_ci	return err;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vcap_tc_flower_handler_portnum_usage);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ciint vcap_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	enum vcap_key_field vid_key = VCAP_KF_8021Q_VID0;
17462306a36Sopenharmony_ci	enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP0;
17562306a36Sopenharmony_ci	struct flow_match_vlan mt;
17662306a36Sopenharmony_ci	u16 tpid;
17762306a36Sopenharmony_ci	int err;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	flow_rule_match_cvlan(st->frule, &mt);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	tpid = be16_to_cpu(mt.key->vlan_tpid);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (tpid == ETH_P_8021Q) {
18462306a36Sopenharmony_ci		vid_key = VCAP_KF_8021Q_VID1;
18562306a36Sopenharmony_ci		pcp_key = VCAP_KF_8021Q_PCP1;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (mt.mask->vlan_id) {
18962306a36Sopenharmony_ci		err = vcap_rule_add_key_u32(st->vrule, vid_key,
19062306a36Sopenharmony_ci					    mt.key->vlan_id,
19162306a36Sopenharmony_ci					    mt.mask->vlan_id);
19262306a36Sopenharmony_ci		if (err)
19362306a36Sopenharmony_ci			goto out;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (mt.mask->vlan_priority) {
19762306a36Sopenharmony_ci		err = vcap_rule_add_key_u32(st->vrule, pcp_key,
19862306a36Sopenharmony_ci					    mt.key->vlan_priority,
19962306a36Sopenharmony_ci					    mt.mask->vlan_priority);
20062306a36Sopenharmony_ci		if (err)
20162306a36Sopenharmony_ci			goto out;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CVLAN);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	return 0;
20762306a36Sopenharmony_ciout:
20862306a36Sopenharmony_ci	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "cvlan parse error");
20962306a36Sopenharmony_ci	return err;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vcap_tc_flower_handler_cvlan_usage);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ciint vcap_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st,
21462306a36Sopenharmony_ci				      enum vcap_key_field vid_key,
21562306a36Sopenharmony_ci				      enum vcap_key_field pcp_key)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct flow_match_vlan mt;
21862306a36Sopenharmony_ci	int err;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	flow_rule_match_vlan(st->frule, &mt);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (mt.mask->vlan_id) {
22362306a36Sopenharmony_ci		err = vcap_rule_add_key_u32(st->vrule, vid_key,
22462306a36Sopenharmony_ci					    mt.key->vlan_id,
22562306a36Sopenharmony_ci					    mt.mask->vlan_id);
22662306a36Sopenharmony_ci		if (err)
22762306a36Sopenharmony_ci			goto out;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (mt.mask->vlan_priority) {
23162306a36Sopenharmony_ci		err = vcap_rule_add_key_u32(st->vrule, pcp_key,
23262306a36Sopenharmony_ci					    mt.key->vlan_priority,
23362306a36Sopenharmony_ci					    mt.mask->vlan_priority);
23462306a36Sopenharmony_ci		if (err)
23562306a36Sopenharmony_ci			goto out;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if (mt.mask->vlan_tpid)
23962306a36Sopenharmony_ci		st->tpid = be16_to_cpu(mt.key->vlan_tpid);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_VLAN);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	return 0;
24462306a36Sopenharmony_ciout:
24562306a36Sopenharmony_ci	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "vlan parse error");
24662306a36Sopenharmony_ci	return err;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vcap_tc_flower_handler_vlan_usage);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ciint vcap_tc_flower_handler_tcp_usage(struct vcap_tc_flower_parse_usage *st)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct flow_match_tcp mt;
25362306a36Sopenharmony_ci	u16 tcp_flags_mask;
25462306a36Sopenharmony_ci	u16 tcp_flags_key;
25562306a36Sopenharmony_ci	enum vcap_bit val;
25662306a36Sopenharmony_ci	int err = 0;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	flow_rule_match_tcp(st->frule, &mt);
25962306a36Sopenharmony_ci	tcp_flags_key = be16_to_cpu(mt.key->flags);
26062306a36Sopenharmony_ci	tcp_flags_mask = be16_to_cpu(mt.mask->flags);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	if (tcp_flags_mask & TCPHDR_FIN) {
26362306a36Sopenharmony_ci		val = VCAP_BIT_0;
26462306a36Sopenharmony_ci		if (tcp_flags_key & TCPHDR_FIN)
26562306a36Sopenharmony_ci			val = VCAP_BIT_1;
26662306a36Sopenharmony_ci		err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_FIN, val);
26762306a36Sopenharmony_ci		if (err)
26862306a36Sopenharmony_ci			goto out;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (tcp_flags_mask & TCPHDR_SYN) {
27262306a36Sopenharmony_ci		val = VCAP_BIT_0;
27362306a36Sopenharmony_ci		if (tcp_flags_key & TCPHDR_SYN)
27462306a36Sopenharmony_ci			val = VCAP_BIT_1;
27562306a36Sopenharmony_ci		err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_SYN, val);
27662306a36Sopenharmony_ci		if (err)
27762306a36Sopenharmony_ci			goto out;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if (tcp_flags_mask & TCPHDR_RST) {
28162306a36Sopenharmony_ci		val = VCAP_BIT_0;
28262306a36Sopenharmony_ci		if (tcp_flags_key & TCPHDR_RST)
28362306a36Sopenharmony_ci			val = VCAP_BIT_1;
28462306a36Sopenharmony_ci		err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_RST, val);
28562306a36Sopenharmony_ci		if (err)
28662306a36Sopenharmony_ci			goto out;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (tcp_flags_mask & TCPHDR_PSH) {
29062306a36Sopenharmony_ci		val = VCAP_BIT_0;
29162306a36Sopenharmony_ci		if (tcp_flags_key & TCPHDR_PSH)
29262306a36Sopenharmony_ci			val = VCAP_BIT_1;
29362306a36Sopenharmony_ci		err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_PSH, val);
29462306a36Sopenharmony_ci		if (err)
29562306a36Sopenharmony_ci			goto out;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (tcp_flags_mask & TCPHDR_ACK) {
29962306a36Sopenharmony_ci		val = VCAP_BIT_0;
30062306a36Sopenharmony_ci		if (tcp_flags_key & TCPHDR_ACK)
30162306a36Sopenharmony_ci			val = VCAP_BIT_1;
30262306a36Sopenharmony_ci		err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_ACK, val);
30362306a36Sopenharmony_ci		if (err)
30462306a36Sopenharmony_ci			goto out;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (tcp_flags_mask & TCPHDR_URG) {
30862306a36Sopenharmony_ci		val = VCAP_BIT_0;
30962306a36Sopenharmony_ci		if (tcp_flags_key & TCPHDR_URG)
31062306a36Sopenharmony_ci			val = VCAP_BIT_1;
31162306a36Sopenharmony_ci		err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_URG, val);
31262306a36Sopenharmony_ci		if (err)
31362306a36Sopenharmony_ci			goto out;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_TCP);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return err;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ciout:
32162306a36Sopenharmony_ci	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "tcp_flags parse error");
32262306a36Sopenharmony_ci	return err;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vcap_tc_flower_handler_tcp_usage);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ciint vcap_tc_flower_handler_arp_usage(struct vcap_tc_flower_parse_usage *st)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct flow_match_arp mt;
32962306a36Sopenharmony_ci	u16 value, mask;
33062306a36Sopenharmony_ci	u32 ipval, ipmsk;
33162306a36Sopenharmony_ci	int err;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	flow_rule_match_arp(st->frule, &mt);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (mt.mask->op) {
33662306a36Sopenharmony_ci		mask = 0x3;
33762306a36Sopenharmony_ci		if (st->l3_proto == ETH_P_ARP) {
33862306a36Sopenharmony_ci			value = mt.key->op == VCAP_ARP_OP_REQUEST ?
33962306a36Sopenharmony_ci					VCAP_IS2_ARP_REQUEST :
34062306a36Sopenharmony_ci					VCAP_IS2_ARP_REPLY;
34162306a36Sopenharmony_ci		} else { /* RARP */
34262306a36Sopenharmony_ci			value = mt.key->op == VCAP_ARP_OP_REQUEST ?
34362306a36Sopenharmony_ci					VCAP_IS2_RARP_REQUEST :
34462306a36Sopenharmony_ci					VCAP_IS2_RARP_REPLY;
34562306a36Sopenharmony_ci		}
34662306a36Sopenharmony_ci		err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ARP_OPCODE,
34762306a36Sopenharmony_ci					    value, mask);
34862306a36Sopenharmony_ci		if (err)
34962306a36Sopenharmony_ci			goto out;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	/* The IS2 ARP keyset does not support ARP hardware addresses */
35362306a36Sopenharmony_ci	if (!is_zero_ether_addr(mt.mask->sha) ||
35462306a36Sopenharmony_ci	    !is_zero_ether_addr(mt.mask->tha)) {
35562306a36Sopenharmony_ci		err = -EINVAL;
35662306a36Sopenharmony_ci		goto out;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (mt.mask->sip) {
36062306a36Sopenharmony_ci		ipval = be32_to_cpu((__force __be32)mt.key->sip);
36162306a36Sopenharmony_ci		ipmsk = be32_to_cpu((__force __be32)mt.mask->sip);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_SIP,
36462306a36Sopenharmony_ci					    ipval, ipmsk);
36562306a36Sopenharmony_ci		if (err)
36662306a36Sopenharmony_ci			goto out;
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if (mt.mask->tip) {
37062306a36Sopenharmony_ci		ipval = be32_to_cpu((__force __be32)mt.key->tip);
37162306a36Sopenharmony_ci		ipmsk = be32_to_cpu((__force __be32)mt.mask->tip);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_DIP,
37462306a36Sopenharmony_ci					    ipval, ipmsk);
37562306a36Sopenharmony_ci		if (err)
37662306a36Sopenharmony_ci			goto out;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_ARP);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	return 0;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ciout:
38462306a36Sopenharmony_ci	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "arp parse error");
38562306a36Sopenharmony_ci	return err;
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vcap_tc_flower_handler_arp_usage);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ciint vcap_tc_flower_handler_ip_usage(struct vcap_tc_flower_parse_usage *st)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct flow_match_ip mt;
39262306a36Sopenharmony_ci	int err = 0;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	flow_rule_match_ip(st->frule, &mt);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (mt.mask->tos) {
39762306a36Sopenharmony_ci		err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_TOS,
39862306a36Sopenharmony_ci					    mt.key->tos,
39962306a36Sopenharmony_ci					    mt.mask->tos);
40062306a36Sopenharmony_ci		if (err)
40162306a36Sopenharmony_ci			goto out;
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IP);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return err;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ciout:
40962306a36Sopenharmony_ci	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_tos parse error");
41062306a36Sopenharmony_ci	return err;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ip_usage);
413