1c9422999SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e6445719SPravin B Shelar /*
3798c1661Sandy zhou * Copyright (c) 2007-2017 Nicira, Inc.
4e6445719SPravin B Shelar */
5e6445719SPravin B Shelar
62235ad1cSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
72235ad1cSJoe Perches
8e6445719SPravin B Shelar #include "flow.h"
9e6445719SPravin B Shelar #include "datapath.h"
10e6445719SPravin B Shelar #include <linux/uaccess.h>
11e6445719SPravin B Shelar #include <linux/netdevice.h>
12e6445719SPravin B Shelar #include <linux/etherdevice.h>
13e6445719SPravin B Shelar #include <linux/if_ether.h>
14e6445719SPravin B Shelar #include <linux/if_vlan.h>
15e6445719SPravin B Shelar #include <net/llc_pdu.h>
16e6445719SPravin B Shelar #include <linux/kernel.h>
17e6445719SPravin B Shelar #include <linux/jhash.h>
18e6445719SPravin B Shelar #include <linux/jiffies.h>
19e6445719SPravin B Shelar #include <linux/llc.h>
20e6445719SPravin B Shelar #include <linux/module.h>
21e6445719SPravin B Shelar #include <linux/in.h>
22e6445719SPravin B Shelar #include <linux/rcupdate.h>
23e6445719SPravin B Shelar #include <linux/if_arp.h>
24e6445719SPravin B Shelar #include <linux/ip.h>
25e6445719SPravin B Shelar #include <linux/ipv6.h>
26e6445719SPravin B Shelar #include <linux/sctp.h>
27e6445719SPravin B Shelar #include <linux/tcp.h>
28e6445719SPravin B Shelar #include <linux/udp.h>
29e6445719SPravin B Shelar #include <linux/icmp.h>
30e6445719SPravin B Shelar #include <linux/icmpv6.h>
31e6445719SPravin B Shelar #include <linux/rculist.h>
32f5796684SJesse Gross #include <net/geneve.h>
33e6445719SPravin B Shelar #include <net/ip.h>
34e6445719SPravin B Shelar #include <net/ipv6.h>
35e6445719SPravin B Shelar #include <net/ndisc.h>
3625cd9ba0SSimon Horman #include <net/mpls.h>
37614732eaSThomas Graf #include <net/vxlan.h>
38b2d0f5d5SYi Yang #include <net/tun_proto.h>
39fc1372f8SWilliam Tu #include <net/erspan.h>
40e6445719SPravin B Shelar
41e7bc7db9SEric Garver #include "drop.h"
42e6445719SPravin B Shelar #include "flow_netlink.h"
43e6445719SPravin B Shelar
4481bfe3c3SThomas Graf struct ovs_len_tbl {
4581bfe3c3SThomas Graf int len;
4681bfe3c3SThomas Graf const struct ovs_len_tbl *next;
4781bfe3c3SThomas Graf };
4881bfe3c3SThomas Graf
4981bfe3c3SThomas Graf #define OVS_ATTR_NESTED -1
50982b5270SJesse Gross #define OVS_ATTR_VARIABLE -2
516e2f90d3SAaron Conole #define OVS_COPY_ACTIONS_MAX_DEPTH 16
5281bfe3c3SThomas Graf
actions_may_change_flow(const struct nlattr * actions)53798c1661Sandy zhou static bool actions_may_change_flow(const struct nlattr *actions)
54798c1661Sandy zhou {
55798c1661Sandy zhou struct nlattr *nla;
56798c1661Sandy zhou int rem;
57798c1661Sandy zhou
58798c1661Sandy zhou nla_for_each_nested(nla, actions, rem) {
59798c1661Sandy zhou u16 action = nla_type(nla);
60798c1661Sandy zhou
61798c1661Sandy zhou switch (action) {
62798c1661Sandy zhou case OVS_ACTION_ATTR_OUTPUT:
63798c1661Sandy zhou case OVS_ACTION_ATTR_RECIRC:
64798c1661Sandy zhou case OVS_ACTION_ATTR_TRUNC:
65798c1661Sandy zhou case OVS_ACTION_ATTR_USERSPACE:
66e7bc7db9SEric Garver case OVS_ACTION_ATTR_DROP:
67aae0b82bSAdrian Moreno case OVS_ACTION_ATTR_PSAMPLE:
68798c1661Sandy zhou break;
69798c1661Sandy zhou
70798c1661Sandy zhou case OVS_ACTION_ATTR_CT:
71b8226962SEric Garver case OVS_ACTION_ATTR_CT_CLEAR:
72798c1661Sandy zhou case OVS_ACTION_ATTR_HASH:
73798c1661Sandy zhou case OVS_ACTION_ATTR_POP_ETH:
74798c1661Sandy zhou case OVS_ACTION_ATTR_POP_MPLS:
75b2d0f5d5SYi Yang case OVS_ACTION_ATTR_POP_NSH:
76798c1661Sandy zhou case OVS_ACTION_ATTR_POP_VLAN:
77798c1661Sandy zhou case OVS_ACTION_ATTR_PUSH_ETH:
78798c1661Sandy zhou case OVS_ACTION_ATTR_PUSH_MPLS:
79b2d0f5d5SYi Yang case OVS_ACTION_ATTR_PUSH_NSH:
80798c1661Sandy zhou case OVS_ACTION_ATTR_PUSH_VLAN:
81798c1661Sandy zhou case OVS_ACTION_ATTR_SAMPLE:
82798c1661Sandy zhou case OVS_ACTION_ATTR_SET:
83798c1661Sandy zhou case OVS_ACTION_ATTR_SET_MASKED:
84cd8a6c33SAndy Zhou case OVS_ACTION_ATTR_METER:
854d5ec89fSNuman Siddique case OVS_ACTION_ATTR_CHECK_PKT_LEN:
86f66b53fdSMartin Varghese case OVS_ACTION_ATTR_ADD_MPLS:
87744676e7SMatteo Croce case OVS_ACTION_ATTR_DEC_TTL:
88798c1661Sandy zhou default:
89798c1661Sandy zhou return true;
90798c1661Sandy zhou }
91798c1661Sandy zhou }
92798c1661Sandy zhou return false;
93798c1661Sandy zhou }
94798c1661Sandy zhou
update_range(struct sw_flow_match * match,size_t offset,size_t size,bool is_mask)95a85311bfSPravin B Shelar static void update_range(struct sw_flow_match *match,
96e6445719SPravin B Shelar size_t offset, size_t size, bool is_mask)
97e6445719SPravin B Shelar {
98a85311bfSPravin B Shelar struct sw_flow_key_range *range;
99e6445719SPravin B Shelar size_t start = rounddown(offset, sizeof(long));
100e6445719SPravin B Shelar size_t end = roundup(offset + size, sizeof(long));
101e6445719SPravin B Shelar
102e6445719SPravin B Shelar if (!is_mask)
103e6445719SPravin B Shelar range = &match->range;
104a85311bfSPravin B Shelar else
105e6445719SPravin B Shelar range = &match->mask->range;
106e6445719SPravin B Shelar
107e6445719SPravin B Shelar if (range->start == range->end) {
108e6445719SPravin B Shelar range->start = start;
109e6445719SPravin B Shelar range->end = end;
110e6445719SPravin B Shelar return;
111e6445719SPravin B Shelar }
112e6445719SPravin B Shelar
113e6445719SPravin B Shelar if (range->start > start)
114e6445719SPravin B Shelar range->start = start;
115e6445719SPravin B Shelar
116e6445719SPravin B Shelar if (range->end < end)
117e6445719SPravin B Shelar range->end = end;
118e6445719SPravin B Shelar }
119e6445719SPravin B Shelar
120e6445719SPravin B Shelar #define SW_FLOW_KEY_PUT(match, field, value, is_mask) \
121e6445719SPravin B Shelar do { \
122a85311bfSPravin B Shelar update_range(match, offsetof(struct sw_flow_key, field), \
123e6445719SPravin B Shelar sizeof((match)->key->field), is_mask); \
124a85311bfSPravin B Shelar if (is_mask) \
125e6445719SPravin B Shelar (match)->mask->key.field = value; \
126a85311bfSPravin B Shelar else \
127e6445719SPravin B Shelar (match)->key->field = value; \
128e6445719SPravin B Shelar } while (0)
129e6445719SPravin B Shelar
130f5796684SJesse Gross #define SW_FLOW_KEY_MEMCPY_OFFSET(match, offset, value_p, len, is_mask) \
131e6445719SPravin B Shelar do { \
132a85311bfSPravin B Shelar update_range(match, offset, len, is_mask); \
133f5796684SJesse Gross if (is_mask) \
134f5796684SJesse Gross memcpy((u8 *)&(match)->mask->key + offset, value_p, \
135f5796684SJesse Gross len); \
136f5796684SJesse Gross else \
137f5796684SJesse Gross memcpy((u8 *)(match)->key + offset, value_p, len); \
138e6445719SPravin B Shelar } while (0)
139e6445719SPravin B Shelar
140f5796684SJesse Gross #define SW_FLOW_KEY_MEMCPY(match, field, value_p, len, is_mask) \
141f5796684SJesse Gross SW_FLOW_KEY_MEMCPY_OFFSET(match, offsetof(struct sw_flow_key, field), \
142f5796684SJesse Gross value_p, len, is_mask)
143f5796684SJesse Gross
144f47de068SPravin B Shelar #define SW_FLOW_KEY_MEMSET_FIELD(match, field, value, is_mask) \
145f47de068SPravin B Shelar do { \
146a85311bfSPravin B Shelar update_range(match, offsetof(struct sw_flow_key, field), \
147f47de068SPravin B Shelar sizeof((match)->key->field), is_mask); \
148a85311bfSPravin B Shelar if (is_mask) \
149f47de068SPravin B Shelar memset((u8 *)&(match)->mask->key.field, value, \
150f47de068SPravin B Shelar sizeof((match)->mask->key.field)); \
151a85311bfSPravin B Shelar else \
152f47de068SPravin B Shelar memset((u8 *)&(match)->key->field, value, \
153f47de068SPravin B Shelar sizeof((match)->key->field)); \
154f47de068SPravin B Shelar } while (0)
155e6445719SPravin B Shelar
1565832c4a7SAlexander Lobakin #define SW_FLOW_KEY_BITMAP_COPY(match, field, value_p, nbits, is_mask) ({ \
1575832c4a7SAlexander Lobakin update_range(match, offsetof(struct sw_flow_key, field), \
1585832c4a7SAlexander Lobakin bitmap_size(nbits), is_mask); \
1595832c4a7SAlexander Lobakin bitmap_copy(is_mask ? (match)->mask->key.field : (match)->key->field, \
1605832c4a7SAlexander Lobakin value_p, nbits); \
1615832c4a7SAlexander Lobakin })
1625832c4a7SAlexander Lobakin
match_validate(const struct sw_flow_match * match,u64 key_attrs,u64 mask_attrs,bool log)163e6445719SPravin B Shelar static bool match_validate(const struct sw_flow_match *match,
16405da5898SJarno Rajahalme u64 key_attrs, u64 mask_attrs, bool log)
165e6445719SPravin B Shelar {
1660a6410fbSJiri Benc u64 key_expected = 0;
167e6445719SPravin B Shelar u64 mask_allowed = key_attrs; /* At most allow all key attributes */
168e6445719SPravin B Shelar
169e6445719SPravin B Shelar /* The following mask attributes allowed only if they
170e6445719SPravin B Shelar * pass the validation tests. */
171e6445719SPravin B Shelar mask_allowed &= ~((1 << OVS_KEY_ATTR_IPV4)
1729dd7f890SJarno Rajahalme | (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4)
173e6445719SPravin B Shelar | (1 << OVS_KEY_ATTR_IPV6)
1749dd7f890SJarno Rajahalme | (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6)
175e6445719SPravin B Shelar | (1 << OVS_KEY_ATTR_TCP)
1765eb26b15SJarno Rajahalme | (1 << OVS_KEY_ATTR_TCP_FLAGS)
177e6445719SPravin B Shelar | (1 << OVS_KEY_ATTR_UDP)
178e6445719SPravin B Shelar | (1 << OVS_KEY_ATTR_SCTP)
179e6445719SPravin B Shelar | (1 << OVS_KEY_ATTR_ICMP)
180e6445719SPravin B Shelar | (1 << OVS_KEY_ATTR_ICMPV6)
181e6445719SPravin B Shelar | (1 << OVS_KEY_ATTR_ARP)
18225cd9ba0SSimon Horman | (1 << OVS_KEY_ATTR_ND)
183b2d0f5d5SYi Yang | (1 << OVS_KEY_ATTR_MPLS)
184b2d0f5d5SYi Yang | (1 << OVS_KEY_ATTR_NSH));
185e6445719SPravin B Shelar
186e6445719SPravin B Shelar /* Always allowed mask fields. */
187e6445719SPravin B Shelar mask_allowed |= ((1 << OVS_KEY_ATTR_TUNNEL)
188e6445719SPravin B Shelar | (1 << OVS_KEY_ATTR_IN_PORT)
189e6445719SPravin B Shelar | (1 << OVS_KEY_ATTR_ETHERTYPE));
190e6445719SPravin B Shelar
191e6445719SPravin B Shelar /* Check key attributes. */
192e6445719SPravin B Shelar if (match->key->eth.type == htons(ETH_P_ARP)
193e6445719SPravin B Shelar || match->key->eth.type == htons(ETH_P_RARP)) {
194e6445719SPravin B Shelar key_expected |= 1 << OVS_KEY_ATTR_ARP;
195f2a01517SPravin B Shelar if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
196e6445719SPravin B Shelar mask_allowed |= 1 << OVS_KEY_ATTR_ARP;
197e6445719SPravin B Shelar }
198e6445719SPravin B Shelar
19925cd9ba0SSimon Horman if (eth_p_mpls(match->key->eth.type)) {
20025cd9ba0SSimon Horman key_expected |= 1 << OVS_KEY_ATTR_MPLS;
20125cd9ba0SSimon Horman if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
20225cd9ba0SSimon Horman mask_allowed |= 1 << OVS_KEY_ATTR_MPLS;
20325cd9ba0SSimon Horman }
20425cd9ba0SSimon Horman
205e6445719SPravin B Shelar if (match->key->eth.type == htons(ETH_P_IP)) {
206e6445719SPravin B Shelar key_expected |= 1 << OVS_KEY_ATTR_IPV4;
2079dd7f890SJarno Rajahalme if (match->mask && match->mask->key.eth.type == htons(0xffff)) {
208e6445719SPravin B Shelar mask_allowed |= 1 << OVS_KEY_ATTR_IPV4;
2099dd7f890SJarno Rajahalme mask_allowed |= 1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4;
2109dd7f890SJarno Rajahalme }
211e6445719SPravin B Shelar
212e6445719SPravin B Shelar if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) {
213e6445719SPravin B Shelar if (match->key->ip.proto == IPPROTO_UDP) {
214e6445719SPravin B Shelar key_expected |= 1 << OVS_KEY_ATTR_UDP;
215e6445719SPravin B Shelar if (match->mask && (match->mask->key.ip.proto == 0xff))
216e6445719SPravin B Shelar mask_allowed |= 1 << OVS_KEY_ATTR_UDP;
217e6445719SPravin B Shelar }
218e6445719SPravin B Shelar
219e6445719SPravin B Shelar if (match->key->ip.proto == IPPROTO_SCTP) {
220e6445719SPravin B Shelar key_expected |= 1 << OVS_KEY_ATTR_SCTP;
221e6445719SPravin B Shelar if (match->mask && (match->mask->key.ip.proto == 0xff))
222e6445719SPravin B Shelar mask_allowed |= 1 << OVS_KEY_ATTR_SCTP;
223e6445719SPravin B Shelar }
224e6445719SPravin B Shelar
225e6445719SPravin B Shelar if (match->key->ip.proto == IPPROTO_TCP) {
226e6445719SPravin B Shelar key_expected |= 1 << OVS_KEY_ATTR_TCP;
2275eb26b15SJarno Rajahalme key_expected |= 1 << OVS_KEY_ATTR_TCP_FLAGS;
2285eb26b15SJarno Rajahalme if (match->mask && (match->mask->key.ip.proto == 0xff)) {
229e6445719SPravin B Shelar mask_allowed |= 1 << OVS_KEY_ATTR_TCP;
2305eb26b15SJarno Rajahalme mask_allowed |= 1 << OVS_KEY_ATTR_TCP_FLAGS;
2315eb26b15SJarno Rajahalme }
232e6445719SPravin B Shelar }
233e6445719SPravin B Shelar
234e6445719SPravin B Shelar if (match->key->ip.proto == IPPROTO_ICMP) {
235e6445719SPravin B Shelar key_expected |= 1 << OVS_KEY_ATTR_ICMP;
236e6445719SPravin B Shelar if (match->mask && (match->mask->key.ip.proto == 0xff))
237e6445719SPravin B Shelar mask_allowed |= 1 << OVS_KEY_ATTR_ICMP;
238e6445719SPravin B Shelar }
239e6445719SPravin B Shelar }
240e6445719SPravin B Shelar }
241e6445719SPravin B Shelar
242e6445719SPravin B Shelar if (match->key->eth.type == htons(ETH_P_IPV6)) {
243e6445719SPravin B Shelar key_expected |= 1 << OVS_KEY_ATTR_IPV6;
2449dd7f890SJarno Rajahalme if (match->mask && match->mask->key.eth.type == htons(0xffff)) {
245e6445719SPravin B Shelar mask_allowed |= 1 << OVS_KEY_ATTR_IPV6;
2469dd7f890SJarno Rajahalme mask_allowed |= 1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6;
2479dd7f890SJarno Rajahalme }
248e6445719SPravin B Shelar
249e6445719SPravin B Shelar if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) {
250e6445719SPravin B Shelar if (match->key->ip.proto == IPPROTO_UDP) {
251e6445719SPravin B Shelar key_expected |= 1 << OVS_KEY_ATTR_UDP;
252e6445719SPravin B Shelar if (match->mask && (match->mask->key.ip.proto == 0xff))
253e6445719SPravin B Shelar mask_allowed |= 1 << OVS_KEY_ATTR_UDP;
254e6445719SPravin B Shelar }
255e6445719SPravin B Shelar
256e6445719SPravin B Shelar if (match->key->ip.proto == IPPROTO_SCTP) {
257e6445719SPravin B Shelar key_expected |= 1 << OVS_KEY_ATTR_SCTP;
258e6445719SPravin B Shelar if (match->mask && (match->mask->key.ip.proto == 0xff))
259e6445719SPravin B Shelar mask_allowed |= 1 << OVS_KEY_ATTR_SCTP;
260e6445719SPravin B Shelar }
261e6445719SPravin B Shelar
262e6445719SPravin B Shelar if (match->key->ip.proto == IPPROTO_TCP) {
263e6445719SPravin B Shelar key_expected |= 1 << OVS_KEY_ATTR_TCP;
2645eb26b15SJarno Rajahalme key_expected |= 1 << OVS_KEY_ATTR_TCP_FLAGS;
2655eb26b15SJarno Rajahalme if (match->mask && (match->mask->key.ip.proto == 0xff)) {
266e6445719SPravin B Shelar mask_allowed |= 1 << OVS_KEY_ATTR_TCP;
2675eb26b15SJarno Rajahalme mask_allowed |= 1 << OVS_KEY_ATTR_TCP_FLAGS;
2685eb26b15SJarno Rajahalme }
269e6445719SPravin B Shelar }
270e6445719SPravin B Shelar
271e6445719SPravin B Shelar if (match->key->ip.proto == IPPROTO_ICMPV6) {
272e6445719SPravin B Shelar key_expected |= 1 << OVS_KEY_ATTR_ICMPV6;
273e6445719SPravin B Shelar if (match->mask && (match->mask->key.ip.proto == 0xff))
274e6445719SPravin B Shelar mask_allowed |= 1 << OVS_KEY_ATTR_ICMPV6;
275e6445719SPravin B Shelar
2761139e241SJarno Rajahalme if (match->key->tp.src ==
277e6445719SPravin B Shelar htons(NDISC_NEIGHBOUR_SOLICITATION) ||
2781139e241SJarno Rajahalme match->key->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) {
279e6445719SPravin B Shelar key_expected |= 1 << OVS_KEY_ATTR_ND;
2809dd7f890SJarno Rajahalme /* Original direction conntrack tuple
2819dd7f890SJarno Rajahalme * uses the same space as the ND fields
2829dd7f890SJarno Rajahalme * in the key, so both are not allowed
2839dd7f890SJarno Rajahalme * at the same time.
2849dd7f890SJarno Rajahalme */
2859dd7f890SJarno Rajahalme mask_allowed &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6);
286f2a01517SPravin B Shelar if (match->mask && (match->mask->key.tp.src == htons(0xff)))
287e6445719SPravin B Shelar mask_allowed |= 1 << OVS_KEY_ATTR_ND;
288e6445719SPravin B Shelar }
289e6445719SPravin B Shelar }
290e6445719SPravin B Shelar }
291e6445719SPravin B Shelar }
292e6445719SPravin B Shelar
293b2d0f5d5SYi Yang if (match->key->eth.type == htons(ETH_P_NSH)) {
294b2d0f5d5SYi Yang key_expected |= 1 << OVS_KEY_ATTR_NSH;
295b2d0f5d5SYi Yang if (match->mask &&
296b2d0f5d5SYi Yang match->mask->key.eth.type == htons(0xffff)) {
297b2d0f5d5SYi Yang mask_allowed |= 1 << OVS_KEY_ATTR_NSH;
298b2d0f5d5SYi Yang }
299b2d0f5d5SYi Yang }
300b2d0f5d5SYi Yang
301e6445719SPravin B Shelar if ((key_attrs & key_expected) != key_expected) {
302e6445719SPravin B Shelar /* Key attributes check failed. */
30305da5898SJarno Rajahalme OVS_NLERR(log, "Missing key (keys=%llx, expected=%llx)",
30405da5898SJarno Rajahalme (unsigned long long)key_attrs,
30505da5898SJarno Rajahalme (unsigned long long)key_expected);
306e6445719SPravin B Shelar return false;
307e6445719SPravin B Shelar }
308e6445719SPravin B Shelar
309e6445719SPravin B Shelar if ((mask_attrs & mask_allowed) != mask_attrs) {
310e6445719SPravin B Shelar /* Mask attributes check failed. */
31105da5898SJarno Rajahalme OVS_NLERR(log, "Unexpected mask (mask=%llx, allowed=%llx)",
31205da5898SJarno Rajahalme (unsigned long long)mask_attrs,
31305da5898SJarno Rajahalme (unsigned long long)mask_allowed);
314e6445719SPravin B Shelar return false;
315e6445719SPravin B Shelar }
316e6445719SPravin B Shelar
317e6445719SPravin B Shelar return true;
318e6445719SPravin B Shelar }
319e6445719SPravin B Shelar
ovs_tun_key_attr_size(void)3208f0aad6fSWenyu Zhang size_t ovs_tun_key_attr_size(void)
3218f0aad6fSWenyu Zhang {
3228f0aad6fSWenyu Zhang /* Whenever adding new OVS_TUNNEL_KEY_ FIELDS, we should consider
3238f0aad6fSWenyu Zhang * updating this function.
3248f0aad6fSWenyu Zhang */
325b46f6dedSNicolas Dichtel return nla_total_size_64bit(8) /* OVS_TUNNEL_KEY_ATTR_ID */
3266b26ba3aSJiri Benc + nla_total_size(16) /* OVS_TUNNEL_KEY_ATTR_IPV[46]_SRC */
3276b26ba3aSJiri Benc + nla_total_size(16) /* OVS_TUNNEL_KEY_ATTR_IPV[46]_DST */
3288f0aad6fSWenyu Zhang + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */
3298f0aad6fSWenyu Zhang + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */
3308f0aad6fSWenyu Zhang + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
3318f0aad6fSWenyu Zhang + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
3328f0aad6fSWenyu Zhang + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
3338f0aad6fSWenyu Zhang + nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
334fc1372f8SWilliam Tu /* OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS and
335fc1372f8SWilliam Tu * OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS is mutually exclusive with
3361dd144cfSThomas Graf * OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS and covered by it.
3371dd144cfSThomas Graf */
3388f0aad6fSWenyu Zhang + nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */
33995a33208SWilliam Tu + nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */
3408f0aad6fSWenyu Zhang }
3418f0aad6fSWenyu Zhang
ovs_nsh_key_attr_size(void)34206c2351fSWei Yongjun static size_t ovs_nsh_key_attr_size(void)
343b2d0f5d5SYi Yang {
344b2d0f5d5SYi Yang /* Whenever adding new OVS_NSH_KEY_ FIELDS, we should consider
345b2d0f5d5SYi Yang * updating this function.
346b2d0f5d5SYi Yang */
347b2d0f5d5SYi Yang return nla_total_size(NSH_BASE_HDR_LEN) /* OVS_NSH_KEY_ATTR_BASE */
348b2d0f5d5SYi Yang /* OVS_NSH_KEY_ATTR_MD1 and OVS_NSH_KEY_ATTR_MD2 are
349b2d0f5d5SYi Yang * mutually exclusive, so the bigger one can cover
350b2d0f5d5SYi Yang * the small one.
351b2d0f5d5SYi Yang */
352b2d0f5d5SYi Yang + nla_total_size(NSH_CTX_HDRS_MAX_LEN);
353b2d0f5d5SYi Yang }
354b2d0f5d5SYi Yang
ovs_key_attr_size(void)35541af73e9SJoe Stringer size_t ovs_key_attr_size(void)
35641af73e9SJoe Stringer {
35741af73e9SJoe Stringer /* Whenever adding new OVS_KEY_ FIELDS, we should consider
35841af73e9SJoe Stringer * updating this function.
35941af73e9SJoe Stringer */
3601926407aSIlya Maximets BUILD_BUG_ON(OVS_KEY_ATTR_MAX != 32);
36141af73e9SJoe Stringer
36241af73e9SJoe Stringer return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
36341af73e9SJoe Stringer + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
3648f0aad6fSWenyu Zhang + ovs_tun_key_attr_size()
36541af73e9SJoe Stringer + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */
36641af73e9SJoe Stringer + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */
36741af73e9SJoe Stringer + nla_total_size(4) /* OVS_KEY_ATTR_DP_HASH */
36841af73e9SJoe Stringer + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */
369fbccce59SJoe Stringer + nla_total_size(4) /* OVS_KEY_ATTR_CT_STATE */
3707f8a436eSJoe Stringer + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */
371182e3042SJoe Stringer + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */
37233db4125SJoe Stringer + nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */
3739dd7f890SJarno Rajahalme + nla_total_size(40) /* OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6 */
374b2d0f5d5SYi Yang + nla_total_size(0) /* OVS_KEY_ATTR_NSH */
375b2d0f5d5SYi Yang + ovs_nsh_key_attr_size()
37641af73e9SJoe Stringer + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
37741af73e9SJoe Stringer + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
37841af73e9SJoe Stringer + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */
37941af73e9SJoe Stringer + nla_total_size(0) /* OVS_KEY_ATTR_ENCAP */
38041af73e9SJoe Stringer + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
38141af73e9SJoe Stringer + nla_total_size(40) /* OVS_KEY_ATTR_IPV6 */
38241af73e9SJoe Stringer + nla_total_size(2) /* OVS_KEY_ATTR_ICMPV6 */
38328a3f060SToms Atteka + nla_total_size(28) /* OVS_KEY_ATTR_ND */
38428a3f060SToms Atteka + nla_total_size(2); /* OVS_KEY_ATTR_IPV6_EXTHDRS */
38541af73e9SJoe Stringer }
38641af73e9SJoe Stringer
387982b5270SJesse Gross static const struct ovs_len_tbl ovs_vxlan_ext_key_lens[OVS_VXLAN_EXT_MAX + 1] = {
388982b5270SJesse Gross [OVS_VXLAN_EXT_GBP] = { .len = sizeof(u32) },
389982b5270SJesse Gross };
390982b5270SJesse Gross
39181bfe3c3SThomas Graf static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
39281bfe3c3SThomas Graf [OVS_TUNNEL_KEY_ATTR_ID] = { .len = sizeof(u64) },
39381bfe3c3SThomas Graf [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = { .len = sizeof(u32) },
39481bfe3c3SThomas Graf [OVS_TUNNEL_KEY_ATTR_IPV4_DST] = { .len = sizeof(u32) },
39581bfe3c3SThomas Graf [OVS_TUNNEL_KEY_ATTR_TOS] = { .len = 1 },
39681bfe3c3SThomas Graf [OVS_TUNNEL_KEY_ATTR_TTL] = { .len = 1 },
39781bfe3c3SThomas Graf [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = { .len = 0 },
39881bfe3c3SThomas Graf [OVS_TUNNEL_KEY_ATTR_CSUM] = { .len = 0 },
39981bfe3c3SThomas Graf [OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) },
40081bfe3c3SThomas Graf [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) },
40181bfe3c3SThomas Graf [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 },
402982b5270SJesse Gross [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_VARIABLE },
403982b5270SJesse Gross [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED,
404982b5270SJesse Gross .next = ovs_vxlan_ext_key_lens },
4056b26ba3aSJiri Benc [OVS_TUNNEL_KEY_ATTR_IPV6_SRC] = { .len = sizeof(struct in6_addr) },
4066b26ba3aSJiri Benc [OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = sizeof(struct in6_addr) },
407fc1372f8SWilliam Tu [OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS] = { .len = OVS_ATTR_VARIABLE },
40818b6f717Swenxu [OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE] = { .len = 0 },
40981bfe3c3SThomas Graf };
41081bfe3c3SThomas Graf
411b2d0f5d5SYi Yang static const struct ovs_len_tbl
412b2d0f5d5SYi Yang ovs_nsh_key_attr_lens[OVS_NSH_KEY_ATTR_MAX + 1] = {
413b2d0f5d5SYi Yang [OVS_NSH_KEY_ATTR_BASE] = { .len = sizeof(struct ovs_nsh_key_base) },
414b2d0f5d5SYi Yang [OVS_NSH_KEY_ATTR_MD1] = { .len = sizeof(struct ovs_nsh_key_md1) },
415b2d0f5d5SYi Yang [OVS_NSH_KEY_ATTR_MD2] = { .len = OVS_ATTR_VARIABLE },
416b2d0f5d5SYi Yang };
417b2d0f5d5SYi Yang
418e6445719SPravin B Shelar /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */
41981bfe3c3SThomas Graf static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
42081bfe3c3SThomas Graf [OVS_KEY_ATTR_ENCAP] = { .len = OVS_ATTR_NESTED },
42181bfe3c3SThomas Graf [OVS_KEY_ATTR_PRIORITY] = { .len = sizeof(u32) },
42281bfe3c3SThomas Graf [OVS_KEY_ATTR_IN_PORT] = { .len = sizeof(u32) },
42381bfe3c3SThomas Graf [OVS_KEY_ATTR_SKB_MARK] = { .len = sizeof(u32) },
42481bfe3c3SThomas Graf [OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) },
42581bfe3c3SThomas Graf [OVS_KEY_ATTR_VLAN] = { .len = sizeof(__be16) },
42681bfe3c3SThomas Graf [OVS_KEY_ATTR_ETHERTYPE] = { .len = sizeof(__be16) },
42781bfe3c3SThomas Graf [OVS_KEY_ATTR_IPV4] = { .len = sizeof(struct ovs_key_ipv4) },
42881bfe3c3SThomas Graf [OVS_KEY_ATTR_IPV6] = { .len = sizeof(struct ovs_key_ipv6) },
42981bfe3c3SThomas Graf [OVS_KEY_ATTR_TCP] = { .len = sizeof(struct ovs_key_tcp) },
43081bfe3c3SThomas Graf [OVS_KEY_ATTR_TCP_FLAGS] = { .len = sizeof(__be16) },
43181bfe3c3SThomas Graf [OVS_KEY_ATTR_UDP] = { .len = sizeof(struct ovs_key_udp) },
43281bfe3c3SThomas Graf [OVS_KEY_ATTR_SCTP] = { .len = sizeof(struct ovs_key_sctp) },
43381bfe3c3SThomas Graf [OVS_KEY_ATTR_ICMP] = { .len = sizeof(struct ovs_key_icmp) },
43481bfe3c3SThomas Graf [OVS_KEY_ATTR_ICMPV6] = { .len = sizeof(struct ovs_key_icmpv6) },
43581bfe3c3SThomas Graf [OVS_KEY_ATTR_ARP] = { .len = sizeof(struct ovs_key_arp) },
43681bfe3c3SThomas Graf [OVS_KEY_ATTR_ND] = { .len = sizeof(struct ovs_key_nd) },
43781bfe3c3SThomas Graf [OVS_KEY_ATTR_RECIRC_ID] = { .len = sizeof(u32) },
43881bfe3c3SThomas Graf [OVS_KEY_ATTR_DP_HASH] = { .len = sizeof(u32) },
43981bfe3c3SThomas Graf [OVS_KEY_ATTR_TUNNEL] = { .len = OVS_ATTR_NESTED,
44081bfe3c3SThomas Graf .next = ovs_tunnel_key_lens, },
441fbdcdd78SMartin Varghese [OVS_KEY_ATTR_MPLS] = { .len = OVS_ATTR_VARIABLE },
442fbccce59SJoe Stringer [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u32) },
4437f8a436eSJoe Stringer [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) },
444182e3042SJoe Stringer [OVS_KEY_ATTR_CT_MARK] = { .len = sizeof(u32) },
44533db4125SJoe Stringer [OVS_KEY_ATTR_CT_LABELS] = { .len = sizeof(struct ovs_key_ct_labels) },
4469dd7f890SJarno Rajahalme [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4] = {
4479dd7f890SJarno Rajahalme .len = sizeof(struct ovs_key_ct_tuple_ipv4) },
4489dd7f890SJarno Rajahalme [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6] = {
4499dd7f890SJarno Rajahalme .len = sizeof(struct ovs_key_ct_tuple_ipv6) },
450b2d0f5d5SYi Yang [OVS_KEY_ATTR_NSH] = { .len = OVS_ATTR_NESTED,
451b2d0f5d5SYi Yang .next = ovs_nsh_key_attr_lens, },
45228a3f060SToms Atteka [OVS_KEY_ATTR_IPV6_EXTHDRS] = {
45328a3f060SToms Atteka .len = sizeof(struct ovs_key_ipv6_exthdrs) },
454e6445719SPravin B Shelar };
455e6445719SPravin B Shelar
check_attr_len(unsigned int attr_len,unsigned int expected_len)456982b5270SJesse Gross static bool check_attr_len(unsigned int attr_len, unsigned int expected_len)
457982b5270SJesse Gross {
458982b5270SJesse Gross return expected_len == attr_len ||
459982b5270SJesse Gross expected_len == OVS_ATTR_NESTED ||
460982b5270SJesse Gross expected_len == OVS_ATTR_VARIABLE;
461982b5270SJesse Gross }
462982b5270SJesse Gross
is_all_zero(const u8 * fp,size_t size)463e6445719SPravin B Shelar static bool is_all_zero(const u8 *fp, size_t size)
464e6445719SPravin B Shelar {
465e6445719SPravin B Shelar int i;
466e6445719SPravin B Shelar
467e6445719SPravin B Shelar if (!fp)
468e6445719SPravin B Shelar return false;
469e6445719SPravin B Shelar
470e6445719SPravin B Shelar for (i = 0; i < size; i++)
471e6445719SPravin B Shelar if (fp[i])
472e6445719SPravin B Shelar return false;
473e6445719SPravin B Shelar
474e6445719SPravin B Shelar return true;
475e6445719SPravin B Shelar }
476e6445719SPravin B Shelar
__parse_flow_nlattrs(const struct nlattr * attr,const struct nlattr * a[],u64 * attrsp,bool log,bool nz)477e6445719SPravin B Shelar static int __parse_flow_nlattrs(const struct nlattr *attr,
478e6445719SPravin B Shelar const struct nlattr *a[],
47905da5898SJarno Rajahalme u64 *attrsp, bool log, bool nz)
480e6445719SPravin B Shelar {
481e6445719SPravin B Shelar const struct nlattr *nla;
482e6445719SPravin B Shelar u64 attrs;
483e6445719SPravin B Shelar int rem;
484e6445719SPravin B Shelar
485e6445719SPravin B Shelar attrs = *attrsp;
486e6445719SPravin B Shelar nla_for_each_nested(nla, attr, rem) {
487e6445719SPravin B Shelar u16 type = nla_type(nla);
488e6445719SPravin B Shelar int expected_len;
489e6445719SPravin B Shelar
490e6445719SPravin B Shelar if (type > OVS_KEY_ATTR_MAX) {
49105da5898SJarno Rajahalme OVS_NLERR(log, "Key type %d is out of range max %d",
492e6445719SPravin B Shelar type, OVS_KEY_ATTR_MAX);
493e6445719SPravin B Shelar return -EINVAL;
494e6445719SPravin B Shelar }
495e6445719SPravin B Shelar
4961926407aSIlya Maximets if (type == OVS_KEY_ATTR_PACKET_TYPE ||
4971926407aSIlya Maximets type == OVS_KEY_ATTR_ND_EXTENSIONS ||
4981926407aSIlya Maximets type == OVS_KEY_ATTR_TUNNEL_INFO) {
4991926407aSIlya Maximets OVS_NLERR(log, "Key type %d is not supported", type);
5001926407aSIlya Maximets return -EINVAL;
5011926407aSIlya Maximets }
5021926407aSIlya Maximets
5031926407aSIlya Maximets if (attrs & (1ULL << type)) {
50405da5898SJarno Rajahalme OVS_NLERR(log, "Duplicate key (type %d).", type);
505e6445719SPravin B Shelar return -EINVAL;
506e6445719SPravin B Shelar }
507e6445719SPravin B Shelar
50881bfe3c3SThomas Graf expected_len = ovs_key_lens[type].len;
509982b5270SJesse Gross if (!check_attr_len(nla_len(nla), expected_len)) {
51005da5898SJarno Rajahalme OVS_NLERR(log, "Key %d has unexpected len %d expected %d",
51105da5898SJarno Rajahalme type, nla_len(nla), expected_len);
512e6445719SPravin B Shelar return -EINVAL;
513e6445719SPravin B Shelar }
514e6445719SPravin B Shelar
51504a4af33SRoss Lagerwall if (!nz || !is_all_zero(nla_data(nla), nla_len(nla))) {
5161926407aSIlya Maximets attrs |= 1ULL << type;
517e6445719SPravin B Shelar a[type] = nla;
518e6445719SPravin B Shelar }
519e6445719SPravin B Shelar }
520e6445719SPravin B Shelar if (rem) {
52105da5898SJarno Rajahalme OVS_NLERR(log, "Message has %d unknown bytes.", rem);
522e6445719SPravin B Shelar return -EINVAL;
523e6445719SPravin B Shelar }
524e6445719SPravin B Shelar
525e6445719SPravin B Shelar *attrsp = attrs;
526e6445719SPravin B Shelar return 0;
527e6445719SPravin B Shelar }
528e6445719SPravin B Shelar
parse_flow_mask_nlattrs(const struct nlattr * attr,const struct nlattr * a[],u64 * attrsp,bool log)529e6445719SPravin B Shelar static int parse_flow_mask_nlattrs(const struct nlattr *attr,
53005da5898SJarno Rajahalme const struct nlattr *a[], u64 *attrsp,
53105da5898SJarno Rajahalme bool log)
532e6445719SPravin B Shelar {
53305da5898SJarno Rajahalme return __parse_flow_nlattrs(attr, a, attrsp, log, true);
534e6445719SPravin B Shelar }
535e6445719SPravin B Shelar
parse_flow_nlattrs(const struct nlattr * attr,const struct nlattr * a[],u64 * attrsp,bool log)5369dd7f890SJarno Rajahalme int parse_flow_nlattrs(const struct nlattr *attr, const struct nlattr *a[],
5379dd7f890SJarno Rajahalme u64 *attrsp, bool log)
538e6445719SPravin B Shelar {
53905da5898SJarno Rajahalme return __parse_flow_nlattrs(attr, a, attrsp, log, false);
54005da5898SJarno Rajahalme }
54105da5898SJarno Rajahalme
genev_tun_opt_from_nlattr(const struct nlattr * a,struct sw_flow_match * match,bool is_mask,bool log)54205da5898SJarno Rajahalme static int genev_tun_opt_from_nlattr(const struct nlattr *a,
54305da5898SJarno Rajahalme struct sw_flow_match *match, bool is_mask,
54405da5898SJarno Rajahalme bool log)
54505da5898SJarno Rajahalme {
54605da5898SJarno Rajahalme unsigned long opt_key_offset;
54705da5898SJarno Rajahalme
54805da5898SJarno Rajahalme if (nla_len(a) > sizeof(match->key->tun_opts)) {
54905da5898SJarno Rajahalme OVS_NLERR(log, "Geneve option length err (len %d, max %zu).",
55005da5898SJarno Rajahalme nla_len(a), sizeof(match->key->tun_opts));
55105da5898SJarno Rajahalme return -EINVAL;
55205da5898SJarno Rajahalme }
55305da5898SJarno Rajahalme
55405da5898SJarno Rajahalme if (nla_len(a) % 4 != 0) {
55505da5898SJarno Rajahalme OVS_NLERR(log, "Geneve opt len %d is not a multiple of 4.",
55605da5898SJarno Rajahalme nla_len(a));
55705da5898SJarno Rajahalme return -EINVAL;
55805da5898SJarno Rajahalme }
55905da5898SJarno Rajahalme
56005da5898SJarno Rajahalme /* We need to record the length of the options passed
56105da5898SJarno Rajahalme * down, otherwise packets with the same format but
56205da5898SJarno Rajahalme * additional options will be silently matched.
56305da5898SJarno Rajahalme */
56405da5898SJarno Rajahalme if (!is_mask) {
56505da5898SJarno Rajahalme SW_FLOW_KEY_PUT(match, tun_opts_len, nla_len(a),
56605da5898SJarno Rajahalme false);
56705da5898SJarno Rajahalme } else {
56805da5898SJarno Rajahalme /* This is somewhat unusual because it looks at
56905da5898SJarno Rajahalme * both the key and mask while parsing the
57005da5898SJarno Rajahalme * attributes (and by extension assumes the key
57105da5898SJarno Rajahalme * is parsed first). Normally, we would verify
57205da5898SJarno Rajahalme * that each is the correct length and that the
57305da5898SJarno Rajahalme * attributes line up in the validate function.
57405da5898SJarno Rajahalme * However, that is difficult because this is
57505da5898SJarno Rajahalme * variable length and we won't have the
57605da5898SJarno Rajahalme * information later.
57705da5898SJarno Rajahalme */
57805da5898SJarno Rajahalme if (match->key->tun_opts_len != nla_len(a)) {
57905da5898SJarno Rajahalme OVS_NLERR(log, "Geneve option len %d != mask len %d",
58005da5898SJarno Rajahalme match->key->tun_opts_len, nla_len(a));
58105da5898SJarno Rajahalme return -EINVAL;
58205da5898SJarno Rajahalme }
58305da5898SJarno Rajahalme
58405da5898SJarno Rajahalme SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
58505da5898SJarno Rajahalme }
58605da5898SJarno Rajahalme
587d91641d9SThomas Graf opt_key_offset = TUN_METADATA_OFFSET(nla_len(a));
58805da5898SJarno Rajahalme SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, nla_data(a),
58905da5898SJarno Rajahalme nla_len(a), is_mask);
59005da5898SJarno Rajahalme return 0;
591e6445719SPravin B Shelar }
592e6445719SPravin B Shelar
vxlan_tun_opt_from_nlattr(const struct nlattr * attr,struct sw_flow_match * match,bool is_mask,bool log)593982b5270SJesse Gross static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr,
5941dd144cfSThomas Graf struct sw_flow_match *match, bool is_mask,
5951dd144cfSThomas Graf bool log)
5961dd144cfSThomas Graf {
597982b5270SJesse Gross struct nlattr *a;
598982b5270SJesse Gross int rem;
5991dd144cfSThomas Graf unsigned long opt_key_offset;
600614732eaSThomas Graf struct vxlan_metadata opts;
6011dd144cfSThomas Graf
6021dd144cfSThomas Graf BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts));
6031dd144cfSThomas Graf
6041dd144cfSThomas Graf memset(&opts, 0, sizeof(opts));
605982b5270SJesse Gross nla_for_each_nested(a, attr, rem) {
606982b5270SJesse Gross int type = nla_type(a);
6071dd144cfSThomas Graf
608982b5270SJesse Gross if (type > OVS_VXLAN_EXT_MAX) {
609982b5270SJesse Gross OVS_NLERR(log, "VXLAN extension %d out of range max %d",
610982b5270SJesse Gross type, OVS_VXLAN_EXT_MAX);
611982b5270SJesse Gross return -EINVAL;
612982b5270SJesse Gross }
613982b5270SJesse Gross
614982b5270SJesse Gross if (!check_attr_len(nla_len(a),
615982b5270SJesse Gross ovs_vxlan_ext_key_lens[type].len)) {
616982b5270SJesse Gross OVS_NLERR(log, "VXLAN extension %d has unexpected len %d expected %d",
617982b5270SJesse Gross type, nla_len(a),
618982b5270SJesse Gross ovs_vxlan_ext_key_lens[type].len);
619982b5270SJesse Gross return -EINVAL;
620982b5270SJesse Gross }
621982b5270SJesse Gross
622982b5270SJesse Gross switch (type) {
623982b5270SJesse Gross case OVS_VXLAN_EXT_GBP:
624982b5270SJesse Gross opts.gbp = nla_get_u32(a);
625982b5270SJesse Gross break;
626982b5270SJesse Gross default:
627982b5270SJesse Gross OVS_NLERR(log, "Unknown VXLAN extension attribute %d",
628982b5270SJesse Gross type);
629982b5270SJesse Gross return -EINVAL;
630982b5270SJesse Gross }
631982b5270SJesse Gross }
632982b5270SJesse Gross if (rem) {
633982b5270SJesse Gross OVS_NLERR(log, "VXLAN extension message has %d unknown bytes.",
634982b5270SJesse Gross rem);
635982b5270SJesse Gross return -EINVAL;
636982b5270SJesse Gross }
6371dd144cfSThomas Graf
6381dd144cfSThomas Graf if (!is_mask)
6391dd144cfSThomas Graf SW_FLOW_KEY_PUT(match, tun_opts_len, sizeof(opts), false);
6401dd144cfSThomas Graf else
6411dd144cfSThomas Graf SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
6421dd144cfSThomas Graf
6431dd144cfSThomas Graf opt_key_offset = TUN_METADATA_OFFSET(sizeof(opts));
6441dd144cfSThomas Graf SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, &opts, sizeof(opts),
6451dd144cfSThomas Graf is_mask);
6461dd144cfSThomas Graf return 0;
6471dd144cfSThomas Graf }
6481dd144cfSThomas Graf
erspan_tun_opt_from_nlattr(const struct nlattr * a,struct sw_flow_match * match,bool is_mask,bool log)649fc1372f8SWilliam Tu static int erspan_tun_opt_from_nlattr(const struct nlattr *a,
650fc1372f8SWilliam Tu struct sw_flow_match *match, bool is_mask,
651fc1372f8SWilliam Tu bool log)
652fc1372f8SWilliam Tu {
653fc1372f8SWilliam Tu unsigned long opt_key_offset;
654fc1372f8SWilliam Tu
655fc1372f8SWilliam Tu BUILD_BUG_ON(sizeof(struct erspan_metadata) >
656fc1372f8SWilliam Tu sizeof(match->key->tun_opts));
657fc1372f8SWilliam Tu
658fc1372f8SWilliam Tu if (nla_len(a) > sizeof(match->key->tun_opts)) {
659fc1372f8SWilliam Tu OVS_NLERR(log, "ERSPAN option length err (len %d, max %zu).",
660fc1372f8SWilliam Tu nla_len(a), sizeof(match->key->tun_opts));
661fc1372f8SWilliam Tu return -EINVAL;
662fc1372f8SWilliam Tu }
663fc1372f8SWilliam Tu
664fc1372f8SWilliam Tu if (!is_mask)
665fc1372f8SWilliam Tu SW_FLOW_KEY_PUT(match, tun_opts_len,
666fc1372f8SWilliam Tu sizeof(struct erspan_metadata), false);
667fc1372f8SWilliam Tu else
668fc1372f8SWilliam Tu SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true);
669fc1372f8SWilliam Tu
670fc1372f8SWilliam Tu opt_key_offset = TUN_METADATA_OFFSET(nla_len(a));
671fc1372f8SWilliam Tu SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, nla_data(a),
672fc1372f8SWilliam Tu nla_len(a), is_mask);
673fc1372f8SWilliam Tu return 0;
674fc1372f8SWilliam Tu }
675fc1372f8SWilliam Tu
ip_tun_from_nlattr(const struct nlattr * attr,struct sw_flow_match * match,bool is_mask,bool log)6766b26ba3aSJiri Benc static int ip_tun_from_nlattr(const struct nlattr *attr,
67705da5898SJarno Rajahalme struct sw_flow_match *match, bool is_mask,
67805da5898SJarno Rajahalme bool log)
679e6445719SPravin B Shelar {
68099e28f18SPravin B Shelar bool ttl = false, ipv4 = false, ipv6 = false;
6815832c4a7SAlexander Lobakin IP_TUNNEL_DECLARE_FLAGS(tun_flags) = { };
68218b6f717Swenxu bool info_bridge_mode = false;
68399e28f18SPravin B Shelar int opts_type = 0;
684e6445719SPravin B Shelar struct nlattr *a;
685e6445719SPravin B Shelar int rem;
686e6445719SPravin B Shelar
687e6445719SPravin B Shelar nla_for_each_nested(a, attr, rem) {
688e6445719SPravin B Shelar int type = nla_type(a);
68905da5898SJarno Rajahalme int err;
69005da5898SJarno Rajahalme
691e6445719SPravin B Shelar if (type > OVS_TUNNEL_KEY_ATTR_MAX) {
69205da5898SJarno Rajahalme OVS_NLERR(log, "Tunnel attr %d out of range max %d",
693e6445719SPravin B Shelar type, OVS_TUNNEL_KEY_ATTR_MAX);
694e6445719SPravin B Shelar return -EINVAL;
695e6445719SPravin B Shelar }
696e6445719SPravin B Shelar
697982b5270SJesse Gross if (!check_attr_len(nla_len(a),
698982b5270SJesse Gross ovs_tunnel_key_lens[type].len)) {
69905da5898SJarno Rajahalme OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d",
70081bfe3c3SThomas Graf type, nla_len(a), ovs_tunnel_key_lens[type].len);
701e6445719SPravin B Shelar return -EINVAL;
702e6445719SPravin B Shelar }
703e6445719SPravin B Shelar
704e6445719SPravin B Shelar switch (type) {
705e6445719SPravin B Shelar case OVS_TUNNEL_KEY_ATTR_ID:
706e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, tun_key.tun_id,
707e6445719SPravin B Shelar nla_get_be64(a), is_mask);
7085832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_KEY_BIT, tun_flags);
709e6445719SPravin B Shelar break;
710e6445719SPravin B Shelar case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
711c1ea5d67SJiri Benc SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.src,
71267b61f6cSJiri Benc nla_get_in_addr(a), is_mask);
7136b26ba3aSJiri Benc ipv4 = true;
714e6445719SPravin B Shelar break;
715e6445719SPravin B Shelar case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
716c1ea5d67SJiri Benc SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.dst,
71767b61f6cSJiri Benc nla_get_in_addr(a), is_mask);
7186b26ba3aSJiri Benc ipv4 = true;
7196b26ba3aSJiri Benc break;
7206b26ba3aSJiri Benc case OVS_TUNNEL_KEY_ATTR_IPV6_SRC:
7213d20f1f7SOr Gerlitz SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.src,
7226b26ba3aSJiri Benc nla_get_in6_addr(a), is_mask);
7236b26ba3aSJiri Benc ipv6 = true;
7246b26ba3aSJiri Benc break;
7256b26ba3aSJiri Benc case OVS_TUNNEL_KEY_ATTR_IPV6_DST:
7266b26ba3aSJiri Benc SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.dst,
7276b26ba3aSJiri Benc nla_get_in6_addr(a), is_mask);
7286b26ba3aSJiri Benc ipv6 = true;
729e6445719SPravin B Shelar break;
730e6445719SPravin B Shelar case OVS_TUNNEL_KEY_ATTR_TOS:
7317c383fb2SJiri Benc SW_FLOW_KEY_PUT(match, tun_key.tos,
732e6445719SPravin B Shelar nla_get_u8(a), is_mask);
733e6445719SPravin B Shelar break;
734e6445719SPravin B Shelar case OVS_TUNNEL_KEY_ATTR_TTL:
7357c383fb2SJiri Benc SW_FLOW_KEY_PUT(match, tun_key.ttl,
736e6445719SPravin B Shelar nla_get_u8(a), is_mask);
737e6445719SPravin B Shelar ttl = true;
738e6445719SPravin B Shelar break;
739e6445719SPravin B Shelar case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
7405832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_DONT_FRAGMENT_BIT, tun_flags);
741e6445719SPravin B Shelar break;
742e6445719SPravin B Shelar case OVS_TUNNEL_KEY_ATTR_CSUM:
7435832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_CSUM_BIT, tun_flags);
744e6445719SPravin B Shelar break;
7458f0aad6fSWenyu Zhang case OVS_TUNNEL_KEY_ATTR_TP_SRC:
7468f0aad6fSWenyu Zhang SW_FLOW_KEY_PUT(match, tun_key.tp_src,
7478f0aad6fSWenyu Zhang nla_get_be16(a), is_mask);
7488f0aad6fSWenyu Zhang break;
7498f0aad6fSWenyu Zhang case OVS_TUNNEL_KEY_ATTR_TP_DST:
7508f0aad6fSWenyu Zhang SW_FLOW_KEY_PUT(match, tun_key.tp_dst,
7518f0aad6fSWenyu Zhang nla_get_be16(a), is_mask);
7528f0aad6fSWenyu Zhang break;
75367fa0341SJesse Gross case OVS_TUNNEL_KEY_ATTR_OAM:
7545832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_OAM_BIT, tun_flags);
75567fa0341SJesse Gross break;
756f5796684SJesse Gross case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
7571dd144cfSThomas Graf if (opts_type) {
7581dd144cfSThomas Graf OVS_NLERR(log, "Multiple metadata blocks provided");
7591dd144cfSThomas Graf return -EINVAL;
7601dd144cfSThomas Graf }
7611dd144cfSThomas Graf
76205da5898SJarno Rajahalme err = genev_tun_opt_from_nlattr(a, match, is_mask, log);
76305da5898SJarno Rajahalme if (err)
76405da5898SJarno Rajahalme return err;
76505da5898SJarno Rajahalme
7665832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_GENEVE_OPT_BIT, tun_flags);
7671dd144cfSThomas Graf opts_type = type;
7681dd144cfSThomas Graf break;
7691dd144cfSThomas Graf case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
7701dd144cfSThomas Graf if (opts_type) {
7711dd144cfSThomas Graf OVS_NLERR(log, "Multiple metadata blocks provided");
7721dd144cfSThomas Graf return -EINVAL;
7731dd144cfSThomas Graf }
7741dd144cfSThomas Graf
7751dd144cfSThomas Graf err = vxlan_tun_opt_from_nlattr(a, match, is_mask, log);
7761dd144cfSThomas Graf if (err)
7771dd144cfSThomas Graf return err;
7781dd144cfSThomas Graf
7795832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_VXLAN_OPT_BIT, tun_flags);
7801dd144cfSThomas Graf opts_type = type;
781f5796684SJesse Gross break;
7828f3dbfd7SKris Murphy case OVS_TUNNEL_KEY_ATTR_PAD:
7838f3dbfd7SKris Murphy break;
784fc1372f8SWilliam Tu case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS:
785fc1372f8SWilliam Tu if (opts_type) {
786fc1372f8SWilliam Tu OVS_NLERR(log, "Multiple metadata blocks provided");
787fc1372f8SWilliam Tu return -EINVAL;
788fc1372f8SWilliam Tu }
789fc1372f8SWilliam Tu
790fc1372f8SWilliam Tu err = erspan_tun_opt_from_nlattr(a, match, is_mask,
791fc1372f8SWilliam Tu log);
792fc1372f8SWilliam Tu if (err)
793fc1372f8SWilliam Tu return err;
794fc1372f8SWilliam Tu
7955832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, tun_flags);
796fc1372f8SWilliam Tu opts_type = type;
797fc1372f8SWilliam Tu break;
79818b6f717Swenxu case OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE:
79918b6f717Swenxu info_bridge_mode = true;
80018b6f717Swenxu ipv4 = true;
80118b6f717Swenxu break;
802e6445719SPravin B Shelar default:
8036b26ba3aSJiri Benc OVS_NLERR(log, "Unknown IP tunnel attribute %d",
804f5796684SJesse Gross type);
805e6445719SPravin B Shelar return -EINVAL;
806e6445719SPravin B Shelar }
807e6445719SPravin B Shelar }
808e6445719SPravin B Shelar
8095832c4a7SAlexander Lobakin SW_FLOW_KEY_BITMAP_COPY(match, tun_key.tun_flags, tun_flags,
8105832c4a7SAlexander Lobakin __IP_TUNNEL_FLAG_NUM, is_mask);
81100a93babSJiri Benc if (is_mask)
81200a93babSJiri Benc SW_FLOW_KEY_MEMSET_FIELD(match, tun_proto, 0xff, true);
81300a93babSJiri Benc else
8146b26ba3aSJiri Benc SW_FLOW_KEY_PUT(match, tun_proto, ipv6 ? AF_INET6 : AF_INET,
8156b26ba3aSJiri Benc false);
816e6445719SPravin B Shelar
817e6445719SPravin B Shelar if (rem > 0) {
8186b26ba3aSJiri Benc OVS_NLERR(log, "IP tunnel attribute has %d unknown bytes.",
81905da5898SJarno Rajahalme rem);
820e6445719SPravin B Shelar return -EINVAL;
821e6445719SPravin B Shelar }
822e6445719SPravin B Shelar
8236b26ba3aSJiri Benc if (ipv4 && ipv6) {
8246b26ba3aSJiri Benc OVS_NLERR(log, "Mixed IPv4 and IPv6 tunnel attributes");
8256b26ba3aSJiri Benc return -EINVAL;
8266b26ba3aSJiri Benc }
8276b26ba3aSJiri Benc
828e6445719SPravin B Shelar if (!is_mask) {
8296b26ba3aSJiri Benc if (!ipv4 && !ipv6) {
8306b26ba3aSJiri Benc OVS_NLERR(log, "IP tunnel dst address not specified");
8316b26ba3aSJiri Benc return -EINVAL;
8326b26ba3aSJiri Benc }
83318b6f717Swenxu if (ipv4) {
83418b6f717Swenxu if (info_bridge_mode) {
8355832c4a7SAlexander Lobakin __clear_bit(IP_TUNNEL_KEY_BIT, tun_flags);
8365832c4a7SAlexander Lobakin
83718b6f717Swenxu if (match->key->tun_key.u.ipv4.src ||
83818b6f717Swenxu match->key->tun_key.u.ipv4.dst ||
83918b6f717Swenxu match->key->tun_key.tp_src ||
84018b6f717Swenxu match->key->tun_key.tp_dst ||
84118b6f717Swenxu match->key->tun_key.ttl ||
84218b6f717Swenxu match->key->tun_key.tos ||
8435832c4a7SAlexander Lobakin !ip_tunnel_flags_empty(tun_flags)) {
84418b6f717Swenxu OVS_NLERR(log, "IPv4 tun info is not correct");
84518b6f717Swenxu return -EINVAL;
84618b6f717Swenxu }
84718b6f717Swenxu } else if (!match->key->tun_key.u.ipv4.dst) {
84805da5898SJarno Rajahalme OVS_NLERR(log, "IPv4 tunnel dst address is zero");
849e6445719SPravin B Shelar return -EINVAL;
850e6445719SPravin B Shelar }
85118b6f717Swenxu }
8526b26ba3aSJiri Benc if (ipv6 && ipv6_addr_any(&match->key->tun_key.u.ipv6.dst)) {
8536b26ba3aSJiri Benc OVS_NLERR(log, "IPv6 tunnel dst address is zero");
8546b26ba3aSJiri Benc return -EINVAL;
8556b26ba3aSJiri Benc }
856e6445719SPravin B Shelar
85718b6f717Swenxu if (!ttl && !info_bridge_mode) {
8586b26ba3aSJiri Benc OVS_NLERR(log, "IP tunnel TTL not specified.");
859e6445719SPravin B Shelar return -EINVAL;
860e6445719SPravin B Shelar }
861e6445719SPravin B Shelar }
862e6445719SPravin B Shelar
8631dd144cfSThomas Graf return opts_type;
8641dd144cfSThomas Graf }
8651dd144cfSThomas Graf
vxlan_opt_to_nlattr(struct sk_buff * skb,const void * tun_opts,int swkey_tun_opts_len)8661dd144cfSThomas Graf static int vxlan_opt_to_nlattr(struct sk_buff *skb,
8671dd144cfSThomas Graf const void *tun_opts, int swkey_tun_opts_len)
8681dd144cfSThomas Graf {
869614732eaSThomas Graf const struct vxlan_metadata *opts = tun_opts;
8701dd144cfSThomas Graf struct nlattr *nla;
8711dd144cfSThomas Graf
872ae0be8deSMichal Kubecek nla = nla_nest_start_noflag(skb, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
8731dd144cfSThomas Graf if (!nla)
8741dd144cfSThomas Graf return -EMSGSIZE;
8751dd144cfSThomas Graf
8761dd144cfSThomas Graf if (nla_put_u32(skb, OVS_VXLAN_EXT_GBP, opts->gbp) < 0)
8771dd144cfSThomas Graf return -EMSGSIZE;
8781dd144cfSThomas Graf
8791dd144cfSThomas Graf nla_nest_end(skb, nla);
880e6445719SPravin B Shelar return 0;
881e6445719SPravin B Shelar }
882e6445719SPravin B Shelar
__ip_tun_to_nlattr(struct sk_buff * skb,const struct ip_tunnel_key * output,const void * tun_opts,int swkey_tun_opts_len,unsigned short tun_proto,u8 mode)8836b26ba3aSJiri Benc static int __ip_tun_to_nlattr(struct sk_buff *skb,
8841d8fff90SThomas Graf const struct ip_tunnel_key *output,
8856b26ba3aSJiri Benc const void *tun_opts, int swkey_tun_opts_len,
88618b6f717Swenxu unsigned short tun_proto, u8 mode)
887e6445719SPravin B Shelar {
8885832c4a7SAlexander Lobakin if (test_bit(IP_TUNNEL_KEY_BIT, output->tun_flags) &&
889b46f6dedSNicolas Dichtel nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id,
890b46f6dedSNicolas Dichtel OVS_TUNNEL_KEY_ATTR_PAD))
891e6445719SPravin B Shelar return -EMSGSIZE;
89218b6f717Swenxu
89318b6f717Swenxu if (mode & IP_TUNNEL_INFO_BRIDGE)
89418b6f717Swenxu return nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE)
89518b6f717Swenxu ? -EMSGSIZE : 0;
89618b6f717Swenxu
8976b26ba3aSJiri Benc switch (tun_proto) {
8986b26ba3aSJiri Benc case AF_INET:
899c1ea5d67SJiri Benc if (output->u.ipv4.src &&
900930345eaSJiri Benc nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC,
901c1ea5d67SJiri Benc output->u.ipv4.src))
902e6445719SPravin B Shelar return -EMSGSIZE;
903c1ea5d67SJiri Benc if (output->u.ipv4.dst &&
904930345eaSJiri Benc nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST,
905c1ea5d67SJiri Benc output->u.ipv4.dst))
906e6445719SPravin B Shelar return -EMSGSIZE;
9076b26ba3aSJiri Benc break;
9086b26ba3aSJiri Benc case AF_INET6:
9096b26ba3aSJiri Benc if (!ipv6_addr_any(&output->u.ipv6.src) &&
9106b26ba3aSJiri Benc nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_SRC,
9116b26ba3aSJiri Benc &output->u.ipv6.src))
9126b26ba3aSJiri Benc return -EMSGSIZE;
9136b26ba3aSJiri Benc if (!ipv6_addr_any(&output->u.ipv6.dst) &&
9146b26ba3aSJiri Benc nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_DST,
9156b26ba3aSJiri Benc &output->u.ipv6.dst))
9166b26ba3aSJiri Benc return -EMSGSIZE;
9176b26ba3aSJiri Benc break;
9186b26ba3aSJiri Benc }
9197c383fb2SJiri Benc if (output->tos &&
9207c383fb2SJiri Benc nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->tos))
921e6445719SPravin B Shelar return -EMSGSIZE;
9227c383fb2SJiri Benc if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, output->ttl))
923e6445719SPravin B Shelar return -EMSGSIZE;
9245832c4a7SAlexander Lobakin if (test_bit(IP_TUNNEL_DONT_FRAGMENT_BIT, output->tun_flags) &&
925e6445719SPravin B Shelar nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT))
926e6445719SPravin B Shelar return -EMSGSIZE;
9275832c4a7SAlexander Lobakin if (test_bit(IP_TUNNEL_CSUM_BIT, output->tun_flags) &&
928e6445719SPravin B Shelar nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM))
929e6445719SPravin B Shelar return -EMSGSIZE;
9308f0aad6fSWenyu Zhang if (output->tp_src &&
9318f0aad6fSWenyu Zhang nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_SRC, output->tp_src))
9328f0aad6fSWenyu Zhang return -EMSGSIZE;
9338f0aad6fSWenyu Zhang if (output->tp_dst &&
9348f0aad6fSWenyu Zhang nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_DST, output->tp_dst))
9358f0aad6fSWenyu Zhang return -EMSGSIZE;
9365832c4a7SAlexander Lobakin if (test_bit(IP_TUNNEL_OAM_BIT, output->tun_flags) &&
93767fa0341SJesse Gross nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
93867fa0341SJesse Gross return -EMSGSIZE;
939fc4099f1SPravin B Shelar if (swkey_tun_opts_len) {
9405832c4a7SAlexander Lobakin if (test_bit(IP_TUNNEL_GENEVE_OPT_BIT, output->tun_flags) &&
941f5796684SJesse Gross nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
942f5796684SJesse Gross swkey_tun_opts_len, tun_opts))
943f5796684SJesse Gross return -EMSGSIZE;
9445832c4a7SAlexander Lobakin else if (test_bit(IP_TUNNEL_VXLAN_OPT_BIT,
9455832c4a7SAlexander Lobakin output->tun_flags) &&
9461dd144cfSThomas Graf vxlan_opt_to_nlattr(skb, tun_opts, swkey_tun_opts_len))
9471dd144cfSThomas Graf return -EMSGSIZE;
9485832c4a7SAlexander Lobakin else if (test_bit(IP_TUNNEL_ERSPAN_OPT_BIT,
9495832c4a7SAlexander Lobakin output->tun_flags) &&
950fc1372f8SWilliam Tu nla_put(skb, OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS,
951fc1372f8SWilliam Tu swkey_tun_opts_len, tun_opts))
952fc1372f8SWilliam Tu return -EMSGSIZE;
9531dd144cfSThomas Graf }
954f5796684SJesse Gross
955f5796684SJesse Gross return 0;
956f5796684SJesse Gross }
957f5796684SJesse Gross
ip_tun_to_nlattr(struct sk_buff * skb,const struct ip_tunnel_key * output,const void * tun_opts,int swkey_tun_opts_len,unsigned short tun_proto,u8 mode)9586b26ba3aSJiri Benc static int ip_tun_to_nlattr(struct sk_buff *skb,
9591d8fff90SThomas Graf const struct ip_tunnel_key *output,
9606b26ba3aSJiri Benc const void *tun_opts, int swkey_tun_opts_len,
96118b6f717Swenxu unsigned short tun_proto, u8 mode)
962f5796684SJesse Gross {
963f5796684SJesse Gross struct nlattr *nla;
964f5796684SJesse Gross int err;
965f5796684SJesse Gross
966ae0be8deSMichal Kubecek nla = nla_nest_start_noflag(skb, OVS_KEY_ATTR_TUNNEL);
967f5796684SJesse Gross if (!nla)
968f5796684SJesse Gross return -EMSGSIZE;
969f5796684SJesse Gross
9706b26ba3aSJiri Benc err = __ip_tun_to_nlattr(skb, output, tun_opts, swkey_tun_opts_len,
97118b6f717Swenxu tun_proto, mode);
972f5796684SJesse Gross if (err)
973f5796684SJesse Gross return err;
974e6445719SPravin B Shelar
975e6445719SPravin B Shelar nla_nest_end(skb, nla);
976e6445719SPravin B Shelar return 0;
977e6445719SPravin B Shelar }
978e6445719SPravin B Shelar
ovs_nla_put_tunnel_info(struct sk_buff * skb,struct ip_tunnel_info * tun_info)979fc4099f1SPravin B Shelar int ovs_nla_put_tunnel_info(struct sk_buff *skb,
980fc4099f1SPravin B Shelar struct ip_tunnel_info *tun_info)
9818f0aad6fSWenyu Zhang {
982ba3e2084SDavid S. Miller return __ip_tun_to_nlattr(skb, &tun_info->key,
983fc4099f1SPravin B Shelar ip_tunnel_info_opts(tun_info),
984ba3e2084SDavid S. Miller tun_info->options_len,
98518b6f717Swenxu ip_tunnel_info_af(tun_info), tun_info->mode);
9868f0aad6fSWenyu Zhang }
9878f0aad6fSWenyu Zhang
encode_vlan_from_nlattrs(struct sw_flow_match * match,const struct nlattr * a[],bool is_mask,bool inner)988018c1ddaSEric Garver static int encode_vlan_from_nlattrs(struct sw_flow_match *match,
989018c1ddaSEric Garver const struct nlattr *a[],
990018c1ddaSEric Garver bool is_mask, bool inner)
991018c1ddaSEric Garver {
992018c1ddaSEric Garver __be16 tci = 0;
993018c1ddaSEric Garver __be16 tpid = 0;
994018c1ddaSEric Garver
995018c1ddaSEric Garver if (a[OVS_KEY_ATTR_VLAN])
996018c1ddaSEric Garver tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
997018c1ddaSEric Garver
998018c1ddaSEric Garver if (a[OVS_KEY_ATTR_ETHERTYPE])
999018c1ddaSEric Garver tpid = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
1000018c1ddaSEric Garver
1001018c1ddaSEric Garver if (likely(!inner)) {
1002018c1ddaSEric Garver SW_FLOW_KEY_PUT(match, eth.vlan.tpid, tpid, is_mask);
1003018c1ddaSEric Garver SW_FLOW_KEY_PUT(match, eth.vlan.tci, tci, is_mask);
1004018c1ddaSEric Garver } else {
1005018c1ddaSEric Garver SW_FLOW_KEY_PUT(match, eth.cvlan.tpid, tpid, is_mask);
1006018c1ddaSEric Garver SW_FLOW_KEY_PUT(match, eth.cvlan.tci, tci, is_mask);
1007018c1ddaSEric Garver }
1008018c1ddaSEric Garver return 0;
1009018c1ddaSEric Garver }
1010018c1ddaSEric Garver
validate_vlan_from_nlattrs(const struct sw_flow_match * match,u64 key_attrs,bool inner,const struct nlattr ** a,bool log)1011018c1ddaSEric Garver static int validate_vlan_from_nlattrs(const struct sw_flow_match *match,
1012018c1ddaSEric Garver u64 key_attrs, bool inner,
1013018c1ddaSEric Garver const struct nlattr **a, bool log)
1014018c1ddaSEric Garver {
1015018c1ddaSEric Garver __be16 tci = 0;
1016018c1ddaSEric Garver
1017018c1ddaSEric Garver if (!((key_attrs & (1 << OVS_KEY_ATTR_ETHERNET)) &&
1018018c1ddaSEric Garver (key_attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) &&
1019018c1ddaSEric Garver eth_type_vlan(nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE])))) {
1020018c1ddaSEric Garver /* Not a VLAN. */
1021018c1ddaSEric Garver return 0;
1022018c1ddaSEric Garver }
1023018c1ddaSEric Garver
1024018c1ddaSEric Garver if (!((key_attrs & (1 << OVS_KEY_ATTR_VLAN)) &&
1025018c1ddaSEric Garver (key_attrs & (1 << OVS_KEY_ATTR_ENCAP)))) {
1026018c1ddaSEric Garver OVS_NLERR(log, "Invalid %s frame", (inner) ? "C-VLAN" : "VLAN");
1027018c1ddaSEric Garver return -EINVAL;
1028018c1ddaSEric Garver }
1029018c1ddaSEric Garver
1030018c1ddaSEric Garver if (a[OVS_KEY_ATTR_VLAN])
1031018c1ddaSEric Garver tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
1032018c1ddaSEric Garver
10339df46aefSMichał Mirosław if (!(tci & htons(VLAN_CFI_MASK))) {
1034018c1ddaSEric Garver if (tci) {
10359df46aefSMichał Mirosław OVS_NLERR(log, "%s TCI does not have VLAN_CFI_MASK bit set.",
1036018c1ddaSEric Garver (inner) ? "C-VLAN" : "VLAN");
1037018c1ddaSEric Garver return -EINVAL;
1038018c1ddaSEric Garver } else if (nla_len(a[OVS_KEY_ATTR_ENCAP])) {
1039018c1ddaSEric Garver /* Corner case for truncated VLAN header. */
1040018c1ddaSEric Garver OVS_NLERR(log, "Truncated %s header has non-zero encap attribute.",
1041018c1ddaSEric Garver (inner) ? "C-VLAN" : "VLAN");
1042018c1ddaSEric Garver return -EINVAL;
1043018c1ddaSEric Garver }
1044018c1ddaSEric Garver }
1045018c1ddaSEric Garver
1046018c1ddaSEric Garver return 1;
1047018c1ddaSEric Garver }
1048018c1ddaSEric Garver
validate_vlan_mask_from_nlattrs(const struct sw_flow_match * match,u64 key_attrs,bool inner,const struct nlattr ** a,bool log)1049018c1ddaSEric Garver static int validate_vlan_mask_from_nlattrs(const struct sw_flow_match *match,
1050018c1ddaSEric Garver u64 key_attrs, bool inner,
1051018c1ddaSEric Garver const struct nlattr **a, bool log)
1052018c1ddaSEric Garver {
1053018c1ddaSEric Garver __be16 tci = 0;
1054018c1ddaSEric Garver __be16 tpid = 0;
1055018c1ddaSEric Garver bool encap_valid = !!(match->key->eth.vlan.tci &
10569df46aefSMichał Mirosław htons(VLAN_CFI_MASK));
1057018c1ddaSEric Garver bool i_encap_valid = !!(match->key->eth.cvlan.tci &
10589df46aefSMichał Mirosław htons(VLAN_CFI_MASK));
1059018c1ddaSEric Garver
1060018c1ddaSEric Garver if (!(key_attrs & (1 << OVS_KEY_ATTR_ENCAP))) {
1061018c1ddaSEric Garver /* Not a VLAN. */
1062018c1ddaSEric Garver return 0;
1063018c1ddaSEric Garver }
1064018c1ddaSEric Garver
1065018c1ddaSEric Garver if ((!inner && !encap_valid) || (inner && !i_encap_valid)) {
1066018c1ddaSEric Garver OVS_NLERR(log, "Encap mask attribute is set for non-%s frame.",
1067018c1ddaSEric Garver (inner) ? "C-VLAN" : "VLAN");
1068018c1ddaSEric Garver return -EINVAL;
1069018c1ddaSEric Garver }
1070018c1ddaSEric Garver
1071018c1ddaSEric Garver if (a[OVS_KEY_ATTR_VLAN])
1072018c1ddaSEric Garver tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
1073018c1ddaSEric Garver
1074018c1ddaSEric Garver if (a[OVS_KEY_ATTR_ETHERTYPE])
1075018c1ddaSEric Garver tpid = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
1076018c1ddaSEric Garver
1077018c1ddaSEric Garver if (tpid != htons(0xffff)) {
1078018c1ddaSEric Garver OVS_NLERR(log, "Must have an exact match on %s TPID (mask=%x).",
1079018c1ddaSEric Garver (inner) ? "C-VLAN" : "VLAN", ntohs(tpid));
1080018c1ddaSEric Garver return -EINVAL;
1081018c1ddaSEric Garver }
10829df46aefSMichał Mirosław if (!(tci & htons(VLAN_CFI_MASK))) {
10839df46aefSMichał Mirosław OVS_NLERR(log, "%s TCI mask does not have exact match for VLAN_CFI_MASK bit.",
1084018c1ddaSEric Garver (inner) ? "C-VLAN" : "VLAN");
1085018c1ddaSEric Garver return -EINVAL;
1086018c1ddaSEric Garver }
1087018c1ddaSEric Garver
1088018c1ddaSEric Garver return 1;
1089018c1ddaSEric Garver }
1090018c1ddaSEric Garver
__parse_vlan_from_nlattrs(struct sw_flow_match * match,u64 * key_attrs,bool inner,const struct nlattr ** a,bool is_mask,bool log)1091018c1ddaSEric Garver static int __parse_vlan_from_nlattrs(struct sw_flow_match *match,
1092018c1ddaSEric Garver u64 *key_attrs, bool inner,
1093018c1ddaSEric Garver const struct nlattr **a, bool is_mask,
1094018c1ddaSEric Garver bool log)
1095018c1ddaSEric Garver {
1096018c1ddaSEric Garver int err;
1097018c1ddaSEric Garver const struct nlattr *encap;
1098018c1ddaSEric Garver
1099018c1ddaSEric Garver if (!is_mask)
1100018c1ddaSEric Garver err = validate_vlan_from_nlattrs(match, *key_attrs, inner,
1101018c1ddaSEric Garver a, log);
1102018c1ddaSEric Garver else
1103018c1ddaSEric Garver err = validate_vlan_mask_from_nlattrs(match, *key_attrs, inner,
1104018c1ddaSEric Garver a, log);
1105018c1ddaSEric Garver if (err <= 0)
1106018c1ddaSEric Garver return err;
1107018c1ddaSEric Garver
1108018c1ddaSEric Garver err = encode_vlan_from_nlattrs(match, a, is_mask, inner);
1109018c1ddaSEric Garver if (err)
1110018c1ddaSEric Garver return err;
1111018c1ddaSEric Garver
1112018c1ddaSEric Garver *key_attrs &= ~(1 << OVS_KEY_ATTR_ENCAP);
1113018c1ddaSEric Garver *key_attrs &= ~(1 << OVS_KEY_ATTR_VLAN);
1114018c1ddaSEric Garver *key_attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE);
1115018c1ddaSEric Garver
1116018c1ddaSEric Garver encap = a[OVS_KEY_ATTR_ENCAP];
1117018c1ddaSEric Garver
1118018c1ddaSEric Garver if (!is_mask)
1119018c1ddaSEric Garver err = parse_flow_nlattrs(encap, a, key_attrs, log);
1120018c1ddaSEric Garver else
1121018c1ddaSEric Garver err = parse_flow_mask_nlattrs(encap, a, key_attrs, log);
1122018c1ddaSEric Garver
1123018c1ddaSEric Garver return err;
1124018c1ddaSEric Garver }
1125018c1ddaSEric Garver
parse_vlan_from_nlattrs(struct sw_flow_match * match,u64 * key_attrs,const struct nlattr ** a,bool is_mask,bool log)1126018c1ddaSEric Garver static int parse_vlan_from_nlattrs(struct sw_flow_match *match,
1127018c1ddaSEric Garver u64 *key_attrs, const struct nlattr **a,
1128018c1ddaSEric Garver bool is_mask, bool log)
1129018c1ddaSEric Garver {
1130018c1ddaSEric Garver int err;
1131018c1ddaSEric Garver bool encap_valid = false;
1132018c1ddaSEric Garver
1133018c1ddaSEric Garver err = __parse_vlan_from_nlattrs(match, key_attrs, false, a,
1134018c1ddaSEric Garver is_mask, log);
1135018c1ddaSEric Garver if (err)
1136018c1ddaSEric Garver return err;
1137018c1ddaSEric Garver
11389df46aefSMichał Mirosław encap_valid = !!(match->key->eth.vlan.tci & htons(VLAN_CFI_MASK));
1139018c1ddaSEric Garver if (encap_valid) {
1140018c1ddaSEric Garver err = __parse_vlan_from_nlattrs(match, key_attrs, true, a,
1141018c1ddaSEric Garver is_mask, log);
1142018c1ddaSEric Garver if (err)
1143018c1ddaSEric Garver return err;
1144018c1ddaSEric Garver }
1145018c1ddaSEric Garver
1146018c1ddaSEric Garver return 0;
1147018c1ddaSEric Garver }
1148018c1ddaSEric Garver
parse_eth_type_from_nlattrs(struct sw_flow_match * match,u64 * attrs,const struct nlattr ** a,bool is_mask,bool log)11490a6410fbSJiri Benc static int parse_eth_type_from_nlattrs(struct sw_flow_match *match,
11500a6410fbSJiri Benc u64 *attrs, const struct nlattr **a,
11510a6410fbSJiri Benc bool is_mask, bool log)
11520a6410fbSJiri Benc {
11530a6410fbSJiri Benc __be16 eth_type;
11540a6410fbSJiri Benc
11550a6410fbSJiri Benc eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
11560a6410fbSJiri Benc if (is_mask) {
11570a6410fbSJiri Benc /* Always exact match EtherType. */
11580a6410fbSJiri Benc eth_type = htons(0xffff);
11590a6410fbSJiri Benc } else if (!eth_proto_is_802_3(eth_type)) {
11600a6410fbSJiri Benc OVS_NLERR(log, "EtherType %x is less than min %x",
11610a6410fbSJiri Benc ntohs(eth_type), ETH_P_802_3_MIN);
11620a6410fbSJiri Benc return -EINVAL;
11630a6410fbSJiri Benc }
11640a6410fbSJiri Benc
11650a6410fbSJiri Benc SW_FLOW_KEY_PUT(match, eth.type, eth_type, is_mask);
11660a6410fbSJiri Benc *attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE);
11670a6410fbSJiri Benc return 0;
11680a6410fbSJiri Benc }
11690a6410fbSJiri Benc
metadata_from_nlattrs(struct net * net,struct sw_flow_match * match,u64 * attrs,const struct nlattr ** a,bool is_mask,bool log)1170c2ac6673SJoe Stringer static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
1171c2ac6673SJoe Stringer u64 *attrs, const struct nlattr **a,
1172c2ac6673SJoe Stringer bool is_mask, bool log)
1173e6445719SPravin B Shelar {
11740a6410fbSJiri Benc u8 mac_proto = MAC_PROTO_ETHERNET;
11750a6410fbSJiri Benc
1176971427f3SAndy Zhou if (*attrs & (1 << OVS_KEY_ATTR_DP_HASH)) {
1177971427f3SAndy Zhou u32 hash_val = nla_get_u32(a[OVS_KEY_ATTR_DP_HASH]);
1178971427f3SAndy Zhou
1179971427f3SAndy Zhou SW_FLOW_KEY_PUT(match, ovs_flow_hash, hash_val, is_mask);
1180971427f3SAndy Zhou *attrs &= ~(1 << OVS_KEY_ATTR_DP_HASH);
1181971427f3SAndy Zhou }
1182971427f3SAndy Zhou
1183971427f3SAndy Zhou if (*attrs & (1 << OVS_KEY_ATTR_RECIRC_ID)) {
1184971427f3SAndy Zhou u32 recirc_id = nla_get_u32(a[OVS_KEY_ATTR_RECIRC_ID]);
1185971427f3SAndy Zhou
1186971427f3SAndy Zhou SW_FLOW_KEY_PUT(match, recirc_id, recirc_id, is_mask);
1187971427f3SAndy Zhou *attrs &= ~(1 << OVS_KEY_ATTR_RECIRC_ID);
1188971427f3SAndy Zhou }
1189971427f3SAndy Zhou
1190e6445719SPravin B Shelar if (*attrs & (1 << OVS_KEY_ATTR_PRIORITY)) {
1191e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, phy.priority,
1192e6445719SPravin B Shelar nla_get_u32(a[OVS_KEY_ATTR_PRIORITY]), is_mask);
1193e6445719SPravin B Shelar *attrs &= ~(1 << OVS_KEY_ATTR_PRIORITY);
1194e6445719SPravin B Shelar }
1195e6445719SPravin B Shelar
1196e6445719SPravin B Shelar if (*attrs & (1 << OVS_KEY_ATTR_IN_PORT)) {
1197e6445719SPravin B Shelar u32 in_port = nla_get_u32(a[OVS_KEY_ATTR_IN_PORT]);
1198e6445719SPravin B Shelar
1199426cda5cSJesse Gross if (is_mask) {
1200e6445719SPravin B Shelar in_port = 0xffffffff; /* Always exact match in_port. */
1201426cda5cSJesse Gross } else if (in_port >= DP_MAX_PORTS) {
120205da5898SJarno Rajahalme OVS_NLERR(log, "Port %d exceeds max allowable %d",
1203426cda5cSJesse Gross in_port, DP_MAX_PORTS);
1204e6445719SPravin B Shelar return -EINVAL;
1205426cda5cSJesse Gross }
1206e6445719SPravin B Shelar
1207e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, phy.in_port, in_port, is_mask);
1208e6445719SPravin B Shelar *attrs &= ~(1 << OVS_KEY_ATTR_IN_PORT);
1209e6445719SPravin B Shelar } else if (!is_mask) {
1210e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, phy.in_port, DP_MAX_PORTS, is_mask);
1211e6445719SPravin B Shelar }
1212e6445719SPravin B Shelar
1213e6445719SPravin B Shelar if (*attrs & (1 << OVS_KEY_ATTR_SKB_MARK)) {
1214e6445719SPravin B Shelar uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]);
1215e6445719SPravin B Shelar
1216e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, phy.skb_mark, mark, is_mask);
1217e6445719SPravin B Shelar *attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK);
1218e6445719SPravin B Shelar }
1219e6445719SPravin B Shelar if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) {
12206b26ba3aSJiri Benc if (ip_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match,
12211dd144cfSThomas Graf is_mask, log) < 0)
1222e6445719SPravin B Shelar return -EINVAL;
1223e6445719SPravin B Shelar *attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL);
1224e6445719SPravin B Shelar }
12257f8a436eSJoe Stringer
12267f8a436eSJoe Stringer if (*attrs & (1 << OVS_KEY_ATTR_CT_STATE) &&
1227c2ac6673SJoe Stringer ovs_ct_verify(net, OVS_KEY_ATTR_CT_STATE)) {
1228fbccce59SJoe Stringer u32 ct_state = nla_get_u32(a[OVS_KEY_ATTR_CT_STATE]);
12297f8a436eSJoe Stringer
12309e384715SJoe Stringer if (ct_state & ~CT_SUPPORTED_MASK) {
1231fbccce59SJoe Stringer OVS_NLERR(log, "ct_state flags %08x unsupported",
12326f225952SJoe Stringer ct_state);
12336f225952SJoe Stringer return -EINVAL;
12346f225952SJoe Stringer }
12357f8a436eSJoe Stringer
1236316d4d78SJarno Rajahalme SW_FLOW_KEY_PUT(match, ct_state, ct_state, is_mask);
12377f8a436eSJoe Stringer *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_STATE);
12387f8a436eSJoe Stringer }
12397f8a436eSJoe Stringer if (*attrs & (1 << OVS_KEY_ATTR_CT_ZONE) &&
1240c2ac6673SJoe Stringer ovs_ct_verify(net, OVS_KEY_ATTR_CT_ZONE)) {
12417f8a436eSJoe Stringer u16 ct_zone = nla_get_u16(a[OVS_KEY_ATTR_CT_ZONE]);
12427f8a436eSJoe Stringer
1243316d4d78SJarno Rajahalme SW_FLOW_KEY_PUT(match, ct_zone, ct_zone, is_mask);
12447f8a436eSJoe Stringer *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE);
12457f8a436eSJoe Stringer }
1246182e3042SJoe Stringer if (*attrs & (1 << OVS_KEY_ATTR_CT_MARK) &&
1247c2ac6673SJoe Stringer ovs_ct_verify(net, OVS_KEY_ATTR_CT_MARK)) {
1248182e3042SJoe Stringer u32 mark = nla_get_u32(a[OVS_KEY_ATTR_CT_MARK]);
1249182e3042SJoe Stringer
1250182e3042SJoe Stringer SW_FLOW_KEY_PUT(match, ct.mark, mark, is_mask);
1251182e3042SJoe Stringer *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_MARK);
1252182e3042SJoe Stringer }
125333db4125SJoe Stringer if (*attrs & (1 << OVS_KEY_ATTR_CT_LABELS) &&
125433db4125SJoe Stringer ovs_ct_verify(net, OVS_KEY_ATTR_CT_LABELS)) {
125533db4125SJoe Stringer const struct ovs_key_ct_labels *cl;
1256c2ac6673SJoe Stringer
125733db4125SJoe Stringer cl = nla_data(a[OVS_KEY_ATTR_CT_LABELS]);
125833db4125SJoe Stringer SW_FLOW_KEY_MEMCPY(match, ct.labels, cl->ct_labels,
1259c2ac6673SJoe Stringer sizeof(*cl), is_mask);
126033db4125SJoe Stringer *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_LABELS);
1261c2ac6673SJoe Stringer }
12629dd7f890SJarno Rajahalme if (*attrs & (1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4)) {
12639dd7f890SJarno Rajahalme const struct ovs_key_ct_tuple_ipv4 *ct;
12649dd7f890SJarno Rajahalme
12659dd7f890SJarno Rajahalme ct = nla_data(a[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4]);
12669dd7f890SJarno Rajahalme
12679dd7f890SJarno Rajahalme SW_FLOW_KEY_PUT(match, ipv4.ct_orig.src, ct->ipv4_src, is_mask);
12689dd7f890SJarno Rajahalme SW_FLOW_KEY_PUT(match, ipv4.ct_orig.dst, ct->ipv4_dst, is_mask);
12699dd7f890SJarno Rajahalme SW_FLOW_KEY_PUT(match, ct.orig_tp.src, ct->src_port, is_mask);
12709dd7f890SJarno Rajahalme SW_FLOW_KEY_PUT(match, ct.orig_tp.dst, ct->dst_port, is_mask);
1271316d4d78SJarno Rajahalme SW_FLOW_KEY_PUT(match, ct_orig_proto, ct->ipv4_proto, is_mask);
12729dd7f890SJarno Rajahalme *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4);
12739dd7f890SJarno Rajahalme }
12749dd7f890SJarno Rajahalme if (*attrs & (1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6)) {
12759dd7f890SJarno Rajahalme const struct ovs_key_ct_tuple_ipv6 *ct;
12769dd7f890SJarno Rajahalme
12779dd7f890SJarno Rajahalme ct = nla_data(a[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6]);
12789dd7f890SJarno Rajahalme
12799dd7f890SJarno Rajahalme SW_FLOW_KEY_MEMCPY(match, ipv6.ct_orig.src, &ct->ipv6_src,
12809dd7f890SJarno Rajahalme sizeof(match->key->ipv6.ct_orig.src),
12819dd7f890SJarno Rajahalme is_mask);
12829dd7f890SJarno Rajahalme SW_FLOW_KEY_MEMCPY(match, ipv6.ct_orig.dst, &ct->ipv6_dst,
12839dd7f890SJarno Rajahalme sizeof(match->key->ipv6.ct_orig.dst),
12849dd7f890SJarno Rajahalme is_mask);
12859dd7f890SJarno Rajahalme SW_FLOW_KEY_PUT(match, ct.orig_tp.src, ct->src_port, is_mask);
12869dd7f890SJarno Rajahalme SW_FLOW_KEY_PUT(match, ct.orig_tp.dst, ct->dst_port, is_mask);
1287316d4d78SJarno Rajahalme SW_FLOW_KEY_PUT(match, ct_orig_proto, ct->ipv6_proto, is_mask);
12889dd7f890SJarno Rajahalme *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6);
12899dd7f890SJarno Rajahalme }
1290329f45bcSJiri Benc
12910a6410fbSJiri Benc /* For layer 3 packets the Ethernet type is provided
12920a6410fbSJiri Benc * and treated as metadata but no MAC addresses are provided.
12930a6410fbSJiri Benc */
12940a6410fbSJiri Benc if (!(*attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) &&
12950a6410fbSJiri Benc (*attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)))
12960a6410fbSJiri Benc mac_proto = MAC_PROTO_NONE;
12970a6410fbSJiri Benc
1298329f45bcSJiri Benc /* Always exact match mac_proto */
12990a6410fbSJiri Benc SW_FLOW_KEY_PUT(match, mac_proto, is_mask ? 0xff : mac_proto, is_mask);
13000a6410fbSJiri Benc
13010a6410fbSJiri Benc if (mac_proto == MAC_PROTO_NONE)
13020a6410fbSJiri Benc return parse_eth_type_from_nlattrs(match, attrs, a, is_mask,
13030a6410fbSJiri Benc log);
1304329f45bcSJiri Benc
1305e6445719SPravin B Shelar return 0;
1306e6445719SPravin B Shelar }
1307e6445719SPravin B Shelar
nsh_hdr_from_nlattr(const struct nlattr * attr,struct nshhdr * nh,size_t size)1308b2d0f5d5SYi Yang int nsh_hdr_from_nlattr(const struct nlattr *attr,
1309b2d0f5d5SYi Yang struct nshhdr *nh, size_t size)
1310b2d0f5d5SYi Yang {
1311b2d0f5d5SYi Yang struct nlattr *a;
1312b2d0f5d5SYi Yang int rem;
1313b2d0f5d5SYi Yang u8 flags = 0;
1314b2d0f5d5SYi Yang u8 ttl = 0;
1315b2d0f5d5SYi Yang int mdlen = 0;
1316b2d0f5d5SYi Yang
1317b2d0f5d5SYi Yang /* validate_nsh has check this, so we needn't do duplicate check here
1318b2d0f5d5SYi Yang */
1319b2d0f5d5SYi Yang if (size < NSH_BASE_HDR_LEN)
1320b2d0f5d5SYi Yang return -ENOBUFS;
1321b2d0f5d5SYi Yang
1322b2d0f5d5SYi Yang nla_for_each_nested(a, attr, rem) {
1323b2d0f5d5SYi Yang int type = nla_type(a);
1324b2d0f5d5SYi Yang
1325b2d0f5d5SYi Yang switch (type) {
1326b2d0f5d5SYi Yang case OVS_NSH_KEY_ATTR_BASE: {
1327b2d0f5d5SYi Yang const struct ovs_nsh_key_base *base = nla_data(a);
1328b2d0f5d5SYi Yang
1329b2d0f5d5SYi Yang flags = base->flags;
1330b2d0f5d5SYi Yang ttl = base->ttl;
1331b2d0f5d5SYi Yang nh->np = base->np;
1332b2d0f5d5SYi Yang nh->mdtype = base->mdtype;
1333b2d0f5d5SYi Yang nh->path_hdr = base->path_hdr;
1334b2d0f5d5SYi Yang break;
1335b2d0f5d5SYi Yang }
1336b2d0f5d5SYi Yang case OVS_NSH_KEY_ATTR_MD1:
1337b2d0f5d5SYi Yang mdlen = nla_len(a);
1338b2d0f5d5SYi Yang if (mdlen > size - NSH_BASE_HDR_LEN)
1339b2d0f5d5SYi Yang return -ENOBUFS;
1340b2d0f5d5SYi Yang memcpy(&nh->md1, nla_data(a), mdlen);
1341b2d0f5d5SYi Yang break;
1342b2d0f5d5SYi Yang
1343b2d0f5d5SYi Yang case OVS_NSH_KEY_ATTR_MD2:
1344b2d0f5d5SYi Yang mdlen = nla_len(a);
1345b2d0f5d5SYi Yang if (mdlen > size - NSH_BASE_HDR_LEN)
1346b2d0f5d5SYi Yang return -ENOBUFS;
1347b2d0f5d5SYi Yang memcpy(&nh->md2, nla_data(a), mdlen);
1348b2d0f5d5SYi Yang break;
1349b2d0f5d5SYi Yang
1350b2d0f5d5SYi Yang default:
1351b2d0f5d5SYi Yang return -EINVAL;
1352b2d0f5d5SYi Yang }
1353b2d0f5d5SYi Yang }
1354b2d0f5d5SYi Yang
1355b2d0f5d5SYi Yang /* nsh header length = NSH_BASE_HDR_LEN + mdlen */
1356b2d0f5d5SYi Yang nh->ver_flags_ttl_len = 0;
1357b2d0f5d5SYi Yang nsh_set_flags_ttl_len(nh, flags, ttl, NSH_BASE_HDR_LEN + mdlen);
1358b2d0f5d5SYi Yang
1359b2d0f5d5SYi Yang return 0;
1360b2d0f5d5SYi Yang }
1361b2d0f5d5SYi Yang
nsh_key_from_nlattr(const struct nlattr * attr,struct ovs_key_nsh * nsh,struct ovs_key_nsh * nsh_mask)1362b2d0f5d5SYi Yang int nsh_key_from_nlattr(const struct nlattr *attr,
1363b2d0f5d5SYi Yang struct ovs_key_nsh *nsh, struct ovs_key_nsh *nsh_mask)
1364b2d0f5d5SYi Yang {
1365b2d0f5d5SYi Yang struct nlattr *a;
1366b2d0f5d5SYi Yang int rem;
1367b2d0f5d5SYi Yang
1368b2d0f5d5SYi Yang /* validate_nsh has check this, so we needn't do duplicate check here
1369b2d0f5d5SYi Yang */
1370b2d0f5d5SYi Yang nla_for_each_nested(a, attr, rem) {
1371b2d0f5d5SYi Yang int type = nla_type(a);
1372b2d0f5d5SYi Yang
1373b2d0f5d5SYi Yang switch (type) {
1374b2d0f5d5SYi Yang case OVS_NSH_KEY_ATTR_BASE: {
1375b2d0f5d5SYi Yang const struct ovs_nsh_key_base *base = nla_data(a);
1376b2d0f5d5SYi Yang const struct ovs_nsh_key_base *base_mask = base + 1;
1377b2d0f5d5SYi Yang
1378b2d0f5d5SYi Yang nsh->base = *base;
1379b2d0f5d5SYi Yang nsh_mask->base = *base_mask;
1380b2d0f5d5SYi Yang break;
1381b2d0f5d5SYi Yang }
1382b2d0f5d5SYi Yang case OVS_NSH_KEY_ATTR_MD1: {
1383b2d0f5d5SYi Yang const struct ovs_nsh_key_md1 *md1 = nla_data(a);
1384b2d0f5d5SYi Yang const struct ovs_nsh_key_md1 *md1_mask = md1 + 1;
1385b2d0f5d5SYi Yang
1386b2d0f5d5SYi Yang memcpy(nsh->context, md1->context, sizeof(*md1));
1387b2d0f5d5SYi Yang memcpy(nsh_mask->context, md1_mask->context,
1388b2d0f5d5SYi Yang sizeof(*md1_mask));
1389b2d0f5d5SYi Yang break;
1390b2d0f5d5SYi Yang }
1391b2d0f5d5SYi Yang case OVS_NSH_KEY_ATTR_MD2:
1392b2d0f5d5SYi Yang /* Not supported yet */
1393b2d0f5d5SYi Yang return -ENOTSUPP;
1394b2d0f5d5SYi Yang default:
1395b2d0f5d5SYi Yang return -EINVAL;
1396b2d0f5d5SYi Yang }
1397b2d0f5d5SYi Yang }
1398b2d0f5d5SYi Yang
1399b2d0f5d5SYi Yang return 0;
1400b2d0f5d5SYi Yang }
1401b2d0f5d5SYi Yang
nsh_key_put_from_nlattr(const struct nlattr * attr,struct sw_flow_match * match,bool is_mask,bool is_push_nsh,bool log)1402b2d0f5d5SYi Yang static int nsh_key_put_from_nlattr(const struct nlattr *attr,
1403b2d0f5d5SYi Yang struct sw_flow_match *match, bool is_mask,
1404b2d0f5d5SYi Yang bool is_push_nsh, bool log)
1405b2d0f5d5SYi Yang {
1406b2d0f5d5SYi Yang struct nlattr *a;
1407b2d0f5d5SYi Yang int rem;
1408b2d0f5d5SYi Yang bool has_base = false;
1409b2d0f5d5SYi Yang bool has_md1 = false;
1410b2d0f5d5SYi Yang bool has_md2 = false;
1411b2d0f5d5SYi Yang u8 mdtype = 0;
1412b2d0f5d5SYi Yang int mdlen = 0;
1413b2d0f5d5SYi Yang
1414b2d0f5d5SYi Yang if (WARN_ON(is_push_nsh && is_mask))
1415b2d0f5d5SYi Yang return -EINVAL;
1416b2d0f5d5SYi Yang
1417b2d0f5d5SYi Yang nla_for_each_nested(a, attr, rem) {
1418b2d0f5d5SYi Yang int type = nla_type(a);
1419b2d0f5d5SYi Yang int i;
1420b2d0f5d5SYi Yang
1421b2d0f5d5SYi Yang if (type > OVS_NSH_KEY_ATTR_MAX) {
1422b2d0f5d5SYi Yang OVS_NLERR(log, "nsh attr %d is out of range max %d",
1423b2d0f5d5SYi Yang type, OVS_NSH_KEY_ATTR_MAX);
1424b2d0f5d5SYi Yang return -EINVAL;
1425b2d0f5d5SYi Yang }
1426b2d0f5d5SYi Yang
1427b2d0f5d5SYi Yang if (!check_attr_len(nla_len(a),
1428b2d0f5d5SYi Yang ovs_nsh_key_attr_lens[type].len)) {
1429b2d0f5d5SYi Yang OVS_NLERR(
1430b2d0f5d5SYi Yang log,
1431b2d0f5d5SYi Yang "nsh attr %d has unexpected len %d expected %d",
1432b2d0f5d5SYi Yang type,
1433b2d0f5d5SYi Yang nla_len(a),
1434b2d0f5d5SYi Yang ovs_nsh_key_attr_lens[type].len
1435b2d0f5d5SYi Yang );
1436b2d0f5d5SYi Yang return -EINVAL;
1437b2d0f5d5SYi Yang }
1438b2d0f5d5SYi Yang
1439b2d0f5d5SYi Yang switch (type) {
1440b2d0f5d5SYi Yang case OVS_NSH_KEY_ATTR_BASE: {
1441b2d0f5d5SYi Yang const struct ovs_nsh_key_base *base = nla_data(a);
1442b2d0f5d5SYi Yang
1443b2d0f5d5SYi Yang has_base = true;
1444b2d0f5d5SYi Yang mdtype = base->mdtype;
1445b2d0f5d5SYi Yang SW_FLOW_KEY_PUT(match, nsh.base.flags,
1446b2d0f5d5SYi Yang base->flags, is_mask);
1447b2d0f5d5SYi Yang SW_FLOW_KEY_PUT(match, nsh.base.ttl,
1448b2d0f5d5SYi Yang base->ttl, is_mask);
1449b2d0f5d5SYi Yang SW_FLOW_KEY_PUT(match, nsh.base.mdtype,
1450b2d0f5d5SYi Yang base->mdtype, is_mask);
1451b2d0f5d5SYi Yang SW_FLOW_KEY_PUT(match, nsh.base.np,
1452b2d0f5d5SYi Yang base->np, is_mask);
1453b2d0f5d5SYi Yang SW_FLOW_KEY_PUT(match, nsh.base.path_hdr,
1454b2d0f5d5SYi Yang base->path_hdr, is_mask);
1455b2d0f5d5SYi Yang break;
1456b2d0f5d5SYi Yang }
1457b2d0f5d5SYi Yang case OVS_NSH_KEY_ATTR_MD1: {
1458b2d0f5d5SYi Yang const struct ovs_nsh_key_md1 *md1 = nla_data(a);
1459b2d0f5d5SYi Yang
1460b2d0f5d5SYi Yang has_md1 = true;
1461b2d0f5d5SYi Yang for (i = 0; i < NSH_MD1_CONTEXT_SIZE; i++)
1462b2d0f5d5SYi Yang SW_FLOW_KEY_PUT(match, nsh.context[i],
1463b2d0f5d5SYi Yang md1->context[i], is_mask);
1464b2d0f5d5SYi Yang break;
1465b2d0f5d5SYi Yang }
1466b2d0f5d5SYi Yang case OVS_NSH_KEY_ATTR_MD2:
1467b2d0f5d5SYi Yang if (!is_push_nsh) /* Not supported MD type 2 yet */
1468b2d0f5d5SYi Yang return -ENOTSUPP;
1469b2d0f5d5SYi Yang
1470b2d0f5d5SYi Yang has_md2 = true;
1471b2d0f5d5SYi Yang mdlen = nla_len(a);
1472b2d0f5d5SYi Yang if (mdlen > NSH_CTX_HDRS_MAX_LEN || mdlen <= 0) {
1473b2d0f5d5SYi Yang OVS_NLERR(
1474b2d0f5d5SYi Yang log,
1475b2d0f5d5SYi Yang "Invalid MD length %d for MD type %d",
1476b2d0f5d5SYi Yang mdlen,
1477b2d0f5d5SYi Yang mdtype
1478b2d0f5d5SYi Yang );
1479b2d0f5d5SYi Yang return -EINVAL;
1480b2d0f5d5SYi Yang }
1481b2d0f5d5SYi Yang break;
1482b2d0f5d5SYi Yang default:
1483b2d0f5d5SYi Yang OVS_NLERR(log, "Unknown nsh attribute %d",
1484b2d0f5d5SYi Yang type);
1485b2d0f5d5SYi Yang return -EINVAL;
1486b2d0f5d5SYi Yang }
1487b2d0f5d5SYi Yang }
1488b2d0f5d5SYi Yang
1489b2d0f5d5SYi Yang if (rem > 0) {
1490b2d0f5d5SYi Yang OVS_NLERR(log, "nsh attribute has %d unknown bytes.", rem);
1491b2d0f5d5SYi Yang return -EINVAL;
1492b2d0f5d5SYi Yang }
1493b2d0f5d5SYi Yang
1494b2d0f5d5SYi Yang if (has_md1 && has_md2) {
1495b2d0f5d5SYi Yang OVS_NLERR(
1496b2d0f5d5SYi Yang 1,
1497b2d0f5d5SYi Yang "invalid nsh attribute: md1 and md2 are exclusive."
1498b2d0f5d5SYi Yang );
1499b2d0f5d5SYi Yang return -EINVAL;
1500b2d0f5d5SYi Yang }
1501b2d0f5d5SYi Yang
1502b2d0f5d5SYi Yang if (!is_mask) {
1503b2d0f5d5SYi Yang if ((has_md1 && mdtype != NSH_M_TYPE1) ||
1504b2d0f5d5SYi Yang (has_md2 && mdtype != NSH_M_TYPE2)) {
1505b2d0f5d5SYi Yang OVS_NLERR(1, "nsh attribute has unmatched MD type %d.",
1506b2d0f5d5SYi Yang mdtype);
1507b2d0f5d5SYi Yang return -EINVAL;
1508b2d0f5d5SYi Yang }
1509b2d0f5d5SYi Yang
1510b2d0f5d5SYi Yang if (is_push_nsh &&
1511b2d0f5d5SYi Yang (!has_base || (!has_md1 && !has_md2))) {
1512b2d0f5d5SYi Yang OVS_NLERR(
1513b2d0f5d5SYi Yang 1,
1514b2d0f5d5SYi Yang "push_nsh: missing base or metadata attributes"
1515b2d0f5d5SYi Yang );
1516b2d0f5d5SYi Yang return -EINVAL;
1517b2d0f5d5SYi Yang }
1518b2d0f5d5SYi Yang }
1519b2d0f5d5SYi Yang
1520b2d0f5d5SYi Yang return 0;
1521b2d0f5d5SYi Yang }
1522b2d0f5d5SYi Yang
ovs_key_from_nlattrs(struct net * net,struct sw_flow_match * match,u64 attrs,const struct nlattr ** a,bool is_mask,bool log)1523c2ac6673SJoe Stringer static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
1524c2ac6673SJoe Stringer u64 attrs, const struct nlattr **a,
1525c2ac6673SJoe Stringer bool is_mask, bool log)
1526e6445719SPravin B Shelar {
1527e6445719SPravin B Shelar int err;
1528e6445719SPravin B Shelar
1529c2ac6673SJoe Stringer err = metadata_from_nlattrs(net, match, &attrs, a, is_mask, log);
1530e6445719SPravin B Shelar if (err)
1531e6445719SPravin B Shelar return err;
1532e6445719SPravin B Shelar
1533e6445719SPravin B Shelar if (attrs & (1 << OVS_KEY_ATTR_ETHERNET)) {
1534e6445719SPravin B Shelar const struct ovs_key_ethernet *eth_key;
1535e6445719SPravin B Shelar
1536e6445719SPravin B Shelar eth_key = nla_data(a[OVS_KEY_ATTR_ETHERNET]);
1537e6445719SPravin B Shelar SW_FLOW_KEY_MEMCPY(match, eth.src,
1538e6445719SPravin B Shelar eth_key->eth_src, ETH_ALEN, is_mask);
1539e6445719SPravin B Shelar SW_FLOW_KEY_MEMCPY(match, eth.dst,
1540e6445719SPravin B Shelar eth_key->eth_dst, ETH_ALEN, is_mask);
1541e6445719SPravin B Shelar attrs &= ~(1 << OVS_KEY_ATTR_ETHERNET);
1542e6445719SPravin B Shelar
1543e6445719SPravin B Shelar if (attrs & (1 << OVS_KEY_ATTR_VLAN)) {
1544018c1ddaSEric Garver /* VLAN attribute is always parsed before getting here since it
1545018c1ddaSEric Garver * may occur multiple times.
1546018c1ddaSEric Garver */
1547018c1ddaSEric Garver OVS_NLERR(log, "VLAN attribute unexpected.");
1548e6445719SPravin B Shelar return -EINVAL;
1549e6445719SPravin B Shelar }
1550e6445719SPravin B Shelar
1551e6445719SPravin B Shelar if (attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) {
15520a6410fbSJiri Benc err = parse_eth_type_from_nlattrs(match, &attrs, a, is_mask,
15530a6410fbSJiri Benc log);
15540a6410fbSJiri Benc if (err)
15550a6410fbSJiri Benc return err;
1556e6445719SPravin B Shelar } else if (!is_mask) {
1557e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2), is_mask);
1558e6445719SPravin B Shelar }
15590a6410fbSJiri Benc } else if (!match->key->eth.type) {
15600a6410fbSJiri Benc OVS_NLERR(log, "Either Ethernet header or EtherType is required.");
15610a6410fbSJiri Benc return -EINVAL;
15620a6410fbSJiri Benc }
1563e6445719SPravin B Shelar
1564e6445719SPravin B Shelar if (attrs & (1 << OVS_KEY_ATTR_IPV4)) {
1565e6445719SPravin B Shelar const struct ovs_key_ipv4 *ipv4_key;
1566e6445719SPravin B Shelar
1567e6445719SPravin B Shelar ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]);
1568e6445719SPravin B Shelar if (!is_mask && ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) {
156905da5898SJarno Rajahalme OVS_NLERR(log, "IPv4 frag type %d is out of range max %d",
1570e6445719SPravin B Shelar ipv4_key->ipv4_frag, OVS_FRAG_TYPE_MAX);
1571e6445719SPravin B Shelar return -EINVAL;
1572e6445719SPravin B Shelar }
1573e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ip.proto,
1574e6445719SPravin B Shelar ipv4_key->ipv4_proto, is_mask);
1575e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ip.tos,
1576e6445719SPravin B Shelar ipv4_key->ipv4_tos, is_mask);
1577e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ip.ttl,
1578e6445719SPravin B Shelar ipv4_key->ipv4_ttl, is_mask);
1579e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ip.frag,
1580e6445719SPravin B Shelar ipv4_key->ipv4_frag, is_mask);
1581e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ipv4.addr.src,
1582e6445719SPravin B Shelar ipv4_key->ipv4_src, is_mask);
1583e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ipv4.addr.dst,
1584e6445719SPravin B Shelar ipv4_key->ipv4_dst, is_mask);
1585e6445719SPravin B Shelar attrs &= ~(1 << OVS_KEY_ATTR_IPV4);
1586e6445719SPravin B Shelar }
1587e6445719SPravin B Shelar
1588e6445719SPravin B Shelar if (attrs & (1 << OVS_KEY_ATTR_IPV6)) {
1589e6445719SPravin B Shelar const struct ovs_key_ipv6 *ipv6_key;
1590e6445719SPravin B Shelar
1591e6445719SPravin B Shelar ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]);
1592e6445719SPravin B Shelar if (!is_mask && ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) {
159305da5898SJarno Rajahalme OVS_NLERR(log, "IPv6 frag type %d is out of range max %d",
1594e6445719SPravin B Shelar ipv6_key->ipv6_frag, OVS_FRAG_TYPE_MAX);
1595e6445719SPravin B Shelar return -EINVAL;
1596e6445719SPravin B Shelar }
1597fecaef85SJarno Rajahalme
1598d3052bb5SJoe Stringer if (!is_mask && ipv6_key->ipv6_label & htonl(0xFFF00000)) {
15990ed80da5SJoe Perches OVS_NLERR(log, "IPv6 flow label %x is out of range (max=%x)",
1600fecaef85SJarno Rajahalme ntohl(ipv6_key->ipv6_label), (1 << 20) - 1);
1601fecaef85SJarno Rajahalme return -EINVAL;
1602fecaef85SJarno Rajahalme }
1603fecaef85SJarno Rajahalme
1604e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ipv6.label,
1605e6445719SPravin B Shelar ipv6_key->ipv6_label, is_mask);
1606e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ip.proto,
1607e6445719SPravin B Shelar ipv6_key->ipv6_proto, is_mask);
1608e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ip.tos,
1609e6445719SPravin B Shelar ipv6_key->ipv6_tclass, is_mask);
1610e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ip.ttl,
1611e6445719SPravin B Shelar ipv6_key->ipv6_hlimit, is_mask);
1612e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ip.frag,
1613e6445719SPravin B Shelar ipv6_key->ipv6_frag, is_mask);
1614e6445719SPravin B Shelar SW_FLOW_KEY_MEMCPY(match, ipv6.addr.src,
1615e6445719SPravin B Shelar ipv6_key->ipv6_src,
1616e6445719SPravin B Shelar sizeof(match->key->ipv6.addr.src),
1617e6445719SPravin B Shelar is_mask);
1618e6445719SPravin B Shelar SW_FLOW_KEY_MEMCPY(match, ipv6.addr.dst,
1619e6445719SPravin B Shelar ipv6_key->ipv6_dst,
1620e6445719SPravin B Shelar sizeof(match->key->ipv6.addr.dst),
1621e6445719SPravin B Shelar is_mask);
1622e6445719SPravin B Shelar
1623e6445719SPravin B Shelar attrs &= ~(1 << OVS_KEY_ATTR_IPV6);
1624e6445719SPravin B Shelar }
1625e6445719SPravin B Shelar
162628a3f060SToms Atteka if (attrs & (1ULL << OVS_KEY_ATTR_IPV6_EXTHDRS)) {
162728a3f060SToms Atteka const struct ovs_key_ipv6_exthdrs *ipv6_exthdrs_key;
162828a3f060SToms Atteka
162928a3f060SToms Atteka ipv6_exthdrs_key = nla_data(a[OVS_KEY_ATTR_IPV6_EXTHDRS]);
163028a3f060SToms Atteka
163128a3f060SToms Atteka SW_FLOW_KEY_PUT(match, ipv6.exthdrs,
163228a3f060SToms Atteka ipv6_exthdrs_key->hdrs, is_mask);
163328a3f060SToms Atteka
163428a3f060SToms Atteka attrs &= ~(1ULL << OVS_KEY_ATTR_IPV6_EXTHDRS);
163528a3f060SToms Atteka }
163628a3f060SToms Atteka
1637e6445719SPravin B Shelar if (attrs & (1 << OVS_KEY_ATTR_ARP)) {
1638e6445719SPravin B Shelar const struct ovs_key_arp *arp_key;
1639e6445719SPravin B Shelar
1640e6445719SPravin B Shelar arp_key = nla_data(a[OVS_KEY_ATTR_ARP]);
1641e6445719SPravin B Shelar if (!is_mask && (arp_key->arp_op & htons(0xff00))) {
164205da5898SJarno Rajahalme OVS_NLERR(log, "Unknown ARP opcode (opcode=%d).",
1643e6445719SPravin B Shelar arp_key->arp_op);
1644e6445719SPravin B Shelar return -EINVAL;
1645e6445719SPravin B Shelar }
1646e6445719SPravin B Shelar
1647e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ipv4.addr.src,
1648e6445719SPravin B Shelar arp_key->arp_sip, is_mask);
1649e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ipv4.addr.dst,
1650e6445719SPravin B Shelar arp_key->arp_tip, is_mask);
1651e6445719SPravin B Shelar SW_FLOW_KEY_PUT(match, ip.proto,
1652e6445719SPravin B Shelar ntohs(arp_key->arp_op), is_mask);
1653e6445719SPravin B Shelar SW_FLOW_KEY_MEMCPY(match, ipv4.arp.sha,
1654e6445719SPravin B Shelar arp_key->arp_sha, ETH_ALEN, is_mask);
1655e6445719SPravin B Shelar SW_FLOW_KEY_MEMCPY(match, ipv4.arp.tha,
1656e6445719SPravin B Shelar arp_key->arp_tha, ETH_ALEN, is_mask);
1657e6445719SPravin B Shelar
1658e6445719SPravin B Shelar attrs &= ~(1 << OVS_KEY_ATTR_ARP);
1659e6445719SPravin B Shelar }
1660e6445719SPravin B Shelar
1661b2d0f5d5SYi Yang if (attrs & (1 << OVS_KEY_ATTR_NSH)) {
1662b2d0f5d5SYi Yang if (nsh_key_put_from_nlattr(a[OVS_KEY_ATTR_NSH], match,
1663b2d0f5d5SYi Yang is_mask, false, log) < 0)
1664b2d0f5d5SYi Yang return -EINVAL;
1665b2d0f5d5SYi Yang attrs &= ~(1 << OVS_KEY_ATTR_NSH);
1666b2d0f5d5SYi Yang }
1667b2d0f5d5SYi Yang
166825cd9ba0SSimon Horman if (attrs & (1 << OVS_KEY_ATTR_MPLS)) {
166925cd9ba0SSimon Horman const struct ovs_key_mpls *mpls_key;
1670fbdcdd78SMartin Varghese u32 hdr_len;
1671fbdcdd78SMartin Varghese u32 label_count, label_count_mask, i;
167225cd9ba0SSimon Horman
167325cd9ba0SSimon Horman mpls_key = nla_data(a[OVS_KEY_ATTR_MPLS]);
1674fbdcdd78SMartin Varghese hdr_len = nla_len(a[OVS_KEY_ATTR_MPLS]);
1675fbdcdd78SMartin Varghese label_count = hdr_len / sizeof(struct ovs_key_mpls);
1676fbdcdd78SMartin Varghese
1677fbdcdd78SMartin Varghese if (label_count == 0 || label_count > MPLS_LABEL_DEPTH ||
1678fbdcdd78SMartin Varghese hdr_len % sizeof(struct ovs_key_mpls))
1679fbdcdd78SMartin Varghese return -EINVAL;
1680fbdcdd78SMartin Varghese
1681fbdcdd78SMartin Varghese label_count_mask = GENMASK(label_count - 1, 0);
1682fbdcdd78SMartin Varghese
1683fbdcdd78SMartin Varghese for (i = 0 ; i < label_count; i++)
1684fbdcdd78SMartin Varghese SW_FLOW_KEY_PUT(match, mpls.lse[i],
1685fbdcdd78SMartin Varghese mpls_key[i].mpls_lse, is_mask);
1686fbdcdd78SMartin Varghese
1687fbdcdd78SMartin Varghese SW_FLOW_KEY_PUT(match, mpls.num_labels_mask,
1688fbdcdd78SMartin Varghese label_count_mask, is_mask);
168925cd9ba0SSimon Horman
169025cd9ba0SSimon Horman attrs &= ~(1 << OVS_KEY_ATTR_MPLS);
169125cd9ba0SSimon Horman }
169225cd9ba0SSimon Horman
1693e6445719SPravin B Shelar if (attrs & (1 << OVS_KEY_ATTR_TCP)) {
1694e6445719SPravin B Shelar const struct ovs_key_tcp *tcp_key;
1695e6445719SPravin B Shelar
1696e6445719SPravin B Shelar tcp_key = nla_data(a[OVS_KEY_ATTR_TCP]);
16971139e241SJarno Rajahalme SW_FLOW_KEY_PUT(match, tp.src, tcp_key->tcp_src, is_mask);
16981139e241SJarno Rajahalme SW_FLOW_KEY_PUT(match, tp.dst, tcp_key->tcp_dst, is_mask);
1699e6445719SPravin B Shelar attrs &= ~(1 << OVS_KEY_ATTR_TCP);
1700e6445719SPravin B Shelar }
1701e6445719SPravin B Shelar
17025eb26b15SJarno Rajahalme if (attrs & (1 << OVS_KEY_ATTR_TCP_FLAGS)) {
17031139e241SJarno Rajahalme SW_FLOW_KEY_PUT(match, tp.flags,
17045eb26b15SJarno Rajahalme nla_get_be16(a[OVS_KEY_ATTR_TCP_FLAGS]),
17055eb26b15SJarno Rajahalme is_mask);
17065eb26b15SJarno Rajahalme attrs &= ~(1 << OVS_KEY_ATTR_TCP_FLAGS);
17075eb26b15SJarno Rajahalme }
17085eb26b15SJarno Rajahalme
1709e6445719SPravin B Shelar if (attrs & (1 << OVS_KEY_ATTR_UDP)) {
1710e6445719SPravin B Shelar const struct ovs_key_udp *udp_key;
1711e6445719SPravin B Shelar
1712e6445719SPravin B Shelar udp_key = nla_data(a[OVS_KEY_ATTR_UDP]);
17131139e241SJarno Rajahalme SW_FLOW_KEY_PUT(match, tp.src, udp_key->udp_src, is_mask);
17141139e241SJarno Rajahalme SW_FLOW_KEY_PUT(match, tp.dst, udp_key->udp_dst, is_mask);
1715e6445719SPravin B Shelar attrs &= ~(1 << OVS_KEY_ATTR_UDP);
1716e6445719SPravin B Shelar }
1717e6445719SPravin B Shelar
1718e6445719SPravin B Shelar if (attrs & (1 << OVS_KEY_ATTR_SCTP)) {
1719e6445719SPravin B Shelar const struct ovs_key_sctp *sctp_key;
1720e6445719SPravin B Shelar
1721e6445719SPravin B Shelar sctp_key = nla_data(a[OVS_KEY_ATTR_SCTP]);
17221139e241SJarno Rajahalme SW_FLOW_KEY_PUT(match, tp.src, sctp_key->sctp_src, is_mask);
17231139e241SJarno Rajahalme SW_FLOW_KEY_PUT(match, tp.dst, sctp_key->sctp_dst, is_mask);
1724e6445719SPravin B Shelar attrs &= ~(1 << OVS_KEY_ATTR_SCTP);
1725e6445719SPravin B Shelar }
1726e6445719SPravin B Shelar
1727e6445719SPravin B Shelar if (attrs & (1 << OVS_KEY_ATTR_ICMP)) {
1728e6445719SPravin B Shelar const struct ovs_key_icmp *icmp_key;
1729e6445719SPravin B Shelar
1730e6445719SPravin B Shelar icmp_key = nla_data(a[OVS_KEY_ATTR_ICMP]);
17311139e241SJarno Rajahalme SW_FLOW_KEY_PUT(match, tp.src,
1732e6445719SPravin B Shelar htons(icmp_key->icmp_type), is_mask);
17331139e241SJarno Rajahalme SW_FLOW_KEY_PUT(match, tp.dst,
1734e6445719SPravin B Shelar htons(icmp_key->icmp_code), is_mask);
1735e6445719SPravin B Shelar attrs &= ~(1 << OVS_KEY_ATTR_ICMP);
1736e6445719SPravin B Shelar }
1737e6445719SPravin B Shelar
1738e6445719SPravin B Shelar if (attrs & (1 << OVS_KEY_ATTR_ICMPV6)) {
1739e6445719SPravin B Shelar const struct ovs_key_icmpv6 *icmpv6_key;
1740e6445719SPravin B Shelar
1741e6445719SPravin B Shelar icmpv6_key = nla_data(a[OVS_KEY_ATTR_ICMPV6]);
17421139e241SJarno Rajahalme SW_FLOW_KEY_PUT(match, tp.src,
1743e6445719SPravin B Shelar htons(icmpv6_key->icmpv6_type), is_mask);
17441139e241SJarno Rajahalme SW_FLOW_KEY_PUT(match, tp.dst,
1745e6445719SPravin B Shelar htons(icmpv6_key->icmpv6_code), is_mask);
1746e6445719SPravin B Shelar attrs &= ~(1 << OVS_KEY_ATTR_ICMPV6);
1747e6445719SPravin B Shelar }
1748e6445719SPravin B Shelar
1749e6445719SPravin B Shelar if (attrs & (1 << OVS_KEY_ATTR_ND)) {
1750e6445719SPravin B Shelar const struct ovs_key_nd *nd_key;
1751e6445719SPravin B Shelar
1752e6445719SPravin B Shelar nd_key = nla_data(a[OVS_KEY_ATTR_ND]);
1753e6445719SPravin B Shelar SW_FLOW_KEY_MEMCPY(match, ipv6.nd.target,
1754e6445719SPravin B Shelar nd_key->nd_target,
1755e6445719SPravin B Shelar sizeof(match->key->ipv6.nd.target),
1756e6445719SPravin B Shelar is_mask);
1757e6445719SPravin B Shelar SW_FLOW_KEY_MEMCPY(match, ipv6.nd.sll,
1758e6445719SPravin B Shelar nd_key->nd_sll, ETH_ALEN, is_mask);
1759e6445719SPravin B Shelar SW_FLOW_KEY_MEMCPY(match, ipv6.nd.tll,
1760e6445719SPravin B Shelar nd_key->nd_tll, ETH_ALEN, is_mask);
1761e6445719SPravin B Shelar attrs &= ~(1 << OVS_KEY_ATTR_ND);
1762e6445719SPravin B Shelar }
1763e6445719SPravin B Shelar
1764426cda5cSJesse Gross if (attrs != 0) {
176505da5898SJarno Rajahalme OVS_NLERR(log, "Unknown key attributes %llx",
1766426cda5cSJesse Gross (unsigned long long)attrs);
1767e6445719SPravin B Shelar return -EINVAL;
1768426cda5cSJesse Gross }
1769e6445719SPravin B Shelar
1770e6445719SPravin B Shelar return 0;
1771e6445719SPravin B Shelar }
1772e6445719SPravin B Shelar
nlattr_set(struct nlattr * attr,u8 val,const struct ovs_len_tbl * tbl)177381bfe3c3SThomas Graf static void nlattr_set(struct nlattr *attr, u8 val,
177481bfe3c3SThomas Graf const struct ovs_len_tbl *tbl)
1775e6445719SPravin B Shelar {
1776f47de068SPravin B Shelar struct nlattr *nla;
1777f47de068SPravin B Shelar int rem;
1778e6445719SPravin B Shelar
1779f47de068SPravin B Shelar /* The nlattr stream should already have been validated */
1780f47de068SPravin B Shelar nla_for_each_nested(nla, attr, rem) {
178172f17bafSStefano Brivio if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED)
178272f17bafSStefano Brivio nlattr_set(nla, val, tbl[nla_type(nla)].next ? : tbl);
178372f17bafSStefano Brivio else
1784f47de068SPravin B Shelar memset(nla_data(nla), val, nla_len(nla));
17859e384715SJoe Stringer
17869e384715SJoe Stringer if (nla_type(nla) == OVS_KEY_ATTR_CT_STATE)
17879e384715SJoe Stringer *(u32 *)nla_data(nla) &= CT_SUPPORTED_MASK;
1788f47de068SPravin B Shelar }
1789982b5270SJesse Gross }
1790f47de068SPravin B Shelar
mask_set_nlattr(struct nlattr * attr,u8 val)1791f47de068SPravin B Shelar static void mask_set_nlattr(struct nlattr *attr, u8 val)
1792f47de068SPravin B Shelar {
179381bfe3c3SThomas Graf nlattr_set(attr, val, ovs_key_lens);
1794e6445719SPravin B Shelar }
1795e6445719SPravin B Shelar
1796e6445719SPravin B Shelar /**
1797e6445719SPravin B Shelar * ovs_nla_get_match - parses Netlink attributes into a flow key and
1798e6445719SPravin B Shelar * mask. In case the 'mask' is NULL, the flow is treated as exact match
1799e6445719SPravin B Shelar * flow. Otherwise, it is treated as a wildcarded flow, except the mask
1800e6445719SPravin B Shelar * does not include any don't care bit.
1801c2ac6673SJoe Stringer * @net: Used to determine per-namespace field support.
1802e6445719SPravin B Shelar * @match: receives the extracted flow match information.
180396678514SAndrew Lunn * @nla_key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute
1804e6445719SPravin B Shelar * sequence. The fields should of the packet that triggered the creation
1805e6445719SPravin B Shelar * of this flow.
180696678514SAndrew Lunn * @nla_mask: Optional. Netlink attribute holding nested %OVS_KEY_ATTR_*
180796678514SAndrew Lunn * Netlink attribute specifies the mask field of the wildcarded flow.
180805da5898SJarno Rajahalme * @log: Boolean to allow kernel error logging. Normally true, but when
180905da5898SJarno Rajahalme * probing for feature compatibility this should be passed in as false to
181005da5898SJarno Rajahalme * suppress unnecessary error logging.
1811e6445719SPravin B Shelar */
ovs_nla_get_match(struct net * net,struct sw_flow_match * match,const struct nlattr * nla_key,const struct nlattr * nla_mask,bool log)1812c2ac6673SJoe Stringer int ovs_nla_get_match(struct net *net, struct sw_flow_match *match,
1813a85311bfSPravin B Shelar const struct nlattr *nla_key,
181405da5898SJarno Rajahalme const struct nlattr *nla_mask,
181505da5898SJarno Rajahalme bool log)
1816e6445719SPravin B Shelar {
1817e6445719SPravin B Shelar const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
1818f47de068SPravin B Shelar struct nlattr *newmask = NULL;
1819e6445719SPravin B Shelar u64 key_attrs = 0;
1820e6445719SPravin B Shelar u64 mask_attrs = 0;
1821e6445719SPravin B Shelar int err;
1822e6445719SPravin B Shelar
182305da5898SJarno Rajahalme err = parse_flow_nlattrs(nla_key, a, &key_attrs, log);
1824e6445719SPravin B Shelar if (err)
1825e6445719SPravin B Shelar return err;
1826e6445719SPravin B Shelar
1827018c1ddaSEric Garver err = parse_vlan_from_nlattrs(match, &key_attrs, a, false, log);
1828e6445719SPravin B Shelar if (err)
1829e6445719SPravin B Shelar return err;
1830e6445719SPravin B Shelar
1831c2ac6673SJoe Stringer err = ovs_key_from_nlattrs(net, match, key_attrs, a, false, log);
1832e6445719SPravin B Shelar if (err)
1833e6445719SPravin B Shelar return err;
1834e6445719SPravin B Shelar
1835a85311bfSPravin B Shelar if (match->mask) {
1836a85311bfSPravin B Shelar if (!nla_mask) {
1837a85311bfSPravin B Shelar /* Create an exact match mask. We need to set to 0xff
1838a85311bfSPravin B Shelar * all the 'match->mask' fields that have been touched
1839a85311bfSPravin B Shelar * in 'match->key'. We cannot simply memset
1840a85311bfSPravin B Shelar * 'match->mask', because padding bytes and fields not
1841a85311bfSPravin B Shelar * specified in 'match->key' should be left to 0.
1842a85311bfSPravin B Shelar * Instead, we use a stream of netlink attributes,
1843a85311bfSPravin B Shelar * copied from 'key' and set to 0xff.
1844a85311bfSPravin B Shelar * ovs_key_from_nlattrs() will take care of filling
1845a85311bfSPravin B Shelar * 'match->mask' appropriately.
1846f47de068SPravin B Shelar */
1847a85311bfSPravin B Shelar newmask = kmemdup(nla_key,
1848a85311bfSPravin B Shelar nla_total_size(nla_len(nla_key)),
1849f47de068SPravin B Shelar GFP_KERNEL);
1850f47de068SPravin B Shelar if (!newmask)
1851f47de068SPravin B Shelar return -ENOMEM;
1852f47de068SPravin B Shelar
1853f47de068SPravin B Shelar mask_set_nlattr(newmask, 0xff);
1854f47de068SPravin B Shelar
1855a85311bfSPravin B Shelar /* The userspace does not send tunnel attributes that
1856a85311bfSPravin B Shelar * are 0, but we should not wildcard them nonetheless.
1857f47de068SPravin B Shelar */
185800a93babSJiri Benc if (match->key->tun_proto)
1859a85311bfSPravin B Shelar SW_FLOW_KEY_MEMSET_FIELD(match, tun_key,
1860a85311bfSPravin B Shelar 0xff, true);
1861f47de068SPravin B Shelar
1862a85311bfSPravin B Shelar nla_mask = newmask;
1863f47de068SPravin B Shelar }
1864f47de068SPravin B Shelar
186505da5898SJarno Rajahalme err = parse_flow_mask_nlattrs(nla_mask, a, &mask_attrs, log);
1866e6445719SPravin B Shelar if (err)
1867f47de068SPravin B Shelar goto free_newmask;
1868e6445719SPravin B Shelar
1869a85311bfSPravin B Shelar /* Always match on tci. */
1870018c1ddaSEric Garver SW_FLOW_KEY_PUT(match, eth.vlan.tci, htons(0xffff), true);
1871018c1ddaSEric Garver SW_FLOW_KEY_PUT(match, eth.cvlan.tci, htons(0xffff), true);
1872a85311bfSPravin B Shelar
1873018c1ddaSEric Garver err = parse_vlan_from_nlattrs(match, &mask_attrs, a, true, log);
1874f47de068SPravin B Shelar if (err)
1875f47de068SPravin B Shelar goto free_newmask;
1876e6445719SPravin B Shelar
1877c2ac6673SJoe Stringer err = ovs_key_from_nlattrs(net, match, mask_attrs, a, true,
1878c2ac6673SJoe Stringer log);
1879e6445719SPravin B Shelar if (err)
1880f47de068SPravin B Shelar goto free_newmask;
1881e6445719SPravin B Shelar }
1882e6445719SPravin B Shelar
188305da5898SJarno Rajahalme if (!match_validate(match, key_attrs, mask_attrs, log))
1884f47de068SPravin B Shelar err = -EINVAL;
1885e6445719SPravin B Shelar
1886f47de068SPravin B Shelar free_newmask:
1887f47de068SPravin B Shelar kfree(newmask);
1888f47de068SPravin B Shelar return err;
1889e6445719SPravin B Shelar }
1890e6445719SPravin B Shelar
get_ufid_len(const struct nlattr * attr,bool log)189174ed7ab9SJoe Stringer static size_t get_ufid_len(const struct nlattr *attr, bool log)
189274ed7ab9SJoe Stringer {
189374ed7ab9SJoe Stringer size_t len;
189474ed7ab9SJoe Stringer
189574ed7ab9SJoe Stringer if (!attr)
189674ed7ab9SJoe Stringer return 0;
189774ed7ab9SJoe Stringer
189874ed7ab9SJoe Stringer len = nla_len(attr);
189974ed7ab9SJoe Stringer if (len < 1 || len > MAX_UFID_LENGTH) {
190074ed7ab9SJoe Stringer OVS_NLERR(log, "ufid size %u bytes exceeds the range (1, %d)",
190174ed7ab9SJoe Stringer nla_len(attr), MAX_UFID_LENGTH);
190274ed7ab9SJoe Stringer return 0;
190374ed7ab9SJoe Stringer }
190474ed7ab9SJoe Stringer
190574ed7ab9SJoe Stringer return len;
190674ed7ab9SJoe Stringer }
190774ed7ab9SJoe Stringer
190874ed7ab9SJoe Stringer /* Initializes 'flow->ufid', returning true if 'attr' contains a valid UFID,
190974ed7ab9SJoe Stringer * or false otherwise.
191074ed7ab9SJoe Stringer */
ovs_nla_get_ufid(struct sw_flow_id * sfid,const struct nlattr * attr,bool log)191174ed7ab9SJoe Stringer bool ovs_nla_get_ufid(struct sw_flow_id *sfid, const struct nlattr *attr,
191274ed7ab9SJoe Stringer bool log)
191374ed7ab9SJoe Stringer {
191474ed7ab9SJoe Stringer sfid->ufid_len = get_ufid_len(attr, log);
191574ed7ab9SJoe Stringer if (sfid->ufid_len)
191674ed7ab9SJoe Stringer memcpy(sfid->ufid, nla_data(attr), sfid->ufid_len);
191774ed7ab9SJoe Stringer
191874ed7ab9SJoe Stringer return sfid->ufid_len;
191974ed7ab9SJoe Stringer }
192074ed7ab9SJoe Stringer
ovs_nla_get_identifier(struct sw_flow_id * sfid,const struct nlattr * ufid,const struct sw_flow_key * key,bool log)192174ed7ab9SJoe Stringer int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid,
192274ed7ab9SJoe Stringer const struct sw_flow_key *key, bool log)
192374ed7ab9SJoe Stringer {
192474ed7ab9SJoe Stringer struct sw_flow_key *new_key;
192574ed7ab9SJoe Stringer
192674ed7ab9SJoe Stringer if (ovs_nla_get_ufid(sfid, ufid, log))
192774ed7ab9SJoe Stringer return 0;
192874ed7ab9SJoe Stringer
192974ed7ab9SJoe Stringer /* If UFID was not provided, use unmasked key. */
193074ed7ab9SJoe Stringer new_key = kmalloc(sizeof(*new_key), GFP_KERNEL);
193174ed7ab9SJoe Stringer if (!new_key)
193274ed7ab9SJoe Stringer return -ENOMEM;
193374ed7ab9SJoe Stringer memcpy(new_key, key, sizeof(*key));
193474ed7ab9SJoe Stringer sfid->unmasked_key = new_key;
193574ed7ab9SJoe Stringer
193674ed7ab9SJoe Stringer return 0;
193774ed7ab9SJoe Stringer }
193874ed7ab9SJoe Stringer
ovs_nla_get_ufid_flags(const struct nlattr * attr)193974ed7ab9SJoe Stringer u32 ovs_nla_get_ufid_flags(const struct nlattr *attr)
194074ed7ab9SJoe Stringer {
194174ed7ab9SJoe Stringer return attr ? nla_get_u32(attr) : 0;
194274ed7ab9SJoe Stringer }
194374ed7ab9SJoe Stringer
1944e6445719SPravin B Shelar /**
1945e6445719SPravin B Shelar * ovs_nla_get_flow_metadata - parses Netlink attributes into a flow key.
19469dd7f890SJarno Rajahalme * @net: Network namespace.
19479dd7f890SJarno Rajahalme * @key: Receives extracted in_port, priority, tun_key, skb_mark and conntrack
19489dd7f890SJarno Rajahalme * metadata.
19499dd7f890SJarno Rajahalme * @a: Array of netlink attributes holding parsed %OVS_KEY_ATTR_* Netlink
19509dd7f890SJarno Rajahalme * attributes.
19519dd7f890SJarno Rajahalme * @attrs: Bit mask for the netlink attributes included in @a.
195205da5898SJarno Rajahalme * @log: Boolean to allow kernel error logging. Normally true, but when
195305da5898SJarno Rajahalme * probing for feature compatibility this should be passed in as false to
195405da5898SJarno Rajahalme * suppress unnecessary error logging.
1955e6445719SPravin B Shelar *
1956e6445719SPravin B Shelar * This parses a series of Netlink attributes that form a flow key, which must
1957e6445719SPravin B Shelar * take the same form accepted by flow_from_nlattrs(), but only enough of it to
1958e6445719SPravin B Shelar * get the metadata, that is, the parts of the flow key that cannot be
1959e6445719SPravin B Shelar * extracted from the packet itself.
19609dd7f890SJarno Rajahalme *
19619dd7f890SJarno Rajahalme * This must be called before the packet key fields are filled in 'key'.
1962e6445719SPravin B Shelar */
1963e6445719SPravin B Shelar
ovs_nla_get_flow_metadata(struct net * net,const struct nlattr * a[OVS_KEY_ATTR_MAX+1],u64 attrs,struct sw_flow_key * key,bool log)19649dd7f890SJarno Rajahalme int ovs_nla_get_flow_metadata(struct net *net,
19659dd7f890SJarno Rajahalme const struct nlattr *a[OVS_KEY_ATTR_MAX + 1],
19669dd7f890SJarno Rajahalme u64 attrs, struct sw_flow_key *key, bool log)
1967e6445719SPravin B Shelar {
196883c8df26SPravin B Shelar struct sw_flow_match match;
1969e6445719SPravin B Shelar
1970e6445719SPravin B Shelar memset(&match, 0, sizeof(match));
197183c8df26SPravin B Shelar match.key = key;
1972e6445719SPravin B Shelar
1973316d4d78SJarno Rajahalme key->ct_state = 0;
1974316d4d78SJarno Rajahalme key->ct_zone = 0;
1975316d4d78SJarno Rajahalme key->ct_orig_proto = 0;
19767f8a436eSJoe Stringer memset(&key->ct, 0, sizeof(key->ct));
19779dd7f890SJarno Rajahalme memset(&key->ipv4.ct_orig, 0, sizeof(key->ipv4.ct_orig));
19789dd7f890SJarno Rajahalme memset(&key->ipv6.ct_orig, 0, sizeof(key->ipv6.ct_orig));
19799dd7f890SJarno Rajahalme
198083c8df26SPravin B Shelar key->phy.in_port = DP_MAX_PORTS;
1981e6445719SPravin B Shelar
1982c2ac6673SJoe Stringer return metadata_from_nlattrs(net, &match, &attrs, a, false, log);
1983e6445719SPravin B Shelar }
1984e6445719SPravin B Shelar
ovs_nla_put_vlan(struct sk_buff * skb,const struct vlan_head * vh,bool is_mask)1985018c1ddaSEric Garver static int ovs_nla_put_vlan(struct sk_buff *skb, const struct vlan_head *vh,
1986018c1ddaSEric Garver bool is_mask)
1987018c1ddaSEric Garver {
1988018c1ddaSEric Garver __be16 eth_type = !is_mask ? vh->tpid : htons(0xffff);
1989018c1ddaSEric Garver
1990018c1ddaSEric Garver if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, eth_type) ||
1991018c1ddaSEric Garver nla_put_be16(skb, OVS_KEY_ATTR_VLAN, vh->tci))
1992018c1ddaSEric Garver return -EMSGSIZE;
1993018c1ddaSEric Garver return 0;
1994018c1ddaSEric Garver }
1995018c1ddaSEric Garver
nsh_key_to_nlattr(const struct ovs_key_nsh * nsh,bool is_mask,struct sk_buff * skb)1996b2d0f5d5SYi Yang static int nsh_key_to_nlattr(const struct ovs_key_nsh *nsh, bool is_mask,
1997b2d0f5d5SYi Yang struct sk_buff *skb)
1998b2d0f5d5SYi Yang {
1999b2d0f5d5SYi Yang struct nlattr *start;
2000b2d0f5d5SYi Yang
2001ae0be8deSMichal Kubecek start = nla_nest_start_noflag(skb, OVS_KEY_ATTR_NSH);
2002b2d0f5d5SYi Yang if (!start)
2003b2d0f5d5SYi Yang return -EMSGSIZE;
2004b2d0f5d5SYi Yang
2005b2d0f5d5SYi Yang if (nla_put(skb, OVS_NSH_KEY_ATTR_BASE, sizeof(nsh->base), &nsh->base))
2006b2d0f5d5SYi Yang goto nla_put_failure;
2007b2d0f5d5SYi Yang
2008b2d0f5d5SYi Yang if (is_mask || nsh->base.mdtype == NSH_M_TYPE1) {
2009b2d0f5d5SYi Yang if (nla_put(skb, OVS_NSH_KEY_ATTR_MD1,
2010b2d0f5d5SYi Yang sizeof(nsh->context), nsh->context))
2011b2d0f5d5SYi Yang goto nla_put_failure;
2012b2d0f5d5SYi Yang }
2013b2d0f5d5SYi Yang
2014b2d0f5d5SYi Yang /* Don't support MD type 2 yet */
2015b2d0f5d5SYi Yang
2016b2d0f5d5SYi Yang nla_nest_end(skb, start);
2017b2d0f5d5SYi Yang
2018b2d0f5d5SYi Yang return 0;
2019b2d0f5d5SYi Yang
2020b2d0f5d5SYi Yang nla_put_failure:
2021b2d0f5d5SYi Yang return -EMSGSIZE;
2022b2d0f5d5SYi Yang }
2023b2d0f5d5SYi Yang
__ovs_nla_put_key(const struct sw_flow_key * swkey,const struct sw_flow_key * output,bool is_mask,struct sk_buff * skb)20245b4237bbSJoe Stringer static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
20255b4237bbSJoe Stringer const struct sw_flow_key *output, bool is_mask,
20265b4237bbSJoe Stringer struct sk_buff *skb)
2027e6445719SPravin B Shelar {
2028e6445719SPravin B Shelar struct ovs_key_ethernet *eth_key;
2029018c1ddaSEric Garver struct nlattr *nla;
2030018c1ddaSEric Garver struct nlattr *encap = NULL;
2031018c1ddaSEric Garver struct nlattr *in_encap = NULL;
2032e6445719SPravin B Shelar
2033971427f3SAndy Zhou if (nla_put_u32(skb, OVS_KEY_ATTR_RECIRC_ID, output->recirc_id))
2034971427f3SAndy Zhou goto nla_put_failure;
2035971427f3SAndy Zhou
2036971427f3SAndy Zhou if (nla_put_u32(skb, OVS_KEY_ATTR_DP_HASH, output->ovs_flow_hash))
2037971427f3SAndy Zhou goto nla_put_failure;
2038971427f3SAndy Zhou
2039e6445719SPravin B Shelar if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority))
2040e6445719SPravin B Shelar goto nla_put_failure;
2041e6445719SPravin B Shelar
204200a93babSJiri Benc if ((swkey->tun_proto || is_mask)) {
2043d91641d9SThomas Graf const void *opts = NULL;
2044f5796684SJesse Gross
20455832c4a7SAlexander Lobakin if (ip_tunnel_is_options_present(output->tun_key.tun_flags))
2046d91641d9SThomas Graf opts = TUN_METADATA_OPTS(output, swkey->tun_opts_len);
2047f5796684SJesse Gross
20486b26ba3aSJiri Benc if (ip_tun_to_nlattr(skb, &output->tun_key, opts,
204918b6f717Swenxu swkey->tun_opts_len, swkey->tun_proto, 0))
2050e6445719SPravin B Shelar goto nla_put_failure;
2051f5796684SJesse Gross }
2052e6445719SPravin B Shelar
2053e6445719SPravin B Shelar if (swkey->phy.in_port == DP_MAX_PORTS) {
2054e6445719SPravin B Shelar if (is_mask && (output->phy.in_port == 0xffff))
2055e6445719SPravin B Shelar if (nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, 0xffffffff))
2056e6445719SPravin B Shelar goto nla_put_failure;
2057e6445719SPravin B Shelar } else {
2058e6445719SPravin B Shelar u16 upper_u16;
2059e6445719SPravin B Shelar upper_u16 = !is_mask ? 0 : 0xffff;
2060e6445719SPravin B Shelar
2061e6445719SPravin B Shelar if (nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT,
2062e6445719SPravin B Shelar (upper_u16 << 16) | output->phy.in_port))
2063e6445719SPravin B Shelar goto nla_put_failure;
2064e6445719SPravin B Shelar }
2065e6445719SPravin B Shelar
2066e6445719SPravin B Shelar if (nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, output->phy.skb_mark))
2067e6445719SPravin B Shelar goto nla_put_failure;
2068e6445719SPravin B Shelar
20699dd7f890SJarno Rajahalme if (ovs_ct_put_key(swkey, output, skb))
20707f8a436eSJoe Stringer goto nla_put_failure;
20717f8a436eSJoe Stringer
20720a6410fbSJiri Benc if (ovs_key_mac_proto(swkey) == MAC_PROTO_ETHERNET) {
2073e6445719SPravin B Shelar nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
2074e6445719SPravin B Shelar if (!nla)
2075e6445719SPravin B Shelar goto nla_put_failure;
2076e6445719SPravin B Shelar
2077e6445719SPravin B Shelar eth_key = nla_data(nla);
20788c63ff09SJoe Perches ether_addr_copy(eth_key->eth_src, output->eth.src);
20798c63ff09SJoe Perches ether_addr_copy(eth_key->eth_dst, output->eth.dst);
2080e6445719SPravin B Shelar
2081018c1ddaSEric Garver if (swkey->eth.vlan.tci || eth_type_vlan(swkey->eth.type)) {
2082018c1ddaSEric Garver if (ovs_nla_put_vlan(skb, &output->eth.vlan, is_mask))
2083e6445719SPravin B Shelar goto nla_put_failure;
2084ae0be8deSMichal Kubecek encap = nla_nest_start_noflag(skb, OVS_KEY_ATTR_ENCAP);
2085018c1ddaSEric Garver if (!swkey->eth.vlan.tci)
2086e6445719SPravin B Shelar goto unencap;
2087018c1ddaSEric Garver
2088018c1ddaSEric Garver if (swkey->eth.cvlan.tci || eth_type_vlan(swkey->eth.type)) {
2089018c1ddaSEric Garver if (ovs_nla_put_vlan(skb, &output->eth.cvlan, is_mask))
2090018c1ddaSEric Garver goto nla_put_failure;
2091ae0be8deSMichal Kubecek in_encap = nla_nest_start_noflag(skb,
2092ae0be8deSMichal Kubecek OVS_KEY_ATTR_ENCAP);
2093018c1ddaSEric Garver if (!swkey->eth.cvlan.tci)
2094018c1ddaSEric Garver goto unencap;
2095018c1ddaSEric Garver }
2096018c1ddaSEric Garver }
2097e6445719SPravin B Shelar
2098e6445719SPravin B Shelar if (swkey->eth.type == htons(ETH_P_802_2)) {
2099e6445719SPravin B Shelar /*
2100e6445719SPravin B Shelar * Ethertype 802.2 is represented in the netlink with omitted
2101e6445719SPravin B Shelar * OVS_KEY_ATTR_ETHERTYPE in the flow key attribute, and
2102e6445719SPravin B Shelar * 0xffff in the mask attribute. Ethertype can also
2103e6445719SPravin B Shelar * be wildcarded.
2104e6445719SPravin B Shelar */
2105e6445719SPravin B Shelar if (is_mask && output->eth.type)
2106e6445719SPravin B Shelar if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE,
2107e6445719SPravin B Shelar output->eth.type))
2108e6445719SPravin B Shelar goto nla_put_failure;
2109e6445719SPravin B Shelar goto unencap;
2110e6445719SPravin B Shelar }
21110a6410fbSJiri Benc }
2112e6445719SPravin B Shelar
2113e6445719SPravin B Shelar if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, output->eth.type))
2114e6445719SPravin B Shelar goto nla_put_failure;
2115e6445719SPravin B Shelar
2116018c1ddaSEric Garver if (eth_type_vlan(swkey->eth.type)) {
2117018c1ddaSEric Garver /* There are 3 VLAN tags, we don't know anything about the rest
2118018c1ddaSEric Garver * of the packet, so truncate here.
2119018c1ddaSEric Garver */
2120018c1ddaSEric Garver WARN_ON_ONCE(!(encap && in_encap));
2121018c1ddaSEric Garver goto unencap;
2122018c1ddaSEric Garver }
2123018c1ddaSEric Garver
2124e6445719SPravin B Shelar if (swkey->eth.type == htons(ETH_P_IP)) {
2125e6445719SPravin B Shelar struct ovs_key_ipv4 *ipv4_key;
2126e6445719SPravin B Shelar
2127e6445719SPravin B Shelar nla = nla_reserve(skb, OVS_KEY_ATTR_IPV4, sizeof(*ipv4_key));
2128e6445719SPravin B Shelar if (!nla)
2129e6445719SPravin B Shelar goto nla_put_failure;
2130e6445719SPravin B Shelar ipv4_key = nla_data(nla);
2131e6445719SPravin B Shelar ipv4_key->ipv4_src = output->ipv4.addr.src;
2132e6445719SPravin B Shelar ipv4_key->ipv4_dst = output->ipv4.addr.dst;
2133e6445719SPravin B Shelar ipv4_key->ipv4_proto = output->ip.proto;
2134e6445719SPravin B Shelar ipv4_key->ipv4_tos = output->ip.tos;
2135e6445719SPravin B Shelar ipv4_key->ipv4_ttl = output->ip.ttl;
2136e6445719SPravin B Shelar ipv4_key->ipv4_frag = output->ip.frag;
2137e6445719SPravin B Shelar } else if (swkey->eth.type == htons(ETH_P_IPV6)) {
2138e6445719SPravin B Shelar struct ovs_key_ipv6 *ipv6_key;
213928a3f060SToms Atteka struct ovs_key_ipv6_exthdrs *ipv6_exthdrs_key;
2140e6445719SPravin B Shelar
2141e6445719SPravin B Shelar nla = nla_reserve(skb, OVS_KEY_ATTR_IPV6, sizeof(*ipv6_key));
2142e6445719SPravin B Shelar if (!nla)
2143e6445719SPravin B Shelar goto nla_put_failure;
2144e6445719SPravin B Shelar ipv6_key = nla_data(nla);
2145e6445719SPravin B Shelar memcpy(ipv6_key->ipv6_src, &output->ipv6.addr.src,
2146e6445719SPravin B Shelar sizeof(ipv6_key->ipv6_src));
2147e6445719SPravin B Shelar memcpy(ipv6_key->ipv6_dst, &output->ipv6.addr.dst,
2148e6445719SPravin B Shelar sizeof(ipv6_key->ipv6_dst));
2149e6445719SPravin B Shelar ipv6_key->ipv6_label = output->ipv6.label;
2150e6445719SPravin B Shelar ipv6_key->ipv6_proto = output->ip.proto;
2151e6445719SPravin B Shelar ipv6_key->ipv6_tclass = output->ip.tos;
2152e6445719SPravin B Shelar ipv6_key->ipv6_hlimit = output->ip.ttl;
2153e6445719SPravin B Shelar ipv6_key->ipv6_frag = output->ip.frag;
215428a3f060SToms Atteka
215528a3f060SToms Atteka nla = nla_reserve(skb, OVS_KEY_ATTR_IPV6_EXTHDRS,
215628a3f060SToms Atteka sizeof(*ipv6_exthdrs_key));
215728a3f060SToms Atteka if (!nla)
215828a3f060SToms Atteka goto nla_put_failure;
215928a3f060SToms Atteka ipv6_exthdrs_key = nla_data(nla);
216028a3f060SToms Atteka ipv6_exthdrs_key->hdrs = output->ipv6.exthdrs;
2161b2d0f5d5SYi Yang } else if (swkey->eth.type == htons(ETH_P_NSH)) {
2162b2d0f5d5SYi Yang if (nsh_key_to_nlattr(&output->nsh, is_mask, skb))
2163b2d0f5d5SYi Yang goto nla_put_failure;
2164e6445719SPravin B Shelar } else if (swkey->eth.type == htons(ETH_P_ARP) ||
2165e6445719SPravin B Shelar swkey->eth.type == htons(ETH_P_RARP)) {
2166e6445719SPravin B Shelar struct ovs_key_arp *arp_key;
2167e6445719SPravin B Shelar
2168e6445719SPravin B Shelar nla = nla_reserve(skb, OVS_KEY_ATTR_ARP, sizeof(*arp_key));
2169e6445719SPravin B Shelar if (!nla)
2170e6445719SPravin B Shelar goto nla_put_failure;
2171e6445719SPravin B Shelar arp_key = nla_data(nla);
2172e6445719SPravin B Shelar memset(arp_key, 0, sizeof(struct ovs_key_arp));
2173e6445719SPravin B Shelar arp_key->arp_sip = output->ipv4.addr.src;
2174e6445719SPravin B Shelar arp_key->arp_tip = output->ipv4.addr.dst;
2175e6445719SPravin B Shelar arp_key->arp_op = htons(output->ip.proto);
21768c63ff09SJoe Perches ether_addr_copy(arp_key->arp_sha, output->ipv4.arp.sha);
21778c63ff09SJoe Perches ether_addr_copy(arp_key->arp_tha, output->ipv4.arp.tha);
217825cd9ba0SSimon Horman } else if (eth_p_mpls(swkey->eth.type)) {
2179fbdcdd78SMartin Varghese u8 i, num_labels;
218025cd9ba0SSimon Horman struct ovs_key_mpls *mpls_key;
218125cd9ba0SSimon Horman
2182fbdcdd78SMartin Varghese num_labels = hweight_long(output->mpls.num_labels_mask);
2183fbdcdd78SMartin Varghese nla = nla_reserve(skb, OVS_KEY_ATTR_MPLS,
2184fbdcdd78SMartin Varghese num_labels * sizeof(*mpls_key));
218525cd9ba0SSimon Horman if (!nla)
218625cd9ba0SSimon Horman goto nla_put_failure;
2187fbdcdd78SMartin Varghese
218825cd9ba0SSimon Horman mpls_key = nla_data(nla);
2189fbdcdd78SMartin Varghese for (i = 0; i < num_labels; i++)
2190fbdcdd78SMartin Varghese mpls_key[i].mpls_lse = output->mpls.lse[i];
2191e6445719SPravin B Shelar }
2192e6445719SPravin B Shelar
2193e6445719SPravin B Shelar if ((swkey->eth.type == htons(ETH_P_IP) ||
2194e6445719SPravin B Shelar swkey->eth.type == htons(ETH_P_IPV6)) &&
2195e6445719SPravin B Shelar swkey->ip.frag != OVS_FRAG_TYPE_LATER) {
2196e6445719SPravin B Shelar
2197e6445719SPravin B Shelar if (swkey->ip.proto == IPPROTO_TCP) {
2198e6445719SPravin B Shelar struct ovs_key_tcp *tcp_key;
2199e6445719SPravin B Shelar
2200e6445719SPravin B Shelar nla = nla_reserve(skb, OVS_KEY_ATTR_TCP, sizeof(*tcp_key));
2201e6445719SPravin B Shelar if (!nla)
2202e6445719SPravin B Shelar goto nla_put_failure;
2203e6445719SPravin B Shelar tcp_key = nla_data(nla);
22041139e241SJarno Rajahalme tcp_key->tcp_src = output->tp.src;
22051139e241SJarno Rajahalme tcp_key->tcp_dst = output->tp.dst;
22065eb26b15SJarno Rajahalme if (nla_put_be16(skb, OVS_KEY_ATTR_TCP_FLAGS,
22071139e241SJarno Rajahalme output->tp.flags))
22085eb26b15SJarno Rajahalme goto nla_put_failure;
2209e6445719SPravin B Shelar } else if (swkey->ip.proto == IPPROTO_UDP) {
2210e6445719SPravin B Shelar struct ovs_key_udp *udp_key;
2211e6445719SPravin B Shelar
2212e6445719SPravin B Shelar nla = nla_reserve(skb, OVS_KEY_ATTR_UDP, sizeof(*udp_key));
2213e6445719SPravin B Shelar if (!nla)
2214e6445719SPravin B Shelar goto nla_put_failure;
2215e6445719SPravin B Shelar udp_key = nla_data(nla);
22161139e241SJarno Rajahalme udp_key->udp_src = output->tp.src;
22171139e241SJarno Rajahalme udp_key->udp_dst = output->tp.dst;
2218e6445719SPravin B Shelar } else if (swkey->ip.proto == IPPROTO_SCTP) {
2219e6445719SPravin B Shelar struct ovs_key_sctp *sctp_key;
2220e6445719SPravin B Shelar
2221e6445719SPravin B Shelar nla = nla_reserve(skb, OVS_KEY_ATTR_SCTP, sizeof(*sctp_key));
2222e6445719SPravin B Shelar if (!nla)
2223e6445719SPravin B Shelar goto nla_put_failure;
2224e6445719SPravin B Shelar sctp_key = nla_data(nla);
22251139e241SJarno Rajahalme sctp_key->sctp_src = output->tp.src;
22261139e241SJarno Rajahalme sctp_key->sctp_dst = output->tp.dst;
2227e6445719SPravin B Shelar } else if (swkey->eth.type == htons(ETH_P_IP) &&
2228e6445719SPravin B Shelar swkey->ip.proto == IPPROTO_ICMP) {
2229e6445719SPravin B Shelar struct ovs_key_icmp *icmp_key;
2230e6445719SPravin B Shelar
2231e6445719SPravin B Shelar nla = nla_reserve(skb, OVS_KEY_ATTR_ICMP, sizeof(*icmp_key));
2232e6445719SPravin B Shelar if (!nla)
2233e6445719SPravin B Shelar goto nla_put_failure;
2234e6445719SPravin B Shelar icmp_key = nla_data(nla);
22351139e241SJarno Rajahalme icmp_key->icmp_type = ntohs(output->tp.src);
22361139e241SJarno Rajahalme icmp_key->icmp_code = ntohs(output->tp.dst);
2237e6445719SPravin B Shelar } else if (swkey->eth.type == htons(ETH_P_IPV6) &&
2238e6445719SPravin B Shelar swkey->ip.proto == IPPROTO_ICMPV6) {
2239e6445719SPravin B Shelar struct ovs_key_icmpv6 *icmpv6_key;
2240e6445719SPravin B Shelar
2241e6445719SPravin B Shelar nla = nla_reserve(skb, OVS_KEY_ATTR_ICMPV6,
2242e6445719SPravin B Shelar sizeof(*icmpv6_key));
2243e6445719SPravin B Shelar if (!nla)
2244e6445719SPravin B Shelar goto nla_put_failure;
2245e6445719SPravin B Shelar icmpv6_key = nla_data(nla);
22461139e241SJarno Rajahalme icmpv6_key->icmpv6_type = ntohs(output->tp.src);
22471139e241SJarno Rajahalme icmpv6_key->icmpv6_code = ntohs(output->tp.dst);
2248e6445719SPravin B Shelar
2249f19c4445SMartin Varghese if (swkey->tp.src == htons(NDISC_NEIGHBOUR_SOLICITATION) ||
2250f19c4445SMartin Varghese swkey->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) {
2251e6445719SPravin B Shelar struct ovs_key_nd *nd_key;
2252e6445719SPravin B Shelar
2253e6445719SPravin B Shelar nla = nla_reserve(skb, OVS_KEY_ATTR_ND, sizeof(*nd_key));
2254e6445719SPravin B Shelar if (!nla)
2255e6445719SPravin B Shelar goto nla_put_failure;
2256e6445719SPravin B Shelar nd_key = nla_data(nla);
2257e6445719SPravin B Shelar memcpy(nd_key->nd_target, &output->ipv6.nd.target,
2258e6445719SPravin B Shelar sizeof(nd_key->nd_target));
22598c63ff09SJoe Perches ether_addr_copy(nd_key->nd_sll, output->ipv6.nd.sll);
22608c63ff09SJoe Perches ether_addr_copy(nd_key->nd_tll, output->ipv6.nd.tll);
2261e6445719SPravin B Shelar }
2262e6445719SPravin B Shelar }
2263e6445719SPravin B Shelar }
2264e6445719SPravin B Shelar
2265e6445719SPravin B Shelar unencap:
2266018c1ddaSEric Garver if (in_encap)
2267018c1ddaSEric Garver nla_nest_end(skb, in_encap);
2268e6445719SPravin B Shelar if (encap)
2269e6445719SPravin B Shelar nla_nest_end(skb, encap);
2270e6445719SPravin B Shelar
2271e6445719SPravin B Shelar return 0;
2272e6445719SPravin B Shelar
2273e6445719SPravin B Shelar nla_put_failure:
2274e6445719SPravin B Shelar return -EMSGSIZE;
2275e6445719SPravin B Shelar }
2276e6445719SPravin B Shelar
ovs_nla_put_key(const struct sw_flow_key * swkey,const struct sw_flow_key * output,int attr,bool is_mask,struct sk_buff * skb)22775b4237bbSJoe Stringer int ovs_nla_put_key(const struct sw_flow_key *swkey,
22785b4237bbSJoe Stringer const struct sw_flow_key *output, int attr, bool is_mask,
22795b4237bbSJoe Stringer struct sk_buff *skb)
22805b4237bbSJoe Stringer {
22815b4237bbSJoe Stringer int err;
22825b4237bbSJoe Stringer struct nlattr *nla;
22835b4237bbSJoe Stringer
2284ae0be8deSMichal Kubecek nla = nla_nest_start_noflag(skb, attr);
22855b4237bbSJoe Stringer if (!nla)
22865b4237bbSJoe Stringer return -EMSGSIZE;
22875b4237bbSJoe Stringer err = __ovs_nla_put_key(swkey, output, is_mask, skb);
22885b4237bbSJoe Stringer if (err)
22895b4237bbSJoe Stringer return err;
22905b4237bbSJoe Stringer nla_nest_end(skb, nla);
22915b4237bbSJoe Stringer
22925b4237bbSJoe Stringer return 0;
22935b4237bbSJoe Stringer }
22945b4237bbSJoe Stringer
22955b4237bbSJoe Stringer /* Called with ovs_mutex or RCU read lock. */
ovs_nla_put_identifier(const struct sw_flow * flow,struct sk_buff * skb)229674ed7ab9SJoe Stringer int ovs_nla_put_identifier(const struct sw_flow *flow, struct sk_buff *skb)
22975b4237bbSJoe Stringer {
229874ed7ab9SJoe Stringer if (ovs_identifier_is_ufid(&flow->id))
229974ed7ab9SJoe Stringer return nla_put(skb, OVS_FLOW_ATTR_UFID, flow->id.ufid_len,
230074ed7ab9SJoe Stringer flow->id.ufid);
230174ed7ab9SJoe Stringer
230274ed7ab9SJoe Stringer return ovs_nla_put_key(flow->id.unmasked_key, flow->id.unmasked_key,
230374ed7ab9SJoe Stringer OVS_FLOW_ATTR_KEY, false, skb);
230474ed7ab9SJoe Stringer }
230574ed7ab9SJoe Stringer
230674ed7ab9SJoe Stringer /* Called with ovs_mutex or RCU read lock. */
ovs_nla_put_masked_key(const struct sw_flow * flow,struct sk_buff * skb)230774ed7ab9SJoe Stringer int ovs_nla_put_masked_key(const struct sw_flow *flow, struct sk_buff *skb)
230874ed7ab9SJoe Stringer {
230926ad0b83SPravin B Shelar return ovs_nla_put_key(&flow->key, &flow->key,
23105b4237bbSJoe Stringer OVS_FLOW_ATTR_KEY, false, skb);
23115b4237bbSJoe Stringer }
23125b4237bbSJoe Stringer
23135b4237bbSJoe Stringer /* Called with ovs_mutex or RCU read lock. */
ovs_nla_put_mask(const struct sw_flow * flow,struct sk_buff * skb)23145b4237bbSJoe Stringer int ovs_nla_put_mask(const struct sw_flow *flow, struct sk_buff *skb)
23155b4237bbSJoe Stringer {
23165b4237bbSJoe Stringer return ovs_nla_put_key(&flow->key, &flow->mask->key,
23175b4237bbSJoe Stringer OVS_FLOW_ATTR_MASK, true, skb);
23185b4237bbSJoe Stringer }
23195b4237bbSJoe Stringer
2320e6445719SPravin B Shelar #define MAX_ACTIONS_BUFSIZE (32 * 1024)
2321e6445719SPravin B Shelar
nla_alloc_flow_actions(int size)232267c8d22aSzhangliping static struct sw_flow_actions *nla_alloc_flow_actions(int size)
2323e6445719SPravin B Shelar {
2324e6445719SPravin B Shelar struct sw_flow_actions *sfa;
2325e6445719SPravin B Shelar
232667c8d22aSzhangliping WARN_ON_ONCE(size > MAX_ACTIONS_BUFSIZE);
2327e6445719SPravin B Shelar
2328ab3f7828SKees Cook sfa = kmalloc(kmalloc_size_roundup(sizeof(*sfa) + size), GFP_KERNEL);
2329e6445719SPravin B Shelar if (!sfa)
2330e6445719SPravin B Shelar return ERR_PTR(-ENOMEM);
2331e6445719SPravin B Shelar
2332e6445719SPravin B Shelar sfa->actions_len = 0;
2333e6445719SPravin B Shelar return sfa;
2334e6445719SPravin B Shelar }
2335e6445719SPravin B Shelar
23361f30fb91SIlya Maximets static void ovs_nla_free_nested_actions(const struct nlattr *actions, int len);
23371f30fb91SIlya Maximets
ovs_nla_free_check_pkt_len_action(const struct nlattr * action)23381f30fb91SIlya Maximets static void ovs_nla_free_check_pkt_len_action(const struct nlattr *action)
23391f30fb91SIlya Maximets {
23401f30fb91SIlya Maximets const struct nlattr *a;
23411f30fb91SIlya Maximets int rem;
23421f30fb91SIlya Maximets
23431f30fb91SIlya Maximets nla_for_each_nested(a, action, rem) {
23441f30fb91SIlya Maximets switch (nla_type(a)) {
23451f30fb91SIlya Maximets case OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL:
23461f30fb91SIlya Maximets case OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER:
23471f30fb91SIlya Maximets ovs_nla_free_nested_actions(nla_data(a), nla_len(a));
23481f30fb91SIlya Maximets break;
23491f30fb91SIlya Maximets }
23501f30fb91SIlya Maximets }
23511f30fb91SIlya Maximets }
23521f30fb91SIlya Maximets
ovs_nla_free_clone_action(const struct nlattr * action)23531f30fb91SIlya Maximets static void ovs_nla_free_clone_action(const struct nlattr *action)
23541f30fb91SIlya Maximets {
23551f30fb91SIlya Maximets const struct nlattr *a = nla_data(action);
23561f30fb91SIlya Maximets int rem = nla_len(action);
23571f30fb91SIlya Maximets
23581f30fb91SIlya Maximets switch (nla_type(a)) {
23591f30fb91SIlya Maximets case OVS_CLONE_ATTR_EXEC:
23601f30fb91SIlya Maximets /* The real list of actions follows this attribute. */
23611f30fb91SIlya Maximets a = nla_next(a, &rem);
23621f30fb91SIlya Maximets ovs_nla_free_nested_actions(a, rem);
23631f30fb91SIlya Maximets break;
23641f30fb91SIlya Maximets }
23651f30fb91SIlya Maximets }
23661f30fb91SIlya Maximets
ovs_nla_free_dec_ttl_action(const struct nlattr * action)23671f30fb91SIlya Maximets static void ovs_nla_free_dec_ttl_action(const struct nlattr *action)
23681f30fb91SIlya Maximets {
23691f30fb91SIlya Maximets const struct nlattr *a = nla_data(action);
23701f30fb91SIlya Maximets
23711f30fb91SIlya Maximets switch (nla_type(a)) {
23721f30fb91SIlya Maximets case OVS_DEC_TTL_ATTR_ACTION:
23731f30fb91SIlya Maximets ovs_nla_free_nested_actions(nla_data(a), nla_len(a));
23741f30fb91SIlya Maximets break;
23751f30fb91SIlya Maximets }
23761f30fb91SIlya Maximets }
23771f30fb91SIlya Maximets
ovs_nla_free_sample_action(const struct nlattr * action)23781f30fb91SIlya Maximets static void ovs_nla_free_sample_action(const struct nlattr *action)
23791f30fb91SIlya Maximets {
23801f30fb91SIlya Maximets const struct nlattr *a = nla_data(action);
23811f30fb91SIlya Maximets int rem = nla_len(action);
23821f30fb91SIlya Maximets
23831f30fb91SIlya Maximets switch (nla_type(a)) {
23841f30fb91SIlya Maximets case OVS_SAMPLE_ATTR_ARG:
23851f30fb91SIlya Maximets /* The real list of actions follows this attribute. */
23861f30fb91SIlya Maximets a = nla_next(a, &rem);
23871f30fb91SIlya Maximets ovs_nla_free_nested_actions(a, rem);
23881f30fb91SIlya Maximets break;
23891f30fb91SIlya Maximets }
23901f30fb91SIlya Maximets }
23911f30fb91SIlya Maximets
ovs_nla_free_set_action(const struct nlattr * a)239234ae932aSThomas Graf static void ovs_nla_free_set_action(const struct nlattr *a)
239334ae932aSThomas Graf {
239434ae932aSThomas Graf const struct nlattr *ovs_key = nla_data(a);
239534ae932aSThomas Graf struct ovs_tunnel_info *ovs_tun;
239634ae932aSThomas Graf
239734ae932aSThomas Graf switch (nla_type(ovs_key)) {
239834ae932aSThomas Graf case OVS_KEY_ATTR_TUNNEL_INFO:
239934ae932aSThomas Graf ovs_tun = nla_data(ovs_key);
240034ae932aSThomas Graf dst_release((struct dst_entry *)ovs_tun->tun_dst);
240134ae932aSThomas Graf break;
240234ae932aSThomas Graf }
240334ae932aSThomas Graf }
240434ae932aSThomas Graf
ovs_nla_free_nested_actions(const struct nlattr * actions,int len)24051f30fb91SIlya Maximets static void ovs_nla_free_nested_actions(const struct nlattr *actions, int len)
2406e6445719SPravin B Shelar {
240734ae932aSThomas Graf const struct nlattr *a;
240834ae932aSThomas Graf int rem;
240934ae932aSThomas Graf
24101f30fb91SIlya Maximets /* Whenever new actions are added, the need to update this
24111f30fb91SIlya Maximets * function should be considered.
24121f30fb91SIlya Maximets */
2413aae0b82bSAdrian Moreno BUILD_BUG_ON(OVS_ACTION_ATTR_MAX != 25);
24141f30fb91SIlya Maximets
24151f30fb91SIlya Maximets if (!actions)
241634ae932aSThomas Graf return;
241734ae932aSThomas Graf
24181f30fb91SIlya Maximets nla_for_each_attr(a, actions, len, rem) {
241934ae932aSThomas Graf switch (nla_type(a)) {
24201f30fb91SIlya Maximets case OVS_ACTION_ATTR_CHECK_PKT_LEN:
24211f30fb91SIlya Maximets ovs_nla_free_check_pkt_len_action(a);
242234ae932aSThomas Graf break;
24231f30fb91SIlya Maximets
24241f30fb91SIlya Maximets case OVS_ACTION_ATTR_CLONE:
24251f30fb91SIlya Maximets ovs_nla_free_clone_action(a);
24261f30fb91SIlya Maximets break;
24271f30fb91SIlya Maximets
24287f8a436eSJoe Stringer case OVS_ACTION_ATTR_CT:
24297f8a436eSJoe Stringer ovs_ct_free_action(a);
24307f8a436eSJoe Stringer break;
24311f30fb91SIlya Maximets
24321f30fb91SIlya Maximets case OVS_ACTION_ATTR_DEC_TTL:
24331f30fb91SIlya Maximets ovs_nla_free_dec_ttl_action(a);
24341f30fb91SIlya Maximets break;
24351f30fb91SIlya Maximets
24361f30fb91SIlya Maximets case OVS_ACTION_ATTR_SAMPLE:
24371f30fb91SIlya Maximets ovs_nla_free_sample_action(a);
24381f30fb91SIlya Maximets break;
24391f30fb91SIlya Maximets
24401f30fb91SIlya Maximets case OVS_ACTION_ATTR_SET:
24411f30fb91SIlya Maximets ovs_nla_free_set_action(a);
24421f30fb91SIlya Maximets break;
24431f30fb91SIlya Maximets }
244434ae932aSThomas Graf }
244534ae932aSThomas Graf }
244634ae932aSThomas Graf
ovs_nla_free_flow_actions(struct sw_flow_actions * sf_acts)24471f30fb91SIlya Maximets void ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts)
24481f30fb91SIlya Maximets {
24491f30fb91SIlya Maximets if (!sf_acts)
24501f30fb91SIlya Maximets return;
24511f30fb91SIlya Maximets
24521f30fb91SIlya Maximets ovs_nla_free_nested_actions(sf_acts->actions, sf_acts->actions_len);
245334ae932aSThomas Graf kfree(sf_acts);
245434ae932aSThomas Graf }
245534ae932aSThomas Graf
__ovs_nla_free_flow_actions(struct rcu_head * head)245634ae932aSThomas Graf static void __ovs_nla_free_flow_actions(struct rcu_head *head)
245734ae932aSThomas Graf {
245834ae932aSThomas Graf ovs_nla_free_flow_actions(container_of(head, struct sw_flow_actions, rcu));
245934ae932aSThomas Graf }
246034ae932aSThomas Graf
246134ae932aSThomas Graf /* Schedules 'sf_acts' to be freed after the next RCU grace period.
246234ae932aSThomas Graf * The caller must hold rcu_read_lock for this to be sensible. */
ovs_nla_free_flow_actions_rcu(struct sw_flow_actions * sf_acts)246334ae932aSThomas Graf void ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *sf_acts)
246434ae932aSThomas Graf {
246534ae932aSThomas Graf call_rcu(&sf_acts->rcu, __ovs_nla_free_flow_actions);
2466e6445719SPravin B Shelar }
2467e6445719SPravin B Shelar
reserve_sfa_size(struct sw_flow_actions ** sfa,int attr_len,bool log)2468e6445719SPravin B Shelar static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa,
246905da5898SJarno Rajahalme int attr_len, bool log)
2470e6445719SPravin B Shelar {
2471e6445719SPravin B Shelar
2472e6445719SPravin B Shelar struct sw_flow_actions *acts;
2473e6445719SPravin B Shelar int new_acts_size;
2474f28cd2afSAndrea Righi size_t req_size = NLA_ALIGN(attr_len);
2475e6445719SPravin B Shelar int next_offset = offsetof(struct sw_flow_actions, actions) +
2476e6445719SPravin B Shelar (*sfa)->actions_len;
2477e6445719SPravin B Shelar
2478e6445719SPravin B Shelar if (req_size <= (ksize(*sfa) - next_offset))
2479e6445719SPravin B Shelar goto out;
2480e6445719SPravin B Shelar
2481f28cd2afSAndrea Righi new_acts_size = max(next_offset + req_size, ksize(*sfa) * 2);
2482e6445719SPravin B Shelar
2483e6445719SPravin B Shelar if (new_acts_size > MAX_ACTIONS_BUFSIZE) {
2484cefa91b2SPaolo Valerio if ((next_offset + req_size) > MAX_ACTIONS_BUFSIZE) {
248567c8d22aSzhangliping OVS_NLERR(log, "Flow action size exceeds max %u",
248667c8d22aSzhangliping MAX_ACTIONS_BUFSIZE);
2487e6445719SPravin B Shelar return ERR_PTR(-EMSGSIZE);
248867c8d22aSzhangliping }
2489e6445719SPravin B Shelar new_acts_size = MAX_ACTIONS_BUFSIZE;
2490e6445719SPravin B Shelar }
2491e6445719SPravin B Shelar
249267c8d22aSzhangliping acts = nla_alloc_flow_actions(new_acts_size);
2493e6445719SPravin B Shelar if (IS_ERR(acts))
2494*b26b6449SYan Zhen return ERR_CAST(acts);
2495e6445719SPravin B Shelar
2496e6445719SPravin B Shelar memcpy(acts->actions, (*sfa)->actions, (*sfa)->actions_len);
2497e6445719SPravin B Shelar acts->actions_len = (*sfa)->actions_len;
24988e2fed1cSJoe Stringer acts->orig_len = (*sfa)->orig_len;
2499e6445719SPravin B Shelar kfree(*sfa);
2500e6445719SPravin B Shelar *sfa = acts;
2501e6445719SPravin B Shelar
2502e6445719SPravin B Shelar out:
2503e6445719SPravin B Shelar (*sfa)->actions_len += req_size;
2504e6445719SPravin B Shelar return (struct nlattr *) ((unsigned char *)(*sfa) + next_offset);
2505e6445719SPravin B Shelar }
2506e6445719SPravin B Shelar
__add_action(struct sw_flow_actions ** sfa,int attrtype,void * data,int len,bool log)2507f0b128c1SJesse Gross static struct nlattr *__add_action(struct sw_flow_actions **sfa,
250805da5898SJarno Rajahalme int attrtype, void *data, int len, bool log)
2509e6445719SPravin B Shelar {
2510e6445719SPravin B Shelar struct nlattr *a;
2511e6445719SPravin B Shelar
251205da5898SJarno Rajahalme a = reserve_sfa_size(sfa, nla_attr_size(len), log);
2513e6445719SPravin B Shelar if (IS_ERR(a))
2514f0b128c1SJesse Gross return a;
2515e6445719SPravin B Shelar
2516e6445719SPravin B Shelar a->nla_type = attrtype;
2517e6445719SPravin B Shelar a->nla_len = nla_attr_size(len);
2518e6445719SPravin B Shelar
2519e6445719SPravin B Shelar if (data)
2520e6445719SPravin B Shelar memcpy(nla_data(a), data, len);
2521e6445719SPravin B Shelar memset((unsigned char *) a + a->nla_len, 0, nla_padlen(len));
2522e6445719SPravin B Shelar
2523f0b128c1SJesse Gross return a;
2524f0b128c1SJesse Gross }
2525f0b128c1SJesse Gross
ovs_nla_add_action(struct sw_flow_actions ** sfa,int attrtype,void * data,int len,bool log)25267f8a436eSJoe Stringer int ovs_nla_add_action(struct sw_flow_actions **sfa, int attrtype, void *data,
25277f8a436eSJoe Stringer int len, bool log)
2528f0b128c1SJesse Gross {
2529f0b128c1SJesse Gross struct nlattr *a;
2530f0b128c1SJesse Gross
253105da5898SJarno Rajahalme a = __add_action(sfa, attrtype, data, len, log);
2532f0b128c1SJesse Gross
2533f35423c1SFabian Frederick return PTR_ERR_OR_ZERO(a);
2534e6445719SPravin B Shelar }
2535e6445719SPravin B Shelar
add_nested_action_start(struct sw_flow_actions ** sfa,int attrtype,bool log)2536e6445719SPravin B Shelar static inline int add_nested_action_start(struct sw_flow_actions **sfa,
253705da5898SJarno Rajahalme int attrtype, bool log)
2538e6445719SPravin B Shelar {
2539e6445719SPravin B Shelar int used = (*sfa)->actions_len;
2540e6445719SPravin B Shelar int err;
2541e6445719SPravin B Shelar
25427f8a436eSJoe Stringer err = ovs_nla_add_action(sfa, attrtype, NULL, 0, log);
2543e6445719SPravin B Shelar if (err)
2544e6445719SPravin B Shelar return err;
2545e6445719SPravin B Shelar
2546e6445719SPravin B Shelar return used;
2547e6445719SPravin B Shelar }
2548e6445719SPravin B Shelar
add_nested_action_end(struct sw_flow_actions * sfa,int st_offset)2549e6445719SPravin B Shelar static inline void add_nested_action_end(struct sw_flow_actions *sfa,
2550e6445719SPravin B Shelar int st_offset)
2551e6445719SPravin B Shelar {
2552e6445719SPravin B Shelar struct nlattr *a = (struct nlattr *) ((unsigned char *)sfa->actions +
2553e6445719SPravin B Shelar st_offset);
2554e6445719SPravin B Shelar
2555e6445719SPravin B Shelar a->nla_len = sfa->actions_len - st_offset;
2556e6445719SPravin B Shelar }
2557e6445719SPravin B Shelar
25587f8a436eSJoe Stringer static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
255925cd9ba0SSimon Horman const struct sw_flow_key *key,
2560798c1661Sandy zhou struct sw_flow_actions **sfa,
2561fbdcdd78SMartin Varghese __be16 eth_type, __be16 vlan_tci,
25626e2f90d3SAaron Conole u32 mpls_label_count, bool log,
25636e2f90d3SAaron Conole u32 depth);
256425cd9ba0SSimon Horman
validate_and_copy_sample(struct net * net,const struct nlattr * attr,const struct sw_flow_key * key,struct sw_flow_actions ** sfa,__be16 eth_type,__be16 vlan_tci,u32 mpls_label_count,bool log,bool last,u32 depth)25657f8a436eSJoe Stringer static int validate_and_copy_sample(struct net *net, const struct nlattr *attr,
2566798c1661Sandy zhou const struct sw_flow_key *key,
256725cd9ba0SSimon Horman struct sw_flow_actions **sfa,
2568798c1661Sandy zhou __be16 eth_type, __be16 vlan_tci,
25696e2f90d3SAaron Conole u32 mpls_label_count, bool log, bool last,
25706e2f90d3SAaron Conole u32 depth)
2571e6445719SPravin B Shelar {
2572e6445719SPravin B Shelar const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1];
2573e6445719SPravin B Shelar const struct nlattr *probability, *actions;
2574e6445719SPravin B Shelar const struct nlattr *a;
2575798c1661Sandy zhou int rem, start, err;
2576798c1661Sandy zhou struct sample_arg arg;
2577e6445719SPravin B Shelar
2578e6445719SPravin B Shelar memset(attrs, 0, sizeof(attrs));
2579e6445719SPravin B Shelar nla_for_each_nested(a, attr, rem) {
2580e6445719SPravin B Shelar int type = nla_type(a);
2581e6445719SPravin B Shelar if (!type || type > OVS_SAMPLE_ATTR_MAX || attrs[type])
2582e6445719SPravin B Shelar return -EINVAL;
2583e6445719SPravin B Shelar attrs[type] = a;
2584e6445719SPravin B Shelar }
2585e6445719SPravin B Shelar if (rem)
2586e6445719SPravin B Shelar return -EINVAL;
2587e6445719SPravin B Shelar
2588e6445719SPravin B Shelar probability = attrs[OVS_SAMPLE_ATTR_PROBABILITY];
2589e6445719SPravin B Shelar if (!probability || nla_len(probability) != sizeof(u32))
2590e6445719SPravin B Shelar return -EINVAL;
2591e6445719SPravin B Shelar
2592e6445719SPravin B Shelar actions = attrs[OVS_SAMPLE_ATTR_ACTIONS];
2593e6445719SPravin B Shelar if (!actions || (nla_len(actions) && nla_len(actions) < NLA_HDRLEN))
2594e6445719SPravin B Shelar return -EINVAL;
2595e6445719SPravin B Shelar
2596e6445719SPravin B Shelar /* validation done, copy sample action. */
259705da5898SJarno Rajahalme start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SAMPLE, log);
2598e6445719SPravin B Shelar if (start < 0)
2599e6445719SPravin B Shelar return start;
2600798c1661Sandy zhou
2601798c1661Sandy zhou /* When both skb and flow may be changed, put the sample
2602798c1661Sandy zhou * into a deferred fifo. On the other hand, if only skb
2603798c1661Sandy zhou * may be modified, the actions can be executed in place.
2604798c1661Sandy zhou *
2605798c1661Sandy zhou * Do this analysis at the flow installation time.
2606798c1661Sandy zhou * Set 'clone_action->exec' to true if the actions can be
2607798c1661Sandy zhou * executed without being deferred.
2608798c1661Sandy zhou *
2609798c1661Sandy zhou * If the sample is the last action, it can always be excuted
2610798c1661Sandy zhou * rather than deferred.
2611798c1661Sandy zhou */
2612798c1661Sandy zhou arg.exec = last || !actions_may_change_flow(actions);
2613798c1661Sandy zhou arg.probability = nla_get_u32(probability);
2614798c1661Sandy zhou
2615798c1661Sandy zhou err = ovs_nla_add_action(sfa, OVS_SAMPLE_ATTR_ARG, &arg, sizeof(arg),
2616798c1661Sandy zhou log);
2617e6445719SPravin B Shelar if (err)
2618e6445719SPravin B Shelar return err;
2619e6445719SPravin B Shelar
2620798c1661Sandy zhou err = __ovs_nla_copy_actions(net, actions, key, sfa,
26216e2f90d3SAaron Conole eth_type, vlan_tci, mpls_label_count, log,
26226e2f90d3SAaron Conole depth + 1);
2623798c1661Sandy zhou
2624e6445719SPravin B Shelar if (err)
2625e6445719SPravin B Shelar return err;
2626e6445719SPravin B Shelar
2627e6445719SPravin B Shelar add_nested_action_end(*sfa, start);
2628e6445719SPravin B Shelar
2629e6445719SPravin B Shelar return 0;
2630e6445719SPravin B Shelar }
2631e6445719SPravin B Shelar
validate_and_copy_dec_ttl(struct net * net,const struct nlattr * attr,const struct sw_flow_key * key,struct sw_flow_actions ** sfa,__be16 eth_type,__be16 vlan_tci,u32 mpls_label_count,bool log,u32 depth)2632744676e7SMatteo Croce static int validate_and_copy_dec_ttl(struct net *net,
2633744676e7SMatteo Croce const struct nlattr *attr,
2634744676e7SMatteo Croce const struct sw_flow_key *key,
2635744676e7SMatteo Croce struct sw_flow_actions **sfa,
2636744676e7SMatteo Croce __be16 eth_type, __be16 vlan_tci,
26376e2f90d3SAaron Conole u32 mpls_label_count, bool log,
26386e2f90d3SAaron Conole u32 depth)
2639744676e7SMatteo Croce {
264069929d4cSEelco Chaudron const struct nlattr *attrs[OVS_DEC_TTL_ATTR_MAX + 1];
264169929d4cSEelco Chaudron int start, action_start, err, rem;
264269929d4cSEelco Chaudron const struct nlattr *a, *actions;
2643744676e7SMatteo Croce
264469929d4cSEelco Chaudron memset(attrs, 0, sizeof(attrs));
264569929d4cSEelco Chaudron nla_for_each_nested(a, attr, rem) {
264669929d4cSEelco Chaudron int type = nla_type(a);
264769929d4cSEelco Chaudron
264869929d4cSEelco Chaudron /* Ignore unknown attributes to be future proof. */
264969929d4cSEelco Chaudron if (type > OVS_DEC_TTL_ATTR_MAX)
265069929d4cSEelco Chaudron continue;
265169929d4cSEelco Chaudron
2652a5317f3bSEelco Chaudron if (!type || attrs[type]) {
2653a5317f3bSEelco Chaudron OVS_NLERR(log, "Duplicate or invalid key (type %d).",
2654a5317f3bSEelco Chaudron type);
265569929d4cSEelco Chaudron return -EINVAL;
2656a5317f3bSEelco Chaudron }
265769929d4cSEelco Chaudron
265869929d4cSEelco Chaudron attrs[type] = a;
265969929d4cSEelco Chaudron }
266069929d4cSEelco Chaudron
2661a5317f3bSEelco Chaudron if (rem) {
2662a5317f3bSEelco Chaudron OVS_NLERR(log, "Message has %d unknown bytes.", rem);
266369929d4cSEelco Chaudron return -EINVAL;
2664a5317f3bSEelco Chaudron }
2665a5317f3bSEelco Chaudron
2666a5317f3bSEelco Chaudron actions = attrs[OVS_DEC_TTL_ATTR_ACTION];
2667a5317f3bSEelco Chaudron if (!actions || (nla_len(actions) && nla_len(actions) < NLA_HDRLEN)) {
2668a5317f3bSEelco Chaudron OVS_NLERR(log, "Missing valid actions attribute.");
2669a5317f3bSEelco Chaudron return -EINVAL;
2670a5317f3bSEelco Chaudron }
2671744676e7SMatteo Croce
2672744676e7SMatteo Croce start = add_nested_action_start(sfa, OVS_ACTION_ATTR_DEC_TTL, log);
2673744676e7SMatteo Croce if (start < 0)
2674744676e7SMatteo Croce return start;
2675744676e7SMatteo Croce
267669929d4cSEelco Chaudron action_start = add_nested_action_start(sfa, OVS_DEC_TTL_ATTR_ACTION, log);
267769929d4cSEelco Chaudron if (action_start < 0)
2678bb2da765SWang Hai return action_start;
2679744676e7SMatteo Croce
268069929d4cSEelco Chaudron err = __ovs_nla_copy_actions(net, actions, key, sfa, eth_type,
26816e2f90d3SAaron Conole vlan_tci, mpls_label_count, log,
26826e2f90d3SAaron Conole depth + 1);
2683744676e7SMatteo Croce if (err)
2684744676e7SMatteo Croce return err;
2685744676e7SMatteo Croce
268669929d4cSEelco Chaudron add_nested_action_end(*sfa, action_start);
2687744676e7SMatteo Croce add_nested_action_end(*sfa, start);
2688744676e7SMatteo Croce return 0;
2689744676e7SMatteo Croce }
2690744676e7SMatteo Croce
validate_and_copy_clone(struct net * net,const struct nlattr * attr,const struct sw_flow_key * key,struct sw_flow_actions ** sfa,__be16 eth_type,__be16 vlan_tci,u32 mpls_label_count,bool log,bool last,u32 depth)2691b2335040SYifeng Sun static int validate_and_copy_clone(struct net *net,
2692b2335040SYifeng Sun const struct nlattr *attr,
2693b2335040SYifeng Sun const struct sw_flow_key *key,
2694b2335040SYifeng Sun struct sw_flow_actions **sfa,
2695b2335040SYifeng Sun __be16 eth_type, __be16 vlan_tci,
26966e2f90d3SAaron Conole u32 mpls_label_count, bool log, bool last,
26976e2f90d3SAaron Conole u32 depth)
2698b2335040SYifeng Sun {
2699b2335040SYifeng Sun int start, err;
2700b2335040SYifeng Sun u32 exec;
2701b2335040SYifeng Sun
2702b2335040SYifeng Sun if (nla_len(attr) && nla_len(attr) < NLA_HDRLEN)
2703b2335040SYifeng Sun return -EINVAL;
2704b2335040SYifeng Sun
2705b2335040SYifeng Sun start = add_nested_action_start(sfa, OVS_ACTION_ATTR_CLONE, log);
2706b2335040SYifeng Sun if (start < 0)
2707b2335040SYifeng Sun return start;
2708b2335040SYifeng Sun
2709b2335040SYifeng Sun exec = last || !actions_may_change_flow(attr);
2710b2335040SYifeng Sun
2711b2335040SYifeng Sun err = ovs_nla_add_action(sfa, OVS_CLONE_ATTR_EXEC, &exec,
2712b2335040SYifeng Sun sizeof(exec), log);
2713b2335040SYifeng Sun if (err)
2714b2335040SYifeng Sun return err;
2715b2335040SYifeng Sun
2716b2335040SYifeng Sun err = __ovs_nla_copy_actions(net, attr, key, sfa,
27176e2f90d3SAaron Conole eth_type, vlan_tci, mpls_label_count, log,
27186e2f90d3SAaron Conole depth + 1);
2719b2335040SYifeng Sun if (err)
2720b2335040SYifeng Sun return err;
2721b2335040SYifeng Sun
2722b2335040SYifeng Sun add_nested_action_end(*sfa, start);
2723b2335040SYifeng Sun
2724b2335040SYifeng Sun return 0;
2725b2335040SYifeng Sun }
2726b2335040SYifeng Sun
ovs_match_init(struct sw_flow_match * match,struct sw_flow_key * key,bool reset_key,struct sw_flow_mask * mask)2727e6445719SPravin B Shelar void ovs_match_init(struct sw_flow_match *match,
2728e6445719SPravin B Shelar struct sw_flow_key *key,
27292279994dSpravin shelar bool reset_key,
2730e6445719SPravin B Shelar struct sw_flow_mask *mask)
2731e6445719SPravin B Shelar {
2732e6445719SPravin B Shelar memset(match, 0, sizeof(*match));
2733e6445719SPravin B Shelar match->key = key;
2734e6445719SPravin B Shelar match->mask = mask;
2735e6445719SPravin B Shelar
27362279994dSpravin shelar if (reset_key)
2737e6445719SPravin B Shelar memset(key, 0, sizeof(*key));
2738e6445719SPravin B Shelar
2739e6445719SPravin B Shelar if (mask) {
2740e6445719SPravin B Shelar memset(&mask->key, 0, sizeof(mask->key));
2741e6445719SPravin B Shelar mask->range.start = mask->range.end = 0;
2742e6445719SPravin B Shelar }
2743e6445719SPravin B Shelar }
2744e6445719SPravin B Shelar
validate_geneve_opts(struct sw_flow_key * key)2745d91641d9SThomas Graf static int validate_geneve_opts(struct sw_flow_key *key)
2746e6445719SPravin B Shelar {
2747d91641d9SThomas Graf struct geneve_opt *option;
2748d91641d9SThomas Graf int opts_len = key->tun_opts_len;
2749f5796684SJesse Gross bool crit_opt = false;
2750f5796684SJesse Gross
2751d91641d9SThomas Graf option = (struct geneve_opt *)TUN_METADATA_OPTS(key, key->tun_opts_len);
2752f5796684SJesse Gross while (opts_len > 0) {
2753f5796684SJesse Gross int len;
2754f5796684SJesse Gross
2755f5796684SJesse Gross if (opts_len < sizeof(*option))
2756f5796684SJesse Gross return -EINVAL;
2757f5796684SJesse Gross
2758f5796684SJesse Gross len = sizeof(*option) + option->length * 4;
2759f5796684SJesse Gross if (len > opts_len)
2760f5796684SJesse Gross return -EINVAL;
2761f5796684SJesse Gross
2762f5796684SJesse Gross crit_opt |= !!(option->type & GENEVE_CRIT_OPT_TYPE);
2763f5796684SJesse Gross
2764f5796684SJesse Gross option = (struct geneve_opt *)((u8 *)option + len);
2765f5796684SJesse Gross opts_len -= len;
276689290b83SChristopher Díaz Riveros }
2767f5796684SJesse Gross
27685832c4a7SAlexander Lobakin if (crit_opt)
27695832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_CRIT_OPT_BIT, key->tun_key.tun_flags);
2770d91641d9SThomas Graf
2771d91641d9SThomas Graf return 0;
2772d91641d9SThomas Graf }
2773d91641d9SThomas Graf
validate_and_copy_set_tun(const struct nlattr * attr,struct sw_flow_actions ** sfa,bool log)2774d91641d9SThomas Graf static int validate_and_copy_set_tun(const struct nlattr *attr,
2775d91641d9SThomas Graf struct sw_flow_actions **sfa, bool log)
2776d91641d9SThomas Graf {
27775832c4a7SAlexander Lobakin IP_TUNNEL_DECLARE_FLAGS(dst_opt_type) = { };
2778d91641d9SThomas Graf struct sw_flow_match match;
2779d91641d9SThomas Graf struct sw_flow_key key;
278034ae932aSThomas Graf struct metadata_dst *tun_dst;
27811d8fff90SThomas Graf struct ip_tunnel_info *tun_info;
278234ae932aSThomas Graf struct ovs_tunnel_info *ovs_tun;
2783d91641d9SThomas Graf struct nlattr *a;
278413101602SGeert Uytterhoeven int err = 0, start, opts_type;
2785d91641d9SThomas Graf
27862279994dSpravin shelar ovs_match_init(&match, &key, true, NULL);
27876b26ba3aSJiri Benc opts_type = ip_tun_from_nlattr(nla_data(attr), &match, false, log);
27881dd144cfSThomas Graf if (opts_type < 0)
27891dd144cfSThomas Graf return opts_type;
2790d91641d9SThomas Graf
2791d91641d9SThomas Graf if (key.tun_opts_len) {
27921dd144cfSThomas Graf switch (opts_type) {
27931dd144cfSThomas Graf case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
2794d91641d9SThomas Graf err = validate_geneve_opts(&key);
2795d91641d9SThomas Graf if (err < 0)
2796d91641d9SThomas Graf return err;
27975832c4a7SAlexander Lobakin
27985832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_GENEVE_OPT_BIT, dst_opt_type);
27991dd144cfSThomas Graf break;
28001dd144cfSThomas Graf case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
28015832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_VXLAN_OPT_BIT, dst_opt_type);
28021dd144cfSThomas Graf break;
2803fc1372f8SWilliam Tu case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS:
28045832c4a7SAlexander Lobakin __set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, dst_opt_type);
2805fc1372f8SWilliam Tu break;
28061dd144cfSThomas Graf }
280789290b83SChristopher Díaz Riveros }
2808f5796684SJesse Gross
280905da5898SJarno Rajahalme start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET, log);
2810e6445719SPravin B Shelar if (start < 0)
2811e6445719SPravin B Shelar return start;
2812e6445719SPravin B Shelar
28133fcece12SJakub Kicinski tun_dst = metadata_dst_alloc(key.tun_opts_len, METADATA_IP_TUNNEL,
28143fcece12SJakub Kicinski GFP_KERNEL);
28153fcece12SJakub Kicinski
281634ae932aSThomas Graf if (!tun_dst)
281734ae932aSThomas Graf return -ENOMEM;
2818f0b128c1SJesse Gross
2819d71785ffSPaolo Abeni err = dst_cache_init(&tun_dst->u.tun_info.dst_cache, GFP_KERNEL);
2820d71785ffSPaolo Abeni if (err) {
2821d71785ffSPaolo Abeni dst_release((struct dst_entry *)tun_dst);
2822d71785ffSPaolo Abeni return err;
2823d71785ffSPaolo Abeni }
2824d71785ffSPaolo Abeni
282534ae932aSThomas Graf a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL,
282634ae932aSThomas Graf sizeof(*ovs_tun), log);
282734ae932aSThomas Graf if (IS_ERR(a)) {
282834ae932aSThomas Graf dst_release((struct dst_entry *)tun_dst);
282934ae932aSThomas Graf return PTR_ERR(a);
283034ae932aSThomas Graf }
283134ae932aSThomas Graf
283234ae932aSThomas Graf ovs_tun = nla_data(a);
283334ae932aSThomas Graf ovs_tun->tun_dst = tun_dst;
283434ae932aSThomas Graf
283534ae932aSThomas Graf tun_info = &tun_dst->u.tun_info;
283634ae932aSThomas Graf tun_info->mode = IP_TUNNEL_INFO_TX;
283700a93babSJiri Benc if (key.tun_proto == AF_INET6)
283800a93babSJiri Benc tun_info->mode |= IP_TUNNEL_INFO_IPV6;
283918b6f717Swenxu else if (key.tun_proto == AF_INET && key.tun_key.u.ipv4.dst == 0)
284018b6f717Swenxu tun_info->mode |= IP_TUNNEL_INFO_BRIDGE;
28411d8fff90SThomas Graf tun_info->key = key.tun_key;
2842f5796684SJesse Gross
2843f5796684SJesse Gross /* We need to store the options in the action itself since
2844f5796684SJesse Gross * everything else will go away after flow setup. We can append
2845f5796684SJesse Gross * it to tun_info and then point there.
2846f5796684SJesse Gross */
28474c222798SPravin B Shelar ip_tunnel_info_opts_set(tun_info,
28484c222798SPravin B Shelar TUN_METADATA_OPTS(&key, key.tun_opts_len),
2849256c87c1SPieter Jansen van Vuuren key.tun_opts_len, dst_opt_type);
2850e6445719SPravin B Shelar add_nested_action_end(*sfa, start);
2851e6445719SPravin B Shelar
2852e6445719SPravin B Shelar return err;
2853e6445719SPravin B Shelar }
2854e6445719SPravin B Shelar
validate_nsh(const struct nlattr * attr,bool is_mask,bool is_push_nsh,bool log)2855b2d0f5d5SYi Yang static bool validate_nsh(const struct nlattr *attr, bool is_mask,
2856b2d0f5d5SYi Yang bool is_push_nsh, bool log)
2857b2d0f5d5SYi Yang {
2858b2d0f5d5SYi Yang struct sw_flow_match match;
2859b2d0f5d5SYi Yang struct sw_flow_key key;
2860b2d0f5d5SYi Yang int ret = 0;
2861b2d0f5d5SYi Yang
2862b2d0f5d5SYi Yang ovs_match_init(&match, &key, true, NULL);
2863b2d0f5d5SYi Yang ret = nsh_key_put_from_nlattr(attr, &match, is_mask,
2864b2d0f5d5SYi Yang is_push_nsh, log);
2865b2d0f5d5SYi Yang return !ret;
2866b2d0f5d5SYi Yang }
2867b2d0f5d5SYi Yang
286883d2b9baSJarno Rajahalme /* Return false if there are any non-masked bits set.
286983d2b9baSJarno Rajahalme * Mask follows data immediately, before any netlink padding.
287083d2b9baSJarno Rajahalme */
validate_masked(u8 * data,int len)287183d2b9baSJarno Rajahalme static bool validate_masked(u8 *data, int len)
287283d2b9baSJarno Rajahalme {
287383d2b9baSJarno Rajahalme u8 *mask = data + len;
287483d2b9baSJarno Rajahalme
287583d2b9baSJarno Rajahalme while (len--)
287683d2b9baSJarno Rajahalme if (*data++ & ~*mask++)
287783d2b9baSJarno Rajahalme return false;
287883d2b9baSJarno Rajahalme
287983d2b9baSJarno Rajahalme return true;
288083d2b9baSJarno Rajahalme }
288183d2b9baSJarno Rajahalme
validate_set(const struct nlattr * a,const struct sw_flow_key * flow_key,struct sw_flow_actions ** sfa,bool * skip_copy,u8 mac_proto,__be16 eth_type,bool masked,bool log)2882e6445719SPravin B Shelar static int validate_set(const struct nlattr *a,
2883e6445719SPravin B Shelar const struct sw_flow_key *flow_key,
28840a6410fbSJiri Benc struct sw_flow_actions **sfa, bool *skip_copy,
28850a6410fbSJiri Benc u8 mac_proto, __be16 eth_type, bool masked, bool log)
2886e6445719SPravin B Shelar {
2887e6445719SPravin B Shelar const struct nlattr *ovs_key = nla_data(a);
2888e6445719SPravin B Shelar int key_type = nla_type(ovs_key);
288983d2b9baSJarno Rajahalme size_t key_len;
2890e6445719SPravin B Shelar
2891e6445719SPravin B Shelar /* There can be only one key in a action */
2892e6445719SPravin B Shelar if (nla_total_size(nla_len(ovs_key)) != nla_len(a))
2893e6445719SPravin B Shelar return -EINVAL;
2894e6445719SPravin B Shelar
289583d2b9baSJarno Rajahalme key_len = nla_len(ovs_key);
289683d2b9baSJarno Rajahalme if (masked)
289783d2b9baSJarno Rajahalme key_len /= 2;
289883d2b9baSJarno Rajahalme
2899e6445719SPravin B Shelar if (key_type > OVS_KEY_ATTR_MAX ||
2900982b5270SJesse Gross !check_attr_len(key_len, ovs_key_lens[key_type].len))
2901e6445719SPravin B Shelar return -EINVAL;
2902e6445719SPravin B Shelar
290383d2b9baSJarno Rajahalme if (masked && !validate_masked(nla_data(ovs_key), key_len))
290483d2b9baSJarno Rajahalme return -EINVAL;
290583d2b9baSJarno Rajahalme
2906e6445719SPravin B Shelar switch (key_type) {
2907e6445719SPravin B Shelar case OVS_KEY_ATTR_PRIORITY:
2908e6445719SPravin B Shelar case OVS_KEY_ATTR_SKB_MARK:
2909182e3042SJoe Stringer case OVS_KEY_ATTR_CT_MARK:
291033db4125SJoe Stringer case OVS_KEY_ATTR_CT_LABELS:
2911e6445719SPravin B Shelar break;
2912e6445719SPravin B Shelar
29130a6410fbSJiri Benc case OVS_KEY_ATTR_ETHERNET:
29140a6410fbSJiri Benc if (mac_proto != MAC_PROTO_ETHERNET)
29150a6410fbSJiri Benc return -EINVAL;
291687e159c5SJarno Rajahalme break;
29170a6410fbSJiri Benc
291816a556eeSKees Cook case OVS_KEY_ATTR_TUNNEL: {
291916a556eeSKees Cook int err;
292016a556eeSKees Cook
292183d2b9baSJarno Rajahalme if (masked)
292283d2b9baSJarno Rajahalme return -EINVAL; /* Masked tunnel set not supported. */
292383d2b9baSJarno Rajahalme
292483d2b9baSJarno Rajahalme *skip_copy = true;
292505da5898SJarno Rajahalme err = validate_and_copy_set_tun(a, sfa, log);
2926e6445719SPravin B Shelar if (err)
2927e6445719SPravin B Shelar return err;
2928e6445719SPravin B Shelar break;
292916a556eeSKees Cook }
293016a556eeSKees Cook case OVS_KEY_ATTR_IPV4: {
293116a556eeSKees Cook const struct ovs_key_ipv4 *ipv4_key;
2932e6445719SPravin B Shelar
293325cd9ba0SSimon Horman if (eth_type != htons(ETH_P_IP))
2934e6445719SPravin B Shelar return -EINVAL;
2935e6445719SPravin B Shelar
2936e6445719SPravin B Shelar ipv4_key = nla_data(ovs_key);
293783d2b9baSJarno Rajahalme
293883d2b9baSJarno Rajahalme if (masked) {
293983d2b9baSJarno Rajahalme const struct ovs_key_ipv4 *mask = ipv4_key + 1;
294083d2b9baSJarno Rajahalme
294183d2b9baSJarno Rajahalme /* Non-writeable fields. */
294283d2b9baSJarno Rajahalme if (mask->ipv4_proto || mask->ipv4_frag)
294383d2b9baSJarno Rajahalme return -EINVAL;
294483d2b9baSJarno Rajahalme } else {
2945e6445719SPravin B Shelar if (ipv4_key->ipv4_proto != flow_key->ip.proto)
2946e6445719SPravin B Shelar return -EINVAL;
2947e6445719SPravin B Shelar
2948e6445719SPravin B Shelar if (ipv4_key->ipv4_frag != flow_key->ip.frag)
2949e6445719SPravin B Shelar return -EINVAL;
295083d2b9baSJarno Rajahalme }
2951e6445719SPravin B Shelar break;
295216a556eeSKees Cook }
295316a556eeSKees Cook case OVS_KEY_ATTR_IPV6: {
295416a556eeSKees Cook const struct ovs_key_ipv6 *ipv6_key;
2955e6445719SPravin B Shelar
295625cd9ba0SSimon Horman if (eth_type != htons(ETH_P_IPV6))
2957e6445719SPravin B Shelar return -EINVAL;
2958e6445719SPravin B Shelar
295983d2b9baSJarno Rajahalme ipv6_key = nla_data(ovs_key);
296083d2b9baSJarno Rajahalme
296183d2b9baSJarno Rajahalme if (masked) {
296283d2b9baSJarno Rajahalme const struct ovs_key_ipv6 *mask = ipv6_key + 1;
296383d2b9baSJarno Rajahalme
296483d2b9baSJarno Rajahalme /* Non-writeable fields. */
296583d2b9baSJarno Rajahalme if (mask->ipv6_proto || mask->ipv6_frag)
2966e6445719SPravin B Shelar return -EINVAL;
2967e6445719SPravin B Shelar
296883d2b9baSJarno Rajahalme /* Invalid bits in the flow label mask? */
296983d2b9baSJarno Rajahalme if (ntohl(mask->ipv6_label) & 0xFFF00000)
297083d2b9baSJarno Rajahalme return -EINVAL;
297183d2b9baSJarno Rajahalme } else {
2972e6445719SPravin B Shelar if (ipv6_key->ipv6_proto != flow_key->ip.proto)
2973e6445719SPravin B Shelar return -EINVAL;
2974e6445719SPravin B Shelar
2975e6445719SPravin B Shelar if (ipv6_key->ipv6_frag != flow_key->ip.frag)
2976e6445719SPravin B Shelar return -EINVAL;
297783d2b9baSJarno Rajahalme }
2978e6445719SPravin B Shelar if (ntohl(ipv6_key->ipv6_label) & 0xFFF00000)
2979e6445719SPravin B Shelar return -EINVAL;
2980e6445719SPravin B Shelar
2981e6445719SPravin B Shelar break;
298216a556eeSKees Cook }
2983e6445719SPravin B Shelar case OVS_KEY_ATTR_TCP:
298483d2b9baSJarno Rajahalme if ((eth_type != htons(ETH_P_IP) &&
298583d2b9baSJarno Rajahalme eth_type != htons(ETH_P_IPV6)) ||
298683d2b9baSJarno Rajahalme flow_key->ip.proto != IPPROTO_TCP)
2987e6445719SPravin B Shelar return -EINVAL;
2988e6445719SPravin B Shelar
298983d2b9baSJarno Rajahalme break;
2990e6445719SPravin B Shelar
2991e6445719SPravin B Shelar case OVS_KEY_ATTR_UDP:
299283d2b9baSJarno Rajahalme if ((eth_type != htons(ETH_P_IP) &&
299383d2b9baSJarno Rajahalme eth_type != htons(ETH_P_IPV6)) ||
299483d2b9baSJarno Rajahalme flow_key->ip.proto != IPPROTO_UDP)
2995e6445719SPravin B Shelar return -EINVAL;
2996e6445719SPravin B Shelar
299783d2b9baSJarno Rajahalme break;
299825cd9ba0SSimon Horman
299925cd9ba0SSimon Horman case OVS_KEY_ATTR_MPLS:
300025cd9ba0SSimon Horman if (!eth_p_mpls(eth_type))
300125cd9ba0SSimon Horman return -EINVAL;
300225cd9ba0SSimon Horman break;
3003e6445719SPravin B Shelar
3004e6445719SPravin B Shelar case OVS_KEY_ATTR_SCTP:
300583d2b9baSJarno Rajahalme if ((eth_type != htons(ETH_P_IP) &&
300683d2b9baSJarno Rajahalme eth_type != htons(ETH_P_IPV6)) ||
300783d2b9baSJarno Rajahalme flow_key->ip.proto != IPPROTO_SCTP)
3008e6445719SPravin B Shelar return -EINVAL;
3009e6445719SPravin B Shelar
301083d2b9baSJarno Rajahalme break;
3011e6445719SPravin B Shelar
3012b2d0f5d5SYi Yang case OVS_KEY_ATTR_NSH:
3013b2d0f5d5SYi Yang if (eth_type != htons(ETH_P_NSH))
3014b2d0f5d5SYi Yang return -EINVAL;
3015b2d0f5d5SYi Yang if (!validate_nsh(nla_data(a), masked, false, log))
3016b2d0f5d5SYi Yang return -EINVAL;
3017b2d0f5d5SYi Yang break;
3018b2d0f5d5SYi Yang
3019e6445719SPravin B Shelar default:
3020e6445719SPravin B Shelar return -EINVAL;
3021e6445719SPravin B Shelar }
3022e6445719SPravin B Shelar
302383d2b9baSJarno Rajahalme /* Convert non-masked non-tunnel set actions to masked set actions. */
302483d2b9baSJarno Rajahalme if (!masked && key_type != OVS_KEY_ATTR_TUNNEL) {
302583d2b9baSJarno Rajahalme int start, len = key_len * 2;
302683d2b9baSJarno Rajahalme struct nlattr *at;
302783d2b9baSJarno Rajahalme
302883d2b9baSJarno Rajahalme *skip_copy = true;
302983d2b9baSJarno Rajahalme
303083d2b9baSJarno Rajahalme start = add_nested_action_start(sfa,
303183d2b9baSJarno Rajahalme OVS_ACTION_ATTR_SET_TO_MASKED,
303283d2b9baSJarno Rajahalme log);
303383d2b9baSJarno Rajahalme if (start < 0)
303483d2b9baSJarno Rajahalme return start;
303583d2b9baSJarno Rajahalme
303683d2b9baSJarno Rajahalme at = __add_action(sfa, key_type, NULL, len, log);
303783d2b9baSJarno Rajahalme if (IS_ERR(at))
303883d2b9baSJarno Rajahalme return PTR_ERR(at);
303983d2b9baSJarno Rajahalme
304083d2b9baSJarno Rajahalme memcpy(nla_data(at), nla_data(ovs_key), key_len); /* Key. */
304183d2b9baSJarno Rajahalme memset(nla_data(at) + key_len, 0xff, key_len); /* Mask. */
304283d2b9baSJarno Rajahalme /* Clear non-writeable bits from otherwise writeable fields. */
304383d2b9baSJarno Rajahalme if (key_type == OVS_KEY_ATTR_IPV6) {
304483d2b9baSJarno Rajahalme struct ovs_key_ipv6 *mask = nla_data(at) + key_len;
304583d2b9baSJarno Rajahalme
304683d2b9baSJarno Rajahalme mask->ipv6_label &= htonl(0x000FFFFF);
304783d2b9baSJarno Rajahalme }
304883d2b9baSJarno Rajahalme add_nested_action_end(*sfa, start);
304983d2b9baSJarno Rajahalme }
305083d2b9baSJarno Rajahalme
3051e6445719SPravin B Shelar return 0;
3052e6445719SPravin B Shelar }
3053e6445719SPravin B Shelar
validate_userspace(const struct nlattr * attr)3054e6445719SPravin B Shelar static int validate_userspace(const struct nlattr *attr)
3055e6445719SPravin B Shelar {
3056e6445719SPravin B Shelar static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] = {
3057e6445719SPravin B Shelar [OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 },
3058e6445719SPravin B Shelar [OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC },
30598f0aad6fSWenyu Zhang [OVS_USERSPACE_ATTR_EGRESS_TUN_PORT] = {.type = NLA_U32 },
3060e6445719SPravin B Shelar };
3061e6445719SPravin B Shelar struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1];
3062e6445719SPravin B Shelar int error;
3063e6445719SPravin B Shelar
30648cb08174SJohannes Berg error = nla_parse_nested_deprecated(a, OVS_USERSPACE_ATTR_MAX, attr,
3065fceb6435SJohannes Berg userspace_policy, NULL);
3066e6445719SPravin B Shelar if (error)
3067e6445719SPravin B Shelar return error;
3068e6445719SPravin B Shelar
3069e6445719SPravin B Shelar if (!a[OVS_USERSPACE_ATTR_PID] ||
3070e6445719SPravin B Shelar !nla_get_u32(a[OVS_USERSPACE_ATTR_PID]))
3071e6445719SPravin B Shelar return -EINVAL;
3072e6445719SPravin B Shelar
3073e6445719SPravin B Shelar return 0;
3074e6445719SPravin B Shelar }
3075e6445719SPravin B Shelar
30764d5ec89fSNuman Siddique static const struct nla_policy cpl_policy[OVS_CHECK_PKT_LEN_ATTR_MAX + 1] = {
30774d5ec89fSNuman Siddique [OVS_CHECK_PKT_LEN_ATTR_PKT_LEN] = {.type = NLA_U16 },
30784d5ec89fSNuman Siddique [OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER] = {.type = NLA_NESTED },
30794d5ec89fSNuman Siddique [OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL] = {.type = NLA_NESTED },
30804d5ec89fSNuman Siddique };
30814d5ec89fSNuman Siddique
validate_and_copy_check_pkt_len(struct net * net,const struct nlattr * attr,const struct sw_flow_key * key,struct sw_flow_actions ** sfa,__be16 eth_type,__be16 vlan_tci,u32 mpls_label_count,bool log,bool last,u32 depth)30824d5ec89fSNuman Siddique static int validate_and_copy_check_pkt_len(struct net *net,
30834d5ec89fSNuman Siddique const struct nlattr *attr,
30844d5ec89fSNuman Siddique const struct sw_flow_key *key,
30854d5ec89fSNuman Siddique struct sw_flow_actions **sfa,
30864d5ec89fSNuman Siddique __be16 eth_type, __be16 vlan_tci,
3087fbdcdd78SMartin Varghese u32 mpls_label_count,
30886e2f90d3SAaron Conole bool log, bool last, u32 depth)
30894d5ec89fSNuman Siddique {
30904d5ec89fSNuman Siddique const struct nlattr *acts_if_greater, *acts_if_lesser_eq;
30914d5ec89fSNuman Siddique struct nlattr *a[OVS_CHECK_PKT_LEN_ATTR_MAX + 1];
30924d5ec89fSNuman Siddique struct check_pkt_len_arg arg;
30934d5ec89fSNuman Siddique int nested_acts_start;
30944d5ec89fSNuman Siddique int start, err;
30954d5ec89fSNuman Siddique
30968cb08174SJohannes Berg err = nla_parse_deprecated_strict(a, OVS_CHECK_PKT_LEN_ATTR_MAX,
30978cb08174SJohannes Berg nla_data(attr), nla_len(attr),
30988cb08174SJohannes Berg cpl_policy, NULL);
30994d5ec89fSNuman Siddique if (err)
31004d5ec89fSNuman Siddique return err;
31014d5ec89fSNuman Siddique
31024d5ec89fSNuman Siddique if (!a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN] ||
31034d5ec89fSNuman Siddique !nla_get_u16(a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN]))
31044d5ec89fSNuman Siddique return -EINVAL;
31054d5ec89fSNuman Siddique
31064d5ec89fSNuman Siddique acts_if_lesser_eq = a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL];
31074d5ec89fSNuman Siddique acts_if_greater = a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER];
31084d5ec89fSNuman Siddique
31094d5ec89fSNuman Siddique /* Both the nested action should be present. */
31104d5ec89fSNuman Siddique if (!acts_if_greater || !acts_if_lesser_eq)
31114d5ec89fSNuman Siddique return -EINVAL;
31124d5ec89fSNuman Siddique
31134d5ec89fSNuman Siddique /* validation done, copy the nested actions. */
31144d5ec89fSNuman Siddique start = add_nested_action_start(sfa, OVS_ACTION_ATTR_CHECK_PKT_LEN,
31154d5ec89fSNuman Siddique log);
31164d5ec89fSNuman Siddique if (start < 0)
31174d5ec89fSNuman Siddique return start;
31184d5ec89fSNuman Siddique
31194d5ec89fSNuman Siddique arg.pkt_len = nla_get_u16(a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN]);
31204d5ec89fSNuman Siddique arg.exec_for_lesser_equal =
31214d5ec89fSNuman Siddique last || !actions_may_change_flow(acts_if_lesser_eq);
31224d5ec89fSNuman Siddique arg.exec_for_greater =
31234d5ec89fSNuman Siddique last || !actions_may_change_flow(acts_if_greater);
31244d5ec89fSNuman Siddique
31254d5ec89fSNuman Siddique err = ovs_nla_add_action(sfa, OVS_CHECK_PKT_LEN_ATTR_ARG, &arg,
31264d5ec89fSNuman Siddique sizeof(arg), log);
31274d5ec89fSNuman Siddique if (err)
31284d5ec89fSNuman Siddique return err;
31294d5ec89fSNuman Siddique
31304d5ec89fSNuman Siddique nested_acts_start = add_nested_action_start(sfa,
31314d5ec89fSNuman Siddique OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL, log);
31324d5ec89fSNuman Siddique if (nested_acts_start < 0)
31334d5ec89fSNuman Siddique return nested_acts_start;
31344d5ec89fSNuman Siddique
31354d5ec89fSNuman Siddique err = __ovs_nla_copy_actions(net, acts_if_lesser_eq, key, sfa,
31366e2f90d3SAaron Conole eth_type, vlan_tci, mpls_label_count, log,
31376e2f90d3SAaron Conole depth + 1);
31384d5ec89fSNuman Siddique
31394d5ec89fSNuman Siddique if (err)
31404d5ec89fSNuman Siddique return err;
31414d5ec89fSNuman Siddique
31424d5ec89fSNuman Siddique add_nested_action_end(*sfa, nested_acts_start);
31434d5ec89fSNuman Siddique
31444d5ec89fSNuman Siddique nested_acts_start = add_nested_action_start(sfa,
31454d5ec89fSNuman Siddique OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER, log);
31464d5ec89fSNuman Siddique if (nested_acts_start < 0)
31474d5ec89fSNuman Siddique return nested_acts_start;
31484d5ec89fSNuman Siddique
31494d5ec89fSNuman Siddique err = __ovs_nla_copy_actions(net, acts_if_greater, key, sfa,
31506e2f90d3SAaron Conole eth_type, vlan_tci, mpls_label_count, log,
31516e2f90d3SAaron Conole depth + 1);
31524d5ec89fSNuman Siddique
31534d5ec89fSNuman Siddique if (err)
31544d5ec89fSNuman Siddique return err;
31554d5ec89fSNuman Siddique
31564d5ec89fSNuman Siddique add_nested_action_end(*sfa, nested_acts_start);
31574d5ec89fSNuman Siddique add_nested_action_end(*sfa, start);
31584d5ec89fSNuman Siddique return 0;
31594d5ec89fSNuman Siddique }
31604d5ec89fSNuman Siddique
validate_psample(const struct nlattr * attr)3161aae0b82bSAdrian Moreno static int validate_psample(const struct nlattr *attr)
3162aae0b82bSAdrian Moreno {
3163aae0b82bSAdrian Moreno static const struct nla_policy policy[OVS_PSAMPLE_ATTR_MAX + 1] = {
3164aae0b82bSAdrian Moreno [OVS_PSAMPLE_ATTR_GROUP] = { .type = NLA_U32 },
3165aae0b82bSAdrian Moreno [OVS_PSAMPLE_ATTR_COOKIE] = {
3166aae0b82bSAdrian Moreno .type = NLA_BINARY,
3167aae0b82bSAdrian Moreno .len = OVS_PSAMPLE_COOKIE_MAX_SIZE,
3168aae0b82bSAdrian Moreno },
3169aae0b82bSAdrian Moreno };
3170aae0b82bSAdrian Moreno struct nlattr *a[OVS_PSAMPLE_ATTR_MAX + 1];
3171aae0b82bSAdrian Moreno int err;
3172aae0b82bSAdrian Moreno
3173aae0b82bSAdrian Moreno if (!IS_ENABLED(CONFIG_PSAMPLE))
3174aae0b82bSAdrian Moreno return -EOPNOTSUPP;
3175aae0b82bSAdrian Moreno
3176aae0b82bSAdrian Moreno err = nla_parse_nested(a, OVS_PSAMPLE_ATTR_MAX, attr, policy, NULL);
3177aae0b82bSAdrian Moreno if (err)
3178aae0b82bSAdrian Moreno return err;
3179aae0b82bSAdrian Moreno
3180aae0b82bSAdrian Moreno return a[OVS_PSAMPLE_ATTR_GROUP] ? 0 : -EINVAL;
3181aae0b82bSAdrian Moreno }
3182aae0b82bSAdrian Moreno
copy_action(const struct nlattr * from,struct sw_flow_actions ** sfa,bool log)3183e6445719SPravin B Shelar static int copy_action(const struct nlattr *from,
318405da5898SJarno Rajahalme struct sw_flow_actions **sfa, bool log)
3185e6445719SPravin B Shelar {
3186e6445719SPravin B Shelar int totlen = NLA_ALIGN(from->nla_len);
3187e6445719SPravin B Shelar struct nlattr *to;
3188e6445719SPravin B Shelar
318905da5898SJarno Rajahalme to = reserve_sfa_size(sfa, from->nla_len, log);
3190e6445719SPravin B Shelar if (IS_ERR(to))
3191e6445719SPravin B Shelar return PTR_ERR(to);
3192e6445719SPravin B Shelar
3193e6445719SPravin B Shelar memcpy(to, from, totlen);
3194e6445719SPravin B Shelar return 0;
3195e6445719SPravin B Shelar }
3196e6445719SPravin B Shelar
__ovs_nla_copy_actions(struct net * net,const struct nlattr * attr,const struct sw_flow_key * key,struct sw_flow_actions ** sfa,__be16 eth_type,__be16 vlan_tci,u32 mpls_label_count,bool log,u32 depth)31977f8a436eSJoe Stringer static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
3198e6445719SPravin B Shelar const struct sw_flow_key *key,
3199798c1661Sandy zhou struct sw_flow_actions **sfa,
3200fbdcdd78SMartin Varghese __be16 eth_type, __be16 vlan_tci,
32016e2f90d3SAaron Conole u32 mpls_label_count, bool log,
32026e2f90d3SAaron Conole u32 depth)
3203e6445719SPravin B Shelar {
32040a6410fbSJiri Benc u8 mac_proto = ovs_key_mac_proto(key);
3205e6445719SPravin B Shelar const struct nlattr *a;
3206e6445719SPravin B Shelar int rem, err;
3207e6445719SPravin B Shelar
32086e2f90d3SAaron Conole if (depth > OVS_COPY_ACTIONS_MAX_DEPTH)
32096e2f90d3SAaron Conole return -EOVERFLOW;
32106e2f90d3SAaron Conole
3211e6445719SPravin B Shelar nla_for_each_nested(a, attr, rem) {
3212e6445719SPravin B Shelar /* Expected argument lengths, (u32)-1 for variable length. */
3213e6445719SPravin B Shelar static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {
3214e6445719SPravin B Shelar [OVS_ACTION_ATTR_OUTPUT] = sizeof(u32),
3215971427f3SAndy Zhou [OVS_ACTION_ATTR_RECIRC] = sizeof(u32),
3216e6445719SPravin B Shelar [OVS_ACTION_ATTR_USERSPACE] = (u32)-1,
321725cd9ba0SSimon Horman [OVS_ACTION_ATTR_PUSH_MPLS] = sizeof(struct ovs_action_push_mpls),
321825cd9ba0SSimon Horman [OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16),
3219e6445719SPravin B Shelar [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan),
3220e6445719SPravin B Shelar [OVS_ACTION_ATTR_POP_VLAN] = 0,
3221e6445719SPravin B Shelar [OVS_ACTION_ATTR_SET] = (u32)-1,
322283d2b9baSJarno Rajahalme [OVS_ACTION_ATTR_SET_MASKED] = (u32)-1,
3223971427f3SAndy Zhou [OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
32247f8a436eSJoe Stringer [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash),
32257f8a436eSJoe Stringer [OVS_ACTION_ATTR_CT] = (u32)-1,
3226b8226962SEric Garver [OVS_ACTION_ATTR_CT_CLEAR] = 0,
3227f2a4d086SWilliam Tu [OVS_ACTION_ATTR_TRUNC] = sizeof(struct ovs_action_trunc),
322891820da6SJiri Benc [OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth),
322991820da6SJiri Benc [OVS_ACTION_ATTR_POP_ETH] = 0,
3230b2d0f5d5SYi Yang [OVS_ACTION_ATTR_PUSH_NSH] = (u32)-1,
3231b2d0f5d5SYi Yang [OVS_ACTION_ATTR_POP_NSH] = 0,
3232cd8a6c33SAndy Zhou [OVS_ACTION_ATTR_METER] = sizeof(u32),
3233b2335040SYifeng Sun [OVS_ACTION_ATTR_CLONE] = (u32)-1,
32344d5ec89fSNuman Siddique [OVS_ACTION_ATTR_CHECK_PKT_LEN] = (u32)-1,
3235f66b53fdSMartin Varghese [OVS_ACTION_ATTR_ADD_MPLS] = sizeof(struct ovs_action_add_mpls),
3236744676e7SMatteo Croce [OVS_ACTION_ATTR_DEC_TTL] = (u32)-1,
3237e7bc7db9SEric Garver [OVS_ACTION_ATTR_DROP] = sizeof(u32),
3238aae0b82bSAdrian Moreno [OVS_ACTION_ATTR_PSAMPLE] = (u32)-1,
3239e6445719SPravin B Shelar };
3240e6445719SPravin B Shelar const struct ovs_action_push_vlan *vlan;
3241e6445719SPravin B Shelar int type = nla_type(a);
3242e6445719SPravin B Shelar bool skip_copy;
3243e6445719SPravin B Shelar
3244e6445719SPravin B Shelar if (type > OVS_ACTION_ATTR_MAX ||
3245e6445719SPravin B Shelar (action_lens[type] != nla_len(a) &&
3246e6445719SPravin B Shelar action_lens[type] != (u32)-1))
3247e6445719SPravin B Shelar return -EINVAL;
3248e6445719SPravin B Shelar
3249e6445719SPravin B Shelar skip_copy = false;
3250e6445719SPravin B Shelar switch (type) {
3251e6445719SPravin B Shelar case OVS_ACTION_ATTR_UNSPEC:
3252e6445719SPravin B Shelar return -EINVAL;
3253e6445719SPravin B Shelar
3254e6445719SPravin B Shelar case OVS_ACTION_ATTR_USERSPACE:
3255e6445719SPravin B Shelar err = validate_userspace(a);
3256e6445719SPravin B Shelar if (err)
3257e6445719SPravin B Shelar return err;
3258e6445719SPravin B Shelar break;
3259e6445719SPravin B Shelar
3260e6445719SPravin B Shelar case OVS_ACTION_ATTR_OUTPUT:
3261e6445719SPravin B Shelar if (nla_get_u32(a) >= DP_MAX_PORTS)
3262e6445719SPravin B Shelar return -EINVAL;
3263e6445719SPravin B Shelar break;
3264e6445719SPravin B Shelar
3265f2a4d086SWilliam Tu case OVS_ACTION_ATTR_TRUNC: {
3266f2a4d086SWilliam Tu const struct ovs_action_trunc *trunc = nla_data(a);
3267f2a4d086SWilliam Tu
3268f2a4d086SWilliam Tu if (trunc->max_len < ETH_HLEN)
3269f2a4d086SWilliam Tu return -EINVAL;
3270f2a4d086SWilliam Tu break;
3271f2a4d086SWilliam Tu }
3272f2a4d086SWilliam Tu
3273971427f3SAndy Zhou case OVS_ACTION_ATTR_HASH: {
3274971427f3SAndy Zhou const struct ovs_action_hash *act_hash = nla_data(a);
3275971427f3SAndy Zhou
3276971427f3SAndy Zhou switch (act_hash->hash_alg) {
3277971427f3SAndy Zhou case OVS_HASH_ALG_L4:
3278e069ba07SAaron Conole fallthrough;
3279e069ba07SAaron Conole case OVS_HASH_ALG_SYM_L4:
3280971427f3SAndy Zhou break;
3281971427f3SAndy Zhou default:
3282971427f3SAndy Zhou return -EINVAL;
3283971427f3SAndy Zhou }
3284971427f3SAndy Zhou
3285971427f3SAndy Zhou break;
3286971427f3SAndy Zhou }
3287e6445719SPravin B Shelar
3288e6445719SPravin B Shelar case OVS_ACTION_ATTR_POP_VLAN:
32890a6410fbSJiri Benc if (mac_proto != MAC_PROTO_ETHERNET)
32900a6410fbSJiri Benc return -EINVAL;
329125cd9ba0SSimon Horman vlan_tci = htons(0);
3292e6445719SPravin B Shelar break;
3293e6445719SPravin B Shelar
3294e6445719SPravin B Shelar case OVS_ACTION_ATTR_PUSH_VLAN:
32950a6410fbSJiri Benc if (mac_proto != MAC_PROTO_ETHERNET)
32960a6410fbSJiri Benc return -EINVAL;
3297e6445719SPravin B Shelar vlan = nla_data(a);
3298018c1ddaSEric Garver if (!eth_type_vlan(vlan->vlan_tpid))
3299e6445719SPravin B Shelar return -EINVAL;
33009df46aefSMichał Mirosław if (!(vlan->vlan_tci & htons(VLAN_CFI_MASK)))
3301e6445719SPravin B Shelar return -EINVAL;
330225cd9ba0SSimon Horman vlan_tci = vlan->vlan_tci;
3303e6445719SPravin B Shelar break;
3304e6445719SPravin B Shelar
3305971427f3SAndy Zhou case OVS_ACTION_ATTR_RECIRC:
3306971427f3SAndy Zhou break;
3307971427f3SAndy Zhou
3308f66b53fdSMartin Varghese case OVS_ACTION_ATTR_ADD_MPLS: {
3309f66b53fdSMartin Varghese const struct ovs_action_add_mpls *mpls = nla_data(a);
3310f66b53fdSMartin Varghese
3311f66b53fdSMartin Varghese if (!eth_p_mpls(mpls->mpls_ethertype))
3312f66b53fdSMartin Varghese return -EINVAL;
3313f66b53fdSMartin Varghese
3314f66b53fdSMartin Varghese if (mpls->tun_flags & OVS_MPLS_L3_TUNNEL_FLAG_MASK) {
3315f66b53fdSMartin Varghese if (vlan_tci & htons(VLAN_CFI_MASK) ||
3316f66b53fdSMartin Varghese (eth_type != htons(ETH_P_IP) &&
3317f66b53fdSMartin Varghese eth_type != htons(ETH_P_IPV6) &&
3318f66b53fdSMartin Varghese eth_type != htons(ETH_P_ARP) &&
3319f66b53fdSMartin Varghese eth_type != htons(ETH_P_RARP) &&
3320f66b53fdSMartin Varghese !eth_p_mpls(eth_type)))
3321f66b53fdSMartin Varghese return -EINVAL;
3322f66b53fdSMartin Varghese mpls_label_count++;
3323f66b53fdSMartin Varghese } else {
3324f66b53fdSMartin Varghese if (mac_proto == MAC_PROTO_ETHERNET) {
3325f66b53fdSMartin Varghese mpls_label_count = 1;
3326f66b53fdSMartin Varghese mac_proto = MAC_PROTO_NONE;
3327f66b53fdSMartin Varghese } else {
3328f66b53fdSMartin Varghese mpls_label_count++;
3329f66b53fdSMartin Varghese }
3330f66b53fdSMartin Varghese }
3331f66b53fdSMartin Varghese eth_type = mpls->mpls_ethertype;
3332f66b53fdSMartin Varghese break;
3333f66b53fdSMartin Varghese }
3334f66b53fdSMartin Varghese
333525cd9ba0SSimon Horman case OVS_ACTION_ATTR_PUSH_MPLS: {
333625cd9ba0SSimon Horman const struct ovs_action_push_mpls *mpls = nla_data(a);
333725cd9ba0SSimon Horman
333825cd9ba0SSimon Horman if (!eth_p_mpls(mpls->mpls_ethertype))
333925cd9ba0SSimon Horman return -EINVAL;
334025cd9ba0SSimon Horman /* Prohibit push MPLS other than to a white list
334125cd9ba0SSimon Horman * for packets that have a known tag order.
334225cd9ba0SSimon Horman */
33439df46aefSMichał Mirosław if (vlan_tci & htons(VLAN_CFI_MASK) ||
334425cd9ba0SSimon Horman (eth_type != htons(ETH_P_IP) &&
334525cd9ba0SSimon Horman eth_type != htons(ETH_P_IPV6) &&
334625cd9ba0SSimon Horman eth_type != htons(ETH_P_ARP) &&
334725cd9ba0SSimon Horman eth_type != htons(ETH_P_RARP) &&
334825cd9ba0SSimon Horman !eth_p_mpls(eth_type)))
334925cd9ba0SSimon Horman return -EINVAL;
335025cd9ba0SSimon Horman eth_type = mpls->mpls_ethertype;
3351fbdcdd78SMartin Varghese mpls_label_count++;
335225cd9ba0SSimon Horman break;
335325cd9ba0SSimon Horman }
335425cd9ba0SSimon Horman
3355fbdcdd78SMartin Varghese case OVS_ACTION_ATTR_POP_MPLS: {
3356fbdcdd78SMartin Varghese __be16 proto;
33579df46aefSMichał Mirosław if (vlan_tci & htons(VLAN_CFI_MASK) ||
335825cd9ba0SSimon Horman !eth_p_mpls(eth_type))
335925cd9ba0SSimon Horman return -EINVAL;
336025cd9ba0SSimon Horman
3361fbdcdd78SMartin Varghese /* Disallow subsequent L2.5+ set actions and mpls_pop
3362fbdcdd78SMartin Varghese * actions once the last MPLS label in the packet is
3363169ccf0eSJilin Yuan * popped as there is no check here to ensure that
3364fbdcdd78SMartin Varghese * the new eth type is valid and thus set actions could
3365fbdcdd78SMartin Varghese * write off the end of the packet or otherwise corrupt
3366fbdcdd78SMartin Varghese * it.
336725cd9ba0SSimon Horman *
336825cd9ba0SSimon Horman * Support for these actions is planned using packet
336925cd9ba0SSimon Horman * recirculation.
337025cd9ba0SSimon Horman */
3371fbdcdd78SMartin Varghese proto = nla_get_be16(a);
3372f66b53fdSMartin Varghese
3373f66b53fdSMartin Varghese if (proto == htons(ETH_P_TEB) &&
3374f66b53fdSMartin Varghese mac_proto != MAC_PROTO_NONE)
3375f66b53fdSMartin Varghese return -EINVAL;
3376f66b53fdSMartin Varghese
3377fbdcdd78SMartin Varghese mpls_label_count--;
3378fbdcdd78SMartin Varghese
3379fbdcdd78SMartin Varghese if (!eth_p_mpls(proto) || !mpls_label_count)
338025cd9ba0SSimon Horman eth_type = htons(0);
3381fbdcdd78SMartin Varghese else
3382fbdcdd78SMartin Varghese eth_type = proto;
3383fbdcdd78SMartin Varghese
338425cd9ba0SSimon Horman break;
3385fbdcdd78SMartin Varghese }
338625cd9ba0SSimon Horman
3387e6445719SPravin B Shelar case OVS_ACTION_ATTR_SET:
338825cd9ba0SSimon Horman err = validate_set(a, key, sfa,
33890a6410fbSJiri Benc &skip_copy, mac_proto, eth_type,
33900a6410fbSJiri Benc false, log);
339183d2b9baSJarno Rajahalme if (err)
339283d2b9baSJarno Rajahalme return err;
339383d2b9baSJarno Rajahalme break;
339483d2b9baSJarno Rajahalme
339583d2b9baSJarno Rajahalme case OVS_ACTION_ATTR_SET_MASKED:
339683d2b9baSJarno Rajahalme err = validate_set(a, key, sfa,
33970a6410fbSJiri Benc &skip_copy, mac_proto, eth_type,
33980a6410fbSJiri Benc true, log);
3399e6445719SPravin B Shelar if (err)
3400e6445719SPravin B Shelar return err;
3401e6445719SPravin B Shelar break;
3402e6445719SPravin B Shelar
3403798c1661Sandy zhou case OVS_ACTION_ATTR_SAMPLE: {
3404798c1661Sandy zhou bool last = nla_is_last(a, rem);
3405798c1661Sandy zhou
3406798c1661Sandy zhou err = validate_and_copy_sample(net, a, key, sfa,
3407798c1661Sandy zhou eth_type, vlan_tci,
3408fbdcdd78SMartin Varghese mpls_label_count,
34096e2f90d3SAaron Conole log, last, depth);
3410e6445719SPravin B Shelar if (err)
3411e6445719SPravin B Shelar return err;
3412e6445719SPravin B Shelar skip_copy = true;
3413e6445719SPravin B Shelar break;
3414798c1661Sandy zhou }
3415e6445719SPravin B Shelar
34167f8a436eSJoe Stringer case OVS_ACTION_ATTR_CT:
34177f8a436eSJoe Stringer err = ovs_ct_copy_action(net, a, key, sfa, log);
34187f8a436eSJoe Stringer if (err)
34197f8a436eSJoe Stringer return err;
34207f8a436eSJoe Stringer skip_copy = true;
34217f8a436eSJoe Stringer break;
34227f8a436eSJoe Stringer
3423b8226962SEric Garver case OVS_ACTION_ATTR_CT_CLEAR:
3424b8226962SEric Garver break;
3425b8226962SEric Garver
342691820da6SJiri Benc case OVS_ACTION_ATTR_PUSH_ETH:
342791820da6SJiri Benc /* Disallow pushing an Ethernet header if one
342891820da6SJiri Benc * is already present */
342991820da6SJiri Benc if (mac_proto != MAC_PROTO_NONE)
343091820da6SJiri Benc return -EINVAL;
343146ebe283SJaime Caamaño Ruiz mac_proto = MAC_PROTO_ETHERNET;
343291820da6SJiri Benc break;
343391820da6SJiri Benc
343491820da6SJiri Benc case OVS_ACTION_ATTR_POP_ETH:
343591820da6SJiri Benc if (mac_proto != MAC_PROTO_ETHERNET)
343691820da6SJiri Benc return -EINVAL;
34379df46aefSMichał Mirosław if (vlan_tci & htons(VLAN_CFI_MASK))
343891820da6SJiri Benc return -EINVAL;
343946ebe283SJaime Caamaño Ruiz mac_proto = MAC_PROTO_NONE;
344091820da6SJiri Benc break;
344191820da6SJiri Benc
3442b2d0f5d5SYi Yang case OVS_ACTION_ATTR_PUSH_NSH:
3443b2d0f5d5SYi Yang if (mac_proto != MAC_PROTO_ETHERNET) {
3444b2d0f5d5SYi Yang u8 next_proto;
3445b2d0f5d5SYi Yang
3446b2d0f5d5SYi Yang next_proto = tun_p_from_eth_p(eth_type);
3447b2d0f5d5SYi Yang if (!next_proto)
3448b2d0f5d5SYi Yang return -EINVAL;
3449b2d0f5d5SYi Yang }
3450b2d0f5d5SYi Yang mac_proto = MAC_PROTO_NONE;
3451b2d0f5d5SYi Yang if (!validate_nsh(nla_data(a), false, true, true))
3452b2d0f5d5SYi Yang return -EINVAL;
3453b2d0f5d5SYi Yang break;
3454b2d0f5d5SYi Yang
3455b2d0f5d5SYi Yang case OVS_ACTION_ATTR_POP_NSH: {
3456b2d0f5d5SYi Yang __be16 inner_proto;
3457b2d0f5d5SYi Yang
3458b2d0f5d5SYi Yang if (eth_type != htons(ETH_P_NSH))
3459b2d0f5d5SYi Yang return -EINVAL;
3460b2d0f5d5SYi Yang inner_proto = tun_p_to_eth_p(key->nsh.base.np);
3461b2d0f5d5SYi Yang if (!inner_proto)
3462b2d0f5d5SYi Yang return -EINVAL;
3463b2d0f5d5SYi Yang if (key->nsh.base.np == TUN_P_ETHERNET)
3464b2d0f5d5SYi Yang mac_proto = MAC_PROTO_ETHERNET;
3465b2d0f5d5SYi Yang else
3466b2d0f5d5SYi Yang mac_proto = MAC_PROTO_NONE;
3467b2d0f5d5SYi Yang break;
3468b2d0f5d5SYi Yang }
3469b2d0f5d5SYi Yang
3470cd8a6c33SAndy Zhou case OVS_ACTION_ATTR_METER:
3471cd8a6c33SAndy Zhou /* Non-existent meters are simply ignored. */
3472cd8a6c33SAndy Zhou break;
3473cd8a6c33SAndy Zhou
3474b2335040SYifeng Sun case OVS_ACTION_ATTR_CLONE: {
3475b2335040SYifeng Sun bool last = nla_is_last(a, rem);
3476b2335040SYifeng Sun
3477b2335040SYifeng Sun err = validate_and_copy_clone(net, a, key, sfa,
3478b2335040SYifeng Sun eth_type, vlan_tci,
3479fbdcdd78SMartin Varghese mpls_label_count,
34806e2f90d3SAaron Conole log, last, depth);
3481b2335040SYifeng Sun if (err)
3482b2335040SYifeng Sun return err;
3483b2335040SYifeng Sun skip_copy = true;
3484b2335040SYifeng Sun break;
3485b2335040SYifeng Sun }
3486b2335040SYifeng Sun
34874d5ec89fSNuman Siddique case OVS_ACTION_ATTR_CHECK_PKT_LEN: {
34884d5ec89fSNuman Siddique bool last = nla_is_last(a, rem);
34894d5ec89fSNuman Siddique
34904d5ec89fSNuman Siddique err = validate_and_copy_check_pkt_len(net, a, key, sfa,
34914d5ec89fSNuman Siddique eth_type,
3492fbdcdd78SMartin Varghese vlan_tci,
3493fbdcdd78SMartin Varghese mpls_label_count,
34946e2f90d3SAaron Conole log, last,
34956e2f90d3SAaron Conole depth);
34964d5ec89fSNuman Siddique if (err)
34974d5ec89fSNuman Siddique return err;
34984d5ec89fSNuman Siddique skip_copy = true;
34994d5ec89fSNuman Siddique break;
35004d5ec89fSNuman Siddique }
35014d5ec89fSNuman Siddique
3502744676e7SMatteo Croce case OVS_ACTION_ATTR_DEC_TTL:
3503744676e7SMatteo Croce err = validate_and_copy_dec_ttl(net, a, key, sfa,
3504744676e7SMatteo Croce eth_type, vlan_tci,
35056e2f90d3SAaron Conole mpls_label_count, log,
35066e2f90d3SAaron Conole depth);
3507744676e7SMatteo Croce if (err)
3508744676e7SMatteo Croce return err;
3509744676e7SMatteo Croce skip_copy = true;
3510744676e7SMatteo Croce break;
3511744676e7SMatteo Croce
3512e7bc7db9SEric Garver case OVS_ACTION_ATTR_DROP:
3513e7bc7db9SEric Garver if (!nla_is_last(a, rem))
3514e7bc7db9SEric Garver return -EINVAL;
3515e7bc7db9SEric Garver break;
3516e7bc7db9SEric Garver
3517aae0b82bSAdrian Moreno case OVS_ACTION_ATTR_PSAMPLE:
3518aae0b82bSAdrian Moreno err = validate_psample(a);
3519aae0b82bSAdrian Moreno if (err)
3520aae0b82bSAdrian Moreno return err;
3521aae0b82bSAdrian Moreno break;
3522aae0b82bSAdrian Moreno
3523e6445719SPravin B Shelar default:
352405da5898SJarno Rajahalme OVS_NLERR(log, "Unknown Action type %d", type);
3525e6445719SPravin B Shelar return -EINVAL;
3526e6445719SPravin B Shelar }
3527e6445719SPravin B Shelar if (!skip_copy) {
352805da5898SJarno Rajahalme err = copy_action(a, sfa, log);
3529e6445719SPravin B Shelar if (err)
3530e6445719SPravin B Shelar return err;
3531e6445719SPravin B Shelar }
3532e6445719SPravin B Shelar }
3533e6445719SPravin B Shelar
3534e6445719SPravin B Shelar if (rem > 0)
3535e6445719SPravin B Shelar return -EINVAL;
3536e6445719SPravin B Shelar
3537e6445719SPravin B Shelar return 0;
3538e6445719SPravin B Shelar }
3539e6445719SPravin B Shelar
354083d2b9baSJarno Rajahalme /* 'key' must be the masked key. */
ovs_nla_copy_actions(struct net * net,const struct nlattr * attr,const struct sw_flow_key * key,struct sw_flow_actions ** sfa,bool log)35417f8a436eSJoe Stringer int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
354225cd9ba0SSimon Horman const struct sw_flow_key *key,
354305da5898SJarno Rajahalme struct sw_flow_actions **sfa, bool log)
354425cd9ba0SSimon Horman {
35452fdb957dSPravin B Shelar int err;
3546fbdcdd78SMartin Varghese u32 mpls_label_count = 0;
35472fdb957dSPravin B Shelar
354867c8d22aSzhangliping *sfa = nla_alloc_flow_actions(min(nla_len(attr), MAX_ACTIONS_BUFSIZE));
35492fdb957dSPravin B Shelar if (IS_ERR(*sfa))
35502fdb957dSPravin B Shelar return PTR_ERR(*sfa);
35512fdb957dSPravin B Shelar
3552fbdcdd78SMartin Varghese if (eth_p_mpls(key->eth.type))
3553fbdcdd78SMartin Varghese mpls_label_count = hweight_long(key->mpls.num_labels_mask);
3554fbdcdd78SMartin Varghese
35558e2fed1cSJoe Stringer (*sfa)->orig_len = nla_len(attr);
3556798c1661Sandy zhou err = __ovs_nla_copy_actions(net, attr, key, sfa, key->eth.type,
35576e2f90d3SAaron Conole key->eth.vlan.tci, mpls_label_count, log,
35586e2f90d3SAaron Conole 0);
35592fdb957dSPravin B Shelar if (err)
356034ae932aSThomas Graf ovs_nla_free_flow_actions(*sfa);
35612fdb957dSPravin B Shelar
35622fdb957dSPravin B Shelar return err;
356325cd9ba0SSimon Horman }
356425cd9ba0SSimon Horman
sample_action_to_attr(const struct nlattr * attr,struct sk_buff * skb)3565798c1661Sandy zhou static int sample_action_to_attr(const struct nlattr *attr,
3566798c1661Sandy zhou struct sk_buff *skb)
3567e6445719SPravin B Shelar {
3568798c1661Sandy zhou struct nlattr *start, *ac_start = NULL, *sample_arg;
3569798c1661Sandy zhou int err = 0, rem = nla_len(attr);
3570798c1661Sandy zhou const struct sample_arg *arg;
3571798c1661Sandy zhou struct nlattr *actions;
3572e6445719SPravin B Shelar
3573ae0be8deSMichal Kubecek start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SAMPLE);
3574e6445719SPravin B Shelar if (!start)
3575e6445719SPravin B Shelar return -EMSGSIZE;
3576e6445719SPravin B Shelar
3577798c1661Sandy zhou sample_arg = nla_data(attr);
3578798c1661Sandy zhou arg = nla_data(sample_arg);
3579798c1661Sandy zhou actions = nla_next(sample_arg, &rem);
3580e6445719SPravin B Shelar
3581798c1661Sandy zhou if (nla_put_u32(skb, OVS_SAMPLE_ATTR_PROBABILITY, arg->probability)) {
3582798c1661Sandy zhou err = -EMSGSIZE;
3583798c1661Sandy zhou goto out;
3584e6445719SPravin B Shelar }
3585e6445719SPravin B Shelar
3586ae0be8deSMichal Kubecek ac_start = nla_nest_start_noflag(skb, OVS_SAMPLE_ATTR_ACTIONS);
3587798c1661Sandy zhou if (!ac_start) {
3588798c1661Sandy zhou err = -EMSGSIZE;
3589798c1661Sandy zhou goto out;
3590798c1661Sandy zhou }
3591798c1661Sandy zhou
3592798c1661Sandy zhou err = ovs_nla_put_actions(actions, rem, skb);
3593798c1661Sandy zhou
3594798c1661Sandy zhou out:
3595798c1661Sandy zhou if (err) {
3596798c1661Sandy zhou nla_nest_cancel(skb, ac_start);
3597798c1661Sandy zhou nla_nest_cancel(skb, start);
3598798c1661Sandy zhou } else {
3599798c1661Sandy zhou nla_nest_end(skb, ac_start);
3600e6445719SPravin B Shelar nla_nest_end(skb, start);
3601798c1661Sandy zhou }
3602798c1661Sandy zhou
3603e6445719SPravin B Shelar return err;
3604e6445719SPravin B Shelar }
3605e6445719SPravin B Shelar
clone_action_to_attr(const struct nlattr * attr,struct sk_buff * skb)3606b2335040SYifeng Sun static int clone_action_to_attr(const struct nlattr *attr,
3607b2335040SYifeng Sun struct sk_buff *skb)
3608b2335040SYifeng Sun {
3609b2335040SYifeng Sun struct nlattr *start;
3610b2335040SYifeng Sun int err = 0, rem = nla_len(attr);
3611b2335040SYifeng Sun
3612ae0be8deSMichal Kubecek start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_CLONE);
3613b2335040SYifeng Sun if (!start)
3614b2335040SYifeng Sun return -EMSGSIZE;
3615b2335040SYifeng Sun
36163f2a3050SIlya Maximets /* Skipping the OVS_CLONE_ATTR_EXEC that is always the first attribute. */
36173f2a3050SIlya Maximets attr = nla_next(nla_data(attr), &rem);
36183f2a3050SIlya Maximets err = ovs_nla_put_actions(attr, rem, skb);
3619b2335040SYifeng Sun
3620b2335040SYifeng Sun if (err)
3621b2335040SYifeng Sun nla_nest_cancel(skb, start);
3622b2335040SYifeng Sun else
3623b2335040SYifeng Sun nla_nest_end(skb, start);
3624b2335040SYifeng Sun
3625b2335040SYifeng Sun return err;
3626b2335040SYifeng Sun }
3627b2335040SYifeng Sun
check_pkt_len_action_to_attr(const struct nlattr * attr,struct sk_buff * skb)36284d5ec89fSNuman Siddique static int check_pkt_len_action_to_attr(const struct nlattr *attr,
36294d5ec89fSNuman Siddique struct sk_buff *skb)
36304d5ec89fSNuman Siddique {
36314d5ec89fSNuman Siddique struct nlattr *start, *ac_start = NULL;
36324d5ec89fSNuman Siddique const struct check_pkt_len_arg *arg;
36334d5ec89fSNuman Siddique const struct nlattr *a, *cpl_arg;
36344d5ec89fSNuman Siddique int err = 0, rem = nla_len(attr);
36354d5ec89fSNuman Siddique
3636ae0be8deSMichal Kubecek start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_CHECK_PKT_LEN);
36374d5ec89fSNuman Siddique if (!start)
36384d5ec89fSNuman Siddique return -EMSGSIZE;
36394d5ec89fSNuman Siddique
36404d5ec89fSNuman Siddique /* The first nested attribute in 'attr' is always
36414d5ec89fSNuman Siddique * 'OVS_CHECK_PKT_LEN_ATTR_ARG'.
36424d5ec89fSNuman Siddique */
36434d5ec89fSNuman Siddique cpl_arg = nla_data(attr);
36444d5ec89fSNuman Siddique arg = nla_data(cpl_arg);
36454d5ec89fSNuman Siddique
36464d5ec89fSNuman Siddique if (nla_put_u16(skb, OVS_CHECK_PKT_LEN_ATTR_PKT_LEN, arg->pkt_len)) {
36474d5ec89fSNuman Siddique err = -EMSGSIZE;
36484d5ec89fSNuman Siddique goto out;
36494d5ec89fSNuman Siddique }
36504d5ec89fSNuman Siddique
36514d5ec89fSNuman Siddique /* Second nested attribute in 'attr' is always
36524d5ec89fSNuman Siddique * 'OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL'.
36534d5ec89fSNuman Siddique */
36544d5ec89fSNuman Siddique a = nla_next(cpl_arg, &rem);
3655ae0be8deSMichal Kubecek ac_start = nla_nest_start_noflag(skb,
36564d5ec89fSNuman Siddique OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL);
36574d5ec89fSNuman Siddique if (!ac_start) {
36584d5ec89fSNuman Siddique err = -EMSGSIZE;
36594d5ec89fSNuman Siddique goto out;
36604d5ec89fSNuman Siddique }
36614d5ec89fSNuman Siddique
36624d5ec89fSNuman Siddique err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb);
36634d5ec89fSNuman Siddique if (err) {
36644d5ec89fSNuman Siddique nla_nest_cancel(skb, ac_start);
36654d5ec89fSNuman Siddique goto out;
36664d5ec89fSNuman Siddique } else {
36674d5ec89fSNuman Siddique nla_nest_end(skb, ac_start);
36684d5ec89fSNuman Siddique }
36694d5ec89fSNuman Siddique
36704d5ec89fSNuman Siddique /* Third nested attribute in 'attr' is always
36714d5ec89fSNuman Siddique * OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER.
36724d5ec89fSNuman Siddique */
36734d5ec89fSNuman Siddique a = nla_next(a, &rem);
3674ae0be8deSMichal Kubecek ac_start = nla_nest_start_noflag(skb,
36754d5ec89fSNuman Siddique OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER);
36764d5ec89fSNuman Siddique if (!ac_start) {
36774d5ec89fSNuman Siddique err = -EMSGSIZE;
36784d5ec89fSNuman Siddique goto out;
36794d5ec89fSNuman Siddique }
36804d5ec89fSNuman Siddique
36814d5ec89fSNuman Siddique err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb);
36824d5ec89fSNuman Siddique if (err) {
36834d5ec89fSNuman Siddique nla_nest_cancel(skb, ac_start);
36844d5ec89fSNuman Siddique goto out;
36854d5ec89fSNuman Siddique } else {
36864d5ec89fSNuman Siddique nla_nest_end(skb, ac_start);
36874d5ec89fSNuman Siddique }
36884d5ec89fSNuman Siddique
36894d5ec89fSNuman Siddique nla_nest_end(skb, start);
36904d5ec89fSNuman Siddique return 0;
36914d5ec89fSNuman Siddique
36924d5ec89fSNuman Siddique out:
36934d5ec89fSNuman Siddique nla_nest_cancel(skb, start);
36944d5ec89fSNuman Siddique return err;
36954d5ec89fSNuman Siddique }
36964d5ec89fSNuman Siddique
dec_ttl_action_to_attr(const struct nlattr * attr,struct sk_buff * skb)3697744676e7SMatteo Croce static int dec_ttl_action_to_attr(const struct nlattr *attr,
3698744676e7SMatteo Croce struct sk_buff *skb)
3699744676e7SMatteo Croce {
370069929d4cSEelco Chaudron struct nlattr *start, *action_start;
370169929d4cSEelco Chaudron const struct nlattr *a;
370269929d4cSEelco Chaudron int err = 0, rem;
3703744676e7SMatteo Croce
3704744676e7SMatteo Croce start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_DEC_TTL);
3705744676e7SMatteo Croce if (!start)
3706744676e7SMatteo Croce return -EMSGSIZE;
3707744676e7SMatteo Croce
370869929d4cSEelco Chaudron nla_for_each_attr(a, nla_data(attr), nla_len(attr), rem) {
370969929d4cSEelco Chaudron switch (nla_type(a)) {
371069929d4cSEelco Chaudron case OVS_DEC_TTL_ATTR_ACTION:
3711744676e7SMatteo Croce
371269929d4cSEelco Chaudron action_start = nla_nest_start_noflag(skb, OVS_DEC_TTL_ATTR_ACTION);
371369929d4cSEelco Chaudron if (!action_start) {
371469929d4cSEelco Chaudron err = -EMSGSIZE;
371569929d4cSEelco Chaudron goto out;
371669929d4cSEelco Chaudron }
371769929d4cSEelco Chaudron
371869929d4cSEelco Chaudron err = ovs_nla_put_actions(nla_data(a), nla_len(a), skb);
371969929d4cSEelco Chaudron if (err)
372069929d4cSEelco Chaudron goto out;
372169929d4cSEelco Chaudron
372269929d4cSEelco Chaudron nla_nest_end(skb, action_start);
372369929d4cSEelco Chaudron break;
372469929d4cSEelco Chaudron
372569929d4cSEelco Chaudron default:
372669929d4cSEelco Chaudron /* Ignore all other option to be future compatible */
372769929d4cSEelco Chaudron break;
372869929d4cSEelco Chaudron }
372969929d4cSEelco Chaudron }
373069929d4cSEelco Chaudron
373169929d4cSEelco Chaudron nla_nest_end(skb, start);
373269929d4cSEelco Chaudron return 0;
373369929d4cSEelco Chaudron
373469929d4cSEelco Chaudron out:
373569929d4cSEelco Chaudron nla_nest_cancel(skb, start);
3736744676e7SMatteo Croce return err;
3737744676e7SMatteo Croce }
3738744676e7SMatteo Croce
set_action_to_attr(const struct nlattr * a,struct sk_buff * skb)3739e6445719SPravin B Shelar static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
3740e6445719SPravin B Shelar {
3741e6445719SPravin B Shelar const struct nlattr *ovs_key = nla_data(a);
3742e6445719SPravin B Shelar int key_type = nla_type(ovs_key);
3743e6445719SPravin B Shelar struct nlattr *start;
3744e6445719SPravin B Shelar int err;
3745e6445719SPravin B Shelar
3746e6445719SPravin B Shelar switch (key_type) {
3747f0b128c1SJesse Gross case OVS_KEY_ATTR_TUNNEL_INFO: {
374834ae932aSThomas Graf struct ovs_tunnel_info *ovs_tun = nla_data(ovs_key);
374934ae932aSThomas Graf struct ip_tunnel_info *tun_info = &ovs_tun->tun_dst->u.tun_info;
3750f0b128c1SJesse Gross
3751ae0be8deSMichal Kubecek start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SET);
3752e6445719SPravin B Shelar if (!start)
3753e6445719SPravin B Shelar return -EMSGSIZE;
3754e6445719SPravin B Shelar
3755e905eabcSSimon Horman err = ip_tun_to_nlattr(skb, &tun_info->key,
3756e905eabcSSimon Horman ip_tunnel_info_opts(tun_info),
3757e905eabcSSimon Horman tun_info->options_len,
375818b6f717Swenxu ip_tunnel_info_af(tun_info), tun_info->mode);
3759e6445719SPravin B Shelar if (err)
3760e6445719SPravin B Shelar return err;
3761e6445719SPravin B Shelar nla_nest_end(skb, start);
3762e6445719SPravin B Shelar break;
3763f0b128c1SJesse Gross }
3764e6445719SPravin B Shelar default:
3765e6445719SPravin B Shelar if (nla_put(skb, OVS_ACTION_ATTR_SET, nla_len(a), ovs_key))
3766e6445719SPravin B Shelar return -EMSGSIZE;
3767e6445719SPravin B Shelar break;
3768e6445719SPravin B Shelar }
3769e6445719SPravin B Shelar
3770e6445719SPravin B Shelar return 0;
3771e6445719SPravin B Shelar }
3772e6445719SPravin B Shelar
masked_set_action_to_set_action_attr(const struct nlattr * a,struct sk_buff * skb)377383d2b9baSJarno Rajahalme static int masked_set_action_to_set_action_attr(const struct nlattr *a,
377483d2b9baSJarno Rajahalme struct sk_buff *skb)
377583d2b9baSJarno Rajahalme {
377683d2b9baSJarno Rajahalme const struct nlattr *ovs_key = nla_data(a);
3777f4f8e738SJoe Stringer struct nlattr *nla;
377883d2b9baSJarno Rajahalme size_t key_len = nla_len(ovs_key) / 2;
377983d2b9baSJarno Rajahalme
378083d2b9baSJarno Rajahalme /* Revert the conversion we did from a non-masked set action to
378183d2b9baSJarno Rajahalme * masked set action.
378283d2b9baSJarno Rajahalme */
3783ae0be8deSMichal Kubecek nla = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_SET);
3784f4f8e738SJoe Stringer if (!nla)
378583d2b9baSJarno Rajahalme return -EMSGSIZE;
378683d2b9baSJarno Rajahalme
3787f4f8e738SJoe Stringer if (nla_put(skb, nla_type(ovs_key), key_len, nla_data(ovs_key)))
3788f4f8e738SJoe Stringer return -EMSGSIZE;
3789f4f8e738SJoe Stringer
3790f4f8e738SJoe Stringer nla_nest_end(skb, nla);
379183d2b9baSJarno Rajahalme return 0;
379283d2b9baSJarno Rajahalme }
379383d2b9baSJarno Rajahalme
ovs_nla_put_actions(const struct nlattr * attr,int len,struct sk_buff * skb)3794e6445719SPravin B Shelar int ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb)
3795e6445719SPravin B Shelar {
3796e6445719SPravin B Shelar const struct nlattr *a;
3797e6445719SPravin B Shelar int rem, err;
3798e6445719SPravin B Shelar
3799e6445719SPravin B Shelar nla_for_each_attr(a, attr, len, rem) {
3800e6445719SPravin B Shelar int type = nla_type(a);
3801e6445719SPravin B Shelar
3802e6445719SPravin B Shelar switch (type) {
3803e6445719SPravin B Shelar case OVS_ACTION_ATTR_SET:
3804e6445719SPravin B Shelar err = set_action_to_attr(a, skb);
3805e6445719SPravin B Shelar if (err)
3806e6445719SPravin B Shelar return err;
3807e6445719SPravin B Shelar break;
3808e6445719SPravin B Shelar
380983d2b9baSJarno Rajahalme case OVS_ACTION_ATTR_SET_TO_MASKED:
381083d2b9baSJarno Rajahalme err = masked_set_action_to_set_action_attr(a, skb);
381183d2b9baSJarno Rajahalme if (err)
381283d2b9baSJarno Rajahalme return err;
381383d2b9baSJarno Rajahalme break;
381483d2b9baSJarno Rajahalme
3815e6445719SPravin B Shelar case OVS_ACTION_ATTR_SAMPLE:
3816e6445719SPravin B Shelar err = sample_action_to_attr(a, skb);
3817e6445719SPravin B Shelar if (err)
3818e6445719SPravin B Shelar return err;
3819e6445719SPravin B Shelar break;
38207f8a436eSJoe Stringer
38217f8a436eSJoe Stringer case OVS_ACTION_ATTR_CT:
38227f8a436eSJoe Stringer err = ovs_ct_action_to_attr(nla_data(a), skb);
38237f8a436eSJoe Stringer if (err)
38247f8a436eSJoe Stringer return err;
38257f8a436eSJoe Stringer break;
38267f8a436eSJoe Stringer
3827b2335040SYifeng Sun case OVS_ACTION_ATTR_CLONE:
3828b2335040SYifeng Sun err = clone_action_to_attr(a, skb);
3829b2335040SYifeng Sun if (err)
3830b2335040SYifeng Sun return err;
3831b2335040SYifeng Sun break;
3832b2335040SYifeng Sun
38334d5ec89fSNuman Siddique case OVS_ACTION_ATTR_CHECK_PKT_LEN:
38344d5ec89fSNuman Siddique err = check_pkt_len_action_to_attr(a, skb);
38354d5ec89fSNuman Siddique if (err)
38364d5ec89fSNuman Siddique return err;
38374d5ec89fSNuman Siddique break;
38384d5ec89fSNuman Siddique
3839744676e7SMatteo Croce case OVS_ACTION_ATTR_DEC_TTL:
3840744676e7SMatteo Croce err = dec_ttl_action_to_attr(a, skb);
3841744676e7SMatteo Croce if (err)
3842744676e7SMatteo Croce return err;
3843744676e7SMatteo Croce break;
3844744676e7SMatteo Croce
3845e6445719SPravin B Shelar default:
3846e6445719SPravin B Shelar if (nla_put(skb, type, nla_len(a), nla_data(a)))
3847e6445719SPravin B Shelar return -EMSGSIZE;
3848e6445719SPravin B Shelar break;
3849e6445719SPravin B Shelar }
3850e6445719SPravin B Shelar }
3851e6445719SPravin B Shelar
3852e6445719SPravin B Shelar return 0;
3853e6445719SPravin B Shelar }
3854