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_bos(&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
;
1006 int ef
= ROUND_UP(mf
, 4);
1008 if (m
->htype
!= type
) {
1012 /* check overlap between current pedit key, which is always
1013 * 4 bytes (range [off, off + 3]), and a map entry in
1014 * flower_pedit_map sf = ROUND_DOWN(mf, 4)
1015 * (range [sf|mf, (mf + sz - 1)|ef]) */
1016 if ((keys
->off
>= mf
&& keys
->off
< mf
+ sz
)
1017 || (keys
->off
+ 3 >= mf
&& keys
->off
+ 3 < ef
)) {
1018 int diff
= flower_off
+ (keys
->off
- mf
);
1019 ovs_be32
*dst
= (void *) (rewrite_key
+ diff
);
1020 ovs_be32
*dst_m
= (void *) (rewrite_mask
+ diff
);
1021 ovs_be32 mask
, mask_word
, data_word
;
1024 mask_word
= htonl(ntohl(keys
->mask
) << m
->boundary_shift
);
1025 data_word
= htonl(ntohl(keys
->val
) << m
->boundary_shift
);
1026 mask
= ~(mask_word
);
1028 if (keys
->off
< mf
) {
1029 zero_bits
= 8 * (mf
- keys
->off
);
1030 mask
&= htonl(UINT32_MAX
>> zero_bits
);
1031 } else if (keys
->off
+ 4 > mf
+ m
->size
) {
1032 zero_bits
= 8 * (keys
->off
+ 4 - mf
- m
->size
);
1033 mask
&= htonl(UINT32_MAX
<< zero_bits
);
1037 *dst
|= data_word
& mask
;
1045 action
= &flower
->actions
[flower
->action_count
++];
1046 action
->type
= TC_ACT_PEDIT
;
1051 static const struct nl_policy tunnel_key_policy
[] = {
1052 [TCA_TUNNEL_KEY_PARMS
] = { .type
= NL_A_UNSPEC
,
1053 .min_len
= sizeof(struct tc_tunnel_key
),
1054 .optional
= false, },
1055 [TCA_TUNNEL_KEY_ENC_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
1056 [TCA_TUNNEL_KEY_ENC_IPV4_DST
] = { .type
= NL_A_U32
, .optional
= true, },
1057 [TCA_TUNNEL_KEY_ENC_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
1058 .min_len
= sizeof(struct in6_addr
),
1059 .optional
= true, },
1060 [TCA_TUNNEL_KEY_ENC_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
1061 .min_len
= sizeof(struct in6_addr
),
1062 .optional
= true, },
1063 [TCA_TUNNEL_KEY_ENC_KEY_ID
] = { .type
= NL_A_U32
, .optional
= true, },
1064 [TCA_TUNNEL_KEY_ENC_DST_PORT
] = { .type
= NL_A_U16
, .optional
= true, },
1065 [TCA_TUNNEL_KEY_ENC_TOS
] = { .type
= NL_A_U8
, .optional
= true, },
1066 [TCA_TUNNEL_KEY_ENC_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
1067 [TCA_TUNNEL_KEY_ENC_OPTS
] = { .type
= NL_A_NESTED
, .optional
= true, },
1068 [TCA_TUNNEL_KEY_NO_CSUM
] = { .type
= NL_A_U8
, .optional
= true, },
1072 nl_parse_act_geneve_opts(const struct nlattr
*in_nlattr
,
1073 struct tc_action
*action
)
1075 struct geneve_opt
*opt
= NULL
;
1076 const struct ofpbuf
*msg
;
1077 uint16_t last_opt_type
;
1083 nl_attr_get_nested(in_nlattr
, &buf
);
1086 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_UNSPEC
;
1088 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
1089 uint16_t type
= nl_attr_type(nla
);
1092 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
:
1093 if (cnt
&& last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
) {
1094 VLOG_ERR_RL(&error_rl
,
1095 "failed to parse action geneve options class");
1099 opt
= &action
->encap
.data
.opts
.gnv
[cnt
];
1100 opt
->opt_class
= nl_attr_get_be16(nla
);
1101 cnt
+= sizeof(struct geneve_opt
) / 4;
1102 action
->encap
.data
.present
.len
+= sizeof(struct geneve_opt
);
1103 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
;
1105 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
:
1106 if (last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
) {
1107 VLOG_ERR_RL(&error_rl
,
1108 "failed to parse action geneve options type");
1112 opt
->type
= nl_attr_get_u8(nla
);
1113 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
;
1115 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
:
1116 if (last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
) {
1117 VLOG_ERR_RL(&error_rl
,
1118 "failed to parse action geneve options data");
1122 opt
->length
= nl_attr_get_size(nla
) / 4;
1123 memcpy(opt
+ 1, nl_attr_get_unspec(nla
, 1), opt
->length
* 4);
1125 action
->encap
.data
.present
.len
+= opt
->length
* 4;
1126 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
;
1131 if (last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
) {
1132 VLOG_ERR_RL(&error_rl
,
1133 "failed to parse action geneve options without data");
1141 nl_parse_act_tunnel_opts(struct nlattr
*options
, struct tc_action
*action
)
1143 const struct ofpbuf
*msg
;
1153 nl_attr_get_nested(options
, &buf
);
1156 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
1157 uint16_t type
= nl_attr_type(nla
);
1159 case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
:
1160 err
= nl_parse_act_geneve_opts(nla
, action
);
1173 nl_parse_act_tunnel_key(struct nlattr
*options
, struct tc_flower
*flower
)
1175 struct nlattr
*tun_attrs
[ARRAY_SIZE(tunnel_key_policy
)];
1176 const struct nlattr
*tun_parms
;
1177 const struct tc_tunnel_key
*tun
;
1178 struct tc_action
*action
;
1181 if (!nl_parse_nested(options
, tunnel_key_policy
, tun_attrs
,
1182 ARRAY_SIZE(tunnel_key_policy
))) {
1183 VLOG_ERR_RL(&error_rl
, "failed to parse tunnel_key action options");
1187 tun_parms
= tun_attrs
[TCA_TUNNEL_KEY_PARMS
];
1188 tun
= nl_attr_get_unspec(tun_parms
, sizeof *tun
);
1189 if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_SET
) {
1190 struct nlattr
*id
= tun_attrs
[TCA_TUNNEL_KEY_ENC_KEY_ID
];
1191 struct nlattr
*dst_port
= tun_attrs
[TCA_TUNNEL_KEY_ENC_DST_PORT
];
1192 struct nlattr
*ipv4_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_SRC
];
1193 struct nlattr
*ipv4_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_DST
];
1194 struct nlattr
*ipv6_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_SRC
];
1195 struct nlattr
*ipv6_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_DST
];
1196 struct nlattr
*tos
= tun_attrs
[TCA_TUNNEL_KEY_ENC_TOS
];
1197 struct nlattr
*ttl
= tun_attrs
[TCA_TUNNEL_KEY_ENC_TTL
];
1198 struct nlattr
*tun_opt
= tun_attrs
[TCA_TUNNEL_KEY_ENC_OPTS
];
1199 struct nlattr
*no_csum
= tun_attrs
[TCA_TUNNEL_KEY_NO_CSUM
];
1201 action
= &flower
->actions
[flower
->action_count
++];
1202 action
->type
= TC_ACT_ENCAP
;
1203 action
->encap
.ipv4
.ipv4_src
= ipv4_src
? nl_attr_get_be32(ipv4_src
) : 0;
1204 action
->encap
.ipv4
.ipv4_dst
= ipv4_dst
? nl_attr_get_be32(ipv4_dst
) : 0;
1206 action
->encap
.ipv6
.ipv6_src
= nl_attr_get_in6_addr(ipv6_src
);
1209 action
->encap
.ipv6
.ipv6_dst
= nl_attr_get_in6_addr(ipv6_dst
);
1211 action
->encap
.id
= id
? be32_to_be64(nl_attr_get_be32(id
)) : 0;
1212 action
->encap
.id_present
= id
? true : false;
1213 action
->encap
.tp_dst
= dst_port
? nl_attr_get_be16(dst_port
) : 0;
1214 action
->encap
.tos
= tos
? nl_attr_get_u8(tos
) : 0;
1215 action
->encap
.ttl
= ttl
? nl_attr_get_u8(ttl
) : 0;
1216 action
->encap
.no_csum
= no_csum
? nl_attr_get_u8(no_csum
) : 0;
1218 err
= nl_parse_act_tunnel_opts(tun_opt
, action
);
1222 } else if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_RELEASE
) {
1223 flower
->tunnel
= true;
1225 VLOG_ERR_RL(&error_rl
, "unknown tunnel actions: %d, %d",
1226 tun
->action
, tun
->t_action
);
1232 static const struct nl_policy gact_policy
[] = {
1233 [TCA_GACT_PARMS
] = { .type
= NL_A_UNSPEC
,
1234 .min_len
= sizeof(struct tc_gact
),
1235 .optional
= false, },
1236 [TCA_GACT_TM
] = { .type
= NL_A_UNSPEC
,
1237 .min_len
= sizeof(struct tcf_t
),
1238 .optional
= false, },
1244 static struct ovsthread_once once
= OVSTHREAD_ONCE_INITIALIZER
;
1245 static int user_hz
= 100;
1247 if (ovsthread_once_start(&once
)) {
1248 user_hz
= sysconf(_SC_CLK_TCK
);
1249 ovsthread_once_done(&once
);
1256 nl_parse_tcf(const struct tcf_t
*tm
, struct tc_flower
*flower
)
1258 flower
->lastused
= time_msec() - (tm
->lastuse
* 1000 / get_user_hz());
1262 nl_parse_act_gact(struct nlattr
*options
, struct tc_flower
*flower
)
1264 struct nlattr
*gact_attrs
[ARRAY_SIZE(gact_policy
)];
1265 const struct tc_gact
*p
;
1266 struct nlattr
*gact_parms
;
1267 const struct tcf_t
*tm
;
1268 struct tc_action
*action
;
1270 if (!nl_parse_nested(options
, gact_policy
, gact_attrs
,
1271 ARRAY_SIZE(gact_policy
))) {
1272 VLOG_ERR_RL(&error_rl
, "failed to parse gact action options");
1276 gact_parms
= gact_attrs
[TCA_GACT_PARMS
];
1277 p
= nl_attr_get_unspec(gact_parms
, sizeof *p
);
1279 if (TC_ACT_EXT_CMP(p
->action
, TC_ACT_GOTO_CHAIN
)) {
1280 action
= &flower
->actions
[flower
->action_count
++];
1281 action
->chain
= p
->action
& TC_ACT_EXT_VAL_MASK
;
1282 action
->type
= TC_ACT_GOTO
;
1283 } else if (p
->action
!= TC_ACT_SHOT
) {
1284 VLOG_ERR_RL(&error_rl
, "unknown gact action: %d", p
->action
);
1288 tm
= nl_attr_get_unspec(gact_attrs
[TCA_GACT_TM
], sizeof *tm
);
1289 nl_parse_tcf(tm
, flower
);
1294 static const struct nl_policy mirred_policy
[] = {
1295 [TCA_MIRRED_PARMS
] = { .type
= NL_A_UNSPEC
,
1296 .min_len
= sizeof(struct tc_mirred
),
1297 .optional
= false, },
1298 [TCA_MIRRED_TM
] = { .type
= NL_A_UNSPEC
,
1299 .min_len
= sizeof(struct tcf_t
),
1300 .optional
= false, },
1304 nl_parse_act_mirred(struct nlattr
*options
, struct tc_flower
*flower
)
1307 struct nlattr
*mirred_attrs
[ARRAY_SIZE(mirred_policy
)];
1308 const struct tc_mirred
*m
;
1309 const struct nlattr
*mirred_parms
;
1310 const struct tcf_t
*tm
;
1311 struct nlattr
*mirred_tm
;
1312 struct tc_action
*action
;
1314 if (!nl_parse_nested(options
, mirred_policy
, mirred_attrs
,
1315 ARRAY_SIZE(mirred_policy
))) {
1316 VLOG_ERR_RL(&error_rl
, "failed to parse mirred action options");
1320 mirred_parms
= mirred_attrs
[TCA_MIRRED_PARMS
];
1321 m
= nl_attr_get_unspec(mirred_parms
, sizeof *m
);
1323 if (m
->eaction
!= TCA_EGRESS_REDIR
&& m
->eaction
!= TCA_EGRESS_MIRROR
&&
1324 m
->eaction
!= TCA_INGRESS_REDIR
&& m
->eaction
!= TCA_INGRESS_MIRROR
) {
1325 VLOG_ERR_RL(&error_rl
, "unknown mirred action: %d, %d, %d",
1326 m
->action
, m
->eaction
, m
->ifindex
);
1330 action
= &flower
->actions
[flower
->action_count
++];
1331 action
->out
.ifindex_out
= m
->ifindex
;
1332 if (m
->eaction
== TCA_INGRESS_REDIR
|| m
->eaction
== TCA_INGRESS_MIRROR
) {
1333 action
->out
.ingress
= true;
1335 action
->out
.ingress
= false;
1337 action
->type
= TC_ACT_OUTPUT
;
1339 mirred_tm
= mirred_attrs
[TCA_MIRRED_TM
];
1340 tm
= nl_attr_get_unspec(mirred_tm
, sizeof *tm
);
1341 nl_parse_tcf(tm
, flower
);
1346 static const struct nl_policy ct_policy
[] = {
1347 [TCA_CT_PARMS
] = { .type
= NL_A_UNSPEC
,
1348 .min_len
= sizeof(struct tc_ct
),
1349 .optional
= false, },
1350 [TCA_CT_ACTION
] = { .type
= NL_A_U16
,
1351 .optional
= true, },
1352 [TCA_CT_ZONE
] = { .type
= NL_A_U16
,
1353 .optional
= true, },
1354 [TCA_CT_MARK
] = { .type
= NL_A_U32
,
1355 .optional
= true, },
1356 [TCA_CT_MARK_MASK
] = { .type
= NL_A_U32
,
1357 .optional
= true, },
1358 [TCA_CT_LABELS
] = { .type
= NL_A_UNSPEC
,
1359 .optional
= true, },
1360 [TCA_CT_LABELS_MASK
] = { .type
= NL_A_UNSPEC
,
1361 .optional
= true, },
1362 [TCA_CT_NAT_IPV4_MIN
] = { .type
= NL_A_U32
,
1363 .optional
= true, },
1364 [TCA_CT_NAT_IPV4_MAX
] = { .type
= NL_A_U32
,
1365 .optional
= true, },
1366 [TCA_CT_NAT_IPV6_MIN
] = { .min_len
= sizeof(struct in6_addr
),
1367 .type
= NL_A_UNSPEC
,
1369 [TCA_CT_NAT_IPV6_MAX
] = { .min_len
= sizeof(struct in6_addr
),
1370 .type
= NL_A_UNSPEC
,
1372 [TCA_CT_NAT_PORT_MIN
] = { .type
= NL_A_U16
,
1373 .optional
= true, },
1374 [TCA_CT_NAT_PORT_MAX
] = { .type
= NL_A_U16
,
1375 .optional
= true, },
1379 nl_parse_act_ct(struct nlattr
*options
, struct tc_flower
*flower
)
1381 struct nlattr
*ct_attrs
[ARRAY_SIZE(ct_policy
)];
1382 const struct nlattr
*ct_parms
;
1383 struct tc_action
*action
;
1384 const struct tc_ct
*ct
;
1385 uint16_t ct_action
= 0;
1387 if (!nl_parse_nested(options
, ct_policy
, ct_attrs
,
1388 ARRAY_SIZE(ct_policy
))) {
1389 VLOG_ERR_RL(&error_rl
, "failed to parse ct action options");
1393 ct_parms
= ct_attrs
[TCA_CT_PARMS
];
1394 ct
= nl_attr_get_unspec(ct_parms
, sizeof *ct
);
1396 if (ct_attrs
[TCA_CT_ACTION
]) {
1397 ct_action
= nl_attr_get_u16(ct_attrs
[TCA_CT_ACTION
]);
1400 action
= &flower
->actions
[flower
->action_count
++];
1401 action
->ct
.clear
= ct_action
& TCA_CT_ACT_CLEAR
;
1402 if (!action
->ct
.clear
) {
1403 struct nlattr
*zone
= ct_attrs
[TCA_CT_ZONE
];
1404 struct nlattr
*mark
= ct_attrs
[TCA_CT_MARK
];
1405 struct nlattr
*mark_mask
= ct_attrs
[TCA_CT_MARK_MASK
];
1406 struct nlattr
*label
= ct_attrs
[TCA_CT_LABELS
];
1407 struct nlattr
*label_mask
= ct_attrs
[TCA_CT_LABELS_MASK
];
1409 action
->ct
.commit
= ct_action
& TCA_CT_ACT_COMMIT
;
1410 action
->ct
.force
= ct_action
& TCA_CT_ACT_FORCE
;
1412 action
->ct
.zone
= zone
? nl_attr_get_u16(zone
) : 0;
1413 action
->ct
.mark
= mark
? nl_attr_get_u32(mark
) : 0;
1414 action
->ct
.mark_mask
= mark_mask
? nl_attr_get_u32(mark_mask
) : 0;
1415 action
->ct
.label
= label
? nl_attr_get_u128(label
) : OVS_U128_ZERO
;
1416 action
->ct
.label_mask
= label_mask
?
1417 nl_attr_get_u128(label_mask
) : OVS_U128_ZERO
;
1419 if (ct_action
& TCA_CT_ACT_NAT
) {
1420 struct nlattr
*ipv4_min
= ct_attrs
[TCA_CT_NAT_IPV4_MIN
];
1421 struct nlattr
*ipv4_max
= ct_attrs
[TCA_CT_NAT_IPV4_MAX
];
1422 struct nlattr
*ipv6_min
= ct_attrs
[TCA_CT_NAT_IPV6_MIN
];
1423 struct nlattr
*ipv6_max
= ct_attrs
[TCA_CT_NAT_IPV6_MAX
];
1424 struct nlattr
*port_min
= ct_attrs
[TCA_CT_NAT_PORT_MIN
];
1425 struct nlattr
*port_max
= ct_attrs
[TCA_CT_NAT_PORT_MAX
];
1427 action
->ct
.nat_type
= TC_NAT_RESTORE
;
1428 if (ct_action
& TCA_CT_ACT_NAT_SRC
) {
1429 action
->ct
.nat_type
= TC_NAT_SRC
;
1430 } else if (ct_action
& TCA_CT_ACT_NAT_DST
) {
1431 action
->ct
.nat_type
= TC_NAT_DST
;
1435 action
->ct
.range
.ip_family
= AF_INET
;
1436 action
->ct
.range
.ipv4
.min
= nl_attr_get_be32(ipv4_min
);
1438 ovs_be32 addr
= nl_attr_get_be32(ipv4_max
);
1440 action
->ct
.range
.ipv4
.max
= addr
;
1442 } else if (ipv6_min
) {
1443 action
->ct
.range
.ip_family
= AF_INET6
;
1444 action
->ct
.range
.ipv6
.min
1445 = nl_attr_get_in6_addr(ipv6_min
);
1447 struct in6_addr addr
= nl_attr_get_in6_addr(ipv6_max
);
1449 action
->ct
.range
.ipv6
.max
= addr
;
1454 action
->ct
.range
.port
.min
= nl_attr_get_be16(port_min
);
1456 action
->ct
.range
.port
.max
= nl_attr_get_be16(port_max
);
1461 action
->type
= TC_ACT_CT
;
1466 static const struct nl_policy vlan_policy
[] = {
1467 [TCA_VLAN_PARMS
] = { .type
= NL_A_UNSPEC
,
1468 .min_len
= sizeof(struct tc_vlan
),
1469 .optional
= false, },
1470 [TCA_VLAN_PUSH_VLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
1471 [TCA_VLAN_PUSH_VLAN_PROTOCOL
] = { .type
= NL_A_U16
, .optional
= true, },
1472 [TCA_VLAN_PUSH_VLAN_PRIORITY
] = { .type
= NL_A_U8
, .optional
= true, },
1476 nl_parse_act_vlan(struct nlattr
*options
, struct tc_flower
*flower
)
1478 struct nlattr
*vlan_attrs
[ARRAY_SIZE(vlan_policy
)];
1479 const struct tc_vlan
*v
;
1480 const struct nlattr
*vlan_parms
;
1481 struct tc_action
*action
;
1483 if (!nl_parse_nested(options
, vlan_policy
, vlan_attrs
,
1484 ARRAY_SIZE(vlan_policy
))) {
1485 VLOG_ERR_RL(&error_rl
, "failed to parse vlan action options");
1489 action
= &flower
->actions
[flower
->action_count
++];
1490 vlan_parms
= vlan_attrs
[TCA_VLAN_PARMS
];
1491 v
= nl_attr_get_unspec(vlan_parms
, sizeof *v
);
1492 if (v
->v_action
== TCA_VLAN_ACT_PUSH
) {
1493 struct nlattr
*vlan_tpid
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PROTOCOL
];
1494 struct nlattr
*vlan_id
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_ID
];
1495 struct nlattr
*vlan_prio
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PRIORITY
];
1497 action
->vlan
.vlan_push_tpid
= nl_attr_get_be16(vlan_tpid
);
1498 action
->vlan
.vlan_push_id
= nl_attr_get_u16(vlan_id
);
1499 action
->vlan
.vlan_push_prio
= vlan_prio
? nl_attr_get_u8(vlan_prio
) : 0;
1500 action
->type
= TC_ACT_VLAN_PUSH
;
1501 } else if (v
->v_action
== TCA_VLAN_ACT_POP
) {
1502 action
->type
= TC_ACT_VLAN_POP
;
1504 VLOG_ERR_RL(&error_rl
, "unknown vlan action: %d, %d",
1505 v
->action
, v
->v_action
);
1511 static const struct nl_policy mpls_policy
[] = {
1512 [TCA_MPLS_PARMS
] = { .type
= NL_A_UNSPEC
,
1513 .min_len
= sizeof(struct tc_mpls
),
1514 .optional
= false, },
1515 [TCA_MPLS_PROTO
] = { .type
= NL_A_U16
, .optional
= true, },
1516 [TCA_MPLS_LABEL
] = { .type
= NL_A_U32
, .optional
= true, },
1517 [TCA_MPLS_TC
] = { .type
= NL_A_U8
, .optional
= true, },
1518 [TCA_MPLS_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
1519 [TCA_MPLS_BOS
] = { .type
= NL_A_U8
, .optional
= true, },
1523 nl_parse_act_mpls(struct nlattr
*options
, struct tc_flower
*flower
)
1525 struct nlattr
*mpls_attrs
[ARRAY_SIZE(mpls_policy
)];
1526 const struct nlattr
*mpls_parms
;
1527 struct nlattr
*mpls_proto
;
1528 struct nlattr
*mpls_label
;
1529 struct tc_action
*action
;
1530 const struct tc_mpls
*m
;
1531 struct nlattr
*mpls_ttl
;
1532 struct nlattr
*mpls_bos
;
1533 struct nlattr
*mpls_tc
;
1535 if (!nl_parse_nested(options
, mpls_policy
, mpls_attrs
,
1536 ARRAY_SIZE(mpls_policy
))) {
1537 VLOG_ERR_RL(&error_rl
, "failed to parse mpls action options");
1541 action
= &flower
->actions
[flower
->action_count
++];
1542 mpls_parms
= mpls_attrs
[TCA_MPLS_PARMS
];
1543 m
= nl_attr_get_unspec(mpls_parms
, sizeof *m
);
1545 switch (m
->m_action
) {
1546 case TCA_MPLS_ACT_POP
:
1547 mpls_proto
= mpls_attrs
[TCA_MPLS_PROTO
];
1549 action
->mpls
.proto
= nl_attr_get_be16(mpls_proto
);
1551 action
->type
= TC_ACT_MPLS_POP
;
1553 case TCA_MPLS_ACT_PUSH
:
1554 mpls_proto
= mpls_attrs
[TCA_MPLS_PROTO
];
1556 action
->mpls
.proto
= nl_attr_get_be16(mpls_proto
);
1558 mpls_label
= mpls_attrs
[TCA_MPLS_LABEL
];
1560 action
->mpls
.label
= nl_attr_get_u32(mpls_label
);
1562 mpls_tc
= mpls_attrs
[TCA_MPLS_TC
];
1564 action
->mpls
.tc
= nl_attr_get_u8(mpls_tc
);
1566 mpls_ttl
= mpls_attrs
[TCA_MPLS_TTL
];
1568 action
->mpls
.ttl
= nl_attr_get_u8(mpls_ttl
);
1570 mpls_bos
= mpls_attrs
[TCA_MPLS_BOS
];
1572 action
->mpls
.bos
= nl_attr_get_u8(mpls_bos
);
1574 action
->type
= TC_ACT_MPLS_PUSH
;
1576 case TCA_MPLS_ACT_MODIFY
:
1577 mpls_label
= mpls_attrs
[TCA_MPLS_LABEL
];
1579 action
->mpls
.label
= nl_attr_get_u32(mpls_label
);
1581 mpls_tc
= mpls_attrs
[TCA_MPLS_TC
];
1583 action
->mpls
.tc
= nl_attr_get_u8(mpls_tc
);
1585 mpls_ttl
= mpls_attrs
[TCA_MPLS_TTL
];
1587 action
->mpls
.ttl
= nl_attr_get_u8(mpls_ttl
);
1589 mpls_bos
= mpls_attrs
[TCA_MPLS_BOS
];
1591 action
->mpls
.bos
= nl_attr_get_u8(mpls_bos
);
1593 action
->type
= TC_ACT_MPLS_SET
;
1596 VLOG_ERR_RL(&error_rl
, "unknown mpls action: %d, %d",
1597 m
->action
, m
->m_action
);
1604 static const struct nl_policy csum_policy
[] = {
1605 [TCA_CSUM_PARMS
] = { .type
= NL_A_UNSPEC
,
1606 .min_len
= sizeof(struct tc_csum
),
1607 .optional
= false, },
1611 nl_parse_act_csum(struct nlattr
*options
, struct tc_flower
*flower
)
1613 struct nlattr
*csum_attrs
[ARRAY_SIZE(csum_policy
)];
1614 const struct tc_csum
*c
;
1615 const struct nlattr
*csum_parms
;
1617 if (!nl_parse_nested(options
, csum_policy
, csum_attrs
,
1618 ARRAY_SIZE(csum_policy
))) {
1619 VLOG_ERR_RL(&error_rl
, "failed to parse csum action options");
1623 csum_parms
= csum_attrs
[TCA_CSUM_PARMS
];
1624 c
= nl_attr_get_unspec(csum_parms
, sizeof *c
);
1627 if (c
->update_flags
!= flower
->csum_update_flags
) {
1628 VLOG_WARN_RL(&error_rl
,
1629 "expected different act csum flags: 0x%x != 0x%x",
1630 flower
->csum_update_flags
, c
->update_flags
);
1633 flower
->csum_update_flags
= 0; /* so we know csum was handled */
1635 if (flower
->needs_full_ip_proto_mask
1636 && flower
->mask
.ip_proto
!= UINT8_MAX
) {
1637 VLOG_WARN_RL(&error_rl
, "expected full matching on flower ip_proto");
1644 static const struct nl_policy act_policy
[] = {
1645 [TCA_ACT_KIND
] = { .type
= NL_A_STRING
, .optional
= false, },
1646 [TCA_ACT_COOKIE
] = { .type
= NL_A_UNSPEC
, .optional
= true, },
1647 [TCA_ACT_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= true, },
1648 [TCA_ACT_STATS
] = { .type
= NL_A_NESTED
, .optional
= false, },
1651 static const struct nl_policy stats_policy
[] = {
1652 [TCA_STATS_BASIC
] = { .type
= NL_A_UNSPEC
,
1653 .min_len
= sizeof(struct gnet_stats_basic
),
1654 .optional
= false, },
1658 nl_parse_single_action(struct nlattr
*action
, struct tc_flower
*flower
,
1661 struct nlattr
*act_options
;
1662 struct nlattr
*act_stats
;
1663 struct nlattr
*act_cookie
;
1664 const char *act_kind
;
1665 struct nlattr
*action_attrs
[ARRAY_SIZE(act_policy
)];
1666 struct nlattr
*stats_attrs
[ARRAY_SIZE(stats_policy
)];
1667 struct ovs_flow_stats
*stats
= &flower
->stats
;
1668 const struct gnet_stats_basic
*bs
;
1671 if (!nl_parse_nested(action
, act_policy
, action_attrs
,
1672 ARRAY_SIZE(act_policy
)) ||
1673 (!terse
&& !action_attrs
[TCA_ACT_OPTIONS
])) {
1674 VLOG_ERR_RL(&error_rl
, "failed to parse single action options");
1678 act_kind
= nl_attr_get_string(action_attrs
[TCA_ACT_KIND
]);
1679 act_options
= action_attrs
[TCA_ACT_OPTIONS
];
1680 act_cookie
= action_attrs
[TCA_ACT_COOKIE
];
1683 /* Terse dump doesn't provide act options attribute. */
1684 } else if (!strcmp(act_kind
, "gact")) {
1685 err
= nl_parse_act_gact(act_options
, flower
);
1686 } else if (!strcmp(act_kind
, "mirred")) {
1687 err
= nl_parse_act_mirred(act_options
, flower
);
1688 } else if (!strcmp(act_kind
, "vlan")) {
1689 err
= nl_parse_act_vlan(act_options
, flower
);
1690 } else if (!strcmp(act_kind
, "mpls")) {
1691 err
= nl_parse_act_mpls(act_options
, flower
);
1692 } else if (!strcmp(act_kind
, "tunnel_key")) {
1693 err
= nl_parse_act_tunnel_key(act_options
, flower
);
1694 } else if (!strcmp(act_kind
, "pedit")) {
1695 err
= nl_parse_act_pedit(act_options
, flower
);
1696 } else if (!strcmp(act_kind
, "csum")) {
1697 nl_parse_act_csum(act_options
, flower
);
1698 } else if (!strcmp(act_kind
, "skbedit")) {
1699 /* Added for TC rule only (not in OvS rule) so ignore. */
1700 } else if (!strcmp(act_kind
, "ct")) {
1701 nl_parse_act_ct(act_options
, flower
);
1703 VLOG_ERR_RL(&error_rl
, "unknown tc action kind: %s", act_kind
);
1712 flower
->act_cookie
.data
= nl_attr_get(act_cookie
);
1713 flower
->act_cookie
.len
= nl_attr_get_size(act_cookie
);
1716 act_stats
= action_attrs
[TCA_ACT_STATS
];
1718 if (!nl_parse_nested(act_stats
, stats_policy
, stats_attrs
,
1719 ARRAY_SIZE(stats_policy
))) {
1720 VLOG_ERR_RL(&error_rl
, "failed to parse action stats policy");
1724 bs
= nl_attr_get_unspec(stats_attrs
[TCA_STATS_BASIC
], sizeof *bs
);
1726 put_32aligned_u64(&stats
->n_packets
, bs
->packets
);
1727 put_32aligned_u64(&stats
->n_bytes
, bs
->bytes
);
1733 #define TCA_ACT_MIN_PRIO 1
1736 nl_parse_flower_actions(struct nlattr
**attrs
, struct tc_flower
*flower
,
1739 const struct nlattr
*actions
= attrs
[TCA_FLOWER_ACT
];
1740 static struct nl_policy actions_orders_policy
[TCA_ACT_MAX_NUM
+ 1] = {};
1741 struct nlattr
*actions_orders
[ARRAY_SIZE(actions_orders_policy
)];
1742 const int max_size
= ARRAY_SIZE(actions_orders_policy
);
1744 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
1745 actions_orders_policy
[i
].type
= NL_A_NESTED
;
1746 actions_orders_policy
[i
].optional
= true;
1749 if (!nl_parse_nested(actions
, actions_orders_policy
, actions_orders
,
1750 ARRAY_SIZE(actions_orders_policy
))) {
1751 VLOG_ERR_RL(&error_rl
, "failed to parse flower order of actions");
1755 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
1756 if (actions_orders
[i
]) {
1759 if (flower
->action_count
>= TCA_ACT_MAX_NUM
) {
1760 VLOG_DBG_RL(&error_rl
, "Can only support %d actions", TCA_ACT_MAX_NUM
);
1763 err
= nl_parse_single_action(actions_orders
[i
], flower
, terse
);
1771 if (flower
->csum_update_flags
) {
1772 VLOG_WARN_RL(&error_rl
,
1773 "expected act csum with flags: 0x%x",
1774 flower
->csum_update_flags
);
1782 nl_parse_flower_options(struct nlattr
*nl_options
, struct tc_flower
*flower
,
1785 struct nlattr
*attrs
[ARRAY_SIZE(tca_flower_policy
)];
1789 if (!nl_parse_nested(nl_options
, tca_flower_terse_policy
,
1790 attrs
, ARRAY_SIZE(tca_flower_terse_policy
))) {
1791 VLOG_ERR_RL(&error_rl
, "failed to parse flower classifier terse options");
1794 goto skip_flower_opts
;
1797 if (!nl_parse_nested(nl_options
, tca_flower_policy
,
1798 attrs
, ARRAY_SIZE(tca_flower_policy
))) {
1799 VLOG_ERR_RL(&error_rl
, "failed to parse flower classifier options");
1803 nl_parse_flower_eth(attrs
, flower
);
1804 nl_parse_flower_arp(attrs
, flower
);
1805 nl_parse_flower_mpls(attrs
, flower
);
1806 nl_parse_flower_vlan(attrs
, flower
);
1807 nl_parse_flower_ip(attrs
, flower
);
1808 err
= nl_parse_flower_tunnel(attrs
, flower
);
1814 nl_parse_flower_flags(attrs
, flower
);
1815 return nl_parse_flower_actions(attrs
, flower
, terse
);
1819 parse_netlink_to_tc_flower(struct ofpbuf
*reply
, struct tcf_id
*id
,
1820 struct tc_flower
*flower
, bool terse
)
1823 struct nlattr
*ta
[ARRAY_SIZE(tca_policy
)];
1826 if (NLMSG_HDRLEN
+ sizeof *tc
> reply
->size
) {
1830 memset(flower
, 0, sizeof *flower
);
1832 tc
= ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
1834 flower
->key
.eth_type
= (OVS_FORCE ovs_be16
) tc_get_minor(tc
->tcm_info
);
1835 flower
->mask
.eth_type
= OVS_BE16_MAX
;
1836 id
->prio
= tc_get_major(tc
->tcm_info
);
1837 id
->handle
= tc
->tcm_handle
;
1839 if (id
->prio
== TC_RESERVED_PRIORITY_POLICE
) {
1847 if (!nl_policy_parse(reply
, NLMSG_HDRLEN
+ sizeof *tc
,
1848 tca_policy
, ta
, ARRAY_SIZE(ta
))) {
1849 VLOG_ERR_RL(&error_rl
, "failed to parse tca policy");
1853 if (ta
[TCA_CHAIN
]) {
1854 id
->chain
= nl_attr_get_u32(ta
[TCA_CHAIN
]);
1857 kind
= nl_attr_get_string(ta
[TCA_KIND
]);
1858 if (strcmp(kind
, "flower")) {
1859 VLOG_DBG_ONCE("Unsupported filter: %s", kind
);
1863 return nl_parse_flower_options(ta
[TCA_OPTIONS
], flower
, terse
);
1867 tc_dump_flower_start(struct tcf_id
*id
, struct nl_dump
*dump
, bool terse
)
1869 struct ofpbuf request
;
1871 request_from_tcf_id(id
, 0, RTM_GETTFILTER
, NLM_F_DUMP
, &request
);
1873 struct nla_bitfield32 dump_flags
= { TCA_DUMP_FLAGS_TERSE
,
1874 TCA_DUMP_FLAGS_TERSE
};
1876 nl_msg_put_unspec(&request
, TCA_DUMP_FLAGS
, &dump_flags
,
1879 nl_dump_start(dump
, NETLINK_ROUTE
, &request
);
1880 ofpbuf_uninit(&request
);
1886 tc_del_filter(struct tcf_id
*id
)
1888 struct ofpbuf request
;
1890 request_from_tcf_id(id
, 0, RTM_DELTFILTER
, NLM_F_ACK
, &request
);
1891 return tc_transact(&request
, NULL
);
1895 tc_get_flower(struct tcf_id
*id
, struct tc_flower
*flower
)
1897 struct ofpbuf request
;
1898 struct ofpbuf
*reply
;
1901 request_from_tcf_id(id
, 0, RTM_GETTFILTER
, NLM_F_ECHO
, &request
);
1902 error
= tc_transact(&request
, &reply
);
1907 error
= parse_netlink_to_tc_flower(reply
, id
, flower
, false);
1908 ofpbuf_delete(reply
);
1913 tc_get_tc_cls_policy(enum tc_offload_policy policy
)
1915 if (policy
== TC_POLICY_SKIP_HW
) {
1916 return TCA_CLS_FLAGS_SKIP_HW
;
1917 } else if (policy
== TC_POLICY_SKIP_SW
) {
1918 return TCA_CLS_FLAGS_SKIP_SW
;
1925 nl_msg_put_act_csum(struct ofpbuf
*request
, uint32_t flags
)
1929 nl_msg_put_string(request
, TCA_ACT_KIND
, "csum");
1930 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1932 struct tc_csum parm
= { .action
= TC_ACT_PIPE
,
1933 .update_flags
= flags
};
1935 nl_msg_put_unspec(request
, TCA_CSUM_PARMS
, &parm
, sizeof parm
);
1937 nl_msg_end_nested(request
, offset
);
1941 nl_msg_put_act_pedit(struct ofpbuf
*request
, struct tc_pedit
*parm
,
1942 struct tc_pedit_key_ex
*ex
)
1944 size_t ksize
= sizeof *parm
+ parm
->nkeys
* sizeof(struct tc_pedit_key
);
1945 size_t offset
, offset_keys_ex
, offset_key
;
1948 nl_msg_put_string(request
, TCA_ACT_KIND
, "pedit");
1949 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1951 parm
->action
= TC_ACT_PIPE
;
1953 nl_msg_put_unspec(request
, TCA_PEDIT_PARMS_EX
, parm
, ksize
);
1954 offset_keys_ex
= nl_msg_start_nested(request
, TCA_PEDIT_KEYS_EX
);
1955 for (i
= 0; i
< parm
->nkeys
; i
++, ex
++) {
1956 offset_key
= nl_msg_start_nested(request
, TCA_PEDIT_KEY_EX
);
1957 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_HTYPE
, ex
->htype
);
1958 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_CMD
, ex
->cmd
);
1959 nl_msg_end_nested(request
, offset_key
);
1961 nl_msg_end_nested(request
, offset_keys_ex
);
1963 nl_msg_end_nested(request
, offset
);
1967 nl_msg_put_act_push_vlan(struct ofpbuf
*request
, ovs_be16 tpid
,
1968 uint16_t vid
, uint8_t prio
)
1972 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1973 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1975 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1976 .v_action
= TCA_VLAN_ACT_PUSH
};
1978 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1979 nl_msg_put_be16(request
, TCA_VLAN_PUSH_VLAN_PROTOCOL
, tpid
);
1980 nl_msg_put_u16(request
, TCA_VLAN_PUSH_VLAN_ID
, vid
);
1981 nl_msg_put_u8(request
, TCA_VLAN_PUSH_VLAN_PRIORITY
, prio
);
1983 nl_msg_end_nested(request
, offset
);
1987 nl_msg_put_act_pop_vlan(struct ofpbuf
*request
)
1991 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1992 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1994 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1995 .v_action
= TCA_VLAN_ACT_POP
};
1997 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1999 nl_msg_end_nested(request
, offset
);
2003 nl_msg_put_act_pop_mpls(struct ofpbuf
*request
, ovs_be16 proto
)
2007 nl_msg_put_string(request
, TCA_ACT_KIND
, "mpls");
2008 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
2010 struct tc_mpls parm
= { .action
= TC_ACT_PIPE
,
2011 .m_action
= TCA_MPLS_ACT_POP
};
2013 nl_msg_put_unspec(request
, TCA_MPLS_PARMS
, &parm
, sizeof parm
);
2014 nl_msg_put_be16(request
, TCA_MPLS_PROTO
, proto
);
2016 nl_msg_end_nested(request
, offset
);
2020 nl_msg_put_act_push_mpls(struct ofpbuf
*request
, ovs_be16 proto
,
2021 uint32_t label
, uint8_t tc
, uint8_t ttl
, uint8_t bos
)
2025 nl_msg_put_string(request
, TCA_ACT_KIND
, "mpls");
2026 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
2028 struct tc_mpls parm
= { .action
= TC_ACT_PIPE
,
2029 .m_action
= TCA_MPLS_ACT_PUSH
};
2031 nl_msg_put_unspec(request
, TCA_MPLS_PARMS
, &parm
, sizeof parm
);
2032 nl_msg_put_be16(request
, TCA_MPLS_PROTO
, proto
);
2033 nl_msg_put_u32(request
, TCA_MPLS_LABEL
, label
);
2034 nl_msg_put_u8(request
, TCA_MPLS_TC
, tc
);
2035 nl_msg_put_u8(request
, TCA_MPLS_TTL
, ttl
);
2036 nl_msg_put_u8(request
, TCA_MPLS_BOS
, bos
);
2038 nl_msg_end_nested(request
, offset
);
2042 nl_msg_put_act_set_mpls(struct ofpbuf
*request
, uint32_t label
, uint8_t tc
,
2043 uint8_t ttl
, uint8_t bos
)
2047 nl_msg_put_string(request
, TCA_ACT_KIND
, "mpls");
2048 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
2050 struct tc_mpls parm
= { .action
= TC_ACT_PIPE
,
2051 .m_action
= TCA_MPLS_ACT_MODIFY
};
2053 nl_msg_put_unspec(request
, TCA_MPLS_PARMS
, &parm
, sizeof parm
);
2054 nl_msg_put_u32(request
, TCA_MPLS_LABEL
, label
);
2055 nl_msg_put_u8(request
, TCA_MPLS_TC
, tc
);
2056 nl_msg_put_u8(request
, TCA_MPLS_TTL
, ttl
);
2057 nl_msg_put_u8(request
, TCA_MPLS_BOS
, bos
);
2059 nl_msg_end_nested(request
, offset
);
2063 nl_msg_put_act_tunnel_key_release(struct ofpbuf
*request
)
2067 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
2068 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2070 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
2071 .t_action
= TCA_TUNNEL_KEY_ACT_RELEASE
};
2073 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
2075 nl_msg_end_nested(request
, offset
);
2079 nl_msg_put_act_tunnel_geneve_option(struct ofpbuf
*request
,
2080 struct tun_metadata tun_metadata
)
2082 const struct geneve_opt
*opt
;
2083 size_t outer
, inner
;
2086 len
= tun_metadata
.present
.len
;
2091 outer
= nl_msg_start_nested(request
, TCA_TUNNEL_KEY_ENC_OPTS
);
2094 opt
= &tun_metadata
.opts
.gnv
[cnt
];
2095 inner
= nl_msg_start_nested(request
, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
);
2097 nl_msg_put_be16(request
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
,
2099 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
, opt
->type
);
2100 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
, opt
+ 1,
2103 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
2104 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
2106 nl_msg_end_nested(request
, inner
);
2109 nl_msg_end_nested(request
, outer
);
2113 nl_msg_put_act_tunnel_key_set(struct ofpbuf
*request
, bool id_present
,
2114 ovs_be64 id
, ovs_be32 ipv4_src
,
2115 ovs_be32 ipv4_dst
, struct in6_addr
*ipv6_src
,
2116 struct in6_addr
*ipv6_dst
,
2117 ovs_be16 tp_dst
, uint8_t tos
, uint8_t ttl
,
2118 struct tun_metadata tun_metadata
,
2123 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
2124 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2126 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
2127 .t_action
= TCA_TUNNEL_KEY_ACT_SET
};
2129 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
2131 ovs_be32 id32
= be64_to_be32(id
);
2133 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_KEY_ID
, id32
);
2136 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_SRC
, ipv4_src
);
2137 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_DST
, ipv4_dst
);
2138 } else if (ipv6_addr_is_set(ipv6_dst
)) {
2139 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_DST
,
2141 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_SRC
,
2145 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_TOS
, tos
);
2148 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_TTL
, ttl
);
2151 nl_msg_put_be16(request
, TCA_TUNNEL_KEY_ENC_DST_PORT
, tp_dst
);
2153 nl_msg_put_act_tunnel_geneve_option(request
, tun_metadata
);
2154 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_NO_CSUM
, no_csum
);
2156 nl_msg_end_nested(request
, offset
);
2160 nl_msg_put_act_gact(struct ofpbuf
*request
, uint32_t chain
)
2164 nl_msg_put_string(request
, TCA_ACT_KIND
, "gact");
2165 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2167 struct tc_gact p
= { .action
= TC_ACT_SHOT
};
2170 p
.action
= TC_ACT_GOTO_CHAIN
| chain
;
2173 nl_msg_put_unspec(request
, TCA_GACT_PARMS
, &p
, sizeof p
);
2175 nl_msg_end_nested(request
, offset
);
2179 nl_msg_put_act_ct(struct ofpbuf
*request
, struct tc_action
*action
)
2181 uint16_t ct_action
= 0;
2184 nl_msg_put_string(request
, TCA_ACT_KIND
, "ct");
2185 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
2188 .action
= TC_ACT_PIPE
,
2191 if (!action
->ct
.clear
) {
2192 if (action
->ct
.zone
) {
2193 nl_msg_put_u16(request
, TCA_CT_ZONE
, action
->ct
.zone
);
2196 if (!is_all_zeros(&action
->ct
.label_mask
,
2197 sizeof action
->ct
.label_mask
)) {
2198 nl_msg_put_u128(request
, TCA_CT_LABELS
,
2200 nl_msg_put_u128(request
, TCA_CT_LABELS_MASK
,
2201 action
->ct
.label_mask
);
2204 if (action
->ct
.mark_mask
) {
2205 nl_msg_put_u32(request
, TCA_CT_MARK
,
2207 nl_msg_put_u32(request
, TCA_CT_MARK_MASK
,
2208 action
->ct
.mark_mask
);
2211 if (action
->ct
.commit
) {
2212 ct_action
= TCA_CT_ACT_COMMIT
;
2213 if (action
->ct
.force
) {
2214 ct_action
|= TCA_CT_ACT_FORCE
;
2218 if (action
->ct
.nat_type
) {
2219 ct_action
|= TCA_CT_ACT_NAT
;
2221 if (action
->ct
.nat_type
== TC_NAT_SRC
) {
2222 ct_action
|= TCA_CT_ACT_NAT_SRC
;
2223 } else if (action
->ct
.nat_type
== TC_NAT_DST
) {
2224 ct_action
|= TCA_CT_ACT_NAT_DST
;
2227 if (action
->ct
.range
.ip_family
== AF_INET
) {
2228 nl_msg_put_be32(request
, TCA_CT_NAT_IPV4_MIN
,
2229 action
->ct
.range
.ipv4
.min
);
2230 if (action
->ct
.range
.ipv4
.max
) {
2231 nl_msg_put_be32(request
, TCA_CT_NAT_IPV4_MAX
,
2232 action
->ct
.range
.ipv4
.max
);
2234 } else if (action
->ct
.range
.ip_family
== AF_INET6
) {
2236 nl_msg_put_in6_addr(request
, TCA_CT_NAT_IPV6_MIN
,
2237 &action
->ct
.range
.ipv6
.min
);
2238 if (ipv6_addr_is_set(&action
->ct
.range
.ipv6
.max
)) {
2239 nl_msg_put_in6_addr(request
, TCA_CT_NAT_IPV6_MAX
,
2240 &action
->ct
.range
.ipv6
.max
);
2244 if (action
->ct
.range
.port
.min
) {
2245 nl_msg_put_be16(request
, TCA_CT_NAT_PORT_MIN
,
2246 action
->ct
.range
.port
.min
);
2247 if (action
->ct
.range
.port
.max
) {
2248 nl_msg_put_be16(request
, TCA_CT_NAT_PORT_MAX
,
2249 action
->ct
.range
.port
.max
);
2254 ct_action
= TCA_CT_ACT_CLEAR
;
2257 nl_msg_put_u16(request
, TCA_CT_ACTION
, ct_action
);
2258 nl_msg_put_unspec(request
, TCA_CT_PARMS
, &ct
, sizeof ct
);
2260 nl_msg_end_nested(request
, offset
);
2264 nl_msg_put_act_skbedit_to_host(struct ofpbuf
*request
)
2268 nl_msg_put_string(request
, TCA_ACT_KIND
, "skbedit");
2269 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2271 struct tc_skbedit s
= { .action
= TC_ACT_PIPE
};
2273 nl_msg_put_unspec(request
, TCA_SKBEDIT_PARMS
, &s
, sizeof s
);
2274 nl_msg_put_be16(request
, TCA_SKBEDIT_PTYPE
, PACKET_HOST
);
2276 nl_msg_end_nested(request
, offset
);
2280 nl_msg_put_act_mirred(struct ofpbuf
*request
, int ifindex
, int action
,
2285 nl_msg_put_string(request
, TCA_ACT_KIND
, "mirred");
2286 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2288 struct tc_mirred m
= { .action
= action
,
2290 .ifindex
= ifindex
};
2292 nl_msg_put_unspec(request
, TCA_MIRRED_PARMS
, &m
, sizeof m
);
2294 nl_msg_end_nested(request
, offset
);
2298 nl_msg_put_act_cookie(struct ofpbuf
*request
, struct tc_cookie
*ck
) {
2300 nl_msg_put_unspec(request
, TCA_ACT_COOKIE
, ck
->data
, ck
->len
);
2305 nl_msg_put_act_flags(struct ofpbuf
*request
) {
2306 struct nla_bitfield32 act_flags
= { TCA_ACT_FLAGS_NO_PERCPU_STATS
,
2307 TCA_ACT_FLAGS_NO_PERCPU_STATS
};
2309 nl_msg_put_unspec(request
, TCA_ACT_FLAGS
, &act_flags
, sizeof act_flags
);
2312 /* Given flower, a key_to_pedit map entry, calculates the rest,
2315 * mask, data - pointers of where read the first word of flower->key/mask.
2316 * current_offset - which offset to use for the first pedit action.
2317 * cnt - max pedits actions to use.
2318 * first_word_mask/last_word_mask - the mask to use for the first/last read
2319 * (as we read entire words). */
2321 calc_offsets(struct tc_flower
*flower
, struct flower_key_to_pedit
*m
,
2322 int *cur_offset
, int *cnt
, ovs_be32
*last_word_mask
,
2323 ovs_be32
*first_word_mask
, ovs_be32
**mask
, ovs_be32
**data
)
2325 int start_offset
, max_offset
, total_size
;
2326 int diff
, right_zero_bits
, left_zero_bits
;
2327 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
2328 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
2330 max_offset
= m
->offset
+ m
->size
;
2331 start_offset
= ROUND_DOWN(m
->offset
, 4);
2332 diff
= m
->offset
- start_offset
;
2333 total_size
= max_offset
- start_offset
;
2334 right_zero_bits
= 8 * (4 - ((max_offset
% 4) ? : 4));
2335 left_zero_bits
= 8 * (m
->offset
- start_offset
);
2337 *cur_offset
= start_offset
;
2338 *cnt
= (total_size
/ 4) + (total_size
% 4 ? 1 : 0);
2339 *last_word_mask
= htonl(UINT32_MAX
<< right_zero_bits
);
2340 *first_word_mask
= htonl(UINT32_MAX
>> left_zero_bits
);
2341 *data
= (void *) (rewrite_key
+ m
->flower_offset
- diff
);
2342 *mask
= (void *) (rewrite_mask
+ m
->flower_offset
- diff
);
2346 csum_update_flag(struct tc_flower
*flower
,
2347 enum pedit_header_type htype
) {
2348 /* Explictily specifiy the csum flags so HW can return EOPNOTSUPP
2349 * if it doesn't support a checksum recalculation of some headers.
2350 * And since OVS allows a flow such as
2351 * eth(dst=<mac>),eth_type(0x0800) actions=set(ipv4(src=<new_ip>))
2352 * we need to force a more specific flow as this can, for example,
2353 * need a recalculation of icmp checksum if the packet that passes
2354 * is ICMPv6 and tcp checksum if its tcp. */
2357 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
:
2358 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_IPV4HDR
;
2360 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
:
2361 case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
:
2362 case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
:
2363 if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
2364 flower
->needs_full_ip_proto_mask
= true;
2365 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_TCP
;
2366 } else if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
2367 flower
->needs_full_ip_proto_mask
= true;
2368 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_UDP
;
2369 } else if (flower
->key
.ip_proto
== IPPROTO_ICMP
) {
2370 flower
->needs_full_ip_proto_mask
= true;
2371 } else if (flower
->key
.ip_proto
== IPPROTO_ICMPV6
) {
2372 flower
->needs_full_ip_proto_mask
= true;
2373 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_ICMP
;
2375 VLOG_WARN_RL(&error_rl
,
2376 "can't offload rewrite of IP/IPV6 with ip_proto: %d",
2377 flower
->key
.ip_proto
);
2381 case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
:
2382 return 0; /* success */
2384 case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK
:
2385 case __PEDIT_HDR_TYPE_MAX
:
2394 nl_msg_put_flower_rewrite_pedits(struct ofpbuf
*request
,
2395 struct tc_flower
*flower
)
2398 struct tc_pedit sel
;
2399 struct tc_pedit_key keys
[MAX_PEDIT_OFFSETS
];
2400 struct tc_pedit_key_ex keys_ex
[MAX_PEDIT_OFFSETS
];
2408 for (i
= 0; i
< ARRAY_SIZE(flower_pedit_map
); i
++) {
2409 struct flower_key_to_pedit
*m
= &flower_pedit_map
[i
];
2410 struct tc_pedit_key
*pedit_key
= NULL
;
2411 struct tc_pedit_key_ex
*pedit_key_ex
= NULL
;
2412 ovs_be32
*mask
, *data
, first_word_mask
, last_word_mask
;
2413 int cnt
= 0, cur_offset
= 0;
2419 calc_offsets(flower
, m
, &cur_offset
, &cnt
, &last_word_mask
,
2420 &first_word_mask
, &mask
, &data
);
2422 for (j
= 0; j
< cnt
; j
++, mask
++, data
++, cur_offset
+= 4) {
2423 ovs_be32 mask_word
= *mask
;
2424 ovs_be32 data_word
= *data
;
2427 mask_word
&= first_word_mask
;
2430 mask_word
&= last_word_mask
;
2435 if (sel
.sel
.nkeys
== MAX_PEDIT_OFFSETS
) {
2436 VLOG_WARN_RL(&error_rl
, "reached too many pedit offsets: %d",
2441 pedit_key
= &sel
.keys
[sel
.sel
.nkeys
];
2442 pedit_key_ex
= &sel
.keys_ex
[sel
.sel
.nkeys
];
2443 pedit_key_ex
->cmd
= TCA_PEDIT_KEY_EX_CMD_SET
;
2444 pedit_key_ex
->htype
= m
->htype
;
2445 pedit_key
->off
= cur_offset
;
2446 mask_word
= htonl(ntohl(mask_word
) >> m
->boundary_shift
);
2447 data_word
= htonl(ntohl(data_word
) >> m
->boundary_shift
);
2448 pedit_key
->mask
= ~mask_word
;
2449 pedit_key
->val
= data_word
& mask_word
;
2452 err
= csum_update_flag(flower
, m
->htype
);
2457 if (flower
->needs_full_ip_proto_mask
) {
2458 flower
->mask
.ip_proto
= UINT8_MAX
;
2462 nl_msg_put_act_pedit(request
, &sel
.sel
, sel
.keys_ex
);
2468 nl_msg_put_flower_acts(struct ofpbuf
*request
, struct tc_flower
*flower
)
2470 bool ingress
, released
= false;
2473 uint16_t act_index
= 1;
2474 struct tc_action
*action
;
2477 offset
= nl_msg_start_nested(request
, TCA_FLOWER_ACT
);
2481 action
= flower
->actions
;
2482 for (i
= 0; i
< flower
->action_count
; i
++, action
++) {
2483 switch (action
->type
) {
2484 case TC_ACT_PEDIT
: {
2485 act_offset
= nl_msg_start_nested(request
, act_index
++);
2486 error
= nl_msg_put_flower_rewrite_pedits(request
, flower
);
2490 nl_msg_end_nested(request
, act_offset
);
2492 if (flower
->csum_update_flags
) {
2493 act_offset
= nl_msg_start_nested(request
, act_index
++);
2494 nl_msg_put_act_csum(request
, flower
->csum_update_flags
);
2495 nl_msg_put_act_flags(request
);
2496 nl_msg_end_nested(request
, act_offset
);
2500 case TC_ACT_ENCAP
: {
2501 act_offset
= nl_msg_start_nested(request
, act_index
++);
2502 nl_msg_put_act_tunnel_key_set(request
, action
->encap
.id_present
,
2504 action
->encap
.ipv4
.ipv4_src
,
2505 action
->encap
.ipv4
.ipv4_dst
,
2506 &action
->encap
.ipv6
.ipv6_src
,
2507 &action
->encap
.ipv6
.ipv6_dst
,
2508 action
->encap
.tp_dst
,
2512 action
->encap
.no_csum
);
2513 nl_msg_put_act_flags(request
);
2514 nl_msg_end_nested(request
, act_offset
);
2517 case TC_ACT_VLAN_POP
: {
2518 act_offset
= nl_msg_start_nested(request
, act_index
++);
2519 nl_msg_put_act_pop_vlan(request
);
2520 nl_msg_put_act_flags(request
);
2521 nl_msg_end_nested(request
, act_offset
);
2524 case TC_ACT_VLAN_PUSH
: {
2525 act_offset
= nl_msg_start_nested(request
, act_index
++);
2526 nl_msg_put_act_push_vlan(request
,
2527 action
->vlan
.vlan_push_tpid
,
2528 action
->vlan
.vlan_push_id
,
2529 action
->vlan
.vlan_push_prio
);
2530 nl_msg_put_act_flags(request
);
2531 nl_msg_end_nested(request
, act_offset
);
2534 case TC_ACT_MPLS_POP
: {
2535 act_offset
= nl_msg_start_nested(request
, act_index
++);
2536 nl_msg_put_act_pop_mpls(request
, action
->mpls
.proto
);
2537 nl_msg_end_nested(request
, act_offset
);
2540 case TC_ACT_MPLS_PUSH
: {
2541 act_offset
= nl_msg_start_nested(request
, act_index
++);
2542 nl_msg_put_act_push_mpls(request
, action
->mpls
.proto
,
2543 action
->mpls
.label
, action
->mpls
.tc
,
2544 action
->mpls
.ttl
, action
->mpls
.bos
);
2545 nl_msg_end_nested(request
, act_offset
);
2548 case TC_ACT_MPLS_SET
: {
2549 act_offset
= nl_msg_start_nested(request
, act_index
++);
2550 nl_msg_put_act_set_mpls(request
, action
->mpls
.label
,
2551 action
->mpls
.tc
, action
->mpls
.ttl
,
2553 nl_msg_end_nested(request
, act_offset
);
2556 case TC_ACT_OUTPUT
: {
2557 if (!released
&& flower
->tunnel
) {
2558 act_offset
= nl_msg_start_nested(request
, act_index
++);
2559 nl_msg_put_act_tunnel_key_release(request
);
2560 nl_msg_end_nested(request
, act_offset
);
2564 ingress
= action
->out
.ingress
;
2565 ifindex
= action
->out
.ifindex_out
;
2567 VLOG_ERR_RL(&error_rl
, "%s: invalid ifindex: %d, type: %d",
2568 __func__
, ifindex
, action
->type
);
2573 /* If redirecting to ingress (internal port) ensure
2574 * pkt_type on skb is set to PACKET_HOST. */
2575 act_offset
= nl_msg_start_nested(request
, act_index
++);
2576 nl_msg_put_act_skbedit_to_host(request
);
2577 nl_msg_end_nested(request
, act_offset
);
2580 act_offset
= nl_msg_start_nested(request
, act_index
++);
2581 if (i
== flower
->action_count
- 1) {
2583 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_STOLEN
,
2586 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_STOLEN
,
2591 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_PIPE
,
2592 TCA_INGRESS_MIRROR
);
2594 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_PIPE
,
2598 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2599 nl_msg_put_act_flags(request
);
2600 nl_msg_end_nested(request
, act_offset
);
2605 /* We don't support tunnel release + output + goto
2606 * for now, as next chain by default will try and match
2607 * the tunnel metadata that was released/unset.
2609 * This will happen with tunnel + mirror ports.
2614 act_offset
= nl_msg_start_nested(request
, act_index
++);
2615 nl_msg_put_act_gact(request
, action
->chain
);
2616 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2617 nl_msg_end_nested(request
, act_offset
);
2621 act_offset
= nl_msg_start_nested(request
, act_index
++);
2622 nl_msg_put_act_ct(request
, action
);
2623 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2624 nl_msg_end_nested(request
, act_offset
);
2631 if (!flower
->action_count
) {
2632 act_offset
= nl_msg_start_nested(request
, act_index
++);
2633 nl_msg_put_act_gact(request
, 0);
2634 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2635 nl_msg_put_act_flags(request
);
2636 nl_msg_end_nested(request
, act_offset
);
2638 nl_msg_end_nested(request
, offset
);
2644 nl_msg_put_masked_value(struct ofpbuf
*request
, uint16_t type
,
2645 uint16_t mask_type
, const void *data
,
2646 const void *mask_data
, size_t len
)
2648 if (mask_type
!= TCA_FLOWER_UNSPEC
) {
2649 if (is_all_zeros(mask_data
, len
)) {
2652 nl_msg_put_unspec(request
, mask_type
, mask_data
, len
);
2654 nl_msg_put_unspec(request
, type
, data
, len
);
2658 nl_msg_put_flower_tunnel_opts(struct ofpbuf
*request
, uint16_t type
,
2659 struct tun_metadata metadata
)
2661 struct geneve_opt
*opt
;
2662 size_t outer
, inner
;
2665 len
= metadata
.present
.len
;
2670 outer
= nl_msg_start_nested(request
, type
);
2672 opt
= &metadata
.opts
.gnv
[cnt
];
2673 inner
= nl_msg_start_nested(request
, TCA_FLOWER_KEY_ENC_OPTS_GENEVE
);
2675 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
,
2677 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
, opt
->type
);
2678 nl_msg_put_unspec(request
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
, opt
+ 1,
2681 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
2682 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
2684 nl_msg_end_nested(request
, inner
);
2686 nl_msg_end_nested(request
, outer
);
2690 nl_msg_put_flower_tunnel(struct ofpbuf
*request
, struct tc_flower
*flower
)
2692 ovs_be32 ipv4_src_mask
= flower
->mask
.tunnel
.ipv4
.ipv4_src
;
2693 ovs_be32 ipv4_dst_mask
= flower
->mask
.tunnel
.ipv4
.ipv4_dst
;
2694 ovs_be32 ipv4_src
= flower
->key
.tunnel
.ipv4
.ipv4_src
;
2695 ovs_be32 ipv4_dst
= flower
->key
.tunnel
.ipv4
.ipv4_dst
;
2696 struct in6_addr
*ipv6_src_mask
= &flower
->mask
.tunnel
.ipv6
.ipv6_src
;
2697 struct in6_addr
*ipv6_dst_mask
= &flower
->mask
.tunnel
.ipv6
.ipv6_dst
;
2698 struct in6_addr
*ipv6_src
= &flower
->key
.tunnel
.ipv6
.ipv6_src
;
2699 struct in6_addr
*ipv6_dst
= &flower
->key
.tunnel
.ipv6
.ipv6_dst
;
2700 ovs_be16 tp_dst
= flower
->key
.tunnel
.tp_dst
;
2701 ovs_be32 id
= be64_to_be32(flower
->key
.tunnel
.id
);
2702 uint8_t tos
= flower
->key
.tunnel
.tos
;
2703 uint8_t ttl
= flower
->key
.tunnel
.ttl
;
2704 uint8_t tos_mask
= flower
->mask
.tunnel
.tos
;
2705 uint8_t ttl_mask
= flower
->mask
.tunnel
.ttl
;
2706 ovs_be64 id_mask
= flower
->mask
.tunnel
.id
;
2708 if (ipv4_dst_mask
|| ipv4_src_mask
) {
2709 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
,
2711 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
,
2713 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_DST
, ipv4_dst
);
2714 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_SRC
, ipv4_src
);
2715 } else if (ipv6_addr_is_set(ipv6_dst_mask
) ||
2716 ipv6_addr_is_set(ipv6_src_mask
)) {
2717 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
,
2719 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
,
2721 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_DST
, ipv6_dst
);
2722 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_SRC
, ipv6_src
);
2725 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TOS
, tos
);
2726 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TOS_MASK
, tos_mask
);
2729 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TTL
, ttl
);
2730 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TTL_MASK
, ttl_mask
);
2733 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_UDP_DST_PORT
, tp_dst
);
2736 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_KEY_ID
, id
);
2738 nl_msg_put_flower_tunnel_opts(request
, TCA_FLOWER_KEY_ENC_OPTS
,
2739 flower
->key
.tunnel
.metadata
);
2740 nl_msg_put_flower_tunnel_opts(request
, TCA_FLOWER_KEY_ENC_OPTS_MASK
,
2741 flower
->mask
.tunnel
.metadata
);
2744 #define FLOWER_PUT_MASKED_VALUE(member, type) \
2745 nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \
2746 &flower->mask.member, sizeof flower->key.member)
2749 nl_msg_put_flower_options(struct ofpbuf
*request
, struct tc_flower
*flower
)
2752 uint16_t host_eth_type
= ntohs(flower
->key
.eth_type
);
2753 bool is_vlan
= eth_type_vlan(flower
->key
.eth_type
);
2754 bool is_qinq
= is_vlan
&& eth_type_vlan(flower
->key
.encap_eth_type
[0]);
2755 bool is_mpls
= eth_type_mpls(flower
->key
.eth_type
);
2756 enum tc_offload_policy policy
= flower
->tc_policy
;
2759 /* need to parse acts first as some acts require changing the matching
2760 * see csum_update_flag() */
2761 err
= nl_msg_put_flower_acts(request
, flower
);
2768 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[1]);
2770 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[0]);
2775 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[0]);
2778 FLOWER_PUT_MASKED_VALUE(dst_mac
, TCA_FLOWER_KEY_ETH_DST
);
2779 FLOWER_PUT_MASKED_VALUE(src_mac
, TCA_FLOWER_KEY_ETH_SRC
);
2781 if (host_eth_type
== ETH_P_ARP
) {
2782 FLOWER_PUT_MASKED_VALUE(arp
.spa
, TCA_FLOWER_KEY_ARP_SIP
);
2783 FLOWER_PUT_MASKED_VALUE(arp
.tpa
, TCA_FLOWER_KEY_ARP_TIP
);
2784 FLOWER_PUT_MASKED_VALUE(arp
.sha
, TCA_FLOWER_KEY_ARP_SHA
);
2785 FLOWER_PUT_MASKED_VALUE(arp
.tha
, TCA_FLOWER_KEY_ARP_THA
);
2786 FLOWER_PUT_MASKED_VALUE(arp
.opcode
, TCA_FLOWER_KEY_ARP_OP
);
2789 if (host_eth_type
== ETH_P_IP
|| host_eth_type
== ETH_P_IPV6
) {
2790 FLOWER_PUT_MASKED_VALUE(ip_ttl
, TCA_FLOWER_KEY_IP_TTL
);
2791 FLOWER_PUT_MASKED_VALUE(ip_tos
, TCA_FLOWER_KEY_IP_TOS
);
2793 if (flower
->mask
.ip_proto
&& flower
->key
.ip_proto
) {
2794 nl_msg_put_u8(request
, TCA_FLOWER_KEY_IP_PROTO
,
2795 flower
->key
.ip_proto
);
2798 if (flower
->mask
.flags
) {
2799 nl_msg_put_be32(request
, TCA_FLOWER_KEY_FLAGS
,
2800 htonl(flower
->key
.flags
));
2801 nl_msg_put_be32(request
, TCA_FLOWER_KEY_FLAGS_MASK
,
2802 htonl(flower
->mask
.flags
));
2805 if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
2806 FLOWER_PUT_MASKED_VALUE(udp_src
, TCA_FLOWER_KEY_UDP_SRC
);
2807 FLOWER_PUT_MASKED_VALUE(udp_dst
, TCA_FLOWER_KEY_UDP_DST
);
2808 } else if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
2809 FLOWER_PUT_MASKED_VALUE(tcp_src
, TCA_FLOWER_KEY_TCP_SRC
);
2810 FLOWER_PUT_MASKED_VALUE(tcp_dst
, TCA_FLOWER_KEY_TCP_DST
);
2811 FLOWER_PUT_MASKED_VALUE(tcp_flags
, TCA_FLOWER_KEY_TCP_FLAGS
);
2812 } else if (flower
->key
.ip_proto
== IPPROTO_SCTP
) {
2813 FLOWER_PUT_MASKED_VALUE(sctp_src
, TCA_FLOWER_KEY_SCTP_SRC
);
2814 FLOWER_PUT_MASKED_VALUE(sctp_dst
, TCA_FLOWER_KEY_SCTP_DST
);
2817 FLOWER_PUT_MASKED_VALUE(ct_state
, TCA_FLOWER_KEY_CT_STATE
);
2818 FLOWER_PUT_MASKED_VALUE(ct_zone
, TCA_FLOWER_KEY_CT_ZONE
);
2819 FLOWER_PUT_MASKED_VALUE(ct_mark
, TCA_FLOWER_KEY_CT_MARK
);
2820 FLOWER_PUT_MASKED_VALUE(ct_label
, TCA_FLOWER_KEY_CT_LABELS
);
2823 if (host_eth_type
== ETH_P_IP
) {
2824 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_src
, TCA_FLOWER_KEY_IPV4_SRC
);
2825 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_dst
, TCA_FLOWER_KEY_IPV4_DST
);
2826 } else if (host_eth_type
== ETH_P_IPV6
) {
2827 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_src
, TCA_FLOWER_KEY_IPV6_SRC
);
2828 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_dst
, TCA_FLOWER_KEY_IPV6_DST
);
2831 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ETH_TYPE
, flower
->key
.eth_type
);
2834 if (mpls_lse_to_ttl(flower
->mask
.mpls_lse
)) {
2835 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_TTL
,
2836 mpls_lse_to_ttl(flower
->key
.mpls_lse
));
2838 if (mpls_lse_to_tc(flower
->mask
.mpls_lse
)) {
2839 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_TC
,
2840 mpls_lse_to_tc(flower
->key
.mpls_lse
));
2842 if (mpls_lse_to_bos(flower
->mask
.mpls_lse
)) {
2843 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_BOS
,
2844 mpls_lse_to_bos(flower
->key
.mpls_lse
));
2846 if (mpls_lse_to_label(flower
->mask
.mpls_lse
)) {
2847 nl_msg_put_u32(request
, TCA_FLOWER_KEY_MPLS_LABEL
,
2848 mpls_lse_to_label(flower
->key
.mpls_lse
));
2853 if (flower
->mask
.vlan_id
[0]) {
2854 nl_msg_put_u16(request
, TCA_FLOWER_KEY_VLAN_ID
,
2855 flower
->key
.vlan_id
[0]);
2857 if (flower
->mask
.vlan_prio
[0]) {
2858 nl_msg_put_u8(request
, TCA_FLOWER_KEY_VLAN_PRIO
,
2859 flower
->key
.vlan_prio
[0]);
2861 if (flower
->key
.encap_eth_type
[0]) {
2862 nl_msg_put_be16(request
, TCA_FLOWER_KEY_VLAN_ETH_TYPE
,
2863 flower
->key
.encap_eth_type
[0]);
2867 if (flower
->mask
.vlan_id
[1]) {
2868 nl_msg_put_u16(request
, TCA_FLOWER_KEY_CVLAN_ID
,
2869 flower
->key
.vlan_id
[1]);
2871 if (flower
->mask
.vlan_prio
[1]) {
2872 nl_msg_put_u8(request
, TCA_FLOWER_KEY_CVLAN_PRIO
,
2873 flower
->key
.vlan_prio
[1]);
2875 if (flower
->key
.encap_eth_type
[1]) {
2876 nl_msg_put_be16(request
, TCA_FLOWER_KEY_CVLAN_ETH_TYPE
,
2877 flower
->key
.encap_eth_type
[1]);
2882 if (policy
== TC_POLICY_NONE
) {
2886 nl_msg_put_u32(request
, TCA_FLOWER_FLAGS
, tc_get_tc_cls_policy(policy
));
2888 if (flower
->tunnel
) {
2889 nl_msg_put_flower_tunnel(request
, flower
);
2896 tc_replace_flower(struct tcf_id
*id
, struct tc_flower
*flower
)
2898 struct ofpbuf request
;
2899 struct ofpbuf
*reply
;
2901 size_t basic_offset
;
2902 uint16_t eth_type
= (OVS_FORCE
uint16_t) flower
->key
.eth_type
;
2904 request_from_tcf_id(id
, eth_type
, RTM_NEWTFILTER
,
2905 NLM_F_CREATE
| NLM_F_ECHO
, &request
);
2907 nl_msg_put_string(&request
, TCA_KIND
, "flower");
2908 basic_offset
= nl_msg_start_nested(&request
, TCA_OPTIONS
);
2910 error
= nl_msg_put_flower_options(&request
, flower
);
2913 ofpbuf_uninit(&request
);
2917 nl_msg_end_nested(&request
, basic_offset
);
2919 error
= tc_transact(&request
, &reply
);
2922 ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
2924 id
->prio
= tc_get_major(tc
->tcm_info
);
2925 id
->handle
= tc
->tcm_handle
;
2926 ofpbuf_delete(reply
);
2933 tc_set_policy(const char *policy
)
2939 if (!strcmp(policy
, "skip_sw")) {
2940 tc_policy
= TC_POLICY_SKIP_SW
;
2941 } else if (!strcmp(policy
, "skip_hw")) {
2942 tc_policy
= TC_POLICY_SKIP_HW
;
2943 } else if (!strcmp(policy
, "none")) {
2944 tc_policy
= TC_POLICY_NONE
;
2946 VLOG_WARN("tc: Invalid policy '%s'", policy
);
2950 VLOG_INFO("tc: Using policy '%s'", policy
);