18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2007-2017 Nicira, Inc.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "flow.h"
98c2ecf20Sopenharmony_ci#include "datapath.h"
108c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
118c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
128c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
138c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
148c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
158c2ecf20Sopenharmony_ci#include <net/llc_pdu.h>
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/jhash.h>
188c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
198c2ecf20Sopenharmony_ci#include <linux/llc.h>
208c2ecf20Sopenharmony_ci#include <linux/module.h>
218c2ecf20Sopenharmony_ci#include <linux/in.h>
228c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
238c2ecf20Sopenharmony_ci#include <linux/if_arp.h>
248c2ecf20Sopenharmony_ci#include <linux/ip.h>
258c2ecf20Sopenharmony_ci#include <linux/ipv6.h>
268c2ecf20Sopenharmony_ci#include <linux/sctp.h>
278c2ecf20Sopenharmony_ci#include <linux/tcp.h>
288c2ecf20Sopenharmony_ci#include <linux/udp.h>
298c2ecf20Sopenharmony_ci#include <linux/icmp.h>
308c2ecf20Sopenharmony_ci#include <linux/icmpv6.h>
318c2ecf20Sopenharmony_ci#include <linux/rculist.h>
328c2ecf20Sopenharmony_ci#include <net/geneve.h>
338c2ecf20Sopenharmony_ci#include <net/ip.h>
348c2ecf20Sopenharmony_ci#include <net/ipv6.h>
358c2ecf20Sopenharmony_ci#include <net/ndisc.h>
368c2ecf20Sopenharmony_ci#include <net/mpls.h>
378c2ecf20Sopenharmony_ci#include <net/vxlan.h>
388c2ecf20Sopenharmony_ci#include <net/tun_proto.h>
398c2ecf20Sopenharmony_ci#include <net/erspan.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include "flow_netlink.h"
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistruct ovs_len_tbl {
448c2ecf20Sopenharmony_ci	int len;
458c2ecf20Sopenharmony_ci	const struct ovs_len_tbl *next;
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define OVS_ATTR_NESTED -1
498c2ecf20Sopenharmony_ci#define OVS_ATTR_VARIABLE -2
508c2ecf20Sopenharmony_ci#define OVS_COPY_ACTIONS_MAX_DEPTH 16
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic bool actions_may_change_flow(const struct nlattr *actions)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	struct nlattr *nla;
558c2ecf20Sopenharmony_ci	int rem;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	nla_for_each_nested(nla, actions, rem) {
588c2ecf20Sopenharmony_ci		u16 action = nla_type(nla);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci		switch (action) {
618c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_OUTPUT:
628c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_RECIRC:
638c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_TRUNC:
648c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_USERSPACE:
658c2ecf20Sopenharmony_ci			break;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CT:
688c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CT_CLEAR:
698c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_HASH:
708c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_POP_ETH:
718c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_POP_MPLS:
728c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_POP_NSH:
738c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_POP_VLAN:
748c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_ETH:
758c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_MPLS:
768c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_NSH:
778c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_VLAN:
788c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SAMPLE:
798c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SET:
808c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SET_MASKED:
818c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_METER:
828c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CHECK_PKT_LEN:
838c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_ADD_MPLS:
848c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_DEC_TTL:
858c2ecf20Sopenharmony_ci		default:
868c2ecf20Sopenharmony_ci			return true;
878c2ecf20Sopenharmony_ci		}
888c2ecf20Sopenharmony_ci	}
898c2ecf20Sopenharmony_ci	return false;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic void update_range(struct sw_flow_match *match,
938c2ecf20Sopenharmony_ci			 size_t offset, size_t size, bool is_mask)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	struct sw_flow_key_range *range;
968c2ecf20Sopenharmony_ci	size_t start = rounddown(offset, sizeof(long));
978c2ecf20Sopenharmony_ci	size_t end = roundup(offset + size, sizeof(long));
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (!is_mask)
1008c2ecf20Sopenharmony_ci		range = &match->range;
1018c2ecf20Sopenharmony_ci	else
1028c2ecf20Sopenharmony_ci		range = &match->mask->range;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (range->start == range->end) {
1058c2ecf20Sopenharmony_ci		range->start = start;
1068c2ecf20Sopenharmony_ci		range->end = end;
1078c2ecf20Sopenharmony_ci		return;
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (range->start > start)
1118c2ecf20Sopenharmony_ci		range->start = start;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (range->end < end)
1148c2ecf20Sopenharmony_ci		range->end = end;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#define SW_FLOW_KEY_PUT(match, field, value, is_mask) \
1188c2ecf20Sopenharmony_ci	do { \
1198c2ecf20Sopenharmony_ci		update_range(match, offsetof(struct sw_flow_key, field),    \
1208c2ecf20Sopenharmony_ci			     sizeof((match)->key->field), is_mask);	    \
1218c2ecf20Sopenharmony_ci		if (is_mask)						    \
1228c2ecf20Sopenharmony_ci			(match)->mask->key.field = value;		    \
1238c2ecf20Sopenharmony_ci		else							    \
1248c2ecf20Sopenharmony_ci			(match)->key->field = value;		            \
1258c2ecf20Sopenharmony_ci	} while (0)
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci#define SW_FLOW_KEY_MEMCPY_OFFSET(match, offset, value_p, len, is_mask)	    \
1288c2ecf20Sopenharmony_ci	do {								    \
1298c2ecf20Sopenharmony_ci		update_range(match, offset, len, is_mask);		    \
1308c2ecf20Sopenharmony_ci		if (is_mask)						    \
1318c2ecf20Sopenharmony_ci			memcpy((u8 *)&(match)->mask->key + offset, value_p, \
1328c2ecf20Sopenharmony_ci			       len);					   \
1338c2ecf20Sopenharmony_ci		else							    \
1348c2ecf20Sopenharmony_ci			memcpy((u8 *)(match)->key + offset, value_p, len);  \
1358c2ecf20Sopenharmony_ci	} while (0)
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci#define SW_FLOW_KEY_MEMCPY(match, field, value_p, len, is_mask)		      \
1388c2ecf20Sopenharmony_ci	SW_FLOW_KEY_MEMCPY_OFFSET(match, offsetof(struct sw_flow_key, field), \
1398c2ecf20Sopenharmony_ci				  value_p, len, is_mask)
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci#define SW_FLOW_KEY_MEMSET_FIELD(match, field, value, is_mask)		    \
1428c2ecf20Sopenharmony_ci	do {								    \
1438c2ecf20Sopenharmony_ci		update_range(match, offsetof(struct sw_flow_key, field),    \
1448c2ecf20Sopenharmony_ci			     sizeof((match)->key->field), is_mask);	    \
1458c2ecf20Sopenharmony_ci		if (is_mask)						    \
1468c2ecf20Sopenharmony_ci			memset((u8 *)&(match)->mask->key.field, value,      \
1478c2ecf20Sopenharmony_ci			       sizeof((match)->mask->key.field));	    \
1488c2ecf20Sopenharmony_ci		else							    \
1498c2ecf20Sopenharmony_ci			memset((u8 *)&(match)->key->field, value,           \
1508c2ecf20Sopenharmony_ci			       sizeof((match)->key->field));                \
1518c2ecf20Sopenharmony_ci	} while (0)
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic bool match_validate(const struct sw_flow_match *match,
1548c2ecf20Sopenharmony_ci			   u64 key_attrs, u64 mask_attrs, bool log)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	u64 key_expected = 0;
1578c2ecf20Sopenharmony_ci	u64 mask_allowed = key_attrs;  /* At most allow all key attributes */
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* The following mask attributes allowed only if they
1608c2ecf20Sopenharmony_ci	 * pass the validation tests. */
1618c2ecf20Sopenharmony_ci	mask_allowed &= ~((1 << OVS_KEY_ATTR_IPV4)
1628c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4)
1638c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_IPV6)
1648c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6)
1658c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_TCP)
1668c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_TCP_FLAGS)
1678c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_UDP)
1688c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_SCTP)
1698c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_ICMP)
1708c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_ICMPV6)
1718c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_ARP)
1728c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_ND)
1738c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_MPLS)
1748c2ecf20Sopenharmony_ci			| (1 << OVS_KEY_ATTR_NSH));
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	/* Always allowed mask fields. */
1778c2ecf20Sopenharmony_ci	mask_allowed |= ((1 << OVS_KEY_ATTR_TUNNEL)
1788c2ecf20Sopenharmony_ci		       | (1 << OVS_KEY_ATTR_IN_PORT)
1798c2ecf20Sopenharmony_ci		       | (1 << OVS_KEY_ATTR_ETHERTYPE));
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/* Check key attributes. */
1828c2ecf20Sopenharmony_ci	if (match->key->eth.type == htons(ETH_P_ARP)
1838c2ecf20Sopenharmony_ci			|| match->key->eth.type == htons(ETH_P_RARP)) {
1848c2ecf20Sopenharmony_ci		key_expected |= 1 << OVS_KEY_ATTR_ARP;
1858c2ecf20Sopenharmony_ci		if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
1868c2ecf20Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_ARP;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (eth_p_mpls(match->key->eth.type)) {
1908c2ecf20Sopenharmony_ci		key_expected |= 1 << OVS_KEY_ATTR_MPLS;
1918c2ecf20Sopenharmony_ci		if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
1928c2ecf20Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_MPLS;
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (match->key->eth.type == htons(ETH_P_IP)) {
1968c2ecf20Sopenharmony_ci		key_expected |= 1 << OVS_KEY_ATTR_IPV4;
1978c2ecf20Sopenharmony_ci		if (match->mask && match->mask->key.eth.type == htons(0xffff)) {
1988c2ecf20Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_IPV4;
1998c2ecf20Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4;
2008c2ecf20Sopenharmony_ci		}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) {
2038c2ecf20Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_UDP) {
2048c2ecf20Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_UDP;
2058c2ecf20Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff))
2068c2ecf20Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_UDP;
2078c2ecf20Sopenharmony_ci			}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_SCTP) {
2108c2ecf20Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_SCTP;
2118c2ecf20Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff))
2128c2ecf20Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_SCTP;
2138c2ecf20Sopenharmony_ci			}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_TCP) {
2168c2ecf20Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_TCP;
2178c2ecf20Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_TCP_FLAGS;
2188c2ecf20Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff)) {
2198c2ecf20Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_TCP;
2208c2ecf20Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_TCP_FLAGS;
2218c2ecf20Sopenharmony_ci				}
2228c2ecf20Sopenharmony_ci			}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_ICMP) {
2258c2ecf20Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_ICMP;
2268c2ecf20Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff))
2278c2ecf20Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_ICMP;
2288c2ecf20Sopenharmony_ci			}
2298c2ecf20Sopenharmony_ci		}
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (match->key->eth.type == htons(ETH_P_IPV6)) {
2338c2ecf20Sopenharmony_ci		key_expected |= 1 << OVS_KEY_ATTR_IPV6;
2348c2ecf20Sopenharmony_ci		if (match->mask && match->mask->key.eth.type == htons(0xffff)) {
2358c2ecf20Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_IPV6;
2368c2ecf20Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6;
2378c2ecf20Sopenharmony_ci		}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci		if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) {
2408c2ecf20Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_UDP) {
2418c2ecf20Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_UDP;
2428c2ecf20Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff))
2438c2ecf20Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_UDP;
2448c2ecf20Sopenharmony_ci			}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_SCTP) {
2478c2ecf20Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_SCTP;
2488c2ecf20Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff))
2498c2ecf20Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_SCTP;
2508c2ecf20Sopenharmony_ci			}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_TCP) {
2538c2ecf20Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_TCP;
2548c2ecf20Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_TCP_FLAGS;
2558c2ecf20Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff)) {
2568c2ecf20Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_TCP;
2578c2ecf20Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_TCP_FLAGS;
2588c2ecf20Sopenharmony_ci				}
2598c2ecf20Sopenharmony_ci			}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci			if (match->key->ip.proto == IPPROTO_ICMPV6) {
2628c2ecf20Sopenharmony_ci				key_expected |= 1 << OVS_KEY_ATTR_ICMPV6;
2638c2ecf20Sopenharmony_ci				if (match->mask && (match->mask->key.ip.proto == 0xff))
2648c2ecf20Sopenharmony_ci					mask_allowed |= 1 << OVS_KEY_ATTR_ICMPV6;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci				if (match->key->tp.src ==
2678c2ecf20Sopenharmony_ci						htons(NDISC_NEIGHBOUR_SOLICITATION) ||
2688c2ecf20Sopenharmony_ci				    match->key->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) {
2698c2ecf20Sopenharmony_ci					key_expected |= 1 << OVS_KEY_ATTR_ND;
2708c2ecf20Sopenharmony_ci					/* Original direction conntrack tuple
2718c2ecf20Sopenharmony_ci					 * uses the same space as the ND fields
2728c2ecf20Sopenharmony_ci					 * in the key, so both are not allowed
2738c2ecf20Sopenharmony_ci					 * at the same time.
2748c2ecf20Sopenharmony_ci					 */
2758c2ecf20Sopenharmony_ci					mask_allowed &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6);
2768c2ecf20Sopenharmony_ci					if (match->mask && (match->mask->key.tp.src == htons(0xff)))
2778c2ecf20Sopenharmony_ci						mask_allowed |= 1 << OVS_KEY_ATTR_ND;
2788c2ecf20Sopenharmony_ci				}
2798c2ecf20Sopenharmony_ci			}
2808c2ecf20Sopenharmony_ci		}
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (match->key->eth.type == htons(ETH_P_NSH)) {
2848c2ecf20Sopenharmony_ci		key_expected |= 1 << OVS_KEY_ATTR_NSH;
2858c2ecf20Sopenharmony_ci		if (match->mask &&
2868c2ecf20Sopenharmony_ci		    match->mask->key.eth.type == htons(0xffff)) {
2878c2ecf20Sopenharmony_ci			mask_allowed |= 1 << OVS_KEY_ATTR_NSH;
2888c2ecf20Sopenharmony_ci		}
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if ((key_attrs & key_expected) != key_expected) {
2928c2ecf20Sopenharmony_ci		/* Key attributes check failed. */
2938c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Missing key (keys=%llx, expected=%llx)",
2948c2ecf20Sopenharmony_ci			  (unsigned long long)key_attrs,
2958c2ecf20Sopenharmony_ci			  (unsigned long long)key_expected);
2968c2ecf20Sopenharmony_ci		return false;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	if ((mask_attrs & mask_allowed) != mask_attrs) {
3008c2ecf20Sopenharmony_ci		/* Mask attributes check failed. */
3018c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Unexpected mask (mask=%llx, allowed=%llx)",
3028c2ecf20Sopenharmony_ci			  (unsigned long long)mask_attrs,
3038c2ecf20Sopenharmony_ci			  (unsigned long long)mask_allowed);
3048c2ecf20Sopenharmony_ci		return false;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return true;
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cisize_t ovs_tun_key_attr_size(void)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	/* Whenever adding new OVS_TUNNEL_KEY_ FIELDS, we should consider
3138c2ecf20Sopenharmony_ci	 * updating this function.
3148c2ecf20Sopenharmony_ci	 */
3158c2ecf20Sopenharmony_ci	return    nla_total_size_64bit(8) /* OVS_TUNNEL_KEY_ATTR_ID */
3168c2ecf20Sopenharmony_ci		+ nla_total_size(16)   /* OVS_TUNNEL_KEY_ATTR_IPV[46]_SRC */
3178c2ecf20Sopenharmony_ci		+ nla_total_size(16)   /* OVS_TUNNEL_KEY_ATTR_IPV[46]_DST */
3188c2ecf20Sopenharmony_ci		+ nla_total_size(1)    /* OVS_TUNNEL_KEY_ATTR_TOS */
3198c2ecf20Sopenharmony_ci		+ nla_total_size(1)    /* OVS_TUNNEL_KEY_ATTR_TTL */
3208c2ecf20Sopenharmony_ci		+ nla_total_size(0)    /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
3218c2ecf20Sopenharmony_ci		+ nla_total_size(0)    /* OVS_TUNNEL_KEY_ATTR_CSUM */
3228c2ecf20Sopenharmony_ci		+ nla_total_size(0)    /* OVS_TUNNEL_KEY_ATTR_OAM */
3238c2ecf20Sopenharmony_ci		+ nla_total_size(256)  /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
3248c2ecf20Sopenharmony_ci		/* OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS and
3258c2ecf20Sopenharmony_ci		 * OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS is mutually exclusive with
3268c2ecf20Sopenharmony_ci		 * OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS and covered by it.
3278c2ecf20Sopenharmony_ci		 */
3288c2ecf20Sopenharmony_ci		+ nla_total_size(2)    /* OVS_TUNNEL_KEY_ATTR_TP_SRC */
3298c2ecf20Sopenharmony_ci		+ nla_total_size(2);   /* OVS_TUNNEL_KEY_ATTR_TP_DST */
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic size_t ovs_nsh_key_attr_size(void)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	/* Whenever adding new OVS_NSH_KEY_ FIELDS, we should consider
3358c2ecf20Sopenharmony_ci	 * updating this function.
3368c2ecf20Sopenharmony_ci	 */
3378c2ecf20Sopenharmony_ci	return  nla_total_size(NSH_BASE_HDR_LEN) /* OVS_NSH_KEY_ATTR_BASE */
3388c2ecf20Sopenharmony_ci		/* OVS_NSH_KEY_ATTR_MD1 and OVS_NSH_KEY_ATTR_MD2 are
3398c2ecf20Sopenharmony_ci		 * mutually exclusive, so the bigger one can cover
3408c2ecf20Sopenharmony_ci		 * the small one.
3418c2ecf20Sopenharmony_ci		 */
3428c2ecf20Sopenharmony_ci		+ nla_total_size(NSH_CTX_HDRS_MAX_LEN);
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cisize_t ovs_key_attr_size(void)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	/* Whenever adding new OVS_KEY_ FIELDS, we should consider
3488c2ecf20Sopenharmony_ci	 * updating this function.
3498c2ecf20Sopenharmony_ci	 */
3508c2ecf20Sopenharmony_ci	BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 29);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	return    nla_total_size(4)   /* OVS_KEY_ATTR_PRIORITY */
3538c2ecf20Sopenharmony_ci		+ nla_total_size(0)   /* OVS_KEY_ATTR_TUNNEL */
3548c2ecf20Sopenharmony_ci		  + ovs_tun_key_attr_size()
3558c2ecf20Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_IN_PORT */
3568c2ecf20Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_SKB_MARK */
3578c2ecf20Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_DP_HASH */
3588c2ecf20Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_RECIRC_ID */
3598c2ecf20Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_CT_STATE */
3608c2ecf20Sopenharmony_ci		+ nla_total_size(2)   /* OVS_KEY_ATTR_CT_ZONE */
3618c2ecf20Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_CT_MARK */
3628c2ecf20Sopenharmony_ci		+ nla_total_size(16)  /* OVS_KEY_ATTR_CT_LABELS */
3638c2ecf20Sopenharmony_ci		+ nla_total_size(40)  /* OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6 */
3648c2ecf20Sopenharmony_ci		+ nla_total_size(0)   /* OVS_KEY_ATTR_NSH */
3658c2ecf20Sopenharmony_ci		  + ovs_nsh_key_attr_size()
3668c2ecf20Sopenharmony_ci		+ nla_total_size(12)  /* OVS_KEY_ATTR_ETHERNET */
3678c2ecf20Sopenharmony_ci		+ nla_total_size(2)   /* OVS_KEY_ATTR_ETHERTYPE */
3688c2ecf20Sopenharmony_ci		+ nla_total_size(4)   /* OVS_KEY_ATTR_VLAN */
3698c2ecf20Sopenharmony_ci		+ nla_total_size(0)   /* OVS_KEY_ATTR_ENCAP */
3708c2ecf20Sopenharmony_ci		+ nla_total_size(2)   /* OVS_KEY_ATTR_ETHERTYPE */
3718c2ecf20Sopenharmony_ci		+ nla_total_size(40)  /* OVS_KEY_ATTR_IPV6 */
3728c2ecf20Sopenharmony_ci		+ nla_total_size(2)   /* OVS_KEY_ATTR_ICMPV6 */
3738c2ecf20Sopenharmony_ci		+ nla_total_size(28); /* OVS_KEY_ATTR_ND */
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic const struct ovs_len_tbl ovs_vxlan_ext_key_lens[OVS_VXLAN_EXT_MAX + 1] = {
3778c2ecf20Sopenharmony_ci	[OVS_VXLAN_EXT_GBP]	    = { .len = sizeof(u32) },
3788c2ecf20Sopenharmony_ci};
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
3818c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_ID]	    = { .len = sizeof(u64) },
3828c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_IPV4_SRC]	    = { .len = sizeof(u32) },
3838c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_IPV4_DST]	    = { .len = sizeof(u32) },
3848c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_TOS]	    = { .len = 1 },
3858c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_TTL]	    = { .len = 1 },
3868c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = { .len = 0 },
3878c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_CSUM]	    = { .len = 0 },
3888c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_TP_SRC]	    = { .len = sizeof(u16) },
3898c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_TP_DST]	    = { .len = sizeof(u16) },
3908c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_OAM]	    = { .len = 0 },
3918c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS]   = { .len = OVS_ATTR_VARIABLE },
3928c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS]    = { .len = OVS_ATTR_NESTED,
3938c2ecf20Sopenharmony_ci						.next = ovs_vxlan_ext_key_lens },
3948c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_IPV6_SRC]      = { .len = sizeof(struct in6_addr) },
3958c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_IPV6_DST]      = { .len = sizeof(struct in6_addr) },
3968c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS]   = { .len = OVS_ATTR_VARIABLE },
3978c2ecf20Sopenharmony_ci	[OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE]   = { .len = 0 },
3988c2ecf20Sopenharmony_ci};
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic const struct ovs_len_tbl
4018c2ecf20Sopenharmony_ciovs_nsh_key_attr_lens[OVS_NSH_KEY_ATTR_MAX + 1] = {
4028c2ecf20Sopenharmony_ci	[OVS_NSH_KEY_ATTR_BASE] = { .len = sizeof(struct ovs_nsh_key_base) },
4038c2ecf20Sopenharmony_ci	[OVS_NSH_KEY_ATTR_MD1]  = { .len = sizeof(struct ovs_nsh_key_md1) },
4048c2ecf20Sopenharmony_ci	[OVS_NSH_KEY_ATTR_MD2]  = { .len = OVS_ATTR_VARIABLE },
4058c2ecf20Sopenharmony_ci};
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute.  */
4088c2ecf20Sopenharmony_cistatic const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
4098c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_ENCAP]	 = { .len = OVS_ATTR_NESTED },
4108c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_PRIORITY]	 = { .len = sizeof(u32) },
4118c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_IN_PORT]	 = { .len = sizeof(u32) },
4128c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_SKB_MARK]	 = { .len = sizeof(u32) },
4138c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_ETHERNET]	 = { .len = sizeof(struct ovs_key_ethernet) },
4148c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_VLAN]	 = { .len = sizeof(__be16) },
4158c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_ETHERTYPE] = { .len = sizeof(__be16) },
4168c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_IPV4]	 = { .len = sizeof(struct ovs_key_ipv4) },
4178c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_IPV6]	 = { .len = sizeof(struct ovs_key_ipv6) },
4188c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_TCP]	 = { .len = sizeof(struct ovs_key_tcp) },
4198c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_TCP_FLAGS] = { .len = sizeof(__be16) },
4208c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_UDP]	 = { .len = sizeof(struct ovs_key_udp) },
4218c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_SCTP]	 = { .len = sizeof(struct ovs_key_sctp) },
4228c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_ICMP]	 = { .len = sizeof(struct ovs_key_icmp) },
4238c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_ICMPV6]	 = { .len = sizeof(struct ovs_key_icmpv6) },
4248c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_ARP]	 = { .len = sizeof(struct ovs_key_arp) },
4258c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_ND]	 = { .len = sizeof(struct ovs_key_nd) },
4268c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_RECIRC_ID] = { .len = sizeof(u32) },
4278c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_DP_HASH]	 = { .len = sizeof(u32) },
4288c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_TUNNEL]	 = { .len = OVS_ATTR_NESTED,
4298c2ecf20Sopenharmony_ci				     .next = ovs_tunnel_key_lens, },
4308c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_MPLS]	 = { .len = OVS_ATTR_VARIABLE },
4318c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_CT_STATE]	 = { .len = sizeof(u32) },
4328c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_CT_ZONE]	 = { .len = sizeof(u16) },
4338c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_CT_MARK]	 = { .len = sizeof(u32) },
4348c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_CT_LABELS] = { .len = sizeof(struct ovs_key_ct_labels) },
4358c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4] = {
4368c2ecf20Sopenharmony_ci		.len = sizeof(struct ovs_key_ct_tuple_ipv4) },
4378c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6] = {
4388c2ecf20Sopenharmony_ci		.len = sizeof(struct ovs_key_ct_tuple_ipv6) },
4398c2ecf20Sopenharmony_ci	[OVS_KEY_ATTR_NSH]       = { .len = OVS_ATTR_NESTED,
4408c2ecf20Sopenharmony_ci				     .next = ovs_nsh_key_attr_lens, },
4418c2ecf20Sopenharmony_ci};
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic bool check_attr_len(unsigned int attr_len, unsigned int expected_len)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	return expected_len == attr_len ||
4468c2ecf20Sopenharmony_ci	       expected_len == OVS_ATTR_NESTED ||
4478c2ecf20Sopenharmony_ci	       expected_len == OVS_ATTR_VARIABLE;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic bool is_all_zero(const u8 *fp, size_t size)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	int i;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	if (!fp)
4558c2ecf20Sopenharmony_ci		return false;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++)
4588c2ecf20Sopenharmony_ci		if (fp[i])
4598c2ecf20Sopenharmony_ci			return false;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	return true;
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic int __parse_flow_nlattrs(const struct nlattr *attr,
4658c2ecf20Sopenharmony_ci				const struct nlattr *a[],
4668c2ecf20Sopenharmony_ci				u64 *attrsp, bool log, bool nz)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	const struct nlattr *nla;
4698c2ecf20Sopenharmony_ci	u64 attrs;
4708c2ecf20Sopenharmony_ci	int rem;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	attrs = *attrsp;
4738c2ecf20Sopenharmony_ci	nla_for_each_nested(nla, attr, rem) {
4748c2ecf20Sopenharmony_ci		u16 type = nla_type(nla);
4758c2ecf20Sopenharmony_ci		int expected_len;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci		if (type > OVS_KEY_ATTR_MAX) {
4788c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Key type %d is out of range max %d",
4798c2ecf20Sopenharmony_ci				  type, OVS_KEY_ATTR_MAX);
4808c2ecf20Sopenharmony_ci			return -EINVAL;
4818c2ecf20Sopenharmony_ci		}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci		if (attrs & (1 << type)) {
4848c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Duplicate key (type %d).", type);
4858c2ecf20Sopenharmony_ci			return -EINVAL;
4868c2ecf20Sopenharmony_ci		}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci		expected_len = ovs_key_lens[type].len;
4898c2ecf20Sopenharmony_ci		if (!check_attr_len(nla_len(nla), expected_len)) {
4908c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Key %d has unexpected len %d expected %d",
4918c2ecf20Sopenharmony_ci				  type, nla_len(nla), expected_len);
4928c2ecf20Sopenharmony_ci			return -EINVAL;
4938c2ecf20Sopenharmony_ci		}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci		if (!nz || !is_all_zero(nla_data(nla), nla_len(nla))) {
4968c2ecf20Sopenharmony_ci			attrs |= 1 << type;
4978c2ecf20Sopenharmony_ci			a[type] = nla;
4988c2ecf20Sopenharmony_ci		}
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci	if (rem) {
5018c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Message has %d unknown bytes.", rem);
5028c2ecf20Sopenharmony_ci		return -EINVAL;
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	*attrsp = attrs;
5068c2ecf20Sopenharmony_ci	return 0;
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic int parse_flow_mask_nlattrs(const struct nlattr *attr,
5108c2ecf20Sopenharmony_ci				   const struct nlattr *a[], u64 *attrsp,
5118c2ecf20Sopenharmony_ci				   bool log)
5128c2ecf20Sopenharmony_ci{
5138c2ecf20Sopenharmony_ci	return __parse_flow_nlattrs(attr, a, attrsp, log, true);
5148c2ecf20Sopenharmony_ci}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ciint parse_flow_nlattrs(const struct nlattr *attr, const struct nlattr *a[],
5178c2ecf20Sopenharmony_ci		       u64 *attrsp, bool log)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	return __parse_flow_nlattrs(attr, a, attrsp, log, false);
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic int genev_tun_opt_from_nlattr(const struct nlattr *a,
5238c2ecf20Sopenharmony_ci				     struct sw_flow_match *match, bool is_mask,
5248c2ecf20Sopenharmony_ci				     bool log)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	unsigned long opt_key_offset;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	if (nla_len(a) > sizeof(match->key->tun_opts)) {
5298c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Geneve option length err (len %d, max %zu).",
5308c2ecf20Sopenharmony_ci			  nla_len(a), sizeof(match->key->tun_opts));
5318c2ecf20Sopenharmony_ci		return -EINVAL;
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	if (nla_len(a) % 4 != 0) {
5358c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Geneve opt len %d is not a multiple of 4.",
5368c2ecf20Sopenharmony_ci			  nla_len(a));
5378c2ecf20Sopenharmony_ci		return -EINVAL;
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	/* We need to record the length of the options passed
5418c2ecf20Sopenharmony_ci	 * down, otherwise packets with the same format but
5428c2ecf20Sopenharmony_ci	 * additional options will be silently matched.
5438c2ecf20Sopenharmony_ci	 */
5448c2ecf20Sopenharmony_ci	if (!is_mask) {
5458c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_opts_len, nla_len(a),
5468c2ecf20Sopenharmony_ci				false);
5478c2ecf20Sopenharmony_ci	} else {
5488c2ecf20Sopenharmony_ci		/* This is somewhat unusual because it looks at
5498c2ecf20Sopenharmony_ci		 * both the key and mask while parsing the
5508c2ecf20Sopenharmony_ci		 * attributes (and by extension assumes the key
5518c2ecf20Sopenharmony_ci		 * is parsed first). Normally, we would verify
5528c2ecf20Sopenharmony_ci		 * that each is the correct length and that the
5538c2ecf20Sopenharmony_ci		 * attributes line up in the validate function.
5548c2ecf20Sopenharmony_ci		 * However, that is difficult because this is
5558c2ecf20Sopenharmony_ci		 * variable length and we won't have the
5568c2ecf20Sopenharmony_ci		 * information later.
5578c2ecf20Sopenharmony_ci		 */
5588c2ecf20Sopenharmony_ci		if (match->key->tun_opts_len != nla_len(a)) {
5598c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Geneve option len %d != mask len %d",
5608c2ecf20Sopenharmony_ci				  match->key->tun_opts_len, nla_len(a));
5618c2ecf20Sopenharmony_ci			return -EINVAL;
5628c2ecf20Sopenharmony_ci		}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	opt_key_offset = TUN_METADATA_OFFSET(nla_len(a));
5688c2ecf20Sopenharmony_ci	SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, nla_data(a),
5698c2ecf20Sopenharmony_ci				  nla_len(a), is_mask);
5708c2ecf20Sopenharmony_ci	return 0;
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic int vxlan_tun_opt_from_nlattr(const struct nlattr *attr,
5748c2ecf20Sopenharmony_ci				     struct sw_flow_match *match, bool is_mask,
5758c2ecf20Sopenharmony_ci				     bool log)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	struct nlattr *a;
5788c2ecf20Sopenharmony_ci	int rem;
5798c2ecf20Sopenharmony_ci	unsigned long opt_key_offset;
5808c2ecf20Sopenharmony_ci	struct vxlan_metadata opts;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts));
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	memset(&opts, 0, sizeof(opts));
5858c2ecf20Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
5868c2ecf20Sopenharmony_ci		int type = nla_type(a);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci		if (type > OVS_VXLAN_EXT_MAX) {
5898c2ecf20Sopenharmony_ci			OVS_NLERR(log, "VXLAN extension %d out of range max %d",
5908c2ecf20Sopenharmony_ci				  type, OVS_VXLAN_EXT_MAX);
5918c2ecf20Sopenharmony_ci			return -EINVAL;
5928c2ecf20Sopenharmony_ci		}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci		if (!check_attr_len(nla_len(a),
5958c2ecf20Sopenharmony_ci				    ovs_vxlan_ext_key_lens[type].len)) {
5968c2ecf20Sopenharmony_ci			OVS_NLERR(log, "VXLAN extension %d has unexpected len %d expected %d",
5978c2ecf20Sopenharmony_ci				  type, nla_len(a),
5988c2ecf20Sopenharmony_ci				  ovs_vxlan_ext_key_lens[type].len);
5998c2ecf20Sopenharmony_ci			return -EINVAL;
6008c2ecf20Sopenharmony_ci		}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci		switch (type) {
6038c2ecf20Sopenharmony_ci		case OVS_VXLAN_EXT_GBP:
6048c2ecf20Sopenharmony_ci			opts.gbp = nla_get_u32(a);
6058c2ecf20Sopenharmony_ci			break;
6068c2ecf20Sopenharmony_ci		default:
6078c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Unknown VXLAN extension attribute %d",
6088c2ecf20Sopenharmony_ci				  type);
6098c2ecf20Sopenharmony_ci			return -EINVAL;
6108c2ecf20Sopenharmony_ci		}
6118c2ecf20Sopenharmony_ci	}
6128c2ecf20Sopenharmony_ci	if (rem) {
6138c2ecf20Sopenharmony_ci		OVS_NLERR(log, "VXLAN extension message has %d unknown bytes.",
6148c2ecf20Sopenharmony_ci			  rem);
6158c2ecf20Sopenharmony_ci		return -EINVAL;
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	if (!is_mask)
6198c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_opts_len, sizeof(opts), false);
6208c2ecf20Sopenharmony_ci	else
6218c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	opt_key_offset = TUN_METADATA_OFFSET(sizeof(opts));
6248c2ecf20Sopenharmony_ci	SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, &opts, sizeof(opts),
6258c2ecf20Sopenharmony_ci				  is_mask);
6268c2ecf20Sopenharmony_ci	return 0;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic int erspan_tun_opt_from_nlattr(const struct nlattr *a,
6308c2ecf20Sopenharmony_ci				      struct sw_flow_match *match, bool is_mask,
6318c2ecf20Sopenharmony_ci				      bool log)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	unsigned long opt_key_offset;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct erspan_metadata) >
6368c2ecf20Sopenharmony_ci		     sizeof(match->key->tun_opts));
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	if (nla_len(a) > sizeof(match->key->tun_opts)) {
6398c2ecf20Sopenharmony_ci		OVS_NLERR(log, "ERSPAN option length err (len %d, max %zu).",
6408c2ecf20Sopenharmony_ci			  nla_len(a), sizeof(match->key->tun_opts));
6418c2ecf20Sopenharmony_ci		return -EINVAL;
6428c2ecf20Sopenharmony_ci	}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	if (!is_mask)
6458c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_opts_len,
6468c2ecf20Sopenharmony_ci				sizeof(struct erspan_metadata), false);
6478c2ecf20Sopenharmony_ci	else
6488c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	opt_key_offset = TUN_METADATA_OFFSET(nla_len(a));
6518c2ecf20Sopenharmony_ci	SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, nla_data(a),
6528c2ecf20Sopenharmony_ci				  nla_len(a), is_mask);
6538c2ecf20Sopenharmony_ci	return 0;
6548c2ecf20Sopenharmony_ci}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_cistatic int ip_tun_from_nlattr(const struct nlattr *attr,
6578c2ecf20Sopenharmony_ci			      struct sw_flow_match *match, bool is_mask,
6588c2ecf20Sopenharmony_ci			      bool log)
6598c2ecf20Sopenharmony_ci{
6608c2ecf20Sopenharmony_ci	bool ttl = false, ipv4 = false, ipv6 = false;
6618c2ecf20Sopenharmony_ci	bool info_bridge_mode = false;
6628c2ecf20Sopenharmony_ci	__be16 tun_flags = 0;
6638c2ecf20Sopenharmony_ci	int opts_type = 0;
6648c2ecf20Sopenharmony_ci	struct nlattr *a;
6658c2ecf20Sopenharmony_ci	int rem;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
6688c2ecf20Sopenharmony_ci		int type = nla_type(a);
6698c2ecf20Sopenharmony_ci		int err;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci		if (type > OVS_TUNNEL_KEY_ATTR_MAX) {
6728c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Tunnel attr %d out of range max %d",
6738c2ecf20Sopenharmony_ci				  type, OVS_TUNNEL_KEY_ATTR_MAX);
6748c2ecf20Sopenharmony_ci			return -EINVAL;
6758c2ecf20Sopenharmony_ci		}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci		if (!check_attr_len(nla_len(a),
6788c2ecf20Sopenharmony_ci				    ovs_tunnel_key_lens[type].len)) {
6798c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d",
6808c2ecf20Sopenharmony_ci				  type, nla_len(a), ovs_tunnel_key_lens[type].len);
6818c2ecf20Sopenharmony_ci			return -EINVAL;
6828c2ecf20Sopenharmony_ci		}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci		switch (type) {
6858c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_ID:
6868c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.tun_id,
6878c2ecf20Sopenharmony_ci					nla_get_be64(a), is_mask);
6888c2ecf20Sopenharmony_ci			tun_flags |= TUNNEL_KEY;
6898c2ecf20Sopenharmony_ci			break;
6908c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
6918c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.src,
6928c2ecf20Sopenharmony_ci					nla_get_in_addr(a), is_mask);
6938c2ecf20Sopenharmony_ci			ipv4 = true;
6948c2ecf20Sopenharmony_ci			break;
6958c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
6968c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.dst,
6978c2ecf20Sopenharmony_ci					nla_get_in_addr(a), is_mask);
6988c2ecf20Sopenharmony_ci			ipv4 = true;
6998c2ecf20Sopenharmony_ci			break;
7008c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_IPV6_SRC:
7018c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.src,
7028c2ecf20Sopenharmony_ci					nla_get_in6_addr(a), is_mask);
7038c2ecf20Sopenharmony_ci			ipv6 = true;
7048c2ecf20Sopenharmony_ci			break;
7058c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_IPV6_DST:
7068c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.dst,
7078c2ecf20Sopenharmony_ci					nla_get_in6_addr(a), is_mask);
7088c2ecf20Sopenharmony_ci			ipv6 = true;
7098c2ecf20Sopenharmony_ci			break;
7108c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_TOS:
7118c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.tos,
7128c2ecf20Sopenharmony_ci					nla_get_u8(a), is_mask);
7138c2ecf20Sopenharmony_ci			break;
7148c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_TTL:
7158c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.ttl,
7168c2ecf20Sopenharmony_ci					nla_get_u8(a), is_mask);
7178c2ecf20Sopenharmony_ci			ttl = true;
7188c2ecf20Sopenharmony_ci			break;
7198c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
7208c2ecf20Sopenharmony_ci			tun_flags |= TUNNEL_DONT_FRAGMENT;
7218c2ecf20Sopenharmony_ci			break;
7228c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_CSUM:
7238c2ecf20Sopenharmony_ci			tun_flags |= TUNNEL_CSUM;
7248c2ecf20Sopenharmony_ci			break;
7258c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_TP_SRC:
7268c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.tp_src,
7278c2ecf20Sopenharmony_ci					nla_get_be16(a), is_mask);
7288c2ecf20Sopenharmony_ci			break;
7298c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_TP_DST:
7308c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, tun_key.tp_dst,
7318c2ecf20Sopenharmony_ci					nla_get_be16(a), is_mask);
7328c2ecf20Sopenharmony_ci			break;
7338c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_OAM:
7348c2ecf20Sopenharmony_ci			tun_flags |= TUNNEL_OAM;
7358c2ecf20Sopenharmony_ci			break;
7368c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
7378c2ecf20Sopenharmony_ci			if (opts_type) {
7388c2ecf20Sopenharmony_ci				OVS_NLERR(log, "Multiple metadata blocks provided");
7398c2ecf20Sopenharmony_ci				return -EINVAL;
7408c2ecf20Sopenharmony_ci			}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci			err = genev_tun_opt_from_nlattr(a, match, is_mask, log);
7438c2ecf20Sopenharmony_ci			if (err)
7448c2ecf20Sopenharmony_ci				return err;
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci			tun_flags |= TUNNEL_GENEVE_OPT;
7478c2ecf20Sopenharmony_ci			opts_type = type;
7488c2ecf20Sopenharmony_ci			break;
7498c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
7508c2ecf20Sopenharmony_ci			if (opts_type) {
7518c2ecf20Sopenharmony_ci				OVS_NLERR(log, "Multiple metadata blocks provided");
7528c2ecf20Sopenharmony_ci				return -EINVAL;
7538c2ecf20Sopenharmony_ci			}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci			err = vxlan_tun_opt_from_nlattr(a, match, is_mask, log);
7568c2ecf20Sopenharmony_ci			if (err)
7578c2ecf20Sopenharmony_ci				return err;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci			tun_flags |= TUNNEL_VXLAN_OPT;
7608c2ecf20Sopenharmony_ci			opts_type = type;
7618c2ecf20Sopenharmony_ci			break;
7628c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_PAD:
7638c2ecf20Sopenharmony_ci			break;
7648c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS:
7658c2ecf20Sopenharmony_ci			if (opts_type) {
7668c2ecf20Sopenharmony_ci				OVS_NLERR(log, "Multiple metadata blocks provided");
7678c2ecf20Sopenharmony_ci				return -EINVAL;
7688c2ecf20Sopenharmony_ci			}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci			err = erspan_tun_opt_from_nlattr(a, match, is_mask,
7718c2ecf20Sopenharmony_ci							 log);
7728c2ecf20Sopenharmony_ci			if (err)
7738c2ecf20Sopenharmony_ci				return err;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci			tun_flags |= TUNNEL_ERSPAN_OPT;
7768c2ecf20Sopenharmony_ci			opts_type = type;
7778c2ecf20Sopenharmony_ci			break;
7788c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE:
7798c2ecf20Sopenharmony_ci			info_bridge_mode = true;
7808c2ecf20Sopenharmony_ci			ipv4 = true;
7818c2ecf20Sopenharmony_ci			break;
7828c2ecf20Sopenharmony_ci		default:
7838c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Unknown IP tunnel attribute %d",
7848c2ecf20Sopenharmony_ci				  type);
7858c2ecf20Sopenharmony_ci			return -EINVAL;
7868c2ecf20Sopenharmony_ci		}
7878c2ecf20Sopenharmony_ci	}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	SW_FLOW_KEY_PUT(match, tun_key.tun_flags, tun_flags, is_mask);
7908c2ecf20Sopenharmony_ci	if (is_mask)
7918c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMSET_FIELD(match, tun_proto, 0xff, true);
7928c2ecf20Sopenharmony_ci	else
7938c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tun_proto, ipv6 ? AF_INET6 : AF_INET,
7948c2ecf20Sopenharmony_ci				false);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	if (rem > 0) {
7978c2ecf20Sopenharmony_ci		OVS_NLERR(log, "IP tunnel attribute has %d unknown bytes.",
7988c2ecf20Sopenharmony_ci			  rem);
7998c2ecf20Sopenharmony_ci		return -EINVAL;
8008c2ecf20Sopenharmony_ci	}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	if (ipv4 && ipv6) {
8038c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Mixed IPv4 and IPv6 tunnel attributes");
8048c2ecf20Sopenharmony_ci		return -EINVAL;
8058c2ecf20Sopenharmony_ci	}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	if (!is_mask) {
8088c2ecf20Sopenharmony_ci		if (!ipv4 && !ipv6) {
8098c2ecf20Sopenharmony_ci			OVS_NLERR(log, "IP tunnel dst address not specified");
8108c2ecf20Sopenharmony_ci			return -EINVAL;
8118c2ecf20Sopenharmony_ci		}
8128c2ecf20Sopenharmony_ci		if (ipv4) {
8138c2ecf20Sopenharmony_ci			if (info_bridge_mode) {
8148c2ecf20Sopenharmony_ci				if (match->key->tun_key.u.ipv4.src ||
8158c2ecf20Sopenharmony_ci				    match->key->tun_key.u.ipv4.dst ||
8168c2ecf20Sopenharmony_ci				    match->key->tun_key.tp_src ||
8178c2ecf20Sopenharmony_ci				    match->key->tun_key.tp_dst ||
8188c2ecf20Sopenharmony_ci				    match->key->tun_key.ttl ||
8198c2ecf20Sopenharmony_ci				    match->key->tun_key.tos ||
8208c2ecf20Sopenharmony_ci				    tun_flags & ~TUNNEL_KEY) {
8218c2ecf20Sopenharmony_ci					OVS_NLERR(log, "IPv4 tun info is not correct");
8228c2ecf20Sopenharmony_ci					return -EINVAL;
8238c2ecf20Sopenharmony_ci				}
8248c2ecf20Sopenharmony_ci			} else if (!match->key->tun_key.u.ipv4.dst) {
8258c2ecf20Sopenharmony_ci				OVS_NLERR(log, "IPv4 tunnel dst address is zero");
8268c2ecf20Sopenharmony_ci				return -EINVAL;
8278c2ecf20Sopenharmony_ci			}
8288c2ecf20Sopenharmony_ci		}
8298c2ecf20Sopenharmony_ci		if (ipv6 && ipv6_addr_any(&match->key->tun_key.u.ipv6.dst)) {
8308c2ecf20Sopenharmony_ci			OVS_NLERR(log, "IPv6 tunnel dst address is zero");
8318c2ecf20Sopenharmony_ci			return -EINVAL;
8328c2ecf20Sopenharmony_ci		}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci		if (!ttl && !info_bridge_mode) {
8358c2ecf20Sopenharmony_ci			OVS_NLERR(log, "IP tunnel TTL not specified.");
8368c2ecf20Sopenharmony_ci			return -EINVAL;
8378c2ecf20Sopenharmony_ci		}
8388c2ecf20Sopenharmony_ci	}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	return opts_type;
8418c2ecf20Sopenharmony_ci}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_cistatic int vxlan_opt_to_nlattr(struct sk_buff *skb,
8448c2ecf20Sopenharmony_ci			       const void *tun_opts, int swkey_tun_opts_len)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	const struct vxlan_metadata *opts = tun_opts;
8478c2ecf20Sopenharmony_ci	struct nlattr *nla;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	nla = nla_nest_start_noflag(skb, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
8508c2ecf20Sopenharmony_ci	if (!nla)
8518c2ecf20Sopenharmony_ci		return -EMSGSIZE;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, OVS_VXLAN_EXT_GBP, opts->gbp) < 0)
8548c2ecf20Sopenharmony_ci		return -EMSGSIZE;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	nla_nest_end(skb, nla);
8578c2ecf20Sopenharmony_ci	return 0;
8588c2ecf20Sopenharmony_ci}
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_cistatic int __ip_tun_to_nlattr(struct sk_buff *skb,
8618c2ecf20Sopenharmony_ci			      const struct ip_tunnel_key *output,
8628c2ecf20Sopenharmony_ci			      const void *tun_opts, int swkey_tun_opts_len,
8638c2ecf20Sopenharmony_ci			      unsigned short tun_proto, u8 mode)
8648c2ecf20Sopenharmony_ci{
8658c2ecf20Sopenharmony_ci	if (output->tun_flags & TUNNEL_KEY &&
8668c2ecf20Sopenharmony_ci	    nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id,
8678c2ecf20Sopenharmony_ci			 OVS_TUNNEL_KEY_ATTR_PAD))
8688c2ecf20Sopenharmony_ci		return -EMSGSIZE;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	if (mode & IP_TUNNEL_INFO_BRIDGE)
8718c2ecf20Sopenharmony_ci		return nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE)
8728c2ecf20Sopenharmony_ci		       ? -EMSGSIZE : 0;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	switch (tun_proto) {
8758c2ecf20Sopenharmony_ci	case AF_INET:
8768c2ecf20Sopenharmony_ci		if (output->u.ipv4.src &&
8778c2ecf20Sopenharmony_ci		    nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC,
8788c2ecf20Sopenharmony_ci				    output->u.ipv4.src))
8798c2ecf20Sopenharmony_ci			return -EMSGSIZE;
8808c2ecf20Sopenharmony_ci		if (output->u.ipv4.dst &&
8818c2ecf20Sopenharmony_ci		    nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST,
8828c2ecf20Sopenharmony_ci				    output->u.ipv4.dst))
8838c2ecf20Sopenharmony_ci			return -EMSGSIZE;
8848c2ecf20Sopenharmony_ci		break;
8858c2ecf20Sopenharmony_ci	case AF_INET6:
8868c2ecf20Sopenharmony_ci		if (!ipv6_addr_any(&output->u.ipv6.src) &&
8878c2ecf20Sopenharmony_ci		    nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_SRC,
8888c2ecf20Sopenharmony_ci				     &output->u.ipv6.src))
8898c2ecf20Sopenharmony_ci			return -EMSGSIZE;
8908c2ecf20Sopenharmony_ci		if (!ipv6_addr_any(&output->u.ipv6.dst) &&
8918c2ecf20Sopenharmony_ci		    nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_DST,
8928c2ecf20Sopenharmony_ci				     &output->u.ipv6.dst))
8938c2ecf20Sopenharmony_ci			return -EMSGSIZE;
8948c2ecf20Sopenharmony_ci		break;
8958c2ecf20Sopenharmony_ci	}
8968c2ecf20Sopenharmony_ci	if (output->tos &&
8978c2ecf20Sopenharmony_ci	    nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->tos))
8988c2ecf20Sopenharmony_ci		return -EMSGSIZE;
8998c2ecf20Sopenharmony_ci	if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, output->ttl))
9008c2ecf20Sopenharmony_ci		return -EMSGSIZE;
9018c2ecf20Sopenharmony_ci	if ((output->tun_flags & TUNNEL_DONT_FRAGMENT) &&
9028c2ecf20Sopenharmony_ci	    nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT))
9038c2ecf20Sopenharmony_ci		return -EMSGSIZE;
9048c2ecf20Sopenharmony_ci	if ((output->tun_flags & TUNNEL_CSUM) &&
9058c2ecf20Sopenharmony_ci	    nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM))
9068c2ecf20Sopenharmony_ci		return -EMSGSIZE;
9078c2ecf20Sopenharmony_ci	if (output->tp_src &&
9088c2ecf20Sopenharmony_ci	    nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_SRC, output->tp_src))
9098c2ecf20Sopenharmony_ci		return -EMSGSIZE;
9108c2ecf20Sopenharmony_ci	if (output->tp_dst &&
9118c2ecf20Sopenharmony_ci	    nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_DST, output->tp_dst))
9128c2ecf20Sopenharmony_ci		return -EMSGSIZE;
9138c2ecf20Sopenharmony_ci	if ((output->tun_flags & TUNNEL_OAM) &&
9148c2ecf20Sopenharmony_ci	    nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
9158c2ecf20Sopenharmony_ci		return -EMSGSIZE;
9168c2ecf20Sopenharmony_ci	if (swkey_tun_opts_len) {
9178c2ecf20Sopenharmony_ci		if (output->tun_flags & TUNNEL_GENEVE_OPT &&
9188c2ecf20Sopenharmony_ci		    nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
9198c2ecf20Sopenharmony_ci			    swkey_tun_opts_len, tun_opts))
9208c2ecf20Sopenharmony_ci			return -EMSGSIZE;
9218c2ecf20Sopenharmony_ci		else if (output->tun_flags & TUNNEL_VXLAN_OPT &&
9228c2ecf20Sopenharmony_ci			 vxlan_opt_to_nlattr(skb, tun_opts, swkey_tun_opts_len))
9238c2ecf20Sopenharmony_ci			return -EMSGSIZE;
9248c2ecf20Sopenharmony_ci		else if (output->tun_flags & TUNNEL_ERSPAN_OPT &&
9258c2ecf20Sopenharmony_ci			 nla_put(skb, OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS,
9268c2ecf20Sopenharmony_ci				 swkey_tun_opts_len, tun_opts))
9278c2ecf20Sopenharmony_ci			return -EMSGSIZE;
9288c2ecf20Sopenharmony_ci	}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	return 0;
9318c2ecf20Sopenharmony_ci}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_cistatic int ip_tun_to_nlattr(struct sk_buff *skb,
9348c2ecf20Sopenharmony_ci			    const struct ip_tunnel_key *output,
9358c2ecf20Sopenharmony_ci			    const void *tun_opts, int swkey_tun_opts_len,
9368c2ecf20Sopenharmony_ci			    unsigned short tun_proto, u8 mode)
9378c2ecf20Sopenharmony_ci{
9388c2ecf20Sopenharmony_ci	struct nlattr *nla;
9398c2ecf20Sopenharmony_ci	int err;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	nla = nla_nest_start_noflag(skb, OVS_KEY_ATTR_TUNNEL);
9428c2ecf20Sopenharmony_ci	if (!nla)
9438c2ecf20Sopenharmony_ci		return -EMSGSIZE;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	err = __ip_tun_to_nlattr(skb, output, tun_opts, swkey_tun_opts_len,
9468c2ecf20Sopenharmony_ci				 tun_proto, mode);
9478c2ecf20Sopenharmony_ci	if (err)
9488c2ecf20Sopenharmony_ci		return err;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	nla_nest_end(skb, nla);
9518c2ecf20Sopenharmony_ci	return 0;
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ciint ovs_nla_put_tunnel_info(struct sk_buff *skb,
9558c2ecf20Sopenharmony_ci			    struct ip_tunnel_info *tun_info)
9568c2ecf20Sopenharmony_ci{
9578c2ecf20Sopenharmony_ci	return __ip_tun_to_nlattr(skb, &tun_info->key,
9588c2ecf20Sopenharmony_ci				  ip_tunnel_info_opts(tun_info),
9598c2ecf20Sopenharmony_ci				  tun_info->options_len,
9608c2ecf20Sopenharmony_ci				  ip_tunnel_info_af(tun_info), tun_info->mode);
9618c2ecf20Sopenharmony_ci}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_cistatic int encode_vlan_from_nlattrs(struct sw_flow_match *match,
9648c2ecf20Sopenharmony_ci				    const struct nlattr *a[],
9658c2ecf20Sopenharmony_ci				    bool is_mask, bool inner)
9668c2ecf20Sopenharmony_ci{
9678c2ecf20Sopenharmony_ci	__be16 tci = 0;
9688c2ecf20Sopenharmony_ci	__be16 tpid = 0;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	if (a[OVS_KEY_ATTR_VLAN])
9718c2ecf20Sopenharmony_ci		tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	if (a[OVS_KEY_ATTR_ETHERTYPE])
9748c2ecf20Sopenharmony_ci		tpid = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	if (likely(!inner)) {
9778c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, eth.vlan.tpid, tpid, is_mask);
9788c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, eth.vlan.tci, tci, is_mask);
9798c2ecf20Sopenharmony_ci	} else {
9808c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, eth.cvlan.tpid, tpid, is_mask);
9818c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, eth.cvlan.tci, tci, is_mask);
9828c2ecf20Sopenharmony_ci	}
9838c2ecf20Sopenharmony_ci	return 0;
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_cistatic int validate_vlan_from_nlattrs(const struct sw_flow_match *match,
9878c2ecf20Sopenharmony_ci				      u64 key_attrs, bool inner,
9888c2ecf20Sopenharmony_ci				      const struct nlattr **a, bool log)
9898c2ecf20Sopenharmony_ci{
9908c2ecf20Sopenharmony_ci	__be16 tci = 0;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	if (!((key_attrs & (1 << OVS_KEY_ATTR_ETHERNET)) &&
9938c2ecf20Sopenharmony_ci	      (key_attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) &&
9948c2ecf20Sopenharmony_ci	       eth_type_vlan(nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE])))) {
9958c2ecf20Sopenharmony_ci		/* Not a VLAN. */
9968c2ecf20Sopenharmony_ci		return 0;
9978c2ecf20Sopenharmony_ci	}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	if (!((key_attrs & (1 << OVS_KEY_ATTR_VLAN)) &&
10008c2ecf20Sopenharmony_ci	      (key_attrs & (1 << OVS_KEY_ATTR_ENCAP)))) {
10018c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Invalid %s frame", (inner) ? "C-VLAN" : "VLAN");
10028c2ecf20Sopenharmony_ci		return -EINVAL;
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (a[OVS_KEY_ATTR_VLAN])
10068c2ecf20Sopenharmony_ci		tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	if (!(tci & htons(VLAN_CFI_MASK))) {
10098c2ecf20Sopenharmony_ci		if (tci) {
10108c2ecf20Sopenharmony_ci			OVS_NLERR(log, "%s TCI does not have VLAN_CFI_MASK bit set.",
10118c2ecf20Sopenharmony_ci				  (inner) ? "C-VLAN" : "VLAN");
10128c2ecf20Sopenharmony_ci			return -EINVAL;
10138c2ecf20Sopenharmony_ci		} else if (nla_len(a[OVS_KEY_ATTR_ENCAP])) {
10148c2ecf20Sopenharmony_ci			/* Corner case for truncated VLAN header. */
10158c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Truncated %s header has non-zero encap attribute.",
10168c2ecf20Sopenharmony_ci				  (inner) ? "C-VLAN" : "VLAN");
10178c2ecf20Sopenharmony_ci			return -EINVAL;
10188c2ecf20Sopenharmony_ci		}
10198c2ecf20Sopenharmony_ci	}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	return 1;
10228c2ecf20Sopenharmony_ci}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_cistatic int validate_vlan_mask_from_nlattrs(const struct sw_flow_match *match,
10258c2ecf20Sopenharmony_ci					   u64 key_attrs, bool inner,
10268c2ecf20Sopenharmony_ci					   const struct nlattr **a, bool log)
10278c2ecf20Sopenharmony_ci{
10288c2ecf20Sopenharmony_ci	__be16 tci = 0;
10298c2ecf20Sopenharmony_ci	__be16 tpid = 0;
10308c2ecf20Sopenharmony_ci	bool encap_valid = !!(match->key->eth.vlan.tci &
10318c2ecf20Sopenharmony_ci			      htons(VLAN_CFI_MASK));
10328c2ecf20Sopenharmony_ci	bool i_encap_valid = !!(match->key->eth.cvlan.tci &
10338c2ecf20Sopenharmony_ci				htons(VLAN_CFI_MASK));
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	if (!(key_attrs & (1 << OVS_KEY_ATTR_ENCAP))) {
10368c2ecf20Sopenharmony_ci		/* Not a VLAN. */
10378c2ecf20Sopenharmony_ci		return 0;
10388c2ecf20Sopenharmony_ci	}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	if ((!inner && !encap_valid) || (inner && !i_encap_valid)) {
10418c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Encap mask attribute is set for non-%s frame.",
10428c2ecf20Sopenharmony_ci			  (inner) ? "C-VLAN" : "VLAN");
10438c2ecf20Sopenharmony_ci		return -EINVAL;
10448c2ecf20Sopenharmony_ci	}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	if (a[OVS_KEY_ATTR_VLAN])
10478c2ecf20Sopenharmony_ci		tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	if (a[OVS_KEY_ATTR_ETHERTYPE])
10508c2ecf20Sopenharmony_ci		tpid = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	if (tpid != htons(0xffff)) {
10538c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Must have an exact match on %s TPID (mask=%x).",
10548c2ecf20Sopenharmony_ci			  (inner) ? "C-VLAN" : "VLAN", ntohs(tpid));
10558c2ecf20Sopenharmony_ci		return -EINVAL;
10568c2ecf20Sopenharmony_ci	}
10578c2ecf20Sopenharmony_ci	if (!(tci & htons(VLAN_CFI_MASK))) {
10588c2ecf20Sopenharmony_ci		OVS_NLERR(log, "%s TCI mask does not have exact match for VLAN_CFI_MASK bit.",
10598c2ecf20Sopenharmony_ci			  (inner) ? "C-VLAN" : "VLAN");
10608c2ecf20Sopenharmony_ci		return -EINVAL;
10618c2ecf20Sopenharmony_ci	}
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	return 1;
10648c2ecf20Sopenharmony_ci}
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_cistatic int __parse_vlan_from_nlattrs(struct sw_flow_match *match,
10678c2ecf20Sopenharmony_ci				     u64 *key_attrs, bool inner,
10688c2ecf20Sopenharmony_ci				     const struct nlattr **a, bool is_mask,
10698c2ecf20Sopenharmony_ci				     bool log)
10708c2ecf20Sopenharmony_ci{
10718c2ecf20Sopenharmony_ci	int err;
10728c2ecf20Sopenharmony_ci	const struct nlattr *encap;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	if (!is_mask)
10758c2ecf20Sopenharmony_ci		err = validate_vlan_from_nlattrs(match, *key_attrs, inner,
10768c2ecf20Sopenharmony_ci						 a, log);
10778c2ecf20Sopenharmony_ci	else
10788c2ecf20Sopenharmony_ci		err = validate_vlan_mask_from_nlattrs(match, *key_attrs, inner,
10798c2ecf20Sopenharmony_ci						      a, log);
10808c2ecf20Sopenharmony_ci	if (err <= 0)
10818c2ecf20Sopenharmony_ci		return err;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	err = encode_vlan_from_nlattrs(match, a, is_mask, inner);
10848c2ecf20Sopenharmony_ci	if (err)
10858c2ecf20Sopenharmony_ci		return err;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	*key_attrs &= ~(1 << OVS_KEY_ATTR_ENCAP);
10888c2ecf20Sopenharmony_ci	*key_attrs &= ~(1 << OVS_KEY_ATTR_VLAN);
10898c2ecf20Sopenharmony_ci	*key_attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE);
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	encap = a[OVS_KEY_ATTR_ENCAP];
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	if (!is_mask)
10948c2ecf20Sopenharmony_ci		err = parse_flow_nlattrs(encap, a, key_attrs, log);
10958c2ecf20Sopenharmony_ci	else
10968c2ecf20Sopenharmony_ci		err = parse_flow_mask_nlattrs(encap, a, key_attrs, log);
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	return err;
10998c2ecf20Sopenharmony_ci}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_cistatic int parse_vlan_from_nlattrs(struct sw_flow_match *match,
11028c2ecf20Sopenharmony_ci				   u64 *key_attrs, const struct nlattr **a,
11038c2ecf20Sopenharmony_ci				   bool is_mask, bool log)
11048c2ecf20Sopenharmony_ci{
11058c2ecf20Sopenharmony_ci	int err;
11068c2ecf20Sopenharmony_ci	bool encap_valid = false;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	err = __parse_vlan_from_nlattrs(match, key_attrs, false, a,
11098c2ecf20Sopenharmony_ci					is_mask, log);
11108c2ecf20Sopenharmony_ci	if (err)
11118c2ecf20Sopenharmony_ci		return err;
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	encap_valid = !!(match->key->eth.vlan.tci & htons(VLAN_CFI_MASK));
11148c2ecf20Sopenharmony_ci	if (encap_valid) {
11158c2ecf20Sopenharmony_ci		err = __parse_vlan_from_nlattrs(match, key_attrs, true, a,
11168c2ecf20Sopenharmony_ci						is_mask, log);
11178c2ecf20Sopenharmony_ci		if (err)
11188c2ecf20Sopenharmony_ci			return err;
11198c2ecf20Sopenharmony_ci	}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	return 0;
11228c2ecf20Sopenharmony_ci}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_cistatic int parse_eth_type_from_nlattrs(struct sw_flow_match *match,
11258c2ecf20Sopenharmony_ci				       u64 *attrs, const struct nlattr **a,
11268c2ecf20Sopenharmony_ci				       bool is_mask, bool log)
11278c2ecf20Sopenharmony_ci{
11288c2ecf20Sopenharmony_ci	__be16 eth_type;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
11318c2ecf20Sopenharmony_ci	if (is_mask) {
11328c2ecf20Sopenharmony_ci		/* Always exact match EtherType. */
11338c2ecf20Sopenharmony_ci		eth_type = htons(0xffff);
11348c2ecf20Sopenharmony_ci	} else if (!eth_proto_is_802_3(eth_type)) {
11358c2ecf20Sopenharmony_ci		OVS_NLERR(log, "EtherType %x is less than min %x",
11368c2ecf20Sopenharmony_ci				ntohs(eth_type), ETH_P_802_3_MIN);
11378c2ecf20Sopenharmony_ci		return -EINVAL;
11388c2ecf20Sopenharmony_ci	}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	SW_FLOW_KEY_PUT(match, eth.type, eth_type, is_mask);
11418c2ecf20Sopenharmony_ci	*attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE);
11428c2ecf20Sopenharmony_ci	return 0;
11438c2ecf20Sopenharmony_ci}
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_cistatic int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
11468c2ecf20Sopenharmony_ci				 u64 *attrs, const struct nlattr **a,
11478c2ecf20Sopenharmony_ci				 bool is_mask, bool log)
11488c2ecf20Sopenharmony_ci{
11498c2ecf20Sopenharmony_ci	u8 mac_proto = MAC_PROTO_ETHERNET;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_DP_HASH)) {
11528c2ecf20Sopenharmony_ci		u32 hash_val = nla_get_u32(a[OVS_KEY_ATTR_DP_HASH]);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ovs_flow_hash, hash_val, is_mask);
11558c2ecf20Sopenharmony_ci		*attrs &= ~(1 << OVS_KEY_ATTR_DP_HASH);
11568c2ecf20Sopenharmony_ci	}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_RECIRC_ID)) {
11598c2ecf20Sopenharmony_ci		u32 recirc_id = nla_get_u32(a[OVS_KEY_ATTR_RECIRC_ID]);
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, recirc_id, recirc_id, is_mask);
11628c2ecf20Sopenharmony_ci		*attrs &= ~(1 << OVS_KEY_ATTR_RECIRC_ID);
11638c2ecf20Sopenharmony_ci	}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_PRIORITY)) {
11668c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, phy.priority,
11678c2ecf20Sopenharmony_ci			  nla_get_u32(a[OVS_KEY_ATTR_PRIORITY]), is_mask);
11688c2ecf20Sopenharmony_ci		*attrs &= ~(1 << OVS_KEY_ATTR_PRIORITY);
11698c2ecf20Sopenharmony_ci	}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_IN_PORT)) {
11728c2ecf20Sopenharmony_ci		u32 in_port = nla_get_u32(a[OVS_KEY_ATTR_IN_PORT]);
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci		if (is_mask) {
11758c2ecf20Sopenharmony_ci			in_port = 0xffffffff; /* Always exact match in_port. */
11768c2ecf20Sopenharmony_ci		} else if (in_port >= DP_MAX_PORTS) {
11778c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Port %d exceeds max allowable %d",
11788c2ecf20Sopenharmony_ci				  in_port, DP_MAX_PORTS);
11798c2ecf20Sopenharmony_ci			return -EINVAL;
11808c2ecf20Sopenharmony_ci		}
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, phy.in_port, in_port, is_mask);
11838c2ecf20Sopenharmony_ci		*attrs &= ~(1 << OVS_KEY_ATTR_IN_PORT);
11848c2ecf20Sopenharmony_ci	} else if (!is_mask) {
11858c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, phy.in_port, DP_MAX_PORTS, is_mask);
11868c2ecf20Sopenharmony_ci	}
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_SKB_MARK)) {
11898c2ecf20Sopenharmony_ci		uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]);
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, phy.skb_mark, mark, is_mask);
11928c2ecf20Sopenharmony_ci		*attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK);
11938c2ecf20Sopenharmony_ci	}
11948c2ecf20Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) {
11958c2ecf20Sopenharmony_ci		if (ip_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match,
11968c2ecf20Sopenharmony_ci				       is_mask, log) < 0)
11978c2ecf20Sopenharmony_ci			return -EINVAL;
11988c2ecf20Sopenharmony_ci		*attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL);
11998c2ecf20Sopenharmony_ci	}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_CT_STATE) &&
12028c2ecf20Sopenharmony_ci	    ovs_ct_verify(net, OVS_KEY_ATTR_CT_STATE)) {
12038c2ecf20Sopenharmony_ci		u32 ct_state = nla_get_u32(a[OVS_KEY_ATTR_CT_STATE]);
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci		if (ct_state & ~CT_SUPPORTED_MASK) {
12068c2ecf20Sopenharmony_ci			OVS_NLERR(log, "ct_state flags %08x unsupported",
12078c2ecf20Sopenharmony_ci				  ct_state);
12088c2ecf20Sopenharmony_ci			return -EINVAL;
12098c2ecf20Sopenharmony_ci		}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct_state, ct_state, is_mask);
12128c2ecf20Sopenharmony_ci		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_STATE);
12138c2ecf20Sopenharmony_ci	}
12148c2ecf20Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_CT_ZONE) &&
12158c2ecf20Sopenharmony_ci	    ovs_ct_verify(net, OVS_KEY_ATTR_CT_ZONE)) {
12168c2ecf20Sopenharmony_ci		u16 ct_zone = nla_get_u16(a[OVS_KEY_ATTR_CT_ZONE]);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct_zone, ct_zone, is_mask);
12198c2ecf20Sopenharmony_ci		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE);
12208c2ecf20Sopenharmony_ci	}
12218c2ecf20Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_CT_MARK) &&
12228c2ecf20Sopenharmony_ci	    ovs_ct_verify(net, OVS_KEY_ATTR_CT_MARK)) {
12238c2ecf20Sopenharmony_ci		u32 mark = nla_get_u32(a[OVS_KEY_ATTR_CT_MARK]);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct.mark, mark, is_mask);
12268c2ecf20Sopenharmony_ci		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_MARK);
12278c2ecf20Sopenharmony_ci	}
12288c2ecf20Sopenharmony_ci	if (*attrs & (1 << OVS_KEY_ATTR_CT_LABELS) &&
12298c2ecf20Sopenharmony_ci	    ovs_ct_verify(net, OVS_KEY_ATTR_CT_LABELS)) {
12308c2ecf20Sopenharmony_ci		const struct ovs_key_ct_labels *cl;
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci		cl = nla_data(a[OVS_KEY_ATTR_CT_LABELS]);
12338c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ct.labels, cl->ct_labels,
12348c2ecf20Sopenharmony_ci				   sizeof(*cl), is_mask);
12358c2ecf20Sopenharmony_ci		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_LABELS);
12368c2ecf20Sopenharmony_ci	}
12378c2ecf20Sopenharmony_ci	if (*attrs & (1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4)) {
12388c2ecf20Sopenharmony_ci		const struct ovs_key_ct_tuple_ipv4 *ct;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci		ct = nla_data(a[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4]);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv4.ct_orig.src, ct->ipv4_src, is_mask);
12438c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv4.ct_orig.dst, ct->ipv4_dst, is_mask);
12448c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct.orig_tp.src, ct->src_port, is_mask);
12458c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct.orig_tp.dst, ct->dst_port, is_mask);
12468c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct_orig_proto, ct->ipv4_proto, is_mask);
12478c2ecf20Sopenharmony_ci		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4);
12488c2ecf20Sopenharmony_ci	}
12498c2ecf20Sopenharmony_ci	if (*attrs & (1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6)) {
12508c2ecf20Sopenharmony_ci		const struct ovs_key_ct_tuple_ipv6 *ct;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci		ct = nla_data(a[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6]);
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.ct_orig.src, &ct->ipv6_src,
12558c2ecf20Sopenharmony_ci				   sizeof(match->key->ipv6.ct_orig.src),
12568c2ecf20Sopenharmony_ci				   is_mask);
12578c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.ct_orig.dst, &ct->ipv6_dst,
12588c2ecf20Sopenharmony_ci				   sizeof(match->key->ipv6.ct_orig.dst),
12598c2ecf20Sopenharmony_ci				   is_mask);
12608c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct.orig_tp.src, ct->src_port, is_mask);
12618c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct.orig_tp.dst, ct->dst_port, is_mask);
12628c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ct_orig_proto, ct->ipv6_proto, is_mask);
12638c2ecf20Sopenharmony_ci		*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6);
12648c2ecf20Sopenharmony_ci	}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	/* For layer 3 packets the Ethernet type is provided
12678c2ecf20Sopenharmony_ci	 * and treated as metadata but no MAC addresses are provided.
12688c2ecf20Sopenharmony_ci	 */
12698c2ecf20Sopenharmony_ci	if (!(*attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) &&
12708c2ecf20Sopenharmony_ci	    (*attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)))
12718c2ecf20Sopenharmony_ci		mac_proto = MAC_PROTO_NONE;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	/* Always exact match mac_proto */
12748c2ecf20Sopenharmony_ci	SW_FLOW_KEY_PUT(match, mac_proto, is_mask ? 0xff : mac_proto, is_mask);
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	if (mac_proto == MAC_PROTO_NONE)
12778c2ecf20Sopenharmony_ci		return parse_eth_type_from_nlattrs(match, attrs, a, is_mask,
12788c2ecf20Sopenharmony_ci						   log);
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	return 0;
12818c2ecf20Sopenharmony_ci}
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ciint nsh_hdr_from_nlattr(const struct nlattr *attr,
12848c2ecf20Sopenharmony_ci			struct nshhdr *nh, size_t size)
12858c2ecf20Sopenharmony_ci{
12868c2ecf20Sopenharmony_ci	struct nlattr *a;
12878c2ecf20Sopenharmony_ci	int rem;
12888c2ecf20Sopenharmony_ci	u8 flags = 0;
12898c2ecf20Sopenharmony_ci	u8 ttl = 0;
12908c2ecf20Sopenharmony_ci	int mdlen = 0;
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	/* validate_nsh has check this, so we needn't do duplicate check here
12938c2ecf20Sopenharmony_ci	 */
12948c2ecf20Sopenharmony_ci	if (size < NSH_BASE_HDR_LEN)
12958c2ecf20Sopenharmony_ci		return -ENOBUFS;
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
12988c2ecf20Sopenharmony_ci		int type = nla_type(a);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci		switch (type) {
13018c2ecf20Sopenharmony_ci		case OVS_NSH_KEY_ATTR_BASE: {
13028c2ecf20Sopenharmony_ci			const struct ovs_nsh_key_base *base = nla_data(a);
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci			flags = base->flags;
13058c2ecf20Sopenharmony_ci			ttl = base->ttl;
13068c2ecf20Sopenharmony_ci			nh->np = base->np;
13078c2ecf20Sopenharmony_ci			nh->mdtype = base->mdtype;
13088c2ecf20Sopenharmony_ci			nh->path_hdr = base->path_hdr;
13098c2ecf20Sopenharmony_ci			break;
13108c2ecf20Sopenharmony_ci		}
13118c2ecf20Sopenharmony_ci		case OVS_NSH_KEY_ATTR_MD1:
13128c2ecf20Sopenharmony_ci			mdlen = nla_len(a);
13138c2ecf20Sopenharmony_ci			if (mdlen > size - NSH_BASE_HDR_LEN)
13148c2ecf20Sopenharmony_ci				return -ENOBUFS;
13158c2ecf20Sopenharmony_ci			memcpy(&nh->md1, nla_data(a), mdlen);
13168c2ecf20Sopenharmony_ci			break;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci		case OVS_NSH_KEY_ATTR_MD2:
13198c2ecf20Sopenharmony_ci			mdlen = nla_len(a);
13208c2ecf20Sopenharmony_ci			if (mdlen > size - NSH_BASE_HDR_LEN)
13218c2ecf20Sopenharmony_ci				return -ENOBUFS;
13228c2ecf20Sopenharmony_ci			memcpy(&nh->md2, nla_data(a), mdlen);
13238c2ecf20Sopenharmony_ci			break;
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci		default:
13268c2ecf20Sopenharmony_ci			return -EINVAL;
13278c2ecf20Sopenharmony_ci		}
13288c2ecf20Sopenharmony_ci	}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	/* nsh header length  = NSH_BASE_HDR_LEN + mdlen */
13318c2ecf20Sopenharmony_ci	nh->ver_flags_ttl_len = 0;
13328c2ecf20Sopenharmony_ci	nsh_set_flags_ttl_len(nh, flags, ttl, NSH_BASE_HDR_LEN + mdlen);
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	return 0;
13358c2ecf20Sopenharmony_ci}
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ciint nsh_key_from_nlattr(const struct nlattr *attr,
13388c2ecf20Sopenharmony_ci			struct ovs_key_nsh *nsh, struct ovs_key_nsh *nsh_mask)
13398c2ecf20Sopenharmony_ci{
13408c2ecf20Sopenharmony_ci	struct nlattr *a;
13418c2ecf20Sopenharmony_ci	int rem;
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	/* validate_nsh has check this, so we needn't do duplicate check here
13448c2ecf20Sopenharmony_ci	 */
13458c2ecf20Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
13468c2ecf20Sopenharmony_ci		int type = nla_type(a);
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci		switch (type) {
13498c2ecf20Sopenharmony_ci		case OVS_NSH_KEY_ATTR_BASE: {
13508c2ecf20Sopenharmony_ci			const struct ovs_nsh_key_base *base = nla_data(a);
13518c2ecf20Sopenharmony_ci			const struct ovs_nsh_key_base *base_mask = base + 1;
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci			nsh->base = *base;
13548c2ecf20Sopenharmony_ci			nsh_mask->base = *base_mask;
13558c2ecf20Sopenharmony_ci			break;
13568c2ecf20Sopenharmony_ci		}
13578c2ecf20Sopenharmony_ci		case OVS_NSH_KEY_ATTR_MD1: {
13588c2ecf20Sopenharmony_ci			const struct ovs_nsh_key_md1 *md1 = nla_data(a);
13598c2ecf20Sopenharmony_ci			const struct ovs_nsh_key_md1 *md1_mask = md1 + 1;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci			memcpy(nsh->context, md1->context, sizeof(*md1));
13628c2ecf20Sopenharmony_ci			memcpy(nsh_mask->context, md1_mask->context,
13638c2ecf20Sopenharmony_ci			       sizeof(*md1_mask));
13648c2ecf20Sopenharmony_ci			break;
13658c2ecf20Sopenharmony_ci		}
13668c2ecf20Sopenharmony_ci		case OVS_NSH_KEY_ATTR_MD2:
13678c2ecf20Sopenharmony_ci			/* Not supported yet */
13688c2ecf20Sopenharmony_ci			return -ENOTSUPP;
13698c2ecf20Sopenharmony_ci		default:
13708c2ecf20Sopenharmony_ci			return -EINVAL;
13718c2ecf20Sopenharmony_ci		}
13728c2ecf20Sopenharmony_ci	}
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	return 0;
13758c2ecf20Sopenharmony_ci}
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_cistatic int nsh_key_put_from_nlattr(const struct nlattr *attr,
13788c2ecf20Sopenharmony_ci				   struct sw_flow_match *match, bool is_mask,
13798c2ecf20Sopenharmony_ci				   bool is_push_nsh, bool log)
13808c2ecf20Sopenharmony_ci{
13818c2ecf20Sopenharmony_ci	struct nlattr *a;
13828c2ecf20Sopenharmony_ci	int rem;
13838c2ecf20Sopenharmony_ci	bool has_base = false;
13848c2ecf20Sopenharmony_ci	bool has_md1 = false;
13858c2ecf20Sopenharmony_ci	bool has_md2 = false;
13868c2ecf20Sopenharmony_ci	u8 mdtype = 0;
13878c2ecf20Sopenharmony_ci	int mdlen = 0;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	if (WARN_ON(is_push_nsh && is_mask))
13908c2ecf20Sopenharmony_ci		return -EINVAL;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
13938c2ecf20Sopenharmony_ci		int type = nla_type(a);
13948c2ecf20Sopenharmony_ci		int i;
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci		if (type > OVS_NSH_KEY_ATTR_MAX) {
13978c2ecf20Sopenharmony_ci			OVS_NLERR(log, "nsh attr %d is out of range max %d",
13988c2ecf20Sopenharmony_ci				  type, OVS_NSH_KEY_ATTR_MAX);
13998c2ecf20Sopenharmony_ci			return -EINVAL;
14008c2ecf20Sopenharmony_ci		}
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci		if (!check_attr_len(nla_len(a),
14038c2ecf20Sopenharmony_ci				    ovs_nsh_key_attr_lens[type].len)) {
14048c2ecf20Sopenharmony_ci			OVS_NLERR(
14058c2ecf20Sopenharmony_ci			    log,
14068c2ecf20Sopenharmony_ci			    "nsh attr %d has unexpected len %d expected %d",
14078c2ecf20Sopenharmony_ci			    type,
14088c2ecf20Sopenharmony_ci			    nla_len(a),
14098c2ecf20Sopenharmony_ci			    ovs_nsh_key_attr_lens[type].len
14108c2ecf20Sopenharmony_ci			);
14118c2ecf20Sopenharmony_ci			return -EINVAL;
14128c2ecf20Sopenharmony_ci		}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci		switch (type) {
14158c2ecf20Sopenharmony_ci		case OVS_NSH_KEY_ATTR_BASE: {
14168c2ecf20Sopenharmony_ci			const struct ovs_nsh_key_base *base = nla_data(a);
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci			has_base = true;
14198c2ecf20Sopenharmony_ci			mdtype = base->mdtype;
14208c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, nsh.base.flags,
14218c2ecf20Sopenharmony_ci					base->flags, is_mask);
14228c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, nsh.base.ttl,
14238c2ecf20Sopenharmony_ci					base->ttl, is_mask);
14248c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, nsh.base.mdtype,
14258c2ecf20Sopenharmony_ci					base->mdtype, is_mask);
14268c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, nsh.base.np,
14278c2ecf20Sopenharmony_ci					base->np, is_mask);
14288c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, nsh.base.path_hdr,
14298c2ecf20Sopenharmony_ci					base->path_hdr, is_mask);
14308c2ecf20Sopenharmony_ci			break;
14318c2ecf20Sopenharmony_ci		}
14328c2ecf20Sopenharmony_ci		case OVS_NSH_KEY_ATTR_MD1: {
14338c2ecf20Sopenharmony_ci			const struct ovs_nsh_key_md1 *md1 = nla_data(a);
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci			has_md1 = true;
14368c2ecf20Sopenharmony_ci			for (i = 0; i < NSH_MD1_CONTEXT_SIZE; i++)
14378c2ecf20Sopenharmony_ci				SW_FLOW_KEY_PUT(match, nsh.context[i],
14388c2ecf20Sopenharmony_ci						md1->context[i], is_mask);
14398c2ecf20Sopenharmony_ci			break;
14408c2ecf20Sopenharmony_ci		}
14418c2ecf20Sopenharmony_ci		case OVS_NSH_KEY_ATTR_MD2:
14428c2ecf20Sopenharmony_ci			if (!is_push_nsh) /* Not supported MD type 2 yet */
14438c2ecf20Sopenharmony_ci				return -ENOTSUPP;
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci			has_md2 = true;
14468c2ecf20Sopenharmony_ci			mdlen = nla_len(a);
14478c2ecf20Sopenharmony_ci			if (mdlen > NSH_CTX_HDRS_MAX_LEN || mdlen <= 0) {
14488c2ecf20Sopenharmony_ci				OVS_NLERR(
14498c2ecf20Sopenharmony_ci				    log,
14508c2ecf20Sopenharmony_ci				    "Invalid MD length %d for MD type %d",
14518c2ecf20Sopenharmony_ci				    mdlen,
14528c2ecf20Sopenharmony_ci				    mdtype
14538c2ecf20Sopenharmony_ci				);
14548c2ecf20Sopenharmony_ci				return -EINVAL;
14558c2ecf20Sopenharmony_ci			}
14568c2ecf20Sopenharmony_ci			break;
14578c2ecf20Sopenharmony_ci		default:
14588c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Unknown nsh attribute %d",
14598c2ecf20Sopenharmony_ci				  type);
14608c2ecf20Sopenharmony_ci			return -EINVAL;
14618c2ecf20Sopenharmony_ci		}
14628c2ecf20Sopenharmony_ci	}
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	if (rem > 0) {
14658c2ecf20Sopenharmony_ci		OVS_NLERR(log, "nsh attribute has %d unknown bytes.", rem);
14668c2ecf20Sopenharmony_ci		return -EINVAL;
14678c2ecf20Sopenharmony_ci	}
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	if (has_md1 && has_md2) {
14708c2ecf20Sopenharmony_ci		OVS_NLERR(
14718c2ecf20Sopenharmony_ci		    1,
14728c2ecf20Sopenharmony_ci		    "invalid nsh attribute: md1 and md2 are exclusive."
14738c2ecf20Sopenharmony_ci		);
14748c2ecf20Sopenharmony_ci		return -EINVAL;
14758c2ecf20Sopenharmony_ci	}
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	if (!is_mask) {
14788c2ecf20Sopenharmony_ci		if ((has_md1 && mdtype != NSH_M_TYPE1) ||
14798c2ecf20Sopenharmony_ci		    (has_md2 && mdtype != NSH_M_TYPE2)) {
14808c2ecf20Sopenharmony_ci			OVS_NLERR(1, "nsh attribute has unmatched MD type %d.",
14818c2ecf20Sopenharmony_ci				  mdtype);
14828c2ecf20Sopenharmony_ci			return -EINVAL;
14838c2ecf20Sopenharmony_ci		}
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci		if (is_push_nsh &&
14868c2ecf20Sopenharmony_ci		    (!has_base || (!has_md1 && !has_md2))) {
14878c2ecf20Sopenharmony_ci			OVS_NLERR(
14888c2ecf20Sopenharmony_ci			    1,
14898c2ecf20Sopenharmony_ci			    "push_nsh: missing base or metadata attributes"
14908c2ecf20Sopenharmony_ci			);
14918c2ecf20Sopenharmony_ci			return -EINVAL;
14928c2ecf20Sopenharmony_ci		}
14938c2ecf20Sopenharmony_ci	}
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	return 0;
14968c2ecf20Sopenharmony_ci}
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_cistatic int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
14998c2ecf20Sopenharmony_ci				u64 attrs, const struct nlattr **a,
15008c2ecf20Sopenharmony_ci				bool is_mask, bool log)
15018c2ecf20Sopenharmony_ci{
15028c2ecf20Sopenharmony_ci	int err;
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	err = metadata_from_nlattrs(net, match, &attrs, a, is_mask, log);
15058c2ecf20Sopenharmony_ci	if (err)
15068c2ecf20Sopenharmony_ci		return err;
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_ETHERNET)) {
15098c2ecf20Sopenharmony_ci		const struct ovs_key_ethernet *eth_key;
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci		eth_key = nla_data(a[OVS_KEY_ATTR_ETHERNET]);
15128c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, eth.src,
15138c2ecf20Sopenharmony_ci				eth_key->eth_src, ETH_ALEN, is_mask);
15148c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, eth.dst,
15158c2ecf20Sopenharmony_ci				eth_key->eth_dst, ETH_ALEN, is_mask);
15168c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_ETHERNET);
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci		if (attrs & (1 << OVS_KEY_ATTR_VLAN)) {
15198c2ecf20Sopenharmony_ci			/* VLAN attribute is always parsed before getting here since it
15208c2ecf20Sopenharmony_ci			 * may occur multiple times.
15218c2ecf20Sopenharmony_ci			 */
15228c2ecf20Sopenharmony_ci			OVS_NLERR(log, "VLAN attribute unexpected.");
15238c2ecf20Sopenharmony_ci			return -EINVAL;
15248c2ecf20Sopenharmony_ci		}
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci		if (attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) {
15278c2ecf20Sopenharmony_ci			err = parse_eth_type_from_nlattrs(match, &attrs, a, is_mask,
15288c2ecf20Sopenharmony_ci							  log);
15298c2ecf20Sopenharmony_ci			if (err)
15308c2ecf20Sopenharmony_ci				return err;
15318c2ecf20Sopenharmony_ci		} else if (!is_mask) {
15328c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2), is_mask);
15338c2ecf20Sopenharmony_ci		}
15348c2ecf20Sopenharmony_ci	} else if (!match->key->eth.type) {
15358c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Either Ethernet header or EtherType is required.");
15368c2ecf20Sopenharmony_ci		return -EINVAL;
15378c2ecf20Sopenharmony_ci	}
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_IPV4)) {
15408c2ecf20Sopenharmony_ci		const struct ovs_key_ipv4 *ipv4_key;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci		ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]);
15438c2ecf20Sopenharmony_ci		if (!is_mask && ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) {
15448c2ecf20Sopenharmony_ci			OVS_NLERR(log, "IPv4 frag type %d is out of range max %d",
15458c2ecf20Sopenharmony_ci				  ipv4_key->ipv4_frag, OVS_FRAG_TYPE_MAX);
15468c2ecf20Sopenharmony_ci			return -EINVAL;
15478c2ecf20Sopenharmony_ci		}
15488c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.proto,
15498c2ecf20Sopenharmony_ci				ipv4_key->ipv4_proto, is_mask);
15508c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.tos,
15518c2ecf20Sopenharmony_ci				ipv4_key->ipv4_tos, is_mask);
15528c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.ttl,
15538c2ecf20Sopenharmony_ci				ipv4_key->ipv4_ttl, is_mask);
15548c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.frag,
15558c2ecf20Sopenharmony_ci				ipv4_key->ipv4_frag, is_mask);
15568c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv4.addr.src,
15578c2ecf20Sopenharmony_ci				ipv4_key->ipv4_src, is_mask);
15588c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv4.addr.dst,
15598c2ecf20Sopenharmony_ci				ipv4_key->ipv4_dst, is_mask);
15608c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_IPV4);
15618c2ecf20Sopenharmony_ci	}
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_IPV6)) {
15648c2ecf20Sopenharmony_ci		const struct ovs_key_ipv6 *ipv6_key;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci		ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]);
15678c2ecf20Sopenharmony_ci		if (!is_mask && ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) {
15688c2ecf20Sopenharmony_ci			OVS_NLERR(log, "IPv6 frag type %d is out of range max %d",
15698c2ecf20Sopenharmony_ci				  ipv6_key->ipv6_frag, OVS_FRAG_TYPE_MAX);
15708c2ecf20Sopenharmony_ci			return -EINVAL;
15718c2ecf20Sopenharmony_ci		}
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci		if (!is_mask && ipv6_key->ipv6_label & htonl(0xFFF00000)) {
15748c2ecf20Sopenharmony_ci			OVS_NLERR(log, "IPv6 flow label %x is out of range (max=%x)",
15758c2ecf20Sopenharmony_ci				  ntohl(ipv6_key->ipv6_label), (1 << 20) - 1);
15768c2ecf20Sopenharmony_ci			return -EINVAL;
15778c2ecf20Sopenharmony_ci		}
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv6.label,
15808c2ecf20Sopenharmony_ci				ipv6_key->ipv6_label, is_mask);
15818c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.proto,
15828c2ecf20Sopenharmony_ci				ipv6_key->ipv6_proto, is_mask);
15838c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.tos,
15848c2ecf20Sopenharmony_ci				ipv6_key->ipv6_tclass, is_mask);
15858c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.ttl,
15868c2ecf20Sopenharmony_ci				ipv6_key->ipv6_hlimit, is_mask);
15878c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.frag,
15888c2ecf20Sopenharmony_ci				ipv6_key->ipv6_frag, is_mask);
15898c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.addr.src,
15908c2ecf20Sopenharmony_ci				ipv6_key->ipv6_src,
15918c2ecf20Sopenharmony_ci				sizeof(match->key->ipv6.addr.src),
15928c2ecf20Sopenharmony_ci				is_mask);
15938c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.addr.dst,
15948c2ecf20Sopenharmony_ci				ipv6_key->ipv6_dst,
15958c2ecf20Sopenharmony_ci				sizeof(match->key->ipv6.addr.dst),
15968c2ecf20Sopenharmony_ci				is_mask);
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_IPV6);
15998c2ecf20Sopenharmony_ci	}
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_ARP)) {
16028c2ecf20Sopenharmony_ci		const struct ovs_key_arp *arp_key;
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci		arp_key = nla_data(a[OVS_KEY_ATTR_ARP]);
16058c2ecf20Sopenharmony_ci		if (!is_mask && (arp_key->arp_op & htons(0xff00))) {
16068c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Unknown ARP opcode (opcode=%d).",
16078c2ecf20Sopenharmony_ci				  arp_key->arp_op);
16088c2ecf20Sopenharmony_ci			return -EINVAL;
16098c2ecf20Sopenharmony_ci		}
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv4.addr.src,
16128c2ecf20Sopenharmony_ci				arp_key->arp_sip, is_mask);
16138c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ipv4.addr.dst,
16148c2ecf20Sopenharmony_ci			arp_key->arp_tip, is_mask);
16158c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, ip.proto,
16168c2ecf20Sopenharmony_ci				ntohs(arp_key->arp_op), is_mask);
16178c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv4.arp.sha,
16188c2ecf20Sopenharmony_ci				arp_key->arp_sha, ETH_ALEN, is_mask);
16198c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv4.arp.tha,
16208c2ecf20Sopenharmony_ci				arp_key->arp_tha, ETH_ALEN, is_mask);
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_ARP);
16238c2ecf20Sopenharmony_ci	}
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_NSH)) {
16268c2ecf20Sopenharmony_ci		if (nsh_key_put_from_nlattr(a[OVS_KEY_ATTR_NSH], match,
16278c2ecf20Sopenharmony_ci					    is_mask, false, log) < 0)
16288c2ecf20Sopenharmony_ci			return -EINVAL;
16298c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_NSH);
16308c2ecf20Sopenharmony_ci	}
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_MPLS)) {
16338c2ecf20Sopenharmony_ci		const struct ovs_key_mpls *mpls_key;
16348c2ecf20Sopenharmony_ci		u32 hdr_len;
16358c2ecf20Sopenharmony_ci		u32 label_count, label_count_mask, i;
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci		mpls_key = nla_data(a[OVS_KEY_ATTR_MPLS]);
16388c2ecf20Sopenharmony_ci		hdr_len = nla_len(a[OVS_KEY_ATTR_MPLS]);
16398c2ecf20Sopenharmony_ci		label_count = hdr_len / sizeof(struct ovs_key_mpls);
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci		if (label_count == 0 || label_count > MPLS_LABEL_DEPTH ||
16428c2ecf20Sopenharmony_ci		    hdr_len % sizeof(struct ovs_key_mpls))
16438c2ecf20Sopenharmony_ci			return -EINVAL;
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci		label_count_mask =  GENMASK(label_count - 1, 0);
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci		for (i = 0 ; i < label_count; i++)
16488c2ecf20Sopenharmony_ci			SW_FLOW_KEY_PUT(match, mpls.lse[i],
16498c2ecf20Sopenharmony_ci					mpls_key[i].mpls_lse, is_mask);
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, mpls.num_labels_mask,
16528c2ecf20Sopenharmony_ci				label_count_mask, is_mask);
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_MPLS);
16558c2ecf20Sopenharmony_ci	 }
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_TCP)) {
16588c2ecf20Sopenharmony_ci		const struct ovs_key_tcp *tcp_key;
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci		tcp_key = nla_data(a[OVS_KEY_ATTR_TCP]);
16618c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.src, tcp_key->tcp_src, is_mask);
16628c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.dst, tcp_key->tcp_dst, is_mask);
16638c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_TCP);
16648c2ecf20Sopenharmony_ci	}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_TCP_FLAGS)) {
16678c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.flags,
16688c2ecf20Sopenharmony_ci				nla_get_be16(a[OVS_KEY_ATTR_TCP_FLAGS]),
16698c2ecf20Sopenharmony_ci				is_mask);
16708c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_TCP_FLAGS);
16718c2ecf20Sopenharmony_ci	}
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_UDP)) {
16748c2ecf20Sopenharmony_ci		const struct ovs_key_udp *udp_key;
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci		udp_key = nla_data(a[OVS_KEY_ATTR_UDP]);
16778c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.src, udp_key->udp_src, is_mask);
16788c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.dst, udp_key->udp_dst, is_mask);
16798c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_UDP);
16808c2ecf20Sopenharmony_ci	}
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_SCTP)) {
16838c2ecf20Sopenharmony_ci		const struct ovs_key_sctp *sctp_key;
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci		sctp_key = nla_data(a[OVS_KEY_ATTR_SCTP]);
16868c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.src, sctp_key->sctp_src, is_mask);
16878c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.dst, sctp_key->sctp_dst, is_mask);
16888c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_SCTP);
16898c2ecf20Sopenharmony_ci	}
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_ICMP)) {
16928c2ecf20Sopenharmony_ci		const struct ovs_key_icmp *icmp_key;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci		icmp_key = nla_data(a[OVS_KEY_ATTR_ICMP]);
16958c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.src,
16968c2ecf20Sopenharmony_ci				htons(icmp_key->icmp_type), is_mask);
16978c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.dst,
16988c2ecf20Sopenharmony_ci				htons(icmp_key->icmp_code), is_mask);
16998c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_ICMP);
17008c2ecf20Sopenharmony_ci	}
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_ICMPV6)) {
17038c2ecf20Sopenharmony_ci		const struct ovs_key_icmpv6 *icmpv6_key;
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci		icmpv6_key = nla_data(a[OVS_KEY_ATTR_ICMPV6]);
17068c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.src,
17078c2ecf20Sopenharmony_ci				htons(icmpv6_key->icmpv6_type), is_mask);
17088c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, tp.dst,
17098c2ecf20Sopenharmony_ci				htons(icmpv6_key->icmpv6_code), is_mask);
17108c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_ICMPV6);
17118c2ecf20Sopenharmony_ci	}
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_ND)) {
17148c2ecf20Sopenharmony_ci		const struct ovs_key_nd *nd_key;
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci		nd_key = nla_data(a[OVS_KEY_ATTR_ND]);
17178c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.nd.target,
17188c2ecf20Sopenharmony_ci			nd_key->nd_target,
17198c2ecf20Sopenharmony_ci			sizeof(match->key->ipv6.nd.target),
17208c2ecf20Sopenharmony_ci			is_mask);
17218c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.nd.sll,
17228c2ecf20Sopenharmony_ci			nd_key->nd_sll, ETH_ALEN, is_mask);
17238c2ecf20Sopenharmony_ci		SW_FLOW_KEY_MEMCPY(match, ipv6.nd.tll,
17248c2ecf20Sopenharmony_ci				nd_key->nd_tll, ETH_ALEN, is_mask);
17258c2ecf20Sopenharmony_ci		attrs &= ~(1 << OVS_KEY_ATTR_ND);
17268c2ecf20Sopenharmony_ci	}
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	if (attrs != 0) {
17298c2ecf20Sopenharmony_ci		OVS_NLERR(log, "Unknown key attributes %llx",
17308c2ecf20Sopenharmony_ci			  (unsigned long long)attrs);
17318c2ecf20Sopenharmony_ci		return -EINVAL;
17328c2ecf20Sopenharmony_ci	}
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	return 0;
17358c2ecf20Sopenharmony_ci}
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_cistatic void nlattr_set(struct nlattr *attr, u8 val,
17388c2ecf20Sopenharmony_ci		       const struct ovs_len_tbl *tbl)
17398c2ecf20Sopenharmony_ci{
17408c2ecf20Sopenharmony_ci	struct nlattr *nla;
17418c2ecf20Sopenharmony_ci	int rem;
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	/* The nlattr stream should already have been validated */
17448c2ecf20Sopenharmony_ci	nla_for_each_nested(nla, attr, rem) {
17458c2ecf20Sopenharmony_ci		if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED)
17468c2ecf20Sopenharmony_ci			nlattr_set(nla, val, tbl[nla_type(nla)].next ? : tbl);
17478c2ecf20Sopenharmony_ci		else
17488c2ecf20Sopenharmony_ci			memset(nla_data(nla), val, nla_len(nla));
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci		if (nla_type(nla) == OVS_KEY_ATTR_CT_STATE)
17518c2ecf20Sopenharmony_ci			*(u32 *)nla_data(nla) &= CT_SUPPORTED_MASK;
17528c2ecf20Sopenharmony_ci	}
17538c2ecf20Sopenharmony_ci}
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_cistatic void mask_set_nlattr(struct nlattr *attr, u8 val)
17568c2ecf20Sopenharmony_ci{
17578c2ecf20Sopenharmony_ci	nlattr_set(attr, val, ovs_key_lens);
17588c2ecf20Sopenharmony_ci}
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci/**
17618c2ecf20Sopenharmony_ci * ovs_nla_get_match - parses Netlink attributes into a flow key and
17628c2ecf20Sopenharmony_ci * mask. In case the 'mask' is NULL, the flow is treated as exact match
17638c2ecf20Sopenharmony_ci * flow. Otherwise, it is treated as a wildcarded flow, except the mask
17648c2ecf20Sopenharmony_ci * does not include any don't care bit.
17658c2ecf20Sopenharmony_ci * @net: Used to determine per-namespace field support.
17668c2ecf20Sopenharmony_ci * @match: receives the extracted flow match information.
17678c2ecf20Sopenharmony_ci * @nla_key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute
17688c2ecf20Sopenharmony_ci * sequence. The fields should of the packet that triggered the creation
17698c2ecf20Sopenharmony_ci * of this flow.
17708c2ecf20Sopenharmony_ci * @nla_mask: Optional. Netlink attribute holding nested %OVS_KEY_ATTR_*
17718c2ecf20Sopenharmony_ci * Netlink attribute specifies the mask field of the wildcarded flow.
17728c2ecf20Sopenharmony_ci * @log: Boolean to allow kernel error logging.  Normally true, but when
17738c2ecf20Sopenharmony_ci * probing for feature compatibility this should be passed in as false to
17748c2ecf20Sopenharmony_ci * suppress unnecessary error logging.
17758c2ecf20Sopenharmony_ci */
17768c2ecf20Sopenharmony_ciint ovs_nla_get_match(struct net *net, struct sw_flow_match *match,
17778c2ecf20Sopenharmony_ci		      const struct nlattr *nla_key,
17788c2ecf20Sopenharmony_ci		      const struct nlattr *nla_mask,
17798c2ecf20Sopenharmony_ci		      bool log)
17808c2ecf20Sopenharmony_ci{
17818c2ecf20Sopenharmony_ci	const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
17828c2ecf20Sopenharmony_ci	struct nlattr *newmask = NULL;
17838c2ecf20Sopenharmony_ci	u64 key_attrs = 0;
17848c2ecf20Sopenharmony_ci	u64 mask_attrs = 0;
17858c2ecf20Sopenharmony_ci	int err;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	err = parse_flow_nlattrs(nla_key, a, &key_attrs, log);
17888c2ecf20Sopenharmony_ci	if (err)
17898c2ecf20Sopenharmony_ci		return err;
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	err = parse_vlan_from_nlattrs(match, &key_attrs, a, false, log);
17928c2ecf20Sopenharmony_ci	if (err)
17938c2ecf20Sopenharmony_ci		return err;
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	err = ovs_key_from_nlattrs(net, match, key_attrs, a, false, log);
17968c2ecf20Sopenharmony_ci	if (err)
17978c2ecf20Sopenharmony_ci		return err;
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	if (match->mask) {
18008c2ecf20Sopenharmony_ci		if (!nla_mask) {
18018c2ecf20Sopenharmony_ci			/* Create an exact match mask. We need to set to 0xff
18028c2ecf20Sopenharmony_ci			 * all the 'match->mask' fields that have been touched
18038c2ecf20Sopenharmony_ci			 * in 'match->key'. We cannot simply memset
18048c2ecf20Sopenharmony_ci			 * 'match->mask', because padding bytes and fields not
18058c2ecf20Sopenharmony_ci			 * specified in 'match->key' should be left to 0.
18068c2ecf20Sopenharmony_ci			 * Instead, we use a stream of netlink attributes,
18078c2ecf20Sopenharmony_ci			 * copied from 'key' and set to 0xff.
18088c2ecf20Sopenharmony_ci			 * ovs_key_from_nlattrs() will take care of filling
18098c2ecf20Sopenharmony_ci			 * 'match->mask' appropriately.
18108c2ecf20Sopenharmony_ci			 */
18118c2ecf20Sopenharmony_ci			newmask = kmemdup(nla_key,
18128c2ecf20Sopenharmony_ci					  nla_total_size(nla_len(nla_key)),
18138c2ecf20Sopenharmony_ci					  GFP_KERNEL);
18148c2ecf20Sopenharmony_ci			if (!newmask)
18158c2ecf20Sopenharmony_ci				return -ENOMEM;
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci			mask_set_nlattr(newmask, 0xff);
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci			/* The userspace does not send tunnel attributes that
18208c2ecf20Sopenharmony_ci			 * are 0, but we should not wildcard them nonetheless.
18218c2ecf20Sopenharmony_ci			 */
18228c2ecf20Sopenharmony_ci			if (match->key->tun_proto)
18238c2ecf20Sopenharmony_ci				SW_FLOW_KEY_MEMSET_FIELD(match, tun_key,
18248c2ecf20Sopenharmony_ci							 0xff, true);
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci			nla_mask = newmask;
18278c2ecf20Sopenharmony_ci		}
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci		err = parse_flow_mask_nlattrs(nla_mask, a, &mask_attrs, log);
18308c2ecf20Sopenharmony_ci		if (err)
18318c2ecf20Sopenharmony_ci			goto free_newmask;
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci		/* Always match on tci. */
18348c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, eth.vlan.tci, htons(0xffff), true);
18358c2ecf20Sopenharmony_ci		SW_FLOW_KEY_PUT(match, eth.cvlan.tci, htons(0xffff), true);
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci		err = parse_vlan_from_nlattrs(match, &mask_attrs, a, true, log);
18388c2ecf20Sopenharmony_ci		if (err)
18398c2ecf20Sopenharmony_ci			goto free_newmask;
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci		err = ovs_key_from_nlattrs(net, match, mask_attrs, a, true,
18428c2ecf20Sopenharmony_ci					   log);
18438c2ecf20Sopenharmony_ci		if (err)
18448c2ecf20Sopenharmony_ci			goto free_newmask;
18458c2ecf20Sopenharmony_ci	}
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	if (!match_validate(match, key_attrs, mask_attrs, log))
18488c2ecf20Sopenharmony_ci		err = -EINVAL;
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_cifree_newmask:
18518c2ecf20Sopenharmony_ci	kfree(newmask);
18528c2ecf20Sopenharmony_ci	return err;
18538c2ecf20Sopenharmony_ci}
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_cistatic size_t get_ufid_len(const struct nlattr *attr, bool log)
18568c2ecf20Sopenharmony_ci{
18578c2ecf20Sopenharmony_ci	size_t len;
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci	if (!attr)
18608c2ecf20Sopenharmony_ci		return 0;
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	len = nla_len(attr);
18638c2ecf20Sopenharmony_ci	if (len < 1 || len > MAX_UFID_LENGTH) {
18648c2ecf20Sopenharmony_ci		OVS_NLERR(log, "ufid size %u bytes exceeds the range (1, %d)",
18658c2ecf20Sopenharmony_ci			  nla_len(attr), MAX_UFID_LENGTH);
18668c2ecf20Sopenharmony_ci		return 0;
18678c2ecf20Sopenharmony_ci	}
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	return len;
18708c2ecf20Sopenharmony_ci}
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci/* Initializes 'flow->ufid', returning true if 'attr' contains a valid UFID,
18738c2ecf20Sopenharmony_ci * or false otherwise.
18748c2ecf20Sopenharmony_ci */
18758c2ecf20Sopenharmony_cibool ovs_nla_get_ufid(struct sw_flow_id *sfid, const struct nlattr *attr,
18768c2ecf20Sopenharmony_ci		      bool log)
18778c2ecf20Sopenharmony_ci{
18788c2ecf20Sopenharmony_ci	sfid->ufid_len = get_ufid_len(attr, log);
18798c2ecf20Sopenharmony_ci	if (sfid->ufid_len)
18808c2ecf20Sopenharmony_ci		memcpy(sfid->ufid, nla_data(attr), sfid->ufid_len);
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	return sfid->ufid_len;
18838c2ecf20Sopenharmony_ci}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ciint ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid,
18868c2ecf20Sopenharmony_ci			   const struct sw_flow_key *key, bool log)
18878c2ecf20Sopenharmony_ci{
18888c2ecf20Sopenharmony_ci	struct sw_flow_key *new_key;
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci	if (ovs_nla_get_ufid(sfid, ufid, log))
18918c2ecf20Sopenharmony_ci		return 0;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	/* If UFID was not provided, use unmasked key. */
18948c2ecf20Sopenharmony_ci	new_key = kmalloc(sizeof(*new_key), GFP_KERNEL);
18958c2ecf20Sopenharmony_ci	if (!new_key)
18968c2ecf20Sopenharmony_ci		return -ENOMEM;
18978c2ecf20Sopenharmony_ci	memcpy(new_key, key, sizeof(*key));
18988c2ecf20Sopenharmony_ci	sfid->unmasked_key = new_key;
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	return 0;
19018c2ecf20Sopenharmony_ci}
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ciu32 ovs_nla_get_ufid_flags(const struct nlattr *attr)
19048c2ecf20Sopenharmony_ci{
19058c2ecf20Sopenharmony_ci	return attr ? nla_get_u32(attr) : 0;
19068c2ecf20Sopenharmony_ci}
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci/**
19098c2ecf20Sopenharmony_ci * ovs_nla_get_flow_metadata - parses Netlink attributes into a flow key.
19108c2ecf20Sopenharmony_ci * @net: Network namespace.
19118c2ecf20Sopenharmony_ci * @key: Receives extracted in_port, priority, tun_key, skb_mark and conntrack
19128c2ecf20Sopenharmony_ci * metadata.
19138c2ecf20Sopenharmony_ci * @a: Array of netlink attributes holding parsed %OVS_KEY_ATTR_* Netlink
19148c2ecf20Sopenharmony_ci * attributes.
19158c2ecf20Sopenharmony_ci * @attrs: Bit mask for the netlink attributes included in @a.
19168c2ecf20Sopenharmony_ci * @log: Boolean to allow kernel error logging.  Normally true, but when
19178c2ecf20Sopenharmony_ci * probing for feature compatibility this should be passed in as false to
19188c2ecf20Sopenharmony_ci * suppress unnecessary error logging.
19198c2ecf20Sopenharmony_ci *
19208c2ecf20Sopenharmony_ci * This parses a series of Netlink attributes that form a flow key, which must
19218c2ecf20Sopenharmony_ci * take the same form accepted by flow_from_nlattrs(), but only enough of it to
19228c2ecf20Sopenharmony_ci * get the metadata, that is, the parts of the flow key that cannot be
19238c2ecf20Sopenharmony_ci * extracted from the packet itself.
19248c2ecf20Sopenharmony_ci *
19258c2ecf20Sopenharmony_ci * This must be called before the packet key fields are filled in 'key'.
19268c2ecf20Sopenharmony_ci */
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ciint ovs_nla_get_flow_metadata(struct net *net,
19298c2ecf20Sopenharmony_ci			      const struct nlattr *a[OVS_KEY_ATTR_MAX + 1],
19308c2ecf20Sopenharmony_ci			      u64 attrs, struct sw_flow_key *key, bool log)
19318c2ecf20Sopenharmony_ci{
19328c2ecf20Sopenharmony_ci	struct sw_flow_match match;
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci	memset(&match, 0, sizeof(match));
19358c2ecf20Sopenharmony_ci	match.key = key;
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci	key->ct_state = 0;
19388c2ecf20Sopenharmony_ci	key->ct_zone = 0;
19398c2ecf20Sopenharmony_ci	key->ct_orig_proto = 0;
19408c2ecf20Sopenharmony_ci	memset(&key->ct, 0, sizeof(key->ct));
19418c2ecf20Sopenharmony_ci	memset(&key->ipv4.ct_orig, 0, sizeof(key->ipv4.ct_orig));
19428c2ecf20Sopenharmony_ci	memset(&key->ipv6.ct_orig, 0, sizeof(key->ipv6.ct_orig));
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci	key->phy.in_port = DP_MAX_PORTS;
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	return metadata_from_nlattrs(net, &match, &attrs, a, false, log);
19478c2ecf20Sopenharmony_ci}
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_cistatic int ovs_nla_put_vlan(struct sk_buff *skb, const struct vlan_head *vh,
19508c2ecf20Sopenharmony_ci			    bool is_mask)
19518c2ecf20Sopenharmony_ci{
19528c2ecf20Sopenharmony_ci	__be16 eth_type = !is_mask ? vh->tpid : htons(0xffff);
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci	if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, eth_type) ||
19558c2ecf20Sopenharmony_ci	    nla_put_be16(skb, OVS_KEY_ATTR_VLAN, vh->tci))
19568c2ecf20Sopenharmony_ci		return -EMSGSIZE;
19578c2ecf20Sopenharmony_ci	return 0;
19588c2ecf20Sopenharmony_ci}
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_cistatic int nsh_key_to_nlattr(const struct ovs_key_nsh *nsh, bool is_mask,
19618c2ecf20Sopenharmony_ci			     struct sk_buff *skb)
19628c2ecf20Sopenharmony_ci{
19638c2ecf20Sopenharmony_ci	struct nlattr *start;
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	start = nla_nest_start_noflag(skb, OVS_KEY_ATTR_NSH);
19668c2ecf20Sopenharmony_ci	if (!start)
19678c2ecf20Sopenharmony_ci		return -EMSGSIZE;
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	if (nla_put(skb, OVS_NSH_KEY_ATTR_BASE, sizeof(nsh->base), &nsh->base))
19708c2ecf20Sopenharmony_ci		goto nla_put_failure;
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	if (is_mask || nsh->base.mdtype == NSH_M_TYPE1) {
19738c2ecf20Sopenharmony_ci		if (nla_put(skb, OVS_NSH_KEY_ATTR_MD1,
19748c2ecf20Sopenharmony_ci			    sizeof(nsh->context), nsh->context))
19758c2ecf20Sopenharmony_ci			goto nla_put_failure;
19768c2ecf20Sopenharmony_ci	}
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	/* Don't support MD type 2 yet */
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	nla_nest_end(skb, start);
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci	return 0;
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_cinla_put_failure:
19858c2ecf20Sopenharmony_ci	return -EMSGSIZE;
19868c2ecf20Sopenharmony_ci}
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_cistatic int __ovs_nla_put_key(const struct sw_flow_key *swkey,
19898c2ecf20Sopenharmony_ci			     const struct sw_flow_key *output, bool is_mask,
19908c2ecf20Sopenharmony_ci			     struct sk_buff *skb)
19918c2ecf20Sopenharmony_ci{
19928c2ecf20Sopenharmony_ci	struct ovs_key_ethernet *eth_key;
19938c2ecf20Sopenharmony_ci	struct nlattr *nla;
19948c2ecf20Sopenharmony_ci	struct nlattr *encap = NULL;
19958c2ecf20Sopenharmony_ci	struct nlattr *in_encap = NULL;
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, OVS_KEY_ATTR_RECIRC_ID, output->recirc_id))
19988c2ecf20Sopenharmony_ci		goto nla_put_failure;
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, OVS_KEY_ATTR_DP_HASH, output->ovs_flow_hash))
20018c2ecf20Sopenharmony_ci		goto nla_put_failure;
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority))
20048c2ecf20Sopenharmony_ci		goto nla_put_failure;
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_ci	if ((swkey->tun_proto || is_mask)) {
20078c2ecf20Sopenharmony_ci		const void *opts = NULL;
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci		if (output->tun_key.tun_flags & TUNNEL_OPTIONS_PRESENT)
20108c2ecf20Sopenharmony_ci			opts = TUN_METADATA_OPTS(output, swkey->tun_opts_len);
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci		if (ip_tun_to_nlattr(skb, &output->tun_key, opts,
20138c2ecf20Sopenharmony_ci				     swkey->tun_opts_len, swkey->tun_proto, 0))
20148c2ecf20Sopenharmony_ci			goto nla_put_failure;
20158c2ecf20Sopenharmony_ci	}
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci	if (swkey->phy.in_port == DP_MAX_PORTS) {
20188c2ecf20Sopenharmony_ci		if (is_mask && (output->phy.in_port == 0xffff))
20198c2ecf20Sopenharmony_ci			if (nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, 0xffffffff))
20208c2ecf20Sopenharmony_ci				goto nla_put_failure;
20218c2ecf20Sopenharmony_ci	} else {
20228c2ecf20Sopenharmony_ci		u16 upper_u16;
20238c2ecf20Sopenharmony_ci		upper_u16 = !is_mask ? 0 : 0xffff;
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci		if (nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT,
20268c2ecf20Sopenharmony_ci				(upper_u16 << 16) | output->phy.in_port))
20278c2ecf20Sopenharmony_ci			goto nla_put_failure;
20288c2ecf20Sopenharmony_ci	}
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, output->phy.skb_mark))
20318c2ecf20Sopenharmony_ci		goto nla_put_failure;
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ci	if (ovs_ct_put_key(swkey, output, skb))
20348c2ecf20Sopenharmony_ci		goto nla_put_failure;
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	if (ovs_key_mac_proto(swkey) == MAC_PROTO_ETHERNET) {
20378c2ecf20Sopenharmony_ci		nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
20388c2ecf20Sopenharmony_ci		if (!nla)
20398c2ecf20Sopenharmony_ci			goto nla_put_failure;
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci		eth_key = nla_data(nla);
20428c2ecf20Sopenharmony_ci		ether_addr_copy(eth_key->eth_src, output->eth.src);
20438c2ecf20Sopenharmony_ci		ether_addr_copy(eth_key->eth_dst, output->eth.dst);
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci		if (swkey->eth.vlan.tci || eth_type_vlan(swkey->eth.type)) {
20468c2ecf20Sopenharmony_ci			if (ovs_nla_put_vlan(skb, &output->eth.vlan, is_mask))
20478c2ecf20Sopenharmony_ci				goto nla_put_failure;
20488c2ecf20Sopenharmony_ci			encap = nla_nest_start_noflag(skb, OVS_KEY_ATTR_ENCAP);
20498c2ecf20Sopenharmony_ci			if (!swkey->eth.vlan.tci)
20508c2ecf20Sopenharmony_ci				goto unencap;
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci			if (swkey->eth.cvlan.tci || eth_type_vlan(swkey->eth.type)) {
20538c2ecf20Sopenharmony_ci				if (ovs_nla_put_vlan(skb, &output->eth.cvlan, is_mask))
20548c2ecf20Sopenharmony_ci					goto nla_put_failure;
20558c2ecf20Sopenharmony_ci				in_encap = nla_nest_start_noflag(skb,
20568c2ecf20Sopenharmony_ci								 OVS_KEY_ATTR_ENCAP);
20578c2ecf20Sopenharmony_ci				if (!swkey->eth.cvlan.tci)
20588c2ecf20Sopenharmony_ci					goto unencap;
20598c2ecf20Sopenharmony_ci			}
20608c2ecf20Sopenharmony_ci		}
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci		if (swkey->eth.type == htons(ETH_P_802_2)) {
20638c2ecf20Sopenharmony_ci			/*
20648c2ecf20Sopenharmony_ci			* Ethertype 802.2 is represented in the netlink with omitted
20658c2ecf20Sopenharmony_ci			* OVS_KEY_ATTR_ETHERTYPE in the flow key attribute, and
20668c2ecf20Sopenharmony_ci			* 0xffff in the mask attribute.  Ethertype can also
20678c2ecf20Sopenharmony_ci			* be wildcarded.
20688c2ecf20Sopenharmony_ci			*/
20698c2ecf20Sopenharmony_ci			if (is_mask && output->eth.type)
20708c2ecf20Sopenharmony_ci				if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE,
20718c2ecf20Sopenharmony_ci							output->eth.type))
20728c2ecf20Sopenharmony_ci					goto nla_put_failure;
20738c2ecf20Sopenharmony_ci			goto unencap;
20748c2ecf20Sopenharmony_ci		}
20758c2ecf20Sopenharmony_ci	}
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci	if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, output->eth.type))
20788c2ecf20Sopenharmony_ci		goto nla_put_failure;
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci	if (eth_type_vlan(swkey->eth.type)) {
20818c2ecf20Sopenharmony_ci		/* There are 3 VLAN tags, we don't know anything about the rest
20828c2ecf20Sopenharmony_ci		 * of the packet, so truncate here.
20838c2ecf20Sopenharmony_ci		 */
20848c2ecf20Sopenharmony_ci		WARN_ON_ONCE(!(encap && in_encap));
20858c2ecf20Sopenharmony_ci		goto unencap;
20868c2ecf20Sopenharmony_ci	}
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci	if (swkey->eth.type == htons(ETH_P_IP)) {
20898c2ecf20Sopenharmony_ci		struct ovs_key_ipv4 *ipv4_key;
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_ci		nla = nla_reserve(skb, OVS_KEY_ATTR_IPV4, sizeof(*ipv4_key));
20928c2ecf20Sopenharmony_ci		if (!nla)
20938c2ecf20Sopenharmony_ci			goto nla_put_failure;
20948c2ecf20Sopenharmony_ci		ipv4_key = nla_data(nla);
20958c2ecf20Sopenharmony_ci		ipv4_key->ipv4_src = output->ipv4.addr.src;
20968c2ecf20Sopenharmony_ci		ipv4_key->ipv4_dst = output->ipv4.addr.dst;
20978c2ecf20Sopenharmony_ci		ipv4_key->ipv4_proto = output->ip.proto;
20988c2ecf20Sopenharmony_ci		ipv4_key->ipv4_tos = output->ip.tos;
20998c2ecf20Sopenharmony_ci		ipv4_key->ipv4_ttl = output->ip.ttl;
21008c2ecf20Sopenharmony_ci		ipv4_key->ipv4_frag = output->ip.frag;
21018c2ecf20Sopenharmony_ci	} else if (swkey->eth.type == htons(ETH_P_IPV6)) {
21028c2ecf20Sopenharmony_ci		struct ovs_key_ipv6 *ipv6_key;
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci		nla = nla_reserve(skb, OVS_KEY_ATTR_IPV6, sizeof(*ipv6_key));
21058c2ecf20Sopenharmony_ci		if (!nla)
21068c2ecf20Sopenharmony_ci			goto nla_put_failure;
21078c2ecf20Sopenharmony_ci		ipv6_key = nla_data(nla);
21088c2ecf20Sopenharmony_ci		memcpy(ipv6_key->ipv6_src, &output->ipv6.addr.src,
21098c2ecf20Sopenharmony_ci				sizeof(ipv6_key->ipv6_src));
21108c2ecf20Sopenharmony_ci		memcpy(ipv6_key->ipv6_dst, &output->ipv6.addr.dst,
21118c2ecf20Sopenharmony_ci				sizeof(ipv6_key->ipv6_dst));
21128c2ecf20Sopenharmony_ci		ipv6_key->ipv6_label = output->ipv6.label;
21138c2ecf20Sopenharmony_ci		ipv6_key->ipv6_proto = output->ip.proto;
21148c2ecf20Sopenharmony_ci		ipv6_key->ipv6_tclass = output->ip.tos;
21158c2ecf20Sopenharmony_ci		ipv6_key->ipv6_hlimit = output->ip.ttl;
21168c2ecf20Sopenharmony_ci		ipv6_key->ipv6_frag = output->ip.frag;
21178c2ecf20Sopenharmony_ci	} else if (swkey->eth.type == htons(ETH_P_NSH)) {
21188c2ecf20Sopenharmony_ci		if (nsh_key_to_nlattr(&output->nsh, is_mask, skb))
21198c2ecf20Sopenharmony_ci			goto nla_put_failure;
21208c2ecf20Sopenharmony_ci	} else if (swkey->eth.type == htons(ETH_P_ARP) ||
21218c2ecf20Sopenharmony_ci		   swkey->eth.type == htons(ETH_P_RARP)) {
21228c2ecf20Sopenharmony_ci		struct ovs_key_arp *arp_key;
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci		nla = nla_reserve(skb, OVS_KEY_ATTR_ARP, sizeof(*arp_key));
21258c2ecf20Sopenharmony_ci		if (!nla)
21268c2ecf20Sopenharmony_ci			goto nla_put_failure;
21278c2ecf20Sopenharmony_ci		arp_key = nla_data(nla);
21288c2ecf20Sopenharmony_ci		memset(arp_key, 0, sizeof(struct ovs_key_arp));
21298c2ecf20Sopenharmony_ci		arp_key->arp_sip = output->ipv4.addr.src;
21308c2ecf20Sopenharmony_ci		arp_key->arp_tip = output->ipv4.addr.dst;
21318c2ecf20Sopenharmony_ci		arp_key->arp_op = htons(output->ip.proto);
21328c2ecf20Sopenharmony_ci		ether_addr_copy(arp_key->arp_sha, output->ipv4.arp.sha);
21338c2ecf20Sopenharmony_ci		ether_addr_copy(arp_key->arp_tha, output->ipv4.arp.tha);
21348c2ecf20Sopenharmony_ci	} else if (eth_p_mpls(swkey->eth.type)) {
21358c2ecf20Sopenharmony_ci		u8 i, num_labels;
21368c2ecf20Sopenharmony_ci		struct ovs_key_mpls *mpls_key;
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci		num_labels = hweight_long(output->mpls.num_labels_mask);
21398c2ecf20Sopenharmony_ci		nla = nla_reserve(skb, OVS_KEY_ATTR_MPLS,
21408c2ecf20Sopenharmony_ci				  num_labels * sizeof(*mpls_key));
21418c2ecf20Sopenharmony_ci		if (!nla)
21428c2ecf20Sopenharmony_ci			goto nla_put_failure;
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci		mpls_key = nla_data(nla);
21458c2ecf20Sopenharmony_ci		for (i = 0; i < num_labels; i++)
21468c2ecf20Sopenharmony_ci			mpls_key[i].mpls_lse = output->mpls.lse[i];
21478c2ecf20Sopenharmony_ci	}
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci	if ((swkey->eth.type == htons(ETH_P_IP) ||
21508c2ecf20Sopenharmony_ci	     swkey->eth.type == htons(ETH_P_IPV6)) &&
21518c2ecf20Sopenharmony_ci	     swkey->ip.frag != OVS_FRAG_TYPE_LATER) {
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_ci		if (swkey->ip.proto == IPPROTO_TCP) {
21548c2ecf20Sopenharmony_ci			struct ovs_key_tcp *tcp_key;
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci			nla = nla_reserve(skb, OVS_KEY_ATTR_TCP, sizeof(*tcp_key));
21578c2ecf20Sopenharmony_ci			if (!nla)
21588c2ecf20Sopenharmony_ci				goto nla_put_failure;
21598c2ecf20Sopenharmony_ci			tcp_key = nla_data(nla);
21608c2ecf20Sopenharmony_ci			tcp_key->tcp_src = output->tp.src;
21618c2ecf20Sopenharmony_ci			tcp_key->tcp_dst = output->tp.dst;
21628c2ecf20Sopenharmony_ci			if (nla_put_be16(skb, OVS_KEY_ATTR_TCP_FLAGS,
21638c2ecf20Sopenharmony_ci					 output->tp.flags))
21648c2ecf20Sopenharmony_ci				goto nla_put_failure;
21658c2ecf20Sopenharmony_ci		} else if (swkey->ip.proto == IPPROTO_UDP) {
21668c2ecf20Sopenharmony_ci			struct ovs_key_udp *udp_key;
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci			nla = nla_reserve(skb, OVS_KEY_ATTR_UDP, sizeof(*udp_key));
21698c2ecf20Sopenharmony_ci			if (!nla)
21708c2ecf20Sopenharmony_ci				goto nla_put_failure;
21718c2ecf20Sopenharmony_ci			udp_key = nla_data(nla);
21728c2ecf20Sopenharmony_ci			udp_key->udp_src = output->tp.src;
21738c2ecf20Sopenharmony_ci			udp_key->udp_dst = output->tp.dst;
21748c2ecf20Sopenharmony_ci		} else if (swkey->ip.proto == IPPROTO_SCTP) {
21758c2ecf20Sopenharmony_ci			struct ovs_key_sctp *sctp_key;
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci			nla = nla_reserve(skb, OVS_KEY_ATTR_SCTP, sizeof(*sctp_key));
21788c2ecf20Sopenharmony_ci			if (!nla)
21798c2ecf20Sopenharmony_ci				goto nla_put_failure;
21808c2ecf20Sopenharmony_ci			sctp_key = nla_data(nla);
21818c2ecf20Sopenharmony_ci			sctp_key->sctp_src = output->tp.src;
21828c2ecf20Sopenharmony_ci			sctp_key->sctp_dst = output->tp.dst;
21838c2ecf20Sopenharmony_ci		} else if (swkey->eth.type == htons(ETH_P_IP) &&
21848c2ecf20Sopenharmony_ci			   swkey->ip.proto == IPPROTO_ICMP) {
21858c2ecf20Sopenharmony_ci			struct ovs_key_icmp *icmp_key;
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci			nla = nla_reserve(skb, OVS_KEY_ATTR_ICMP, sizeof(*icmp_key));
21888c2ecf20Sopenharmony_ci			if (!nla)
21898c2ecf20Sopenharmony_ci				goto nla_put_failure;
21908c2ecf20Sopenharmony_ci			icmp_key = nla_data(nla);
21918c2ecf20Sopenharmony_ci			icmp_key->icmp_type = ntohs(output->tp.src);
21928c2ecf20Sopenharmony_ci			icmp_key->icmp_code = ntohs(output->tp.dst);
21938c2ecf20Sopenharmony_ci		} else if (swkey->eth.type == htons(ETH_P_IPV6) &&
21948c2ecf20Sopenharmony_ci			   swkey->ip.proto == IPPROTO_ICMPV6) {
21958c2ecf20Sopenharmony_ci			struct ovs_key_icmpv6 *icmpv6_key;
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci			nla = nla_reserve(skb, OVS_KEY_ATTR_ICMPV6,
21988c2ecf20Sopenharmony_ci						sizeof(*icmpv6_key));
21998c2ecf20Sopenharmony_ci			if (!nla)
22008c2ecf20Sopenharmony_ci				goto nla_put_failure;
22018c2ecf20Sopenharmony_ci			icmpv6_key = nla_data(nla);
22028c2ecf20Sopenharmony_ci			icmpv6_key->icmpv6_type = ntohs(output->tp.src);
22038c2ecf20Sopenharmony_ci			icmpv6_key->icmpv6_code = ntohs(output->tp.dst);
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci			if (swkey->tp.src == htons(NDISC_NEIGHBOUR_SOLICITATION) ||
22068c2ecf20Sopenharmony_ci			    swkey->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) {
22078c2ecf20Sopenharmony_ci				struct ovs_key_nd *nd_key;
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci				nla = nla_reserve(skb, OVS_KEY_ATTR_ND, sizeof(*nd_key));
22108c2ecf20Sopenharmony_ci				if (!nla)
22118c2ecf20Sopenharmony_ci					goto nla_put_failure;
22128c2ecf20Sopenharmony_ci				nd_key = nla_data(nla);
22138c2ecf20Sopenharmony_ci				memcpy(nd_key->nd_target, &output->ipv6.nd.target,
22148c2ecf20Sopenharmony_ci							sizeof(nd_key->nd_target));
22158c2ecf20Sopenharmony_ci				ether_addr_copy(nd_key->nd_sll, output->ipv6.nd.sll);
22168c2ecf20Sopenharmony_ci				ether_addr_copy(nd_key->nd_tll, output->ipv6.nd.tll);
22178c2ecf20Sopenharmony_ci			}
22188c2ecf20Sopenharmony_ci		}
22198c2ecf20Sopenharmony_ci	}
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ciunencap:
22228c2ecf20Sopenharmony_ci	if (in_encap)
22238c2ecf20Sopenharmony_ci		nla_nest_end(skb, in_encap);
22248c2ecf20Sopenharmony_ci	if (encap)
22258c2ecf20Sopenharmony_ci		nla_nest_end(skb, encap);
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci	return 0;
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_cinla_put_failure:
22308c2ecf20Sopenharmony_ci	return -EMSGSIZE;
22318c2ecf20Sopenharmony_ci}
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ciint ovs_nla_put_key(const struct sw_flow_key *swkey,
22348c2ecf20Sopenharmony_ci		    const struct sw_flow_key *output, int attr, bool is_mask,
22358c2ecf20Sopenharmony_ci		    struct sk_buff *skb)
22368c2ecf20Sopenharmony_ci{
22378c2ecf20Sopenharmony_ci	int err;
22388c2ecf20Sopenharmony_ci	struct nlattr *nla;
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_ci	nla = nla_nest_start_noflag(skb, attr);
22418c2ecf20Sopenharmony_ci	if (!nla)
22428c2ecf20Sopenharmony_ci		return -EMSGSIZE;
22438c2ecf20Sopenharmony_ci	err = __ovs_nla_put_key(swkey, output, is_mask, skb);
22448c2ecf20Sopenharmony_ci	if (err)
22458c2ecf20Sopenharmony_ci		return err;
22468c2ecf20Sopenharmony_ci	nla_nest_end(skb, nla);
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	return 0;
22498c2ecf20Sopenharmony_ci}
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */
22528c2ecf20Sopenharmony_ciint ovs_nla_put_identifier(const struct sw_flow *flow, struct sk_buff *skb)
22538c2ecf20Sopenharmony_ci{
22548c2ecf20Sopenharmony_ci	if (ovs_identifier_is_ufid(&flow->id))
22558c2ecf20Sopenharmony_ci		return nla_put(skb, OVS_FLOW_ATTR_UFID, flow->id.ufid_len,
22568c2ecf20Sopenharmony_ci			       flow->id.ufid);
22578c2ecf20Sopenharmony_ci
22588c2ecf20Sopenharmony_ci	return ovs_nla_put_key(flow->id.unmasked_key, flow->id.unmasked_key,
22598c2ecf20Sopenharmony_ci			       OVS_FLOW_ATTR_KEY, false, skb);
22608c2ecf20Sopenharmony_ci}
22618c2ecf20Sopenharmony_ci
22628c2ecf20Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */
22638c2ecf20Sopenharmony_ciint ovs_nla_put_masked_key(const struct sw_flow *flow, struct sk_buff *skb)
22648c2ecf20Sopenharmony_ci{
22658c2ecf20Sopenharmony_ci	return ovs_nla_put_key(&flow->key, &flow->key,
22668c2ecf20Sopenharmony_ci				OVS_FLOW_ATTR_KEY, false, skb);
22678c2ecf20Sopenharmony_ci}
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */
22708c2ecf20Sopenharmony_ciint ovs_nla_put_mask(const struct sw_flow *flow, struct sk_buff *skb)
22718c2ecf20Sopenharmony_ci{
22728c2ecf20Sopenharmony_ci	return ovs_nla_put_key(&flow->key, &flow->mask->key,
22738c2ecf20Sopenharmony_ci				OVS_FLOW_ATTR_MASK, true, skb);
22748c2ecf20Sopenharmony_ci}
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci#define MAX_ACTIONS_BUFSIZE	(32 * 1024)
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_cistatic struct sw_flow_actions *nla_alloc_flow_actions(int size)
22798c2ecf20Sopenharmony_ci{
22808c2ecf20Sopenharmony_ci	struct sw_flow_actions *sfa;
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci	WARN_ON_ONCE(size > MAX_ACTIONS_BUFSIZE);
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci	sfa = kmalloc(sizeof(*sfa) + size, GFP_KERNEL);
22858c2ecf20Sopenharmony_ci	if (!sfa)
22868c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
22878c2ecf20Sopenharmony_ci
22888c2ecf20Sopenharmony_ci	sfa->actions_len = 0;
22898c2ecf20Sopenharmony_ci	return sfa;
22908c2ecf20Sopenharmony_ci}
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_cistatic void ovs_nla_free_nested_actions(const struct nlattr *actions, int len);
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_cistatic void ovs_nla_free_check_pkt_len_action(const struct nlattr *action)
22958c2ecf20Sopenharmony_ci{
22968c2ecf20Sopenharmony_ci	const struct nlattr *a;
22978c2ecf20Sopenharmony_ci	int rem;
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_ci	nla_for_each_nested(a, action, rem) {
23008c2ecf20Sopenharmony_ci		switch (nla_type(a)) {
23018c2ecf20Sopenharmony_ci		case OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL:
23028c2ecf20Sopenharmony_ci		case OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER:
23038c2ecf20Sopenharmony_ci			ovs_nla_free_nested_actions(nla_data(a), nla_len(a));
23048c2ecf20Sopenharmony_ci			break;
23058c2ecf20Sopenharmony_ci		}
23068c2ecf20Sopenharmony_ci	}
23078c2ecf20Sopenharmony_ci}
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_cistatic void ovs_nla_free_clone_action(const struct nlattr *action)
23108c2ecf20Sopenharmony_ci{
23118c2ecf20Sopenharmony_ci	const struct nlattr *a = nla_data(action);
23128c2ecf20Sopenharmony_ci	int rem = nla_len(action);
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci	switch (nla_type(a)) {
23158c2ecf20Sopenharmony_ci	case OVS_CLONE_ATTR_EXEC:
23168c2ecf20Sopenharmony_ci		/* The real list of actions follows this attribute. */
23178c2ecf20Sopenharmony_ci		a = nla_next(a, &rem);
23188c2ecf20Sopenharmony_ci		ovs_nla_free_nested_actions(a, rem);
23198c2ecf20Sopenharmony_ci		break;
23208c2ecf20Sopenharmony_ci	}
23218c2ecf20Sopenharmony_ci}
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_cistatic void ovs_nla_free_dec_ttl_action(const struct nlattr *action)
23248c2ecf20Sopenharmony_ci{
23258c2ecf20Sopenharmony_ci	const struct nlattr *a = nla_data(action);
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_ci	switch (nla_type(a)) {
23288c2ecf20Sopenharmony_ci	case OVS_DEC_TTL_ATTR_ACTION:
23298c2ecf20Sopenharmony_ci		ovs_nla_free_nested_actions(nla_data(a), nla_len(a));
23308c2ecf20Sopenharmony_ci		break;
23318c2ecf20Sopenharmony_ci	}
23328c2ecf20Sopenharmony_ci}
23338c2ecf20Sopenharmony_ci
23348c2ecf20Sopenharmony_cistatic void ovs_nla_free_sample_action(const struct nlattr *action)
23358c2ecf20Sopenharmony_ci{
23368c2ecf20Sopenharmony_ci	const struct nlattr *a = nla_data(action);
23378c2ecf20Sopenharmony_ci	int rem = nla_len(action);
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	switch (nla_type(a)) {
23408c2ecf20Sopenharmony_ci	case OVS_SAMPLE_ATTR_ARG:
23418c2ecf20Sopenharmony_ci		/* The real list of actions follows this attribute. */
23428c2ecf20Sopenharmony_ci		a = nla_next(a, &rem);
23438c2ecf20Sopenharmony_ci		ovs_nla_free_nested_actions(a, rem);
23448c2ecf20Sopenharmony_ci		break;
23458c2ecf20Sopenharmony_ci	}
23468c2ecf20Sopenharmony_ci}
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_cistatic void ovs_nla_free_set_action(const struct nlattr *a)
23498c2ecf20Sopenharmony_ci{
23508c2ecf20Sopenharmony_ci	const struct nlattr *ovs_key = nla_data(a);
23518c2ecf20Sopenharmony_ci	struct ovs_tunnel_info *ovs_tun;
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci	switch (nla_type(ovs_key)) {
23548c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_TUNNEL_INFO:
23558c2ecf20Sopenharmony_ci		ovs_tun = nla_data(ovs_key);
23568c2ecf20Sopenharmony_ci		dst_release((struct dst_entry *)ovs_tun->tun_dst);
23578c2ecf20Sopenharmony_ci		break;
23588c2ecf20Sopenharmony_ci	}
23598c2ecf20Sopenharmony_ci}
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_cistatic void ovs_nla_free_nested_actions(const struct nlattr *actions, int len)
23628c2ecf20Sopenharmony_ci{
23638c2ecf20Sopenharmony_ci	const struct nlattr *a;
23648c2ecf20Sopenharmony_ci	int rem;
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci	/* Whenever new actions are added, the need to update this
23678c2ecf20Sopenharmony_ci	 * function should be considered.
23688c2ecf20Sopenharmony_ci	 */
23698c2ecf20Sopenharmony_ci	BUILD_BUG_ON(OVS_ACTION_ATTR_MAX != 23);
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci	if (!actions)
23728c2ecf20Sopenharmony_ci		return;
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci	nla_for_each_attr(a, actions, len, rem) {
23758c2ecf20Sopenharmony_ci		switch (nla_type(a)) {
23768c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CHECK_PKT_LEN:
23778c2ecf20Sopenharmony_ci			ovs_nla_free_check_pkt_len_action(a);
23788c2ecf20Sopenharmony_ci			break;
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CLONE:
23818c2ecf20Sopenharmony_ci			ovs_nla_free_clone_action(a);
23828c2ecf20Sopenharmony_ci			break;
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CT:
23858c2ecf20Sopenharmony_ci			ovs_ct_free_action(a);
23868c2ecf20Sopenharmony_ci			break;
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_DEC_TTL:
23898c2ecf20Sopenharmony_ci			ovs_nla_free_dec_ttl_action(a);
23908c2ecf20Sopenharmony_ci			break;
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SAMPLE:
23938c2ecf20Sopenharmony_ci			ovs_nla_free_sample_action(a);
23948c2ecf20Sopenharmony_ci			break;
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SET:
23978c2ecf20Sopenharmony_ci			ovs_nla_free_set_action(a);
23988c2ecf20Sopenharmony_ci			break;
23998c2ecf20Sopenharmony_ci		}
24008c2ecf20Sopenharmony_ci	}
24018c2ecf20Sopenharmony_ci}
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_civoid ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts)
24048c2ecf20Sopenharmony_ci{
24058c2ecf20Sopenharmony_ci	if (!sf_acts)
24068c2ecf20Sopenharmony_ci		return;
24078c2ecf20Sopenharmony_ci
24088c2ecf20Sopenharmony_ci	ovs_nla_free_nested_actions(sf_acts->actions, sf_acts->actions_len);
24098c2ecf20Sopenharmony_ci	kfree(sf_acts);
24108c2ecf20Sopenharmony_ci}
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_cistatic void __ovs_nla_free_flow_actions(struct rcu_head *head)
24138c2ecf20Sopenharmony_ci{
24148c2ecf20Sopenharmony_ci	ovs_nla_free_flow_actions(container_of(head, struct sw_flow_actions, rcu));
24158c2ecf20Sopenharmony_ci}
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci/* Schedules 'sf_acts' to be freed after the next RCU grace period.
24188c2ecf20Sopenharmony_ci * The caller must hold rcu_read_lock for this to be sensible. */
24198c2ecf20Sopenharmony_civoid ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *sf_acts)
24208c2ecf20Sopenharmony_ci{
24218c2ecf20Sopenharmony_ci	call_rcu(&sf_acts->rcu, __ovs_nla_free_flow_actions);
24228c2ecf20Sopenharmony_ci}
24238c2ecf20Sopenharmony_ci
24248c2ecf20Sopenharmony_cistatic struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa,
24258c2ecf20Sopenharmony_ci				       int attr_len, bool log)
24268c2ecf20Sopenharmony_ci{
24278c2ecf20Sopenharmony_ci
24288c2ecf20Sopenharmony_ci	struct sw_flow_actions *acts;
24298c2ecf20Sopenharmony_ci	int new_acts_size;
24308c2ecf20Sopenharmony_ci	size_t req_size = NLA_ALIGN(attr_len);
24318c2ecf20Sopenharmony_ci	int next_offset = offsetof(struct sw_flow_actions, actions) +
24328c2ecf20Sopenharmony_ci					(*sfa)->actions_len;
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	if (req_size <= (ksize(*sfa) - next_offset))
24358c2ecf20Sopenharmony_ci		goto out;
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci	new_acts_size = max(next_offset + req_size, ksize(*sfa) * 2);
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci	if (new_acts_size > MAX_ACTIONS_BUFSIZE) {
24408c2ecf20Sopenharmony_ci		if ((next_offset + req_size) > MAX_ACTIONS_BUFSIZE) {
24418c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Flow action size exceeds max %u",
24428c2ecf20Sopenharmony_ci				  MAX_ACTIONS_BUFSIZE);
24438c2ecf20Sopenharmony_ci			return ERR_PTR(-EMSGSIZE);
24448c2ecf20Sopenharmony_ci		}
24458c2ecf20Sopenharmony_ci		new_acts_size = MAX_ACTIONS_BUFSIZE;
24468c2ecf20Sopenharmony_ci	}
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ci	acts = nla_alloc_flow_actions(new_acts_size);
24498c2ecf20Sopenharmony_ci	if (IS_ERR(acts))
24508c2ecf20Sopenharmony_ci		return (void *)acts;
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci	memcpy(acts->actions, (*sfa)->actions, (*sfa)->actions_len);
24538c2ecf20Sopenharmony_ci	acts->actions_len = (*sfa)->actions_len;
24548c2ecf20Sopenharmony_ci	acts->orig_len = (*sfa)->orig_len;
24558c2ecf20Sopenharmony_ci	kfree(*sfa);
24568c2ecf20Sopenharmony_ci	*sfa = acts;
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ciout:
24598c2ecf20Sopenharmony_ci	(*sfa)->actions_len += req_size;
24608c2ecf20Sopenharmony_ci	return  (struct nlattr *) ((unsigned char *)(*sfa) + next_offset);
24618c2ecf20Sopenharmony_ci}
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_cistatic struct nlattr *__add_action(struct sw_flow_actions **sfa,
24648c2ecf20Sopenharmony_ci				   int attrtype, void *data, int len, bool log)
24658c2ecf20Sopenharmony_ci{
24668c2ecf20Sopenharmony_ci	struct nlattr *a;
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci	a = reserve_sfa_size(sfa, nla_attr_size(len), log);
24698c2ecf20Sopenharmony_ci	if (IS_ERR(a))
24708c2ecf20Sopenharmony_ci		return a;
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	a->nla_type = attrtype;
24738c2ecf20Sopenharmony_ci	a->nla_len = nla_attr_size(len);
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci	if (data)
24768c2ecf20Sopenharmony_ci		memcpy(nla_data(a), data, len);
24778c2ecf20Sopenharmony_ci	memset((unsigned char *) a + a->nla_len, 0, nla_padlen(len));
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci	return a;
24808c2ecf20Sopenharmony_ci}
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ciint ovs_nla_add_action(struct sw_flow_actions **sfa, int attrtype, void *data,
24838c2ecf20Sopenharmony_ci		       int len, bool log)
24848c2ecf20Sopenharmony_ci{
24858c2ecf20Sopenharmony_ci	struct nlattr *a;
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci	a = __add_action(sfa, attrtype, data, len, log);
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(a);
24908c2ecf20Sopenharmony_ci}
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_cistatic inline int add_nested_action_start(struct sw_flow_actions **sfa,
24938c2ecf20Sopenharmony_ci					  int attrtype, bool log)
24948c2ecf20Sopenharmony_ci{
24958c2ecf20Sopenharmony_ci	int used = (*sfa)->actions_len;
24968c2ecf20Sopenharmony_ci	int err;
24978c2ecf20Sopenharmony_ci
24988c2ecf20Sopenharmony_ci	err = ovs_nla_add_action(sfa, attrtype, NULL, 0, log);
24998c2ecf20Sopenharmony_ci	if (err)
25008c2ecf20Sopenharmony_ci		return err;
25018c2ecf20Sopenharmony_ci
25028c2ecf20Sopenharmony_ci	return used;
25038c2ecf20Sopenharmony_ci}
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_cistatic inline void add_nested_action_end(struct sw_flow_actions *sfa,
25068c2ecf20Sopenharmony_ci					 int st_offset)
25078c2ecf20Sopenharmony_ci{
25088c2ecf20Sopenharmony_ci	struct nlattr *a = (struct nlattr *) ((unsigned char *)sfa->actions +
25098c2ecf20Sopenharmony_ci							       st_offset);
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_ci	a->nla_len = sfa->actions_len - st_offset;
25128c2ecf20Sopenharmony_ci}
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_cistatic int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
25158c2ecf20Sopenharmony_ci				  const struct sw_flow_key *key,
25168c2ecf20Sopenharmony_ci				  struct sw_flow_actions **sfa,
25178c2ecf20Sopenharmony_ci				  __be16 eth_type, __be16 vlan_tci,
25188c2ecf20Sopenharmony_ci				  u32 mpls_label_count, bool log,
25198c2ecf20Sopenharmony_ci				  u32 depth);
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_cistatic int validate_and_copy_sample(struct net *net, const struct nlattr *attr,
25228c2ecf20Sopenharmony_ci				    const struct sw_flow_key *key,
25238c2ecf20Sopenharmony_ci				    struct sw_flow_actions **sfa,
25248c2ecf20Sopenharmony_ci				    __be16 eth_type, __be16 vlan_tci,
25258c2ecf20Sopenharmony_ci				    u32 mpls_label_count, bool log, bool last,
25268c2ecf20Sopenharmony_ci				    u32 depth)
25278c2ecf20Sopenharmony_ci{
25288c2ecf20Sopenharmony_ci	const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1];
25298c2ecf20Sopenharmony_ci	const struct nlattr *probability, *actions;
25308c2ecf20Sopenharmony_ci	const struct nlattr *a;
25318c2ecf20Sopenharmony_ci	int rem, start, err;
25328c2ecf20Sopenharmony_ci	struct sample_arg arg;
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_ci	memset(attrs, 0, sizeof(attrs));
25358c2ecf20Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
25368c2ecf20Sopenharmony_ci		int type = nla_type(a);
25378c2ecf20Sopenharmony_ci		if (!type || type > OVS_SAMPLE_ATTR_MAX || attrs[type])
25388c2ecf20Sopenharmony_ci			return -EINVAL;
25398c2ecf20Sopenharmony_ci		attrs[type] = a;
25408c2ecf20Sopenharmony_ci	}
25418c2ecf20Sopenharmony_ci	if (rem)
25428c2ecf20Sopenharmony_ci		return -EINVAL;
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci	probability = attrs[OVS_SAMPLE_ATTR_PROBABILITY];
25458c2ecf20Sopenharmony_ci	if (!probability || nla_len(probability) != sizeof(u32))
25468c2ecf20Sopenharmony_ci		return -EINVAL;
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci	actions = attrs[OVS_SAMPLE_ATTR_ACTIONS];
25498c2ecf20Sopenharmony_ci	if (!actions || (nla_len(actions) && nla_len(actions) < NLA_HDRLEN))
25508c2ecf20Sopenharmony_ci		return -EINVAL;
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci	/* validation done, copy sample action. */
25538c2ecf20Sopenharmony_ci	start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SAMPLE, log);
25548c2ecf20Sopenharmony_ci	if (start < 0)
25558c2ecf20Sopenharmony_ci		return start;
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_ci	/* When both skb and flow may be changed, put the sample
25588c2ecf20Sopenharmony_ci	 * into a deferred fifo. On the other hand, if only skb
25598c2ecf20Sopenharmony_ci	 * may be modified, the actions can be executed in place.
25608c2ecf20Sopenharmony_ci	 *
25618c2ecf20Sopenharmony_ci	 * Do this analysis at the flow installation time.
25628c2ecf20Sopenharmony_ci	 * Set 'clone_action->exec' to true if the actions can be
25638c2ecf20Sopenharmony_ci	 * executed without being deferred.
25648c2ecf20Sopenharmony_ci	 *
25658c2ecf20Sopenharmony_ci	 * If the sample is the last action, it can always be excuted
25668c2ecf20Sopenharmony_ci	 * rather than deferred.
25678c2ecf20Sopenharmony_ci	 */
25688c2ecf20Sopenharmony_ci	arg.exec = last || !actions_may_change_flow(actions);
25698c2ecf20Sopenharmony_ci	arg.probability = nla_get_u32(probability);
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_ci	err = ovs_nla_add_action(sfa, OVS_SAMPLE_ATTR_ARG, &arg, sizeof(arg),
25728c2ecf20Sopenharmony_ci				 log);
25738c2ecf20Sopenharmony_ci	if (err)
25748c2ecf20Sopenharmony_ci		return err;
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_ci	err = __ovs_nla_copy_actions(net, actions, key, sfa,
25778c2ecf20Sopenharmony_ci				     eth_type, vlan_tci, mpls_label_count, log,
25788c2ecf20Sopenharmony_ci				     depth + 1);
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	if (err)
25818c2ecf20Sopenharmony_ci		return err;
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci	add_nested_action_end(*sfa, start);
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci	return 0;
25868c2ecf20Sopenharmony_ci}
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_cistatic int validate_and_copy_dec_ttl(struct net *net,
25898c2ecf20Sopenharmony_ci				     const struct nlattr *attr,
25908c2ecf20Sopenharmony_ci				     const struct sw_flow_key *key,
25918c2ecf20Sopenharmony_ci				     struct sw_flow_actions **sfa,
25928c2ecf20Sopenharmony_ci				     __be16 eth_type, __be16 vlan_tci,
25938c2ecf20Sopenharmony_ci				     u32 mpls_label_count, bool log,
25948c2ecf20Sopenharmony_ci				     u32 depth)
25958c2ecf20Sopenharmony_ci{
25968c2ecf20Sopenharmony_ci	const struct nlattr *attrs[OVS_DEC_TTL_ATTR_MAX + 1];
25978c2ecf20Sopenharmony_ci	int start, action_start, err, rem;
25988c2ecf20Sopenharmony_ci	const struct nlattr *a, *actions;
25998c2ecf20Sopenharmony_ci
26008c2ecf20Sopenharmony_ci	memset(attrs, 0, sizeof(attrs));
26018c2ecf20Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
26028c2ecf20Sopenharmony_ci		int type = nla_type(a);
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_ci		/* Ignore unknown attributes to be future proof. */
26058c2ecf20Sopenharmony_ci		if (type > OVS_DEC_TTL_ATTR_MAX)
26068c2ecf20Sopenharmony_ci			continue;
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci		if (!type || attrs[type])
26098c2ecf20Sopenharmony_ci			return -EINVAL;
26108c2ecf20Sopenharmony_ci
26118c2ecf20Sopenharmony_ci		attrs[type] = a;
26128c2ecf20Sopenharmony_ci	}
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci	actions = attrs[OVS_DEC_TTL_ATTR_ACTION];
26158c2ecf20Sopenharmony_ci	if (rem || !actions || (nla_len(actions) && nla_len(actions) < NLA_HDRLEN))
26168c2ecf20Sopenharmony_ci		return -EINVAL;
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci	start = add_nested_action_start(sfa, OVS_ACTION_ATTR_DEC_TTL, log);
26198c2ecf20Sopenharmony_ci	if (start < 0)
26208c2ecf20Sopenharmony_ci		return start;
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci	action_start = add_nested_action_start(sfa, OVS_DEC_TTL_ATTR_ACTION, log);
26238c2ecf20Sopenharmony_ci	if (action_start < 0)
26248c2ecf20Sopenharmony_ci		return action_start;
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_ci	err = __ovs_nla_copy_actions(net, actions, key, sfa, eth_type,
26278c2ecf20Sopenharmony_ci				     vlan_tci, mpls_label_count, log,
26288c2ecf20Sopenharmony_ci				     depth + 1);
26298c2ecf20Sopenharmony_ci	if (err)
26308c2ecf20Sopenharmony_ci		return err;
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ci	add_nested_action_end(*sfa, action_start);
26338c2ecf20Sopenharmony_ci	add_nested_action_end(*sfa, start);
26348c2ecf20Sopenharmony_ci	return 0;
26358c2ecf20Sopenharmony_ci}
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_cistatic int validate_and_copy_clone(struct net *net,
26388c2ecf20Sopenharmony_ci				   const struct nlattr *attr,
26398c2ecf20Sopenharmony_ci				   const struct sw_flow_key *key,
26408c2ecf20Sopenharmony_ci				   struct sw_flow_actions **sfa,
26418c2ecf20Sopenharmony_ci				   __be16 eth_type, __be16 vlan_tci,
26428c2ecf20Sopenharmony_ci				   u32 mpls_label_count, bool log, bool last,
26438c2ecf20Sopenharmony_ci				   u32 depth)
26448c2ecf20Sopenharmony_ci{
26458c2ecf20Sopenharmony_ci	int start, err;
26468c2ecf20Sopenharmony_ci	u32 exec;
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci	if (nla_len(attr) && nla_len(attr) < NLA_HDRLEN)
26498c2ecf20Sopenharmony_ci		return -EINVAL;
26508c2ecf20Sopenharmony_ci
26518c2ecf20Sopenharmony_ci	start = add_nested_action_start(sfa, OVS_ACTION_ATTR_CLONE, log);
26528c2ecf20Sopenharmony_ci	if (start < 0)
26538c2ecf20Sopenharmony_ci		return start;
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_ci	exec = last || !actions_may_change_flow(attr);
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_ci	err = ovs_nla_add_action(sfa, OVS_CLONE_ATTR_EXEC, &exec,
26588c2ecf20Sopenharmony_ci				 sizeof(exec), log);
26598c2ecf20Sopenharmony_ci	if (err)
26608c2ecf20Sopenharmony_ci		return err;
26618c2ecf20Sopenharmony_ci
26628c2ecf20Sopenharmony_ci	err = __ovs_nla_copy_actions(net, attr, key, sfa,
26638c2ecf20Sopenharmony_ci				     eth_type, vlan_tci, mpls_label_count, log,
26648c2ecf20Sopenharmony_ci				     depth + 1);
26658c2ecf20Sopenharmony_ci	if (err)
26668c2ecf20Sopenharmony_ci		return err;
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci	add_nested_action_end(*sfa, start);
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ci	return 0;
26718c2ecf20Sopenharmony_ci}
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_civoid ovs_match_init(struct sw_flow_match *match,
26748c2ecf20Sopenharmony_ci		    struct sw_flow_key *key,
26758c2ecf20Sopenharmony_ci		    bool reset_key,
26768c2ecf20Sopenharmony_ci		    struct sw_flow_mask *mask)
26778c2ecf20Sopenharmony_ci{
26788c2ecf20Sopenharmony_ci	memset(match, 0, sizeof(*match));
26798c2ecf20Sopenharmony_ci	match->key = key;
26808c2ecf20Sopenharmony_ci	match->mask = mask;
26818c2ecf20Sopenharmony_ci
26828c2ecf20Sopenharmony_ci	if (reset_key)
26838c2ecf20Sopenharmony_ci		memset(key, 0, sizeof(*key));
26848c2ecf20Sopenharmony_ci
26858c2ecf20Sopenharmony_ci	if (mask) {
26868c2ecf20Sopenharmony_ci		memset(&mask->key, 0, sizeof(mask->key));
26878c2ecf20Sopenharmony_ci		mask->range.start = mask->range.end = 0;
26888c2ecf20Sopenharmony_ci	}
26898c2ecf20Sopenharmony_ci}
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_cistatic int validate_geneve_opts(struct sw_flow_key *key)
26928c2ecf20Sopenharmony_ci{
26938c2ecf20Sopenharmony_ci	struct geneve_opt *option;
26948c2ecf20Sopenharmony_ci	int opts_len = key->tun_opts_len;
26958c2ecf20Sopenharmony_ci	bool crit_opt = false;
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	option = (struct geneve_opt *)TUN_METADATA_OPTS(key, key->tun_opts_len);
26988c2ecf20Sopenharmony_ci	while (opts_len > 0) {
26998c2ecf20Sopenharmony_ci		int len;
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci		if (opts_len < sizeof(*option))
27028c2ecf20Sopenharmony_ci			return -EINVAL;
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci		len = sizeof(*option) + option->length * 4;
27058c2ecf20Sopenharmony_ci		if (len > opts_len)
27068c2ecf20Sopenharmony_ci			return -EINVAL;
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci		crit_opt |= !!(option->type & GENEVE_CRIT_OPT_TYPE);
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ci		option = (struct geneve_opt *)((u8 *)option + len);
27118c2ecf20Sopenharmony_ci		opts_len -= len;
27128c2ecf20Sopenharmony_ci	}
27138c2ecf20Sopenharmony_ci
27148c2ecf20Sopenharmony_ci	key->tun_key.tun_flags |= crit_opt ? TUNNEL_CRIT_OPT : 0;
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_ci	return 0;
27178c2ecf20Sopenharmony_ci}
27188c2ecf20Sopenharmony_ci
27198c2ecf20Sopenharmony_cistatic int validate_and_copy_set_tun(const struct nlattr *attr,
27208c2ecf20Sopenharmony_ci				     struct sw_flow_actions **sfa, bool log)
27218c2ecf20Sopenharmony_ci{
27228c2ecf20Sopenharmony_ci	struct sw_flow_match match;
27238c2ecf20Sopenharmony_ci	struct sw_flow_key key;
27248c2ecf20Sopenharmony_ci	struct metadata_dst *tun_dst;
27258c2ecf20Sopenharmony_ci	struct ip_tunnel_info *tun_info;
27268c2ecf20Sopenharmony_ci	struct ovs_tunnel_info *ovs_tun;
27278c2ecf20Sopenharmony_ci	struct nlattr *a;
27288c2ecf20Sopenharmony_ci	int err = 0, start, opts_type;
27298c2ecf20Sopenharmony_ci	__be16 dst_opt_type;
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci	dst_opt_type = 0;
27328c2ecf20Sopenharmony_ci	ovs_match_init(&match, &key, true, NULL);
27338c2ecf20Sopenharmony_ci	opts_type = ip_tun_from_nlattr(nla_data(attr), &match, false, log);
27348c2ecf20Sopenharmony_ci	if (opts_type < 0)
27358c2ecf20Sopenharmony_ci		return opts_type;
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_ci	if (key.tun_opts_len) {
27388c2ecf20Sopenharmony_ci		switch (opts_type) {
27398c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
27408c2ecf20Sopenharmony_ci			err = validate_geneve_opts(&key);
27418c2ecf20Sopenharmony_ci			if (err < 0)
27428c2ecf20Sopenharmony_ci				return err;
27438c2ecf20Sopenharmony_ci			dst_opt_type = TUNNEL_GENEVE_OPT;
27448c2ecf20Sopenharmony_ci			break;
27458c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
27468c2ecf20Sopenharmony_ci			dst_opt_type = TUNNEL_VXLAN_OPT;
27478c2ecf20Sopenharmony_ci			break;
27488c2ecf20Sopenharmony_ci		case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS:
27498c2ecf20Sopenharmony_ci			dst_opt_type = TUNNEL_ERSPAN_OPT;
27508c2ecf20Sopenharmony_ci			break;
27518c2ecf20Sopenharmony_ci		}
27528c2ecf20Sopenharmony_ci	}
27538c2ecf20Sopenharmony_ci
27548c2ecf20Sopenharmony_ci	start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET, log);
27558c2ecf20Sopenharmony_ci	if (start < 0)
27568c2ecf20Sopenharmony_ci		return start;
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci	tun_dst = metadata_dst_alloc(key.tun_opts_len, METADATA_IP_TUNNEL,
27598c2ecf20Sopenharmony_ci				     GFP_KERNEL);
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_ci	if (!tun_dst)
27628c2ecf20Sopenharmony_ci		return -ENOMEM;
27638c2ecf20Sopenharmony_ci
27648c2ecf20Sopenharmony_ci	err = dst_cache_init(&tun_dst->u.tun_info.dst_cache, GFP_KERNEL);
27658c2ecf20Sopenharmony_ci	if (err) {
27668c2ecf20Sopenharmony_ci		dst_release((struct dst_entry *)tun_dst);
27678c2ecf20Sopenharmony_ci		return err;
27688c2ecf20Sopenharmony_ci	}
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL,
27718c2ecf20Sopenharmony_ci			 sizeof(*ovs_tun), log);
27728c2ecf20Sopenharmony_ci	if (IS_ERR(a)) {
27738c2ecf20Sopenharmony_ci		dst_release((struct dst_entry *)tun_dst);
27748c2ecf20Sopenharmony_ci		return PTR_ERR(a);
27758c2ecf20Sopenharmony_ci	}
27768c2ecf20Sopenharmony_ci
27778c2ecf20Sopenharmony_ci	ovs_tun = nla_data(a);
27788c2ecf20Sopenharmony_ci	ovs_tun->tun_dst = tun_dst;
27798c2ecf20Sopenharmony_ci
27808c2ecf20Sopenharmony_ci	tun_info = &tun_dst->u.tun_info;
27818c2ecf20Sopenharmony_ci	tun_info->mode = IP_TUNNEL_INFO_TX;
27828c2ecf20Sopenharmony_ci	if (key.tun_proto == AF_INET6)
27838c2ecf20Sopenharmony_ci		tun_info->mode |= IP_TUNNEL_INFO_IPV6;
27848c2ecf20Sopenharmony_ci	else if (key.tun_proto == AF_INET && key.tun_key.u.ipv4.dst == 0)
27858c2ecf20Sopenharmony_ci		tun_info->mode |= IP_TUNNEL_INFO_BRIDGE;
27868c2ecf20Sopenharmony_ci	tun_info->key = key.tun_key;
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci	/* We need to store the options in the action itself since
27898c2ecf20Sopenharmony_ci	 * everything else will go away after flow setup. We can append
27908c2ecf20Sopenharmony_ci	 * it to tun_info and then point there.
27918c2ecf20Sopenharmony_ci	 */
27928c2ecf20Sopenharmony_ci	ip_tunnel_info_opts_set(tun_info,
27938c2ecf20Sopenharmony_ci				TUN_METADATA_OPTS(&key, key.tun_opts_len),
27948c2ecf20Sopenharmony_ci				key.tun_opts_len, dst_opt_type);
27958c2ecf20Sopenharmony_ci	add_nested_action_end(*sfa, start);
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci	return err;
27988c2ecf20Sopenharmony_ci}
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_cistatic bool validate_nsh(const struct nlattr *attr, bool is_mask,
28018c2ecf20Sopenharmony_ci			 bool is_push_nsh, bool log)
28028c2ecf20Sopenharmony_ci{
28038c2ecf20Sopenharmony_ci	struct sw_flow_match match;
28048c2ecf20Sopenharmony_ci	struct sw_flow_key key;
28058c2ecf20Sopenharmony_ci	int ret = 0;
28068c2ecf20Sopenharmony_ci
28078c2ecf20Sopenharmony_ci	ovs_match_init(&match, &key, true, NULL);
28088c2ecf20Sopenharmony_ci	ret = nsh_key_put_from_nlattr(attr, &match, is_mask,
28098c2ecf20Sopenharmony_ci				      is_push_nsh, log);
28108c2ecf20Sopenharmony_ci	return !ret;
28118c2ecf20Sopenharmony_ci}
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ci/* Return false if there are any non-masked bits set.
28148c2ecf20Sopenharmony_ci * Mask follows data immediately, before any netlink padding.
28158c2ecf20Sopenharmony_ci */
28168c2ecf20Sopenharmony_cistatic bool validate_masked(u8 *data, int len)
28178c2ecf20Sopenharmony_ci{
28188c2ecf20Sopenharmony_ci	u8 *mask = data + len;
28198c2ecf20Sopenharmony_ci
28208c2ecf20Sopenharmony_ci	while (len--)
28218c2ecf20Sopenharmony_ci		if (*data++ & ~*mask++)
28228c2ecf20Sopenharmony_ci			return false;
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci	return true;
28258c2ecf20Sopenharmony_ci}
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_cistatic int validate_set(const struct nlattr *a,
28288c2ecf20Sopenharmony_ci			const struct sw_flow_key *flow_key,
28298c2ecf20Sopenharmony_ci			struct sw_flow_actions **sfa, bool *skip_copy,
28308c2ecf20Sopenharmony_ci			u8 mac_proto, __be16 eth_type, bool masked, bool log)
28318c2ecf20Sopenharmony_ci{
28328c2ecf20Sopenharmony_ci	const struct nlattr *ovs_key = nla_data(a);
28338c2ecf20Sopenharmony_ci	int key_type = nla_type(ovs_key);
28348c2ecf20Sopenharmony_ci	size_t key_len;
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_ci	/* There can be only one key in a action */
28378c2ecf20Sopenharmony_ci	if (nla_total_size(nla_len(ovs_key)) != nla_len(a))
28388c2ecf20Sopenharmony_ci		return -EINVAL;
28398c2ecf20Sopenharmony_ci
28408c2ecf20Sopenharmony_ci	key_len = nla_len(ovs_key);
28418c2ecf20Sopenharmony_ci	if (masked)
28428c2ecf20Sopenharmony_ci		key_len /= 2;
28438c2ecf20Sopenharmony_ci
28448c2ecf20Sopenharmony_ci	if (key_type > OVS_KEY_ATTR_MAX ||
28458c2ecf20Sopenharmony_ci	    !check_attr_len(key_len, ovs_key_lens[key_type].len))
28468c2ecf20Sopenharmony_ci		return -EINVAL;
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_ci	if (masked && !validate_masked(nla_data(ovs_key), key_len))
28498c2ecf20Sopenharmony_ci		return -EINVAL;
28508c2ecf20Sopenharmony_ci
28518c2ecf20Sopenharmony_ci	switch (key_type) {
28528c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_PRIORITY:
28538c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_SKB_MARK:
28548c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_CT_MARK:
28558c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_CT_LABELS:
28568c2ecf20Sopenharmony_ci		break;
28578c2ecf20Sopenharmony_ci
28588c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_ETHERNET:
28598c2ecf20Sopenharmony_ci		if (mac_proto != MAC_PROTO_ETHERNET)
28608c2ecf20Sopenharmony_ci			return -EINVAL;
28618c2ecf20Sopenharmony_ci		break;
28628c2ecf20Sopenharmony_ci
28638c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_TUNNEL: {
28648c2ecf20Sopenharmony_ci		int err;
28658c2ecf20Sopenharmony_ci
28668c2ecf20Sopenharmony_ci		if (masked)
28678c2ecf20Sopenharmony_ci			return -EINVAL; /* Masked tunnel set not supported. */
28688c2ecf20Sopenharmony_ci
28698c2ecf20Sopenharmony_ci		*skip_copy = true;
28708c2ecf20Sopenharmony_ci		err = validate_and_copy_set_tun(a, sfa, log);
28718c2ecf20Sopenharmony_ci		if (err)
28728c2ecf20Sopenharmony_ci			return err;
28738c2ecf20Sopenharmony_ci		break;
28748c2ecf20Sopenharmony_ci	}
28758c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_IPV4: {
28768c2ecf20Sopenharmony_ci		const struct ovs_key_ipv4 *ipv4_key;
28778c2ecf20Sopenharmony_ci
28788c2ecf20Sopenharmony_ci		if (eth_type != htons(ETH_P_IP))
28798c2ecf20Sopenharmony_ci			return -EINVAL;
28808c2ecf20Sopenharmony_ci
28818c2ecf20Sopenharmony_ci		ipv4_key = nla_data(ovs_key);
28828c2ecf20Sopenharmony_ci
28838c2ecf20Sopenharmony_ci		if (masked) {
28848c2ecf20Sopenharmony_ci			const struct ovs_key_ipv4 *mask = ipv4_key + 1;
28858c2ecf20Sopenharmony_ci
28868c2ecf20Sopenharmony_ci			/* Non-writeable fields. */
28878c2ecf20Sopenharmony_ci			if (mask->ipv4_proto || mask->ipv4_frag)
28888c2ecf20Sopenharmony_ci				return -EINVAL;
28898c2ecf20Sopenharmony_ci		} else {
28908c2ecf20Sopenharmony_ci			if (ipv4_key->ipv4_proto != flow_key->ip.proto)
28918c2ecf20Sopenharmony_ci				return -EINVAL;
28928c2ecf20Sopenharmony_ci
28938c2ecf20Sopenharmony_ci			if (ipv4_key->ipv4_frag != flow_key->ip.frag)
28948c2ecf20Sopenharmony_ci				return -EINVAL;
28958c2ecf20Sopenharmony_ci		}
28968c2ecf20Sopenharmony_ci		break;
28978c2ecf20Sopenharmony_ci	}
28988c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_IPV6: {
28998c2ecf20Sopenharmony_ci		const struct ovs_key_ipv6 *ipv6_key;
29008c2ecf20Sopenharmony_ci
29018c2ecf20Sopenharmony_ci		if (eth_type != htons(ETH_P_IPV6))
29028c2ecf20Sopenharmony_ci			return -EINVAL;
29038c2ecf20Sopenharmony_ci
29048c2ecf20Sopenharmony_ci		ipv6_key = nla_data(ovs_key);
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_ci		if (masked) {
29078c2ecf20Sopenharmony_ci			const struct ovs_key_ipv6 *mask = ipv6_key + 1;
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_ci			/* Non-writeable fields. */
29108c2ecf20Sopenharmony_ci			if (mask->ipv6_proto || mask->ipv6_frag)
29118c2ecf20Sopenharmony_ci				return -EINVAL;
29128c2ecf20Sopenharmony_ci
29138c2ecf20Sopenharmony_ci			/* Invalid bits in the flow label mask? */
29148c2ecf20Sopenharmony_ci			if (ntohl(mask->ipv6_label) & 0xFFF00000)
29158c2ecf20Sopenharmony_ci				return -EINVAL;
29168c2ecf20Sopenharmony_ci		} else {
29178c2ecf20Sopenharmony_ci			if (ipv6_key->ipv6_proto != flow_key->ip.proto)
29188c2ecf20Sopenharmony_ci				return -EINVAL;
29198c2ecf20Sopenharmony_ci
29208c2ecf20Sopenharmony_ci			if (ipv6_key->ipv6_frag != flow_key->ip.frag)
29218c2ecf20Sopenharmony_ci				return -EINVAL;
29228c2ecf20Sopenharmony_ci		}
29238c2ecf20Sopenharmony_ci		if (ntohl(ipv6_key->ipv6_label) & 0xFFF00000)
29248c2ecf20Sopenharmony_ci			return -EINVAL;
29258c2ecf20Sopenharmony_ci
29268c2ecf20Sopenharmony_ci		break;
29278c2ecf20Sopenharmony_ci	}
29288c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_TCP:
29298c2ecf20Sopenharmony_ci		if ((eth_type != htons(ETH_P_IP) &&
29308c2ecf20Sopenharmony_ci		     eth_type != htons(ETH_P_IPV6)) ||
29318c2ecf20Sopenharmony_ci		    flow_key->ip.proto != IPPROTO_TCP)
29328c2ecf20Sopenharmony_ci			return -EINVAL;
29338c2ecf20Sopenharmony_ci
29348c2ecf20Sopenharmony_ci		break;
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_UDP:
29378c2ecf20Sopenharmony_ci		if ((eth_type != htons(ETH_P_IP) &&
29388c2ecf20Sopenharmony_ci		     eth_type != htons(ETH_P_IPV6)) ||
29398c2ecf20Sopenharmony_ci		    flow_key->ip.proto != IPPROTO_UDP)
29408c2ecf20Sopenharmony_ci			return -EINVAL;
29418c2ecf20Sopenharmony_ci
29428c2ecf20Sopenharmony_ci		break;
29438c2ecf20Sopenharmony_ci
29448c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_MPLS:
29458c2ecf20Sopenharmony_ci		if (!eth_p_mpls(eth_type))
29468c2ecf20Sopenharmony_ci			return -EINVAL;
29478c2ecf20Sopenharmony_ci		break;
29488c2ecf20Sopenharmony_ci
29498c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_SCTP:
29508c2ecf20Sopenharmony_ci		if ((eth_type != htons(ETH_P_IP) &&
29518c2ecf20Sopenharmony_ci		     eth_type != htons(ETH_P_IPV6)) ||
29528c2ecf20Sopenharmony_ci		    flow_key->ip.proto != IPPROTO_SCTP)
29538c2ecf20Sopenharmony_ci			return -EINVAL;
29548c2ecf20Sopenharmony_ci
29558c2ecf20Sopenharmony_ci		break;
29568c2ecf20Sopenharmony_ci
29578c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_NSH:
29588c2ecf20Sopenharmony_ci		if (eth_type != htons(ETH_P_NSH))
29598c2ecf20Sopenharmony_ci			return -EINVAL;
29608c2ecf20Sopenharmony_ci		if (!validate_nsh(nla_data(a), masked, false, log))
29618c2ecf20Sopenharmony_ci			return -EINVAL;
29628c2ecf20Sopenharmony_ci		break;
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci	default:
29658c2ecf20Sopenharmony_ci		return -EINVAL;
29668c2ecf20Sopenharmony_ci	}
29678c2ecf20Sopenharmony_ci
29688c2ecf20Sopenharmony_ci	/* Convert non-masked non-tunnel set actions to masked set actions. */
29698c2ecf20Sopenharmony_ci	if (!masked && key_type != OVS_KEY_ATTR_TUNNEL) {
29708c2ecf20Sopenharmony_ci		int start, len = key_len * 2;
29718c2ecf20Sopenharmony_ci		struct nlattr *at;
29728c2ecf20Sopenharmony_ci
29738c2ecf20Sopenharmony_ci		*skip_copy = true;
29748c2ecf20Sopenharmony_ci
29758c2ecf20Sopenharmony_ci		start = add_nested_action_start(sfa,
29768c2ecf20Sopenharmony_ci						OVS_ACTION_ATTR_SET_TO_MASKED,
29778c2ecf20Sopenharmony_ci						log);
29788c2ecf20Sopenharmony_ci		if (start < 0)
29798c2ecf20Sopenharmony_ci			return start;
29808c2ecf20Sopenharmony_ci
29818c2ecf20Sopenharmony_ci		at = __add_action(sfa, key_type, NULL, len, log);
29828c2ecf20Sopenharmony_ci		if (IS_ERR(at))
29838c2ecf20Sopenharmony_ci			return PTR_ERR(at);
29848c2ecf20Sopenharmony_ci
29858c2ecf20Sopenharmony_ci		memcpy(nla_data(at), nla_data(ovs_key), key_len); /* Key. */
29868c2ecf20Sopenharmony_ci		memset(nla_data(at) + key_len, 0xff, key_len);    /* Mask. */
29878c2ecf20Sopenharmony_ci		/* Clear non-writeable bits from otherwise writeable fields. */
29888c2ecf20Sopenharmony_ci		if (key_type == OVS_KEY_ATTR_IPV6) {
29898c2ecf20Sopenharmony_ci			struct ovs_key_ipv6 *mask = nla_data(at) + key_len;
29908c2ecf20Sopenharmony_ci
29918c2ecf20Sopenharmony_ci			mask->ipv6_label &= htonl(0x000FFFFF);
29928c2ecf20Sopenharmony_ci		}
29938c2ecf20Sopenharmony_ci		add_nested_action_end(*sfa, start);
29948c2ecf20Sopenharmony_ci	}
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_ci	return 0;
29978c2ecf20Sopenharmony_ci}
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_cistatic int validate_userspace(const struct nlattr *attr)
30008c2ecf20Sopenharmony_ci{
30018c2ecf20Sopenharmony_ci	static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] = {
30028c2ecf20Sopenharmony_ci		[OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 },
30038c2ecf20Sopenharmony_ci		[OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC },
30048c2ecf20Sopenharmony_ci		[OVS_USERSPACE_ATTR_EGRESS_TUN_PORT] = {.type = NLA_U32 },
30058c2ecf20Sopenharmony_ci	};
30068c2ecf20Sopenharmony_ci	struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1];
30078c2ecf20Sopenharmony_ci	int error;
30088c2ecf20Sopenharmony_ci
30098c2ecf20Sopenharmony_ci	error = nla_parse_nested_deprecated(a, OVS_USERSPACE_ATTR_MAX, attr,
30108c2ecf20Sopenharmony_ci					    userspace_policy, NULL);
30118c2ecf20Sopenharmony_ci	if (error)
30128c2ecf20Sopenharmony_ci		return error;
30138c2ecf20Sopenharmony_ci
30148c2ecf20Sopenharmony_ci	if (!a[OVS_USERSPACE_ATTR_PID] ||
30158c2ecf20Sopenharmony_ci	    !nla_get_u32(a[OVS_USERSPACE_ATTR_PID]))
30168c2ecf20Sopenharmony_ci		return -EINVAL;
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_ci	return 0;
30198c2ecf20Sopenharmony_ci}
30208c2ecf20Sopenharmony_ci
30218c2ecf20Sopenharmony_cistatic const struct nla_policy cpl_policy[OVS_CHECK_PKT_LEN_ATTR_MAX + 1] = {
30228c2ecf20Sopenharmony_ci	[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN] = {.type = NLA_U16 },
30238c2ecf20Sopenharmony_ci	[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER] = {.type = NLA_NESTED },
30248c2ecf20Sopenharmony_ci	[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL] = {.type = NLA_NESTED },
30258c2ecf20Sopenharmony_ci};
30268c2ecf20Sopenharmony_ci
30278c2ecf20Sopenharmony_cistatic int validate_and_copy_check_pkt_len(struct net *net,
30288c2ecf20Sopenharmony_ci					   const struct nlattr *attr,
30298c2ecf20Sopenharmony_ci					   const struct sw_flow_key *key,
30308c2ecf20Sopenharmony_ci					   struct sw_flow_actions **sfa,
30318c2ecf20Sopenharmony_ci					   __be16 eth_type, __be16 vlan_tci,
30328c2ecf20Sopenharmony_ci					   u32 mpls_label_count,
30338c2ecf20Sopenharmony_ci					   bool log, bool last, u32 depth)
30348c2ecf20Sopenharmony_ci{
30358c2ecf20Sopenharmony_ci	const struct nlattr *acts_if_greater, *acts_if_lesser_eq;
30368c2ecf20Sopenharmony_ci	struct nlattr *a[OVS_CHECK_PKT_LEN_ATTR_MAX + 1];
30378c2ecf20Sopenharmony_ci	struct check_pkt_len_arg arg;
30388c2ecf20Sopenharmony_ci	int nested_acts_start;
30398c2ecf20Sopenharmony_ci	int start, err;
30408c2ecf20Sopenharmony_ci
30418c2ecf20Sopenharmony_ci	err = nla_parse_deprecated_strict(a, OVS_CHECK_PKT_LEN_ATTR_MAX,
30428c2ecf20Sopenharmony_ci					  nla_data(attr), nla_len(attr),
30438c2ecf20Sopenharmony_ci					  cpl_policy, NULL);
30448c2ecf20Sopenharmony_ci	if (err)
30458c2ecf20Sopenharmony_ci		return err;
30468c2ecf20Sopenharmony_ci
30478c2ecf20Sopenharmony_ci	if (!a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN] ||
30488c2ecf20Sopenharmony_ci	    !nla_get_u16(a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN]))
30498c2ecf20Sopenharmony_ci		return -EINVAL;
30508c2ecf20Sopenharmony_ci
30518c2ecf20Sopenharmony_ci	acts_if_lesser_eq = a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL];
30528c2ecf20Sopenharmony_ci	acts_if_greater = a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER];
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci	/* Both the nested action should be present. */
30558c2ecf20Sopenharmony_ci	if (!acts_if_greater || !acts_if_lesser_eq)
30568c2ecf20Sopenharmony_ci		return -EINVAL;
30578c2ecf20Sopenharmony_ci
30588c2ecf20Sopenharmony_ci	/* validation done, copy the nested actions. */
30598c2ecf20Sopenharmony_ci	start = add_nested_action_start(sfa, OVS_ACTION_ATTR_CHECK_PKT_LEN,
30608c2ecf20Sopenharmony_ci					log);
30618c2ecf20Sopenharmony_ci	if (start < 0)
30628c2ecf20Sopenharmony_ci		return start;
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci	arg.pkt_len = nla_get_u16(a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN]);
30658c2ecf20Sopenharmony_ci	arg.exec_for_lesser_equal =
30668c2ecf20Sopenharmony_ci		last || !actions_may_change_flow(acts_if_lesser_eq);
30678c2ecf20Sopenharmony_ci	arg.exec_for_greater =
30688c2ecf20Sopenharmony_ci		last || !actions_may_change_flow(acts_if_greater);
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci	err = ovs_nla_add_action(sfa, OVS_CHECK_PKT_LEN_ATTR_ARG, &arg,
30718c2ecf20Sopenharmony_ci				 sizeof(arg), log);
30728c2ecf20Sopenharmony_ci	if (err)
30738c2ecf20Sopenharmony_ci		return err;
30748c2ecf20Sopenharmony_ci
30758c2ecf20Sopenharmony_ci	nested_acts_start = add_nested_action_start(sfa,
30768c2ecf20Sopenharmony_ci		OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL, log);
30778c2ecf20Sopenharmony_ci	if (nested_acts_start < 0)
30788c2ecf20Sopenharmony_ci		return nested_acts_start;
30798c2ecf20Sopenharmony_ci
30808c2ecf20Sopenharmony_ci	err = __ovs_nla_copy_actions(net, acts_if_lesser_eq, key, sfa,
30818c2ecf20Sopenharmony_ci				     eth_type, vlan_tci, mpls_label_count, log,
30828c2ecf20Sopenharmony_ci				     depth + 1);
30838c2ecf20Sopenharmony_ci
30848c2ecf20Sopenharmony_ci	if (err)
30858c2ecf20Sopenharmony_ci		return err;
30868c2ecf20Sopenharmony_ci
30878c2ecf20Sopenharmony_ci	add_nested_action_end(*sfa, nested_acts_start);
30888c2ecf20Sopenharmony_ci
30898c2ecf20Sopenharmony_ci	nested_acts_start = add_nested_action_start(sfa,
30908c2ecf20Sopenharmony_ci		OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER, log);
30918c2ecf20Sopenharmony_ci	if (nested_acts_start < 0)
30928c2ecf20Sopenharmony_ci		return nested_acts_start;
30938c2ecf20Sopenharmony_ci
30948c2ecf20Sopenharmony_ci	err = __ovs_nla_copy_actions(net, acts_if_greater, key, sfa,
30958c2ecf20Sopenharmony_ci				     eth_type, vlan_tci, mpls_label_count, log,
30968c2ecf20Sopenharmony_ci				     depth + 1);
30978c2ecf20Sopenharmony_ci
30988c2ecf20Sopenharmony_ci	if (err)
30998c2ecf20Sopenharmony_ci		return err;
31008c2ecf20Sopenharmony_ci
31018c2ecf20Sopenharmony_ci	add_nested_action_end(*sfa, nested_acts_start);
31028c2ecf20Sopenharmony_ci	add_nested_action_end(*sfa, start);
31038c2ecf20Sopenharmony_ci	return 0;
31048c2ecf20Sopenharmony_ci}
31058c2ecf20Sopenharmony_ci
31068c2ecf20Sopenharmony_cistatic int copy_action(const struct nlattr *from,
31078c2ecf20Sopenharmony_ci		       struct sw_flow_actions **sfa, bool log)
31088c2ecf20Sopenharmony_ci{
31098c2ecf20Sopenharmony_ci	int totlen = NLA_ALIGN(from->nla_len);
31108c2ecf20Sopenharmony_ci	struct nlattr *to;
31118c2ecf20Sopenharmony_ci
31128c2ecf20Sopenharmony_ci	to = reserve_sfa_size(sfa, from->nla_len, log);
31138c2ecf20Sopenharmony_ci	if (IS_ERR(to))
31148c2ecf20Sopenharmony_ci		return PTR_ERR(to);
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci	memcpy(to, from, totlen);
31178c2ecf20Sopenharmony_ci	return 0;
31188c2ecf20Sopenharmony_ci}
31198c2ecf20Sopenharmony_ci
31208c2ecf20Sopenharmony_cistatic int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
31218c2ecf20Sopenharmony_ci				  const struct sw_flow_key *key,
31228c2ecf20Sopenharmony_ci				  struct sw_flow_actions **sfa,
31238c2ecf20Sopenharmony_ci				  __be16 eth_type, __be16 vlan_tci,
31248c2ecf20Sopenharmony_ci				  u32 mpls_label_count, bool log,
31258c2ecf20Sopenharmony_ci				  u32 depth)
31268c2ecf20Sopenharmony_ci{
31278c2ecf20Sopenharmony_ci	u8 mac_proto = ovs_key_mac_proto(key);
31288c2ecf20Sopenharmony_ci	const struct nlattr *a;
31298c2ecf20Sopenharmony_ci	int rem, err;
31308c2ecf20Sopenharmony_ci
31318c2ecf20Sopenharmony_ci	if (depth > OVS_COPY_ACTIONS_MAX_DEPTH)
31328c2ecf20Sopenharmony_ci		return -EOVERFLOW;
31338c2ecf20Sopenharmony_ci
31348c2ecf20Sopenharmony_ci	nla_for_each_nested(a, attr, rem) {
31358c2ecf20Sopenharmony_ci		/* Expected argument lengths, (u32)-1 for variable length. */
31368c2ecf20Sopenharmony_ci		static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {
31378c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_OUTPUT] = sizeof(u32),
31388c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_RECIRC] = sizeof(u32),
31398c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_USERSPACE] = (u32)-1,
31408c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_PUSH_MPLS] = sizeof(struct ovs_action_push_mpls),
31418c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16),
31428c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan),
31438c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_POP_VLAN] = 0,
31448c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_SET] = (u32)-1,
31458c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_SET_MASKED] = (u32)-1,
31468c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
31478c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash),
31488c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_CT] = (u32)-1,
31498c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_CT_CLEAR] = 0,
31508c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_TRUNC] = sizeof(struct ovs_action_trunc),
31518c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth),
31528c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_POP_ETH] = 0,
31538c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_PUSH_NSH] = (u32)-1,
31548c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_POP_NSH] = 0,
31558c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_METER] = sizeof(u32),
31568c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_CLONE] = (u32)-1,
31578c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_CHECK_PKT_LEN] = (u32)-1,
31588c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_ADD_MPLS] = sizeof(struct ovs_action_add_mpls),
31598c2ecf20Sopenharmony_ci			[OVS_ACTION_ATTR_DEC_TTL] = (u32)-1,
31608c2ecf20Sopenharmony_ci		};
31618c2ecf20Sopenharmony_ci		const struct ovs_action_push_vlan *vlan;
31628c2ecf20Sopenharmony_ci		int type = nla_type(a);
31638c2ecf20Sopenharmony_ci		bool skip_copy;
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_ci		if (type > OVS_ACTION_ATTR_MAX ||
31668c2ecf20Sopenharmony_ci		    (action_lens[type] != nla_len(a) &&
31678c2ecf20Sopenharmony_ci		     action_lens[type] != (u32)-1))
31688c2ecf20Sopenharmony_ci			return -EINVAL;
31698c2ecf20Sopenharmony_ci
31708c2ecf20Sopenharmony_ci		skip_copy = false;
31718c2ecf20Sopenharmony_ci		switch (type) {
31728c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_UNSPEC:
31738c2ecf20Sopenharmony_ci			return -EINVAL;
31748c2ecf20Sopenharmony_ci
31758c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_USERSPACE:
31768c2ecf20Sopenharmony_ci			err = validate_userspace(a);
31778c2ecf20Sopenharmony_ci			if (err)
31788c2ecf20Sopenharmony_ci				return err;
31798c2ecf20Sopenharmony_ci			break;
31808c2ecf20Sopenharmony_ci
31818c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_OUTPUT:
31828c2ecf20Sopenharmony_ci			if (nla_get_u32(a) >= DP_MAX_PORTS)
31838c2ecf20Sopenharmony_ci				return -EINVAL;
31848c2ecf20Sopenharmony_ci			break;
31858c2ecf20Sopenharmony_ci
31868c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_TRUNC: {
31878c2ecf20Sopenharmony_ci			const struct ovs_action_trunc *trunc = nla_data(a);
31888c2ecf20Sopenharmony_ci
31898c2ecf20Sopenharmony_ci			if (trunc->max_len < ETH_HLEN)
31908c2ecf20Sopenharmony_ci				return -EINVAL;
31918c2ecf20Sopenharmony_ci			break;
31928c2ecf20Sopenharmony_ci		}
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_HASH: {
31958c2ecf20Sopenharmony_ci			const struct ovs_action_hash *act_hash = nla_data(a);
31968c2ecf20Sopenharmony_ci
31978c2ecf20Sopenharmony_ci			switch (act_hash->hash_alg) {
31988c2ecf20Sopenharmony_ci			case OVS_HASH_ALG_L4:
31998c2ecf20Sopenharmony_ci				break;
32008c2ecf20Sopenharmony_ci			default:
32018c2ecf20Sopenharmony_ci				return  -EINVAL;
32028c2ecf20Sopenharmony_ci			}
32038c2ecf20Sopenharmony_ci
32048c2ecf20Sopenharmony_ci			break;
32058c2ecf20Sopenharmony_ci		}
32068c2ecf20Sopenharmony_ci
32078c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_POP_VLAN:
32088c2ecf20Sopenharmony_ci			if (mac_proto != MAC_PROTO_ETHERNET)
32098c2ecf20Sopenharmony_ci				return -EINVAL;
32108c2ecf20Sopenharmony_ci			vlan_tci = htons(0);
32118c2ecf20Sopenharmony_ci			break;
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_VLAN:
32148c2ecf20Sopenharmony_ci			if (mac_proto != MAC_PROTO_ETHERNET)
32158c2ecf20Sopenharmony_ci				return -EINVAL;
32168c2ecf20Sopenharmony_ci			vlan = nla_data(a);
32178c2ecf20Sopenharmony_ci			if (!eth_type_vlan(vlan->vlan_tpid))
32188c2ecf20Sopenharmony_ci				return -EINVAL;
32198c2ecf20Sopenharmony_ci			if (!(vlan->vlan_tci & htons(VLAN_CFI_MASK)))
32208c2ecf20Sopenharmony_ci				return -EINVAL;
32218c2ecf20Sopenharmony_ci			vlan_tci = vlan->vlan_tci;
32228c2ecf20Sopenharmony_ci			break;
32238c2ecf20Sopenharmony_ci
32248c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_RECIRC:
32258c2ecf20Sopenharmony_ci			break;
32268c2ecf20Sopenharmony_ci
32278c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_ADD_MPLS: {
32288c2ecf20Sopenharmony_ci			const struct ovs_action_add_mpls *mpls = nla_data(a);
32298c2ecf20Sopenharmony_ci
32308c2ecf20Sopenharmony_ci			if (!eth_p_mpls(mpls->mpls_ethertype))
32318c2ecf20Sopenharmony_ci				return -EINVAL;
32328c2ecf20Sopenharmony_ci
32338c2ecf20Sopenharmony_ci			if (mpls->tun_flags & OVS_MPLS_L3_TUNNEL_FLAG_MASK) {
32348c2ecf20Sopenharmony_ci				if (vlan_tci & htons(VLAN_CFI_MASK) ||
32358c2ecf20Sopenharmony_ci				    (eth_type != htons(ETH_P_IP) &&
32368c2ecf20Sopenharmony_ci				     eth_type != htons(ETH_P_IPV6) &&
32378c2ecf20Sopenharmony_ci				     eth_type != htons(ETH_P_ARP) &&
32388c2ecf20Sopenharmony_ci				     eth_type != htons(ETH_P_RARP) &&
32398c2ecf20Sopenharmony_ci				     !eth_p_mpls(eth_type)))
32408c2ecf20Sopenharmony_ci					return -EINVAL;
32418c2ecf20Sopenharmony_ci				mpls_label_count++;
32428c2ecf20Sopenharmony_ci			} else {
32438c2ecf20Sopenharmony_ci				if (mac_proto == MAC_PROTO_ETHERNET) {
32448c2ecf20Sopenharmony_ci					mpls_label_count = 1;
32458c2ecf20Sopenharmony_ci					mac_proto = MAC_PROTO_NONE;
32468c2ecf20Sopenharmony_ci				} else {
32478c2ecf20Sopenharmony_ci					mpls_label_count++;
32488c2ecf20Sopenharmony_ci				}
32498c2ecf20Sopenharmony_ci			}
32508c2ecf20Sopenharmony_ci			eth_type = mpls->mpls_ethertype;
32518c2ecf20Sopenharmony_ci			break;
32528c2ecf20Sopenharmony_ci		}
32538c2ecf20Sopenharmony_ci
32548c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_MPLS: {
32558c2ecf20Sopenharmony_ci			const struct ovs_action_push_mpls *mpls = nla_data(a);
32568c2ecf20Sopenharmony_ci
32578c2ecf20Sopenharmony_ci			if (!eth_p_mpls(mpls->mpls_ethertype))
32588c2ecf20Sopenharmony_ci				return -EINVAL;
32598c2ecf20Sopenharmony_ci			/* Prohibit push MPLS other than to a white list
32608c2ecf20Sopenharmony_ci			 * for packets that have a known tag order.
32618c2ecf20Sopenharmony_ci			 */
32628c2ecf20Sopenharmony_ci			if (vlan_tci & htons(VLAN_CFI_MASK) ||
32638c2ecf20Sopenharmony_ci			    (eth_type != htons(ETH_P_IP) &&
32648c2ecf20Sopenharmony_ci			     eth_type != htons(ETH_P_IPV6) &&
32658c2ecf20Sopenharmony_ci			     eth_type != htons(ETH_P_ARP) &&
32668c2ecf20Sopenharmony_ci			     eth_type != htons(ETH_P_RARP) &&
32678c2ecf20Sopenharmony_ci			     !eth_p_mpls(eth_type)))
32688c2ecf20Sopenharmony_ci				return -EINVAL;
32698c2ecf20Sopenharmony_ci			eth_type = mpls->mpls_ethertype;
32708c2ecf20Sopenharmony_ci			mpls_label_count++;
32718c2ecf20Sopenharmony_ci			break;
32728c2ecf20Sopenharmony_ci		}
32738c2ecf20Sopenharmony_ci
32748c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_POP_MPLS: {
32758c2ecf20Sopenharmony_ci			__be16  proto;
32768c2ecf20Sopenharmony_ci			if (vlan_tci & htons(VLAN_CFI_MASK) ||
32778c2ecf20Sopenharmony_ci			    !eth_p_mpls(eth_type))
32788c2ecf20Sopenharmony_ci				return -EINVAL;
32798c2ecf20Sopenharmony_ci
32808c2ecf20Sopenharmony_ci			/* Disallow subsequent L2.5+ set actions and mpls_pop
32818c2ecf20Sopenharmony_ci			 * actions once the last MPLS label in the packet is
32828c2ecf20Sopenharmony_ci			 * is popped as there is no check here to ensure that
32838c2ecf20Sopenharmony_ci			 * the new eth type is valid and thus set actions could
32848c2ecf20Sopenharmony_ci			 * write off the end of the packet or otherwise corrupt
32858c2ecf20Sopenharmony_ci			 * it.
32868c2ecf20Sopenharmony_ci			 *
32878c2ecf20Sopenharmony_ci			 * Support for these actions is planned using packet
32888c2ecf20Sopenharmony_ci			 * recirculation.
32898c2ecf20Sopenharmony_ci			 */
32908c2ecf20Sopenharmony_ci			proto = nla_get_be16(a);
32918c2ecf20Sopenharmony_ci
32928c2ecf20Sopenharmony_ci			if (proto == htons(ETH_P_TEB) &&
32938c2ecf20Sopenharmony_ci			    mac_proto != MAC_PROTO_NONE)
32948c2ecf20Sopenharmony_ci				return -EINVAL;
32958c2ecf20Sopenharmony_ci
32968c2ecf20Sopenharmony_ci			mpls_label_count--;
32978c2ecf20Sopenharmony_ci
32988c2ecf20Sopenharmony_ci			if (!eth_p_mpls(proto) || !mpls_label_count)
32998c2ecf20Sopenharmony_ci				eth_type = htons(0);
33008c2ecf20Sopenharmony_ci			else
33018c2ecf20Sopenharmony_ci				eth_type =  proto;
33028c2ecf20Sopenharmony_ci
33038c2ecf20Sopenharmony_ci			break;
33048c2ecf20Sopenharmony_ci		}
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SET:
33078c2ecf20Sopenharmony_ci			err = validate_set(a, key, sfa,
33088c2ecf20Sopenharmony_ci					   &skip_copy, mac_proto, eth_type,
33098c2ecf20Sopenharmony_ci					   false, log);
33108c2ecf20Sopenharmony_ci			if (err)
33118c2ecf20Sopenharmony_ci				return err;
33128c2ecf20Sopenharmony_ci			break;
33138c2ecf20Sopenharmony_ci
33148c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SET_MASKED:
33158c2ecf20Sopenharmony_ci			err = validate_set(a, key, sfa,
33168c2ecf20Sopenharmony_ci					   &skip_copy, mac_proto, eth_type,
33178c2ecf20Sopenharmony_ci					   true, log);
33188c2ecf20Sopenharmony_ci			if (err)
33198c2ecf20Sopenharmony_ci				return err;
33208c2ecf20Sopenharmony_ci			break;
33218c2ecf20Sopenharmony_ci
33228c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SAMPLE: {
33238c2ecf20Sopenharmony_ci			bool last = nla_is_last(a, rem);
33248c2ecf20Sopenharmony_ci
33258c2ecf20Sopenharmony_ci			err = validate_and_copy_sample(net, a, key, sfa,
33268c2ecf20Sopenharmony_ci						       eth_type, vlan_tci,
33278c2ecf20Sopenharmony_ci						       mpls_label_count,
33288c2ecf20Sopenharmony_ci						       log, last, depth);
33298c2ecf20Sopenharmony_ci			if (err)
33308c2ecf20Sopenharmony_ci				return err;
33318c2ecf20Sopenharmony_ci			skip_copy = true;
33328c2ecf20Sopenharmony_ci			break;
33338c2ecf20Sopenharmony_ci		}
33348c2ecf20Sopenharmony_ci
33358c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CT:
33368c2ecf20Sopenharmony_ci			err = ovs_ct_copy_action(net, a, key, sfa, log);
33378c2ecf20Sopenharmony_ci			if (err)
33388c2ecf20Sopenharmony_ci				return err;
33398c2ecf20Sopenharmony_ci			skip_copy = true;
33408c2ecf20Sopenharmony_ci			break;
33418c2ecf20Sopenharmony_ci
33428c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CT_CLEAR:
33438c2ecf20Sopenharmony_ci			break;
33448c2ecf20Sopenharmony_ci
33458c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_ETH:
33468c2ecf20Sopenharmony_ci			/* Disallow pushing an Ethernet header if one
33478c2ecf20Sopenharmony_ci			 * is already present */
33488c2ecf20Sopenharmony_ci			if (mac_proto != MAC_PROTO_NONE)
33498c2ecf20Sopenharmony_ci				return -EINVAL;
33508c2ecf20Sopenharmony_ci			mac_proto = MAC_PROTO_ETHERNET;
33518c2ecf20Sopenharmony_ci			break;
33528c2ecf20Sopenharmony_ci
33538c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_POP_ETH:
33548c2ecf20Sopenharmony_ci			if (mac_proto != MAC_PROTO_ETHERNET)
33558c2ecf20Sopenharmony_ci				return -EINVAL;
33568c2ecf20Sopenharmony_ci			if (vlan_tci & htons(VLAN_CFI_MASK))
33578c2ecf20Sopenharmony_ci				return -EINVAL;
33588c2ecf20Sopenharmony_ci			mac_proto = MAC_PROTO_NONE;
33598c2ecf20Sopenharmony_ci			break;
33608c2ecf20Sopenharmony_ci
33618c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_NSH:
33628c2ecf20Sopenharmony_ci			if (mac_proto != MAC_PROTO_ETHERNET) {
33638c2ecf20Sopenharmony_ci				u8 next_proto;
33648c2ecf20Sopenharmony_ci
33658c2ecf20Sopenharmony_ci				next_proto = tun_p_from_eth_p(eth_type);
33668c2ecf20Sopenharmony_ci				if (!next_proto)
33678c2ecf20Sopenharmony_ci					return -EINVAL;
33688c2ecf20Sopenharmony_ci			}
33698c2ecf20Sopenharmony_ci			mac_proto = MAC_PROTO_NONE;
33708c2ecf20Sopenharmony_ci			if (!validate_nsh(nla_data(a), false, true, true))
33718c2ecf20Sopenharmony_ci				return -EINVAL;
33728c2ecf20Sopenharmony_ci			break;
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_POP_NSH: {
33758c2ecf20Sopenharmony_ci			__be16 inner_proto;
33768c2ecf20Sopenharmony_ci
33778c2ecf20Sopenharmony_ci			if (eth_type != htons(ETH_P_NSH))
33788c2ecf20Sopenharmony_ci				return -EINVAL;
33798c2ecf20Sopenharmony_ci			inner_proto = tun_p_to_eth_p(key->nsh.base.np);
33808c2ecf20Sopenharmony_ci			if (!inner_proto)
33818c2ecf20Sopenharmony_ci				return -EINVAL;
33828c2ecf20Sopenharmony_ci			if (key->nsh.base.np == TUN_P_ETHERNET)
33838c2ecf20Sopenharmony_ci				mac_proto = MAC_PROTO_ETHERNET;
33848c2ecf20Sopenharmony_ci			else
33858c2ecf20Sopenharmony_ci				mac_proto = MAC_PROTO_NONE;
33868c2ecf20Sopenharmony_ci			break;
33878c2ecf20Sopenharmony_ci		}
33888c2ecf20Sopenharmony_ci
33898c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_METER:
33908c2ecf20Sopenharmony_ci			/* Non-existent meters are simply ignored.  */
33918c2ecf20Sopenharmony_ci			break;
33928c2ecf20Sopenharmony_ci
33938c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CLONE: {
33948c2ecf20Sopenharmony_ci			bool last = nla_is_last(a, rem);
33958c2ecf20Sopenharmony_ci
33968c2ecf20Sopenharmony_ci			err = validate_and_copy_clone(net, a, key, sfa,
33978c2ecf20Sopenharmony_ci						      eth_type, vlan_tci,
33988c2ecf20Sopenharmony_ci						      mpls_label_count,
33998c2ecf20Sopenharmony_ci						      log, last, depth);
34008c2ecf20Sopenharmony_ci			if (err)
34018c2ecf20Sopenharmony_ci				return err;
34028c2ecf20Sopenharmony_ci			skip_copy = true;
34038c2ecf20Sopenharmony_ci			break;
34048c2ecf20Sopenharmony_ci		}
34058c2ecf20Sopenharmony_ci
34068c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CHECK_PKT_LEN: {
34078c2ecf20Sopenharmony_ci			bool last = nla_is_last(a, rem);
34088c2ecf20Sopenharmony_ci
34098c2ecf20Sopenharmony_ci			err = validate_and_copy_check_pkt_len(net, a, key, sfa,
34108c2ecf20Sopenharmony_ci							      eth_type,
34118c2ecf20Sopenharmony_ci							      vlan_tci,
34128c2ecf20Sopenharmony_ci							      mpls_label_count,
34138c2ecf20Sopenharmony_ci							      log, last,
34148c2ecf20Sopenharmony_ci							      depth);
34158c2ecf20Sopenharmony_ci			if (err)
34168c2ecf20Sopenharmony_ci				return err;
34178c2ecf20Sopenharmony_ci			skip_copy = true;
34188c2ecf20Sopenharmony_ci			break;
34198c2ecf20Sopenharmony_ci		}
34208c2ecf20Sopenharmony_ci
34218c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_DEC_TTL:
34228c2ecf20Sopenharmony_ci			err = validate_and_copy_dec_ttl(net, a, key, sfa,
34238c2ecf20Sopenharmony_ci							eth_type, vlan_tci,
34248c2ecf20Sopenharmony_ci							mpls_label_count, log,
34258c2ecf20Sopenharmony_ci							depth);
34268c2ecf20Sopenharmony_ci			if (err)
34278c2ecf20Sopenharmony_ci				return err;
34288c2ecf20Sopenharmony_ci			skip_copy = true;
34298c2ecf20Sopenharmony_ci			break;
34308c2ecf20Sopenharmony_ci
34318c2ecf20Sopenharmony_ci		default:
34328c2ecf20Sopenharmony_ci			OVS_NLERR(log, "Unknown Action type %d", type);
34338c2ecf20Sopenharmony_ci			return -EINVAL;
34348c2ecf20Sopenharmony_ci		}
34358c2ecf20Sopenharmony_ci		if (!skip_copy) {
34368c2ecf20Sopenharmony_ci			err = copy_action(a, sfa, log);
34378c2ecf20Sopenharmony_ci			if (err)
34388c2ecf20Sopenharmony_ci				return err;
34398c2ecf20Sopenharmony_ci		}
34408c2ecf20Sopenharmony_ci	}
34418c2ecf20Sopenharmony_ci
34428c2ecf20Sopenharmony_ci	if (rem > 0)
34438c2ecf20Sopenharmony_ci		return -EINVAL;
34448c2ecf20Sopenharmony_ci
34458c2ecf20Sopenharmony_ci	return 0;
34468c2ecf20Sopenharmony_ci}
34478c2ecf20Sopenharmony_ci
34488c2ecf20Sopenharmony_ci/* 'key' must be the masked key. */
34498c2ecf20Sopenharmony_ciint ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
34508c2ecf20Sopenharmony_ci			 const struct sw_flow_key *key,
34518c2ecf20Sopenharmony_ci			 struct sw_flow_actions **sfa, bool log)
34528c2ecf20Sopenharmony_ci{
34538c2ecf20Sopenharmony_ci	int err;
34548c2ecf20Sopenharmony_ci	u32 mpls_label_count = 0;
34558c2ecf20Sopenharmony_ci
34568c2ecf20Sopenharmony_ci	*sfa = nla_alloc_flow_actions(min(nla_len(attr), MAX_ACTIONS_BUFSIZE));
34578c2ecf20Sopenharmony_ci	if (IS_ERR(*sfa))
34588c2ecf20Sopenharmony_ci		return PTR_ERR(*sfa);
34598c2ecf20Sopenharmony_ci
34608c2ecf20Sopenharmony_ci	if (eth_p_mpls(key->eth.type))
34618c2ecf20Sopenharmony_ci		mpls_label_count = hweight_long(key->mpls.num_labels_mask);
34628c2ecf20Sopenharmony_ci
34638c2ecf20Sopenharmony_ci	(*sfa)->orig_len = nla_len(attr);
34648c2ecf20Sopenharmony_ci	err = __ovs_nla_copy_actions(net, attr, key, sfa, key->eth.type,
34658c2ecf20Sopenharmony_ci				     key->eth.vlan.tci, mpls_label_count, log,
34668c2ecf20Sopenharmony_ci				     0);
34678c2ecf20Sopenharmony_ci	if (err)
34688c2ecf20Sopenharmony_ci		ovs_nla_free_flow_actions(*sfa);
34698c2ecf20Sopenharmony_ci
34708c2ecf20Sopenharmony_ci	return err;
34718c2ecf20Sopenharmony_ci}
34728c2ecf20Sopenharmony_ci
34738c2ecf20Sopenharmony_cistatic int sample_action_to_attr(const struct nlattr *attr,
34748c2ecf20Sopenharmony_ci				 struct sk_buff *skb)
34758c2ecf20Sopenharmony_ci{
34768c2ecf20Sopenharmony_ci	struct nlattr *start, *ac_start = NULL, *sample_arg;
34778c2ecf20Sopenharmony_ci	int err = 0, rem = nla_len(attr);
34788c2ecf20Sopenharmony_ci	const struct sample_arg *arg;
34798c2ecf20Sopenharmony_ci	struct nlattr *actions;
34808c2ecf20Sopenharmony_ci
34818c2ecf20Sopenharmony_ci	start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SAMPLE);
34828c2ecf20Sopenharmony_ci	if (!start)
34838c2ecf20Sopenharmony_ci		return -EMSGSIZE;
34848c2ecf20Sopenharmony_ci
34858c2ecf20Sopenharmony_ci	sample_arg = nla_data(attr);
34868c2ecf20Sopenharmony_ci	arg = nla_data(sample_arg);
34878c2ecf20Sopenharmony_ci	actions = nla_next(sample_arg, &rem);
34888c2ecf20Sopenharmony_ci
34898c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, OVS_SAMPLE_ATTR_PROBABILITY, arg->probability)) {
34908c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
34918c2ecf20Sopenharmony_ci		goto out;
34928c2ecf20Sopenharmony_ci	}
34938c2ecf20Sopenharmony_ci
34948c2ecf20Sopenharmony_ci	ac_start = nla_nest_start_noflag(skb, OVS_SAMPLE_ATTR_ACTIONS);
34958c2ecf20Sopenharmony_ci	if (!ac_start) {
34968c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
34978c2ecf20Sopenharmony_ci		goto out;
34988c2ecf20Sopenharmony_ci	}
34998c2ecf20Sopenharmony_ci
35008c2ecf20Sopenharmony_ci	err = ovs_nla_put_actions(actions, rem, skb);
35018c2ecf20Sopenharmony_ci
35028c2ecf20Sopenharmony_ciout:
35038c2ecf20Sopenharmony_ci	if (err) {
35048c2ecf20Sopenharmony_ci		nla_nest_cancel(skb, ac_start);
35058c2ecf20Sopenharmony_ci		nla_nest_cancel(skb, start);
35068c2ecf20Sopenharmony_ci	} else {
35078c2ecf20Sopenharmony_ci		nla_nest_end(skb, ac_start);
35088c2ecf20Sopenharmony_ci		nla_nest_end(skb, start);
35098c2ecf20Sopenharmony_ci	}
35108c2ecf20Sopenharmony_ci
35118c2ecf20Sopenharmony_ci	return err;
35128c2ecf20Sopenharmony_ci}
35138c2ecf20Sopenharmony_ci
35148c2ecf20Sopenharmony_cistatic int clone_action_to_attr(const struct nlattr *attr,
35158c2ecf20Sopenharmony_ci				struct sk_buff *skb)
35168c2ecf20Sopenharmony_ci{
35178c2ecf20Sopenharmony_ci	struct nlattr *start;
35188c2ecf20Sopenharmony_ci	int err = 0, rem = nla_len(attr);
35198c2ecf20Sopenharmony_ci
35208c2ecf20Sopenharmony_ci	start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_CLONE);
35218c2ecf20Sopenharmony_ci	if (!start)
35228c2ecf20Sopenharmony_ci		return -EMSGSIZE;
35238c2ecf20Sopenharmony_ci
35248c2ecf20Sopenharmony_ci	/* Skipping the OVS_CLONE_ATTR_EXEC that is always the first attribute. */
35258c2ecf20Sopenharmony_ci	attr = nla_next(nla_data(attr), &rem);
35268c2ecf20Sopenharmony_ci	err = ovs_nla_put_actions(attr, rem, skb);
35278c2ecf20Sopenharmony_ci
35288c2ecf20Sopenharmony_ci	if (err)
35298c2ecf20Sopenharmony_ci		nla_nest_cancel(skb, start);
35308c2ecf20Sopenharmony_ci	else
35318c2ecf20Sopenharmony_ci		nla_nest_end(skb, start);
35328c2ecf20Sopenharmony_ci
35338c2ecf20Sopenharmony_ci	return err;
35348c2ecf20Sopenharmony_ci}
35358c2ecf20Sopenharmony_ci
35368c2ecf20Sopenharmony_cistatic int check_pkt_len_action_to_attr(const struct nlattr *attr,
35378c2ecf20Sopenharmony_ci					struct sk_buff *skb)
35388c2ecf20Sopenharmony_ci{
35398c2ecf20Sopenharmony_ci	struct nlattr *start, *ac_start = NULL;
35408c2ecf20Sopenharmony_ci	const struct check_pkt_len_arg *arg;
35418c2ecf20Sopenharmony_ci	const struct nlattr *a, *cpl_arg;
35428c2ecf20Sopenharmony_ci	int err = 0, rem = nla_len(attr);
35438c2ecf20Sopenharmony_ci
35448c2ecf20Sopenharmony_ci	start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_CHECK_PKT_LEN);
35458c2ecf20Sopenharmony_ci	if (!start)
35468c2ecf20Sopenharmony_ci		return -EMSGSIZE;
35478c2ecf20Sopenharmony_ci
35488c2ecf20Sopenharmony_ci	/* The first nested attribute in 'attr' is always
35498c2ecf20Sopenharmony_ci	 * 'OVS_CHECK_PKT_LEN_ATTR_ARG'.
35508c2ecf20Sopenharmony_ci	 */
35518c2ecf20Sopenharmony_ci	cpl_arg = nla_data(attr);
35528c2ecf20Sopenharmony_ci	arg = nla_data(cpl_arg);
35538c2ecf20Sopenharmony_ci
35548c2ecf20Sopenharmony_ci	if (nla_put_u16(skb, OVS_CHECK_PKT_LEN_ATTR_PKT_LEN, arg->pkt_len)) {
35558c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
35568c2ecf20Sopenharmony_ci		goto out;
35578c2ecf20Sopenharmony_ci	}
35588c2ecf20Sopenharmony_ci
35598c2ecf20Sopenharmony_ci	/* Second nested attribute in 'attr' is always
35608c2ecf20Sopenharmony_ci	 * 'OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL'.
35618c2ecf20Sopenharmony_ci	 */
35628c2ecf20Sopenharmony_ci	a = nla_next(cpl_arg, &rem);
35638c2ecf20Sopenharmony_ci	ac_start =  nla_nest_start_noflag(skb,
35648c2ecf20Sopenharmony_ci					  OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL);
35658c2ecf20Sopenharmony_ci	if (!ac_start) {
35668c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
35678c2ecf20Sopenharmony_ci		goto out;
35688c2ecf20Sopenharmony_ci	}
35698c2ecf20Sopenharmony_ci
35708c2ecf20Sopenharmony_ci	err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb);
35718c2ecf20Sopenharmony_ci	if (err) {
35728c2ecf20Sopenharmony_ci		nla_nest_cancel(skb, ac_start);
35738c2ecf20Sopenharmony_ci		goto out;
35748c2ecf20Sopenharmony_ci	} else {
35758c2ecf20Sopenharmony_ci		nla_nest_end(skb, ac_start);
35768c2ecf20Sopenharmony_ci	}
35778c2ecf20Sopenharmony_ci
35788c2ecf20Sopenharmony_ci	/* Third nested attribute in 'attr' is always
35798c2ecf20Sopenharmony_ci	 * OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER.
35808c2ecf20Sopenharmony_ci	 */
35818c2ecf20Sopenharmony_ci	a = nla_next(a, &rem);
35828c2ecf20Sopenharmony_ci	ac_start =  nla_nest_start_noflag(skb,
35838c2ecf20Sopenharmony_ci					  OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER);
35848c2ecf20Sopenharmony_ci	if (!ac_start) {
35858c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
35868c2ecf20Sopenharmony_ci		goto out;
35878c2ecf20Sopenharmony_ci	}
35888c2ecf20Sopenharmony_ci
35898c2ecf20Sopenharmony_ci	err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb);
35908c2ecf20Sopenharmony_ci	if (err) {
35918c2ecf20Sopenharmony_ci		nla_nest_cancel(skb, ac_start);
35928c2ecf20Sopenharmony_ci		goto out;
35938c2ecf20Sopenharmony_ci	} else {
35948c2ecf20Sopenharmony_ci		nla_nest_end(skb, ac_start);
35958c2ecf20Sopenharmony_ci	}
35968c2ecf20Sopenharmony_ci
35978c2ecf20Sopenharmony_ci	nla_nest_end(skb, start);
35988c2ecf20Sopenharmony_ci	return 0;
35998c2ecf20Sopenharmony_ci
36008c2ecf20Sopenharmony_ciout:
36018c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, start);
36028c2ecf20Sopenharmony_ci	return err;
36038c2ecf20Sopenharmony_ci}
36048c2ecf20Sopenharmony_ci
36058c2ecf20Sopenharmony_cistatic int dec_ttl_action_to_attr(const struct nlattr *attr,
36068c2ecf20Sopenharmony_ci				  struct sk_buff *skb)
36078c2ecf20Sopenharmony_ci{
36088c2ecf20Sopenharmony_ci	struct nlattr *start, *action_start;
36098c2ecf20Sopenharmony_ci	const struct nlattr *a;
36108c2ecf20Sopenharmony_ci	int err = 0, rem;
36118c2ecf20Sopenharmony_ci
36128c2ecf20Sopenharmony_ci	start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_DEC_TTL);
36138c2ecf20Sopenharmony_ci	if (!start)
36148c2ecf20Sopenharmony_ci		return -EMSGSIZE;
36158c2ecf20Sopenharmony_ci
36168c2ecf20Sopenharmony_ci	nla_for_each_attr(a, nla_data(attr), nla_len(attr), rem) {
36178c2ecf20Sopenharmony_ci		switch (nla_type(a)) {
36188c2ecf20Sopenharmony_ci		case OVS_DEC_TTL_ATTR_ACTION:
36198c2ecf20Sopenharmony_ci
36208c2ecf20Sopenharmony_ci			action_start = nla_nest_start_noflag(skb, OVS_DEC_TTL_ATTR_ACTION);
36218c2ecf20Sopenharmony_ci			if (!action_start) {
36228c2ecf20Sopenharmony_ci				err = -EMSGSIZE;
36238c2ecf20Sopenharmony_ci				goto out;
36248c2ecf20Sopenharmony_ci			}
36258c2ecf20Sopenharmony_ci
36268c2ecf20Sopenharmony_ci			err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb);
36278c2ecf20Sopenharmony_ci			if (err)
36288c2ecf20Sopenharmony_ci				goto out;
36298c2ecf20Sopenharmony_ci
36308c2ecf20Sopenharmony_ci			nla_nest_end(skb, action_start);
36318c2ecf20Sopenharmony_ci			break;
36328c2ecf20Sopenharmony_ci
36338c2ecf20Sopenharmony_ci		default:
36348c2ecf20Sopenharmony_ci			/* Ignore all other option to be future compatible */
36358c2ecf20Sopenharmony_ci			break;
36368c2ecf20Sopenharmony_ci		}
36378c2ecf20Sopenharmony_ci	}
36388c2ecf20Sopenharmony_ci
36398c2ecf20Sopenharmony_ci	nla_nest_end(skb, start);
36408c2ecf20Sopenharmony_ci	return 0;
36418c2ecf20Sopenharmony_ci
36428c2ecf20Sopenharmony_ciout:
36438c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, start);
36448c2ecf20Sopenharmony_ci	return err;
36458c2ecf20Sopenharmony_ci}
36468c2ecf20Sopenharmony_ci
36478c2ecf20Sopenharmony_cistatic int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
36488c2ecf20Sopenharmony_ci{
36498c2ecf20Sopenharmony_ci	const struct nlattr *ovs_key = nla_data(a);
36508c2ecf20Sopenharmony_ci	int key_type = nla_type(ovs_key);
36518c2ecf20Sopenharmony_ci	struct nlattr *start;
36528c2ecf20Sopenharmony_ci	int err;
36538c2ecf20Sopenharmony_ci
36548c2ecf20Sopenharmony_ci	switch (key_type) {
36558c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_TUNNEL_INFO: {
36568c2ecf20Sopenharmony_ci		struct ovs_tunnel_info *ovs_tun = nla_data(ovs_key);
36578c2ecf20Sopenharmony_ci		struct ip_tunnel_info *tun_info = &ovs_tun->tun_dst->u.tun_info;
36588c2ecf20Sopenharmony_ci
36598c2ecf20Sopenharmony_ci		start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SET);
36608c2ecf20Sopenharmony_ci		if (!start)
36618c2ecf20Sopenharmony_ci			return -EMSGSIZE;
36628c2ecf20Sopenharmony_ci
36638c2ecf20Sopenharmony_ci		err =  ip_tun_to_nlattr(skb, &tun_info->key,
36648c2ecf20Sopenharmony_ci					ip_tunnel_info_opts(tun_info),
36658c2ecf20Sopenharmony_ci					tun_info->options_len,
36668c2ecf20Sopenharmony_ci					ip_tunnel_info_af(tun_info), tun_info->mode);
36678c2ecf20Sopenharmony_ci		if (err)
36688c2ecf20Sopenharmony_ci			return err;
36698c2ecf20Sopenharmony_ci		nla_nest_end(skb, start);
36708c2ecf20Sopenharmony_ci		break;
36718c2ecf20Sopenharmony_ci	}
36728c2ecf20Sopenharmony_ci	default:
36738c2ecf20Sopenharmony_ci		if (nla_put(skb, OVS_ACTION_ATTR_SET, nla_len(a), ovs_key))
36748c2ecf20Sopenharmony_ci			return -EMSGSIZE;
36758c2ecf20Sopenharmony_ci		break;
36768c2ecf20Sopenharmony_ci	}
36778c2ecf20Sopenharmony_ci
36788c2ecf20Sopenharmony_ci	return 0;
36798c2ecf20Sopenharmony_ci}
36808c2ecf20Sopenharmony_ci
36818c2ecf20Sopenharmony_cistatic int masked_set_action_to_set_action_attr(const struct nlattr *a,
36828c2ecf20Sopenharmony_ci						struct sk_buff *skb)
36838c2ecf20Sopenharmony_ci{
36848c2ecf20Sopenharmony_ci	const struct nlattr *ovs_key = nla_data(a);
36858c2ecf20Sopenharmony_ci	struct nlattr *nla;
36868c2ecf20Sopenharmony_ci	size_t key_len = nla_len(ovs_key) / 2;
36878c2ecf20Sopenharmony_ci
36888c2ecf20Sopenharmony_ci	/* Revert the conversion we did from a non-masked set action to
36898c2ecf20Sopenharmony_ci	 * masked set action.
36908c2ecf20Sopenharmony_ci	 */
36918c2ecf20Sopenharmony_ci	nla = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SET);
36928c2ecf20Sopenharmony_ci	if (!nla)
36938c2ecf20Sopenharmony_ci		return -EMSGSIZE;
36948c2ecf20Sopenharmony_ci
36958c2ecf20Sopenharmony_ci	if (nla_put(skb, nla_type(ovs_key), key_len, nla_data(ovs_key)))
36968c2ecf20Sopenharmony_ci		return -EMSGSIZE;
36978c2ecf20Sopenharmony_ci
36988c2ecf20Sopenharmony_ci	nla_nest_end(skb, nla);
36998c2ecf20Sopenharmony_ci	return 0;
37008c2ecf20Sopenharmony_ci}
37018c2ecf20Sopenharmony_ci
37028c2ecf20Sopenharmony_ciint ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb)
37038c2ecf20Sopenharmony_ci{
37048c2ecf20Sopenharmony_ci	const struct nlattr *a;
37058c2ecf20Sopenharmony_ci	int rem, err;
37068c2ecf20Sopenharmony_ci
37078c2ecf20Sopenharmony_ci	nla_for_each_attr(a, attr, len, rem) {
37088c2ecf20Sopenharmony_ci		int type = nla_type(a);
37098c2ecf20Sopenharmony_ci
37108c2ecf20Sopenharmony_ci		switch (type) {
37118c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SET:
37128c2ecf20Sopenharmony_ci			err = set_action_to_attr(a, skb);
37138c2ecf20Sopenharmony_ci			if (err)
37148c2ecf20Sopenharmony_ci				return err;
37158c2ecf20Sopenharmony_ci			break;
37168c2ecf20Sopenharmony_ci
37178c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SET_TO_MASKED:
37188c2ecf20Sopenharmony_ci			err = masked_set_action_to_set_action_attr(a, skb);
37198c2ecf20Sopenharmony_ci			if (err)
37208c2ecf20Sopenharmony_ci				return err;
37218c2ecf20Sopenharmony_ci			break;
37228c2ecf20Sopenharmony_ci
37238c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SAMPLE:
37248c2ecf20Sopenharmony_ci			err = sample_action_to_attr(a, skb);
37258c2ecf20Sopenharmony_ci			if (err)
37268c2ecf20Sopenharmony_ci				return err;
37278c2ecf20Sopenharmony_ci			break;
37288c2ecf20Sopenharmony_ci
37298c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CT:
37308c2ecf20Sopenharmony_ci			err = ovs_ct_action_to_attr(nla_data(a), skb);
37318c2ecf20Sopenharmony_ci			if (err)
37328c2ecf20Sopenharmony_ci				return err;
37338c2ecf20Sopenharmony_ci			break;
37348c2ecf20Sopenharmony_ci
37358c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CLONE:
37368c2ecf20Sopenharmony_ci			err = clone_action_to_attr(a, skb);
37378c2ecf20Sopenharmony_ci			if (err)
37388c2ecf20Sopenharmony_ci				return err;
37398c2ecf20Sopenharmony_ci			break;
37408c2ecf20Sopenharmony_ci
37418c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CHECK_PKT_LEN:
37428c2ecf20Sopenharmony_ci			err = check_pkt_len_action_to_attr(a, skb);
37438c2ecf20Sopenharmony_ci			if (err)
37448c2ecf20Sopenharmony_ci				return err;
37458c2ecf20Sopenharmony_ci			break;
37468c2ecf20Sopenharmony_ci
37478c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_DEC_TTL:
37488c2ecf20Sopenharmony_ci			err = dec_ttl_action_to_attr(a, skb);
37498c2ecf20Sopenharmony_ci			if (err)
37508c2ecf20Sopenharmony_ci				return err;
37518c2ecf20Sopenharmony_ci			break;
37528c2ecf20Sopenharmony_ci
37538c2ecf20Sopenharmony_ci		default:
37548c2ecf20Sopenharmony_ci			if (nla_put(skb, type, nla_len(a), nla_data(a)))
37558c2ecf20Sopenharmony_ci				return -EMSGSIZE;
37568c2ecf20Sopenharmony_ci			break;
37578c2ecf20Sopenharmony_ci		}
37588c2ecf20Sopenharmony_ci	}
37598c2ecf20Sopenharmony_ci
37608c2ecf20Sopenharmony_ci	return 0;
37618c2ecf20Sopenharmony_ci}
3762