2 * Copyright (c) 2009-2017 Nicira, Inc.
3 * Copyright (c) 2016 Mellanox Technologies, Ltd.
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include <linux/if_ether.h>
23 #include <linux/if_packet.h>
24 #include <linux/rtnetlink.h>
25 #include <linux/tc_act/tc_csum.h>
26 #include <linux/tc_act/tc_gact.h>
27 #include <linux/tc_act/tc_mirred.h>
28 #include <linux/tc_act/tc_mpls.h>
29 #include <linux/tc_act/tc_pedit.h>
30 #include <linux/tc_act/tc_skbedit.h>
31 #include <linux/tc_act/tc_tunnel_key.h>
32 #include <linux/tc_act/tc_vlan.h>
33 #include <linux/tc_act/tc_ct.h>
34 #include <linux/gen_stats.h>
38 #include "byte-order.h"
39 #include "netlink-socket.h"
41 #include "openvswitch/ofpbuf.h"
42 #include "openvswitch/util.h"
43 #include "openvswitch/vlog.h"
46 #include "unaligned.h"
48 #define MAX_PEDIT_OFFSETS 32
50 #ifndef TCM_IFINDEX_MAGIC_BLOCK
51 #define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
54 #ifndef TCA_DUMP_FLAGS_TERSE
55 #define TCA_DUMP_FLAGS_TERSE (1 << 0)
60 #define TCA_INGRESS_BLOCK 13
61 #define TCA_DUMP_FLAGS 15
64 VLOG_DEFINE_THIS_MODULE(tc
);
66 static struct vlog_rate_limit error_rl
= VLOG_RATE_LIMIT_INIT(60, 5);
68 static enum tc_offload_policy tc_policy
= TC_POLICY_NONE
;
70 struct tc_pedit_key_ex
{
71 enum pedit_header_type htype
;
75 struct flower_key_to_pedit
{
76 enum pedit_header_type htype
;
83 static struct flower_key_to_pedit flower_pedit_map
[] = {
85 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
87 offsetof(struct tc_flower_key
, ipv4
.ipv4_src
),
88 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.ipv4_src
),
91 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
93 offsetof(struct tc_flower_key
, ipv4
.ipv4_dst
),
94 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.ipv4_dst
),
97 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
99 offsetof(struct tc_flower_key
, ipv4
.rewrite_ttl
),
100 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.rewrite_ttl
),
103 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
105 offsetof(struct tc_flower_key
, ipv4
.rewrite_tos
),
106 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.rewrite_tos
),
109 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
111 offsetof(struct tc_flower_key
, ipv6
.rewrite_hlimit
),
112 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.rewrite_hlimit
),
115 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
117 offsetof(struct tc_flower_key
, ipv6
.ipv6_src
),
118 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.ipv6_src
),
121 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
123 offsetof(struct tc_flower_key
, ipv6
.ipv6_dst
),
124 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.ipv6_dst
),
127 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
129 offsetof(struct tc_flower_key
, ipv6
.rewrite_tclass
),
130 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.rewrite_tclass
),
133 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
135 offsetof(struct tc_flower_key
, src_mac
),
136 MEMBER_SIZEOF(struct tc_flower_key
, src_mac
),
139 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
141 offsetof(struct tc_flower_key
, dst_mac
),
142 MEMBER_SIZEOF(struct tc_flower_key
, dst_mac
),
145 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
147 offsetof(struct tc_flower_key
, eth_type
),
148 MEMBER_SIZEOF(struct tc_flower_key
, eth_type
),
151 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
,
153 offsetof(struct tc_flower_key
, tcp_src
),
154 MEMBER_SIZEOF(struct tc_flower_key
, tcp_src
),
157 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
,
159 offsetof(struct tc_flower_key
, tcp_dst
),
160 MEMBER_SIZEOF(struct tc_flower_key
, tcp_dst
),
163 TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
,
165 offsetof(struct tc_flower_key
, udp_src
),
166 MEMBER_SIZEOF(struct tc_flower_key
, udp_src
),
169 TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
,
171 offsetof(struct tc_flower_key
, udp_dst
),
172 MEMBER_SIZEOF(struct tc_flower_key
, udp_dst
),
178 csum_update_flag(struct tc_flower
*flower
,
179 enum pedit_header_type htype
);
182 tc_make_request(int ifindex
, int type
, unsigned int flags
,
183 struct ofpbuf
*request
)
187 ofpbuf_init(request
, 512);
188 nl_msg_put_nlmsghdr(request
, sizeof *tcmsg
, type
, NLM_F_REQUEST
| flags
);
189 tcmsg
= ofpbuf_put_zeros(request
, sizeof *tcmsg
);
190 tcmsg
->tcm_family
= AF_UNSPEC
;
191 tcmsg
->tcm_ifindex
= ifindex
;
192 /* Caller should fill in tcmsg->tcm_handle. */
193 /* Caller should fill in tcmsg->tcm_parent. */
198 static void request_from_tcf_id(struct tcf_id
*id
, uint16_t eth_type
,
199 int type
, unsigned int flags
,
200 struct ofpbuf
*request
)
202 int ifindex
= id
->block_id
? TCM_IFINDEX_MAGIC_BLOCK
: id
->ifindex
;
203 uint32_t ingress_parent
= id
->block_id
? : TC_INGRESS_PARENT
;
206 tcmsg
= tc_make_request(ifindex
, type
, flags
, request
);
207 tcmsg
->tcm_parent
= (id
->hook
== TC_EGRESS
) ?
208 TC_EGRESS_PARENT
: ingress_parent
;
209 tcmsg
->tcm_info
= tc_make_handle(id
->prio
, eth_type
);
210 tcmsg
->tcm_handle
= id
->handle
;
213 nl_msg_put_u32(request
, TCA_CHAIN
, id
->chain
);
218 tc_transact(struct ofpbuf
*request
, struct ofpbuf
**replyp
)
220 int error
= nl_transact(NETLINK_ROUTE
, request
, replyp
);
221 ofpbuf_uninit(request
);
225 /* Adds or deletes a root qdisc on device with specified ifindex.
227 * The tc_qdisc_hook parameter determines if the qdisc is added on device
230 * If tc_qdisc_hook is TC_INGRESS, this function is equivalent to running the
231 * following when 'add' is true:
232 * /sbin/tc qdisc add dev <devname> handle ffff: ingress
234 * This function is equivalent to running the following when 'add' is false:
235 * /sbin/tc qdisc del dev <devname> handle ffff: ingress
237 * If tc_qdisc_hook is TC_EGRESS, this function is equivalent to:
238 * /sbin/tc qdisc (add|del) dev <devname> handle ffff: clsact
240 * Where dev <devname> is the device with specified ifindex name.
242 * The configuration and stats may be seen with the following command:
243 * /sbin/tc -s qdisc show dev <devname>
245 * If block_id is greater than 0, then the ingress qdisc is added to a block.
246 * In this case, it is equivalent to running (when 'add' is true):
247 * /sbin/tc qdisc add dev <devname> ingress_block <block_id> ingress
249 * Returns 0 if successful, otherwise a positive errno value.
252 tc_add_del_qdisc(int ifindex
, bool add
, uint32_t block_id
,
253 enum tc_qdisc_hook hook
)
255 struct ofpbuf request
;
258 int type
= add
? RTM_NEWQDISC
: RTM_DELQDISC
;
259 int flags
= add
? NLM_F_EXCL
| NLM_F_CREATE
: 0;
261 tcmsg
= tc_make_request(ifindex
, type
, flags
, &request
);
263 if (hook
== TC_EGRESS
) {
264 tcmsg
->tcm_handle
= TC_H_MAKE(TC_H_CLSACT
, 0);
265 tcmsg
->tcm_parent
= TC_H_CLSACT
;
266 nl_msg_put_string(&request
, TCA_KIND
, "clsact");
268 tcmsg
->tcm_handle
= TC_H_MAKE(TC_H_INGRESS
, 0);
269 tcmsg
->tcm_parent
= TC_H_INGRESS
;
270 nl_msg_put_string(&request
, TCA_KIND
, "ingress");
273 nl_msg_put_unspec(&request
, TCA_OPTIONS
, NULL
, 0);
274 if (hook
== TC_INGRESS
&& block_id
) {
275 nl_msg_put_u32(&request
, TCA_INGRESS_BLOCK
, block_id
);
278 error
= tc_transact(&request
, NULL
);
280 /* If we're deleting the qdisc, don't worry about some of the
281 * error conditions. */
282 if (!add
&& (error
== ENOENT
|| error
== EINVAL
)) {
291 static const struct nl_policy tca_policy
[] = {
292 [TCA_KIND
] = { .type
= NL_A_STRING
, .optional
= false, },
293 [TCA_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= false, },
294 [TCA_CHAIN
] = { .type
= NL_A_U32
, .optional
= true, },
295 [TCA_STATS
] = { .type
= NL_A_UNSPEC
,
296 .min_len
= sizeof(struct tc_stats
), .optional
= true, },
297 [TCA_STATS2
] = { .type
= NL_A_NESTED
, .optional
= true, },
300 static const struct nl_policy tca_flower_policy
[] = {
301 [TCA_FLOWER_CLASSID
] = { .type
= NL_A_U32
, .optional
= true, },
302 [TCA_FLOWER_INDEV
] = { .type
= NL_A_STRING
, .max_len
= IFNAMSIZ
,
304 [TCA_FLOWER_KEY_ETH_SRC
] = { .type
= NL_A_UNSPEC
,
305 .min_len
= ETH_ALEN
, .optional
= true, },
306 [TCA_FLOWER_KEY_ETH_DST
] = { .type
= NL_A_UNSPEC
,
307 .min_len
= ETH_ALEN
, .optional
= true, },
308 [TCA_FLOWER_KEY_ETH_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
311 [TCA_FLOWER_KEY_ETH_DST_MASK
] = { .type
= NL_A_UNSPEC
,
314 [TCA_FLOWER_KEY_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= false, },
315 [TCA_FLOWER_KEY_ARP_SIP
] = { .type
= NL_A_U32
, .optional
= true, },
316 [TCA_FLOWER_KEY_ARP_TIP
] = { .type
= NL_A_U32
, .optional
= true, },
317 [TCA_FLOWER_KEY_ARP_SHA
] = { .type
= NL_A_UNSPEC
,
320 [TCA_FLOWER_KEY_ARP_THA
] = { .type
= NL_A_UNSPEC
,
323 [TCA_FLOWER_KEY_ARP_OP
] = { .type
= NL_A_U8
, .optional
= true, },
324 [TCA_FLOWER_KEY_ARP_SIP_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
325 [TCA_FLOWER_KEY_ARP_TIP_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
326 [TCA_FLOWER_KEY_ARP_SHA_MASK
] = { .type
= NL_A_UNSPEC
,
329 [TCA_FLOWER_KEY_ARP_THA_MASK
] = { .type
= NL_A_UNSPEC
,
332 [TCA_FLOWER_KEY_ARP_OP_MASK
] = { .type
= NL_A_U8
, .optional
= true, },
333 [TCA_FLOWER_FLAGS
] = { .type
= NL_A_U32
, .optional
= false, },
334 [TCA_FLOWER_ACT
] = { .type
= NL_A_NESTED
, .optional
= false, },
335 [TCA_FLOWER_KEY_IP_PROTO
] = { .type
= NL_A_U8
, .optional
= true, },
336 [TCA_FLOWER_KEY_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
337 [TCA_FLOWER_KEY_IPV4_DST
] = {.type
= NL_A_U32
, .optional
= true, },
338 [TCA_FLOWER_KEY_IPV4_SRC_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
339 [TCA_FLOWER_KEY_IPV4_DST_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
340 [TCA_FLOWER_KEY_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
341 .min_len
= sizeof(struct in6_addr
),
343 [TCA_FLOWER_KEY_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
344 .min_len
= sizeof(struct in6_addr
),
346 [TCA_FLOWER_KEY_IPV6_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
347 .min_len
= sizeof(struct in6_addr
),
349 [TCA_FLOWER_KEY_IPV6_DST_MASK
] = { .type
= NL_A_UNSPEC
,
350 .min_len
= sizeof(struct in6_addr
),
352 [TCA_FLOWER_KEY_TCP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
353 [TCA_FLOWER_KEY_TCP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
354 [TCA_FLOWER_KEY_TCP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
355 [TCA_FLOWER_KEY_TCP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
356 [TCA_FLOWER_KEY_UDP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
357 [TCA_FLOWER_KEY_UDP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
358 [TCA_FLOWER_KEY_UDP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
359 [TCA_FLOWER_KEY_UDP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
360 [TCA_FLOWER_KEY_SCTP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
361 [TCA_FLOWER_KEY_SCTP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
362 [TCA_FLOWER_KEY_SCTP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
363 [TCA_FLOWER_KEY_SCTP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
364 [TCA_FLOWER_KEY_MPLS_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
365 [TCA_FLOWER_KEY_MPLS_TC
] = { .type
= NL_A_U8
, .optional
= true, },
366 [TCA_FLOWER_KEY_MPLS_BOS
] = { .type
= NL_A_U8
, .optional
= true, },
367 [TCA_FLOWER_KEY_MPLS_LABEL
] = { .type
= NL_A_U32
, .optional
= true, },
368 [TCA_FLOWER_KEY_VLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
369 [TCA_FLOWER_KEY_VLAN_PRIO
] = { .type
= NL_A_U8
, .optional
= true, },
370 [TCA_FLOWER_KEY_VLAN_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= true, },
371 [TCA_FLOWER_KEY_ENC_KEY_ID
] = { .type
= NL_A_U32
, .optional
= true, },
372 [TCA_FLOWER_KEY_ENC_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
373 [TCA_FLOWER_KEY_ENC_IPV4_DST
] = { .type
= NL_A_U32
, .optional
= true, },
374 [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
] = { .type
= NL_A_U32
,
376 [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
] = { .type
= NL_A_U32
,
378 [TCA_FLOWER_KEY_ENC_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
379 .min_len
= sizeof(struct in6_addr
),
381 [TCA_FLOWER_KEY_ENC_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
382 .min_len
= sizeof(struct in6_addr
),
384 [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
385 .min_len
= sizeof(struct in6_addr
),
387 [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
] = { .type
= NL_A_UNSPEC
,
388 .min_len
= sizeof(struct in6_addr
),
390 [TCA_FLOWER_KEY_ENC_UDP_DST_PORT
] = { .type
= NL_A_U16
,
392 [TCA_FLOWER_KEY_FLAGS
] = { .type
= NL_A_BE32
, .optional
= true, },
393 [TCA_FLOWER_KEY_FLAGS_MASK
] = { .type
= NL_A_BE32
, .optional
= true, },
394 [TCA_FLOWER_KEY_IP_TTL
] = { .type
= NL_A_U8
,
396 [TCA_FLOWER_KEY_IP_TTL_MASK
] = { .type
= NL_A_U8
,
398 [TCA_FLOWER_KEY_IP_TOS
] = { .type
= NL_A_U8
,
400 [TCA_FLOWER_KEY_IP_TOS_MASK
] = { .type
= NL_A_U8
,
402 [TCA_FLOWER_KEY_TCP_FLAGS
] = { .type
= NL_A_U16
,
404 [TCA_FLOWER_KEY_TCP_FLAGS_MASK
] = { .type
= NL_A_U16
,
406 [TCA_FLOWER_KEY_CVLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
407 [TCA_FLOWER_KEY_CVLAN_PRIO
] = { .type
= NL_A_U8
, .optional
= true, },
408 [TCA_FLOWER_KEY_CVLAN_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= true, },
409 [TCA_FLOWER_KEY_ENC_IP_TOS
] = { .type
= NL_A_U8
,
411 [TCA_FLOWER_KEY_ENC_IP_TOS_MASK
] = { .type
= NL_A_U8
,
413 [TCA_FLOWER_KEY_ENC_IP_TTL
] = { .type
= NL_A_U8
,
415 [TCA_FLOWER_KEY_ENC_IP_TTL_MASK
] = { .type
= NL_A_U8
,
417 [TCA_FLOWER_KEY_ENC_OPTS
] = { .type
= NL_A_NESTED
, .optional
= true, },
418 [TCA_FLOWER_KEY_ENC_OPTS_MASK
] = { .type
= NL_A_NESTED
,
420 [TCA_FLOWER_KEY_CT_STATE
] = { .type
= NL_A_U16
, .optional
= true, },
421 [TCA_FLOWER_KEY_CT_STATE_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
422 [TCA_FLOWER_KEY_CT_ZONE
] = { .type
= NL_A_U16
, .optional
= true, },
423 [TCA_FLOWER_KEY_CT_ZONE_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
424 [TCA_FLOWER_KEY_CT_MARK
] = { .type
= NL_A_U32
, .optional
= true, },
425 [TCA_FLOWER_KEY_CT_MARK_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
426 [TCA_FLOWER_KEY_CT_LABELS
] = { .type
= NL_A_U128
, .optional
= true, },
427 [TCA_FLOWER_KEY_CT_LABELS_MASK
] = { .type
= NL_A_U128
,
431 static const struct nl_policy tca_flower_terse_policy
[] = {
432 [TCA_FLOWER_FLAGS
] = { .type
= NL_A_U32
, .optional
= false, },
433 [TCA_FLOWER_ACT
] = { .type
= NL_A_NESTED
, .optional
= false, },
437 nl_parse_flower_arp(struct nlattr
**attrs
, struct tc_flower
*flower
)
439 const struct eth_addr
*eth
;
441 if (attrs
[TCA_FLOWER_KEY_ARP_SIP_MASK
]) {
442 flower
->key
.arp
.spa
=
443 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ARP_SIP
]);
444 flower
->mask
.arp
.spa
=
445 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ARP_SIP_MASK
]);
447 if (attrs
[TCA_FLOWER_KEY_ARP_TIP_MASK
]) {
448 flower
->key
.arp
.tpa
=
449 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ARP_TIP
]);
450 flower
->mask
.arp
.tpa
=
451 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ARP_TIP_MASK
]);
453 if (attrs
[TCA_FLOWER_KEY_ARP_SHA_MASK
]) {
454 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ARP_SHA
], ETH_ALEN
);
455 memcpy(&flower
->key
.arp
.sha
, eth
, sizeof flower
->key
.arp
.sha
);
457 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ARP_SHA_MASK
], ETH_ALEN
);
458 memcpy(&flower
->mask
.arp
.sha
, eth
, sizeof flower
->mask
.arp
.sha
);
460 if (attrs
[TCA_FLOWER_KEY_ARP_THA_MASK
]) {
461 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ARP_THA
], ETH_ALEN
);
462 memcpy(&flower
->key
.arp
.tha
, eth
, sizeof flower
->key
.arp
.tha
);
464 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ARP_THA_MASK
], ETH_ALEN
);
465 memcpy(&flower
->mask
.arp
.tha
, eth
, sizeof flower
->mask
.arp
.tha
);
467 if (attrs
[TCA_FLOWER_KEY_ARP_OP_MASK
]) {
468 flower
->key
.arp
.opcode
=
469 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ARP_OP
]);
470 flower
->mask
.arp
.opcode
=
471 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ARP_OP_MASK
]);
476 nl_parse_flower_eth(struct nlattr
**attrs
, struct tc_flower
*flower
)
478 const struct eth_addr
*eth
;
480 if (attrs
[TCA_FLOWER_KEY_ETH_SRC_MASK
]) {
481 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_SRC
], ETH_ALEN
);
482 memcpy(&flower
->key
.src_mac
, eth
, sizeof flower
->key
.src_mac
);
484 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_SRC_MASK
], ETH_ALEN
);
485 memcpy(&flower
->mask
.src_mac
, eth
, sizeof flower
->mask
.src_mac
);
487 if (attrs
[TCA_FLOWER_KEY_ETH_DST_MASK
]) {
488 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_DST
], ETH_ALEN
);
489 memcpy(&flower
->key
.dst_mac
, eth
, sizeof flower
->key
.dst_mac
);
491 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_DST_MASK
], ETH_ALEN
);
492 memcpy(&flower
->mask
.dst_mac
, eth
, sizeof flower
->mask
.dst_mac
);
497 nl_parse_flower_mpls(struct nlattr
**attrs
, struct tc_flower
*flower
)
499 uint8_t ttl
, tc
, bos
;
502 if (!eth_type_mpls(flower
->key
.eth_type
)) {
506 flower
->key
.encap_eth_type
[0] =
507 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ETH_TYPE
]);
508 flower
->key
.mpls_lse
= 0;
509 flower
->mask
.mpls_lse
= 0;
511 if (attrs
[TCA_FLOWER_KEY_MPLS_TTL
]) {
512 ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_MPLS_TTL
]);
513 set_mpls_lse_ttl(&flower
->key
.mpls_lse
, ttl
);
514 set_mpls_lse_ttl(&flower
->mask
.mpls_lse
, 0xff);
517 if (attrs
[TCA_FLOWER_KEY_MPLS_BOS
]) {
518 bos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_MPLS_BOS
]);
519 set_mpls_lse_bos(&flower
->key
.mpls_lse
, bos
);
520 set_mpls_lse_ttl(&flower
->mask
.mpls_lse
, 0xff);
523 if (attrs
[TCA_FLOWER_KEY_MPLS_TC
]) {
524 tc
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_MPLS_TC
]);
525 set_mpls_lse_tc(&flower
->key
.mpls_lse
, tc
);
526 set_mpls_lse_tc(&flower
->mask
.mpls_lse
, 0xff);
529 if (attrs
[TCA_FLOWER_KEY_MPLS_LABEL
]) {
530 label
= nl_attr_get_u32(attrs
[TCA_FLOWER_KEY_MPLS_LABEL
]);
531 set_mpls_lse_label(&flower
->key
.mpls_lse
, htonl(label
));
532 set_mpls_lse_label(&flower
->mask
.mpls_lse
, OVS_BE32_MAX
);
537 nl_parse_flower_vlan(struct nlattr
**attrs
, struct tc_flower
*flower
)
539 ovs_be16 encap_ethtype
;
541 if (!eth_type_vlan(flower
->key
.eth_type
)) {
545 flower
->key
.encap_eth_type
[0] =
546 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ETH_TYPE
]);
548 if (attrs
[TCA_FLOWER_KEY_VLAN_ID
]) {
549 flower
->key
.vlan_id
[0] =
550 nl_attr_get_u16(attrs
[TCA_FLOWER_KEY_VLAN_ID
]);
551 flower
->mask
.vlan_id
[0] = 0xffff;
553 if (attrs
[TCA_FLOWER_KEY_VLAN_PRIO
]) {
554 flower
->key
.vlan_prio
[0] =
555 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_VLAN_PRIO
]);
556 flower
->mask
.vlan_prio
[0] = 0xff;
559 if (!attrs
[TCA_FLOWER_KEY_VLAN_ETH_TYPE
]) {
563 encap_ethtype
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_VLAN_ETH_TYPE
]);
564 if (!eth_type_vlan(encap_ethtype
)) {
568 flower
->key
.encap_eth_type
[1] = flower
->key
.encap_eth_type
[0];
569 flower
->key
.encap_eth_type
[0] = encap_ethtype
;
571 if (attrs
[TCA_FLOWER_KEY_CVLAN_ID
]) {
572 flower
->key
.vlan_id
[1] =
573 nl_attr_get_u16(attrs
[TCA_FLOWER_KEY_CVLAN_ID
]);
574 flower
->mask
.vlan_id
[1] = 0xffff;
576 if (attrs
[TCA_FLOWER_KEY_CVLAN_PRIO
]) {
577 flower
->key
.vlan_prio
[1] =
578 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_CVLAN_PRIO
]);
579 flower
->mask
.vlan_prio
[1] = 0xff;
584 nl_parse_geneve_key(const struct nlattr
*in_nlattr
,
585 struct tun_metadata
*metadata
)
587 struct geneve_opt
*opt
= NULL
;
588 const struct ofpbuf
*msg
;
589 uint16_t last_opt_type
;
595 nl_attr_get_nested(in_nlattr
, &buf
);
598 last_opt_type
= TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC
;
600 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
601 uint16_t type
= nl_attr_type(nla
);
604 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
:
605 if (cnt
&& last_opt_type
!= TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
) {
606 VLOG_ERR_RL(&error_rl
, "failed to parse tun options class");
610 opt
= &metadata
->opts
.gnv
[cnt
];
611 opt
->opt_class
= nl_attr_get_be16(nla
);
612 cnt
+= sizeof(struct geneve_opt
) / 4;
613 metadata
->present
.len
+= sizeof(struct geneve_opt
);
614 last_opt_type
= TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
;
616 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
:
617 if (last_opt_type
!= TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
) {
618 VLOG_ERR_RL(&error_rl
, "failed to parse tun options type");
622 opt
->type
= nl_attr_get_u8(nla
);
623 last_opt_type
= TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
;
625 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
:
626 if (last_opt_type
!= TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
) {
627 VLOG_ERR_RL(&error_rl
, "failed to parse tun options data");
631 opt
->length
= nl_attr_get_size(nla
) / 4;
632 memcpy(opt
+ 1, nl_attr_get_unspec(nla
, 1), opt
->length
* 4);
634 metadata
->present
.len
+= opt
->length
* 4;
635 last_opt_type
= TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
;
640 if (last_opt_type
!= TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
) {
641 VLOG_ERR_RL(&error_rl
, "failed to parse tun options without data");
649 nl_parse_flower_tunnel_opts(struct nlattr
*options
,
650 struct tun_metadata
*metadata
)
652 const struct ofpbuf
*msg
;
658 nl_attr_get_nested(options
, &buf
);
661 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
662 uint16_t type
= nl_attr_type(nla
);
664 case TCA_FLOWER_KEY_ENC_OPTS_GENEVE
:
665 err
= nl_parse_geneve_key(nla
, metadata
);
678 flower_tun_geneve_opt_check_len(struct tun_metadata
*key
,
679 struct tun_metadata
*mask
)
681 const struct geneve_opt
*opt
, *opt_mask
;
684 len
= key
->present
.len
;
686 opt
= &key
->opts
.gnv
[cnt
];
687 opt_mask
= &mask
->opts
.gnv
[cnt
];
689 if (opt
->length
!= opt_mask
->length
) {
690 VLOG_ERR_RL(&error_rl
,
691 "failed to parse tun options; key/mask length differ");
695 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
696 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
703 nl_parse_flower_tunnel(struct nlattr
**attrs
, struct tc_flower
*flower
)
707 if (attrs
[TCA_FLOWER_KEY_ENC_KEY_ID
]) {
708 ovs_be32 id
= nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_KEY_ID
]);
710 flower
->key
.tunnel
.id
= be32_to_be64(id
);
711 flower
->mask
.tunnel
.id
= OVS_BE64_MAX
;
713 if (attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
]) {
714 flower
->mask
.tunnel
.ipv4
.ipv4_src
=
715 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
]);
716 flower
->key
.tunnel
.ipv4
.ipv4_src
=
717 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC
]);
719 if (attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
]) {
720 flower
->mask
.tunnel
.ipv4
.ipv4_dst
=
721 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
]);
722 flower
->key
.tunnel
.ipv4
.ipv4_dst
=
723 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST
]);
725 if (attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
]) {
726 flower
->mask
.tunnel
.ipv6
.ipv6_src
=
727 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
]);
728 flower
->key
.tunnel
.ipv6
.ipv6_src
=
729 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC
]);
731 if (attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
]) {
732 flower
->mask
.tunnel
.ipv6
.ipv6_dst
=
733 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
]);
734 flower
->key
.tunnel
.ipv6
.ipv6_dst
=
735 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST
]);
737 if (attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]) {
738 flower
->key
.tunnel
.tp_dst
=
739 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]);
741 if (attrs
[TCA_FLOWER_KEY_ENC_IP_TOS_MASK
]) {
742 flower
->key
.tunnel
.tos
=
743 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TOS
]);
744 flower
->mask
.tunnel
.tos
=
745 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TOS_MASK
]);
747 if (attrs
[TCA_FLOWER_KEY_ENC_IP_TTL_MASK
]) {
748 flower
->key
.tunnel
.ttl
=
749 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TTL
]);
750 flower
->mask
.tunnel
.ttl
=
751 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TTL_MASK
]);
754 if (!is_all_zeros(&flower
->mask
.tunnel
, sizeof flower
->mask
.tunnel
) ||
755 !is_all_zeros(&flower
->key
.tunnel
, sizeof flower
->key
.tunnel
)) {
756 flower
->tunnel
= true;
759 if (attrs
[TCA_FLOWER_KEY_ENC_OPTS
] &&
760 attrs
[TCA_FLOWER_KEY_ENC_OPTS_MASK
]) {
761 err
= nl_parse_flower_tunnel_opts(attrs
[TCA_FLOWER_KEY_ENC_OPTS
],
762 &flower
->key
.tunnel
.metadata
);
767 err
= nl_parse_flower_tunnel_opts(attrs
[TCA_FLOWER_KEY_ENC_OPTS_MASK
],
768 &flower
->mask
.tunnel
.metadata
);
773 err
= flower_tun_geneve_opt_check_len(&flower
->key
.tunnel
.metadata
,
774 &flower
->mask
.tunnel
.metadata
);
778 } else if (attrs
[TCA_FLOWER_KEY_ENC_OPTS
]) {
779 VLOG_ERR_RL(&error_rl
,
780 "failed to parse tun options; no mask supplied");
782 } else if (attrs
[TCA_FLOWER_KEY_ENC_OPTS_MASK
]) {
783 VLOG_ERR_RL(&error_rl
, "failed to parse tun options; no key supplied");
791 nl_parse_flower_ct_match(struct nlattr
**attrs
, struct tc_flower
*flower
) {
792 struct tc_flower_key
*key
= &flower
->key
;
793 struct tc_flower_key
*mask
= &flower
->mask
;
794 struct nlattr
*attr_key
, *attr_mask
;
796 attr_key
= attrs
[TCA_FLOWER_KEY_CT_STATE
];
797 attr_mask
= attrs
[TCA_FLOWER_KEY_CT_STATE_MASK
];
799 key
->ct_state
= nl_attr_get_u16(attr_key
);
800 mask
->ct_state
= nl_attr_get_u16(attr_mask
);
803 attr_key
= attrs
[TCA_FLOWER_KEY_CT_ZONE
];
804 attr_mask
= attrs
[TCA_FLOWER_KEY_CT_ZONE_MASK
];
805 if (attrs
[TCA_FLOWER_KEY_CT_ZONE_MASK
]) {
806 key
->ct_zone
= nl_attr_get_u16(attr_key
);
807 mask
->ct_zone
= nl_attr_get_u16(attr_mask
);
810 attr_key
= attrs
[TCA_FLOWER_KEY_CT_MARK
];
811 attr_mask
= attrs
[TCA_FLOWER_KEY_CT_MARK_MASK
];
812 if (attrs
[TCA_FLOWER_KEY_CT_MARK_MASK
]) {
813 key
->ct_mark
= nl_attr_get_u32(attr_key
);
814 mask
->ct_mark
= nl_attr_get_u32(attr_mask
);
817 attr_key
= attrs
[TCA_FLOWER_KEY_CT_LABELS
];
818 attr_mask
= attrs
[TCA_FLOWER_KEY_CT_LABELS_MASK
];
819 if (attrs
[TCA_FLOWER_KEY_CT_LABELS_MASK
]) {
820 key
->ct_label
= nl_attr_get_u128(attr_key
);
821 mask
->ct_label
= nl_attr_get_u128(attr_mask
);
826 nl_parse_flower_ip(struct nlattr
**attrs
, struct tc_flower
*flower
) {
827 uint8_t ip_proto
= 0;
828 struct tc_flower_key
*key
= &flower
->key
;
829 struct tc_flower_key
*mask
= &flower
->mask
;
831 if (attrs
[TCA_FLOWER_KEY_IP_PROTO
]) {
832 ip_proto
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_PROTO
]);
833 key
->ip_proto
= ip_proto
;
834 mask
->ip_proto
= UINT8_MAX
;
837 if (attrs
[TCA_FLOWER_KEY_FLAGS_MASK
]) {
838 key
->flags
= ntohl(nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_FLAGS
]));
840 ntohl(nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_FLAGS_MASK
]));
843 if (attrs
[TCA_FLOWER_KEY_IPV4_SRC_MASK
]) {
845 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_SRC
]);
846 mask
->ipv4
.ipv4_src
=
847 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_SRC_MASK
]);
849 if (attrs
[TCA_FLOWER_KEY_IPV4_DST_MASK
]) {
851 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_DST
]);
852 mask
->ipv4
.ipv4_dst
=
853 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_DST_MASK
]);
855 if (attrs
[TCA_FLOWER_KEY_IPV6_SRC_MASK
]) {
856 struct nlattr
*attr
= attrs
[TCA_FLOWER_KEY_IPV6_SRC
];
857 struct nlattr
*attr_mask
= attrs
[TCA_FLOWER_KEY_IPV6_SRC_MASK
];
859 key
->ipv6
.ipv6_src
= nl_attr_get_in6_addr(attr
);
860 mask
->ipv6
.ipv6_src
= nl_attr_get_in6_addr(attr_mask
);
862 if (attrs
[TCA_FLOWER_KEY_IPV6_DST_MASK
]) {
863 struct nlattr
*attr
= attrs
[TCA_FLOWER_KEY_IPV6_DST
];
864 struct nlattr
*attr_mask
= attrs
[TCA_FLOWER_KEY_IPV6_DST_MASK
];
866 key
->ipv6
.ipv6_dst
= nl_attr_get_in6_addr(attr
);
867 mask
->ipv6
.ipv6_dst
= nl_attr_get_in6_addr(attr_mask
);
870 if (ip_proto
== IPPROTO_TCP
) {
871 if (attrs
[TCA_FLOWER_KEY_TCP_SRC_MASK
]) {
873 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_SRC
]);
875 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_SRC_MASK
]);
877 if (attrs
[TCA_FLOWER_KEY_TCP_DST_MASK
]) {
879 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_DST
]);
881 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_DST_MASK
]);
883 if (attrs
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]) {
885 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_FLAGS
]);
887 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]);
889 } else if (ip_proto
== IPPROTO_UDP
) {
890 if (attrs
[TCA_FLOWER_KEY_UDP_SRC_MASK
]) {
891 key
->udp_src
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_SRC
]);
893 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_SRC_MASK
]);
895 if (attrs
[TCA_FLOWER_KEY_UDP_DST_MASK
]) {
896 key
->udp_dst
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_DST
]);
898 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_DST_MASK
]);
900 } else if (ip_proto
== IPPROTO_SCTP
) {
901 if (attrs
[TCA_FLOWER_KEY_SCTP_SRC_MASK
]) {
902 key
->sctp_src
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_SRC
]);
904 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_SRC_MASK
]);
906 if (attrs
[TCA_FLOWER_KEY_SCTP_DST_MASK
]) {
907 key
->sctp_dst
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_DST
]);
909 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_DST_MASK
]);
913 if (attrs
[TCA_FLOWER_KEY_IP_TTL_MASK
]) {
914 key
->ip_ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TTL
]);
915 mask
->ip_ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TTL_MASK
]);
918 if (attrs
[TCA_FLOWER_KEY_IP_TOS_MASK
]) {
919 key
->ip_tos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TOS
]);
920 mask
->ip_tos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TOS_MASK
]);
923 nl_parse_flower_ct_match(attrs
, flower
);
926 static enum tc_offloaded_state
927 nl_get_flower_offloaded_state(struct nlattr
**attrs
)
929 uint32_t flower_flags
= 0;
931 if (attrs
[TCA_FLOWER_FLAGS
]) {
932 flower_flags
= nl_attr_get_u32(attrs
[TCA_FLOWER_FLAGS
]);
933 if (flower_flags
& TCA_CLS_FLAGS_NOT_IN_HW
) {
934 return TC_OFFLOADED_STATE_NOT_IN_HW
;
935 } else if (flower_flags
& TCA_CLS_FLAGS_IN_HW
) {
936 return TC_OFFLOADED_STATE_IN_HW
;
939 return TC_OFFLOADED_STATE_UNDEFINED
;
943 nl_parse_flower_flags(struct nlattr
**attrs
, struct tc_flower
*flower
)
945 flower
->offloaded_state
= nl_get_flower_offloaded_state(attrs
);
948 static const struct nl_policy pedit_policy
[] = {
949 [TCA_PEDIT_PARMS_EX
] = { .type
= NL_A_UNSPEC
,
950 .min_len
= sizeof(struct tc_pedit
),
951 .optional
= false, },
952 [TCA_PEDIT_KEYS_EX
] = { .type
= NL_A_NESTED
,
953 .optional
= false, },
957 nl_parse_act_pedit(struct nlattr
*options
, struct tc_flower
*flower
)
959 struct tc_action
*action
;
960 struct nlattr
*pe_attrs
[ARRAY_SIZE(pedit_policy
)];
961 const struct tc_pedit
*pe
;
962 const struct tc_pedit_key
*keys
;
963 const struct nlattr
*nla
, *keys_ex
, *ex_type
;
964 const void *keys_attr
;
965 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
966 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
967 size_t keys_ex_size
, left
;
968 int type
, i
= 0, err
;
970 if (!nl_parse_nested(options
, pedit_policy
, pe_attrs
,
971 ARRAY_SIZE(pedit_policy
))) {
972 VLOG_ERR_RL(&error_rl
, "failed to parse pedit action options");
976 pe
= nl_attr_get_unspec(pe_attrs
[TCA_PEDIT_PARMS_EX
], sizeof *pe
);
978 keys_attr
= pe_attrs
[TCA_PEDIT_KEYS_EX
];
979 keys_ex
= nl_attr_get(keys_attr
);
980 keys_ex_size
= nl_attr_get_size(keys_attr
);
982 NL_ATTR_FOR_EACH (nla
, left
, keys_ex
, keys_ex_size
) {
983 if (i
>= pe
->nkeys
) {
987 if (nl_attr_type(nla
) != TCA_PEDIT_KEY_EX
) {
988 VLOG_ERR_RL(&error_rl
, "unable to parse legacy pedit type: %d",
993 ex_type
= nl_attr_find_nested(nla
, TCA_PEDIT_KEY_EX_HTYPE
);
994 type
= nl_attr_get_u16(ex_type
);
996 err
= csum_update_flag(flower
, type
);
1001 for (int j
= 0; j
< ARRAY_SIZE(flower_pedit_map
); j
++) {
1002 struct flower_key_to_pedit
*m
= &flower_pedit_map
[j
];
1003 int flower_off
= m
->flower_offset
;
1007 if (m
->htype
!= type
) {
1011 /* check overlap between current pedit key, which is always
1012 * 4 bytes (range [off, off + 3]), and a map entry in
1013 * flower_pedit_map (range [mf, mf + sz - 1]) */
1014 if ((keys
->off
>= mf
&& keys
->off
< mf
+ sz
)
1015 || (keys
->off
+ 3 >= mf
&& keys
->off
+ 3 < mf
+ sz
)) {
1016 int diff
= flower_off
+ (keys
->off
- mf
);
1017 ovs_be32
*dst
= (void *) (rewrite_key
+ diff
);
1018 ovs_be32
*dst_m
= (void *) (rewrite_mask
+ diff
);
1019 ovs_be32 mask
, mask_word
, data_word
;
1022 mask_word
= htonl(ntohl(keys
->mask
) << m
->boundary_shift
);
1023 data_word
= htonl(ntohl(keys
->val
) << m
->boundary_shift
);
1024 mask
= ~(mask_word
);
1026 if (keys
->off
< mf
) {
1027 zero_bits
= 8 * (mf
- keys
->off
);
1028 mask
&= htonl(UINT32_MAX
>> zero_bits
);
1029 } else if (keys
->off
+ 4 > mf
+ m
->size
) {
1030 zero_bits
= 8 * (keys
->off
+ 4 - mf
- m
->size
);
1031 mask
&= htonl(UINT32_MAX
<< zero_bits
);
1035 *dst
|= data_word
& mask
;
1043 action
= &flower
->actions
[flower
->action_count
++];
1044 action
->type
= TC_ACT_PEDIT
;
1049 static const struct nl_policy tunnel_key_policy
[] = {
1050 [TCA_TUNNEL_KEY_PARMS
] = { .type
= NL_A_UNSPEC
,
1051 .min_len
= sizeof(struct tc_tunnel_key
),
1052 .optional
= false, },
1053 [TCA_TUNNEL_KEY_ENC_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
1054 [TCA_TUNNEL_KEY_ENC_IPV4_DST
] = { .type
= NL_A_U32
, .optional
= true, },
1055 [TCA_TUNNEL_KEY_ENC_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
1056 .min_len
= sizeof(struct in6_addr
),
1057 .optional
= true, },
1058 [TCA_TUNNEL_KEY_ENC_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
1059 .min_len
= sizeof(struct in6_addr
),
1060 .optional
= true, },
1061 [TCA_TUNNEL_KEY_ENC_KEY_ID
] = { .type
= NL_A_U32
, .optional
= true, },
1062 [TCA_TUNNEL_KEY_ENC_DST_PORT
] = { .type
= NL_A_U16
, .optional
= true, },
1063 [TCA_TUNNEL_KEY_ENC_TOS
] = { .type
= NL_A_U8
, .optional
= true, },
1064 [TCA_TUNNEL_KEY_ENC_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
1065 [TCA_TUNNEL_KEY_ENC_OPTS
] = { .type
= NL_A_NESTED
, .optional
= true, },
1066 [TCA_TUNNEL_KEY_NO_CSUM
] = { .type
= NL_A_U8
, .optional
= true, },
1070 nl_parse_act_geneve_opts(const struct nlattr
*in_nlattr
,
1071 struct tc_action
*action
)
1073 struct geneve_opt
*opt
= NULL
;
1074 const struct ofpbuf
*msg
;
1075 uint16_t last_opt_type
;
1081 nl_attr_get_nested(in_nlattr
, &buf
);
1084 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_UNSPEC
;
1086 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
1087 uint16_t type
= nl_attr_type(nla
);
1090 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
:
1091 if (cnt
&& last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
) {
1092 VLOG_ERR_RL(&error_rl
,
1093 "failed to parse action geneve options class");
1097 opt
= &action
->encap
.data
.opts
.gnv
[cnt
];
1098 opt
->opt_class
= nl_attr_get_be16(nla
);
1099 cnt
+= sizeof(struct geneve_opt
) / 4;
1100 action
->encap
.data
.present
.len
+= sizeof(struct geneve_opt
);
1101 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
;
1103 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
:
1104 if (last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
) {
1105 VLOG_ERR_RL(&error_rl
,
1106 "failed to parse action geneve options type");
1110 opt
->type
= nl_attr_get_u8(nla
);
1111 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
;
1113 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
:
1114 if (last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
) {
1115 VLOG_ERR_RL(&error_rl
,
1116 "failed to parse action geneve options data");
1120 opt
->length
= nl_attr_get_size(nla
) / 4;
1121 memcpy(opt
+ 1, nl_attr_get_unspec(nla
, 1), opt
->length
* 4);
1123 action
->encap
.data
.present
.len
+= opt
->length
* 4;
1124 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
;
1129 if (last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
) {
1130 VLOG_ERR_RL(&error_rl
,
1131 "failed to parse action geneve options without data");
1139 nl_parse_act_tunnel_opts(struct nlattr
*options
, struct tc_action
*action
)
1141 const struct ofpbuf
*msg
;
1151 nl_attr_get_nested(options
, &buf
);
1154 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
1155 uint16_t type
= nl_attr_type(nla
);
1157 case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
:
1158 err
= nl_parse_act_geneve_opts(nla
, action
);
1171 nl_parse_act_tunnel_key(struct nlattr
*options
, struct tc_flower
*flower
)
1173 struct nlattr
*tun_attrs
[ARRAY_SIZE(tunnel_key_policy
)];
1174 const struct nlattr
*tun_parms
;
1175 const struct tc_tunnel_key
*tun
;
1176 struct tc_action
*action
;
1179 if (!nl_parse_nested(options
, tunnel_key_policy
, tun_attrs
,
1180 ARRAY_SIZE(tunnel_key_policy
))) {
1181 VLOG_ERR_RL(&error_rl
, "failed to parse tunnel_key action options");
1185 tun_parms
= tun_attrs
[TCA_TUNNEL_KEY_PARMS
];
1186 tun
= nl_attr_get_unspec(tun_parms
, sizeof *tun
);
1187 if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_SET
) {
1188 struct nlattr
*id
= tun_attrs
[TCA_TUNNEL_KEY_ENC_KEY_ID
];
1189 struct nlattr
*dst_port
= tun_attrs
[TCA_TUNNEL_KEY_ENC_DST_PORT
];
1190 struct nlattr
*ipv4_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_SRC
];
1191 struct nlattr
*ipv4_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_DST
];
1192 struct nlattr
*ipv6_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_SRC
];
1193 struct nlattr
*ipv6_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_DST
];
1194 struct nlattr
*tos
= tun_attrs
[TCA_TUNNEL_KEY_ENC_TOS
];
1195 struct nlattr
*ttl
= tun_attrs
[TCA_TUNNEL_KEY_ENC_TTL
];
1196 struct nlattr
*tun_opt
= tun_attrs
[TCA_TUNNEL_KEY_ENC_OPTS
];
1197 struct nlattr
*no_csum
= tun_attrs
[TCA_TUNNEL_KEY_NO_CSUM
];
1199 action
= &flower
->actions
[flower
->action_count
++];
1200 action
->type
= TC_ACT_ENCAP
;
1201 action
->encap
.ipv4
.ipv4_src
= ipv4_src
? nl_attr_get_be32(ipv4_src
) : 0;
1202 action
->encap
.ipv4
.ipv4_dst
= ipv4_dst
? nl_attr_get_be32(ipv4_dst
) : 0;
1204 action
->encap
.ipv6
.ipv6_src
= nl_attr_get_in6_addr(ipv6_src
);
1207 action
->encap
.ipv6
.ipv6_dst
= nl_attr_get_in6_addr(ipv6_dst
);
1209 action
->encap
.id
= id
? be32_to_be64(nl_attr_get_be32(id
)) : 0;
1210 action
->encap
.id_present
= id
? true : false;
1211 action
->encap
.tp_dst
= dst_port
? nl_attr_get_be16(dst_port
) : 0;
1212 action
->encap
.tos
= tos
? nl_attr_get_u8(tos
) : 0;
1213 action
->encap
.ttl
= ttl
? nl_attr_get_u8(ttl
) : 0;
1214 action
->encap
.no_csum
= no_csum
? nl_attr_get_u8(no_csum
) : 0;
1216 err
= nl_parse_act_tunnel_opts(tun_opt
, action
);
1220 } else if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_RELEASE
) {
1221 flower
->tunnel
= true;
1223 VLOG_ERR_RL(&error_rl
, "unknown tunnel actions: %d, %d",
1224 tun
->action
, tun
->t_action
);
1230 static const struct nl_policy gact_policy
[] = {
1231 [TCA_GACT_PARMS
] = { .type
= NL_A_UNSPEC
,
1232 .min_len
= sizeof(struct tc_gact
),
1233 .optional
= false, },
1234 [TCA_GACT_TM
] = { .type
= NL_A_UNSPEC
,
1235 .min_len
= sizeof(struct tcf_t
),
1236 .optional
= false, },
1242 static struct ovsthread_once once
= OVSTHREAD_ONCE_INITIALIZER
;
1243 static int user_hz
= 100;
1245 if (ovsthread_once_start(&once
)) {
1246 user_hz
= sysconf(_SC_CLK_TCK
);
1247 ovsthread_once_done(&once
);
1254 nl_parse_tcf(const struct tcf_t
*tm
, struct tc_flower
*flower
)
1256 flower
->lastused
= time_msec() - (tm
->lastuse
* 1000 / get_user_hz());
1260 nl_parse_act_gact(struct nlattr
*options
, struct tc_flower
*flower
)
1262 struct nlattr
*gact_attrs
[ARRAY_SIZE(gact_policy
)];
1263 const struct tc_gact
*p
;
1264 struct nlattr
*gact_parms
;
1265 const struct tcf_t
*tm
;
1266 struct tc_action
*action
;
1268 if (!nl_parse_nested(options
, gact_policy
, gact_attrs
,
1269 ARRAY_SIZE(gact_policy
))) {
1270 VLOG_ERR_RL(&error_rl
, "failed to parse gact action options");
1274 gact_parms
= gact_attrs
[TCA_GACT_PARMS
];
1275 p
= nl_attr_get_unspec(gact_parms
, sizeof *p
);
1277 if (TC_ACT_EXT_CMP(p
->action
, TC_ACT_GOTO_CHAIN
)) {
1278 action
= &flower
->actions
[flower
->action_count
++];
1279 action
->chain
= p
->action
& TC_ACT_EXT_VAL_MASK
;
1280 action
->type
= TC_ACT_GOTO
;
1281 } else if (p
->action
!= TC_ACT_SHOT
) {
1282 VLOG_ERR_RL(&error_rl
, "unknown gact action: %d", p
->action
);
1286 tm
= nl_attr_get_unspec(gact_attrs
[TCA_GACT_TM
], sizeof *tm
);
1287 nl_parse_tcf(tm
, flower
);
1292 static const struct nl_policy mirred_policy
[] = {
1293 [TCA_MIRRED_PARMS
] = { .type
= NL_A_UNSPEC
,
1294 .min_len
= sizeof(struct tc_mirred
),
1295 .optional
= false, },
1296 [TCA_MIRRED_TM
] = { .type
= NL_A_UNSPEC
,
1297 .min_len
= sizeof(struct tcf_t
),
1298 .optional
= false, },
1302 nl_parse_act_mirred(struct nlattr
*options
, struct tc_flower
*flower
)
1305 struct nlattr
*mirred_attrs
[ARRAY_SIZE(mirred_policy
)];
1306 const struct tc_mirred
*m
;
1307 const struct nlattr
*mirred_parms
;
1308 const struct tcf_t
*tm
;
1309 struct nlattr
*mirred_tm
;
1310 struct tc_action
*action
;
1312 if (!nl_parse_nested(options
, mirred_policy
, mirred_attrs
,
1313 ARRAY_SIZE(mirred_policy
))) {
1314 VLOG_ERR_RL(&error_rl
, "failed to parse mirred action options");
1318 mirred_parms
= mirred_attrs
[TCA_MIRRED_PARMS
];
1319 m
= nl_attr_get_unspec(mirred_parms
, sizeof *m
);
1321 if (m
->eaction
!= TCA_EGRESS_REDIR
&& m
->eaction
!= TCA_EGRESS_MIRROR
&&
1322 m
->eaction
!= TCA_INGRESS_REDIR
&& m
->eaction
!= TCA_INGRESS_MIRROR
) {
1323 VLOG_ERR_RL(&error_rl
, "unknown mirred action: %d, %d, %d",
1324 m
->action
, m
->eaction
, m
->ifindex
);
1328 action
= &flower
->actions
[flower
->action_count
++];
1329 action
->out
.ifindex_out
= m
->ifindex
;
1330 if (m
->eaction
== TCA_INGRESS_REDIR
|| m
->eaction
== TCA_INGRESS_MIRROR
) {
1331 action
->out
.ingress
= true;
1333 action
->out
.ingress
= false;
1335 action
->type
= TC_ACT_OUTPUT
;
1337 mirred_tm
= mirred_attrs
[TCA_MIRRED_TM
];
1338 tm
= nl_attr_get_unspec(mirred_tm
, sizeof *tm
);
1339 nl_parse_tcf(tm
, flower
);
1344 static const struct nl_policy ct_policy
[] = {
1345 [TCA_CT_PARMS
] = { .type
= NL_A_UNSPEC
,
1346 .min_len
= sizeof(struct tc_ct
),
1347 .optional
= false, },
1348 [TCA_CT_ACTION
] = { .type
= NL_A_U16
,
1349 .optional
= true, },
1350 [TCA_CT_ZONE
] = { .type
= NL_A_U16
,
1351 .optional
= true, },
1352 [TCA_CT_MARK
] = { .type
= NL_A_U32
,
1353 .optional
= true, },
1354 [TCA_CT_MARK_MASK
] = { .type
= NL_A_U32
,
1355 .optional
= true, },
1356 [TCA_CT_LABELS
] = { .type
= NL_A_UNSPEC
,
1357 .optional
= true, },
1358 [TCA_CT_LABELS_MASK
] = { .type
= NL_A_UNSPEC
,
1359 .optional
= true, },
1360 [TCA_CT_NAT_IPV4_MIN
] = { .type
= NL_A_U32
,
1361 .optional
= true, },
1362 [TCA_CT_NAT_IPV4_MAX
] = { .type
= NL_A_U32
,
1363 .optional
= true, },
1364 [TCA_CT_NAT_IPV6_MIN
] = { .min_len
= sizeof(struct in6_addr
),
1365 .type
= NL_A_UNSPEC
,
1367 [TCA_CT_NAT_IPV6_MAX
] = { .min_len
= sizeof(struct in6_addr
),
1368 .type
= NL_A_UNSPEC
,
1370 [TCA_CT_NAT_PORT_MIN
] = { .type
= NL_A_U16
,
1371 .optional
= true, },
1372 [TCA_CT_NAT_PORT_MAX
] = { .type
= NL_A_U16
,
1373 .optional
= true, },
1377 nl_parse_act_ct(struct nlattr
*options
, struct tc_flower
*flower
)
1379 struct nlattr
*ct_attrs
[ARRAY_SIZE(ct_policy
)];
1380 const struct nlattr
*ct_parms
;
1381 struct tc_action
*action
;
1382 const struct tc_ct
*ct
;
1383 uint16_t ct_action
= 0;
1385 if (!nl_parse_nested(options
, ct_policy
, ct_attrs
,
1386 ARRAY_SIZE(ct_policy
))) {
1387 VLOG_ERR_RL(&error_rl
, "failed to parse ct action options");
1391 ct_parms
= ct_attrs
[TCA_CT_PARMS
];
1392 ct
= nl_attr_get_unspec(ct_parms
, sizeof *ct
);
1394 if (ct_attrs
[TCA_CT_ACTION
]) {
1395 ct_action
= nl_attr_get_u16(ct_attrs
[TCA_CT_ACTION
]);
1398 action
= &flower
->actions
[flower
->action_count
++];
1399 action
->ct
.clear
= ct_action
& TCA_CT_ACT_CLEAR
;
1400 if (!action
->ct
.clear
) {
1401 struct nlattr
*zone
= ct_attrs
[TCA_CT_ZONE
];
1402 struct nlattr
*mark
= ct_attrs
[TCA_CT_MARK
];
1403 struct nlattr
*mark_mask
= ct_attrs
[TCA_CT_MARK_MASK
];
1404 struct nlattr
*label
= ct_attrs
[TCA_CT_LABELS
];
1405 struct nlattr
*label_mask
= ct_attrs
[TCA_CT_LABELS_MASK
];
1407 action
->ct
.commit
= ct_action
& TCA_CT_ACT_COMMIT
;
1408 action
->ct
.force
= ct_action
& TCA_CT_ACT_FORCE
;
1410 action
->ct
.zone
= zone
? nl_attr_get_u16(zone
) : 0;
1411 action
->ct
.mark
= mark
? nl_attr_get_u32(mark
) : 0;
1412 action
->ct
.mark_mask
= mark_mask
? nl_attr_get_u32(mark_mask
) : 0;
1413 action
->ct
.label
= label
? nl_attr_get_u128(label
) : OVS_U128_ZERO
;
1414 action
->ct
.label_mask
= label_mask
?
1415 nl_attr_get_u128(label_mask
) : OVS_U128_ZERO
;
1417 if (ct_action
& TCA_CT_ACT_NAT
) {
1418 struct nlattr
*ipv4_min
= ct_attrs
[TCA_CT_NAT_IPV4_MIN
];
1419 struct nlattr
*ipv4_max
= ct_attrs
[TCA_CT_NAT_IPV4_MAX
];
1420 struct nlattr
*ipv6_min
= ct_attrs
[TCA_CT_NAT_IPV6_MIN
];
1421 struct nlattr
*ipv6_max
= ct_attrs
[TCA_CT_NAT_IPV6_MAX
];
1422 struct nlattr
*port_min
= ct_attrs
[TCA_CT_NAT_PORT_MIN
];
1423 struct nlattr
*port_max
= ct_attrs
[TCA_CT_NAT_PORT_MAX
];
1425 action
->ct
.nat_type
= TC_NAT_RESTORE
;
1426 if (ct_action
& TCA_CT_ACT_NAT_SRC
) {
1427 action
->ct
.nat_type
= TC_NAT_SRC
;
1428 } else if (ct_action
& TCA_CT_ACT_NAT_DST
) {
1429 action
->ct
.nat_type
= TC_NAT_DST
;
1433 action
->ct
.range
.ip_family
= AF_INET
;
1434 action
->ct
.range
.ipv4
.min
= nl_attr_get_be32(ipv4_min
);
1436 ovs_be32 addr
= nl_attr_get_be32(ipv4_max
);
1438 action
->ct
.range
.ipv4
.max
= addr
;
1440 } else if (ipv6_min
) {
1441 action
->ct
.range
.ip_family
= AF_INET6
;
1442 action
->ct
.range
.ipv6
.min
1443 = nl_attr_get_in6_addr(ipv6_min
);
1445 struct in6_addr addr
= nl_attr_get_in6_addr(ipv6_max
);
1447 action
->ct
.range
.ipv6
.max
= addr
;
1452 action
->ct
.range
.port
.min
= nl_attr_get_be16(port_min
);
1454 action
->ct
.range
.port
.max
= nl_attr_get_be16(port_max
);
1459 action
->type
= TC_ACT_CT
;
1464 static const struct nl_policy vlan_policy
[] = {
1465 [TCA_VLAN_PARMS
] = { .type
= NL_A_UNSPEC
,
1466 .min_len
= sizeof(struct tc_vlan
),
1467 .optional
= false, },
1468 [TCA_VLAN_PUSH_VLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
1469 [TCA_VLAN_PUSH_VLAN_PROTOCOL
] = { .type
= NL_A_U16
, .optional
= true, },
1470 [TCA_VLAN_PUSH_VLAN_PRIORITY
] = { .type
= NL_A_U8
, .optional
= true, },
1474 nl_parse_act_vlan(struct nlattr
*options
, struct tc_flower
*flower
)
1476 struct nlattr
*vlan_attrs
[ARRAY_SIZE(vlan_policy
)];
1477 const struct tc_vlan
*v
;
1478 const struct nlattr
*vlan_parms
;
1479 struct tc_action
*action
;
1481 if (!nl_parse_nested(options
, vlan_policy
, vlan_attrs
,
1482 ARRAY_SIZE(vlan_policy
))) {
1483 VLOG_ERR_RL(&error_rl
, "failed to parse vlan action options");
1487 action
= &flower
->actions
[flower
->action_count
++];
1488 vlan_parms
= vlan_attrs
[TCA_VLAN_PARMS
];
1489 v
= nl_attr_get_unspec(vlan_parms
, sizeof *v
);
1490 if (v
->v_action
== TCA_VLAN_ACT_PUSH
) {
1491 struct nlattr
*vlan_tpid
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PROTOCOL
];
1492 struct nlattr
*vlan_id
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_ID
];
1493 struct nlattr
*vlan_prio
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PRIORITY
];
1495 action
->vlan
.vlan_push_tpid
= nl_attr_get_be16(vlan_tpid
);
1496 action
->vlan
.vlan_push_id
= nl_attr_get_u16(vlan_id
);
1497 action
->vlan
.vlan_push_prio
= vlan_prio
? nl_attr_get_u8(vlan_prio
) : 0;
1498 action
->type
= TC_ACT_VLAN_PUSH
;
1499 } else if (v
->v_action
== TCA_VLAN_ACT_POP
) {
1500 action
->type
= TC_ACT_VLAN_POP
;
1502 VLOG_ERR_RL(&error_rl
, "unknown vlan action: %d, %d",
1503 v
->action
, v
->v_action
);
1509 static const struct nl_policy mpls_policy
[] = {
1510 [TCA_MPLS_PARMS
] = { .type
= NL_A_UNSPEC
,
1511 .min_len
= sizeof(struct tc_mpls
),
1512 .optional
= false, },
1513 [TCA_MPLS_PROTO
] = { .type
= NL_A_U16
, .optional
= true, },
1514 [TCA_MPLS_LABEL
] = { .type
= NL_A_U32
, .optional
= true, },
1515 [TCA_MPLS_TC
] = { .type
= NL_A_U8
, .optional
= true, },
1516 [TCA_MPLS_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
1517 [TCA_MPLS_BOS
] = { .type
= NL_A_U8
, .optional
= true, },
1521 nl_parse_act_mpls(struct nlattr
*options
, struct tc_flower
*flower
)
1523 struct nlattr
*mpls_attrs
[ARRAY_SIZE(mpls_policy
)];
1524 const struct nlattr
*mpls_parms
;
1525 struct nlattr
*mpls_proto
;
1526 struct nlattr
*mpls_label
;
1527 struct tc_action
*action
;
1528 const struct tc_mpls
*m
;
1529 struct nlattr
*mpls_ttl
;
1530 struct nlattr
*mpls_bos
;
1531 struct nlattr
*mpls_tc
;
1533 if (!nl_parse_nested(options
, mpls_policy
, mpls_attrs
,
1534 ARRAY_SIZE(mpls_policy
))) {
1535 VLOG_ERR_RL(&error_rl
, "failed to parse mpls action options");
1539 action
= &flower
->actions
[flower
->action_count
++];
1540 mpls_parms
= mpls_attrs
[TCA_MPLS_PARMS
];
1541 m
= nl_attr_get_unspec(mpls_parms
, sizeof *m
);
1543 switch (m
->m_action
) {
1544 case TCA_MPLS_ACT_POP
:
1545 mpls_proto
= mpls_attrs
[TCA_MPLS_PROTO
];
1547 action
->mpls
.proto
= nl_attr_get_be16(mpls_proto
);
1549 action
->type
= TC_ACT_MPLS_POP
;
1551 case TCA_MPLS_ACT_PUSH
:
1552 mpls_proto
= mpls_attrs
[TCA_MPLS_PROTO
];
1554 action
->mpls
.proto
= nl_attr_get_be16(mpls_proto
);
1556 mpls_label
= mpls_attrs
[TCA_MPLS_LABEL
];
1558 action
->mpls
.label
= nl_attr_get_u32(mpls_label
);
1560 mpls_tc
= mpls_attrs
[TCA_MPLS_TC
];
1562 action
->mpls
.tc
= nl_attr_get_u8(mpls_tc
);
1564 mpls_ttl
= mpls_attrs
[TCA_MPLS_TTL
];
1566 action
->mpls
.ttl
= nl_attr_get_u8(mpls_ttl
);
1568 mpls_bos
= mpls_attrs
[TCA_MPLS_BOS
];
1570 action
->mpls
.bos
= nl_attr_get_u8(mpls_bos
);
1572 action
->type
= TC_ACT_MPLS_PUSH
;
1574 case TCA_MPLS_ACT_MODIFY
:
1575 mpls_label
= mpls_attrs
[TCA_MPLS_LABEL
];
1577 action
->mpls
.label
= nl_attr_get_u32(mpls_label
);
1579 mpls_tc
= mpls_attrs
[TCA_MPLS_TC
];
1581 action
->mpls
.tc
= nl_attr_get_u8(mpls_tc
);
1583 mpls_ttl
= mpls_attrs
[TCA_MPLS_TTL
];
1585 action
->mpls
.ttl
= nl_attr_get_u8(mpls_ttl
);
1587 mpls_bos
= mpls_attrs
[TCA_MPLS_BOS
];
1589 action
->mpls
.bos
= nl_attr_get_u8(mpls_bos
);
1591 action
->type
= TC_ACT_MPLS_SET
;
1594 VLOG_ERR_RL(&error_rl
, "unknown mpls action: %d, %d",
1595 m
->action
, m
->m_action
);
1602 static const struct nl_policy csum_policy
[] = {
1603 [TCA_CSUM_PARMS
] = { .type
= NL_A_UNSPEC
,
1604 .min_len
= sizeof(struct tc_csum
),
1605 .optional
= false, },
1609 nl_parse_act_csum(struct nlattr
*options
, struct tc_flower
*flower
)
1611 struct nlattr
*csum_attrs
[ARRAY_SIZE(csum_policy
)];
1612 const struct tc_csum
*c
;
1613 const struct nlattr
*csum_parms
;
1615 if (!nl_parse_nested(options
, csum_policy
, csum_attrs
,
1616 ARRAY_SIZE(csum_policy
))) {
1617 VLOG_ERR_RL(&error_rl
, "failed to parse csum action options");
1621 csum_parms
= csum_attrs
[TCA_CSUM_PARMS
];
1622 c
= nl_attr_get_unspec(csum_parms
, sizeof *c
);
1625 if (c
->update_flags
!= flower
->csum_update_flags
) {
1626 VLOG_WARN_RL(&error_rl
,
1627 "expected different act csum flags: 0x%x != 0x%x",
1628 flower
->csum_update_flags
, c
->update_flags
);
1631 flower
->csum_update_flags
= 0; /* so we know csum was handled */
1633 if (flower
->needs_full_ip_proto_mask
1634 && flower
->mask
.ip_proto
!= UINT8_MAX
) {
1635 VLOG_WARN_RL(&error_rl
, "expected full matching on flower ip_proto");
1642 static const struct nl_policy act_policy
[] = {
1643 [TCA_ACT_KIND
] = { .type
= NL_A_STRING
, .optional
= false, },
1644 [TCA_ACT_COOKIE
] = { .type
= NL_A_UNSPEC
, .optional
= true, },
1645 [TCA_ACT_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= true, },
1646 [TCA_ACT_STATS
] = { .type
= NL_A_NESTED
, .optional
= false, },
1649 static const struct nl_policy stats_policy
[] = {
1650 [TCA_STATS_BASIC
] = { .type
= NL_A_UNSPEC
,
1651 .min_len
= sizeof(struct gnet_stats_basic
),
1652 .optional
= false, },
1656 nl_parse_single_action(struct nlattr
*action
, struct tc_flower
*flower
,
1659 struct nlattr
*act_options
;
1660 struct nlattr
*act_stats
;
1661 struct nlattr
*act_cookie
;
1662 const char *act_kind
;
1663 struct nlattr
*action_attrs
[ARRAY_SIZE(act_policy
)];
1664 struct nlattr
*stats_attrs
[ARRAY_SIZE(stats_policy
)];
1665 struct ovs_flow_stats
*stats
= &flower
->stats
;
1666 const struct gnet_stats_basic
*bs
;
1669 if (!nl_parse_nested(action
, act_policy
, action_attrs
,
1670 ARRAY_SIZE(act_policy
)) ||
1671 (!terse
&& !action_attrs
[TCA_ACT_OPTIONS
])) {
1672 VLOG_ERR_RL(&error_rl
, "failed to parse single action options");
1676 act_kind
= nl_attr_get_string(action_attrs
[TCA_ACT_KIND
]);
1677 act_options
= action_attrs
[TCA_ACT_OPTIONS
];
1678 act_cookie
= action_attrs
[TCA_ACT_COOKIE
];
1681 /* Terse dump doesn't provide act options attribute. */
1682 } else if (!strcmp(act_kind
, "gact")) {
1683 err
= nl_parse_act_gact(act_options
, flower
);
1684 } else if (!strcmp(act_kind
, "mirred")) {
1685 err
= nl_parse_act_mirred(act_options
, flower
);
1686 } else if (!strcmp(act_kind
, "vlan")) {
1687 err
= nl_parse_act_vlan(act_options
, flower
);
1688 } else if (!strcmp(act_kind
, "mpls")) {
1689 err
= nl_parse_act_mpls(act_options
, flower
);
1690 } else if (!strcmp(act_kind
, "tunnel_key")) {
1691 err
= nl_parse_act_tunnel_key(act_options
, flower
);
1692 } else if (!strcmp(act_kind
, "pedit")) {
1693 err
= nl_parse_act_pedit(act_options
, flower
);
1694 } else if (!strcmp(act_kind
, "csum")) {
1695 nl_parse_act_csum(act_options
, flower
);
1696 } else if (!strcmp(act_kind
, "skbedit")) {
1697 /* Added for TC rule only (not in OvS rule) so ignore. */
1698 } else if (!strcmp(act_kind
, "ct")) {
1699 nl_parse_act_ct(act_options
, flower
);
1701 VLOG_ERR_RL(&error_rl
, "unknown tc action kind: %s", act_kind
);
1710 flower
->act_cookie
.data
= nl_attr_get(act_cookie
);
1711 flower
->act_cookie
.len
= nl_attr_get_size(act_cookie
);
1714 act_stats
= action_attrs
[TCA_ACT_STATS
];
1716 if (!nl_parse_nested(act_stats
, stats_policy
, stats_attrs
,
1717 ARRAY_SIZE(stats_policy
))) {
1718 VLOG_ERR_RL(&error_rl
, "failed to parse action stats policy");
1722 bs
= nl_attr_get_unspec(stats_attrs
[TCA_STATS_BASIC
], sizeof *bs
);
1724 put_32aligned_u64(&stats
->n_packets
, bs
->packets
);
1725 put_32aligned_u64(&stats
->n_bytes
, bs
->bytes
);
1731 #define TCA_ACT_MIN_PRIO 1
1734 nl_parse_flower_actions(struct nlattr
**attrs
, struct tc_flower
*flower
,
1737 const struct nlattr
*actions
= attrs
[TCA_FLOWER_ACT
];
1738 static struct nl_policy actions_orders_policy
[TCA_ACT_MAX_NUM
+ 1] = {};
1739 struct nlattr
*actions_orders
[ARRAY_SIZE(actions_orders_policy
)];
1740 const int max_size
= ARRAY_SIZE(actions_orders_policy
);
1742 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
1743 actions_orders_policy
[i
].type
= NL_A_NESTED
;
1744 actions_orders_policy
[i
].optional
= true;
1747 if (!nl_parse_nested(actions
, actions_orders_policy
, actions_orders
,
1748 ARRAY_SIZE(actions_orders_policy
))) {
1749 VLOG_ERR_RL(&error_rl
, "failed to parse flower order of actions");
1753 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
1754 if (actions_orders
[i
]) {
1757 if (flower
->action_count
>= TCA_ACT_MAX_NUM
) {
1758 VLOG_DBG_RL(&error_rl
, "Can only support %d actions", TCA_ACT_MAX_NUM
);
1761 err
= nl_parse_single_action(actions_orders
[i
], flower
, terse
);
1769 if (flower
->csum_update_flags
) {
1770 VLOG_WARN_RL(&error_rl
,
1771 "expected act csum with flags: 0x%x",
1772 flower
->csum_update_flags
);
1780 nl_parse_flower_options(struct nlattr
*nl_options
, struct tc_flower
*flower
,
1783 struct nlattr
*attrs
[ARRAY_SIZE(tca_flower_policy
)];
1787 if (!nl_parse_nested(nl_options
, tca_flower_terse_policy
,
1788 attrs
, ARRAY_SIZE(tca_flower_terse_policy
))) {
1789 VLOG_ERR_RL(&error_rl
, "failed to parse flower classifier terse options");
1792 goto skip_flower_opts
;
1795 if (!nl_parse_nested(nl_options
, tca_flower_policy
,
1796 attrs
, ARRAY_SIZE(tca_flower_policy
))) {
1797 VLOG_ERR_RL(&error_rl
, "failed to parse flower classifier options");
1801 nl_parse_flower_eth(attrs
, flower
);
1802 nl_parse_flower_arp(attrs
, flower
);
1803 nl_parse_flower_mpls(attrs
, flower
);
1804 nl_parse_flower_vlan(attrs
, flower
);
1805 nl_parse_flower_ip(attrs
, flower
);
1806 err
= nl_parse_flower_tunnel(attrs
, flower
);
1812 nl_parse_flower_flags(attrs
, flower
);
1813 return nl_parse_flower_actions(attrs
, flower
, terse
);
1817 parse_netlink_to_tc_flower(struct ofpbuf
*reply
, struct tcf_id
*id
,
1818 struct tc_flower
*flower
, bool terse
)
1821 struct nlattr
*ta
[ARRAY_SIZE(tca_policy
)];
1824 if (NLMSG_HDRLEN
+ sizeof *tc
> reply
->size
) {
1828 memset(flower
, 0, sizeof *flower
);
1830 tc
= ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
1832 flower
->key
.eth_type
= (OVS_FORCE ovs_be16
) tc_get_minor(tc
->tcm_info
);
1833 flower
->mask
.eth_type
= OVS_BE16_MAX
;
1834 id
->prio
= tc_get_major(tc
->tcm_info
);
1835 id
->handle
= tc
->tcm_handle
;
1837 if (id
->prio
== TC_RESERVED_PRIORITY_POLICE
) {
1845 if (!nl_policy_parse(reply
, NLMSG_HDRLEN
+ sizeof *tc
,
1846 tca_policy
, ta
, ARRAY_SIZE(ta
))) {
1847 VLOG_ERR_RL(&error_rl
, "failed to parse tca policy");
1851 if (ta
[TCA_CHAIN
]) {
1852 id
->chain
= nl_attr_get_u32(ta
[TCA_CHAIN
]);
1855 kind
= nl_attr_get_string(ta
[TCA_KIND
]);
1856 if (strcmp(kind
, "flower")) {
1857 VLOG_DBG_ONCE("Unsupported filter: %s", kind
);
1861 return nl_parse_flower_options(ta
[TCA_OPTIONS
], flower
, terse
);
1865 tc_dump_flower_start(struct tcf_id
*id
, struct nl_dump
*dump
, bool terse
)
1867 struct ofpbuf request
;
1869 request_from_tcf_id(id
, 0, RTM_GETTFILTER
, NLM_F_DUMP
, &request
);
1871 struct nla_bitfield32 dump_flags
= { TCA_DUMP_FLAGS_TERSE
,
1872 TCA_DUMP_FLAGS_TERSE
};
1874 nl_msg_put_unspec(&request
, TCA_DUMP_FLAGS
, &dump_flags
,
1877 nl_dump_start(dump
, NETLINK_ROUTE
, &request
);
1878 ofpbuf_uninit(&request
);
1884 tc_del_filter(struct tcf_id
*id
)
1886 struct ofpbuf request
;
1888 request_from_tcf_id(id
, 0, RTM_DELTFILTER
, NLM_F_ACK
, &request
);
1889 return tc_transact(&request
, NULL
);
1893 tc_get_flower(struct tcf_id
*id
, struct tc_flower
*flower
)
1895 struct ofpbuf request
;
1896 struct ofpbuf
*reply
;
1899 request_from_tcf_id(id
, 0, RTM_GETTFILTER
, NLM_F_ECHO
, &request
);
1900 error
= tc_transact(&request
, &reply
);
1905 error
= parse_netlink_to_tc_flower(reply
, id
, flower
, false);
1906 ofpbuf_delete(reply
);
1911 tc_get_tc_cls_policy(enum tc_offload_policy policy
)
1913 if (policy
== TC_POLICY_SKIP_HW
) {
1914 return TCA_CLS_FLAGS_SKIP_HW
;
1915 } else if (policy
== TC_POLICY_SKIP_SW
) {
1916 return TCA_CLS_FLAGS_SKIP_SW
;
1923 nl_msg_put_act_csum(struct ofpbuf
*request
, uint32_t flags
)
1927 nl_msg_put_string(request
, TCA_ACT_KIND
, "csum");
1928 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1930 struct tc_csum parm
= { .action
= TC_ACT_PIPE
,
1931 .update_flags
= flags
};
1933 nl_msg_put_unspec(request
, TCA_CSUM_PARMS
, &parm
, sizeof parm
);
1935 nl_msg_end_nested(request
, offset
);
1939 nl_msg_put_act_pedit(struct ofpbuf
*request
, struct tc_pedit
*parm
,
1940 struct tc_pedit_key_ex
*ex
)
1942 size_t ksize
= sizeof *parm
+ parm
->nkeys
* sizeof(struct tc_pedit_key
);
1943 size_t offset
, offset_keys_ex
, offset_key
;
1946 nl_msg_put_string(request
, TCA_ACT_KIND
, "pedit");
1947 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1949 parm
->action
= TC_ACT_PIPE
;
1951 nl_msg_put_unspec(request
, TCA_PEDIT_PARMS_EX
, parm
, ksize
);
1952 offset_keys_ex
= nl_msg_start_nested(request
, TCA_PEDIT_KEYS_EX
);
1953 for (i
= 0; i
< parm
->nkeys
; i
++, ex
++) {
1954 offset_key
= nl_msg_start_nested(request
, TCA_PEDIT_KEY_EX
);
1955 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_HTYPE
, ex
->htype
);
1956 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_CMD
, ex
->cmd
);
1957 nl_msg_end_nested(request
, offset_key
);
1959 nl_msg_end_nested(request
, offset_keys_ex
);
1961 nl_msg_end_nested(request
, offset
);
1965 nl_msg_put_act_push_vlan(struct ofpbuf
*request
, ovs_be16 tpid
,
1966 uint16_t vid
, uint8_t prio
)
1970 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1971 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1973 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1974 .v_action
= TCA_VLAN_ACT_PUSH
};
1976 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1977 nl_msg_put_be16(request
, TCA_VLAN_PUSH_VLAN_PROTOCOL
, tpid
);
1978 nl_msg_put_u16(request
, TCA_VLAN_PUSH_VLAN_ID
, vid
);
1979 nl_msg_put_u8(request
, TCA_VLAN_PUSH_VLAN_PRIORITY
, prio
);
1981 nl_msg_end_nested(request
, offset
);
1985 nl_msg_put_act_pop_vlan(struct ofpbuf
*request
)
1989 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1990 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1992 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1993 .v_action
= TCA_VLAN_ACT_POP
};
1995 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1997 nl_msg_end_nested(request
, offset
);
2001 nl_msg_put_act_pop_mpls(struct ofpbuf
*request
, ovs_be16 proto
)
2005 nl_msg_put_string(request
, TCA_ACT_KIND
, "mpls");
2006 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
2008 struct tc_mpls parm
= { .action
= TC_ACT_PIPE
,
2009 .m_action
= TCA_MPLS_ACT_POP
};
2011 nl_msg_put_unspec(request
, TCA_MPLS_PARMS
, &parm
, sizeof parm
);
2012 nl_msg_put_be16(request
, TCA_MPLS_PROTO
, proto
);
2014 nl_msg_end_nested(request
, offset
);
2018 nl_msg_put_act_push_mpls(struct ofpbuf
*request
, ovs_be16 proto
,
2019 uint32_t label
, uint8_t tc
, uint8_t ttl
, uint8_t bos
)
2023 nl_msg_put_string(request
, TCA_ACT_KIND
, "mpls");
2024 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
2026 struct tc_mpls parm
= { .action
= TC_ACT_PIPE
,
2027 .m_action
= TCA_MPLS_ACT_PUSH
};
2029 nl_msg_put_unspec(request
, TCA_MPLS_PARMS
, &parm
, sizeof parm
);
2030 nl_msg_put_be16(request
, TCA_MPLS_PROTO
, proto
);
2031 nl_msg_put_u32(request
, TCA_MPLS_LABEL
, label
);
2032 nl_msg_put_u8(request
, TCA_MPLS_TC
, tc
);
2033 nl_msg_put_u8(request
, TCA_MPLS_TTL
, ttl
);
2034 nl_msg_put_u8(request
, TCA_MPLS_BOS
, bos
);
2036 nl_msg_end_nested(request
, offset
);
2040 nl_msg_put_act_set_mpls(struct ofpbuf
*request
, uint32_t label
, uint8_t tc
,
2041 uint8_t ttl
, uint8_t bos
)
2045 nl_msg_put_string(request
, TCA_ACT_KIND
, "mpls");
2046 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
2048 struct tc_mpls parm
= { .action
= TC_ACT_PIPE
,
2049 .m_action
= TCA_MPLS_ACT_MODIFY
};
2051 nl_msg_put_unspec(request
, TCA_MPLS_PARMS
, &parm
, sizeof parm
);
2052 nl_msg_put_u32(request
, TCA_MPLS_LABEL
, label
);
2053 nl_msg_put_u8(request
, TCA_MPLS_TC
, tc
);
2054 nl_msg_put_u8(request
, TCA_MPLS_TTL
, ttl
);
2055 nl_msg_put_u8(request
, TCA_MPLS_BOS
, bos
);
2057 nl_msg_end_nested(request
, offset
);
2061 nl_msg_put_act_tunnel_key_release(struct ofpbuf
*request
)
2065 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
2066 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2068 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
2069 .t_action
= TCA_TUNNEL_KEY_ACT_RELEASE
};
2071 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
2073 nl_msg_end_nested(request
, offset
);
2077 nl_msg_put_act_tunnel_geneve_option(struct ofpbuf
*request
,
2078 struct tun_metadata tun_metadata
)
2080 const struct geneve_opt
*opt
;
2081 size_t outer
, inner
;
2084 len
= tun_metadata
.present
.len
;
2089 outer
= nl_msg_start_nested(request
, TCA_TUNNEL_KEY_ENC_OPTS
);
2092 opt
= &tun_metadata
.opts
.gnv
[cnt
];
2093 inner
= nl_msg_start_nested(request
, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
);
2095 nl_msg_put_be16(request
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
,
2097 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
, opt
->type
);
2098 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
, opt
+ 1,
2101 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
2102 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
2104 nl_msg_end_nested(request
, inner
);
2107 nl_msg_end_nested(request
, outer
);
2111 nl_msg_put_act_tunnel_key_set(struct ofpbuf
*request
, bool id_present
,
2112 ovs_be64 id
, ovs_be32 ipv4_src
,
2113 ovs_be32 ipv4_dst
, struct in6_addr
*ipv6_src
,
2114 struct in6_addr
*ipv6_dst
,
2115 ovs_be16 tp_dst
, uint8_t tos
, uint8_t ttl
,
2116 struct tun_metadata tun_metadata
,
2121 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
2122 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2124 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
2125 .t_action
= TCA_TUNNEL_KEY_ACT_SET
};
2127 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
2129 ovs_be32 id32
= be64_to_be32(id
);
2131 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_KEY_ID
, id32
);
2134 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_SRC
, ipv4_src
);
2135 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_DST
, ipv4_dst
);
2136 } else if (ipv6_addr_is_set(ipv6_dst
)) {
2137 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_DST
,
2139 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_SRC
,
2143 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_TOS
, tos
);
2146 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_TTL
, ttl
);
2149 nl_msg_put_be16(request
, TCA_TUNNEL_KEY_ENC_DST_PORT
, tp_dst
);
2151 nl_msg_put_act_tunnel_geneve_option(request
, tun_metadata
);
2152 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_NO_CSUM
, no_csum
);
2154 nl_msg_end_nested(request
, offset
);
2158 nl_msg_put_act_gact(struct ofpbuf
*request
, uint32_t chain
)
2162 nl_msg_put_string(request
, TCA_ACT_KIND
, "gact");
2163 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2165 struct tc_gact p
= { .action
= TC_ACT_SHOT
};
2168 p
.action
= TC_ACT_GOTO_CHAIN
| chain
;
2171 nl_msg_put_unspec(request
, TCA_GACT_PARMS
, &p
, sizeof p
);
2173 nl_msg_end_nested(request
, offset
);
2177 nl_msg_put_act_ct(struct ofpbuf
*request
, struct tc_action
*action
)
2179 uint16_t ct_action
= 0;
2182 nl_msg_put_string(request
, TCA_ACT_KIND
, "ct");
2183 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
2186 .action
= TC_ACT_PIPE
,
2189 if (!action
->ct
.clear
) {
2190 if (action
->ct
.zone
) {
2191 nl_msg_put_u16(request
, TCA_CT_ZONE
, action
->ct
.zone
);
2194 if (!is_all_zeros(&action
->ct
.label_mask
,
2195 sizeof action
->ct
.label_mask
)) {
2196 nl_msg_put_u128(request
, TCA_CT_LABELS
,
2198 nl_msg_put_u128(request
, TCA_CT_LABELS_MASK
,
2199 action
->ct
.label_mask
);
2202 if (action
->ct
.mark_mask
) {
2203 nl_msg_put_u32(request
, TCA_CT_MARK
,
2205 nl_msg_put_u32(request
, TCA_CT_MARK_MASK
,
2206 action
->ct
.mark_mask
);
2209 if (action
->ct
.commit
) {
2210 ct_action
= TCA_CT_ACT_COMMIT
;
2211 if (action
->ct
.force
) {
2212 ct_action
|= TCA_CT_ACT_FORCE
;
2216 if (action
->ct
.nat_type
) {
2217 ct_action
|= TCA_CT_ACT_NAT
;
2219 if (action
->ct
.nat_type
== TC_NAT_SRC
) {
2220 ct_action
|= TCA_CT_ACT_NAT_SRC
;
2221 } else if (action
->ct
.nat_type
== TC_NAT_DST
) {
2222 ct_action
|= TCA_CT_ACT_NAT_DST
;
2225 if (action
->ct
.range
.ip_family
== AF_INET
) {
2226 nl_msg_put_be32(request
, TCA_CT_NAT_IPV4_MIN
,
2227 action
->ct
.range
.ipv4
.min
);
2228 if (action
->ct
.range
.ipv4
.max
) {
2229 nl_msg_put_be32(request
, TCA_CT_NAT_IPV4_MAX
,
2230 action
->ct
.range
.ipv4
.max
);
2232 } else if (action
->ct
.range
.ip_family
== AF_INET6
) {
2234 nl_msg_put_in6_addr(request
, TCA_CT_NAT_IPV6_MIN
,
2235 &action
->ct
.range
.ipv6
.min
);
2236 if (ipv6_addr_is_set(&action
->ct
.range
.ipv6
.max
)) {
2237 nl_msg_put_in6_addr(request
, TCA_CT_NAT_IPV6_MAX
,
2238 &action
->ct
.range
.ipv6
.max
);
2242 if (action
->ct
.range
.port
.min
) {
2243 nl_msg_put_be16(request
, TCA_CT_NAT_PORT_MIN
,
2244 action
->ct
.range
.port
.min
);
2245 if (action
->ct
.range
.port
.max
) {
2246 nl_msg_put_be16(request
, TCA_CT_NAT_PORT_MAX
,
2247 action
->ct
.range
.port
.max
);
2252 ct_action
= TCA_CT_ACT_CLEAR
;
2255 nl_msg_put_u16(request
, TCA_CT_ACTION
, ct_action
);
2256 nl_msg_put_unspec(request
, TCA_CT_PARMS
, &ct
, sizeof ct
);
2258 nl_msg_end_nested(request
, offset
);
2262 nl_msg_put_act_skbedit_to_host(struct ofpbuf
*request
)
2266 nl_msg_put_string(request
, TCA_ACT_KIND
, "skbedit");
2267 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2269 struct tc_skbedit s
= { .action
= TC_ACT_PIPE
};
2271 nl_msg_put_unspec(request
, TCA_SKBEDIT_PARMS
, &s
, sizeof s
);
2272 nl_msg_put_be16(request
, TCA_SKBEDIT_PTYPE
, PACKET_HOST
);
2274 nl_msg_end_nested(request
, offset
);
2278 nl_msg_put_act_mirred(struct ofpbuf
*request
, int ifindex
, int action
,
2283 nl_msg_put_string(request
, TCA_ACT_KIND
, "mirred");
2284 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2286 struct tc_mirred m
= { .action
= action
,
2288 .ifindex
= ifindex
};
2290 nl_msg_put_unspec(request
, TCA_MIRRED_PARMS
, &m
, sizeof m
);
2292 nl_msg_end_nested(request
, offset
);
2296 nl_msg_put_act_cookie(struct ofpbuf
*request
, struct tc_cookie
*ck
) {
2298 nl_msg_put_unspec(request
, TCA_ACT_COOKIE
, ck
->data
, ck
->len
);
2303 nl_msg_put_act_flags(struct ofpbuf
*request
) {
2304 struct nla_bitfield32 act_flags
= { TCA_ACT_FLAGS_NO_PERCPU_STATS
,
2305 TCA_ACT_FLAGS_NO_PERCPU_STATS
};
2307 nl_msg_put_unspec(request
, TCA_ACT_FLAGS
, &act_flags
, sizeof act_flags
);
2310 /* Given flower, a key_to_pedit map entry, calculates the rest,
2313 * mask, data - pointers of where read the first word of flower->key/mask.
2314 * current_offset - which offset to use for the first pedit action.
2315 * cnt - max pedits actions to use.
2316 * first_word_mask/last_word_mask - the mask to use for the first/last read
2317 * (as we read entire words). */
2319 calc_offsets(struct tc_flower
*flower
, struct flower_key_to_pedit
*m
,
2320 int *cur_offset
, int *cnt
, ovs_be32
*last_word_mask
,
2321 ovs_be32
*first_word_mask
, ovs_be32
**mask
, ovs_be32
**data
)
2323 int start_offset
, max_offset
, total_size
;
2324 int diff
, right_zero_bits
, left_zero_bits
;
2325 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
2326 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
2328 max_offset
= m
->offset
+ m
->size
;
2329 start_offset
= ROUND_DOWN(m
->offset
, 4);
2330 diff
= m
->offset
- start_offset
;
2331 total_size
= max_offset
- start_offset
;
2332 right_zero_bits
= 8 * (4 - ((max_offset
% 4) ? : 4));
2333 left_zero_bits
= 8 * (m
->offset
- start_offset
);
2335 *cur_offset
= start_offset
;
2336 *cnt
= (total_size
/ 4) + (total_size
% 4 ? 1 : 0);
2337 *last_word_mask
= htonl(UINT32_MAX
<< right_zero_bits
);
2338 *first_word_mask
= htonl(UINT32_MAX
>> left_zero_bits
);
2339 *data
= (void *) (rewrite_key
+ m
->flower_offset
- diff
);
2340 *mask
= (void *) (rewrite_mask
+ m
->flower_offset
- diff
);
2344 csum_update_flag(struct tc_flower
*flower
,
2345 enum pedit_header_type htype
) {
2346 /* Explictily specifiy the csum flags so HW can return EOPNOTSUPP
2347 * if it doesn't support a checksum recalculation of some headers.
2348 * And since OVS allows a flow such as
2349 * eth(dst=<mac>),eth_type(0x0800) actions=set(ipv4(src=<new_ip>))
2350 * we need to force a more specific flow as this can, for example,
2351 * need a recalculation of icmp checksum if the packet that passes
2352 * is ICMPv6 and tcp checksum if its tcp. */
2355 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
:
2356 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_IPV4HDR
;
2358 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
:
2359 case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
:
2360 case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
:
2361 if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
2362 flower
->needs_full_ip_proto_mask
= true;
2363 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_TCP
;
2364 } else if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
2365 flower
->needs_full_ip_proto_mask
= true;
2366 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_UDP
;
2367 } else if (flower
->key
.ip_proto
== IPPROTO_ICMP
) {
2368 flower
->needs_full_ip_proto_mask
= true;
2369 } else if (flower
->key
.ip_proto
== IPPROTO_ICMPV6
) {
2370 flower
->needs_full_ip_proto_mask
= true;
2371 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_ICMP
;
2373 VLOG_WARN_RL(&error_rl
,
2374 "can't offload rewrite of IP/IPV6 with ip_proto: %d",
2375 flower
->key
.ip_proto
);
2379 case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
:
2380 return 0; /* success */
2382 case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK
:
2383 case __PEDIT_HDR_TYPE_MAX
:
2392 nl_msg_put_flower_rewrite_pedits(struct ofpbuf
*request
,
2393 struct tc_flower
*flower
)
2396 struct tc_pedit sel
;
2397 struct tc_pedit_key keys
[MAX_PEDIT_OFFSETS
];
2398 struct tc_pedit_key_ex keys_ex
[MAX_PEDIT_OFFSETS
];
2406 for (i
= 0; i
< ARRAY_SIZE(flower_pedit_map
); i
++) {
2407 struct flower_key_to_pedit
*m
= &flower_pedit_map
[i
];
2408 struct tc_pedit_key
*pedit_key
= NULL
;
2409 struct tc_pedit_key_ex
*pedit_key_ex
= NULL
;
2410 ovs_be32
*mask
, *data
, first_word_mask
, last_word_mask
;
2411 int cnt
= 0, cur_offset
= 0;
2417 calc_offsets(flower
, m
, &cur_offset
, &cnt
, &last_word_mask
,
2418 &first_word_mask
, &mask
, &data
);
2420 for (j
= 0; j
< cnt
; j
++, mask
++, data
++, cur_offset
+= 4) {
2421 ovs_be32 mask_word
= *mask
;
2422 ovs_be32 data_word
= *data
;
2425 mask_word
&= first_word_mask
;
2428 mask_word
&= last_word_mask
;
2433 if (sel
.sel
.nkeys
== MAX_PEDIT_OFFSETS
) {
2434 VLOG_WARN_RL(&error_rl
, "reached too many pedit offsets: %d",
2439 pedit_key
= &sel
.keys
[sel
.sel
.nkeys
];
2440 pedit_key_ex
= &sel
.keys_ex
[sel
.sel
.nkeys
];
2441 pedit_key_ex
->cmd
= TCA_PEDIT_KEY_EX_CMD_SET
;
2442 pedit_key_ex
->htype
= m
->htype
;
2443 pedit_key
->off
= cur_offset
;
2444 mask_word
= htonl(ntohl(mask_word
) >> m
->boundary_shift
);
2445 data_word
= htonl(ntohl(data_word
) >> m
->boundary_shift
);
2446 pedit_key
->mask
= ~mask_word
;
2447 pedit_key
->val
= data_word
& mask_word
;
2450 err
= csum_update_flag(flower
, m
->htype
);
2455 if (flower
->needs_full_ip_proto_mask
) {
2456 flower
->mask
.ip_proto
= UINT8_MAX
;
2460 nl_msg_put_act_pedit(request
, &sel
.sel
, sel
.keys_ex
);
2466 nl_msg_put_flower_acts(struct ofpbuf
*request
, struct tc_flower
*flower
)
2468 bool ingress
, released
= false;
2471 uint16_t act_index
= 1;
2472 struct tc_action
*action
;
2475 offset
= nl_msg_start_nested(request
, TCA_FLOWER_ACT
);
2479 action
= flower
->actions
;
2480 for (i
= 0; i
< flower
->action_count
; i
++, action
++) {
2481 switch (action
->type
) {
2482 case TC_ACT_PEDIT
: {
2483 act_offset
= nl_msg_start_nested(request
, act_index
++);
2484 error
= nl_msg_put_flower_rewrite_pedits(request
, flower
);
2488 nl_msg_end_nested(request
, act_offset
);
2490 if (flower
->csum_update_flags
) {
2491 act_offset
= nl_msg_start_nested(request
, act_index
++);
2492 nl_msg_put_act_csum(request
, flower
->csum_update_flags
);
2493 nl_msg_put_act_flags(request
);
2494 nl_msg_end_nested(request
, act_offset
);
2498 case TC_ACT_ENCAP
: {
2499 act_offset
= nl_msg_start_nested(request
, act_index
++);
2500 nl_msg_put_act_tunnel_key_set(request
, action
->encap
.id_present
,
2502 action
->encap
.ipv4
.ipv4_src
,
2503 action
->encap
.ipv4
.ipv4_dst
,
2504 &action
->encap
.ipv6
.ipv6_src
,
2505 &action
->encap
.ipv6
.ipv6_dst
,
2506 action
->encap
.tp_dst
,
2510 action
->encap
.no_csum
);
2511 nl_msg_put_act_flags(request
);
2512 nl_msg_end_nested(request
, act_offset
);
2515 case TC_ACT_VLAN_POP
: {
2516 act_offset
= nl_msg_start_nested(request
, act_index
++);
2517 nl_msg_put_act_pop_vlan(request
);
2518 nl_msg_put_act_flags(request
);
2519 nl_msg_end_nested(request
, act_offset
);
2522 case TC_ACT_VLAN_PUSH
: {
2523 act_offset
= nl_msg_start_nested(request
, act_index
++);
2524 nl_msg_put_act_push_vlan(request
,
2525 action
->vlan
.vlan_push_tpid
,
2526 action
->vlan
.vlan_push_id
,
2527 action
->vlan
.vlan_push_prio
);
2528 nl_msg_put_act_flags(request
);
2529 nl_msg_end_nested(request
, act_offset
);
2532 case TC_ACT_MPLS_POP
: {
2533 act_offset
= nl_msg_start_nested(request
, act_index
++);
2534 nl_msg_put_act_pop_mpls(request
, action
->mpls
.proto
);
2535 nl_msg_end_nested(request
, act_offset
);
2538 case TC_ACT_MPLS_PUSH
: {
2539 act_offset
= nl_msg_start_nested(request
, act_index
++);
2540 nl_msg_put_act_push_mpls(request
, action
->mpls
.proto
,
2541 action
->mpls
.label
, action
->mpls
.tc
,
2542 action
->mpls
.ttl
, action
->mpls
.bos
);
2543 nl_msg_end_nested(request
, act_offset
);
2546 case TC_ACT_MPLS_SET
: {
2547 act_offset
= nl_msg_start_nested(request
, act_index
++);
2548 nl_msg_put_act_set_mpls(request
, action
->mpls
.label
,
2549 action
->mpls
.tc
, action
->mpls
.ttl
,
2551 nl_msg_end_nested(request
, act_offset
);
2554 case TC_ACT_OUTPUT
: {
2555 if (!released
&& flower
->tunnel
) {
2556 act_offset
= nl_msg_start_nested(request
, act_index
++);
2557 nl_msg_put_act_tunnel_key_release(request
);
2558 nl_msg_end_nested(request
, act_offset
);
2562 ingress
= action
->out
.ingress
;
2563 ifindex
= action
->out
.ifindex_out
;
2565 VLOG_ERR_RL(&error_rl
, "%s: invalid ifindex: %d, type: %d",
2566 __func__
, ifindex
, action
->type
);
2571 /* If redirecting to ingress (internal port) ensure
2572 * pkt_type on skb is set to PACKET_HOST. */
2573 act_offset
= nl_msg_start_nested(request
, act_index
++);
2574 nl_msg_put_act_skbedit_to_host(request
);
2575 nl_msg_end_nested(request
, act_offset
);
2578 act_offset
= nl_msg_start_nested(request
, act_index
++);
2579 if (i
== flower
->action_count
- 1) {
2581 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_STOLEN
,
2584 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_STOLEN
,
2589 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_PIPE
,
2590 TCA_INGRESS_MIRROR
);
2592 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_PIPE
,
2596 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2597 nl_msg_put_act_flags(request
);
2598 nl_msg_end_nested(request
, act_offset
);
2603 /* We don't support tunnel release + output + goto
2604 * for now, as next chain by default will try and match
2605 * the tunnel metadata that was released/unset.
2607 * This will happen with tunnel + mirror ports.
2612 act_offset
= nl_msg_start_nested(request
, act_index
++);
2613 nl_msg_put_act_gact(request
, action
->chain
);
2614 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2615 nl_msg_end_nested(request
, act_offset
);
2619 act_offset
= nl_msg_start_nested(request
, act_index
++);
2620 nl_msg_put_act_ct(request
, action
);
2621 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2622 nl_msg_end_nested(request
, act_offset
);
2629 if (!flower
->action_count
) {
2630 act_offset
= nl_msg_start_nested(request
, act_index
++);
2631 nl_msg_put_act_gact(request
, 0);
2632 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2633 nl_msg_put_act_flags(request
);
2634 nl_msg_end_nested(request
, act_offset
);
2636 nl_msg_end_nested(request
, offset
);
2642 nl_msg_put_masked_value(struct ofpbuf
*request
, uint16_t type
,
2643 uint16_t mask_type
, const void *data
,
2644 const void *mask_data
, size_t len
)
2646 if (mask_type
!= TCA_FLOWER_UNSPEC
) {
2647 if (is_all_zeros(mask_data
, len
)) {
2650 nl_msg_put_unspec(request
, mask_type
, mask_data
, len
);
2652 nl_msg_put_unspec(request
, type
, data
, len
);
2656 nl_msg_put_flower_tunnel_opts(struct ofpbuf
*request
, uint16_t type
,
2657 struct tun_metadata metadata
)
2659 struct geneve_opt
*opt
;
2660 size_t outer
, inner
;
2663 len
= metadata
.present
.len
;
2668 outer
= nl_msg_start_nested(request
, type
);
2670 opt
= &metadata
.opts
.gnv
[cnt
];
2671 inner
= nl_msg_start_nested(request
, TCA_FLOWER_KEY_ENC_OPTS_GENEVE
);
2673 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
,
2675 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
, opt
->type
);
2676 nl_msg_put_unspec(request
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
, opt
+ 1,
2679 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
2680 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
2682 nl_msg_end_nested(request
, inner
);
2684 nl_msg_end_nested(request
, outer
);
2688 nl_msg_put_flower_tunnel(struct ofpbuf
*request
, struct tc_flower
*flower
)
2690 ovs_be32 ipv4_src_mask
= flower
->mask
.tunnel
.ipv4
.ipv4_src
;
2691 ovs_be32 ipv4_dst_mask
= flower
->mask
.tunnel
.ipv4
.ipv4_dst
;
2692 ovs_be32 ipv4_src
= flower
->key
.tunnel
.ipv4
.ipv4_src
;
2693 ovs_be32 ipv4_dst
= flower
->key
.tunnel
.ipv4
.ipv4_dst
;
2694 struct in6_addr
*ipv6_src_mask
= &flower
->mask
.tunnel
.ipv6
.ipv6_src
;
2695 struct in6_addr
*ipv6_dst_mask
= &flower
->mask
.tunnel
.ipv6
.ipv6_dst
;
2696 struct in6_addr
*ipv6_src
= &flower
->key
.tunnel
.ipv6
.ipv6_src
;
2697 struct in6_addr
*ipv6_dst
= &flower
->key
.tunnel
.ipv6
.ipv6_dst
;
2698 ovs_be16 tp_dst
= flower
->key
.tunnel
.tp_dst
;
2699 ovs_be32 id
= be64_to_be32(flower
->key
.tunnel
.id
);
2700 uint8_t tos
= flower
->key
.tunnel
.tos
;
2701 uint8_t ttl
= flower
->key
.tunnel
.ttl
;
2702 uint8_t tos_mask
= flower
->mask
.tunnel
.tos
;
2703 uint8_t ttl_mask
= flower
->mask
.tunnel
.ttl
;
2704 ovs_be64 id_mask
= flower
->mask
.tunnel
.id
;
2706 if (ipv4_dst_mask
|| ipv4_src_mask
) {
2707 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
,
2709 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
,
2711 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_DST
, ipv4_dst
);
2712 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_SRC
, ipv4_src
);
2713 } else if (ipv6_addr_is_set(ipv6_dst_mask
) ||
2714 ipv6_addr_is_set(ipv6_src_mask
)) {
2715 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
,
2717 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
,
2719 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_DST
, ipv6_dst
);
2720 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_SRC
, ipv6_src
);
2723 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TOS
, tos
);
2724 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TOS_MASK
, tos_mask
);
2727 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TTL
, ttl
);
2728 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TTL_MASK
, ttl_mask
);
2731 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_UDP_DST_PORT
, tp_dst
);
2734 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_KEY_ID
, id
);
2736 nl_msg_put_flower_tunnel_opts(request
, TCA_FLOWER_KEY_ENC_OPTS
,
2737 flower
->key
.tunnel
.metadata
);
2738 nl_msg_put_flower_tunnel_opts(request
, TCA_FLOWER_KEY_ENC_OPTS_MASK
,
2739 flower
->mask
.tunnel
.metadata
);
2742 #define FLOWER_PUT_MASKED_VALUE(member, type) \
2743 nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \
2744 &flower->mask.member, sizeof flower->key.member)
2747 nl_msg_put_flower_options(struct ofpbuf
*request
, struct tc_flower
*flower
)
2750 uint16_t host_eth_type
= ntohs(flower
->key
.eth_type
);
2751 bool is_vlan
= eth_type_vlan(flower
->key
.eth_type
);
2752 bool is_qinq
= is_vlan
&& eth_type_vlan(flower
->key
.encap_eth_type
[0]);
2753 bool is_mpls
= eth_type_mpls(flower
->key
.eth_type
);
2754 enum tc_offload_policy policy
= flower
->tc_policy
;
2757 /* need to parse acts first as some acts require changing the matching
2758 * see csum_update_flag() */
2759 err
= nl_msg_put_flower_acts(request
, flower
);
2766 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[1]);
2768 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[0]);
2773 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[0]);
2776 FLOWER_PUT_MASKED_VALUE(dst_mac
, TCA_FLOWER_KEY_ETH_DST
);
2777 FLOWER_PUT_MASKED_VALUE(src_mac
, TCA_FLOWER_KEY_ETH_SRC
);
2779 if (host_eth_type
== ETH_P_ARP
) {
2780 FLOWER_PUT_MASKED_VALUE(arp
.spa
, TCA_FLOWER_KEY_ARP_SIP
);
2781 FLOWER_PUT_MASKED_VALUE(arp
.tpa
, TCA_FLOWER_KEY_ARP_TIP
);
2782 FLOWER_PUT_MASKED_VALUE(arp
.sha
, TCA_FLOWER_KEY_ARP_SHA
);
2783 FLOWER_PUT_MASKED_VALUE(arp
.tha
, TCA_FLOWER_KEY_ARP_THA
);
2784 FLOWER_PUT_MASKED_VALUE(arp
.opcode
, TCA_FLOWER_KEY_ARP_OP
);
2787 if (host_eth_type
== ETH_P_IP
|| host_eth_type
== ETH_P_IPV6
) {
2788 FLOWER_PUT_MASKED_VALUE(ip_ttl
, TCA_FLOWER_KEY_IP_TTL
);
2789 FLOWER_PUT_MASKED_VALUE(ip_tos
, TCA_FLOWER_KEY_IP_TOS
);
2791 if (flower
->mask
.ip_proto
&& flower
->key
.ip_proto
) {
2792 nl_msg_put_u8(request
, TCA_FLOWER_KEY_IP_PROTO
,
2793 flower
->key
.ip_proto
);
2796 if (flower
->mask
.flags
) {
2797 nl_msg_put_be32(request
, TCA_FLOWER_KEY_FLAGS
,
2798 htonl(flower
->key
.flags
));
2799 nl_msg_put_be32(request
, TCA_FLOWER_KEY_FLAGS_MASK
,
2800 htonl(flower
->mask
.flags
));
2803 if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
2804 FLOWER_PUT_MASKED_VALUE(udp_src
, TCA_FLOWER_KEY_UDP_SRC
);
2805 FLOWER_PUT_MASKED_VALUE(udp_dst
, TCA_FLOWER_KEY_UDP_DST
);
2806 } else if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
2807 FLOWER_PUT_MASKED_VALUE(tcp_src
, TCA_FLOWER_KEY_TCP_SRC
);
2808 FLOWER_PUT_MASKED_VALUE(tcp_dst
, TCA_FLOWER_KEY_TCP_DST
);
2809 FLOWER_PUT_MASKED_VALUE(tcp_flags
, TCA_FLOWER_KEY_TCP_FLAGS
);
2810 } else if (flower
->key
.ip_proto
== IPPROTO_SCTP
) {
2811 FLOWER_PUT_MASKED_VALUE(sctp_src
, TCA_FLOWER_KEY_SCTP_SRC
);
2812 FLOWER_PUT_MASKED_VALUE(sctp_dst
, TCA_FLOWER_KEY_SCTP_DST
);
2815 FLOWER_PUT_MASKED_VALUE(ct_state
, TCA_FLOWER_KEY_CT_STATE
);
2816 FLOWER_PUT_MASKED_VALUE(ct_zone
, TCA_FLOWER_KEY_CT_ZONE
);
2817 FLOWER_PUT_MASKED_VALUE(ct_mark
, TCA_FLOWER_KEY_CT_MARK
);
2818 FLOWER_PUT_MASKED_VALUE(ct_label
, TCA_FLOWER_KEY_CT_LABELS
);
2821 if (host_eth_type
== ETH_P_IP
) {
2822 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_src
, TCA_FLOWER_KEY_IPV4_SRC
);
2823 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_dst
, TCA_FLOWER_KEY_IPV4_DST
);
2824 } else if (host_eth_type
== ETH_P_IPV6
) {
2825 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_src
, TCA_FLOWER_KEY_IPV6_SRC
);
2826 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_dst
, TCA_FLOWER_KEY_IPV6_DST
);
2829 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ETH_TYPE
, flower
->key
.eth_type
);
2832 if (mpls_lse_to_ttl(flower
->mask
.mpls_lse
)) {
2833 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_TTL
,
2834 mpls_lse_to_ttl(flower
->key
.mpls_lse
));
2836 if (mpls_lse_to_tc(flower
->mask
.mpls_lse
)) {
2837 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_TC
,
2838 mpls_lse_to_tc(flower
->key
.mpls_lse
));
2840 if (mpls_lse_to_bos(flower
->mask
.mpls_lse
)) {
2841 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_BOS
,
2842 mpls_lse_to_bos(flower
->key
.mpls_lse
));
2844 if (mpls_lse_to_label(flower
->mask
.mpls_lse
)) {
2845 nl_msg_put_u32(request
, TCA_FLOWER_KEY_MPLS_LABEL
,
2846 mpls_lse_to_label(flower
->key
.mpls_lse
));
2851 if (flower
->mask
.vlan_id
[0]) {
2852 nl_msg_put_u16(request
, TCA_FLOWER_KEY_VLAN_ID
,
2853 flower
->key
.vlan_id
[0]);
2855 if (flower
->mask
.vlan_prio
[0]) {
2856 nl_msg_put_u8(request
, TCA_FLOWER_KEY_VLAN_PRIO
,
2857 flower
->key
.vlan_prio
[0]);
2859 if (flower
->key
.encap_eth_type
[0]) {
2860 nl_msg_put_be16(request
, TCA_FLOWER_KEY_VLAN_ETH_TYPE
,
2861 flower
->key
.encap_eth_type
[0]);
2865 if (flower
->mask
.vlan_id
[1]) {
2866 nl_msg_put_u16(request
, TCA_FLOWER_KEY_CVLAN_ID
,
2867 flower
->key
.vlan_id
[1]);
2869 if (flower
->mask
.vlan_prio
[1]) {
2870 nl_msg_put_u8(request
, TCA_FLOWER_KEY_CVLAN_PRIO
,
2871 flower
->key
.vlan_prio
[1]);
2873 if (flower
->key
.encap_eth_type
[1]) {
2874 nl_msg_put_be16(request
, TCA_FLOWER_KEY_CVLAN_ETH_TYPE
,
2875 flower
->key
.encap_eth_type
[1]);
2880 if (policy
== TC_POLICY_NONE
) {
2884 nl_msg_put_u32(request
, TCA_FLOWER_FLAGS
, tc_get_tc_cls_policy(policy
));
2886 if (flower
->tunnel
) {
2887 nl_msg_put_flower_tunnel(request
, flower
);
2894 tc_replace_flower(struct tcf_id
*id
, struct tc_flower
*flower
)
2896 struct ofpbuf request
;
2897 struct ofpbuf
*reply
;
2899 size_t basic_offset
;
2900 uint16_t eth_type
= (OVS_FORCE
uint16_t) flower
->key
.eth_type
;
2902 request_from_tcf_id(id
, eth_type
, RTM_NEWTFILTER
,
2903 NLM_F_CREATE
| NLM_F_ECHO
, &request
);
2905 nl_msg_put_string(&request
, TCA_KIND
, "flower");
2906 basic_offset
= nl_msg_start_nested(&request
, TCA_OPTIONS
);
2908 error
= nl_msg_put_flower_options(&request
, flower
);
2911 ofpbuf_uninit(&request
);
2915 nl_msg_end_nested(&request
, basic_offset
);
2917 error
= tc_transact(&request
, &reply
);
2920 ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
2922 id
->prio
= tc_get_major(tc
->tcm_info
);
2923 id
->handle
= tc
->tcm_handle
;
2924 ofpbuf_delete(reply
);
2931 tc_set_policy(const char *policy
)
2937 if (!strcmp(policy
, "skip_sw")) {
2938 tc_policy
= TC_POLICY_SKIP_SW
;
2939 } else if (!strcmp(policy
, "skip_hw")) {
2940 tc_policy
= TC_POLICY_SKIP_HW
;
2941 } else if (!strcmp(policy
, "none")) {
2942 tc_policy
= TC_POLICY_NONE
;
2944 VLOG_WARN("tc: Invalid policy '%s'", policy
);
2948 VLOG_INFO("tc: Using policy '%s'", policy
);