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