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 "flow.h" 962306a36Sopenharmony_ci#include "datapath.h" 1062306a36Sopenharmony_ci#include <linux/uaccess.h> 1162306a36Sopenharmony_ci#include <linux/netdevice.h> 1262306a36Sopenharmony_ci#include <linux/etherdevice.h> 1362306a36Sopenharmony_ci#include <linux/if_ether.h> 1462306a36Sopenharmony_ci#include <linux/if_vlan.h> 1562306a36Sopenharmony_ci#include <net/llc_pdu.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/jhash.h> 1862306a36Sopenharmony_ci#include <linux/jiffies.h> 1962306a36Sopenharmony_ci#include <linux/llc.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/in.h> 2262306a36Sopenharmony_ci#include <linux/rcupdate.h> 2362306a36Sopenharmony_ci#include <linux/if_arp.h> 2462306a36Sopenharmony_ci#include <linux/ip.h> 2562306a36Sopenharmony_ci#include <linux/ipv6.h> 2662306a36Sopenharmony_ci#include <linux/sctp.h> 2762306a36Sopenharmony_ci#include <linux/tcp.h> 2862306a36Sopenharmony_ci#include <linux/udp.h> 2962306a36Sopenharmony_ci#include <linux/icmp.h> 3062306a36Sopenharmony_ci#include <linux/icmpv6.h> 3162306a36Sopenharmony_ci#include <linux/rculist.h> 3262306a36Sopenharmony_ci#include <net/geneve.h> 3362306a36Sopenharmony_ci#include <net/ip.h> 3462306a36Sopenharmony_ci#include <net/ipv6.h> 3562306a36Sopenharmony_ci#include <net/ndisc.h> 3662306a36Sopenharmony_ci#include <net/mpls.h> 3762306a36Sopenharmony_ci#include <net/vxlan.h> 3862306a36Sopenharmony_ci#include <net/tun_proto.h> 3962306a36Sopenharmony_ci#include <net/erspan.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include "drop.h" 4262306a36Sopenharmony_ci#include "flow_netlink.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistruct ovs_len_tbl { 4562306a36Sopenharmony_ci int len; 4662306a36Sopenharmony_ci const struct ovs_len_tbl *next; 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define OVS_ATTR_NESTED -1 5062306a36Sopenharmony_ci#define OVS_ATTR_VARIABLE -2 5162306a36Sopenharmony_ci#define OVS_COPY_ACTIONS_MAX_DEPTH 16 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic bool actions_may_change_flow(const struct nlattr *actions) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct nlattr *nla; 5662306a36Sopenharmony_ci int rem; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci nla_for_each_nested(nla, actions, rem) { 5962306a36Sopenharmony_ci u16 action = nla_type(nla); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci switch (action) { 6262306a36Sopenharmony_ci case OVS_ACTION_ATTR_OUTPUT: 6362306a36Sopenharmony_ci case OVS_ACTION_ATTR_RECIRC: 6462306a36Sopenharmony_ci case OVS_ACTION_ATTR_TRUNC: 6562306a36Sopenharmony_ci case OVS_ACTION_ATTR_USERSPACE: 6662306a36Sopenharmony_ci case OVS_ACTION_ATTR_DROP: 6762306a36Sopenharmony_ci break; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci case OVS_ACTION_ATTR_CT: 7062306a36Sopenharmony_ci case OVS_ACTION_ATTR_CT_CLEAR: 7162306a36Sopenharmony_ci case OVS_ACTION_ATTR_HASH: 7262306a36Sopenharmony_ci case OVS_ACTION_ATTR_POP_ETH: 7362306a36Sopenharmony_ci case OVS_ACTION_ATTR_POP_MPLS: 7462306a36Sopenharmony_ci case OVS_ACTION_ATTR_POP_NSH: 7562306a36Sopenharmony_ci case OVS_ACTION_ATTR_POP_VLAN: 7662306a36Sopenharmony_ci case OVS_ACTION_ATTR_PUSH_ETH: 7762306a36Sopenharmony_ci case OVS_ACTION_ATTR_PUSH_MPLS: 7862306a36Sopenharmony_ci case OVS_ACTION_ATTR_PUSH_NSH: 7962306a36Sopenharmony_ci case OVS_ACTION_ATTR_PUSH_VLAN: 8062306a36Sopenharmony_ci case OVS_ACTION_ATTR_SAMPLE: 8162306a36Sopenharmony_ci case OVS_ACTION_ATTR_SET: 8262306a36Sopenharmony_ci case OVS_ACTION_ATTR_SET_MASKED: 8362306a36Sopenharmony_ci case OVS_ACTION_ATTR_METER: 8462306a36Sopenharmony_ci case OVS_ACTION_ATTR_CHECK_PKT_LEN: 8562306a36Sopenharmony_ci case OVS_ACTION_ATTR_ADD_MPLS: 8662306a36Sopenharmony_ci case OVS_ACTION_ATTR_DEC_TTL: 8762306a36Sopenharmony_ci default: 8862306a36Sopenharmony_ci return true; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci return false; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic void update_range(struct sw_flow_match *match, 9562306a36Sopenharmony_ci size_t offset, size_t size, bool is_mask) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct sw_flow_key_range *range; 9862306a36Sopenharmony_ci size_t start = rounddown(offset, sizeof(long)); 9962306a36Sopenharmony_ci size_t end = roundup(offset + size, sizeof(long)); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (!is_mask) 10262306a36Sopenharmony_ci range = &match->range; 10362306a36Sopenharmony_ci else 10462306a36Sopenharmony_ci range = &match->mask->range; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (range->start == range->end) { 10762306a36Sopenharmony_ci range->start = start; 10862306a36Sopenharmony_ci range->end = end; 10962306a36Sopenharmony_ci return; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (range->start > start) 11362306a36Sopenharmony_ci range->start = start; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (range->end < end) 11662306a36Sopenharmony_ci range->end = end; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci#define SW_FLOW_KEY_PUT(match, field, value, is_mask) \ 12062306a36Sopenharmony_ci do { \ 12162306a36Sopenharmony_ci update_range(match, offsetof(struct sw_flow_key, field), \ 12262306a36Sopenharmony_ci sizeof((match)->key->field), is_mask); \ 12362306a36Sopenharmony_ci if (is_mask) \ 12462306a36Sopenharmony_ci (match)->mask->key.field = value; \ 12562306a36Sopenharmony_ci else \ 12662306a36Sopenharmony_ci (match)->key->field = value; \ 12762306a36Sopenharmony_ci } while (0) 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci#define SW_FLOW_KEY_MEMCPY_OFFSET(match, offset, value_p, len, is_mask) \ 13062306a36Sopenharmony_ci do { \ 13162306a36Sopenharmony_ci update_range(match, offset, len, is_mask); \ 13262306a36Sopenharmony_ci if (is_mask) \ 13362306a36Sopenharmony_ci memcpy((u8 *)&(match)->mask->key + offset, value_p, \ 13462306a36Sopenharmony_ci len); \ 13562306a36Sopenharmony_ci else \ 13662306a36Sopenharmony_ci memcpy((u8 *)(match)->key + offset, value_p, len); \ 13762306a36Sopenharmony_ci } while (0) 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define SW_FLOW_KEY_MEMCPY(match, field, value_p, len, is_mask) \ 14062306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY_OFFSET(match, offsetof(struct sw_flow_key, field), \ 14162306a36Sopenharmony_ci value_p, len, is_mask) 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#define SW_FLOW_KEY_MEMSET_FIELD(match, field, value, is_mask) \ 14462306a36Sopenharmony_ci do { \ 14562306a36Sopenharmony_ci update_range(match, offsetof(struct sw_flow_key, field), \ 14662306a36Sopenharmony_ci sizeof((match)->key->field), is_mask); \ 14762306a36Sopenharmony_ci if (is_mask) \ 14862306a36Sopenharmony_ci memset((u8 *)&(match)->mask->key.field, value, \ 14962306a36Sopenharmony_ci sizeof((match)->mask->key.field)); \ 15062306a36Sopenharmony_ci else \ 15162306a36Sopenharmony_ci memset((u8 *)&(match)->key->field, value, \ 15262306a36Sopenharmony_ci sizeof((match)->key->field)); \ 15362306a36Sopenharmony_ci } while (0) 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic bool match_validate(const struct sw_flow_match *match, 15662306a36Sopenharmony_ci u64 key_attrs, u64 mask_attrs, bool log) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci u64 key_expected = 0; 15962306a36Sopenharmony_ci u64 mask_allowed = key_attrs; /* At most allow all key attributes */ 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* The following mask attributes allowed only if they 16262306a36Sopenharmony_ci * pass the validation tests. */ 16362306a36Sopenharmony_ci mask_allowed &= ~((1 << OVS_KEY_ATTR_IPV4) 16462306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4) 16562306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_IPV6) 16662306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6) 16762306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_TCP) 16862306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_TCP_FLAGS) 16962306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_UDP) 17062306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_SCTP) 17162306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_ICMP) 17262306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_ICMPV6) 17362306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_ARP) 17462306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_ND) 17562306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_MPLS) 17662306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_NSH)); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* Always allowed mask fields. */ 17962306a36Sopenharmony_ci mask_allowed |= ((1 << OVS_KEY_ATTR_TUNNEL) 18062306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_IN_PORT) 18162306a36Sopenharmony_ci | (1 << OVS_KEY_ATTR_ETHERTYPE)); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* Check key attributes. */ 18462306a36Sopenharmony_ci if (match->key->eth.type == htons(ETH_P_ARP) 18562306a36Sopenharmony_ci || match->key->eth.type == htons(ETH_P_RARP)) { 18662306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_ARP; 18762306a36Sopenharmony_ci if (match->mask && (match->mask->key.eth.type == htons(0xffff))) 18862306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_ARP; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (eth_p_mpls(match->key->eth.type)) { 19262306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_MPLS; 19362306a36Sopenharmony_ci if (match->mask && (match->mask->key.eth.type == htons(0xffff))) 19462306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_MPLS; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (match->key->eth.type == htons(ETH_P_IP)) { 19862306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_IPV4; 19962306a36Sopenharmony_ci if (match->mask && match->mask->key.eth.type == htons(0xffff)) { 20062306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_IPV4; 20162306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) { 20562306a36Sopenharmony_ci if (match->key->ip.proto == IPPROTO_UDP) { 20662306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_UDP; 20762306a36Sopenharmony_ci if (match->mask && (match->mask->key.ip.proto == 0xff)) 20862306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_UDP; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (match->key->ip.proto == IPPROTO_SCTP) { 21262306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_SCTP; 21362306a36Sopenharmony_ci if (match->mask && (match->mask->key.ip.proto == 0xff)) 21462306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_SCTP; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (match->key->ip.proto == IPPROTO_TCP) { 21862306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_TCP; 21962306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_TCP_FLAGS; 22062306a36Sopenharmony_ci if (match->mask && (match->mask->key.ip.proto == 0xff)) { 22162306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_TCP; 22262306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_TCP_FLAGS; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (match->key->ip.proto == IPPROTO_ICMP) { 22762306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_ICMP; 22862306a36Sopenharmony_ci if (match->mask && (match->mask->key.ip.proto == 0xff)) 22962306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_ICMP; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (match->key->eth.type == htons(ETH_P_IPV6)) { 23562306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_IPV6; 23662306a36Sopenharmony_ci if (match->mask && match->mask->key.eth.type == htons(0xffff)) { 23762306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_IPV6; 23862306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) { 24262306a36Sopenharmony_ci if (match->key->ip.proto == IPPROTO_UDP) { 24362306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_UDP; 24462306a36Sopenharmony_ci if (match->mask && (match->mask->key.ip.proto == 0xff)) 24562306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_UDP; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (match->key->ip.proto == IPPROTO_SCTP) { 24962306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_SCTP; 25062306a36Sopenharmony_ci if (match->mask && (match->mask->key.ip.proto == 0xff)) 25162306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_SCTP; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (match->key->ip.proto == IPPROTO_TCP) { 25562306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_TCP; 25662306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_TCP_FLAGS; 25762306a36Sopenharmony_ci if (match->mask && (match->mask->key.ip.proto == 0xff)) { 25862306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_TCP; 25962306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_TCP_FLAGS; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (match->key->ip.proto == IPPROTO_ICMPV6) { 26462306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_ICMPV6; 26562306a36Sopenharmony_ci if (match->mask && (match->mask->key.ip.proto == 0xff)) 26662306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_ICMPV6; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (match->key->tp.src == 26962306a36Sopenharmony_ci htons(NDISC_NEIGHBOUR_SOLICITATION) || 27062306a36Sopenharmony_ci match->key->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) { 27162306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_ND; 27262306a36Sopenharmony_ci /* Original direction conntrack tuple 27362306a36Sopenharmony_ci * uses the same space as the ND fields 27462306a36Sopenharmony_ci * in the key, so both are not allowed 27562306a36Sopenharmony_ci * at the same time. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci mask_allowed &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6); 27862306a36Sopenharmony_ci if (match->mask && (match->mask->key.tp.src == htons(0xff))) 27962306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_ND; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (match->key->eth.type == htons(ETH_P_NSH)) { 28662306a36Sopenharmony_ci key_expected |= 1 << OVS_KEY_ATTR_NSH; 28762306a36Sopenharmony_ci if (match->mask && 28862306a36Sopenharmony_ci match->mask->key.eth.type == htons(0xffff)) { 28962306a36Sopenharmony_ci mask_allowed |= 1 << OVS_KEY_ATTR_NSH; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if ((key_attrs & key_expected) != key_expected) { 29462306a36Sopenharmony_ci /* Key attributes check failed. */ 29562306a36Sopenharmony_ci OVS_NLERR(log, "Missing key (keys=%llx, expected=%llx)", 29662306a36Sopenharmony_ci (unsigned long long)key_attrs, 29762306a36Sopenharmony_ci (unsigned long long)key_expected); 29862306a36Sopenharmony_ci return false; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if ((mask_attrs & mask_allowed) != mask_attrs) { 30262306a36Sopenharmony_ci /* Mask attributes check failed. */ 30362306a36Sopenharmony_ci OVS_NLERR(log, "Unexpected mask (mask=%llx, allowed=%llx)", 30462306a36Sopenharmony_ci (unsigned long long)mask_attrs, 30562306a36Sopenharmony_ci (unsigned long long)mask_allowed); 30662306a36Sopenharmony_ci return false; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return true; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cisize_t ovs_tun_key_attr_size(void) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci /* Whenever adding new OVS_TUNNEL_KEY_ FIELDS, we should consider 31562306a36Sopenharmony_ci * updating this function. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_ci return nla_total_size_64bit(8) /* OVS_TUNNEL_KEY_ATTR_ID */ 31862306a36Sopenharmony_ci + nla_total_size(16) /* OVS_TUNNEL_KEY_ATTR_IPV[46]_SRC */ 31962306a36Sopenharmony_ci + nla_total_size(16) /* OVS_TUNNEL_KEY_ATTR_IPV[46]_DST */ 32062306a36Sopenharmony_ci + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */ 32162306a36Sopenharmony_ci + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */ 32262306a36Sopenharmony_ci + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */ 32362306a36Sopenharmony_ci + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */ 32462306a36Sopenharmony_ci + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */ 32562306a36Sopenharmony_ci + nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */ 32662306a36Sopenharmony_ci /* OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS and 32762306a36Sopenharmony_ci * OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS is mutually exclusive with 32862306a36Sopenharmony_ci * OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS and covered by it. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci + nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */ 33162306a36Sopenharmony_ci + nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */ 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic size_t ovs_nsh_key_attr_size(void) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci /* Whenever adding new OVS_NSH_KEY_ FIELDS, we should consider 33762306a36Sopenharmony_ci * updating this function. 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_ci return nla_total_size(NSH_BASE_HDR_LEN) /* OVS_NSH_KEY_ATTR_BASE */ 34062306a36Sopenharmony_ci /* OVS_NSH_KEY_ATTR_MD1 and OVS_NSH_KEY_ATTR_MD2 are 34162306a36Sopenharmony_ci * mutually exclusive, so the bigger one can cover 34262306a36Sopenharmony_ci * the small one. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ci + nla_total_size(NSH_CTX_HDRS_MAX_LEN); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cisize_t ovs_key_attr_size(void) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci /* Whenever adding new OVS_KEY_ FIELDS, we should consider 35062306a36Sopenharmony_ci * updating this function. 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_ci BUILD_BUG_ON(OVS_KEY_ATTR_MAX != 32); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ 35562306a36Sopenharmony_ci + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ 35662306a36Sopenharmony_ci + ovs_tun_key_attr_size() 35762306a36Sopenharmony_ci + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */ 35862306a36Sopenharmony_ci + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */ 35962306a36Sopenharmony_ci + nla_total_size(4) /* OVS_KEY_ATTR_DP_HASH */ 36062306a36Sopenharmony_ci + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */ 36162306a36Sopenharmony_ci + nla_total_size(4) /* OVS_KEY_ATTR_CT_STATE */ 36262306a36Sopenharmony_ci + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */ 36362306a36Sopenharmony_ci + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */ 36462306a36Sopenharmony_ci + nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */ 36562306a36Sopenharmony_ci + nla_total_size(40) /* OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6 */ 36662306a36Sopenharmony_ci + nla_total_size(0) /* OVS_KEY_ATTR_NSH */ 36762306a36Sopenharmony_ci + ovs_nsh_key_attr_size() 36862306a36Sopenharmony_ci + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ 36962306a36Sopenharmony_ci + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ 37062306a36Sopenharmony_ci + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */ 37162306a36Sopenharmony_ci + nla_total_size(0) /* OVS_KEY_ATTR_ENCAP */ 37262306a36Sopenharmony_ci + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ 37362306a36Sopenharmony_ci + nla_total_size(40) /* OVS_KEY_ATTR_IPV6 */ 37462306a36Sopenharmony_ci + nla_total_size(2) /* OVS_KEY_ATTR_ICMPV6 */ 37562306a36Sopenharmony_ci + nla_total_size(28) /* OVS_KEY_ATTR_ND */ 37662306a36Sopenharmony_ci + nla_total_size(2); /* OVS_KEY_ATTR_IPV6_EXTHDRS */ 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic const struct ovs_len_tbl ovs_vxlan_ext_key_lens[OVS_VXLAN_EXT_MAX + 1] = { 38062306a36Sopenharmony_ci [OVS_VXLAN_EXT_GBP] = { .len = sizeof(u32) }, 38162306a36Sopenharmony_ci}; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = { 38462306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_ID] = { .len = sizeof(u64) }, 38562306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = { .len = sizeof(u32) }, 38662306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_IPV4_DST] = { .len = sizeof(u32) }, 38762306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_TOS] = { .len = 1 }, 38862306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_TTL] = { .len = 1 }, 38962306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = { .len = 0 }, 39062306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_CSUM] = { .len = 0 }, 39162306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) }, 39262306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) }, 39362306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 }, 39462306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_VARIABLE }, 39562306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED, 39662306a36Sopenharmony_ci .next = ovs_vxlan_ext_key_lens }, 39762306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, 39862306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = sizeof(struct in6_addr) }, 39962306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS] = { .len = OVS_ATTR_VARIABLE }, 40062306a36Sopenharmony_ci [OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE] = { .len = 0 }, 40162306a36Sopenharmony_ci}; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic const struct ovs_len_tbl 40462306a36Sopenharmony_ciovs_nsh_key_attr_lens[OVS_NSH_KEY_ATTR_MAX + 1] = { 40562306a36Sopenharmony_ci [OVS_NSH_KEY_ATTR_BASE] = { .len = sizeof(struct ovs_nsh_key_base) }, 40662306a36Sopenharmony_ci [OVS_NSH_KEY_ATTR_MD1] = { .len = sizeof(struct ovs_nsh_key_md1) }, 40762306a36Sopenharmony_ci [OVS_NSH_KEY_ATTR_MD2] = { .len = OVS_ATTR_VARIABLE }, 40862306a36Sopenharmony_ci}; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ 41162306a36Sopenharmony_cistatic const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { 41262306a36Sopenharmony_ci [OVS_KEY_ATTR_ENCAP] = { .len = OVS_ATTR_NESTED }, 41362306a36Sopenharmony_ci [OVS_KEY_ATTR_PRIORITY] = { .len = sizeof(u32) }, 41462306a36Sopenharmony_ci [OVS_KEY_ATTR_IN_PORT] = { .len = sizeof(u32) }, 41562306a36Sopenharmony_ci [OVS_KEY_ATTR_SKB_MARK] = { .len = sizeof(u32) }, 41662306a36Sopenharmony_ci [OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) }, 41762306a36Sopenharmony_ci [OVS_KEY_ATTR_VLAN] = { .len = sizeof(__be16) }, 41862306a36Sopenharmony_ci [OVS_KEY_ATTR_ETHERTYPE] = { .len = sizeof(__be16) }, 41962306a36Sopenharmony_ci [OVS_KEY_ATTR_IPV4] = { .len = sizeof(struct ovs_key_ipv4) }, 42062306a36Sopenharmony_ci [OVS_KEY_ATTR_IPV6] = { .len = sizeof(struct ovs_key_ipv6) }, 42162306a36Sopenharmony_ci [OVS_KEY_ATTR_TCP] = { .len = sizeof(struct ovs_key_tcp) }, 42262306a36Sopenharmony_ci [OVS_KEY_ATTR_TCP_FLAGS] = { .len = sizeof(__be16) }, 42362306a36Sopenharmony_ci [OVS_KEY_ATTR_UDP] = { .len = sizeof(struct ovs_key_udp) }, 42462306a36Sopenharmony_ci [OVS_KEY_ATTR_SCTP] = { .len = sizeof(struct ovs_key_sctp) }, 42562306a36Sopenharmony_ci [OVS_KEY_ATTR_ICMP] = { .len = sizeof(struct ovs_key_icmp) }, 42662306a36Sopenharmony_ci [OVS_KEY_ATTR_ICMPV6] = { .len = sizeof(struct ovs_key_icmpv6) }, 42762306a36Sopenharmony_ci [OVS_KEY_ATTR_ARP] = { .len = sizeof(struct ovs_key_arp) }, 42862306a36Sopenharmony_ci [OVS_KEY_ATTR_ND] = { .len = sizeof(struct ovs_key_nd) }, 42962306a36Sopenharmony_ci [OVS_KEY_ATTR_RECIRC_ID] = { .len = sizeof(u32) }, 43062306a36Sopenharmony_ci [OVS_KEY_ATTR_DP_HASH] = { .len = sizeof(u32) }, 43162306a36Sopenharmony_ci [OVS_KEY_ATTR_TUNNEL] = { .len = OVS_ATTR_NESTED, 43262306a36Sopenharmony_ci .next = ovs_tunnel_key_lens, }, 43362306a36Sopenharmony_ci [OVS_KEY_ATTR_MPLS] = { .len = OVS_ATTR_VARIABLE }, 43462306a36Sopenharmony_ci [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u32) }, 43562306a36Sopenharmony_ci [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) }, 43662306a36Sopenharmony_ci [OVS_KEY_ATTR_CT_MARK] = { .len = sizeof(u32) }, 43762306a36Sopenharmony_ci [OVS_KEY_ATTR_CT_LABELS] = { .len = sizeof(struct ovs_key_ct_labels) }, 43862306a36Sopenharmony_ci [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4] = { 43962306a36Sopenharmony_ci .len = sizeof(struct ovs_key_ct_tuple_ipv4) }, 44062306a36Sopenharmony_ci [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6] = { 44162306a36Sopenharmony_ci .len = sizeof(struct ovs_key_ct_tuple_ipv6) }, 44262306a36Sopenharmony_ci [OVS_KEY_ATTR_NSH] = { .len = OVS_ATTR_NESTED, 44362306a36Sopenharmony_ci .next = ovs_nsh_key_attr_lens, }, 44462306a36Sopenharmony_ci [OVS_KEY_ATTR_IPV6_EXTHDRS] = { 44562306a36Sopenharmony_ci .len = sizeof(struct ovs_key_ipv6_exthdrs) }, 44662306a36Sopenharmony_ci}; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic bool check_attr_len(unsigned int attr_len, unsigned int expected_len) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci return expected_len == attr_len || 45162306a36Sopenharmony_ci expected_len == OVS_ATTR_NESTED || 45262306a36Sopenharmony_ci expected_len == OVS_ATTR_VARIABLE; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic bool is_all_zero(const u8 *fp, size_t size) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci int i; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (!fp) 46062306a36Sopenharmony_ci return false; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci for (i = 0; i < size; i++) 46362306a36Sopenharmony_ci if (fp[i]) 46462306a36Sopenharmony_ci return false; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci return true; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic int __parse_flow_nlattrs(const struct nlattr *attr, 47062306a36Sopenharmony_ci const struct nlattr *a[], 47162306a36Sopenharmony_ci u64 *attrsp, bool log, bool nz) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci const struct nlattr *nla; 47462306a36Sopenharmony_ci u64 attrs; 47562306a36Sopenharmony_ci int rem; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci attrs = *attrsp; 47862306a36Sopenharmony_ci nla_for_each_nested(nla, attr, rem) { 47962306a36Sopenharmony_ci u16 type = nla_type(nla); 48062306a36Sopenharmony_ci int expected_len; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (type > OVS_KEY_ATTR_MAX) { 48362306a36Sopenharmony_ci OVS_NLERR(log, "Key type %d is out of range max %d", 48462306a36Sopenharmony_ci type, OVS_KEY_ATTR_MAX); 48562306a36Sopenharmony_ci return -EINVAL; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (type == OVS_KEY_ATTR_PACKET_TYPE || 48962306a36Sopenharmony_ci type == OVS_KEY_ATTR_ND_EXTENSIONS || 49062306a36Sopenharmony_ci type == OVS_KEY_ATTR_TUNNEL_INFO) { 49162306a36Sopenharmony_ci OVS_NLERR(log, "Key type %d is not supported", type); 49262306a36Sopenharmony_ci return -EINVAL; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (attrs & (1ULL << type)) { 49662306a36Sopenharmony_ci OVS_NLERR(log, "Duplicate key (type %d).", type); 49762306a36Sopenharmony_ci return -EINVAL; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci expected_len = ovs_key_lens[type].len; 50162306a36Sopenharmony_ci if (!check_attr_len(nla_len(nla), expected_len)) { 50262306a36Sopenharmony_ci OVS_NLERR(log, "Key %d has unexpected len %d expected %d", 50362306a36Sopenharmony_ci type, nla_len(nla), expected_len); 50462306a36Sopenharmony_ci return -EINVAL; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (!nz || !is_all_zero(nla_data(nla), nla_len(nla))) { 50862306a36Sopenharmony_ci attrs |= 1ULL << type; 50962306a36Sopenharmony_ci a[type] = nla; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci if (rem) { 51362306a36Sopenharmony_ci OVS_NLERR(log, "Message has %d unknown bytes.", rem); 51462306a36Sopenharmony_ci return -EINVAL; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci *attrsp = attrs; 51862306a36Sopenharmony_ci return 0; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic int parse_flow_mask_nlattrs(const struct nlattr *attr, 52262306a36Sopenharmony_ci const struct nlattr *a[], u64 *attrsp, 52362306a36Sopenharmony_ci bool log) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci return __parse_flow_nlattrs(attr, a, attrsp, log, true); 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ciint parse_flow_nlattrs(const struct nlattr *attr, const struct nlattr *a[], 52962306a36Sopenharmony_ci u64 *attrsp, bool log) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci return __parse_flow_nlattrs(attr, a, attrsp, log, false); 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic int genev_tun_opt_from_nlattr(const struct nlattr *a, 53562306a36Sopenharmony_ci struct sw_flow_match *match, bool is_mask, 53662306a36Sopenharmony_ci bool log) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci unsigned long opt_key_offset; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (nla_len(a) > sizeof(match->key->tun_opts)) { 54162306a36Sopenharmony_ci OVS_NLERR(log, "Geneve option length err (len %d, max %zu).", 54262306a36Sopenharmony_ci nla_len(a), sizeof(match->key->tun_opts)); 54362306a36Sopenharmony_ci return -EINVAL; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (nla_len(a) % 4 != 0) { 54762306a36Sopenharmony_ci OVS_NLERR(log, "Geneve opt len %d is not a multiple of 4.", 54862306a36Sopenharmony_ci nla_len(a)); 54962306a36Sopenharmony_ci return -EINVAL; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* We need to record the length of the options passed 55362306a36Sopenharmony_ci * down, otherwise packets with the same format but 55462306a36Sopenharmony_ci * additional options will be silently matched. 55562306a36Sopenharmony_ci */ 55662306a36Sopenharmony_ci if (!is_mask) { 55762306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_opts_len, nla_len(a), 55862306a36Sopenharmony_ci false); 55962306a36Sopenharmony_ci } else { 56062306a36Sopenharmony_ci /* This is somewhat unusual because it looks at 56162306a36Sopenharmony_ci * both the key and mask while parsing the 56262306a36Sopenharmony_ci * attributes (and by extension assumes the key 56362306a36Sopenharmony_ci * is parsed first). Normally, we would verify 56462306a36Sopenharmony_ci * that each is the correct length and that the 56562306a36Sopenharmony_ci * attributes line up in the validate function. 56662306a36Sopenharmony_ci * However, that is difficult because this is 56762306a36Sopenharmony_ci * variable length and we won't have the 56862306a36Sopenharmony_ci * information later. 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ci if (match->key->tun_opts_len != nla_len(a)) { 57162306a36Sopenharmony_ci OVS_NLERR(log, "Geneve option len %d != mask len %d", 57262306a36Sopenharmony_ci match->key->tun_opts_len, nla_len(a)); 57362306a36Sopenharmony_ci return -EINVAL; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci opt_key_offset = TUN_METADATA_OFFSET(nla_len(a)); 58062306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, nla_data(a), 58162306a36Sopenharmony_ci nla_len(a), is_mask); 58262306a36Sopenharmony_ci return 0; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic int vxlan_tun_opt_from_nlattr(const struct nlattr *attr, 58662306a36Sopenharmony_ci struct sw_flow_match *match, bool is_mask, 58762306a36Sopenharmony_ci bool log) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci struct nlattr *a; 59062306a36Sopenharmony_ci int rem; 59162306a36Sopenharmony_ci unsigned long opt_key_offset; 59262306a36Sopenharmony_ci struct vxlan_metadata opts; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts)); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci memset(&opts, 0, sizeof(opts)); 59762306a36Sopenharmony_ci nla_for_each_nested(a, attr, rem) { 59862306a36Sopenharmony_ci int type = nla_type(a); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (type > OVS_VXLAN_EXT_MAX) { 60162306a36Sopenharmony_ci OVS_NLERR(log, "VXLAN extension %d out of range max %d", 60262306a36Sopenharmony_ci type, OVS_VXLAN_EXT_MAX); 60362306a36Sopenharmony_ci return -EINVAL; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (!check_attr_len(nla_len(a), 60762306a36Sopenharmony_ci ovs_vxlan_ext_key_lens[type].len)) { 60862306a36Sopenharmony_ci OVS_NLERR(log, "VXLAN extension %d has unexpected len %d expected %d", 60962306a36Sopenharmony_ci type, nla_len(a), 61062306a36Sopenharmony_ci ovs_vxlan_ext_key_lens[type].len); 61162306a36Sopenharmony_ci return -EINVAL; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci switch (type) { 61562306a36Sopenharmony_ci case OVS_VXLAN_EXT_GBP: 61662306a36Sopenharmony_ci opts.gbp = nla_get_u32(a); 61762306a36Sopenharmony_ci break; 61862306a36Sopenharmony_ci default: 61962306a36Sopenharmony_ci OVS_NLERR(log, "Unknown VXLAN extension attribute %d", 62062306a36Sopenharmony_ci type); 62162306a36Sopenharmony_ci return -EINVAL; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci if (rem) { 62562306a36Sopenharmony_ci OVS_NLERR(log, "VXLAN extension message has %d unknown bytes.", 62662306a36Sopenharmony_ci rem); 62762306a36Sopenharmony_ci return -EINVAL; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (!is_mask) 63162306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_opts_len, sizeof(opts), false); 63262306a36Sopenharmony_ci else 63362306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci opt_key_offset = TUN_METADATA_OFFSET(sizeof(opts)); 63662306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, &opts, sizeof(opts), 63762306a36Sopenharmony_ci is_mask); 63862306a36Sopenharmony_ci return 0; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic int erspan_tun_opt_from_nlattr(const struct nlattr *a, 64262306a36Sopenharmony_ci struct sw_flow_match *match, bool is_mask, 64362306a36Sopenharmony_ci bool log) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci unsigned long opt_key_offset; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct erspan_metadata) > 64862306a36Sopenharmony_ci sizeof(match->key->tun_opts)); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (nla_len(a) > sizeof(match->key->tun_opts)) { 65162306a36Sopenharmony_ci OVS_NLERR(log, "ERSPAN option length err (len %d, max %zu).", 65262306a36Sopenharmony_ci nla_len(a), sizeof(match->key->tun_opts)); 65362306a36Sopenharmony_ci return -EINVAL; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (!is_mask) 65762306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_opts_len, 65862306a36Sopenharmony_ci sizeof(struct erspan_metadata), false); 65962306a36Sopenharmony_ci else 66062306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci opt_key_offset = TUN_METADATA_OFFSET(nla_len(a)); 66362306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, nla_data(a), 66462306a36Sopenharmony_ci nla_len(a), is_mask); 66562306a36Sopenharmony_ci return 0; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic int ip_tun_from_nlattr(const struct nlattr *attr, 66962306a36Sopenharmony_ci struct sw_flow_match *match, bool is_mask, 67062306a36Sopenharmony_ci bool log) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci bool ttl = false, ipv4 = false, ipv6 = false; 67362306a36Sopenharmony_ci bool info_bridge_mode = false; 67462306a36Sopenharmony_ci __be16 tun_flags = 0; 67562306a36Sopenharmony_ci int opts_type = 0; 67662306a36Sopenharmony_ci struct nlattr *a; 67762306a36Sopenharmony_ci int rem; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci nla_for_each_nested(a, attr, rem) { 68062306a36Sopenharmony_ci int type = nla_type(a); 68162306a36Sopenharmony_ci int err; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (type > OVS_TUNNEL_KEY_ATTR_MAX) { 68462306a36Sopenharmony_ci OVS_NLERR(log, "Tunnel attr %d out of range max %d", 68562306a36Sopenharmony_ci type, OVS_TUNNEL_KEY_ATTR_MAX); 68662306a36Sopenharmony_ci return -EINVAL; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (!check_attr_len(nla_len(a), 69062306a36Sopenharmony_ci ovs_tunnel_key_lens[type].len)) { 69162306a36Sopenharmony_ci OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d", 69262306a36Sopenharmony_ci type, nla_len(a), ovs_tunnel_key_lens[type].len); 69362306a36Sopenharmony_ci return -EINVAL; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci switch (type) { 69762306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_ID: 69862306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_key.tun_id, 69962306a36Sopenharmony_ci nla_get_be64(a), is_mask); 70062306a36Sopenharmony_ci tun_flags |= TUNNEL_KEY; 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: 70362306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.src, 70462306a36Sopenharmony_ci nla_get_in_addr(a), is_mask); 70562306a36Sopenharmony_ci ipv4 = true; 70662306a36Sopenharmony_ci break; 70762306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_IPV4_DST: 70862306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.dst, 70962306a36Sopenharmony_ci nla_get_in_addr(a), is_mask); 71062306a36Sopenharmony_ci ipv4 = true; 71162306a36Sopenharmony_ci break; 71262306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_IPV6_SRC: 71362306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.src, 71462306a36Sopenharmony_ci nla_get_in6_addr(a), is_mask); 71562306a36Sopenharmony_ci ipv6 = true; 71662306a36Sopenharmony_ci break; 71762306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_IPV6_DST: 71862306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.dst, 71962306a36Sopenharmony_ci nla_get_in6_addr(a), is_mask); 72062306a36Sopenharmony_ci ipv6 = true; 72162306a36Sopenharmony_ci break; 72262306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_TOS: 72362306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_key.tos, 72462306a36Sopenharmony_ci nla_get_u8(a), is_mask); 72562306a36Sopenharmony_ci break; 72662306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_TTL: 72762306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_key.ttl, 72862306a36Sopenharmony_ci nla_get_u8(a), is_mask); 72962306a36Sopenharmony_ci ttl = true; 73062306a36Sopenharmony_ci break; 73162306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT: 73262306a36Sopenharmony_ci tun_flags |= TUNNEL_DONT_FRAGMENT; 73362306a36Sopenharmony_ci break; 73462306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_CSUM: 73562306a36Sopenharmony_ci tun_flags |= TUNNEL_CSUM; 73662306a36Sopenharmony_ci break; 73762306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_TP_SRC: 73862306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_key.tp_src, 73962306a36Sopenharmony_ci nla_get_be16(a), is_mask); 74062306a36Sopenharmony_ci break; 74162306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_TP_DST: 74262306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_key.tp_dst, 74362306a36Sopenharmony_ci nla_get_be16(a), is_mask); 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_OAM: 74662306a36Sopenharmony_ci tun_flags |= TUNNEL_OAM; 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS: 74962306a36Sopenharmony_ci if (opts_type) { 75062306a36Sopenharmony_ci OVS_NLERR(log, "Multiple metadata blocks provided"); 75162306a36Sopenharmony_ci return -EINVAL; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci err = genev_tun_opt_from_nlattr(a, match, is_mask, log); 75562306a36Sopenharmony_ci if (err) 75662306a36Sopenharmony_ci return err; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci tun_flags |= TUNNEL_GENEVE_OPT; 75962306a36Sopenharmony_ci opts_type = type; 76062306a36Sopenharmony_ci break; 76162306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS: 76262306a36Sopenharmony_ci if (opts_type) { 76362306a36Sopenharmony_ci OVS_NLERR(log, "Multiple metadata blocks provided"); 76462306a36Sopenharmony_ci return -EINVAL; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci err = vxlan_tun_opt_from_nlattr(a, match, is_mask, log); 76862306a36Sopenharmony_ci if (err) 76962306a36Sopenharmony_ci return err; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci tun_flags |= TUNNEL_VXLAN_OPT; 77262306a36Sopenharmony_ci opts_type = type; 77362306a36Sopenharmony_ci break; 77462306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_PAD: 77562306a36Sopenharmony_ci break; 77662306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS: 77762306a36Sopenharmony_ci if (opts_type) { 77862306a36Sopenharmony_ci OVS_NLERR(log, "Multiple metadata blocks provided"); 77962306a36Sopenharmony_ci return -EINVAL; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci err = erspan_tun_opt_from_nlattr(a, match, is_mask, 78362306a36Sopenharmony_ci log); 78462306a36Sopenharmony_ci if (err) 78562306a36Sopenharmony_ci return err; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci tun_flags |= TUNNEL_ERSPAN_OPT; 78862306a36Sopenharmony_ci opts_type = type; 78962306a36Sopenharmony_ci break; 79062306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE: 79162306a36Sopenharmony_ci info_bridge_mode = true; 79262306a36Sopenharmony_ci ipv4 = true; 79362306a36Sopenharmony_ci break; 79462306a36Sopenharmony_ci default: 79562306a36Sopenharmony_ci OVS_NLERR(log, "Unknown IP tunnel attribute %d", 79662306a36Sopenharmony_ci type); 79762306a36Sopenharmony_ci return -EINVAL; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_key.tun_flags, tun_flags, is_mask); 80262306a36Sopenharmony_ci if (is_mask) 80362306a36Sopenharmony_ci SW_FLOW_KEY_MEMSET_FIELD(match, tun_proto, 0xff, true); 80462306a36Sopenharmony_ci else 80562306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tun_proto, ipv6 ? AF_INET6 : AF_INET, 80662306a36Sopenharmony_ci false); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (rem > 0) { 80962306a36Sopenharmony_ci OVS_NLERR(log, "IP tunnel attribute has %d unknown bytes.", 81062306a36Sopenharmony_ci rem); 81162306a36Sopenharmony_ci return -EINVAL; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (ipv4 && ipv6) { 81562306a36Sopenharmony_ci OVS_NLERR(log, "Mixed IPv4 and IPv6 tunnel attributes"); 81662306a36Sopenharmony_ci return -EINVAL; 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (!is_mask) { 82062306a36Sopenharmony_ci if (!ipv4 && !ipv6) { 82162306a36Sopenharmony_ci OVS_NLERR(log, "IP tunnel dst address not specified"); 82262306a36Sopenharmony_ci return -EINVAL; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci if (ipv4) { 82562306a36Sopenharmony_ci if (info_bridge_mode) { 82662306a36Sopenharmony_ci if (match->key->tun_key.u.ipv4.src || 82762306a36Sopenharmony_ci match->key->tun_key.u.ipv4.dst || 82862306a36Sopenharmony_ci match->key->tun_key.tp_src || 82962306a36Sopenharmony_ci match->key->tun_key.tp_dst || 83062306a36Sopenharmony_ci match->key->tun_key.ttl || 83162306a36Sopenharmony_ci match->key->tun_key.tos || 83262306a36Sopenharmony_ci tun_flags & ~TUNNEL_KEY) { 83362306a36Sopenharmony_ci OVS_NLERR(log, "IPv4 tun info is not correct"); 83462306a36Sopenharmony_ci return -EINVAL; 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci } else if (!match->key->tun_key.u.ipv4.dst) { 83762306a36Sopenharmony_ci OVS_NLERR(log, "IPv4 tunnel dst address is zero"); 83862306a36Sopenharmony_ci return -EINVAL; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci if (ipv6 && ipv6_addr_any(&match->key->tun_key.u.ipv6.dst)) { 84262306a36Sopenharmony_ci OVS_NLERR(log, "IPv6 tunnel dst address is zero"); 84362306a36Sopenharmony_ci return -EINVAL; 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (!ttl && !info_bridge_mode) { 84762306a36Sopenharmony_ci OVS_NLERR(log, "IP tunnel TTL not specified."); 84862306a36Sopenharmony_ci return -EINVAL; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci return opts_type; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic int vxlan_opt_to_nlattr(struct sk_buff *skb, 85662306a36Sopenharmony_ci const void *tun_opts, int swkey_tun_opts_len) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci const struct vxlan_metadata *opts = tun_opts; 85962306a36Sopenharmony_ci struct nlattr *nla; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci nla = nla_nest_start_noflag(skb, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS); 86262306a36Sopenharmony_ci if (!nla) 86362306a36Sopenharmony_ci return -EMSGSIZE; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (nla_put_u32(skb, OVS_VXLAN_EXT_GBP, opts->gbp) < 0) 86662306a36Sopenharmony_ci return -EMSGSIZE; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci nla_nest_end(skb, nla); 86962306a36Sopenharmony_ci return 0; 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_cistatic int __ip_tun_to_nlattr(struct sk_buff *skb, 87362306a36Sopenharmony_ci const struct ip_tunnel_key *output, 87462306a36Sopenharmony_ci const void *tun_opts, int swkey_tun_opts_len, 87562306a36Sopenharmony_ci unsigned short tun_proto, u8 mode) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci if (output->tun_flags & TUNNEL_KEY && 87862306a36Sopenharmony_ci nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id, 87962306a36Sopenharmony_ci OVS_TUNNEL_KEY_ATTR_PAD)) 88062306a36Sopenharmony_ci return -EMSGSIZE; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (mode & IP_TUNNEL_INFO_BRIDGE) 88362306a36Sopenharmony_ci return nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE) 88462306a36Sopenharmony_ci ? -EMSGSIZE : 0; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci switch (tun_proto) { 88762306a36Sopenharmony_ci case AF_INET: 88862306a36Sopenharmony_ci if (output->u.ipv4.src && 88962306a36Sopenharmony_ci nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, 89062306a36Sopenharmony_ci output->u.ipv4.src)) 89162306a36Sopenharmony_ci return -EMSGSIZE; 89262306a36Sopenharmony_ci if (output->u.ipv4.dst && 89362306a36Sopenharmony_ci nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, 89462306a36Sopenharmony_ci output->u.ipv4.dst)) 89562306a36Sopenharmony_ci return -EMSGSIZE; 89662306a36Sopenharmony_ci break; 89762306a36Sopenharmony_ci case AF_INET6: 89862306a36Sopenharmony_ci if (!ipv6_addr_any(&output->u.ipv6.src) && 89962306a36Sopenharmony_ci nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_SRC, 90062306a36Sopenharmony_ci &output->u.ipv6.src)) 90162306a36Sopenharmony_ci return -EMSGSIZE; 90262306a36Sopenharmony_ci if (!ipv6_addr_any(&output->u.ipv6.dst) && 90362306a36Sopenharmony_ci nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_DST, 90462306a36Sopenharmony_ci &output->u.ipv6.dst)) 90562306a36Sopenharmony_ci return -EMSGSIZE; 90662306a36Sopenharmony_ci break; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci if (output->tos && 90962306a36Sopenharmony_ci nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->tos)) 91062306a36Sopenharmony_ci return -EMSGSIZE; 91162306a36Sopenharmony_ci if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, output->ttl)) 91262306a36Sopenharmony_ci return -EMSGSIZE; 91362306a36Sopenharmony_ci if ((output->tun_flags & TUNNEL_DONT_FRAGMENT) && 91462306a36Sopenharmony_ci nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT)) 91562306a36Sopenharmony_ci return -EMSGSIZE; 91662306a36Sopenharmony_ci if ((output->tun_flags & TUNNEL_CSUM) && 91762306a36Sopenharmony_ci nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM)) 91862306a36Sopenharmony_ci return -EMSGSIZE; 91962306a36Sopenharmony_ci if (output->tp_src && 92062306a36Sopenharmony_ci nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_SRC, output->tp_src)) 92162306a36Sopenharmony_ci return -EMSGSIZE; 92262306a36Sopenharmony_ci if (output->tp_dst && 92362306a36Sopenharmony_ci nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_DST, output->tp_dst)) 92462306a36Sopenharmony_ci return -EMSGSIZE; 92562306a36Sopenharmony_ci if ((output->tun_flags & TUNNEL_OAM) && 92662306a36Sopenharmony_ci nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM)) 92762306a36Sopenharmony_ci return -EMSGSIZE; 92862306a36Sopenharmony_ci if (swkey_tun_opts_len) { 92962306a36Sopenharmony_ci if (output->tun_flags & TUNNEL_GENEVE_OPT && 93062306a36Sopenharmony_ci nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, 93162306a36Sopenharmony_ci swkey_tun_opts_len, tun_opts)) 93262306a36Sopenharmony_ci return -EMSGSIZE; 93362306a36Sopenharmony_ci else if (output->tun_flags & TUNNEL_VXLAN_OPT && 93462306a36Sopenharmony_ci vxlan_opt_to_nlattr(skb, tun_opts, swkey_tun_opts_len)) 93562306a36Sopenharmony_ci return -EMSGSIZE; 93662306a36Sopenharmony_ci else if (output->tun_flags & TUNNEL_ERSPAN_OPT && 93762306a36Sopenharmony_ci nla_put(skb, OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS, 93862306a36Sopenharmony_ci swkey_tun_opts_len, tun_opts)) 93962306a36Sopenharmony_ci return -EMSGSIZE; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci return 0; 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_cistatic int ip_tun_to_nlattr(struct sk_buff *skb, 94662306a36Sopenharmony_ci const struct ip_tunnel_key *output, 94762306a36Sopenharmony_ci const void *tun_opts, int swkey_tun_opts_len, 94862306a36Sopenharmony_ci unsigned short tun_proto, u8 mode) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci struct nlattr *nla; 95162306a36Sopenharmony_ci int err; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci nla = nla_nest_start_noflag(skb, OVS_KEY_ATTR_TUNNEL); 95462306a36Sopenharmony_ci if (!nla) 95562306a36Sopenharmony_ci return -EMSGSIZE; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci err = __ip_tun_to_nlattr(skb, output, tun_opts, swkey_tun_opts_len, 95862306a36Sopenharmony_ci tun_proto, mode); 95962306a36Sopenharmony_ci if (err) 96062306a36Sopenharmony_ci return err; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci nla_nest_end(skb, nla); 96362306a36Sopenharmony_ci return 0; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ciint ovs_nla_put_tunnel_info(struct sk_buff *skb, 96762306a36Sopenharmony_ci struct ip_tunnel_info *tun_info) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci return __ip_tun_to_nlattr(skb, &tun_info->key, 97062306a36Sopenharmony_ci ip_tunnel_info_opts(tun_info), 97162306a36Sopenharmony_ci tun_info->options_len, 97262306a36Sopenharmony_ci ip_tunnel_info_af(tun_info), tun_info->mode); 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cistatic int encode_vlan_from_nlattrs(struct sw_flow_match *match, 97662306a36Sopenharmony_ci const struct nlattr *a[], 97762306a36Sopenharmony_ci bool is_mask, bool inner) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci __be16 tci = 0; 98062306a36Sopenharmony_ci __be16 tpid = 0; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci if (a[OVS_KEY_ATTR_VLAN]) 98362306a36Sopenharmony_ci tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci if (a[OVS_KEY_ATTR_ETHERTYPE]) 98662306a36Sopenharmony_ci tpid = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci if (likely(!inner)) { 98962306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, eth.vlan.tpid, tpid, is_mask); 99062306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, eth.vlan.tci, tci, is_mask); 99162306a36Sopenharmony_ci } else { 99262306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, eth.cvlan.tpid, tpid, is_mask); 99362306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, eth.cvlan.tci, tci, is_mask); 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci return 0; 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic int validate_vlan_from_nlattrs(const struct sw_flow_match *match, 99962306a36Sopenharmony_ci u64 key_attrs, bool inner, 100062306a36Sopenharmony_ci const struct nlattr **a, bool log) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci __be16 tci = 0; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci if (!((key_attrs & (1 << OVS_KEY_ATTR_ETHERNET)) && 100562306a36Sopenharmony_ci (key_attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) && 100662306a36Sopenharmony_ci eth_type_vlan(nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE])))) { 100762306a36Sopenharmony_ci /* Not a VLAN. */ 100862306a36Sopenharmony_ci return 0; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (!((key_attrs & (1 << OVS_KEY_ATTR_VLAN)) && 101262306a36Sopenharmony_ci (key_attrs & (1 << OVS_KEY_ATTR_ENCAP)))) { 101362306a36Sopenharmony_ci OVS_NLERR(log, "Invalid %s frame", (inner) ? "C-VLAN" : "VLAN"); 101462306a36Sopenharmony_ci return -EINVAL; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci if (a[OVS_KEY_ATTR_VLAN]) 101862306a36Sopenharmony_ci tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci if (!(tci & htons(VLAN_CFI_MASK))) { 102162306a36Sopenharmony_ci if (tci) { 102262306a36Sopenharmony_ci OVS_NLERR(log, "%s TCI does not have VLAN_CFI_MASK bit set.", 102362306a36Sopenharmony_ci (inner) ? "C-VLAN" : "VLAN"); 102462306a36Sopenharmony_ci return -EINVAL; 102562306a36Sopenharmony_ci } else if (nla_len(a[OVS_KEY_ATTR_ENCAP])) { 102662306a36Sopenharmony_ci /* Corner case for truncated VLAN header. */ 102762306a36Sopenharmony_ci OVS_NLERR(log, "Truncated %s header has non-zero encap attribute.", 102862306a36Sopenharmony_ci (inner) ? "C-VLAN" : "VLAN"); 102962306a36Sopenharmony_ci return -EINVAL; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci return 1; 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_cistatic int validate_vlan_mask_from_nlattrs(const struct sw_flow_match *match, 103762306a36Sopenharmony_ci u64 key_attrs, bool inner, 103862306a36Sopenharmony_ci const struct nlattr **a, bool log) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci __be16 tci = 0; 104162306a36Sopenharmony_ci __be16 tpid = 0; 104262306a36Sopenharmony_ci bool encap_valid = !!(match->key->eth.vlan.tci & 104362306a36Sopenharmony_ci htons(VLAN_CFI_MASK)); 104462306a36Sopenharmony_ci bool i_encap_valid = !!(match->key->eth.cvlan.tci & 104562306a36Sopenharmony_ci htons(VLAN_CFI_MASK)); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci if (!(key_attrs & (1 << OVS_KEY_ATTR_ENCAP))) { 104862306a36Sopenharmony_ci /* Not a VLAN. */ 104962306a36Sopenharmony_ci return 0; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if ((!inner && !encap_valid) || (inner && !i_encap_valid)) { 105362306a36Sopenharmony_ci OVS_NLERR(log, "Encap mask attribute is set for non-%s frame.", 105462306a36Sopenharmony_ci (inner) ? "C-VLAN" : "VLAN"); 105562306a36Sopenharmony_ci return -EINVAL; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci if (a[OVS_KEY_ATTR_VLAN]) 105962306a36Sopenharmony_ci tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (a[OVS_KEY_ATTR_ETHERTYPE]) 106262306a36Sopenharmony_ci tpid = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci if (tpid != htons(0xffff)) { 106562306a36Sopenharmony_ci OVS_NLERR(log, "Must have an exact match on %s TPID (mask=%x).", 106662306a36Sopenharmony_ci (inner) ? "C-VLAN" : "VLAN", ntohs(tpid)); 106762306a36Sopenharmony_ci return -EINVAL; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci if (!(tci & htons(VLAN_CFI_MASK))) { 107062306a36Sopenharmony_ci OVS_NLERR(log, "%s TCI mask does not have exact match for VLAN_CFI_MASK bit.", 107162306a36Sopenharmony_ci (inner) ? "C-VLAN" : "VLAN"); 107262306a36Sopenharmony_ci return -EINVAL; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci return 1; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistatic int __parse_vlan_from_nlattrs(struct sw_flow_match *match, 107962306a36Sopenharmony_ci u64 *key_attrs, bool inner, 108062306a36Sopenharmony_ci const struct nlattr **a, bool is_mask, 108162306a36Sopenharmony_ci bool log) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci int err; 108462306a36Sopenharmony_ci const struct nlattr *encap; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (!is_mask) 108762306a36Sopenharmony_ci err = validate_vlan_from_nlattrs(match, *key_attrs, inner, 108862306a36Sopenharmony_ci a, log); 108962306a36Sopenharmony_ci else 109062306a36Sopenharmony_ci err = validate_vlan_mask_from_nlattrs(match, *key_attrs, inner, 109162306a36Sopenharmony_ci a, log); 109262306a36Sopenharmony_ci if (err <= 0) 109362306a36Sopenharmony_ci return err; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci err = encode_vlan_from_nlattrs(match, a, is_mask, inner); 109662306a36Sopenharmony_ci if (err) 109762306a36Sopenharmony_ci return err; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci *key_attrs &= ~(1 << OVS_KEY_ATTR_ENCAP); 110062306a36Sopenharmony_ci *key_attrs &= ~(1 << OVS_KEY_ATTR_VLAN); 110162306a36Sopenharmony_ci *key_attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci encap = a[OVS_KEY_ATTR_ENCAP]; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (!is_mask) 110662306a36Sopenharmony_ci err = parse_flow_nlattrs(encap, a, key_attrs, log); 110762306a36Sopenharmony_ci else 110862306a36Sopenharmony_ci err = parse_flow_mask_nlattrs(encap, a, key_attrs, log); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci return err; 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic int parse_vlan_from_nlattrs(struct sw_flow_match *match, 111462306a36Sopenharmony_ci u64 *key_attrs, const struct nlattr **a, 111562306a36Sopenharmony_ci bool is_mask, bool log) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci int err; 111862306a36Sopenharmony_ci bool encap_valid = false; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci err = __parse_vlan_from_nlattrs(match, key_attrs, false, a, 112162306a36Sopenharmony_ci is_mask, log); 112262306a36Sopenharmony_ci if (err) 112362306a36Sopenharmony_ci return err; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci encap_valid = !!(match->key->eth.vlan.tci & htons(VLAN_CFI_MASK)); 112662306a36Sopenharmony_ci if (encap_valid) { 112762306a36Sopenharmony_ci err = __parse_vlan_from_nlattrs(match, key_attrs, true, a, 112862306a36Sopenharmony_ci is_mask, log); 112962306a36Sopenharmony_ci if (err) 113062306a36Sopenharmony_ci return err; 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci return 0; 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_cistatic int parse_eth_type_from_nlattrs(struct sw_flow_match *match, 113762306a36Sopenharmony_ci u64 *attrs, const struct nlattr **a, 113862306a36Sopenharmony_ci bool is_mask, bool log) 113962306a36Sopenharmony_ci{ 114062306a36Sopenharmony_ci __be16 eth_type; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]); 114362306a36Sopenharmony_ci if (is_mask) { 114462306a36Sopenharmony_ci /* Always exact match EtherType. */ 114562306a36Sopenharmony_ci eth_type = htons(0xffff); 114662306a36Sopenharmony_ci } else if (!eth_proto_is_802_3(eth_type)) { 114762306a36Sopenharmony_ci OVS_NLERR(log, "EtherType %x is less than min %x", 114862306a36Sopenharmony_ci ntohs(eth_type), ETH_P_802_3_MIN); 114962306a36Sopenharmony_ci return -EINVAL; 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, eth.type, eth_type, is_mask); 115362306a36Sopenharmony_ci *attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE); 115462306a36Sopenharmony_ci return 0; 115562306a36Sopenharmony_ci} 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_cistatic int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match, 115862306a36Sopenharmony_ci u64 *attrs, const struct nlattr **a, 115962306a36Sopenharmony_ci bool is_mask, bool log) 116062306a36Sopenharmony_ci{ 116162306a36Sopenharmony_ci u8 mac_proto = MAC_PROTO_ETHERNET; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci if (*attrs & (1 << OVS_KEY_ATTR_DP_HASH)) { 116462306a36Sopenharmony_ci u32 hash_val = nla_get_u32(a[OVS_KEY_ATTR_DP_HASH]); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ovs_flow_hash, hash_val, is_mask); 116762306a36Sopenharmony_ci *attrs &= ~(1 << OVS_KEY_ATTR_DP_HASH); 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci if (*attrs & (1 << OVS_KEY_ATTR_RECIRC_ID)) { 117162306a36Sopenharmony_ci u32 recirc_id = nla_get_u32(a[OVS_KEY_ATTR_RECIRC_ID]); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, recirc_id, recirc_id, is_mask); 117462306a36Sopenharmony_ci *attrs &= ~(1 << OVS_KEY_ATTR_RECIRC_ID); 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci if (*attrs & (1 << OVS_KEY_ATTR_PRIORITY)) { 117862306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, phy.priority, 117962306a36Sopenharmony_ci nla_get_u32(a[OVS_KEY_ATTR_PRIORITY]), is_mask); 118062306a36Sopenharmony_ci *attrs &= ~(1 << OVS_KEY_ATTR_PRIORITY); 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci if (*attrs & (1 << OVS_KEY_ATTR_IN_PORT)) { 118462306a36Sopenharmony_ci u32 in_port = nla_get_u32(a[OVS_KEY_ATTR_IN_PORT]); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (is_mask) { 118762306a36Sopenharmony_ci in_port = 0xffffffff; /* Always exact match in_port. */ 118862306a36Sopenharmony_ci } else if (in_port >= DP_MAX_PORTS) { 118962306a36Sopenharmony_ci OVS_NLERR(log, "Port %d exceeds max allowable %d", 119062306a36Sopenharmony_ci in_port, DP_MAX_PORTS); 119162306a36Sopenharmony_ci return -EINVAL; 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, phy.in_port, in_port, is_mask); 119562306a36Sopenharmony_ci *attrs &= ~(1 << OVS_KEY_ATTR_IN_PORT); 119662306a36Sopenharmony_ci } else if (!is_mask) { 119762306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, phy.in_port, DP_MAX_PORTS, is_mask); 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci if (*attrs & (1 << OVS_KEY_ATTR_SKB_MARK)) { 120162306a36Sopenharmony_ci uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, phy.skb_mark, mark, is_mask); 120462306a36Sopenharmony_ci *attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK); 120562306a36Sopenharmony_ci } 120662306a36Sopenharmony_ci if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) { 120762306a36Sopenharmony_ci if (ip_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match, 120862306a36Sopenharmony_ci is_mask, log) < 0) 120962306a36Sopenharmony_ci return -EINVAL; 121062306a36Sopenharmony_ci *attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL); 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci if (*attrs & (1 << OVS_KEY_ATTR_CT_STATE) && 121462306a36Sopenharmony_ci ovs_ct_verify(net, OVS_KEY_ATTR_CT_STATE)) { 121562306a36Sopenharmony_ci u32 ct_state = nla_get_u32(a[OVS_KEY_ATTR_CT_STATE]); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci if (ct_state & ~CT_SUPPORTED_MASK) { 121862306a36Sopenharmony_ci OVS_NLERR(log, "ct_state flags %08x unsupported", 121962306a36Sopenharmony_ci ct_state); 122062306a36Sopenharmony_ci return -EINVAL; 122162306a36Sopenharmony_ci } 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ct_state, ct_state, is_mask); 122462306a36Sopenharmony_ci *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_STATE); 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci if (*attrs & (1 << OVS_KEY_ATTR_CT_ZONE) && 122762306a36Sopenharmony_ci ovs_ct_verify(net, OVS_KEY_ATTR_CT_ZONE)) { 122862306a36Sopenharmony_ci u16 ct_zone = nla_get_u16(a[OVS_KEY_ATTR_CT_ZONE]); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ct_zone, ct_zone, is_mask); 123162306a36Sopenharmony_ci *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE); 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci if (*attrs & (1 << OVS_KEY_ATTR_CT_MARK) && 123462306a36Sopenharmony_ci ovs_ct_verify(net, OVS_KEY_ATTR_CT_MARK)) { 123562306a36Sopenharmony_ci u32 mark = nla_get_u32(a[OVS_KEY_ATTR_CT_MARK]); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ct.mark, mark, is_mask); 123862306a36Sopenharmony_ci *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_MARK); 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci if (*attrs & (1 << OVS_KEY_ATTR_CT_LABELS) && 124162306a36Sopenharmony_ci ovs_ct_verify(net, OVS_KEY_ATTR_CT_LABELS)) { 124262306a36Sopenharmony_ci const struct ovs_key_ct_labels *cl; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci cl = nla_data(a[OVS_KEY_ATTR_CT_LABELS]); 124562306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY(match, ct.labels, cl->ct_labels, 124662306a36Sopenharmony_ci sizeof(*cl), is_mask); 124762306a36Sopenharmony_ci *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_LABELS); 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci if (*attrs & (1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4)) { 125062306a36Sopenharmony_ci const struct ovs_key_ct_tuple_ipv4 *ct; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci ct = nla_data(a[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4]); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ipv4.ct_orig.src, ct->ipv4_src, is_mask); 125562306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ipv4.ct_orig.dst, ct->ipv4_dst, is_mask); 125662306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ct.orig_tp.src, ct->src_port, is_mask); 125762306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ct.orig_tp.dst, ct->dst_port, is_mask); 125862306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ct_orig_proto, ct->ipv4_proto, is_mask); 125962306a36Sopenharmony_ci *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4); 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci if (*attrs & (1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6)) { 126262306a36Sopenharmony_ci const struct ovs_key_ct_tuple_ipv6 *ct; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci ct = nla_data(a[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6]); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY(match, ipv6.ct_orig.src, &ct->ipv6_src, 126762306a36Sopenharmony_ci sizeof(match->key->ipv6.ct_orig.src), 126862306a36Sopenharmony_ci is_mask); 126962306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY(match, ipv6.ct_orig.dst, &ct->ipv6_dst, 127062306a36Sopenharmony_ci sizeof(match->key->ipv6.ct_orig.dst), 127162306a36Sopenharmony_ci is_mask); 127262306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ct.orig_tp.src, ct->src_port, is_mask); 127362306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ct.orig_tp.dst, ct->dst_port, is_mask); 127462306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ct_orig_proto, ct->ipv6_proto, is_mask); 127562306a36Sopenharmony_ci *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6); 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci /* For layer 3 packets the Ethernet type is provided 127962306a36Sopenharmony_ci * and treated as metadata but no MAC addresses are provided. 128062306a36Sopenharmony_ci */ 128162306a36Sopenharmony_ci if (!(*attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) && 128262306a36Sopenharmony_ci (*attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE))) 128362306a36Sopenharmony_ci mac_proto = MAC_PROTO_NONE; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci /* Always exact match mac_proto */ 128662306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, mac_proto, is_mask ? 0xff : mac_proto, is_mask); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (mac_proto == MAC_PROTO_NONE) 128962306a36Sopenharmony_ci return parse_eth_type_from_nlattrs(match, attrs, a, is_mask, 129062306a36Sopenharmony_ci log); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci return 0; 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ciint nsh_hdr_from_nlattr(const struct nlattr *attr, 129662306a36Sopenharmony_ci struct nshhdr *nh, size_t size) 129762306a36Sopenharmony_ci{ 129862306a36Sopenharmony_ci struct nlattr *a; 129962306a36Sopenharmony_ci int rem; 130062306a36Sopenharmony_ci u8 flags = 0; 130162306a36Sopenharmony_ci u8 ttl = 0; 130262306a36Sopenharmony_ci int mdlen = 0; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci /* validate_nsh has check this, so we needn't do duplicate check here 130562306a36Sopenharmony_ci */ 130662306a36Sopenharmony_ci if (size < NSH_BASE_HDR_LEN) 130762306a36Sopenharmony_ci return -ENOBUFS; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci nla_for_each_nested(a, attr, rem) { 131062306a36Sopenharmony_ci int type = nla_type(a); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci switch (type) { 131362306a36Sopenharmony_ci case OVS_NSH_KEY_ATTR_BASE: { 131462306a36Sopenharmony_ci const struct ovs_nsh_key_base *base = nla_data(a); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci flags = base->flags; 131762306a36Sopenharmony_ci ttl = base->ttl; 131862306a36Sopenharmony_ci nh->np = base->np; 131962306a36Sopenharmony_ci nh->mdtype = base->mdtype; 132062306a36Sopenharmony_ci nh->path_hdr = base->path_hdr; 132162306a36Sopenharmony_ci break; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci case OVS_NSH_KEY_ATTR_MD1: 132462306a36Sopenharmony_ci mdlen = nla_len(a); 132562306a36Sopenharmony_ci if (mdlen > size - NSH_BASE_HDR_LEN) 132662306a36Sopenharmony_ci return -ENOBUFS; 132762306a36Sopenharmony_ci memcpy(&nh->md1, nla_data(a), mdlen); 132862306a36Sopenharmony_ci break; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci case OVS_NSH_KEY_ATTR_MD2: 133162306a36Sopenharmony_ci mdlen = nla_len(a); 133262306a36Sopenharmony_ci if (mdlen > size - NSH_BASE_HDR_LEN) 133362306a36Sopenharmony_ci return -ENOBUFS; 133462306a36Sopenharmony_ci memcpy(&nh->md2, nla_data(a), mdlen); 133562306a36Sopenharmony_ci break; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci default: 133862306a36Sopenharmony_ci return -EINVAL; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci /* nsh header length = NSH_BASE_HDR_LEN + mdlen */ 134362306a36Sopenharmony_ci nh->ver_flags_ttl_len = 0; 134462306a36Sopenharmony_ci nsh_set_flags_ttl_len(nh, flags, ttl, NSH_BASE_HDR_LEN + mdlen); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci return 0; 134762306a36Sopenharmony_ci} 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ciint nsh_key_from_nlattr(const struct nlattr *attr, 135062306a36Sopenharmony_ci struct ovs_key_nsh *nsh, struct ovs_key_nsh *nsh_mask) 135162306a36Sopenharmony_ci{ 135262306a36Sopenharmony_ci struct nlattr *a; 135362306a36Sopenharmony_ci int rem; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci /* validate_nsh has check this, so we needn't do duplicate check here 135662306a36Sopenharmony_ci */ 135762306a36Sopenharmony_ci nla_for_each_nested(a, attr, rem) { 135862306a36Sopenharmony_ci int type = nla_type(a); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci switch (type) { 136162306a36Sopenharmony_ci case OVS_NSH_KEY_ATTR_BASE: { 136262306a36Sopenharmony_ci const struct ovs_nsh_key_base *base = nla_data(a); 136362306a36Sopenharmony_ci const struct ovs_nsh_key_base *base_mask = base + 1; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci nsh->base = *base; 136662306a36Sopenharmony_ci nsh_mask->base = *base_mask; 136762306a36Sopenharmony_ci break; 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci case OVS_NSH_KEY_ATTR_MD1: { 137062306a36Sopenharmony_ci const struct ovs_nsh_key_md1 *md1 = nla_data(a); 137162306a36Sopenharmony_ci const struct ovs_nsh_key_md1 *md1_mask = md1 + 1; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci memcpy(nsh->context, md1->context, sizeof(*md1)); 137462306a36Sopenharmony_ci memcpy(nsh_mask->context, md1_mask->context, 137562306a36Sopenharmony_ci sizeof(*md1_mask)); 137662306a36Sopenharmony_ci break; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci case OVS_NSH_KEY_ATTR_MD2: 137962306a36Sopenharmony_ci /* Not supported yet */ 138062306a36Sopenharmony_ci return -ENOTSUPP; 138162306a36Sopenharmony_ci default: 138262306a36Sopenharmony_ci return -EINVAL; 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci return 0; 138762306a36Sopenharmony_ci} 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_cistatic int nsh_key_put_from_nlattr(const struct nlattr *attr, 139062306a36Sopenharmony_ci struct sw_flow_match *match, bool is_mask, 139162306a36Sopenharmony_ci bool is_push_nsh, bool log) 139262306a36Sopenharmony_ci{ 139362306a36Sopenharmony_ci struct nlattr *a; 139462306a36Sopenharmony_ci int rem; 139562306a36Sopenharmony_ci bool has_base = false; 139662306a36Sopenharmony_ci bool has_md1 = false; 139762306a36Sopenharmony_ci bool has_md2 = false; 139862306a36Sopenharmony_ci u8 mdtype = 0; 139962306a36Sopenharmony_ci int mdlen = 0; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci if (WARN_ON(is_push_nsh && is_mask)) 140262306a36Sopenharmony_ci return -EINVAL; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci nla_for_each_nested(a, attr, rem) { 140562306a36Sopenharmony_ci int type = nla_type(a); 140662306a36Sopenharmony_ci int i; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci if (type > OVS_NSH_KEY_ATTR_MAX) { 140962306a36Sopenharmony_ci OVS_NLERR(log, "nsh attr %d is out of range max %d", 141062306a36Sopenharmony_ci type, OVS_NSH_KEY_ATTR_MAX); 141162306a36Sopenharmony_ci return -EINVAL; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (!check_attr_len(nla_len(a), 141562306a36Sopenharmony_ci ovs_nsh_key_attr_lens[type].len)) { 141662306a36Sopenharmony_ci OVS_NLERR( 141762306a36Sopenharmony_ci log, 141862306a36Sopenharmony_ci "nsh attr %d has unexpected len %d expected %d", 141962306a36Sopenharmony_ci type, 142062306a36Sopenharmony_ci nla_len(a), 142162306a36Sopenharmony_ci ovs_nsh_key_attr_lens[type].len 142262306a36Sopenharmony_ci ); 142362306a36Sopenharmony_ci return -EINVAL; 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci switch (type) { 142762306a36Sopenharmony_ci case OVS_NSH_KEY_ATTR_BASE: { 142862306a36Sopenharmony_ci const struct ovs_nsh_key_base *base = nla_data(a); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci has_base = true; 143162306a36Sopenharmony_ci mdtype = base->mdtype; 143262306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, nsh.base.flags, 143362306a36Sopenharmony_ci base->flags, is_mask); 143462306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, nsh.base.ttl, 143562306a36Sopenharmony_ci base->ttl, is_mask); 143662306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, nsh.base.mdtype, 143762306a36Sopenharmony_ci base->mdtype, is_mask); 143862306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, nsh.base.np, 143962306a36Sopenharmony_ci base->np, is_mask); 144062306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, nsh.base.path_hdr, 144162306a36Sopenharmony_ci base->path_hdr, is_mask); 144262306a36Sopenharmony_ci break; 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci case OVS_NSH_KEY_ATTR_MD1: { 144562306a36Sopenharmony_ci const struct ovs_nsh_key_md1 *md1 = nla_data(a); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci has_md1 = true; 144862306a36Sopenharmony_ci for (i = 0; i < NSH_MD1_CONTEXT_SIZE; i++) 144962306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, nsh.context[i], 145062306a36Sopenharmony_ci md1->context[i], is_mask); 145162306a36Sopenharmony_ci break; 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci case OVS_NSH_KEY_ATTR_MD2: 145462306a36Sopenharmony_ci if (!is_push_nsh) /* Not supported MD type 2 yet */ 145562306a36Sopenharmony_ci return -ENOTSUPP; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci has_md2 = true; 145862306a36Sopenharmony_ci mdlen = nla_len(a); 145962306a36Sopenharmony_ci if (mdlen > NSH_CTX_HDRS_MAX_LEN || mdlen <= 0) { 146062306a36Sopenharmony_ci OVS_NLERR( 146162306a36Sopenharmony_ci log, 146262306a36Sopenharmony_ci "Invalid MD length %d for MD type %d", 146362306a36Sopenharmony_ci mdlen, 146462306a36Sopenharmony_ci mdtype 146562306a36Sopenharmony_ci ); 146662306a36Sopenharmony_ci return -EINVAL; 146762306a36Sopenharmony_ci } 146862306a36Sopenharmony_ci break; 146962306a36Sopenharmony_ci default: 147062306a36Sopenharmony_ci OVS_NLERR(log, "Unknown nsh attribute %d", 147162306a36Sopenharmony_ci type); 147262306a36Sopenharmony_ci return -EINVAL; 147362306a36Sopenharmony_ci } 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci if (rem > 0) { 147762306a36Sopenharmony_ci OVS_NLERR(log, "nsh attribute has %d unknown bytes.", rem); 147862306a36Sopenharmony_ci return -EINVAL; 147962306a36Sopenharmony_ci } 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci if (has_md1 && has_md2) { 148262306a36Sopenharmony_ci OVS_NLERR( 148362306a36Sopenharmony_ci 1, 148462306a36Sopenharmony_ci "invalid nsh attribute: md1 and md2 are exclusive." 148562306a36Sopenharmony_ci ); 148662306a36Sopenharmony_ci return -EINVAL; 148762306a36Sopenharmony_ci } 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if (!is_mask) { 149062306a36Sopenharmony_ci if ((has_md1 && mdtype != NSH_M_TYPE1) || 149162306a36Sopenharmony_ci (has_md2 && mdtype != NSH_M_TYPE2)) { 149262306a36Sopenharmony_ci OVS_NLERR(1, "nsh attribute has unmatched MD type %d.", 149362306a36Sopenharmony_ci mdtype); 149462306a36Sopenharmony_ci return -EINVAL; 149562306a36Sopenharmony_ci } 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci if (is_push_nsh && 149862306a36Sopenharmony_ci (!has_base || (!has_md1 && !has_md2))) { 149962306a36Sopenharmony_ci OVS_NLERR( 150062306a36Sopenharmony_ci 1, 150162306a36Sopenharmony_ci "push_nsh: missing base or metadata attributes" 150262306a36Sopenharmony_ci ); 150362306a36Sopenharmony_ci return -EINVAL; 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci return 0; 150862306a36Sopenharmony_ci} 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_cistatic int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match, 151162306a36Sopenharmony_ci u64 attrs, const struct nlattr **a, 151262306a36Sopenharmony_ci bool is_mask, bool log) 151362306a36Sopenharmony_ci{ 151462306a36Sopenharmony_ci int err; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci err = metadata_from_nlattrs(net, match, &attrs, a, is_mask, log); 151762306a36Sopenharmony_ci if (err) 151862306a36Sopenharmony_ci return err; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_ETHERNET)) { 152162306a36Sopenharmony_ci const struct ovs_key_ethernet *eth_key; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci eth_key = nla_data(a[OVS_KEY_ATTR_ETHERNET]); 152462306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY(match, eth.src, 152562306a36Sopenharmony_ci eth_key->eth_src, ETH_ALEN, is_mask); 152662306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY(match, eth.dst, 152762306a36Sopenharmony_ci eth_key->eth_dst, ETH_ALEN, is_mask); 152862306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_ETHERNET); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_VLAN)) { 153162306a36Sopenharmony_ci /* VLAN attribute is always parsed before getting here since it 153262306a36Sopenharmony_ci * may occur multiple times. 153362306a36Sopenharmony_ci */ 153462306a36Sopenharmony_ci OVS_NLERR(log, "VLAN attribute unexpected."); 153562306a36Sopenharmony_ci return -EINVAL; 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) { 153962306a36Sopenharmony_ci err = parse_eth_type_from_nlattrs(match, &attrs, a, is_mask, 154062306a36Sopenharmony_ci log); 154162306a36Sopenharmony_ci if (err) 154262306a36Sopenharmony_ci return err; 154362306a36Sopenharmony_ci } else if (!is_mask) { 154462306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2), is_mask); 154562306a36Sopenharmony_ci } 154662306a36Sopenharmony_ci } else if (!match->key->eth.type) { 154762306a36Sopenharmony_ci OVS_NLERR(log, "Either Ethernet header or EtherType is required."); 154862306a36Sopenharmony_ci return -EINVAL; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_IPV4)) { 155262306a36Sopenharmony_ci const struct ovs_key_ipv4 *ipv4_key; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]); 155562306a36Sopenharmony_ci if (!is_mask && ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) { 155662306a36Sopenharmony_ci OVS_NLERR(log, "IPv4 frag type %d is out of range max %d", 155762306a36Sopenharmony_ci ipv4_key->ipv4_frag, OVS_FRAG_TYPE_MAX); 155862306a36Sopenharmony_ci return -EINVAL; 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ip.proto, 156162306a36Sopenharmony_ci ipv4_key->ipv4_proto, is_mask); 156262306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ip.tos, 156362306a36Sopenharmony_ci ipv4_key->ipv4_tos, is_mask); 156462306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ip.ttl, 156562306a36Sopenharmony_ci ipv4_key->ipv4_ttl, is_mask); 156662306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ip.frag, 156762306a36Sopenharmony_ci ipv4_key->ipv4_frag, is_mask); 156862306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ipv4.addr.src, 156962306a36Sopenharmony_ci ipv4_key->ipv4_src, is_mask); 157062306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ipv4.addr.dst, 157162306a36Sopenharmony_ci ipv4_key->ipv4_dst, is_mask); 157262306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_IPV4); 157362306a36Sopenharmony_ci } 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_IPV6)) { 157662306a36Sopenharmony_ci const struct ovs_key_ipv6 *ipv6_key; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]); 157962306a36Sopenharmony_ci if (!is_mask && ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) { 158062306a36Sopenharmony_ci OVS_NLERR(log, "IPv6 frag type %d is out of range max %d", 158162306a36Sopenharmony_ci ipv6_key->ipv6_frag, OVS_FRAG_TYPE_MAX); 158262306a36Sopenharmony_ci return -EINVAL; 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (!is_mask && ipv6_key->ipv6_label & htonl(0xFFF00000)) { 158662306a36Sopenharmony_ci OVS_NLERR(log, "IPv6 flow label %x is out of range (max=%x)", 158762306a36Sopenharmony_ci ntohl(ipv6_key->ipv6_label), (1 << 20) - 1); 158862306a36Sopenharmony_ci return -EINVAL; 158962306a36Sopenharmony_ci } 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ipv6.label, 159262306a36Sopenharmony_ci ipv6_key->ipv6_label, is_mask); 159362306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ip.proto, 159462306a36Sopenharmony_ci ipv6_key->ipv6_proto, is_mask); 159562306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ip.tos, 159662306a36Sopenharmony_ci ipv6_key->ipv6_tclass, is_mask); 159762306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ip.ttl, 159862306a36Sopenharmony_ci ipv6_key->ipv6_hlimit, is_mask); 159962306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ip.frag, 160062306a36Sopenharmony_ci ipv6_key->ipv6_frag, is_mask); 160162306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY(match, ipv6.addr.src, 160262306a36Sopenharmony_ci ipv6_key->ipv6_src, 160362306a36Sopenharmony_ci sizeof(match->key->ipv6.addr.src), 160462306a36Sopenharmony_ci is_mask); 160562306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY(match, ipv6.addr.dst, 160662306a36Sopenharmony_ci ipv6_key->ipv6_dst, 160762306a36Sopenharmony_ci sizeof(match->key->ipv6.addr.dst), 160862306a36Sopenharmony_ci is_mask); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_IPV6); 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci if (attrs & (1ULL << OVS_KEY_ATTR_IPV6_EXTHDRS)) { 161462306a36Sopenharmony_ci const struct ovs_key_ipv6_exthdrs *ipv6_exthdrs_key; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci ipv6_exthdrs_key = nla_data(a[OVS_KEY_ATTR_IPV6_EXTHDRS]); 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ipv6.exthdrs, 161962306a36Sopenharmony_ci ipv6_exthdrs_key->hdrs, is_mask); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci attrs &= ~(1ULL << OVS_KEY_ATTR_IPV6_EXTHDRS); 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_ARP)) { 162562306a36Sopenharmony_ci const struct ovs_key_arp *arp_key; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci arp_key = nla_data(a[OVS_KEY_ATTR_ARP]); 162862306a36Sopenharmony_ci if (!is_mask && (arp_key->arp_op & htons(0xff00))) { 162962306a36Sopenharmony_ci OVS_NLERR(log, "Unknown ARP opcode (opcode=%d).", 163062306a36Sopenharmony_ci arp_key->arp_op); 163162306a36Sopenharmony_ci return -EINVAL; 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ipv4.addr.src, 163562306a36Sopenharmony_ci arp_key->arp_sip, is_mask); 163662306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ipv4.addr.dst, 163762306a36Sopenharmony_ci arp_key->arp_tip, is_mask); 163862306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, ip.proto, 163962306a36Sopenharmony_ci ntohs(arp_key->arp_op), is_mask); 164062306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY(match, ipv4.arp.sha, 164162306a36Sopenharmony_ci arp_key->arp_sha, ETH_ALEN, is_mask); 164262306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY(match, ipv4.arp.tha, 164362306a36Sopenharmony_ci arp_key->arp_tha, ETH_ALEN, is_mask); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_ARP); 164662306a36Sopenharmony_ci } 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_NSH)) { 164962306a36Sopenharmony_ci if (nsh_key_put_from_nlattr(a[OVS_KEY_ATTR_NSH], match, 165062306a36Sopenharmony_ci is_mask, false, log) < 0) 165162306a36Sopenharmony_ci return -EINVAL; 165262306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_NSH); 165362306a36Sopenharmony_ci } 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_MPLS)) { 165662306a36Sopenharmony_ci const struct ovs_key_mpls *mpls_key; 165762306a36Sopenharmony_ci u32 hdr_len; 165862306a36Sopenharmony_ci u32 label_count, label_count_mask, i; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci mpls_key = nla_data(a[OVS_KEY_ATTR_MPLS]); 166162306a36Sopenharmony_ci hdr_len = nla_len(a[OVS_KEY_ATTR_MPLS]); 166262306a36Sopenharmony_ci label_count = hdr_len / sizeof(struct ovs_key_mpls); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci if (label_count == 0 || label_count > MPLS_LABEL_DEPTH || 166562306a36Sopenharmony_ci hdr_len % sizeof(struct ovs_key_mpls)) 166662306a36Sopenharmony_ci return -EINVAL; 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci label_count_mask = GENMASK(label_count - 1, 0); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci for (i = 0 ; i < label_count; i++) 167162306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, mpls.lse[i], 167262306a36Sopenharmony_ci mpls_key[i].mpls_lse, is_mask); 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, mpls.num_labels_mask, 167562306a36Sopenharmony_ci label_count_mask, is_mask); 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_MPLS); 167862306a36Sopenharmony_ci } 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_TCP)) { 168162306a36Sopenharmony_ci const struct ovs_key_tcp *tcp_key; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci tcp_key = nla_data(a[OVS_KEY_ATTR_TCP]); 168462306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tp.src, tcp_key->tcp_src, is_mask); 168562306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tp.dst, tcp_key->tcp_dst, is_mask); 168662306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_TCP); 168762306a36Sopenharmony_ci } 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_TCP_FLAGS)) { 169062306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tp.flags, 169162306a36Sopenharmony_ci nla_get_be16(a[OVS_KEY_ATTR_TCP_FLAGS]), 169262306a36Sopenharmony_ci is_mask); 169362306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_TCP_FLAGS); 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_UDP)) { 169762306a36Sopenharmony_ci const struct ovs_key_udp *udp_key; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci udp_key = nla_data(a[OVS_KEY_ATTR_UDP]); 170062306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tp.src, udp_key->udp_src, is_mask); 170162306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tp.dst, udp_key->udp_dst, is_mask); 170262306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_UDP); 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_SCTP)) { 170662306a36Sopenharmony_ci const struct ovs_key_sctp *sctp_key; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci sctp_key = nla_data(a[OVS_KEY_ATTR_SCTP]); 170962306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tp.src, sctp_key->sctp_src, is_mask); 171062306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tp.dst, sctp_key->sctp_dst, is_mask); 171162306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_SCTP); 171262306a36Sopenharmony_ci } 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_ICMP)) { 171562306a36Sopenharmony_ci const struct ovs_key_icmp *icmp_key; 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci icmp_key = nla_data(a[OVS_KEY_ATTR_ICMP]); 171862306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tp.src, 171962306a36Sopenharmony_ci htons(icmp_key->icmp_type), is_mask); 172062306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tp.dst, 172162306a36Sopenharmony_ci htons(icmp_key->icmp_code), is_mask); 172262306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_ICMP); 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_ICMPV6)) { 172662306a36Sopenharmony_ci const struct ovs_key_icmpv6 *icmpv6_key; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci icmpv6_key = nla_data(a[OVS_KEY_ATTR_ICMPV6]); 172962306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tp.src, 173062306a36Sopenharmony_ci htons(icmpv6_key->icmpv6_type), is_mask); 173162306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, tp.dst, 173262306a36Sopenharmony_ci htons(icmpv6_key->icmpv6_code), is_mask); 173362306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_ICMPV6); 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci if (attrs & (1 << OVS_KEY_ATTR_ND)) { 173762306a36Sopenharmony_ci const struct ovs_key_nd *nd_key; 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci nd_key = nla_data(a[OVS_KEY_ATTR_ND]); 174062306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY(match, ipv6.nd.target, 174162306a36Sopenharmony_ci nd_key->nd_target, 174262306a36Sopenharmony_ci sizeof(match->key->ipv6.nd.target), 174362306a36Sopenharmony_ci is_mask); 174462306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY(match, ipv6.nd.sll, 174562306a36Sopenharmony_ci nd_key->nd_sll, ETH_ALEN, is_mask); 174662306a36Sopenharmony_ci SW_FLOW_KEY_MEMCPY(match, ipv6.nd.tll, 174762306a36Sopenharmony_ci nd_key->nd_tll, ETH_ALEN, is_mask); 174862306a36Sopenharmony_ci attrs &= ~(1 << OVS_KEY_ATTR_ND); 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci if (attrs != 0) { 175262306a36Sopenharmony_ci OVS_NLERR(log, "Unknown key attributes %llx", 175362306a36Sopenharmony_ci (unsigned long long)attrs); 175462306a36Sopenharmony_ci return -EINVAL; 175562306a36Sopenharmony_ci } 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci return 0; 175862306a36Sopenharmony_ci} 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_cistatic void nlattr_set(struct nlattr *attr, u8 val, 176162306a36Sopenharmony_ci const struct ovs_len_tbl *tbl) 176262306a36Sopenharmony_ci{ 176362306a36Sopenharmony_ci struct nlattr *nla; 176462306a36Sopenharmony_ci int rem; 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci /* The nlattr stream should already have been validated */ 176762306a36Sopenharmony_ci nla_for_each_nested(nla, attr, rem) { 176862306a36Sopenharmony_ci if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED) 176962306a36Sopenharmony_ci nlattr_set(nla, val, tbl[nla_type(nla)].next ? : tbl); 177062306a36Sopenharmony_ci else 177162306a36Sopenharmony_ci memset(nla_data(nla), val, nla_len(nla)); 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci if (nla_type(nla) == OVS_KEY_ATTR_CT_STATE) 177462306a36Sopenharmony_ci *(u32 *)nla_data(nla) &= CT_SUPPORTED_MASK; 177562306a36Sopenharmony_ci } 177662306a36Sopenharmony_ci} 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_cistatic void mask_set_nlattr(struct nlattr *attr, u8 val) 177962306a36Sopenharmony_ci{ 178062306a36Sopenharmony_ci nlattr_set(attr, val, ovs_key_lens); 178162306a36Sopenharmony_ci} 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci/** 178462306a36Sopenharmony_ci * ovs_nla_get_match - parses Netlink attributes into a flow key and 178562306a36Sopenharmony_ci * mask. In case the 'mask' is NULL, the flow is treated as exact match 178662306a36Sopenharmony_ci * flow. Otherwise, it is treated as a wildcarded flow, except the mask 178762306a36Sopenharmony_ci * does not include any don't care bit. 178862306a36Sopenharmony_ci * @net: Used to determine per-namespace field support. 178962306a36Sopenharmony_ci * @match: receives the extracted flow match information. 179062306a36Sopenharmony_ci * @nla_key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute 179162306a36Sopenharmony_ci * sequence. The fields should of the packet that triggered the creation 179262306a36Sopenharmony_ci * of this flow. 179362306a36Sopenharmony_ci * @nla_mask: Optional. Netlink attribute holding nested %OVS_KEY_ATTR_* 179462306a36Sopenharmony_ci * Netlink attribute specifies the mask field of the wildcarded flow. 179562306a36Sopenharmony_ci * @log: Boolean to allow kernel error logging. Normally true, but when 179662306a36Sopenharmony_ci * probing for feature compatibility this should be passed in as false to 179762306a36Sopenharmony_ci * suppress unnecessary error logging. 179862306a36Sopenharmony_ci */ 179962306a36Sopenharmony_ciint ovs_nla_get_match(struct net *net, struct sw_flow_match *match, 180062306a36Sopenharmony_ci const struct nlattr *nla_key, 180162306a36Sopenharmony_ci const struct nlattr *nla_mask, 180262306a36Sopenharmony_ci bool log) 180362306a36Sopenharmony_ci{ 180462306a36Sopenharmony_ci const struct nlattr *a[OVS_KEY_ATTR_MAX + 1]; 180562306a36Sopenharmony_ci struct nlattr *newmask = NULL; 180662306a36Sopenharmony_ci u64 key_attrs = 0; 180762306a36Sopenharmony_ci u64 mask_attrs = 0; 180862306a36Sopenharmony_ci int err; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci err = parse_flow_nlattrs(nla_key, a, &key_attrs, log); 181162306a36Sopenharmony_ci if (err) 181262306a36Sopenharmony_ci return err; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci err = parse_vlan_from_nlattrs(match, &key_attrs, a, false, log); 181562306a36Sopenharmony_ci if (err) 181662306a36Sopenharmony_ci return err; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci err = ovs_key_from_nlattrs(net, match, key_attrs, a, false, log); 181962306a36Sopenharmony_ci if (err) 182062306a36Sopenharmony_ci return err; 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci if (match->mask) { 182362306a36Sopenharmony_ci if (!nla_mask) { 182462306a36Sopenharmony_ci /* Create an exact match mask. We need to set to 0xff 182562306a36Sopenharmony_ci * all the 'match->mask' fields that have been touched 182662306a36Sopenharmony_ci * in 'match->key'. We cannot simply memset 182762306a36Sopenharmony_ci * 'match->mask', because padding bytes and fields not 182862306a36Sopenharmony_ci * specified in 'match->key' should be left to 0. 182962306a36Sopenharmony_ci * Instead, we use a stream of netlink attributes, 183062306a36Sopenharmony_ci * copied from 'key' and set to 0xff. 183162306a36Sopenharmony_ci * ovs_key_from_nlattrs() will take care of filling 183262306a36Sopenharmony_ci * 'match->mask' appropriately. 183362306a36Sopenharmony_ci */ 183462306a36Sopenharmony_ci newmask = kmemdup(nla_key, 183562306a36Sopenharmony_ci nla_total_size(nla_len(nla_key)), 183662306a36Sopenharmony_ci GFP_KERNEL); 183762306a36Sopenharmony_ci if (!newmask) 183862306a36Sopenharmony_ci return -ENOMEM; 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci mask_set_nlattr(newmask, 0xff); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci /* The userspace does not send tunnel attributes that 184362306a36Sopenharmony_ci * are 0, but we should not wildcard them nonetheless. 184462306a36Sopenharmony_ci */ 184562306a36Sopenharmony_ci if (match->key->tun_proto) 184662306a36Sopenharmony_ci SW_FLOW_KEY_MEMSET_FIELD(match, tun_key, 184762306a36Sopenharmony_ci 0xff, true); 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci nla_mask = newmask; 185062306a36Sopenharmony_ci } 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci err = parse_flow_mask_nlattrs(nla_mask, a, &mask_attrs, log); 185362306a36Sopenharmony_ci if (err) 185462306a36Sopenharmony_ci goto free_newmask; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci /* Always match on tci. */ 185762306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, eth.vlan.tci, htons(0xffff), true); 185862306a36Sopenharmony_ci SW_FLOW_KEY_PUT(match, eth.cvlan.tci, htons(0xffff), true); 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci err = parse_vlan_from_nlattrs(match, &mask_attrs, a, true, log); 186162306a36Sopenharmony_ci if (err) 186262306a36Sopenharmony_ci goto free_newmask; 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci err = ovs_key_from_nlattrs(net, match, mask_attrs, a, true, 186562306a36Sopenharmony_ci log); 186662306a36Sopenharmony_ci if (err) 186762306a36Sopenharmony_ci goto free_newmask; 186862306a36Sopenharmony_ci } 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci if (!match_validate(match, key_attrs, mask_attrs, log)) 187162306a36Sopenharmony_ci err = -EINVAL; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_cifree_newmask: 187462306a36Sopenharmony_ci kfree(newmask); 187562306a36Sopenharmony_ci return err; 187662306a36Sopenharmony_ci} 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_cistatic size_t get_ufid_len(const struct nlattr *attr, bool log) 187962306a36Sopenharmony_ci{ 188062306a36Sopenharmony_ci size_t len; 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci if (!attr) 188362306a36Sopenharmony_ci return 0; 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci len = nla_len(attr); 188662306a36Sopenharmony_ci if (len < 1 || len > MAX_UFID_LENGTH) { 188762306a36Sopenharmony_ci OVS_NLERR(log, "ufid size %u bytes exceeds the range (1, %d)", 188862306a36Sopenharmony_ci nla_len(attr), MAX_UFID_LENGTH); 188962306a36Sopenharmony_ci return 0; 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci return len; 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci/* Initializes 'flow->ufid', returning true if 'attr' contains a valid UFID, 189662306a36Sopenharmony_ci * or false otherwise. 189762306a36Sopenharmony_ci */ 189862306a36Sopenharmony_cibool ovs_nla_get_ufid(struct sw_flow_id *sfid, const struct nlattr *attr, 189962306a36Sopenharmony_ci bool log) 190062306a36Sopenharmony_ci{ 190162306a36Sopenharmony_ci sfid->ufid_len = get_ufid_len(attr, log); 190262306a36Sopenharmony_ci if (sfid->ufid_len) 190362306a36Sopenharmony_ci memcpy(sfid->ufid, nla_data(attr), sfid->ufid_len); 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci return sfid->ufid_len; 190662306a36Sopenharmony_ci} 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ciint ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid, 190962306a36Sopenharmony_ci const struct sw_flow_key *key, bool log) 191062306a36Sopenharmony_ci{ 191162306a36Sopenharmony_ci struct sw_flow_key *new_key; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci if (ovs_nla_get_ufid(sfid, ufid, log)) 191462306a36Sopenharmony_ci return 0; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci /* If UFID was not provided, use unmasked key. */ 191762306a36Sopenharmony_ci new_key = kmalloc(sizeof(*new_key), GFP_KERNEL); 191862306a36Sopenharmony_ci if (!new_key) 191962306a36Sopenharmony_ci return -ENOMEM; 192062306a36Sopenharmony_ci memcpy(new_key, key, sizeof(*key)); 192162306a36Sopenharmony_ci sfid->unmasked_key = new_key; 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci return 0; 192462306a36Sopenharmony_ci} 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ciu32 ovs_nla_get_ufid_flags(const struct nlattr *attr) 192762306a36Sopenharmony_ci{ 192862306a36Sopenharmony_ci return attr ? nla_get_u32(attr) : 0; 192962306a36Sopenharmony_ci} 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci/** 193262306a36Sopenharmony_ci * ovs_nla_get_flow_metadata - parses Netlink attributes into a flow key. 193362306a36Sopenharmony_ci * @net: Network namespace. 193462306a36Sopenharmony_ci * @key: Receives extracted in_port, priority, tun_key, skb_mark and conntrack 193562306a36Sopenharmony_ci * metadata. 193662306a36Sopenharmony_ci * @a: Array of netlink attributes holding parsed %OVS_KEY_ATTR_* Netlink 193762306a36Sopenharmony_ci * attributes. 193862306a36Sopenharmony_ci * @attrs: Bit mask for the netlink attributes included in @a. 193962306a36Sopenharmony_ci * @log: Boolean to allow kernel error logging. Normally true, but when 194062306a36Sopenharmony_ci * probing for feature compatibility this should be passed in as false to 194162306a36Sopenharmony_ci * suppress unnecessary error logging. 194262306a36Sopenharmony_ci * 194362306a36Sopenharmony_ci * This parses a series of Netlink attributes that form a flow key, which must 194462306a36Sopenharmony_ci * take the same form accepted by flow_from_nlattrs(), but only enough of it to 194562306a36Sopenharmony_ci * get the metadata, that is, the parts of the flow key that cannot be 194662306a36Sopenharmony_ci * extracted from the packet itself. 194762306a36Sopenharmony_ci * 194862306a36Sopenharmony_ci * This must be called before the packet key fields are filled in 'key'. 194962306a36Sopenharmony_ci */ 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ciint ovs_nla_get_flow_metadata(struct net *net, 195262306a36Sopenharmony_ci const struct nlattr *a[OVS_KEY_ATTR_MAX + 1], 195362306a36Sopenharmony_ci u64 attrs, struct sw_flow_key *key, bool log) 195462306a36Sopenharmony_ci{ 195562306a36Sopenharmony_ci struct sw_flow_match match; 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci memset(&match, 0, sizeof(match)); 195862306a36Sopenharmony_ci match.key = key; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci key->ct_state = 0; 196162306a36Sopenharmony_ci key->ct_zone = 0; 196262306a36Sopenharmony_ci key->ct_orig_proto = 0; 196362306a36Sopenharmony_ci memset(&key->ct, 0, sizeof(key->ct)); 196462306a36Sopenharmony_ci memset(&key->ipv4.ct_orig, 0, sizeof(key->ipv4.ct_orig)); 196562306a36Sopenharmony_ci memset(&key->ipv6.ct_orig, 0, sizeof(key->ipv6.ct_orig)); 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci key->phy.in_port = DP_MAX_PORTS; 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci return metadata_from_nlattrs(net, &match, &attrs, a, false, log); 197062306a36Sopenharmony_ci} 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_cistatic int ovs_nla_put_vlan(struct sk_buff *skb, const struct vlan_head *vh, 197362306a36Sopenharmony_ci bool is_mask) 197462306a36Sopenharmony_ci{ 197562306a36Sopenharmony_ci __be16 eth_type = !is_mask ? vh->tpid : htons(0xffff); 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, eth_type) || 197862306a36Sopenharmony_ci nla_put_be16(skb, OVS_KEY_ATTR_VLAN, vh->tci)) 197962306a36Sopenharmony_ci return -EMSGSIZE; 198062306a36Sopenharmony_ci return 0; 198162306a36Sopenharmony_ci} 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_cistatic int nsh_key_to_nlattr(const struct ovs_key_nsh *nsh, bool is_mask, 198462306a36Sopenharmony_ci struct sk_buff *skb) 198562306a36Sopenharmony_ci{ 198662306a36Sopenharmony_ci struct nlattr *start; 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci start = nla_nest_start_noflag(skb, OVS_KEY_ATTR_NSH); 198962306a36Sopenharmony_ci if (!start) 199062306a36Sopenharmony_ci return -EMSGSIZE; 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci if (nla_put(skb, OVS_NSH_KEY_ATTR_BASE, sizeof(nsh->base), &nsh->base)) 199362306a36Sopenharmony_ci goto nla_put_failure; 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci if (is_mask || nsh->base.mdtype == NSH_M_TYPE1) { 199662306a36Sopenharmony_ci if (nla_put(skb, OVS_NSH_KEY_ATTR_MD1, 199762306a36Sopenharmony_ci sizeof(nsh->context), nsh->context)) 199862306a36Sopenharmony_ci goto nla_put_failure; 199962306a36Sopenharmony_ci } 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci /* Don't support MD type 2 yet */ 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci nla_nest_end(skb, start); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci return 0; 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_cinla_put_failure: 200862306a36Sopenharmony_ci return -EMSGSIZE; 200962306a36Sopenharmony_ci} 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_cistatic int __ovs_nla_put_key(const struct sw_flow_key *swkey, 201262306a36Sopenharmony_ci const struct sw_flow_key *output, bool is_mask, 201362306a36Sopenharmony_ci struct sk_buff *skb) 201462306a36Sopenharmony_ci{ 201562306a36Sopenharmony_ci struct ovs_key_ethernet *eth_key; 201662306a36Sopenharmony_ci struct nlattr *nla; 201762306a36Sopenharmony_ci struct nlattr *encap = NULL; 201862306a36Sopenharmony_ci struct nlattr *in_encap = NULL; 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci if (nla_put_u32(skb, OVS_KEY_ATTR_RECIRC_ID, output->recirc_id)) 202162306a36Sopenharmony_ci goto nla_put_failure; 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci if (nla_put_u32(skb, OVS_KEY_ATTR_DP_HASH, output->ovs_flow_hash)) 202462306a36Sopenharmony_ci goto nla_put_failure; 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority)) 202762306a36Sopenharmony_ci goto nla_put_failure; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci if ((swkey->tun_proto || is_mask)) { 203062306a36Sopenharmony_ci const void *opts = NULL; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci if (output->tun_key.tun_flags & TUNNEL_OPTIONS_PRESENT) 203362306a36Sopenharmony_ci opts = TUN_METADATA_OPTS(output, swkey->tun_opts_len); 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci if (ip_tun_to_nlattr(skb, &output->tun_key, opts, 203662306a36Sopenharmony_ci swkey->tun_opts_len, swkey->tun_proto, 0)) 203762306a36Sopenharmony_ci goto nla_put_failure; 203862306a36Sopenharmony_ci } 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci if (swkey->phy.in_port == DP_MAX_PORTS) { 204162306a36Sopenharmony_ci if (is_mask && (output->phy.in_port == 0xffff)) 204262306a36Sopenharmony_ci if (nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, 0xffffffff)) 204362306a36Sopenharmony_ci goto nla_put_failure; 204462306a36Sopenharmony_ci } else { 204562306a36Sopenharmony_ci u16 upper_u16; 204662306a36Sopenharmony_ci upper_u16 = !is_mask ? 0 : 0xffff; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci if (nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, 204962306a36Sopenharmony_ci (upper_u16 << 16) | output->phy.in_port)) 205062306a36Sopenharmony_ci goto nla_put_failure; 205162306a36Sopenharmony_ci } 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci if (nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, output->phy.skb_mark)) 205462306a36Sopenharmony_ci goto nla_put_failure; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci if (ovs_ct_put_key(swkey, output, skb)) 205762306a36Sopenharmony_ci goto nla_put_failure; 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci if (ovs_key_mac_proto(swkey) == MAC_PROTO_ETHERNET) { 206062306a36Sopenharmony_ci nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key)); 206162306a36Sopenharmony_ci if (!nla) 206262306a36Sopenharmony_ci goto nla_put_failure; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci eth_key = nla_data(nla); 206562306a36Sopenharmony_ci ether_addr_copy(eth_key->eth_src, output->eth.src); 206662306a36Sopenharmony_ci ether_addr_copy(eth_key->eth_dst, output->eth.dst); 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci if (swkey->eth.vlan.tci || eth_type_vlan(swkey->eth.type)) { 206962306a36Sopenharmony_ci if (ovs_nla_put_vlan(skb, &output->eth.vlan, is_mask)) 207062306a36Sopenharmony_ci goto nla_put_failure; 207162306a36Sopenharmony_ci encap = nla_nest_start_noflag(skb, OVS_KEY_ATTR_ENCAP); 207262306a36Sopenharmony_ci if (!swkey->eth.vlan.tci) 207362306a36Sopenharmony_ci goto unencap; 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci if (swkey->eth.cvlan.tci || eth_type_vlan(swkey->eth.type)) { 207662306a36Sopenharmony_ci if (ovs_nla_put_vlan(skb, &output->eth.cvlan, is_mask)) 207762306a36Sopenharmony_ci goto nla_put_failure; 207862306a36Sopenharmony_ci in_encap = nla_nest_start_noflag(skb, 207962306a36Sopenharmony_ci OVS_KEY_ATTR_ENCAP); 208062306a36Sopenharmony_ci if (!swkey->eth.cvlan.tci) 208162306a36Sopenharmony_ci goto unencap; 208262306a36Sopenharmony_ci } 208362306a36Sopenharmony_ci } 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci if (swkey->eth.type == htons(ETH_P_802_2)) { 208662306a36Sopenharmony_ci /* 208762306a36Sopenharmony_ci * Ethertype 802.2 is represented in the netlink with omitted 208862306a36Sopenharmony_ci * OVS_KEY_ATTR_ETHERTYPE in the flow key attribute, and 208962306a36Sopenharmony_ci * 0xffff in the mask attribute. Ethertype can also 209062306a36Sopenharmony_ci * be wildcarded. 209162306a36Sopenharmony_ci */ 209262306a36Sopenharmony_ci if (is_mask && output->eth.type) 209362306a36Sopenharmony_ci if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, 209462306a36Sopenharmony_ci output->eth.type)) 209562306a36Sopenharmony_ci goto nla_put_failure; 209662306a36Sopenharmony_ci goto unencap; 209762306a36Sopenharmony_ci } 209862306a36Sopenharmony_ci } 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, output->eth.type)) 210162306a36Sopenharmony_ci goto nla_put_failure; 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci if (eth_type_vlan(swkey->eth.type)) { 210462306a36Sopenharmony_ci /* There are 3 VLAN tags, we don't know anything about the rest 210562306a36Sopenharmony_ci * of the packet, so truncate here. 210662306a36Sopenharmony_ci */ 210762306a36Sopenharmony_ci WARN_ON_ONCE(!(encap && in_encap)); 210862306a36Sopenharmony_ci goto unencap; 210962306a36Sopenharmony_ci } 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci if (swkey->eth.type == htons(ETH_P_IP)) { 211262306a36Sopenharmony_ci struct ovs_key_ipv4 *ipv4_key; 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci nla = nla_reserve(skb, OVS_KEY_ATTR_IPV4, sizeof(*ipv4_key)); 211562306a36Sopenharmony_ci if (!nla) 211662306a36Sopenharmony_ci goto nla_put_failure; 211762306a36Sopenharmony_ci ipv4_key = nla_data(nla); 211862306a36Sopenharmony_ci ipv4_key->ipv4_src = output->ipv4.addr.src; 211962306a36Sopenharmony_ci ipv4_key->ipv4_dst = output->ipv4.addr.dst; 212062306a36Sopenharmony_ci ipv4_key->ipv4_proto = output->ip.proto; 212162306a36Sopenharmony_ci ipv4_key->ipv4_tos = output->ip.tos; 212262306a36Sopenharmony_ci ipv4_key->ipv4_ttl = output->ip.ttl; 212362306a36Sopenharmony_ci ipv4_key->ipv4_frag = output->ip.frag; 212462306a36Sopenharmony_ci } else if (swkey->eth.type == htons(ETH_P_IPV6)) { 212562306a36Sopenharmony_ci struct ovs_key_ipv6 *ipv6_key; 212662306a36Sopenharmony_ci struct ovs_key_ipv6_exthdrs *ipv6_exthdrs_key; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci nla = nla_reserve(skb, OVS_KEY_ATTR_IPV6, sizeof(*ipv6_key)); 212962306a36Sopenharmony_ci if (!nla) 213062306a36Sopenharmony_ci goto nla_put_failure; 213162306a36Sopenharmony_ci ipv6_key = nla_data(nla); 213262306a36Sopenharmony_ci memcpy(ipv6_key->ipv6_src, &output->ipv6.addr.src, 213362306a36Sopenharmony_ci sizeof(ipv6_key->ipv6_src)); 213462306a36Sopenharmony_ci memcpy(ipv6_key->ipv6_dst, &output->ipv6.addr.dst, 213562306a36Sopenharmony_ci sizeof(ipv6_key->ipv6_dst)); 213662306a36Sopenharmony_ci ipv6_key->ipv6_label = output->ipv6.label; 213762306a36Sopenharmony_ci ipv6_key->ipv6_proto = output->ip.proto; 213862306a36Sopenharmony_ci ipv6_key->ipv6_tclass = output->ip.tos; 213962306a36Sopenharmony_ci ipv6_key->ipv6_hlimit = output->ip.ttl; 214062306a36Sopenharmony_ci ipv6_key->ipv6_frag = output->ip.frag; 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci nla = nla_reserve(skb, OVS_KEY_ATTR_IPV6_EXTHDRS, 214362306a36Sopenharmony_ci sizeof(*ipv6_exthdrs_key)); 214462306a36Sopenharmony_ci if (!nla) 214562306a36Sopenharmony_ci goto nla_put_failure; 214662306a36Sopenharmony_ci ipv6_exthdrs_key = nla_data(nla); 214762306a36Sopenharmony_ci ipv6_exthdrs_key->hdrs = output->ipv6.exthdrs; 214862306a36Sopenharmony_ci } else if (swkey->eth.type == htons(ETH_P_NSH)) { 214962306a36Sopenharmony_ci if (nsh_key_to_nlattr(&output->nsh, is_mask, skb)) 215062306a36Sopenharmony_ci goto nla_put_failure; 215162306a36Sopenharmony_ci } else if (swkey->eth.type == htons(ETH_P_ARP) || 215262306a36Sopenharmony_ci swkey->eth.type == htons(ETH_P_RARP)) { 215362306a36Sopenharmony_ci struct ovs_key_arp *arp_key; 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci nla = nla_reserve(skb, OVS_KEY_ATTR_ARP, sizeof(*arp_key)); 215662306a36Sopenharmony_ci if (!nla) 215762306a36Sopenharmony_ci goto nla_put_failure; 215862306a36Sopenharmony_ci arp_key = nla_data(nla); 215962306a36Sopenharmony_ci memset(arp_key, 0, sizeof(struct ovs_key_arp)); 216062306a36Sopenharmony_ci arp_key->arp_sip = output->ipv4.addr.src; 216162306a36Sopenharmony_ci arp_key->arp_tip = output->ipv4.addr.dst; 216262306a36Sopenharmony_ci arp_key->arp_op = htons(output->ip.proto); 216362306a36Sopenharmony_ci ether_addr_copy(arp_key->arp_sha, output->ipv4.arp.sha); 216462306a36Sopenharmony_ci ether_addr_copy(arp_key->arp_tha, output->ipv4.arp.tha); 216562306a36Sopenharmony_ci } else if (eth_p_mpls(swkey->eth.type)) { 216662306a36Sopenharmony_ci u8 i, num_labels; 216762306a36Sopenharmony_ci struct ovs_key_mpls *mpls_key; 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci num_labels = hweight_long(output->mpls.num_labels_mask); 217062306a36Sopenharmony_ci nla = nla_reserve(skb, OVS_KEY_ATTR_MPLS, 217162306a36Sopenharmony_ci num_labels * sizeof(*mpls_key)); 217262306a36Sopenharmony_ci if (!nla) 217362306a36Sopenharmony_ci goto nla_put_failure; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci mpls_key = nla_data(nla); 217662306a36Sopenharmony_ci for (i = 0; i < num_labels; i++) 217762306a36Sopenharmony_ci mpls_key[i].mpls_lse = output->mpls.lse[i]; 217862306a36Sopenharmony_ci } 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci if ((swkey->eth.type == htons(ETH_P_IP) || 218162306a36Sopenharmony_ci swkey->eth.type == htons(ETH_P_IPV6)) && 218262306a36Sopenharmony_ci swkey->ip.frag != OVS_FRAG_TYPE_LATER) { 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci if (swkey->ip.proto == IPPROTO_TCP) { 218562306a36Sopenharmony_ci struct ovs_key_tcp *tcp_key; 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci nla = nla_reserve(skb, OVS_KEY_ATTR_TCP, sizeof(*tcp_key)); 218862306a36Sopenharmony_ci if (!nla) 218962306a36Sopenharmony_ci goto nla_put_failure; 219062306a36Sopenharmony_ci tcp_key = nla_data(nla); 219162306a36Sopenharmony_ci tcp_key->tcp_src = output->tp.src; 219262306a36Sopenharmony_ci tcp_key->tcp_dst = output->tp.dst; 219362306a36Sopenharmony_ci if (nla_put_be16(skb, OVS_KEY_ATTR_TCP_FLAGS, 219462306a36Sopenharmony_ci output->tp.flags)) 219562306a36Sopenharmony_ci goto nla_put_failure; 219662306a36Sopenharmony_ci } else if (swkey->ip.proto == IPPROTO_UDP) { 219762306a36Sopenharmony_ci struct ovs_key_udp *udp_key; 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci nla = nla_reserve(skb, OVS_KEY_ATTR_UDP, sizeof(*udp_key)); 220062306a36Sopenharmony_ci if (!nla) 220162306a36Sopenharmony_ci goto nla_put_failure; 220262306a36Sopenharmony_ci udp_key = nla_data(nla); 220362306a36Sopenharmony_ci udp_key->udp_src = output->tp.src; 220462306a36Sopenharmony_ci udp_key->udp_dst = output->tp.dst; 220562306a36Sopenharmony_ci } else if (swkey->ip.proto == IPPROTO_SCTP) { 220662306a36Sopenharmony_ci struct ovs_key_sctp *sctp_key; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci nla = nla_reserve(skb, OVS_KEY_ATTR_SCTP, sizeof(*sctp_key)); 220962306a36Sopenharmony_ci if (!nla) 221062306a36Sopenharmony_ci goto nla_put_failure; 221162306a36Sopenharmony_ci sctp_key = nla_data(nla); 221262306a36Sopenharmony_ci sctp_key->sctp_src = output->tp.src; 221362306a36Sopenharmony_ci sctp_key->sctp_dst = output->tp.dst; 221462306a36Sopenharmony_ci } else if (swkey->eth.type == htons(ETH_P_IP) && 221562306a36Sopenharmony_ci swkey->ip.proto == IPPROTO_ICMP) { 221662306a36Sopenharmony_ci struct ovs_key_icmp *icmp_key; 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci nla = nla_reserve(skb, OVS_KEY_ATTR_ICMP, sizeof(*icmp_key)); 221962306a36Sopenharmony_ci if (!nla) 222062306a36Sopenharmony_ci goto nla_put_failure; 222162306a36Sopenharmony_ci icmp_key = nla_data(nla); 222262306a36Sopenharmony_ci icmp_key->icmp_type = ntohs(output->tp.src); 222362306a36Sopenharmony_ci icmp_key->icmp_code = ntohs(output->tp.dst); 222462306a36Sopenharmony_ci } else if (swkey->eth.type == htons(ETH_P_IPV6) && 222562306a36Sopenharmony_ci swkey->ip.proto == IPPROTO_ICMPV6) { 222662306a36Sopenharmony_ci struct ovs_key_icmpv6 *icmpv6_key; 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci nla = nla_reserve(skb, OVS_KEY_ATTR_ICMPV6, 222962306a36Sopenharmony_ci sizeof(*icmpv6_key)); 223062306a36Sopenharmony_ci if (!nla) 223162306a36Sopenharmony_ci goto nla_put_failure; 223262306a36Sopenharmony_ci icmpv6_key = nla_data(nla); 223362306a36Sopenharmony_ci icmpv6_key->icmpv6_type = ntohs(output->tp.src); 223462306a36Sopenharmony_ci icmpv6_key->icmpv6_code = ntohs(output->tp.dst); 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci if (swkey->tp.src == htons(NDISC_NEIGHBOUR_SOLICITATION) || 223762306a36Sopenharmony_ci swkey->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) { 223862306a36Sopenharmony_ci struct ovs_key_nd *nd_key; 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci nla = nla_reserve(skb, OVS_KEY_ATTR_ND, sizeof(*nd_key)); 224162306a36Sopenharmony_ci if (!nla) 224262306a36Sopenharmony_ci goto nla_put_failure; 224362306a36Sopenharmony_ci nd_key = nla_data(nla); 224462306a36Sopenharmony_ci memcpy(nd_key->nd_target, &output->ipv6.nd.target, 224562306a36Sopenharmony_ci sizeof(nd_key->nd_target)); 224662306a36Sopenharmony_ci ether_addr_copy(nd_key->nd_sll, output->ipv6.nd.sll); 224762306a36Sopenharmony_ci ether_addr_copy(nd_key->nd_tll, output->ipv6.nd.tll); 224862306a36Sopenharmony_ci } 224962306a36Sopenharmony_ci } 225062306a36Sopenharmony_ci } 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ciunencap: 225362306a36Sopenharmony_ci if (in_encap) 225462306a36Sopenharmony_ci nla_nest_end(skb, in_encap); 225562306a36Sopenharmony_ci if (encap) 225662306a36Sopenharmony_ci nla_nest_end(skb, encap); 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci return 0; 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_cinla_put_failure: 226162306a36Sopenharmony_ci return -EMSGSIZE; 226262306a36Sopenharmony_ci} 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ciint ovs_nla_put_key(const struct sw_flow_key *swkey, 226562306a36Sopenharmony_ci const struct sw_flow_key *output, int attr, bool is_mask, 226662306a36Sopenharmony_ci struct sk_buff *skb) 226762306a36Sopenharmony_ci{ 226862306a36Sopenharmony_ci int err; 226962306a36Sopenharmony_ci struct nlattr *nla; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci nla = nla_nest_start_noflag(skb, attr); 227262306a36Sopenharmony_ci if (!nla) 227362306a36Sopenharmony_ci return -EMSGSIZE; 227462306a36Sopenharmony_ci err = __ovs_nla_put_key(swkey, output, is_mask, skb); 227562306a36Sopenharmony_ci if (err) 227662306a36Sopenharmony_ci return err; 227762306a36Sopenharmony_ci nla_nest_end(skb, nla); 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci return 0; 228062306a36Sopenharmony_ci} 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */ 228362306a36Sopenharmony_ciint ovs_nla_put_identifier(const struct sw_flow *flow, struct sk_buff *skb) 228462306a36Sopenharmony_ci{ 228562306a36Sopenharmony_ci if (ovs_identifier_is_ufid(&flow->id)) 228662306a36Sopenharmony_ci return nla_put(skb, OVS_FLOW_ATTR_UFID, flow->id.ufid_len, 228762306a36Sopenharmony_ci flow->id.ufid); 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci return ovs_nla_put_key(flow->id.unmasked_key, flow->id.unmasked_key, 229062306a36Sopenharmony_ci OVS_FLOW_ATTR_KEY, false, skb); 229162306a36Sopenharmony_ci} 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */ 229462306a36Sopenharmony_ciint ovs_nla_put_masked_key(const struct sw_flow *flow, struct sk_buff *skb) 229562306a36Sopenharmony_ci{ 229662306a36Sopenharmony_ci return ovs_nla_put_key(&flow->key, &flow->key, 229762306a36Sopenharmony_ci OVS_FLOW_ATTR_KEY, false, skb); 229862306a36Sopenharmony_ci} 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci/* Called with ovs_mutex or RCU read lock. */ 230162306a36Sopenharmony_ciint ovs_nla_put_mask(const struct sw_flow *flow, struct sk_buff *skb) 230262306a36Sopenharmony_ci{ 230362306a36Sopenharmony_ci return ovs_nla_put_key(&flow->key, &flow->mask->key, 230462306a36Sopenharmony_ci OVS_FLOW_ATTR_MASK, true, skb); 230562306a36Sopenharmony_ci} 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci#define MAX_ACTIONS_BUFSIZE (32 * 1024) 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_cistatic struct sw_flow_actions *nla_alloc_flow_actions(int size) 231062306a36Sopenharmony_ci{ 231162306a36Sopenharmony_ci struct sw_flow_actions *sfa; 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci WARN_ON_ONCE(size > MAX_ACTIONS_BUFSIZE); 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci sfa = kmalloc(kmalloc_size_roundup(sizeof(*sfa) + size), GFP_KERNEL); 231662306a36Sopenharmony_ci if (!sfa) 231762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci sfa->actions_len = 0; 232062306a36Sopenharmony_ci return sfa; 232162306a36Sopenharmony_ci} 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_cistatic void ovs_nla_free_nested_actions(const struct nlattr *actions, int len); 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_cistatic void ovs_nla_free_check_pkt_len_action(const struct nlattr *action) 232662306a36Sopenharmony_ci{ 232762306a36Sopenharmony_ci const struct nlattr *a; 232862306a36Sopenharmony_ci int rem; 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci nla_for_each_nested(a, action, rem) { 233162306a36Sopenharmony_ci switch (nla_type(a)) { 233262306a36Sopenharmony_ci case OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL: 233362306a36Sopenharmony_ci case OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER: 233462306a36Sopenharmony_ci ovs_nla_free_nested_actions(nla_data(a), nla_len(a)); 233562306a36Sopenharmony_ci break; 233662306a36Sopenharmony_ci } 233762306a36Sopenharmony_ci } 233862306a36Sopenharmony_ci} 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_cistatic void ovs_nla_free_clone_action(const struct nlattr *action) 234162306a36Sopenharmony_ci{ 234262306a36Sopenharmony_ci const struct nlattr *a = nla_data(action); 234362306a36Sopenharmony_ci int rem = nla_len(action); 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci switch (nla_type(a)) { 234662306a36Sopenharmony_ci case OVS_CLONE_ATTR_EXEC: 234762306a36Sopenharmony_ci /* The real list of actions follows this attribute. */ 234862306a36Sopenharmony_ci a = nla_next(a, &rem); 234962306a36Sopenharmony_ci ovs_nla_free_nested_actions(a, rem); 235062306a36Sopenharmony_ci break; 235162306a36Sopenharmony_ci } 235262306a36Sopenharmony_ci} 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_cistatic void ovs_nla_free_dec_ttl_action(const struct nlattr *action) 235562306a36Sopenharmony_ci{ 235662306a36Sopenharmony_ci const struct nlattr *a = nla_data(action); 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci switch (nla_type(a)) { 235962306a36Sopenharmony_ci case OVS_DEC_TTL_ATTR_ACTION: 236062306a36Sopenharmony_ci ovs_nla_free_nested_actions(nla_data(a), nla_len(a)); 236162306a36Sopenharmony_ci break; 236262306a36Sopenharmony_ci } 236362306a36Sopenharmony_ci} 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_cistatic void ovs_nla_free_sample_action(const struct nlattr *action) 236662306a36Sopenharmony_ci{ 236762306a36Sopenharmony_ci const struct nlattr *a = nla_data(action); 236862306a36Sopenharmony_ci int rem = nla_len(action); 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci switch (nla_type(a)) { 237162306a36Sopenharmony_ci case OVS_SAMPLE_ATTR_ARG: 237262306a36Sopenharmony_ci /* The real list of actions follows this attribute. */ 237362306a36Sopenharmony_ci a = nla_next(a, &rem); 237462306a36Sopenharmony_ci ovs_nla_free_nested_actions(a, rem); 237562306a36Sopenharmony_ci break; 237662306a36Sopenharmony_ci } 237762306a36Sopenharmony_ci} 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_cistatic void ovs_nla_free_set_action(const struct nlattr *a) 238062306a36Sopenharmony_ci{ 238162306a36Sopenharmony_ci const struct nlattr *ovs_key = nla_data(a); 238262306a36Sopenharmony_ci struct ovs_tunnel_info *ovs_tun; 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci switch (nla_type(ovs_key)) { 238562306a36Sopenharmony_ci case OVS_KEY_ATTR_TUNNEL_INFO: 238662306a36Sopenharmony_ci ovs_tun = nla_data(ovs_key); 238762306a36Sopenharmony_ci dst_release((struct dst_entry *)ovs_tun->tun_dst); 238862306a36Sopenharmony_ci break; 238962306a36Sopenharmony_ci } 239062306a36Sopenharmony_ci} 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_cistatic void ovs_nla_free_nested_actions(const struct nlattr *actions, int len) 239362306a36Sopenharmony_ci{ 239462306a36Sopenharmony_ci const struct nlattr *a; 239562306a36Sopenharmony_ci int rem; 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci /* Whenever new actions are added, the need to update this 239862306a36Sopenharmony_ci * function should be considered. 239962306a36Sopenharmony_ci */ 240062306a36Sopenharmony_ci BUILD_BUG_ON(OVS_ACTION_ATTR_MAX != 24); 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci if (!actions) 240362306a36Sopenharmony_ci return; 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci nla_for_each_attr(a, actions, len, rem) { 240662306a36Sopenharmony_ci switch (nla_type(a)) { 240762306a36Sopenharmony_ci case OVS_ACTION_ATTR_CHECK_PKT_LEN: 240862306a36Sopenharmony_ci ovs_nla_free_check_pkt_len_action(a); 240962306a36Sopenharmony_ci break; 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci case OVS_ACTION_ATTR_CLONE: 241262306a36Sopenharmony_ci ovs_nla_free_clone_action(a); 241362306a36Sopenharmony_ci break; 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci case OVS_ACTION_ATTR_CT: 241662306a36Sopenharmony_ci ovs_ct_free_action(a); 241762306a36Sopenharmony_ci break; 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci case OVS_ACTION_ATTR_DEC_TTL: 242062306a36Sopenharmony_ci ovs_nla_free_dec_ttl_action(a); 242162306a36Sopenharmony_ci break; 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci case OVS_ACTION_ATTR_SAMPLE: 242462306a36Sopenharmony_ci ovs_nla_free_sample_action(a); 242562306a36Sopenharmony_ci break; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci case OVS_ACTION_ATTR_SET: 242862306a36Sopenharmony_ci ovs_nla_free_set_action(a); 242962306a36Sopenharmony_ci break; 243062306a36Sopenharmony_ci } 243162306a36Sopenharmony_ci } 243262306a36Sopenharmony_ci} 243362306a36Sopenharmony_ci 243462306a36Sopenharmony_civoid ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts) 243562306a36Sopenharmony_ci{ 243662306a36Sopenharmony_ci if (!sf_acts) 243762306a36Sopenharmony_ci return; 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci ovs_nla_free_nested_actions(sf_acts->actions, sf_acts->actions_len); 244062306a36Sopenharmony_ci kfree(sf_acts); 244162306a36Sopenharmony_ci} 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_cistatic void __ovs_nla_free_flow_actions(struct rcu_head *head) 244462306a36Sopenharmony_ci{ 244562306a36Sopenharmony_ci ovs_nla_free_flow_actions(container_of(head, struct sw_flow_actions, rcu)); 244662306a36Sopenharmony_ci} 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci/* Schedules 'sf_acts' to be freed after the next RCU grace period. 244962306a36Sopenharmony_ci * The caller must hold rcu_read_lock for this to be sensible. */ 245062306a36Sopenharmony_civoid ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *sf_acts) 245162306a36Sopenharmony_ci{ 245262306a36Sopenharmony_ci call_rcu(&sf_acts->rcu, __ovs_nla_free_flow_actions); 245362306a36Sopenharmony_ci} 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_cistatic struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, 245662306a36Sopenharmony_ci int attr_len, bool log) 245762306a36Sopenharmony_ci{ 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci struct sw_flow_actions *acts; 246062306a36Sopenharmony_ci int new_acts_size; 246162306a36Sopenharmony_ci size_t req_size = NLA_ALIGN(attr_len); 246262306a36Sopenharmony_ci int next_offset = offsetof(struct sw_flow_actions, actions) + 246362306a36Sopenharmony_ci (*sfa)->actions_len; 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci if (req_size <= (ksize(*sfa) - next_offset)) 246662306a36Sopenharmony_ci goto out; 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ci new_acts_size = max(next_offset + req_size, ksize(*sfa) * 2); 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci if (new_acts_size > MAX_ACTIONS_BUFSIZE) { 247162306a36Sopenharmony_ci if ((next_offset + req_size) > MAX_ACTIONS_BUFSIZE) { 247262306a36Sopenharmony_ci OVS_NLERR(log, "Flow action size exceeds max %u", 247362306a36Sopenharmony_ci MAX_ACTIONS_BUFSIZE); 247462306a36Sopenharmony_ci return ERR_PTR(-EMSGSIZE); 247562306a36Sopenharmony_ci } 247662306a36Sopenharmony_ci new_acts_size = MAX_ACTIONS_BUFSIZE; 247762306a36Sopenharmony_ci } 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci acts = nla_alloc_flow_actions(new_acts_size); 248062306a36Sopenharmony_ci if (IS_ERR(acts)) 248162306a36Sopenharmony_ci return (void *)acts; 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci memcpy(acts->actions, (*sfa)->actions, (*sfa)->actions_len); 248462306a36Sopenharmony_ci acts->actions_len = (*sfa)->actions_len; 248562306a36Sopenharmony_ci acts->orig_len = (*sfa)->orig_len; 248662306a36Sopenharmony_ci kfree(*sfa); 248762306a36Sopenharmony_ci *sfa = acts; 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ciout: 249062306a36Sopenharmony_ci (*sfa)->actions_len += req_size; 249162306a36Sopenharmony_ci return (struct nlattr *) ((unsigned char *)(*sfa) + next_offset); 249262306a36Sopenharmony_ci} 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_cistatic struct nlattr *__add_action(struct sw_flow_actions **sfa, 249562306a36Sopenharmony_ci int attrtype, void *data, int len, bool log) 249662306a36Sopenharmony_ci{ 249762306a36Sopenharmony_ci struct nlattr *a; 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci a = reserve_sfa_size(sfa, nla_attr_size(len), log); 250062306a36Sopenharmony_ci if (IS_ERR(a)) 250162306a36Sopenharmony_ci return a; 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci a->nla_type = attrtype; 250462306a36Sopenharmony_ci a->nla_len = nla_attr_size(len); 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci if (data) 250762306a36Sopenharmony_ci memcpy(nla_data(a), data, len); 250862306a36Sopenharmony_ci memset((unsigned char *) a + a->nla_len, 0, nla_padlen(len)); 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci return a; 251162306a36Sopenharmony_ci} 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ciint ovs_nla_add_action(struct sw_flow_actions **sfa, int attrtype, void *data, 251462306a36Sopenharmony_ci int len, bool log) 251562306a36Sopenharmony_ci{ 251662306a36Sopenharmony_ci struct nlattr *a; 251762306a36Sopenharmony_ci 251862306a36Sopenharmony_ci a = __add_action(sfa, attrtype, data, len, log); 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(a); 252162306a36Sopenharmony_ci} 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_cistatic inline int add_nested_action_start(struct sw_flow_actions **sfa, 252462306a36Sopenharmony_ci int attrtype, bool log) 252562306a36Sopenharmony_ci{ 252662306a36Sopenharmony_ci int used = (*sfa)->actions_len; 252762306a36Sopenharmony_ci int err; 252862306a36Sopenharmony_ci 252962306a36Sopenharmony_ci err = ovs_nla_add_action(sfa, attrtype, NULL, 0, log); 253062306a36Sopenharmony_ci if (err) 253162306a36Sopenharmony_ci return err; 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci return used; 253462306a36Sopenharmony_ci} 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_cistatic inline void add_nested_action_end(struct sw_flow_actions *sfa, 253762306a36Sopenharmony_ci int st_offset) 253862306a36Sopenharmony_ci{ 253962306a36Sopenharmony_ci struct nlattr *a = (struct nlattr *) ((unsigned char *)sfa->actions + 254062306a36Sopenharmony_ci st_offset); 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci a->nla_len = sfa->actions_len - st_offset; 254362306a36Sopenharmony_ci} 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_cistatic int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, 254662306a36Sopenharmony_ci const struct sw_flow_key *key, 254762306a36Sopenharmony_ci struct sw_flow_actions **sfa, 254862306a36Sopenharmony_ci __be16 eth_type, __be16 vlan_tci, 254962306a36Sopenharmony_ci u32 mpls_label_count, bool log, 255062306a36Sopenharmony_ci u32 depth); 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_cistatic int validate_and_copy_sample(struct net *net, const struct nlattr *attr, 255362306a36Sopenharmony_ci const struct sw_flow_key *key, 255462306a36Sopenharmony_ci struct sw_flow_actions **sfa, 255562306a36Sopenharmony_ci __be16 eth_type, __be16 vlan_tci, 255662306a36Sopenharmony_ci u32 mpls_label_count, bool log, bool last, 255762306a36Sopenharmony_ci u32 depth) 255862306a36Sopenharmony_ci{ 255962306a36Sopenharmony_ci const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1]; 256062306a36Sopenharmony_ci const struct nlattr *probability, *actions; 256162306a36Sopenharmony_ci const struct nlattr *a; 256262306a36Sopenharmony_ci int rem, start, err; 256362306a36Sopenharmony_ci struct sample_arg arg; 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci memset(attrs, 0, sizeof(attrs)); 256662306a36Sopenharmony_ci nla_for_each_nested(a, attr, rem) { 256762306a36Sopenharmony_ci int type = nla_type(a); 256862306a36Sopenharmony_ci if (!type || type > OVS_SAMPLE_ATTR_MAX || attrs[type]) 256962306a36Sopenharmony_ci return -EINVAL; 257062306a36Sopenharmony_ci attrs[type] = a; 257162306a36Sopenharmony_ci } 257262306a36Sopenharmony_ci if (rem) 257362306a36Sopenharmony_ci return -EINVAL; 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci probability = attrs[OVS_SAMPLE_ATTR_PROBABILITY]; 257662306a36Sopenharmony_ci if (!probability || nla_len(probability) != sizeof(u32)) 257762306a36Sopenharmony_ci return -EINVAL; 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci actions = attrs[OVS_SAMPLE_ATTR_ACTIONS]; 258062306a36Sopenharmony_ci if (!actions || (nla_len(actions) && nla_len(actions) < NLA_HDRLEN)) 258162306a36Sopenharmony_ci return -EINVAL; 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci /* validation done, copy sample action. */ 258462306a36Sopenharmony_ci start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SAMPLE, log); 258562306a36Sopenharmony_ci if (start < 0) 258662306a36Sopenharmony_ci return start; 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci /* When both skb and flow may be changed, put the sample 258962306a36Sopenharmony_ci * into a deferred fifo. On the other hand, if only skb 259062306a36Sopenharmony_ci * may be modified, the actions can be executed in place. 259162306a36Sopenharmony_ci * 259262306a36Sopenharmony_ci * Do this analysis at the flow installation time. 259362306a36Sopenharmony_ci * Set 'clone_action->exec' to true if the actions can be 259462306a36Sopenharmony_ci * executed without being deferred. 259562306a36Sopenharmony_ci * 259662306a36Sopenharmony_ci * If the sample is the last action, it can always be excuted 259762306a36Sopenharmony_ci * rather than deferred. 259862306a36Sopenharmony_ci */ 259962306a36Sopenharmony_ci arg.exec = last || !actions_may_change_flow(actions); 260062306a36Sopenharmony_ci arg.probability = nla_get_u32(probability); 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci err = ovs_nla_add_action(sfa, OVS_SAMPLE_ATTR_ARG, &arg, sizeof(arg), 260362306a36Sopenharmony_ci log); 260462306a36Sopenharmony_ci if (err) 260562306a36Sopenharmony_ci return err; 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci err = __ovs_nla_copy_actions(net, actions, key, sfa, 260862306a36Sopenharmony_ci eth_type, vlan_tci, mpls_label_count, log, 260962306a36Sopenharmony_ci depth + 1); 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci if (err) 261262306a36Sopenharmony_ci return err; 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ci add_nested_action_end(*sfa, start); 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci return 0; 261762306a36Sopenharmony_ci} 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_cistatic int validate_and_copy_dec_ttl(struct net *net, 262062306a36Sopenharmony_ci const struct nlattr *attr, 262162306a36Sopenharmony_ci const struct sw_flow_key *key, 262262306a36Sopenharmony_ci struct sw_flow_actions **sfa, 262362306a36Sopenharmony_ci __be16 eth_type, __be16 vlan_tci, 262462306a36Sopenharmony_ci u32 mpls_label_count, bool log, 262562306a36Sopenharmony_ci u32 depth) 262662306a36Sopenharmony_ci{ 262762306a36Sopenharmony_ci const struct nlattr *attrs[OVS_DEC_TTL_ATTR_MAX + 1]; 262862306a36Sopenharmony_ci int start, action_start, err, rem; 262962306a36Sopenharmony_ci const struct nlattr *a, *actions; 263062306a36Sopenharmony_ci 263162306a36Sopenharmony_ci memset(attrs, 0, sizeof(attrs)); 263262306a36Sopenharmony_ci nla_for_each_nested(a, attr, rem) { 263362306a36Sopenharmony_ci int type = nla_type(a); 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_ci /* Ignore unknown attributes to be future proof. */ 263662306a36Sopenharmony_ci if (type > OVS_DEC_TTL_ATTR_MAX) 263762306a36Sopenharmony_ci continue; 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci if (!type || attrs[type]) { 264062306a36Sopenharmony_ci OVS_NLERR(log, "Duplicate or invalid key (type %d).", 264162306a36Sopenharmony_ci type); 264262306a36Sopenharmony_ci return -EINVAL; 264362306a36Sopenharmony_ci } 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci attrs[type] = a; 264662306a36Sopenharmony_ci } 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci if (rem) { 264962306a36Sopenharmony_ci OVS_NLERR(log, "Message has %d unknown bytes.", rem); 265062306a36Sopenharmony_ci return -EINVAL; 265162306a36Sopenharmony_ci } 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci actions = attrs[OVS_DEC_TTL_ATTR_ACTION]; 265462306a36Sopenharmony_ci if (!actions || (nla_len(actions) && nla_len(actions) < NLA_HDRLEN)) { 265562306a36Sopenharmony_ci OVS_NLERR(log, "Missing valid actions attribute."); 265662306a36Sopenharmony_ci return -EINVAL; 265762306a36Sopenharmony_ci } 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci start = add_nested_action_start(sfa, OVS_ACTION_ATTR_DEC_TTL, log); 266062306a36Sopenharmony_ci if (start < 0) 266162306a36Sopenharmony_ci return start; 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci action_start = add_nested_action_start(sfa, OVS_DEC_TTL_ATTR_ACTION, log); 266462306a36Sopenharmony_ci if (action_start < 0) 266562306a36Sopenharmony_ci return action_start; 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci err = __ovs_nla_copy_actions(net, actions, key, sfa, eth_type, 266862306a36Sopenharmony_ci vlan_tci, mpls_label_count, log, 266962306a36Sopenharmony_ci depth + 1); 267062306a36Sopenharmony_ci if (err) 267162306a36Sopenharmony_ci return err; 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci add_nested_action_end(*sfa, action_start); 267462306a36Sopenharmony_ci add_nested_action_end(*sfa, start); 267562306a36Sopenharmony_ci return 0; 267662306a36Sopenharmony_ci} 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_cistatic int validate_and_copy_clone(struct net *net, 267962306a36Sopenharmony_ci const struct nlattr *attr, 268062306a36Sopenharmony_ci const struct sw_flow_key *key, 268162306a36Sopenharmony_ci struct sw_flow_actions **sfa, 268262306a36Sopenharmony_ci __be16 eth_type, __be16 vlan_tci, 268362306a36Sopenharmony_ci u32 mpls_label_count, bool log, bool last, 268462306a36Sopenharmony_ci u32 depth) 268562306a36Sopenharmony_ci{ 268662306a36Sopenharmony_ci int start, err; 268762306a36Sopenharmony_ci u32 exec; 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci if (nla_len(attr) && nla_len(attr) < NLA_HDRLEN) 269062306a36Sopenharmony_ci return -EINVAL; 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_ci start = add_nested_action_start(sfa, OVS_ACTION_ATTR_CLONE, log); 269362306a36Sopenharmony_ci if (start < 0) 269462306a36Sopenharmony_ci return start; 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci exec = last || !actions_may_change_flow(attr); 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci err = ovs_nla_add_action(sfa, OVS_CLONE_ATTR_EXEC, &exec, 269962306a36Sopenharmony_ci sizeof(exec), log); 270062306a36Sopenharmony_ci if (err) 270162306a36Sopenharmony_ci return err; 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ci err = __ovs_nla_copy_actions(net, attr, key, sfa, 270462306a36Sopenharmony_ci eth_type, vlan_tci, mpls_label_count, log, 270562306a36Sopenharmony_ci depth + 1); 270662306a36Sopenharmony_ci if (err) 270762306a36Sopenharmony_ci return err; 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_ci add_nested_action_end(*sfa, start); 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci return 0; 271262306a36Sopenharmony_ci} 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_civoid ovs_match_init(struct sw_flow_match *match, 271562306a36Sopenharmony_ci struct sw_flow_key *key, 271662306a36Sopenharmony_ci bool reset_key, 271762306a36Sopenharmony_ci struct sw_flow_mask *mask) 271862306a36Sopenharmony_ci{ 271962306a36Sopenharmony_ci memset(match, 0, sizeof(*match)); 272062306a36Sopenharmony_ci match->key = key; 272162306a36Sopenharmony_ci match->mask = mask; 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_ci if (reset_key) 272462306a36Sopenharmony_ci memset(key, 0, sizeof(*key)); 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci if (mask) { 272762306a36Sopenharmony_ci memset(&mask->key, 0, sizeof(mask->key)); 272862306a36Sopenharmony_ci mask->range.start = mask->range.end = 0; 272962306a36Sopenharmony_ci } 273062306a36Sopenharmony_ci} 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_cistatic int validate_geneve_opts(struct sw_flow_key *key) 273362306a36Sopenharmony_ci{ 273462306a36Sopenharmony_ci struct geneve_opt *option; 273562306a36Sopenharmony_ci int opts_len = key->tun_opts_len; 273662306a36Sopenharmony_ci bool crit_opt = false; 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci option = (struct geneve_opt *)TUN_METADATA_OPTS(key, key->tun_opts_len); 273962306a36Sopenharmony_ci while (opts_len > 0) { 274062306a36Sopenharmony_ci int len; 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_ci if (opts_len < sizeof(*option)) 274362306a36Sopenharmony_ci return -EINVAL; 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ci len = sizeof(*option) + option->length * 4; 274662306a36Sopenharmony_ci if (len > opts_len) 274762306a36Sopenharmony_ci return -EINVAL; 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci crit_opt |= !!(option->type & GENEVE_CRIT_OPT_TYPE); 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci option = (struct geneve_opt *)((u8 *)option + len); 275262306a36Sopenharmony_ci opts_len -= len; 275362306a36Sopenharmony_ci } 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ci key->tun_key.tun_flags |= crit_opt ? TUNNEL_CRIT_OPT : 0; 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci return 0; 275862306a36Sopenharmony_ci} 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_cistatic int validate_and_copy_set_tun(const struct nlattr *attr, 276162306a36Sopenharmony_ci struct sw_flow_actions **sfa, bool log) 276262306a36Sopenharmony_ci{ 276362306a36Sopenharmony_ci struct sw_flow_match match; 276462306a36Sopenharmony_ci struct sw_flow_key key; 276562306a36Sopenharmony_ci struct metadata_dst *tun_dst; 276662306a36Sopenharmony_ci struct ip_tunnel_info *tun_info; 276762306a36Sopenharmony_ci struct ovs_tunnel_info *ovs_tun; 276862306a36Sopenharmony_ci struct nlattr *a; 276962306a36Sopenharmony_ci int err = 0, start, opts_type; 277062306a36Sopenharmony_ci __be16 dst_opt_type; 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci dst_opt_type = 0; 277362306a36Sopenharmony_ci ovs_match_init(&match, &key, true, NULL); 277462306a36Sopenharmony_ci opts_type = ip_tun_from_nlattr(nla_data(attr), &match, false, log); 277562306a36Sopenharmony_ci if (opts_type < 0) 277662306a36Sopenharmony_ci return opts_type; 277762306a36Sopenharmony_ci 277862306a36Sopenharmony_ci if (key.tun_opts_len) { 277962306a36Sopenharmony_ci switch (opts_type) { 278062306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS: 278162306a36Sopenharmony_ci err = validate_geneve_opts(&key); 278262306a36Sopenharmony_ci if (err < 0) 278362306a36Sopenharmony_ci return err; 278462306a36Sopenharmony_ci dst_opt_type = TUNNEL_GENEVE_OPT; 278562306a36Sopenharmony_ci break; 278662306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS: 278762306a36Sopenharmony_ci dst_opt_type = TUNNEL_VXLAN_OPT; 278862306a36Sopenharmony_ci break; 278962306a36Sopenharmony_ci case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS: 279062306a36Sopenharmony_ci dst_opt_type = TUNNEL_ERSPAN_OPT; 279162306a36Sopenharmony_ci break; 279262306a36Sopenharmony_ci } 279362306a36Sopenharmony_ci } 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET, log); 279662306a36Sopenharmony_ci if (start < 0) 279762306a36Sopenharmony_ci return start; 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci tun_dst = metadata_dst_alloc(key.tun_opts_len, METADATA_IP_TUNNEL, 280062306a36Sopenharmony_ci GFP_KERNEL); 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci if (!tun_dst) 280362306a36Sopenharmony_ci return -ENOMEM; 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci err = dst_cache_init(&tun_dst->u.tun_info.dst_cache, GFP_KERNEL); 280662306a36Sopenharmony_ci if (err) { 280762306a36Sopenharmony_ci dst_release((struct dst_entry *)tun_dst); 280862306a36Sopenharmony_ci return err; 280962306a36Sopenharmony_ci } 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_ci a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL, 281262306a36Sopenharmony_ci sizeof(*ovs_tun), log); 281362306a36Sopenharmony_ci if (IS_ERR(a)) { 281462306a36Sopenharmony_ci dst_release((struct dst_entry *)tun_dst); 281562306a36Sopenharmony_ci return PTR_ERR(a); 281662306a36Sopenharmony_ci } 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci ovs_tun = nla_data(a); 281962306a36Sopenharmony_ci ovs_tun->tun_dst = tun_dst; 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci tun_info = &tun_dst->u.tun_info; 282262306a36Sopenharmony_ci tun_info->mode = IP_TUNNEL_INFO_TX; 282362306a36Sopenharmony_ci if (key.tun_proto == AF_INET6) 282462306a36Sopenharmony_ci tun_info->mode |= IP_TUNNEL_INFO_IPV6; 282562306a36Sopenharmony_ci else if (key.tun_proto == AF_INET && key.tun_key.u.ipv4.dst == 0) 282662306a36Sopenharmony_ci tun_info->mode |= IP_TUNNEL_INFO_BRIDGE; 282762306a36Sopenharmony_ci tun_info->key = key.tun_key; 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci /* We need to store the options in the action itself since 283062306a36Sopenharmony_ci * everything else will go away after flow setup. We can append 283162306a36Sopenharmony_ci * it to tun_info and then point there. 283262306a36Sopenharmony_ci */ 283362306a36Sopenharmony_ci ip_tunnel_info_opts_set(tun_info, 283462306a36Sopenharmony_ci TUN_METADATA_OPTS(&key, key.tun_opts_len), 283562306a36Sopenharmony_ci key.tun_opts_len, dst_opt_type); 283662306a36Sopenharmony_ci add_nested_action_end(*sfa, start); 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci return err; 283962306a36Sopenharmony_ci} 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_cistatic bool validate_nsh(const struct nlattr *attr, bool is_mask, 284262306a36Sopenharmony_ci bool is_push_nsh, bool log) 284362306a36Sopenharmony_ci{ 284462306a36Sopenharmony_ci struct sw_flow_match match; 284562306a36Sopenharmony_ci struct sw_flow_key key; 284662306a36Sopenharmony_ci int ret = 0; 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci ovs_match_init(&match, &key, true, NULL); 284962306a36Sopenharmony_ci ret = nsh_key_put_from_nlattr(attr, &match, is_mask, 285062306a36Sopenharmony_ci is_push_nsh, log); 285162306a36Sopenharmony_ci return !ret; 285262306a36Sopenharmony_ci} 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci/* Return false if there are any non-masked bits set. 285562306a36Sopenharmony_ci * Mask follows data immediately, before any netlink padding. 285662306a36Sopenharmony_ci */ 285762306a36Sopenharmony_cistatic bool validate_masked(u8 *data, int len) 285862306a36Sopenharmony_ci{ 285962306a36Sopenharmony_ci u8 *mask = data + len; 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci while (len--) 286262306a36Sopenharmony_ci if (*data++ & ~*mask++) 286362306a36Sopenharmony_ci return false; 286462306a36Sopenharmony_ci 286562306a36Sopenharmony_ci return true; 286662306a36Sopenharmony_ci} 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_cistatic int validate_set(const struct nlattr *a, 286962306a36Sopenharmony_ci const struct sw_flow_key *flow_key, 287062306a36Sopenharmony_ci struct sw_flow_actions **sfa, bool *skip_copy, 287162306a36Sopenharmony_ci u8 mac_proto, __be16 eth_type, bool masked, bool log) 287262306a36Sopenharmony_ci{ 287362306a36Sopenharmony_ci const struct nlattr *ovs_key = nla_data(a); 287462306a36Sopenharmony_ci int key_type = nla_type(ovs_key); 287562306a36Sopenharmony_ci size_t key_len; 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci /* There can be only one key in a action */ 287862306a36Sopenharmony_ci if (nla_total_size(nla_len(ovs_key)) != nla_len(a)) 287962306a36Sopenharmony_ci return -EINVAL; 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci key_len = nla_len(ovs_key); 288262306a36Sopenharmony_ci if (masked) 288362306a36Sopenharmony_ci key_len /= 2; 288462306a36Sopenharmony_ci 288562306a36Sopenharmony_ci if (key_type > OVS_KEY_ATTR_MAX || 288662306a36Sopenharmony_ci !check_attr_len(key_len, ovs_key_lens[key_type].len)) 288762306a36Sopenharmony_ci return -EINVAL; 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_ci if (masked && !validate_masked(nla_data(ovs_key), key_len)) 289062306a36Sopenharmony_ci return -EINVAL; 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci switch (key_type) { 289362306a36Sopenharmony_ci case OVS_KEY_ATTR_PRIORITY: 289462306a36Sopenharmony_ci case OVS_KEY_ATTR_SKB_MARK: 289562306a36Sopenharmony_ci case OVS_KEY_ATTR_CT_MARK: 289662306a36Sopenharmony_ci case OVS_KEY_ATTR_CT_LABELS: 289762306a36Sopenharmony_ci break; 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci case OVS_KEY_ATTR_ETHERNET: 290062306a36Sopenharmony_ci if (mac_proto != MAC_PROTO_ETHERNET) 290162306a36Sopenharmony_ci return -EINVAL; 290262306a36Sopenharmony_ci break; 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_ci case OVS_KEY_ATTR_TUNNEL: { 290562306a36Sopenharmony_ci int err; 290662306a36Sopenharmony_ci 290762306a36Sopenharmony_ci if (masked) 290862306a36Sopenharmony_ci return -EINVAL; /* Masked tunnel set not supported. */ 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_ci *skip_copy = true; 291162306a36Sopenharmony_ci err = validate_and_copy_set_tun(a, sfa, log); 291262306a36Sopenharmony_ci if (err) 291362306a36Sopenharmony_ci return err; 291462306a36Sopenharmony_ci break; 291562306a36Sopenharmony_ci } 291662306a36Sopenharmony_ci case OVS_KEY_ATTR_IPV4: { 291762306a36Sopenharmony_ci const struct ovs_key_ipv4 *ipv4_key; 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci if (eth_type != htons(ETH_P_IP)) 292062306a36Sopenharmony_ci return -EINVAL; 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci ipv4_key = nla_data(ovs_key); 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci if (masked) { 292562306a36Sopenharmony_ci const struct ovs_key_ipv4 *mask = ipv4_key + 1; 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci /* Non-writeable fields. */ 292862306a36Sopenharmony_ci if (mask->ipv4_proto || mask->ipv4_frag) 292962306a36Sopenharmony_ci return -EINVAL; 293062306a36Sopenharmony_ci } else { 293162306a36Sopenharmony_ci if (ipv4_key->ipv4_proto != flow_key->ip.proto) 293262306a36Sopenharmony_ci return -EINVAL; 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci if (ipv4_key->ipv4_frag != flow_key->ip.frag) 293562306a36Sopenharmony_ci return -EINVAL; 293662306a36Sopenharmony_ci } 293762306a36Sopenharmony_ci break; 293862306a36Sopenharmony_ci } 293962306a36Sopenharmony_ci case OVS_KEY_ATTR_IPV6: { 294062306a36Sopenharmony_ci const struct ovs_key_ipv6 *ipv6_key; 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci if (eth_type != htons(ETH_P_IPV6)) 294362306a36Sopenharmony_ci return -EINVAL; 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci ipv6_key = nla_data(ovs_key); 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_ci if (masked) { 294862306a36Sopenharmony_ci const struct ovs_key_ipv6 *mask = ipv6_key + 1; 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_ci /* Non-writeable fields. */ 295162306a36Sopenharmony_ci if (mask->ipv6_proto || mask->ipv6_frag) 295262306a36Sopenharmony_ci return -EINVAL; 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_ci /* Invalid bits in the flow label mask? */ 295562306a36Sopenharmony_ci if (ntohl(mask->ipv6_label) & 0xFFF00000) 295662306a36Sopenharmony_ci return -EINVAL; 295762306a36Sopenharmony_ci } else { 295862306a36Sopenharmony_ci if (ipv6_key->ipv6_proto != flow_key->ip.proto) 295962306a36Sopenharmony_ci return -EINVAL; 296062306a36Sopenharmony_ci 296162306a36Sopenharmony_ci if (ipv6_key->ipv6_frag != flow_key->ip.frag) 296262306a36Sopenharmony_ci return -EINVAL; 296362306a36Sopenharmony_ci } 296462306a36Sopenharmony_ci if (ntohl(ipv6_key->ipv6_label) & 0xFFF00000) 296562306a36Sopenharmony_ci return -EINVAL; 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci break; 296862306a36Sopenharmony_ci } 296962306a36Sopenharmony_ci case OVS_KEY_ATTR_TCP: 297062306a36Sopenharmony_ci if ((eth_type != htons(ETH_P_IP) && 297162306a36Sopenharmony_ci eth_type != htons(ETH_P_IPV6)) || 297262306a36Sopenharmony_ci flow_key->ip.proto != IPPROTO_TCP) 297362306a36Sopenharmony_ci return -EINVAL; 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_ci break; 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci case OVS_KEY_ATTR_UDP: 297862306a36Sopenharmony_ci if ((eth_type != htons(ETH_P_IP) && 297962306a36Sopenharmony_ci eth_type != htons(ETH_P_IPV6)) || 298062306a36Sopenharmony_ci flow_key->ip.proto != IPPROTO_UDP) 298162306a36Sopenharmony_ci return -EINVAL; 298262306a36Sopenharmony_ci 298362306a36Sopenharmony_ci break; 298462306a36Sopenharmony_ci 298562306a36Sopenharmony_ci case OVS_KEY_ATTR_MPLS: 298662306a36Sopenharmony_ci if (!eth_p_mpls(eth_type)) 298762306a36Sopenharmony_ci return -EINVAL; 298862306a36Sopenharmony_ci break; 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci case OVS_KEY_ATTR_SCTP: 299162306a36Sopenharmony_ci if ((eth_type != htons(ETH_P_IP) && 299262306a36Sopenharmony_ci eth_type != htons(ETH_P_IPV6)) || 299362306a36Sopenharmony_ci flow_key->ip.proto != IPPROTO_SCTP) 299462306a36Sopenharmony_ci return -EINVAL; 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci break; 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_ci case OVS_KEY_ATTR_NSH: 299962306a36Sopenharmony_ci if (eth_type != htons(ETH_P_NSH)) 300062306a36Sopenharmony_ci return -EINVAL; 300162306a36Sopenharmony_ci if (!validate_nsh(nla_data(a), masked, false, log)) 300262306a36Sopenharmony_ci return -EINVAL; 300362306a36Sopenharmony_ci break; 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ci default: 300662306a36Sopenharmony_ci return -EINVAL; 300762306a36Sopenharmony_ci } 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci /* Convert non-masked non-tunnel set actions to masked set actions. */ 301062306a36Sopenharmony_ci if (!masked && key_type != OVS_KEY_ATTR_TUNNEL) { 301162306a36Sopenharmony_ci int start, len = key_len * 2; 301262306a36Sopenharmony_ci struct nlattr *at; 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_ci *skip_copy = true; 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ci start = add_nested_action_start(sfa, 301762306a36Sopenharmony_ci OVS_ACTION_ATTR_SET_TO_MASKED, 301862306a36Sopenharmony_ci log); 301962306a36Sopenharmony_ci if (start < 0) 302062306a36Sopenharmony_ci return start; 302162306a36Sopenharmony_ci 302262306a36Sopenharmony_ci at = __add_action(sfa, key_type, NULL, len, log); 302362306a36Sopenharmony_ci if (IS_ERR(at)) 302462306a36Sopenharmony_ci return PTR_ERR(at); 302562306a36Sopenharmony_ci 302662306a36Sopenharmony_ci memcpy(nla_data(at), nla_data(ovs_key), key_len); /* Key. */ 302762306a36Sopenharmony_ci memset(nla_data(at) + key_len, 0xff, key_len); /* Mask. */ 302862306a36Sopenharmony_ci /* Clear non-writeable bits from otherwise writeable fields. */ 302962306a36Sopenharmony_ci if (key_type == OVS_KEY_ATTR_IPV6) { 303062306a36Sopenharmony_ci struct ovs_key_ipv6 *mask = nla_data(at) + key_len; 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci mask->ipv6_label &= htonl(0x000FFFFF); 303362306a36Sopenharmony_ci } 303462306a36Sopenharmony_ci add_nested_action_end(*sfa, start); 303562306a36Sopenharmony_ci } 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci return 0; 303862306a36Sopenharmony_ci} 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_cistatic int validate_userspace(const struct nlattr *attr) 304162306a36Sopenharmony_ci{ 304262306a36Sopenharmony_ci static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] = { 304362306a36Sopenharmony_ci [OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 }, 304462306a36Sopenharmony_ci [OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC }, 304562306a36Sopenharmony_ci [OVS_USERSPACE_ATTR_EGRESS_TUN_PORT] = {.type = NLA_U32 }, 304662306a36Sopenharmony_ci }; 304762306a36Sopenharmony_ci struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1]; 304862306a36Sopenharmony_ci int error; 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci error = nla_parse_nested_deprecated(a, OVS_USERSPACE_ATTR_MAX, attr, 305162306a36Sopenharmony_ci userspace_policy, NULL); 305262306a36Sopenharmony_ci if (error) 305362306a36Sopenharmony_ci return error; 305462306a36Sopenharmony_ci 305562306a36Sopenharmony_ci if (!a[OVS_USERSPACE_ATTR_PID] || 305662306a36Sopenharmony_ci !nla_get_u32(a[OVS_USERSPACE_ATTR_PID])) 305762306a36Sopenharmony_ci return -EINVAL; 305862306a36Sopenharmony_ci 305962306a36Sopenharmony_ci return 0; 306062306a36Sopenharmony_ci} 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_cistatic const struct nla_policy cpl_policy[OVS_CHECK_PKT_LEN_ATTR_MAX + 1] = { 306362306a36Sopenharmony_ci [OVS_CHECK_PKT_LEN_ATTR_PKT_LEN] = {.type = NLA_U16 }, 306462306a36Sopenharmony_ci [OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER] = {.type = NLA_NESTED }, 306562306a36Sopenharmony_ci [OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL] = {.type = NLA_NESTED }, 306662306a36Sopenharmony_ci}; 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_cistatic int validate_and_copy_check_pkt_len(struct net *net, 306962306a36Sopenharmony_ci const struct nlattr *attr, 307062306a36Sopenharmony_ci const struct sw_flow_key *key, 307162306a36Sopenharmony_ci struct sw_flow_actions **sfa, 307262306a36Sopenharmony_ci __be16 eth_type, __be16 vlan_tci, 307362306a36Sopenharmony_ci u32 mpls_label_count, 307462306a36Sopenharmony_ci bool log, bool last, u32 depth) 307562306a36Sopenharmony_ci{ 307662306a36Sopenharmony_ci const struct nlattr *acts_if_greater, *acts_if_lesser_eq; 307762306a36Sopenharmony_ci struct nlattr *a[OVS_CHECK_PKT_LEN_ATTR_MAX + 1]; 307862306a36Sopenharmony_ci struct check_pkt_len_arg arg; 307962306a36Sopenharmony_ci int nested_acts_start; 308062306a36Sopenharmony_ci int start, err; 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci err = nla_parse_deprecated_strict(a, OVS_CHECK_PKT_LEN_ATTR_MAX, 308362306a36Sopenharmony_ci nla_data(attr), nla_len(attr), 308462306a36Sopenharmony_ci cpl_policy, NULL); 308562306a36Sopenharmony_ci if (err) 308662306a36Sopenharmony_ci return err; 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_ci if (!a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN] || 308962306a36Sopenharmony_ci !nla_get_u16(a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN])) 309062306a36Sopenharmony_ci return -EINVAL; 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci acts_if_lesser_eq = a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL]; 309362306a36Sopenharmony_ci acts_if_greater = a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER]; 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci /* Both the nested action should be present. */ 309662306a36Sopenharmony_ci if (!acts_if_greater || !acts_if_lesser_eq) 309762306a36Sopenharmony_ci return -EINVAL; 309862306a36Sopenharmony_ci 309962306a36Sopenharmony_ci /* validation done, copy the nested actions. */ 310062306a36Sopenharmony_ci start = add_nested_action_start(sfa, OVS_ACTION_ATTR_CHECK_PKT_LEN, 310162306a36Sopenharmony_ci log); 310262306a36Sopenharmony_ci if (start < 0) 310362306a36Sopenharmony_ci return start; 310462306a36Sopenharmony_ci 310562306a36Sopenharmony_ci arg.pkt_len = nla_get_u16(a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN]); 310662306a36Sopenharmony_ci arg.exec_for_lesser_equal = 310762306a36Sopenharmony_ci last || !actions_may_change_flow(acts_if_lesser_eq); 310862306a36Sopenharmony_ci arg.exec_for_greater = 310962306a36Sopenharmony_ci last || !actions_may_change_flow(acts_if_greater); 311062306a36Sopenharmony_ci 311162306a36Sopenharmony_ci err = ovs_nla_add_action(sfa, OVS_CHECK_PKT_LEN_ATTR_ARG, &arg, 311262306a36Sopenharmony_ci sizeof(arg), log); 311362306a36Sopenharmony_ci if (err) 311462306a36Sopenharmony_ci return err; 311562306a36Sopenharmony_ci 311662306a36Sopenharmony_ci nested_acts_start = add_nested_action_start(sfa, 311762306a36Sopenharmony_ci OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL, log); 311862306a36Sopenharmony_ci if (nested_acts_start < 0) 311962306a36Sopenharmony_ci return nested_acts_start; 312062306a36Sopenharmony_ci 312162306a36Sopenharmony_ci err = __ovs_nla_copy_actions(net, acts_if_lesser_eq, key, sfa, 312262306a36Sopenharmony_ci eth_type, vlan_tci, mpls_label_count, log, 312362306a36Sopenharmony_ci depth + 1); 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_ci if (err) 312662306a36Sopenharmony_ci return err; 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_ci add_nested_action_end(*sfa, nested_acts_start); 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci nested_acts_start = add_nested_action_start(sfa, 313162306a36Sopenharmony_ci OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER, log); 313262306a36Sopenharmony_ci if (nested_acts_start < 0) 313362306a36Sopenharmony_ci return nested_acts_start; 313462306a36Sopenharmony_ci 313562306a36Sopenharmony_ci err = __ovs_nla_copy_actions(net, acts_if_greater, key, sfa, 313662306a36Sopenharmony_ci eth_type, vlan_tci, mpls_label_count, log, 313762306a36Sopenharmony_ci depth + 1); 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci if (err) 314062306a36Sopenharmony_ci return err; 314162306a36Sopenharmony_ci 314262306a36Sopenharmony_ci add_nested_action_end(*sfa, nested_acts_start); 314362306a36Sopenharmony_ci add_nested_action_end(*sfa, start); 314462306a36Sopenharmony_ci return 0; 314562306a36Sopenharmony_ci} 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_cistatic int copy_action(const struct nlattr *from, 314862306a36Sopenharmony_ci struct sw_flow_actions **sfa, bool log) 314962306a36Sopenharmony_ci{ 315062306a36Sopenharmony_ci int totlen = NLA_ALIGN(from->nla_len); 315162306a36Sopenharmony_ci struct nlattr *to; 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci to = reserve_sfa_size(sfa, from->nla_len, log); 315462306a36Sopenharmony_ci if (IS_ERR(to)) 315562306a36Sopenharmony_ci return PTR_ERR(to); 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_ci memcpy(to, from, totlen); 315862306a36Sopenharmony_ci return 0; 315962306a36Sopenharmony_ci} 316062306a36Sopenharmony_ci 316162306a36Sopenharmony_cistatic int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, 316262306a36Sopenharmony_ci const struct sw_flow_key *key, 316362306a36Sopenharmony_ci struct sw_flow_actions **sfa, 316462306a36Sopenharmony_ci __be16 eth_type, __be16 vlan_tci, 316562306a36Sopenharmony_ci u32 mpls_label_count, bool log, 316662306a36Sopenharmony_ci u32 depth) 316762306a36Sopenharmony_ci{ 316862306a36Sopenharmony_ci u8 mac_proto = ovs_key_mac_proto(key); 316962306a36Sopenharmony_ci const struct nlattr *a; 317062306a36Sopenharmony_ci int rem, err; 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci if (depth > OVS_COPY_ACTIONS_MAX_DEPTH) 317362306a36Sopenharmony_ci return -EOVERFLOW; 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci nla_for_each_nested(a, attr, rem) { 317662306a36Sopenharmony_ci /* Expected argument lengths, (u32)-1 for variable length. */ 317762306a36Sopenharmony_ci static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = { 317862306a36Sopenharmony_ci [OVS_ACTION_ATTR_OUTPUT] = sizeof(u32), 317962306a36Sopenharmony_ci [OVS_ACTION_ATTR_RECIRC] = sizeof(u32), 318062306a36Sopenharmony_ci [OVS_ACTION_ATTR_USERSPACE] = (u32)-1, 318162306a36Sopenharmony_ci [OVS_ACTION_ATTR_PUSH_MPLS] = sizeof(struct ovs_action_push_mpls), 318262306a36Sopenharmony_ci [OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16), 318362306a36Sopenharmony_ci [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan), 318462306a36Sopenharmony_ci [OVS_ACTION_ATTR_POP_VLAN] = 0, 318562306a36Sopenharmony_ci [OVS_ACTION_ATTR_SET] = (u32)-1, 318662306a36Sopenharmony_ci [OVS_ACTION_ATTR_SET_MASKED] = (u32)-1, 318762306a36Sopenharmony_ci [OVS_ACTION_ATTR_SAMPLE] = (u32)-1, 318862306a36Sopenharmony_ci [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash), 318962306a36Sopenharmony_ci [OVS_ACTION_ATTR_CT] = (u32)-1, 319062306a36Sopenharmony_ci [OVS_ACTION_ATTR_CT_CLEAR] = 0, 319162306a36Sopenharmony_ci [OVS_ACTION_ATTR_TRUNC] = sizeof(struct ovs_action_trunc), 319262306a36Sopenharmony_ci [OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth), 319362306a36Sopenharmony_ci [OVS_ACTION_ATTR_POP_ETH] = 0, 319462306a36Sopenharmony_ci [OVS_ACTION_ATTR_PUSH_NSH] = (u32)-1, 319562306a36Sopenharmony_ci [OVS_ACTION_ATTR_POP_NSH] = 0, 319662306a36Sopenharmony_ci [OVS_ACTION_ATTR_METER] = sizeof(u32), 319762306a36Sopenharmony_ci [OVS_ACTION_ATTR_CLONE] = (u32)-1, 319862306a36Sopenharmony_ci [OVS_ACTION_ATTR_CHECK_PKT_LEN] = (u32)-1, 319962306a36Sopenharmony_ci [OVS_ACTION_ATTR_ADD_MPLS] = sizeof(struct ovs_action_add_mpls), 320062306a36Sopenharmony_ci [OVS_ACTION_ATTR_DEC_TTL] = (u32)-1, 320162306a36Sopenharmony_ci [OVS_ACTION_ATTR_DROP] = sizeof(u32), 320262306a36Sopenharmony_ci }; 320362306a36Sopenharmony_ci const struct ovs_action_push_vlan *vlan; 320462306a36Sopenharmony_ci int type = nla_type(a); 320562306a36Sopenharmony_ci bool skip_copy; 320662306a36Sopenharmony_ci 320762306a36Sopenharmony_ci if (type > OVS_ACTION_ATTR_MAX || 320862306a36Sopenharmony_ci (action_lens[type] != nla_len(a) && 320962306a36Sopenharmony_ci action_lens[type] != (u32)-1)) 321062306a36Sopenharmony_ci return -EINVAL; 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_ci skip_copy = false; 321362306a36Sopenharmony_ci switch (type) { 321462306a36Sopenharmony_ci case OVS_ACTION_ATTR_UNSPEC: 321562306a36Sopenharmony_ci return -EINVAL; 321662306a36Sopenharmony_ci 321762306a36Sopenharmony_ci case OVS_ACTION_ATTR_USERSPACE: 321862306a36Sopenharmony_ci err = validate_userspace(a); 321962306a36Sopenharmony_ci if (err) 322062306a36Sopenharmony_ci return err; 322162306a36Sopenharmony_ci break; 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci case OVS_ACTION_ATTR_OUTPUT: 322462306a36Sopenharmony_ci if (nla_get_u32(a) >= DP_MAX_PORTS) 322562306a36Sopenharmony_ci return -EINVAL; 322662306a36Sopenharmony_ci break; 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci case OVS_ACTION_ATTR_TRUNC: { 322962306a36Sopenharmony_ci const struct ovs_action_trunc *trunc = nla_data(a); 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci if (trunc->max_len < ETH_HLEN) 323262306a36Sopenharmony_ci return -EINVAL; 323362306a36Sopenharmony_ci break; 323462306a36Sopenharmony_ci } 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_ci case OVS_ACTION_ATTR_HASH: { 323762306a36Sopenharmony_ci const struct ovs_action_hash *act_hash = nla_data(a); 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_ci switch (act_hash->hash_alg) { 324062306a36Sopenharmony_ci case OVS_HASH_ALG_L4: 324162306a36Sopenharmony_ci fallthrough; 324262306a36Sopenharmony_ci case OVS_HASH_ALG_SYM_L4: 324362306a36Sopenharmony_ci break; 324462306a36Sopenharmony_ci default: 324562306a36Sopenharmony_ci return -EINVAL; 324662306a36Sopenharmony_ci } 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci break; 324962306a36Sopenharmony_ci } 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci case OVS_ACTION_ATTR_POP_VLAN: 325262306a36Sopenharmony_ci if (mac_proto != MAC_PROTO_ETHERNET) 325362306a36Sopenharmony_ci return -EINVAL; 325462306a36Sopenharmony_ci vlan_tci = htons(0); 325562306a36Sopenharmony_ci break; 325662306a36Sopenharmony_ci 325762306a36Sopenharmony_ci case OVS_ACTION_ATTR_PUSH_VLAN: 325862306a36Sopenharmony_ci if (mac_proto != MAC_PROTO_ETHERNET) 325962306a36Sopenharmony_ci return -EINVAL; 326062306a36Sopenharmony_ci vlan = nla_data(a); 326162306a36Sopenharmony_ci if (!eth_type_vlan(vlan->vlan_tpid)) 326262306a36Sopenharmony_ci return -EINVAL; 326362306a36Sopenharmony_ci if (!(vlan->vlan_tci & htons(VLAN_CFI_MASK))) 326462306a36Sopenharmony_ci return -EINVAL; 326562306a36Sopenharmony_ci vlan_tci = vlan->vlan_tci; 326662306a36Sopenharmony_ci break; 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_ci case OVS_ACTION_ATTR_RECIRC: 326962306a36Sopenharmony_ci break; 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_ci case OVS_ACTION_ATTR_ADD_MPLS: { 327262306a36Sopenharmony_ci const struct ovs_action_add_mpls *mpls = nla_data(a); 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_ci if (!eth_p_mpls(mpls->mpls_ethertype)) 327562306a36Sopenharmony_ci return -EINVAL; 327662306a36Sopenharmony_ci 327762306a36Sopenharmony_ci if (mpls->tun_flags & OVS_MPLS_L3_TUNNEL_FLAG_MASK) { 327862306a36Sopenharmony_ci if (vlan_tci & htons(VLAN_CFI_MASK) || 327962306a36Sopenharmony_ci (eth_type != htons(ETH_P_IP) && 328062306a36Sopenharmony_ci eth_type != htons(ETH_P_IPV6) && 328162306a36Sopenharmony_ci eth_type != htons(ETH_P_ARP) && 328262306a36Sopenharmony_ci eth_type != htons(ETH_P_RARP) && 328362306a36Sopenharmony_ci !eth_p_mpls(eth_type))) 328462306a36Sopenharmony_ci return -EINVAL; 328562306a36Sopenharmony_ci mpls_label_count++; 328662306a36Sopenharmony_ci } else { 328762306a36Sopenharmony_ci if (mac_proto == MAC_PROTO_ETHERNET) { 328862306a36Sopenharmony_ci mpls_label_count = 1; 328962306a36Sopenharmony_ci mac_proto = MAC_PROTO_NONE; 329062306a36Sopenharmony_ci } else { 329162306a36Sopenharmony_ci mpls_label_count++; 329262306a36Sopenharmony_ci } 329362306a36Sopenharmony_ci } 329462306a36Sopenharmony_ci eth_type = mpls->mpls_ethertype; 329562306a36Sopenharmony_ci break; 329662306a36Sopenharmony_ci } 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci case OVS_ACTION_ATTR_PUSH_MPLS: { 329962306a36Sopenharmony_ci const struct ovs_action_push_mpls *mpls = nla_data(a); 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_ci if (!eth_p_mpls(mpls->mpls_ethertype)) 330262306a36Sopenharmony_ci return -EINVAL; 330362306a36Sopenharmony_ci /* Prohibit push MPLS other than to a white list 330462306a36Sopenharmony_ci * for packets that have a known tag order. 330562306a36Sopenharmony_ci */ 330662306a36Sopenharmony_ci if (vlan_tci & htons(VLAN_CFI_MASK) || 330762306a36Sopenharmony_ci (eth_type != htons(ETH_P_IP) && 330862306a36Sopenharmony_ci eth_type != htons(ETH_P_IPV6) && 330962306a36Sopenharmony_ci eth_type != htons(ETH_P_ARP) && 331062306a36Sopenharmony_ci eth_type != htons(ETH_P_RARP) && 331162306a36Sopenharmony_ci !eth_p_mpls(eth_type))) 331262306a36Sopenharmony_ci return -EINVAL; 331362306a36Sopenharmony_ci eth_type = mpls->mpls_ethertype; 331462306a36Sopenharmony_ci mpls_label_count++; 331562306a36Sopenharmony_ci break; 331662306a36Sopenharmony_ci } 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_ci case OVS_ACTION_ATTR_POP_MPLS: { 331962306a36Sopenharmony_ci __be16 proto; 332062306a36Sopenharmony_ci if (vlan_tci & htons(VLAN_CFI_MASK) || 332162306a36Sopenharmony_ci !eth_p_mpls(eth_type)) 332262306a36Sopenharmony_ci return -EINVAL; 332362306a36Sopenharmony_ci 332462306a36Sopenharmony_ci /* Disallow subsequent L2.5+ set actions and mpls_pop 332562306a36Sopenharmony_ci * actions once the last MPLS label in the packet is 332662306a36Sopenharmony_ci * popped as there is no check here to ensure that 332762306a36Sopenharmony_ci * the new eth type is valid and thus set actions could 332862306a36Sopenharmony_ci * write off the end of the packet or otherwise corrupt 332962306a36Sopenharmony_ci * it. 333062306a36Sopenharmony_ci * 333162306a36Sopenharmony_ci * Support for these actions is planned using packet 333262306a36Sopenharmony_ci * recirculation. 333362306a36Sopenharmony_ci */ 333462306a36Sopenharmony_ci proto = nla_get_be16(a); 333562306a36Sopenharmony_ci 333662306a36Sopenharmony_ci if (proto == htons(ETH_P_TEB) && 333762306a36Sopenharmony_ci mac_proto != MAC_PROTO_NONE) 333862306a36Sopenharmony_ci return -EINVAL; 333962306a36Sopenharmony_ci 334062306a36Sopenharmony_ci mpls_label_count--; 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci if (!eth_p_mpls(proto) || !mpls_label_count) 334362306a36Sopenharmony_ci eth_type = htons(0); 334462306a36Sopenharmony_ci else 334562306a36Sopenharmony_ci eth_type = proto; 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci break; 334862306a36Sopenharmony_ci } 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_ci case OVS_ACTION_ATTR_SET: 335162306a36Sopenharmony_ci err = validate_set(a, key, sfa, 335262306a36Sopenharmony_ci &skip_copy, mac_proto, eth_type, 335362306a36Sopenharmony_ci false, log); 335462306a36Sopenharmony_ci if (err) 335562306a36Sopenharmony_ci return err; 335662306a36Sopenharmony_ci break; 335762306a36Sopenharmony_ci 335862306a36Sopenharmony_ci case OVS_ACTION_ATTR_SET_MASKED: 335962306a36Sopenharmony_ci err = validate_set(a, key, sfa, 336062306a36Sopenharmony_ci &skip_copy, mac_proto, eth_type, 336162306a36Sopenharmony_ci true, log); 336262306a36Sopenharmony_ci if (err) 336362306a36Sopenharmony_ci return err; 336462306a36Sopenharmony_ci break; 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ci case OVS_ACTION_ATTR_SAMPLE: { 336762306a36Sopenharmony_ci bool last = nla_is_last(a, rem); 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_ci err = validate_and_copy_sample(net, a, key, sfa, 337062306a36Sopenharmony_ci eth_type, vlan_tci, 337162306a36Sopenharmony_ci mpls_label_count, 337262306a36Sopenharmony_ci log, last, depth); 337362306a36Sopenharmony_ci if (err) 337462306a36Sopenharmony_ci return err; 337562306a36Sopenharmony_ci skip_copy = true; 337662306a36Sopenharmony_ci break; 337762306a36Sopenharmony_ci } 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_ci case OVS_ACTION_ATTR_CT: 338062306a36Sopenharmony_ci err = ovs_ct_copy_action(net, a, key, sfa, log); 338162306a36Sopenharmony_ci if (err) 338262306a36Sopenharmony_ci return err; 338362306a36Sopenharmony_ci skip_copy = true; 338462306a36Sopenharmony_ci break; 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci case OVS_ACTION_ATTR_CT_CLEAR: 338762306a36Sopenharmony_ci break; 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_ci case OVS_ACTION_ATTR_PUSH_ETH: 339062306a36Sopenharmony_ci /* Disallow pushing an Ethernet header if one 339162306a36Sopenharmony_ci * is already present */ 339262306a36Sopenharmony_ci if (mac_proto != MAC_PROTO_NONE) 339362306a36Sopenharmony_ci return -EINVAL; 339462306a36Sopenharmony_ci mac_proto = MAC_PROTO_ETHERNET; 339562306a36Sopenharmony_ci break; 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_ci case OVS_ACTION_ATTR_POP_ETH: 339862306a36Sopenharmony_ci if (mac_proto != MAC_PROTO_ETHERNET) 339962306a36Sopenharmony_ci return -EINVAL; 340062306a36Sopenharmony_ci if (vlan_tci & htons(VLAN_CFI_MASK)) 340162306a36Sopenharmony_ci return -EINVAL; 340262306a36Sopenharmony_ci mac_proto = MAC_PROTO_NONE; 340362306a36Sopenharmony_ci break; 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci case OVS_ACTION_ATTR_PUSH_NSH: 340662306a36Sopenharmony_ci if (mac_proto != MAC_PROTO_ETHERNET) { 340762306a36Sopenharmony_ci u8 next_proto; 340862306a36Sopenharmony_ci 340962306a36Sopenharmony_ci next_proto = tun_p_from_eth_p(eth_type); 341062306a36Sopenharmony_ci if (!next_proto) 341162306a36Sopenharmony_ci return -EINVAL; 341262306a36Sopenharmony_ci } 341362306a36Sopenharmony_ci mac_proto = MAC_PROTO_NONE; 341462306a36Sopenharmony_ci if (!validate_nsh(nla_data(a), false, true, true)) 341562306a36Sopenharmony_ci return -EINVAL; 341662306a36Sopenharmony_ci break; 341762306a36Sopenharmony_ci 341862306a36Sopenharmony_ci case OVS_ACTION_ATTR_POP_NSH: { 341962306a36Sopenharmony_ci __be16 inner_proto; 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci if (eth_type != htons(ETH_P_NSH)) 342262306a36Sopenharmony_ci return -EINVAL; 342362306a36Sopenharmony_ci inner_proto = tun_p_to_eth_p(key->nsh.base.np); 342462306a36Sopenharmony_ci if (!inner_proto) 342562306a36Sopenharmony_ci return -EINVAL; 342662306a36Sopenharmony_ci if (key->nsh.base.np == TUN_P_ETHERNET) 342762306a36Sopenharmony_ci mac_proto = MAC_PROTO_ETHERNET; 342862306a36Sopenharmony_ci else 342962306a36Sopenharmony_ci mac_proto = MAC_PROTO_NONE; 343062306a36Sopenharmony_ci break; 343162306a36Sopenharmony_ci } 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci case OVS_ACTION_ATTR_METER: 343462306a36Sopenharmony_ci /* Non-existent meters are simply ignored. */ 343562306a36Sopenharmony_ci break; 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci case OVS_ACTION_ATTR_CLONE: { 343862306a36Sopenharmony_ci bool last = nla_is_last(a, rem); 343962306a36Sopenharmony_ci 344062306a36Sopenharmony_ci err = validate_and_copy_clone(net, a, key, sfa, 344162306a36Sopenharmony_ci eth_type, vlan_tci, 344262306a36Sopenharmony_ci mpls_label_count, 344362306a36Sopenharmony_ci log, last, depth); 344462306a36Sopenharmony_ci if (err) 344562306a36Sopenharmony_ci return err; 344662306a36Sopenharmony_ci skip_copy = true; 344762306a36Sopenharmony_ci break; 344862306a36Sopenharmony_ci } 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ci case OVS_ACTION_ATTR_CHECK_PKT_LEN: { 345162306a36Sopenharmony_ci bool last = nla_is_last(a, rem); 345262306a36Sopenharmony_ci 345362306a36Sopenharmony_ci err = validate_and_copy_check_pkt_len(net, a, key, sfa, 345462306a36Sopenharmony_ci eth_type, 345562306a36Sopenharmony_ci vlan_tci, 345662306a36Sopenharmony_ci mpls_label_count, 345762306a36Sopenharmony_ci log, last, 345862306a36Sopenharmony_ci depth); 345962306a36Sopenharmony_ci if (err) 346062306a36Sopenharmony_ci return err; 346162306a36Sopenharmony_ci skip_copy = true; 346262306a36Sopenharmony_ci break; 346362306a36Sopenharmony_ci } 346462306a36Sopenharmony_ci 346562306a36Sopenharmony_ci case OVS_ACTION_ATTR_DEC_TTL: 346662306a36Sopenharmony_ci err = validate_and_copy_dec_ttl(net, a, key, sfa, 346762306a36Sopenharmony_ci eth_type, vlan_tci, 346862306a36Sopenharmony_ci mpls_label_count, log, 346962306a36Sopenharmony_ci depth); 347062306a36Sopenharmony_ci if (err) 347162306a36Sopenharmony_ci return err; 347262306a36Sopenharmony_ci skip_copy = true; 347362306a36Sopenharmony_ci break; 347462306a36Sopenharmony_ci 347562306a36Sopenharmony_ci case OVS_ACTION_ATTR_DROP: 347662306a36Sopenharmony_ci if (!nla_is_last(a, rem)) 347762306a36Sopenharmony_ci return -EINVAL; 347862306a36Sopenharmony_ci break; 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci default: 348162306a36Sopenharmony_ci OVS_NLERR(log, "Unknown Action type %d", type); 348262306a36Sopenharmony_ci return -EINVAL; 348362306a36Sopenharmony_ci } 348462306a36Sopenharmony_ci if (!skip_copy) { 348562306a36Sopenharmony_ci err = copy_action(a, sfa, log); 348662306a36Sopenharmony_ci if (err) 348762306a36Sopenharmony_ci return err; 348862306a36Sopenharmony_ci } 348962306a36Sopenharmony_ci } 349062306a36Sopenharmony_ci 349162306a36Sopenharmony_ci if (rem > 0) 349262306a36Sopenharmony_ci return -EINVAL; 349362306a36Sopenharmony_ci 349462306a36Sopenharmony_ci return 0; 349562306a36Sopenharmony_ci} 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ci/* 'key' must be the masked key. */ 349862306a36Sopenharmony_ciint ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, 349962306a36Sopenharmony_ci const struct sw_flow_key *key, 350062306a36Sopenharmony_ci struct sw_flow_actions **sfa, bool log) 350162306a36Sopenharmony_ci{ 350262306a36Sopenharmony_ci int err; 350362306a36Sopenharmony_ci u32 mpls_label_count = 0; 350462306a36Sopenharmony_ci 350562306a36Sopenharmony_ci *sfa = nla_alloc_flow_actions(min(nla_len(attr), MAX_ACTIONS_BUFSIZE)); 350662306a36Sopenharmony_ci if (IS_ERR(*sfa)) 350762306a36Sopenharmony_ci return PTR_ERR(*sfa); 350862306a36Sopenharmony_ci 350962306a36Sopenharmony_ci if (eth_p_mpls(key->eth.type)) 351062306a36Sopenharmony_ci mpls_label_count = hweight_long(key->mpls.num_labels_mask); 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci (*sfa)->orig_len = nla_len(attr); 351362306a36Sopenharmony_ci err = __ovs_nla_copy_actions(net, attr, key, sfa, key->eth.type, 351462306a36Sopenharmony_ci key->eth.vlan.tci, mpls_label_count, log, 351562306a36Sopenharmony_ci 0); 351662306a36Sopenharmony_ci if (err) 351762306a36Sopenharmony_ci ovs_nla_free_flow_actions(*sfa); 351862306a36Sopenharmony_ci 351962306a36Sopenharmony_ci return err; 352062306a36Sopenharmony_ci} 352162306a36Sopenharmony_ci 352262306a36Sopenharmony_cistatic int sample_action_to_attr(const struct nlattr *attr, 352362306a36Sopenharmony_ci struct sk_buff *skb) 352462306a36Sopenharmony_ci{ 352562306a36Sopenharmony_ci struct nlattr *start, *ac_start = NULL, *sample_arg; 352662306a36Sopenharmony_ci int err = 0, rem = nla_len(attr); 352762306a36Sopenharmony_ci const struct sample_arg *arg; 352862306a36Sopenharmony_ci struct nlattr *actions; 352962306a36Sopenharmony_ci 353062306a36Sopenharmony_ci start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SAMPLE); 353162306a36Sopenharmony_ci if (!start) 353262306a36Sopenharmony_ci return -EMSGSIZE; 353362306a36Sopenharmony_ci 353462306a36Sopenharmony_ci sample_arg = nla_data(attr); 353562306a36Sopenharmony_ci arg = nla_data(sample_arg); 353662306a36Sopenharmony_ci actions = nla_next(sample_arg, &rem); 353762306a36Sopenharmony_ci 353862306a36Sopenharmony_ci if (nla_put_u32(skb, OVS_SAMPLE_ATTR_PROBABILITY, arg->probability)) { 353962306a36Sopenharmony_ci err = -EMSGSIZE; 354062306a36Sopenharmony_ci goto out; 354162306a36Sopenharmony_ci } 354262306a36Sopenharmony_ci 354362306a36Sopenharmony_ci ac_start = nla_nest_start_noflag(skb, OVS_SAMPLE_ATTR_ACTIONS); 354462306a36Sopenharmony_ci if (!ac_start) { 354562306a36Sopenharmony_ci err = -EMSGSIZE; 354662306a36Sopenharmony_ci goto out; 354762306a36Sopenharmony_ci } 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_ci err = ovs_nla_put_actions(actions, rem, skb); 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_ciout: 355262306a36Sopenharmony_ci if (err) { 355362306a36Sopenharmony_ci nla_nest_cancel(skb, ac_start); 355462306a36Sopenharmony_ci nla_nest_cancel(skb, start); 355562306a36Sopenharmony_ci } else { 355662306a36Sopenharmony_ci nla_nest_end(skb, ac_start); 355762306a36Sopenharmony_ci nla_nest_end(skb, start); 355862306a36Sopenharmony_ci } 355962306a36Sopenharmony_ci 356062306a36Sopenharmony_ci return err; 356162306a36Sopenharmony_ci} 356262306a36Sopenharmony_ci 356362306a36Sopenharmony_cistatic int clone_action_to_attr(const struct nlattr *attr, 356462306a36Sopenharmony_ci struct sk_buff *skb) 356562306a36Sopenharmony_ci{ 356662306a36Sopenharmony_ci struct nlattr *start; 356762306a36Sopenharmony_ci int err = 0, rem = nla_len(attr); 356862306a36Sopenharmony_ci 356962306a36Sopenharmony_ci start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_CLONE); 357062306a36Sopenharmony_ci if (!start) 357162306a36Sopenharmony_ci return -EMSGSIZE; 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci /* Skipping the OVS_CLONE_ATTR_EXEC that is always the first attribute. */ 357462306a36Sopenharmony_ci attr = nla_next(nla_data(attr), &rem); 357562306a36Sopenharmony_ci err = ovs_nla_put_actions(attr, rem, skb); 357662306a36Sopenharmony_ci 357762306a36Sopenharmony_ci if (err) 357862306a36Sopenharmony_ci nla_nest_cancel(skb, start); 357962306a36Sopenharmony_ci else 358062306a36Sopenharmony_ci nla_nest_end(skb, start); 358162306a36Sopenharmony_ci 358262306a36Sopenharmony_ci return err; 358362306a36Sopenharmony_ci} 358462306a36Sopenharmony_ci 358562306a36Sopenharmony_cistatic int check_pkt_len_action_to_attr(const struct nlattr *attr, 358662306a36Sopenharmony_ci struct sk_buff *skb) 358762306a36Sopenharmony_ci{ 358862306a36Sopenharmony_ci struct nlattr *start, *ac_start = NULL; 358962306a36Sopenharmony_ci const struct check_pkt_len_arg *arg; 359062306a36Sopenharmony_ci const struct nlattr *a, *cpl_arg; 359162306a36Sopenharmony_ci int err = 0, rem = nla_len(attr); 359262306a36Sopenharmony_ci 359362306a36Sopenharmony_ci start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_CHECK_PKT_LEN); 359462306a36Sopenharmony_ci if (!start) 359562306a36Sopenharmony_ci return -EMSGSIZE; 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_ci /* The first nested attribute in 'attr' is always 359862306a36Sopenharmony_ci * 'OVS_CHECK_PKT_LEN_ATTR_ARG'. 359962306a36Sopenharmony_ci */ 360062306a36Sopenharmony_ci cpl_arg = nla_data(attr); 360162306a36Sopenharmony_ci arg = nla_data(cpl_arg); 360262306a36Sopenharmony_ci 360362306a36Sopenharmony_ci if (nla_put_u16(skb, OVS_CHECK_PKT_LEN_ATTR_PKT_LEN, arg->pkt_len)) { 360462306a36Sopenharmony_ci err = -EMSGSIZE; 360562306a36Sopenharmony_ci goto out; 360662306a36Sopenharmony_ci } 360762306a36Sopenharmony_ci 360862306a36Sopenharmony_ci /* Second nested attribute in 'attr' is always 360962306a36Sopenharmony_ci * 'OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL'. 361062306a36Sopenharmony_ci */ 361162306a36Sopenharmony_ci a = nla_next(cpl_arg, &rem); 361262306a36Sopenharmony_ci ac_start = nla_nest_start_noflag(skb, 361362306a36Sopenharmony_ci OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL); 361462306a36Sopenharmony_ci if (!ac_start) { 361562306a36Sopenharmony_ci err = -EMSGSIZE; 361662306a36Sopenharmony_ci goto out; 361762306a36Sopenharmony_ci } 361862306a36Sopenharmony_ci 361962306a36Sopenharmony_ci err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb); 362062306a36Sopenharmony_ci if (err) { 362162306a36Sopenharmony_ci nla_nest_cancel(skb, ac_start); 362262306a36Sopenharmony_ci goto out; 362362306a36Sopenharmony_ci } else { 362462306a36Sopenharmony_ci nla_nest_end(skb, ac_start); 362562306a36Sopenharmony_ci } 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci /* Third nested attribute in 'attr' is always 362862306a36Sopenharmony_ci * OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER. 362962306a36Sopenharmony_ci */ 363062306a36Sopenharmony_ci a = nla_next(a, &rem); 363162306a36Sopenharmony_ci ac_start = nla_nest_start_noflag(skb, 363262306a36Sopenharmony_ci OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER); 363362306a36Sopenharmony_ci if (!ac_start) { 363462306a36Sopenharmony_ci err = -EMSGSIZE; 363562306a36Sopenharmony_ci goto out; 363662306a36Sopenharmony_ci } 363762306a36Sopenharmony_ci 363862306a36Sopenharmony_ci err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb); 363962306a36Sopenharmony_ci if (err) { 364062306a36Sopenharmony_ci nla_nest_cancel(skb, ac_start); 364162306a36Sopenharmony_ci goto out; 364262306a36Sopenharmony_ci } else { 364362306a36Sopenharmony_ci nla_nest_end(skb, ac_start); 364462306a36Sopenharmony_ci } 364562306a36Sopenharmony_ci 364662306a36Sopenharmony_ci nla_nest_end(skb, start); 364762306a36Sopenharmony_ci return 0; 364862306a36Sopenharmony_ci 364962306a36Sopenharmony_ciout: 365062306a36Sopenharmony_ci nla_nest_cancel(skb, start); 365162306a36Sopenharmony_ci return err; 365262306a36Sopenharmony_ci} 365362306a36Sopenharmony_ci 365462306a36Sopenharmony_cistatic int dec_ttl_action_to_attr(const struct nlattr *attr, 365562306a36Sopenharmony_ci struct sk_buff *skb) 365662306a36Sopenharmony_ci{ 365762306a36Sopenharmony_ci struct nlattr *start, *action_start; 365862306a36Sopenharmony_ci const struct nlattr *a; 365962306a36Sopenharmony_ci int err = 0, rem; 366062306a36Sopenharmony_ci 366162306a36Sopenharmony_ci start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_DEC_TTL); 366262306a36Sopenharmony_ci if (!start) 366362306a36Sopenharmony_ci return -EMSGSIZE; 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci nla_for_each_attr(a, nla_data(attr), nla_len(attr), rem) { 366662306a36Sopenharmony_ci switch (nla_type(a)) { 366762306a36Sopenharmony_ci case OVS_DEC_TTL_ATTR_ACTION: 366862306a36Sopenharmony_ci 366962306a36Sopenharmony_ci action_start = nla_nest_start_noflag(skb, OVS_DEC_TTL_ATTR_ACTION); 367062306a36Sopenharmony_ci if (!action_start) { 367162306a36Sopenharmony_ci err = -EMSGSIZE; 367262306a36Sopenharmony_ci goto out; 367362306a36Sopenharmony_ci } 367462306a36Sopenharmony_ci 367562306a36Sopenharmony_ci err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb); 367662306a36Sopenharmony_ci if (err) 367762306a36Sopenharmony_ci goto out; 367862306a36Sopenharmony_ci 367962306a36Sopenharmony_ci nla_nest_end(skb, action_start); 368062306a36Sopenharmony_ci break; 368162306a36Sopenharmony_ci 368262306a36Sopenharmony_ci default: 368362306a36Sopenharmony_ci /* Ignore all other option to be future compatible */ 368462306a36Sopenharmony_ci break; 368562306a36Sopenharmony_ci } 368662306a36Sopenharmony_ci } 368762306a36Sopenharmony_ci 368862306a36Sopenharmony_ci nla_nest_end(skb, start); 368962306a36Sopenharmony_ci return 0; 369062306a36Sopenharmony_ci 369162306a36Sopenharmony_ciout: 369262306a36Sopenharmony_ci nla_nest_cancel(skb, start); 369362306a36Sopenharmony_ci return err; 369462306a36Sopenharmony_ci} 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_cistatic int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) 369762306a36Sopenharmony_ci{ 369862306a36Sopenharmony_ci const struct nlattr *ovs_key = nla_data(a); 369962306a36Sopenharmony_ci int key_type = nla_type(ovs_key); 370062306a36Sopenharmony_ci struct nlattr *start; 370162306a36Sopenharmony_ci int err; 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ci switch (key_type) { 370462306a36Sopenharmony_ci case OVS_KEY_ATTR_TUNNEL_INFO: { 370562306a36Sopenharmony_ci struct ovs_tunnel_info *ovs_tun = nla_data(ovs_key); 370662306a36Sopenharmony_ci struct ip_tunnel_info *tun_info = &ovs_tun->tun_dst->u.tun_info; 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SET); 370962306a36Sopenharmony_ci if (!start) 371062306a36Sopenharmony_ci return -EMSGSIZE; 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_ci err = ip_tun_to_nlattr(skb, &tun_info->key, 371362306a36Sopenharmony_ci ip_tunnel_info_opts(tun_info), 371462306a36Sopenharmony_ci tun_info->options_len, 371562306a36Sopenharmony_ci ip_tunnel_info_af(tun_info), tun_info->mode); 371662306a36Sopenharmony_ci if (err) 371762306a36Sopenharmony_ci return err; 371862306a36Sopenharmony_ci nla_nest_end(skb, start); 371962306a36Sopenharmony_ci break; 372062306a36Sopenharmony_ci } 372162306a36Sopenharmony_ci default: 372262306a36Sopenharmony_ci if (nla_put(skb, OVS_ACTION_ATTR_SET, nla_len(a), ovs_key)) 372362306a36Sopenharmony_ci return -EMSGSIZE; 372462306a36Sopenharmony_ci break; 372562306a36Sopenharmony_ci } 372662306a36Sopenharmony_ci 372762306a36Sopenharmony_ci return 0; 372862306a36Sopenharmony_ci} 372962306a36Sopenharmony_ci 373062306a36Sopenharmony_cistatic int masked_set_action_to_set_action_attr(const struct nlattr *a, 373162306a36Sopenharmony_ci struct sk_buff *skb) 373262306a36Sopenharmony_ci{ 373362306a36Sopenharmony_ci const struct nlattr *ovs_key = nla_data(a); 373462306a36Sopenharmony_ci struct nlattr *nla; 373562306a36Sopenharmony_ci size_t key_len = nla_len(ovs_key) / 2; 373662306a36Sopenharmony_ci 373762306a36Sopenharmony_ci /* Revert the conversion we did from a non-masked set action to 373862306a36Sopenharmony_ci * masked set action. 373962306a36Sopenharmony_ci */ 374062306a36Sopenharmony_ci nla = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SET); 374162306a36Sopenharmony_ci if (!nla) 374262306a36Sopenharmony_ci return -EMSGSIZE; 374362306a36Sopenharmony_ci 374462306a36Sopenharmony_ci if (nla_put(skb, nla_type(ovs_key), key_len, nla_data(ovs_key))) 374562306a36Sopenharmony_ci return -EMSGSIZE; 374662306a36Sopenharmony_ci 374762306a36Sopenharmony_ci nla_nest_end(skb, nla); 374862306a36Sopenharmony_ci return 0; 374962306a36Sopenharmony_ci} 375062306a36Sopenharmony_ci 375162306a36Sopenharmony_ciint ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb) 375262306a36Sopenharmony_ci{ 375362306a36Sopenharmony_ci const struct nlattr *a; 375462306a36Sopenharmony_ci int rem, err; 375562306a36Sopenharmony_ci 375662306a36Sopenharmony_ci nla_for_each_attr(a, attr, len, rem) { 375762306a36Sopenharmony_ci int type = nla_type(a); 375862306a36Sopenharmony_ci 375962306a36Sopenharmony_ci switch (type) { 376062306a36Sopenharmony_ci case OVS_ACTION_ATTR_SET: 376162306a36Sopenharmony_ci err = set_action_to_attr(a, skb); 376262306a36Sopenharmony_ci if (err) 376362306a36Sopenharmony_ci return err; 376462306a36Sopenharmony_ci break; 376562306a36Sopenharmony_ci 376662306a36Sopenharmony_ci case OVS_ACTION_ATTR_SET_TO_MASKED: 376762306a36Sopenharmony_ci err = masked_set_action_to_set_action_attr(a, skb); 376862306a36Sopenharmony_ci if (err) 376962306a36Sopenharmony_ci return err; 377062306a36Sopenharmony_ci break; 377162306a36Sopenharmony_ci 377262306a36Sopenharmony_ci case OVS_ACTION_ATTR_SAMPLE: 377362306a36Sopenharmony_ci err = sample_action_to_attr(a, skb); 377462306a36Sopenharmony_ci if (err) 377562306a36Sopenharmony_ci return err; 377662306a36Sopenharmony_ci break; 377762306a36Sopenharmony_ci 377862306a36Sopenharmony_ci case OVS_ACTION_ATTR_CT: 377962306a36Sopenharmony_ci err = ovs_ct_action_to_attr(nla_data(a), skb); 378062306a36Sopenharmony_ci if (err) 378162306a36Sopenharmony_ci return err; 378262306a36Sopenharmony_ci break; 378362306a36Sopenharmony_ci 378462306a36Sopenharmony_ci case OVS_ACTION_ATTR_CLONE: 378562306a36Sopenharmony_ci err = clone_action_to_attr(a, skb); 378662306a36Sopenharmony_ci if (err) 378762306a36Sopenharmony_ci return err; 378862306a36Sopenharmony_ci break; 378962306a36Sopenharmony_ci 379062306a36Sopenharmony_ci case OVS_ACTION_ATTR_CHECK_PKT_LEN: 379162306a36Sopenharmony_ci err = check_pkt_len_action_to_attr(a, skb); 379262306a36Sopenharmony_ci if (err) 379362306a36Sopenharmony_ci return err; 379462306a36Sopenharmony_ci break; 379562306a36Sopenharmony_ci 379662306a36Sopenharmony_ci case OVS_ACTION_ATTR_DEC_TTL: 379762306a36Sopenharmony_ci err = dec_ttl_action_to_attr(a, skb); 379862306a36Sopenharmony_ci if (err) 379962306a36Sopenharmony_ci return err; 380062306a36Sopenharmony_ci break; 380162306a36Sopenharmony_ci 380262306a36Sopenharmony_ci default: 380362306a36Sopenharmony_ci if (nla_put(skb, type, nla_len(a), nla_data(a))) 380462306a36Sopenharmony_ci return -EMSGSIZE; 380562306a36Sopenharmony_ci break; 380662306a36Sopenharmony_ci } 380762306a36Sopenharmony_ci } 380862306a36Sopenharmony_ci 380962306a36Sopenharmony_ci return 0; 381062306a36Sopenharmony_ci} 3811