162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2007-2017 Nicira, Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/skbuff.h> 962306a36Sopenharmony_ci#include <linux/in.h> 1062306a36Sopenharmony_ci#include <linux/ip.h> 1162306a36Sopenharmony_ci#include <linux/openvswitch.h> 1262306a36Sopenharmony_ci#include <linux/sctp.h> 1362306a36Sopenharmony_ci#include <linux/tcp.h> 1462306a36Sopenharmony_ci#include <linux/udp.h> 1562306a36Sopenharmony_ci#include <linux/in6.h> 1662306a36Sopenharmony_ci#include <linux/if_arp.h> 1762306a36Sopenharmony_ci#include <linux/if_vlan.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <net/dst.h> 2062306a36Sopenharmony_ci#include <net/gso.h> 2162306a36Sopenharmony_ci#include <net/ip.h> 2262306a36Sopenharmony_ci#include <net/ipv6.h> 2362306a36Sopenharmony_ci#include <net/ip6_fib.h> 2462306a36Sopenharmony_ci#include <net/checksum.h> 2562306a36Sopenharmony_ci#include <net/dsfield.h> 2662306a36Sopenharmony_ci#include <net/mpls.h> 2762306a36Sopenharmony_ci#include <net/sctp/checksum.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "datapath.h" 3062306a36Sopenharmony_ci#include "drop.h" 3162306a36Sopenharmony_ci#include "flow.h" 3262306a36Sopenharmony_ci#include "conntrack.h" 3362306a36Sopenharmony_ci#include "vport.h" 3462306a36Sopenharmony_ci#include "flow_netlink.h" 3562306a36Sopenharmony_ci#include "openvswitch_trace.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct deferred_action { 3862306a36Sopenharmony_ci struct sk_buff *skb; 3962306a36Sopenharmony_ci const struct nlattr *actions; 4062306a36Sopenharmony_ci int actions_len; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci /* Store pkt_key clone when creating deferred action. */ 4362306a36Sopenharmony_ci struct sw_flow_key pkt_key; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define MAX_L2_LEN (VLAN_ETH_HLEN + 3 * MPLS_HLEN) 4762306a36Sopenharmony_cistruct ovs_frag_data { 4862306a36Sopenharmony_ci unsigned long dst; 4962306a36Sopenharmony_ci struct vport *vport; 5062306a36Sopenharmony_ci struct ovs_skb_cb cb; 5162306a36Sopenharmony_ci __be16 inner_protocol; 5262306a36Sopenharmony_ci u16 network_offset; /* valid only for MPLS */ 5362306a36Sopenharmony_ci u16 vlan_tci; 5462306a36Sopenharmony_ci __be16 vlan_proto; 5562306a36Sopenharmony_ci unsigned int l2_len; 5662306a36Sopenharmony_ci u8 mac_proto; 5762306a36Sopenharmony_ci u8 l2_data[MAX_L2_LEN]; 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct ovs_frag_data, ovs_frag_data_storage); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define DEFERRED_ACTION_FIFO_SIZE 10 6362306a36Sopenharmony_ci#define OVS_RECURSION_LIMIT 5 6462306a36Sopenharmony_ci#define OVS_DEFERRED_ACTION_THRESHOLD (OVS_RECURSION_LIMIT - 2) 6562306a36Sopenharmony_cistruct action_fifo { 6662306a36Sopenharmony_ci int head; 6762306a36Sopenharmony_ci int tail; 6862306a36Sopenharmony_ci /* Deferred action fifo queue storage. */ 6962306a36Sopenharmony_ci struct deferred_action fifo[DEFERRED_ACTION_FIFO_SIZE]; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct action_flow_keys { 7362306a36Sopenharmony_ci struct sw_flow_key key[OVS_DEFERRED_ACTION_THRESHOLD]; 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic struct action_fifo __percpu *action_fifos; 7762306a36Sopenharmony_cistatic struct action_flow_keys __percpu *flow_keys; 7862306a36Sopenharmony_cistatic DEFINE_PER_CPU(int, exec_actions_level); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* Make a clone of the 'key', using the pre-allocated percpu 'flow_keys' 8162306a36Sopenharmony_ci * space. Return NULL if out of key spaces. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_cistatic struct sw_flow_key *clone_key(const struct sw_flow_key *key_) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct action_flow_keys *keys = this_cpu_ptr(flow_keys); 8662306a36Sopenharmony_ci int level = this_cpu_read(exec_actions_level); 8762306a36Sopenharmony_ci struct sw_flow_key *key = NULL; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (level <= OVS_DEFERRED_ACTION_THRESHOLD) { 9062306a36Sopenharmony_ci key = &keys->key[level - 1]; 9162306a36Sopenharmony_ci *key = *key_; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return key; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic void action_fifo_init(struct action_fifo *fifo) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci fifo->head = 0; 10062306a36Sopenharmony_ci fifo->tail = 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic bool action_fifo_is_empty(const struct action_fifo *fifo) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci return (fifo->head == fifo->tail); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic struct deferred_action *action_fifo_get(struct action_fifo *fifo) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci if (action_fifo_is_empty(fifo)) 11162306a36Sopenharmony_ci return NULL; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return &fifo->fifo[fifo->tail++]; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic struct deferred_action *action_fifo_put(struct action_fifo *fifo) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci if (fifo->head >= DEFERRED_ACTION_FIFO_SIZE - 1) 11962306a36Sopenharmony_ci return NULL; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return &fifo->fifo[fifo->head++]; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* Return true if fifo is not full */ 12562306a36Sopenharmony_cistatic struct deferred_action *add_deferred_actions(struct sk_buff *skb, 12662306a36Sopenharmony_ci const struct sw_flow_key *key, 12762306a36Sopenharmony_ci const struct nlattr *actions, 12862306a36Sopenharmony_ci const int actions_len) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct action_fifo *fifo; 13162306a36Sopenharmony_ci struct deferred_action *da; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci fifo = this_cpu_ptr(action_fifos); 13462306a36Sopenharmony_ci da = action_fifo_put(fifo); 13562306a36Sopenharmony_ci if (da) { 13662306a36Sopenharmony_ci da->skb = skb; 13762306a36Sopenharmony_ci da->actions = actions; 13862306a36Sopenharmony_ci da->actions_len = actions_len; 13962306a36Sopenharmony_ci da->pkt_key = *key; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return da; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic void invalidate_flow_key(struct sw_flow_key *key) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci key->mac_proto |= SW_FLOW_KEY_INVALID; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic bool is_flow_key_valid(const struct sw_flow_key *key) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci return !(key->mac_proto & SW_FLOW_KEY_INVALID); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int clone_execute(struct datapath *dp, struct sk_buff *skb, 15662306a36Sopenharmony_ci struct sw_flow_key *key, 15762306a36Sopenharmony_ci u32 recirc_id, 15862306a36Sopenharmony_ci const struct nlattr *actions, int len, 15962306a36Sopenharmony_ci bool last, bool clone_flow_key); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int do_execute_actions(struct datapath *dp, struct sk_buff *skb, 16262306a36Sopenharmony_ci struct sw_flow_key *key, 16362306a36Sopenharmony_ci const struct nlattr *attr, int len); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, 16662306a36Sopenharmony_ci __be32 mpls_lse, __be16 mpls_ethertype, __u16 mac_len) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci int err; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci err = skb_mpls_push(skb, mpls_lse, mpls_ethertype, mac_len, !!mac_len); 17162306a36Sopenharmony_ci if (err) 17262306a36Sopenharmony_ci return err; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (!mac_len) 17562306a36Sopenharmony_ci key->mac_proto = MAC_PROTO_NONE; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci invalidate_flow_key(key); 17862306a36Sopenharmony_ci return 0; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key, 18262306a36Sopenharmony_ci const __be16 ethertype) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci int err; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci err = skb_mpls_pop(skb, ethertype, skb->mac_len, 18762306a36Sopenharmony_ci ovs_key_mac_proto(key) == MAC_PROTO_ETHERNET); 18862306a36Sopenharmony_ci if (err) 18962306a36Sopenharmony_ci return err; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (ethertype == htons(ETH_P_TEB)) 19262306a36Sopenharmony_ci key->mac_proto = MAC_PROTO_ETHERNET; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci invalidate_flow_key(key); 19562306a36Sopenharmony_ci return 0; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int set_mpls(struct sk_buff *skb, struct sw_flow_key *flow_key, 19962306a36Sopenharmony_ci const __be32 *mpls_lse, const __be32 *mask) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct mpls_shim_hdr *stack; 20262306a36Sopenharmony_ci __be32 lse; 20362306a36Sopenharmony_ci int err; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (!pskb_may_pull(skb, skb_network_offset(skb) + MPLS_HLEN)) 20662306a36Sopenharmony_ci return -ENOMEM; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci stack = mpls_hdr(skb); 20962306a36Sopenharmony_ci lse = OVS_MASKED(stack->label_stack_entry, *mpls_lse, *mask); 21062306a36Sopenharmony_ci err = skb_mpls_update_lse(skb, lse); 21162306a36Sopenharmony_ci if (err) 21262306a36Sopenharmony_ci return err; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci flow_key->mpls.lse[0] = lse; 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci int err; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci err = skb_vlan_pop(skb); 22362306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 22462306a36Sopenharmony_ci invalidate_flow_key(key); 22562306a36Sopenharmony_ci } else { 22662306a36Sopenharmony_ci key->eth.vlan.tci = 0; 22762306a36Sopenharmony_ci key->eth.vlan.tpid = 0; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci return err; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int push_vlan(struct sk_buff *skb, struct sw_flow_key *key, 23362306a36Sopenharmony_ci const struct ovs_action_push_vlan *vlan) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 23662306a36Sopenharmony_ci invalidate_flow_key(key); 23762306a36Sopenharmony_ci } else { 23862306a36Sopenharmony_ci key->eth.vlan.tci = vlan->vlan_tci; 23962306a36Sopenharmony_ci key->eth.vlan.tpid = vlan->vlan_tpid; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci return skb_vlan_push(skb, vlan->vlan_tpid, 24262306a36Sopenharmony_ci ntohs(vlan->vlan_tci) & ~VLAN_CFI_MASK); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci/* 'src' is already properly masked. */ 24662306a36Sopenharmony_cistatic void ether_addr_copy_masked(u8 *dst_, const u8 *src_, const u8 *mask_) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci u16 *dst = (u16 *)dst_; 24962306a36Sopenharmony_ci const u16 *src = (const u16 *)src_; 25062306a36Sopenharmony_ci const u16 *mask = (const u16 *)mask_; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci OVS_SET_MASKED(dst[0], src[0], mask[0]); 25362306a36Sopenharmony_ci OVS_SET_MASKED(dst[1], src[1], mask[1]); 25462306a36Sopenharmony_ci OVS_SET_MASKED(dst[2], src[2], mask[2]); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key, 25862306a36Sopenharmony_ci const struct ovs_key_ethernet *key, 25962306a36Sopenharmony_ci const struct ovs_key_ethernet *mask) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci int err; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci err = skb_ensure_writable(skb, ETH_HLEN); 26462306a36Sopenharmony_ci if (unlikely(err)) 26562306a36Sopenharmony_ci return err; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci skb_postpull_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci ether_addr_copy_masked(eth_hdr(skb)->h_source, key->eth_src, 27062306a36Sopenharmony_ci mask->eth_src); 27162306a36Sopenharmony_ci ether_addr_copy_masked(eth_hdr(skb)->h_dest, key->eth_dst, 27262306a36Sopenharmony_ci mask->eth_dst); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci skb_postpush_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci ether_addr_copy(flow_key->eth.src, eth_hdr(skb)->h_source); 27762306a36Sopenharmony_ci ether_addr_copy(flow_key->eth.dst, eth_hdr(skb)->h_dest); 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci/* pop_eth does not support VLAN packets as this action is never called 28262306a36Sopenharmony_ci * for them. 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_cistatic int pop_eth(struct sk_buff *skb, struct sw_flow_key *key) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci int err; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci err = skb_eth_pop(skb); 28962306a36Sopenharmony_ci if (err) 29062306a36Sopenharmony_ci return err; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* safe right before invalidate_flow_key */ 29362306a36Sopenharmony_ci key->mac_proto = MAC_PROTO_NONE; 29462306a36Sopenharmony_ci invalidate_flow_key(key); 29562306a36Sopenharmony_ci return 0; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int push_eth(struct sk_buff *skb, struct sw_flow_key *key, 29962306a36Sopenharmony_ci const struct ovs_action_push_eth *ethh) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci int err; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci err = skb_eth_push(skb, ethh->addresses.eth_dst, 30462306a36Sopenharmony_ci ethh->addresses.eth_src); 30562306a36Sopenharmony_ci if (err) 30662306a36Sopenharmony_ci return err; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* safe right before invalidate_flow_key */ 30962306a36Sopenharmony_ci key->mac_proto = MAC_PROTO_ETHERNET; 31062306a36Sopenharmony_ci invalidate_flow_key(key); 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int push_nsh(struct sk_buff *skb, struct sw_flow_key *key, 31562306a36Sopenharmony_ci const struct nshhdr *nh) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci int err; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci err = nsh_push(skb, nh); 32062306a36Sopenharmony_ci if (err) 32162306a36Sopenharmony_ci return err; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* safe right before invalidate_flow_key */ 32462306a36Sopenharmony_ci key->mac_proto = MAC_PROTO_NONE; 32562306a36Sopenharmony_ci invalidate_flow_key(key); 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci int err; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci err = nsh_pop(skb); 33462306a36Sopenharmony_ci if (err) 33562306a36Sopenharmony_ci return err; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* safe right before invalidate_flow_key */ 33862306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_TEB)) 33962306a36Sopenharmony_ci key->mac_proto = MAC_PROTO_ETHERNET; 34062306a36Sopenharmony_ci else 34162306a36Sopenharmony_ci key->mac_proto = MAC_PROTO_NONE; 34262306a36Sopenharmony_ci invalidate_flow_key(key); 34362306a36Sopenharmony_ci return 0; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh, 34762306a36Sopenharmony_ci __be32 addr, __be32 new_addr) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci int transport_len = skb->len - skb_transport_offset(skb); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (nh->frag_off & htons(IP_OFFSET)) 35262306a36Sopenharmony_ci return; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (nh->protocol == IPPROTO_TCP) { 35562306a36Sopenharmony_ci if (likely(transport_len >= sizeof(struct tcphdr))) 35662306a36Sopenharmony_ci inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb, 35762306a36Sopenharmony_ci addr, new_addr, true); 35862306a36Sopenharmony_ci } else if (nh->protocol == IPPROTO_UDP) { 35962306a36Sopenharmony_ci if (likely(transport_len >= sizeof(struct udphdr))) { 36062306a36Sopenharmony_ci struct udphdr *uh = udp_hdr(skb); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { 36362306a36Sopenharmony_ci inet_proto_csum_replace4(&uh->check, skb, 36462306a36Sopenharmony_ci addr, new_addr, true); 36562306a36Sopenharmony_ci if (!uh->check) 36662306a36Sopenharmony_ci uh->check = CSUM_MANGLED_0; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, 37362306a36Sopenharmony_ci __be32 *addr, __be32 new_addr) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci update_ip_l4_checksum(skb, nh, *addr, new_addr); 37662306a36Sopenharmony_ci csum_replace4(&nh->check, *addr, new_addr); 37762306a36Sopenharmony_ci skb_clear_hash(skb); 37862306a36Sopenharmony_ci ovs_ct_clear(skb, NULL); 37962306a36Sopenharmony_ci *addr = new_addr; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto, 38362306a36Sopenharmony_ci __be32 addr[4], const __be32 new_addr[4]) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci int transport_len = skb->len - skb_transport_offset(skb); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (l4_proto == NEXTHDR_TCP) { 38862306a36Sopenharmony_ci if (likely(transport_len >= sizeof(struct tcphdr))) 38962306a36Sopenharmony_ci inet_proto_csum_replace16(&tcp_hdr(skb)->check, skb, 39062306a36Sopenharmony_ci addr, new_addr, true); 39162306a36Sopenharmony_ci } else if (l4_proto == NEXTHDR_UDP) { 39262306a36Sopenharmony_ci if (likely(transport_len >= sizeof(struct udphdr))) { 39362306a36Sopenharmony_ci struct udphdr *uh = udp_hdr(skb); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { 39662306a36Sopenharmony_ci inet_proto_csum_replace16(&uh->check, skb, 39762306a36Sopenharmony_ci addr, new_addr, true); 39862306a36Sopenharmony_ci if (!uh->check) 39962306a36Sopenharmony_ci uh->check = CSUM_MANGLED_0; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci } else if (l4_proto == NEXTHDR_ICMP) { 40362306a36Sopenharmony_ci if (likely(transport_len >= sizeof(struct icmp6hdr))) 40462306a36Sopenharmony_ci inet_proto_csum_replace16(&icmp6_hdr(skb)->icmp6_cksum, 40562306a36Sopenharmony_ci skb, addr, new_addr, true); 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic void mask_ipv6_addr(const __be32 old[4], const __be32 addr[4], 41062306a36Sopenharmony_ci const __be32 mask[4], __be32 masked[4]) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci masked[0] = OVS_MASKED(old[0], addr[0], mask[0]); 41362306a36Sopenharmony_ci masked[1] = OVS_MASKED(old[1], addr[1], mask[1]); 41462306a36Sopenharmony_ci masked[2] = OVS_MASKED(old[2], addr[2], mask[2]); 41562306a36Sopenharmony_ci masked[3] = OVS_MASKED(old[3], addr[3], mask[3]); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto, 41962306a36Sopenharmony_ci __be32 addr[4], const __be32 new_addr[4], 42062306a36Sopenharmony_ci bool recalculate_csum) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci if (recalculate_csum) 42362306a36Sopenharmony_ci update_ipv6_checksum(skb, l4_proto, addr, new_addr); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci skb_clear_hash(skb); 42662306a36Sopenharmony_ci ovs_ct_clear(skb, NULL); 42762306a36Sopenharmony_ci memcpy(addr, new_addr, sizeof(__be32[4])); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic void set_ipv6_dsfield(struct sk_buff *skb, struct ipv6hdr *nh, u8 ipv6_tclass, u8 mask) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci u8 old_ipv6_tclass = ipv6_get_dsfield(nh); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci ipv6_tclass = OVS_MASKED(old_ipv6_tclass, ipv6_tclass, mask); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_COMPLETE) 43762306a36Sopenharmony_ci csum_replace(&skb->csum, (__force __wsum)(old_ipv6_tclass << 12), 43862306a36Sopenharmony_ci (__force __wsum)(ipv6_tclass << 12)); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci ipv6_change_dsfield(nh, ~mask, ipv6_tclass); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic void set_ipv6_fl(struct sk_buff *skb, struct ipv6hdr *nh, u32 fl, u32 mask) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci u32 ofl; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci ofl = nh->flow_lbl[0] << 16 | nh->flow_lbl[1] << 8 | nh->flow_lbl[2]; 44862306a36Sopenharmony_ci fl = OVS_MASKED(ofl, fl, mask); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* Bits 21-24 are always unmasked, so this retains their values. */ 45162306a36Sopenharmony_ci nh->flow_lbl[0] = (u8)(fl >> 16); 45262306a36Sopenharmony_ci nh->flow_lbl[1] = (u8)(fl >> 8); 45362306a36Sopenharmony_ci nh->flow_lbl[2] = (u8)fl; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_COMPLETE) 45662306a36Sopenharmony_ci csum_replace(&skb->csum, (__force __wsum)htonl(ofl), (__force __wsum)htonl(fl)); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic void set_ipv6_ttl(struct sk_buff *skb, struct ipv6hdr *nh, u8 new_ttl, u8 mask) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci new_ttl = OVS_MASKED(nh->hop_limit, new_ttl, mask); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_COMPLETE) 46462306a36Sopenharmony_ci csum_replace(&skb->csum, (__force __wsum)(nh->hop_limit << 8), 46562306a36Sopenharmony_ci (__force __wsum)(new_ttl << 8)); 46662306a36Sopenharmony_ci nh->hop_limit = new_ttl; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl, 47062306a36Sopenharmony_ci u8 mask) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci new_ttl = OVS_MASKED(nh->ttl, new_ttl, mask); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8)); 47562306a36Sopenharmony_ci nh->ttl = new_ttl; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic int set_ipv4(struct sk_buff *skb, struct sw_flow_key *flow_key, 47962306a36Sopenharmony_ci const struct ovs_key_ipv4 *key, 48062306a36Sopenharmony_ci const struct ovs_key_ipv4 *mask) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct iphdr *nh; 48362306a36Sopenharmony_ci __be32 new_addr; 48462306a36Sopenharmony_ci int err; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci err = skb_ensure_writable(skb, skb_network_offset(skb) + 48762306a36Sopenharmony_ci sizeof(struct iphdr)); 48862306a36Sopenharmony_ci if (unlikely(err)) 48962306a36Sopenharmony_ci return err; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci nh = ip_hdr(skb); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* Setting an IP addresses is typically only a side effect of 49462306a36Sopenharmony_ci * matching on them in the current userspace implementation, so it 49562306a36Sopenharmony_ci * makes sense to check if the value actually changed. 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_ci if (mask->ipv4_src) { 49862306a36Sopenharmony_ci new_addr = OVS_MASKED(nh->saddr, key->ipv4_src, mask->ipv4_src); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (unlikely(new_addr != nh->saddr)) { 50162306a36Sopenharmony_ci set_ip_addr(skb, nh, &nh->saddr, new_addr); 50262306a36Sopenharmony_ci flow_key->ipv4.addr.src = new_addr; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci if (mask->ipv4_dst) { 50662306a36Sopenharmony_ci new_addr = OVS_MASKED(nh->daddr, key->ipv4_dst, mask->ipv4_dst); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (unlikely(new_addr != nh->daddr)) { 50962306a36Sopenharmony_ci set_ip_addr(skb, nh, &nh->daddr, new_addr); 51062306a36Sopenharmony_ci flow_key->ipv4.addr.dst = new_addr; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci if (mask->ipv4_tos) { 51462306a36Sopenharmony_ci ipv4_change_dsfield(nh, ~mask->ipv4_tos, key->ipv4_tos); 51562306a36Sopenharmony_ci flow_key->ip.tos = nh->tos; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci if (mask->ipv4_ttl) { 51862306a36Sopenharmony_ci set_ip_ttl(skb, nh, key->ipv4_ttl, mask->ipv4_ttl); 51962306a36Sopenharmony_ci flow_key->ip.ttl = nh->ttl; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic bool is_ipv6_mask_nonzero(const __be32 addr[4]) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci return !!(addr[0] | addr[1] | addr[2] | addr[3]); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key, 53162306a36Sopenharmony_ci const struct ovs_key_ipv6 *key, 53262306a36Sopenharmony_ci const struct ovs_key_ipv6 *mask) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct ipv6hdr *nh; 53562306a36Sopenharmony_ci int err; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci err = skb_ensure_writable(skb, skb_network_offset(skb) + 53862306a36Sopenharmony_ci sizeof(struct ipv6hdr)); 53962306a36Sopenharmony_ci if (unlikely(err)) 54062306a36Sopenharmony_ci return err; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci nh = ipv6_hdr(skb); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* Setting an IP addresses is typically only a side effect of 54562306a36Sopenharmony_ci * matching on them in the current userspace implementation, so it 54662306a36Sopenharmony_ci * makes sense to check if the value actually changed. 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_ci if (is_ipv6_mask_nonzero(mask->ipv6_src)) { 54962306a36Sopenharmony_ci __be32 *saddr = (__be32 *)&nh->saddr; 55062306a36Sopenharmony_ci __be32 masked[4]; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci mask_ipv6_addr(saddr, key->ipv6_src, mask->ipv6_src, masked); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (unlikely(memcmp(saddr, masked, sizeof(masked)))) { 55562306a36Sopenharmony_ci set_ipv6_addr(skb, flow_key->ip.proto, saddr, masked, 55662306a36Sopenharmony_ci true); 55762306a36Sopenharmony_ci memcpy(&flow_key->ipv6.addr.src, masked, 55862306a36Sopenharmony_ci sizeof(flow_key->ipv6.addr.src)); 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci if (is_ipv6_mask_nonzero(mask->ipv6_dst)) { 56262306a36Sopenharmony_ci unsigned int offset = 0; 56362306a36Sopenharmony_ci int flags = IP6_FH_F_SKIP_RH; 56462306a36Sopenharmony_ci bool recalc_csum = true; 56562306a36Sopenharmony_ci __be32 *daddr = (__be32 *)&nh->daddr; 56662306a36Sopenharmony_ci __be32 masked[4]; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci mask_ipv6_addr(daddr, key->ipv6_dst, mask->ipv6_dst, masked); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (unlikely(memcmp(daddr, masked, sizeof(masked)))) { 57162306a36Sopenharmony_ci if (ipv6_ext_hdr(nh->nexthdr)) 57262306a36Sopenharmony_ci recalc_csum = (ipv6_find_hdr(skb, &offset, 57362306a36Sopenharmony_ci NEXTHDR_ROUTING, 57462306a36Sopenharmony_ci NULL, &flags) 57562306a36Sopenharmony_ci != NEXTHDR_ROUTING); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci set_ipv6_addr(skb, flow_key->ip.proto, daddr, masked, 57862306a36Sopenharmony_ci recalc_csum); 57962306a36Sopenharmony_ci memcpy(&flow_key->ipv6.addr.dst, masked, 58062306a36Sopenharmony_ci sizeof(flow_key->ipv6.addr.dst)); 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci if (mask->ipv6_tclass) { 58462306a36Sopenharmony_ci set_ipv6_dsfield(skb, nh, key->ipv6_tclass, mask->ipv6_tclass); 58562306a36Sopenharmony_ci flow_key->ip.tos = ipv6_get_dsfield(nh); 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci if (mask->ipv6_label) { 58862306a36Sopenharmony_ci set_ipv6_fl(skb, nh, ntohl(key->ipv6_label), 58962306a36Sopenharmony_ci ntohl(mask->ipv6_label)); 59062306a36Sopenharmony_ci flow_key->ipv6.label = 59162306a36Sopenharmony_ci *(__be32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL); 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci if (mask->ipv6_hlimit) { 59462306a36Sopenharmony_ci set_ipv6_ttl(skb, nh, key->ipv6_hlimit, mask->ipv6_hlimit); 59562306a36Sopenharmony_ci flow_key->ip.ttl = nh->hop_limit; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci return 0; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic int set_nsh(struct sk_buff *skb, struct sw_flow_key *flow_key, 60162306a36Sopenharmony_ci const struct nlattr *a) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci struct nshhdr *nh; 60462306a36Sopenharmony_ci size_t length; 60562306a36Sopenharmony_ci int err; 60662306a36Sopenharmony_ci u8 flags; 60762306a36Sopenharmony_ci u8 ttl; 60862306a36Sopenharmony_ci int i; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci struct ovs_key_nsh key; 61162306a36Sopenharmony_ci struct ovs_key_nsh mask; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci err = nsh_key_from_nlattr(a, &key, &mask); 61462306a36Sopenharmony_ci if (err) 61562306a36Sopenharmony_ci return err; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* Make sure the NSH base header is there */ 61862306a36Sopenharmony_ci if (!pskb_may_pull(skb, skb_network_offset(skb) + NSH_BASE_HDR_LEN)) 61962306a36Sopenharmony_ci return -ENOMEM; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci nh = nsh_hdr(skb); 62262306a36Sopenharmony_ci length = nsh_hdr_len(nh); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* Make sure the whole NSH header is there */ 62562306a36Sopenharmony_ci err = skb_ensure_writable(skb, skb_network_offset(skb) + 62662306a36Sopenharmony_ci length); 62762306a36Sopenharmony_ci if (unlikely(err)) 62862306a36Sopenharmony_ci return err; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci nh = nsh_hdr(skb); 63162306a36Sopenharmony_ci skb_postpull_rcsum(skb, nh, length); 63262306a36Sopenharmony_ci flags = nsh_get_flags(nh); 63362306a36Sopenharmony_ci flags = OVS_MASKED(flags, key.base.flags, mask.base.flags); 63462306a36Sopenharmony_ci flow_key->nsh.base.flags = flags; 63562306a36Sopenharmony_ci ttl = nsh_get_ttl(nh); 63662306a36Sopenharmony_ci ttl = OVS_MASKED(ttl, key.base.ttl, mask.base.ttl); 63762306a36Sopenharmony_ci flow_key->nsh.base.ttl = ttl; 63862306a36Sopenharmony_ci nsh_set_flags_and_ttl(nh, flags, ttl); 63962306a36Sopenharmony_ci nh->path_hdr = OVS_MASKED(nh->path_hdr, key.base.path_hdr, 64062306a36Sopenharmony_ci mask.base.path_hdr); 64162306a36Sopenharmony_ci flow_key->nsh.base.path_hdr = nh->path_hdr; 64262306a36Sopenharmony_ci switch (nh->mdtype) { 64362306a36Sopenharmony_ci case NSH_M_TYPE1: 64462306a36Sopenharmony_ci for (i = 0; i < NSH_MD1_CONTEXT_SIZE; i++) { 64562306a36Sopenharmony_ci nh->md1.context[i] = 64662306a36Sopenharmony_ci OVS_MASKED(nh->md1.context[i], key.context[i], 64762306a36Sopenharmony_ci mask.context[i]); 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci memcpy(flow_key->nsh.context, nh->md1.context, 65062306a36Sopenharmony_ci sizeof(nh->md1.context)); 65162306a36Sopenharmony_ci break; 65262306a36Sopenharmony_ci case NSH_M_TYPE2: 65362306a36Sopenharmony_ci memset(flow_key->nsh.context, 0, 65462306a36Sopenharmony_ci sizeof(flow_key->nsh.context)); 65562306a36Sopenharmony_ci break; 65662306a36Sopenharmony_ci default: 65762306a36Sopenharmony_ci return -EINVAL; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci skb_postpush_rcsum(skb, nh, length); 66062306a36Sopenharmony_ci return 0; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci/* Must follow skb_ensure_writable() since that can move the skb data. */ 66462306a36Sopenharmony_cistatic void set_tp_port(struct sk_buff *skb, __be16 *port, 66562306a36Sopenharmony_ci __be16 new_port, __sum16 *check) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci ovs_ct_clear(skb, NULL); 66862306a36Sopenharmony_ci inet_proto_csum_replace2(check, skb, *port, new_port, false); 66962306a36Sopenharmony_ci *port = new_port; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic int set_udp(struct sk_buff *skb, struct sw_flow_key *flow_key, 67362306a36Sopenharmony_ci const struct ovs_key_udp *key, 67462306a36Sopenharmony_ci const struct ovs_key_udp *mask) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci struct udphdr *uh; 67762306a36Sopenharmony_ci __be16 src, dst; 67862306a36Sopenharmony_ci int err; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci err = skb_ensure_writable(skb, skb_transport_offset(skb) + 68162306a36Sopenharmony_ci sizeof(struct udphdr)); 68262306a36Sopenharmony_ci if (unlikely(err)) 68362306a36Sopenharmony_ci return err; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci uh = udp_hdr(skb); 68662306a36Sopenharmony_ci /* Either of the masks is non-zero, so do not bother checking them. */ 68762306a36Sopenharmony_ci src = OVS_MASKED(uh->source, key->udp_src, mask->udp_src); 68862306a36Sopenharmony_ci dst = OVS_MASKED(uh->dest, key->udp_dst, mask->udp_dst); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (uh->check && skb->ip_summed != CHECKSUM_PARTIAL) { 69162306a36Sopenharmony_ci if (likely(src != uh->source)) { 69262306a36Sopenharmony_ci set_tp_port(skb, &uh->source, src, &uh->check); 69362306a36Sopenharmony_ci flow_key->tp.src = src; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci if (likely(dst != uh->dest)) { 69662306a36Sopenharmony_ci set_tp_port(skb, &uh->dest, dst, &uh->check); 69762306a36Sopenharmony_ci flow_key->tp.dst = dst; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci if (unlikely(!uh->check)) 70162306a36Sopenharmony_ci uh->check = CSUM_MANGLED_0; 70262306a36Sopenharmony_ci } else { 70362306a36Sopenharmony_ci uh->source = src; 70462306a36Sopenharmony_ci uh->dest = dst; 70562306a36Sopenharmony_ci flow_key->tp.src = src; 70662306a36Sopenharmony_ci flow_key->tp.dst = dst; 70762306a36Sopenharmony_ci ovs_ct_clear(skb, NULL); 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci skb_clear_hash(skb); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return 0; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic int set_tcp(struct sk_buff *skb, struct sw_flow_key *flow_key, 71662306a36Sopenharmony_ci const struct ovs_key_tcp *key, 71762306a36Sopenharmony_ci const struct ovs_key_tcp *mask) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct tcphdr *th; 72062306a36Sopenharmony_ci __be16 src, dst; 72162306a36Sopenharmony_ci int err; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci err = skb_ensure_writable(skb, skb_transport_offset(skb) + 72462306a36Sopenharmony_ci sizeof(struct tcphdr)); 72562306a36Sopenharmony_ci if (unlikely(err)) 72662306a36Sopenharmony_ci return err; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci th = tcp_hdr(skb); 72962306a36Sopenharmony_ci src = OVS_MASKED(th->source, key->tcp_src, mask->tcp_src); 73062306a36Sopenharmony_ci if (likely(src != th->source)) { 73162306a36Sopenharmony_ci set_tp_port(skb, &th->source, src, &th->check); 73262306a36Sopenharmony_ci flow_key->tp.src = src; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci dst = OVS_MASKED(th->dest, key->tcp_dst, mask->tcp_dst); 73562306a36Sopenharmony_ci if (likely(dst != th->dest)) { 73662306a36Sopenharmony_ci set_tp_port(skb, &th->dest, dst, &th->check); 73762306a36Sopenharmony_ci flow_key->tp.dst = dst; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci skb_clear_hash(skb); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci return 0; 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic int set_sctp(struct sk_buff *skb, struct sw_flow_key *flow_key, 74562306a36Sopenharmony_ci const struct ovs_key_sctp *key, 74662306a36Sopenharmony_ci const struct ovs_key_sctp *mask) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci unsigned int sctphoff = skb_transport_offset(skb); 74962306a36Sopenharmony_ci struct sctphdr *sh; 75062306a36Sopenharmony_ci __le32 old_correct_csum, new_csum, old_csum; 75162306a36Sopenharmony_ci int err; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci err = skb_ensure_writable(skb, sctphoff + sizeof(struct sctphdr)); 75462306a36Sopenharmony_ci if (unlikely(err)) 75562306a36Sopenharmony_ci return err; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci sh = sctp_hdr(skb); 75862306a36Sopenharmony_ci old_csum = sh->checksum; 75962306a36Sopenharmony_ci old_correct_csum = sctp_compute_cksum(skb, sctphoff); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci sh->source = OVS_MASKED(sh->source, key->sctp_src, mask->sctp_src); 76262306a36Sopenharmony_ci sh->dest = OVS_MASKED(sh->dest, key->sctp_dst, mask->sctp_dst); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci new_csum = sctp_compute_cksum(skb, sctphoff); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* Carry any checksum errors through. */ 76762306a36Sopenharmony_ci sh->checksum = old_csum ^ old_correct_csum ^ new_csum; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci skb_clear_hash(skb); 77062306a36Sopenharmony_ci ovs_ct_clear(skb, NULL); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci flow_key->tp.src = sh->source; 77362306a36Sopenharmony_ci flow_key->tp.dst = sh->dest; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci return 0; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic int ovs_vport_output(struct net *net, struct sock *sk, 77962306a36Sopenharmony_ci struct sk_buff *skb) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci struct ovs_frag_data *data = this_cpu_ptr(&ovs_frag_data_storage); 78262306a36Sopenharmony_ci struct vport *vport = data->vport; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (skb_cow_head(skb, data->l2_len) < 0) { 78562306a36Sopenharmony_ci kfree_skb_reason(skb, SKB_DROP_REASON_NOMEM); 78662306a36Sopenharmony_ci return -ENOMEM; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci __skb_dst_copy(skb, data->dst); 79062306a36Sopenharmony_ci *OVS_CB(skb) = data->cb; 79162306a36Sopenharmony_ci skb->inner_protocol = data->inner_protocol; 79262306a36Sopenharmony_ci if (data->vlan_tci & VLAN_CFI_MASK) 79362306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, data->vlan_proto, data->vlan_tci & ~VLAN_CFI_MASK); 79462306a36Sopenharmony_ci else 79562306a36Sopenharmony_ci __vlan_hwaccel_clear_tag(skb); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci /* Reconstruct the MAC header. */ 79862306a36Sopenharmony_ci skb_push(skb, data->l2_len); 79962306a36Sopenharmony_ci memcpy(skb->data, &data->l2_data, data->l2_len); 80062306a36Sopenharmony_ci skb_postpush_rcsum(skb, skb->data, data->l2_len); 80162306a36Sopenharmony_ci skb_reset_mac_header(skb); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (eth_p_mpls(skb->protocol)) { 80462306a36Sopenharmony_ci skb->inner_network_header = skb->network_header; 80562306a36Sopenharmony_ci skb_set_network_header(skb, data->network_offset); 80662306a36Sopenharmony_ci skb_reset_mac_len(skb); 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci ovs_vport_send(vport, skb, data->mac_proto); 81062306a36Sopenharmony_ci return 0; 81162306a36Sopenharmony_ci} 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cistatic unsigned int 81462306a36Sopenharmony_ciovs_dst_get_mtu(const struct dst_entry *dst) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci return dst->dev->mtu; 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cistatic struct dst_ops ovs_dst_ops = { 82062306a36Sopenharmony_ci .family = AF_UNSPEC, 82162306a36Sopenharmony_ci .mtu = ovs_dst_get_mtu, 82262306a36Sopenharmony_ci}; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci/* prepare_frag() is called once per (larger-than-MTU) frame; its inverse is 82562306a36Sopenharmony_ci * ovs_vport_output(), which is called once per fragmented packet. 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_cistatic void prepare_frag(struct vport *vport, struct sk_buff *skb, 82862306a36Sopenharmony_ci u16 orig_network_offset, u8 mac_proto) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci unsigned int hlen = skb_network_offset(skb); 83162306a36Sopenharmony_ci struct ovs_frag_data *data; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci data = this_cpu_ptr(&ovs_frag_data_storage); 83462306a36Sopenharmony_ci data->dst = skb->_skb_refdst; 83562306a36Sopenharmony_ci data->vport = vport; 83662306a36Sopenharmony_ci data->cb = *OVS_CB(skb); 83762306a36Sopenharmony_ci data->inner_protocol = skb->inner_protocol; 83862306a36Sopenharmony_ci data->network_offset = orig_network_offset; 83962306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) 84062306a36Sopenharmony_ci data->vlan_tci = skb_vlan_tag_get(skb) | VLAN_CFI_MASK; 84162306a36Sopenharmony_ci else 84262306a36Sopenharmony_ci data->vlan_tci = 0; 84362306a36Sopenharmony_ci data->vlan_proto = skb->vlan_proto; 84462306a36Sopenharmony_ci data->mac_proto = mac_proto; 84562306a36Sopenharmony_ci data->l2_len = hlen; 84662306a36Sopenharmony_ci memcpy(&data->l2_data, skb->data, hlen); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); 84962306a36Sopenharmony_ci skb_pull(skb, hlen); 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_cistatic void ovs_fragment(struct net *net, struct vport *vport, 85362306a36Sopenharmony_ci struct sk_buff *skb, u16 mru, 85462306a36Sopenharmony_ci struct sw_flow_key *key) 85562306a36Sopenharmony_ci{ 85662306a36Sopenharmony_ci enum ovs_drop_reason reason; 85762306a36Sopenharmony_ci u16 orig_network_offset = 0; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (eth_p_mpls(skb->protocol)) { 86062306a36Sopenharmony_ci orig_network_offset = skb_network_offset(skb); 86162306a36Sopenharmony_ci skb->network_header = skb->inner_network_header; 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci if (skb_network_offset(skb) > MAX_L2_LEN) { 86562306a36Sopenharmony_ci OVS_NLERR(1, "L2 header too long to fragment"); 86662306a36Sopenharmony_ci reason = OVS_DROP_FRAG_L2_TOO_LONG; 86762306a36Sopenharmony_ci goto err; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (key->eth.type == htons(ETH_P_IP)) { 87162306a36Sopenharmony_ci struct rtable ovs_rt = { 0 }; 87262306a36Sopenharmony_ci unsigned long orig_dst; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci prepare_frag(vport, skb, orig_network_offset, 87562306a36Sopenharmony_ci ovs_key_mac_proto(key)); 87662306a36Sopenharmony_ci dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1, 87762306a36Sopenharmony_ci DST_OBSOLETE_NONE, DST_NOCOUNT); 87862306a36Sopenharmony_ci ovs_rt.dst.dev = vport->dev; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci orig_dst = skb->_skb_refdst; 88162306a36Sopenharmony_ci skb_dst_set_noref(skb, &ovs_rt.dst); 88262306a36Sopenharmony_ci IPCB(skb)->frag_max_size = mru; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci ip_do_fragment(net, skb->sk, skb, ovs_vport_output); 88562306a36Sopenharmony_ci refdst_drop(orig_dst); 88662306a36Sopenharmony_ci } else if (key->eth.type == htons(ETH_P_IPV6)) { 88762306a36Sopenharmony_ci unsigned long orig_dst; 88862306a36Sopenharmony_ci struct rt6_info ovs_rt; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci prepare_frag(vport, skb, orig_network_offset, 89162306a36Sopenharmony_ci ovs_key_mac_proto(key)); 89262306a36Sopenharmony_ci memset(&ovs_rt, 0, sizeof(ovs_rt)); 89362306a36Sopenharmony_ci dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1, 89462306a36Sopenharmony_ci DST_OBSOLETE_NONE, DST_NOCOUNT); 89562306a36Sopenharmony_ci ovs_rt.dst.dev = vport->dev; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci orig_dst = skb->_skb_refdst; 89862306a36Sopenharmony_ci skb_dst_set_noref(skb, &ovs_rt.dst); 89962306a36Sopenharmony_ci IP6CB(skb)->frag_max_size = mru; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci ipv6_stub->ipv6_fragment(net, skb->sk, skb, ovs_vport_output); 90262306a36Sopenharmony_ci refdst_drop(orig_dst); 90362306a36Sopenharmony_ci } else { 90462306a36Sopenharmony_ci WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.", 90562306a36Sopenharmony_ci ovs_vport_name(vport), ntohs(key->eth.type), mru, 90662306a36Sopenharmony_ci vport->dev->mtu); 90762306a36Sopenharmony_ci reason = OVS_DROP_FRAG_INVALID_PROTO; 90862306a36Sopenharmony_ci goto err; 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return; 91262306a36Sopenharmony_cierr: 91362306a36Sopenharmony_ci ovs_kfree_skb_reason(skb, reason); 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic void do_output(struct datapath *dp, struct sk_buff *skb, int out_port, 91762306a36Sopenharmony_ci struct sw_flow_key *key) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci struct vport *vport = ovs_vport_rcu(dp, out_port); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci if (likely(vport && netif_carrier_ok(vport->dev))) { 92262306a36Sopenharmony_ci u16 mru = OVS_CB(skb)->mru; 92362306a36Sopenharmony_ci u32 cutlen = OVS_CB(skb)->cutlen; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (unlikely(cutlen > 0)) { 92662306a36Sopenharmony_ci if (skb->len - cutlen > ovs_mac_header_len(key)) 92762306a36Sopenharmony_ci pskb_trim(skb, skb->len - cutlen); 92862306a36Sopenharmony_ci else 92962306a36Sopenharmony_ci pskb_trim(skb, ovs_mac_header_len(key)); 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (likely(!mru || 93362306a36Sopenharmony_ci (skb->len <= mru + vport->dev->hard_header_len))) { 93462306a36Sopenharmony_ci ovs_vport_send(vport, skb, ovs_key_mac_proto(key)); 93562306a36Sopenharmony_ci } else if (mru <= vport->dev->mtu) { 93662306a36Sopenharmony_ci struct net *net = read_pnet(&dp->net); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci ovs_fragment(net, vport, skb, mru, key); 93962306a36Sopenharmony_ci } else { 94062306a36Sopenharmony_ci kfree_skb_reason(skb, SKB_DROP_REASON_PKT_TOO_BIG); 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci } else { 94362306a36Sopenharmony_ci kfree_skb_reason(skb, SKB_DROP_REASON_DEV_READY); 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci} 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_cistatic int output_userspace(struct datapath *dp, struct sk_buff *skb, 94862306a36Sopenharmony_ci struct sw_flow_key *key, const struct nlattr *attr, 94962306a36Sopenharmony_ci const struct nlattr *actions, int actions_len, 95062306a36Sopenharmony_ci uint32_t cutlen) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci struct dp_upcall_info upcall; 95362306a36Sopenharmony_ci const struct nlattr *a; 95462306a36Sopenharmony_ci int rem; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci memset(&upcall, 0, sizeof(upcall)); 95762306a36Sopenharmony_ci upcall.cmd = OVS_PACKET_CMD_ACTION; 95862306a36Sopenharmony_ci upcall.mru = OVS_CB(skb)->mru; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci for (a = nla_data(attr), rem = nla_len(attr); rem > 0; 96162306a36Sopenharmony_ci a = nla_next(a, &rem)) { 96262306a36Sopenharmony_ci switch (nla_type(a)) { 96362306a36Sopenharmony_ci case OVS_USERSPACE_ATTR_USERDATA: 96462306a36Sopenharmony_ci upcall.userdata = a; 96562306a36Sopenharmony_ci break; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci case OVS_USERSPACE_ATTR_PID: 96862306a36Sopenharmony_ci if (dp->user_features & 96962306a36Sopenharmony_ci OVS_DP_F_DISPATCH_UPCALL_PER_CPU) 97062306a36Sopenharmony_ci upcall.portid = 97162306a36Sopenharmony_ci ovs_dp_get_upcall_portid(dp, 97262306a36Sopenharmony_ci smp_processor_id()); 97362306a36Sopenharmony_ci else 97462306a36Sopenharmony_ci upcall.portid = nla_get_u32(a); 97562306a36Sopenharmony_ci break; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci case OVS_USERSPACE_ATTR_EGRESS_TUN_PORT: { 97862306a36Sopenharmony_ci /* Get out tunnel info. */ 97962306a36Sopenharmony_ci struct vport *vport; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci vport = ovs_vport_rcu(dp, nla_get_u32(a)); 98262306a36Sopenharmony_ci if (vport) { 98362306a36Sopenharmony_ci int err; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci err = dev_fill_metadata_dst(vport->dev, skb); 98662306a36Sopenharmony_ci if (!err) 98762306a36Sopenharmony_ci upcall.egress_tun_info = skb_tunnel_info(skb); 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci break; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci case OVS_USERSPACE_ATTR_ACTIONS: { 99462306a36Sopenharmony_ci /* Include actions. */ 99562306a36Sopenharmony_ci upcall.actions = actions; 99662306a36Sopenharmony_ci upcall.actions_len = actions_len; 99762306a36Sopenharmony_ci break; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci } /* End of switch. */ 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci return ovs_dp_upcall(dp, skb, key, &upcall, cutlen); 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic int dec_ttl_exception_handler(struct datapath *dp, struct sk_buff *skb, 100762306a36Sopenharmony_ci struct sw_flow_key *key, 100862306a36Sopenharmony_ci const struct nlattr *attr) 100962306a36Sopenharmony_ci{ 101062306a36Sopenharmony_ci /* The first attribute is always 'OVS_DEC_TTL_ATTR_ACTION'. */ 101162306a36Sopenharmony_ci struct nlattr *actions = nla_data(attr); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci if (nla_len(actions)) 101462306a36Sopenharmony_ci return clone_execute(dp, skb, key, 0, nla_data(actions), 101562306a36Sopenharmony_ci nla_len(actions), true, false); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci ovs_kfree_skb_reason(skb, OVS_DROP_IP_TTL); 101862306a36Sopenharmony_ci return 0; 101962306a36Sopenharmony_ci} 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci/* When 'last' is true, sample() should always consume the 'skb'. 102262306a36Sopenharmony_ci * Otherwise, sample() should keep 'skb' intact regardless what 102362306a36Sopenharmony_ci * actions are executed within sample(). 102462306a36Sopenharmony_ci */ 102562306a36Sopenharmony_cistatic int sample(struct datapath *dp, struct sk_buff *skb, 102662306a36Sopenharmony_ci struct sw_flow_key *key, const struct nlattr *attr, 102762306a36Sopenharmony_ci bool last) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci struct nlattr *actions; 103062306a36Sopenharmony_ci struct nlattr *sample_arg; 103162306a36Sopenharmony_ci int rem = nla_len(attr); 103262306a36Sopenharmony_ci const struct sample_arg *arg; 103362306a36Sopenharmony_ci bool clone_flow_key; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci /* The first action is always 'OVS_SAMPLE_ATTR_ARG'. */ 103662306a36Sopenharmony_ci sample_arg = nla_data(attr); 103762306a36Sopenharmony_ci arg = nla_data(sample_arg); 103862306a36Sopenharmony_ci actions = nla_next(sample_arg, &rem); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci if ((arg->probability != U32_MAX) && 104162306a36Sopenharmony_ci (!arg->probability || get_random_u32() > arg->probability)) { 104262306a36Sopenharmony_ci if (last) 104362306a36Sopenharmony_ci ovs_kfree_skb_reason(skb, OVS_DROP_LAST_ACTION); 104462306a36Sopenharmony_ci return 0; 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci clone_flow_key = !arg->exec; 104862306a36Sopenharmony_ci return clone_execute(dp, skb, key, 0, actions, rem, last, 104962306a36Sopenharmony_ci clone_flow_key); 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci/* When 'last' is true, clone() should always consume the 'skb'. 105362306a36Sopenharmony_ci * Otherwise, clone() should keep 'skb' intact regardless what 105462306a36Sopenharmony_ci * actions are executed within clone(). 105562306a36Sopenharmony_ci */ 105662306a36Sopenharmony_cistatic int clone(struct datapath *dp, struct sk_buff *skb, 105762306a36Sopenharmony_ci struct sw_flow_key *key, const struct nlattr *attr, 105862306a36Sopenharmony_ci bool last) 105962306a36Sopenharmony_ci{ 106062306a36Sopenharmony_ci struct nlattr *actions; 106162306a36Sopenharmony_ci struct nlattr *clone_arg; 106262306a36Sopenharmony_ci int rem = nla_len(attr); 106362306a36Sopenharmony_ci bool dont_clone_flow_key; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci /* The first action is always 'OVS_CLONE_ATTR_EXEC'. */ 106662306a36Sopenharmony_ci clone_arg = nla_data(attr); 106762306a36Sopenharmony_ci dont_clone_flow_key = nla_get_u32(clone_arg); 106862306a36Sopenharmony_ci actions = nla_next(clone_arg, &rem); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci return clone_execute(dp, skb, key, 0, actions, rem, last, 107162306a36Sopenharmony_ci !dont_clone_flow_key); 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cistatic void execute_hash(struct sk_buff *skb, struct sw_flow_key *key, 107562306a36Sopenharmony_ci const struct nlattr *attr) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci struct ovs_action_hash *hash_act = nla_data(attr); 107862306a36Sopenharmony_ci u32 hash = 0; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (hash_act->hash_alg == OVS_HASH_ALG_L4) { 108162306a36Sopenharmony_ci /* OVS_HASH_ALG_L4 hasing type. */ 108262306a36Sopenharmony_ci hash = skb_get_hash(skb); 108362306a36Sopenharmony_ci } else if (hash_act->hash_alg == OVS_HASH_ALG_SYM_L4) { 108462306a36Sopenharmony_ci /* OVS_HASH_ALG_SYM_L4 hashing type. NOTE: this doesn't 108562306a36Sopenharmony_ci * extend past an encapsulated header. 108662306a36Sopenharmony_ci */ 108762306a36Sopenharmony_ci hash = __skb_get_hash_symmetric(skb); 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci hash = jhash_1word(hash, hash_act->hash_basis); 109162306a36Sopenharmony_ci if (!hash) 109262306a36Sopenharmony_ci hash = 0x1; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci key->ovs_flow_hash = hash; 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic int execute_set_action(struct sk_buff *skb, 109862306a36Sopenharmony_ci struct sw_flow_key *flow_key, 109962306a36Sopenharmony_ci const struct nlattr *a) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci /* Only tunnel set execution is supported without a mask. */ 110262306a36Sopenharmony_ci if (nla_type(a) == OVS_KEY_ATTR_TUNNEL_INFO) { 110362306a36Sopenharmony_ci struct ovs_tunnel_info *tun = nla_data(a); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci skb_dst_drop(skb); 110662306a36Sopenharmony_ci dst_hold((struct dst_entry *)tun->tun_dst); 110762306a36Sopenharmony_ci skb_dst_set(skb, (struct dst_entry *)tun->tun_dst); 110862306a36Sopenharmony_ci return 0; 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci return -EINVAL; 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci/* Mask is at the midpoint of the data. */ 111562306a36Sopenharmony_ci#define get_mask(a, type) ((const type)nla_data(a) + 1) 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cistatic int execute_masked_set_action(struct sk_buff *skb, 111862306a36Sopenharmony_ci struct sw_flow_key *flow_key, 111962306a36Sopenharmony_ci const struct nlattr *a) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci int err = 0; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci switch (nla_type(a)) { 112462306a36Sopenharmony_ci case OVS_KEY_ATTR_PRIORITY: 112562306a36Sopenharmony_ci OVS_SET_MASKED(skb->priority, nla_get_u32(a), 112662306a36Sopenharmony_ci *get_mask(a, u32 *)); 112762306a36Sopenharmony_ci flow_key->phy.priority = skb->priority; 112862306a36Sopenharmony_ci break; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci case OVS_KEY_ATTR_SKB_MARK: 113162306a36Sopenharmony_ci OVS_SET_MASKED(skb->mark, nla_get_u32(a), *get_mask(a, u32 *)); 113262306a36Sopenharmony_ci flow_key->phy.skb_mark = skb->mark; 113362306a36Sopenharmony_ci break; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci case OVS_KEY_ATTR_TUNNEL_INFO: 113662306a36Sopenharmony_ci /* Masked data not supported for tunnel. */ 113762306a36Sopenharmony_ci err = -EINVAL; 113862306a36Sopenharmony_ci break; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci case OVS_KEY_ATTR_ETHERNET: 114162306a36Sopenharmony_ci err = set_eth_addr(skb, flow_key, nla_data(a), 114262306a36Sopenharmony_ci get_mask(a, struct ovs_key_ethernet *)); 114362306a36Sopenharmony_ci break; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci case OVS_KEY_ATTR_NSH: 114662306a36Sopenharmony_ci err = set_nsh(skb, flow_key, a); 114762306a36Sopenharmony_ci break; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci case OVS_KEY_ATTR_IPV4: 115062306a36Sopenharmony_ci err = set_ipv4(skb, flow_key, nla_data(a), 115162306a36Sopenharmony_ci get_mask(a, struct ovs_key_ipv4 *)); 115262306a36Sopenharmony_ci break; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci case OVS_KEY_ATTR_IPV6: 115562306a36Sopenharmony_ci err = set_ipv6(skb, flow_key, nla_data(a), 115662306a36Sopenharmony_ci get_mask(a, struct ovs_key_ipv6 *)); 115762306a36Sopenharmony_ci break; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci case OVS_KEY_ATTR_TCP: 116062306a36Sopenharmony_ci err = set_tcp(skb, flow_key, nla_data(a), 116162306a36Sopenharmony_ci get_mask(a, struct ovs_key_tcp *)); 116262306a36Sopenharmony_ci break; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci case OVS_KEY_ATTR_UDP: 116562306a36Sopenharmony_ci err = set_udp(skb, flow_key, nla_data(a), 116662306a36Sopenharmony_ci get_mask(a, struct ovs_key_udp *)); 116762306a36Sopenharmony_ci break; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci case OVS_KEY_ATTR_SCTP: 117062306a36Sopenharmony_ci err = set_sctp(skb, flow_key, nla_data(a), 117162306a36Sopenharmony_ci get_mask(a, struct ovs_key_sctp *)); 117262306a36Sopenharmony_ci break; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci case OVS_KEY_ATTR_MPLS: 117562306a36Sopenharmony_ci err = set_mpls(skb, flow_key, nla_data(a), get_mask(a, 117662306a36Sopenharmony_ci __be32 *)); 117762306a36Sopenharmony_ci break; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci case OVS_KEY_ATTR_CT_STATE: 118062306a36Sopenharmony_ci case OVS_KEY_ATTR_CT_ZONE: 118162306a36Sopenharmony_ci case OVS_KEY_ATTR_CT_MARK: 118262306a36Sopenharmony_ci case OVS_KEY_ATTR_CT_LABELS: 118362306a36Sopenharmony_ci case OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4: 118462306a36Sopenharmony_ci case OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6: 118562306a36Sopenharmony_ci err = -EINVAL; 118662306a36Sopenharmony_ci break; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci return err; 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cistatic int execute_recirc(struct datapath *dp, struct sk_buff *skb, 119362306a36Sopenharmony_ci struct sw_flow_key *key, 119462306a36Sopenharmony_ci const struct nlattr *a, bool last) 119562306a36Sopenharmony_ci{ 119662306a36Sopenharmony_ci u32 recirc_id; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci if (!is_flow_key_valid(key)) { 119962306a36Sopenharmony_ci int err; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci err = ovs_flow_key_update(skb, key); 120262306a36Sopenharmony_ci if (err) 120362306a36Sopenharmony_ci return err; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci BUG_ON(!is_flow_key_valid(key)); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci recirc_id = nla_get_u32(a); 120862306a36Sopenharmony_ci return clone_execute(dp, skb, key, recirc_id, NULL, 0, last, true); 120962306a36Sopenharmony_ci} 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_cistatic int execute_check_pkt_len(struct datapath *dp, struct sk_buff *skb, 121262306a36Sopenharmony_ci struct sw_flow_key *key, 121362306a36Sopenharmony_ci const struct nlattr *attr, bool last) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci struct ovs_skb_cb *ovs_cb = OVS_CB(skb); 121662306a36Sopenharmony_ci const struct nlattr *actions, *cpl_arg; 121762306a36Sopenharmony_ci int len, max_len, rem = nla_len(attr); 121862306a36Sopenharmony_ci const struct check_pkt_len_arg *arg; 121962306a36Sopenharmony_ci bool clone_flow_key; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci /* The first netlink attribute in 'attr' is always 122262306a36Sopenharmony_ci * 'OVS_CHECK_PKT_LEN_ATTR_ARG'. 122362306a36Sopenharmony_ci */ 122462306a36Sopenharmony_ci cpl_arg = nla_data(attr); 122562306a36Sopenharmony_ci arg = nla_data(cpl_arg); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci len = ovs_cb->mru ? ovs_cb->mru + skb->mac_len : skb->len; 122862306a36Sopenharmony_ci max_len = arg->pkt_len; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci if ((skb_is_gso(skb) && skb_gso_validate_mac_len(skb, max_len)) || 123162306a36Sopenharmony_ci len <= max_len) { 123262306a36Sopenharmony_ci /* Second netlink attribute in 'attr' is always 123362306a36Sopenharmony_ci * 'OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL'. 123462306a36Sopenharmony_ci */ 123562306a36Sopenharmony_ci actions = nla_next(cpl_arg, &rem); 123662306a36Sopenharmony_ci clone_flow_key = !arg->exec_for_lesser_equal; 123762306a36Sopenharmony_ci } else { 123862306a36Sopenharmony_ci /* Third netlink attribute in 'attr' is always 123962306a36Sopenharmony_ci * 'OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER'. 124062306a36Sopenharmony_ci */ 124162306a36Sopenharmony_ci actions = nla_next(cpl_arg, &rem); 124262306a36Sopenharmony_ci actions = nla_next(actions, &rem); 124362306a36Sopenharmony_ci clone_flow_key = !arg->exec_for_greater; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci return clone_execute(dp, skb, key, 0, nla_data(actions), 124762306a36Sopenharmony_ci nla_len(actions), last, clone_flow_key); 124862306a36Sopenharmony_ci} 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_cistatic int execute_dec_ttl(struct sk_buff *skb, struct sw_flow_key *key) 125162306a36Sopenharmony_ci{ 125262306a36Sopenharmony_ci int err; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IPV6)) { 125562306a36Sopenharmony_ci struct ipv6hdr *nh; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci err = skb_ensure_writable(skb, skb_network_offset(skb) + 125862306a36Sopenharmony_ci sizeof(*nh)); 125962306a36Sopenharmony_ci if (unlikely(err)) 126062306a36Sopenharmony_ci return err; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci nh = ipv6_hdr(skb); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci if (nh->hop_limit <= 1) 126562306a36Sopenharmony_ci return -EHOSTUNREACH; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci key->ip.ttl = --nh->hop_limit; 126862306a36Sopenharmony_ci } else if (skb->protocol == htons(ETH_P_IP)) { 126962306a36Sopenharmony_ci struct iphdr *nh; 127062306a36Sopenharmony_ci u8 old_ttl; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci err = skb_ensure_writable(skb, skb_network_offset(skb) + 127362306a36Sopenharmony_ci sizeof(*nh)); 127462306a36Sopenharmony_ci if (unlikely(err)) 127562306a36Sopenharmony_ci return err; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci nh = ip_hdr(skb); 127862306a36Sopenharmony_ci if (nh->ttl <= 1) 127962306a36Sopenharmony_ci return -EHOSTUNREACH; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci old_ttl = nh->ttl--; 128262306a36Sopenharmony_ci csum_replace2(&nh->check, htons(old_ttl << 8), 128362306a36Sopenharmony_ci htons(nh->ttl << 8)); 128462306a36Sopenharmony_ci key->ip.ttl = nh->ttl; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci return 0; 128762306a36Sopenharmony_ci} 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci/* Execute a list of actions against 'skb'. */ 129062306a36Sopenharmony_cistatic int do_execute_actions(struct datapath *dp, struct sk_buff *skb, 129162306a36Sopenharmony_ci struct sw_flow_key *key, 129262306a36Sopenharmony_ci const struct nlattr *attr, int len) 129362306a36Sopenharmony_ci{ 129462306a36Sopenharmony_ci const struct nlattr *a; 129562306a36Sopenharmony_ci int rem; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci for (a = attr, rem = len; rem > 0; 129862306a36Sopenharmony_ci a = nla_next(a, &rem)) { 129962306a36Sopenharmony_ci int err = 0; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci if (trace_ovs_do_execute_action_enabled()) 130262306a36Sopenharmony_ci trace_ovs_do_execute_action(dp, skb, key, a, rem); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci /* Actions that rightfully have to consume the skb should do it 130562306a36Sopenharmony_ci * and return directly. 130662306a36Sopenharmony_ci */ 130762306a36Sopenharmony_ci switch (nla_type(a)) { 130862306a36Sopenharmony_ci case OVS_ACTION_ATTR_OUTPUT: { 130962306a36Sopenharmony_ci int port = nla_get_u32(a); 131062306a36Sopenharmony_ci struct sk_buff *clone; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci /* Every output action needs a separate clone 131362306a36Sopenharmony_ci * of 'skb', In case the output action is the 131462306a36Sopenharmony_ci * last action, cloning can be avoided. 131562306a36Sopenharmony_ci */ 131662306a36Sopenharmony_ci if (nla_is_last(a, rem)) { 131762306a36Sopenharmony_ci do_output(dp, skb, port, key); 131862306a36Sopenharmony_ci /* 'skb' has been used for output. 131962306a36Sopenharmony_ci */ 132062306a36Sopenharmony_ci return 0; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci clone = skb_clone(skb, GFP_ATOMIC); 132462306a36Sopenharmony_ci if (clone) 132562306a36Sopenharmony_ci do_output(dp, clone, port, key); 132662306a36Sopenharmony_ci OVS_CB(skb)->cutlen = 0; 132762306a36Sopenharmony_ci break; 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci case OVS_ACTION_ATTR_TRUNC: { 133162306a36Sopenharmony_ci struct ovs_action_trunc *trunc = nla_data(a); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci if (skb->len > trunc->max_len) 133462306a36Sopenharmony_ci OVS_CB(skb)->cutlen = skb->len - trunc->max_len; 133562306a36Sopenharmony_ci break; 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci case OVS_ACTION_ATTR_USERSPACE: 133962306a36Sopenharmony_ci output_userspace(dp, skb, key, a, attr, 134062306a36Sopenharmony_ci len, OVS_CB(skb)->cutlen); 134162306a36Sopenharmony_ci OVS_CB(skb)->cutlen = 0; 134262306a36Sopenharmony_ci if (nla_is_last(a, rem)) { 134362306a36Sopenharmony_ci consume_skb(skb); 134462306a36Sopenharmony_ci return 0; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci break; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci case OVS_ACTION_ATTR_HASH: 134962306a36Sopenharmony_ci execute_hash(skb, key, a); 135062306a36Sopenharmony_ci break; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci case OVS_ACTION_ATTR_PUSH_MPLS: { 135362306a36Sopenharmony_ci struct ovs_action_push_mpls *mpls = nla_data(a); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci err = push_mpls(skb, key, mpls->mpls_lse, 135662306a36Sopenharmony_ci mpls->mpls_ethertype, skb->mac_len); 135762306a36Sopenharmony_ci break; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci case OVS_ACTION_ATTR_ADD_MPLS: { 136062306a36Sopenharmony_ci struct ovs_action_add_mpls *mpls = nla_data(a); 136162306a36Sopenharmony_ci __u16 mac_len = 0; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci if (mpls->tun_flags & OVS_MPLS_L3_TUNNEL_FLAG_MASK) 136462306a36Sopenharmony_ci mac_len = skb->mac_len; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci err = push_mpls(skb, key, mpls->mpls_lse, 136762306a36Sopenharmony_ci mpls->mpls_ethertype, mac_len); 136862306a36Sopenharmony_ci break; 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci case OVS_ACTION_ATTR_POP_MPLS: 137162306a36Sopenharmony_ci err = pop_mpls(skb, key, nla_get_be16(a)); 137262306a36Sopenharmony_ci break; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci case OVS_ACTION_ATTR_PUSH_VLAN: 137562306a36Sopenharmony_ci err = push_vlan(skb, key, nla_data(a)); 137662306a36Sopenharmony_ci break; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci case OVS_ACTION_ATTR_POP_VLAN: 137962306a36Sopenharmony_ci err = pop_vlan(skb, key); 138062306a36Sopenharmony_ci break; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci case OVS_ACTION_ATTR_RECIRC: { 138362306a36Sopenharmony_ci bool last = nla_is_last(a, rem); 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci err = execute_recirc(dp, skb, key, a, last); 138662306a36Sopenharmony_ci if (last) { 138762306a36Sopenharmony_ci /* If this is the last action, the skb has 138862306a36Sopenharmony_ci * been consumed or freed. 138962306a36Sopenharmony_ci * Return immediately. 139062306a36Sopenharmony_ci */ 139162306a36Sopenharmony_ci return err; 139262306a36Sopenharmony_ci } 139362306a36Sopenharmony_ci break; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci case OVS_ACTION_ATTR_SET: 139762306a36Sopenharmony_ci err = execute_set_action(skb, key, nla_data(a)); 139862306a36Sopenharmony_ci break; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci case OVS_ACTION_ATTR_SET_MASKED: 140162306a36Sopenharmony_ci case OVS_ACTION_ATTR_SET_TO_MASKED: 140262306a36Sopenharmony_ci err = execute_masked_set_action(skb, key, nla_data(a)); 140362306a36Sopenharmony_ci break; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci case OVS_ACTION_ATTR_SAMPLE: { 140662306a36Sopenharmony_ci bool last = nla_is_last(a, rem); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci err = sample(dp, skb, key, a, last); 140962306a36Sopenharmony_ci if (last) 141062306a36Sopenharmony_ci return err; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci break; 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci case OVS_ACTION_ATTR_CT: 141662306a36Sopenharmony_ci if (!is_flow_key_valid(key)) { 141762306a36Sopenharmony_ci err = ovs_flow_key_update(skb, key); 141862306a36Sopenharmony_ci if (err) 141962306a36Sopenharmony_ci return err; 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci err = ovs_ct_execute(ovs_dp_get_net(dp), skb, key, 142362306a36Sopenharmony_ci nla_data(a)); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci /* Hide stolen IP fragments from user space. */ 142662306a36Sopenharmony_ci if (err) 142762306a36Sopenharmony_ci return err == -EINPROGRESS ? 0 : err; 142862306a36Sopenharmony_ci break; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci case OVS_ACTION_ATTR_CT_CLEAR: 143162306a36Sopenharmony_ci err = ovs_ct_clear(skb, key); 143262306a36Sopenharmony_ci break; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci case OVS_ACTION_ATTR_PUSH_ETH: 143562306a36Sopenharmony_ci err = push_eth(skb, key, nla_data(a)); 143662306a36Sopenharmony_ci break; 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci case OVS_ACTION_ATTR_POP_ETH: 143962306a36Sopenharmony_ci err = pop_eth(skb, key); 144062306a36Sopenharmony_ci break; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci case OVS_ACTION_ATTR_PUSH_NSH: { 144362306a36Sopenharmony_ci u8 buffer[NSH_HDR_MAX_LEN]; 144462306a36Sopenharmony_ci struct nshhdr *nh = (struct nshhdr *)buffer; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci err = nsh_hdr_from_nlattr(nla_data(a), nh, 144762306a36Sopenharmony_ci NSH_HDR_MAX_LEN); 144862306a36Sopenharmony_ci if (unlikely(err)) 144962306a36Sopenharmony_ci break; 145062306a36Sopenharmony_ci err = push_nsh(skb, key, nh); 145162306a36Sopenharmony_ci break; 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci case OVS_ACTION_ATTR_POP_NSH: 145562306a36Sopenharmony_ci err = pop_nsh(skb, key); 145662306a36Sopenharmony_ci break; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci case OVS_ACTION_ATTR_METER: 145962306a36Sopenharmony_ci if (ovs_meter_execute(dp, skb, key, nla_get_u32(a))) { 146062306a36Sopenharmony_ci ovs_kfree_skb_reason(skb, OVS_DROP_METER); 146162306a36Sopenharmony_ci return 0; 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci break; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci case OVS_ACTION_ATTR_CLONE: { 146662306a36Sopenharmony_ci bool last = nla_is_last(a, rem); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci err = clone(dp, skb, key, a, last); 146962306a36Sopenharmony_ci if (last) 147062306a36Sopenharmony_ci return err; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci break; 147362306a36Sopenharmony_ci } 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci case OVS_ACTION_ATTR_CHECK_PKT_LEN: { 147662306a36Sopenharmony_ci bool last = nla_is_last(a, rem); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci err = execute_check_pkt_len(dp, skb, key, a, last); 147962306a36Sopenharmony_ci if (last) 148062306a36Sopenharmony_ci return err; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci break; 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci case OVS_ACTION_ATTR_DEC_TTL: 148662306a36Sopenharmony_ci err = execute_dec_ttl(skb, key); 148762306a36Sopenharmony_ci if (err == -EHOSTUNREACH) 148862306a36Sopenharmony_ci return dec_ttl_exception_handler(dp, skb, 148962306a36Sopenharmony_ci key, a); 149062306a36Sopenharmony_ci break; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci case OVS_ACTION_ATTR_DROP: { 149362306a36Sopenharmony_ci enum ovs_drop_reason reason = nla_get_u32(a) 149462306a36Sopenharmony_ci ? OVS_DROP_EXPLICIT_WITH_ERROR 149562306a36Sopenharmony_ci : OVS_DROP_EXPLICIT; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci ovs_kfree_skb_reason(skb, reason); 149862306a36Sopenharmony_ci return 0; 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci if (unlikely(err)) { 150362306a36Sopenharmony_ci ovs_kfree_skb_reason(skb, OVS_DROP_ACTION_ERROR); 150462306a36Sopenharmony_ci return err; 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci ovs_kfree_skb_reason(skb, OVS_DROP_LAST_ACTION); 150962306a36Sopenharmony_ci return 0; 151062306a36Sopenharmony_ci} 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci/* Execute the actions on the clone of the packet. The effect of the 151362306a36Sopenharmony_ci * execution does not affect the original 'skb' nor the original 'key'. 151462306a36Sopenharmony_ci * 151562306a36Sopenharmony_ci * The execution may be deferred in case the actions can not be executed 151662306a36Sopenharmony_ci * immediately. 151762306a36Sopenharmony_ci */ 151862306a36Sopenharmony_cistatic int clone_execute(struct datapath *dp, struct sk_buff *skb, 151962306a36Sopenharmony_ci struct sw_flow_key *key, u32 recirc_id, 152062306a36Sopenharmony_ci const struct nlattr *actions, int len, 152162306a36Sopenharmony_ci bool last, bool clone_flow_key) 152262306a36Sopenharmony_ci{ 152362306a36Sopenharmony_ci struct deferred_action *da; 152462306a36Sopenharmony_ci struct sw_flow_key *clone; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci skb = last ? skb : skb_clone(skb, GFP_ATOMIC); 152762306a36Sopenharmony_ci if (!skb) { 152862306a36Sopenharmony_ci /* Out of memory, skip this action. 152962306a36Sopenharmony_ci */ 153062306a36Sopenharmony_ci return 0; 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci /* When clone_flow_key is false, the 'key' will not be change 153462306a36Sopenharmony_ci * by the actions, then the 'key' can be used directly. 153562306a36Sopenharmony_ci * Otherwise, try to clone key from the next recursion level of 153662306a36Sopenharmony_ci * 'flow_keys'. If clone is successful, execute the actions 153762306a36Sopenharmony_ci * without deferring. 153862306a36Sopenharmony_ci */ 153962306a36Sopenharmony_ci clone = clone_flow_key ? clone_key(key) : key; 154062306a36Sopenharmony_ci if (clone) { 154162306a36Sopenharmony_ci int err = 0; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci if (actions) { /* Sample action */ 154462306a36Sopenharmony_ci if (clone_flow_key) 154562306a36Sopenharmony_ci __this_cpu_inc(exec_actions_level); 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci err = do_execute_actions(dp, skb, clone, 154862306a36Sopenharmony_ci actions, len); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci if (clone_flow_key) 155162306a36Sopenharmony_ci __this_cpu_dec(exec_actions_level); 155262306a36Sopenharmony_ci } else { /* Recirc action */ 155362306a36Sopenharmony_ci clone->recirc_id = recirc_id; 155462306a36Sopenharmony_ci ovs_dp_process_packet(skb, clone); 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci return err; 155762306a36Sopenharmony_ci } 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci /* Out of 'flow_keys' space. Defer actions */ 156062306a36Sopenharmony_ci da = add_deferred_actions(skb, key, actions, len); 156162306a36Sopenharmony_ci if (da) { 156262306a36Sopenharmony_ci if (!actions) { /* Recirc action */ 156362306a36Sopenharmony_ci key = &da->pkt_key; 156462306a36Sopenharmony_ci key->recirc_id = recirc_id; 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci } else { 156762306a36Sopenharmony_ci /* Out of per CPU action FIFO space. Drop the 'skb' and 156862306a36Sopenharmony_ci * log an error. 156962306a36Sopenharmony_ci */ 157062306a36Sopenharmony_ci ovs_kfree_skb_reason(skb, OVS_DROP_DEFERRED_LIMIT); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci if (net_ratelimit()) { 157362306a36Sopenharmony_ci if (actions) { /* Sample action */ 157462306a36Sopenharmony_ci pr_warn("%s: deferred action limit reached, drop sample action\n", 157562306a36Sopenharmony_ci ovs_dp_name(dp)); 157662306a36Sopenharmony_ci } else { /* Recirc action */ 157762306a36Sopenharmony_ci pr_warn("%s: deferred action limit reached, drop recirc action (recirc_id=%#x)\n", 157862306a36Sopenharmony_ci ovs_dp_name(dp), recirc_id); 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci } 158162306a36Sopenharmony_ci } 158262306a36Sopenharmony_ci return 0; 158362306a36Sopenharmony_ci} 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_cistatic void process_deferred_actions(struct datapath *dp) 158662306a36Sopenharmony_ci{ 158762306a36Sopenharmony_ci struct action_fifo *fifo = this_cpu_ptr(action_fifos); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci /* Do not touch the FIFO in case there is no deferred actions. */ 159062306a36Sopenharmony_ci if (action_fifo_is_empty(fifo)) 159162306a36Sopenharmony_ci return; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci /* Finishing executing all deferred actions. */ 159462306a36Sopenharmony_ci do { 159562306a36Sopenharmony_ci struct deferred_action *da = action_fifo_get(fifo); 159662306a36Sopenharmony_ci struct sk_buff *skb = da->skb; 159762306a36Sopenharmony_ci struct sw_flow_key *key = &da->pkt_key; 159862306a36Sopenharmony_ci const struct nlattr *actions = da->actions; 159962306a36Sopenharmony_ci int actions_len = da->actions_len; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (actions) 160262306a36Sopenharmony_ci do_execute_actions(dp, skb, key, actions, actions_len); 160362306a36Sopenharmony_ci else 160462306a36Sopenharmony_ci ovs_dp_process_packet(skb, key); 160562306a36Sopenharmony_ci } while (!action_fifo_is_empty(fifo)); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci /* Reset FIFO for the next packet. */ 160862306a36Sopenharmony_ci action_fifo_init(fifo); 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci/* Execute a list of actions against 'skb'. */ 161262306a36Sopenharmony_ciint ovs_execute_actions(struct datapath *dp, struct sk_buff *skb, 161362306a36Sopenharmony_ci const struct sw_flow_actions *acts, 161462306a36Sopenharmony_ci struct sw_flow_key *key) 161562306a36Sopenharmony_ci{ 161662306a36Sopenharmony_ci int err, level; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci level = __this_cpu_inc_return(exec_actions_level); 161962306a36Sopenharmony_ci if (unlikely(level > OVS_RECURSION_LIMIT)) { 162062306a36Sopenharmony_ci net_crit_ratelimited("ovs: recursion limit reached on datapath %s, probable configuration error\n", 162162306a36Sopenharmony_ci ovs_dp_name(dp)); 162262306a36Sopenharmony_ci ovs_kfree_skb_reason(skb, OVS_DROP_RECURSION_LIMIT); 162362306a36Sopenharmony_ci err = -ENETDOWN; 162462306a36Sopenharmony_ci goto out; 162562306a36Sopenharmony_ci } 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci OVS_CB(skb)->acts_origlen = acts->orig_len; 162862306a36Sopenharmony_ci err = do_execute_actions(dp, skb, key, 162962306a36Sopenharmony_ci acts->actions, acts->actions_len); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci if (level == 1) 163262306a36Sopenharmony_ci process_deferred_actions(dp); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ciout: 163562306a36Sopenharmony_ci __this_cpu_dec(exec_actions_level); 163662306a36Sopenharmony_ci return err; 163762306a36Sopenharmony_ci} 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ciint action_fifos_init(void) 164062306a36Sopenharmony_ci{ 164162306a36Sopenharmony_ci action_fifos = alloc_percpu(struct action_fifo); 164262306a36Sopenharmony_ci if (!action_fifos) 164362306a36Sopenharmony_ci return -ENOMEM; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci flow_keys = alloc_percpu(struct action_flow_keys); 164662306a36Sopenharmony_ci if (!flow_keys) { 164762306a36Sopenharmony_ci free_percpu(action_fifos); 164862306a36Sopenharmony_ci return -ENOMEM; 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci return 0; 165262306a36Sopenharmony_ci} 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_civoid action_fifos_exit(void) 165562306a36Sopenharmony_ci{ 165662306a36Sopenharmony_ci free_percpu(action_fifos); 165762306a36Sopenharmony_ci free_percpu(flow_keys); 165862306a36Sopenharmony_ci} 1659