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