162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2007-2017 Nicira, Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "flow.h"
962306a36Sopenharmony_ci#include "datapath.h"
1062306a36Sopenharmony_ci#include <linux/uaccess.h>
1162306a36Sopenharmony_ci#include <linux/netdevice.h>
1262306a36Sopenharmony_ci#include <linux/etherdevice.h>
1362306a36Sopenharmony_ci#include <linux/if_ether.h>
1462306a36Sopenharmony_ci#include <linux/if_vlan.h>
1562306a36Sopenharmony_ci#include <net/llc_pdu.h>
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/jhash.h>
1862306a36Sopenharmony_ci#include <linux/jiffies.h>
1962306a36Sopenharmony_ci#include <linux/llc.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/in.h>
2262306a36Sopenharmony_ci#include <linux/rcupdate.h>
2362306a36Sopenharmony_ci#include <linux/if_arp.h>
2462306a36Sopenharmony_ci#include <linux/ip.h>
2562306a36Sopenharmony_ci#include <linux/ipv6.h>
2662306a36Sopenharmony_ci#include <linux/sctp.h>
2762306a36Sopenharmony_ci#include <linux/tcp.h>
2862306a36Sopenharmony_ci#include <linux/udp.h>
2962306a36Sopenharmony_ci#include <linux/icmp.h>
3062306a36Sopenharmony_ci#include <linux/icmpv6.h>
3162306a36Sopenharmony_ci#include <linux/rculist.h>
3262306a36Sopenharmony_ci#include <net/geneve.h>
3362306a36Sopenharmony_ci#include <net/ip.h>
3462306a36Sopenharmony_ci#include <net/ipv6.h>
3562306a36Sopenharmony_ci#include <net/ndisc.h>
3662306a36Sopenharmony_ci#include <net/mpls.h>
3762306a36Sopenharmony_ci#include <net/vxlan.h>
3862306a36Sopenharmony_ci#include <net/tun_proto.h>
3962306a36Sopenharmony_ci#include <net/erspan.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include "drop.h"
4262306a36Sopenharmony_ci#include "flow_netlink.h"
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistruct ovs_len_tbl {
4562306a36Sopenharmony_ci	int len;
4662306a36Sopenharmony_ci	const struct ovs_len_tbl *next;
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define OVS_ATTR_NESTED -1
5062306a36Sopenharmony_ci#define OVS_ATTR_VARIABLE -2
5162306a36Sopenharmony_ci#define OVS_COPY_ACTIONS_MAX_DEPTH 16
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic bool actions_may_change_flow(const struct nlattr *actions)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct nlattr *nla;
5662306a36Sopenharmony_ci	int rem;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	nla_for_each_nested(nla, actions, rem) {
5962306a36Sopenharmony_ci		u16 action = nla_type(nla);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		switch (action) {
6262306a36Sopenharmony_ci		case OVS_ACTION_ATTR_OUTPUT:
6362306a36Sopenharmony_ci		case OVS_ACTION_ATTR_RECIRC:
6462306a36Sopenharmony_ci		case OVS_ACTION_ATTR_TRUNC:
6562306a36Sopenharmony_ci		case OVS_ACTION_ATTR_USERSPACE:
6662306a36Sopenharmony_ci		case OVS_ACTION_ATTR_DROP:
6762306a36Sopenharmony_ci			break;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CT:
7062306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CT_CLEAR:
7162306a36Sopenharmony_ci		case OVS_ACTION_ATTR_HASH:
7262306a36Sopenharmony_ci		case OVS_ACTION_ATTR_POP_ETH:
7362306a36Sopenharmony_ci		case OVS_ACTION_ATTR_POP_MPLS:
7462306a36Sopenharmony_ci		case OVS_ACTION_ATTR_POP_NSH:
7562306a36Sopenharmony_ci		case OVS_ACTION_ATTR_POP_VLAN:
7662306a36Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_ETH:
7762306a36Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_MPLS:
7862306a36Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_NSH:
7962306a36Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_VLAN:
8062306a36Sopenharmony_ci		case OVS_ACTION_ATTR_SAMPLE:
8162306a36Sopenharmony_ci		case OVS_ACTION_ATTR_SET:
8262306a36Sopenharmony_ci		case OVS_ACTION_ATTR_SET_MASKED:
8362306a36Sopenharmony_ci		case OVS_ACTION_ATTR_METER:
8462306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CHECK_PKT_LEN:
8562306a36Sopenharmony_ci		case OVS_ACTION_ATTR_ADD_MPLS:
8662306a36Sopenharmony_ci		case OVS_ACTION_ATTR_DEC_TTL:
8762306a36Sopenharmony_ci		default:
8862306a36Sopenharmony_ci			return true;
8962306a36Sopenharmony_ci		}
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci	return false;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic void update_range(struct sw_flow_match *match,
9562306a36Sopenharmony_ci			 size_t offset, size_t size, bool is_mask)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct sw_flow_key_range *range;
9862306a36Sopenharmony_ci	size_t start = rounddown(offset, sizeof(long));
9962306a36Sopenharmony_ci	size_t end = roundup(offset + size, sizeof(long));
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (!is_mask)
10262306a36Sopenharmony_ci		range = &match->range;
10362306a36Sopenharmony_ci	else
10462306a36Sopenharmony_ci		range = &match->mask->range;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	if (range->start == range->end) {
10762306a36Sopenharmony_ci		range->start = start;
10862306a36Sopenharmony_ci		range->end = end;
10962306a36Sopenharmony_ci		return;
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	if (range->start > start)
11362306a36Sopenharmony_ci		range->start = start;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (range->end < end)
11662306a36Sopenharmony_ci		range->end = end;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci#define SW_FLOW_KEY_PUT(match, field, value, is_mask) \
12062306a36Sopenharmony_ci	do { \
12162306a36Sopenharmony_ci		update_range(match, offsetof(struct sw_flow_key, field),    \
12262306a36Sopenharmony_ci			     sizeof((match)->key->field), is_mask);	    \
12362306a36Sopenharmony_ci		if (is_mask)						    \
12462306a36Sopenharmony_ci			(match)->mask->key.field = value;		    \
12562306a36Sopenharmony_ci		else							    \
12662306a36Sopenharmony_ci			(match)->key->field = value;		            \
12762306a36Sopenharmony_ci	} while (0)
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#define SW_FLOW_KEY_MEMCPY_OFFSET(match, offset, value_p, len, is_mask)	    \
13062306a36Sopenharmony_ci	do {								    \
13162306a36Sopenharmony_ci		update_range(match, offset, len, is_mask);		    \
13262306a36Sopenharmony_ci		if (is_mask)						    \
13362306a36Sopenharmony_ci			memcpy((u8 *)&(match)->mask->key + offset, value_p, \
13462306a36Sopenharmony_ci			       len);					   \
13562306a36Sopenharmony_ci		else							    \
13662306a36Sopenharmony_ci			memcpy((u8 *)(match)->key + offset, value_p, len);  \
13762306a36Sopenharmony_ci	} while (0)
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci#define SW_FLOW_KEY_MEMCPY(match, field, value_p, len, is_mask)		      \
14062306a36Sopenharmony_ci	SW_FLOW_KEY_MEMCPY_OFFSET(match, offsetof(struct sw_flow_key, field), \
14162306a36Sopenharmony_ci				  value_p, len, is_mask)
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#define SW_FLOW_KEY_MEMSET_FIELD(match, field, value, is_mask)		    \
14462306a36Sopenharmony_ci	do {								    \
14562306a36Sopenharmony_ci		update_range(match, offsetof(struct sw_flow_key, field),    \
14662306a36Sopenharmony_ci			     sizeof((match)->key->field), is_mask);	    \
14762306a36Sopenharmony_ci		if (is_mask)						    \
14862306a36Sopenharmony_ci			memset((u8 *)&(match)->mask->key.field, value,      \
14962306a36Sopenharmony_ci			       sizeof((match)->mask->key.field));	    \
15062306a36Sopenharmony_ci		else							    \
15162306a36Sopenharmony_ci			memset((u8 *)&(match)->key->field, value,           \
15262306a36Sopenharmony_ci			       sizeof((match)->key->field));                \
15362306a36Sopenharmony_ci	} while (0)
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic bool match_validate(const struct sw_flow_match *match,
15662306a36Sopenharmony_ci			   u64 key_attrs, u64 mask_attrs, bool log)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	u64 key_expected = 0;
15962306a36Sopenharmony_ci	u64 mask_allowed = key_attrs;  /* At most allow all key attributes */
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* The following mask attributes allowed only if they
16262306a36Sopenharmony_ci	 * pass the validation tests. */
16362306a36Sopenharmony_ci	mask_allowed &= ~((1 << OVS_KEY_ATTR_IPV4)
16462306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4)
16562306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_IPV6)
16662306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6)
16762306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_TCP)
16862306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_TCP_FLAGS)
16962306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_UDP)
17062306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_SCTP)
17162306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_ICMP)
17262306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_ICMPV6)
17362306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_ARP)
17462306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_ND)
17562306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_MPLS)
17662306a36Sopenharmony_ci			| (1 << OVS_KEY_ATTR_NSH));
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* Always allowed mask fields. */
17962306a36Sopenharmony_ci	mask_allowed |= ((1 << OVS_KEY_ATTR_TUNNEL)
18062306a36Sopenharmony_ci		       | (1 << OVS_KEY_ATTR_IN_PORT)
18162306a36Sopenharmony_ci		       | (1 << OVS_KEY_ATTR_ETHERTYPE));
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* Check key attributes. */
18462306a36Sopenharmony_ci	if (match->key->eth.type == htons(ETH_P_ARP)
18562306a36Sopenharmony_ci			|| match->key->eth.type == htons(ETH_P_RARP)) {
18662306a36Sopenharmony_ci		key_expected |= 1 << OVS_KEY_ATTR_ARP;
18762306a36Sopenharmony_ci		if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
18862306a36Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_ARP;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (eth_p_mpls(match->key->eth.type)) {
19262306a36Sopenharmony_ci		key_expected |= 1 << OVS_KEY_ATTR_MPLS;
19362306a36Sopenharmony_ci		if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
19462306a36Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_MPLS;
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (match->key->eth.type == htons(ETH_P_IP)) {
19862306a36Sopenharmony_ci		key_expected |= 1 << OVS_KEY_ATTR_IPV4;
19962306a36Sopenharmony_ci		if (match->mask && match->mask->key.eth.type == htons(0xffff)) {
20062306a36Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_IPV4;
20162306a36Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4;
20262306a36Sopenharmony_ci		}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) {
20562306a36Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_UDP) {
20662306a36Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_UDP;
20762306a36Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff))
20862306a36Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_UDP;
20962306a36Sopenharmony_ci			}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_SCTP) {
21262306a36Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_SCTP;
21362306a36Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff))
21462306a36Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_SCTP;
21562306a36Sopenharmony_ci			}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_TCP) {
21862306a36Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_TCP;
21962306a36Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_TCP_FLAGS;
22062306a36Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff)) {
22162306a36Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_TCP;
22262306a36Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_TCP_FLAGS;
22362306a36Sopenharmony_ci				}
22462306a36Sopenharmony_ci			}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_ICMP) {
22762306a36Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_ICMP;
22862306a36Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff))
22962306a36Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_ICMP;
23062306a36Sopenharmony_ci			}
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (match->key->eth.type == htons(ETH_P_IPV6)) {
23562306a36Sopenharmony_ci		key_expected |= 1 << OVS_KEY_ATTR_IPV6;
23662306a36Sopenharmony_ci		if (match->mask && match->mask->key.eth.type == htons(0xffff)) {
23762306a36Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_IPV6;
23862306a36Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6;
23962306a36Sopenharmony_ci		}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci		if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) {
24262306a36Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_UDP) {
24362306a36Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_UDP;
24462306a36Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff))
24562306a36Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_UDP;
24662306a36Sopenharmony_ci			}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_SCTP) {
24962306a36Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_SCTP;
25062306a36Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff))
25162306a36Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_SCTP;
25262306a36Sopenharmony_ci			}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_TCP) {
25562306a36Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_TCP;
25662306a36Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_TCP_FLAGS;
25762306a36Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff)) {
25862306a36Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_TCP;
25962306a36Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_TCP_FLAGS;
26062306a36Sopenharmony_ci				}
26162306a36Sopenharmony_ci			}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_ICMPV6) {
26462306a36Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_ICMPV6;
26562306a36Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff))
26662306a36Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_ICMPV6;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci				if (match->key->tp.src ==
26962306a36Sopenharmony_ci						htons(NDISC_NEIGHBOUR_SOLICITATION) ||
27062306a36Sopenharmony_ci				    match->key->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) {
27162306a36Sopenharmony_ci					key_expected |= 1 << OVS_KEY_ATTR_ND;
27262306a36Sopenharmony_ci					/* Original direction conntrack tuple
27362306a36Sopenharmony_ci					 * uses the same space as the ND fields
27462306a36Sopenharmony_ci					 * in the key, so both are not allowed
27562306a36Sopenharmony_ci					 * at the same time.
27662306a36Sopenharmony_ci					 */
27762306a36Sopenharmony_ci					mask_allowed &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6);
27862306a36Sopenharmony_ci					if (match->mask && (match->mask->key.tp.src == htons(0xff)))
27962306a36Sopenharmony_ci						mask_allowed |= 1 << OVS_KEY_ATTR_ND;
28062306a36Sopenharmony_ci				}
28162306a36Sopenharmony_ci			}
28262306a36Sopenharmony_ci		}
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (match->key->eth.type == htons(ETH_P_NSH)) {
28662306a36Sopenharmony_ci		key_expected |= 1 << OVS_KEY_ATTR_NSH;
28762306a36Sopenharmony_ci		if (match->mask &&
28862306a36Sopenharmony_ci		    match->mask->key.eth.type == htons(0xffff)) {
28962306a36Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_NSH;
29062306a36Sopenharmony_ci		}
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	if ((key_attrs & key_expected) != key_expected) {
29462306a36Sopenharmony_ci		/* Key attributes check failed. */
29562306a36Sopenharmony_ci		OVS_NLERR(log, "Missing key (keys=%llx, expected=%llx)",
29662306a36Sopenharmony_ci			  (unsigned long long)key_attrs,
29762306a36Sopenharmony_ci			  (unsigned long long)key_expected);
29862306a36Sopenharmony_ci		return false;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if ((mask_attrs & mask_allowed) != mask_attrs) {
30262306a36Sopenharmony_ci		/* Mask attributes check failed. */
30362306a36Sopenharmony_ci		OVS_NLERR(log, "Unexpected mask (mask=%llx, allowed=%llx)",
30462306a36Sopenharmony_ci			  (unsigned long long)mask_attrs,
30562306a36Sopenharmony_ci			  (unsigned long long)mask_allowed);
30662306a36Sopenharmony_ci		return false;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	return true;
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cisize_t ovs_tun_key_attr_size(void)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	/* Whenever adding new OVS_TUNNEL_KEY_ FIELDS, we should consider
31562306a36Sopenharmony_ci	 * updating this function.
31662306a36Sopenharmony_ci	 */
31762306a36Sopenharmony_ci	return    nla_total_size_64bit(8) /* OVS_TUNNEL_KEY_ATTR_ID */
31862306a36Sopenharmony_ci		+ nla_total_size(16)   /* OVS_TUNNEL_KEY_ATTR_IPV[46]_SRC */
31962306a36Sopenharmony_ci		+ nla_total_size(16)   /* OVS_TUNNEL_KEY_ATTR_IPV[46]_DST */
32062306a36Sopenharmony_ci		+ nla_total_size(1)    /* OVS_TUNNEL_KEY_ATTR_TOS */
32162306a36Sopenharmony_ci		+ nla_total_size(1)    /* OVS_TUNNEL_KEY_ATTR_TTL */
32262306a36Sopenharmony_ci		+ nla_total_size(0)    /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
32362306a36Sopenharmony_ci		+ nla_total_size(0)    /* OVS_TUNNEL_KEY_ATTR_CSUM */
32462306a36Sopenharmony_ci		+ nla_total_size(0)    /* OVS_TUNNEL_KEY_ATTR_OAM */
32562306a36Sopenharmony_ci		+ nla_total_size(256)  /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
32662306a36Sopenharmony_ci		/* OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS and
32762306a36Sopenharmony_ci		 * OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS is mutually exclusive with
32862306a36Sopenharmony_ci		 * OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS and covered by it.
32962306a36Sopenharmony_ci		 */
33062306a36Sopenharmony_ci		+ nla_total_size(2)    /* OVS_TUNNEL_KEY_ATTR_TP_SRC */
33162306a36Sopenharmony_ci		+ nla_total_size(2);   /* OVS_TUNNEL_KEY_ATTR_TP_DST */
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic size_t ovs_nsh_key_attr_size(void)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	/* Whenever adding new OVS_NSH_KEY_ FIELDS, we should consider
33762306a36Sopenharmony_ci	 * updating this function.
33862306a36Sopenharmony_ci	 */
33962306a36Sopenharmony_ci	return  nla_total_size(NSH_BASE_HDR_LEN) /* OVS_NSH_KEY_ATTR_BASE */
34062306a36Sopenharmony_ci		/* OVS_NSH_KEY_ATTR_MD1 and OVS_NSH_KEY_ATTR_MD2 are
34162306a36Sopenharmony_ci		 * mutually exclusive, so the bigger one can cover
34262306a36Sopenharmony_ci		 * the small one.
34362306a36Sopenharmony_ci		 */
34462306a36Sopenharmony_ci		+ nla_total_size(NSH_CTX_HDRS_MAX_LEN);
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cisize_t ovs_key_attr_size(void)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	/* Whenever adding new OVS_KEY_ FIELDS, we should consider
35062306a36Sopenharmony_ci	 * updating this function.
35162306a36Sopenharmony_ci	 */
35262306a36Sopenharmony_ci	BUILD_BUG_ON(OVS_KEY_ATTR_MAX != 32);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	return    nla_total_size(4)   /* OVS_KEY_ATTR_PRIORITY */
35562306a36Sopenharmony_ci		+ nla_total_size(0)   /* OVS_KEY_ATTR_TUNNEL */
35662306a36Sopenharmony_ci		  + ovs_tun_key_attr_size()
35762306a36Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_IN_PORT */
35862306a36Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_SKB_MARK */
35962306a36Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_DP_HASH */
36062306a36Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_RECIRC_ID */
36162306a36Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_CT_STATE */
36262306a36Sopenharmony_ci		+ nla_total_size(2)   /* OVS_KEY_ATTR_CT_ZONE */
36362306a36Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_CT_MARK */
36462306a36Sopenharmony_ci		+ nla_total_size(16)  /* OVS_KEY_ATTR_CT_LABELS */
36562306a36Sopenharmony_ci		+ nla_total_size(40)  /* OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6 */
36662306a36Sopenharmony_ci		+ nla_total_size(0)   /* OVS_KEY_ATTR_NSH */
36762306a36Sopenharmony_ci		  + ovs_nsh_key_attr_size()
36862306a36Sopenharmony_ci		+ nla_total_size(12)  /* OVS_KEY_ATTR_ETHERNET */
36962306a36Sopenharmony_ci		+ nla_total_size(2)   /* OVS_KEY_ATTR_ETHERTYPE */
37062306a36Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_VLAN */
37162306a36Sopenharmony_ci		+ nla_total_size(0)   /* OVS_KEY_ATTR_ENCAP */
37262306a36Sopenharmony_ci		+ nla_total_size(2)   /* OVS_KEY_ATTR_ETHERTYPE */
37362306a36Sopenharmony_ci		+ nla_total_size(40)  /* OVS_KEY_ATTR_IPV6 */
37462306a36Sopenharmony_ci		+ nla_total_size(2)   /* OVS_KEY_ATTR_ICMPV6 */
37562306a36Sopenharmony_ci		+ nla_total_size(28)  /* OVS_KEY_ATTR_ND */
37662306a36Sopenharmony_ci		+ nla_total_size(2);  /* OVS_KEY_ATTR_IPV6_EXTHDRS */
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic const struct ovs_len_tbl ovs_vxlan_ext_key_lens[OVS_VXLAN_EXT_MAX + 1] = {
38062306a36Sopenharmony_ci	[OVS_VXLAN_EXT_GBP]	    = { .len = sizeof(u32) },
38162306a36Sopenharmony_ci};
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
38462306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_ID]	    = { .len = sizeof(u64) },
38562306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_IPV4_SRC]	    = { .len = sizeof(u32) },
38662306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_IPV4_DST]	    = { .len = sizeof(u32) },
38762306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_TOS]	    = { .len = 1 },
38862306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_TTL]	    = { .len = 1 },
38962306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = { .len = 0 },
39062306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_CSUM]	    = { .len = 0 },
39162306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_TP_SRC]	    = { .len = sizeof(u16) },
39262306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_TP_DST]	    = { .len = sizeof(u16) },
39362306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_OAM]	    = { .len = 0 },
39462306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS]   = { .len = OVS_ATTR_VARIABLE },
39562306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS]    = { .len = OVS_ATTR_NESTED,
39662306a36Sopenharmony_ci						.next = ovs_vxlan_ext_key_lens },
39762306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_IPV6_SRC]      = { .len = sizeof(struct in6_addr) },
39862306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_IPV6_DST]      = { .len = sizeof(struct in6_addr) },
39962306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS]   = { .len = OVS_ATTR_VARIABLE },
40062306a36Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE]   = { .len = 0 },
40162306a36Sopenharmony_ci};
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic const struct ovs_len_tbl
40462306a36Sopenharmony_ciovs_nsh_key_attr_lens[OVS_NSH_KEY_ATTR_MAX + 1] = {
40562306a36Sopenharmony_ci	[OVS_NSH_KEY_ATTR_BASE] = { .len = sizeof(struct ovs_nsh_key_base) },
40662306a36Sopenharmony_ci	[OVS_NSH_KEY_ATTR_MD1]  = { .len = sizeof(struct ovs_nsh_key_md1) },
40762306a36Sopenharmony_ci	[OVS_NSH_KEY_ATTR_MD2]  = { .len = OVS_ATTR_VARIABLE },
40862306a36Sopenharmony_ci};
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute.  */
41162306a36Sopenharmony_cistatic const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
41262306a36Sopenharmony_ci	[OVS_KEY_ATTR_ENCAP]	 = { .len = OVS_ATTR_NESTED },
41362306a36Sopenharmony_ci	[OVS_KEY_ATTR_PRIORITY]	 = { .len = sizeof(u32) },
41462306a36Sopenharmony_ci	[OVS_KEY_ATTR_IN_PORT]	 = { .len = sizeof(u32) },
41562306a36Sopenharmony_ci	[OVS_KEY_ATTR_SKB_MARK]	 = { .len = sizeof(u32) },
41662306a36Sopenharmony_ci	[OVS_KEY_ATTR_ETHERNET]	 = { .len = sizeof(struct ovs_key_ethernet) },
41762306a36Sopenharmony_ci	[OVS_KEY_ATTR_VLAN]	 = { .len = sizeof(__be16) },
41862306a36Sopenharmony_ci	[OVS_KEY_ATTR_ETHERTYPE] = { .len = sizeof(__be16) },
41962306a36Sopenharmony_ci	[OVS_KEY_ATTR_IPV4]	 = { .len = sizeof(struct ovs_key_ipv4) },
42062306a36Sopenharmony_ci	[OVS_KEY_ATTR_IPV6]	 = { .len = sizeof(struct ovs_key_ipv6) },
42162306a36Sopenharmony_ci	[OVS_KEY_ATTR_TCP]	 = { .len = sizeof(struct ovs_key_tcp) },
42262306a36Sopenharmony_ci	[OVS_KEY_ATTR_TCP_FLAGS] = { .len = sizeof(__be16) },
42362306a36Sopenharmony_ci	[OVS_KEY_ATTR_UDP]	 = { .len = sizeof(struct ovs_key_udp) },
42462306a36Sopenharmony_ci	[OVS_KEY_ATTR_SCTP]	 = { .len = sizeof(struct ovs_key_sctp) },
42562306a36Sopenharmony_ci	[OVS_KEY_ATTR_ICMP]	 = { .len = sizeof(struct ovs_key_icmp) },
42662306a36Sopenharmony_ci	[OVS_KEY_ATTR_ICMPV6]	 = { .len = sizeof(struct ovs_key_icmpv6) },
42762306a36Sopenharmony_ci	[OVS_KEY_ATTR_ARP]	 = { .len = sizeof(struct ovs_key_arp) },
42862306a36Sopenharmony_ci	[OVS_KEY_ATTR_ND]	 = { .len = sizeof(struct ovs_key_nd) },
42962306a36Sopenharmony_ci	[OVS_KEY_ATTR_RECIRC_ID] = { .len = sizeof(u32) },
43062306a36Sopenharmony_ci	[OVS_KEY_ATTR_DP_HASH]	 = { .len = sizeof(u32) },
43162306a36Sopenharmony_ci	[OVS_KEY_ATTR_TUNNEL]	 = { .len = OVS_ATTR_NESTED,
43262306a36Sopenharmony_ci				     .next = ovs_tunnel_key_lens, },
43362306a36Sopenharmony_ci	[OVS_KEY_ATTR_MPLS]	 = { .len = OVS_ATTR_VARIABLE },
43462306a36Sopenharmony_ci	[OVS_KEY_ATTR_CT_STATE]	 = { .len = sizeof(u32) },
43562306a36Sopenharmony_ci	[OVS_KEY_ATTR_CT_ZONE]	 = { .len = sizeof(u16) },
43662306a36Sopenharmony_ci	[OVS_KEY_ATTR_CT_MARK]	 = { .len = sizeof(u32) },
43762306a36Sopenharmony_ci	[OVS_KEY_ATTR_CT_LABELS] = { .len = sizeof(struct ovs_key_ct_labels) },
43862306a36Sopenharmony_ci	[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4] = {
43962306a36Sopenharmony_ci		.len = sizeof(struct ovs_key_ct_tuple_ipv4) },
44062306a36Sopenharmony_ci	[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6] = {
44162306a36Sopenharmony_ci		.len = sizeof(struct ovs_key_ct_tuple_ipv6) },
44262306a36Sopenharmony_ci	[OVS_KEY_ATTR_NSH]       = { .len = OVS_ATTR_NESTED,
44362306a36Sopenharmony_ci				     .next = ovs_nsh_key_attr_lens, },
44462306a36Sopenharmony_ci	[OVS_KEY_ATTR_IPV6_EXTHDRS] = {
44562306a36Sopenharmony_ci		.len = sizeof(struct ovs_key_ipv6_exthdrs) },
44662306a36Sopenharmony_ci};
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic bool check_attr_len(unsigned int attr_len, unsigned int expected_len)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	return expected_len == attr_len ||
45162306a36Sopenharmony_ci	       expected_len == OVS_ATTR_NESTED ||
45262306a36Sopenharmony_ci	       expected_len == OVS_ATTR_VARIABLE;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic bool is_all_zero(const u8 *fp, size_t size)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	int i;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	if (!fp)
46062306a36Sopenharmony_ci		return false;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	for (i = 0; i < size; i++)
46362306a36Sopenharmony_ci		if (fp[i])
46462306a36Sopenharmony_ci			return false;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	return true;
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic int __parse_flow_nlattrs(const struct nlattr *attr,
47062306a36Sopenharmony_ci				const struct nlattr *a[],
47162306a36Sopenharmony_ci				u64 *attrsp, bool log, bool nz)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	const struct nlattr *nla;
47462306a36Sopenharmony_ci	u64 attrs;
47562306a36Sopenharmony_ci	int rem;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	attrs = *attrsp;
47862306a36Sopenharmony_ci	nla_for_each_nested(nla, attr, rem) {
47962306a36Sopenharmony_ci		u16 type = nla_type(nla);
48062306a36Sopenharmony_ci		int expected_len;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci		if (type > OVS_KEY_ATTR_MAX) {
48362306a36Sopenharmony_ci			OVS_NLERR(log, "Key type %d is out of range max %d",
48462306a36Sopenharmony_ci				  type, OVS_KEY_ATTR_MAX);
48562306a36Sopenharmony_ci			return -EINVAL;
48662306a36Sopenharmony_ci		}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci		if (type == OVS_KEY_ATTR_PACKET_TYPE ||
48962306a36Sopenharmony_ci		    type == OVS_KEY_ATTR_ND_EXTENSIONS ||
49062306a36Sopenharmony_ci		    type == OVS_KEY_ATTR_TUNNEL_INFO) {
49162306a36Sopenharmony_ci			OVS_NLERR(log, "Key type %d is not supported", type);
49262306a36Sopenharmony_ci			return -EINVAL;
49362306a36Sopenharmony_ci		}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		if (attrs & (1ULL << type)) {
49662306a36Sopenharmony_ci			OVS_NLERR(log, "Duplicate key (type %d).", type);
49762306a36Sopenharmony_ci			return -EINVAL;
49862306a36Sopenharmony_ci		}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci		expected_len = ovs_key_lens[type].len;
50162306a36Sopenharmony_ci		if (!check_attr_len(nla_len(nla), expected_len)) {
50262306a36Sopenharmony_ci			OVS_NLERR(log, "Key %d has unexpected len %d expected %d",
50362306a36Sopenharmony_ci				  type, nla_len(nla), expected_len);
50462306a36Sopenharmony_ci			return -EINVAL;
50562306a36Sopenharmony_ci		}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		if (!nz || !is_all_zero(nla_data(nla), nla_len(nla))) {
50862306a36Sopenharmony_ci			attrs |= 1ULL << type;
50962306a36Sopenharmony_ci			a[type] = nla;
51062306a36Sopenharmony_ci		}
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci	if (rem) {
51362306a36Sopenharmony_ci		OVS_NLERR(log, "Message has %d unknown bytes.", rem);
51462306a36Sopenharmony_ci		return -EINVAL;
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	*attrsp = attrs;
51862306a36Sopenharmony_ci	return 0;
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic int parse_flow_mask_nlattrs(const struct nlattr *attr,
52262306a36Sopenharmony_ci				   const struct nlattr *a[], u64 *attrsp,
52362306a36Sopenharmony_ci				   bool log)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	return __parse_flow_nlattrs(attr, a, attrsp, log, true);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ciint parse_flow_nlattrs(const struct nlattr *attr, const struct nlattr *a[],
52962306a36Sopenharmony_ci		       u64 *attrsp, bool log)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	return __parse_flow_nlattrs(attr, a, attrsp, log, false);
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic int genev_tun_opt_from_nlattr(const struct nlattr *a,
53562306a36Sopenharmony_ci				     struct sw_flow_match *match, bool is_mask,
53662306a36Sopenharmony_ci				     bool log)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	unsigned long opt_key_offset;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (nla_len(a) > sizeof(match->key->tun_opts)) {
54162306a36Sopenharmony_ci		OVS_NLERR(log, "Geneve option length err (len %d, max %zu).",
54262306a36Sopenharmony_ci			  nla_len(a), sizeof(match->key->tun_opts));
54362306a36Sopenharmony_ci		return -EINVAL;
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	if (nla_len(a) % 4 != 0) {
54762306a36Sopenharmony_ci		OVS_NLERR(log, "Geneve opt len %d is not a multiple of 4.",
54862306a36Sopenharmony_ci			  nla_len(a));
54962306a36Sopenharmony_ci		return -EINVAL;
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	/* We need to record the length of the options passed
55362306a36Sopenharmony_ci	 * down, otherwise packets with the same format but
55462306a36Sopenharmony_ci	 * additional options will be silently matched.
55562306a36Sopenharmony_ci	 */
55662306a36Sopenharmony_ci	if (!is_mask) {
55762306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_opts_len, nla_len(a),
55862306a36Sopenharmony_ci				false);
55962306a36Sopenharmony_ci	} else {
56062306a36Sopenharmony_ci		/* This is somewhat unusual because it looks at
56162306a36Sopenharmony_ci		 * both the key and mask while parsing the
56262306a36Sopenharmony_ci		 * attributes (and by extension assumes the key
56362306a36Sopenharmony_ci		 * is parsed first). Normally, we would verify
56462306a36Sopenharmony_ci		 * that each is the correct length and that the
56562306a36Sopenharmony_ci		 * attributes line up in the validate function.
56662306a36Sopenharmony_ci		 * However, that is difficult because this is
56762306a36Sopenharmony_ci		 * variable length and we won't have the
56862306a36Sopenharmony_ci		 * information later.
56962306a36Sopenharmony_ci		 */
57062306a36Sopenharmony_ci		if (match->key->tun_opts_len != nla_len(a)) {
57162306a36Sopenharmony_ci			OVS_NLERR(log, "Geneve option len %d != mask len %d",
57262306a36Sopenharmony_ci				  match->key->tun_opts_len, nla_len(a));
57362306a36Sopenharmony_ci			return -EINVAL;
57462306a36Sopenharmony_ci		}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	opt_key_offset = TUN_METADATA_OFFSET(nla_len(a));
58062306a36Sopenharmony_ci	SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, nla_data(a),
58162306a36Sopenharmony_ci				  nla_len(a), is_mask);
58262306a36Sopenharmony_ci	return 0;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic int vxlan_tun_opt_from_nlattr(const struct nlattr *attr,
58662306a36Sopenharmony_ci				     struct sw_flow_match *match, bool is_mask,
58762306a36Sopenharmony_ci				     bool log)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	struct nlattr *a;
59062306a36Sopenharmony_ci	int rem;
59162306a36Sopenharmony_ci	unsigned long opt_key_offset;
59262306a36Sopenharmony_ci	struct vxlan_metadata opts;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts));
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	memset(&opts, 0, sizeof(opts));
59762306a36Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
59862306a36Sopenharmony_ci		int type = nla_type(a);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci		if (type > OVS_VXLAN_EXT_MAX) {
60162306a36Sopenharmony_ci			OVS_NLERR(log, "VXLAN extension %d out of range max %d",
60262306a36Sopenharmony_ci				  type, OVS_VXLAN_EXT_MAX);
60362306a36Sopenharmony_ci			return -EINVAL;
60462306a36Sopenharmony_ci		}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci		if (!check_attr_len(nla_len(a),
60762306a36Sopenharmony_ci				    ovs_vxlan_ext_key_lens[type].len)) {
60862306a36Sopenharmony_ci			OVS_NLERR(log, "VXLAN extension %d has unexpected len %d expected %d",
60962306a36Sopenharmony_ci				  type, nla_len(a),
61062306a36Sopenharmony_ci				  ovs_vxlan_ext_key_lens[type].len);
61162306a36Sopenharmony_ci			return -EINVAL;
61262306a36Sopenharmony_ci		}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		switch (type) {
61562306a36Sopenharmony_ci		case OVS_VXLAN_EXT_GBP:
61662306a36Sopenharmony_ci			opts.gbp = nla_get_u32(a);
61762306a36Sopenharmony_ci			break;
61862306a36Sopenharmony_ci		default:
61962306a36Sopenharmony_ci			OVS_NLERR(log, "Unknown VXLAN extension attribute %d",
62062306a36Sopenharmony_ci				  type);
62162306a36Sopenharmony_ci			return -EINVAL;
62262306a36Sopenharmony_ci		}
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci	if (rem) {
62562306a36Sopenharmony_ci		OVS_NLERR(log, "VXLAN extension message has %d unknown bytes.",
62662306a36Sopenharmony_ci			  rem);
62762306a36Sopenharmony_ci		return -EINVAL;
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if (!is_mask)
63162306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_opts_len, sizeof(opts), false);
63262306a36Sopenharmony_ci	else
63362306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	opt_key_offset = TUN_METADATA_OFFSET(sizeof(opts));
63662306a36Sopenharmony_ci	SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, &opts, sizeof(opts),
63762306a36Sopenharmony_ci				  is_mask);
63862306a36Sopenharmony_ci	return 0;
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic int erspan_tun_opt_from_nlattr(const struct nlattr *a,
64262306a36Sopenharmony_ci				      struct sw_flow_match *match, bool is_mask,
64362306a36Sopenharmony_ci				      bool log)
64462306a36Sopenharmony_ci{
64562306a36Sopenharmony_ci	unsigned long opt_key_offset;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct erspan_metadata) >
64862306a36Sopenharmony_ci		     sizeof(match->key->tun_opts));
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	if (nla_len(a) > sizeof(match->key->tun_opts)) {
65162306a36Sopenharmony_ci		OVS_NLERR(log, "ERSPAN option length err (len %d, max %zu).",
65262306a36Sopenharmony_ci			  nla_len(a), sizeof(match->key->tun_opts));
65362306a36Sopenharmony_ci		return -EINVAL;
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	if (!is_mask)
65762306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_opts_len,
65862306a36Sopenharmony_ci				sizeof(struct erspan_metadata), false);
65962306a36Sopenharmony_ci	else
66062306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	opt_key_offset = TUN_METADATA_OFFSET(nla_len(a));
66362306a36Sopenharmony_ci	SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, nla_data(a),
66462306a36Sopenharmony_ci				  nla_len(a), is_mask);
66562306a36Sopenharmony_ci	return 0;
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cistatic int ip_tun_from_nlattr(const struct nlattr *attr,
66962306a36Sopenharmony_ci			      struct sw_flow_match *match, bool is_mask,
67062306a36Sopenharmony_ci			      bool log)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	bool ttl = false, ipv4 = false, ipv6 = false;
67362306a36Sopenharmony_ci	bool info_bridge_mode = false;
67462306a36Sopenharmony_ci	__be16 tun_flags = 0;
67562306a36Sopenharmony_ci	int opts_type = 0;
67662306a36Sopenharmony_ci	struct nlattr *a;
67762306a36Sopenharmony_ci	int rem;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
68062306a36Sopenharmony_ci		int type = nla_type(a);
68162306a36Sopenharmony_ci		int err;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci		if (type > OVS_TUNNEL_KEY_ATTR_MAX) {
68462306a36Sopenharmony_ci			OVS_NLERR(log, "Tunnel attr %d out of range max %d",
68562306a36Sopenharmony_ci				  type, OVS_TUNNEL_KEY_ATTR_MAX);
68662306a36Sopenharmony_ci			return -EINVAL;
68762306a36Sopenharmony_ci		}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		if (!check_attr_len(nla_len(a),
69062306a36Sopenharmony_ci				    ovs_tunnel_key_lens[type].len)) {
69162306a36Sopenharmony_ci			OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d",
69262306a36Sopenharmony_ci				  type, nla_len(a), ovs_tunnel_key_lens[type].len);
69362306a36Sopenharmony_ci			return -EINVAL;
69462306a36Sopenharmony_ci		}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci		switch (type) {
69762306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_ID:
69862306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.tun_id,
69962306a36Sopenharmony_ci					nla_get_be64(a), is_mask);
70062306a36Sopenharmony_ci			tun_flags |= TUNNEL_KEY;
70162306a36Sopenharmony_ci			break;
70262306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
70362306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.src,
70462306a36Sopenharmony_ci					nla_get_in_addr(a), is_mask);
70562306a36Sopenharmony_ci			ipv4 = true;
70662306a36Sopenharmony_ci			break;
70762306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
70862306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.dst,
70962306a36Sopenharmony_ci					nla_get_in_addr(a), is_mask);
71062306a36Sopenharmony_ci			ipv4 = true;
71162306a36Sopenharmony_ci			break;
71262306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_IPV6_SRC:
71362306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.src,
71462306a36Sopenharmony_ci					nla_get_in6_addr(a), is_mask);
71562306a36Sopenharmony_ci			ipv6 = true;
71662306a36Sopenharmony_ci			break;
71762306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_IPV6_DST:
71862306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.dst,
71962306a36Sopenharmony_ci					nla_get_in6_addr(a), is_mask);
72062306a36Sopenharmony_ci			ipv6 = true;
72162306a36Sopenharmony_ci			break;
72262306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_TOS:
72362306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.tos,
72462306a36Sopenharmony_ci					nla_get_u8(a), is_mask);
72562306a36Sopenharmony_ci			break;
72662306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_TTL:
72762306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.ttl,
72862306a36Sopenharmony_ci					nla_get_u8(a), is_mask);
72962306a36Sopenharmony_ci			ttl = true;
73062306a36Sopenharmony_ci			break;
73162306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
73262306a36Sopenharmony_ci			tun_flags |= TUNNEL_DONT_FRAGMENT;
73362306a36Sopenharmony_ci			break;
73462306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_CSUM:
73562306a36Sopenharmony_ci			tun_flags |= TUNNEL_CSUM;
73662306a36Sopenharmony_ci			break;
73762306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_TP_SRC:
73862306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.tp_src,
73962306a36Sopenharmony_ci					nla_get_be16(a), is_mask);
74062306a36Sopenharmony_ci			break;
74162306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_TP_DST:
74262306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.tp_dst,
74362306a36Sopenharmony_ci					nla_get_be16(a), is_mask);
74462306a36Sopenharmony_ci			break;
74562306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_OAM:
74662306a36Sopenharmony_ci			tun_flags |= TUNNEL_OAM;
74762306a36Sopenharmony_ci			break;
74862306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
74962306a36Sopenharmony_ci			if (opts_type) {
75062306a36Sopenharmony_ci				OVS_NLERR(log, "Multiple metadata blocks provided");
75162306a36Sopenharmony_ci				return -EINVAL;
75262306a36Sopenharmony_ci			}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci			err = genev_tun_opt_from_nlattr(a, match, is_mask, log);
75562306a36Sopenharmony_ci			if (err)
75662306a36Sopenharmony_ci				return err;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci			tun_flags |= TUNNEL_GENEVE_OPT;
75962306a36Sopenharmony_ci			opts_type = type;
76062306a36Sopenharmony_ci			break;
76162306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
76262306a36Sopenharmony_ci			if (opts_type) {
76362306a36Sopenharmony_ci				OVS_NLERR(log, "Multiple metadata blocks provided");
76462306a36Sopenharmony_ci				return -EINVAL;
76562306a36Sopenharmony_ci			}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci			err = vxlan_tun_opt_from_nlattr(a, match, is_mask, log);
76862306a36Sopenharmony_ci			if (err)
76962306a36Sopenharmony_ci				return err;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci			tun_flags |= TUNNEL_VXLAN_OPT;
77262306a36Sopenharmony_ci			opts_type = type;
77362306a36Sopenharmony_ci			break;
77462306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_PAD:
77562306a36Sopenharmony_ci			break;
77662306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS:
77762306a36Sopenharmony_ci			if (opts_type) {
77862306a36Sopenharmony_ci				OVS_NLERR(log, "Multiple metadata blocks provided");
77962306a36Sopenharmony_ci				return -EINVAL;
78062306a36Sopenharmony_ci			}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci			err = erspan_tun_opt_from_nlattr(a, match, is_mask,
78362306a36Sopenharmony_ci							 log);
78462306a36Sopenharmony_ci			if (err)
78562306a36Sopenharmony_ci				return err;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci			tun_flags |= TUNNEL_ERSPAN_OPT;
78862306a36Sopenharmony_ci			opts_type = type;
78962306a36Sopenharmony_ci			break;
79062306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE:
79162306a36Sopenharmony_ci			info_bridge_mode = true;
79262306a36Sopenharmony_ci			ipv4 = true;
79362306a36Sopenharmony_ci			break;
79462306a36Sopenharmony_ci		default:
79562306a36Sopenharmony_ci			OVS_NLERR(log, "Unknown IP tunnel attribute %d",
79662306a36Sopenharmony_ci				  type);
79762306a36Sopenharmony_ci			return -EINVAL;
79862306a36Sopenharmony_ci		}
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	SW_FLOW_KEY_PUT(match, tun_key.tun_flags, tun_flags, is_mask);
80262306a36Sopenharmony_ci	if (is_mask)
80362306a36Sopenharmony_ci		SW_FLOW_KEY_MEMSET_FIELD(match, tun_proto, 0xff, true);
80462306a36Sopenharmony_ci	else
80562306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_proto, ipv6 ? AF_INET6 : AF_INET,
80662306a36Sopenharmony_ci				false);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	if (rem > 0) {
80962306a36Sopenharmony_ci		OVS_NLERR(log, "IP tunnel attribute has %d unknown bytes.",
81062306a36Sopenharmony_ci			  rem);
81162306a36Sopenharmony_ci		return -EINVAL;
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	if (ipv4 && ipv6) {
81562306a36Sopenharmony_ci		OVS_NLERR(log, "Mixed IPv4 and IPv6 tunnel attributes");
81662306a36Sopenharmony_ci		return -EINVAL;
81762306a36Sopenharmony_ci	}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	if (!is_mask) {
82062306a36Sopenharmony_ci		if (!ipv4 && !ipv6) {
82162306a36Sopenharmony_ci			OVS_NLERR(log, "IP tunnel dst address not specified");
82262306a36Sopenharmony_ci			return -EINVAL;
82362306a36Sopenharmony_ci		}
82462306a36Sopenharmony_ci		if (ipv4) {
82562306a36Sopenharmony_ci			if (info_bridge_mode) {
82662306a36Sopenharmony_ci				if (match->key->tun_key.u.ipv4.src ||
82762306a36Sopenharmony_ci				    match->key->tun_key.u.ipv4.dst ||
82862306a36Sopenharmony_ci				    match->key->tun_key.tp_src ||
82962306a36Sopenharmony_ci				    match->key->tun_key.tp_dst ||
83062306a36Sopenharmony_ci				    match->key->tun_key.ttl ||
83162306a36Sopenharmony_ci				    match->key->tun_key.tos ||
83262306a36Sopenharmony_ci				    tun_flags & ~TUNNEL_KEY) {
83362306a36Sopenharmony_ci					OVS_NLERR(log, "IPv4 tun info is not correct");
83462306a36Sopenharmony_ci					return -EINVAL;
83562306a36Sopenharmony_ci				}
83662306a36Sopenharmony_ci			} else if (!match->key->tun_key.u.ipv4.dst) {
83762306a36Sopenharmony_ci				OVS_NLERR(log, "IPv4 tunnel dst address is zero");
83862306a36Sopenharmony_ci				return -EINVAL;
83962306a36Sopenharmony_ci			}
84062306a36Sopenharmony_ci		}
84162306a36Sopenharmony_ci		if (ipv6 && ipv6_addr_any(&match->key->tun_key.u.ipv6.dst)) {
84262306a36Sopenharmony_ci			OVS_NLERR(log, "IPv6 tunnel dst address is zero");
84362306a36Sopenharmony_ci			return -EINVAL;
84462306a36Sopenharmony_ci		}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci		if (!ttl && !info_bridge_mode) {
84762306a36Sopenharmony_ci			OVS_NLERR(log, "IP tunnel TTL not specified.");
84862306a36Sopenharmony_ci			return -EINVAL;
84962306a36Sopenharmony_ci		}
85062306a36Sopenharmony_ci	}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	return opts_type;
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_cistatic int vxlan_opt_to_nlattr(struct sk_buff *skb,
85662306a36Sopenharmony_ci			       const void *tun_opts, int swkey_tun_opts_len)
85762306a36Sopenharmony_ci{
85862306a36Sopenharmony_ci	const struct vxlan_metadata *opts = tun_opts;
85962306a36Sopenharmony_ci	struct nlattr *nla;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	nla = nla_nest_start_noflag(skb, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
86262306a36Sopenharmony_ci	if (!nla)
86362306a36Sopenharmony_ci		return -EMSGSIZE;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	if (nla_put_u32(skb, OVS_VXLAN_EXT_GBP, opts->gbp) < 0)
86662306a36Sopenharmony_ci		return -EMSGSIZE;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	nla_nest_end(skb, nla);
86962306a36Sopenharmony_ci	return 0;
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_cistatic int __ip_tun_to_nlattr(struct sk_buff *skb,
87362306a36Sopenharmony_ci			      const struct ip_tunnel_key *output,
87462306a36Sopenharmony_ci			      const void *tun_opts, int swkey_tun_opts_len,
87562306a36Sopenharmony_ci			      unsigned short tun_proto, u8 mode)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	if (output->tun_flags & TUNNEL_KEY &&
87862306a36Sopenharmony_ci	    nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id,
87962306a36Sopenharmony_ci			 OVS_TUNNEL_KEY_ATTR_PAD))
88062306a36Sopenharmony_ci		return -EMSGSIZE;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	if (mode & IP_TUNNEL_INFO_BRIDGE)
88362306a36Sopenharmony_ci		return nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE)
88462306a36Sopenharmony_ci		       ? -EMSGSIZE : 0;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	switch (tun_proto) {
88762306a36Sopenharmony_ci	case AF_INET:
88862306a36Sopenharmony_ci		if (output->u.ipv4.src &&
88962306a36Sopenharmony_ci		    nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC,
89062306a36Sopenharmony_ci				    output->u.ipv4.src))
89162306a36Sopenharmony_ci			return -EMSGSIZE;
89262306a36Sopenharmony_ci		if (output->u.ipv4.dst &&
89362306a36Sopenharmony_ci		    nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST,
89462306a36Sopenharmony_ci				    output->u.ipv4.dst))
89562306a36Sopenharmony_ci			return -EMSGSIZE;
89662306a36Sopenharmony_ci		break;
89762306a36Sopenharmony_ci	case AF_INET6:
89862306a36Sopenharmony_ci		if (!ipv6_addr_any(&output->u.ipv6.src) &&
89962306a36Sopenharmony_ci		    nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_SRC,
90062306a36Sopenharmony_ci				     &output->u.ipv6.src))
90162306a36Sopenharmony_ci			return -EMSGSIZE;
90262306a36Sopenharmony_ci		if (!ipv6_addr_any(&output->u.ipv6.dst) &&
90362306a36Sopenharmony_ci		    nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_DST,
90462306a36Sopenharmony_ci				     &output->u.ipv6.dst))
90562306a36Sopenharmony_ci			return -EMSGSIZE;
90662306a36Sopenharmony_ci		break;
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci	if (output->tos &&
90962306a36Sopenharmony_ci	    nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->tos))
91062306a36Sopenharmony_ci		return -EMSGSIZE;
91162306a36Sopenharmony_ci	if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, output->ttl))
91262306a36Sopenharmony_ci		return -EMSGSIZE;
91362306a36Sopenharmony_ci	if ((output->tun_flags & TUNNEL_DONT_FRAGMENT) &&
91462306a36Sopenharmony_ci	    nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT))
91562306a36Sopenharmony_ci		return -EMSGSIZE;
91662306a36Sopenharmony_ci	if ((output->tun_flags & TUNNEL_CSUM) &&
91762306a36Sopenharmony_ci	    nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM))
91862306a36Sopenharmony_ci		return -EMSGSIZE;
91962306a36Sopenharmony_ci	if (output->tp_src &&
92062306a36Sopenharmony_ci	    nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_SRC, output->tp_src))
92162306a36Sopenharmony_ci		return -EMSGSIZE;
92262306a36Sopenharmony_ci	if (output->tp_dst &&
92362306a36Sopenharmony_ci	    nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_DST, output->tp_dst))
92462306a36Sopenharmony_ci		return -EMSGSIZE;
92562306a36Sopenharmony_ci	if ((output->tun_flags & TUNNEL_OAM) &&
92662306a36Sopenharmony_ci	    nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
92762306a36Sopenharmony_ci		return -EMSGSIZE;
92862306a36Sopenharmony_ci	if (swkey_tun_opts_len) {
92962306a36Sopenharmony_ci		if (output->tun_flags & TUNNEL_GENEVE_OPT &&
93062306a36Sopenharmony_ci		    nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
93162306a36Sopenharmony_ci			    swkey_tun_opts_len, tun_opts))
93262306a36Sopenharmony_ci			return -EMSGSIZE;
93362306a36Sopenharmony_ci		else if (output->tun_flags & TUNNEL_VXLAN_OPT &&
93462306a36Sopenharmony_ci			 vxlan_opt_to_nlattr(skb, tun_opts, swkey_tun_opts_len))
93562306a36Sopenharmony_ci			return -EMSGSIZE;
93662306a36Sopenharmony_ci		else if (output->tun_flags & TUNNEL_ERSPAN_OPT &&
93762306a36Sopenharmony_ci			 nla_put(skb, OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS,
93862306a36Sopenharmony_ci				 swkey_tun_opts_len, tun_opts))
93962306a36Sopenharmony_ci			return -EMSGSIZE;
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	return 0;
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_cistatic int ip_tun_to_nlattr(struct sk_buff *skb,
94662306a36Sopenharmony_ci			    const struct ip_tunnel_key *output,
94762306a36Sopenharmony_ci			    const void *tun_opts, int swkey_tun_opts_len,
94862306a36Sopenharmony_ci			    unsigned short tun_proto, u8 mode)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	struct nlattr *nla;
95162306a36Sopenharmony_ci	int err;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	nla = nla_nest_start_noflag(skb, OVS_KEY_ATTR_TUNNEL);
95462306a36Sopenharmony_ci	if (!nla)
95562306a36Sopenharmony_ci		return -EMSGSIZE;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	err = __ip_tun_to_nlattr(skb, output, tun_opts, swkey_tun_opts_len,
95862306a36Sopenharmony_ci				 tun_proto, mode);
95962306a36Sopenharmony_ci	if (err)
96062306a36Sopenharmony_ci		return err;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	nla_nest_end(skb, nla);
96362306a36Sopenharmony_ci	return 0;
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ciint ovs_nla_put_tunnel_info(struct sk_buff *skb,
96762306a36Sopenharmony_ci			    struct ip_tunnel_info *tun_info)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	return __ip_tun_to_nlattr(skb, &tun_info->key,
97062306a36Sopenharmony_ci				  ip_tunnel_info_opts(tun_info),
97162306a36Sopenharmony_ci				  tun_info->options_len,
97262306a36Sopenharmony_ci				  ip_tunnel_info_af(tun_info), tun_info->mode);
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic int encode_vlan_from_nlattrs(struct sw_flow_match *match,
97662306a36Sopenharmony_ci				    const struct nlattr *a[],
97762306a36Sopenharmony_ci				    bool is_mask, bool inner)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	__be16 tci = 0;
98062306a36Sopenharmony_ci	__be16 tpid = 0;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	if (a[OVS_KEY_ATTR_VLAN])
98362306a36Sopenharmony_ci		tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	if (a[OVS_KEY_ATTR_ETHERTYPE])
98662306a36Sopenharmony_ci		tpid = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	if (likely(!inner)) {
98962306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, eth.vlan.tpid, tpid, is_mask);
99062306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, eth.vlan.tci, tci, is_mask);
99162306a36Sopenharmony_ci	} else {
99262306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, eth.cvlan.tpid, tpid, is_mask);
99362306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, eth.cvlan.tci, tci, is_mask);
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci	return 0;
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic int validate_vlan_from_nlattrs(const struct sw_flow_match *match,
99962306a36Sopenharmony_ci				      u64 key_attrs, bool inner,
100062306a36Sopenharmony_ci				      const struct nlattr **a, bool log)
100162306a36Sopenharmony_ci{
100262306a36Sopenharmony_ci	__be16 tci = 0;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	if (!((key_attrs & (1 << OVS_KEY_ATTR_ETHERNET)) &&
100562306a36Sopenharmony_ci	      (key_attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) &&
100662306a36Sopenharmony_ci	       eth_type_vlan(nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE])))) {
100762306a36Sopenharmony_ci		/* Not a VLAN. */
100862306a36Sopenharmony_ci		return 0;
100962306a36Sopenharmony_ci	}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	if (!((key_attrs & (1 << OVS_KEY_ATTR_VLAN)) &&
101262306a36Sopenharmony_ci	      (key_attrs & (1 << OVS_KEY_ATTR_ENCAP)))) {
101362306a36Sopenharmony_ci		OVS_NLERR(log, "Invalid %s frame", (inner) ? "C-VLAN" : "VLAN");
101462306a36Sopenharmony_ci		return -EINVAL;
101562306a36Sopenharmony_ci	}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if (a[OVS_KEY_ATTR_VLAN])
101862306a36Sopenharmony_ci		tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	if (!(tci & htons(VLAN_CFI_MASK))) {
102162306a36Sopenharmony_ci		if (tci) {
102262306a36Sopenharmony_ci			OVS_NLERR(log, "%s TCI does not have VLAN_CFI_MASK bit set.",
102362306a36Sopenharmony_ci				  (inner) ? "C-VLAN" : "VLAN");
102462306a36Sopenharmony_ci			return -EINVAL;
102562306a36Sopenharmony_ci		} else if (nla_len(a[OVS_KEY_ATTR_ENCAP])) {
102662306a36Sopenharmony_ci			/* Corner case for truncated VLAN header. */
102762306a36Sopenharmony_ci			OVS_NLERR(log, "Truncated %s header has non-zero encap attribute.",
102862306a36Sopenharmony_ci				  (inner) ? "C-VLAN" : "VLAN");
102962306a36Sopenharmony_ci			return -EINVAL;
103062306a36Sopenharmony_ci		}
103162306a36Sopenharmony_ci	}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	return 1;
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cistatic int validate_vlan_mask_from_nlattrs(const struct sw_flow_match *match,
103762306a36Sopenharmony_ci					   u64 key_attrs, bool inner,
103862306a36Sopenharmony_ci					   const struct nlattr **a, bool log)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci	__be16 tci = 0;
104162306a36Sopenharmony_ci	__be16 tpid = 0;
104262306a36Sopenharmony_ci	bool encap_valid = !!(match->key->eth.vlan.tci &
104362306a36Sopenharmony_ci			      htons(VLAN_CFI_MASK));
104462306a36Sopenharmony_ci	bool i_encap_valid = !!(match->key->eth.cvlan.tci &
104562306a36Sopenharmony_ci				htons(VLAN_CFI_MASK));
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	if (!(key_attrs & (1 << OVS_KEY_ATTR_ENCAP))) {
104862306a36Sopenharmony_ci		/* Not a VLAN. */
104962306a36Sopenharmony_ci		return 0;
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	if ((!inner && !encap_valid) || (inner && !i_encap_valid)) {
105362306a36Sopenharmony_ci		OVS_NLERR(log, "Encap mask attribute is set for non-%s frame.",
105462306a36Sopenharmony_ci			  (inner) ? "C-VLAN" : "VLAN");
105562306a36Sopenharmony_ci		return -EINVAL;
105662306a36Sopenharmony_ci	}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	if (a[OVS_KEY_ATTR_VLAN])
105962306a36Sopenharmony_ci		tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	if (a[OVS_KEY_ATTR_ETHERTYPE])
106262306a36Sopenharmony_ci		tpid = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	if (tpid != htons(0xffff)) {
106562306a36Sopenharmony_ci		OVS_NLERR(log, "Must have an exact match on %s TPID (mask=%x).",
106662306a36Sopenharmony_ci			  (inner) ? "C-VLAN" : "VLAN", ntohs(tpid));
106762306a36Sopenharmony_ci		return -EINVAL;
106862306a36Sopenharmony_ci	}
106962306a36Sopenharmony_ci	if (!(tci & htons(VLAN_CFI_MASK))) {
107062306a36Sopenharmony_ci		OVS_NLERR(log, "%s TCI mask does not have exact match for VLAN_CFI_MASK bit.",
107162306a36Sopenharmony_ci			  (inner) ? "C-VLAN" : "VLAN");
107262306a36Sopenharmony_ci		return -EINVAL;
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	return 1;
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cistatic int __parse_vlan_from_nlattrs(struct sw_flow_match *match,
107962306a36Sopenharmony_ci				     u64 *key_attrs, bool inner,
108062306a36Sopenharmony_ci				     const struct nlattr **a, bool is_mask,
108162306a36Sopenharmony_ci				     bool log)
108262306a36Sopenharmony_ci{
108362306a36Sopenharmony_ci	int err;
108462306a36Sopenharmony_ci	const struct nlattr *encap;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	if (!is_mask)
108762306a36Sopenharmony_ci		err = validate_vlan_from_nlattrs(match, *key_attrs, inner,
108862306a36Sopenharmony_ci						 a, log);
108962306a36Sopenharmony_ci	else
109062306a36Sopenharmony_ci		err = validate_vlan_mask_from_nlattrs(match, *key_attrs, inner,
109162306a36Sopenharmony_ci						      a, log);
109262306a36Sopenharmony_ci	if (err <= 0)
109362306a36Sopenharmony_ci		return err;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	err = encode_vlan_from_nlattrs(match, a, is_mask, inner);
109662306a36Sopenharmony_ci	if (err)
109762306a36Sopenharmony_ci		return err;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	*key_attrs &= ~(1 << OVS_KEY_ATTR_ENCAP);
110062306a36Sopenharmony_ci	*key_attrs &= ~(1 << OVS_KEY_ATTR_VLAN);
110162306a36Sopenharmony_ci	*key_attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE);
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	encap = a[OVS_KEY_ATTR_ENCAP];
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	if (!is_mask)
110662306a36Sopenharmony_ci		err = parse_flow_nlattrs(encap, a, key_attrs, log);
110762306a36Sopenharmony_ci	else
110862306a36Sopenharmony_ci		err = parse_flow_mask_nlattrs(encap, a, key_attrs, log);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	return err;
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic int parse_vlan_from_nlattrs(struct sw_flow_match *match,
111462306a36Sopenharmony_ci				   u64 *key_attrs, const struct nlattr **a,
111562306a36Sopenharmony_ci				   bool is_mask, bool log)
111662306a36Sopenharmony_ci{
111762306a36Sopenharmony_ci	int err;
111862306a36Sopenharmony_ci	bool encap_valid = false;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	err = __parse_vlan_from_nlattrs(match, key_attrs, false, a,
112162306a36Sopenharmony_ci					is_mask, log);
112262306a36Sopenharmony_ci	if (err)
112362306a36Sopenharmony_ci		return err;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	encap_valid = !!(match->key->eth.vlan.tci & htons(VLAN_CFI_MASK));
112662306a36Sopenharmony_ci	if (encap_valid) {
112762306a36Sopenharmony_ci		err = __parse_vlan_from_nlattrs(match, key_attrs, true, a,
112862306a36Sopenharmony_ci						is_mask, log);
112962306a36Sopenharmony_ci		if (err)
113062306a36Sopenharmony_ci			return err;
113162306a36Sopenharmony_ci	}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	return 0;
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_cistatic int parse_eth_type_from_nlattrs(struct sw_flow_match *match,
113762306a36Sopenharmony_ci				       u64 *attrs, const struct nlattr **a,
113862306a36Sopenharmony_ci				       bool is_mask, bool log)
113962306a36Sopenharmony_ci{
114062306a36Sopenharmony_ci	__be16 eth_type;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
114362306a36Sopenharmony_ci	if (is_mask) {
114462306a36Sopenharmony_ci		/* Always exact match EtherType. */
114562306a36Sopenharmony_ci		eth_type = htons(0xffff);
114662306a36Sopenharmony_ci	} else if (!eth_proto_is_802_3(eth_type)) {
114762306a36Sopenharmony_ci		OVS_NLERR(log, "EtherType %x is less than min %x",
114862306a36Sopenharmony_ci				ntohs(eth_type), ETH_P_802_3_MIN);
114962306a36Sopenharmony_ci		return -EINVAL;
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	SW_FLOW_KEY_PUT(match, eth.type, eth_type, is_mask);
115362306a36Sopenharmony_ci	*attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE);
115462306a36Sopenharmony_ci	return 0;
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
115862306a36Sopenharmony_ci				 u64 *attrs, const struct nlattr **a,
115962306a36Sopenharmony_ci				 bool is_mask, bool log)
116062306a36Sopenharmony_ci{
116162306a36Sopenharmony_ci	u8 mac_proto = MAC_PROTO_ETHERNET;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_DP_HASH)) {
116462306a36Sopenharmony_ci		u32 hash_val = nla_get_u32(a[OVS_KEY_ATTR_DP_HASH]);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ovs_flow_hash, hash_val, is_mask);
116762306a36Sopenharmony_ci		*attrs &= ~(1 << OVS_KEY_ATTR_DP_HASH);
116862306a36Sopenharmony_ci	}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_RECIRC_ID)) {
117162306a36Sopenharmony_ci		u32 recirc_id = nla_get_u32(a[OVS_KEY_ATTR_RECIRC_ID]);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, recirc_id, recirc_id, is_mask);
117462306a36Sopenharmony_ci		*attrs &= ~(1 << OVS_KEY_ATTR_RECIRC_ID);
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_PRIORITY)) {
117862306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, phy.priority,
117962306a36Sopenharmony_ci			  nla_get_u32(a[OVS_KEY_ATTR_PRIORITY]), is_mask);
118062306a36Sopenharmony_ci		*attrs &= ~(1 << OVS_KEY_ATTR_PRIORITY);
118162306a36Sopenharmony_ci	}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_IN_PORT)) {
118462306a36Sopenharmony_ci		u32 in_port = nla_get_u32(a[OVS_KEY_ATTR_IN_PORT]);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci		if (is_mask) {
118762306a36Sopenharmony_ci			in_port = 0xffffffff; /* Always exact match in_port. */
118862306a36Sopenharmony_ci		} else if (in_port >= DP_MAX_PORTS) {
118962306a36Sopenharmony_ci			OVS_NLERR(log, "Port %d exceeds max allowable %d",
119062306a36Sopenharmony_ci				  in_port, DP_MAX_PORTS);
119162306a36Sopenharmony_ci			return -EINVAL;
119262306a36Sopenharmony_ci		}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, phy.in_port, in_port, is_mask);
119562306a36Sopenharmony_ci		*attrs &= ~(1 << OVS_KEY_ATTR_IN_PORT);
119662306a36Sopenharmony_ci	} else if (!is_mask) {
119762306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, phy.in_port, DP_MAX_PORTS, is_mask);
119862306a36Sopenharmony_ci	}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_SKB_MARK)) {
120162306a36Sopenharmony_ci		uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, phy.skb_mark, mark, is_mask);
120462306a36Sopenharmony_ci		*attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK);
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) {
120762306a36Sopenharmony_ci		if (ip_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match,
120862306a36Sopenharmony_ci				       is_mask, log) < 0)
120962306a36Sopenharmony_ci			return -EINVAL;
121062306a36Sopenharmony_ci		*attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL);
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_CT_STATE) &&
121462306a36Sopenharmony_ci	    ovs_ct_verify(net, OVS_KEY_ATTR_CT_STATE)) {
121562306a36Sopenharmony_ci		u32 ct_state = nla_get_u32(a[OVS_KEY_ATTR_CT_STATE]);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci		if (ct_state & ~CT_SUPPORTED_MASK) {
121862306a36Sopenharmony_ci			OVS_NLERR(log, "ct_state flags %08x unsupported",
121962306a36Sopenharmony_ci				  ct_state);
122062306a36Sopenharmony_ci			return -EINVAL;
122162306a36Sopenharmony_ci		}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct_state, ct_state, is_mask);
122462306a36Sopenharmony_ci		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_STATE);
122562306a36Sopenharmony_ci	}
122662306a36Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_CT_ZONE) &&
122762306a36Sopenharmony_ci	    ovs_ct_verify(net, OVS_KEY_ATTR_CT_ZONE)) {
122862306a36Sopenharmony_ci		u16 ct_zone = nla_get_u16(a[OVS_KEY_ATTR_CT_ZONE]);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct_zone, ct_zone, is_mask);
123162306a36Sopenharmony_ci		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE);
123262306a36Sopenharmony_ci	}
123362306a36Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_CT_MARK) &&
123462306a36Sopenharmony_ci	    ovs_ct_verify(net, OVS_KEY_ATTR_CT_MARK)) {
123562306a36Sopenharmony_ci		u32 mark = nla_get_u32(a[OVS_KEY_ATTR_CT_MARK]);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct.mark, mark, is_mask);
123862306a36Sopenharmony_ci		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_MARK);
123962306a36Sopenharmony_ci	}
124062306a36Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_CT_LABELS) &&
124162306a36Sopenharmony_ci	    ovs_ct_verify(net, OVS_KEY_ATTR_CT_LABELS)) {
124262306a36Sopenharmony_ci		const struct ovs_key_ct_labels *cl;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci		cl = nla_data(a[OVS_KEY_ATTR_CT_LABELS]);
124562306a36Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ct.labels, cl->ct_labels,
124662306a36Sopenharmony_ci				   sizeof(*cl), is_mask);
124762306a36Sopenharmony_ci		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_LABELS);
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci	if (*attrs & (1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4)) {
125062306a36Sopenharmony_ci		const struct ovs_key_ct_tuple_ipv4 *ct;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci		ct = nla_data(a[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4]);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv4.ct_orig.src, ct->ipv4_src, is_mask);
125562306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv4.ct_orig.dst, ct->ipv4_dst, is_mask);
125662306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct.orig_tp.src, ct->src_port, is_mask);
125762306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct.orig_tp.dst, ct->dst_port, is_mask);
125862306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct_orig_proto, ct->ipv4_proto, is_mask);
125962306a36Sopenharmony_ci		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4);
126062306a36Sopenharmony_ci	}
126162306a36Sopenharmony_ci	if (*attrs & (1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6)) {
126262306a36Sopenharmony_ci		const struct ovs_key_ct_tuple_ipv6 *ct;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci		ct = nla_data(a[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6]);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.ct_orig.src, &ct->ipv6_src,
126762306a36Sopenharmony_ci				   sizeof(match->key->ipv6.ct_orig.src),
126862306a36Sopenharmony_ci				   is_mask);
126962306a36Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.ct_orig.dst, &ct->ipv6_dst,
127062306a36Sopenharmony_ci				   sizeof(match->key->ipv6.ct_orig.dst),
127162306a36Sopenharmony_ci				   is_mask);
127262306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct.orig_tp.src, ct->src_port, is_mask);
127362306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct.orig_tp.dst, ct->dst_port, is_mask);
127462306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct_orig_proto, ct->ipv6_proto, is_mask);
127562306a36Sopenharmony_ci		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6);
127662306a36Sopenharmony_ci	}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	/* For layer 3 packets the Ethernet type is provided
127962306a36Sopenharmony_ci	 * and treated as metadata but no MAC addresses are provided.
128062306a36Sopenharmony_ci	 */
128162306a36Sopenharmony_ci	if (!(*attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) &&
128262306a36Sopenharmony_ci	    (*attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)))
128362306a36Sopenharmony_ci		mac_proto = MAC_PROTO_NONE;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	/* Always exact match mac_proto */
128662306a36Sopenharmony_ci	SW_FLOW_KEY_PUT(match, mac_proto, is_mask ? 0xff : mac_proto, is_mask);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	if (mac_proto == MAC_PROTO_NONE)
128962306a36Sopenharmony_ci		return parse_eth_type_from_nlattrs(match, attrs, a, is_mask,
129062306a36Sopenharmony_ci						   log);
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	return 0;
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ciint nsh_hdr_from_nlattr(const struct nlattr *attr,
129662306a36Sopenharmony_ci			struct nshhdr *nh, size_t size)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	struct nlattr *a;
129962306a36Sopenharmony_ci	int rem;
130062306a36Sopenharmony_ci	u8 flags = 0;
130162306a36Sopenharmony_ci	u8 ttl = 0;
130262306a36Sopenharmony_ci	int mdlen = 0;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	/* validate_nsh has check this, so we needn't do duplicate check here
130562306a36Sopenharmony_ci	 */
130662306a36Sopenharmony_ci	if (size < NSH_BASE_HDR_LEN)
130762306a36Sopenharmony_ci		return -ENOBUFS;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
131062306a36Sopenharmony_ci		int type = nla_type(a);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci		switch (type) {
131362306a36Sopenharmony_ci		case OVS_NSH_KEY_ATTR_BASE: {
131462306a36Sopenharmony_ci			const struct ovs_nsh_key_base *base = nla_data(a);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci			flags = base->flags;
131762306a36Sopenharmony_ci			ttl = base->ttl;
131862306a36Sopenharmony_ci			nh->np = base->np;
131962306a36Sopenharmony_ci			nh->mdtype = base->mdtype;
132062306a36Sopenharmony_ci			nh->path_hdr = base->path_hdr;
132162306a36Sopenharmony_ci			break;
132262306a36Sopenharmony_ci		}
132362306a36Sopenharmony_ci		case OVS_NSH_KEY_ATTR_MD1:
132462306a36Sopenharmony_ci			mdlen = nla_len(a);
132562306a36Sopenharmony_ci			if (mdlen > size - NSH_BASE_HDR_LEN)
132662306a36Sopenharmony_ci				return -ENOBUFS;
132762306a36Sopenharmony_ci			memcpy(&nh->md1, nla_data(a), mdlen);
132862306a36Sopenharmony_ci			break;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci		case OVS_NSH_KEY_ATTR_MD2:
133162306a36Sopenharmony_ci			mdlen = nla_len(a);
133262306a36Sopenharmony_ci			if (mdlen > size - NSH_BASE_HDR_LEN)
133362306a36Sopenharmony_ci				return -ENOBUFS;
133462306a36Sopenharmony_ci			memcpy(&nh->md2, nla_data(a), mdlen);
133562306a36Sopenharmony_ci			break;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci		default:
133862306a36Sopenharmony_ci			return -EINVAL;
133962306a36Sopenharmony_ci		}
134062306a36Sopenharmony_ci	}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	/* nsh header length  = NSH_BASE_HDR_LEN + mdlen */
134362306a36Sopenharmony_ci	nh->ver_flags_ttl_len = 0;
134462306a36Sopenharmony_ci	nsh_set_flags_ttl_len(nh, flags, ttl, NSH_BASE_HDR_LEN + mdlen);
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	return 0;
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ciint nsh_key_from_nlattr(const struct nlattr *attr,
135062306a36Sopenharmony_ci			struct ovs_key_nsh *nsh, struct ovs_key_nsh *nsh_mask)
135162306a36Sopenharmony_ci{
135262306a36Sopenharmony_ci	struct nlattr *a;
135362306a36Sopenharmony_ci	int rem;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	/* validate_nsh has check this, so we needn't do duplicate check here
135662306a36Sopenharmony_ci	 */
135762306a36Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
135862306a36Sopenharmony_ci		int type = nla_type(a);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci		switch (type) {
136162306a36Sopenharmony_ci		case OVS_NSH_KEY_ATTR_BASE: {
136262306a36Sopenharmony_ci			const struct ovs_nsh_key_base *base = nla_data(a);
136362306a36Sopenharmony_ci			const struct ovs_nsh_key_base *base_mask = base + 1;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci			nsh->base = *base;
136662306a36Sopenharmony_ci			nsh_mask->base = *base_mask;
136762306a36Sopenharmony_ci			break;
136862306a36Sopenharmony_ci		}
136962306a36Sopenharmony_ci		case OVS_NSH_KEY_ATTR_MD1: {
137062306a36Sopenharmony_ci			const struct ovs_nsh_key_md1 *md1 = nla_data(a);
137162306a36Sopenharmony_ci			const struct ovs_nsh_key_md1 *md1_mask = md1 + 1;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci			memcpy(nsh->context, md1->context, sizeof(*md1));
137462306a36Sopenharmony_ci			memcpy(nsh_mask->context, md1_mask->context,
137562306a36Sopenharmony_ci			       sizeof(*md1_mask));
137662306a36Sopenharmony_ci			break;
137762306a36Sopenharmony_ci		}
137862306a36Sopenharmony_ci		case OVS_NSH_KEY_ATTR_MD2:
137962306a36Sopenharmony_ci			/* Not supported yet */
138062306a36Sopenharmony_ci			return -ENOTSUPP;
138162306a36Sopenharmony_ci		default:
138262306a36Sopenharmony_ci			return -EINVAL;
138362306a36Sopenharmony_ci		}
138462306a36Sopenharmony_ci	}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	return 0;
138762306a36Sopenharmony_ci}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_cistatic int nsh_key_put_from_nlattr(const struct nlattr *attr,
139062306a36Sopenharmony_ci				   struct sw_flow_match *match, bool is_mask,
139162306a36Sopenharmony_ci				   bool is_push_nsh, bool log)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	struct nlattr *a;
139462306a36Sopenharmony_ci	int rem;
139562306a36Sopenharmony_ci	bool has_base = false;
139662306a36Sopenharmony_ci	bool has_md1 = false;
139762306a36Sopenharmony_ci	bool has_md2 = false;
139862306a36Sopenharmony_ci	u8 mdtype = 0;
139962306a36Sopenharmony_ci	int mdlen = 0;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	if (WARN_ON(is_push_nsh && is_mask))
140262306a36Sopenharmony_ci		return -EINVAL;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
140562306a36Sopenharmony_ci		int type = nla_type(a);
140662306a36Sopenharmony_ci		int i;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci		if (type > OVS_NSH_KEY_ATTR_MAX) {
140962306a36Sopenharmony_ci			OVS_NLERR(log, "nsh attr %d is out of range max %d",
141062306a36Sopenharmony_ci				  type, OVS_NSH_KEY_ATTR_MAX);
141162306a36Sopenharmony_ci			return -EINVAL;
141262306a36Sopenharmony_ci		}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci		if (!check_attr_len(nla_len(a),
141562306a36Sopenharmony_ci				    ovs_nsh_key_attr_lens[type].len)) {
141662306a36Sopenharmony_ci			OVS_NLERR(
141762306a36Sopenharmony_ci			    log,
141862306a36Sopenharmony_ci			    "nsh attr %d has unexpected len %d expected %d",
141962306a36Sopenharmony_ci			    type,
142062306a36Sopenharmony_ci			    nla_len(a),
142162306a36Sopenharmony_ci			    ovs_nsh_key_attr_lens[type].len
142262306a36Sopenharmony_ci			);
142362306a36Sopenharmony_ci			return -EINVAL;
142462306a36Sopenharmony_ci		}
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci		switch (type) {
142762306a36Sopenharmony_ci		case OVS_NSH_KEY_ATTR_BASE: {
142862306a36Sopenharmony_ci			const struct ovs_nsh_key_base *base = nla_data(a);
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci			has_base = true;
143162306a36Sopenharmony_ci			mdtype = base->mdtype;
143262306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, nsh.base.flags,
143362306a36Sopenharmony_ci					base->flags, is_mask);
143462306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, nsh.base.ttl,
143562306a36Sopenharmony_ci					base->ttl, is_mask);
143662306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, nsh.base.mdtype,
143762306a36Sopenharmony_ci					base->mdtype, is_mask);
143862306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, nsh.base.np,
143962306a36Sopenharmony_ci					base->np, is_mask);
144062306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, nsh.base.path_hdr,
144162306a36Sopenharmony_ci					base->path_hdr, is_mask);
144262306a36Sopenharmony_ci			break;
144362306a36Sopenharmony_ci		}
144462306a36Sopenharmony_ci		case OVS_NSH_KEY_ATTR_MD1: {
144562306a36Sopenharmony_ci			const struct ovs_nsh_key_md1 *md1 = nla_data(a);
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci			has_md1 = true;
144862306a36Sopenharmony_ci			for (i = 0; i < NSH_MD1_CONTEXT_SIZE; i++)
144962306a36Sopenharmony_ci				SW_FLOW_KEY_PUT(match, nsh.context[i],
145062306a36Sopenharmony_ci						md1->context[i], is_mask);
145162306a36Sopenharmony_ci			break;
145262306a36Sopenharmony_ci		}
145362306a36Sopenharmony_ci		case OVS_NSH_KEY_ATTR_MD2:
145462306a36Sopenharmony_ci			if (!is_push_nsh) /* Not supported MD type 2 yet */
145562306a36Sopenharmony_ci				return -ENOTSUPP;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci			has_md2 = true;
145862306a36Sopenharmony_ci			mdlen = nla_len(a);
145962306a36Sopenharmony_ci			if (mdlen > NSH_CTX_HDRS_MAX_LEN || mdlen <= 0) {
146062306a36Sopenharmony_ci				OVS_NLERR(
146162306a36Sopenharmony_ci				    log,
146262306a36Sopenharmony_ci				    "Invalid MD length %d for MD type %d",
146362306a36Sopenharmony_ci				    mdlen,
146462306a36Sopenharmony_ci				    mdtype
146562306a36Sopenharmony_ci				);
146662306a36Sopenharmony_ci				return -EINVAL;
146762306a36Sopenharmony_ci			}
146862306a36Sopenharmony_ci			break;
146962306a36Sopenharmony_ci		default:
147062306a36Sopenharmony_ci			OVS_NLERR(log, "Unknown nsh attribute %d",
147162306a36Sopenharmony_ci				  type);
147262306a36Sopenharmony_ci			return -EINVAL;
147362306a36Sopenharmony_ci		}
147462306a36Sopenharmony_ci	}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	if (rem > 0) {
147762306a36Sopenharmony_ci		OVS_NLERR(log, "nsh attribute has %d unknown bytes.", rem);
147862306a36Sopenharmony_ci		return -EINVAL;
147962306a36Sopenharmony_ci	}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	if (has_md1 && has_md2) {
148262306a36Sopenharmony_ci		OVS_NLERR(
148362306a36Sopenharmony_ci		    1,
148462306a36Sopenharmony_ci		    "invalid nsh attribute: md1 and md2 are exclusive."
148562306a36Sopenharmony_ci		);
148662306a36Sopenharmony_ci		return -EINVAL;
148762306a36Sopenharmony_ci	}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	if (!is_mask) {
149062306a36Sopenharmony_ci		if ((has_md1 && mdtype != NSH_M_TYPE1) ||
149162306a36Sopenharmony_ci		    (has_md2 && mdtype != NSH_M_TYPE2)) {
149262306a36Sopenharmony_ci			OVS_NLERR(1, "nsh attribute has unmatched MD type %d.",
149362306a36Sopenharmony_ci				  mdtype);
149462306a36Sopenharmony_ci			return -EINVAL;
149562306a36Sopenharmony_ci		}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci		if (is_push_nsh &&
149862306a36Sopenharmony_ci		    (!has_base || (!has_md1 && !has_md2))) {
149962306a36Sopenharmony_ci			OVS_NLERR(
150062306a36Sopenharmony_ci			    1,
150162306a36Sopenharmony_ci			    "push_nsh: missing base or metadata attributes"
150262306a36Sopenharmony_ci			);
150362306a36Sopenharmony_ci			return -EINVAL;
150462306a36Sopenharmony_ci		}
150562306a36Sopenharmony_ci	}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	return 0;
150862306a36Sopenharmony_ci}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_cistatic int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
151162306a36Sopenharmony_ci				u64 attrs, const struct nlattr **a,
151262306a36Sopenharmony_ci				bool is_mask, bool log)
151362306a36Sopenharmony_ci{
151462306a36Sopenharmony_ci	int err;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	err = metadata_from_nlattrs(net, match, &attrs, a, is_mask, log);
151762306a36Sopenharmony_ci	if (err)
151862306a36Sopenharmony_ci		return err;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_ETHERNET)) {
152162306a36Sopenharmony_ci		const struct ovs_key_ethernet *eth_key;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci		eth_key = nla_data(a[OVS_KEY_ATTR_ETHERNET]);
152462306a36Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, eth.src,
152562306a36Sopenharmony_ci				eth_key->eth_src, ETH_ALEN, is_mask);
152662306a36Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, eth.dst,
152762306a36Sopenharmony_ci				eth_key->eth_dst, ETH_ALEN, is_mask);
152862306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_ETHERNET);
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci		if (attrs & (1 << OVS_KEY_ATTR_VLAN)) {
153162306a36Sopenharmony_ci			/* VLAN attribute is always parsed before getting here since it
153262306a36Sopenharmony_ci			 * may occur multiple times.
153362306a36Sopenharmony_ci			 */
153462306a36Sopenharmony_ci			OVS_NLERR(log, "VLAN attribute unexpected.");
153562306a36Sopenharmony_ci			return -EINVAL;
153662306a36Sopenharmony_ci		}
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci		if (attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) {
153962306a36Sopenharmony_ci			err = parse_eth_type_from_nlattrs(match, &attrs, a, is_mask,
154062306a36Sopenharmony_ci							  log);
154162306a36Sopenharmony_ci			if (err)
154262306a36Sopenharmony_ci				return err;
154362306a36Sopenharmony_ci		} else if (!is_mask) {
154462306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2), is_mask);
154562306a36Sopenharmony_ci		}
154662306a36Sopenharmony_ci	} else if (!match->key->eth.type) {
154762306a36Sopenharmony_ci		OVS_NLERR(log, "Either Ethernet header or EtherType is required.");
154862306a36Sopenharmony_ci		return -EINVAL;
154962306a36Sopenharmony_ci	}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_IPV4)) {
155262306a36Sopenharmony_ci		const struct ovs_key_ipv4 *ipv4_key;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci		ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]);
155562306a36Sopenharmony_ci		if (!is_mask && ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) {
155662306a36Sopenharmony_ci			OVS_NLERR(log, "IPv4 frag type %d is out of range max %d",
155762306a36Sopenharmony_ci				  ipv4_key->ipv4_frag, OVS_FRAG_TYPE_MAX);
155862306a36Sopenharmony_ci			return -EINVAL;
155962306a36Sopenharmony_ci		}
156062306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.proto,
156162306a36Sopenharmony_ci				ipv4_key->ipv4_proto, is_mask);
156262306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.tos,
156362306a36Sopenharmony_ci				ipv4_key->ipv4_tos, is_mask);
156462306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.ttl,
156562306a36Sopenharmony_ci				ipv4_key->ipv4_ttl, is_mask);
156662306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.frag,
156762306a36Sopenharmony_ci				ipv4_key->ipv4_frag, is_mask);
156862306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv4.addr.src,
156962306a36Sopenharmony_ci				ipv4_key->ipv4_src, is_mask);
157062306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv4.addr.dst,
157162306a36Sopenharmony_ci				ipv4_key->ipv4_dst, is_mask);
157262306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_IPV4);
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_IPV6)) {
157662306a36Sopenharmony_ci		const struct ovs_key_ipv6 *ipv6_key;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci		ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]);
157962306a36Sopenharmony_ci		if (!is_mask && ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) {
158062306a36Sopenharmony_ci			OVS_NLERR(log, "IPv6 frag type %d is out of range max %d",
158162306a36Sopenharmony_ci				  ipv6_key->ipv6_frag, OVS_FRAG_TYPE_MAX);
158262306a36Sopenharmony_ci			return -EINVAL;
158362306a36Sopenharmony_ci		}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci		if (!is_mask && ipv6_key->ipv6_label & htonl(0xFFF00000)) {
158662306a36Sopenharmony_ci			OVS_NLERR(log, "IPv6 flow label %x is out of range (max=%x)",
158762306a36Sopenharmony_ci				  ntohl(ipv6_key->ipv6_label), (1 << 20) - 1);
158862306a36Sopenharmony_ci			return -EINVAL;
158962306a36Sopenharmony_ci		}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv6.label,
159262306a36Sopenharmony_ci				ipv6_key->ipv6_label, is_mask);
159362306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.proto,
159462306a36Sopenharmony_ci				ipv6_key->ipv6_proto, is_mask);
159562306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.tos,
159662306a36Sopenharmony_ci				ipv6_key->ipv6_tclass, is_mask);
159762306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.ttl,
159862306a36Sopenharmony_ci				ipv6_key->ipv6_hlimit, is_mask);
159962306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.frag,
160062306a36Sopenharmony_ci				ipv6_key->ipv6_frag, is_mask);
160162306a36Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.addr.src,
160262306a36Sopenharmony_ci				ipv6_key->ipv6_src,
160362306a36Sopenharmony_ci				sizeof(match->key->ipv6.addr.src),
160462306a36Sopenharmony_ci				is_mask);
160562306a36Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.addr.dst,
160662306a36Sopenharmony_ci				ipv6_key->ipv6_dst,
160762306a36Sopenharmony_ci				sizeof(match->key->ipv6.addr.dst),
160862306a36Sopenharmony_ci				is_mask);
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_IPV6);
161162306a36Sopenharmony_ci	}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	if (attrs & (1ULL << OVS_KEY_ATTR_IPV6_EXTHDRS)) {
161462306a36Sopenharmony_ci		const struct ovs_key_ipv6_exthdrs *ipv6_exthdrs_key;
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci		ipv6_exthdrs_key = nla_data(a[OVS_KEY_ATTR_IPV6_EXTHDRS]);
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv6.exthdrs,
161962306a36Sopenharmony_ci				ipv6_exthdrs_key->hdrs, is_mask);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci		attrs &= ~(1ULL << OVS_KEY_ATTR_IPV6_EXTHDRS);
162262306a36Sopenharmony_ci	}
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_ARP)) {
162562306a36Sopenharmony_ci		const struct ovs_key_arp *arp_key;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci		arp_key = nla_data(a[OVS_KEY_ATTR_ARP]);
162862306a36Sopenharmony_ci		if (!is_mask && (arp_key->arp_op & htons(0xff00))) {
162962306a36Sopenharmony_ci			OVS_NLERR(log, "Unknown ARP opcode (opcode=%d).",
163062306a36Sopenharmony_ci				  arp_key->arp_op);
163162306a36Sopenharmony_ci			return -EINVAL;
163262306a36Sopenharmony_ci		}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv4.addr.src,
163562306a36Sopenharmony_ci				arp_key->arp_sip, is_mask);
163662306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv4.addr.dst,
163762306a36Sopenharmony_ci			arp_key->arp_tip, is_mask);
163862306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.proto,
163962306a36Sopenharmony_ci				ntohs(arp_key->arp_op), is_mask);
164062306a36Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv4.arp.sha,
164162306a36Sopenharmony_ci				arp_key->arp_sha, ETH_ALEN, is_mask);
164262306a36Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv4.arp.tha,
164362306a36Sopenharmony_ci				arp_key->arp_tha, ETH_ALEN, is_mask);
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_ARP);
164662306a36Sopenharmony_ci	}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_NSH)) {
164962306a36Sopenharmony_ci		if (nsh_key_put_from_nlattr(a[OVS_KEY_ATTR_NSH], match,
165062306a36Sopenharmony_ci					    is_mask, false, log) < 0)
165162306a36Sopenharmony_ci			return -EINVAL;
165262306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_NSH);
165362306a36Sopenharmony_ci	}
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_MPLS)) {
165662306a36Sopenharmony_ci		const struct ovs_key_mpls *mpls_key;
165762306a36Sopenharmony_ci		u32 hdr_len;
165862306a36Sopenharmony_ci		u32 label_count, label_count_mask, i;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci		mpls_key = nla_data(a[OVS_KEY_ATTR_MPLS]);
166162306a36Sopenharmony_ci		hdr_len = nla_len(a[OVS_KEY_ATTR_MPLS]);
166262306a36Sopenharmony_ci		label_count = hdr_len / sizeof(struct ovs_key_mpls);
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci		if (label_count == 0 || label_count > MPLS_LABEL_DEPTH ||
166562306a36Sopenharmony_ci		    hdr_len % sizeof(struct ovs_key_mpls))
166662306a36Sopenharmony_ci			return -EINVAL;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci		label_count_mask =  GENMASK(label_count - 1, 0);
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci		for (i = 0 ; i < label_count; i++)
167162306a36Sopenharmony_ci			SW_FLOW_KEY_PUT(match, mpls.lse[i],
167262306a36Sopenharmony_ci					mpls_key[i].mpls_lse, is_mask);
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, mpls.num_labels_mask,
167562306a36Sopenharmony_ci				label_count_mask, is_mask);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_MPLS);
167862306a36Sopenharmony_ci	 }
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_TCP)) {
168162306a36Sopenharmony_ci		const struct ovs_key_tcp *tcp_key;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci		tcp_key = nla_data(a[OVS_KEY_ATTR_TCP]);
168462306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.src, tcp_key->tcp_src, is_mask);
168562306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.dst, tcp_key->tcp_dst, is_mask);
168662306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_TCP);
168762306a36Sopenharmony_ci	}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_TCP_FLAGS)) {
169062306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.flags,
169162306a36Sopenharmony_ci				nla_get_be16(a[OVS_KEY_ATTR_TCP_FLAGS]),
169262306a36Sopenharmony_ci				is_mask);
169362306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_TCP_FLAGS);
169462306a36Sopenharmony_ci	}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_UDP)) {
169762306a36Sopenharmony_ci		const struct ovs_key_udp *udp_key;
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci		udp_key = nla_data(a[OVS_KEY_ATTR_UDP]);
170062306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.src, udp_key->udp_src, is_mask);
170162306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.dst, udp_key->udp_dst, is_mask);
170262306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_UDP);
170362306a36Sopenharmony_ci	}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_SCTP)) {
170662306a36Sopenharmony_ci		const struct ovs_key_sctp *sctp_key;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci		sctp_key = nla_data(a[OVS_KEY_ATTR_SCTP]);
170962306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.src, sctp_key->sctp_src, is_mask);
171062306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.dst, sctp_key->sctp_dst, is_mask);
171162306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_SCTP);
171262306a36Sopenharmony_ci	}
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_ICMP)) {
171562306a36Sopenharmony_ci		const struct ovs_key_icmp *icmp_key;
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci		icmp_key = nla_data(a[OVS_KEY_ATTR_ICMP]);
171862306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.src,
171962306a36Sopenharmony_ci				htons(icmp_key->icmp_type), is_mask);
172062306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.dst,
172162306a36Sopenharmony_ci				htons(icmp_key->icmp_code), is_mask);
172262306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_ICMP);
172362306a36Sopenharmony_ci	}
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_ICMPV6)) {
172662306a36Sopenharmony_ci		const struct ovs_key_icmpv6 *icmpv6_key;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci		icmpv6_key = nla_data(a[OVS_KEY_ATTR_ICMPV6]);
172962306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.src,
173062306a36Sopenharmony_ci				htons(icmpv6_key->icmpv6_type), is_mask);
173162306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.dst,
173262306a36Sopenharmony_ci				htons(icmpv6_key->icmpv6_code), is_mask);
173362306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_ICMPV6);
173462306a36Sopenharmony_ci	}
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_ND)) {
173762306a36Sopenharmony_ci		const struct ovs_key_nd *nd_key;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci		nd_key = nla_data(a[OVS_KEY_ATTR_ND]);
174062306a36Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.nd.target,
174162306a36Sopenharmony_ci			nd_key->nd_target,
174262306a36Sopenharmony_ci			sizeof(match->key->ipv6.nd.target),
174362306a36Sopenharmony_ci			is_mask);
174462306a36Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.nd.sll,
174562306a36Sopenharmony_ci			nd_key->nd_sll, ETH_ALEN, is_mask);
174662306a36Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.nd.tll,
174762306a36Sopenharmony_ci				nd_key->nd_tll, ETH_ALEN, is_mask);
174862306a36Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_ND);
174962306a36Sopenharmony_ci	}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	if (attrs != 0) {
175262306a36Sopenharmony_ci		OVS_NLERR(log, "Unknown key attributes %llx",
175362306a36Sopenharmony_ci			  (unsigned long long)attrs);
175462306a36Sopenharmony_ci		return -EINVAL;
175562306a36Sopenharmony_ci	}
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	return 0;
175862306a36Sopenharmony_ci}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_cistatic void nlattr_set(struct nlattr *attr, u8 val,
176162306a36Sopenharmony_ci		       const struct ovs_len_tbl *tbl)
176262306a36Sopenharmony_ci{
176362306a36Sopenharmony_ci	struct nlattr *nla;
176462306a36Sopenharmony_ci	int rem;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	/* The nlattr stream should already have been validated */
176762306a36Sopenharmony_ci	nla_for_each_nested(nla, attr, rem) {
176862306a36Sopenharmony_ci		if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED)
176962306a36Sopenharmony_ci			nlattr_set(nla, val, tbl[nla_type(nla)].next ? : tbl);
177062306a36Sopenharmony_ci		else
177162306a36Sopenharmony_ci			memset(nla_data(nla), val, nla_len(nla));
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci		if (nla_type(nla) == OVS_KEY_ATTR_CT_STATE)
177462306a36Sopenharmony_ci			*(u32 *)nla_data(nla) &= CT_SUPPORTED_MASK;
177562306a36Sopenharmony_ci	}
177662306a36Sopenharmony_ci}
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_cistatic void mask_set_nlattr(struct nlattr *attr, u8 val)
177962306a36Sopenharmony_ci{
178062306a36Sopenharmony_ci	nlattr_set(attr, val, ovs_key_lens);
178162306a36Sopenharmony_ci}
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci/**
178462306a36Sopenharmony_ci * ovs_nla_get_match - parses Netlink attributes into a flow key and
178562306a36Sopenharmony_ci * mask. In case the 'mask' is NULL, the flow is treated as exact match
178662306a36Sopenharmony_ci * flow. Otherwise, it is treated as a wildcarded flow, except the mask
178762306a36Sopenharmony_ci * does not include any don't care bit.
178862306a36Sopenharmony_ci * @net: Used to determine per-namespace field support.
178962306a36Sopenharmony_ci * @match: receives the extracted flow match information.
179062306a36Sopenharmony_ci * @nla_key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute
179162306a36Sopenharmony_ci * sequence. The fields should of the packet that triggered the creation
179262306a36Sopenharmony_ci * of this flow.
179362306a36Sopenharmony_ci * @nla_mask: Optional. Netlink attribute holding nested %OVS_KEY_ATTR_*
179462306a36Sopenharmony_ci * Netlink attribute specifies the mask field of the wildcarded flow.
179562306a36Sopenharmony_ci * @log: Boolean to allow kernel error logging.  Normally true, but when
179662306a36Sopenharmony_ci * probing for feature compatibility this should be passed in as false to
179762306a36Sopenharmony_ci * suppress unnecessary error logging.
179862306a36Sopenharmony_ci */
179962306a36Sopenharmony_ciint ovs_nla_get_match(struct net *net, struct sw_flow_match *match,
180062306a36Sopenharmony_ci		      const struct nlattr *nla_key,
180162306a36Sopenharmony_ci		      const struct nlattr *nla_mask,
180262306a36Sopenharmony_ci		      bool log)
180362306a36Sopenharmony_ci{
180462306a36Sopenharmony_ci	const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
180562306a36Sopenharmony_ci	struct nlattr *newmask = NULL;
180662306a36Sopenharmony_ci	u64 key_attrs = 0;
180762306a36Sopenharmony_ci	u64 mask_attrs = 0;
180862306a36Sopenharmony_ci	int err;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	err = parse_flow_nlattrs(nla_key, a, &key_attrs, log);
181162306a36Sopenharmony_ci	if (err)
181262306a36Sopenharmony_ci		return err;
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	err = parse_vlan_from_nlattrs(match, &key_attrs, a, false, log);
181562306a36Sopenharmony_ci	if (err)
181662306a36Sopenharmony_ci		return err;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	err = ovs_key_from_nlattrs(net, match, key_attrs, a, false, log);
181962306a36Sopenharmony_ci	if (err)
182062306a36Sopenharmony_ci		return err;
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	if (match->mask) {
182362306a36Sopenharmony_ci		if (!nla_mask) {
182462306a36Sopenharmony_ci			/* Create an exact match mask. We need to set to 0xff
182562306a36Sopenharmony_ci			 * all the 'match->mask' fields that have been touched
182662306a36Sopenharmony_ci			 * in 'match->key'. We cannot simply memset
182762306a36Sopenharmony_ci			 * 'match->mask', because padding bytes and fields not
182862306a36Sopenharmony_ci			 * specified in 'match->key' should be left to 0.
182962306a36Sopenharmony_ci			 * Instead, we use a stream of netlink attributes,
183062306a36Sopenharmony_ci			 * copied from 'key' and set to 0xff.
183162306a36Sopenharmony_ci			 * ovs_key_from_nlattrs() will take care of filling
183262306a36Sopenharmony_ci			 * 'match->mask' appropriately.
183362306a36Sopenharmony_ci			 */
183462306a36Sopenharmony_ci			newmask = kmemdup(nla_key,
183562306a36Sopenharmony_ci					  nla_total_size(nla_len(nla_key)),
183662306a36Sopenharmony_ci					  GFP_KERNEL);
183762306a36Sopenharmony_ci			if (!newmask)
183862306a36Sopenharmony_ci				return -ENOMEM;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci			mask_set_nlattr(newmask, 0xff);
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci			/* The userspace does not send tunnel attributes that
184362306a36Sopenharmony_ci			 * are 0, but we should not wildcard them nonetheless.
184462306a36Sopenharmony_ci			 */
184562306a36Sopenharmony_ci			if (match->key->tun_proto)
184662306a36Sopenharmony_ci				SW_FLOW_KEY_MEMSET_FIELD(match, tun_key,
184762306a36Sopenharmony_ci							 0xff, true);
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci			nla_mask = newmask;
185062306a36Sopenharmony_ci		}
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci		err = parse_flow_mask_nlattrs(nla_mask, a, &mask_attrs, log);
185362306a36Sopenharmony_ci		if (err)
185462306a36Sopenharmony_ci			goto free_newmask;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci		/* Always match on tci. */
185762306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, eth.vlan.tci, htons(0xffff), true);
185862306a36Sopenharmony_ci		SW_FLOW_KEY_PUT(match, eth.cvlan.tci, htons(0xffff), true);
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci		err = parse_vlan_from_nlattrs(match, &mask_attrs, a, true, log);
186162306a36Sopenharmony_ci		if (err)
186262306a36Sopenharmony_ci			goto free_newmask;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci		err = ovs_key_from_nlattrs(net, match, mask_attrs, a, true,
186562306a36Sopenharmony_ci					   log);
186662306a36Sopenharmony_ci		if (err)
186762306a36Sopenharmony_ci			goto free_newmask;
186862306a36Sopenharmony_ci	}
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	if (!match_validate(match, key_attrs, mask_attrs, log))
187162306a36Sopenharmony_ci		err = -EINVAL;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_cifree_newmask:
187462306a36Sopenharmony_ci	kfree(newmask);
187562306a36Sopenharmony_ci	return err;
187662306a36Sopenharmony_ci}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_cistatic size_t get_ufid_len(const struct nlattr *attr, bool log)
187962306a36Sopenharmony_ci{
188062306a36Sopenharmony_ci	size_t len;
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	if (!attr)
188362306a36Sopenharmony_ci		return 0;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	len = nla_len(attr);
188662306a36Sopenharmony_ci	if (len < 1 || len > MAX_UFID_LENGTH) {
188762306a36Sopenharmony_ci		OVS_NLERR(log, "ufid size %u bytes exceeds the range (1, %d)",
188862306a36Sopenharmony_ci			  nla_len(attr), MAX_UFID_LENGTH);
188962306a36Sopenharmony_ci		return 0;
189062306a36Sopenharmony_ci	}
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	return len;
189362306a36Sopenharmony_ci}
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci/* Initializes 'flow->ufid', returning true if 'attr' contains a valid UFID,
189662306a36Sopenharmony_ci * or false otherwise.
189762306a36Sopenharmony_ci */
189862306a36Sopenharmony_cibool ovs_nla_get_ufid(struct sw_flow_id *sfid, const struct nlattr *attr,
189962306a36Sopenharmony_ci		      bool log)
190062306a36Sopenharmony_ci{
190162306a36Sopenharmony_ci	sfid->ufid_len = get_ufid_len(attr, log);
190262306a36Sopenharmony_ci	if (sfid->ufid_len)
190362306a36Sopenharmony_ci		memcpy(sfid->ufid, nla_data(attr), sfid->ufid_len);
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	return sfid->ufid_len;
190662306a36Sopenharmony_ci}
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ciint ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid,
190962306a36Sopenharmony_ci			   const struct sw_flow_key *key, bool log)
191062306a36Sopenharmony_ci{
191162306a36Sopenharmony_ci	struct sw_flow_key *new_key;
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	if (ovs_nla_get_ufid(sfid, ufid, log))
191462306a36Sopenharmony_ci		return 0;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	/* If UFID was not provided, use unmasked key. */
191762306a36Sopenharmony_ci	new_key = kmalloc(sizeof(*new_key), GFP_KERNEL);
191862306a36Sopenharmony_ci	if (!new_key)
191962306a36Sopenharmony_ci		return -ENOMEM;
192062306a36Sopenharmony_ci	memcpy(new_key, key, sizeof(*key));
192162306a36Sopenharmony_ci	sfid->unmasked_key = new_key;
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	return 0;
192462306a36Sopenharmony_ci}
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ciu32 ovs_nla_get_ufid_flags(const struct nlattr *attr)
192762306a36Sopenharmony_ci{
192862306a36Sopenharmony_ci	return attr ? nla_get_u32(attr) : 0;
192962306a36Sopenharmony_ci}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci/**
193262306a36Sopenharmony_ci * ovs_nla_get_flow_metadata - parses Netlink attributes into a flow key.
193362306a36Sopenharmony_ci * @net: Network namespace.
193462306a36Sopenharmony_ci * @key: Receives extracted in_port, priority, tun_key, skb_mark and conntrack
193562306a36Sopenharmony_ci * metadata.
193662306a36Sopenharmony_ci * @a: Array of netlink attributes holding parsed %OVS_KEY_ATTR_* Netlink
193762306a36Sopenharmony_ci * attributes.
193862306a36Sopenharmony_ci * @attrs: Bit mask for the netlink attributes included in @a.
193962306a36Sopenharmony_ci * @log: Boolean to allow kernel error logging.  Normally true, but when
194062306a36Sopenharmony_ci * probing for feature compatibility this should be passed in as false to
194162306a36Sopenharmony_ci * suppress unnecessary error logging.
194262306a36Sopenharmony_ci *
194362306a36Sopenharmony_ci * This parses a series of Netlink attributes that form a flow key, which must
194462306a36Sopenharmony_ci * take the same form accepted by flow_from_nlattrs(), but only enough of it to
194562306a36Sopenharmony_ci * get the metadata, that is, the parts of the flow key that cannot be
194662306a36Sopenharmony_ci * extracted from the packet itself.
194762306a36Sopenharmony_ci *
194862306a36Sopenharmony_ci * This must be called before the packet key fields are filled in 'key'.
194962306a36Sopenharmony_ci */
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ciint ovs_nla_get_flow_metadata(struct net *net,
195262306a36Sopenharmony_ci			      const struct nlattr *a[OVS_KEY_ATTR_MAX + 1],
195362306a36Sopenharmony_ci			      u64 attrs, struct sw_flow_key *key, bool log)
195462306a36Sopenharmony_ci{
195562306a36Sopenharmony_ci	struct sw_flow_match match;
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	memset(&match, 0, sizeof(match));
195862306a36Sopenharmony_ci	match.key = key;
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	key->ct_state = 0;
196162306a36Sopenharmony_ci	key->ct_zone = 0;
196262306a36Sopenharmony_ci	key->ct_orig_proto = 0;
196362306a36Sopenharmony_ci	memset(&key->ct, 0, sizeof(key->ct));
196462306a36Sopenharmony_ci	memset(&key->ipv4.ct_orig, 0, sizeof(key->ipv4.ct_orig));
196562306a36Sopenharmony_ci	memset(&key->ipv6.ct_orig, 0, sizeof(key->ipv6.ct_orig));
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	key->phy.in_port = DP_MAX_PORTS;
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	return metadata_from_nlattrs(net, &match, &attrs, a, false, log);
197062306a36Sopenharmony_ci}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_cistatic int ovs_nla_put_vlan(struct sk_buff *skb, const struct vlan_head *vh,
197362306a36Sopenharmony_ci			    bool is_mask)
197462306a36Sopenharmony_ci{
197562306a36Sopenharmony_ci	__be16 eth_type = !is_mask ? vh->tpid : htons(0xffff);
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, eth_type) ||
197862306a36Sopenharmony_ci	    nla_put_be16(skb, OVS_KEY_ATTR_VLAN, vh->tci))
197962306a36Sopenharmony_ci		return -EMSGSIZE;
198062306a36Sopenharmony_ci	return 0;
198162306a36Sopenharmony_ci}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_cistatic int nsh_key_to_nlattr(const struct ovs_key_nsh *nsh, bool is_mask,
198462306a36Sopenharmony_ci			     struct sk_buff *skb)
198562306a36Sopenharmony_ci{
198662306a36Sopenharmony_ci	struct nlattr *start;
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	start = nla_nest_start_noflag(skb, OVS_KEY_ATTR_NSH);
198962306a36Sopenharmony_ci	if (!start)
199062306a36Sopenharmony_ci		return -EMSGSIZE;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	if (nla_put(skb, OVS_NSH_KEY_ATTR_BASE, sizeof(nsh->base), &nsh->base))
199362306a36Sopenharmony_ci		goto nla_put_failure;
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	if (is_mask || nsh->base.mdtype == NSH_M_TYPE1) {
199662306a36Sopenharmony_ci		if (nla_put(skb, OVS_NSH_KEY_ATTR_MD1,
199762306a36Sopenharmony_ci			    sizeof(nsh->context), nsh->context))
199862306a36Sopenharmony_ci			goto nla_put_failure;
199962306a36Sopenharmony_ci	}
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	/* Don't support MD type 2 yet */
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	nla_nest_end(skb, start);
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	return 0;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_cinla_put_failure:
200862306a36Sopenharmony_ci	return -EMSGSIZE;
200962306a36Sopenharmony_ci}
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_cistatic int __ovs_nla_put_key(const struct sw_flow_key *swkey,
201262306a36Sopenharmony_ci			     const struct sw_flow_key *output, bool is_mask,
201362306a36Sopenharmony_ci			     struct sk_buff *skb)
201462306a36Sopenharmony_ci{
201562306a36Sopenharmony_ci	struct ovs_key_ethernet *eth_key;
201662306a36Sopenharmony_ci	struct nlattr *nla;
201762306a36Sopenharmony_ci	struct nlattr *encap = NULL;
201862306a36Sopenharmony_ci	struct nlattr *in_encap = NULL;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	if (nla_put_u32(skb, OVS_KEY_ATTR_RECIRC_ID, output->recirc_id))
202162306a36Sopenharmony_ci		goto nla_put_failure;
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	if (nla_put_u32(skb, OVS_KEY_ATTR_DP_HASH, output->ovs_flow_hash))
202462306a36Sopenharmony_ci		goto nla_put_failure;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority))
202762306a36Sopenharmony_ci		goto nla_put_failure;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	if ((swkey->tun_proto || is_mask)) {
203062306a36Sopenharmony_ci		const void *opts = NULL;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci		if (output->tun_key.tun_flags & TUNNEL_OPTIONS_PRESENT)
203362306a36Sopenharmony_ci			opts = TUN_METADATA_OPTS(output, swkey->tun_opts_len);
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci		if (ip_tun_to_nlattr(skb, &output->tun_key, opts,
203662306a36Sopenharmony_ci				     swkey->tun_opts_len, swkey->tun_proto, 0))
203762306a36Sopenharmony_ci			goto nla_put_failure;
203862306a36Sopenharmony_ci	}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	if (swkey->phy.in_port == DP_MAX_PORTS) {
204162306a36Sopenharmony_ci		if (is_mask && (output->phy.in_port == 0xffff))
204262306a36Sopenharmony_ci			if (nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, 0xffffffff))
204362306a36Sopenharmony_ci				goto nla_put_failure;
204462306a36Sopenharmony_ci	} else {
204562306a36Sopenharmony_ci		u16 upper_u16;
204662306a36Sopenharmony_ci		upper_u16 = !is_mask ? 0 : 0xffff;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci		if (nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT,
204962306a36Sopenharmony_ci				(upper_u16 << 16) | output->phy.in_port))
205062306a36Sopenharmony_ci			goto nla_put_failure;
205162306a36Sopenharmony_ci	}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	if (nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, output->phy.skb_mark))
205462306a36Sopenharmony_ci		goto nla_put_failure;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	if (ovs_ct_put_key(swkey, output, skb))
205762306a36Sopenharmony_ci		goto nla_put_failure;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	if (ovs_key_mac_proto(swkey) == MAC_PROTO_ETHERNET) {
206062306a36Sopenharmony_ci		nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
206162306a36Sopenharmony_ci		if (!nla)
206262306a36Sopenharmony_ci			goto nla_put_failure;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci		eth_key = nla_data(nla);
206562306a36Sopenharmony_ci		ether_addr_copy(eth_key->eth_src, output->eth.src);
206662306a36Sopenharmony_ci		ether_addr_copy(eth_key->eth_dst, output->eth.dst);
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci		if (swkey->eth.vlan.tci || eth_type_vlan(swkey->eth.type)) {
206962306a36Sopenharmony_ci			if (ovs_nla_put_vlan(skb, &output->eth.vlan, is_mask))
207062306a36Sopenharmony_ci				goto nla_put_failure;
207162306a36Sopenharmony_ci			encap = nla_nest_start_noflag(skb, OVS_KEY_ATTR_ENCAP);
207262306a36Sopenharmony_ci			if (!swkey->eth.vlan.tci)
207362306a36Sopenharmony_ci				goto unencap;
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci			if (swkey->eth.cvlan.tci || eth_type_vlan(swkey->eth.type)) {
207662306a36Sopenharmony_ci				if (ovs_nla_put_vlan(skb, &output->eth.cvlan, is_mask))
207762306a36Sopenharmony_ci					goto nla_put_failure;
207862306a36Sopenharmony_ci				in_encap = nla_nest_start_noflag(skb,
207962306a36Sopenharmony_ci								 OVS_KEY_ATTR_ENCAP);
208062306a36Sopenharmony_ci				if (!swkey->eth.cvlan.tci)
208162306a36Sopenharmony_ci					goto unencap;
208262306a36Sopenharmony_ci			}
208362306a36Sopenharmony_ci		}
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci		if (swkey->eth.type == htons(ETH_P_802_2)) {
208662306a36Sopenharmony_ci			/*
208762306a36Sopenharmony_ci			* Ethertype 802.2 is represented in the netlink with omitted
208862306a36Sopenharmony_ci			* OVS_KEY_ATTR_ETHERTYPE in the flow key attribute, and
208962306a36Sopenharmony_ci			* 0xffff in the mask attribute.  Ethertype can also
209062306a36Sopenharmony_ci			* be wildcarded.
209162306a36Sopenharmony_ci			*/
209262306a36Sopenharmony_ci			if (is_mask && output->eth.type)
209362306a36Sopenharmony_ci				if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE,
209462306a36Sopenharmony_ci							output->eth.type))
209562306a36Sopenharmony_ci					goto nla_put_failure;
209662306a36Sopenharmony_ci			goto unencap;
209762306a36Sopenharmony_ci		}
209862306a36Sopenharmony_ci	}
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, output->eth.type))
210162306a36Sopenharmony_ci		goto nla_put_failure;
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	if (eth_type_vlan(swkey->eth.type)) {
210462306a36Sopenharmony_ci		/* There are 3 VLAN tags, we don't know anything about the rest
210562306a36Sopenharmony_ci		 * of the packet, so truncate here.
210662306a36Sopenharmony_ci		 */
210762306a36Sopenharmony_ci		WARN_ON_ONCE(!(encap && in_encap));
210862306a36Sopenharmony_ci		goto unencap;
210962306a36Sopenharmony_ci	}
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	if (swkey->eth.type == htons(ETH_P_IP)) {
211262306a36Sopenharmony_ci		struct ovs_key_ipv4 *ipv4_key;
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci		nla = nla_reserve(skb, OVS_KEY_ATTR_IPV4, sizeof(*ipv4_key));
211562306a36Sopenharmony_ci		if (!nla)
211662306a36Sopenharmony_ci			goto nla_put_failure;
211762306a36Sopenharmony_ci		ipv4_key = nla_data(nla);
211862306a36Sopenharmony_ci		ipv4_key->ipv4_src = output->ipv4.addr.src;
211962306a36Sopenharmony_ci		ipv4_key->ipv4_dst = output->ipv4.addr.dst;
212062306a36Sopenharmony_ci		ipv4_key->ipv4_proto = output->ip.proto;
212162306a36Sopenharmony_ci		ipv4_key->ipv4_tos = output->ip.tos;
212262306a36Sopenharmony_ci		ipv4_key->ipv4_ttl = output->ip.ttl;
212362306a36Sopenharmony_ci		ipv4_key->ipv4_frag = output->ip.frag;
212462306a36Sopenharmony_ci	} else if (swkey->eth.type == htons(ETH_P_IPV6)) {
212562306a36Sopenharmony_ci		struct ovs_key_ipv6 *ipv6_key;
212662306a36Sopenharmony_ci		struct ovs_key_ipv6_exthdrs *ipv6_exthdrs_key;
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci		nla = nla_reserve(skb, OVS_KEY_ATTR_IPV6, sizeof(*ipv6_key));
212962306a36Sopenharmony_ci		if (!nla)
213062306a36Sopenharmony_ci			goto nla_put_failure;
213162306a36Sopenharmony_ci		ipv6_key = nla_data(nla);
213262306a36Sopenharmony_ci		memcpy(ipv6_key->ipv6_src, &output->ipv6.addr.src,
213362306a36Sopenharmony_ci				sizeof(ipv6_key->ipv6_src));
213462306a36Sopenharmony_ci		memcpy(ipv6_key->ipv6_dst, &output->ipv6.addr.dst,
213562306a36Sopenharmony_ci				sizeof(ipv6_key->ipv6_dst));
213662306a36Sopenharmony_ci		ipv6_key->ipv6_label = output->ipv6.label;
213762306a36Sopenharmony_ci		ipv6_key->ipv6_proto = output->ip.proto;
213862306a36Sopenharmony_ci		ipv6_key->ipv6_tclass = output->ip.tos;
213962306a36Sopenharmony_ci		ipv6_key->ipv6_hlimit = output->ip.ttl;
214062306a36Sopenharmony_ci		ipv6_key->ipv6_frag = output->ip.frag;
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci		nla = nla_reserve(skb, OVS_KEY_ATTR_IPV6_EXTHDRS,
214362306a36Sopenharmony_ci				  sizeof(*ipv6_exthdrs_key));
214462306a36Sopenharmony_ci		if (!nla)
214562306a36Sopenharmony_ci			goto nla_put_failure;
214662306a36Sopenharmony_ci		ipv6_exthdrs_key = nla_data(nla);
214762306a36Sopenharmony_ci		ipv6_exthdrs_key->hdrs = output->ipv6.exthdrs;
214862306a36Sopenharmony_ci	} else if (swkey->eth.type == htons(ETH_P_NSH)) {
214962306a36Sopenharmony_ci		if (nsh_key_to_nlattr(&output->nsh, is_mask, skb))
215062306a36Sopenharmony_ci			goto nla_put_failure;
215162306a36Sopenharmony_ci	} else if (swkey->eth.type == htons(ETH_P_ARP) ||
215262306a36Sopenharmony_ci		   swkey->eth.type == htons(ETH_P_RARP)) {
215362306a36Sopenharmony_ci		struct ovs_key_arp *arp_key;
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci		nla = nla_reserve(skb, OVS_KEY_ATTR_ARP, sizeof(*arp_key));
215662306a36Sopenharmony_ci		if (!nla)
215762306a36Sopenharmony_ci			goto nla_put_failure;
215862306a36Sopenharmony_ci		arp_key = nla_data(nla);
215962306a36Sopenharmony_ci		memset(arp_key, 0, sizeof(struct ovs_key_arp));
216062306a36Sopenharmony_ci		arp_key->arp_sip = output->ipv4.addr.src;
216162306a36Sopenharmony_ci		arp_key->arp_tip = output->ipv4.addr.dst;
216262306a36Sopenharmony_ci		arp_key->arp_op = htons(output->ip.proto);
216362306a36Sopenharmony_ci		ether_addr_copy(arp_key->arp_sha, output->ipv4.arp.sha);
216462306a36Sopenharmony_ci		ether_addr_copy(arp_key->arp_tha, output->ipv4.arp.tha);
216562306a36Sopenharmony_ci	} else if (eth_p_mpls(swkey->eth.type)) {
216662306a36Sopenharmony_ci		u8 i, num_labels;
216762306a36Sopenharmony_ci		struct ovs_key_mpls *mpls_key;
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci		num_labels = hweight_long(output->mpls.num_labels_mask);
217062306a36Sopenharmony_ci		nla = nla_reserve(skb, OVS_KEY_ATTR_MPLS,
217162306a36Sopenharmony_ci				  num_labels * sizeof(*mpls_key));
217262306a36Sopenharmony_ci		if (!nla)
217362306a36Sopenharmony_ci			goto nla_put_failure;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci		mpls_key = nla_data(nla);
217662306a36Sopenharmony_ci		for (i = 0; i < num_labels; i++)
217762306a36Sopenharmony_ci			mpls_key[i].mpls_lse = output->mpls.lse[i];
217862306a36Sopenharmony_ci	}
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	if ((swkey->eth.type == htons(ETH_P_IP) ||
218162306a36Sopenharmony_ci	     swkey->eth.type == htons(ETH_P_IPV6)) &&
218262306a36Sopenharmony_ci	     swkey->ip.frag != OVS_FRAG_TYPE_LATER) {
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci		if (swkey->ip.proto == IPPROTO_TCP) {
218562306a36Sopenharmony_ci			struct ovs_key_tcp *tcp_key;
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci			nla = nla_reserve(skb, OVS_KEY_ATTR_TCP, sizeof(*tcp_key));
218862306a36Sopenharmony_ci			if (!nla)
218962306a36Sopenharmony_ci				goto nla_put_failure;
219062306a36Sopenharmony_ci			tcp_key = nla_data(nla);
219162306a36Sopenharmony_ci			tcp_key->tcp_src = output->tp.src;
219262306a36Sopenharmony_ci			tcp_key->tcp_dst = output->tp.dst;
219362306a36Sopenharmony_ci			if (nla_put_be16(skb, OVS_KEY_ATTR_TCP_FLAGS,
219462306a36Sopenharmony_ci					 output->tp.flags))
219562306a36Sopenharmony_ci				goto nla_put_failure;
219662306a36Sopenharmony_ci		} else if (swkey->ip.proto == IPPROTO_UDP) {
219762306a36Sopenharmony_ci			struct ovs_key_udp *udp_key;
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci			nla = nla_reserve(skb, OVS_KEY_ATTR_UDP, sizeof(*udp_key));
220062306a36Sopenharmony_ci			if (!nla)
220162306a36Sopenharmony_ci				goto nla_put_failure;
220262306a36Sopenharmony_ci			udp_key = nla_data(nla);
220362306a36Sopenharmony_ci			udp_key->udp_src = output->tp.src;
220462306a36Sopenharmony_ci			udp_key->udp_dst = output->tp.dst;
220562306a36Sopenharmony_ci		} else if (swkey->ip.proto == IPPROTO_SCTP) {
220662306a36Sopenharmony_ci			struct ovs_key_sctp *sctp_key;
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci			nla = nla_reserve(skb, OVS_KEY_ATTR_SCTP, sizeof(*sctp_key));
220962306a36Sopenharmony_ci			if (!nla)
221062306a36Sopenharmony_ci				goto nla_put_failure;
221162306a36Sopenharmony_ci			sctp_key = nla_data(nla);
221262306a36Sopenharmony_ci			sctp_key->sctp_src = output->tp.src;
221362306a36Sopenharmony_ci			sctp_key->sctp_dst = output->tp.dst;
221462306a36Sopenharmony_ci		} else if (swkey->eth.type == htons(ETH_P_IP) &&
221562306a36Sopenharmony_ci			   swkey->ip.proto == IPPROTO_ICMP) {
221662306a36Sopenharmony_ci			struct ovs_key_icmp *icmp_key;
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci			nla = nla_reserve(skb, OVS_KEY_ATTR_ICMP, sizeof(*icmp_key));
221962306a36Sopenharmony_ci			if (!nla)
222062306a36Sopenharmony_ci				goto nla_put_failure;
222162306a36Sopenharmony_ci			icmp_key = nla_data(nla);
222262306a36Sopenharmony_ci			icmp_key->icmp_type = ntohs(output->tp.src);
222362306a36Sopenharmony_ci			icmp_key->icmp_code = ntohs(output->tp.dst);
222462306a36Sopenharmony_ci		} else if (swkey->eth.type == htons(ETH_P_IPV6) &&
222562306a36Sopenharmony_ci			   swkey->ip.proto == IPPROTO_ICMPV6) {
222662306a36Sopenharmony_ci			struct ovs_key_icmpv6 *icmpv6_key;
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci			nla = nla_reserve(skb, OVS_KEY_ATTR_ICMPV6,
222962306a36Sopenharmony_ci						sizeof(*icmpv6_key));
223062306a36Sopenharmony_ci			if (!nla)
223162306a36Sopenharmony_ci				goto nla_put_failure;
223262306a36Sopenharmony_ci			icmpv6_key = nla_data(nla);
223362306a36Sopenharmony_ci			icmpv6_key->icmpv6_type = ntohs(output->tp.src);
223462306a36Sopenharmony_ci			icmpv6_key->icmpv6_code = ntohs(output->tp.dst);
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci			if (swkey->tp.src == htons(NDISC_NEIGHBOUR_SOLICITATION) ||
223762306a36Sopenharmony_ci			    swkey->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) {
223862306a36Sopenharmony_ci				struct ovs_key_nd *nd_key;
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci				nla = nla_reserve(skb, OVS_KEY_ATTR_ND, sizeof(*nd_key));
224162306a36Sopenharmony_ci				if (!nla)
224262306a36Sopenharmony_ci					goto nla_put_failure;
224362306a36Sopenharmony_ci				nd_key = nla_data(nla);
224462306a36Sopenharmony_ci				memcpy(nd_key->nd_target, &output->ipv6.nd.target,
224562306a36Sopenharmony_ci							sizeof(nd_key->nd_target));
224662306a36Sopenharmony_ci				ether_addr_copy(nd_key->nd_sll, output->ipv6.nd.sll);
224762306a36Sopenharmony_ci				ether_addr_copy(nd_key->nd_tll, output->ipv6.nd.tll);
224862306a36Sopenharmony_ci			}
224962306a36Sopenharmony_ci		}
225062306a36Sopenharmony_ci	}
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ciunencap:
225362306a36Sopenharmony_ci	if (in_encap)
225462306a36Sopenharmony_ci		nla_nest_end(skb, in_encap);
225562306a36Sopenharmony_ci	if (encap)
225662306a36Sopenharmony_ci		nla_nest_end(skb, encap);
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	return 0;
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_cinla_put_failure:
226162306a36Sopenharmony_ci	return -EMSGSIZE;
226262306a36Sopenharmony_ci}
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_ciint ovs_nla_put_key(const struct sw_flow_key *swkey,
226562306a36Sopenharmony_ci		    const struct sw_flow_key *output, int attr, bool is_mask,
226662306a36Sopenharmony_ci		    struct sk_buff *skb)
226762306a36Sopenharmony_ci{
226862306a36Sopenharmony_ci	int err;
226962306a36Sopenharmony_ci	struct nlattr *nla;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	nla = nla_nest_start_noflag(skb, attr);
227262306a36Sopenharmony_ci	if (!nla)
227362306a36Sopenharmony_ci		return -EMSGSIZE;
227462306a36Sopenharmony_ci	err = __ovs_nla_put_key(swkey, output, is_mask, skb);
227562306a36Sopenharmony_ci	if (err)
227662306a36Sopenharmony_ci		return err;
227762306a36Sopenharmony_ci	nla_nest_end(skb, nla);
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci	return 0;
228062306a36Sopenharmony_ci}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */
228362306a36Sopenharmony_ciint ovs_nla_put_identifier(const struct sw_flow *flow, struct sk_buff *skb)
228462306a36Sopenharmony_ci{
228562306a36Sopenharmony_ci	if (ovs_identifier_is_ufid(&flow->id))
228662306a36Sopenharmony_ci		return nla_put(skb, OVS_FLOW_ATTR_UFID, flow->id.ufid_len,
228762306a36Sopenharmony_ci			       flow->id.ufid);
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci	return ovs_nla_put_key(flow->id.unmasked_key, flow->id.unmasked_key,
229062306a36Sopenharmony_ci			       OVS_FLOW_ATTR_KEY, false, skb);
229162306a36Sopenharmony_ci}
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */
229462306a36Sopenharmony_ciint ovs_nla_put_masked_key(const struct sw_flow *flow, struct sk_buff *skb)
229562306a36Sopenharmony_ci{
229662306a36Sopenharmony_ci	return ovs_nla_put_key(&flow->key, &flow->key,
229762306a36Sopenharmony_ci				OVS_FLOW_ATTR_KEY, false, skb);
229862306a36Sopenharmony_ci}
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */
230162306a36Sopenharmony_ciint ovs_nla_put_mask(const struct sw_flow *flow, struct sk_buff *skb)
230262306a36Sopenharmony_ci{
230362306a36Sopenharmony_ci	return ovs_nla_put_key(&flow->key, &flow->mask->key,
230462306a36Sopenharmony_ci				OVS_FLOW_ATTR_MASK, true, skb);
230562306a36Sopenharmony_ci}
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci#define MAX_ACTIONS_BUFSIZE	(32 * 1024)
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_cistatic struct sw_flow_actions *nla_alloc_flow_actions(int size)
231062306a36Sopenharmony_ci{
231162306a36Sopenharmony_ci	struct sw_flow_actions *sfa;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	WARN_ON_ONCE(size > MAX_ACTIONS_BUFSIZE);
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	sfa = kmalloc(kmalloc_size_roundup(sizeof(*sfa) + size), GFP_KERNEL);
231662306a36Sopenharmony_ci	if (!sfa)
231762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	sfa->actions_len = 0;
232062306a36Sopenharmony_ci	return sfa;
232162306a36Sopenharmony_ci}
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_cistatic void ovs_nla_free_nested_actions(const struct nlattr *actions, int len);
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_cistatic void ovs_nla_free_check_pkt_len_action(const struct nlattr *action)
232662306a36Sopenharmony_ci{
232762306a36Sopenharmony_ci	const struct nlattr *a;
232862306a36Sopenharmony_ci	int rem;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	nla_for_each_nested(a, action, rem) {
233162306a36Sopenharmony_ci		switch (nla_type(a)) {
233262306a36Sopenharmony_ci		case OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL:
233362306a36Sopenharmony_ci		case OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER:
233462306a36Sopenharmony_ci			ovs_nla_free_nested_actions(nla_data(a), nla_len(a));
233562306a36Sopenharmony_ci			break;
233662306a36Sopenharmony_ci		}
233762306a36Sopenharmony_ci	}
233862306a36Sopenharmony_ci}
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_cistatic void ovs_nla_free_clone_action(const struct nlattr *action)
234162306a36Sopenharmony_ci{
234262306a36Sopenharmony_ci	const struct nlattr *a = nla_data(action);
234362306a36Sopenharmony_ci	int rem = nla_len(action);
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	switch (nla_type(a)) {
234662306a36Sopenharmony_ci	case OVS_CLONE_ATTR_EXEC:
234762306a36Sopenharmony_ci		/* The real list of actions follows this attribute. */
234862306a36Sopenharmony_ci		a = nla_next(a, &rem);
234962306a36Sopenharmony_ci		ovs_nla_free_nested_actions(a, rem);
235062306a36Sopenharmony_ci		break;
235162306a36Sopenharmony_ci	}
235262306a36Sopenharmony_ci}
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_cistatic void ovs_nla_free_dec_ttl_action(const struct nlattr *action)
235562306a36Sopenharmony_ci{
235662306a36Sopenharmony_ci	const struct nlattr *a = nla_data(action);
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci	switch (nla_type(a)) {
235962306a36Sopenharmony_ci	case OVS_DEC_TTL_ATTR_ACTION:
236062306a36Sopenharmony_ci		ovs_nla_free_nested_actions(nla_data(a), nla_len(a));
236162306a36Sopenharmony_ci		break;
236262306a36Sopenharmony_ci	}
236362306a36Sopenharmony_ci}
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_cistatic void ovs_nla_free_sample_action(const struct nlattr *action)
236662306a36Sopenharmony_ci{
236762306a36Sopenharmony_ci	const struct nlattr *a = nla_data(action);
236862306a36Sopenharmony_ci	int rem = nla_len(action);
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	switch (nla_type(a)) {
237162306a36Sopenharmony_ci	case OVS_SAMPLE_ATTR_ARG:
237262306a36Sopenharmony_ci		/* The real list of actions follows this attribute. */
237362306a36Sopenharmony_ci		a = nla_next(a, &rem);
237462306a36Sopenharmony_ci		ovs_nla_free_nested_actions(a, rem);
237562306a36Sopenharmony_ci		break;
237662306a36Sopenharmony_ci	}
237762306a36Sopenharmony_ci}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_cistatic void ovs_nla_free_set_action(const struct nlattr *a)
238062306a36Sopenharmony_ci{
238162306a36Sopenharmony_ci	const struct nlattr *ovs_key = nla_data(a);
238262306a36Sopenharmony_ci	struct ovs_tunnel_info *ovs_tun;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	switch (nla_type(ovs_key)) {
238562306a36Sopenharmony_ci	case OVS_KEY_ATTR_TUNNEL_INFO:
238662306a36Sopenharmony_ci		ovs_tun = nla_data(ovs_key);
238762306a36Sopenharmony_ci		dst_release((struct dst_entry *)ovs_tun->tun_dst);
238862306a36Sopenharmony_ci		break;
238962306a36Sopenharmony_ci	}
239062306a36Sopenharmony_ci}
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_cistatic void ovs_nla_free_nested_actions(const struct nlattr *actions, int len)
239362306a36Sopenharmony_ci{
239462306a36Sopenharmony_ci	const struct nlattr *a;
239562306a36Sopenharmony_ci	int rem;
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci	/* Whenever new actions are added, the need to update this
239862306a36Sopenharmony_ci	 * function should be considered.
239962306a36Sopenharmony_ci	 */
240062306a36Sopenharmony_ci	BUILD_BUG_ON(OVS_ACTION_ATTR_MAX != 24);
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	if (!actions)
240362306a36Sopenharmony_ci		return;
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	nla_for_each_attr(a, actions, len, rem) {
240662306a36Sopenharmony_ci		switch (nla_type(a)) {
240762306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CHECK_PKT_LEN:
240862306a36Sopenharmony_ci			ovs_nla_free_check_pkt_len_action(a);
240962306a36Sopenharmony_ci			break;
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CLONE:
241262306a36Sopenharmony_ci			ovs_nla_free_clone_action(a);
241362306a36Sopenharmony_ci			break;
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CT:
241662306a36Sopenharmony_ci			ovs_ct_free_action(a);
241762306a36Sopenharmony_ci			break;
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci		case OVS_ACTION_ATTR_DEC_TTL:
242062306a36Sopenharmony_ci			ovs_nla_free_dec_ttl_action(a);
242162306a36Sopenharmony_ci			break;
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci		case OVS_ACTION_ATTR_SAMPLE:
242462306a36Sopenharmony_ci			ovs_nla_free_sample_action(a);
242562306a36Sopenharmony_ci			break;
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci		case OVS_ACTION_ATTR_SET:
242862306a36Sopenharmony_ci			ovs_nla_free_set_action(a);
242962306a36Sopenharmony_ci			break;
243062306a36Sopenharmony_ci		}
243162306a36Sopenharmony_ci	}
243262306a36Sopenharmony_ci}
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_civoid ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts)
243562306a36Sopenharmony_ci{
243662306a36Sopenharmony_ci	if (!sf_acts)
243762306a36Sopenharmony_ci		return;
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci	ovs_nla_free_nested_actions(sf_acts->actions, sf_acts->actions_len);
244062306a36Sopenharmony_ci	kfree(sf_acts);
244162306a36Sopenharmony_ci}
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_cistatic void __ovs_nla_free_flow_actions(struct rcu_head *head)
244462306a36Sopenharmony_ci{
244562306a36Sopenharmony_ci	ovs_nla_free_flow_actions(container_of(head, struct sw_flow_actions, rcu));
244662306a36Sopenharmony_ci}
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci/* Schedules 'sf_acts' to be freed after the next RCU grace period.
244962306a36Sopenharmony_ci * The caller must hold rcu_read_lock for this to be sensible. */
245062306a36Sopenharmony_civoid ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *sf_acts)
245162306a36Sopenharmony_ci{
245262306a36Sopenharmony_ci	call_rcu(&sf_acts->rcu, __ovs_nla_free_flow_actions);
245362306a36Sopenharmony_ci}
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_cistatic struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa,
245662306a36Sopenharmony_ci				       int attr_len, bool log)
245762306a36Sopenharmony_ci{
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	struct sw_flow_actions *acts;
246062306a36Sopenharmony_ci	int new_acts_size;
246162306a36Sopenharmony_ci	size_t req_size = NLA_ALIGN(attr_len);
246262306a36Sopenharmony_ci	int next_offset = offsetof(struct sw_flow_actions, actions) +
246362306a36Sopenharmony_ci					(*sfa)->actions_len;
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	if (req_size <= (ksize(*sfa) - next_offset))
246662306a36Sopenharmony_ci		goto out;
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	new_acts_size = max(next_offset + req_size, ksize(*sfa) * 2);
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci	if (new_acts_size > MAX_ACTIONS_BUFSIZE) {
247162306a36Sopenharmony_ci		if ((next_offset + req_size) > MAX_ACTIONS_BUFSIZE) {
247262306a36Sopenharmony_ci			OVS_NLERR(log, "Flow action size exceeds max %u",
247362306a36Sopenharmony_ci				  MAX_ACTIONS_BUFSIZE);
247462306a36Sopenharmony_ci			return ERR_PTR(-EMSGSIZE);
247562306a36Sopenharmony_ci		}
247662306a36Sopenharmony_ci		new_acts_size = MAX_ACTIONS_BUFSIZE;
247762306a36Sopenharmony_ci	}
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	acts = nla_alloc_flow_actions(new_acts_size);
248062306a36Sopenharmony_ci	if (IS_ERR(acts))
248162306a36Sopenharmony_ci		return (void *)acts;
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	memcpy(acts->actions, (*sfa)->actions, (*sfa)->actions_len);
248462306a36Sopenharmony_ci	acts->actions_len = (*sfa)->actions_len;
248562306a36Sopenharmony_ci	acts->orig_len = (*sfa)->orig_len;
248662306a36Sopenharmony_ci	kfree(*sfa);
248762306a36Sopenharmony_ci	*sfa = acts;
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ciout:
249062306a36Sopenharmony_ci	(*sfa)->actions_len += req_size;
249162306a36Sopenharmony_ci	return  (struct nlattr *) ((unsigned char *)(*sfa) + next_offset);
249262306a36Sopenharmony_ci}
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_cistatic struct nlattr *__add_action(struct sw_flow_actions **sfa,
249562306a36Sopenharmony_ci				   int attrtype, void *data, int len, bool log)
249662306a36Sopenharmony_ci{
249762306a36Sopenharmony_ci	struct nlattr *a;
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	a = reserve_sfa_size(sfa, nla_attr_size(len), log);
250062306a36Sopenharmony_ci	if (IS_ERR(a))
250162306a36Sopenharmony_ci		return a;
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	a->nla_type = attrtype;
250462306a36Sopenharmony_ci	a->nla_len = nla_attr_size(len);
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	if (data)
250762306a36Sopenharmony_ci		memcpy(nla_data(a), data, len);
250862306a36Sopenharmony_ci	memset((unsigned char *) a + a->nla_len, 0, nla_padlen(len));
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci	return a;
251162306a36Sopenharmony_ci}
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ciint ovs_nla_add_action(struct sw_flow_actions **sfa, int attrtype, void *data,
251462306a36Sopenharmony_ci		       int len, bool log)
251562306a36Sopenharmony_ci{
251662306a36Sopenharmony_ci	struct nlattr *a;
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci	a = __add_action(sfa, attrtype, data, len, log);
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(a);
252162306a36Sopenharmony_ci}
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_cistatic inline int add_nested_action_start(struct sw_flow_actions **sfa,
252462306a36Sopenharmony_ci					  int attrtype, bool log)
252562306a36Sopenharmony_ci{
252662306a36Sopenharmony_ci	int used = (*sfa)->actions_len;
252762306a36Sopenharmony_ci	int err;
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	err = ovs_nla_add_action(sfa, attrtype, NULL, 0, log);
253062306a36Sopenharmony_ci	if (err)
253162306a36Sopenharmony_ci		return err;
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ci	return used;
253462306a36Sopenharmony_ci}
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_cistatic inline void add_nested_action_end(struct sw_flow_actions *sfa,
253762306a36Sopenharmony_ci					 int st_offset)
253862306a36Sopenharmony_ci{
253962306a36Sopenharmony_ci	struct nlattr *a = (struct nlattr *) ((unsigned char *)sfa->actions +
254062306a36Sopenharmony_ci							       st_offset);
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	a->nla_len = sfa->actions_len - st_offset;
254362306a36Sopenharmony_ci}
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_cistatic int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
254662306a36Sopenharmony_ci				  const struct sw_flow_key *key,
254762306a36Sopenharmony_ci				  struct sw_flow_actions **sfa,
254862306a36Sopenharmony_ci				  __be16 eth_type, __be16 vlan_tci,
254962306a36Sopenharmony_ci				  u32 mpls_label_count, bool log,
255062306a36Sopenharmony_ci				  u32 depth);
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_cistatic int validate_and_copy_sample(struct net *net, const struct nlattr *attr,
255362306a36Sopenharmony_ci				    const struct sw_flow_key *key,
255462306a36Sopenharmony_ci				    struct sw_flow_actions **sfa,
255562306a36Sopenharmony_ci				    __be16 eth_type, __be16 vlan_tci,
255662306a36Sopenharmony_ci				    u32 mpls_label_count, bool log, bool last,
255762306a36Sopenharmony_ci				    u32 depth)
255862306a36Sopenharmony_ci{
255962306a36Sopenharmony_ci	const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1];
256062306a36Sopenharmony_ci	const struct nlattr *probability, *actions;
256162306a36Sopenharmony_ci	const struct nlattr *a;
256262306a36Sopenharmony_ci	int rem, start, err;
256362306a36Sopenharmony_ci	struct sample_arg arg;
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci	memset(attrs, 0, sizeof(attrs));
256662306a36Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
256762306a36Sopenharmony_ci		int type = nla_type(a);
256862306a36Sopenharmony_ci		if (!type || type > OVS_SAMPLE_ATTR_MAX || attrs[type])
256962306a36Sopenharmony_ci			return -EINVAL;
257062306a36Sopenharmony_ci		attrs[type] = a;
257162306a36Sopenharmony_ci	}
257262306a36Sopenharmony_ci	if (rem)
257362306a36Sopenharmony_ci		return -EINVAL;
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	probability = attrs[OVS_SAMPLE_ATTR_PROBABILITY];
257662306a36Sopenharmony_ci	if (!probability || nla_len(probability) != sizeof(u32))
257762306a36Sopenharmony_ci		return -EINVAL;
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_ci	actions = attrs[OVS_SAMPLE_ATTR_ACTIONS];
258062306a36Sopenharmony_ci	if (!actions || (nla_len(actions) && nla_len(actions) < NLA_HDRLEN))
258162306a36Sopenharmony_ci		return -EINVAL;
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	/* validation done, copy sample action. */
258462306a36Sopenharmony_ci	start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SAMPLE, log);
258562306a36Sopenharmony_ci	if (start < 0)
258662306a36Sopenharmony_ci		return start;
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	/* When both skb and flow may be changed, put the sample
258962306a36Sopenharmony_ci	 * into a deferred fifo. On the other hand, if only skb
259062306a36Sopenharmony_ci	 * may be modified, the actions can be executed in place.
259162306a36Sopenharmony_ci	 *
259262306a36Sopenharmony_ci	 * Do this analysis at the flow installation time.
259362306a36Sopenharmony_ci	 * Set 'clone_action->exec' to true if the actions can be
259462306a36Sopenharmony_ci	 * executed without being deferred.
259562306a36Sopenharmony_ci	 *
259662306a36Sopenharmony_ci	 * If the sample is the last action, it can always be excuted
259762306a36Sopenharmony_ci	 * rather than deferred.
259862306a36Sopenharmony_ci	 */
259962306a36Sopenharmony_ci	arg.exec = last || !actions_may_change_flow(actions);
260062306a36Sopenharmony_ci	arg.probability = nla_get_u32(probability);
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	err = ovs_nla_add_action(sfa, OVS_SAMPLE_ATTR_ARG, &arg, sizeof(arg),
260362306a36Sopenharmony_ci				 log);
260462306a36Sopenharmony_ci	if (err)
260562306a36Sopenharmony_ci		return err;
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	err = __ovs_nla_copy_actions(net, actions, key, sfa,
260862306a36Sopenharmony_ci				     eth_type, vlan_tci, mpls_label_count, log,
260962306a36Sopenharmony_ci				     depth + 1);
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci	if (err)
261262306a36Sopenharmony_ci		return err;
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	add_nested_action_end(*sfa, start);
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	return 0;
261762306a36Sopenharmony_ci}
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_cistatic int validate_and_copy_dec_ttl(struct net *net,
262062306a36Sopenharmony_ci				     const struct nlattr *attr,
262162306a36Sopenharmony_ci				     const struct sw_flow_key *key,
262262306a36Sopenharmony_ci				     struct sw_flow_actions **sfa,
262362306a36Sopenharmony_ci				     __be16 eth_type, __be16 vlan_tci,
262462306a36Sopenharmony_ci				     u32 mpls_label_count, bool log,
262562306a36Sopenharmony_ci				     u32 depth)
262662306a36Sopenharmony_ci{
262762306a36Sopenharmony_ci	const struct nlattr *attrs[OVS_DEC_TTL_ATTR_MAX + 1];
262862306a36Sopenharmony_ci	int start, action_start, err, rem;
262962306a36Sopenharmony_ci	const struct nlattr *a, *actions;
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	memset(attrs, 0, sizeof(attrs));
263262306a36Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
263362306a36Sopenharmony_ci		int type = nla_type(a);
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci		/* Ignore unknown attributes to be future proof. */
263662306a36Sopenharmony_ci		if (type > OVS_DEC_TTL_ATTR_MAX)
263762306a36Sopenharmony_ci			continue;
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci		if (!type || attrs[type]) {
264062306a36Sopenharmony_ci			OVS_NLERR(log, "Duplicate or invalid key (type %d).",
264162306a36Sopenharmony_ci				  type);
264262306a36Sopenharmony_ci			return -EINVAL;
264362306a36Sopenharmony_ci		}
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_ci		attrs[type] = a;
264662306a36Sopenharmony_ci	}
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci	if (rem) {
264962306a36Sopenharmony_ci		OVS_NLERR(log, "Message has %d unknown bytes.", rem);
265062306a36Sopenharmony_ci		return -EINVAL;
265162306a36Sopenharmony_ci	}
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	actions = attrs[OVS_DEC_TTL_ATTR_ACTION];
265462306a36Sopenharmony_ci	if (!actions || (nla_len(actions) && nla_len(actions) < NLA_HDRLEN)) {
265562306a36Sopenharmony_ci		OVS_NLERR(log, "Missing valid actions attribute.");
265662306a36Sopenharmony_ci		return -EINVAL;
265762306a36Sopenharmony_ci	}
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	start = add_nested_action_start(sfa, OVS_ACTION_ATTR_DEC_TTL, log);
266062306a36Sopenharmony_ci	if (start < 0)
266162306a36Sopenharmony_ci		return start;
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci	action_start = add_nested_action_start(sfa, OVS_DEC_TTL_ATTR_ACTION, log);
266462306a36Sopenharmony_ci	if (action_start < 0)
266562306a36Sopenharmony_ci		return action_start;
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	err = __ovs_nla_copy_actions(net, actions, key, sfa, eth_type,
266862306a36Sopenharmony_ci				     vlan_tci, mpls_label_count, log,
266962306a36Sopenharmony_ci				     depth + 1);
267062306a36Sopenharmony_ci	if (err)
267162306a36Sopenharmony_ci		return err;
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci	add_nested_action_end(*sfa, action_start);
267462306a36Sopenharmony_ci	add_nested_action_end(*sfa, start);
267562306a36Sopenharmony_ci	return 0;
267662306a36Sopenharmony_ci}
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_cistatic int validate_and_copy_clone(struct net *net,
267962306a36Sopenharmony_ci				   const struct nlattr *attr,
268062306a36Sopenharmony_ci				   const struct sw_flow_key *key,
268162306a36Sopenharmony_ci				   struct sw_flow_actions **sfa,
268262306a36Sopenharmony_ci				   __be16 eth_type, __be16 vlan_tci,
268362306a36Sopenharmony_ci				   u32 mpls_label_count, bool log, bool last,
268462306a36Sopenharmony_ci				   u32 depth)
268562306a36Sopenharmony_ci{
268662306a36Sopenharmony_ci	int start, err;
268762306a36Sopenharmony_ci	u32 exec;
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	if (nla_len(attr) && nla_len(attr) < NLA_HDRLEN)
269062306a36Sopenharmony_ci		return -EINVAL;
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	start = add_nested_action_start(sfa, OVS_ACTION_ATTR_CLONE, log);
269362306a36Sopenharmony_ci	if (start < 0)
269462306a36Sopenharmony_ci		return start;
269562306a36Sopenharmony_ci
269662306a36Sopenharmony_ci	exec = last || !actions_may_change_flow(attr);
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	err = ovs_nla_add_action(sfa, OVS_CLONE_ATTR_EXEC, &exec,
269962306a36Sopenharmony_ci				 sizeof(exec), log);
270062306a36Sopenharmony_ci	if (err)
270162306a36Sopenharmony_ci		return err;
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci	err = __ovs_nla_copy_actions(net, attr, key, sfa,
270462306a36Sopenharmony_ci				     eth_type, vlan_tci, mpls_label_count, log,
270562306a36Sopenharmony_ci				     depth + 1);
270662306a36Sopenharmony_ci	if (err)
270762306a36Sopenharmony_ci		return err;
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci	add_nested_action_end(*sfa, start);
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ci	return 0;
271262306a36Sopenharmony_ci}
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_civoid ovs_match_init(struct sw_flow_match *match,
271562306a36Sopenharmony_ci		    struct sw_flow_key *key,
271662306a36Sopenharmony_ci		    bool reset_key,
271762306a36Sopenharmony_ci		    struct sw_flow_mask *mask)
271862306a36Sopenharmony_ci{
271962306a36Sopenharmony_ci	memset(match, 0, sizeof(*match));
272062306a36Sopenharmony_ci	match->key = key;
272162306a36Sopenharmony_ci	match->mask = mask;
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	if (reset_key)
272462306a36Sopenharmony_ci		memset(key, 0, sizeof(*key));
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	if (mask) {
272762306a36Sopenharmony_ci		memset(&mask->key, 0, sizeof(mask->key));
272862306a36Sopenharmony_ci		mask->range.start = mask->range.end = 0;
272962306a36Sopenharmony_ci	}
273062306a36Sopenharmony_ci}
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_cistatic int validate_geneve_opts(struct sw_flow_key *key)
273362306a36Sopenharmony_ci{
273462306a36Sopenharmony_ci	struct geneve_opt *option;
273562306a36Sopenharmony_ci	int opts_len = key->tun_opts_len;
273662306a36Sopenharmony_ci	bool crit_opt = false;
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci	option = (struct geneve_opt *)TUN_METADATA_OPTS(key, key->tun_opts_len);
273962306a36Sopenharmony_ci	while (opts_len > 0) {
274062306a36Sopenharmony_ci		int len;
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci		if (opts_len < sizeof(*option))
274362306a36Sopenharmony_ci			return -EINVAL;
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci		len = sizeof(*option) + option->length * 4;
274662306a36Sopenharmony_ci		if (len > opts_len)
274762306a36Sopenharmony_ci			return -EINVAL;
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci		crit_opt |= !!(option->type & GENEVE_CRIT_OPT_TYPE);
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci		option = (struct geneve_opt *)((u8 *)option + len);
275262306a36Sopenharmony_ci		opts_len -= len;
275362306a36Sopenharmony_ci	}
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci	key->tun_key.tun_flags |= crit_opt ? TUNNEL_CRIT_OPT : 0;
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci	return 0;
275862306a36Sopenharmony_ci}
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_cistatic int validate_and_copy_set_tun(const struct nlattr *attr,
276162306a36Sopenharmony_ci				     struct sw_flow_actions **sfa, bool log)
276262306a36Sopenharmony_ci{
276362306a36Sopenharmony_ci	struct sw_flow_match match;
276462306a36Sopenharmony_ci	struct sw_flow_key key;
276562306a36Sopenharmony_ci	struct metadata_dst *tun_dst;
276662306a36Sopenharmony_ci	struct ip_tunnel_info *tun_info;
276762306a36Sopenharmony_ci	struct ovs_tunnel_info *ovs_tun;
276862306a36Sopenharmony_ci	struct nlattr *a;
276962306a36Sopenharmony_ci	int err = 0, start, opts_type;
277062306a36Sopenharmony_ci	__be16 dst_opt_type;
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	dst_opt_type = 0;
277362306a36Sopenharmony_ci	ovs_match_init(&match, &key, true, NULL);
277462306a36Sopenharmony_ci	opts_type = ip_tun_from_nlattr(nla_data(attr), &match, false, log);
277562306a36Sopenharmony_ci	if (opts_type < 0)
277662306a36Sopenharmony_ci		return opts_type;
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_ci	if (key.tun_opts_len) {
277962306a36Sopenharmony_ci		switch (opts_type) {
278062306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
278162306a36Sopenharmony_ci			err = validate_geneve_opts(&key);
278262306a36Sopenharmony_ci			if (err < 0)
278362306a36Sopenharmony_ci				return err;
278462306a36Sopenharmony_ci			dst_opt_type = TUNNEL_GENEVE_OPT;
278562306a36Sopenharmony_ci			break;
278662306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
278762306a36Sopenharmony_ci			dst_opt_type = TUNNEL_VXLAN_OPT;
278862306a36Sopenharmony_ci			break;
278962306a36Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS:
279062306a36Sopenharmony_ci			dst_opt_type = TUNNEL_ERSPAN_OPT;
279162306a36Sopenharmony_ci			break;
279262306a36Sopenharmony_ci		}
279362306a36Sopenharmony_ci	}
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_ci	start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET, log);
279662306a36Sopenharmony_ci	if (start < 0)
279762306a36Sopenharmony_ci		return start;
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	tun_dst = metadata_dst_alloc(key.tun_opts_len, METADATA_IP_TUNNEL,
280062306a36Sopenharmony_ci				     GFP_KERNEL);
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	if (!tun_dst)
280362306a36Sopenharmony_ci		return -ENOMEM;
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	err = dst_cache_init(&tun_dst->u.tun_info.dst_cache, GFP_KERNEL);
280662306a36Sopenharmony_ci	if (err) {
280762306a36Sopenharmony_ci		dst_release((struct dst_entry *)tun_dst);
280862306a36Sopenharmony_ci		return err;
280962306a36Sopenharmony_ci	}
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci	a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL,
281262306a36Sopenharmony_ci			 sizeof(*ovs_tun), log);
281362306a36Sopenharmony_ci	if (IS_ERR(a)) {
281462306a36Sopenharmony_ci		dst_release((struct dst_entry *)tun_dst);
281562306a36Sopenharmony_ci		return PTR_ERR(a);
281662306a36Sopenharmony_ci	}
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci	ovs_tun = nla_data(a);
281962306a36Sopenharmony_ci	ovs_tun->tun_dst = tun_dst;
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci	tun_info = &tun_dst->u.tun_info;
282262306a36Sopenharmony_ci	tun_info->mode = IP_TUNNEL_INFO_TX;
282362306a36Sopenharmony_ci	if (key.tun_proto == AF_INET6)
282462306a36Sopenharmony_ci		tun_info->mode |= IP_TUNNEL_INFO_IPV6;
282562306a36Sopenharmony_ci	else if (key.tun_proto == AF_INET && key.tun_key.u.ipv4.dst == 0)
282662306a36Sopenharmony_ci		tun_info->mode |= IP_TUNNEL_INFO_BRIDGE;
282762306a36Sopenharmony_ci	tun_info->key = key.tun_key;
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	/* We need to store the options in the action itself since
283062306a36Sopenharmony_ci	 * everything else will go away after flow setup. We can append
283162306a36Sopenharmony_ci	 * it to tun_info and then point there.
283262306a36Sopenharmony_ci	 */
283362306a36Sopenharmony_ci	ip_tunnel_info_opts_set(tun_info,
283462306a36Sopenharmony_ci				TUN_METADATA_OPTS(&key, key.tun_opts_len),
283562306a36Sopenharmony_ci				key.tun_opts_len, dst_opt_type);
283662306a36Sopenharmony_ci	add_nested_action_end(*sfa, start);
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci	return err;
283962306a36Sopenharmony_ci}
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_cistatic bool validate_nsh(const struct nlattr *attr, bool is_mask,
284262306a36Sopenharmony_ci			 bool is_push_nsh, bool log)
284362306a36Sopenharmony_ci{
284462306a36Sopenharmony_ci	struct sw_flow_match match;
284562306a36Sopenharmony_ci	struct sw_flow_key key;
284662306a36Sopenharmony_ci	int ret = 0;
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	ovs_match_init(&match, &key, true, NULL);
284962306a36Sopenharmony_ci	ret = nsh_key_put_from_nlattr(attr, &match, is_mask,
285062306a36Sopenharmony_ci				      is_push_nsh, log);
285162306a36Sopenharmony_ci	return !ret;
285262306a36Sopenharmony_ci}
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci/* Return false if there are any non-masked bits set.
285562306a36Sopenharmony_ci * Mask follows data immediately, before any netlink padding.
285662306a36Sopenharmony_ci */
285762306a36Sopenharmony_cistatic bool validate_masked(u8 *data, int len)
285862306a36Sopenharmony_ci{
285962306a36Sopenharmony_ci	u8 *mask = data + len;
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci	while (len--)
286262306a36Sopenharmony_ci		if (*data++ & ~*mask++)
286362306a36Sopenharmony_ci			return false;
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	return true;
286662306a36Sopenharmony_ci}
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_cistatic int validate_set(const struct nlattr *a,
286962306a36Sopenharmony_ci			const struct sw_flow_key *flow_key,
287062306a36Sopenharmony_ci			struct sw_flow_actions **sfa, bool *skip_copy,
287162306a36Sopenharmony_ci			u8 mac_proto, __be16 eth_type, bool masked, bool log)
287262306a36Sopenharmony_ci{
287362306a36Sopenharmony_ci	const struct nlattr *ovs_key = nla_data(a);
287462306a36Sopenharmony_ci	int key_type = nla_type(ovs_key);
287562306a36Sopenharmony_ci	size_t key_len;
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_ci	/* There can be only one key in a action */
287862306a36Sopenharmony_ci	if (nla_total_size(nla_len(ovs_key)) != nla_len(a))
287962306a36Sopenharmony_ci		return -EINVAL;
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci	key_len = nla_len(ovs_key);
288262306a36Sopenharmony_ci	if (masked)
288362306a36Sopenharmony_ci		key_len /= 2;
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci	if (key_type > OVS_KEY_ATTR_MAX ||
288662306a36Sopenharmony_ci	    !check_attr_len(key_len, ovs_key_lens[key_type].len))
288762306a36Sopenharmony_ci		return -EINVAL;
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci	if (masked && !validate_masked(nla_data(ovs_key), key_len))
289062306a36Sopenharmony_ci		return -EINVAL;
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci	switch (key_type) {
289362306a36Sopenharmony_ci	case OVS_KEY_ATTR_PRIORITY:
289462306a36Sopenharmony_ci	case OVS_KEY_ATTR_SKB_MARK:
289562306a36Sopenharmony_ci	case OVS_KEY_ATTR_CT_MARK:
289662306a36Sopenharmony_ci	case OVS_KEY_ATTR_CT_LABELS:
289762306a36Sopenharmony_ci		break;
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci	case OVS_KEY_ATTR_ETHERNET:
290062306a36Sopenharmony_ci		if (mac_proto != MAC_PROTO_ETHERNET)
290162306a36Sopenharmony_ci			return -EINVAL;
290262306a36Sopenharmony_ci		break;
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci	case OVS_KEY_ATTR_TUNNEL: {
290562306a36Sopenharmony_ci		int err;
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci		if (masked)
290862306a36Sopenharmony_ci			return -EINVAL; /* Masked tunnel set not supported. */
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci		*skip_copy = true;
291162306a36Sopenharmony_ci		err = validate_and_copy_set_tun(a, sfa, log);
291262306a36Sopenharmony_ci		if (err)
291362306a36Sopenharmony_ci			return err;
291462306a36Sopenharmony_ci		break;
291562306a36Sopenharmony_ci	}
291662306a36Sopenharmony_ci	case OVS_KEY_ATTR_IPV4: {
291762306a36Sopenharmony_ci		const struct ovs_key_ipv4 *ipv4_key;
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci		if (eth_type != htons(ETH_P_IP))
292062306a36Sopenharmony_ci			return -EINVAL;
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci		ipv4_key = nla_data(ovs_key);
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci		if (masked) {
292562306a36Sopenharmony_ci			const struct ovs_key_ipv4 *mask = ipv4_key + 1;
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_ci			/* Non-writeable fields. */
292862306a36Sopenharmony_ci			if (mask->ipv4_proto || mask->ipv4_frag)
292962306a36Sopenharmony_ci				return -EINVAL;
293062306a36Sopenharmony_ci		} else {
293162306a36Sopenharmony_ci			if (ipv4_key->ipv4_proto != flow_key->ip.proto)
293262306a36Sopenharmony_ci				return -EINVAL;
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci			if (ipv4_key->ipv4_frag != flow_key->ip.frag)
293562306a36Sopenharmony_ci				return -EINVAL;
293662306a36Sopenharmony_ci		}
293762306a36Sopenharmony_ci		break;
293862306a36Sopenharmony_ci	}
293962306a36Sopenharmony_ci	case OVS_KEY_ATTR_IPV6: {
294062306a36Sopenharmony_ci		const struct ovs_key_ipv6 *ipv6_key;
294162306a36Sopenharmony_ci
294262306a36Sopenharmony_ci		if (eth_type != htons(ETH_P_IPV6))
294362306a36Sopenharmony_ci			return -EINVAL;
294462306a36Sopenharmony_ci
294562306a36Sopenharmony_ci		ipv6_key = nla_data(ovs_key);
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_ci		if (masked) {
294862306a36Sopenharmony_ci			const struct ovs_key_ipv6 *mask = ipv6_key + 1;
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci			/* Non-writeable fields. */
295162306a36Sopenharmony_ci			if (mask->ipv6_proto || mask->ipv6_frag)
295262306a36Sopenharmony_ci				return -EINVAL;
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci			/* Invalid bits in the flow label mask? */
295562306a36Sopenharmony_ci			if (ntohl(mask->ipv6_label) & 0xFFF00000)
295662306a36Sopenharmony_ci				return -EINVAL;
295762306a36Sopenharmony_ci		} else {
295862306a36Sopenharmony_ci			if (ipv6_key->ipv6_proto != flow_key->ip.proto)
295962306a36Sopenharmony_ci				return -EINVAL;
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci			if (ipv6_key->ipv6_frag != flow_key->ip.frag)
296262306a36Sopenharmony_ci				return -EINVAL;
296362306a36Sopenharmony_ci		}
296462306a36Sopenharmony_ci		if (ntohl(ipv6_key->ipv6_label) & 0xFFF00000)
296562306a36Sopenharmony_ci			return -EINVAL;
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci		break;
296862306a36Sopenharmony_ci	}
296962306a36Sopenharmony_ci	case OVS_KEY_ATTR_TCP:
297062306a36Sopenharmony_ci		if ((eth_type != htons(ETH_P_IP) &&
297162306a36Sopenharmony_ci		     eth_type != htons(ETH_P_IPV6)) ||
297262306a36Sopenharmony_ci		    flow_key->ip.proto != IPPROTO_TCP)
297362306a36Sopenharmony_ci			return -EINVAL;
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci		break;
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci	case OVS_KEY_ATTR_UDP:
297862306a36Sopenharmony_ci		if ((eth_type != htons(ETH_P_IP) &&
297962306a36Sopenharmony_ci		     eth_type != htons(ETH_P_IPV6)) ||
298062306a36Sopenharmony_ci		    flow_key->ip.proto != IPPROTO_UDP)
298162306a36Sopenharmony_ci			return -EINVAL;
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_ci		break;
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci	case OVS_KEY_ATTR_MPLS:
298662306a36Sopenharmony_ci		if (!eth_p_mpls(eth_type))
298762306a36Sopenharmony_ci			return -EINVAL;
298862306a36Sopenharmony_ci		break;
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci	case OVS_KEY_ATTR_SCTP:
299162306a36Sopenharmony_ci		if ((eth_type != htons(ETH_P_IP) &&
299262306a36Sopenharmony_ci		     eth_type != htons(ETH_P_IPV6)) ||
299362306a36Sopenharmony_ci		    flow_key->ip.proto != IPPROTO_SCTP)
299462306a36Sopenharmony_ci			return -EINVAL;
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci		break;
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci	case OVS_KEY_ATTR_NSH:
299962306a36Sopenharmony_ci		if (eth_type != htons(ETH_P_NSH))
300062306a36Sopenharmony_ci			return -EINVAL;
300162306a36Sopenharmony_ci		if (!validate_nsh(nla_data(a), masked, false, log))
300262306a36Sopenharmony_ci			return -EINVAL;
300362306a36Sopenharmony_ci		break;
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci	default:
300662306a36Sopenharmony_ci		return -EINVAL;
300762306a36Sopenharmony_ci	}
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci	/* Convert non-masked non-tunnel set actions to masked set actions. */
301062306a36Sopenharmony_ci	if (!masked && key_type != OVS_KEY_ATTR_TUNNEL) {
301162306a36Sopenharmony_ci		int start, len = key_len * 2;
301262306a36Sopenharmony_ci		struct nlattr *at;
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci		*skip_copy = true;
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci		start = add_nested_action_start(sfa,
301762306a36Sopenharmony_ci						OVS_ACTION_ATTR_SET_TO_MASKED,
301862306a36Sopenharmony_ci						log);
301962306a36Sopenharmony_ci		if (start < 0)
302062306a36Sopenharmony_ci			return start;
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci		at = __add_action(sfa, key_type, NULL, len, log);
302362306a36Sopenharmony_ci		if (IS_ERR(at))
302462306a36Sopenharmony_ci			return PTR_ERR(at);
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci		memcpy(nla_data(at), nla_data(ovs_key), key_len); /* Key. */
302762306a36Sopenharmony_ci		memset(nla_data(at) + key_len, 0xff, key_len);    /* Mask. */
302862306a36Sopenharmony_ci		/* Clear non-writeable bits from otherwise writeable fields. */
302962306a36Sopenharmony_ci		if (key_type == OVS_KEY_ATTR_IPV6) {
303062306a36Sopenharmony_ci			struct ovs_key_ipv6 *mask = nla_data(at) + key_len;
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_ci			mask->ipv6_label &= htonl(0x000FFFFF);
303362306a36Sopenharmony_ci		}
303462306a36Sopenharmony_ci		add_nested_action_end(*sfa, start);
303562306a36Sopenharmony_ci	}
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci	return 0;
303862306a36Sopenharmony_ci}
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_cistatic int validate_userspace(const struct nlattr *attr)
304162306a36Sopenharmony_ci{
304262306a36Sopenharmony_ci	static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] = {
304362306a36Sopenharmony_ci		[OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 },
304462306a36Sopenharmony_ci		[OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC },
304562306a36Sopenharmony_ci		[OVS_USERSPACE_ATTR_EGRESS_TUN_PORT] = {.type = NLA_U32 },
304662306a36Sopenharmony_ci	};
304762306a36Sopenharmony_ci	struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1];
304862306a36Sopenharmony_ci	int error;
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_ci	error = nla_parse_nested_deprecated(a, OVS_USERSPACE_ATTR_MAX, attr,
305162306a36Sopenharmony_ci					    userspace_policy, NULL);
305262306a36Sopenharmony_ci	if (error)
305362306a36Sopenharmony_ci		return error;
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci	if (!a[OVS_USERSPACE_ATTR_PID] ||
305662306a36Sopenharmony_ci	    !nla_get_u32(a[OVS_USERSPACE_ATTR_PID]))
305762306a36Sopenharmony_ci		return -EINVAL;
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci	return 0;
306062306a36Sopenharmony_ci}
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_cistatic const struct nla_policy cpl_policy[OVS_CHECK_PKT_LEN_ATTR_MAX + 1] = {
306362306a36Sopenharmony_ci	[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN] = {.type = NLA_U16 },
306462306a36Sopenharmony_ci	[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER] = {.type = NLA_NESTED },
306562306a36Sopenharmony_ci	[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL] = {.type = NLA_NESTED },
306662306a36Sopenharmony_ci};
306762306a36Sopenharmony_ci
306862306a36Sopenharmony_cistatic int validate_and_copy_check_pkt_len(struct net *net,
306962306a36Sopenharmony_ci					   const struct nlattr *attr,
307062306a36Sopenharmony_ci					   const struct sw_flow_key *key,
307162306a36Sopenharmony_ci					   struct sw_flow_actions **sfa,
307262306a36Sopenharmony_ci					   __be16 eth_type, __be16 vlan_tci,
307362306a36Sopenharmony_ci					   u32 mpls_label_count,
307462306a36Sopenharmony_ci					   bool log, bool last, u32 depth)
307562306a36Sopenharmony_ci{
307662306a36Sopenharmony_ci	const struct nlattr *acts_if_greater, *acts_if_lesser_eq;
307762306a36Sopenharmony_ci	struct nlattr *a[OVS_CHECK_PKT_LEN_ATTR_MAX + 1];
307862306a36Sopenharmony_ci	struct check_pkt_len_arg arg;
307962306a36Sopenharmony_ci	int nested_acts_start;
308062306a36Sopenharmony_ci	int start, err;
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	err = nla_parse_deprecated_strict(a, OVS_CHECK_PKT_LEN_ATTR_MAX,
308362306a36Sopenharmony_ci					  nla_data(attr), nla_len(attr),
308462306a36Sopenharmony_ci					  cpl_policy, NULL);
308562306a36Sopenharmony_ci	if (err)
308662306a36Sopenharmony_ci		return err;
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_ci	if (!a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN] ||
308962306a36Sopenharmony_ci	    !nla_get_u16(a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN]))
309062306a36Sopenharmony_ci		return -EINVAL;
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	acts_if_lesser_eq = a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL];
309362306a36Sopenharmony_ci	acts_if_greater = a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER];
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ci	/* Both the nested action should be present. */
309662306a36Sopenharmony_ci	if (!acts_if_greater || !acts_if_lesser_eq)
309762306a36Sopenharmony_ci		return -EINVAL;
309862306a36Sopenharmony_ci
309962306a36Sopenharmony_ci	/* validation done, copy the nested actions. */
310062306a36Sopenharmony_ci	start = add_nested_action_start(sfa, OVS_ACTION_ATTR_CHECK_PKT_LEN,
310162306a36Sopenharmony_ci					log);
310262306a36Sopenharmony_ci	if (start < 0)
310362306a36Sopenharmony_ci		return start;
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci	arg.pkt_len = nla_get_u16(a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN]);
310662306a36Sopenharmony_ci	arg.exec_for_lesser_equal =
310762306a36Sopenharmony_ci		last || !actions_may_change_flow(acts_if_lesser_eq);
310862306a36Sopenharmony_ci	arg.exec_for_greater =
310962306a36Sopenharmony_ci		last || !actions_may_change_flow(acts_if_greater);
311062306a36Sopenharmony_ci
311162306a36Sopenharmony_ci	err = ovs_nla_add_action(sfa, OVS_CHECK_PKT_LEN_ATTR_ARG, &arg,
311262306a36Sopenharmony_ci				 sizeof(arg), log);
311362306a36Sopenharmony_ci	if (err)
311462306a36Sopenharmony_ci		return err;
311562306a36Sopenharmony_ci
311662306a36Sopenharmony_ci	nested_acts_start = add_nested_action_start(sfa,
311762306a36Sopenharmony_ci		OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL, log);
311862306a36Sopenharmony_ci	if (nested_acts_start < 0)
311962306a36Sopenharmony_ci		return nested_acts_start;
312062306a36Sopenharmony_ci
312162306a36Sopenharmony_ci	err = __ovs_nla_copy_actions(net, acts_if_lesser_eq, key, sfa,
312262306a36Sopenharmony_ci				     eth_type, vlan_tci, mpls_label_count, log,
312362306a36Sopenharmony_ci				     depth + 1);
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	if (err)
312662306a36Sopenharmony_ci		return err;
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci	add_nested_action_end(*sfa, nested_acts_start);
312962306a36Sopenharmony_ci
313062306a36Sopenharmony_ci	nested_acts_start = add_nested_action_start(sfa,
313162306a36Sopenharmony_ci		OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER, log);
313262306a36Sopenharmony_ci	if (nested_acts_start < 0)
313362306a36Sopenharmony_ci		return nested_acts_start;
313462306a36Sopenharmony_ci
313562306a36Sopenharmony_ci	err = __ovs_nla_copy_actions(net, acts_if_greater, key, sfa,
313662306a36Sopenharmony_ci				     eth_type, vlan_tci, mpls_label_count, log,
313762306a36Sopenharmony_ci				     depth + 1);
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	if (err)
314062306a36Sopenharmony_ci		return err;
314162306a36Sopenharmony_ci
314262306a36Sopenharmony_ci	add_nested_action_end(*sfa, nested_acts_start);
314362306a36Sopenharmony_ci	add_nested_action_end(*sfa, start);
314462306a36Sopenharmony_ci	return 0;
314562306a36Sopenharmony_ci}
314662306a36Sopenharmony_ci
314762306a36Sopenharmony_cistatic int copy_action(const struct nlattr *from,
314862306a36Sopenharmony_ci		       struct sw_flow_actions **sfa, bool log)
314962306a36Sopenharmony_ci{
315062306a36Sopenharmony_ci	int totlen = NLA_ALIGN(from->nla_len);
315162306a36Sopenharmony_ci	struct nlattr *to;
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_ci	to = reserve_sfa_size(sfa, from->nla_len, log);
315462306a36Sopenharmony_ci	if (IS_ERR(to))
315562306a36Sopenharmony_ci		return PTR_ERR(to);
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci	memcpy(to, from, totlen);
315862306a36Sopenharmony_ci	return 0;
315962306a36Sopenharmony_ci}
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_cistatic int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
316262306a36Sopenharmony_ci				  const struct sw_flow_key *key,
316362306a36Sopenharmony_ci				  struct sw_flow_actions **sfa,
316462306a36Sopenharmony_ci				  __be16 eth_type, __be16 vlan_tci,
316562306a36Sopenharmony_ci				  u32 mpls_label_count, bool log,
316662306a36Sopenharmony_ci				  u32 depth)
316762306a36Sopenharmony_ci{
316862306a36Sopenharmony_ci	u8 mac_proto = ovs_key_mac_proto(key);
316962306a36Sopenharmony_ci	const struct nlattr *a;
317062306a36Sopenharmony_ci	int rem, err;
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci	if (depth > OVS_COPY_ACTIONS_MAX_DEPTH)
317362306a36Sopenharmony_ci		return -EOVERFLOW;
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
317662306a36Sopenharmony_ci		/* Expected argument lengths, (u32)-1 for variable length. */
317762306a36Sopenharmony_ci		static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {
317862306a36Sopenharmony_ci			[OVS_ACTION_ATTR_OUTPUT] = sizeof(u32),
317962306a36Sopenharmony_ci			[OVS_ACTION_ATTR_RECIRC] = sizeof(u32),
318062306a36Sopenharmony_ci			[OVS_ACTION_ATTR_USERSPACE] = (u32)-1,
318162306a36Sopenharmony_ci			[OVS_ACTION_ATTR_PUSH_MPLS] = sizeof(struct ovs_action_push_mpls),
318262306a36Sopenharmony_ci			[OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16),
318362306a36Sopenharmony_ci			[OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan),
318462306a36Sopenharmony_ci			[OVS_ACTION_ATTR_POP_VLAN] = 0,
318562306a36Sopenharmony_ci			[OVS_ACTION_ATTR_SET] = (u32)-1,
318662306a36Sopenharmony_ci			[OVS_ACTION_ATTR_SET_MASKED] = (u32)-1,
318762306a36Sopenharmony_ci			[OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
318862306a36Sopenharmony_ci			[OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash),
318962306a36Sopenharmony_ci			[OVS_ACTION_ATTR_CT] = (u32)-1,
319062306a36Sopenharmony_ci			[OVS_ACTION_ATTR_CT_CLEAR] = 0,
319162306a36Sopenharmony_ci			[OVS_ACTION_ATTR_TRUNC] = sizeof(struct ovs_action_trunc),
319262306a36Sopenharmony_ci			[OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth),
319362306a36Sopenharmony_ci			[OVS_ACTION_ATTR_POP_ETH] = 0,
319462306a36Sopenharmony_ci			[OVS_ACTION_ATTR_PUSH_NSH] = (u32)-1,
319562306a36Sopenharmony_ci			[OVS_ACTION_ATTR_POP_NSH] = 0,
319662306a36Sopenharmony_ci			[OVS_ACTION_ATTR_METER] = sizeof(u32),
319762306a36Sopenharmony_ci			[OVS_ACTION_ATTR_CLONE] = (u32)-1,
319862306a36Sopenharmony_ci			[OVS_ACTION_ATTR_CHECK_PKT_LEN] = (u32)-1,
319962306a36Sopenharmony_ci			[OVS_ACTION_ATTR_ADD_MPLS] = sizeof(struct ovs_action_add_mpls),
320062306a36Sopenharmony_ci			[OVS_ACTION_ATTR_DEC_TTL] = (u32)-1,
320162306a36Sopenharmony_ci			[OVS_ACTION_ATTR_DROP] = sizeof(u32),
320262306a36Sopenharmony_ci		};
320362306a36Sopenharmony_ci		const struct ovs_action_push_vlan *vlan;
320462306a36Sopenharmony_ci		int type = nla_type(a);
320562306a36Sopenharmony_ci		bool skip_copy;
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci		if (type > OVS_ACTION_ATTR_MAX ||
320862306a36Sopenharmony_ci		    (action_lens[type] != nla_len(a) &&
320962306a36Sopenharmony_ci		     action_lens[type] != (u32)-1))
321062306a36Sopenharmony_ci			return -EINVAL;
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci		skip_copy = false;
321362306a36Sopenharmony_ci		switch (type) {
321462306a36Sopenharmony_ci		case OVS_ACTION_ATTR_UNSPEC:
321562306a36Sopenharmony_ci			return -EINVAL;
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci		case OVS_ACTION_ATTR_USERSPACE:
321862306a36Sopenharmony_ci			err = validate_userspace(a);
321962306a36Sopenharmony_ci			if (err)
322062306a36Sopenharmony_ci				return err;
322162306a36Sopenharmony_ci			break;
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci		case OVS_ACTION_ATTR_OUTPUT:
322462306a36Sopenharmony_ci			if (nla_get_u32(a) >= DP_MAX_PORTS)
322562306a36Sopenharmony_ci				return -EINVAL;
322662306a36Sopenharmony_ci			break;
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci		case OVS_ACTION_ATTR_TRUNC: {
322962306a36Sopenharmony_ci			const struct ovs_action_trunc *trunc = nla_data(a);
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci			if (trunc->max_len < ETH_HLEN)
323262306a36Sopenharmony_ci				return -EINVAL;
323362306a36Sopenharmony_ci			break;
323462306a36Sopenharmony_ci		}
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci		case OVS_ACTION_ATTR_HASH: {
323762306a36Sopenharmony_ci			const struct ovs_action_hash *act_hash = nla_data(a);
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci			switch (act_hash->hash_alg) {
324062306a36Sopenharmony_ci			case OVS_HASH_ALG_L4:
324162306a36Sopenharmony_ci				fallthrough;
324262306a36Sopenharmony_ci			case OVS_HASH_ALG_SYM_L4:
324362306a36Sopenharmony_ci				break;
324462306a36Sopenharmony_ci			default:
324562306a36Sopenharmony_ci				return  -EINVAL;
324662306a36Sopenharmony_ci			}
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci			break;
324962306a36Sopenharmony_ci		}
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci		case OVS_ACTION_ATTR_POP_VLAN:
325262306a36Sopenharmony_ci			if (mac_proto != MAC_PROTO_ETHERNET)
325362306a36Sopenharmony_ci				return -EINVAL;
325462306a36Sopenharmony_ci			vlan_tci = htons(0);
325562306a36Sopenharmony_ci			break;
325662306a36Sopenharmony_ci
325762306a36Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_VLAN:
325862306a36Sopenharmony_ci			if (mac_proto != MAC_PROTO_ETHERNET)
325962306a36Sopenharmony_ci				return -EINVAL;
326062306a36Sopenharmony_ci			vlan = nla_data(a);
326162306a36Sopenharmony_ci			if (!eth_type_vlan(vlan->vlan_tpid))
326262306a36Sopenharmony_ci				return -EINVAL;
326362306a36Sopenharmony_ci			if (!(vlan->vlan_tci & htons(VLAN_CFI_MASK)))
326462306a36Sopenharmony_ci				return -EINVAL;
326562306a36Sopenharmony_ci			vlan_tci = vlan->vlan_tci;
326662306a36Sopenharmony_ci			break;
326762306a36Sopenharmony_ci
326862306a36Sopenharmony_ci		case OVS_ACTION_ATTR_RECIRC:
326962306a36Sopenharmony_ci			break;
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci		case OVS_ACTION_ATTR_ADD_MPLS: {
327262306a36Sopenharmony_ci			const struct ovs_action_add_mpls *mpls = nla_data(a);
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci			if (!eth_p_mpls(mpls->mpls_ethertype))
327562306a36Sopenharmony_ci				return -EINVAL;
327662306a36Sopenharmony_ci
327762306a36Sopenharmony_ci			if (mpls->tun_flags & OVS_MPLS_L3_TUNNEL_FLAG_MASK) {
327862306a36Sopenharmony_ci				if (vlan_tci & htons(VLAN_CFI_MASK) ||
327962306a36Sopenharmony_ci				    (eth_type != htons(ETH_P_IP) &&
328062306a36Sopenharmony_ci				     eth_type != htons(ETH_P_IPV6) &&
328162306a36Sopenharmony_ci				     eth_type != htons(ETH_P_ARP) &&
328262306a36Sopenharmony_ci				     eth_type != htons(ETH_P_RARP) &&
328362306a36Sopenharmony_ci				     !eth_p_mpls(eth_type)))
328462306a36Sopenharmony_ci					return -EINVAL;
328562306a36Sopenharmony_ci				mpls_label_count++;
328662306a36Sopenharmony_ci			} else {
328762306a36Sopenharmony_ci				if (mac_proto == MAC_PROTO_ETHERNET) {
328862306a36Sopenharmony_ci					mpls_label_count = 1;
328962306a36Sopenharmony_ci					mac_proto = MAC_PROTO_NONE;
329062306a36Sopenharmony_ci				} else {
329162306a36Sopenharmony_ci					mpls_label_count++;
329262306a36Sopenharmony_ci				}
329362306a36Sopenharmony_ci			}
329462306a36Sopenharmony_ci			eth_type = mpls->mpls_ethertype;
329562306a36Sopenharmony_ci			break;
329662306a36Sopenharmony_ci		}
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_MPLS: {
329962306a36Sopenharmony_ci			const struct ovs_action_push_mpls *mpls = nla_data(a);
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ci			if (!eth_p_mpls(mpls->mpls_ethertype))
330262306a36Sopenharmony_ci				return -EINVAL;
330362306a36Sopenharmony_ci			/* Prohibit push MPLS other than to a white list
330462306a36Sopenharmony_ci			 * for packets that have a known tag order.
330562306a36Sopenharmony_ci			 */
330662306a36Sopenharmony_ci			if (vlan_tci & htons(VLAN_CFI_MASK) ||
330762306a36Sopenharmony_ci			    (eth_type != htons(ETH_P_IP) &&
330862306a36Sopenharmony_ci			     eth_type != htons(ETH_P_IPV6) &&
330962306a36Sopenharmony_ci			     eth_type != htons(ETH_P_ARP) &&
331062306a36Sopenharmony_ci			     eth_type != htons(ETH_P_RARP) &&
331162306a36Sopenharmony_ci			     !eth_p_mpls(eth_type)))
331262306a36Sopenharmony_ci				return -EINVAL;
331362306a36Sopenharmony_ci			eth_type = mpls->mpls_ethertype;
331462306a36Sopenharmony_ci			mpls_label_count++;
331562306a36Sopenharmony_ci			break;
331662306a36Sopenharmony_ci		}
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci		case OVS_ACTION_ATTR_POP_MPLS: {
331962306a36Sopenharmony_ci			__be16  proto;
332062306a36Sopenharmony_ci			if (vlan_tci & htons(VLAN_CFI_MASK) ||
332162306a36Sopenharmony_ci			    !eth_p_mpls(eth_type))
332262306a36Sopenharmony_ci				return -EINVAL;
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_ci			/* Disallow subsequent L2.5+ set actions and mpls_pop
332562306a36Sopenharmony_ci			 * actions once the last MPLS label in the packet is
332662306a36Sopenharmony_ci			 * popped as there is no check here to ensure that
332762306a36Sopenharmony_ci			 * the new eth type is valid and thus set actions could
332862306a36Sopenharmony_ci			 * write off the end of the packet or otherwise corrupt
332962306a36Sopenharmony_ci			 * it.
333062306a36Sopenharmony_ci			 *
333162306a36Sopenharmony_ci			 * Support for these actions is planned using packet
333262306a36Sopenharmony_ci			 * recirculation.
333362306a36Sopenharmony_ci			 */
333462306a36Sopenharmony_ci			proto = nla_get_be16(a);
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci			if (proto == htons(ETH_P_TEB) &&
333762306a36Sopenharmony_ci			    mac_proto != MAC_PROTO_NONE)
333862306a36Sopenharmony_ci				return -EINVAL;
333962306a36Sopenharmony_ci
334062306a36Sopenharmony_ci			mpls_label_count--;
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ci			if (!eth_p_mpls(proto) || !mpls_label_count)
334362306a36Sopenharmony_ci				eth_type = htons(0);
334462306a36Sopenharmony_ci			else
334562306a36Sopenharmony_ci				eth_type =  proto;
334662306a36Sopenharmony_ci
334762306a36Sopenharmony_ci			break;
334862306a36Sopenharmony_ci		}
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci		case OVS_ACTION_ATTR_SET:
335162306a36Sopenharmony_ci			err = validate_set(a, key, sfa,
335262306a36Sopenharmony_ci					   &skip_copy, mac_proto, eth_type,
335362306a36Sopenharmony_ci					   false, log);
335462306a36Sopenharmony_ci			if (err)
335562306a36Sopenharmony_ci				return err;
335662306a36Sopenharmony_ci			break;
335762306a36Sopenharmony_ci
335862306a36Sopenharmony_ci		case OVS_ACTION_ATTR_SET_MASKED:
335962306a36Sopenharmony_ci			err = validate_set(a, key, sfa,
336062306a36Sopenharmony_ci					   &skip_copy, mac_proto, eth_type,
336162306a36Sopenharmony_ci					   true, log);
336262306a36Sopenharmony_ci			if (err)
336362306a36Sopenharmony_ci				return err;
336462306a36Sopenharmony_ci			break;
336562306a36Sopenharmony_ci
336662306a36Sopenharmony_ci		case OVS_ACTION_ATTR_SAMPLE: {
336762306a36Sopenharmony_ci			bool last = nla_is_last(a, rem);
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_ci			err = validate_and_copy_sample(net, a, key, sfa,
337062306a36Sopenharmony_ci						       eth_type, vlan_tci,
337162306a36Sopenharmony_ci						       mpls_label_count,
337262306a36Sopenharmony_ci						       log, last, depth);
337362306a36Sopenharmony_ci			if (err)
337462306a36Sopenharmony_ci				return err;
337562306a36Sopenharmony_ci			skip_copy = true;
337662306a36Sopenharmony_ci			break;
337762306a36Sopenharmony_ci		}
337862306a36Sopenharmony_ci
337962306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CT:
338062306a36Sopenharmony_ci			err = ovs_ct_copy_action(net, a, key, sfa, log);
338162306a36Sopenharmony_ci			if (err)
338262306a36Sopenharmony_ci				return err;
338362306a36Sopenharmony_ci			skip_copy = true;
338462306a36Sopenharmony_ci			break;
338562306a36Sopenharmony_ci
338662306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CT_CLEAR:
338762306a36Sopenharmony_ci			break;
338862306a36Sopenharmony_ci
338962306a36Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_ETH:
339062306a36Sopenharmony_ci			/* Disallow pushing an Ethernet header if one
339162306a36Sopenharmony_ci			 * is already present */
339262306a36Sopenharmony_ci			if (mac_proto != MAC_PROTO_NONE)
339362306a36Sopenharmony_ci				return -EINVAL;
339462306a36Sopenharmony_ci			mac_proto = MAC_PROTO_ETHERNET;
339562306a36Sopenharmony_ci			break;
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_ci		case OVS_ACTION_ATTR_POP_ETH:
339862306a36Sopenharmony_ci			if (mac_proto != MAC_PROTO_ETHERNET)
339962306a36Sopenharmony_ci				return -EINVAL;
340062306a36Sopenharmony_ci			if (vlan_tci & htons(VLAN_CFI_MASK))
340162306a36Sopenharmony_ci				return -EINVAL;
340262306a36Sopenharmony_ci			mac_proto = MAC_PROTO_NONE;
340362306a36Sopenharmony_ci			break;
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_NSH:
340662306a36Sopenharmony_ci			if (mac_proto != MAC_PROTO_ETHERNET) {
340762306a36Sopenharmony_ci				u8 next_proto;
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci				next_proto = tun_p_from_eth_p(eth_type);
341062306a36Sopenharmony_ci				if (!next_proto)
341162306a36Sopenharmony_ci					return -EINVAL;
341262306a36Sopenharmony_ci			}
341362306a36Sopenharmony_ci			mac_proto = MAC_PROTO_NONE;
341462306a36Sopenharmony_ci			if (!validate_nsh(nla_data(a), false, true, true))
341562306a36Sopenharmony_ci				return -EINVAL;
341662306a36Sopenharmony_ci			break;
341762306a36Sopenharmony_ci
341862306a36Sopenharmony_ci		case OVS_ACTION_ATTR_POP_NSH: {
341962306a36Sopenharmony_ci			__be16 inner_proto;
342062306a36Sopenharmony_ci
342162306a36Sopenharmony_ci			if (eth_type != htons(ETH_P_NSH))
342262306a36Sopenharmony_ci				return -EINVAL;
342362306a36Sopenharmony_ci			inner_proto = tun_p_to_eth_p(key->nsh.base.np);
342462306a36Sopenharmony_ci			if (!inner_proto)
342562306a36Sopenharmony_ci				return -EINVAL;
342662306a36Sopenharmony_ci			if (key->nsh.base.np == TUN_P_ETHERNET)
342762306a36Sopenharmony_ci				mac_proto = MAC_PROTO_ETHERNET;
342862306a36Sopenharmony_ci			else
342962306a36Sopenharmony_ci				mac_proto = MAC_PROTO_NONE;
343062306a36Sopenharmony_ci			break;
343162306a36Sopenharmony_ci		}
343262306a36Sopenharmony_ci
343362306a36Sopenharmony_ci		case OVS_ACTION_ATTR_METER:
343462306a36Sopenharmony_ci			/* Non-existent meters are simply ignored.  */
343562306a36Sopenharmony_ci			break;
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CLONE: {
343862306a36Sopenharmony_ci			bool last = nla_is_last(a, rem);
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci			err = validate_and_copy_clone(net, a, key, sfa,
344162306a36Sopenharmony_ci						      eth_type, vlan_tci,
344262306a36Sopenharmony_ci						      mpls_label_count,
344362306a36Sopenharmony_ci						      log, last, depth);
344462306a36Sopenharmony_ci			if (err)
344562306a36Sopenharmony_ci				return err;
344662306a36Sopenharmony_ci			skip_copy = true;
344762306a36Sopenharmony_ci			break;
344862306a36Sopenharmony_ci		}
344962306a36Sopenharmony_ci
345062306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CHECK_PKT_LEN: {
345162306a36Sopenharmony_ci			bool last = nla_is_last(a, rem);
345262306a36Sopenharmony_ci
345362306a36Sopenharmony_ci			err = validate_and_copy_check_pkt_len(net, a, key, sfa,
345462306a36Sopenharmony_ci							      eth_type,
345562306a36Sopenharmony_ci							      vlan_tci,
345662306a36Sopenharmony_ci							      mpls_label_count,
345762306a36Sopenharmony_ci							      log, last,
345862306a36Sopenharmony_ci							      depth);
345962306a36Sopenharmony_ci			if (err)
346062306a36Sopenharmony_ci				return err;
346162306a36Sopenharmony_ci			skip_copy = true;
346262306a36Sopenharmony_ci			break;
346362306a36Sopenharmony_ci		}
346462306a36Sopenharmony_ci
346562306a36Sopenharmony_ci		case OVS_ACTION_ATTR_DEC_TTL:
346662306a36Sopenharmony_ci			err = validate_and_copy_dec_ttl(net, a, key, sfa,
346762306a36Sopenharmony_ci							eth_type, vlan_tci,
346862306a36Sopenharmony_ci							mpls_label_count, log,
346962306a36Sopenharmony_ci							depth);
347062306a36Sopenharmony_ci			if (err)
347162306a36Sopenharmony_ci				return err;
347262306a36Sopenharmony_ci			skip_copy = true;
347362306a36Sopenharmony_ci			break;
347462306a36Sopenharmony_ci
347562306a36Sopenharmony_ci		case OVS_ACTION_ATTR_DROP:
347662306a36Sopenharmony_ci			if (!nla_is_last(a, rem))
347762306a36Sopenharmony_ci				return -EINVAL;
347862306a36Sopenharmony_ci			break;
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_ci		default:
348162306a36Sopenharmony_ci			OVS_NLERR(log, "Unknown Action type %d", type);
348262306a36Sopenharmony_ci			return -EINVAL;
348362306a36Sopenharmony_ci		}
348462306a36Sopenharmony_ci		if (!skip_copy) {
348562306a36Sopenharmony_ci			err = copy_action(a, sfa, log);
348662306a36Sopenharmony_ci			if (err)
348762306a36Sopenharmony_ci				return err;
348862306a36Sopenharmony_ci		}
348962306a36Sopenharmony_ci	}
349062306a36Sopenharmony_ci
349162306a36Sopenharmony_ci	if (rem > 0)
349262306a36Sopenharmony_ci		return -EINVAL;
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci	return 0;
349562306a36Sopenharmony_ci}
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci/* 'key' must be the masked key. */
349862306a36Sopenharmony_ciint ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
349962306a36Sopenharmony_ci			 const struct sw_flow_key *key,
350062306a36Sopenharmony_ci			 struct sw_flow_actions **sfa, bool log)
350162306a36Sopenharmony_ci{
350262306a36Sopenharmony_ci	int err;
350362306a36Sopenharmony_ci	u32 mpls_label_count = 0;
350462306a36Sopenharmony_ci
350562306a36Sopenharmony_ci	*sfa = nla_alloc_flow_actions(min(nla_len(attr), MAX_ACTIONS_BUFSIZE));
350662306a36Sopenharmony_ci	if (IS_ERR(*sfa))
350762306a36Sopenharmony_ci		return PTR_ERR(*sfa);
350862306a36Sopenharmony_ci
350962306a36Sopenharmony_ci	if (eth_p_mpls(key->eth.type))
351062306a36Sopenharmony_ci		mpls_label_count = hweight_long(key->mpls.num_labels_mask);
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci	(*sfa)->orig_len = nla_len(attr);
351362306a36Sopenharmony_ci	err = __ovs_nla_copy_actions(net, attr, key, sfa, key->eth.type,
351462306a36Sopenharmony_ci				     key->eth.vlan.tci, mpls_label_count, log,
351562306a36Sopenharmony_ci				     0);
351662306a36Sopenharmony_ci	if (err)
351762306a36Sopenharmony_ci		ovs_nla_free_flow_actions(*sfa);
351862306a36Sopenharmony_ci
351962306a36Sopenharmony_ci	return err;
352062306a36Sopenharmony_ci}
352162306a36Sopenharmony_ci
352262306a36Sopenharmony_cistatic int sample_action_to_attr(const struct nlattr *attr,
352362306a36Sopenharmony_ci				 struct sk_buff *skb)
352462306a36Sopenharmony_ci{
352562306a36Sopenharmony_ci	struct nlattr *start, *ac_start = NULL, *sample_arg;
352662306a36Sopenharmony_ci	int err = 0, rem = nla_len(attr);
352762306a36Sopenharmony_ci	const struct sample_arg *arg;
352862306a36Sopenharmony_ci	struct nlattr *actions;
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_ci	start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SAMPLE);
353162306a36Sopenharmony_ci	if (!start)
353262306a36Sopenharmony_ci		return -EMSGSIZE;
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_ci	sample_arg = nla_data(attr);
353562306a36Sopenharmony_ci	arg = nla_data(sample_arg);
353662306a36Sopenharmony_ci	actions = nla_next(sample_arg, &rem);
353762306a36Sopenharmony_ci
353862306a36Sopenharmony_ci	if (nla_put_u32(skb, OVS_SAMPLE_ATTR_PROBABILITY, arg->probability)) {
353962306a36Sopenharmony_ci		err = -EMSGSIZE;
354062306a36Sopenharmony_ci		goto out;
354162306a36Sopenharmony_ci	}
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_ci	ac_start = nla_nest_start_noflag(skb, OVS_SAMPLE_ATTR_ACTIONS);
354462306a36Sopenharmony_ci	if (!ac_start) {
354562306a36Sopenharmony_ci		err = -EMSGSIZE;
354662306a36Sopenharmony_ci		goto out;
354762306a36Sopenharmony_ci	}
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci	err = ovs_nla_put_actions(actions, rem, skb);
355062306a36Sopenharmony_ci
355162306a36Sopenharmony_ciout:
355262306a36Sopenharmony_ci	if (err) {
355362306a36Sopenharmony_ci		nla_nest_cancel(skb, ac_start);
355462306a36Sopenharmony_ci		nla_nest_cancel(skb, start);
355562306a36Sopenharmony_ci	} else {
355662306a36Sopenharmony_ci		nla_nest_end(skb, ac_start);
355762306a36Sopenharmony_ci		nla_nest_end(skb, start);
355862306a36Sopenharmony_ci	}
355962306a36Sopenharmony_ci
356062306a36Sopenharmony_ci	return err;
356162306a36Sopenharmony_ci}
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_cistatic int clone_action_to_attr(const struct nlattr *attr,
356462306a36Sopenharmony_ci				struct sk_buff *skb)
356562306a36Sopenharmony_ci{
356662306a36Sopenharmony_ci	struct nlattr *start;
356762306a36Sopenharmony_ci	int err = 0, rem = nla_len(attr);
356862306a36Sopenharmony_ci
356962306a36Sopenharmony_ci	start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_CLONE);
357062306a36Sopenharmony_ci	if (!start)
357162306a36Sopenharmony_ci		return -EMSGSIZE;
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci	/* Skipping the OVS_CLONE_ATTR_EXEC that is always the first attribute. */
357462306a36Sopenharmony_ci	attr = nla_next(nla_data(attr), &rem);
357562306a36Sopenharmony_ci	err = ovs_nla_put_actions(attr, rem, skb);
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_ci	if (err)
357862306a36Sopenharmony_ci		nla_nest_cancel(skb, start);
357962306a36Sopenharmony_ci	else
358062306a36Sopenharmony_ci		nla_nest_end(skb, start);
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_ci	return err;
358362306a36Sopenharmony_ci}
358462306a36Sopenharmony_ci
358562306a36Sopenharmony_cistatic int check_pkt_len_action_to_attr(const struct nlattr *attr,
358662306a36Sopenharmony_ci					struct sk_buff *skb)
358762306a36Sopenharmony_ci{
358862306a36Sopenharmony_ci	struct nlattr *start, *ac_start = NULL;
358962306a36Sopenharmony_ci	const struct check_pkt_len_arg *arg;
359062306a36Sopenharmony_ci	const struct nlattr *a, *cpl_arg;
359162306a36Sopenharmony_ci	int err = 0, rem = nla_len(attr);
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_ci	start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_CHECK_PKT_LEN);
359462306a36Sopenharmony_ci	if (!start)
359562306a36Sopenharmony_ci		return -EMSGSIZE;
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_ci	/* The first nested attribute in 'attr' is always
359862306a36Sopenharmony_ci	 * 'OVS_CHECK_PKT_LEN_ATTR_ARG'.
359962306a36Sopenharmony_ci	 */
360062306a36Sopenharmony_ci	cpl_arg = nla_data(attr);
360162306a36Sopenharmony_ci	arg = nla_data(cpl_arg);
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_ci	if (nla_put_u16(skb, OVS_CHECK_PKT_LEN_ATTR_PKT_LEN, arg->pkt_len)) {
360462306a36Sopenharmony_ci		err = -EMSGSIZE;
360562306a36Sopenharmony_ci		goto out;
360662306a36Sopenharmony_ci	}
360762306a36Sopenharmony_ci
360862306a36Sopenharmony_ci	/* Second nested attribute in 'attr' is always
360962306a36Sopenharmony_ci	 * 'OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL'.
361062306a36Sopenharmony_ci	 */
361162306a36Sopenharmony_ci	a = nla_next(cpl_arg, &rem);
361262306a36Sopenharmony_ci	ac_start =  nla_nest_start_noflag(skb,
361362306a36Sopenharmony_ci					  OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL);
361462306a36Sopenharmony_ci	if (!ac_start) {
361562306a36Sopenharmony_ci		err = -EMSGSIZE;
361662306a36Sopenharmony_ci		goto out;
361762306a36Sopenharmony_ci	}
361862306a36Sopenharmony_ci
361962306a36Sopenharmony_ci	err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb);
362062306a36Sopenharmony_ci	if (err) {
362162306a36Sopenharmony_ci		nla_nest_cancel(skb, ac_start);
362262306a36Sopenharmony_ci		goto out;
362362306a36Sopenharmony_ci	} else {
362462306a36Sopenharmony_ci		nla_nest_end(skb, ac_start);
362562306a36Sopenharmony_ci	}
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci	/* Third nested attribute in 'attr' is always
362862306a36Sopenharmony_ci	 * OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER.
362962306a36Sopenharmony_ci	 */
363062306a36Sopenharmony_ci	a = nla_next(a, &rem);
363162306a36Sopenharmony_ci	ac_start =  nla_nest_start_noflag(skb,
363262306a36Sopenharmony_ci					  OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER);
363362306a36Sopenharmony_ci	if (!ac_start) {
363462306a36Sopenharmony_ci		err = -EMSGSIZE;
363562306a36Sopenharmony_ci		goto out;
363662306a36Sopenharmony_ci	}
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci	err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb);
363962306a36Sopenharmony_ci	if (err) {
364062306a36Sopenharmony_ci		nla_nest_cancel(skb, ac_start);
364162306a36Sopenharmony_ci		goto out;
364262306a36Sopenharmony_ci	} else {
364362306a36Sopenharmony_ci		nla_nest_end(skb, ac_start);
364462306a36Sopenharmony_ci	}
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ci	nla_nest_end(skb, start);
364762306a36Sopenharmony_ci	return 0;
364862306a36Sopenharmony_ci
364962306a36Sopenharmony_ciout:
365062306a36Sopenharmony_ci	nla_nest_cancel(skb, start);
365162306a36Sopenharmony_ci	return err;
365262306a36Sopenharmony_ci}
365362306a36Sopenharmony_ci
365462306a36Sopenharmony_cistatic int dec_ttl_action_to_attr(const struct nlattr *attr,
365562306a36Sopenharmony_ci				  struct sk_buff *skb)
365662306a36Sopenharmony_ci{
365762306a36Sopenharmony_ci	struct nlattr *start, *action_start;
365862306a36Sopenharmony_ci	const struct nlattr *a;
365962306a36Sopenharmony_ci	int err = 0, rem;
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci	start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_DEC_TTL);
366262306a36Sopenharmony_ci	if (!start)
366362306a36Sopenharmony_ci		return -EMSGSIZE;
366462306a36Sopenharmony_ci
366562306a36Sopenharmony_ci	nla_for_each_attr(a, nla_data(attr), nla_len(attr), rem) {
366662306a36Sopenharmony_ci		switch (nla_type(a)) {
366762306a36Sopenharmony_ci		case OVS_DEC_TTL_ATTR_ACTION:
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci			action_start = nla_nest_start_noflag(skb, OVS_DEC_TTL_ATTR_ACTION);
367062306a36Sopenharmony_ci			if (!action_start) {
367162306a36Sopenharmony_ci				err = -EMSGSIZE;
367262306a36Sopenharmony_ci				goto out;
367362306a36Sopenharmony_ci			}
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_ci			err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb);
367662306a36Sopenharmony_ci			if (err)
367762306a36Sopenharmony_ci				goto out;
367862306a36Sopenharmony_ci
367962306a36Sopenharmony_ci			nla_nest_end(skb, action_start);
368062306a36Sopenharmony_ci			break;
368162306a36Sopenharmony_ci
368262306a36Sopenharmony_ci		default:
368362306a36Sopenharmony_ci			/* Ignore all other option to be future compatible */
368462306a36Sopenharmony_ci			break;
368562306a36Sopenharmony_ci		}
368662306a36Sopenharmony_ci	}
368762306a36Sopenharmony_ci
368862306a36Sopenharmony_ci	nla_nest_end(skb, start);
368962306a36Sopenharmony_ci	return 0;
369062306a36Sopenharmony_ci
369162306a36Sopenharmony_ciout:
369262306a36Sopenharmony_ci	nla_nest_cancel(skb, start);
369362306a36Sopenharmony_ci	return err;
369462306a36Sopenharmony_ci}
369562306a36Sopenharmony_ci
369662306a36Sopenharmony_cistatic int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
369762306a36Sopenharmony_ci{
369862306a36Sopenharmony_ci	const struct nlattr *ovs_key = nla_data(a);
369962306a36Sopenharmony_ci	int key_type = nla_type(ovs_key);
370062306a36Sopenharmony_ci	struct nlattr *start;
370162306a36Sopenharmony_ci	int err;
370262306a36Sopenharmony_ci
370362306a36Sopenharmony_ci	switch (key_type) {
370462306a36Sopenharmony_ci	case OVS_KEY_ATTR_TUNNEL_INFO: {
370562306a36Sopenharmony_ci		struct ovs_tunnel_info *ovs_tun = nla_data(ovs_key);
370662306a36Sopenharmony_ci		struct ip_tunnel_info *tun_info = &ovs_tun->tun_dst->u.tun_info;
370762306a36Sopenharmony_ci
370862306a36Sopenharmony_ci		start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SET);
370962306a36Sopenharmony_ci		if (!start)
371062306a36Sopenharmony_ci			return -EMSGSIZE;
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci		err =  ip_tun_to_nlattr(skb, &tun_info->key,
371362306a36Sopenharmony_ci					ip_tunnel_info_opts(tun_info),
371462306a36Sopenharmony_ci					tun_info->options_len,
371562306a36Sopenharmony_ci					ip_tunnel_info_af(tun_info), tun_info->mode);
371662306a36Sopenharmony_ci		if (err)
371762306a36Sopenharmony_ci			return err;
371862306a36Sopenharmony_ci		nla_nest_end(skb, start);
371962306a36Sopenharmony_ci		break;
372062306a36Sopenharmony_ci	}
372162306a36Sopenharmony_ci	default:
372262306a36Sopenharmony_ci		if (nla_put(skb, OVS_ACTION_ATTR_SET, nla_len(a), ovs_key))
372362306a36Sopenharmony_ci			return -EMSGSIZE;
372462306a36Sopenharmony_ci		break;
372562306a36Sopenharmony_ci	}
372662306a36Sopenharmony_ci
372762306a36Sopenharmony_ci	return 0;
372862306a36Sopenharmony_ci}
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_cistatic int masked_set_action_to_set_action_attr(const struct nlattr *a,
373162306a36Sopenharmony_ci						struct sk_buff *skb)
373262306a36Sopenharmony_ci{
373362306a36Sopenharmony_ci	const struct nlattr *ovs_key = nla_data(a);
373462306a36Sopenharmony_ci	struct nlattr *nla;
373562306a36Sopenharmony_ci	size_t key_len = nla_len(ovs_key) / 2;
373662306a36Sopenharmony_ci
373762306a36Sopenharmony_ci	/* Revert the conversion we did from a non-masked set action to
373862306a36Sopenharmony_ci	 * masked set action.
373962306a36Sopenharmony_ci	 */
374062306a36Sopenharmony_ci	nla = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SET);
374162306a36Sopenharmony_ci	if (!nla)
374262306a36Sopenharmony_ci		return -EMSGSIZE;
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_ci	if (nla_put(skb, nla_type(ovs_key), key_len, nla_data(ovs_key)))
374562306a36Sopenharmony_ci		return -EMSGSIZE;
374662306a36Sopenharmony_ci
374762306a36Sopenharmony_ci	nla_nest_end(skb, nla);
374862306a36Sopenharmony_ci	return 0;
374962306a36Sopenharmony_ci}
375062306a36Sopenharmony_ci
375162306a36Sopenharmony_ciint ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb)
375262306a36Sopenharmony_ci{
375362306a36Sopenharmony_ci	const struct nlattr *a;
375462306a36Sopenharmony_ci	int rem, err;
375562306a36Sopenharmony_ci
375662306a36Sopenharmony_ci	nla_for_each_attr(a, attr, len, rem) {
375762306a36Sopenharmony_ci		int type = nla_type(a);
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_ci		switch (type) {
376062306a36Sopenharmony_ci		case OVS_ACTION_ATTR_SET:
376162306a36Sopenharmony_ci			err = set_action_to_attr(a, skb);
376262306a36Sopenharmony_ci			if (err)
376362306a36Sopenharmony_ci				return err;
376462306a36Sopenharmony_ci			break;
376562306a36Sopenharmony_ci
376662306a36Sopenharmony_ci		case OVS_ACTION_ATTR_SET_TO_MASKED:
376762306a36Sopenharmony_ci			err = masked_set_action_to_set_action_attr(a, skb);
376862306a36Sopenharmony_ci			if (err)
376962306a36Sopenharmony_ci				return err;
377062306a36Sopenharmony_ci			break;
377162306a36Sopenharmony_ci
377262306a36Sopenharmony_ci		case OVS_ACTION_ATTR_SAMPLE:
377362306a36Sopenharmony_ci			err = sample_action_to_attr(a, skb);
377462306a36Sopenharmony_ci			if (err)
377562306a36Sopenharmony_ci				return err;
377662306a36Sopenharmony_ci			break;
377762306a36Sopenharmony_ci
377862306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CT:
377962306a36Sopenharmony_ci			err = ovs_ct_action_to_attr(nla_data(a), skb);
378062306a36Sopenharmony_ci			if (err)
378162306a36Sopenharmony_ci				return err;
378262306a36Sopenharmony_ci			break;
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CLONE:
378562306a36Sopenharmony_ci			err = clone_action_to_attr(a, skb);
378662306a36Sopenharmony_ci			if (err)
378762306a36Sopenharmony_ci				return err;
378862306a36Sopenharmony_ci			break;
378962306a36Sopenharmony_ci
379062306a36Sopenharmony_ci		case OVS_ACTION_ATTR_CHECK_PKT_LEN:
379162306a36Sopenharmony_ci			err = check_pkt_len_action_to_attr(a, skb);
379262306a36Sopenharmony_ci			if (err)
379362306a36Sopenharmony_ci				return err;
379462306a36Sopenharmony_ci			break;
379562306a36Sopenharmony_ci
379662306a36Sopenharmony_ci		case OVS_ACTION_ATTR_DEC_TTL:
379762306a36Sopenharmony_ci			err = dec_ttl_action_to_attr(a, skb);
379862306a36Sopenharmony_ci			if (err)
379962306a36Sopenharmony_ci				return err;
380062306a36Sopenharmony_ci			break;
380162306a36Sopenharmony_ci
380262306a36Sopenharmony_ci		default:
380362306a36Sopenharmony_ci			if (nla_put(skb, type, nla_len(a), nla_data(a)))
380462306a36Sopenharmony_ci				return -EMSGSIZE;
380562306a36Sopenharmony_ci			break;
380662306a36Sopenharmony_ci		}
380762306a36Sopenharmony_ci	}
380862306a36Sopenharmony_ci
380962306a36Sopenharmony_ci	return 0;
381062306a36Sopenharmony_ci}
3811