]> git.proxmox.com Git - mirror_ovs.git/blame - lib/tc.c
cirrus: Use FreeBSD 12.2.
[mirror_ovs.git] / lib / tc.c
CommitLineData
c1c5c723 1/*
ef3767f5 2 * Copyright (c) 2009-2017 Nicira, Inc.
f98e418f 3 * Copyright (c) 2016 Mellanox Technologies, Ltd.
c1c5c723
PB
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <config.h>
19#include "tc.h"
ef3767f5 20
c1c5c723 21#include <errno.h>
f98e418f 22#include <linux/if_ether.h>
4aa2dc04 23#include <linux/if_packet.h>
f98e418f 24#include <linux/rtnetlink.h>
8ada482b 25#include <linux/tc_act/tc_csum.h>
f98e418f
RD
26#include <linux/tc_act/tc_gact.h>
27#include <linux/tc_act/tc_mirred.h>
55412eac 28#include <linux/tc_act/tc_mpls.h>
8ada482b 29#include <linux/tc_act/tc_pedit.h>
4aa2dc04 30#include <linux/tc_act/tc_skbedit.h>
f98e418f
RD
31#include <linux/tc_act/tc_tunnel_key.h>
32#include <linux/tc_act/tc_vlan.h>
576126a9 33#include <linux/tc_act/tc_ct.h>
f98e418f
RD
34#include <linux/gen_stats.h>
35#include <net/if.h>
8c1e74d1 36#include <unistd.h>
ef3767f5 37
f98e418f 38#include "byte-order.h"
c1c5c723
PB
39#include "netlink-socket.h"
40#include "netlink.h"
41#include "openvswitch/ofpbuf.h"
8ada482b 42#include "openvswitch/util.h"
c1c5c723 43#include "openvswitch/vlog.h"
f98e418f
RD
44#include "packets.h"
45#include "timeval.h"
ef3767f5 46#include "unaligned.h"
c1c5c723 47
8ada482b
PB
48#define MAX_PEDIT_OFFSETS 32
49
093c9458
JH
50#ifndef TCM_IFINDEX_MAGIC_BLOCK
51#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
52#endif
53
5db012c4
VB
54#ifndef TCA_DUMP_FLAGS_TERSE
55#define TCA_DUMP_FLAGS_TERSE (1 << 0)
56#endif
57
58#if TCA_MAX < 15
b2ae4069 59#define TCA_CHAIN 11
093c9458 60#define TCA_INGRESS_BLOCK 13
5db012c4 61#define TCA_DUMP_FLAGS 15
093c9458
JH
62#endif
63
c1c5c723
PB
64VLOG_DEFINE_THIS_MODULE(tc);
65
f98e418f
RD
66static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);
67
691d20cb
PB
68static enum tc_offload_policy tc_policy = TC_POLICY_NONE;
69
8ada482b
PB
70struct tc_pedit_key_ex {
71 enum pedit_header_type htype;
72 enum pedit_cmd cmd;
73};
74
75struct flower_key_to_pedit {
76 enum pedit_header_type htype;
8ada482b 77 int offset;
fbaf1bf9 78 int flower_offset;
8ada482b 79 int size;
dbcb014d 80 int boundary_shift;
8ada482b
PB
81};
82
83static struct flower_key_to_pedit flower_pedit_map[] = {
84 {
85 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,
86 12,
87 offsetof(struct tc_flower_key, ipv4.ipv4_src),
dbcb014d
PJV
88 MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_src),
89 0
8ada482b
PB
90 }, {
91 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,
92 16,
93 offsetof(struct tc_flower_key, ipv4.ipv4_dst),
dbcb014d
PJV
94 MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_dst),
95 0
8ada482b
PB
96 }, {
97 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,
98 8,
99 offsetof(struct tc_flower_key, ipv4.rewrite_ttl),
dbcb014d
PJV
100 MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_ttl),
101 0
95431229
PJV
102 }, {
103 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,
104 1,
105 offsetof(struct tc_flower_key, ipv4.rewrite_tos),
dbcb014d
PJV
106 MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_tos),
107 0
46df7fac
EB
108 }, {
109 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,
110 7,
111 offsetof(struct tc_flower_key, ipv6.rewrite_hlimit),
dbcb014d
PJV
112 MEMBER_SIZEOF(struct tc_flower_key, ipv6.rewrite_hlimit),
113 0
8ada482b
PB
114 }, {
115 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,
116 8,
117 offsetof(struct tc_flower_key, ipv6.ipv6_src),
dbcb014d
PJV
118 MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_src),
119 0
8ada482b
PB
120 }, {
121 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,
122 24,
123 offsetof(struct tc_flower_key, ipv6.ipv6_dst),
dbcb014d
PJV
124 MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_dst),
125 0
126 }, {
127 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,
128 0,
129 offsetof(struct tc_flower_key, ipv6.rewrite_tclass),
130 MEMBER_SIZEOF(struct tc_flower_key, ipv6.rewrite_tclass),
131 4
8ada482b
PB
132 }, {
133 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,
134 6,
135 offsetof(struct tc_flower_key, src_mac),
dbcb014d
PJV
136 MEMBER_SIZEOF(struct tc_flower_key, src_mac),
137 0
8ada482b
PB
138 }, {
139 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,
140 0,
141 offsetof(struct tc_flower_key, dst_mac),
dbcb014d
PJV
142 MEMBER_SIZEOF(struct tc_flower_key, dst_mac),
143 0
8ada482b
PB
144 }, {
145 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,
146 12,
147 offsetof(struct tc_flower_key, eth_type),
dbcb014d
PJV
148 MEMBER_SIZEOF(struct tc_flower_key, eth_type),
149 0
8ada482b
PB
150 }, {
151 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,
152 0,
153 offsetof(struct tc_flower_key, tcp_src),
dbcb014d
PJV
154 MEMBER_SIZEOF(struct tc_flower_key, tcp_src),
155 0
8ada482b
PB
156 }, {
157 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,
158 2,
159 offsetof(struct tc_flower_key, tcp_dst),
dbcb014d
PJV
160 MEMBER_SIZEOF(struct tc_flower_key, tcp_dst),
161 0
8ada482b
PB
162 }, {
163 TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,
164 0,
165 offsetof(struct tc_flower_key, udp_src),
dbcb014d
PJV
166 MEMBER_SIZEOF(struct tc_flower_key, udp_src),
167 0
8ada482b
PB
168 }, {
169 TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,
170 2,
171 offsetof(struct tc_flower_key, udp_dst),
dbcb014d
PJV
172 MEMBER_SIZEOF(struct tc_flower_key, udp_dst),
173 0
8ada482b
PB
174 },
175};
176
d6118e62
PB
177static inline int
178csum_update_flag(struct tc_flower *flower,
179 enum pedit_header_type htype);
180
c1c5c723
PB
181struct tcmsg *
182tc_make_request(int ifindex, int type, unsigned int flags,
183 struct ofpbuf *request)
184{
185 struct tcmsg *tcmsg;
186
187 ofpbuf_init(request, 512);
188 nl_msg_put_nlmsghdr(request, sizeof *tcmsg, type, NLM_F_REQUEST | flags);
189 tcmsg = ofpbuf_put_zeros(request, sizeof *tcmsg);
190 tcmsg->tcm_family = AF_UNSPEC;
191 tcmsg->tcm_ifindex = ifindex;
192 /* Caller should fill in tcmsg->tcm_handle. */
193 /* Caller should fill in tcmsg->tcm_parent. */
194
195 return tcmsg;
196}
197
acdd544c
PB
198static void request_from_tcf_id(struct tcf_id *id, uint16_t eth_type,
199 int type, unsigned int flags,
200 struct ofpbuf *request)
201{
202 int ifindex = id->block_id ? TCM_IFINDEX_MAGIC_BLOCK : id->ifindex;
203 uint32_t ingress_parent = id->block_id ? : TC_INGRESS_PARENT;
204 struct tcmsg *tcmsg;
205
206 tcmsg = tc_make_request(ifindex, type, flags, request);
207 tcmsg->tcm_parent = (id->hook == TC_EGRESS) ?
208 TC_EGRESS_PARENT : ingress_parent;
209 tcmsg->tcm_info = tc_make_handle(id->prio, eth_type);
210 tcmsg->tcm_handle = id->handle;
b2ae4069
PB
211
212 if (id->chain) {
213 nl_msg_put_u32(request, TCA_CHAIN, id->chain);
214 }
acdd544c
PB
215}
216
c1c5c723
PB
217int
218tc_transact(struct ofpbuf *request, struct ofpbuf **replyp)
219{
220 int error = nl_transact(NETLINK_ROUTE, request, replyp);
221 ofpbuf_uninit(request);
222 return error;
223}
224
95255018 225/* Adds or deletes a root qdisc on device with specified ifindex.
c1c5c723 226 *
95255018
JH
227 * The tc_qdisc_hook parameter determines if the qdisc is added on device
228 * ingress or egress.
229 *
230 * If tc_qdisc_hook is TC_INGRESS, this function is equivalent to running the
231 * following when 'add' is true:
c1c5c723
PB
232 * /sbin/tc qdisc add dev <devname> handle ffff: ingress
233 *
234 * This function is equivalent to running the following when 'add' is false:
235 * /sbin/tc qdisc del dev <devname> handle ffff: ingress
236 *
95255018
JH
237 * If tc_qdisc_hook is TC_EGRESS, this function is equivalent to:
238 * /sbin/tc qdisc (add|del) dev <devname> handle ffff: clsact
239 *
c1c5c723
PB
240 * Where dev <devname> is the device with specified ifindex name.
241 *
242 * The configuration and stats may be seen with the following command:
243 * /sbin/tc -s qdisc show dev <devname>
244 *
093c9458
JH
245 * If block_id is greater than 0, then the ingress qdisc is added to a block.
246 * In this case, it is equivalent to running (when 'add' is true):
247 * /sbin/tc qdisc add dev <devname> ingress_block <block_id> ingress
248 *
c1c5c723
PB
249 * Returns 0 if successful, otherwise a positive errno value.
250 */
251int
95255018
JH
252tc_add_del_qdisc(int ifindex, bool add, uint32_t block_id,
253 enum tc_qdisc_hook hook)
c1c5c723
PB
254{
255 struct ofpbuf request;
256 struct tcmsg *tcmsg;
257 int error;
258 int type = add ? RTM_NEWQDISC : RTM_DELQDISC;
259 int flags = add ? NLM_F_EXCL | NLM_F_CREATE : 0;
260
261 tcmsg = tc_make_request(ifindex, type, flags, &request);
95255018
JH
262
263 if (hook == TC_EGRESS) {
264 tcmsg->tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0);
265 tcmsg->tcm_parent = TC_H_CLSACT;
266 nl_msg_put_string(&request, TCA_KIND, "clsact");
267 } else {
268 tcmsg->tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0);
269 tcmsg->tcm_parent = TC_H_INGRESS;
270 nl_msg_put_string(&request, TCA_KIND, "ingress");
271 }
272
c1c5c723 273 nl_msg_put_unspec(&request, TCA_OPTIONS, NULL, 0);
95255018 274 if (hook == TC_INGRESS && block_id) {
093c9458
JH
275 nl_msg_put_u32(&request, TCA_INGRESS_BLOCK, block_id);
276 }
c1c5c723
PB
277
278 error = tc_transact(&request, NULL);
279 if (error) {
280 /* If we're deleting the qdisc, don't worry about some of the
281 * error conditions. */
282 if (!add && (error == ENOENT || error == EINVAL)) {
283 return 0;
284 }
285 return error;
286 }
287
288 return 0;
289}
f98e418f
RD
290
291static const struct nl_policy tca_policy[] = {
292 [TCA_KIND] = { .type = NL_A_STRING, .optional = false, },
293 [TCA_OPTIONS] = { .type = NL_A_NESTED, .optional = false, },
b2ae4069 294 [TCA_CHAIN] = { .type = NL_A_U32, .optional = true, },
f98e418f
RD
295 [TCA_STATS] = { .type = NL_A_UNSPEC,
296 .min_len = sizeof(struct tc_stats), .optional = true, },
297 [TCA_STATS2] = { .type = NL_A_NESTED, .optional = true, },
298};
299
300static const struct nl_policy tca_flower_policy[] = {
301 [TCA_FLOWER_CLASSID] = { .type = NL_A_U32, .optional = true, },
302 [TCA_FLOWER_INDEV] = { .type = NL_A_STRING, .max_len = IFNAMSIZ,
303 .optional = true, },
304 [TCA_FLOWER_KEY_ETH_SRC] = { .type = NL_A_UNSPEC,
305 .min_len = ETH_ALEN, .optional = true, },
306 [TCA_FLOWER_KEY_ETH_DST] = { .type = NL_A_UNSPEC,
307 .min_len = ETH_ALEN, .optional = true, },
308 [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .type = NL_A_UNSPEC,
309 .min_len = ETH_ALEN,
310 .optional = true, },
311 [TCA_FLOWER_KEY_ETH_DST_MASK] = { .type = NL_A_UNSPEC,
312 .min_len = ETH_ALEN,
313 .optional = true, },
314 [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NL_A_U16, .optional = false, },
a3db6e47
TZ
315 [TCA_FLOWER_KEY_ARP_SIP] = { .type = NL_A_U32, .optional = true, },
316 [TCA_FLOWER_KEY_ARP_TIP] = { .type = NL_A_U32, .optional = true, },
317 [TCA_FLOWER_KEY_ARP_SHA] = { .type = NL_A_UNSPEC,
318 .min_len = ETH_ALEN,
319 .optional = true, },
320 [TCA_FLOWER_KEY_ARP_THA] = { .type = NL_A_UNSPEC,
321 .min_len = ETH_ALEN,
322 .optional = true, },
323 [TCA_FLOWER_KEY_ARP_OP] = { .type = NL_A_U8, .optional = true, },
324 [TCA_FLOWER_KEY_ARP_SIP_MASK] = { .type = NL_A_U32, .optional = true, },
325 [TCA_FLOWER_KEY_ARP_TIP_MASK] = { .type = NL_A_U32, .optional = true, },
326 [TCA_FLOWER_KEY_ARP_SHA_MASK] = { .type = NL_A_UNSPEC,
327 .min_len = ETH_ALEN,
328 .optional = true, },
329 [TCA_FLOWER_KEY_ARP_THA_MASK] = { .type = NL_A_UNSPEC,
330 .min_len = ETH_ALEN,
331 .optional = true, },
332 [TCA_FLOWER_KEY_ARP_OP_MASK] = { .type = NL_A_U8, .optional = true, },
f98e418f
RD
333 [TCA_FLOWER_FLAGS] = { .type = NL_A_U32, .optional = false, },
334 [TCA_FLOWER_ACT] = { .type = NL_A_NESTED, .optional = false, },
335 [TCA_FLOWER_KEY_IP_PROTO] = { .type = NL_A_U8, .optional = true, },
336 [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NL_A_U32, .optional = true, },
337 [TCA_FLOWER_KEY_IPV4_DST] = {.type = NL_A_U32, .optional = true, },
338 [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NL_A_U32, .optional = true, },
339 [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NL_A_U32, .optional = true, },
340 [TCA_FLOWER_KEY_IPV6_SRC] = { .type = NL_A_UNSPEC,
341 .min_len = sizeof(struct in6_addr),
342 .optional = true, },
343 [TCA_FLOWER_KEY_IPV6_DST] = { .type = NL_A_UNSPEC,
344 .min_len = sizeof(struct in6_addr),
345 .optional = true, },
346 [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .type = NL_A_UNSPEC,
347 .min_len = sizeof(struct in6_addr),
348 .optional = true, },
349 [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .type = NL_A_UNSPEC,
350 .min_len = sizeof(struct in6_addr),
351 .optional = true, },
352 [TCA_FLOWER_KEY_TCP_SRC] = { .type = NL_A_U16, .optional = true, },
353 [TCA_FLOWER_KEY_TCP_DST] = { .type = NL_A_U16, .optional = true, },
354 [TCA_FLOWER_KEY_TCP_SRC_MASK] = { .type = NL_A_U16, .optional = true, },
355 [TCA_FLOWER_KEY_TCP_DST_MASK] = { .type = NL_A_U16, .optional = true, },
356 [TCA_FLOWER_KEY_UDP_SRC] = { .type = NL_A_U16, .optional = true, },
357 [TCA_FLOWER_KEY_UDP_DST] = { .type = NL_A_U16, .optional = true, },
358 [TCA_FLOWER_KEY_UDP_SRC_MASK] = { .type = NL_A_U16, .optional = true, },
359 [TCA_FLOWER_KEY_UDP_DST_MASK] = { .type = NL_A_U16, .optional = true, },
4862b4e5
VB
360 [TCA_FLOWER_KEY_SCTP_SRC] = { .type = NL_A_U16, .optional = true, },
361 [TCA_FLOWER_KEY_SCTP_DST] = { .type = NL_A_U16, .optional = true, },
362 [TCA_FLOWER_KEY_SCTP_SRC_MASK] = { .type = NL_A_U16, .optional = true, },
363 [TCA_FLOWER_KEY_SCTP_DST_MASK] = { .type = NL_A_U16, .optional = true, },
34b16955
PJV
364 [TCA_FLOWER_KEY_MPLS_TTL] = { .type = NL_A_U8, .optional = true, },
365 [TCA_FLOWER_KEY_MPLS_TC] = { .type = NL_A_U8, .optional = true, },
366 [TCA_FLOWER_KEY_MPLS_BOS] = { .type = NL_A_U8, .optional = true, },
367 [TCA_FLOWER_KEY_MPLS_LABEL] = { .type = NL_A_U32, .optional = true, },
f98e418f
RD
368 [TCA_FLOWER_KEY_VLAN_ID] = { .type = NL_A_U16, .optional = true, },
369 [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NL_A_U8, .optional = true, },
370 [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NL_A_U16, .optional = true, },
371 [TCA_FLOWER_KEY_ENC_KEY_ID] = { .type = NL_A_U32, .optional = true, },
372 [TCA_FLOWER_KEY_ENC_IPV4_SRC] = { .type = NL_A_U32, .optional = true, },
373 [TCA_FLOWER_KEY_ENC_IPV4_DST] = { .type = NL_A_U32, .optional = true, },
374 [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NL_A_U32,
375 .optional = true, },
376 [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NL_A_U32,
377 .optional = true, },
378 [TCA_FLOWER_KEY_ENC_IPV6_SRC] = { .type = NL_A_UNSPEC,
379 .min_len = sizeof(struct in6_addr),
380 .optional = true, },
381 [TCA_FLOWER_KEY_ENC_IPV6_DST] = { .type = NL_A_UNSPEC,
382 .min_len = sizeof(struct in6_addr),
383 .optional = true, },
384 [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .type = NL_A_UNSPEC,
385 .min_len = sizeof(struct in6_addr),
386 .optional = true, },
387 [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .type = NL_A_UNSPEC,
388 .min_len = sizeof(struct in6_addr),
389 .optional = true, },
390 [TCA_FLOWER_KEY_ENC_UDP_DST_PORT] = { .type = NL_A_U16,
391 .optional = true, },
83e86606
RD
392 [TCA_FLOWER_KEY_FLAGS] = { .type = NL_A_BE32, .optional = true, },
393 [TCA_FLOWER_KEY_FLAGS_MASK] = { .type = NL_A_BE32, .optional = true, },
0b4b5203
PB
394 [TCA_FLOWER_KEY_IP_TTL] = { .type = NL_A_U8,
395 .optional = true, },
396 [TCA_FLOWER_KEY_IP_TTL_MASK] = { .type = NL_A_U8,
397 .optional = true, },
dfa2ccdb
OG
398 [TCA_FLOWER_KEY_IP_TOS] = { .type = NL_A_U8,
399 .optional = true, },
400 [TCA_FLOWER_KEY_IP_TOS_MASK] = { .type = NL_A_U8,
401 .optional = true, },
cd081043
PB
402 [TCA_FLOWER_KEY_TCP_FLAGS] = { .type = NL_A_U16,
403 .optional = true, },
404 [TCA_FLOWER_KEY_TCP_FLAGS_MASK] = { .type = NL_A_U16,
405 .optional = true, },
f9885dc5
JL
406 [TCA_FLOWER_KEY_CVLAN_ID] = { .type = NL_A_U16, .optional = true, },
407 [TCA_FLOWER_KEY_CVLAN_PRIO] = { .type = NL_A_U8, .optional = true, },
408 [TCA_FLOWER_KEY_CVLAN_ETH_TYPE] = { .type = NL_A_U16, .optional = true, },
dd83253e
OG
409 [TCA_FLOWER_KEY_ENC_IP_TOS] = { .type = NL_A_U8,
410 .optional = true, },
411 [TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NL_A_U8,
412 .optional = true, },
413 [TCA_FLOWER_KEY_ENC_IP_TTL] = { .type = NL_A_U8,
414 .optional = true, },
415 [TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NL_A_U8,
416 .optional = true, },
a468645c
PJV
417 [TCA_FLOWER_KEY_ENC_OPTS] = { .type = NL_A_NESTED, .optional = true, },
418 [TCA_FLOWER_KEY_ENC_OPTS_MASK] = { .type = NL_A_NESTED,
419 .optional = true, },
576126a9
PB
420 [TCA_FLOWER_KEY_CT_STATE] = { .type = NL_A_U16, .optional = true, },
421 [TCA_FLOWER_KEY_CT_STATE_MASK] = { .type = NL_A_U16, .optional = true, },
422 [TCA_FLOWER_KEY_CT_ZONE] = { .type = NL_A_U16, .optional = true, },
423 [TCA_FLOWER_KEY_CT_ZONE_MASK] = { .type = NL_A_U16, .optional = true, },
9221c721
PB
424 [TCA_FLOWER_KEY_CT_MARK] = { .type = NL_A_U32, .optional = true, },
425 [TCA_FLOWER_KEY_CT_MARK_MASK] = { .type = NL_A_U32, .optional = true, },
426 [TCA_FLOWER_KEY_CT_LABELS] = { .type = NL_A_U128, .optional = true, },
427 [TCA_FLOWER_KEY_CT_LABELS_MASK] = { .type = NL_A_U128,
428 .optional = true, },
75e1e6fd
MD
429 [TCA_FLOWER_KEY_ICMPV4_CODE] = { .type = NL_A_U8,
430 .optional = true, },
431 [TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NL_A_U8,
432 .optional = true, },
433 [TCA_FLOWER_KEY_ICMPV4_TYPE] = { .type = NL_A_U8,
434 .optional = true, },
435 [TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NL_A_U8,
436 .optional = true, },
437 [TCA_FLOWER_KEY_ICMPV6_CODE] = { .type = NL_A_U8,
438 .optional = true, },
439 [TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NL_A_U8,
440 .optional = true, },
441 [TCA_FLOWER_KEY_ICMPV6_TYPE] = { .type = NL_A_U8,
442 .optional = true, },
443 [TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NL_A_U8,
444 .optional = true, },
f98e418f
RD
445};
446
5db012c4
VB
447static const struct nl_policy tca_flower_terse_policy[] = {
448 [TCA_FLOWER_FLAGS] = { .type = NL_A_U32, .optional = false, },
449 [TCA_FLOWER_ACT] = { .type = NL_A_NESTED, .optional = false, },
450};
451
a3db6e47
TZ
452static void
453nl_parse_flower_arp(struct nlattr **attrs, struct tc_flower *flower)
454{
455 const struct eth_addr *eth;
456
457 if (attrs[TCA_FLOWER_KEY_ARP_SIP_MASK]) {
458 flower->key.arp.spa =
459 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ARP_SIP]);
460 flower->mask.arp.spa =
461 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ARP_SIP_MASK]);
462 }
463 if (attrs[TCA_FLOWER_KEY_ARP_TIP_MASK]) {
464 flower->key.arp.tpa =
465 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ARP_TIP]);
466 flower->mask.arp.tpa =
467 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ARP_TIP_MASK]);
468 }
469 if (attrs[TCA_FLOWER_KEY_ARP_SHA_MASK]) {
470 eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ARP_SHA], ETH_ALEN);
471 memcpy(&flower->key.arp.sha, eth, sizeof flower->key.arp.sha);
472
473 eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ARP_SHA_MASK], ETH_ALEN);
474 memcpy(&flower->mask.arp.sha, eth, sizeof flower->mask.arp.sha);
475 }
476 if (attrs[TCA_FLOWER_KEY_ARP_THA_MASK]) {
477 eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ARP_THA], ETH_ALEN);
478 memcpy(&flower->key.arp.tha, eth, sizeof flower->key.arp.tha);
479
480 eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ARP_THA_MASK], ETH_ALEN);
481 memcpy(&flower->mask.arp.tha, eth, sizeof flower->mask.arp.tha);
482 }
483 if (attrs[TCA_FLOWER_KEY_ARP_OP_MASK]) {
484 flower->key.arp.opcode =
485 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ARP_OP]);
486 flower->mask.arp.opcode =
487 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ARP_OP_MASK]);
488 }
489}
490
f98e418f
RD
491static void
492nl_parse_flower_eth(struct nlattr **attrs, struct tc_flower *flower)
493{
494 const struct eth_addr *eth;
495
496 if (attrs[TCA_FLOWER_KEY_ETH_SRC_MASK]) {
497 eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ETH_SRC], ETH_ALEN);
498 memcpy(&flower->key.src_mac, eth, sizeof flower->key.src_mac);
499
500 eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ETH_SRC_MASK], ETH_ALEN);
501 memcpy(&flower->mask.src_mac, eth, sizeof flower->mask.src_mac);
502 }
503 if (attrs[TCA_FLOWER_KEY_ETH_DST_MASK]) {
504 eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ETH_DST], ETH_ALEN);
505 memcpy(&flower->key.dst_mac, eth, sizeof flower->key.dst_mac);
506
507 eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ETH_DST_MASK], ETH_ALEN);
508 memcpy(&flower->mask.dst_mac, eth, sizeof flower->mask.dst_mac);
509 }
510}
511
34b16955
PJV
512static void
513nl_parse_flower_mpls(struct nlattr **attrs, struct tc_flower *flower)
514{
515 uint8_t ttl, tc, bos;
516 uint32_t label;
517
518 if (!eth_type_mpls(flower->key.eth_type)) {
519 return;
520 }
521
522 flower->key.encap_eth_type[0] =
523 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ETH_TYPE]);
524 flower->key.mpls_lse = 0;
525 flower->mask.mpls_lse = 0;
526
527 if (attrs[TCA_FLOWER_KEY_MPLS_TTL]) {
528 ttl = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_MPLS_TTL]);
529 set_mpls_lse_ttl(&flower->key.mpls_lse, ttl);
530 set_mpls_lse_ttl(&flower->mask.mpls_lse, 0xff);
531 }
532
533 if (attrs[TCA_FLOWER_KEY_MPLS_BOS]) {
534 bos = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_MPLS_BOS]);
535 set_mpls_lse_bos(&flower->key.mpls_lse, bos);
0f252daa 536 set_mpls_lse_bos(&flower->mask.mpls_lse, 0xff);
34b16955
PJV
537 }
538
539 if (attrs[TCA_FLOWER_KEY_MPLS_TC]) {
540 tc = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_MPLS_TC]);
541 set_mpls_lse_tc(&flower->key.mpls_lse, tc);
542 set_mpls_lse_tc(&flower->mask.mpls_lse, 0xff);
543 }
544
545 if (attrs[TCA_FLOWER_KEY_MPLS_LABEL]) {
546 label = nl_attr_get_u32(attrs[TCA_FLOWER_KEY_MPLS_LABEL]);
547 set_mpls_lse_label(&flower->key.mpls_lse, htonl(label));
548 set_mpls_lse_label(&flower->mask.mpls_lse, OVS_BE32_MAX);
549 }
550}
551
f98e418f
RD
552static void
553nl_parse_flower_vlan(struct nlattr **attrs, struct tc_flower *flower)
554{
f9885dc5
JL
555 ovs_be16 encap_ethtype;
556
b5ad40a9 557 if (!eth_type_vlan(flower->key.eth_type)) {
f98e418f
RD
558 return;
559 }
560
f9885dc5 561 flower->key.encap_eth_type[0] =
f98e418f
RD
562 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ETH_TYPE]);
563
564 if (attrs[TCA_FLOWER_KEY_VLAN_ID]) {
f9885dc5 565 flower->key.vlan_id[0] =
f98e418f 566 nl_attr_get_u16(attrs[TCA_FLOWER_KEY_VLAN_ID]);
7f02f26c 567 flower->mask.vlan_id[0] = 0xffff;
f98e418f
RD
568 }
569 if (attrs[TCA_FLOWER_KEY_VLAN_PRIO]) {
f9885dc5 570 flower->key.vlan_prio[0] =
f98e418f 571 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_VLAN_PRIO]);
7f02f26c 572 flower->mask.vlan_prio[0] = 0xff;
f98e418f 573 }
f9885dc5
JL
574
575 if (!attrs[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
576 return;
577 }
578
579 encap_ethtype = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_VLAN_ETH_TYPE]);
580 if (!eth_type_vlan(encap_ethtype)) {
581 return;
582 }
583
584 flower->key.encap_eth_type[1] = flower->key.encap_eth_type[0];
585 flower->key.encap_eth_type[0] = encap_ethtype;
586
587 if (attrs[TCA_FLOWER_KEY_CVLAN_ID]) {
588 flower->key.vlan_id[1] =
589 nl_attr_get_u16(attrs[TCA_FLOWER_KEY_CVLAN_ID]);
7f02f26c 590 flower->mask.vlan_id[1] = 0xffff;
f9885dc5
JL
591 }
592 if (attrs[TCA_FLOWER_KEY_CVLAN_PRIO]) {
593 flower->key.vlan_prio[1] =
594 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_CVLAN_PRIO]);
7f02f26c 595 flower->mask.vlan_prio[1] = 0xff;
f9885dc5 596 }
f98e418f
RD
597}
598
a468645c
PJV
599static int
600nl_parse_geneve_key(const struct nlattr *in_nlattr,
601 struct tun_metadata *metadata)
602{
603 struct geneve_opt *opt = NULL;
604 const struct ofpbuf *msg;
605 uint16_t last_opt_type;
606 struct nlattr *nla;
607 struct ofpbuf buf;
608 size_t left;
609 int cnt;
610
611 nl_attr_get_nested(in_nlattr, &buf);
612 msg = &buf;
613
614 last_opt_type = TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC;
615 cnt = 0;
616 NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) {
617 uint16_t type = nl_attr_type(nla);
618
619 switch (type) {
620 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS:
621 if (cnt && last_opt_type != TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA) {
622 VLOG_ERR_RL(&error_rl, "failed to parse tun options class");
623 return EINVAL;
624 }
625
626 opt = &metadata->opts.gnv[cnt];
627 opt->opt_class = nl_attr_get_be16(nla);
628 cnt += sizeof(struct geneve_opt) / 4;
629 metadata->present.len += sizeof(struct geneve_opt);
630 last_opt_type = TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS;
631 break;
632 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE:
633 if (last_opt_type != TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS) {
634 VLOG_ERR_RL(&error_rl, "failed to parse tun options type");
635 return EINVAL;
636 }
637
638 opt->type = nl_attr_get_u8(nla);
639 last_opt_type = TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE;
640 break;
641 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA:
642 if (last_opt_type != TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE) {
643 VLOG_ERR_RL(&error_rl, "failed to parse tun options data");
644 return EINVAL;
645 }
646
647 opt->length = nl_attr_get_size(nla) / 4;
648 memcpy(opt + 1, nl_attr_get_unspec(nla, 1), opt->length * 4);
649 cnt += opt->length;
650 metadata->present.len += opt->length * 4;
651 last_opt_type = TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA;
652 break;
653 }
654 }
655
656 if (last_opt_type != TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA) {
657 VLOG_ERR_RL(&error_rl, "failed to parse tun options without data");
658 return EINVAL;
659 }
660
661 return 0;
662}
663
664static int
665nl_parse_flower_tunnel_opts(struct nlattr *options,
666 struct tun_metadata *metadata)
667{
668 const struct ofpbuf *msg;
669 struct nlattr *nla;
670 struct ofpbuf buf;
671 size_t left;
672 int err;
673
674 nl_attr_get_nested(options, &buf);
675 msg = &buf;
676
677 NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) {
678 uint16_t type = nl_attr_type(nla);
679 switch (type) {
680 case TCA_FLOWER_KEY_ENC_OPTS_GENEVE:
681 err = nl_parse_geneve_key(nla, metadata);
682 if (err) {
683 return err;
684 }
685
686 break;
687 }
688 }
689
690 return 0;
691}
692
693static int
694flower_tun_geneve_opt_check_len(struct tun_metadata *key,
695 struct tun_metadata *mask)
696{
697 const struct geneve_opt *opt, *opt_mask;
698 int len, cnt = 0;
699
700 len = key->present.len;
701 while (len) {
702 opt = &key->opts.gnv[cnt];
703 opt_mask = &mask->opts.gnv[cnt];
704
705 if (opt->length != opt_mask->length) {
706 VLOG_ERR_RL(&error_rl,
707 "failed to parse tun options; key/mask length differ");
708 return EINVAL;
709 }
710
711 cnt += sizeof(struct geneve_opt) / 4 + opt->length;
712 len -= sizeof(struct geneve_opt) + opt->length * 4;
713 }
714
715 return 0;
716}
717
718static int
f98e418f
RD
719nl_parse_flower_tunnel(struct nlattr **attrs, struct tc_flower *flower)
720{
a468645c
PJV
721 int err;
722
f98e418f
RD
723 if (attrs[TCA_FLOWER_KEY_ENC_KEY_ID]) {
724 ovs_be32 id = nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_KEY_ID]);
725
105e8179 726 flower->key.tunnel.id = be32_to_be64(id);
0227bf09 727 flower->mask.tunnel.id = OVS_BE64_MAX;
f98e418f
RD
728 }
729 if (attrs[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK]) {
5f568d04
TZ
730 flower->mask.tunnel.ipv4.ipv4_src =
731 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK]);
105e8179 732 flower->key.tunnel.ipv4.ipv4_src =
f98e418f
RD
733 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_SRC]);
734 }
735 if (attrs[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK]) {
5f568d04
TZ
736 flower->mask.tunnel.ipv4.ipv4_dst =
737 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK]);
105e8179 738 flower->key.tunnel.ipv4.ipv4_dst =
f98e418f
RD
739 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_DST]);
740 }
741 if (attrs[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]) {
5f568d04
TZ
742 flower->mask.tunnel.ipv6.ipv6_src =
743 nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]);
105e8179 744 flower->key.tunnel.ipv6.ipv6_src =
f98e418f
RD
745 nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_SRC]);
746 }
747 if (attrs[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]) {
5f568d04
TZ
748 flower->mask.tunnel.ipv6.ipv6_dst =
749 nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]);
105e8179 750 flower->key.tunnel.ipv6.ipv6_dst =
f98e418f
RD
751 nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_DST]);
752 }
1fe42975 753 if (attrs[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]) {
105e8179 754 flower->key.tunnel.tp_dst =
f98e418f
RD
755 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]);
756 }
49a7961f 757 if (attrs[TCA_FLOWER_KEY_ENC_IP_TOS_MASK]) {
105e8179 758 flower->key.tunnel.tos =
dd83253e 759 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ENC_IP_TOS]);
49a7961f
OG
760 flower->mask.tunnel.tos =
761 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ENC_IP_TOS_MASK]);
dd83253e 762 }
49a7961f 763 if (attrs[TCA_FLOWER_KEY_ENC_IP_TTL_MASK]) {
105e8179 764 flower->key.tunnel.ttl =
dd83253e 765 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ENC_IP_TTL]);
49a7961f
OG
766 flower->mask.tunnel.ttl =
767 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ENC_IP_TTL_MASK]);
dd83253e 768 }
7c53bd78
PB
769
770 if (!is_all_zeros(&flower->mask.tunnel, sizeof flower->mask.tunnel) ||
771 !is_all_zeros(&flower->key.tunnel, sizeof flower->key.tunnel)) {
772 flower->tunnel = true;
773 }
774
a468645c
PJV
775 if (attrs[TCA_FLOWER_KEY_ENC_OPTS] &&
776 attrs[TCA_FLOWER_KEY_ENC_OPTS_MASK]) {
777 err = nl_parse_flower_tunnel_opts(attrs[TCA_FLOWER_KEY_ENC_OPTS],
778 &flower->key.tunnel.metadata);
779 if (err) {
780 return err;
781 }
782
783 err = nl_parse_flower_tunnel_opts(attrs[TCA_FLOWER_KEY_ENC_OPTS_MASK],
784 &flower->mask.tunnel.metadata);
785 if (err) {
786 return err;
787 }
788
789 err = flower_tun_geneve_opt_check_len(&flower->key.tunnel.metadata,
790 &flower->mask.tunnel.metadata);
791 if (err) {
792 return err;
793 }
794 } else if (attrs[TCA_FLOWER_KEY_ENC_OPTS]) {
795 VLOG_ERR_RL(&error_rl,
796 "failed to parse tun options; no mask supplied");
797 return EINVAL;
798 } else if (attrs[TCA_FLOWER_KEY_ENC_OPTS_MASK]) {
799 VLOG_ERR_RL(&error_rl, "failed to parse tun options; no key supplied");
800 return EINVAL;
801 }
802
803 return 0;
f98e418f
RD
804}
805
576126a9
PB
806static void
807nl_parse_flower_ct_match(struct nlattr **attrs, struct tc_flower *flower) {
808 struct tc_flower_key *key = &flower->key;
809 struct tc_flower_key *mask = &flower->mask;
810 struct nlattr *attr_key, *attr_mask;
811
812 attr_key = attrs[TCA_FLOWER_KEY_CT_STATE];
813 attr_mask = attrs[TCA_FLOWER_KEY_CT_STATE_MASK];
814 if (attr_mask) {
815 key->ct_state = nl_attr_get_u16(attr_key);
816 mask->ct_state = nl_attr_get_u16(attr_mask);
817 }
818
819 attr_key = attrs[TCA_FLOWER_KEY_CT_ZONE];
820 attr_mask = attrs[TCA_FLOWER_KEY_CT_ZONE_MASK];
821 if (attrs[TCA_FLOWER_KEY_CT_ZONE_MASK]) {
822 key->ct_zone = nl_attr_get_u16(attr_key);
823 mask->ct_zone = nl_attr_get_u16(attr_mask);
824 }
9221c721
PB
825
826 attr_key = attrs[TCA_FLOWER_KEY_CT_MARK];
827 attr_mask = attrs[TCA_FLOWER_KEY_CT_MARK_MASK];
828 if (attrs[TCA_FLOWER_KEY_CT_MARK_MASK]) {
829 key->ct_mark = nl_attr_get_u32(attr_key);
830 mask->ct_mark = nl_attr_get_u32(attr_mask);
831 }
832
833 attr_key = attrs[TCA_FLOWER_KEY_CT_LABELS];
834 attr_mask = attrs[TCA_FLOWER_KEY_CT_LABELS_MASK];
835 if (attrs[TCA_FLOWER_KEY_CT_LABELS_MASK]) {
836 key->ct_label = nl_attr_get_u128(attr_key);
837 mask->ct_label = nl_attr_get_u128(attr_mask);
838 }
576126a9
PB
839}
840
f98e418f
RD
841static void
842nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {
843 uint8_t ip_proto = 0;
844 struct tc_flower_key *key = &flower->key;
845 struct tc_flower_key *mask = &flower->mask;
846
847 if (attrs[TCA_FLOWER_KEY_IP_PROTO]) {
848 ip_proto = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_PROTO]);
849 key->ip_proto = ip_proto;
850 mask->ip_proto = UINT8_MAX;
851 }
852
83e86606 853 if (attrs[TCA_FLOWER_KEY_FLAGS_MASK]) {
7e0f69b5
IS
854 key->flags = ntohl(nl_attr_get_be32(attrs[TCA_FLOWER_KEY_FLAGS]));
855 mask->flags =
856 ntohl(nl_attr_get_be32(attrs[TCA_FLOWER_KEY_FLAGS_MASK]));
83e86606
RD
857 }
858
f98e418f
RD
859 if (attrs[TCA_FLOWER_KEY_IPV4_SRC_MASK]) {
860 key->ipv4.ipv4_src =
861 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_IPV4_SRC]);
862 mask->ipv4.ipv4_src =
863 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_IPV4_SRC_MASK]);
864 }
865 if (attrs[TCA_FLOWER_KEY_IPV4_DST_MASK]) {
866 key->ipv4.ipv4_dst =
867 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_IPV4_DST]);
868 mask->ipv4.ipv4_dst =
869 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_IPV4_DST_MASK]);
870 }
871 if (attrs[TCA_FLOWER_KEY_IPV6_SRC_MASK]) {
872 struct nlattr *attr = attrs[TCA_FLOWER_KEY_IPV6_SRC];
873 struct nlattr *attr_mask = attrs[TCA_FLOWER_KEY_IPV6_SRC_MASK];
874
875 key->ipv6.ipv6_src = nl_attr_get_in6_addr(attr);
876 mask->ipv6.ipv6_src = nl_attr_get_in6_addr(attr_mask);
877 }
878 if (attrs[TCA_FLOWER_KEY_IPV6_DST_MASK]) {
879 struct nlattr *attr = attrs[TCA_FLOWER_KEY_IPV6_DST];
880 struct nlattr *attr_mask = attrs[TCA_FLOWER_KEY_IPV6_DST_MASK];
881
882 key->ipv6.ipv6_dst = nl_attr_get_in6_addr(attr);
883 mask->ipv6.ipv6_dst = nl_attr_get_in6_addr(attr_mask);
884 }
885
886 if (ip_proto == IPPROTO_TCP) {
887 if (attrs[TCA_FLOWER_KEY_TCP_SRC_MASK]) {
2b1d9fa9 888 key->tcp_src =
f98e418f 889 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_SRC]);
2b1d9fa9 890 mask->tcp_src =
f98e418f
RD
891 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_SRC_MASK]);
892 }
893 if (attrs[TCA_FLOWER_KEY_TCP_DST_MASK]) {
2b1d9fa9 894 key->tcp_dst =
f98e418f 895 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_DST]);
2b1d9fa9 896 mask->tcp_dst =
f98e418f
RD
897 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_DST_MASK]);
898 }
cd081043
PB
899 if (attrs[TCA_FLOWER_KEY_TCP_FLAGS_MASK]) {
900 key->tcp_flags =
901 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_FLAGS]);
902 mask->tcp_flags =
903 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_FLAGS_MASK]);
904 }
f98e418f
RD
905 } else if (ip_proto == IPPROTO_UDP) {
906 if (attrs[TCA_FLOWER_KEY_UDP_SRC_MASK]) {
2b1d9fa9
PB
907 key->udp_src = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_UDP_SRC]);
908 mask->udp_src =
f98e418f
RD
909 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_UDP_SRC_MASK]);
910 }
911 if (attrs[TCA_FLOWER_KEY_UDP_DST_MASK]) {
2b1d9fa9
PB
912 key->udp_dst = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_UDP_DST]);
913 mask->udp_dst =
f98e418f
RD
914 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_UDP_DST_MASK]);
915 }
4862b4e5
VB
916 } else if (ip_proto == IPPROTO_SCTP) {
917 if (attrs[TCA_FLOWER_KEY_SCTP_SRC_MASK]) {
2b1d9fa9
PB
918 key->sctp_src = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_SCTP_SRC]);
919 mask->sctp_src =
4862b4e5
VB
920 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_SCTP_SRC_MASK]);
921 }
922 if (attrs[TCA_FLOWER_KEY_SCTP_DST_MASK]) {
2b1d9fa9
PB
923 key->sctp_dst = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_SCTP_DST]);
924 mask->sctp_dst =
4862b4e5
VB
925 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_SCTP_DST_MASK]);
926 }
75e1e6fd
MD
927 } else if (ip_proto == IPPROTO_ICMP) {
928 if (attrs[TCA_FLOWER_KEY_ICMPV4_CODE_MASK]) {
929 key->icmp_code =
930 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_CODE]);
931 mask->icmp_code =
932 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_CODE]);
933 }
934 if (attrs[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK]) {
935 key->icmp_type =
936 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK]);
937 mask->icmp_type =
938 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK]);
939 }
940 } else if (ip_proto == IPPROTO_ICMPV6) {
941 if (attrs[TCA_FLOWER_KEY_ICMPV6_CODE_MASK]) {
942 key->icmp_code =
943 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_CODE]);
944 mask->icmp_code =
945 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_CODE]);
946 }
947 if (attrs[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK]) {
948 key->icmp_type =
949 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK]);
950 mask->icmp_type =
951 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK]);
952 }
f98e418f 953 }
0b4b5203
PB
954
955 if (attrs[TCA_FLOWER_KEY_IP_TTL_MASK]) {
956 key->ip_ttl = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TTL]);
957 mask->ip_ttl = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TTL_MASK]);
958 }
dfa2ccdb
OG
959
960 if (attrs[TCA_FLOWER_KEY_IP_TOS_MASK]) {
961 key->ip_tos = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TOS]);
962 mask->ip_tos = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TOS_MASK]);
963 }
576126a9
PB
964
965 nl_parse_flower_ct_match(attrs, flower);
f98e418f
RD
966}
967
d63ca532
GT
968static enum tc_offloaded_state
969nl_get_flower_offloaded_state(struct nlattr **attrs)
970{
971 uint32_t flower_flags = 0;
972
973 if (attrs[TCA_FLOWER_FLAGS]) {
974 flower_flags = nl_attr_get_u32(attrs[TCA_FLOWER_FLAGS]);
975 if (flower_flags & TCA_CLS_FLAGS_NOT_IN_HW) {
976 return TC_OFFLOADED_STATE_NOT_IN_HW;
977 } else if (flower_flags & TCA_CLS_FLAGS_IN_HW) {
978 return TC_OFFLOADED_STATE_IN_HW;
979 }
980 }
981 return TC_OFFLOADED_STATE_UNDEFINED;
982}
983
984static void
985nl_parse_flower_flags(struct nlattr **attrs, struct tc_flower *flower)
986{
987 flower->offloaded_state = nl_get_flower_offloaded_state(attrs);
988}
989
8ada482b
PB
990static const struct nl_policy pedit_policy[] = {
991 [TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC,
992 .min_len = sizeof(struct tc_pedit),
993 .optional = false, },
994 [TCA_PEDIT_KEYS_EX] = { .type = NL_A_NESTED,
995 .optional = false, },
996};
997
998static int
999nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower)
1000{
0c70132c 1001 struct tc_action *action;
8ada482b
PB
1002 struct nlattr *pe_attrs[ARRAY_SIZE(pedit_policy)];
1003 const struct tc_pedit *pe;
1004 const struct tc_pedit_key *keys;
1005 const struct nlattr *nla, *keys_ex, *ex_type;
1006 const void *keys_attr;
1007 char *rewrite_key = (void *) &flower->rewrite.key;
1008 char *rewrite_mask = (void *) &flower->rewrite.mask;
1009 size_t keys_ex_size, left;
d6118e62 1010 int type, i = 0, err;
8ada482b
PB
1011
1012 if (!nl_parse_nested(options, pedit_policy, pe_attrs,
1013 ARRAY_SIZE(pedit_policy))) {
1014 VLOG_ERR_RL(&error_rl, "failed to parse pedit action options");
1015 return EPROTO;
1016 }
1017
1018 pe = nl_attr_get_unspec(pe_attrs[TCA_PEDIT_PARMS_EX], sizeof *pe);
1019 keys = pe->keys;
1020 keys_attr = pe_attrs[TCA_PEDIT_KEYS_EX];
1021 keys_ex = nl_attr_get(keys_attr);
1022 keys_ex_size = nl_attr_get_size(keys_attr);
1023
1024 NL_ATTR_FOR_EACH (nla, left, keys_ex, keys_ex_size) {
1025 if (i >= pe->nkeys) {
1026 break;
1027 }
1028
408671c4 1029 if (nl_attr_type(nla) != TCA_PEDIT_KEY_EX) {
8ada482b
PB
1030 VLOG_ERR_RL(&error_rl, "unable to parse legacy pedit type: %d",
1031 nl_attr_type(nla));
1032 return EOPNOTSUPP;
1033 }
1034
1035 ex_type = nl_attr_find_nested(nla, TCA_PEDIT_KEY_EX_HTYPE);
1036 type = nl_attr_get_u16(ex_type);
1037
d6118e62
PB
1038 err = csum_update_flag(flower, type);
1039 if (err) {
1040 return err;
1041 }
1042
8ada482b
PB
1043 for (int j = 0; j < ARRAY_SIZE(flower_pedit_map); j++) {
1044 struct flower_key_to_pedit *m = &flower_pedit_map[j];
1045 int flower_off = m->flower_offset;
1046 int sz = m->size;
1047 int mf = m->offset;
71d0c0d8 1048 int ef = ROUND_UP(mf, 4);
8ada482b
PB
1049
1050 if (m->htype != type) {
1051 continue;
1052 }
1053
1054 /* check overlap between current pedit key, which is always
1055 * 4 bytes (range [off, off + 3]), and a map entry in
71d0c0d8 1056 * flower_pedit_map sf = ROUND_DOWN(mf, 4)
1057 * (range [sf|mf, (mf + sz - 1)|ef]) */
8ada482b 1058 if ((keys->off >= mf && keys->off < mf + sz)
71d0c0d8 1059 || (keys->off + 3 >= mf && keys->off + 3 < ef)) {
8ada482b 1060 int diff = flower_off + (keys->off - mf);
f8b63e59
PJV
1061 ovs_be32 *dst = (void *) (rewrite_key + diff);
1062 ovs_be32 *dst_m = (void *) (rewrite_mask + diff);
dbcb014d 1063 ovs_be32 mask, mask_word, data_word;
8ada482b
PB
1064 uint32_t zero_bits;
1065
dbcb014d
PJV
1066 mask_word = htonl(ntohl(keys->mask) << m->boundary_shift);
1067 data_word = htonl(ntohl(keys->val) << m->boundary_shift);
1068 mask = ~(mask_word);
1069
8ada482b
PB
1070 if (keys->off < mf) {
1071 zero_bits = 8 * (mf - keys->off);
f8b63e59 1072 mask &= htonl(UINT32_MAX >> zero_bits);
8ada482b
PB
1073 } else if (keys->off + 4 > mf + m->size) {
1074 zero_bits = 8 * (keys->off + 4 - mf - m->size);
f8b63e59 1075 mask &= htonl(UINT32_MAX << zero_bits);
8ada482b
PB
1076 }
1077
1078 *dst_m |= mask;
dbcb014d 1079 *dst |= data_word & mask;
8ada482b
PB
1080 }
1081 }
1082
1083 keys++;
1084 i++;
1085 }
1086
0c70132c
CM
1087 action = &flower->actions[flower->action_count++];
1088 action->type = TC_ACT_PEDIT;
8ada482b
PB
1089
1090 return 0;
1091}
1092
f98e418f
RD
1093static const struct nl_policy tunnel_key_policy[] = {
1094 [TCA_TUNNEL_KEY_PARMS] = { .type = NL_A_UNSPEC,
1095 .min_len = sizeof(struct tc_tunnel_key),
1096 .optional = false, },
1097 [TCA_TUNNEL_KEY_ENC_IPV4_SRC] = { .type = NL_A_U32, .optional = true, },
1098 [TCA_TUNNEL_KEY_ENC_IPV4_DST] = { .type = NL_A_U32, .optional = true, },
1099 [TCA_TUNNEL_KEY_ENC_IPV6_SRC] = { .type = NL_A_UNSPEC,
1100 .min_len = sizeof(struct in6_addr),
1101 .optional = true, },
1102 [TCA_TUNNEL_KEY_ENC_IPV6_DST] = { .type = NL_A_UNSPEC,
1103 .min_len = sizeof(struct in6_addr),
1104 .optional = true, },
1105 [TCA_TUNNEL_KEY_ENC_KEY_ID] = { .type = NL_A_U32, .optional = true, },
1106 [TCA_TUNNEL_KEY_ENC_DST_PORT] = { .type = NL_A_U16, .optional = true, },
4b12e454
OG
1107 [TCA_TUNNEL_KEY_ENC_TOS] = { .type = NL_A_U8, .optional = true, },
1108 [TCA_TUNNEL_KEY_ENC_TTL] = { .type = NL_A_U8, .optional = true, },
202469aa 1109 [TCA_TUNNEL_KEY_ENC_OPTS] = { .type = NL_A_NESTED, .optional = true, },
d9677a1f 1110 [TCA_TUNNEL_KEY_NO_CSUM] = { .type = NL_A_U8, .optional = true, },
f98e418f
RD
1111};
1112
202469aa
PJV
1113static int
1114nl_parse_act_geneve_opts(const struct nlattr *in_nlattr,
1115 struct tc_action *action)
1116{
1117 struct geneve_opt *opt = NULL;
1118 const struct ofpbuf *msg;
1119 uint16_t last_opt_type;
1120 struct nlattr *nla;
1121 struct ofpbuf buf;
1122 size_t left;
1123 int cnt;
1124
1125 nl_attr_get_nested(in_nlattr, &buf);
1126 msg = &buf;
1127
1128 last_opt_type = TCA_TUNNEL_KEY_ENC_OPT_GENEVE_UNSPEC;
1129 cnt = 0;
1130 NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) {
1131 uint16_t type = nl_attr_type(nla);
1132
1133 switch (type) {
1134 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS:
1135 if (cnt && last_opt_type != TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA) {
1136 VLOG_ERR_RL(&error_rl,
1137 "failed to parse action geneve options class");
1138 return EINVAL;
1139 }
1140
1141 opt = &action->encap.data.opts.gnv[cnt];
1142 opt->opt_class = nl_attr_get_be16(nla);
1143 cnt += sizeof(struct geneve_opt) / 4;
1144 action->encap.data.present.len += sizeof(struct geneve_opt);
1145 last_opt_type = TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS;
1146 break;
1147 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE:
1148 if (last_opt_type != TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS) {
1149 VLOG_ERR_RL(&error_rl,
1150 "failed to parse action geneve options type");
1151 return EINVAL;
1152 }
1153
1154 opt->type = nl_attr_get_u8(nla);
1155 last_opt_type = TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE;
1156 break;
1157 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA:
1158 if (last_opt_type != TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE) {
1159 VLOG_ERR_RL(&error_rl,
1160 "failed to parse action geneve options data");
1161 return EINVAL;
1162 }
1163
1164 opt->length = nl_attr_get_size(nla) / 4;
1165 memcpy(opt + 1, nl_attr_get_unspec(nla, 1), opt->length * 4);
1166 cnt += opt->length;
1167 action->encap.data.present.len += opt->length * 4;
1168 last_opt_type = TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA;
1169 break;
1170 }
1171 }
1172
1173 if (last_opt_type != TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA) {
1174 VLOG_ERR_RL(&error_rl,
1175 "failed to parse action geneve options without data");
1176 return EINVAL;
1177 }
1178
1179 return 0;
1180}
1181
1182static int
1183nl_parse_act_tunnel_opts(struct nlattr *options, struct tc_action *action)
1184{
1185 const struct ofpbuf *msg;
1186 struct nlattr *nla;
1187 struct ofpbuf buf;
1188 size_t left;
1189 int err;
1190
1191 if (!options) {
1192 return 0;
1193 }
1194
1195 nl_attr_get_nested(options, &buf);
1196 msg = &buf;
1197
1198 NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) {
1199 uint16_t type = nl_attr_type(nla);
1200 switch (type) {
1201 case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE:
1202 err = nl_parse_act_geneve_opts(nla, action);
1203 if (err) {
1204 return err;
1205 }
1206
1207 break;
1208 }
1209 }
1210
1211 return 0;
1212}
1213
f98e418f
RD
1214static int
1215nl_parse_act_tunnel_key(struct nlattr *options, struct tc_flower *flower)
1216{
1217 struct nlattr *tun_attrs[ARRAY_SIZE(tunnel_key_policy)];
1218 const struct nlattr *tun_parms;
1219 const struct tc_tunnel_key *tun;
0c70132c 1220 struct tc_action *action;
202469aa 1221 int err;
f98e418f
RD
1222
1223 if (!nl_parse_nested(options, tunnel_key_policy, tun_attrs,
1224 ARRAY_SIZE(tunnel_key_policy))) {
1225 VLOG_ERR_RL(&error_rl, "failed to parse tunnel_key action options");
1226 return EPROTO;
1227 }
1228
1229 tun_parms = tun_attrs[TCA_TUNNEL_KEY_PARMS];
1230 tun = nl_attr_get_unspec(tun_parms, sizeof *tun);
1231 if (tun->t_action == TCA_TUNNEL_KEY_ACT_SET) {
1232 struct nlattr *id = tun_attrs[TCA_TUNNEL_KEY_ENC_KEY_ID];
1233 struct nlattr *dst_port = tun_attrs[TCA_TUNNEL_KEY_ENC_DST_PORT];
1234 struct nlattr *ipv4_src = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV4_SRC];
1235 struct nlattr *ipv4_dst = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV4_DST];
1236 struct nlattr *ipv6_src = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV6_SRC];
1237 struct nlattr *ipv6_dst = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV6_DST];
4b12e454
OG
1238 struct nlattr *tos = tun_attrs[TCA_TUNNEL_KEY_ENC_TOS];
1239 struct nlattr *ttl = tun_attrs[TCA_TUNNEL_KEY_ENC_TTL];
202469aa 1240 struct nlattr *tun_opt = tun_attrs[TCA_TUNNEL_KEY_ENC_OPTS];
d9677a1f 1241 struct nlattr *no_csum = tun_attrs[TCA_TUNNEL_KEY_NO_CSUM];
f98e418f 1242
0c70132c
CM
1243 action = &flower->actions[flower->action_count++];
1244 action->type = TC_ACT_ENCAP;
1245 action->encap.ipv4.ipv4_src = ipv4_src ? nl_attr_get_be32(ipv4_src) : 0;
1246 action->encap.ipv4.ipv4_dst = ipv4_dst ? nl_attr_get_be32(ipv4_dst) : 0;
f98e418f 1247 if (ipv6_src) {
0c70132c 1248 action->encap.ipv6.ipv6_src = nl_attr_get_in6_addr(ipv6_src);
f98e418f
RD
1249 }
1250 if (ipv6_dst) {
0c70132c 1251 action->encap.ipv6.ipv6_dst = nl_attr_get_in6_addr(ipv6_dst);
f98e418f 1252 }
0c70132c 1253 action->encap.id = id ? be32_to_be64(nl_attr_get_be32(id)) : 0;
0227bf09 1254 action->encap.id_present = id ? true : false;
0c70132c 1255 action->encap.tp_dst = dst_port ? nl_attr_get_be16(dst_port) : 0;
4b12e454
OG
1256 action->encap.tos = tos ? nl_attr_get_u8(tos) : 0;
1257 action->encap.ttl = ttl ? nl_attr_get_u8(ttl) : 0;
d9677a1f 1258 action->encap.no_csum = no_csum ? nl_attr_get_u8(no_csum) : 0;
202469aa
PJV
1259
1260 err = nl_parse_act_tunnel_opts(tun_opt, action);
1261 if (err) {
1262 return err;
1263 }
f98e418f 1264 } else if (tun->t_action == TCA_TUNNEL_KEY_ACT_RELEASE) {
105e8179 1265 flower->tunnel = true;
f98e418f
RD
1266 } else {
1267 VLOG_ERR_RL(&error_rl, "unknown tunnel actions: %d, %d",
1268 tun->action, tun->t_action);
1269 return EINVAL;
1270 }
1271 return 0;
1272}
1273
1274static const struct nl_policy gact_policy[] = {
1275 [TCA_GACT_PARMS] = { .type = NL_A_UNSPEC,
1276 .min_len = sizeof(struct tc_gact),
1277 .optional = false, },
1278 [TCA_GACT_TM] = { .type = NL_A_UNSPEC,
1279 .min_len = sizeof(struct tcf_t),
1280 .optional = false, },
1281};
1282
8c1e74d1
PB
1283static int
1284get_user_hz(void)
1285{
1286 static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
1287 static int user_hz = 100;
1288
1289 if (ovsthread_once_start(&once)) {
1290 user_hz = sysconf(_SC_CLK_TCK);
1291 ovsthread_once_done(&once);
1292 }
1293
1294 return user_hz;
1295}
f98e418f
RD
1296
1297static void
1298nl_parse_tcf(const struct tcf_t *tm, struct tc_flower *flower)
1299{
8c1e74d1 1300 flower->lastused = time_msec() - (tm->lastuse * 1000 / get_user_hz());
f98e418f
RD
1301}
1302
1303static int
b2ae4069 1304nl_parse_act_gact(struct nlattr *options, struct tc_flower *flower)
f98e418f
RD
1305{
1306 struct nlattr *gact_attrs[ARRAY_SIZE(gact_policy)];
1307 const struct tc_gact *p;
1308 struct nlattr *gact_parms;
1309 const struct tcf_t *tm;
b2ae4069 1310 struct tc_action *action;
f98e418f
RD
1311
1312 if (!nl_parse_nested(options, gact_policy, gact_attrs,
1313 ARRAY_SIZE(gact_policy))) {
1314 VLOG_ERR_RL(&error_rl, "failed to parse gact action options");
1315 return EPROTO;
1316 }
1317
1318 gact_parms = gact_attrs[TCA_GACT_PARMS];
1319 p = nl_attr_get_unspec(gact_parms, sizeof *p);
1320
b2ae4069
PB
1321 if (TC_ACT_EXT_CMP(p->action, TC_ACT_GOTO_CHAIN)) {
1322 action = &flower->actions[flower->action_count++];
1323 action->chain = p->action & TC_ACT_EXT_VAL_MASK;
1324 action->type = TC_ACT_GOTO;
1325 } else if (p->action != TC_ACT_SHOT) {
f98e418f
RD
1326 VLOG_ERR_RL(&error_rl, "unknown gact action: %d", p->action);
1327 return EINVAL;
1328 }
1329
1330 tm = nl_attr_get_unspec(gact_attrs[TCA_GACT_TM], sizeof *tm);
1331 nl_parse_tcf(tm, flower);
1332
1333 return 0;
1334}
1335
1336static const struct nl_policy mirred_policy[] = {
1337 [TCA_MIRRED_PARMS] = { .type = NL_A_UNSPEC,
1338 .min_len = sizeof(struct tc_mirred),
1339 .optional = false, },
1340 [TCA_MIRRED_TM] = { .type = NL_A_UNSPEC,
1341 .min_len = sizeof(struct tcf_t),
1342 .optional = false, },
1343};
1344
1345static int
1346nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower)
1347{
1348
1349 struct nlattr *mirred_attrs[ARRAY_SIZE(mirred_policy)];
1350 const struct tc_mirred *m;
1351 const struct nlattr *mirred_parms;
1352 const struct tcf_t *tm;
1353 struct nlattr *mirred_tm;
0c70132c 1354 struct tc_action *action;
f98e418f
RD
1355
1356 if (!nl_parse_nested(options, mirred_policy, mirred_attrs,
1357 ARRAY_SIZE(mirred_policy))) {
1358 VLOG_ERR_RL(&error_rl, "failed to parse mirred action options");
1359 return EPROTO;
1360 }
1361
1362 mirred_parms = mirred_attrs[TCA_MIRRED_PARMS];
1363 m = nl_attr_get_unspec(mirred_parms, sizeof *m);
1364
4aa2dc04
JH
1365 if (m->eaction != TCA_EGRESS_REDIR && m->eaction != TCA_EGRESS_MIRROR &&
1366 m->eaction != TCA_INGRESS_REDIR && m->eaction != TCA_INGRESS_MIRROR) {
f98e418f 1367 VLOG_ERR_RL(&error_rl, "unknown mirred action: %d, %d, %d",
0c70132c 1368 m->action, m->eaction, m->ifindex);
f98e418f
RD
1369 return EINVAL;
1370 }
1371
0c70132c 1372 action = &flower->actions[flower->action_count++];
4aa2dc04
JH
1373 action->out.ifindex_out = m->ifindex;
1374 if (m->eaction == TCA_INGRESS_REDIR || m->eaction == TCA_INGRESS_MIRROR) {
1375 action->out.ingress = true;
1376 } else {
1377 action->out.ingress = false;
1378 }
0c70132c 1379 action->type = TC_ACT_OUTPUT;
f98e418f
RD
1380
1381 mirred_tm = mirred_attrs[TCA_MIRRED_TM];
1382 tm = nl_attr_get_unspec(mirred_tm, sizeof *tm);
1383 nl_parse_tcf(tm, flower);
1384
1385 return 0;
1386}
1387
576126a9
PB
1388static const struct nl_policy ct_policy[] = {
1389 [TCA_CT_PARMS] = { .type = NL_A_UNSPEC,
1390 .min_len = sizeof(struct tc_ct),
1391 .optional = false, },
1392 [TCA_CT_ACTION] = { .type = NL_A_U16,
1393 .optional = true, },
1394 [TCA_CT_ZONE] = { .type = NL_A_U16,
1395 .optional = true, },
9221c721
PB
1396 [TCA_CT_MARK] = { .type = NL_A_U32,
1397 .optional = true, },
1398 [TCA_CT_MARK_MASK] = { .type = NL_A_U32,
1399 .optional = true, },
1400 [TCA_CT_LABELS] = { .type = NL_A_UNSPEC,
1401 .optional = true, },
1402 [TCA_CT_LABELS_MASK] = { .type = NL_A_UNSPEC,
1403 .optional = true, },
2bf6ffb7
PB
1404 [TCA_CT_NAT_IPV4_MIN] = { .type = NL_A_U32,
1405 .optional = true, },
1406 [TCA_CT_NAT_IPV4_MAX] = { .type = NL_A_U32,
1407 .optional = true, },
1408 [TCA_CT_NAT_IPV6_MIN] = { .min_len = sizeof(struct in6_addr),
1409 .type = NL_A_UNSPEC,
1410 .optional = true },
1411 [TCA_CT_NAT_IPV6_MAX] = { .min_len = sizeof(struct in6_addr),
1412 .type = NL_A_UNSPEC,
1413 .optional = true },
1414 [TCA_CT_NAT_PORT_MIN] = { .type = NL_A_U16,
1415 .optional = true, },
1416 [TCA_CT_NAT_PORT_MAX] = { .type = NL_A_U16,
1417 .optional = true, },
576126a9
PB
1418};
1419
1420static int
1421nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower)
1422{
1423 struct nlattr *ct_attrs[ARRAY_SIZE(ct_policy)];
1424 const struct nlattr *ct_parms;
1425 struct tc_action *action;
1426 const struct tc_ct *ct;
1427 uint16_t ct_action = 0;
1428
1429 if (!nl_parse_nested(options, ct_policy, ct_attrs,
1430 ARRAY_SIZE(ct_policy))) {
1431 VLOG_ERR_RL(&error_rl, "failed to parse ct action options");
1432 return EPROTO;
1433 }
1434
1435 ct_parms = ct_attrs[TCA_CT_PARMS];
1436 ct = nl_attr_get_unspec(ct_parms, sizeof *ct);
1437
1438 if (ct_attrs[TCA_CT_ACTION]) {
1439 ct_action = nl_attr_get_u16(ct_attrs[TCA_CT_ACTION]);
1440 }
1441
1442 action = &flower->actions[flower->action_count++];
1443 action->ct.clear = ct_action & TCA_CT_ACT_CLEAR;
1444 if (!action->ct.clear) {
1445 struct nlattr *zone = ct_attrs[TCA_CT_ZONE];
9221c721
PB
1446 struct nlattr *mark = ct_attrs[TCA_CT_MARK];
1447 struct nlattr *mark_mask = ct_attrs[TCA_CT_MARK_MASK];
1448 struct nlattr *label = ct_attrs[TCA_CT_LABELS];
1449 struct nlattr *label_mask = ct_attrs[TCA_CT_LABELS_MASK];
576126a9
PB
1450
1451 action->ct.commit = ct_action & TCA_CT_ACT_COMMIT;
1452 action->ct.force = ct_action & TCA_CT_ACT_FORCE;
1453
1454 action->ct.zone = zone ? nl_attr_get_u16(zone) : 0;
9221c721
PB
1455 action->ct.mark = mark ? nl_attr_get_u32(mark) : 0;
1456 action->ct.mark_mask = mark_mask ? nl_attr_get_u32(mark_mask) : 0;
1457 action->ct.label = label? nl_attr_get_u128(label) : OVS_U128_ZERO;
1458 action->ct.label_mask = label_mask ?
1459 nl_attr_get_u128(label_mask) : OVS_U128_ZERO;
576126a9 1460
2bf6ffb7
PB
1461 if (ct_action & TCA_CT_ACT_NAT) {
1462 struct nlattr *ipv4_min = ct_attrs[TCA_CT_NAT_IPV4_MIN];
1463 struct nlattr *ipv4_max = ct_attrs[TCA_CT_NAT_IPV4_MAX];
1464 struct nlattr *ipv6_min = ct_attrs[TCA_CT_NAT_IPV6_MIN];
1465 struct nlattr *ipv6_max = ct_attrs[TCA_CT_NAT_IPV6_MAX];
1466 struct nlattr *port_min = ct_attrs[TCA_CT_NAT_PORT_MIN];
1467 struct nlattr *port_max = ct_attrs[TCA_CT_NAT_PORT_MAX];
1468
1469 action->ct.nat_type = TC_NAT_RESTORE;
1470 if (ct_action & TCA_CT_ACT_NAT_SRC) {
1471 action->ct.nat_type = TC_NAT_SRC;
1472 } else if (ct_action & TCA_CT_ACT_NAT_DST) {
1473 action->ct.nat_type = TC_NAT_DST;
1474 }
1475
1476 if (ipv4_min) {
1477 action->ct.range.ip_family = AF_INET;
1478 action->ct.range.ipv4.min = nl_attr_get_be32(ipv4_min);
1479 if (ipv4_max) {
1480 ovs_be32 addr = nl_attr_get_be32(ipv4_max);
1481
1482 action->ct.range.ipv4.max = addr;
1483 }
1484 } else if (ipv6_min) {
1485 action->ct.range.ip_family = AF_INET6;
1486 action->ct.range.ipv6.min
1487 = nl_attr_get_in6_addr(ipv6_min);
1488 if (ipv6_max) {
1489 struct in6_addr addr = nl_attr_get_in6_addr(ipv6_max);
1490
1491 action->ct.range.ipv6.max = addr;
1492 }
1493 }
1494
1495 if (port_min) {
1496 action->ct.range.port.min = nl_attr_get_be16(port_min);
1497 if (port_max) {
1498 action->ct.range.port.max = nl_attr_get_be16(port_max);
1499 }
1500 }
1501 }
576126a9
PB
1502 }
1503 action->type = TC_ACT_CT;
1504
1505 return 0;
1506}
1507
f98e418f
RD
1508static const struct nl_policy vlan_policy[] = {
1509 [TCA_VLAN_PARMS] = { .type = NL_A_UNSPEC,
1510 .min_len = sizeof(struct tc_vlan),
1511 .optional = false, },
1512 [TCA_VLAN_PUSH_VLAN_ID] = { .type = NL_A_U16, .optional = true, },
1513 [TCA_VLAN_PUSH_VLAN_PROTOCOL] = { .type = NL_A_U16, .optional = true, },
1514 [TCA_VLAN_PUSH_VLAN_PRIORITY] = { .type = NL_A_U8, .optional = true, },
1515};
1516
1517static int
1518nl_parse_act_vlan(struct nlattr *options, struct tc_flower *flower)
1519{
1520 struct nlattr *vlan_attrs[ARRAY_SIZE(vlan_policy)];
1521 const struct tc_vlan *v;
1522 const struct nlattr *vlan_parms;
0c70132c 1523 struct tc_action *action;
f98e418f
RD
1524
1525 if (!nl_parse_nested(options, vlan_policy, vlan_attrs,
1526 ARRAY_SIZE(vlan_policy))) {
1527 VLOG_ERR_RL(&error_rl, "failed to parse vlan action options");
1528 return EPROTO;
1529 }
1530
0c70132c 1531 action = &flower->actions[flower->action_count++];
f98e418f
RD
1532 vlan_parms = vlan_attrs[TCA_VLAN_PARMS];
1533 v = nl_attr_get_unspec(vlan_parms, sizeof *v);
1534 if (v->v_action == TCA_VLAN_ACT_PUSH) {
61e8655c 1535 struct nlattr *vlan_tpid = vlan_attrs[TCA_VLAN_PUSH_VLAN_PROTOCOL];
f98e418f
RD
1536 struct nlattr *vlan_id = vlan_attrs[TCA_VLAN_PUSH_VLAN_ID];
1537 struct nlattr *vlan_prio = vlan_attrs[TCA_VLAN_PUSH_VLAN_PRIORITY];
1538
10097f3f 1539 action->vlan.vlan_push_tpid = nl_attr_get_be16(vlan_tpid);
0c70132c
CM
1540 action->vlan.vlan_push_id = nl_attr_get_u16(vlan_id);
1541 action->vlan.vlan_push_prio = vlan_prio ? nl_attr_get_u8(vlan_prio) : 0;
1542 action->type = TC_ACT_VLAN_PUSH;
f98e418f 1543 } else if (v->v_action == TCA_VLAN_ACT_POP) {
0c70132c 1544 action->type = TC_ACT_VLAN_POP;
f98e418f
RD
1545 } else {
1546 VLOG_ERR_RL(&error_rl, "unknown vlan action: %d, %d",
1547 v->action, v->v_action);
1548 return EINVAL;
1549 }
1550 return 0;
1551}
1552
55412eac
JH
1553static const struct nl_policy mpls_policy[] = {
1554 [TCA_MPLS_PARMS] = { .type = NL_A_UNSPEC,
1555 .min_len = sizeof(struct tc_mpls),
1556 .optional = false, },
1557 [TCA_MPLS_PROTO] = { .type = NL_A_U16, .optional = true, },
283dcf85
JH
1558 [TCA_MPLS_LABEL] = { .type = NL_A_U32, .optional = true, },
1559 [TCA_MPLS_TC] = { .type = NL_A_U8, .optional = true, },
1560 [TCA_MPLS_TTL] = { .type = NL_A_U8, .optional = true, },
1561 [TCA_MPLS_BOS] = { .type = NL_A_U8, .optional = true, },
55412eac
JH
1562};
1563
1564static int
1565nl_parse_act_mpls(struct nlattr *options, struct tc_flower *flower)
1566{
1567 struct nlattr *mpls_attrs[ARRAY_SIZE(mpls_policy)];
1568 const struct nlattr *mpls_parms;
1569 struct nlattr *mpls_proto;
283dcf85 1570 struct nlattr *mpls_label;
55412eac
JH
1571 struct tc_action *action;
1572 const struct tc_mpls *m;
283dcf85
JH
1573 struct nlattr *mpls_ttl;
1574 struct nlattr *mpls_bos;
1575 struct nlattr *mpls_tc;
55412eac
JH
1576
1577 if (!nl_parse_nested(options, mpls_policy, mpls_attrs,
1578 ARRAY_SIZE(mpls_policy))) {
1579 VLOG_ERR_RL(&error_rl, "failed to parse mpls action options");
1580 return EPROTO;
1581 }
1582
1583 action = &flower->actions[flower->action_count++];
1584 mpls_parms = mpls_attrs[TCA_MPLS_PARMS];
1585 m = nl_attr_get_unspec(mpls_parms, sizeof *m);
1586
1587 switch (m->m_action) {
1588 case TCA_MPLS_ACT_POP:
1589 mpls_proto = mpls_attrs[TCA_MPLS_PROTO];
1590 if (mpls_proto) {
1591 action->mpls.proto = nl_attr_get_be16(mpls_proto);
1592 }
1593 action->type = TC_ACT_MPLS_POP;
1594 break;
283dcf85
JH
1595 case TCA_MPLS_ACT_PUSH:
1596 mpls_proto = mpls_attrs[TCA_MPLS_PROTO];
1597 if (mpls_proto) {
1598 action->mpls.proto = nl_attr_get_be16(mpls_proto);
1599 }
1600 mpls_label = mpls_attrs[TCA_MPLS_LABEL];
1601 if (mpls_label) {
1602 action->mpls.label = nl_attr_get_u32(mpls_label);
1603 }
1604 mpls_tc = mpls_attrs[TCA_MPLS_TC];
1605 if (mpls_tc) {
1606 action->mpls.tc = nl_attr_get_u8(mpls_tc);
1607 }
1608 mpls_ttl = mpls_attrs[TCA_MPLS_TTL];
1609 if (mpls_ttl) {
1610 action->mpls.ttl = nl_attr_get_u8(mpls_ttl);
1611 }
1612 mpls_bos = mpls_attrs[TCA_MPLS_BOS];
1613 if (mpls_bos) {
1614 action->mpls.bos = nl_attr_get_u8(mpls_bos);
1615 }
1616 action->type = TC_ACT_MPLS_PUSH;
1617 break;
a8f005cf
JH
1618 case TCA_MPLS_ACT_MODIFY:
1619 mpls_label = mpls_attrs[TCA_MPLS_LABEL];
1620 if (mpls_label) {
1621 action->mpls.label = nl_attr_get_u32(mpls_label);
1622 }
1623 mpls_tc = mpls_attrs[TCA_MPLS_TC];
1624 if (mpls_tc) {
1625 action->mpls.tc = nl_attr_get_u8(mpls_tc);
1626 }
1627 mpls_ttl = mpls_attrs[TCA_MPLS_TTL];
1628 if (mpls_ttl) {
1629 action->mpls.ttl = nl_attr_get_u8(mpls_ttl);
1630 }
1631 mpls_bos = mpls_attrs[TCA_MPLS_BOS];
1632 if (mpls_bos) {
1633 action->mpls.bos = nl_attr_get_u8(mpls_bos);
1634 }
1635 action->type = TC_ACT_MPLS_SET;
1636 break;
55412eac
JH
1637 default:
1638 VLOG_ERR_RL(&error_rl, "unknown mpls action: %d, %d",
1639 m->action, m->m_action);
1640 return EINVAL;
1641 }
1642
1643 return 0;
1644}
1645
d6118e62
PB
1646static const struct nl_policy csum_policy[] = {
1647 [TCA_CSUM_PARMS] = { .type = NL_A_UNSPEC,
1648 .min_len = sizeof(struct tc_csum),
1649 .optional = false, },
1650};
1651
1652static int
1653nl_parse_act_csum(struct nlattr *options, struct tc_flower *flower)
1654{
1655 struct nlattr *csum_attrs[ARRAY_SIZE(csum_policy)];
1656 const struct tc_csum *c;
1657 const struct nlattr *csum_parms;
1658
1659 if (!nl_parse_nested(options, csum_policy, csum_attrs,
1660 ARRAY_SIZE(csum_policy))) {
1661 VLOG_ERR_RL(&error_rl, "failed to parse csum action options");
1662 return EPROTO;
1663 }
1664
1665 csum_parms = csum_attrs[TCA_CSUM_PARMS];
1666 c = nl_attr_get_unspec(csum_parms, sizeof *c);
1667
1668 /* sanity checks */
1669 if (c->update_flags != flower->csum_update_flags) {
1670 VLOG_WARN_RL(&error_rl,
1671 "expected different act csum flags: 0x%x != 0x%x",
1672 flower->csum_update_flags, c->update_flags);
1673 return EINVAL;
1674 }
1675 flower->csum_update_flags = 0; /* so we know csum was handled */
1676
1677 if (flower->needs_full_ip_proto_mask
1678 && flower->mask.ip_proto != UINT8_MAX) {
1679 VLOG_WARN_RL(&error_rl, "expected full matching on flower ip_proto");
1680 return EINVAL;
1681 }
1682
1683 return 0;
1684}
1685
f98e418f
RD
1686static const struct nl_policy act_policy[] = {
1687 [TCA_ACT_KIND] = { .type = NL_A_STRING, .optional = false, },
1688 [TCA_ACT_COOKIE] = { .type = NL_A_UNSPEC, .optional = true, },
5db012c4 1689 [TCA_ACT_OPTIONS] = { .type = NL_A_NESTED, .optional = true, },
f98e418f
RD
1690 [TCA_ACT_STATS] = { .type = NL_A_NESTED, .optional = false, },
1691};
1692
1693static const struct nl_policy stats_policy[] = {
1694 [TCA_STATS_BASIC] = { .type = NL_A_UNSPEC,
1695 .min_len = sizeof(struct gnet_stats_basic),
1696 .optional = false, },
1697};
1698
1699static int
5db012c4
VB
1700nl_parse_single_action(struct nlattr *action, struct tc_flower *flower,
1701 bool terse)
f98e418f
RD
1702{
1703 struct nlattr *act_options;
1704 struct nlattr *act_stats;
1705 struct nlattr *act_cookie;
1706 const char *act_kind;
1707 struct nlattr *action_attrs[ARRAY_SIZE(act_policy)];
1708 struct nlattr *stats_attrs[ARRAY_SIZE(stats_policy)];
1709 struct ovs_flow_stats *stats = &flower->stats;
1710 const struct gnet_stats_basic *bs;
40c5aa11 1711 int err = 0;
f98e418f
RD
1712
1713 if (!nl_parse_nested(action, act_policy, action_attrs,
5db012c4
VB
1714 ARRAY_SIZE(act_policy)) ||
1715 (!terse && !action_attrs[TCA_ACT_OPTIONS])) {
f98e418f
RD
1716 VLOG_ERR_RL(&error_rl, "failed to parse single action options");
1717 return EPROTO;
1718 }
1719
1720 act_kind = nl_attr_get_string(action_attrs[TCA_ACT_KIND]);
1721 act_options = action_attrs[TCA_ACT_OPTIONS];
1722 act_cookie = action_attrs[TCA_ACT_COOKIE];
1723
5db012c4
VB
1724 if (terse) {
1725 /* Terse dump doesn't provide act options attribute. */
1726 } else if (!strcmp(act_kind, "gact")) {
b2ae4069 1727 err = nl_parse_act_gact(act_options, flower);
f98e418f 1728 } else if (!strcmp(act_kind, "mirred")) {
40c5aa11 1729 err = nl_parse_act_mirred(act_options, flower);
f98e418f 1730 } else if (!strcmp(act_kind, "vlan")) {
40c5aa11 1731 err = nl_parse_act_vlan(act_options, flower);
55412eac
JH
1732 } else if (!strcmp(act_kind, "mpls")) {
1733 err = nl_parse_act_mpls(act_options, flower);
f98e418f 1734 } else if (!strcmp(act_kind, "tunnel_key")) {
40c5aa11 1735 err = nl_parse_act_tunnel_key(act_options, flower);
8ada482b 1736 } else if (!strcmp(act_kind, "pedit")) {
40c5aa11 1737 err = nl_parse_act_pedit(act_options, flower);
8ada482b 1738 } else if (!strcmp(act_kind, "csum")) {
d6118e62 1739 nl_parse_act_csum(act_options, flower);
4aa2dc04
JH
1740 } else if (!strcmp(act_kind, "skbedit")) {
1741 /* Added for TC rule only (not in OvS rule) so ignore. */
576126a9
PB
1742 } else if (!strcmp(act_kind, "ct")) {
1743 nl_parse_act_ct(act_options, flower);
f98e418f
RD
1744 } else {
1745 VLOG_ERR_RL(&error_rl, "unknown tc action kind: %s", act_kind);
40c5aa11
RD
1746 err = EINVAL;
1747 }
1748
1749 if (err) {
1750 return err;
f98e418f
RD
1751 }
1752
1753 if (act_cookie) {
1754 flower->act_cookie.data = nl_attr_get(act_cookie);
1755 flower->act_cookie.len = nl_attr_get_size(act_cookie);
1756 }
1757
1758 act_stats = action_attrs[TCA_ACT_STATS];
1759
1760 if (!nl_parse_nested(act_stats, stats_policy, stats_attrs,
1761 ARRAY_SIZE(stats_policy))) {
1762 VLOG_ERR_RL(&error_rl, "failed to parse action stats policy");
1763 return EPROTO;
1764 }
1765
1766 bs = nl_attr_get_unspec(stats_attrs[TCA_STATS_BASIC], sizeof *bs);
0fc38297 1767 if (bs->packets) {
1768 put_32aligned_u64(&stats->n_packets, bs->packets);
1769 put_32aligned_u64(&stats->n_bytes, bs->bytes);
1770 }
f98e418f
RD
1771
1772 return 0;
1773}
1774
1775#define TCA_ACT_MIN_PRIO 1
1776
1777static int
5db012c4
VB
1778nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower,
1779 bool terse)
f98e418f
RD
1780{
1781 const struct nlattr *actions = attrs[TCA_FLOWER_ACT];
d0fbb09f 1782 static struct nl_policy actions_orders_policy[TCA_ACT_MAX_NUM + 1] = {};
f98e418f
RD
1783 struct nlattr *actions_orders[ARRAY_SIZE(actions_orders_policy)];
1784 const int max_size = ARRAY_SIZE(actions_orders_policy);
1785
1786 for (int i = TCA_ACT_MIN_PRIO; i < max_size; i++) {
1787 actions_orders_policy[i].type = NL_A_NESTED;
1788 actions_orders_policy[i].optional = true;
1789 }
1790
1791 if (!nl_parse_nested(actions, actions_orders_policy, actions_orders,
1792 ARRAY_SIZE(actions_orders_policy))) {
1793 VLOG_ERR_RL(&error_rl, "failed to parse flower order of actions");
1794 return EPROTO;
1795 }
1796
1797 for (int i = TCA_ACT_MIN_PRIO; i < max_size; i++) {
1798 if (actions_orders[i]) {
0c70132c
CM
1799 int err;
1800
d0fbb09f
CM
1801 if (flower->action_count >= TCA_ACT_MAX_NUM) {
1802 VLOG_DBG_RL(&error_rl, "Can only support %d actions", TCA_ACT_MAX_NUM);
0c70132c
CM
1803 return EOPNOTSUPP;
1804 }
5db012c4 1805 err = nl_parse_single_action(actions_orders[i], flower, terse);
f98e418f
RD
1806
1807 if (err) {
1808 return err;
1809 }
1810 }
1811 }
1812
d6118e62
PB
1813 if (flower->csum_update_flags) {
1814 VLOG_WARN_RL(&error_rl,
1815 "expected act csum with flags: 0x%x",
1816 flower->csum_update_flags);
1817 return EINVAL;
1818 }
1819
f98e418f
RD
1820 return 0;
1821}
1822
1823static int
5db012c4
VB
1824nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower,
1825 bool terse)
f98e418f
RD
1826{
1827 struct nlattr *attrs[ARRAY_SIZE(tca_flower_policy)];
a468645c 1828 int err;
f98e418f 1829
5db012c4
VB
1830 if (terse) {
1831 if (!nl_parse_nested(nl_options, tca_flower_terse_policy,
1832 attrs, ARRAY_SIZE(tca_flower_terse_policy))) {
1833 VLOG_ERR_RL(&error_rl, "failed to parse flower classifier terse options");
1834 return EPROTO;
1835 }
1836 goto skip_flower_opts;
1837 }
1838
f98e418f
RD
1839 if (!nl_parse_nested(nl_options, tca_flower_policy,
1840 attrs, ARRAY_SIZE(tca_flower_policy))) {
1841 VLOG_ERR_RL(&error_rl, "failed to parse flower classifier options");
1842 return EPROTO;
1843 }
1844
1845 nl_parse_flower_eth(attrs, flower);
a3db6e47 1846 nl_parse_flower_arp(attrs, flower);
34b16955 1847 nl_parse_flower_mpls(attrs, flower);
f98e418f
RD
1848 nl_parse_flower_vlan(attrs, flower);
1849 nl_parse_flower_ip(attrs, flower);
a468645c
PJV
1850 err = nl_parse_flower_tunnel(attrs, flower);
1851 if (err) {
1852 return err;
1853 }
1854
5db012c4 1855skip_flower_opts:
d63ca532 1856 nl_parse_flower_flags(attrs, flower);
5db012c4 1857 return nl_parse_flower_actions(attrs, flower, terse);
f98e418f
RD
1858}
1859
1860int
acdd544c 1861parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tcf_id *id,
5db012c4 1862 struct tc_flower *flower, bool terse)
f98e418f
RD
1863{
1864 struct tcmsg *tc;
1865 struct nlattr *ta[ARRAY_SIZE(tca_policy)];
1866 const char *kind;
1867
1868 if (NLMSG_HDRLEN + sizeof *tc > reply->size) {
1869 return EPROTO;
1870 }
1871
1872 memset(flower, 0, sizeof *flower);
1873
1874 tc = ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tc);
acdd544c 1875
f98e418f
RD
1876 flower->key.eth_type = (OVS_FORCE ovs_be16) tc_get_minor(tc->tcm_info);
1877 flower->mask.eth_type = OVS_BE16_MAX;
acdd544c
PB
1878 id->prio = tc_get_major(tc->tcm_info);
1879 id->handle = tc->tcm_handle;
f98e418f 1880
acdd544c 1881 if (id->prio == TC_RESERVED_PRIORITY_POLICE) {
e7f6ba22
PJV
1882 return 0;
1883 }
1884
acdd544c 1885 if (!id->handle) {
f98e418f
RD
1886 return EAGAIN;
1887 }
1888
1889 if (!nl_policy_parse(reply, NLMSG_HDRLEN + sizeof *tc,
1890 tca_policy, ta, ARRAY_SIZE(ta))) {
1891 VLOG_ERR_RL(&error_rl, "failed to parse tca policy");
1892 return EPROTO;
1893 }
1894
b2ae4069
PB
1895 if (ta[TCA_CHAIN]) {
1896 id->chain = nl_attr_get_u32(ta[TCA_CHAIN]);
1897 }
1898
f98e418f
RD
1899 kind = nl_attr_get_string(ta[TCA_KIND]);
1900 if (strcmp(kind, "flower")) {
763e120d 1901 VLOG_DBG_ONCE("Unsupported filter: %s", kind);
f98e418f
RD
1902 return EPROTO;
1903 }
1904
5db012c4 1905 return nl_parse_flower_options(ta[TCA_OPTIONS], flower, terse);
f98e418f
RD
1906}
1907
1908int
5db012c4 1909tc_dump_flower_start(struct tcf_id *id, struct nl_dump *dump, bool terse)
f98e418f
RD
1910{
1911 struct ofpbuf request;
f98e418f 1912
acdd544c 1913 request_from_tcf_id(id, 0, RTM_GETTFILTER, NLM_F_DUMP, &request);
5db012c4
VB
1914 if (terse) {
1915 struct nla_bitfield32 dump_flags = { TCA_DUMP_FLAGS_TERSE,
1916 TCA_DUMP_FLAGS_TERSE };
1917
1918 nl_msg_put_unspec(&request, TCA_DUMP_FLAGS, &dump_flags,
1919 sizeof dump_flags);
1920 }
f98e418f
RD
1921 nl_dump_start(dump, NETLINK_ROUTE, &request);
1922 ofpbuf_uninit(&request);
1923
1924 return 0;
1925}
1926
1927int
acdd544c 1928tc_del_filter(struct tcf_id *id)
f98e418f
RD
1929{
1930 struct ofpbuf request;
f98e418f 1931
acdd544c 1932 request_from_tcf_id(id, 0, RTM_DELTFILTER, NLM_F_ACK, &request);
f98e418f
RD
1933 return tc_transact(&request, NULL);
1934}
1935
1936int
acdd544c 1937tc_get_flower(struct tcf_id *id, struct tc_flower *flower)
f98e418f
RD
1938{
1939 struct ofpbuf request;
f98e418f
RD
1940 struct ofpbuf *reply;
1941 int error;
f98e418f 1942
acdd544c 1943 request_from_tcf_id(id, 0, RTM_GETTFILTER, NLM_F_ECHO, &request);
f98e418f
RD
1944 error = tc_transact(&request, &reply);
1945 if (error) {
1946 return error;
1947 }
1948
5db012c4 1949 error = parse_netlink_to_tc_flower(reply, id, flower, false);
f98e418f
RD
1950 ofpbuf_delete(reply);
1951 return error;
1952}
1953
691d20cb
PB
1954static int
1955tc_get_tc_cls_policy(enum tc_offload_policy policy)
1956{
1957 if (policy == TC_POLICY_SKIP_HW) {
1958 return TCA_CLS_FLAGS_SKIP_HW;
1959 } else if (policy == TC_POLICY_SKIP_SW) {
1960 return TCA_CLS_FLAGS_SKIP_SW;
1961 }
1962
1963 return 0;
1964}
1965
8ada482b
PB
1966static void
1967nl_msg_put_act_csum(struct ofpbuf *request, uint32_t flags)
1968{
1969 size_t offset;
1970
1971 nl_msg_put_string(request, TCA_ACT_KIND, "csum");
1972 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
1973 {
1974 struct tc_csum parm = { .action = TC_ACT_PIPE,
1975 .update_flags = flags };
1976
1977 nl_msg_put_unspec(request, TCA_CSUM_PARMS, &parm, sizeof parm);
1978 }
1979 nl_msg_end_nested(request, offset);
1980}
1981
1982static void
1983nl_msg_put_act_pedit(struct ofpbuf *request, struct tc_pedit *parm,
1984 struct tc_pedit_key_ex *ex)
1985{
e13bbbab 1986 size_t ksize = sizeof *parm + parm->nkeys * sizeof(struct tc_pedit_key);
8ada482b
PB
1987 size_t offset, offset_keys_ex, offset_key;
1988 int i;
1989
1990 nl_msg_put_string(request, TCA_ACT_KIND, "pedit");
1991 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
1992 {
1993 parm->action = TC_ACT_PIPE;
1994
1995 nl_msg_put_unspec(request, TCA_PEDIT_PARMS_EX, parm, ksize);
1996 offset_keys_ex = nl_msg_start_nested(request, TCA_PEDIT_KEYS_EX);
1997 for (i = 0; i < parm->nkeys; i++, ex++) {
1998 offset_key = nl_msg_start_nested(request, TCA_PEDIT_KEY_EX);
1999 nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_HTYPE, ex->htype);
2000 nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_CMD, ex->cmd);
2001 nl_msg_end_nested(request, offset_key);
2002 }
2003 nl_msg_end_nested(request, offset_keys_ex);
2004 }
2005 nl_msg_end_nested(request, offset);
2006}
2007
f98e418f 2008static void
10097f3f 2009nl_msg_put_act_push_vlan(struct ofpbuf *request, ovs_be16 tpid,
61e8655c 2010 uint16_t vid, uint8_t prio)
f98e418f
RD
2011{
2012 size_t offset;
2013
2014 nl_msg_put_string(request, TCA_ACT_KIND, "vlan");
2015 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2016 {
2017 struct tc_vlan parm = { .action = TC_ACT_PIPE,
2018 .v_action = TCA_VLAN_ACT_PUSH };
2019
2020 nl_msg_put_unspec(request, TCA_VLAN_PARMS, &parm, sizeof parm);
10097f3f 2021 nl_msg_put_be16(request, TCA_VLAN_PUSH_VLAN_PROTOCOL, tpid);
f98e418f
RD
2022 nl_msg_put_u16(request, TCA_VLAN_PUSH_VLAN_ID, vid);
2023 nl_msg_put_u8(request, TCA_VLAN_PUSH_VLAN_PRIORITY, prio);
2024 }
2025 nl_msg_end_nested(request, offset);
2026}
2027
2028static void
2029nl_msg_put_act_pop_vlan(struct ofpbuf *request)
2030{
2031 size_t offset;
2032
2033 nl_msg_put_string(request, TCA_ACT_KIND, "vlan");
2034 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2035 {
2036 struct tc_vlan parm = { .action = TC_ACT_PIPE,
2037 .v_action = TCA_VLAN_ACT_POP };
2038
2039 nl_msg_put_unspec(request, TCA_VLAN_PARMS, &parm, sizeof parm);
2040 }
2041 nl_msg_end_nested(request, offset);
2042}
2043
55412eac
JH
2044static void
2045nl_msg_put_act_pop_mpls(struct ofpbuf *request, ovs_be16 proto)
2046{
2047 size_t offset;
2048
2049 nl_msg_put_string(request, TCA_ACT_KIND, "mpls");
2050 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED);
2051 {
2052 struct tc_mpls parm = { .action = TC_ACT_PIPE,
2053 .m_action = TCA_MPLS_ACT_POP };
2054
2055 nl_msg_put_unspec(request, TCA_MPLS_PARMS, &parm, sizeof parm);
2056 nl_msg_put_be16(request, TCA_MPLS_PROTO, proto);
2057 }
2058 nl_msg_end_nested(request, offset);
2059}
2060
283dcf85
JH
2061static void
2062nl_msg_put_act_push_mpls(struct ofpbuf *request, ovs_be16 proto,
2063 uint32_t label, uint8_t tc, uint8_t ttl, uint8_t bos)
2064{
2065 size_t offset;
2066
2067 nl_msg_put_string(request, TCA_ACT_KIND, "mpls");
2068 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED);
2069 {
2070 struct tc_mpls parm = { .action = TC_ACT_PIPE,
2071 .m_action = TCA_MPLS_ACT_PUSH };
2072
2073 nl_msg_put_unspec(request, TCA_MPLS_PARMS, &parm, sizeof parm);
2074 nl_msg_put_be16(request, TCA_MPLS_PROTO, proto);
2075 nl_msg_put_u32(request, TCA_MPLS_LABEL, label);
2076 nl_msg_put_u8(request, TCA_MPLS_TC, tc);
2077 nl_msg_put_u8(request, TCA_MPLS_TTL, ttl);
2078 nl_msg_put_u8(request, TCA_MPLS_BOS, bos);
2079 }
2080 nl_msg_end_nested(request, offset);
2081}
2082
a8f005cf
JH
2083static void
2084nl_msg_put_act_set_mpls(struct ofpbuf *request, uint32_t label, uint8_t tc,
2085 uint8_t ttl, uint8_t bos)
2086{
2087 size_t offset;
2088
2089 nl_msg_put_string(request, TCA_ACT_KIND, "mpls");
2090 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED);
2091 {
2092 struct tc_mpls parm = { .action = TC_ACT_PIPE,
2093 .m_action = TCA_MPLS_ACT_MODIFY };
2094
2095 nl_msg_put_unspec(request, TCA_MPLS_PARMS, &parm, sizeof parm);
2096 nl_msg_put_u32(request, TCA_MPLS_LABEL, label);
2097 nl_msg_put_u8(request, TCA_MPLS_TC, tc);
2098 nl_msg_put_u8(request, TCA_MPLS_TTL, ttl);
2099 nl_msg_put_u8(request, TCA_MPLS_BOS, bos);
2100 }
2101 nl_msg_end_nested(request, offset);
2102}
2103
f98e418f
RD
2104static void
2105nl_msg_put_act_tunnel_key_release(struct ofpbuf *request)
2106{
2107 size_t offset;
2108
2109 nl_msg_put_string(request, TCA_ACT_KIND, "tunnel_key");
2110 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2111 {
2112 struct tc_tunnel_key tun = { .action = TC_ACT_PIPE,
2113 .t_action = TCA_TUNNEL_KEY_ACT_RELEASE };
2114
2115 nl_msg_put_unspec(request, TCA_TUNNEL_KEY_PARMS, &tun, sizeof tun);
2116 }
2117 nl_msg_end_nested(request, offset);
2118}
2119
202469aa
PJV
2120static void
2121nl_msg_put_act_tunnel_geneve_option(struct ofpbuf *request,
2122 struct tun_metadata tun_metadata)
2123{
2124 const struct geneve_opt *opt;
2125 size_t outer, inner;
2126 int len, cnt = 0;
2127
2128 len = tun_metadata.present.len;
2129 if (!len) {
2130 return;
2131 }
2132
2133 outer = nl_msg_start_nested(request, TCA_TUNNEL_KEY_ENC_OPTS);
2134
2135 while (len) {
2136 opt = &tun_metadata.opts.gnv[cnt];
2137 inner = nl_msg_start_nested(request, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE);
2138
2139 nl_msg_put_be16(request, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS,
2140 opt->opt_class);
2141 nl_msg_put_u8(request, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE, opt->type);
2142 nl_msg_put_unspec(request, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA, opt + 1,
2143 opt->length * 4);
2144
2145 cnt += sizeof(struct geneve_opt) / 4 + opt->length;
2146 len -= sizeof(struct geneve_opt) + opt->length * 4;
2147
2148 nl_msg_end_nested(request, inner);
2149 }
2150
2151 nl_msg_end_nested(request, outer);
2152}
2153
f98e418f 2154static void
0227bf09
AN
2155nl_msg_put_act_tunnel_key_set(struct ofpbuf *request, bool id_present,
2156 ovs_be64 id, ovs_be32 ipv4_src,
2157 ovs_be32 ipv4_dst, struct in6_addr *ipv6_src,
202469aa
PJV
2158 struct in6_addr *ipv6_dst,
2159 ovs_be16 tp_dst, uint8_t tos, uint8_t ttl,
d9677a1f
EB
2160 struct tun_metadata tun_metadata,
2161 uint8_t no_csum)
f98e418f
RD
2162{
2163 size_t offset;
2164
2165 nl_msg_put_string(request, TCA_ACT_KIND, "tunnel_key");
2166 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2167 {
2168 struct tc_tunnel_key tun = { .action = TC_ACT_PIPE,
2169 .t_action = TCA_TUNNEL_KEY_ACT_SET };
2170
2171 nl_msg_put_unspec(request, TCA_TUNNEL_KEY_PARMS, &tun, sizeof tun);
2172
2173 ovs_be32 id32 = be64_to_be32(id);
0227bf09
AN
2174 if (id_present) {
2175 nl_msg_put_be32(request, TCA_TUNNEL_KEY_ENC_KEY_ID, id32);
2176 }
f98e418f
RD
2177 if (ipv4_dst) {
2178 nl_msg_put_be32(request, TCA_TUNNEL_KEY_ENC_IPV4_SRC, ipv4_src);
2179 nl_msg_put_be32(request, TCA_TUNNEL_KEY_ENC_IPV4_DST, ipv4_dst);
4f4be08e 2180 } else if (ipv6_addr_is_set(ipv6_dst)) {
f98e418f
RD
2181 nl_msg_put_in6_addr(request, TCA_TUNNEL_KEY_ENC_IPV6_DST,
2182 ipv6_dst);
2183 nl_msg_put_in6_addr(request, TCA_TUNNEL_KEY_ENC_IPV6_SRC,
2184 ipv6_src);
2185 }
4b12e454
OG
2186 if (tos) {
2187 nl_msg_put_u8(request, TCA_TUNNEL_KEY_ENC_TOS, tos);
2188 }
2189 if (ttl) {
2190 nl_msg_put_u8(request, TCA_TUNNEL_KEY_ENC_TTL, ttl);
2191 }
e48f49e0
EB
2192 if (tp_dst) {
2193 nl_msg_put_be16(request, TCA_TUNNEL_KEY_ENC_DST_PORT, tp_dst);
2194 }
202469aa 2195 nl_msg_put_act_tunnel_geneve_option(request, tun_metadata);
d9677a1f 2196 nl_msg_put_u8(request, TCA_TUNNEL_KEY_NO_CSUM, no_csum);
f98e418f
RD
2197 }
2198 nl_msg_end_nested(request, offset);
2199}
2200
2201static void
b2ae4069 2202nl_msg_put_act_gact(struct ofpbuf *request, uint32_t chain)
f98e418f
RD
2203{
2204 size_t offset;
2205
2206 nl_msg_put_string(request, TCA_ACT_KIND, "gact");
2207 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2208 {
2209 struct tc_gact p = { .action = TC_ACT_SHOT };
2210
b2ae4069
PB
2211 if (chain) {
2212 p.action = TC_ACT_GOTO_CHAIN | chain;
2213 }
2214
f98e418f
RD
2215 nl_msg_put_unspec(request, TCA_GACT_PARMS, &p, sizeof p);
2216 }
2217 nl_msg_end_nested(request, offset);
2218}
2219
576126a9
PB
2220static void
2221nl_msg_put_act_ct(struct ofpbuf *request, struct tc_action *action)
2222{
2223 uint16_t ct_action = 0;
2224 size_t offset;
2225
2226 nl_msg_put_string(request, TCA_ACT_KIND, "ct");
2227 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED);
2228 {
2229 struct tc_ct ct = {
2230 .action = TC_ACT_PIPE,
2231 };
2232
2233 if (!action->ct.clear) {
2234 if (action->ct.zone) {
2235 nl_msg_put_u16(request, TCA_CT_ZONE, action->ct.zone);
2236 }
2237
9221c721
PB
2238 if (!is_all_zeros(&action->ct.label_mask,
2239 sizeof action->ct.label_mask)) {
2240 nl_msg_put_u128(request, TCA_CT_LABELS,
2241 action->ct.label);
2242 nl_msg_put_u128(request, TCA_CT_LABELS_MASK,
2243 action->ct.label_mask);
2244 }
2245
2246 if (action->ct.mark_mask) {
2247 nl_msg_put_u32(request, TCA_CT_MARK,
2248 action->ct.mark);
2249 nl_msg_put_u32(request, TCA_CT_MARK_MASK,
2250 action->ct.mark_mask);
2251 }
2252
576126a9
PB
2253 if (action->ct.commit) {
2254 ct_action = TCA_CT_ACT_COMMIT;
2255 if (action->ct.force) {
2256 ct_action |= TCA_CT_ACT_FORCE;
2257 }
2258 }
2bf6ffb7
PB
2259
2260 if (action->ct.nat_type) {
2261 ct_action |= TCA_CT_ACT_NAT;
2262
2263 if (action->ct.nat_type == TC_NAT_SRC) {
2264 ct_action |= TCA_CT_ACT_NAT_SRC;
2265 } else if (action->ct.nat_type == TC_NAT_DST) {
2266 ct_action |= TCA_CT_ACT_NAT_DST;
2267 }
2268
2269 if (action->ct.range.ip_family == AF_INET) {
2270 nl_msg_put_be32(request, TCA_CT_NAT_IPV4_MIN,
2271 action->ct.range.ipv4.min);
2272 if (action->ct.range.ipv4.max) {
2273 nl_msg_put_be32(request, TCA_CT_NAT_IPV4_MAX,
2274 action->ct.range.ipv4.max);
2275 }
2276 } else if (action->ct.range.ip_family == AF_INET6) {
2bf6ffb7
PB
2277
2278 nl_msg_put_in6_addr(request, TCA_CT_NAT_IPV6_MIN,
2279 &action->ct.range.ipv6.min);
4f4be08e 2280 if (ipv6_addr_is_set(&action->ct.range.ipv6.max)) {
2bf6ffb7
PB
2281 nl_msg_put_in6_addr(request, TCA_CT_NAT_IPV6_MAX,
2282 &action->ct.range.ipv6.max);
2283 }
2284 }
2285
2286 if (action->ct.range.port.min) {
2287 nl_msg_put_be16(request, TCA_CT_NAT_PORT_MIN,
2288 action->ct.range.port.min);
2289 if (action->ct.range.port.max) {
2290 nl_msg_put_be16(request, TCA_CT_NAT_PORT_MAX,
2291 action->ct.range.port.max);
2292 }
2293 }
2294 }
576126a9
PB
2295 } else {
2296 ct_action = TCA_CT_ACT_CLEAR;
2297 }
2298
2299 nl_msg_put_u16(request, TCA_CT_ACTION, ct_action);
2300 nl_msg_put_unspec(request, TCA_CT_PARMS, &ct, sizeof ct);
2301 }
2302 nl_msg_end_nested(request, offset);
2303}
2304
4aa2dc04
JH
2305static void
2306nl_msg_put_act_skbedit_to_host(struct ofpbuf *request)
2307{
2308 size_t offset;
2309
2310 nl_msg_put_string(request, TCA_ACT_KIND, "skbedit");
2311 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2312 {
2313 struct tc_skbedit s = { .action = TC_ACT_PIPE };
2314
2315 nl_msg_put_unspec(request, TCA_SKBEDIT_PARMS, &s, sizeof s);
2316 nl_msg_put_be16(request, TCA_SKBEDIT_PTYPE, PACKET_HOST);
2317 }
2318 nl_msg_end_nested(request, offset);
2319}
2320
f98e418f 2321static void
00a0a011
CM
2322nl_msg_put_act_mirred(struct ofpbuf *request, int ifindex, int action,
2323 int eaction)
f98e418f
RD
2324{
2325 size_t offset;
2326
2327 nl_msg_put_string(request, TCA_ACT_KIND, "mirred");
2328 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
2329 {
00a0a011
CM
2330 struct tc_mirred m = { .action = action,
2331 .eaction = eaction,
f98e418f
RD
2332 .ifindex = ifindex };
2333
2334 nl_msg_put_unspec(request, TCA_MIRRED_PARMS, &m, sizeof m);
2335 }
2336 nl_msg_end_nested(request, offset);
2337}
2338
2339static inline void
2340nl_msg_put_act_cookie(struct ofpbuf *request, struct tc_cookie *ck) {
2341 if (ck->len) {
2342 nl_msg_put_unspec(request, TCA_ACT_COOKIE, ck->data, ck->len);
2343 }
2344}
2345
292d5bd9
VB
2346static inline void
2347nl_msg_put_act_flags(struct ofpbuf *request) {
2348 struct nla_bitfield32 act_flags = { TCA_ACT_FLAGS_NO_PERCPU_STATS,
2349 TCA_ACT_FLAGS_NO_PERCPU_STATS };
2350
2351 nl_msg_put_unspec(request, TCA_ACT_FLAGS, &act_flags, sizeof act_flags);
2352}
2353
8ada482b
PB
2354/* Given flower, a key_to_pedit map entry, calculates the rest,
2355 * where:
2356 *
2357 * mask, data - pointers of where read the first word of flower->key/mask.
2358 * current_offset - which offset to use for the first pedit action.
2359 * cnt - max pedits actions to use.
2360 * first_word_mask/last_word_mask - the mask to use for the first/last read
2361 * (as we read entire words). */
f98e418f 2362static void
8ada482b 2363calc_offsets(struct tc_flower *flower, struct flower_key_to_pedit *m,
f8b63e59
PJV
2364 int *cur_offset, int *cnt, ovs_be32 *last_word_mask,
2365 ovs_be32 *first_word_mask, ovs_be32 **mask, ovs_be32 **data)
8ada482b
PB
2366{
2367 int start_offset, max_offset, total_size;
2368 int diff, right_zero_bits, left_zero_bits;
2369 char *rewrite_key = (void *) &flower->rewrite.key;
2370 char *rewrite_mask = (void *) &flower->rewrite.mask;
2371
2372 max_offset = m->offset + m->size;
2373 start_offset = ROUND_DOWN(m->offset, 4);
2374 diff = m->offset - start_offset;
2375 total_size = max_offset - start_offset;
0d9f0cd4 2376 right_zero_bits = 8 * (4 - ((max_offset % 4) ? : 4));
8ada482b
PB
2377 left_zero_bits = 8 * (m->offset - start_offset);
2378
2379 *cur_offset = start_offset;
2380 *cnt = (total_size / 4) + (total_size % 4 ? 1 : 0);
f8b63e59
PJV
2381 *last_word_mask = htonl(UINT32_MAX << right_zero_bits);
2382 *first_word_mask = htonl(UINT32_MAX >> left_zero_bits);
8ada482b
PB
2383 *data = (void *) (rewrite_key + m->flower_offset - diff);
2384 *mask = (void *) (rewrite_mask + m->flower_offset - diff);
2385}
2386
d6118e62 2387static inline int
8ada482b
PB
2388csum_update_flag(struct tc_flower *flower,
2389 enum pedit_header_type htype) {
d6118e62
PB
2390 /* Explictily specifiy the csum flags so HW can return EOPNOTSUPP
2391 * if it doesn't support a checksum recalculation of some headers.
2392 * And since OVS allows a flow such as
2393 * eth(dst=<mac>),eth_type(0x0800) actions=set(ipv4(src=<new_ip>))
2394 * we need to force a more specific flow as this can, for example,
2395 * need a recalculation of icmp checksum if the packet that passes
d5ac6458 2396 * is ICMPv6 and tcp checksum if its tcp. */
d6118e62
PB
2397
2398 switch (htype) {
2399 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4:
8ada482b 2400 flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR;
eeb0ca88 2401 /* Fall through. */
d6118e62
PB
2402 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
2403 case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP:
2404 case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP:
8ada482b 2405 if (flower->key.ip_proto == IPPROTO_TCP) {
d6118e62 2406 flower->needs_full_ip_proto_mask = true;
8ada482b
PB
2407 flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_TCP;
2408 } else if (flower->key.ip_proto == IPPROTO_UDP) {
d6118e62 2409 flower->needs_full_ip_proto_mask = true;
8ada482b 2410 flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_UDP;
d5ac6458
JL
2411 } else if (flower->key.ip_proto == IPPROTO_ICMP) {
2412 flower->needs_full_ip_proto_mask = true;
2413 } else if (flower->key.ip_proto == IPPROTO_ICMPV6) {
d6118e62 2414 flower->needs_full_ip_proto_mask = true;
8ada482b 2415 flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP;
d6118e62
PB
2416 } else {
2417 VLOG_WARN_RL(&error_rl,
2418 "can't offload rewrite of IP/IPV6 with ip_proto: %d",
2419 flower->key.ip_proto);
2420 break;
8ada482b 2421 }
eeb0ca88 2422 /* Fall through. */
d6118e62
PB
2423 case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH:
2424 return 0; /* success */
2425
2426 case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK:
2427 case __PEDIT_HDR_TYPE_MAX:
2428 default:
2429 break;
8ada482b 2430 }
d6118e62
PB
2431
2432 return EOPNOTSUPP;
8ada482b
PB
2433}
2434
2435static int
2436nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request,
2437 struct tc_flower *flower)
2438{
2439 struct {
2440 struct tc_pedit sel;
2441 struct tc_pedit_key keys[MAX_PEDIT_OFFSETS];
2442 struct tc_pedit_key_ex keys_ex[MAX_PEDIT_OFFSETS];
2443 } sel = {
2444 .sel = {
2445 .nkeys = 0
2446 }
2447 };
d6118e62 2448 int i, j, err;
8ada482b
PB
2449
2450 for (i = 0; i < ARRAY_SIZE(flower_pedit_map); i++) {
2451 struct flower_key_to_pedit *m = &flower_pedit_map[i];
2452 struct tc_pedit_key *pedit_key = NULL;
2453 struct tc_pedit_key_ex *pedit_key_ex = NULL;
f8b63e59 2454 ovs_be32 *mask, *data, first_word_mask, last_word_mask;
8ada482b
PB
2455 int cnt = 0, cur_offset = 0;
2456
2457 if (!m->size) {
2458 continue;
2459 }
2460
2461 calc_offsets(flower, m, &cur_offset, &cnt, &last_word_mask,
2462 &first_word_mask, &mask, &data);
2463
2464 for (j = 0; j < cnt; j++, mask++, data++, cur_offset += 4) {
f8b63e59 2465 ovs_be32 mask_word = *mask;
dbcb014d 2466 ovs_be32 data_word = *data;
8ada482b
PB
2467
2468 if (j == 0) {
2469 mask_word &= first_word_mask;
2470 }
2471 if (j == cnt - 1) {
2472 mask_word &= last_word_mask;
2473 }
2474 if (!mask_word) {
2475 continue;
2476 }
2477 if (sel.sel.nkeys == MAX_PEDIT_OFFSETS) {
2478 VLOG_WARN_RL(&error_rl, "reached too many pedit offsets: %d",
2479 MAX_PEDIT_OFFSETS);
2480 return EOPNOTSUPP;
2481 }
2482
2483 pedit_key = &sel.keys[sel.sel.nkeys];
2484 pedit_key_ex = &sel.keys_ex[sel.sel.nkeys];
2485 pedit_key_ex->cmd = TCA_PEDIT_KEY_EX_CMD_SET;
2486 pedit_key_ex->htype = m->htype;
2487 pedit_key->off = cur_offset;
dbcb014d
PJV
2488 mask_word = htonl(ntohl(mask_word) >> m->boundary_shift);
2489 data_word = htonl(ntohl(data_word) >> m->boundary_shift);
8ada482b 2490 pedit_key->mask = ~mask_word;
dbcb014d 2491 pedit_key->val = data_word & mask_word;
8ada482b 2492 sel.sel.nkeys++;
d6118e62
PB
2493
2494 err = csum_update_flag(flower, m->htype);
2495 if (err) {
2496 return err;
2497 }
2498
2499 if (flower->needs_full_ip_proto_mask) {
2500 flower->mask.ip_proto = UINT8_MAX;
2501 }
8ada482b
PB
2502 }
2503 }
2504 nl_msg_put_act_pedit(request, &sel.sel, sel.keys_ex);
2505
2506 return 0;
2507}
2508
2509static int
f98e418f
RD
2510nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
2511{
7c53bd78 2512 bool ingress, released = false;
f98e418f
RD
2513 size_t offset;
2514 size_t act_offset;
0c70132c
CM
2515 uint16_t act_index = 1;
2516 struct tc_action *action;
2517 int i, ifindex = 0;
f98e418f
RD
2518
2519 offset = nl_msg_start_nested(request, TCA_FLOWER_ACT);
2520 {
8ada482b
PB
2521 int error;
2522
0c70132c
CM
2523 action = flower->actions;
2524 for (i = 0; i < flower->action_count; i++, action++) {
2525 switch (action->type) {
2526 case TC_ACT_PEDIT: {
a7ce5b85 2527 act_offset = nl_msg_start_nested(request, act_index++);
0c70132c
CM
2528 error = nl_msg_put_flower_rewrite_pedits(request, flower);
2529 if (error) {
2530 return error;
2531 }
a7ce5b85 2532 nl_msg_end_nested(request, act_offset);
0c70132c
CM
2533
2534 if (flower->csum_update_flags) {
2535 act_offset = nl_msg_start_nested(request, act_index++);
2536 nl_msg_put_act_csum(request, flower->csum_update_flags);
292d5bd9 2537 nl_msg_put_act_flags(request);
0c70132c
CM
2538 nl_msg_end_nested(request, act_offset);
2539 }
2540 }
2541 break;
2542 case TC_ACT_ENCAP: {
2543 act_offset = nl_msg_start_nested(request, act_index++);
0227bf09
AN
2544 nl_msg_put_act_tunnel_key_set(request, action->encap.id_present,
2545 action->encap.id,
0c70132c
CM
2546 action->encap.ipv4.ipv4_src,
2547 action->encap.ipv4.ipv4_dst,
2548 &action->encap.ipv6.ipv6_src,
2549 &action->encap.ipv6.ipv6_dst,
4b12e454
OG
2550 action->encap.tp_dst,
2551 action->encap.tos,
202469aa 2552 action->encap.ttl,
d9677a1f
EB
2553 action->encap.data,
2554 action->encap.no_csum);
292d5bd9 2555 nl_msg_put_act_flags(request);
0c70132c
CM
2556 nl_msg_end_nested(request, act_offset);
2557 }
2558 break;
2559 case TC_ACT_VLAN_POP: {
2560 act_offset = nl_msg_start_nested(request, act_index++);
2561 nl_msg_put_act_pop_vlan(request);
292d5bd9 2562 nl_msg_put_act_flags(request);
0c70132c
CM
2563 nl_msg_end_nested(request, act_offset);
2564 }
2565 break;
2566 case TC_ACT_VLAN_PUSH: {
2567 act_offset = nl_msg_start_nested(request, act_index++);
2568 nl_msg_put_act_push_vlan(request,
61e8655c 2569 action->vlan.vlan_push_tpid,
0c70132c
CM
2570 action->vlan.vlan_push_id,
2571 action->vlan.vlan_push_prio);
292d5bd9 2572 nl_msg_put_act_flags(request);
0c70132c
CM
2573 nl_msg_end_nested(request, act_offset);
2574 }
2575 break;
55412eac
JH
2576 case TC_ACT_MPLS_POP: {
2577 act_offset = nl_msg_start_nested(request, act_index++);
2578 nl_msg_put_act_pop_mpls(request, action->mpls.proto);
2579 nl_msg_end_nested(request, act_offset);
2580 }
2581 break;
283dcf85
JH
2582 case TC_ACT_MPLS_PUSH: {
2583 act_offset = nl_msg_start_nested(request, act_index++);
2584 nl_msg_put_act_push_mpls(request, action->mpls.proto,
2585 action->mpls.label, action->mpls.tc,
2586 action->mpls.ttl, action->mpls.bos);
2587 nl_msg_end_nested(request, act_offset);
2588 }
2589 break;
a8f005cf
JH
2590 case TC_ACT_MPLS_SET: {
2591 act_offset = nl_msg_start_nested(request, act_index++);
2592 nl_msg_put_act_set_mpls(request, action->mpls.label,
2593 action->mpls.tc, action->mpls.ttl,
2594 action->mpls.bos);
2595 nl_msg_end_nested(request, act_offset);
2596 }
2597 break;
0c70132c 2598 case TC_ACT_OUTPUT: {
7c53bd78
PB
2599 if (!released && flower->tunnel) {
2600 act_offset = nl_msg_start_nested(request, act_index++);
2601 nl_msg_put_act_tunnel_key_release(request);
2602 nl_msg_end_nested(request, act_offset);
2603 released = true;
2604 }
2605
4aa2dc04
JH
2606 ingress = action->out.ingress;
2607 ifindex = action->out.ifindex_out;
0c70132c
CM
2608 if (ifindex < 1) {
2609 VLOG_ERR_RL(&error_rl, "%s: invalid ifindex: %d, type: %d",
2610 __func__, ifindex, action->type);
2611 return EINVAL;
2612 }
4aa2dc04
JH
2613
2614 if (ingress) {
2615 /* If redirecting to ingress (internal port) ensure
2616 * pkt_type on skb is set to PACKET_HOST. */
2617 act_offset = nl_msg_start_nested(request, act_index++);
2618 nl_msg_put_act_skbedit_to_host(request);
2619 nl_msg_end_nested(request, act_offset);
2620 }
2621
0c70132c 2622 act_offset = nl_msg_start_nested(request, act_index++);
00a0a011 2623 if (i == flower->action_count - 1) {
4aa2dc04
JH
2624 if (ingress) {
2625 nl_msg_put_act_mirred(request, ifindex, TC_ACT_STOLEN,
2626 TCA_INGRESS_REDIR);
2627 } else {
2628 nl_msg_put_act_mirred(request, ifindex, TC_ACT_STOLEN,
2629 TCA_EGRESS_REDIR);
2630 }
00a0a011 2631 } else {
4aa2dc04
JH
2632 if (ingress) {
2633 nl_msg_put_act_mirred(request, ifindex, TC_ACT_PIPE,
2634 TCA_INGRESS_MIRROR);
2635 } else {
2636 nl_msg_put_act_mirred(request, ifindex, TC_ACT_PIPE,
2637 TCA_EGRESS_MIRROR);
2638 }
00a0a011 2639 }
0c70132c 2640 nl_msg_put_act_cookie(request, &flower->act_cookie);
292d5bd9 2641 nl_msg_put_act_flags(request);
0c70132c
CM
2642 nl_msg_end_nested(request, act_offset);
2643 }
2644 break;
b2ae4069
PB
2645 case TC_ACT_GOTO: {
2646 if (released) {
2647 /* We don't support tunnel release + output + goto
2648 * for now, as next chain by default will try and match
2649 * the tunnel metadata that was released/unset.
2650 *
2651 * This will happen with tunnel + mirror ports.
2652 */
2653 return -EOPNOTSUPP;
2654 }
2655
2656 act_offset = nl_msg_start_nested(request, act_index++);
2657 nl_msg_put_act_gact(request, action->chain);
2658 nl_msg_put_act_cookie(request, &flower->act_cookie);
2659 nl_msg_end_nested(request, act_offset);
2660 }
2661 break;
576126a9
PB
2662 case TC_ACT_CT: {
2663 act_offset = nl_msg_start_nested(request, act_index++);
2664 nl_msg_put_act_ct(request, action);
2665 nl_msg_put_act_cookie(request, &flower->act_cookie);
2666 nl_msg_end_nested(request, act_offset);
2667 }
2668 break;
a7ce5b85 2669 }
8ada482b 2670 }
0c70132c 2671 }
b2ae4069
PB
2672
2673 if (!flower->action_count) {
0c70132c 2674 act_offset = nl_msg_start_nested(request, act_index++);
b2ae4069 2675 nl_msg_put_act_gact(request, 0);
0c70132c 2676 nl_msg_put_act_cookie(request, &flower->act_cookie);
292d5bd9 2677 nl_msg_put_act_flags(request);
0c70132c 2678 nl_msg_end_nested(request, act_offset);
f98e418f
RD
2679 }
2680 nl_msg_end_nested(request, offset);
8ada482b
PB
2681
2682 return 0;
f98e418f
RD
2683}
2684
2685static void
2686nl_msg_put_masked_value(struct ofpbuf *request, uint16_t type,
2687 uint16_t mask_type, const void *data,
2688 const void *mask_data, size_t len)
2689{
2690 if (mask_type != TCA_FLOWER_UNSPEC) {
2691 if (is_all_zeros(mask_data, len)) {
2692 return;
2693 }
2694 nl_msg_put_unspec(request, mask_type, mask_data, len);
2695 }
2696 nl_msg_put_unspec(request, type, data, len);
2697}
2698
a468645c
PJV
2699static void
2700nl_msg_put_flower_tunnel_opts(struct ofpbuf *request, uint16_t type,
2701 struct tun_metadata metadata)
2702{
2703 struct geneve_opt *opt;
2704 size_t outer, inner;
2705 int len, cnt = 0;
2706
2707 len = metadata.present.len;
2708 if (!len) {
2709 return;
2710 }
2711
2712 outer = nl_msg_start_nested(request, type);
2713 while (len) {
2714 opt = &metadata.opts.gnv[cnt];
2715 inner = nl_msg_start_nested(request, TCA_FLOWER_KEY_ENC_OPTS_GENEVE);
2716
2717 nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS,
2718 opt->opt_class);
2719 nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, opt->type);
2720 nl_msg_put_unspec(request, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, opt + 1,
2721 opt->length * 4);
2722
2723 cnt += sizeof(struct geneve_opt) / 4 + opt->length;
2724 len -= sizeof(struct geneve_opt) + opt->length * 4;
2725
2726 nl_msg_end_nested(request, inner);
2727 }
2728 nl_msg_end_nested(request, outer);
2729}
2730
f98e418f
RD
2731static void
2732nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)
2733{
5f568d04
TZ
2734 ovs_be32 ipv4_src_mask = flower->mask.tunnel.ipv4.ipv4_src;
2735 ovs_be32 ipv4_dst_mask = flower->mask.tunnel.ipv4.ipv4_dst;
105e8179
OG
2736 ovs_be32 ipv4_src = flower->key.tunnel.ipv4.ipv4_src;
2737 ovs_be32 ipv4_dst = flower->key.tunnel.ipv4.ipv4_dst;
5f568d04
TZ
2738 struct in6_addr *ipv6_src_mask = &flower->mask.tunnel.ipv6.ipv6_src;
2739 struct in6_addr *ipv6_dst_mask = &flower->mask.tunnel.ipv6.ipv6_dst;
105e8179
OG
2740 struct in6_addr *ipv6_src = &flower->key.tunnel.ipv6.ipv6_src;
2741 struct in6_addr *ipv6_dst = &flower->key.tunnel.ipv6.ipv6_dst;
2742 ovs_be16 tp_dst = flower->key.tunnel.tp_dst;
2743 ovs_be32 id = be64_to_be32(flower->key.tunnel.id);
2744 uint8_t tos = flower->key.tunnel.tos;
2745 uint8_t ttl = flower->key.tunnel.ttl;
49a7961f
OG
2746 uint8_t tos_mask = flower->mask.tunnel.tos;
2747 uint8_t ttl_mask = flower->mask.tunnel.ttl;
0227bf09 2748 ovs_be64 id_mask = flower->mask.tunnel.id;
f98e418f 2749
5f568d04
TZ
2750 if (ipv4_dst_mask || ipv4_src_mask) {
2751 nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
2752 ipv4_dst_mask);
2753 nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
2754 ipv4_src_mask);
f98e418f 2755 nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_DST, ipv4_dst);
5f568d04
TZ
2756 nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_SRC, ipv4_src);
2757 } else if (ipv6_addr_is_set(ipv6_dst_mask) ||
2758 ipv6_addr_is_set(ipv6_src_mask)) {
2759 nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
2760 ipv6_dst_mask);
2761 nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
2762 ipv6_src_mask);
f98e418f 2763 nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_DST, ipv6_dst);
5f568d04 2764 nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_SRC, ipv6_src);
f98e418f 2765 }
49a7961f 2766 if (tos_mask) {
dd83253e 2767 nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TOS, tos);
49a7961f 2768 nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TOS_MASK, tos_mask);
dd83253e 2769 }
49a7961f 2770 if (ttl_mask) {
dd83253e 2771 nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TTL, ttl);
49a7961f 2772 nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TTL_MASK, ttl_mask);
dd83253e 2773 }
1fe42975 2774 if (tp_dst) {
e48f49e0
EB
2775 nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, tp_dst);
2776 }
0227bf09
AN
2777 if (id_mask) {
2778 nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_KEY_ID, id);
2779 }
a468645c
PJV
2780 nl_msg_put_flower_tunnel_opts(request, TCA_FLOWER_KEY_ENC_OPTS,
2781 flower->key.tunnel.metadata);
2782 nl_msg_put_flower_tunnel_opts(request, TCA_FLOWER_KEY_ENC_OPTS_MASK,
2783 flower->mask.tunnel.metadata);
f98e418f
RD
2784}
2785
bb170644
PB
2786#define FLOWER_PUT_MASKED_VALUE(member, type) \
2787 nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \
2788 &flower->mask.member, sizeof flower->key.member)
2789
8ada482b 2790static int
f98e418f
RD
2791nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)
2792{
8ada482b 2793
f98e418f 2794 uint16_t host_eth_type = ntohs(flower->key.eth_type);
b5ad40a9 2795 bool is_vlan = eth_type_vlan(flower->key.eth_type);
f9885dc5 2796 bool is_qinq = is_vlan && eth_type_vlan(flower->key.encap_eth_type[0]);
34b16955 2797 bool is_mpls = eth_type_mpls(flower->key.eth_type);
d5659751 2798 enum tc_offload_policy policy = flower->tc_policy;
8ada482b
PB
2799 int err;
2800
d6118e62
PB
2801 /* need to parse acts first as some acts require changing the matching
2802 * see csum_update_flag() */
8ada482b
PB
2803 err = nl_msg_put_flower_acts(request, flower);
2804 if (err) {
2805 return err;
2806 }
f98e418f
RD
2807
2808 if (is_vlan) {
f9885dc5
JL
2809 if (is_qinq) {
2810 host_eth_type = ntohs(flower->key.encap_eth_type[1]);
2811 } else {
2812 host_eth_type = ntohs(flower->key.encap_eth_type[0]);
2813 }
f98e418f
RD
2814 }
2815
34b16955
PJV
2816 if (is_mpls) {
2817 host_eth_type = ntohs(flower->key.encap_eth_type[0]);
2818 }
2819
bb170644
PB
2820 FLOWER_PUT_MASKED_VALUE(dst_mac, TCA_FLOWER_KEY_ETH_DST);
2821 FLOWER_PUT_MASKED_VALUE(src_mac, TCA_FLOWER_KEY_ETH_SRC);
f98e418f 2822
a3db6e47
TZ
2823 if (host_eth_type == ETH_P_ARP) {
2824 FLOWER_PUT_MASKED_VALUE(arp.spa, TCA_FLOWER_KEY_ARP_SIP);
2825 FLOWER_PUT_MASKED_VALUE(arp.tpa, TCA_FLOWER_KEY_ARP_TIP);
2826 FLOWER_PUT_MASKED_VALUE(arp.sha, TCA_FLOWER_KEY_ARP_SHA);
2827 FLOWER_PUT_MASKED_VALUE(arp.tha, TCA_FLOWER_KEY_ARP_THA);
2828 FLOWER_PUT_MASKED_VALUE(arp.opcode, TCA_FLOWER_KEY_ARP_OP);
2829 }
2830
f98e418f 2831 if (host_eth_type == ETH_P_IP || host_eth_type == ETH_P_IPV6) {
b4496fc9 2832 FLOWER_PUT_MASKED_VALUE(ip_ttl, TCA_FLOWER_KEY_IP_TTL);
dfa2ccdb 2833 FLOWER_PUT_MASKED_VALUE(ip_tos, TCA_FLOWER_KEY_IP_TOS);
b4496fc9 2834
f98e418f
RD
2835 if (flower->mask.ip_proto && flower->key.ip_proto) {
2836 nl_msg_put_u8(request, TCA_FLOWER_KEY_IP_PROTO,
2837 flower->key.ip_proto);
2838 }
2839
83e86606 2840 if (flower->mask.flags) {
7e0f69b5 2841 nl_msg_put_be32(request, TCA_FLOWER_KEY_FLAGS,
83e86606 2842 htonl(flower->key.flags));
7e0f69b5 2843 nl_msg_put_be32(request, TCA_FLOWER_KEY_FLAGS_MASK,
83e86606
RD
2844 htonl(flower->mask.flags));
2845 }
2846
f98e418f 2847 if (flower->key.ip_proto == IPPROTO_UDP) {
2b1d9fa9
PB
2848 FLOWER_PUT_MASKED_VALUE(udp_src, TCA_FLOWER_KEY_UDP_SRC);
2849 FLOWER_PUT_MASKED_VALUE(udp_dst, TCA_FLOWER_KEY_UDP_DST);
f98e418f 2850 } else if (flower->key.ip_proto == IPPROTO_TCP) {
2b1d9fa9
PB
2851 FLOWER_PUT_MASKED_VALUE(tcp_src, TCA_FLOWER_KEY_TCP_SRC);
2852 FLOWER_PUT_MASKED_VALUE(tcp_dst, TCA_FLOWER_KEY_TCP_DST);
cd081043 2853 FLOWER_PUT_MASKED_VALUE(tcp_flags, TCA_FLOWER_KEY_TCP_FLAGS);
4862b4e5 2854 } else if (flower->key.ip_proto == IPPROTO_SCTP) {
2b1d9fa9
PB
2855 FLOWER_PUT_MASKED_VALUE(sctp_src, TCA_FLOWER_KEY_SCTP_SRC);
2856 FLOWER_PUT_MASKED_VALUE(sctp_dst, TCA_FLOWER_KEY_SCTP_DST);
75e1e6fd
MD
2857 } else if (flower->key.ip_proto == IPPROTO_ICMP) {
2858 FLOWER_PUT_MASKED_VALUE(icmp_code, TCA_FLOWER_KEY_ICMPV4_CODE);
2859 FLOWER_PUT_MASKED_VALUE(icmp_type, TCA_FLOWER_KEY_ICMPV4_TYPE);
2860 } else if (flower->key.ip_proto == IPPROTO_ICMPV6) {
2861 FLOWER_PUT_MASKED_VALUE(icmp_code, TCA_FLOWER_KEY_ICMPV6_CODE);
2862 FLOWER_PUT_MASKED_VALUE(icmp_type, TCA_FLOWER_KEY_ICMPV6_TYPE);
f98e418f 2863 }
576126a9
PB
2864
2865 FLOWER_PUT_MASKED_VALUE(ct_state, TCA_FLOWER_KEY_CT_STATE);
2866 FLOWER_PUT_MASKED_VALUE(ct_zone, TCA_FLOWER_KEY_CT_ZONE);
9221c721
PB
2867 FLOWER_PUT_MASKED_VALUE(ct_mark, TCA_FLOWER_KEY_CT_MARK);
2868 FLOWER_PUT_MASKED_VALUE(ct_label, TCA_FLOWER_KEY_CT_LABELS);
f98e418f
RD
2869 }
2870
2871 if (host_eth_type == ETH_P_IP) {
bb170644
PB
2872 FLOWER_PUT_MASKED_VALUE(ipv4.ipv4_src, TCA_FLOWER_KEY_IPV4_SRC);
2873 FLOWER_PUT_MASKED_VALUE(ipv4.ipv4_dst, TCA_FLOWER_KEY_IPV4_DST);
f98e418f 2874 } else if (host_eth_type == ETH_P_IPV6) {
bb170644
PB
2875 FLOWER_PUT_MASKED_VALUE(ipv6.ipv6_src, TCA_FLOWER_KEY_IPV6_SRC);
2876 FLOWER_PUT_MASKED_VALUE(ipv6.ipv6_dst, TCA_FLOWER_KEY_IPV6_DST);
f98e418f
RD
2877 }
2878
2879 nl_msg_put_be16(request, TCA_FLOWER_KEY_ETH_TYPE, flower->key.eth_type);
2880
34b16955
PJV
2881 if (is_mpls) {
2882 if (mpls_lse_to_ttl(flower->mask.mpls_lse)) {
2883 nl_msg_put_u8(request, TCA_FLOWER_KEY_MPLS_TTL,
2884 mpls_lse_to_ttl(flower->key.mpls_lse));
2885 }
2886 if (mpls_lse_to_tc(flower->mask.mpls_lse)) {
2887 nl_msg_put_u8(request, TCA_FLOWER_KEY_MPLS_TC,
2888 mpls_lse_to_tc(flower->key.mpls_lse));
2889 }
2890 if (mpls_lse_to_bos(flower->mask.mpls_lse)) {
2891 nl_msg_put_u8(request, TCA_FLOWER_KEY_MPLS_BOS,
2892 mpls_lse_to_bos(flower->key.mpls_lse));
2893 }
2894 if (mpls_lse_to_label(flower->mask.mpls_lse)) {
2895 nl_msg_put_u32(request, TCA_FLOWER_KEY_MPLS_LABEL,
2896 mpls_lse_to_label(flower->key.mpls_lse));
2897 }
2898 }
2899
f98e418f 2900 if (is_vlan) {
7f02f26c 2901 if (flower->mask.vlan_id[0]) {
f98e418f 2902 nl_msg_put_u16(request, TCA_FLOWER_KEY_VLAN_ID,
f9885dc5 2903 flower->key.vlan_id[0]);
7f02f26c
PJV
2904 }
2905 if (flower->mask.vlan_prio[0]) {
f98e418f 2906 nl_msg_put_u8(request, TCA_FLOWER_KEY_VLAN_PRIO,
f9885dc5 2907 flower->key.vlan_prio[0]);
f98e418f 2908 }
f9885dc5 2909 if (flower->key.encap_eth_type[0]) {
f98e418f 2910 nl_msg_put_be16(request, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
f9885dc5
JL
2911 flower->key.encap_eth_type[0]);
2912 }
2913
2914 if (is_qinq) {
7f02f26c 2915 if (flower->mask.vlan_id[1]) {
f9885dc5
JL
2916 nl_msg_put_u16(request, TCA_FLOWER_KEY_CVLAN_ID,
2917 flower->key.vlan_id[1]);
7f02f26c
PJV
2918 }
2919 if (flower->mask.vlan_prio[1]) {
f9885dc5
JL
2920 nl_msg_put_u8(request, TCA_FLOWER_KEY_CVLAN_PRIO,
2921 flower->key.vlan_prio[1]);
2922 }
2923 if (flower->key.encap_eth_type[1]) {
2924 nl_msg_put_be16(request, TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
2925 flower->key.encap_eth_type[1]);
2926 }
f98e418f
RD
2927 }
2928 }
2929
d5659751
RD
2930 if (policy == TC_POLICY_NONE) {
2931 policy = tc_policy;
2932 }
2933
2934 nl_msg_put_u32(request, TCA_FLOWER_FLAGS, tc_get_tc_cls_policy(policy));
f98e418f 2935
105e8179 2936 if (flower->tunnel) {
f98e418f
RD
2937 nl_msg_put_flower_tunnel(request, flower);
2938 }
2939
8ada482b 2940 return 0;
f98e418f
RD
2941}
2942
2943int
acdd544c 2944tc_replace_flower(struct tcf_id *id, struct tc_flower *flower)
f98e418f
RD
2945{
2946 struct ofpbuf request;
f98e418f
RD
2947 struct ofpbuf *reply;
2948 int error = 0;
2949 size_t basic_offset;
2950 uint16_t eth_type = (OVS_FORCE uint16_t) flower->key.eth_type;
2951
acdd544c
PB
2952 request_from_tcf_id(id, eth_type, RTM_NEWTFILTER,
2953 NLM_F_CREATE | NLM_F_ECHO, &request);
f98e418f
RD
2954
2955 nl_msg_put_string(&request, TCA_KIND, "flower");
2956 basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
2957 {
8ada482b
PB
2958 error = nl_msg_put_flower_options(&request, flower);
2959
2960 if (error) {
2961 ofpbuf_uninit(&request);
2962 return error;
2963 }
f98e418f
RD
2964 }
2965 nl_msg_end_nested(&request, basic_offset);
2966
2967 error = tc_transact(&request, &reply);
2968 if (!error) {
2969 struct tcmsg *tc =
2970 ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tc);
2971
acdd544c
PB
2972 id->prio = tc_get_major(tc->tcm_info);
2973 id->handle = tc->tcm_handle;
f98e418f
RD
2974 ofpbuf_delete(reply);
2975 }
2976
2977 return error;
2978}
691d20cb
PB
2979
2980void
2981tc_set_policy(const char *policy)
2982{
2983 if (!policy) {
2984 return;
2985 }
2986
2987 if (!strcmp(policy, "skip_sw")) {
2988 tc_policy = TC_POLICY_SKIP_SW;
2989 } else if (!strcmp(policy, "skip_hw")) {
2990 tc_policy = TC_POLICY_SKIP_HW;
2991 } else if (!strcmp(policy, "none")) {
2992 tc_policy = TC_POLICY_NONE;
2993 } else {
2994 VLOG_WARN("tc: Invalid policy '%s'", policy);
2995 return;
2996 }
2997
2998 VLOG_INFO("tc: Using policy '%s'", policy);
2999}