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