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)
56 #define TCA_INGRESS_BLOCK 13
59 VLOG_DEFINE_THIS_MODULE(tc
);
61 static struct vlog_rate_limit error_rl
= VLOG_RATE_LIMIT_INIT(60, 5);
63 enum tc_offload_policy
{
69 static enum tc_offload_policy tc_policy
= TC_POLICY_NONE
;
71 struct tc_pedit_key_ex
{
72 enum pedit_header_type htype
;
76 struct flower_key_to_pedit
{
77 enum pedit_header_type htype
;
84 static struct flower_key_to_pedit flower_pedit_map
[] = {
86 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
88 offsetof(struct tc_flower_key
, ipv4
.ipv4_src
),
89 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.ipv4_src
),
92 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
94 offsetof(struct tc_flower_key
, ipv4
.ipv4_dst
),
95 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.ipv4_dst
),
98 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
100 offsetof(struct tc_flower_key
, ipv4
.rewrite_ttl
),
101 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.rewrite_ttl
),
104 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
106 offsetof(struct tc_flower_key
, ipv4
.rewrite_tos
),
107 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.rewrite_tos
),
110 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
112 offsetof(struct tc_flower_key
, ipv6
.rewrite_hlimit
),
113 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.rewrite_hlimit
),
116 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
118 offsetof(struct tc_flower_key
, ipv6
.ipv6_src
),
119 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.ipv6_src
),
122 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
124 offsetof(struct tc_flower_key
, ipv6
.ipv6_dst
),
125 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.ipv6_dst
),
128 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
130 offsetof(struct tc_flower_key
, ipv6
.rewrite_tclass
),
131 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.rewrite_tclass
),
134 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
136 offsetof(struct tc_flower_key
, src_mac
),
137 MEMBER_SIZEOF(struct tc_flower_key
, src_mac
),
140 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
142 offsetof(struct tc_flower_key
, dst_mac
),
143 MEMBER_SIZEOF(struct tc_flower_key
, dst_mac
),
146 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
148 offsetof(struct tc_flower_key
, eth_type
),
149 MEMBER_SIZEOF(struct tc_flower_key
, eth_type
),
152 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
,
154 offsetof(struct tc_flower_key
, tcp_src
),
155 MEMBER_SIZEOF(struct tc_flower_key
, tcp_src
),
158 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
,
160 offsetof(struct tc_flower_key
, tcp_dst
),
161 MEMBER_SIZEOF(struct tc_flower_key
, tcp_dst
),
164 TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
,
166 offsetof(struct tc_flower_key
, udp_src
),
167 MEMBER_SIZEOF(struct tc_flower_key
, udp_src
),
170 TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
,
172 offsetof(struct tc_flower_key
, udp_dst
),
173 MEMBER_SIZEOF(struct tc_flower_key
, udp_dst
),
179 csum_update_flag(struct tc_flower
*flower
,
180 enum pedit_header_type htype
);
183 tc_make_request(int ifindex
, int type
, unsigned int flags
,
184 struct ofpbuf
*request
)
188 ofpbuf_init(request
, 512);
189 nl_msg_put_nlmsghdr(request
, sizeof *tcmsg
, type
, NLM_F_REQUEST
| flags
);
190 tcmsg
= ofpbuf_put_zeros(request
, sizeof *tcmsg
);
191 tcmsg
->tcm_family
= AF_UNSPEC
;
192 tcmsg
->tcm_ifindex
= ifindex
;
193 /* Caller should fill in tcmsg->tcm_handle. */
194 /* Caller should fill in tcmsg->tcm_parent. */
199 static void request_from_tcf_id(struct tcf_id
*id
, uint16_t eth_type
,
200 int type
, unsigned int flags
,
201 struct ofpbuf
*request
)
203 int ifindex
= id
->block_id
? TCM_IFINDEX_MAGIC_BLOCK
: id
->ifindex
;
204 uint32_t ingress_parent
= id
->block_id
? : TC_INGRESS_PARENT
;
207 tcmsg
= tc_make_request(ifindex
, type
, flags
, request
);
208 tcmsg
->tcm_parent
= (id
->hook
== TC_EGRESS
) ?
209 TC_EGRESS_PARENT
: ingress_parent
;
210 tcmsg
->tcm_info
= tc_make_handle(id
->prio
, eth_type
);
211 tcmsg
->tcm_handle
= id
->handle
;
214 nl_msg_put_u32(request
, TCA_CHAIN
, id
->chain
);
219 tc_transact(struct ofpbuf
*request
, struct ofpbuf
**replyp
)
221 int error
= nl_transact(NETLINK_ROUTE
, request
, replyp
);
222 ofpbuf_uninit(request
);
226 /* Adds or deletes a root qdisc on device with specified ifindex.
228 * The tc_qdisc_hook parameter determines if the qdisc is added on device
231 * If tc_qdisc_hook is TC_INGRESS, this function is equivalent to running the
232 * following when 'add' is true:
233 * /sbin/tc qdisc add dev <devname> handle ffff: ingress
235 * This function is equivalent to running the following when 'add' is false:
236 * /sbin/tc qdisc del dev <devname> handle ffff: ingress
238 * If tc_qdisc_hook is TC_EGRESS, this function is equivalent to:
239 * /sbin/tc qdisc (add|del) dev <devname> handle ffff: clsact
241 * Where dev <devname> is the device with specified ifindex name.
243 * The configuration and stats may be seen with the following command:
244 * /sbin/tc -s qdisc show dev <devname>
246 * If block_id is greater than 0, then the ingress qdisc is added to a block.
247 * In this case, it is equivalent to running (when 'add' is true):
248 * /sbin/tc qdisc add dev <devname> ingress_block <block_id> ingress
250 * Returns 0 if successful, otherwise a positive errno value.
253 tc_add_del_qdisc(int ifindex
, bool add
, uint32_t block_id
,
254 enum tc_qdisc_hook hook
)
256 struct ofpbuf request
;
259 int type
= add
? RTM_NEWQDISC
: RTM_DELQDISC
;
260 int flags
= add
? NLM_F_EXCL
| NLM_F_CREATE
: 0;
262 tcmsg
= tc_make_request(ifindex
, type
, flags
, &request
);
264 if (hook
== TC_EGRESS
) {
265 tcmsg
->tcm_handle
= TC_H_MAKE(TC_H_CLSACT
, 0);
266 tcmsg
->tcm_parent
= TC_H_CLSACT
;
267 nl_msg_put_string(&request
, TCA_KIND
, "clsact");
269 tcmsg
->tcm_handle
= TC_H_MAKE(TC_H_INGRESS
, 0);
270 tcmsg
->tcm_parent
= TC_H_INGRESS
;
271 nl_msg_put_string(&request
, TCA_KIND
, "ingress");
274 nl_msg_put_unspec(&request
, TCA_OPTIONS
, NULL
, 0);
275 if (hook
== TC_INGRESS
&& block_id
) {
276 nl_msg_put_u32(&request
, TCA_INGRESS_BLOCK
, block_id
);
279 error
= tc_transact(&request
, NULL
);
281 /* If we're deleting the qdisc, don't worry about some of the
282 * error conditions. */
283 if (!add
&& (error
== ENOENT
|| error
== EINVAL
)) {
292 static const struct nl_policy tca_policy
[] = {
293 [TCA_KIND
] = { .type
= NL_A_STRING
, .optional
= false, },
294 [TCA_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= false, },
295 [TCA_CHAIN
] = { .type
= NL_A_U32
, .optional
= true, },
296 [TCA_STATS
] = { .type
= NL_A_UNSPEC
,
297 .min_len
= sizeof(struct tc_stats
), .optional
= true, },
298 [TCA_STATS2
] = { .type
= NL_A_NESTED
, .optional
= true, },
301 static const struct nl_policy tca_flower_policy
[] = {
302 [TCA_FLOWER_CLASSID
] = { .type
= NL_A_U32
, .optional
= true, },
303 [TCA_FLOWER_INDEV
] = { .type
= NL_A_STRING
, .max_len
= IFNAMSIZ
,
305 [TCA_FLOWER_KEY_ETH_SRC
] = { .type
= NL_A_UNSPEC
,
306 .min_len
= ETH_ALEN
, .optional
= true, },
307 [TCA_FLOWER_KEY_ETH_DST
] = { .type
= NL_A_UNSPEC
,
308 .min_len
= ETH_ALEN
, .optional
= true, },
309 [TCA_FLOWER_KEY_ETH_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
312 [TCA_FLOWER_KEY_ETH_DST_MASK
] = { .type
= NL_A_UNSPEC
,
315 [TCA_FLOWER_KEY_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= false, },
316 [TCA_FLOWER_FLAGS
] = { .type
= NL_A_U32
, .optional
= false, },
317 [TCA_FLOWER_ACT
] = { .type
= NL_A_NESTED
, .optional
= false, },
318 [TCA_FLOWER_KEY_IP_PROTO
] = { .type
= NL_A_U8
, .optional
= true, },
319 [TCA_FLOWER_KEY_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
320 [TCA_FLOWER_KEY_IPV4_DST
] = {.type
= NL_A_U32
, .optional
= true, },
321 [TCA_FLOWER_KEY_IPV4_SRC_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
322 [TCA_FLOWER_KEY_IPV4_DST_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
323 [TCA_FLOWER_KEY_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
324 .min_len
= sizeof(struct in6_addr
),
326 [TCA_FLOWER_KEY_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
327 .min_len
= sizeof(struct in6_addr
),
329 [TCA_FLOWER_KEY_IPV6_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
330 .min_len
= sizeof(struct in6_addr
),
332 [TCA_FLOWER_KEY_IPV6_DST_MASK
] = { .type
= NL_A_UNSPEC
,
333 .min_len
= sizeof(struct in6_addr
),
335 [TCA_FLOWER_KEY_TCP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
336 [TCA_FLOWER_KEY_TCP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
337 [TCA_FLOWER_KEY_TCP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
338 [TCA_FLOWER_KEY_TCP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
339 [TCA_FLOWER_KEY_UDP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
340 [TCA_FLOWER_KEY_UDP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
341 [TCA_FLOWER_KEY_UDP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
342 [TCA_FLOWER_KEY_UDP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
343 [TCA_FLOWER_KEY_SCTP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
344 [TCA_FLOWER_KEY_SCTP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
345 [TCA_FLOWER_KEY_SCTP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
346 [TCA_FLOWER_KEY_SCTP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
347 [TCA_FLOWER_KEY_MPLS_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
348 [TCA_FLOWER_KEY_MPLS_TC
] = { .type
= NL_A_U8
, .optional
= true, },
349 [TCA_FLOWER_KEY_MPLS_BOS
] = { .type
= NL_A_U8
, .optional
= true, },
350 [TCA_FLOWER_KEY_MPLS_LABEL
] = { .type
= NL_A_U32
, .optional
= true, },
351 [TCA_FLOWER_KEY_VLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
352 [TCA_FLOWER_KEY_VLAN_PRIO
] = { .type
= NL_A_U8
, .optional
= true, },
353 [TCA_FLOWER_KEY_VLAN_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= true, },
354 [TCA_FLOWER_KEY_ENC_KEY_ID
] = { .type
= NL_A_U32
, .optional
= true, },
355 [TCA_FLOWER_KEY_ENC_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
356 [TCA_FLOWER_KEY_ENC_IPV4_DST
] = { .type
= NL_A_U32
, .optional
= true, },
357 [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
] = { .type
= NL_A_U32
,
359 [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
] = { .type
= NL_A_U32
,
361 [TCA_FLOWER_KEY_ENC_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
362 .min_len
= sizeof(struct in6_addr
),
364 [TCA_FLOWER_KEY_ENC_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
365 .min_len
= sizeof(struct in6_addr
),
367 [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
368 .min_len
= sizeof(struct in6_addr
),
370 [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
] = { .type
= NL_A_UNSPEC
,
371 .min_len
= sizeof(struct in6_addr
),
373 [TCA_FLOWER_KEY_ENC_UDP_DST_PORT
] = { .type
= NL_A_U16
,
375 [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT
] = { .type
= NL_A_U16
,
377 [TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK
] = { .type
= NL_A_U16
,
379 [TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK
] = { .type
= NL_A_U16
,
381 [TCA_FLOWER_KEY_FLAGS
] = { .type
= NL_A_BE32
, .optional
= true, },
382 [TCA_FLOWER_KEY_FLAGS_MASK
] = { .type
= NL_A_BE32
, .optional
= true, },
383 [TCA_FLOWER_KEY_IP_TTL
] = { .type
= NL_A_U8
,
385 [TCA_FLOWER_KEY_IP_TTL_MASK
] = { .type
= NL_A_U8
,
387 [TCA_FLOWER_KEY_IP_TOS
] = { .type
= NL_A_U8
,
389 [TCA_FLOWER_KEY_IP_TOS_MASK
] = { .type
= NL_A_U8
,
391 [TCA_FLOWER_KEY_TCP_FLAGS
] = { .type
= NL_A_U16
,
393 [TCA_FLOWER_KEY_TCP_FLAGS_MASK
] = { .type
= NL_A_U16
,
395 [TCA_FLOWER_KEY_CVLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
396 [TCA_FLOWER_KEY_CVLAN_PRIO
] = { .type
= NL_A_U8
, .optional
= true, },
397 [TCA_FLOWER_KEY_CVLAN_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= true, },
398 [TCA_FLOWER_KEY_ENC_IP_TOS
] = { .type
= NL_A_U8
,
400 [TCA_FLOWER_KEY_ENC_IP_TOS_MASK
] = { .type
= NL_A_U8
,
402 [TCA_FLOWER_KEY_ENC_IP_TTL
] = { .type
= NL_A_U8
,
404 [TCA_FLOWER_KEY_ENC_IP_TTL_MASK
] = { .type
= NL_A_U8
,
406 [TCA_FLOWER_KEY_ENC_OPTS
] = { .type
= NL_A_NESTED
, .optional
= true, },
407 [TCA_FLOWER_KEY_ENC_OPTS_MASK
] = { .type
= NL_A_NESTED
,
409 [TCA_FLOWER_KEY_CT_STATE
] = { .type
= NL_A_U16
, .optional
= true, },
410 [TCA_FLOWER_KEY_CT_STATE_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
411 [TCA_FLOWER_KEY_CT_ZONE
] = { .type
= NL_A_U16
, .optional
= true, },
412 [TCA_FLOWER_KEY_CT_ZONE_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
413 [TCA_FLOWER_KEY_CT_MARK
] = { .type
= NL_A_U32
, .optional
= true, },
414 [TCA_FLOWER_KEY_CT_MARK_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
415 [TCA_FLOWER_KEY_CT_LABELS
] = { .type
= NL_A_U128
, .optional
= true, },
416 [TCA_FLOWER_KEY_CT_LABELS_MASK
] = { .type
= NL_A_U128
,
421 nl_parse_flower_eth(struct nlattr
**attrs
, struct tc_flower
*flower
)
423 const struct eth_addr
*eth
;
425 if (attrs
[TCA_FLOWER_KEY_ETH_SRC_MASK
]) {
426 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_SRC
], ETH_ALEN
);
427 memcpy(&flower
->key
.src_mac
, eth
, sizeof flower
->key
.src_mac
);
429 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_SRC_MASK
], ETH_ALEN
);
430 memcpy(&flower
->mask
.src_mac
, eth
, sizeof flower
->mask
.src_mac
);
432 if (attrs
[TCA_FLOWER_KEY_ETH_DST_MASK
]) {
433 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_DST
], ETH_ALEN
);
434 memcpy(&flower
->key
.dst_mac
, eth
, sizeof flower
->key
.dst_mac
);
436 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_DST_MASK
], ETH_ALEN
);
437 memcpy(&flower
->mask
.dst_mac
, eth
, sizeof flower
->mask
.dst_mac
);
442 nl_parse_flower_mpls(struct nlattr
**attrs
, struct tc_flower
*flower
)
444 uint8_t ttl
, tc
, bos
;
447 if (!eth_type_mpls(flower
->key
.eth_type
)) {
451 flower
->key
.encap_eth_type
[0] =
452 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ETH_TYPE
]);
453 flower
->key
.mpls_lse
= 0;
454 flower
->mask
.mpls_lse
= 0;
456 if (attrs
[TCA_FLOWER_KEY_MPLS_TTL
]) {
457 ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_MPLS_TTL
]);
458 set_mpls_lse_ttl(&flower
->key
.mpls_lse
, ttl
);
459 set_mpls_lse_ttl(&flower
->mask
.mpls_lse
, 0xff);
462 if (attrs
[TCA_FLOWER_KEY_MPLS_BOS
]) {
463 bos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_MPLS_BOS
]);
464 set_mpls_lse_bos(&flower
->key
.mpls_lse
, bos
);
465 set_mpls_lse_ttl(&flower
->mask
.mpls_lse
, 0xff);
468 if (attrs
[TCA_FLOWER_KEY_MPLS_TC
]) {
469 tc
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_MPLS_TC
]);
470 set_mpls_lse_tc(&flower
->key
.mpls_lse
, tc
);
471 set_mpls_lse_tc(&flower
->mask
.mpls_lse
, 0xff);
474 if (attrs
[TCA_FLOWER_KEY_MPLS_LABEL
]) {
475 label
= nl_attr_get_u32(attrs
[TCA_FLOWER_KEY_MPLS_LABEL
]);
476 set_mpls_lse_label(&flower
->key
.mpls_lse
, htonl(label
));
477 set_mpls_lse_label(&flower
->mask
.mpls_lse
, OVS_BE32_MAX
);
482 nl_parse_flower_vlan(struct nlattr
**attrs
, struct tc_flower
*flower
)
484 ovs_be16 encap_ethtype
;
486 if (!eth_type_vlan(flower
->key
.eth_type
)) {
490 flower
->key
.encap_eth_type
[0] =
491 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ETH_TYPE
]);
493 if (attrs
[TCA_FLOWER_KEY_VLAN_ID
]) {
494 flower
->key
.vlan_id
[0] =
495 nl_attr_get_u16(attrs
[TCA_FLOWER_KEY_VLAN_ID
]);
496 flower
->mask
.vlan_id
[0] = 0xffff;
498 if (attrs
[TCA_FLOWER_KEY_VLAN_PRIO
]) {
499 flower
->key
.vlan_prio
[0] =
500 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_VLAN_PRIO
]);
501 flower
->mask
.vlan_prio
[0] = 0xff;
504 if (!attrs
[TCA_FLOWER_KEY_VLAN_ETH_TYPE
]) {
508 encap_ethtype
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_VLAN_ETH_TYPE
]);
509 if (!eth_type_vlan(encap_ethtype
)) {
513 flower
->key
.encap_eth_type
[1] = flower
->key
.encap_eth_type
[0];
514 flower
->key
.encap_eth_type
[0] = encap_ethtype
;
516 if (attrs
[TCA_FLOWER_KEY_CVLAN_ID
]) {
517 flower
->key
.vlan_id
[1] =
518 nl_attr_get_u16(attrs
[TCA_FLOWER_KEY_CVLAN_ID
]);
519 flower
->mask
.vlan_id
[1] = 0xffff;
521 if (attrs
[TCA_FLOWER_KEY_CVLAN_PRIO
]) {
522 flower
->key
.vlan_prio
[1] =
523 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_CVLAN_PRIO
]);
524 flower
->mask
.vlan_prio
[1] = 0xff;
529 nl_parse_geneve_key(const struct nlattr
*in_nlattr
,
530 struct tun_metadata
*metadata
)
532 struct geneve_opt
*opt
= NULL
;
533 const struct ofpbuf
*msg
;
534 uint16_t last_opt_type
;
540 nl_attr_get_nested(in_nlattr
, &buf
);
543 last_opt_type
= TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC
;
545 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
546 uint16_t type
= nl_attr_type(nla
);
549 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
:
550 if (cnt
&& last_opt_type
!= TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
) {
551 VLOG_ERR_RL(&error_rl
, "failed to parse tun options class");
555 opt
= &metadata
->opts
.gnv
[cnt
];
556 opt
->opt_class
= nl_attr_get_be16(nla
);
557 cnt
+= sizeof(struct geneve_opt
) / 4;
558 metadata
->present
.len
+= sizeof(struct geneve_opt
);
559 last_opt_type
= TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
;
561 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
:
562 if (last_opt_type
!= TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
) {
563 VLOG_ERR_RL(&error_rl
, "failed to parse tun options type");
567 opt
->type
= nl_attr_get_u8(nla
);
568 last_opt_type
= TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
;
570 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
:
571 if (last_opt_type
!= TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
) {
572 VLOG_ERR_RL(&error_rl
, "failed to parse tun options data");
576 opt
->length
= nl_attr_get_size(nla
) / 4;
577 memcpy(opt
+ 1, nl_attr_get_unspec(nla
, 1), opt
->length
* 4);
579 metadata
->present
.len
+= opt
->length
* 4;
580 last_opt_type
= TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
;
585 if (last_opt_type
!= TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
) {
586 VLOG_ERR_RL(&error_rl
, "failed to parse tun options without data");
594 nl_parse_flower_tunnel_opts(struct nlattr
*options
,
595 struct tun_metadata
*metadata
)
597 const struct ofpbuf
*msg
;
603 nl_attr_get_nested(options
, &buf
);
606 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
607 uint16_t type
= nl_attr_type(nla
);
609 case TCA_FLOWER_KEY_ENC_OPTS_GENEVE
:
610 err
= nl_parse_geneve_key(nla
, metadata
);
623 flower_tun_geneve_opt_check_len(struct tun_metadata
*key
,
624 struct tun_metadata
*mask
)
626 const struct geneve_opt
*opt
, *opt_mask
;
629 len
= key
->present
.len
;
631 opt
= &key
->opts
.gnv
[cnt
];
632 opt_mask
= &mask
->opts
.gnv
[cnt
];
634 if (opt
->length
!= opt_mask
->length
) {
635 VLOG_ERR_RL(&error_rl
,
636 "failed to parse tun options; key/mask length differ");
640 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
641 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
648 nl_parse_flower_tunnel(struct nlattr
**attrs
, struct tc_flower
*flower
)
652 if (attrs
[TCA_FLOWER_KEY_ENC_KEY_ID
]) {
653 ovs_be32 id
= nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_KEY_ID
]);
655 flower
->key
.tunnel
.id
= be32_to_be64(id
);
656 flower
->mask
.tunnel
.id
= OVS_BE64_MAX
;
658 if (attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
]) {
659 flower
->mask
.tunnel
.ipv4
.ipv4_src
=
660 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
]);
661 flower
->key
.tunnel
.ipv4
.ipv4_src
=
662 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC
]);
664 if (attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
]) {
665 flower
->mask
.tunnel
.ipv4
.ipv4_dst
=
666 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
]);
667 flower
->key
.tunnel
.ipv4
.ipv4_dst
=
668 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST
]);
670 if (attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
]) {
671 flower
->mask
.tunnel
.ipv6
.ipv6_src
=
672 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
]);
673 flower
->key
.tunnel
.ipv6
.ipv6_src
=
674 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC
]);
676 if (attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
]) {
677 flower
->mask
.tunnel
.ipv6
.ipv6_dst
=
678 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
]);
679 flower
->key
.tunnel
.ipv6
.ipv6_dst
=
680 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST
]);
682 if (attrs
[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK
]) {
683 flower
->mask
.tunnel
.tp_src
=
684 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK
]);
685 flower
->key
.tunnel
.tp_src
=
686 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT
]);
688 if (attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK
]) {
689 flower
->mask
.tunnel
.tp_dst
=
690 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK
]);
691 flower
->key
.tunnel
.tp_dst
=
692 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]);
694 if (attrs
[TCA_FLOWER_KEY_ENC_IP_TOS_MASK
]) {
695 flower
->key
.tunnel
.tos
=
696 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TOS
]);
697 flower
->mask
.tunnel
.tos
=
698 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TOS_MASK
]);
700 if (attrs
[TCA_FLOWER_KEY_ENC_IP_TTL_MASK
]) {
701 flower
->key
.tunnel
.ttl
=
702 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TTL
]);
703 flower
->mask
.tunnel
.ttl
=
704 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TTL_MASK
]);
707 if (!is_all_zeros(&flower
->mask
.tunnel
, sizeof flower
->mask
.tunnel
) ||
708 !is_all_zeros(&flower
->key
.tunnel
, sizeof flower
->key
.tunnel
)) {
709 flower
->tunnel
= true;
712 if (attrs
[TCA_FLOWER_KEY_ENC_OPTS
] &&
713 attrs
[TCA_FLOWER_KEY_ENC_OPTS_MASK
]) {
714 err
= nl_parse_flower_tunnel_opts(attrs
[TCA_FLOWER_KEY_ENC_OPTS
],
715 &flower
->key
.tunnel
.metadata
);
720 err
= nl_parse_flower_tunnel_opts(attrs
[TCA_FLOWER_KEY_ENC_OPTS_MASK
],
721 &flower
->mask
.tunnel
.metadata
);
726 err
= flower_tun_geneve_opt_check_len(&flower
->key
.tunnel
.metadata
,
727 &flower
->mask
.tunnel
.metadata
);
731 } else if (attrs
[TCA_FLOWER_KEY_ENC_OPTS
]) {
732 VLOG_ERR_RL(&error_rl
,
733 "failed to parse tun options; no mask supplied");
735 } else if (attrs
[TCA_FLOWER_KEY_ENC_OPTS_MASK
]) {
736 VLOG_ERR_RL(&error_rl
, "failed to parse tun options; no key supplied");
744 nl_parse_flower_ct_match(struct nlattr
**attrs
, struct tc_flower
*flower
) {
745 struct tc_flower_key
*key
= &flower
->key
;
746 struct tc_flower_key
*mask
= &flower
->mask
;
747 struct nlattr
*attr_key
, *attr_mask
;
749 attr_key
= attrs
[TCA_FLOWER_KEY_CT_STATE
];
750 attr_mask
= attrs
[TCA_FLOWER_KEY_CT_STATE_MASK
];
752 key
->ct_state
= nl_attr_get_u16(attr_key
);
753 mask
->ct_state
= nl_attr_get_u16(attr_mask
);
756 attr_key
= attrs
[TCA_FLOWER_KEY_CT_ZONE
];
757 attr_mask
= attrs
[TCA_FLOWER_KEY_CT_ZONE_MASK
];
758 if (attrs
[TCA_FLOWER_KEY_CT_ZONE_MASK
]) {
759 key
->ct_zone
= nl_attr_get_u16(attr_key
);
760 mask
->ct_zone
= nl_attr_get_u16(attr_mask
);
763 attr_key
= attrs
[TCA_FLOWER_KEY_CT_MARK
];
764 attr_mask
= attrs
[TCA_FLOWER_KEY_CT_MARK_MASK
];
765 if (attrs
[TCA_FLOWER_KEY_CT_MARK_MASK
]) {
766 key
->ct_mark
= nl_attr_get_u32(attr_key
);
767 mask
->ct_mark
= nl_attr_get_u32(attr_mask
);
770 attr_key
= attrs
[TCA_FLOWER_KEY_CT_LABELS
];
771 attr_mask
= attrs
[TCA_FLOWER_KEY_CT_LABELS_MASK
];
772 if (attrs
[TCA_FLOWER_KEY_CT_LABELS_MASK
]) {
773 key
->ct_label
= nl_attr_get_u128(attr_key
);
774 mask
->ct_label
= nl_attr_get_u128(attr_mask
);
779 nl_parse_flower_ip(struct nlattr
**attrs
, struct tc_flower
*flower
) {
780 uint8_t ip_proto
= 0;
781 struct tc_flower_key
*key
= &flower
->key
;
782 struct tc_flower_key
*mask
= &flower
->mask
;
784 if (attrs
[TCA_FLOWER_KEY_IP_PROTO
]) {
785 ip_proto
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_PROTO
]);
786 key
->ip_proto
= ip_proto
;
787 mask
->ip_proto
= UINT8_MAX
;
790 if (attrs
[TCA_FLOWER_KEY_FLAGS_MASK
]) {
791 key
->flags
= ntohl(nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_FLAGS
]));
793 ntohl(nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_FLAGS_MASK
]));
796 if (attrs
[TCA_FLOWER_KEY_IPV4_SRC_MASK
]) {
798 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_SRC
]);
799 mask
->ipv4
.ipv4_src
=
800 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_SRC_MASK
]);
802 if (attrs
[TCA_FLOWER_KEY_IPV4_DST_MASK
]) {
804 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_DST
]);
805 mask
->ipv4
.ipv4_dst
=
806 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_DST_MASK
]);
808 if (attrs
[TCA_FLOWER_KEY_IPV6_SRC_MASK
]) {
809 struct nlattr
*attr
= attrs
[TCA_FLOWER_KEY_IPV6_SRC
];
810 struct nlattr
*attr_mask
= attrs
[TCA_FLOWER_KEY_IPV6_SRC_MASK
];
812 key
->ipv6
.ipv6_src
= nl_attr_get_in6_addr(attr
);
813 mask
->ipv6
.ipv6_src
= nl_attr_get_in6_addr(attr_mask
);
815 if (attrs
[TCA_FLOWER_KEY_IPV6_DST_MASK
]) {
816 struct nlattr
*attr
= attrs
[TCA_FLOWER_KEY_IPV6_DST
];
817 struct nlattr
*attr_mask
= attrs
[TCA_FLOWER_KEY_IPV6_DST_MASK
];
819 key
->ipv6
.ipv6_dst
= nl_attr_get_in6_addr(attr
);
820 mask
->ipv6
.ipv6_dst
= nl_attr_get_in6_addr(attr_mask
);
823 if (ip_proto
== IPPROTO_TCP
) {
824 if (attrs
[TCA_FLOWER_KEY_TCP_SRC_MASK
]) {
826 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_SRC
]);
828 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_SRC_MASK
]);
830 if (attrs
[TCA_FLOWER_KEY_TCP_DST_MASK
]) {
832 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_DST
]);
834 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_DST_MASK
]);
836 if (attrs
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]) {
838 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_FLAGS
]);
840 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]);
842 } else if (ip_proto
== IPPROTO_UDP
) {
843 if (attrs
[TCA_FLOWER_KEY_UDP_SRC_MASK
]) {
844 key
->udp_src
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_SRC
]);
846 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_SRC_MASK
]);
848 if (attrs
[TCA_FLOWER_KEY_UDP_DST_MASK
]) {
849 key
->udp_dst
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_DST
]);
851 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_DST_MASK
]);
853 } else if (ip_proto
== IPPROTO_SCTP
) {
854 if (attrs
[TCA_FLOWER_KEY_SCTP_SRC_MASK
]) {
855 key
->sctp_src
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_SRC
]);
857 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_SRC_MASK
]);
859 if (attrs
[TCA_FLOWER_KEY_SCTP_DST_MASK
]) {
860 key
->sctp_dst
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_DST
]);
862 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_DST_MASK
]);
866 if (attrs
[TCA_FLOWER_KEY_IP_TTL_MASK
]) {
867 key
->ip_ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TTL
]);
868 mask
->ip_ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TTL_MASK
]);
871 if (attrs
[TCA_FLOWER_KEY_IP_TOS_MASK
]) {
872 key
->ip_tos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TOS
]);
873 mask
->ip_tos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TOS_MASK
]);
876 nl_parse_flower_ct_match(attrs
, flower
);
879 static enum tc_offloaded_state
880 nl_get_flower_offloaded_state(struct nlattr
**attrs
)
882 uint32_t flower_flags
= 0;
884 if (attrs
[TCA_FLOWER_FLAGS
]) {
885 flower_flags
= nl_attr_get_u32(attrs
[TCA_FLOWER_FLAGS
]);
886 if (flower_flags
& TCA_CLS_FLAGS_NOT_IN_HW
) {
887 return TC_OFFLOADED_STATE_NOT_IN_HW
;
888 } else if (flower_flags
& TCA_CLS_FLAGS_IN_HW
) {
889 return TC_OFFLOADED_STATE_IN_HW
;
892 return TC_OFFLOADED_STATE_UNDEFINED
;
896 nl_parse_flower_flags(struct nlattr
**attrs
, struct tc_flower
*flower
)
898 flower
->offloaded_state
= nl_get_flower_offloaded_state(attrs
);
901 static const struct nl_policy pedit_policy
[] = {
902 [TCA_PEDIT_PARMS_EX
] = { .type
= NL_A_UNSPEC
,
903 .min_len
= sizeof(struct tc_pedit
),
904 .optional
= false, },
905 [TCA_PEDIT_KEYS_EX
] = { .type
= NL_A_NESTED
,
906 .optional
= false, },
910 nl_parse_act_pedit(struct nlattr
*options
, struct tc_flower
*flower
)
912 struct tc_action
*action
;
913 struct nlattr
*pe_attrs
[ARRAY_SIZE(pedit_policy
)];
914 const struct tc_pedit
*pe
;
915 const struct tc_pedit_key
*keys
;
916 const struct nlattr
*nla
, *keys_ex
, *ex_type
;
917 const void *keys_attr
;
918 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
919 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
920 size_t keys_ex_size
, left
;
921 int type
, i
= 0, err
;
923 if (!nl_parse_nested(options
, pedit_policy
, pe_attrs
,
924 ARRAY_SIZE(pedit_policy
))) {
925 VLOG_ERR_RL(&error_rl
, "failed to parse pedit action options");
929 pe
= nl_attr_get_unspec(pe_attrs
[TCA_PEDIT_PARMS_EX
], sizeof *pe
);
931 keys_attr
= pe_attrs
[TCA_PEDIT_KEYS_EX
];
932 keys_ex
= nl_attr_get(keys_attr
);
933 keys_ex_size
= nl_attr_get_size(keys_attr
);
935 NL_ATTR_FOR_EACH (nla
, left
, keys_ex
, keys_ex_size
) {
936 if (i
>= pe
->nkeys
) {
940 if (nl_attr_type(nla
) != TCA_PEDIT_KEY_EX
) {
941 VLOG_ERR_RL(&error_rl
, "unable to parse legacy pedit type: %d",
946 ex_type
= nl_attr_find_nested(nla
, TCA_PEDIT_KEY_EX_HTYPE
);
947 type
= nl_attr_get_u16(ex_type
);
949 err
= csum_update_flag(flower
, type
);
954 for (int j
= 0; j
< ARRAY_SIZE(flower_pedit_map
); j
++) {
955 struct flower_key_to_pedit
*m
= &flower_pedit_map
[j
];
956 int flower_off
= m
->flower_offset
;
960 if (m
->htype
!= type
) {
964 /* check overlap between current pedit key, which is always
965 * 4 bytes (range [off, off + 3]), and a map entry in
966 * flower_pedit_map (range [mf, mf + sz - 1]) */
967 if ((keys
->off
>= mf
&& keys
->off
< mf
+ sz
)
968 || (keys
->off
+ 3 >= mf
&& keys
->off
+ 3 < mf
+ sz
)) {
969 int diff
= flower_off
+ (keys
->off
- mf
);
970 ovs_be32
*dst
= (void *) (rewrite_key
+ diff
);
971 ovs_be32
*dst_m
= (void *) (rewrite_mask
+ diff
);
972 ovs_be32 mask
, mask_word
, data_word
;
975 mask_word
= htonl(ntohl(keys
->mask
) << m
->boundary_shift
);
976 data_word
= htonl(ntohl(keys
->val
) << m
->boundary_shift
);
979 if (keys
->off
< mf
) {
980 zero_bits
= 8 * (mf
- keys
->off
);
981 mask
&= htonl(UINT32_MAX
>> zero_bits
);
982 } else if (keys
->off
+ 4 > mf
+ m
->size
) {
983 zero_bits
= 8 * (keys
->off
+ 4 - mf
- m
->size
);
984 mask
&= htonl(UINT32_MAX
<< zero_bits
);
988 *dst
|= data_word
& mask
;
996 action
= &flower
->actions
[flower
->action_count
++];
997 action
->type
= TC_ACT_PEDIT
;
1002 static const struct nl_policy tunnel_key_policy
[] = {
1003 [TCA_TUNNEL_KEY_PARMS
] = { .type
= NL_A_UNSPEC
,
1004 .min_len
= sizeof(struct tc_tunnel_key
),
1005 .optional
= false, },
1006 [TCA_TUNNEL_KEY_ENC_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
1007 [TCA_TUNNEL_KEY_ENC_IPV4_DST
] = { .type
= NL_A_U32
, .optional
= true, },
1008 [TCA_TUNNEL_KEY_ENC_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
1009 .min_len
= sizeof(struct in6_addr
),
1010 .optional
= true, },
1011 [TCA_TUNNEL_KEY_ENC_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
1012 .min_len
= sizeof(struct in6_addr
),
1013 .optional
= true, },
1014 [TCA_TUNNEL_KEY_ENC_KEY_ID
] = { .type
= NL_A_U32
, .optional
= true, },
1015 [TCA_TUNNEL_KEY_ENC_DST_PORT
] = { .type
= NL_A_U16
, .optional
= true, },
1016 [TCA_TUNNEL_KEY_ENC_TOS
] = { .type
= NL_A_U8
, .optional
= true, },
1017 [TCA_TUNNEL_KEY_ENC_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
1018 [TCA_TUNNEL_KEY_ENC_OPTS
] = { .type
= NL_A_NESTED
, .optional
= true, },
1019 [TCA_TUNNEL_KEY_NO_CSUM
] = { .type
= NL_A_U8
, .optional
= true, },
1023 nl_parse_act_geneve_opts(const struct nlattr
*in_nlattr
,
1024 struct tc_action
*action
)
1026 struct geneve_opt
*opt
= NULL
;
1027 const struct ofpbuf
*msg
;
1028 uint16_t last_opt_type
;
1034 nl_attr_get_nested(in_nlattr
, &buf
);
1037 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_UNSPEC
;
1039 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
1040 uint16_t type
= nl_attr_type(nla
);
1043 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
:
1044 if (cnt
&& last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
) {
1045 VLOG_ERR_RL(&error_rl
,
1046 "failed to parse action geneve options class");
1050 opt
= &action
->encap
.data
.opts
.gnv
[cnt
];
1051 opt
->opt_class
= nl_attr_get_be16(nla
);
1052 cnt
+= sizeof(struct geneve_opt
) / 4;
1053 action
->encap
.data
.present
.len
+= sizeof(struct geneve_opt
);
1054 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
;
1056 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
:
1057 if (last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
) {
1058 VLOG_ERR_RL(&error_rl
,
1059 "failed to parse action geneve options type");
1063 opt
->type
= nl_attr_get_u8(nla
);
1064 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
;
1066 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
:
1067 if (last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
) {
1068 VLOG_ERR_RL(&error_rl
,
1069 "failed to parse action geneve options data");
1073 opt
->length
= nl_attr_get_size(nla
) / 4;
1074 memcpy(opt
+ 1, nl_attr_get_unspec(nla
, 1), opt
->length
* 4);
1076 action
->encap
.data
.present
.len
+= opt
->length
* 4;
1077 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
;
1082 if (last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
) {
1083 VLOG_ERR_RL(&error_rl
,
1084 "failed to parse action geneve options without data");
1092 nl_parse_act_tunnel_opts(struct nlattr
*options
, struct tc_action
*action
)
1094 const struct ofpbuf
*msg
;
1104 nl_attr_get_nested(options
, &buf
);
1107 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
1108 uint16_t type
= nl_attr_type(nla
);
1110 case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
:
1111 err
= nl_parse_act_geneve_opts(nla
, action
);
1124 nl_parse_act_tunnel_key(struct nlattr
*options
, struct tc_flower
*flower
)
1126 struct nlattr
*tun_attrs
[ARRAY_SIZE(tunnel_key_policy
)];
1127 const struct nlattr
*tun_parms
;
1128 const struct tc_tunnel_key
*tun
;
1129 struct tc_action
*action
;
1132 if (!nl_parse_nested(options
, tunnel_key_policy
, tun_attrs
,
1133 ARRAY_SIZE(tunnel_key_policy
))) {
1134 VLOG_ERR_RL(&error_rl
, "failed to parse tunnel_key action options");
1138 tun_parms
= tun_attrs
[TCA_TUNNEL_KEY_PARMS
];
1139 tun
= nl_attr_get_unspec(tun_parms
, sizeof *tun
);
1140 if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_SET
) {
1141 struct nlattr
*id
= tun_attrs
[TCA_TUNNEL_KEY_ENC_KEY_ID
];
1142 struct nlattr
*dst_port
= tun_attrs
[TCA_TUNNEL_KEY_ENC_DST_PORT
];
1143 struct nlattr
*ipv4_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_SRC
];
1144 struct nlattr
*ipv4_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_DST
];
1145 struct nlattr
*ipv6_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_SRC
];
1146 struct nlattr
*ipv6_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_DST
];
1147 struct nlattr
*tos
= tun_attrs
[TCA_TUNNEL_KEY_ENC_TOS
];
1148 struct nlattr
*ttl
= tun_attrs
[TCA_TUNNEL_KEY_ENC_TTL
];
1149 struct nlattr
*tun_opt
= tun_attrs
[TCA_TUNNEL_KEY_ENC_OPTS
];
1150 struct nlattr
*no_csum
= tun_attrs
[TCA_TUNNEL_KEY_NO_CSUM
];
1152 action
= &flower
->actions
[flower
->action_count
++];
1153 action
->type
= TC_ACT_ENCAP
;
1154 action
->encap
.ipv4
.ipv4_src
= ipv4_src
? nl_attr_get_be32(ipv4_src
) : 0;
1155 action
->encap
.ipv4
.ipv4_dst
= ipv4_dst
? nl_attr_get_be32(ipv4_dst
) : 0;
1157 action
->encap
.ipv6
.ipv6_src
= nl_attr_get_in6_addr(ipv6_src
);
1160 action
->encap
.ipv6
.ipv6_dst
= nl_attr_get_in6_addr(ipv6_dst
);
1162 action
->encap
.id
= id
? be32_to_be64(nl_attr_get_be32(id
)) : 0;
1163 action
->encap
.id_present
= id
? true : false;
1164 action
->encap
.tp_dst
= dst_port
? nl_attr_get_be16(dst_port
) : 0;
1165 action
->encap
.tos
= tos
? nl_attr_get_u8(tos
) : 0;
1166 action
->encap
.ttl
= ttl
? nl_attr_get_u8(ttl
) : 0;
1167 action
->encap
.no_csum
= no_csum
? nl_attr_get_u8(no_csum
) : 0;
1169 err
= nl_parse_act_tunnel_opts(tun_opt
, action
);
1173 } else if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_RELEASE
) {
1174 flower
->tunnel
= true;
1176 VLOG_ERR_RL(&error_rl
, "unknown tunnel actions: %d, %d",
1177 tun
->action
, tun
->t_action
);
1183 static const struct nl_policy gact_policy
[] = {
1184 [TCA_GACT_PARMS
] = { .type
= NL_A_UNSPEC
,
1185 .min_len
= sizeof(struct tc_gact
),
1186 .optional
= false, },
1187 [TCA_GACT_TM
] = { .type
= NL_A_UNSPEC
,
1188 .min_len
= sizeof(struct tcf_t
),
1189 .optional
= false, },
1195 static struct ovsthread_once once
= OVSTHREAD_ONCE_INITIALIZER
;
1196 static int user_hz
= 100;
1198 if (ovsthread_once_start(&once
)) {
1199 user_hz
= sysconf(_SC_CLK_TCK
);
1200 ovsthread_once_done(&once
);
1207 nl_parse_tcf(const struct tcf_t
*tm
, struct tc_flower
*flower
)
1209 flower
->lastused
= time_msec() - (tm
->lastuse
* 1000 / get_user_hz());
1213 nl_parse_act_gact(struct nlattr
*options
, struct tc_flower
*flower
)
1215 struct nlattr
*gact_attrs
[ARRAY_SIZE(gact_policy
)];
1216 const struct tc_gact
*p
;
1217 struct nlattr
*gact_parms
;
1218 const struct tcf_t
*tm
;
1219 struct tc_action
*action
;
1221 if (!nl_parse_nested(options
, gact_policy
, gact_attrs
,
1222 ARRAY_SIZE(gact_policy
))) {
1223 VLOG_ERR_RL(&error_rl
, "failed to parse gact action options");
1227 gact_parms
= gact_attrs
[TCA_GACT_PARMS
];
1228 p
= nl_attr_get_unspec(gact_parms
, sizeof *p
);
1230 if (TC_ACT_EXT_CMP(p
->action
, TC_ACT_GOTO_CHAIN
)) {
1231 action
= &flower
->actions
[flower
->action_count
++];
1232 action
->chain
= p
->action
& TC_ACT_EXT_VAL_MASK
;
1233 action
->type
= TC_ACT_GOTO
;
1234 } else if (p
->action
!= TC_ACT_SHOT
) {
1235 VLOG_ERR_RL(&error_rl
, "unknown gact action: %d", p
->action
);
1239 tm
= nl_attr_get_unspec(gact_attrs
[TCA_GACT_TM
], sizeof *tm
);
1240 nl_parse_tcf(tm
, flower
);
1245 static const struct nl_policy mirred_policy
[] = {
1246 [TCA_MIRRED_PARMS
] = { .type
= NL_A_UNSPEC
,
1247 .min_len
= sizeof(struct tc_mirred
),
1248 .optional
= false, },
1249 [TCA_MIRRED_TM
] = { .type
= NL_A_UNSPEC
,
1250 .min_len
= sizeof(struct tcf_t
),
1251 .optional
= false, },
1255 nl_parse_act_mirred(struct nlattr
*options
, struct tc_flower
*flower
)
1258 struct nlattr
*mirred_attrs
[ARRAY_SIZE(mirred_policy
)];
1259 const struct tc_mirred
*m
;
1260 const struct nlattr
*mirred_parms
;
1261 const struct tcf_t
*tm
;
1262 struct nlattr
*mirred_tm
;
1263 struct tc_action
*action
;
1265 if (!nl_parse_nested(options
, mirred_policy
, mirred_attrs
,
1266 ARRAY_SIZE(mirred_policy
))) {
1267 VLOG_ERR_RL(&error_rl
, "failed to parse mirred action options");
1271 mirred_parms
= mirred_attrs
[TCA_MIRRED_PARMS
];
1272 m
= nl_attr_get_unspec(mirred_parms
, sizeof *m
);
1274 if (m
->eaction
!= TCA_EGRESS_REDIR
&& m
->eaction
!= TCA_EGRESS_MIRROR
&&
1275 m
->eaction
!= TCA_INGRESS_REDIR
&& m
->eaction
!= TCA_INGRESS_MIRROR
) {
1276 VLOG_ERR_RL(&error_rl
, "unknown mirred action: %d, %d, %d",
1277 m
->action
, m
->eaction
, m
->ifindex
);
1281 action
= &flower
->actions
[flower
->action_count
++];
1282 action
->out
.ifindex_out
= m
->ifindex
;
1283 if (m
->eaction
== TCA_INGRESS_REDIR
|| m
->eaction
== TCA_INGRESS_MIRROR
) {
1284 action
->out
.ingress
= true;
1286 action
->out
.ingress
= false;
1288 action
->type
= TC_ACT_OUTPUT
;
1290 mirred_tm
= mirred_attrs
[TCA_MIRRED_TM
];
1291 tm
= nl_attr_get_unspec(mirred_tm
, sizeof *tm
);
1292 nl_parse_tcf(tm
, flower
);
1297 static const struct nl_policy ct_policy
[] = {
1298 [TCA_CT_PARMS
] = { .type
= NL_A_UNSPEC
,
1299 .min_len
= sizeof(struct tc_ct
),
1300 .optional
= false, },
1301 [TCA_CT_ACTION
] = { .type
= NL_A_U16
,
1302 .optional
= true, },
1303 [TCA_CT_ZONE
] = { .type
= NL_A_U16
,
1304 .optional
= true, },
1305 [TCA_CT_MARK
] = { .type
= NL_A_U32
,
1306 .optional
= true, },
1307 [TCA_CT_MARK_MASK
] = { .type
= NL_A_U32
,
1308 .optional
= true, },
1309 [TCA_CT_LABELS
] = { .type
= NL_A_UNSPEC
,
1310 .optional
= true, },
1311 [TCA_CT_LABELS_MASK
] = { .type
= NL_A_UNSPEC
,
1312 .optional
= true, },
1313 [TCA_CT_NAT_IPV4_MIN
] = { .type
= NL_A_U32
,
1314 .optional
= true, },
1315 [TCA_CT_NAT_IPV4_MAX
] = { .type
= NL_A_U32
,
1316 .optional
= true, },
1317 [TCA_CT_NAT_IPV6_MIN
] = { .min_len
= sizeof(struct in6_addr
),
1318 .type
= NL_A_UNSPEC
,
1320 [TCA_CT_NAT_IPV6_MAX
] = { .min_len
= sizeof(struct in6_addr
),
1321 .type
= NL_A_UNSPEC
,
1323 [TCA_CT_NAT_PORT_MIN
] = { .type
= NL_A_U16
,
1324 .optional
= true, },
1325 [TCA_CT_NAT_PORT_MAX
] = { .type
= NL_A_U16
,
1326 .optional
= true, },
1330 nl_parse_act_ct(struct nlattr
*options
, struct tc_flower
*flower
)
1332 struct nlattr
*ct_attrs
[ARRAY_SIZE(ct_policy
)];
1333 const struct nlattr
*ct_parms
;
1334 struct tc_action
*action
;
1335 const struct tc_ct
*ct
;
1336 uint16_t ct_action
= 0;
1338 if (!nl_parse_nested(options
, ct_policy
, ct_attrs
,
1339 ARRAY_SIZE(ct_policy
))) {
1340 VLOG_ERR_RL(&error_rl
, "failed to parse ct action options");
1344 ct_parms
= ct_attrs
[TCA_CT_PARMS
];
1345 ct
= nl_attr_get_unspec(ct_parms
, sizeof *ct
);
1347 if (ct_attrs
[TCA_CT_ACTION
]) {
1348 ct_action
= nl_attr_get_u16(ct_attrs
[TCA_CT_ACTION
]);
1351 action
= &flower
->actions
[flower
->action_count
++];
1352 action
->ct
.clear
= ct_action
& TCA_CT_ACT_CLEAR
;
1353 if (!action
->ct
.clear
) {
1354 struct nlattr
*zone
= ct_attrs
[TCA_CT_ZONE
];
1355 struct nlattr
*mark
= ct_attrs
[TCA_CT_MARK
];
1356 struct nlattr
*mark_mask
= ct_attrs
[TCA_CT_MARK_MASK
];
1357 struct nlattr
*label
= ct_attrs
[TCA_CT_LABELS
];
1358 struct nlattr
*label_mask
= ct_attrs
[TCA_CT_LABELS_MASK
];
1360 action
->ct
.commit
= ct_action
& TCA_CT_ACT_COMMIT
;
1361 action
->ct
.force
= ct_action
& TCA_CT_ACT_FORCE
;
1363 action
->ct
.zone
= zone
? nl_attr_get_u16(zone
) : 0;
1364 action
->ct
.mark
= mark
? nl_attr_get_u32(mark
) : 0;
1365 action
->ct
.mark_mask
= mark_mask
? nl_attr_get_u32(mark_mask
) : 0;
1366 action
->ct
.label
= label
? nl_attr_get_u128(label
) : OVS_U128_ZERO
;
1367 action
->ct
.label_mask
= label_mask
?
1368 nl_attr_get_u128(label_mask
) : OVS_U128_ZERO
;
1370 if (ct_action
& TCA_CT_ACT_NAT
) {
1371 struct nlattr
*ipv4_min
= ct_attrs
[TCA_CT_NAT_IPV4_MIN
];
1372 struct nlattr
*ipv4_max
= ct_attrs
[TCA_CT_NAT_IPV4_MAX
];
1373 struct nlattr
*ipv6_min
= ct_attrs
[TCA_CT_NAT_IPV6_MIN
];
1374 struct nlattr
*ipv6_max
= ct_attrs
[TCA_CT_NAT_IPV6_MAX
];
1375 struct nlattr
*port_min
= ct_attrs
[TCA_CT_NAT_PORT_MIN
];
1376 struct nlattr
*port_max
= ct_attrs
[TCA_CT_NAT_PORT_MAX
];
1378 action
->ct
.nat_type
= TC_NAT_RESTORE
;
1379 if (ct_action
& TCA_CT_ACT_NAT_SRC
) {
1380 action
->ct
.nat_type
= TC_NAT_SRC
;
1381 } else if (ct_action
& TCA_CT_ACT_NAT_DST
) {
1382 action
->ct
.nat_type
= TC_NAT_DST
;
1386 action
->ct
.range
.ip_family
= AF_INET
;
1387 action
->ct
.range
.ipv4
.min
= nl_attr_get_be32(ipv4_min
);
1389 ovs_be32 addr
= nl_attr_get_be32(ipv4_max
);
1391 action
->ct
.range
.ipv4
.max
= addr
;
1393 } else if (ipv6_min
) {
1394 action
->ct
.range
.ip_family
= AF_INET6
;
1395 action
->ct
.range
.ipv6
.min
1396 = nl_attr_get_in6_addr(ipv6_min
);
1398 struct in6_addr addr
= nl_attr_get_in6_addr(ipv6_max
);
1400 action
->ct
.range
.ipv6
.max
= addr
;
1405 action
->ct
.range
.port
.min
= nl_attr_get_be16(port_min
);
1407 action
->ct
.range
.port
.max
= nl_attr_get_be16(port_max
);
1412 action
->type
= TC_ACT_CT
;
1417 static const struct nl_policy vlan_policy
[] = {
1418 [TCA_VLAN_PARMS
] = { .type
= NL_A_UNSPEC
,
1419 .min_len
= sizeof(struct tc_vlan
),
1420 .optional
= false, },
1421 [TCA_VLAN_PUSH_VLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
1422 [TCA_VLAN_PUSH_VLAN_PROTOCOL
] = { .type
= NL_A_U16
, .optional
= true, },
1423 [TCA_VLAN_PUSH_VLAN_PRIORITY
] = { .type
= NL_A_U8
, .optional
= true, },
1427 nl_parse_act_vlan(struct nlattr
*options
, struct tc_flower
*flower
)
1429 struct nlattr
*vlan_attrs
[ARRAY_SIZE(vlan_policy
)];
1430 const struct tc_vlan
*v
;
1431 const struct nlattr
*vlan_parms
;
1432 struct tc_action
*action
;
1434 if (!nl_parse_nested(options
, vlan_policy
, vlan_attrs
,
1435 ARRAY_SIZE(vlan_policy
))) {
1436 VLOG_ERR_RL(&error_rl
, "failed to parse vlan action options");
1440 action
= &flower
->actions
[flower
->action_count
++];
1441 vlan_parms
= vlan_attrs
[TCA_VLAN_PARMS
];
1442 v
= nl_attr_get_unspec(vlan_parms
, sizeof *v
);
1443 if (v
->v_action
== TCA_VLAN_ACT_PUSH
) {
1444 struct nlattr
*vlan_tpid
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PROTOCOL
];
1445 struct nlattr
*vlan_id
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_ID
];
1446 struct nlattr
*vlan_prio
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PRIORITY
];
1448 action
->vlan
.vlan_push_tpid
= nl_attr_get_be16(vlan_tpid
);
1449 action
->vlan
.vlan_push_id
= nl_attr_get_u16(vlan_id
);
1450 action
->vlan
.vlan_push_prio
= vlan_prio
? nl_attr_get_u8(vlan_prio
) : 0;
1451 action
->type
= TC_ACT_VLAN_PUSH
;
1452 } else if (v
->v_action
== TCA_VLAN_ACT_POP
) {
1453 action
->type
= TC_ACT_VLAN_POP
;
1455 VLOG_ERR_RL(&error_rl
, "unknown vlan action: %d, %d",
1456 v
->action
, v
->v_action
);
1462 static const struct nl_policy mpls_policy
[] = {
1463 [TCA_MPLS_PARMS
] = { .type
= NL_A_UNSPEC
,
1464 .min_len
= sizeof(struct tc_mpls
),
1465 .optional
= false, },
1466 [TCA_MPLS_PROTO
] = { .type
= NL_A_U16
, .optional
= true, },
1467 [TCA_MPLS_LABEL
] = { .type
= NL_A_U32
, .optional
= true, },
1468 [TCA_MPLS_TC
] = { .type
= NL_A_U8
, .optional
= true, },
1469 [TCA_MPLS_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
1470 [TCA_MPLS_BOS
] = { .type
= NL_A_U8
, .optional
= true, },
1474 nl_parse_act_mpls(struct nlattr
*options
, struct tc_flower
*flower
)
1476 struct nlattr
*mpls_attrs
[ARRAY_SIZE(mpls_policy
)];
1477 const struct nlattr
*mpls_parms
;
1478 struct nlattr
*mpls_proto
;
1479 struct nlattr
*mpls_label
;
1480 struct tc_action
*action
;
1481 const struct tc_mpls
*m
;
1482 struct nlattr
*mpls_ttl
;
1483 struct nlattr
*mpls_bos
;
1484 struct nlattr
*mpls_tc
;
1486 if (!nl_parse_nested(options
, mpls_policy
, mpls_attrs
,
1487 ARRAY_SIZE(mpls_policy
))) {
1488 VLOG_ERR_RL(&error_rl
, "failed to parse mpls action options");
1492 action
= &flower
->actions
[flower
->action_count
++];
1493 mpls_parms
= mpls_attrs
[TCA_MPLS_PARMS
];
1494 m
= nl_attr_get_unspec(mpls_parms
, sizeof *m
);
1496 switch (m
->m_action
) {
1497 case TCA_MPLS_ACT_POP
:
1498 mpls_proto
= mpls_attrs
[TCA_MPLS_PROTO
];
1500 action
->mpls
.proto
= nl_attr_get_be16(mpls_proto
);
1502 action
->type
= TC_ACT_MPLS_POP
;
1504 case TCA_MPLS_ACT_PUSH
:
1505 mpls_proto
= mpls_attrs
[TCA_MPLS_PROTO
];
1507 action
->mpls
.proto
= nl_attr_get_be16(mpls_proto
);
1509 mpls_label
= mpls_attrs
[TCA_MPLS_LABEL
];
1511 action
->mpls
.label
= nl_attr_get_u32(mpls_label
);
1513 mpls_tc
= mpls_attrs
[TCA_MPLS_TC
];
1515 action
->mpls
.tc
= nl_attr_get_u8(mpls_tc
);
1517 mpls_ttl
= mpls_attrs
[TCA_MPLS_TTL
];
1519 action
->mpls
.ttl
= nl_attr_get_u8(mpls_ttl
);
1521 mpls_bos
= mpls_attrs
[TCA_MPLS_BOS
];
1523 action
->mpls
.bos
= nl_attr_get_u8(mpls_bos
);
1525 action
->type
= TC_ACT_MPLS_PUSH
;
1527 case TCA_MPLS_ACT_MODIFY
:
1528 mpls_label
= mpls_attrs
[TCA_MPLS_LABEL
];
1530 action
->mpls
.label
= nl_attr_get_u32(mpls_label
);
1532 mpls_tc
= mpls_attrs
[TCA_MPLS_TC
];
1534 action
->mpls
.tc
= nl_attr_get_u8(mpls_tc
);
1536 mpls_ttl
= mpls_attrs
[TCA_MPLS_TTL
];
1538 action
->mpls
.ttl
= nl_attr_get_u8(mpls_ttl
);
1540 mpls_bos
= mpls_attrs
[TCA_MPLS_BOS
];
1542 action
->mpls
.bos
= nl_attr_get_u8(mpls_bos
);
1544 action
->type
= TC_ACT_MPLS_SET
;
1547 VLOG_ERR_RL(&error_rl
, "unknown mpls action: %d, %d",
1548 m
->action
, m
->m_action
);
1555 static const struct nl_policy csum_policy
[] = {
1556 [TCA_CSUM_PARMS
] = { .type
= NL_A_UNSPEC
,
1557 .min_len
= sizeof(struct tc_csum
),
1558 .optional
= false, },
1562 nl_parse_act_csum(struct nlattr
*options
, struct tc_flower
*flower
)
1564 struct nlattr
*csum_attrs
[ARRAY_SIZE(csum_policy
)];
1565 const struct tc_csum
*c
;
1566 const struct nlattr
*csum_parms
;
1568 if (!nl_parse_nested(options
, csum_policy
, csum_attrs
,
1569 ARRAY_SIZE(csum_policy
))) {
1570 VLOG_ERR_RL(&error_rl
, "failed to parse csum action options");
1574 csum_parms
= csum_attrs
[TCA_CSUM_PARMS
];
1575 c
= nl_attr_get_unspec(csum_parms
, sizeof *c
);
1578 if (c
->update_flags
!= flower
->csum_update_flags
) {
1579 VLOG_WARN_RL(&error_rl
,
1580 "expected different act csum flags: 0x%x != 0x%x",
1581 flower
->csum_update_flags
, c
->update_flags
);
1584 flower
->csum_update_flags
= 0; /* so we know csum was handled */
1586 if (flower
->needs_full_ip_proto_mask
1587 && flower
->mask
.ip_proto
!= UINT8_MAX
) {
1588 VLOG_WARN_RL(&error_rl
, "expected full matching on flower ip_proto");
1595 static const struct nl_policy act_policy
[] = {
1596 [TCA_ACT_KIND
] = { .type
= NL_A_STRING
, .optional
= false, },
1597 [TCA_ACT_COOKIE
] = { .type
= NL_A_UNSPEC
, .optional
= true, },
1598 [TCA_ACT_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= false, },
1599 [TCA_ACT_STATS
] = { .type
= NL_A_NESTED
, .optional
= false, },
1602 static const struct nl_policy stats_policy
[] = {
1603 [TCA_STATS_BASIC
] = { .type
= NL_A_UNSPEC
,
1604 .min_len
= sizeof(struct gnet_stats_basic
),
1605 .optional
= false, },
1609 nl_parse_single_action(struct nlattr
*action
, struct tc_flower
*flower
)
1611 struct nlattr
*act_options
;
1612 struct nlattr
*act_stats
;
1613 struct nlattr
*act_cookie
;
1614 const char *act_kind
;
1615 struct nlattr
*action_attrs
[ARRAY_SIZE(act_policy
)];
1616 struct nlattr
*stats_attrs
[ARRAY_SIZE(stats_policy
)];
1617 struct ovs_flow_stats
*stats
= &flower
->stats
;
1618 const struct gnet_stats_basic
*bs
;
1621 if (!nl_parse_nested(action
, act_policy
, action_attrs
,
1622 ARRAY_SIZE(act_policy
))) {
1623 VLOG_ERR_RL(&error_rl
, "failed to parse single action options");
1627 act_kind
= nl_attr_get_string(action_attrs
[TCA_ACT_KIND
]);
1628 act_options
= action_attrs
[TCA_ACT_OPTIONS
];
1629 act_cookie
= action_attrs
[TCA_ACT_COOKIE
];
1631 if (!strcmp(act_kind
, "gact")) {
1632 err
= nl_parse_act_gact(act_options
, flower
);
1633 } else if (!strcmp(act_kind
, "mirred")) {
1634 err
= nl_parse_act_mirred(act_options
, flower
);
1635 } else if (!strcmp(act_kind
, "vlan")) {
1636 err
= nl_parse_act_vlan(act_options
, flower
);
1637 } else if (!strcmp(act_kind
, "mpls")) {
1638 err
= nl_parse_act_mpls(act_options
, flower
);
1639 } else if (!strcmp(act_kind
, "tunnel_key")) {
1640 err
= nl_parse_act_tunnel_key(act_options
, flower
);
1641 } else if (!strcmp(act_kind
, "pedit")) {
1642 err
= nl_parse_act_pedit(act_options
, flower
);
1643 } else if (!strcmp(act_kind
, "csum")) {
1644 nl_parse_act_csum(act_options
, flower
);
1645 } else if (!strcmp(act_kind
, "skbedit")) {
1646 /* Added for TC rule only (not in OvS rule) so ignore. */
1647 } else if (!strcmp(act_kind
, "ct")) {
1648 nl_parse_act_ct(act_options
, flower
);
1650 VLOG_ERR_RL(&error_rl
, "unknown tc action kind: %s", act_kind
);
1659 flower
->act_cookie
.data
= nl_attr_get(act_cookie
);
1660 flower
->act_cookie
.len
= nl_attr_get_size(act_cookie
);
1663 act_stats
= action_attrs
[TCA_ACT_STATS
];
1665 if (!nl_parse_nested(act_stats
, stats_policy
, stats_attrs
,
1666 ARRAY_SIZE(stats_policy
))) {
1667 VLOG_ERR_RL(&error_rl
, "failed to parse action stats policy");
1671 bs
= nl_attr_get_unspec(stats_attrs
[TCA_STATS_BASIC
], sizeof *bs
);
1672 put_32aligned_u64(&stats
->n_packets
, bs
->packets
);
1673 put_32aligned_u64(&stats
->n_bytes
, bs
->bytes
);
1678 #define TCA_ACT_MIN_PRIO 1
1681 nl_parse_flower_actions(struct nlattr
**attrs
, struct tc_flower
*flower
)
1683 const struct nlattr
*actions
= attrs
[TCA_FLOWER_ACT
];
1684 static struct nl_policy actions_orders_policy
[TCA_ACT_MAX_NUM
+ 1] = {};
1685 struct nlattr
*actions_orders
[ARRAY_SIZE(actions_orders_policy
)];
1686 const int max_size
= ARRAY_SIZE(actions_orders_policy
);
1688 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
1689 actions_orders_policy
[i
].type
= NL_A_NESTED
;
1690 actions_orders_policy
[i
].optional
= true;
1693 if (!nl_parse_nested(actions
, actions_orders_policy
, actions_orders
,
1694 ARRAY_SIZE(actions_orders_policy
))) {
1695 VLOG_ERR_RL(&error_rl
, "failed to parse flower order of actions");
1699 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
1700 if (actions_orders
[i
]) {
1703 if (flower
->action_count
>= TCA_ACT_MAX_NUM
) {
1704 VLOG_DBG_RL(&error_rl
, "Can only support %d actions", TCA_ACT_MAX_NUM
);
1707 err
= nl_parse_single_action(actions_orders
[i
], flower
);
1715 if (flower
->csum_update_flags
) {
1716 VLOG_WARN_RL(&error_rl
,
1717 "expected act csum with flags: 0x%x",
1718 flower
->csum_update_flags
);
1726 nl_parse_flower_options(struct nlattr
*nl_options
, struct tc_flower
*flower
)
1728 struct nlattr
*attrs
[ARRAY_SIZE(tca_flower_policy
)];
1731 if (!nl_parse_nested(nl_options
, tca_flower_policy
,
1732 attrs
, ARRAY_SIZE(tca_flower_policy
))) {
1733 VLOG_ERR_RL(&error_rl
, "failed to parse flower classifier options");
1737 nl_parse_flower_eth(attrs
, flower
);
1738 nl_parse_flower_mpls(attrs
, flower
);
1739 nl_parse_flower_vlan(attrs
, flower
);
1740 nl_parse_flower_ip(attrs
, flower
);
1741 err
= nl_parse_flower_tunnel(attrs
, flower
);
1746 nl_parse_flower_flags(attrs
, flower
);
1747 return nl_parse_flower_actions(attrs
, flower
);
1751 parse_netlink_to_tc_flower(struct ofpbuf
*reply
, struct tcf_id
*id
,
1752 struct tc_flower
*flower
)
1755 struct nlattr
*ta
[ARRAY_SIZE(tca_policy
)];
1758 if (NLMSG_HDRLEN
+ sizeof *tc
> reply
->size
) {
1762 memset(flower
, 0, sizeof *flower
);
1764 tc
= ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
1766 flower
->key
.eth_type
= (OVS_FORCE ovs_be16
) tc_get_minor(tc
->tcm_info
);
1767 flower
->mask
.eth_type
= OVS_BE16_MAX
;
1768 id
->prio
= tc_get_major(tc
->tcm_info
);
1769 id
->handle
= tc
->tcm_handle
;
1771 if (id
->prio
== TC_RESERVED_PRIORITY_POLICE
) {
1779 if (!nl_policy_parse(reply
, NLMSG_HDRLEN
+ sizeof *tc
,
1780 tca_policy
, ta
, ARRAY_SIZE(ta
))) {
1781 VLOG_ERR_RL(&error_rl
, "failed to parse tca policy");
1785 if (ta
[TCA_CHAIN
]) {
1786 id
->chain
= nl_attr_get_u32(ta
[TCA_CHAIN
]);
1789 kind
= nl_attr_get_string(ta
[TCA_KIND
]);
1790 if (strcmp(kind
, "flower")) {
1791 VLOG_DBG_ONCE("Unsupported filter: %s", kind
);
1795 return nl_parse_flower_options(ta
[TCA_OPTIONS
], flower
);
1799 tc_dump_flower_start(struct tcf_id
*id
, struct nl_dump
*dump
)
1801 struct ofpbuf request
;
1803 request_from_tcf_id(id
, 0, RTM_GETTFILTER
, NLM_F_DUMP
, &request
);
1804 nl_dump_start(dump
, NETLINK_ROUTE
, &request
);
1805 ofpbuf_uninit(&request
);
1811 tc_del_filter(struct tcf_id
*id
)
1813 struct ofpbuf request
;
1815 request_from_tcf_id(id
, 0, RTM_DELTFILTER
, NLM_F_ACK
, &request
);
1816 return tc_transact(&request
, NULL
);
1820 tc_get_flower(struct tcf_id
*id
, struct tc_flower
*flower
)
1822 struct ofpbuf request
;
1823 struct ofpbuf
*reply
;
1826 request_from_tcf_id(id
, 0, RTM_GETTFILTER
, NLM_F_ECHO
, &request
);
1827 error
= tc_transact(&request
, &reply
);
1832 error
= parse_netlink_to_tc_flower(reply
, id
, flower
);
1833 ofpbuf_delete(reply
);
1838 tc_get_tc_cls_policy(enum tc_offload_policy policy
)
1840 if (policy
== TC_POLICY_SKIP_HW
) {
1841 return TCA_CLS_FLAGS_SKIP_HW
;
1842 } else if (policy
== TC_POLICY_SKIP_SW
) {
1843 return TCA_CLS_FLAGS_SKIP_SW
;
1850 nl_msg_put_act_csum(struct ofpbuf
*request
, uint32_t flags
)
1854 nl_msg_put_string(request
, TCA_ACT_KIND
, "csum");
1855 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1857 struct tc_csum parm
= { .action
= TC_ACT_PIPE
,
1858 .update_flags
= flags
};
1860 nl_msg_put_unspec(request
, TCA_CSUM_PARMS
, &parm
, sizeof parm
);
1862 nl_msg_end_nested(request
, offset
);
1866 nl_msg_put_act_pedit(struct ofpbuf
*request
, struct tc_pedit
*parm
,
1867 struct tc_pedit_key_ex
*ex
)
1869 size_t ksize
= sizeof *parm
+ parm
->nkeys
* sizeof(struct tc_pedit_key
);
1870 size_t offset
, offset_keys_ex
, offset_key
;
1873 nl_msg_put_string(request
, TCA_ACT_KIND
, "pedit");
1874 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1876 parm
->action
= TC_ACT_PIPE
;
1878 nl_msg_put_unspec(request
, TCA_PEDIT_PARMS_EX
, parm
, ksize
);
1879 offset_keys_ex
= nl_msg_start_nested(request
, TCA_PEDIT_KEYS_EX
);
1880 for (i
= 0; i
< parm
->nkeys
; i
++, ex
++) {
1881 offset_key
= nl_msg_start_nested(request
, TCA_PEDIT_KEY_EX
);
1882 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_HTYPE
, ex
->htype
);
1883 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_CMD
, ex
->cmd
);
1884 nl_msg_end_nested(request
, offset_key
);
1886 nl_msg_end_nested(request
, offset_keys_ex
);
1888 nl_msg_end_nested(request
, offset
);
1892 nl_msg_put_act_push_vlan(struct ofpbuf
*request
, ovs_be16 tpid
,
1893 uint16_t vid
, uint8_t prio
)
1897 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1898 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1900 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1901 .v_action
= TCA_VLAN_ACT_PUSH
};
1903 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1904 nl_msg_put_be16(request
, TCA_VLAN_PUSH_VLAN_PROTOCOL
, tpid
);
1905 nl_msg_put_u16(request
, TCA_VLAN_PUSH_VLAN_ID
, vid
);
1906 nl_msg_put_u8(request
, TCA_VLAN_PUSH_VLAN_PRIORITY
, prio
);
1908 nl_msg_end_nested(request
, offset
);
1912 nl_msg_put_act_pop_vlan(struct ofpbuf
*request
)
1916 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1917 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1919 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1920 .v_action
= TCA_VLAN_ACT_POP
};
1922 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1924 nl_msg_end_nested(request
, offset
);
1928 nl_msg_put_act_pop_mpls(struct ofpbuf
*request
, ovs_be16 proto
)
1932 nl_msg_put_string(request
, TCA_ACT_KIND
, "mpls");
1933 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
1935 struct tc_mpls parm
= { .action
= TC_ACT_PIPE
,
1936 .m_action
= TCA_MPLS_ACT_POP
};
1938 nl_msg_put_unspec(request
, TCA_MPLS_PARMS
, &parm
, sizeof parm
);
1939 nl_msg_put_be16(request
, TCA_MPLS_PROTO
, proto
);
1941 nl_msg_end_nested(request
, offset
);
1945 nl_msg_put_act_push_mpls(struct ofpbuf
*request
, ovs_be16 proto
,
1946 uint32_t label
, uint8_t tc
, uint8_t ttl
, uint8_t bos
)
1950 nl_msg_put_string(request
, TCA_ACT_KIND
, "mpls");
1951 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
1953 struct tc_mpls parm
= { .action
= TC_ACT_PIPE
,
1954 .m_action
= TCA_MPLS_ACT_PUSH
};
1956 nl_msg_put_unspec(request
, TCA_MPLS_PARMS
, &parm
, sizeof parm
);
1957 nl_msg_put_be16(request
, TCA_MPLS_PROTO
, proto
);
1958 nl_msg_put_u32(request
, TCA_MPLS_LABEL
, label
);
1959 nl_msg_put_u8(request
, TCA_MPLS_TC
, tc
);
1960 nl_msg_put_u8(request
, TCA_MPLS_TTL
, ttl
);
1961 nl_msg_put_u8(request
, TCA_MPLS_BOS
, bos
);
1963 nl_msg_end_nested(request
, offset
);
1967 nl_msg_put_act_set_mpls(struct ofpbuf
*request
, uint32_t label
, uint8_t tc
,
1968 uint8_t ttl
, uint8_t bos
)
1972 nl_msg_put_string(request
, TCA_ACT_KIND
, "mpls");
1973 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
1975 struct tc_mpls parm
= { .action
= TC_ACT_PIPE
,
1976 .m_action
= TCA_MPLS_ACT_MODIFY
};
1978 nl_msg_put_unspec(request
, TCA_MPLS_PARMS
, &parm
, sizeof parm
);
1979 nl_msg_put_u32(request
, TCA_MPLS_LABEL
, label
);
1980 nl_msg_put_u8(request
, TCA_MPLS_TC
, tc
);
1981 nl_msg_put_u8(request
, TCA_MPLS_TTL
, ttl
);
1982 nl_msg_put_u8(request
, TCA_MPLS_BOS
, bos
);
1984 nl_msg_end_nested(request
, offset
);
1988 nl_msg_put_act_tunnel_key_release(struct ofpbuf
*request
)
1992 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
1993 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1995 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
1996 .t_action
= TCA_TUNNEL_KEY_ACT_RELEASE
};
1998 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
2000 nl_msg_end_nested(request
, offset
);
2004 nl_msg_put_act_tunnel_geneve_option(struct ofpbuf
*request
,
2005 struct tun_metadata tun_metadata
)
2007 const struct geneve_opt
*opt
;
2008 size_t outer
, inner
;
2011 len
= tun_metadata
.present
.len
;
2016 outer
= nl_msg_start_nested(request
, TCA_TUNNEL_KEY_ENC_OPTS
);
2019 opt
= &tun_metadata
.opts
.gnv
[cnt
];
2020 inner
= nl_msg_start_nested(request
, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
);
2022 nl_msg_put_be16(request
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
,
2024 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
, opt
->type
);
2025 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
, opt
+ 1,
2028 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
2029 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
2031 nl_msg_end_nested(request
, inner
);
2034 nl_msg_end_nested(request
, outer
);
2038 nl_msg_put_act_tunnel_key_set(struct ofpbuf
*request
, bool id_present
,
2039 ovs_be64 id
, ovs_be32 ipv4_src
,
2040 ovs_be32 ipv4_dst
, struct in6_addr
*ipv6_src
,
2041 struct in6_addr
*ipv6_dst
,
2042 ovs_be16 tp_dst
, uint8_t tos
, uint8_t ttl
,
2043 struct tun_metadata tun_metadata
,
2048 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
2049 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2051 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
2052 .t_action
= TCA_TUNNEL_KEY_ACT_SET
};
2054 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
2056 ovs_be32 id32
= be64_to_be32(id
);
2058 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_KEY_ID
, id32
);
2061 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_SRC
, ipv4_src
);
2062 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_DST
, ipv4_dst
);
2063 } else if (ipv6_addr_is_set(ipv6_dst
)) {
2064 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_DST
,
2066 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_SRC
,
2070 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_TOS
, tos
);
2073 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_TTL
, ttl
);
2076 nl_msg_put_be16(request
, TCA_TUNNEL_KEY_ENC_DST_PORT
, tp_dst
);
2078 nl_msg_put_act_tunnel_geneve_option(request
, tun_metadata
);
2079 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_NO_CSUM
, no_csum
);
2081 nl_msg_end_nested(request
, offset
);
2085 nl_msg_put_act_gact(struct ofpbuf
*request
, uint32_t chain
)
2089 nl_msg_put_string(request
, TCA_ACT_KIND
, "gact");
2090 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2092 struct tc_gact p
= { .action
= TC_ACT_SHOT
};
2095 p
.action
= TC_ACT_GOTO_CHAIN
| chain
;
2098 nl_msg_put_unspec(request
, TCA_GACT_PARMS
, &p
, sizeof p
);
2100 nl_msg_end_nested(request
, offset
);
2104 nl_msg_put_act_ct(struct ofpbuf
*request
, struct tc_action
*action
)
2106 uint16_t ct_action
= 0;
2109 nl_msg_put_string(request
, TCA_ACT_KIND
, "ct");
2110 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
2113 .action
= TC_ACT_PIPE
,
2116 if (!action
->ct
.clear
) {
2117 if (action
->ct
.zone
) {
2118 nl_msg_put_u16(request
, TCA_CT_ZONE
, action
->ct
.zone
);
2121 if (!is_all_zeros(&action
->ct
.label_mask
,
2122 sizeof action
->ct
.label_mask
)) {
2123 nl_msg_put_u128(request
, TCA_CT_LABELS
,
2125 nl_msg_put_u128(request
, TCA_CT_LABELS_MASK
,
2126 action
->ct
.label_mask
);
2129 if (action
->ct
.mark_mask
) {
2130 nl_msg_put_u32(request
, TCA_CT_MARK
,
2132 nl_msg_put_u32(request
, TCA_CT_MARK_MASK
,
2133 action
->ct
.mark_mask
);
2136 if (action
->ct
.commit
) {
2137 ct_action
= TCA_CT_ACT_COMMIT
;
2138 if (action
->ct
.force
) {
2139 ct_action
|= TCA_CT_ACT_FORCE
;
2143 if (action
->ct
.nat_type
) {
2144 ct_action
|= TCA_CT_ACT_NAT
;
2146 if (action
->ct
.nat_type
== TC_NAT_SRC
) {
2147 ct_action
|= TCA_CT_ACT_NAT_SRC
;
2148 } else if (action
->ct
.nat_type
== TC_NAT_DST
) {
2149 ct_action
|= TCA_CT_ACT_NAT_DST
;
2152 if (action
->ct
.range
.ip_family
== AF_INET
) {
2153 nl_msg_put_be32(request
, TCA_CT_NAT_IPV4_MIN
,
2154 action
->ct
.range
.ipv4
.min
);
2155 if (action
->ct
.range
.ipv4
.max
) {
2156 nl_msg_put_be32(request
, TCA_CT_NAT_IPV4_MAX
,
2157 action
->ct
.range
.ipv4
.max
);
2159 } else if (action
->ct
.range
.ip_family
== AF_INET6
) {
2161 nl_msg_put_in6_addr(request
, TCA_CT_NAT_IPV6_MIN
,
2162 &action
->ct
.range
.ipv6
.min
);
2163 if (ipv6_addr_is_set(&action
->ct
.range
.ipv6
.max
)) {
2164 nl_msg_put_in6_addr(request
, TCA_CT_NAT_IPV6_MAX
,
2165 &action
->ct
.range
.ipv6
.max
);
2169 if (action
->ct
.range
.port
.min
) {
2170 nl_msg_put_be16(request
, TCA_CT_NAT_PORT_MIN
,
2171 action
->ct
.range
.port
.min
);
2172 if (action
->ct
.range
.port
.max
) {
2173 nl_msg_put_be16(request
, TCA_CT_NAT_PORT_MAX
,
2174 action
->ct
.range
.port
.max
);
2179 ct_action
= TCA_CT_ACT_CLEAR
;
2182 nl_msg_put_u16(request
, TCA_CT_ACTION
, ct_action
);
2183 nl_msg_put_unspec(request
, TCA_CT_PARMS
, &ct
, sizeof ct
);
2185 nl_msg_end_nested(request
, offset
);
2189 nl_msg_put_act_skbedit_to_host(struct ofpbuf
*request
)
2193 nl_msg_put_string(request
, TCA_ACT_KIND
, "skbedit");
2194 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2196 struct tc_skbedit s
= { .action
= TC_ACT_PIPE
};
2198 nl_msg_put_unspec(request
, TCA_SKBEDIT_PARMS
, &s
, sizeof s
);
2199 nl_msg_put_be16(request
, TCA_SKBEDIT_PTYPE
, PACKET_HOST
);
2201 nl_msg_end_nested(request
, offset
);
2205 nl_msg_put_act_mirred(struct ofpbuf
*request
, int ifindex
, int action
,
2210 nl_msg_put_string(request
, TCA_ACT_KIND
, "mirred");
2211 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
2213 struct tc_mirred m
= { .action
= action
,
2215 .ifindex
= ifindex
};
2217 nl_msg_put_unspec(request
, TCA_MIRRED_PARMS
, &m
, sizeof m
);
2219 nl_msg_end_nested(request
, offset
);
2223 nl_msg_put_act_cookie(struct ofpbuf
*request
, struct tc_cookie
*ck
) {
2225 nl_msg_put_unspec(request
, TCA_ACT_COOKIE
, ck
->data
, ck
->len
);
2230 nl_msg_put_act_flags(struct ofpbuf
*request
) {
2231 struct nla_bitfield32 act_flags
= { TCA_ACT_FLAGS_NO_PERCPU_STATS
,
2232 TCA_ACT_FLAGS_NO_PERCPU_STATS
};
2234 nl_msg_put_unspec(request
, TCA_ACT_FLAGS
, &act_flags
, sizeof act_flags
);
2237 /* Given flower, a key_to_pedit map entry, calculates the rest,
2240 * mask, data - pointers of where read the first word of flower->key/mask.
2241 * current_offset - which offset to use for the first pedit action.
2242 * cnt - max pedits actions to use.
2243 * first_word_mask/last_word_mask - the mask to use for the first/last read
2244 * (as we read entire words). */
2246 calc_offsets(struct tc_flower
*flower
, struct flower_key_to_pedit
*m
,
2247 int *cur_offset
, int *cnt
, ovs_be32
*last_word_mask
,
2248 ovs_be32
*first_word_mask
, ovs_be32
**mask
, ovs_be32
**data
)
2250 int start_offset
, max_offset
, total_size
;
2251 int diff
, right_zero_bits
, left_zero_bits
;
2252 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
2253 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
2255 max_offset
= m
->offset
+ m
->size
;
2256 start_offset
= ROUND_DOWN(m
->offset
, 4);
2257 diff
= m
->offset
- start_offset
;
2258 total_size
= max_offset
- start_offset
;
2259 right_zero_bits
= 8 * (4 - ((max_offset
% 4) ? : 4));
2260 left_zero_bits
= 8 * (m
->offset
- start_offset
);
2262 *cur_offset
= start_offset
;
2263 *cnt
= (total_size
/ 4) + (total_size
% 4 ? 1 : 0);
2264 *last_word_mask
= htonl(UINT32_MAX
<< right_zero_bits
);
2265 *first_word_mask
= htonl(UINT32_MAX
>> left_zero_bits
);
2266 *data
= (void *) (rewrite_key
+ m
->flower_offset
- diff
);
2267 *mask
= (void *) (rewrite_mask
+ m
->flower_offset
- diff
);
2271 csum_update_flag(struct tc_flower
*flower
,
2272 enum pedit_header_type htype
) {
2273 /* Explictily specifiy the csum flags so HW can return EOPNOTSUPP
2274 * if it doesn't support a checksum recalculation of some headers.
2275 * And since OVS allows a flow such as
2276 * eth(dst=<mac>),eth_type(0x0800) actions=set(ipv4(src=<new_ip>))
2277 * we need to force a more specific flow as this can, for example,
2278 * need a recalculation of icmp checksum if the packet that passes
2279 * is ICMPv6 and tcp checksum if its tcp. */
2282 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
:
2283 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_IPV4HDR
;
2285 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
:
2286 case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
:
2287 case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
:
2288 if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
2289 flower
->needs_full_ip_proto_mask
= true;
2290 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_TCP
;
2291 } else if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
2292 flower
->needs_full_ip_proto_mask
= true;
2293 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_UDP
;
2294 } else if (flower
->key
.ip_proto
== IPPROTO_ICMP
) {
2295 flower
->needs_full_ip_proto_mask
= true;
2296 } else if (flower
->key
.ip_proto
== IPPROTO_ICMPV6
) {
2297 flower
->needs_full_ip_proto_mask
= true;
2298 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_ICMP
;
2300 VLOG_WARN_RL(&error_rl
,
2301 "can't offload rewrite of IP/IPV6 with ip_proto: %d",
2302 flower
->key
.ip_proto
);
2306 case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
:
2307 return 0; /* success */
2309 case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK
:
2310 case __PEDIT_HDR_TYPE_MAX
:
2319 nl_msg_put_flower_rewrite_pedits(struct ofpbuf
*request
,
2320 struct tc_flower
*flower
)
2323 struct tc_pedit sel
;
2324 struct tc_pedit_key keys
[MAX_PEDIT_OFFSETS
];
2325 struct tc_pedit_key_ex keys_ex
[MAX_PEDIT_OFFSETS
];
2333 for (i
= 0; i
< ARRAY_SIZE(flower_pedit_map
); i
++) {
2334 struct flower_key_to_pedit
*m
= &flower_pedit_map
[i
];
2335 struct tc_pedit_key
*pedit_key
= NULL
;
2336 struct tc_pedit_key_ex
*pedit_key_ex
= NULL
;
2337 ovs_be32
*mask
, *data
, first_word_mask
, last_word_mask
;
2338 int cnt
= 0, cur_offset
= 0;
2344 calc_offsets(flower
, m
, &cur_offset
, &cnt
, &last_word_mask
,
2345 &first_word_mask
, &mask
, &data
);
2347 for (j
= 0; j
< cnt
; j
++, mask
++, data
++, cur_offset
+= 4) {
2348 ovs_be32 mask_word
= *mask
;
2349 ovs_be32 data_word
= *data
;
2352 mask_word
&= first_word_mask
;
2355 mask_word
&= last_word_mask
;
2360 if (sel
.sel
.nkeys
== MAX_PEDIT_OFFSETS
) {
2361 VLOG_WARN_RL(&error_rl
, "reached too many pedit offsets: %d",
2366 pedit_key
= &sel
.keys
[sel
.sel
.nkeys
];
2367 pedit_key_ex
= &sel
.keys_ex
[sel
.sel
.nkeys
];
2368 pedit_key_ex
->cmd
= TCA_PEDIT_KEY_EX_CMD_SET
;
2369 pedit_key_ex
->htype
= m
->htype
;
2370 pedit_key
->off
= cur_offset
;
2371 mask_word
= htonl(ntohl(mask_word
) >> m
->boundary_shift
);
2372 data_word
= htonl(ntohl(data_word
) >> m
->boundary_shift
);
2373 pedit_key
->mask
= ~mask_word
;
2374 pedit_key
->val
= data_word
& mask_word
;
2377 err
= csum_update_flag(flower
, m
->htype
);
2382 if (flower
->needs_full_ip_proto_mask
) {
2383 flower
->mask
.ip_proto
= UINT8_MAX
;
2387 nl_msg_put_act_pedit(request
, &sel
.sel
, sel
.keys_ex
);
2393 nl_msg_put_flower_acts(struct ofpbuf
*request
, struct tc_flower
*flower
)
2395 bool ingress
, released
= false;
2398 uint16_t act_index
= 1;
2399 struct tc_action
*action
;
2402 offset
= nl_msg_start_nested(request
, TCA_FLOWER_ACT
);
2406 action
= flower
->actions
;
2407 for (i
= 0; i
< flower
->action_count
; i
++, action
++) {
2408 switch (action
->type
) {
2409 case TC_ACT_PEDIT
: {
2410 act_offset
= nl_msg_start_nested(request
, act_index
++);
2411 error
= nl_msg_put_flower_rewrite_pedits(request
, flower
);
2415 nl_msg_end_nested(request
, act_offset
);
2417 if (flower
->csum_update_flags
) {
2418 act_offset
= nl_msg_start_nested(request
, act_index
++);
2419 nl_msg_put_act_csum(request
, flower
->csum_update_flags
);
2420 nl_msg_put_act_flags(request
);
2421 nl_msg_end_nested(request
, act_offset
);
2425 case TC_ACT_ENCAP
: {
2426 act_offset
= nl_msg_start_nested(request
, act_index
++);
2427 nl_msg_put_act_tunnel_key_set(request
, action
->encap
.id_present
,
2429 action
->encap
.ipv4
.ipv4_src
,
2430 action
->encap
.ipv4
.ipv4_dst
,
2431 &action
->encap
.ipv6
.ipv6_src
,
2432 &action
->encap
.ipv6
.ipv6_dst
,
2433 action
->encap
.tp_dst
,
2437 action
->encap
.no_csum
);
2438 nl_msg_put_act_flags(request
);
2439 nl_msg_end_nested(request
, act_offset
);
2442 case TC_ACT_VLAN_POP
: {
2443 act_offset
= nl_msg_start_nested(request
, act_index
++);
2444 nl_msg_put_act_pop_vlan(request
);
2445 nl_msg_put_act_flags(request
);
2446 nl_msg_end_nested(request
, act_offset
);
2449 case TC_ACT_VLAN_PUSH
: {
2450 act_offset
= nl_msg_start_nested(request
, act_index
++);
2451 nl_msg_put_act_push_vlan(request
,
2452 action
->vlan
.vlan_push_tpid
,
2453 action
->vlan
.vlan_push_id
,
2454 action
->vlan
.vlan_push_prio
);
2455 nl_msg_put_act_flags(request
);
2456 nl_msg_end_nested(request
, act_offset
);
2459 case TC_ACT_MPLS_POP
: {
2460 act_offset
= nl_msg_start_nested(request
, act_index
++);
2461 nl_msg_put_act_pop_mpls(request
, action
->mpls
.proto
);
2462 nl_msg_end_nested(request
, act_offset
);
2465 case TC_ACT_MPLS_PUSH
: {
2466 act_offset
= nl_msg_start_nested(request
, act_index
++);
2467 nl_msg_put_act_push_mpls(request
, action
->mpls
.proto
,
2468 action
->mpls
.label
, action
->mpls
.tc
,
2469 action
->mpls
.ttl
, action
->mpls
.bos
);
2470 nl_msg_end_nested(request
, act_offset
);
2473 case TC_ACT_MPLS_SET
: {
2474 act_offset
= nl_msg_start_nested(request
, act_index
++);
2475 nl_msg_put_act_set_mpls(request
, action
->mpls
.label
,
2476 action
->mpls
.tc
, action
->mpls
.ttl
,
2478 nl_msg_end_nested(request
, act_offset
);
2481 case TC_ACT_OUTPUT
: {
2482 if (!released
&& flower
->tunnel
) {
2483 act_offset
= nl_msg_start_nested(request
, act_index
++);
2484 nl_msg_put_act_tunnel_key_release(request
);
2485 nl_msg_end_nested(request
, act_offset
);
2489 ingress
= action
->out
.ingress
;
2490 ifindex
= action
->out
.ifindex_out
;
2492 VLOG_ERR_RL(&error_rl
, "%s: invalid ifindex: %d, type: %d",
2493 __func__
, ifindex
, action
->type
);
2498 /* If redirecting to ingress (internal port) ensure
2499 * pkt_type on skb is set to PACKET_HOST. */
2500 act_offset
= nl_msg_start_nested(request
, act_index
++);
2501 nl_msg_put_act_skbedit_to_host(request
);
2502 nl_msg_end_nested(request
, act_offset
);
2505 act_offset
= nl_msg_start_nested(request
, act_index
++);
2506 if (i
== flower
->action_count
- 1) {
2508 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_STOLEN
,
2511 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_STOLEN
,
2516 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_PIPE
,
2517 TCA_INGRESS_MIRROR
);
2519 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_PIPE
,
2523 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2524 nl_msg_put_act_flags(request
);
2525 nl_msg_end_nested(request
, act_offset
);
2530 /* We don't support tunnel release + output + goto
2531 * for now, as next chain by default will try and match
2532 * the tunnel metadata that was released/unset.
2534 * This will happen with tunnel + mirror ports.
2539 act_offset
= nl_msg_start_nested(request
, act_index
++);
2540 nl_msg_put_act_gact(request
, action
->chain
);
2541 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2542 nl_msg_end_nested(request
, act_offset
);
2546 act_offset
= nl_msg_start_nested(request
, act_index
++);
2547 nl_msg_put_act_ct(request
, action
);
2548 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2549 nl_msg_end_nested(request
, act_offset
);
2556 if (!flower
->action_count
) {
2557 act_offset
= nl_msg_start_nested(request
, act_index
++);
2558 nl_msg_put_act_gact(request
, 0);
2559 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2560 nl_msg_put_act_flags(request
);
2561 nl_msg_end_nested(request
, act_offset
);
2563 nl_msg_end_nested(request
, offset
);
2569 nl_msg_put_masked_value(struct ofpbuf
*request
, uint16_t type
,
2570 uint16_t mask_type
, const void *data
,
2571 const void *mask_data
, size_t len
)
2573 if (mask_type
!= TCA_FLOWER_UNSPEC
) {
2574 if (is_all_zeros(mask_data
, len
)) {
2577 nl_msg_put_unspec(request
, mask_type
, mask_data
, len
);
2579 nl_msg_put_unspec(request
, type
, data
, len
);
2583 nl_msg_put_flower_tunnel_opts(struct ofpbuf
*request
, uint16_t type
,
2584 struct tun_metadata metadata
)
2586 struct geneve_opt
*opt
;
2587 size_t outer
, inner
;
2590 len
= metadata
.present
.len
;
2595 outer
= nl_msg_start_nested(request
, type
);
2597 opt
= &metadata
.opts
.gnv
[cnt
];
2598 inner
= nl_msg_start_nested(request
, TCA_FLOWER_KEY_ENC_OPTS_GENEVE
);
2600 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
,
2602 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
, opt
->type
);
2603 nl_msg_put_unspec(request
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
, opt
+ 1,
2606 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
2607 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
2609 nl_msg_end_nested(request
, inner
);
2611 nl_msg_end_nested(request
, outer
);
2615 nl_msg_put_flower_tunnel(struct ofpbuf
*request
, struct tc_flower
*flower
)
2617 ovs_be32 ipv4_src_mask
= flower
->mask
.tunnel
.ipv4
.ipv4_src
;
2618 ovs_be32 ipv4_dst_mask
= flower
->mask
.tunnel
.ipv4
.ipv4_dst
;
2619 ovs_be32 ipv4_src
= flower
->key
.tunnel
.ipv4
.ipv4_src
;
2620 ovs_be32 ipv4_dst
= flower
->key
.tunnel
.ipv4
.ipv4_dst
;
2621 struct in6_addr
*ipv6_src_mask
= &flower
->mask
.tunnel
.ipv6
.ipv6_src
;
2622 struct in6_addr
*ipv6_dst_mask
= &flower
->mask
.tunnel
.ipv6
.ipv6_dst
;
2623 struct in6_addr
*ipv6_src
= &flower
->key
.tunnel
.ipv6
.ipv6_src
;
2624 struct in6_addr
*ipv6_dst
= &flower
->key
.tunnel
.ipv6
.ipv6_dst
;
2625 ovs_be16 tp_dst_mask
= flower
->mask
.tunnel
.tp_dst
;
2626 ovs_be16 tp_src_mask
= flower
->mask
.tunnel
.tp_src
;
2627 ovs_be16 tp_dst
= flower
->key
.tunnel
.tp_dst
;
2628 ovs_be16 tp_src
= flower
->key
.tunnel
.tp_src
;
2629 ovs_be32 id
= be64_to_be32(flower
->key
.tunnel
.id
);
2630 uint8_t tos
= flower
->key
.tunnel
.tos
;
2631 uint8_t ttl
= flower
->key
.tunnel
.ttl
;
2632 uint8_t tos_mask
= flower
->mask
.tunnel
.tos
;
2633 uint8_t ttl_mask
= flower
->mask
.tunnel
.ttl
;
2634 ovs_be64 id_mask
= flower
->mask
.tunnel
.id
;
2636 if (ipv4_dst_mask
|| ipv4_src_mask
) {
2637 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
,
2639 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
,
2641 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_DST
, ipv4_dst
);
2642 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_SRC
, ipv4_src
);
2643 } else if (ipv6_addr_is_set(ipv6_dst_mask
) ||
2644 ipv6_addr_is_set(ipv6_src_mask
)) {
2645 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
,
2647 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
,
2649 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_DST
, ipv6_dst
);
2650 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_SRC
, ipv6_src
);
2653 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TOS
, tos
);
2654 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TOS_MASK
, tos_mask
);
2657 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TTL
, ttl
);
2658 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TTL_MASK
, ttl_mask
);
2661 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK
,
2663 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_UDP_DST_PORT
, tp_dst
);
2666 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK
,
2668 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT
, tp_src
);
2671 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_KEY_ID
, id
);
2673 nl_msg_put_flower_tunnel_opts(request
, TCA_FLOWER_KEY_ENC_OPTS
,
2674 flower
->key
.tunnel
.metadata
);
2675 nl_msg_put_flower_tunnel_opts(request
, TCA_FLOWER_KEY_ENC_OPTS_MASK
,
2676 flower
->mask
.tunnel
.metadata
);
2679 #define FLOWER_PUT_MASKED_VALUE(member, type) \
2680 nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \
2681 &flower->mask.member, sizeof flower->key.member)
2684 nl_msg_put_flower_options(struct ofpbuf
*request
, struct tc_flower
*flower
)
2687 uint16_t host_eth_type
= ntohs(flower
->key
.eth_type
);
2688 bool is_vlan
= eth_type_vlan(flower
->key
.eth_type
);
2689 bool is_qinq
= is_vlan
&& eth_type_vlan(flower
->key
.encap_eth_type
[0]);
2690 bool is_mpls
= eth_type_mpls(flower
->key
.eth_type
);
2693 /* need to parse acts first as some acts require changing the matching
2694 * see csum_update_flag() */
2695 err
= nl_msg_put_flower_acts(request
, flower
);
2702 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[1]);
2704 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[0]);
2709 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[0]);
2712 FLOWER_PUT_MASKED_VALUE(dst_mac
, TCA_FLOWER_KEY_ETH_DST
);
2713 FLOWER_PUT_MASKED_VALUE(src_mac
, TCA_FLOWER_KEY_ETH_SRC
);
2715 if (host_eth_type
== ETH_P_IP
|| host_eth_type
== ETH_P_IPV6
) {
2716 FLOWER_PUT_MASKED_VALUE(ip_ttl
, TCA_FLOWER_KEY_IP_TTL
);
2717 FLOWER_PUT_MASKED_VALUE(ip_tos
, TCA_FLOWER_KEY_IP_TOS
);
2719 if (flower
->mask
.ip_proto
&& flower
->key
.ip_proto
) {
2720 nl_msg_put_u8(request
, TCA_FLOWER_KEY_IP_PROTO
,
2721 flower
->key
.ip_proto
);
2724 if (flower
->mask
.flags
) {
2725 nl_msg_put_be32(request
, TCA_FLOWER_KEY_FLAGS
,
2726 htonl(flower
->key
.flags
));
2727 nl_msg_put_be32(request
, TCA_FLOWER_KEY_FLAGS_MASK
,
2728 htonl(flower
->mask
.flags
));
2731 if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
2732 FLOWER_PUT_MASKED_VALUE(udp_src
, TCA_FLOWER_KEY_UDP_SRC
);
2733 FLOWER_PUT_MASKED_VALUE(udp_dst
, TCA_FLOWER_KEY_UDP_DST
);
2734 } else if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
2735 FLOWER_PUT_MASKED_VALUE(tcp_src
, TCA_FLOWER_KEY_TCP_SRC
);
2736 FLOWER_PUT_MASKED_VALUE(tcp_dst
, TCA_FLOWER_KEY_TCP_DST
);
2737 FLOWER_PUT_MASKED_VALUE(tcp_flags
, TCA_FLOWER_KEY_TCP_FLAGS
);
2738 } else if (flower
->key
.ip_proto
== IPPROTO_SCTP
) {
2739 FLOWER_PUT_MASKED_VALUE(sctp_src
, TCA_FLOWER_KEY_SCTP_SRC
);
2740 FLOWER_PUT_MASKED_VALUE(sctp_dst
, TCA_FLOWER_KEY_SCTP_DST
);
2743 FLOWER_PUT_MASKED_VALUE(ct_state
, TCA_FLOWER_KEY_CT_STATE
);
2744 FLOWER_PUT_MASKED_VALUE(ct_zone
, TCA_FLOWER_KEY_CT_ZONE
);
2745 FLOWER_PUT_MASKED_VALUE(ct_mark
, TCA_FLOWER_KEY_CT_MARK
);
2746 FLOWER_PUT_MASKED_VALUE(ct_label
, TCA_FLOWER_KEY_CT_LABELS
);
2749 if (host_eth_type
== ETH_P_IP
) {
2750 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_src
, TCA_FLOWER_KEY_IPV4_SRC
);
2751 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_dst
, TCA_FLOWER_KEY_IPV4_DST
);
2752 } else if (host_eth_type
== ETH_P_IPV6
) {
2753 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_src
, TCA_FLOWER_KEY_IPV6_SRC
);
2754 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_dst
, TCA_FLOWER_KEY_IPV6_DST
);
2757 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ETH_TYPE
, flower
->key
.eth_type
);
2760 if (mpls_lse_to_ttl(flower
->mask
.mpls_lse
)) {
2761 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_TTL
,
2762 mpls_lse_to_ttl(flower
->key
.mpls_lse
));
2764 if (mpls_lse_to_tc(flower
->mask
.mpls_lse
)) {
2765 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_TC
,
2766 mpls_lse_to_tc(flower
->key
.mpls_lse
));
2768 if (mpls_lse_to_bos(flower
->mask
.mpls_lse
)) {
2769 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_BOS
,
2770 mpls_lse_to_bos(flower
->key
.mpls_lse
));
2772 if (mpls_lse_to_label(flower
->mask
.mpls_lse
)) {
2773 nl_msg_put_u32(request
, TCA_FLOWER_KEY_MPLS_LABEL
,
2774 mpls_lse_to_label(flower
->key
.mpls_lse
));
2779 if (flower
->mask
.vlan_id
[0]) {
2780 nl_msg_put_u16(request
, TCA_FLOWER_KEY_VLAN_ID
,
2781 flower
->key
.vlan_id
[0]);
2783 if (flower
->mask
.vlan_prio
[0]) {
2784 nl_msg_put_u8(request
, TCA_FLOWER_KEY_VLAN_PRIO
,
2785 flower
->key
.vlan_prio
[0]);
2787 if (flower
->key
.encap_eth_type
[0]) {
2788 nl_msg_put_be16(request
, TCA_FLOWER_KEY_VLAN_ETH_TYPE
,
2789 flower
->key
.encap_eth_type
[0]);
2793 if (flower
->mask
.vlan_id
[1]) {
2794 nl_msg_put_u16(request
, TCA_FLOWER_KEY_CVLAN_ID
,
2795 flower
->key
.vlan_id
[1]);
2797 if (flower
->mask
.vlan_prio
[1]) {
2798 nl_msg_put_u8(request
, TCA_FLOWER_KEY_CVLAN_PRIO
,
2799 flower
->key
.vlan_prio
[1]);
2801 if (flower
->key
.encap_eth_type
[1]) {
2802 nl_msg_put_be16(request
, TCA_FLOWER_KEY_CVLAN_ETH_TYPE
,
2803 flower
->key
.encap_eth_type
[1]);
2808 nl_msg_put_u32(request
, TCA_FLOWER_FLAGS
, tc_get_tc_cls_policy(tc_policy
));
2810 if (flower
->tunnel
) {
2811 nl_msg_put_flower_tunnel(request
, flower
);
2818 tc_replace_flower(struct tcf_id
*id
, struct tc_flower
*flower
)
2820 struct ofpbuf request
;
2821 struct ofpbuf
*reply
;
2823 size_t basic_offset
;
2824 uint16_t eth_type
= (OVS_FORCE
uint16_t) flower
->key
.eth_type
;
2826 request_from_tcf_id(id
, eth_type
, RTM_NEWTFILTER
,
2827 NLM_F_CREATE
| NLM_F_ECHO
, &request
);
2829 nl_msg_put_string(&request
, TCA_KIND
, "flower");
2830 basic_offset
= nl_msg_start_nested(&request
, TCA_OPTIONS
);
2832 error
= nl_msg_put_flower_options(&request
, flower
);
2835 ofpbuf_uninit(&request
);
2839 nl_msg_end_nested(&request
, basic_offset
);
2841 error
= tc_transact(&request
, &reply
);
2844 ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
2846 id
->prio
= tc_get_major(tc
->tcm_info
);
2847 id
->handle
= tc
->tcm_handle
;
2848 ofpbuf_delete(reply
);
2855 tc_set_policy(const char *policy
)
2861 if (!strcmp(policy
, "skip_sw")) {
2862 tc_policy
= TC_POLICY_SKIP_SW
;
2863 } else if (!strcmp(policy
, "skip_hw")) {
2864 tc_policy
= TC_POLICY_SKIP_HW
;
2865 } else if (!strcmp(policy
, "none")) {
2866 tc_policy
= TC_POLICY_NONE
;
2868 VLOG_WARN("tc: Invalid policy '%s'", policy
);
2872 VLOG_INFO("tc: Using policy '%s'", policy
);