18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2007-2014 Nicira, Inc.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
78c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
88c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
98c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
108c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
118c2ecf20Sopenharmony_ci#include <net/llc_pdu.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/jhash.h>
148c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
158c2ecf20Sopenharmony_ci#include <linux/llc.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/in.h>
188c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
198c2ecf20Sopenharmony_ci#include <linux/cpumask.h>
208c2ecf20Sopenharmony_ci#include <linux/if_arp.h>
218c2ecf20Sopenharmony_ci#include <linux/ip.h>
228c2ecf20Sopenharmony_ci#include <linux/ipv6.h>
238c2ecf20Sopenharmony_ci#include <linux/mpls.h>
248c2ecf20Sopenharmony_ci#include <linux/sctp.h>
258c2ecf20Sopenharmony_ci#include <linux/smp.h>
268c2ecf20Sopenharmony_ci#include <linux/tcp.h>
278c2ecf20Sopenharmony_ci#include <linux/udp.h>
288c2ecf20Sopenharmony_ci#include <linux/icmp.h>
298c2ecf20Sopenharmony_ci#include <linux/icmpv6.h>
308c2ecf20Sopenharmony_ci#include <linux/rculist.h>
318c2ecf20Sopenharmony_ci#include <net/ip.h>
328c2ecf20Sopenharmony_ci#include <net/ip_tunnels.h>
338c2ecf20Sopenharmony_ci#include <net/ipv6.h>
348c2ecf20Sopenharmony_ci#include <net/mpls.h>
358c2ecf20Sopenharmony_ci#include <net/ndisc.h>
368c2ecf20Sopenharmony_ci#include <net/nsh.h>
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#include "conntrack.h"
398c2ecf20Sopenharmony_ci#include "datapath.h"
408c2ecf20Sopenharmony_ci#include "flow.h"
418c2ecf20Sopenharmony_ci#include "flow_netlink.h"
428c2ecf20Sopenharmony_ci#include "vport.h"
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ciu64 ovs_flow_used_time(unsigned long flow_jiffies)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	struct timespec64 cur_ts;
478c2ecf20Sopenharmony_ci	u64 cur_ms, idle_ms;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	ktime_get_ts64(&cur_ts);
508c2ecf20Sopenharmony_ci	idle_ms = jiffies_to_msecs(jiffies - flow_jiffies);
518c2ecf20Sopenharmony_ci	cur_ms = (u64)(u32)cur_ts.tv_sec * MSEC_PER_SEC +
528c2ecf20Sopenharmony_ci		 cur_ts.tv_nsec / NSEC_PER_MSEC;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	return cur_ms - idle_ms;
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define TCP_FLAGS_BE16(tp) (*(__be16 *)&tcp_flag_word(tp) & htons(0x0FFF))
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_civoid ovs_flow_stats_update(struct sw_flow *flow, __be16 tcp_flags,
608c2ecf20Sopenharmony_ci			   const struct sk_buff *skb)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	struct sw_flow_stats *stats;
638c2ecf20Sopenharmony_ci	unsigned int cpu = smp_processor_id();
648c2ecf20Sopenharmony_ci	int len = skb->len + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	stats = rcu_dereference(flow->stats[cpu]);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	/* Check if already have CPU-specific stats. */
698c2ecf20Sopenharmony_ci	if (likely(stats)) {
708c2ecf20Sopenharmony_ci		spin_lock(&stats->lock);
718c2ecf20Sopenharmony_ci		/* Mark if we write on the pre-allocated stats. */
728c2ecf20Sopenharmony_ci		if (cpu == 0 && unlikely(flow->stats_last_writer != cpu))
738c2ecf20Sopenharmony_ci			flow->stats_last_writer = cpu;
748c2ecf20Sopenharmony_ci	} else {
758c2ecf20Sopenharmony_ci		stats = rcu_dereference(flow->stats[0]); /* Pre-allocated. */
768c2ecf20Sopenharmony_ci		spin_lock(&stats->lock);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		/* If the current CPU is the only writer on the
798c2ecf20Sopenharmony_ci		 * pre-allocated stats keep using them.
808c2ecf20Sopenharmony_ci		 */
818c2ecf20Sopenharmony_ci		if (unlikely(flow->stats_last_writer != cpu)) {
828c2ecf20Sopenharmony_ci			/* A previous locker may have already allocated the
838c2ecf20Sopenharmony_ci			 * stats, so we need to check again.  If CPU-specific
848c2ecf20Sopenharmony_ci			 * stats were already allocated, we update the pre-
858c2ecf20Sopenharmony_ci			 * allocated stats as we have already locked them.
868c2ecf20Sopenharmony_ci			 */
878c2ecf20Sopenharmony_ci			if (likely(flow->stats_last_writer != -1) &&
888c2ecf20Sopenharmony_ci			    likely(!rcu_access_pointer(flow->stats[cpu]))) {
898c2ecf20Sopenharmony_ci				/* Try to allocate CPU-specific stats. */
908c2ecf20Sopenharmony_ci				struct sw_flow_stats *new_stats;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci				new_stats =
938c2ecf20Sopenharmony_ci					kmem_cache_alloc_node(flow_stats_cache,
948c2ecf20Sopenharmony_ci							      GFP_NOWAIT |
958c2ecf20Sopenharmony_ci							      __GFP_THISNODE |
968c2ecf20Sopenharmony_ci							      __GFP_NOWARN |
978c2ecf20Sopenharmony_ci							      __GFP_NOMEMALLOC,
988c2ecf20Sopenharmony_ci							      numa_node_id());
998c2ecf20Sopenharmony_ci				if (likely(new_stats)) {
1008c2ecf20Sopenharmony_ci					new_stats->used = jiffies;
1018c2ecf20Sopenharmony_ci					new_stats->packet_count = 1;
1028c2ecf20Sopenharmony_ci					new_stats->byte_count = len;
1038c2ecf20Sopenharmony_ci					new_stats->tcp_flags = tcp_flags;
1048c2ecf20Sopenharmony_ci					spin_lock_init(&new_stats->lock);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci					rcu_assign_pointer(flow->stats[cpu],
1078c2ecf20Sopenharmony_ci							   new_stats);
1088c2ecf20Sopenharmony_ci					cpumask_set_cpu(cpu, &flow->cpu_used_mask);
1098c2ecf20Sopenharmony_ci					goto unlock;
1108c2ecf20Sopenharmony_ci				}
1118c2ecf20Sopenharmony_ci			}
1128c2ecf20Sopenharmony_ci			flow->stats_last_writer = cpu;
1138c2ecf20Sopenharmony_ci		}
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	stats->used = jiffies;
1178c2ecf20Sopenharmony_ci	stats->packet_count++;
1188c2ecf20Sopenharmony_ci	stats->byte_count += len;
1198c2ecf20Sopenharmony_ci	stats->tcp_flags |= tcp_flags;
1208c2ecf20Sopenharmony_ciunlock:
1218c2ecf20Sopenharmony_ci	spin_unlock(&stats->lock);
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/* Must be called with rcu_read_lock or ovs_mutex. */
1258c2ecf20Sopenharmony_civoid ovs_flow_stats_get(const struct sw_flow *flow,
1268c2ecf20Sopenharmony_ci			struct ovs_flow_stats *ovs_stats,
1278c2ecf20Sopenharmony_ci			unsigned long *used, __be16 *tcp_flags)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	int cpu;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	*used = 0;
1328c2ecf20Sopenharmony_ci	*tcp_flags = 0;
1338c2ecf20Sopenharmony_ci	memset(ovs_stats, 0, sizeof(*ovs_stats));
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* We open code this to make sure cpu 0 is always considered */
1368c2ecf20Sopenharmony_ci	for (cpu = 0; cpu < nr_cpu_ids; cpu = cpumask_next(cpu, &flow->cpu_used_mask)) {
1378c2ecf20Sopenharmony_ci		struct sw_flow_stats *stats = rcu_dereference_ovsl(flow->stats[cpu]);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci		if (stats) {
1408c2ecf20Sopenharmony_ci			/* Local CPU may write on non-local stats, so we must
1418c2ecf20Sopenharmony_ci			 * block bottom-halves here.
1428c2ecf20Sopenharmony_ci			 */
1438c2ecf20Sopenharmony_ci			spin_lock_bh(&stats->lock);
1448c2ecf20Sopenharmony_ci			if (!*used || time_after(stats->used, *used))
1458c2ecf20Sopenharmony_ci				*used = stats->used;
1468c2ecf20Sopenharmony_ci			*tcp_flags |= stats->tcp_flags;
1478c2ecf20Sopenharmony_ci			ovs_stats->n_packets += stats->packet_count;
1488c2ecf20Sopenharmony_ci			ovs_stats->n_bytes += stats->byte_count;
1498c2ecf20Sopenharmony_ci			spin_unlock_bh(&stats->lock);
1508c2ecf20Sopenharmony_ci		}
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci/* Called with ovs_mutex. */
1558c2ecf20Sopenharmony_civoid ovs_flow_stats_clear(struct sw_flow *flow)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	int cpu;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* We open code this to make sure cpu 0 is always considered */
1608c2ecf20Sopenharmony_ci	for (cpu = 0; cpu < nr_cpu_ids; cpu = cpumask_next(cpu, &flow->cpu_used_mask)) {
1618c2ecf20Sopenharmony_ci		struct sw_flow_stats *stats = ovsl_dereference(flow->stats[cpu]);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci		if (stats) {
1648c2ecf20Sopenharmony_ci			spin_lock_bh(&stats->lock);
1658c2ecf20Sopenharmony_ci			stats->used = 0;
1668c2ecf20Sopenharmony_ci			stats->packet_count = 0;
1678c2ecf20Sopenharmony_ci			stats->byte_count = 0;
1688c2ecf20Sopenharmony_ci			stats->tcp_flags = 0;
1698c2ecf20Sopenharmony_ci			spin_unlock_bh(&stats->lock);
1708c2ecf20Sopenharmony_ci		}
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int check_header(struct sk_buff *skb, int len)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	if (unlikely(skb->len < len))
1778c2ecf20Sopenharmony_ci		return -EINVAL;
1788c2ecf20Sopenharmony_ci	if (unlikely(!pskb_may_pull(skb, len)))
1798c2ecf20Sopenharmony_ci		return -ENOMEM;
1808c2ecf20Sopenharmony_ci	return 0;
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic bool arphdr_ok(struct sk_buff *skb)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	return pskb_may_pull(skb, skb_network_offset(skb) +
1868c2ecf20Sopenharmony_ci				  sizeof(struct arp_eth_header));
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic int check_iphdr(struct sk_buff *skb)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	unsigned int nh_ofs = skb_network_offset(skb);
1928c2ecf20Sopenharmony_ci	unsigned int ip_len;
1938c2ecf20Sopenharmony_ci	int err;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	err = check_header(skb, nh_ofs + sizeof(struct iphdr));
1968c2ecf20Sopenharmony_ci	if (unlikely(err))
1978c2ecf20Sopenharmony_ci		return err;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	ip_len = ip_hdrlen(skb);
2008c2ecf20Sopenharmony_ci	if (unlikely(ip_len < sizeof(struct iphdr) ||
2018c2ecf20Sopenharmony_ci		     skb->len < nh_ofs + ip_len))
2028c2ecf20Sopenharmony_ci		return -EINVAL;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	skb_set_transport_header(skb, nh_ofs + ip_len);
2058c2ecf20Sopenharmony_ci	return 0;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic bool tcphdr_ok(struct sk_buff *skb)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	int th_ofs = skb_transport_offset(skb);
2118c2ecf20Sopenharmony_ci	int tcp_len;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (unlikely(!pskb_may_pull(skb, th_ofs + sizeof(struct tcphdr))))
2148c2ecf20Sopenharmony_ci		return false;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	tcp_len = tcp_hdrlen(skb);
2178c2ecf20Sopenharmony_ci	if (unlikely(tcp_len < sizeof(struct tcphdr) ||
2188c2ecf20Sopenharmony_ci		     skb->len < th_ofs + tcp_len))
2198c2ecf20Sopenharmony_ci		return false;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return true;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic bool udphdr_ok(struct sk_buff *skb)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	return pskb_may_pull(skb, skb_transport_offset(skb) +
2278c2ecf20Sopenharmony_ci				  sizeof(struct udphdr));
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic bool sctphdr_ok(struct sk_buff *skb)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	return pskb_may_pull(skb, skb_transport_offset(skb) +
2338c2ecf20Sopenharmony_ci				  sizeof(struct sctphdr));
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic bool icmphdr_ok(struct sk_buff *skb)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	return pskb_may_pull(skb, skb_transport_offset(skb) +
2398c2ecf20Sopenharmony_ci				  sizeof(struct icmphdr));
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	unsigned short frag_off;
2458c2ecf20Sopenharmony_ci	unsigned int payload_ofs = 0;
2468c2ecf20Sopenharmony_ci	unsigned int nh_ofs = skb_network_offset(skb);
2478c2ecf20Sopenharmony_ci	unsigned int nh_len;
2488c2ecf20Sopenharmony_ci	struct ipv6hdr *nh;
2498c2ecf20Sopenharmony_ci	int err, nexthdr, flags = 0;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	err = check_header(skb, nh_ofs + sizeof(*nh));
2528c2ecf20Sopenharmony_ci	if (unlikely(err))
2538c2ecf20Sopenharmony_ci		return err;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	nh = ipv6_hdr(skb);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	key->ip.proto = NEXTHDR_NONE;
2588c2ecf20Sopenharmony_ci	key->ip.tos = ipv6_get_dsfield(nh);
2598c2ecf20Sopenharmony_ci	key->ip.ttl = nh->hop_limit;
2608c2ecf20Sopenharmony_ci	key->ipv6.label = *(__be32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL);
2618c2ecf20Sopenharmony_ci	key->ipv6.addr.src = nh->saddr;
2628c2ecf20Sopenharmony_ci	key->ipv6.addr.dst = nh->daddr;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	nexthdr = ipv6_find_hdr(skb, &payload_ofs, -1, &frag_off, &flags);
2658c2ecf20Sopenharmony_ci	if (flags & IP6_FH_F_FRAG) {
2668c2ecf20Sopenharmony_ci		if (frag_off) {
2678c2ecf20Sopenharmony_ci			key->ip.frag = OVS_FRAG_TYPE_LATER;
2688c2ecf20Sopenharmony_ci			key->ip.proto = NEXTHDR_FRAGMENT;
2698c2ecf20Sopenharmony_ci			return 0;
2708c2ecf20Sopenharmony_ci		}
2718c2ecf20Sopenharmony_ci		key->ip.frag = OVS_FRAG_TYPE_FIRST;
2728c2ecf20Sopenharmony_ci	} else {
2738c2ecf20Sopenharmony_ci		key->ip.frag = OVS_FRAG_TYPE_NONE;
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	/* Delayed handling of error in ipv6_find_hdr() as it
2778c2ecf20Sopenharmony_ci	 * always sets flags and frag_off to a valid value which may be
2788c2ecf20Sopenharmony_ci	 * used to set key->ip.frag above.
2798c2ecf20Sopenharmony_ci	 */
2808c2ecf20Sopenharmony_ci	if (unlikely(nexthdr < 0))
2818c2ecf20Sopenharmony_ci		return -EPROTO;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	nh_len = payload_ofs - nh_ofs;
2848c2ecf20Sopenharmony_ci	skb_set_transport_header(skb, nh_ofs + nh_len);
2858c2ecf20Sopenharmony_ci	key->ip.proto = nexthdr;
2868c2ecf20Sopenharmony_ci	return nh_len;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic bool icmp6hdr_ok(struct sk_buff *skb)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	return pskb_may_pull(skb, skb_transport_offset(skb) +
2928c2ecf20Sopenharmony_ci				  sizeof(struct icmp6hdr));
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci/**
2968c2ecf20Sopenharmony_ci * Parse vlan tag from vlan header.
2978c2ecf20Sopenharmony_ci * Returns ERROR on memory error.
2988c2ecf20Sopenharmony_ci * Returns 0 if it encounters a non-vlan or incomplete packet.
2998c2ecf20Sopenharmony_ci * Returns 1 after successfully parsing vlan tag.
3008c2ecf20Sopenharmony_ci */
3018c2ecf20Sopenharmony_cistatic int parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh,
3028c2ecf20Sopenharmony_ci			  bool untag_vlan)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct vlan_head *vh = (struct vlan_head *)skb->data;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (likely(!eth_type_vlan(vh->tpid)))
3078c2ecf20Sopenharmony_ci		return 0;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (unlikely(skb->len < sizeof(struct vlan_head) + sizeof(__be16)))
3108c2ecf20Sopenharmony_ci		return 0;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (unlikely(!pskb_may_pull(skb, sizeof(struct vlan_head) +
3138c2ecf20Sopenharmony_ci				 sizeof(__be16))))
3148c2ecf20Sopenharmony_ci		return -ENOMEM;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	vh = (struct vlan_head *)skb->data;
3178c2ecf20Sopenharmony_ci	key_vh->tci = vh->tci | htons(VLAN_CFI_MASK);
3188c2ecf20Sopenharmony_ci	key_vh->tpid = vh->tpid;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (unlikely(untag_vlan)) {
3218c2ecf20Sopenharmony_ci		int offset = skb->data - skb_mac_header(skb);
3228c2ecf20Sopenharmony_ci		u16 tci;
3238c2ecf20Sopenharmony_ci		int err;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		__skb_push(skb, offset);
3268c2ecf20Sopenharmony_ci		err = __skb_vlan_pop(skb, &tci);
3278c2ecf20Sopenharmony_ci		__skb_pull(skb, offset);
3288c2ecf20Sopenharmony_ci		if (err)
3298c2ecf20Sopenharmony_ci			return err;
3308c2ecf20Sopenharmony_ci		__vlan_hwaccel_put_tag(skb, key_vh->tpid, tci);
3318c2ecf20Sopenharmony_ci	} else {
3328c2ecf20Sopenharmony_ci		__skb_pull(skb, sizeof(struct vlan_head));
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci	return 1;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic void clear_vlan(struct sw_flow_key *key)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	key->eth.vlan.tci = 0;
3408c2ecf20Sopenharmony_ci	key->eth.vlan.tpid = 0;
3418c2ecf20Sopenharmony_ci	key->eth.cvlan.tci = 0;
3428c2ecf20Sopenharmony_ci	key->eth.cvlan.tpid = 0;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	int res;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (skb_vlan_tag_present(skb)) {
3508c2ecf20Sopenharmony_ci		key->eth.vlan.tci = htons(skb->vlan_tci) | htons(VLAN_CFI_MASK);
3518c2ecf20Sopenharmony_ci		key->eth.vlan.tpid = skb->vlan_proto;
3528c2ecf20Sopenharmony_ci	} else {
3538c2ecf20Sopenharmony_ci		/* Parse outer vlan tag in the non-accelerated case. */
3548c2ecf20Sopenharmony_ci		res = parse_vlan_tag(skb, &key->eth.vlan, true);
3558c2ecf20Sopenharmony_ci		if (res <= 0)
3568c2ecf20Sopenharmony_ci			return res;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/* Parse inner vlan tag. */
3608c2ecf20Sopenharmony_ci	res = parse_vlan_tag(skb, &key->eth.cvlan, false);
3618c2ecf20Sopenharmony_ci	if (res <= 0)
3628c2ecf20Sopenharmony_ci		return res;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	return 0;
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic __be16 parse_ethertype(struct sk_buff *skb)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	struct llc_snap_hdr {
3708c2ecf20Sopenharmony_ci		u8  dsap;  /* Always 0xAA */
3718c2ecf20Sopenharmony_ci		u8  ssap;  /* Always 0xAA */
3728c2ecf20Sopenharmony_ci		u8  ctrl;
3738c2ecf20Sopenharmony_ci		u8  oui[3];
3748c2ecf20Sopenharmony_ci		__be16 ethertype;
3758c2ecf20Sopenharmony_ci	};
3768c2ecf20Sopenharmony_ci	struct llc_snap_hdr *llc;
3778c2ecf20Sopenharmony_ci	__be16 proto;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	proto = *(__be16 *) skb->data;
3808c2ecf20Sopenharmony_ci	__skb_pull(skb, sizeof(__be16));
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	if (eth_proto_is_802_3(proto))
3838c2ecf20Sopenharmony_ci		return proto;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (skb->len < sizeof(struct llc_snap_hdr))
3868c2ecf20Sopenharmony_ci		return htons(ETH_P_802_2);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (unlikely(!pskb_may_pull(skb, sizeof(struct llc_snap_hdr))))
3898c2ecf20Sopenharmony_ci		return htons(0);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	llc = (struct llc_snap_hdr *) skb->data;
3928c2ecf20Sopenharmony_ci	if (llc->dsap != LLC_SAP_SNAP ||
3938c2ecf20Sopenharmony_ci	    llc->ssap != LLC_SAP_SNAP ||
3948c2ecf20Sopenharmony_ci	    (llc->oui[0] | llc->oui[1] | llc->oui[2]) != 0)
3958c2ecf20Sopenharmony_ci		return htons(ETH_P_802_2);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	__skb_pull(skb, sizeof(struct llc_snap_hdr));
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	if (eth_proto_is_802_3(llc->ethertype))
4008c2ecf20Sopenharmony_ci		return llc->ethertype;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	return htons(ETH_P_802_2);
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
4068c2ecf20Sopenharmony_ci			int nh_len)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	struct icmp6hdr *icmp = icmp6_hdr(skb);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	/* The ICMPv6 type and code fields use the 16-bit transport port
4118c2ecf20Sopenharmony_ci	 * fields, so we need to store them in 16-bit network byte order.
4128c2ecf20Sopenharmony_ci	 */
4138c2ecf20Sopenharmony_ci	key->tp.src = htons(icmp->icmp6_type);
4148c2ecf20Sopenharmony_ci	key->tp.dst = htons(icmp->icmp6_code);
4158c2ecf20Sopenharmony_ci	memset(&key->ipv6.nd, 0, sizeof(key->ipv6.nd));
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	if (icmp->icmp6_code == 0 &&
4188c2ecf20Sopenharmony_ci	    (icmp->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION ||
4198c2ecf20Sopenharmony_ci	     icmp->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT)) {
4208c2ecf20Sopenharmony_ci		int icmp_len = skb->len - skb_transport_offset(skb);
4218c2ecf20Sopenharmony_ci		struct nd_msg *nd;
4228c2ecf20Sopenharmony_ci		int offset;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		/* In order to process neighbor discovery options, we need the
4258c2ecf20Sopenharmony_ci		 * entire packet.
4268c2ecf20Sopenharmony_ci		 */
4278c2ecf20Sopenharmony_ci		if (unlikely(icmp_len < sizeof(*nd)))
4288c2ecf20Sopenharmony_ci			return 0;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci		if (unlikely(skb_linearize(skb)))
4318c2ecf20Sopenharmony_ci			return -ENOMEM;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci		nd = (struct nd_msg *)skb_transport_header(skb);
4348c2ecf20Sopenharmony_ci		key->ipv6.nd.target = nd->target;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci		icmp_len -= sizeof(*nd);
4378c2ecf20Sopenharmony_ci		offset = 0;
4388c2ecf20Sopenharmony_ci		while (icmp_len >= 8) {
4398c2ecf20Sopenharmony_ci			struct nd_opt_hdr *nd_opt =
4408c2ecf20Sopenharmony_ci				 (struct nd_opt_hdr *)(nd->opt + offset);
4418c2ecf20Sopenharmony_ci			int opt_len = nd_opt->nd_opt_len * 8;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci			if (unlikely(!opt_len || opt_len > icmp_len))
4448c2ecf20Sopenharmony_ci				return 0;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci			/* Store the link layer address if the appropriate
4478c2ecf20Sopenharmony_ci			 * option is provided.  It is considered an error if
4488c2ecf20Sopenharmony_ci			 * the same link layer option is specified twice.
4498c2ecf20Sopenharmony_ci			 */
4508c2ecf20Sopenharmony_ci			if (nd_opt->nd_opt_type == ND_OPT_SOURCE_LL_ADDR
4518c2ecf20Sopenharmony_ci			    && opt_len == 8) {
4528c2ecf20Sopenharmony_ci				if (unlikely(!is_zero_ether_addr(key->ipv6.nd.sll)))
4538c2ecf20Sopenharmony_ci					goto invalid;
4548c2ecf20Sopenharmony_ci				ether_addr_copy(key->ipv6.nd.sll,
4558c2ecf20Sopenharmony_ci						&nd->opt[offset+sizeof(*nd_opt)]);
4568c2ecf20Sopenharmony_ci			} else if (nd_opt->nd_opt_type == ND_OPT_TARGET_LL_ADDR
4578c2ecf20Sopenharmony_ci				   && opt_len == 8) {
4588c2ecf20Sopenharmony_ci				if (unlikely(!is_zero_ether_addr(key->ipv6.nd.tll)))
4598c2ecf20Sopenharmony_ci					goto invalid;
4608c2ecf20Sopenharmony_ci				ether_addr_copy(key->ipv6.nd.tll,
4618c2ecf20Sopenharmony_ci						&nd->opt[offset+sizeof(*nd_opt)]);
4628c2ecf20Sopenharmony_ci			}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci			icmp_len -= opt_len;
4658c2ecf20Sopenharmony_ci			offset += opt_len;
4668c2ecf20Sopenharmony_ci		}
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	return 0;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ciinvalid:
4728c2ecf20Sopenharmony_ci	memset(&key->ipv6.nd.target, 0, sizeof(key->ipv6.nd.target));
4738c2ecf20Sopenharmony_ci	memset(key->ipv6.nd.sll, 0, sizeof(key->ipv6.nd.sll));
4748c2ecf20Sopenharmony_ci	memset(key->ipv6.nd.tll, 0, sizeof(key->ipv6.nd.tll));
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	return 0;
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_cistatic int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	struct nshhdr *nh;
4828c2ecf20Sopenharmony_ci	unsigned int nh_ofs = skb_network_offset(skb);
4838c2ecf20Sopenharmony_ci	u8 version, length;
4848c2ecf20Sopenharmony_ci	int err;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	err = check_header(skb, nh_ofs + NSH_BASE_HDR_LEN);
4878c2ecf20Sopenharmony_ci	if (unlikely(err))
4888c2ecf20Sopenharmony_ci		return err;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	nh = nsh_hdr(skb);
4918c2ecf20Sopenharmony_ci	version = nsh_get_ver(nh);
4928c2ecf20Sopenharmony_ci	length = nsh_hdr_len(nh);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	if (version != 0)
4958c2ecf20Sopenharmony_ci		return -EINVAL;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	err = check_header(skb, nh_ofs + length);
4988c2ecf20Sopenharmony_ci	if (unlikely(err))
4998c2ecf20Sopenharmony_ci		return err;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	nh = nsh_hdr(skb);
5028c2ecf20Sopenharmony_ci	key->nsh.base.flags = nsh_get_flags(nh);
5038c2ecf20Sopenharmony_ci	key->nsh.base.ttl = nsh_get_ttl(nh);
5048c2ecf20Sopenharmony_ci	key->nsh.base.mdtype = nh->mdtype;
5058c2ecf20Sopenharmony_ci	key->nsh.base.np = nh->np;
5068c2ecf20Sopenharmony_ci	key->nsh.base.path_hdr = nh->path_hdr;
5078c2ecf20Sopenharmony_ci	switch (key->nsh.base.mdtype) {
5088c2ecf20Sopenharmony_ci	case NSH_M_TYPE1:
5098c2ecf20Sopenharmony_ci		if (length != NSH_M_TYPE1_LEN)
5108c2ecf20Sopenharmony_ci			return -EINVAL;
5118c2ecf20Sopenharmony_ci		memcpy(key->nsh.context, nh->md1.context,
5128c2ecf20Sopenharmony_ci		       sizeof(nh->md1));
5138c2ecf20Sopenharmony_ci		break;
5148c2ecf20Sopenharmony_ci	case NSH_M_TYPE2:
5158c2ecf20Sopenharmony_ci		memset(key->nsh.context, 0,
5168c2ecf20Sopenharmony_ci		       sizeof(nh->md1));
5178c2ecf20Sopenharmony_ci		break;
5188c2ecf20Sopenharmony_ci	default:
5198c2ecf20Sopenharmony_ci		return -EINVAL;
5208c2ecf20Sopenharmony_ci	}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	return 0;
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci/**
5268c2ecf20Sopenharmony_ci * key_extract_l3l4 - extracts L3/L4 header information.
5278c2ecf20Sopenharmony_ci * @skb: sk_buff that contains the frame, with skb->data pointing to the
5288c2ecf20Sopenharmony_ci *       L3 header
5298c2ecf20Sopenharmony_ci * @key: output flow key
5308c2ecf20Sopenharmony_ci *
5318c2ecf20Sopenharmony_ci */
5328c2ecf20Sopenharmony_cistatic int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	int error;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	/* Network layer. */
5378c2ecf20Sopenharmony_ci	if (key->eth.type == htons(ETH_P_IP)) {
5388c2ecf20Sopenharmony_ci		struct iphdr *nh;
5398c2ecf20Sopenharmony_ci		__be16 offset;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci		error = check_iphdr(skb);
5428c2ecf20Sopenharmony_ci		if (unlikely(error)) {
5438c2ecf20Sopenharmony_ci			memset(&key->ip, 0, sizeof(key->ip));
5448c2ecf20Sopenharmony_ci			memset(&key->ipv4, 0, sizeof(key->ipv4));
5458c2ecf20Sopenharmony_ci			if (error == -EINVAL) {
5468c2ecf20Sopenharmony_ci				skb->transport_header = skb->network_header;
5478c2ecf20Sopenharmony_ci				error = 0;
5488c2ecf20Sopenharmony_ci			}
5498c2ecf20Sopenharmony_ci			return error;
5508c2ecf20Sopenharmony_ci		}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		nh = ip_hdr(skb);
5538c2ecf20Sopenharmony_ci		key->ipv4.addr.src = nh->saddr;
5548c2ecf20Sopenharmony_ci		key->ipv4.addr.dst = nh->daddr;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci		key->ip.proto = nh->protocol;
5578c2ecf20Sopenharmony_ci		key->ip.tos = nh->tos;
5588c2ecf20Sopenharmony_ci		key->ip.ttl = nh->ttl;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci		offset = nh->frag_off & htons(IP_OFFSET);
5618c2ecf20Sopenharmony_ci		if (offset) {
5628c2ecf20Sopenharmony_ci			key->ip.frag = OVS_FRAG_TYPE_LATER;
5638c2ecf20Sopenharmony_ci			memset(&key->tp, 0, sizeof(key->tp));
5648c2ecf20Sopenharmony_ci			return 0;
5658c2ecf20Sopenharmony_ci		}
5668c2ecf20Sopenharmony_ci		if (nh->frag_off & htons(IP_MF) ||
5678c2ecf20Sopenharmony_ci			skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
5688c2ecf20Sopenharmony_ci			key->ip.frag = OVS_FRAG_TYPE_FIRST;
5698c2ecf20Sopenharmony_ci		else
5708c2ecf20Sopenharmony_ci			key->ip.frag = OVS_FRAG_TYPE_NONE;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci		/* Transport layer. */
5738c2ecf20Sopenharmony_ci		if (key->ip.proto == IPPROTO_TCP) {
5748c2ecf20Sopenharmony_ci			if (tcphdr_ok(skb)) {
5758c2ecf20Sopenharmony_ci				struct tcphdr *tcp = tcp_hdr(skb);
5768c2ecf20Sopenharmony_ci				key->tp.src = tcp->source;
5778c2ecf20Sopenharmony_ci				key->tp.dst = tcp->dest;
5788c2ecf20Sopenharmony_ci				key->tp.flags = TCP_FLAGS_BE16(tcp);
5798c2ecf20Sopenharmony_ci			} else {
5808c2ecf20Sopenharmony_ci				memset(&key->tp, 0, sizeof(key->tp));
5818c2ecf20Sopenharmony_ci			}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci		} else if (key->ip.proto == IPPROTO_UDP) {
5848c2ecf20Sopenharmony_ci			if (udphdr_ok(skb)) {
5858c2ecf20Sopenharmony_ci				struct udphdr *udp = udp_hdr(skb);
5868c2ecf20Sopenharmony_ci				key->tp.src = udp->source;
5878c2ecf20Sopenharmony_ci				key->tp.dst = udp->dest;
5888c2ecf20Sopenharmony_ci			} else {
5898c2ecf20Sopenharmony_ci				memset(&key->tp, 0, sizeof(key->tp));
5908c2ecf20Sopenharmony_ci			}
5918c2ecf20Sopenharmony_ci		} else if (key->ip.proto == IPPROTO_SCTP) {
5928c2ecf20Sopenharmony_ci			if (sctphdr_ok(skb)) {
5938c2ecf20Sopenharmony_ci				struct sctphdr *sctp = sctp_hdr(skb);
5948c2ecf20Sopenharmony_ci				key->tp.src = sctp->source;
5958c2ecf20Sopenharmony_ci				key->tp.dst = sctp->dest;
5968c2ecf20Sopenharmony_ci			} else {
5978c2ecf20Sopenharmony_ci				memset(&key->tp, 0, sizeof(key->tp));
5988c2ecf20Sopenharmony_ci			}
5998c2ecf20Sopenharmony_ci		} else if (key->ip.proto == IPPROTO_ICMP) {
6008c2ecf20Sopenharmony_ci			if (icmphdr_ok(skb)) {
6018c2ecf20Sopenharmony_ci				struct icmphdr *icmp = icmp_hdr(skb);
6028c2ecf20Sopenharmony_ci				/* The ICMP type and code fields use the 16-bit
6038c2ecf20Sopenharmony_ci				 * transport port fields, so we need to store
6048c2ecf20Sopenharmony_ci				 * them in 16-bit network byte order. */
6058c2ecf20Sopenharmony_ci				key->tp.src = htons(icmp->type);
6068c2ecf20Sopenharmony_ci				key->tp.dst = htons(icmp->code);
6078c2ecf20Sopenharmony_ci			} else {
6088c2ecf20Sopenharmony_ci				memset(&key->tp, 0, sizeof(key->tp));
6098c2ecf20Sopenharmony_ci			}
6108c2ecf20Sopenharmony_ci		}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	} else if (key->eth.type == htons(ETH_P_ARP) ||
6138c2ecf20Sopenharmony_ci		   key->eth.type == htons(ETH_P_RARP)) {
6148c2ecf20Sopenharmony_ci		struct arp_eth_header *arp;
6158c2ecf20Sopenharmony_ci		bool arp_available = arphdr_ok(skb);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci		arp = (struct arp_eth_header *)skb_network_header(skb);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		if (arp_available &&
6208c2ecf20Sopenharmony_ci		    arp->ar_hrd == htons(ARPHRD_ETHER) &&
6218c2ecf20Sopenharmony_ci		    arp->ar_pro == htons(ETH_P_IP) &&
6228c2ecf20Sopenharmony_ci		    arp->ar_hln == ETH_ALEN &&
6238c2ecf20Sopenharmony_ci		    arp->ar_pln == 4) {
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci			/* We only match on the lower 8 bits of the opcode. */
6268c2ecf20Sopenharmony_ci			if (ntohs(arp->ar_op) <= 0xff)
6278c2ecf20Sopenharmony_ci				key->ip.proto = ntohs(arp->ar_op);
6288c2ecf20Sopenharmony_ci			else
6298c2ecf20Sopenharmony_ci				key->ip.proto = 0;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci			memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src));
6328c2ecf20Sopenharmony_ci			memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst));
6338c2ecf20Sopenharmony_ci			ether_addr_copy(key->ipv4.arp.sha, arp->ar_sha);
6348c2ecf20Sopenharmony_ci			ether_addr_copy(key->ipv4.arp.tha, arp->ar_tha);
6358c2ecf20Sopenharmony_ci		} else {
6368c2ecf20Sopenharmony_ci			memset(&key->ip, 0, sizeof(key->ip));
6378c2ecf20Sopenharmony_ci			memset(&key->ipv4, 0, sizeof(key->ipv4));
6388c2ecf20Sopenharmony_ci		}
6398c2ecf20Sopenharmony_ci	} else if (eth_p_mpls(key->eth.type)) {
6408c2ecf20Sopenharmony_ci		u8 label_count = 1;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		memset(&key->mpls, 0, sizeof(key->mpls));
6438c2ecf20Sopenharmony_ci		skb_set_inner_network_header(skb, skb->mac_len);
6448c2ecf20Sopenharmony_ci		while (1) {
6458c2ecf20Sopenharmony_ci			__be32 lse;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci			error = check_header(skb, skb->mac_len +
6488c2ecf20Sopenharmony_ci					     label_count * MPLS_HLEN);
6498c2ecf20Sopenharmony_ci			if (unlikely(error))
6508c2ecf20Sopenharmony_ci				return 0;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci			memcpy(&lse, skb_inner_network_header(skb), MPLS_HLEN);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci			if (label_count <= MPLS_LABEL_DEPTH)
6558c2ecf20Sopenharmony_ci				memcpy(&key->mpls.lse[label_count - 1], &lse,
6568c2ecf20Sopenharmony_ci				       MPLS_HLEN);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci			skb_set_inner_network_header(skb, skb->mac_len +
6598c2ecf20Sopenharmony_ci						     label_count * MPLS_HLEN);
6608c2ecf20Sopenharmony_ci			if (lse & htonl(MPLS_LS_S_MASK))
6618c2ecf20Sopenharmony_ci				break;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci			label_count++;
6648c2ecf20Sopenharmony_ci		}
6658c2ecf20Sopenharmony_ci		if (label_count > MPLS_LABEL_DEPTH)
6668c2ecf20Sopenharmony_ci			label_count = MPLS_LABEL_DEPTH;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci		key->mpls.num_labels_mask = GENMASK(label_count - 1, 0);
6698c2ecf20Sopenharmony_ci	} else if (key->eth.type == htons(ETH_P_IPV6)) {
6708c2ecf20Sopenharmony_ci		int nh_len;             /* IPv6 Header + Extensions */
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci		nh_len = parse_ipv6hdr(skb, key);
6738c2ecf20Sopenharmony_ci		if (unlikely(nh_len < 0)) {
6748c2ecf20Sopenharmony_ci			switch (nh_len) {
6758c2ecf20Sopenharmony_ci			case -EINVAL:
6768c2ecf20Sopenharmony_ci				memset(&key->ip, 0, sizeof(key->ip));
6778c2ecf20Sopenharmony_ci				memset(&key->ipv6.addr, 0, sizeof(key->ipv6.addr));
6788c2ecf20Sopenharmony_ci				fallthrough;
6798c2ecf20Sopenharmony_ci			case -EPROTO:
6808c2ecf20Sopenharmony_ci				skb->transport_header = skb->network_header;
6818c2ecf20Sopenharmony_ci				error = 0;
6828c2ecf20Sopenharmony_ci				break;
6838c2ecf20Sopenharmony_ci			default:
6848c2ecf20Sopenharmony_ci				error = nh_len;
6858c2ecf20Sopenharmony_ci			}
6868c2ecf20Sopenharmony_ci			return error;
6878c2ecf20Sopenharmony_ci		}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci		if (key->ip.frag == OVS_FRAG_TYPE_LATER) {
6908c2ecf20Sopenharmony_ci			memset(&key->tp, 0, sizeof(key->tp));
6918c2ecf20Sopenharmony_ci			return 0;
6928c2ecf20Sopenharmony_ci		}
6938c2ecf20Sopenharmony_ci		if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
6948c2ecf20Sopenharmony_ci			key->ip.frag = OVS_FRAG_TYPE_FIRST;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci		/* Transport layer. */
6978c2ecf20Sopenharmony_ci		if (key->ip.proto == NEXTHDR_TCP) {
6988c2ecf20Sopenharmony_ci			if (tcphdr_ok(skb)) {
6998c2ecf20Sopenharmony_ci				struct tcphdr *tcp = tcp_hdr(skb);
7008c2ecf20Sopenharmony_ci				key->tp.src = tcp->source;
7018c2ecf20Sopenharmony_ci				key->tp.dst = tcp->dest;
7028c2ecf20Sopenharmony_ci				key->tp.flags = TCP_FLAGS_BE16(tcp);
7038c2ecf20Sopenharmony_ci			} else {
7048c2ecf20Sopenharmony_ci				memset(&key->tp, 0, sizeof(key->tp));
7058c2ecf20Sopenharmony_ci			}
7068c2ecf20Sopenharmony_ci		} else if (key->ip.proto == NEXTHDR_UDP) {
7078c2ecf20Sopenharmony_ci			if (udphdr_ok(skb)) {
7088c2ecf20Sopenharmony_ci				struct udphdr *udp = udp_hdr(skb);
7098c2ecf20Sopenharmony_ci				key->tp.src = udp->source;
7108c2ecf20Sopenharmony_ci				key->tp.dst = udp->dest;
7118c2ecf20Sopenharmony_ci			} else {
7128c2ecf20Sopenharmony_ci				memset(&key->tp, 0, sizeof(key->tp));
7138c2ecf20Sopenharmony_ci			}
7148c2ecf20Sopenharmony_ci		} else if (key->ip.proto == NEXTHDR_SCTP) {
7158c2ecf20Sopenharmony_ci			if (sctphdr_ok(skb)) {
7168c2ecf20Sopenharmony_ci				struct sctphdr *sctp = sctp_hdr(skb);
7178c2ecf20Sopenharmony_ci				key->tp.src = sctp->source;
7188c2ecf20Sopenharmony_ci				key->tp.dst = sctp->dest;
7198c2ecf20Sopenharmony_ci			} else {
7208c2ecf20Sopenharmony_ci				memset(&key->tp, 0, sizeof(key->tp));
7218c2ecf20Sopenharmony_ci			}
7228c2ecf20Sopenharmony_ci		} else if (key->ip.proto == NEXTHDR_ICMP) {
7238c2ecf20Sopenharmony_ci			if (icmp6hdr_ok(skb)) {
7248c2ecf20Sopenharmony_ci				error = parse_icmpv6(skb, key, nh_len);
7258c2ecf20Sopenharmony_ci				if (error)
7268c2ecf20Sopenharmony_ci					return error;
7278c2ecf20Sopenharmony_ci			} else {
7288c2ecf20Sopenharmony_ci				memset(&key->tp, 0, sizeof(key->tp));
7298c2ecf20Sopenharmony_ci			}
7308c2ecf20Sopenharmony_ci		}
7318c2ecf20Sopenharmony_ci	} else if (key->eth.type == htons(ETH_P_NSH)) {
7328c2ecf20Sopenharmony_ci		error = parse_nsh(skb, key);
7338c2ecf20Sopenharmony_ci		if (error)
7348c2ecf20Sopenharmony_ci			return error;
7358c2ecf20Sopenharmony_ci	}
7368c2ecf20Sopenharmony_ci	return 0;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci/**
7408c2ecf20Sopenharmony_ci * key_extract - extracts a flow key from an Ethernet frame.
7418c2ecf20Sopenharmony_ci * @skb: sk_buff that contains the frame, with skb->data pointing to the
7428c2ecf20Sopenharmony_ci * Ethernet header
7438c2ecf20Sopenharmony_ci * @key: output flow key
7448c2ecf20Sopenharmony_ci *
7458c2ecf20Sopenharmony_ci * The caller must ensure that skb->len >= ETH_HLEN.
7468c2ecf20Sopenharmony_ci *
7478c2ecf20Sopenharmony_ci * Returns 0 if successful, otherwise a negative errno value.
7488c2ecf20Sopenharmony_ci *
7498c2ecf20Sopenharmony_ci * Initializes @skb header fields as follows:
7508c2ecf20Sopenharmony_ci *
7518c2ecf20Sopenharmony_ci *    - skb->mac_header: the L2 header.
7528c2ecf20Sopenharmony_ci *
7538c2ecf20Sopenharmony_ci *    - skb->network_header: just past the L2 header, or just past the
7548c2ecf20Sopenharmony_ci *      VLAN header, to the first byte of the L2 payload.
7558c2ecf20Sopenharmony_ci *
7568c2ecf20Sopenharmony_ci *    - skb->transport_header: If key->eth.type is ETH_P_IP or ETH_P_IPV6
7578c2ecf20Sopenharmony_ci *      on output, then just past the IP header, if one is present and
7588c2ecf20Sopenharmony_ci *      of a correct length, otherwise the same as skb->network_header.
7598c2ecf20Sopenharmony_ci *      For other key->eth.type values it is left untouched.
7608c2ecf20Sopenharmony_ci *
7618c2ecf20Sopenharmony_ci *    - skb->protocol: the type of the data starting at skb->network_header.
7628c2ecf20Sopenharmony_ci *      Equals to key->eth.type.
7638c2ecf20Sopenharmony_ci */
7648c2ecf20Sopenharmony_cistatic int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
7658c2ecf20Sopenharmony_ci{
7668c2ecf20Sopenharmony_ci	struct ethhdr *eth;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	/* Flags are always used as part of stats */
7698c2ecf20Sopenharmony_ci	key->tp.flags = 0;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	skb_reset_mac_header(skb);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	/* Link layer. */
7748c2ecf20Sopenharmony_ci	clear_vlan(key);
7758c2ecf20Sopenharmony_ci	if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) {
7768c2ecf20Sopenharmony_ci		if (unlikely(eth_type_vlan(skb->protocol)))
7778c2ecf20Sopenharmony_ci			return -EINVAL;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci		skb_reset_network_header(skb);
7808c2ecf20Sopenharmony_ci		key->eth.type = skb->protocol;
7818c2ecf20Sopenharmony_ci	} else {
7828c2ecf20Sopenharmony_ci		eth = eth_hdr(skb);
7838c2ecf20Sopenharmony_ci		ether_addr_copy(key->eth.src, eth->h_source);
7848c2ecf20Sopenharmony_ci		ether_addr_copy(key->eth.dst, eth->h_dest);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci		__skb_pull(skb, 2 * ETH_ALEN);
7878c2ecf20Sopenharmony_ci		/* We are going to push all headers that we pull, so no need to
7888c2ecf20Sopenharmony_ci		 * update skb->csum here.
7898c2ecf20Sopenharmony_ci		 */
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci		if (unlikely(parse_vlan(skb, key)))
7928c2ecf20Sopenharmony_ci			return -ENOMEM;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci		key->eth.type = parse_ethertype(skb);
7958c2ecf20Sopenharmony_ci		if (unlikely(key->eth.type == htons(0)))
7968c2ecf20Sopenharmony_ci			return -ENOMEM;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci		/* Multiple tagged packets need to retain TPID to satisfy
7998c2ecf20Sopenharmony_ci		 * skb_vlan_pop(), which will later shift the ethertype into
8008c2ecf20Sopenharmony_ci		 * skb->protocol.
8018c2ecf20Sopenharmony_ci		 */
8028c2ecf20Sopenharmony_ci		if (key->eth.cvlan.tci & htons(VLAN_CFI_MASK))
8038c2ecf20Sopenharmony_ci			skb->protocol = key->eth.cvlan.tpid;
8048c2ecf20Sopenharmony_ci		else
8058c2ecf20Sopenharmony_ci			skb->protocol = key->eth.type;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci		skb_reset_network_header(skb);
8088c2ecf20Sopenharmony_ci		__skb_push(skb, skb->data - skb_mac_header(skb));
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	skb_reset_mac_len(skb);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	/* Fill out L3/L4 key info, if any */
8148c2ecf20Sopenharmony_ci	return key_extract_l3l4(skb, key);
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci/* In the case of conntrack fragment handling it expects L3 headers,
8188c2ecf20Sopenharmony_ci * add a helper.
8198c2ecf20Sopenharmony_ci */
8208c2ecf20Sopenharmony_ciint ovs_flow_key_update_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	return key_extract_l3l4(skb, key);
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ciint ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key)
8268c2ecf20Sopenharmony_ci{
8278c2ecf20Sopenharmony_ci	int res;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	res = key_extract(skb, key);
8308c2ecf20Sopenharmony_ci	if (!res)
8318c2ecf20Sopenharmony_ci		key->mac_proto &= ~SW_FLOW_KEY_INVALID;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	return res;
8348c2ecf20Sopenharmony_ci}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_cistatic int key_extract_mac_proto(struct sk_buff *skb)
8378c2ecf20Sopenharmony_ci{
8388c2ecf20Sopenharmony_ci	switch (skb->dev->type) {
8398c2ecf20Sopenharmony_ci	case ARPHRD_ETHER:
8408c2ecf20Sopenharmony_ci		return MAC_PROTO_ETHERNET;
8418c2ecf20Sopenharmony_ci	case ARPHRD_NONE:
8428c2ecf20Sopenharmony_ci		if (skb->protocol == htons(ETH_P_TEB))
8438c2ecf20Sopenharmony_ci			return MAC_PROTO_ETHERNET;
8448c2ecf20Sopenharmony_ci		return MAC_PROTO_NONE;
8458c2ecf20Sopenharmony_ci	}
8468c2ecf20Sopenharmony_ci	WARN_ON_ONCE(1);
8478c2ecf20Sopenharmony_ci	return -EINVAL;
8488c2ecf20Sopenharmony_ci}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ciint ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
8518c2ecf20Sopenharmony_ci			 struct sk_buff *skb, struct sw_flow_key *key)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
8548c2ecf20Sopenharmony_ci	struct tc_skb_ext *tc_ext;
8558c2ecf20Sopenharmony_ci#endif
8568c2ecf20Sopenharmony_ci	int res, err;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	/* Extract metadata from packet. */
8598c2ecf20Sopenharmony_ci	if (tun_info) {
8608c2ecf20Sopenharmony_ci		key->tun_proto = ip_tunnel_info_af(tun_info);
8618c2ecf20Sopenharmony_ci		memcpy(&key->tun_key, &tun_info->key, sizeof(key->tun_key));
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci		if (tun_info->options_len) {
8648c2ecf20Sopenharmony_ci			BUILD_BUG_ON((1 << (sizeof(tun_info->options_len) *
8658c2ecf20Sopenharmony_ci						   8)) - 1
8668c2ecf20Sopenharmony_ci					> sizeof(key->tun_opts));
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci			ip_tunnel_info_opts_get(TUN_METADATA_OPTS(key, tun_info->options_len),
8698c2ecf20Sopenharmony_ci						tun_info);
8708c2ecf20Sopenharmony_ci			key->tun_opts_len = tun_info->options_len;
8718c2ecf20Sopenharmony_ci		} else {
8728c2ecf20Sopenharmony_ci			key->tun_opts_len = 0;
8738c2ecf20Sopenharmony_ci		}
8748c2ecf20Sopenharmony_ci	} else  {
8758c2ecf20Sopenharmony_ci		key->tun_proto = 0;
8768c2ecf20Sopenharmony_ci		key->tun_opts_len = 0;
8778c2ecf20Sopenharmony_ci		memset(&key->tun_key, 0, sizeof(key->tun_key));
8788c2ecf20Sopenharmony_ci	}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	key->phy.priority = skb->priority;
8818c2ecf20Sopenharmony_ci	key->phy.in_port = OVS_CB(skb)->input_vport->port_no;
8828c2ecf20Sopenharmony_ci	key->phy.skb_mark = skb->mark;
8838c2ecf20Sopenharmony_ci	key->ovs_flow_hash = 0;
8848c2ecf20Sopenharmony_ci	res = key_extract_mac_proto(skb);
8858c2ecf20Sopenharmony_ci	if (res < 0)
8868c2ecf20Sopenharmony_ci		return res;
8878c2ecf20Sopenharmony_ci	key->mac_proto = res;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
8908c2ecf20Sopenharmony_ci	if (static_branch_unlikely(&tc_recirc_sharing_support)) {
8918c2ecf20Sopenharmony_ci		tc_ext = skb_ext_find(skb, TC_SKB_EXT);
8928c2ecf20Sopenharmony_ci		key->recirc_id = tc_ext ? tc_ext->chain : 0;
8938c2ecf20Sopenharmony_ci		OVS_CB(skb)->mru = tc_ext ? tc_ext->mru : 0;
8948c2ecf20Sopenharmony_ci	} else {
8958c2ecf20Sopenharmony_ci		key->recirc_id = 0;
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci#else
8988c2ecf20Sopenharmony_ci	key->recirc_id = 0;
8998c2ecf20Sopenharmony_ci#endif
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	err = key_extract(skb, key);
9028c2ecf20Sopenharmony_ci	if (!err)
9038c2ecf20Sopenharmony_ci		ovs_ct_fill_key(skb, key);   /* Must be after key_extract(). */
9048c2ecf20Sopenharmony_ci	return err;
9058c2ecf20Sopenharmony_ci}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ciint ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr,
9088c2ecf20Sopenharmony_ci				   struct sk_buff *skb,
9098c2ecf20Sopenharmony_ci				   struct sw_flow_key *key, bool log)
9108c2ecf20Sopenharmony_ci{
9118c2ecf20Sopenharmony_ci	const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
9128c2ecf20Sopenharmony_ci	u64 attrs = 0;
9138c2ecf20Sopenharmony_ci	int err;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	err = parse_flow_nlattrs(attr, a, &attrs, log);
9168c2ecf20Sopenharmony_ci	if (err)
9178c2ecf20Sopenharmony_ci		return -EINVAL;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	/* Extract metadata from netlink attributes. */
9208c2ecf20Sopenharmony_ci	err = ovs_nla_get_flow_metadata(net, a, attrs, key, log);
9218c2ecf20Sopenharmony_ci	if (err)
9228c2ecf20Sopenharmony_ci		return err;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	/* key_extract assumes that skb->protocol is set-up for
9258c2ecf20Sopenharmony_ci	 * layer 3 packets which is the case for other callers,
9268c2ecf20Sopenharmony_ci	 * in particular packets received from the network stack.
9278c2ecf20Sopenharmony_ci	 * Here the correct value can be set from the metadata
9288c2ecf20Sopenharmony_ci	 * extracted above.
9298c2ecf20Sopenharmony_ci	 * For L2 packet key eth type would be zero. skb protocol
9308c2ecf20Sopenharmony_ci	 * would be set to correct value later during key-extact.
9318c2ecf20Sopenharmony_ci	 */
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	skb->protocol = key->eth.type;
9348c2ecf20Sopenharmony_ci	err = key_extract(skb, key);
9358c2ecf20Sopenharmony_ci	if (err)
9368c2ecf20Sopenharmony_ci		return err;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	/* Check that we have conntrack original direction tuple metadata only
9398c2ecf20Sopenharmony_ci	 * for packets for which it makes sense.  Otherwise the key may be
9408c2ecf20Sopenharmony_ci	 * corrupted due to overlapping key fields.
9418c2ecf20Sopenharmony_ci	 */
9428c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4) &&
9438c2ecf20Sopenharmony_ci	    key->eth.type != htons(ETH_P_IP))
9448c2ecf20Sopenharmony_ci		return -EINVAL;
9458c2ecf20Sopenharmony_ci	if (attrs & (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6) &&
9468c2ecf20Sopenharmony_ci	    (key->eth.type != htons(ETH_P_IPV6) ||
9478c2ecf20Sopenharmony_ci	     sw_flow_key_is_nd(key)))
9488c2ecf20Sopenharmony_ci		return -EINVAL;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	return 0;
9518c2ecf20Sopenharmony_ci}
952