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 <linux/skbuff.h>
98c2ecf20Sopenharmony_ci#include <linux/in.h>
108c2ecf20Sopenharmony_ci#include <linux/ip.h>
118c2ecf20Sopenharmony_ci#include <linux/openvswitch.h>
128c2ecf20Sopenharmony_ci#include <linux/sctp.h>
138c2ecf20Sopenharmony_ci#include <linux/tcp.h>
148c2ecf20Sopenharmony_ci#include <linux/udp.h>
158c2ecf20Sopenharmony_ci#include <linux/in6.h>
168c2ecf20Sopenharmony_ci#include <linux/if_arp.h>
178c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <net/dst.h>
208c2ecf20Sopenharmony_ci#include <net/ip.h>
218c2ecf20Sopenharmony_ci#include <net/ipv6.h>
228c2ecf20Sopenharmony_ci#include <net/ip6_fib.h>
238c2ecf20Sopenharmony_ci#include <net/checksum.h>
248c2ecf20Sopenharmony_ci#include <net/dsfield.h>
258c2ecf20Sopenharmony_ci#include <net/mpls.h>
268c2ecf20Sopenharmony_ci#include <net/sctp/checksum.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include "datapath.h"
298c2ecf20Sopenharmony_ci#include "flow.h"
308c2ecf20Sopenharmony_ci#include "conntrack.h"
318c2ecf20Sopenharmony_ci#include "vport.h"
328c2ecf20Sopenharmony_ci#include "flow_netlink.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct deferred_action {
358c2ecf20Sopenharmony_ci	struct sk_buff *skb;
368c2ecf20Sopenharmony_ci	const struct nlattr *actions;
378c2ecf20Sopenharmony_ci	int actions_len;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	/* Store pkt_key clone when creating deferred action. */
408c2ecf20Sopenharmony_ci	struct sw_flow_key pkt_key;
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define MAX_L2_LEN	(VLAN_ETH_HLEN + 3 * MPLS_HLEN)
448c2ecf20Sopenharmony_cistruct ovs_frag_data {
458c2ecf20Sopenharmony_ci	unsigned long dst;
468c2ecf20Sopenharmony_ci	struct vport *vport;
478c2ecf20Sopenharmony_ci	struct ovs_skb_cb cb;
488c2ecf20Sopenharmony_ci	__be16 inner_protocol;
498c2ecf20Sopenharmony_ci	u16 network_offset;	/* valid only for MPLS */
508c2ecf20Sopenharmony_ci	u16 vlan_tci;
518c2ecf20Sopenharmony_ci	__be16 vlan_proto;
528c2ecf20Sopenharmony_ci	unsigned int l2_len;
538c2ecf20Sopenharmony_ci	u8 mac_proto;
548c2ecf20Sopenharmony_ci	u8 l2_data[MAX_L2_LEN];
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct ovs_frag_data, ovs_frag_data_storage);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define DEFERRED_ACTION_FIFO_SIZE 10
608c2ecf20Sopenharmony_ci#define OVS_RECURSION_LIMIT 5
618c2ecf20Sopenharmony_ci#define OVS_DEFERRED_ACTION_THRESHOLD (OVS_RECURSION_LIMIT - 2)
628c2ecf20Sopenharmony_cistruct action_fifo {
638c2ecf20Sopenharmony_ci	int head;
648c2ecf20Sopenharmony_ci	int tail;
658c2ecf20Sopenharmony_ci	/* Deferred action fifo queue storage. */
668c2ecf20Sopenharmony_ci	struct deferred_action fifo[DEFERRED_ACTION_FIFO_SIZE];
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistruct action_flow_keys {
708c2ecf20Sopenharmony_ci	struct sw_flow_key key[OVS_DEFERRED_ACTION_THRESHOLD];
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic struct action_fifo __percpu *action_fifos;
748c2ecf20Sopenharmony_cistatic struct action_flow_keys __percpu *flow_keys;
758c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(int, exec_actions_level);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/* Make a clone of the 'key', using the pre-allocated percpu 'flow_keys'
788c2ecf20Sopenharmony_ci * space. Return NULL if out of key spaces.
798c2ecf20Sopenharmony_ci */
808c2ecf20Sopenharmony_cistatic struct sw_flow_key *clone_key(const struct sw_flow_key *key_)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct action_flow_keys *keys = this_cpu_ptr(flow_keys);
838c2ecf20Sopenharmony_ci	int level = this_cpu_read(exec_actions_level);
848c2ecf20Sopenharmony_ci	struct sw_flow_key *key = NULL;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (level <= OVS_DEFERRED_ACTION_THRESHOLD) {
878c2ecf20Sopenharmony_ci		key = &keys->key[level - 1];
888c2ecf20Sopenharmony_ci		*key = *key_;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	return key;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic void action_fifo_init(struct action_fifo *fifo)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	fifo->head = 0;
978c2ecf20Sopenharmony_ci	fifo->tail = 0;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic bool action_fifo_is_empty(const struct action_fifo *fifo)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	return (fifo->head == fifo->tail);
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic struct deferred_action *action_fifo_get(struct action_fifo *fifo)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	if (action_fifo_is_empty(fifo))
1088c2ecf20Sopenharmony_ci		return NULL;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return &fifo->fifo[fifo->tail++];
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic struct deferred_action *action_fifo_put(struct action_fifo *fifo)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	if (fifo->head >= DEFERRED_ACTION_FIFO_SIZE - 1)
1168c2ecf20Sopenharmony_ci		return NULL;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	return &fifo->fifo[fifo->head++];
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/* Return true if fifo is not full */
1228c2ecf20Sopenharmony_cistatic struct deferred_action *add_deferred_actions(struct sk_buff *skb,
1238c2ecf20Sopenharmony_ci				    const struct sw_flow_key *key,
1248c2ecf20Sopenharmony_ci				    const struct nlattr *actions,
1258c2ecf20Sopenharmony_ci				    const int actions_len)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct action_fifo *fifo;
1288c2ecf20Sopenharmony_ci	struct deferred_action *da;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	fifo = this_cpu_ptr(action_fifos);
1318c2ecf20Sopenharmony_ci	da = action_fifo_put(fifo);
1328c2ecf20Sopenharmony_ci	if (da) {
1338c2ecf20Sopenharmony_ci		da->skb = skb;
1348c2ecf20Sopenharmony_ci		da->actions = actions;
1358c2ecf20Sopenharmony_ci		da->actions_len = actions_len;
1368c2ecf20Sopenharmony_ci		da->pkt_key = *key;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	return da;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic void invalidate_flow_key(struct sw_flow_key *key)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	key->mac_proto |= SW_FLOW_KEY_INVALID;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic bool is_flow_key_valid(const struct sw_flow_key *key)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	return !(key->mac_proto & SW_FLOW_KEY_INVALID);
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int clone_execute(struct datapath *dp, struct sk_buff *skb,
1538c2ecf20Sopenharmony_ci			 struct sw_flow_key *key,
1548c2ecf20Sopenharmony_ci			 u32 recirc_id,
1558c2ecf20Sopenharmony_ci			 const struct nlattr *actions, int len,
1568c2ecf20Sopenharmony_ci			 bool last, bool clone_flow_key);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
1598c2ecf20Sopenharmony_ci			      struct sw_flow_key *key,
1608c2ecf20Sopenharmony_ci			      const struct nlattr *attr, int len);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic int push_mpls(struct sk_buff *skb, struct sw_flow_key *key,
1638c2ecf20Sopenharmony_ci		     __be32 mpls_lse, __be16 mpls_ethertype, __u16 mac_len)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	int err;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	err = skb_mpls_push(skb, mpls_lse, mpls_ethertype, mac_len, !!mac_len);
1688c2ecf20Sopenharmony_ci	if (err)
1698c2ecf20Sopenharmony_ci		return err;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (!mac_len)
1728c2ecf20Sopenharmony_ci		key->mac_proto = MAC_PROTO_NONE;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	invalidate_flow_key(key);
1758c2ecf20Sopenharmony_ci	return 0;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key,
1798c2ecf20Sopenharmony_ci		    const __be16 ethertype)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	int err;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	err = skb_mpls_pop(skb, ethertype, skb->mac_len,
1848c2ecf20Sopenharmony_ci			   ovs_key_mac_proto(key) == MAC_PROTO_ETHERNET);
1858c2ecf20Sopenharmony_ci	if (err)
1868c2ecf20Sopenharmony_ci		return err;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (ethertype == htons(ETH_P_TEB))
1898c2ecf20Sopenharmony_ci		key->mac_proto = MAC_PROTO_ETHERNET;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	invalidate_flow_key(key);
1928c2ecf20Sopenharmony_ci	return 0;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int set_mpls(struct sk_buff *skb, struct sw_flow_key *flow_key,
1968c2ecf20Sopenharmony_ci		    const __be32 *mpls_lse, const __be32 *mask)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct mpls_shim_hdr *stack;
1998c2ecf20Sopenharmony_ci	__be32 lse;
2008c2ecf20Sopenharmony_ci	int err;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if (!pskb_may_pull(skb, skb_network_offset(skb) + MPLS_HLEN))
2038c2ecf20Sopenharmony_ci		return -ENOMEM;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	stack = mpls_hdr(skb);
2068c2ecf20Sopenharmony_ci	lse = OVS_MASKED(stack->label_stack_entry, *mpls_lse, *mask);
2078c2ecf20Sopenharmony_ci	err = skb_mpls_update_lse(skb, lse);
2088c2ecf20Sopenharmony_ci	if (err)
2098c2ecf20Sopenharmony_ci		return err;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	flow_key->mpls.lse[0] = lse;
2128c2ecf20Sopenharmony_ci	return 0;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	int err;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	err = skb_vlan_pop(skb);
2208c2ecf20Sopenharmony_ci	if (skb_vlan_tag_present(skb)) {
2218c2ecf20Sopenharmony_ci		invalidate_flow_key(key);
2228c2ecf20Sopenharmony_ci	} else {
2238c2ecf20Sopenharmony_ci		key->eth.vlan.tci = 0;
2248c2ecf20Sopenharmony_ci		key->eth.vlan.tpid = 0;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci	return err;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic int push_vlan(struct sk_buff *skb, struct sw_flow_key *key,
2308c2ecf20Sopenharmony_ci		     const struct ovs_action_push_vlan *vlan)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	if (skb_vlan_tag_present(skb)) {
2338c2ecf20Sopenharmony_ci		invalidate_flow_key(key);
2348c2ecf20Sopenharmony_ci	} else {
2358c2ecf20Sopenharmony_ci		key->eth.vlan.tci = vlan->vlan_tci;
2368c2ecf20Sopenharmony_ci		key->eth.vlan.tpid = vlan->vlan_tpid;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci	return skb_vlan_push(skb, vlan->vlan_tpid,
2398c2ecf20Sopenharmony_ci			     ntohs(vlan->vlan_tci) & ~VLAN_CFI_MASK);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci/* 'src' is already properly masked. */
2438c2ecf20Sopenharmony_cistatic void ether_addr_copy_masked(u8 *dst_, const u8 *src_, const u8 *mask_)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	u16 *dst = (u16 *)dst_;
2468c2ecf20Sopenharmony_ci	const u16 *src = (const u16 *)src_;
2478c2ecf20Sopenharmony_ci	const u16 *mask = (const u16 *)mask_;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	OVS_SET_MASKED(dst[0], src[0], mask[0]);
2508c2ecf20Sopenharmony_ci	OVS_SET_MASKED(dst[1], src[1], mask[1]);
2518c2ecf20Sopenharmony_ci	OVS_SET_MASKED(dst[2], src[2], mask[2]);
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key,
2558c2ecf20Sopenharmony_ci			const struct ovs_key_ethernet *key,
2568c2ecf20Sopenharmony_ci			const struct ovs_key_ethernet *mask)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	int err;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	err = skb_ensure_writable(skb, ETH_HLEN);
2618c2ecf20Sopenharmony_ci	if (unlikely(err))
2628c2ecf20Sopenharmony_ci		return err;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	skb_postpull_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	ether_addr_copy_masked(eth_hdr(skb)->h_source, key->eth_src,
2678c2ecf20Sopenharmony_ci			       mask->eth_src);
2688c2ecf20Sopenharmony_ci	ether_addr_copy_masked(eth_hdr(skb)->h_dest, key->eth_dst,
2698c2ecf20Sopenharmony_ci			       mask->eth_dst);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	skb_postpush_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	ether_addr_copy(flow_key->eth.src, eth_hdr(skb)->h_source);
2748c2ecf20Sopenharmony_ci	ether_addr_copy(flow_key->eth.dst, eth_hdr(skb)->h_dest);
2758c2ecf20Sopenharmony_ci	return 0;
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci/* pop_eth does not support VLAN packets as this action is never called
2798c2ecf20Sopenharmony_ci * for them.
2808c2ecf20Sopenharmony_ci */
2818c2ecf20Sopenharmony_cistatic int pop_eth(struct sk_buff *skb, struct sw_flow_key *key)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	int err;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	err = skb_eth_pop(skb);
2868c2ecf20Sopenharmony_ci	if (err)
2878c2ecf20Sopenharmony_ci		return err;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	/* safe right before invalidate_flow_key */
2908c2ecf20Sopenharmony_ci	key->mac_proto = MAC_PROTO_NONE;
2918c2ecf20Sopenharmony_ci	invalidate_flow_key(key);
2928c2ecf20Sopenharmony_ci	return 0;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic int push_eth(struct sk_buff *skb, struct sw_flow_key *key,
2968c2ecf20Sopenharmony_ci		    const struct ovs_action_push_eth *ethh)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	int err;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	err = skb_eth_push(skb, ethh->addresses.eth_dst,
3018c2ecf20Sopenharmony_ci			   ethh->addresses.eth_src);
3028c2ecf20Sopenharmony_ci	if (err)
3038c2ecf20Sopenharmony_ci		return err;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/* safe right before invalidate_flow_key */
3068c2ecf20Sopenharmony_ci	key->mac_proto = MAC_PROTO_ETHERNET;
3078c2ecf20Sopenharmony_ci	invalidate_flow_key(key);
3088c2ecf20Sopenharmony_ci	return 0;
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic int push_nsh(struct sk_buff *skb, struct sw_flow_key *key,
3128c2ecf20Sopenharmony_ci		    const struct nshhdr *nh)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	int err;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	err = nsh_push(skb, nh);
3178c2ecf20Sopenharmony_ci	if (err)
3188c2ecf20Sopenharmony_ci		return err;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/* safe right before invalidate_flow_key */
3218c2ecf20Sopenharmony_ci	key->mac_proto = MAC_PROTO_NONE;
3228c2ecf20Sopenharmony_ci	invalidate_flow_key(key);
3238c2ecf20Sopenharmony_ci	return 0;
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	int err;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	err = nsh_pop(skb);
3318c2ecf20Sopenharmony_ci	if (err)
3328c2ecf20Sopenharmony_ci		return err;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	/* safe right before invalidate_flow_key */
3358c2ecf20Sopenharmony_ci	if (skb->protocol == htons(ETH_P_TEB))
3368c2ecf20Sopenharmony_ci		key->mac_proto = MAC_PROTO_ETHERNET;
3378c2ecf20Sopenharmony_ci	else
3388c2ecf20Sopenharmony_ci		key->mac_proto = MAC_PROTO_NONE;
3398c2ecf20Sopenharmony_ci	invalidate_flow_key(key);
3408c2ecf20Sopenharmony_ci	return 0;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh,
3448c2ecf20Sopenharmony_ci				  __be32 addr, __be32 new_addr)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	int transport_len = skb->len - skb_transport_offset(skb);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (nh->frag_off & htons(IP_OFFSET))
3498c2ecf20Sopenharmony_ci		return;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	if (nh->protocol == IPPROTO_TCP) {
3528c2ecf20Sopenharmony_ci		if (likely(transport_len >= sizeof(struct tcphdr)))
3538c2ecf20Sopenharmony_ci			inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb,
3548c2ecf20Sopenharmony_ci						 addr, new_addr, true);
3558c2ecf20Sopenharmony_ci	} else if (nh->protocol == IPPROTO_UDP) {
3568c2ecf20Sopenharmony_ci		if (likely(transport_len >= sizeof(struct udphdr))) {
3578c2ecf20Sopenharmony_ci			struct udphdr *uh = udp_hdr(skb);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci			if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
3608c2ecf20Sopenharmony_ci				inet_proto_csum_replace4(&uh->check, skb,
3618c2ecf20Sopenharmony_ci							 addr, new_addr, true);
3628c2ecf20Sopenharmony_ci				if (!uh->check)
3638c2ecf20Sopenharmony_ci					uh->check = CSUM_MANGLED_0;
3648c2ecf20Sopenharmony_ci			}
3658c2ecf20Sopenharmony_ci		}
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
3708c2ecf20Sopenharmony_ci			__be32 *addr, __be32 new_addr)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	update_ip_l4_checksum(skb, nh, *addr, new_addr);
3738c2ecf20Sopenharmony_ci	csum_replace4(&nh->check, *addr, new_addr);
3748c2ecf20Sopenharmony_ci	skb_clear_hash(skb);
3758c2ecf20Sopenharmony_ci	ovs_ct_clear(skb, NULL);
3768c2ecf20Sopenharmony_ci	*addr = new_addr;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto,
3808c2ecf20Sopenharmony_ci				 __be32 addr[4], const __be32 new_addr[4])
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	int transport_len = skb->len - skb_transport_offset(skb);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (l4_proto == NEXTHDR_TCP) {
3858c2ecf20Sopenharmony_ci		if (likely(transport_len >= sizeof(struct tcphdr)))
3868c2ecf20Sopenharmony_ci			inet_proto_csum_replace16(&tcp_hdr(skb)->check, skb,
3878c2ecf20Sopenharmony_ci						  addr, new_addr, true);
3888c2ecf20Sopenharmony_ci	} else if (l4_proto == NEXTHDR_UDP) {
3898c2ecf20Sopenharmony_ci		if (likely(transport_len >= sizeof(struct udphdr))) {
3908c2ecf20Sopenharmony_ci			struct udphdr *uh = udp_hdr(skb);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci			if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
3938c2ecf20Sopenharmony_ci				inet_proto_csum_replace16(&uh->check, skb,
3948c2ecf20Sopenharmony_ci							  addr, new_addr, true);
3958c2ecf20Sopenharmony_ci				if (!uh->check)
3968c2ecf20Sopenharmony_ci					uh->check = CSUM_MANGLED_0;
3978c2ecf20Sopenharmony_ci			}
3988c2ecf20Sopenharmony_ci		}
3998c2ecf20Sopenharmony_ci	} else if (l4_proto == NEXTHDR_ICMP) {
4008c2ecf20Sopenharmony_ci		if (likely(transport_len >= sizeof(struct icmp6hdr)))
4018c2ecf20Sopenharmony_ci			inet_proto_csum_replace16(&icmp6_hdr(skb)->icmp6_cksum,
4028c2ecf20Sopenharmony_ci						  skb, addr, new_addr, true);
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic void mask_ipv6_addr(const __be32 old[4], const __be32 addr[4],
4078c2ecf20Sopenharmony_ci			   const __be32 mask[4], __be32 masked[4])
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	masked[0] = OVS_MASKED(old[0], addr[0], mask[0]);
4108c2ecf20Sopenharmony_ci	masked[1] = OVS_MASKED(old[1], addr[1], mask[1]);
4118c2ecf20Sopenharmony_ci	masked[2] = OVS_MASKED(old[2], addr[2], mask[2]);
4128c2ecf20Sopenharmony_ci	masked[3] = OVS_MASKED(old[3], addr[3], mask[3]);
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto,
4168c2ecf20Sopenharmony_ci			  __be32 addr[4], const __be32 new_addr[4],
4178c2ecf20Sopenharmony_ci			  bool recalculate_csum)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	if (recalculate_csum)
4208c2ecf20Sopenharmony_ci		update_ipv6_checksum(skb, l4_proto, addr, new_addr);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	skb_clear_hash(skb);
4238c2ecf20Sopenharmony_ci	ovs_ct_clear(skb, NULL);
4248c2ecf20Sopenharmony_ci	memcpy(addr, new_addr, sizeof(__be32[4]));
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic void set_ipv6_dsfield(struct sk_buff *skb, struct ipv6hdr *nh, u8 ipv6_tclass, u8 mask)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	u8 old_ipv6_tclass = ipv6_get_dsfield(nh);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	ipv6_tclass = OVS_MASKED(old_ipv6_tclass, ipv6_tclass, mask);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_COMPLETE)
4348c2ecf20Sopenharmony_ci		csum_replace(&skb->csum, (__force __wsum)(old_ipv6_tclass << 12),
4358c2ecf20Sopenharmony_ci			     (__force __wsum)(ipv6_tclass << 12));
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	ipv6_change_dsfield(nh, ~mask, ipv6_tclass);
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic void set_ipv6_fl(struct sk_buff *skb, struct ipv6hdr *nh, u32 fl, u32 mask)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	u32 ofl;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	ofl = nh->flow_lbl[0] << 16 |  nh->flow_lbl[1] << 8 |  nh->flow_lbl[2];
4458c2ecf20Sopenharmony_ci	fl = OVS_MASKED(ofl, fl, mask);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	/* Bits 21-24 are always unmasked, so this retains their values. */
4488c2ecf20Sopenharmony_ci	nh->flow_lbl[0] = (u8)(fl >> 16);
4498c2ecf20Sopenharmony_ci	nh->flow_lbl[1] = (u8)(fl >> 8);
4508c2ecf20Sopenharmony_ci	nh->flow_lbl[2] = (u8)fl;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_COMPLETE)
4538c2ecf20Sopenharmony_ci		csum_replace(&skb->csum, (__force __wsum)htonl(ofl), (__force __wsum)htonl(fl));
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cistatic void set_ipv6_ttl(struct sk_buff *skb, struct ipv6hdr *nh, u8 new_ttl, u8 mask)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci	new_ttl = OVS_MASKED(nh->hop_limit, new_ttl, mask);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_COMPLETE)
4618c2ecf20Sopenharmony_ci		csum_replace(&skb->csum, (__force __wsum)(nh->hop_limit << 8),
4628c2ecf20Sopenharmony_ci			     (__force __wsum)(new_ttl << 8));
4638c2ecf20Sopenharmony_ci	nh->hop_limit = new_ttl;
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cistatic void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl,
4678c2ecf20Sopenharmony_ci		       u8 mask)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	new_ttl = OVS_MASKED(nh->ttl, new_ttl, mask);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8));
4728c2ecf20Sopenharmony_ci	nh->ttl = new_ttl;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic int set_ipv4(struct sk_buff *skb, struct sw_flow_key *flow_key,
4768c2ecf20Sopenharmony_ci		    const struct ovs_key_ipv4 *key,
4778c2ecf20Sopenharmony_ci		    const struct ovs_key_ipv4 *mask)
4788c2ecf20Sopenharmony_ci{
4798c2ecf20Sopenharmony_ci	struct iphdr *nh;
4808c2ecf20Sopenharmony_ci	__be32 new_addr;
4818c2ecf20Sopenharmony_ci	int err;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	err = skb_ensure_writable(skb, skb_network_offset(skb) +
4848c2ecf20Sopenharmony_ci				  sizeof(struct iphdr));
4858c2ecf20Sopenharmony_ci	if (unlikely(err))
4868c2ecf20Sopenharmony_ci		return err;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	nh = ip_hdr(skb);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	/* Setting an IP addresses is typically only a side effect of
4918c2ecf20Sopenharmony_ci	 * matching on them in the current userspace implementation, so it
4928c2ecf20Sopenharmony_ci	 * makes sense to check if the value actually changed.
4938c2ecf20Sopenharmony_ci	 */
4948c2ecf20Sopenharmony_ci	if (mask->ipv4_src) {
4958c2ecf20Sopenharmony_ci		new_addr = OVS_MASKED(nh->saddr, key->ipv4_src, mask->ipv4_src);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci		if (unlikely(new_addr != nh->saddr)) {
4988c2ecf20Sopenharmony_ci			set_ip_addr(skb, nh, &nh->saddr, new_addr);
4998c2ecf20Sopenharmony_ci			flow_key->ipv4.addr.src = new_addr;
5008c2ecf20Sopenharmony_ci		}
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci	if (mask->ipv4_dst) {
5038c2ecf20Sopenharmony_ci		new_addr = OVS_MASKED(nh->daddr, key->ipv4_dst, mask->ipv4_dst);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		if (unlikely(new_addr != nh->daddr)) {
5068c2ecf20Sopenharmony_ci			set_ip_addr(skb, nh, &nh->daddr, new_addr);
5078c2ecf20Sopenharmony_ci			flow_key->ipv4.addr.dst = new_addr;
5088c2ecf20Sopenharmony_ci		}
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci	if (mask->ipv4_tos) {
5118c2ecf20Sopenharmony_ci		ipv4_change_dsfield(nh, ~mask->ipv4_tos, key->ipv4_tos);
5128c2ecf20Sopenharmony_ci		flow_key->ip.tos = nh->tos;
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci	if (mask->ipv4_ttl) {
5158c2ecf20Sopenharmony_ci		set_ip_ttl(skb, nh, key->ipv4_ttl, mask->ipv4_ttl);
5168c2ecf20Sopenharmony_ci		flow_key->ip.ttl = nh->ttl;
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	return 0;
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic bool is_ipv6_mask_nonzero(const __be32 addr[4])
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	return !!(addr[0] | addr[1] | addr[2] | addr[3]);
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key,
5288c2ecf20Sopenharmony_ci		    const struct ovs_key_ipv6 *key,
5298c2ecf20Sopenharmony_ci		    const struct ovs_key_ipv6 *mask)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	struct ipv6hdr *nh;
5328c2ecf20Sopenharmony_ci	int err;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	err = skb_ensure_writable(skb, skb_network_offset(skb) +
5358c2ecf20Sopenharmony_ci				  sizeof(struct ipv6hdr));
5368c2ecf20Sopenharmony_ci	if (unlikely(err))
5378c2ecf20Sopenharmony_ci		return err;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	nh = ipv6_hdr(skb);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	/* Setting an IP addresses is typically only a side effect of
5428c2ecf20Sopenharmony_ci	 * matching on them in the current userspace implementation, so it
5438c2ecf20Sopenharmony_ci	 * makes sense to check if the value actually changed.
5448c2ecf20Sopenharmony_ci	 */
5458c2ecf20Sopenharmony_ci	if (is_ipv6_mask_nonzero(mask->ipv6_src)) {
5468c2ecf20Sopenharmony_ci		__be32 *saddr = (__be32 *)&nh->saddr;
5478c2ecf20Sopenharmony_ci		__be32 masked[4];
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci		mask_ipv6_addr(saddr, key->ipv6_src, mask->ipv6_src, masked);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci		if (unlikely(memcmp(saddr, masked, sizeof(masked)))) {
5528c2ecf20Sopenharmony_ci			set_ipv6_addr(skb, flow_key->ip.proto, saddr, masked,
5538c2ecf20Sopenharmony_ci				      true);
5548c2ecf20Sopenharmony_ci			memcpy(&flow_key->ipv6.addr.src, masked,
5558c2ecf20Sopenharmony_ci			       sizeof(flow_key->ipv6.addr.src));
5568c2ecf20Sopenharmony_ci		}
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci	if (is_ipv6_mask_nonzero(mask->ipv6_dst)) {
5598c2ecf20Sopenharmony_ci		unsigned int offset = 0;
5608c2ecf20Sopenharmony_ci		int flags = IP6_FH_F_SKIP_RH;
5618c2ecf20Sopenharmony_ci		bool recalc_csum = true;
5628c2ecf20Sopenharmony_ci		__be32 *daddr = (__be32 *)&nh->daddr;
5638c2ecf20Sopenharmony_ci		__be32 masked[4];
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci		mask_ipv6_addr(daddr, key->ipv6_dst, mask->ipv6_dst, masked);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci		if (unlikely(memcmp(daddr, masked, sizeof(masked)))) {
5688c2ecf20Sopenharmony_ci			if (ipv6_ext_hdr(nh->nexthdr))
5698c2ecf20Sopenharmony_ci				recalc_csum = (ipv6_find_hdr(skb, &offset,
5708c2ecf20Sopenharmony_ci							     NEXTHDR_ROUTING,
5718c2ecf20Sopenharmony_ci							     NULL, &flags)
5728c2ecf20Sopenharmony_ci					       != NEXTHDR_ROUTING);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci			set_ipv6_addr(skb, flow_key->ip.proto, daddr, masked,
5758c2ecf20Sopenharmony_ci				      recalc_csum);
5768c2ecf20Sopenharmony_ci			memcpy(&flow_key->ipv6.addr.dst, masked,
5778c2ecf20Sopenharmony_ci			       sizeof(flow_key->ipv6.addr.dst));
5788c2ecf20Sopenharmony_ci		}
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci	if (mask->ipv6_tclass) {
5818c2ecf20Sopenharmony_ci		set_ipv6_dsfield(skb, nh, key->ipv6_tclass, mask->ipv6_tclass);
5828c2ecf20Sopenharmony_ci		flow_key->ip.tos = ipv6_get_dsfield(nh);
5838c2ecf20Sopenharmony_ci	}
5848c2ecf20Sopenharmony_ci	if (mask->ipv6_label) {
5858c2ecf20Sopenharmony_ci		set_ipv6_fl(skb, nh, ntohl(key->ipv6_label),
5868c2ecf20Sopenharmony_ci			    ntohl(mask->ipv6_label));
5878c2ecf20Sopenharmony_ci		flow_key->ipv6.label =
5888c2ecf20Sopenharmony_ci		    *(__be32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL);
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci	if (mask->ipv6_hlimit) {
5918c2ecf20Sopenharmony_ci		set_ipv6_ttl(skb, nh, key->ipv6_hlimit, mask->ipv6_hlimit);
5928c2ecf20Sopenharmony_ci		flow_key->ip.ttl = nh->hop_limit;
5938c2ecf20Sopenharmony_ci	}
5948c2ecf20Sopenharmony_ci	return 0;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic int set_nsh(struct sk_buff *skb, struct sw_flow_key *flow_key,
5988c2ecf20Sopenharmony_ci		   const struct nlattr *a)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	struct nshhdr *nh;
6018c2ecf20Sopenharmony_ci	size_t length;
6028c2ecf20Sopenharmony_ci	int err;
6038c2ecf20Sopenharmony_ci	u8 flags;
6048c2ecf20Sopenharmony_ci	u8 ttl;
6058c2ecf20Sopenharmony_ci	int i;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	struct ovs_key_nsh key;
6088c2ecf20Sopenharmony_ci	struct ovs_key_nsh mask;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	err = nsh_key_from_nlattr(a, &key, &mask);
6118c2ecf20Sopenharmony_ci	if (err)
6128c2ecf20Sopenharmony_ci		return err;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	/* Make sure the NSH base header is there */
6158c2ecf20Sopenharmony_ci	if (!pskb_may_pull(skb, skb_network_offset(skb) + NSH_BASE_HDR_LEN))
6168c2ecf20Sopenharmony_ci		return -ENOMEM;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	nh = nsh_hdr(skb);
6198c2ecf20Sopenharmony_ci	length = nsh_hdr_len(nh);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	/* Make sure the whole NSH header is there */
6228c2ecf20Sopenharmony_ci	err = skb_ensure_writable(skb, skb_network_offset(skb) +
6238c2ecf20Sopenharmony_ci				       length);
6248c2ecf20Sopenharmony_ci	if (unlikely(err))
6258c2ecf20Sopenharmony_ci		return err;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	nh = nsh_hdr(skb);
6288c2ecf20Sopenharmony_ci	skb_postpull_rcsum(skb, nh, length);
6298c2ecf20Sopenharmony_ci	flags = nsh_get_flags(nh);
6308c2ecf20Sopenharmony_ci	flags = OVS_MASKED(flags, key.base.flags, mask.base.flags);
6318c2ecf20Sopenharmony_ci	flow_key->nsh.base.flags = flags;
6328c2ecf20Sopenharmony_ci	ttl = nsh_get_ttl(nh);
6338c2ecf20Sopenharmony_ci	ttl = OVS_MASKED(ttl, key.base.ttl, mask.base.ttl);
6348c2ecf20Sopenharmony_ci	flow_key->nsh.base.ttl = ttl;
6358c2ecf20Sopenharmony_ci	nsh_set_flags_and_ttl(nh, flags, ttl);
6368c2ecf20Sopenharmony_ci	nh->path_hdr = OVS_MASKED(nh->path_hdr, key.base.path_hdr,
6378c2ecf20Sopenharmony_ci				  mask.base.path_hdr);
6388c2ecf20Sopenharmony_ci	flow_key->nsh.base.path_hdr = nh->path_hdr;
6398c2ecf20Sopenharmony_ci	switch (nh->mdtype) {
6408c2ecf20Sopenharmony_ci	case NSH_M_TYPE1:
6418c2ecf20Sopenharmony_ci		for (i = 0; i < NSH_MD1_CONTEXT_SIZE; i++) {
6428c2ecf20Sopenharmony_ci			nh->md1.context[i] =
6438c2ecf20Sopenharmony_ci			    OVS_MASKED(nh->md1.context[i], key.context[i],
6448c2ecf20Sopenharmony_ci				       mask.context[i]);
6458c2ecf20Sopenharmony_ci		}
6468c2ecf20Sopenharmony_ci		memcpy(flow_key->nsh.context, nh->md1.context,
6478c2ecf20Sopenharmony_ci		       sizeof(nh->md1.context));
6488c2ecf20Sopenharmony_ci		break;
6498c2ecf20Sopenharmony_ci	case NSH_M_TYPE2:
6508c2ecf20Sopenharmony_ci		memset(flow_key->nsh.context, 0,
6518c2ecf20Sopenharmony_ci		       sizeof(flow_key->nsh.context));
6528c2ecf20Sopenharmony_ci		break;
6538c2ecf20Sopenharmony_ci	default:
6548c2ecf20Sopenharmony_ci		return -EINVAL;
6558c2ecf20Sopenharmony_ci	}
6568c2ecf20Sopenharmony_ci	skb_postpush_rcsum(skb, nh, length);
6578c2ecf20Sopenharmony_ci	return 0;
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci/* Must follow skb_ensure_writable() since that can move the skb data. */
6618c2ecf20Sopenharmony_cistatic void set_tp_port(struct sk_buff *skb, __be16 *port,
6628c2ecf20Sopenharmony_ci			__be16 new_port, __sum16 *check)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	ovs_ct_clear(skb, NULL);
6658c2ecf20Sopenharmony_ci	inet_proto_csum_replace2(check, skb, *port, new_port, false);
6668c2ecf20Sopenharmony_ci	*port = new_port;
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_cistatic int set_udp(struct sk_buff *skb, struct sw_flow_key *flow_key,
6708c2ecf20Sopenharmony_ci		   const struct ovs_key_udp *key,
6718c2ecf20Sopenharmony_ci		   const struct ovs_key_udp *mask)
6728c2ecf20Sopenharmony_ci{
6738c2ecf20Sopenharmony_ci	struct udphdr *uh;
6748c2ecf20Sopenharmony_ci	__be16 src, dst;
6758c2ecf20Sopenharmony_ci	int err;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	err = skb_ensure_writable(skb, skb_transport_offset(skb) +
6788c2ecf20Sopenharmony_ci				  sizeof(struct udphdr));
6798c2ecf20Sopenharmony_ci	if (unlikely(err))
6808c2ecf20Sopenharmony_ci		return err;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	uh = udp_hdr(skb);
6838c2ecf20Sopenharmony_ci	/* Either of the masks is non-zero, so do not bother checking them. */
6848c2ecf20Sopenharmony_ci	src = OVS_MASKED(uh->source, key->udp_src, mask->udp_src);
6858c2ecf20Sopenharmony_ci	dst = OVS_MASKED(uh->dest, key->udp_dst, mask->udp_dst);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	if (uh->check && skb->ip_summed != CHECKSUM_PARTIAL) {
6888c2ecf20Sopenharmony_ci		if (likely(src != uh->source)) {
6898c2ecf20Sopenharmony_ci			set_tp_port(skb, &uh->source, src, &uh->check);
6908c2ecf20Sopenharmony_ci			flow_key->tp.src = src;
6918c2ecf20Sopenharmony_ci		}
6928c2ecf20Sopenharmony_ci		if (likely(dst != uh->dest)) {
6938c2ecf20Sopenharmony_ci			set_tp_port(skb, &uh->dest, dst, &uh->check);
6948c2ecf20Sopenharmony_ci			flow_key->tp.dst = dst;
6958c2ecf20Sopenharmony_ci		}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci		if (unlikely(!uh->check))
6988c2ecf20Sopenharmony_ci			uh->check = CSUM_MANGLED_0;
6998c2ecf20Sopenharmony_ci	} else {
7008c2ecf20Sopenharmony_ci		uh->source = src;
7018c2ecf20Sopenharmony_ci		uh->dest = dst;
7028c2ecf20Sopenharmony_ci		flow_key->tp.src = src;
7038c2ecf20Sopenharmony_ci		flow_key->tp.dst = dst;
7048c2ecf20Sopenharmony_ci		ovs_ct_clear(skb, NULL);
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	skb_clear_hash(skb);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	return 0;
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic int set_tcp(struct sk_buff *skb, struct sw_flow_key *flow_key,
7138c2ecf20Sopenharmony_ci		   const struct ovs_key_tcp *key,
7148c2ecf20Sopenharmony_ci		   const struct ovs_key_tcp *mask)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	struct tcphdr *th;
7178c2ecf20Sopenharmony_ci	__be16 src, dst;
7188c2ecf20Sopenharmony_ci	int err;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	err = skb_ensure_writable(skb, skb_transport_offset(skb) +
7218c2ecf20Sopenharmony_ci				  sizeof(struct tcphdr));
7228c2ecf20Sopenharmony_ci	if (unlikely(err))
7238c2ecf20Sopenharmony_ci		return err;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	th = tcp_hdr(skb);
7268c2ecf20Sopenharmony_ci	src = OVS_MASKED(th->source, key->tcp_src, mask->tcp_src);
7278c2ecf20Sopenharmony_ci	if (likely(src != th->source)) {
7288c2ecf20Sopenharmony_ci		set_tp_port(skb, &th->source, src, &th->check);
7298c2ecf20Sopenharmony_ci		flow_key->tp.src = src;
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci	dst = OVS_MASKED(th->dest, key->tcp_dst, mask->tcp_dst);
7328c2ecf20Sopenharmony_ci	if (likely(dst != th->dest)) {
7338c2ecf20Sopenharmony_ci		set_tp_port(skb, &th->dest, dst, &th->check);
7348c2ecf20Sopenharmony_ci		flow_key->tp.dst = dst;
7358c2ecf20Sopenharmony_ci	}
7368c2ecf20Sopenharmony_ci	skb_clear_hash(skb);
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	return 0;
7398c2ecf20Sopenharmony_ci}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_cistatic int set_sctp(struct sk_buff *skb, struct sw_flow_key *flow_key,
7428c2ecf20Sopenharmony_ci		    const struct ovs_key_sctp *key,
7438c2ecf20Sopenharmony_ci		    const struct ovs_key_sctp *mask)
7448c2ecf20Sopenharmony_ci{
7458c2ecf20Sopenharmony_ci	unsigned int sctphoff = skb_transport_offset(skb);
7468c2ecf20Sopenharmony_ci	struct sctphdr *sh;
7478c2ecf20Sopenharmony_ci	__le32 old_correct_csum, new_csum, old_csum;
7488c2ecf20Sopenharmony_ci	int err;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	err = skb_ensure_writable(skb, sctphoff + sizeof(struct sctphdr));
7518c2ecf20Sopenharmony_ci	if (unlikely(err))
7528c2ecf20Sopenharmony_ci		return err;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	sh = sctp_hdr(skb);
7558c2ecf20Sopenharmony_ci	old_csum = sh->checksum;
7568c2ecf20Sopenharmony_ci	old_correct_csum = sctp_compute_cksum(skb, sctphoff);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	sh->source = OVS_MASKED(sh->source, key->sctp_src, mask->sctp_src);
7598c2ecf20Sopenharmony_ci	sh->dest = OVS_MASKED(sh->dest, key->sctp_dst, mask->sctp_dst);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	new_csum = sctp_compute_cksum(skb, sctphoff);
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	/* Carry any checksum errors through. */
7648c2ecf20Sopenharmony_ci	sh->checksum = old_csum ^ old_correct_csum ^ new_csum;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	skb_clear_hash(skb);
7678c2ecf20Sopenharmony_ci	ovs_ct_clear(skb, NULL);
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	flow_key->tp.src = sh->source;
7708c2ecf20Sopenharmony_ci	flow_key->tp.dst = sh->dest;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	return 0;
7738c2ecf20Sopenharmony_ci}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cistatic int ovs_vport_output(struct net *net, struct sock *sk,
7768c2ecf20Sopenharmony_ci			    struct sk_buff *skb)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	struct ovs_frag_data *data = this_cpu_ptr(&ovs_frag_data_storage);
7798c2ecf20Sopenharmony_ci	struct vport *vport = data->vport;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	if (skb_cow_head(skb, data->l2_len) < 0) {
7828c2ecf20Sopenharmony_ci		kfree_skb(skb);
7838c2ecf20Sopenharmony_ci		return -ENOMEM;
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	__skb_dst_copy(skb, data->dst);
7878c2ecf20Sopenharmony_ci	*OVS_CB(skb) = data->cb;
7888c2ecf20Sopenharmony_ci	skb->inner_protocol = data->inner_protocol;
7898c2ecf20Sopenharmony_ci	if (data->vlan_tci & VLAN_CFI_MASK)
7908c2ecf20Sopenharmony_ci		__vlan_hwaccel_put_tag(skb, data->vlan_proto, data->vlan_tci & ~VLAN_CFI_MASK);
7918c2ecf20Sopenharmony_ci	else
7928c2ecf20Sopenharmony_ci		__vlan_hwaccel_clear_tag(skb);
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	/* Reconstruct the MAC header.  */
7958c2ecf20Sopenharmony_ci	skb_push(skb, data->l2_len);
7968c2ecf20Sopenharmony_ci	memcpy(skb->data, &data->l2_data, data->l2_len);
7978c2ecf20Sopenharmony_ci	skb_postpush_rcsum(skb, skb->data, data->l2_len);
7988c2ecf20Sopenharmony_ci	skb_reset_mac_header(skb);
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	if (eth_p_mpls(skb->protocol)) {
8018c2ecf20Sopenharmony_ci		skb->inner_network_header = skb->network_header;
8028c2ecf20Sopenharmony_ci		skb_set_network_header(skb, data->network_offset);
8038c2ecf20Sopenharmony_ci		skb_reset_mac_len(skb);
8048c2ecf20Sopenharmony_ci	}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	ovs_vport_send(vport, skb, data->mac_proto);
8078c2ecf20Sopenharmony_ci	return 0;
8088c2ecf20Sopenharmony_ci}
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_cistatic unsigned int
8118c2ecf20Sopenharmony_ciovs_dst_get_mtu(const struct dst_entry *dst)
8128c2ecf20Sopenharmony_ci{
8138c2ecf20Sopenharmony_ci	return dst->dev->mtu;
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_cistatic struct dst_ops ovs_dst_ops = {
8178c2ecf20Sopenharmony_ci	.family = AF_UNSPEC,
8188c2ecf20Sopenharmony_ci	.mtu = ovs_dst_get_mtu,
8198c2ecf20Sopenharmony_ci};
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci/* prepare_frag() is called once per (larger-than-MTU) frame; its inverse is
8228c2ecf20Sopenharmony_ci * ovs_vport_output(), which is called once per fragmented packet.
8238c2ecf20Sopenharmony_ci */
8248c2ecf20Sopenharmony_cistatic void prepare_frag(struct vport *vport, struct sk_buff *skb,
8258c2ecf20Sopenharmony_ci			 u16 orig_network_offset, u8 mac_proto)
8268c2ecf20Sopenharmony_ci{
8278c2ecf20Sopenharmony_ci	unsigned int hlen = skb_network_offset(skb);
8288c2ecf20Sopenharmony_ci	struct ovs_frag_data *data;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	data = this_cpu_ptr(&ovs_frag_data_storage);
8318c2ecf20Sopenharmony_ci	data->dst = skb->_skb_refdst;
8328c2ecf20Sopenharmony_ci	data->vport = vport;
8338c2ecf20Sopenharmony_ci	data->cb = *OVS_CB(skb);
8348c2ecf20Sopenharmony_ci	data->inner_protocol = skb->inner_protocol;
8358c2ecf20Sopenharmony_ci	data->network_offset = orig_network_offset;
8368c2ecf20Sopenharmony_ci	if (skb_vlan_tag_present(skb))
8378c2ecf20Sopenharmony_ci		data->vlan_tci = skb_vlan_tag_get(skb) | VLAN_CFI_MASK;
8388c2ecf20Sopenharmony_ci	else
8398c2ecf20Sopenharmony_ci		data->vlan_tci = 0;
8408c2ecf20Sopenharmony_ci	data->vlan_proto = skb->vlan_proto;
8418c2ecf20Sopenharmony_ci	data->mac_proto = mac_proto;
8428c2ecf20Sopenharmony_ci	data->l2_len = hlen;
8438c2ecf20Sopenharmony_ci	memcpy(&data->l2_data, skb->data, hlen);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
8468c2ecf20Sopenharmony_ci	skb_pull(skb, hlen);
8478c2ecf20Sopenharmony_ci}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_cistatic void ovs_fragment(struct net *net, struct vport *vport,
8508c2ecf20Sopenharmony_ci			 struct sk_buff *skb, u16 mru,
8518c2ecf20Sopenharmony_ci			 struct sw_flow_key *key)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	u16 orig_network_offset = 0;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	if (eth_p_mpls(skb->protocol)) {
8568c2ecf20Sopenharmony_ci		orig_network_offset = skb_network_offset(skb);
8578c2ecf20Sopenharmony_ci		skb->network_header = skb->inner_network_header;
8588c2ecf20Sopenharmony_ci	}
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	if (skb_network_offset(skb) > MAX_L2_LEN) {
8618c2ecf20Sopenharmony_ci		OVS_NLERR(1, "L2 header too long to fragment");
8628c2ecf20Sopenharmony_ci		goto err;
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	if (key->eth.type == htons(ETH_P_IP)) {
8668c2ecf20Sopenharmony_ci		struct rtable ovs_rt = { 0 };
8678c2ecf20Sopenharmony_ci		unsigned long orig_dst;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci		prepare_frag(vport, skb, orig_network_offset,
8708c2ecf20Sopenharmony_ci			     ovs_key_mac_proto(key));
8718c2ecf20Sopenharmony_ci		dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1,
8728c2ecf20Sopenharmony_ci			 DST_OBSOLETE_NONE, DST_NOCOUNT);
8738c2ecf20Sopenharmony_ci		ovs_rt.dst.dev = vport->dev;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci		orig_dst = skb->_skb_refdst;
8768c2ecf20Sopenharmony_ci		skb_dst_set_noref(skb, &ovs_rt.dst);
8778c2ecf20Sopenharmony_ci		IPCB(skb)->frag_max_size = mru;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci		ip_do_fragment(net, skb->sk, skb, ovs_vport_output);
8808c2ecf20Sopenharmony_ci		refdst_drop(orig_dst);
8818c2ecf20Sopenharmony_ci	} else if (key->eth.type == htons(ETH_P_IPV6)) {
8828c2ecf20Sopenharmony_ci		unsigned long orig_dst;
8838c2ecf20Sopenharmony_ci		struct rt6_info ovs_rt;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci		prepare_frag(vport, skb, orig_network_offset,
8868c2ecf20Sopenharmony_ci			     ovs_key_mac_proto(key));
8878c2ecf20Sopenharmony_ci		memset(&ovs_rt, 0, sizeof(ovs_rt));
8888c2ecf20Sopenharmony_ci		dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1,
8898c2ecf20Sopenharmony_ci			 DST_OBSOLETE_NONE, DST_NOCOUNT);
8908c2ecf20Sopenharmony_ci		ovs_rt.dst.dev = vport->dev;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci		orig_dst = skb->_skb_refdst;
8938c2ecf20Sopenharmony_ci		skb_dst_set_noref(skb, &ovs_rt.dst);
8948c2ecf20Sopenharmony_ci		IP6CB(skb)->frag_max_size = mru;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci		ipv6_stub->ipv6_fragment(net, skb->sk, skb, ovs_vport_output);
8978c2ecf20Sopenharmony_ci		refdst_drop(orig_dst);
8988c2ecf20Sopenharmony_ci	} else {
8998c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.",
9008c2ecf20Sopenharmony_ci			  ovs_vport_name(vport), ntohs(key->eth.type), mru,
9018c2ecf20Sopenharmony_ci			  vport->dev->mtu);
9028c2ecf20Sopenharmony_ci		goto err;
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	return;
9068c2ecf20Sopenharmony_cierr:
9078c2ecf20Sopenharmony_ci	kfree_skb(skb);
9088c2ecf20Sopenharmony_ci}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_cistatic void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
9118c2ecf20Sopenharmony_ci		      struct sw_flow_key *key)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	struct vport *vport = ovs_vport_rcu(dp, out_port);
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	if (likely(vport)) {
9168c2ecf20Sopenharmony_ci		u16 mru = OVS_CB(skb)->mru;
9178c2ecf20Sopenharmony_ci		u32 cutlen = OVS_CB(skb)->cutlen;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci		if (unlikely(cutlen > 0)) {
9208c2ecf20Sopenharmony_ci			if (skb->len - cutlen > ovs_mac_header_len(key))
9218c2ecf20Sopenharmony_ci				pskb_trim(skb, skb->len - cutlen);
9228c2ecf20Sopenharmony_ci			else
9238c2ecf20Sopenharmony_ci				pskb_trim(skb, ovs_mac_header_len(key));
9248c2ecf20Sopenharmony_ci		}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci		if (likely(!mru ||
9278c2ecf20Sopenharmony_ci		           (skb->len <= mru + vport->dev->hard_header_len))) {
9288c2ecf20Sopenharmony_ci			ovs_vport_send(vport, skb, ovs_key_mac_proto(key));
9298c2ecf20Sopenharmony_ci		} else if (mru <= vport->dev->mtu) {
9308c2ecf20Sopenharmony_ci			struct net *net = read_pnet(&dp->net);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci			ovs_fragment(net, vport, skb, mru, key);
9338c2ecf20Sopenharmony_ci		} else {
9348c2ecf20Sopenharmony_ci			kfree_skb(skb);
9358c2ecf20Sopenharmony_ci		}
9368c2ecf20Sopenharmony_ci	} else {
9378c2ecf20Sopenharmony_ci		kfree_skb(skb);
9388c2ecf20Sopenharmony_ci	}
9398c2ecf20Sopenharmony_ci}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_cistatic int output_userspace(struct datapath *dp, struct sk_buff *skb,
9428c2ecf20Sopenharmony_ci			    struct sw_flow_key *key, const struct nlattr *attr,
9438c2ecf20Sopenharmony_ci			    const struct nlattr *actions, int actions_len,
9448c2ecf20Sopenharmony_ci			    uint32_t cutlen)
9458c2ecf20Sopenharmony_ci{
9468c2ecf20Sopenharmony_ci	struct dp_upcall_info upcall;
9478c2ecf20Sopenharmony_ci	const struct nlattr *a;
9488c2ecf20Sopenharmony_ci	int rem;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	memset(&upcall, 0, sizeof(upcall));
9518c2ecf20Sopenharmony_ci	upcall.cmd = OVS_PACKET_CMD_ACTION;
9528c2ecf20Sopenharmony_ci	upcall.mru = OVS_CB(skb)->mru;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
9558c2ecf20Sopenharmony_ci	     a = nla_next(a, &rem)) {
9568c2ecf20Sopenharmony_ci		switch (nla_type(a)) {
9578c2ecf20Sopenharmony_ci		case OVS_USERSPACE_ATTR_USERDATA:
9588c2ecf20Sopenharmony_ci			upcall.userdata = a;
9598c2ecf20Sopenharmony_ci			break;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci		case OVS_USERSPACE_ATTR_PID:
9628c2ecf20Sopenharmony_ci			upcall.portid = nla_get_u32(a);
9638c2ecf20Sopenharmony_ci			break;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci		case OVS_USERSPACE_ATTR_EGRESS_TUN_PORT: {
9668c2ecf20Sopenharmony_ci			/* Get out tunnel info. */
9678c2ecf20Sopenharmony_ci			struct vport *vport;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci			vport = ovs_vport_rcu(dp, nla_get_u32(a));
9708c2ecf20Sopenharmony_ci			if (vport) {
9718c2ecf20Sopenharmony_ci				int err;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci				err = dev_fill_metadata_dst(vport->dev, skb);
9748c2ecf20Sopenharmony_ci				if (!err)
9758c2ecf20Sopenharmony_ci					upcall.egress_tun_info = skb_tunnel_info(skb);
9768c2ecf20Sopenharmony_ci			}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci			break;
9798c2ecf20Sopenharmony_ci		}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci		case OVS_USERSPACE_ATTR_ACTIONS: {
9828c2ecf20Sopenharmony_ci			/* Include actions. */
9838c2ecf20Sopenharmony_ci			upcall.actions = actions;
9848c2ecf20Sopenharmony_ci			upcall.actions_len = actions_len;
9858c2ecf20Sopenharmony_ci			break;
9868c2ecf20Sopenharmony_ci		}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci		} /* End of switch. */
9898c2ecf20Sopenharmony_ci	}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	return ovs_dp_upcall(dp, skb, key, &upcall, cutlen);
9928c2ecf20Sopenharmony_ci}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_cistatic int dec_ttl_exception_handler(struct datapath *dp, struct sk_buff *skb,
9958c2ecf20Sopenharmony_ci				     struct sw_flow_key *key,
9968c2ecf20Sopenharmony_ci				     const struct nlattr *attr, bool last)
9978c2ecf20Sopenharmony_ci{
9988c2ecf20Sopenharmony_ci	/* The first attribute is always 'OVS_DEC_TTL_ATTR_ACTION'. */
9998c2ecf20Sopenharmony_ci	struct nlattr *actions = nla_data(attr);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	if (nla_len(actions))
10028c2ecf20Sopenharmony_ci		return clone_execute(dp, skb, key, 0, nla_data(actions),
10038c2ecf20Sopenharmony_ci				     nla_len(actions), last, false);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	consume_skb(skb);
10068c2ecf20Sopenharmony_ci	return 0;
10078c2ecf20Sopenharmony_ci}
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci/* When 'last' is true, sample() should always consume the 'skb'.
10108c2ecf20Sopenharmony_ci * Otherwise, sample() should keep 'skb' intact regardless what
10118c2ecf20Sopenharmony_ci * actions are executed within sample().
10128c2ecf20Sopenharmony_ci */
10138c2ecf20Sopenharmony_cistatic int sample(struct datapath *dp, struct sk_buff *skb,
10148c2ecf20Sopenharmony_ci		  struct sw_flow_key *key, const struct nlattr *attr,
10158c2ecf20Sopenharmony_ci		  bool last)
10168c2ecf20Sopenharmony_ci{
10178c2ecf20Sopenharmony_ci	struct nlattr *actions;
10188c2ecf20Sopenharmony_ci	struct nlattr *sample_arg;
10198c2ecf20Sopenharmony_ci	int rem = nla_len(attr);
10208c2ecf20Sopenharmony_ci	const struct sample_arg *arg;
10218c2ecf20Sopenharmony_ci	bool clone_flow_key;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	/* The first action is always 'OVS_SAMPLE_ATTR_ARG'. */
10248c2ecf20Sopenharmony_ci	sample_arg = nla_data(attr);
10258c2ecf20Sopenharmony_ci	arg = nla_data(sample_arg);
10268c2ecf20Sopenharmony_ci	actions = nla_next(sample_arg, &rem);
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	if ((arg->probability != U32_MAX) &&
10298c2ecf20Sopenharmony_ci	    (!arg->probability || prandom_u32() > arg->probability)) {
10308c2ecf20Sopenharmony_ci		if (last)
10318c2ecf20Sopenharmony_ci			consume_skb(skb);
10328c2ecf20Sopenharmony_ci		return 0;
10338c2ecf20Sopenharmony_ci	}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	clone_flow_key = !arg->exec;
10368c2ecf20Sopenharmony_ci	return clone_execute(dp, skb, key, 0, actions, rem, last,
10378c2ecf20Sopenharmony_ci			     clone_flow_key);
10388c2ecf20Sopenharmony_ci}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci/* When 'last' is true, clone() should always consume the 'skb'.
10418c2ecf20Sopenharmony_ci * Otherwise, clone() should keep 'skb' intact regardless what
10428c2ecf20Sopenharmony_ci * actions are executed within clone().
10438c2ecf20Sopenharmony_ci */
10448c2ecf20Sopenharmony_cistatic int clone(struct datapath *dp, struct sk_buff *skb,
10458c2ecf20Sopenharmony_ci		 struct sw_flow_key *key, const struct nlattr *attr,
10468c2ecf20Sopenharmony_ci		 bool last)
10478c2ecf20Sopenharmony_ci{
10488c2ecf20Sopenharmony_ci	struct nlattr *actions;
10498c2ecf20Sopenharmony_ci	struct nlattr *clone_arg;
10508c2ecf20Sopenharmony_ci	int rem = nla_len(attr);
10518c2ecf20Sopenharmony_ci	bool dont_clone_flow_key;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	/* The first action is always 'OVS_CLONE_ATTR_EXEC'. */
10548c2ecf20Sopenharmony_ci	clone_arg = nla_data(attr);
10558c2ecf20Sopenharmony_ci	dont_clone_flow_key = nla_get_u32(clone_arg);
10568c2ecf20Sopenharmony_ci	actions = nla_next(clone_arg, &rem);
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	return clone_execute(dp, skb, key, 0, actions, rem, last,
10598c2ecf20Sopenharmony_ci			     !dont_clone_flow_key);
10608c2ecf20Sopenharmony_ci}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_cistatic void execute_hash(struct sk_buff *skb, struct sw_flow_key *key,
10638c2ecf20Sopenharmony_ci			 const struct nlattr *attr)
10648c2ecf20Sopenharmony_ci{
10658c2ecf20Sopenharmony_ci	struct ovs_action_hash *hash_act = nla_data(attr);
10668c2ecf20Sopenharmony_ci	u32 hash = 0;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	/* OVS_HASH_ALG_L4 is the only possible hash algorithm.  */
10698c2ecf20Sopenharmony_ci	hash = skb_get_hash(skb);
10708c2ecf20Sopenharmony_ci	hash = jhash_1word(hash, hash_act->hash_basis);
10718c2ecf20Sopenharmony_ci	if (!hash)
10728c2ecf20Sopenharmony_ci		hash = 0x1;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	key->ovs_flow_hash = hash;
10758c2ecf20Sopenharmony_ci}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_cistatic int execute_set_action(struct sk_buff *skb,
10788c2ecf20Sopenharmony_ci			      struct sw_flow_key *flow_key,
10798c2ecf20Sopenharmony_ci			      const struct nlattr *a)
10808c2ecf20Sopenharmony_ci{
10818c2ecf20Sopenharmony_ci	/* Only tunnel set execution is supported without a mask. */
10828c2ecf20Sopenharmony_ci	if (nla_type(a) == OVS_KEY_ATTR_TUNNEL_INFO) {
10838c2ecf20Sopenharmony_ci		struct ovs_tunnel_info *tun = nla_data(a);
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci		skb_dst_drop(skb);
10868c2ecf20Sopenharmony_ci		dst_hold((struct dst_entry *)tun->tun_dst);
10878c2ecf20Sopenharmony_ci		skb_dst_set(skb, (struct dst_entry *)tun->tun_dst);
10888c2ecf20Sopenharmony_ci		return 0;
10898c2ecf20Sopenharmony_ci	}
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	return -EINVAL;
10928c2ecf20Sopenharmony_ci}
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci/* Mask is at the midpoint of the data. */
10958c2ecf20Sopenharmony_ci#define get_mask(a, type) ((const type)nla_data(a) + 1)
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_cistatic int execute_masked_set_action(struct sk_buff *skb,
10988c2ecf20Sopenharmony_ci				     struct sw_flow_key *flow_key,
10998c2ecf20Sopenharmony_ci				     const struct nlattr *a)
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	int err = 0;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	switch (nla_type(a)) {
11048c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_PRIORITY:
11058c2ecf20Sopenharmony_ci		OVS_SET_MASKED(skb->priority, nla_get_u32(a),
11068c2ecf20Sopenharmony_ci			       *get_mask(a, u32 *));
11078c2ecf20Sopenharmony_ci		flow_key->phy.priority = skb->priority;
11088c2ecf20Sopenharmony_ci		break;
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_SKB_MARK:
11118c2ecf20Sopenharmony_ci		OVS_SET_MASKED(skb->mark, nla_get_u32(a), *get_mask(a, u32 *));
11128c2ecf20Sopenharmony_ci		flow_key->phy.skb_mark = skb->mark;
11138c2ecf20Sopenharmony_ci		break;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_TUNNEL_INFO:
11168c2ecf20Sopenharmony_ci		/* Masked data not supported for tunnel. */
11178c2ecf20Sopenharmony_ci		err = -EINVAL;
11188c2ecf20Sopenharmony_ci		break;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_ETHERNET:
11218c2ecf20Sopenharmony_ci		err = set_eth_addr(skb, flow_key, nla_data(a),
11228c2ecf20Sopenharmony_ci				   get_mask(a, struct ovs_key_ethernet *));
11238c2ecf20Sopenharmony_ci		break;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_NSH:
11268c2ecf20Sopenharmony_ci		err = set_nsh(skb, flow_key, a);
11278c2ecf20Sopenharmony_ci		break;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_IPV4:
11308c2ecf20Sopenharmony_ci		err = set_ipv4(skb, flow_key, nla_data(a),
11318c2ecf20Sopenharmony_ci			       get_mask(a, struct ovs_key_ipv4 *));
11328c2ecf20Sopenharmony_ci		break;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_IPV6:
11358c2ecf20Sopenharmony_ci		err = set_ipv6(skb, flow_key, nla_data(a),
11368c2ecf20Sopenharmony_ci			       get_mask(a, struct ovs_key_ipv6 *));
11378c2ecf20Sopenharmony_ci		break;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_TCP:
11408c2ecf20Sopenharmony_ci		err = set_tcp(skb, flow_key, nla_data(a),
11418c2ecf20Sopenharmony_ci			      get_mask(a, struct ovs_key_tcp *));
11428c2ecf20Sopenharmony_ci		break;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_UDP:
11458c2ecf20Sopenharmony_ci		err = set_udp(skb, flow_key, nla_data(a),
11468c2ecf20Sopenharmony_ci			      get_mask(a, struct ovs_key_udp *));
11478c2ecf20Sopenharmony_ci		break;
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_SCTP:
11508c2ecf20Sopenharmony_ci		err = set_sctp(skb, flow_key, nla_data(a),
11518c2ecf20Sopenharmony_ci			       get_mask(a, struct ovs_key_sctp *));
11528c2ecf20Sopenharmony_ci		break;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_MPLS:
11558c2ecf20Sopenharmony_ci		err = set_mpls(skb, flow_key, nla_data(a), get_mask(a,
11568c2ecf20Sopenharmony_ci								    __be32 *));
11578c2ecf20Sopenharmony_ci		break;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_CT_STATE:
11608c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_CT_ZONE:
11618c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_CT_MARK:
11628c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_CT_LABELS:
11638c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4:
11648c2ecf20Sopenharmony_ci	case OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6:
11658c2ecf20Sopenharmony_ci		err = -EINVAL;
11668c2ecf20Sopenharmony_ci		break;
11678c2ecf20Sopenharmony_ci	}
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	return err;
11708c2ecf20Sopenharmony_ci}
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_cistatic int execute_recirc(struct datapath *dp, struct sk_buff *skb,
11738c2ecf20Sopenharmony_ci			  struct sw_flow_key *key,
11748c2ecf20Sopenharmony_ci			  const struct nlattr *a, bool last)
11758c2ecf20Sopenharmony_ci{
11768c2ecf20Sopenharmony_ci	u32 recirc_id;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	if (!is_flow_key_valid(key)) {
11798c2ecf20Sopenharmony_ci		int err;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci		err = ovs_flow_key_update(skb, key);
11828c2ecf20Sopenharmony_ci		if (err)
11838c2ecf20Sopenharmony_ci			return err;
11848c2ecf20Sopenharmony_ci	}
11858c2ecf20Sopenharmony_ci	BUG_ON(!is_flow_key_valid(key));
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	recirc_id = nla_get_u32(a);
11888c2ecf20Sopenharmony_ci	return clone_execute(dp, skb, key, recirc_id, NULL, 0, last, true);
11898c2ecf20Sopenharmony_ci}
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_cistatic int execute_check_pkt_len(struct datapath *dp, struct sk_buff *skb,
11928c2ecf20Sopenharmony_ci				 struct sw_flow_key *key,
11938c2ecf20Sopenharmony_ci				 const struct nlattr *attr, bool last)
11948c2ecf20Sopenharmony_ci{
11958c2ecf20Sopenharmony_ci	struct ovs_skb_cb *ovs_cb = OVS_CB(skb);
11968c2ecf20Sopenharmony_ci	const struct nlattr *actions, *cpl_arg;
11978c2ecf20Sopenharmony_ci	int len, max_len, rem = nla_len(attr);
11988c2ecf20Sopenharmony_ci	const struct check_pkt_len_arg *arg;
11998c2ecf20Sopenharmony_ci	bool clone_flow_key;
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	/* The first netlink attribute in 'attr' is always
12028c2ecf20Sopenharmony_ci	 * 'OVS_CHECK_PKT_LEN_ATTR_ARG'.
12038c2ecf20Sopenharmony_ci	 */
12048c2ecf20Sopenharmony_ci	cpl_arg = nla_data(attr);
12058c2ecf20Sopenharmony_ci	arg = nla_data(cpl_arg);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	len = ovs_cb->mru ? ovs_cb->mru + skb->mac_len : skb->len;
12088c2ecf20Sopenharmony_ci	max_len = arg->pkt_len;
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	if ((skb_is_gso(skb) && skb_gso_validate_mac_len(skb, max_len)) ||
12118c2ecf20Sopenharmony_ci	    len <= max_len) {
12128c2ecf20Sopenharmony_ci		/* Second netlink attribute in 'attr' is always
12138c2ecf20Sopenharmony_ci		 * 'OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL'.
12148c2ecf20Sopenharmony_ci		 */
12158c2ecf20Sopenharmony_ci		actions = nla_next(cpl_arg, &rem);
12168c2ecf20Sopenharmony_ci		clone_flow_key = !arg->exec_for_lesser_equal;
12178c2ecf20Sopenharmony_ci	} else {
12188c2ecf20Sopenharmony_ci		/* Third netlink attribute in 'attr' is always
12198c2ecf20Sopenharmony_ci		 * 'OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER'.
12208c2ecf20Sopenharmony_ci		 */
12218c2ecf20Sopenharmony_ci		actions = nla_next(cpl_arg, &rem);
12228c2ecf20Sopenharmony_ci		actions = nla_next(actions, &rem);
12238c2ecf20Sopenharmony_ci		clone_flow_key = !arg->exec_for_greater;
12248c2ecf20Sopenharmony_ci	}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	return clone_execute(dp, skb, key, 0, nla_data(actions),
12278c2ecf20Sopenharmony_ci			     nla_len(actions), last, clone_flow_key);
12288c2ecf20Sopenharmony_ci}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_cistatic int execute_dec_ttl(struct sk_buff *skb, struct sw_flow_key *key)
12318c2ecf20Sopenharmony_ci{
12328c2ecf20Sopenharmony_ci	int err;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	if (skb->protocol == htons(ETH_P_IPV6)) {
12358c2ecf20Sopenharmony_ci		struct ipv6hdr *nh;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci		err = skb_ensure_writable(skb, skb_network_offset(skb) +
12388c2ecf20Sopenharmony_ci					  sizeof(*nh));
12398c2ecf20Sopenharmony_ci		if (unlikely(err))
12408c2ecf20Sopenharmony_ci			return err;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci		nh = ipv6_hdr(skb);
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci		if (nh->hop_limit <= 1)
12458c2ecf20Sopenharmony_ci			return -EHOSTUNREACH;
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci		key->ip.ttl = --nh->hop_limit;
12488c2ecf20Sopenharmony_ci	} else if (skb->protocol == htons(ETH_P_IP)) {
12498c2ecf20Sopenharmony_ci		struct iphdr *nh;
12508c2ecf20Sopenharmony_ci		u8 old_ttl;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci		err = skb_ensure_writable(skb, skb_network_offset(skb) +
12538c2ecf20Sopenharmony_ci					  sizeof(*nh));
12548c2ecf20Sopenharmony_ci		if (unlikely(err))
12558c2ecf20Sopenharmony_ci			return err;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci		nh = ip_hdr(skb);
12588c2ecf20Sopenharmony_ci		if (nh->ttl <= 1)
12598c2ecf20Sopenharmony_ci			return -EHOSTUNREACH;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci		old_ttl = nh->ttl--;
12628c2ecf20Sopenharmony_ci		csum_replace2(&nh->check, htons(old_ttl << 8),
12638c2ecf20Sopenharmony_ci			      htons(nh->ttl << 8));
12648c2ecf20Sopenharmony_ci		key->ip.ttl = nh->ttl;
12658c2ecf20Sopenharmony_ci	}
12668c2ecf20Sopenharmony_ci	return 0;
12678c2ecf20Sopenharmony_ci}
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci/* Execute a list of actions against 'skb'. */
12708c2ecf20Sopenharmony_cistatic int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
12718c2ecf20Sopenharmony_ci			      struct sw_flow_key *key,
12728c2ecf20Sopenharmony_ci			      const struct nlattr *attr, int len)
12738c2ecf20Sopenharmony_ci{
12748c2ecf20Sopenharmony_ci	const struct nlattr *a;
12758c2ecf20Sopenharmony_ci	int rem;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	for (a = attr, rem = len; rem > 0;
12788c2ecf20Sopenharmony_ci	     a = nla_next(a, &rem)) {
12798c2ecf20Sopenharmony_ci		int err = 0;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci		switch (nla_type(a)) {
12828c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_OUTPUT: {
12838c2ecf20Sopenharmony_ci			int port = nla_get_u32(a);
12848c2ecf20Sopenharmony_ci			struct sk_buff *clone;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci			/* Every output action needs a separate clone
12878c2ecf20Sopenharmony_ci			 * of 'skb', In case the output action is the
12888c2ecf20Sopenharmony_ci			 * last action, cloning can be avoided.
12898c2ecf20Sopenharmony_ci			 */
12908c2ecf20Sopenharmony_ci			if (nla_is_last(a, rem)) {
12918c2ecf20Sopenharmony_ci				do_output(dp, skb, port, key);
12928c2ecf20Sopenharmony_ci				/* 'skb' has been used for output.
12938c2ecf20Sopenharmony_ci				 */
12948c2ecf20Sopenharmony_ci				return 0;
12958c2ecf20Sopenharmony_ci			}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci			clone = skb_clone(skb, GFP_ATOMIC);
12988c2ecf20Sopenharmony_ci			if (clone)
12998c2ecf20Sopenharmony_ci				do_output(dp, clone, port, key);
13008c2ecf20Sopenharmony_ci			OVS_CB(skb)->cutlen = 0;
13018c2ecf20Sopenharmony_ci			break;
13028c2ecf20Sopenharmony_ci		}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_TRUNC: {
13058c2ecf20Sopenharmony_ci			struct ovs_action_trunc *trunc = nla_data(a);
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci			if (skb->len > trunc->max_len)
13088c2ecf20Sopenharmony_ci				OVS_CB(skb)->cutlen = skb->len - trunc->max_len;
13098c2ecf20Sopenharmony_ci			break;
13108c2ecf20Sopenharmony_ci		}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_USERSPACE:
13138c2ecf20Sopenharmony_ci			output_userspace(dp, skb, key, a, attr,
13148c2ecf20Sopenharmony_ci						     len, OVS_CB(skb)->cutlen);
13158c2ecf20Sopenharmony_ci			OVS_CB(skb)->cutlen = 0;
13168c2ecf20Sopenharmony_ci			break;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_HASH:
13198c2ecf20Sopenharmony_ci			execute_hash(skb, key, a);
13208c2ecf20Sopenharmony_ci			break;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_MPLS: {
13238c2ecf20Sopenharmony_ci			struct ovs_action_push_mpls *mpls = nla_data(a);
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci			err = push_mpls(skb, key, mpls->mpls_lse,
13268c2ecf20Sopenharmony_ci					mpls->mpls_ethertype, skb->mac_len);
13278c2ecf20Sopenharmony_ci			break;
13288c2ecf20Sopenharmony_ci		}
13298c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_ADD_MPLS: {
13308c2ecf20Sopenharmony_ci			struct ovs_action_add_mpls *mpls = nla_data(a);
13318c2ecf20Sopenharmony_ci			__u16 mac_len = 0;
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci			if (mpls->tun_flags & OVS_MPLS_L3_TUNNEL_FLAG_MASK)
13348c2ecf20Sopenharmony_ci				mac_len = skb->mac_len;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci			err = push_mpls(skb, key, mpls->mpls_lse,
13378c2ecf20Sopenharmony_ci					mpls->mpls_ethertype, mac_len);
13388c2ecf20Sopenharmony_ci			break;
13398c2ecf20Sopenharmony_ci		}
13408c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_POP_MPLS:
13418c2ecf20Sopenharmony_ci			err = pop_mpls(skb, key, nla_get_be16(a));
13428c2ecf20Sopenharmony_ci			break;
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_VLAN:
13458c2ecf20Sopenharmony_ci			err = push_vlan(skb, key, nla_data(a));
13468c2ecf20Sopenharmony_ci			break;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_POP_VLAN:
13498c2ecf20Sopenharmony_ci			err = pop_vlan(skb, key);
13508c2ecf20Sopenharmony_ci			break;
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_RECIRC: {
13538c2ecf20Sopenharmony_ci			bool last = nla_is_last(a, rem);
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci			err = execute_recirc(dp, skb, key, a, last);
13568c2ecf20Sopenharmony_ci			if (last) {
13578c2ecf20Sopenharmony_ci				/* If this is the last action, the skb has
13588c2ecf20Sopenharmony_ci				 * been consumed or freed.
13598c2ecf20Sopenharmony_ci				 * Return immediately.
13608c2ecf20Sopenharmony_ci				 */
13618c2ecf20Sopenharmony_ci				return err;
13628c2ecf20Sopenharmony_ci			}
13638c2ecf20Sopenharmony_ci			break;
13648c2ecf20Sopenharmony_ci		}
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SET:
13678c2ecf20Sopenharmony_ci			err = execute_set_action(skb, key, nla_data(a));
13688c2ecf20Sopenharmony_ci			break;
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SET_MASKED:
13718c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SET_TO_MASKED:
13728c2ecf20Sopenharmony_ci			err = execute_masked_set_action(skb, key, nla_data(a));
13738c2ecf20Sopenharmony_ci			break;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_SAMPLE: {
13768c2ecf20Sopenharmony_ci			bool last = nla_is_last(a, rem);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci			err = sample(dp, skb, key, a, last);
13798c2ecf20Sopenharmony_ci			if (last)
13808c2ecf20Sopenharmony_ci				return err;
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci			break;
13838c2ecf20Sopenharmony_ci		}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CT:
13868c2ecf20Sopenharmony_ci			if (!is_flow_key_valid(key)) {
13878c2ecf20Sopenharmony_ci				err = ovs_flow_key_update(skb, key);
13888c2ecf20Sopenharmony_ci				if (err)
13898c2ecf20Sopenharmony_ci					return err;
13908c2ecf20Sopenharmony_ci			}
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci			err = ovs_ct_execute(ovs_dp_get_net(dp), skb, key,
13938c2ecf20Sopenharmony_ci					     nla_data(a));
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci			/* Hide stolen IP fragments from user space. */
13968c2ecf20Sopenharmony_ci			if (err)
13978c2ecf20Sopenharmony_ci				return err == -EINPROGRESS ? 0 : err;
13988c2ecf20Sopenharmony_ci			break;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CT_CLEAR:
14018c2ecf20Sopenharmony_ci			err = ovs_ct_clear(skb, key);
14028c2ecf20Sopenharmony_ci			break;
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_ETH:
14058c2ecf20Sopenharmony_ci			err = push_eth(skb, key, nla_data(a));
14068c2ecf20Sopenharmony_ci			break;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_POP_ETH:
14098c2ecf20Sopenharmony_ci			err = pop_eth(skb, key);
14108c2ecf20Sopenharmony_ci			break;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_PUSH_NSH: {
14138c2ecf20Sopenharmony_ci			u8 buffer[NSH_HDR_MAX_LEN];
14148c2ecf20Sopenharmony_ci			struct nshhdr *nh = (struct nshhdr *)buffer;
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci			err = nsh_hdr_from_nlattr(nla_data(a), nh,
14178c2ecf20Sopenharmony_ci						  NSH_HDR_MAX_LEN);
14188c2ecf20Sopenharmony_ci			if (unlikely(err))
14198c2ecf20Sopenharmony_ci				break;
14208c2ecf20Sopenharmony_ci			err = push_nsh(skb, key, nh);
14218c2ecf20Sopenharmony_ci			break;
14228c2ecf20Sopenharmony_ci		}
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_POP_NSH:
14258c2ecf20Sopenharmony_ci			err = pop_nsh(skb, key);
14268c2ecf20Sopenharmony_ci			break;
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_METER:
14298c2ecf20Sopenharmony_ci			if (ovs_meter_execute(dp, skb, key, nla_get_u32(a))) {
14308c2ecf20Sopenharmony_ci				consume_skb(skb);
14318c2ecf20Sopenharmony_ci				return 0;
14328c2ecf20Sopenharmony_ci			}
14338c2ecf20Sopenharmony_ci			break;
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CLONE: {
14368c2ecf20Sopenharmony_ci			bool last = nla_is_last(a, rem);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci			err = clone(dp, skb, key, a, last);
14398c2ecf20Sopenharmony_ci			if (last)
14408c2ecf20Sopenharmony_ci				return err;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci			break;
14438c2ecf20Sopenharmony_ci		}
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_CHECK_PKT_LEN: {
14468c2ecf20Sopenharmony_ci			bool last = nla_is_last(a, rem);
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci			err = execute_check_pkt_len(dp, skb, key, a, last);
14498c2ecf20Sopenharmony_ci			if (last)
14508c2ecf20Sopenharmony_ci				return err;
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci			break;
14538c2ecf20Sopenharmony_ci		}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci		case OVS_ACTION_ATTR_DEC_TTL:
14568c2ecf20Sopenharmony_ci			err = execute_dec_ttl(skb, key);
14578c2ecf20Sopenharmony_ci			if (err == -EHOSTUNREACH) {
14588c2ecf20Sopenharmony_ci				err = dec_ttl_exception_handler(dp, skb, key,
14598c2ecf20Sopenharmony_ci								a, true);
14608c2ecf20Sopenharmony_ci				return err;
14618c2ecf20Sopenharmony_ci			}
14628c2ecf20Sopenharmony_ci			break;
14638c2ecf20Sopenharmony_ci		}
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci		if (unlikely(err)) {
14668c2ecf20Sopenharmony_ci			kfree_skb(skb);
14678c2ecf20Sopenharmony_ci			return err;
14688c2ecf20Sopenharmony_ci		}
14698c2ecf20Sopenharmony_ci	}
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	consume_skb(skb);
14728c2ecf20Sopenharmony_ci	return 0;
14738c2ecf20Sopenharmony_ci}
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci/* Execute the actions on the clone of the packet. The effect of the
14768c2ecf20Sopenharmony_ci * execution does not affect the original 'skb' nor the original 'key'.
14778c2ecf20Sopenharmony_ci *
14788c2ecf20Sopenharmony_ci * The execution may be deferred in case the actions can not be executed
14798c2ecf20Sopenharmony_ci * immediately.
14808c2ecf20Sopenharmony_ci */
14818c2ecf20Sopenharmony_cistatic int clone_execute(struct datapath *dp, struct sk_buff *skb,
14828c2ecf20Sopenharmony_ci			 struct sw_flow_key *key, u32 recirc_id,
14838c2ecf20Sopenharmony_ci			 const struct nlattr *actions, int len,
14848c2ecf20Sopenharmony_ci			 bool last, bool clone_flow_key)
14858c2ecf20Sopenharmony_ci{
14868c2ecf20Sopenharmony_ci	struct deferred_action *da;
14878c2ecf20Sopenharmony_ci	struct sw_flow_key *clone;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	skb = last ? skb : skb_clone(skb, GFP_ATOMIC);
14908c2ecf20Sopenharmony_ci	if (!skb) {
14918c2ecf20Sopenharmony_ci		/* Out of memory, skip this action.
14928c2ecf20Sopenharmony_ci		 */
14938c2ecf20Sopenharmony_ci		return 0;
14948c2ecf20Sopenharmony_ci	}
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	/* When clone_flow_key is false, the 'key' will not be change
14978c2ecf20Sopenharmony_ci	 * by the actions, then the 'key' can be used directly.
14988c2ecf20Sopenharmony_ci	 * Otherwise, try to clone key from the next recursion level of
14998c2ecf20Sopenharmony_ci	 * 'flow_keys'. If clone is successful, execute the actions
15008c2ecf20Sopenharmony_ci	 * without deferring.
15018c2ecf20Sopenharmony_ci	 */
15028c2ecf20Sopenharmony_ci	clone = clone_flow_key ? clone_key(key) : key;
15038c2ecf20Sopenharmony_ci	if (clone) {
15048c2ecf20Sopenharmony_ci		int err = 0;
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci		if (actions) { /* Sample action */
15078c2ecf20Sopenharmony_ci			if (clone_flow_key)
15088c2ecf20Sopenharmony_ci				__this_cpu_inc(exec_actions_level);
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci			err = do_execute_actions(dp, skb, clone,
15118c2ecf20Sopenharmony_ci						 actions, len);
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci			if (clone_flow_key)
15148c2ecf20Sopenharmony_ci				__this_cpu_dec(exec_actions_level);
15158c2ecf20Sopenharmony_ci		} else { /* Recirc action */
15168c2ecf20Sopenharmony_ci			clone->recirc_id = recirc_id;
15178c2ecf20Sopenharmony_ci			ovs_dp_process_packet(skb, clone);
15188c2ecf20Sopenharmony_ci		}
15198c2ecf20Sopenharmony_ci		return err;
15208c2ecf20Sopenharmony_ci	}
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	/* Out of 'flow_keys' space. Defer actions */
15238c2ecf20Sopenharmony_ci	da = add_deferred_actions(skb, key, actions, len);
15248c2ecf20Sopenharmony_ci	if (da) {
15258c2ecf20Sopenharmony_ci		if (!actions) { /* Recirc action */
15268c2ecf20Sopenharmony_ci			key = &da->pkt_key;
15278c2ecf20Sopenharmony_ci			key->recirc_id = recirc_id;
15288c2ecf20Sopenharmony_ci		}
15298c2ecf20Sopenharmony_ci	} else {
15308c2ecf20Sopenharmony_ci		/* Out of per CPU action FIFO space. Drop the 'skb' and
15318c2ecf20Sopenharmony_ci		 * log an error.
15328c2ecf20Sopenharmony_ci		 */
15338c2ecf20Sopenharmony_ci		kfree_skb(skb);
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci		if (net_ratelimit()) {
15368c2ecf20Sopenharmony_ci			if (actions) { /* Sample action */
15378c2ecf20Sopenharmony_ci				pr_warn("%s: deferred action limit reached, drop sample action\n",
15388c2ecf20Sopenharmony_ci					ovs_dp_name(dp));
15398c2ecf20Sopenharmony_ci			} else {  /* Recirc action */
15408c2ecf20Sopenharmony_ci				pr_warn("%s: deferred action limit reached, drop recirc action\n",
15418c2ecf20Sopenharmony_ci					ovs_dp_name(dp));
15428c2ecf20Sopenharmony_ci			}
15438c2ecf20Sopenharmony_ci		}
15448c2ecf20Sopenharmony_ci	}
15458c2ecf20Sopenharmony_ci	return 0;
15468c2ecf20Sopenharmony_ci}
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_cistatic void process_deferred_actions(struct datapath *dp)
15498c2ecf20Sopenharmony_ci{
15508c2ecf20Sopenharmony_ci	struct action_fifo *fifo = this_cpu_ptr(action_fifos);
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	/* Do not touch the FIFO in case there is no deferred actions. */
15538c2ecf20Sopenharmony_ci	if (action_fifo_is_empty(fifo))
15548c2ecf20Sopenharmony_ci		return;
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	/* Finishing executing all deferred actions. */
15578c2ecf20Sopenharmony_ci	do {
15588c2ecf20Sopenharmony_ci		struct deferred_action *da = action_fifo_get(fifo);
15598c2ecf20Sopenharmony_ci		struct sk_buff *skb = da->skb;
15608c2ecf20Sopenharmony_ci		struct sw_flow_key *key = &da->pkt_key;
15618c2ecf20Sopenharmony_ci		const struct nlattr *actions = da->actions;
15628c2ecf20Sopenharmony_ci		int actions_len = da->actions_len;
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci		if (actions)
15658c2ecf20Sopenharmony_ci			do_execute_actions(dp, skb, key, actions, actions_len);
15668c2ecf20Sopenharmony_ci		else
15678c2ecf20Sopenharmony_ci			ovs_dp_process_packet(skb, key);
15688c2ecf20Sopenharmony_ci	} while (!action_fifo_is_empty(fifo));
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	/* Reset FIFO for the next packet.  */
15718c2ecf20Sopenharmony_ci	action_fifo_init(fifo);
15728c2ecf20Sopenharmony_ci}
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci/* Execute a list of actions against 'skb'. */
15758c2ecf20Sopenharmony_ciint ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
15768c2ecf20Sopenharmony_ci			const struct sw_flow_actions *acts,
15778c2ecf20Sopenharmony_ci			struct sw_flow_key *key)
15788c2ecf20Sopenharmony_ci{
15798c2ecf20Sopenharmony_ci	int err, level;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	level = __this_cpu_inc_return(exec_actions_level);
15828c2ecf20Sopenharmony_ci	if (unlikely(level > OVS_RECURSION_LIMIT)) {
15838c2ecf20Sopenharmony_ci		net_crit_ratelimited("ovs: recursion limit reached on datapath %s, probable configuration error\n",
15848c2ecf20Sopenharmony_ci				     ovs_dp_name(dp));
15858c2ecf20Sopenharmony_ci		kfree_skb(skb);
15868c2ecf20Sopenharmony_ci		err = -ENETDOWN;
15878c2ecf20Sopenharmony_ci		goto out;
15888c2ecf20Sopenharmony_ci	}
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	OVS_CB(skb)->acts_origlen = acts->orig_len;
15918c2ecf20Sopenharmony_ci	err = do_execute_actions(dp, skb, key,
15928c2ecf20Sopenharmony_ci				 acts->actions, acts->actions_len);
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	if (level == 1)
15958c2ecf20Sopenharmony_ci		process_deferred_actions(dp);
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ciout:
15988c2ecf20Sopenharmony_ci	__this_cpu_dec(exec_actions_level);
15998c2ecf20Sopenharmony_ci	return err;
16008c2ecf20Sopenharmony_ci}
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ciint action_fifos_init(void)
16038c2ecf20Sopenharmony_ci{
16048c2ecf20Sopenharmony_ci	action_fifos = alloc_percpu(struct action_fifo);
16058c2ecf20Sopenharmony_ci	if (!action_fifos)
16068c2ecf20Sopenharmony_ci		return -ENOMEM;
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	flow_keys = alloc_percpu(struct action_flow_keys);
16098c2ecf20Sopenharmony_ci	if (!flow_keys) {
16108c2ecf20Sopenharmony_ci		free_percpu(action_fifos);
16118c2ecf20Sopenharmony_ci		return -ENOMEM;
16128c2ecf20Sopenharmony_ci	}
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci	return 0;
16158c2ecf20Sopenharmony_ci}
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_civoid action_fifos_exit(void)
16188c2ecf20Sopenharmony_ci{
16198c2ecf20Sopenharmony_ci	free_percpu(action_fifos);
16208c2ecf20Sopenharmony_ci	free_percpu(flow_keys);
16218c2ecf20Sopenharmony_ci}
1622