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