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/gen_stats.h>
37 #include "byte-order.h"
38 #include "netlink-socket.h"
40 #include "openvswitch/ofpbuf.h"
41 #include "openvswitch/util.h"
42 #include "openvswitch/vlog.h"
45 #include "unaligned.h"
47 #define MAX_PEDIT_OFFSETS 32
49 #ifndef TCM_IFINDEX_MAGIC_BLOCK
50 #define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
54 #define TCA_INGRESS_BLOCK 13
57 VLOG_DEFINE_THIS_MODULE(tc
);
59 static struct vlog_rate_limit error_rl
= VLOG_RATE_LIMIT_INIT(60, 5);
61 enum tc_offload_policy
{
67 static enum tc_offload_policy tc_policy
= TC_POLICY_NONE
;
69 struct tc_pedit_key_ex
{
70 enum pedit_header_type htype
;
74 struct flower_key_to_pedit
{
75 enum pedit_header_type htype
;
82 static struct flower_key_to_pedit flower_pedit_map
[] = {
84 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
86 offsetof(struct tc_flower_key
, ipv4
.ipv4_src
),
87 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.ipv4_src
),
90 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
92 offsetof(struct tc_flower_key
, ipv4
.ipv4_dst
),
93 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.ipv4_dst
),
96 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
98 offsetof(struct tc_flower_key
, ipv4
.rewrite_ttl
),
99 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.rewrite_ttl
),
102 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
104 offsetof(struct tc_flower_key
, ipv4
.rewrite_tos
),
105 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.rewrite_tos
),
108 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
110 offsetof(struct tc_flower_key
, ipv6
.rewrite_hlimit
),
111 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.rewrite_hlimit
),
114 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
116 offsetof(struct tc_flower_key
, ipv6
.ipv6_src
),
117 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.ipv6_src
),
120 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
122 offsetof(struct tc_flower_key
, ipv6
.ipv6_dst
),
123 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.ipv6_dst
),
126 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
128 offsetof(struct tc_flower_key
, ipv6
.rewrite_tclass
),
129 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.rewrite_tclass
),
132 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
134 offsetof(struct tc_flower_key
, src_mac
),
135 MEMBER_SIZEOF(struct tc_flower_key
, src_mac
),
138 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
140 offsetof(struct tc_flower_key
, dst_mac
),
141 MEMBER_SIZEOF(struct tc_flower_key
, dst_mac
),
144 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
146 offsetof(struct tc_flower_key
, eth_type
),
147 MEMBER_SIZEOF(struct tc_flower_key
, eth_type
),
150 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
,
152 offsetof(struct tc_flower_key
, tcp_src
),
153 MEMBER_SIZEOF(struct tc_flower_key
, tcp_src
),
156 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
,
158 offsetof(struct tc_flower_key
, tcp_dst
),
159 MEMBER_SIZEOF(struct tc_flower_key
, tcp_dst
),
162 TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
,
164 offsetof(struct tc_flower_key
, udp_src
),
165 MEMBER_SIZEOF(struct tc_flower_key
, udp_src
),
168 TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
,
170 offsetof(struct tc_flower_key
, udp_dst
),
171 MEMBER_SIZEOF(struct tc_flower_key
, udp_dst
),
177 csum_update_flag(struct tc_flower
*flower
,
178 enum pedit_header_type htype
);
181 tc_make_request(int ifindex
, int type
, unsigned int flags
,
182 struct ofpbuf
*request
)
186 ofpbuf_init(request
, 512);
187 nl_msg_put_nlmsghdr(request
, sizeof *tcmsg
, type
, NLM_F_REQUEST
| flags
);
188 tcmsg
= ofpbuf_put_zeros(request
, sizeof *tcmsg
);
189 tcmsg
->tcm_family
= AF_UNSPEC
;
190 tcmsg
->tcm_ifindex
= ifindex
;
191 /* Caller should fill in tcmsg->tcm_handle. */
192 /* Caller should fill in tcmsg->tcm_parent. */
198 tc_transact(struct ofpbuf
*request
, struct ofpbuf
**replyp
)
200 int error
= nl_transact(NETLINK_ROUTE
, request
, replyp
);
201 ofpbuf_uninit(request
);
205 /* Adds or deletes a root qdisc on device with specified ifindex.
207 * The tc_qdisc_hook parameter determines if the qdisc is added on device
210 * If tc_qdisc_hook is TC_INGRESS, this function is equivalent to running the
211 * following when 'add' is true:
212 * /sbin/tc qdisc add dev <devname> handle ffff: ingress
214 * This function is equivalent to running the following when 'add' is false:
215 * /sbin/tc qdisc del dev <devname> handle ffff: ingress
217 * If tc_qdisc_hook is TC_EGRESS, this function is equivalent to:
218 * /sbin/tc qdisc (add|del) dev <devname> handle ffff: clsact
220 * Where dev <devname> is the device with specified ifindex name.
222 * The configuration and stats may be seen with the following command:
223 * /sbin/tc -s qdisc show dev <devname>
225 * If block_id is greater than 0, then the ingress qdisc is added to a block.
226 * In this case, it is equivalent to running (when 'add' is true):
227 * /sbin/tc qdisc add dev <devname> ingress_block <block_id> ingress
229 * Returns 0 if successful, otherwise a positive errno value.
232 tc_add_del_qdisc(int ifindex
, bool add
, uint32_t block_id
,
233 enum tc_qdisc_hook hook
)
235 struct ofpbuf request
;
238 int type
= add
? RTM_NEWQDISC
: RTM_DELQDISC
;
239 int flags
= add
? NLM_F_EXCL
| NLM_F_CREATE
: 0;
241 tcmsg
= tc_make_request(ifindex
, type
, flags
, &request
);
243 if (hook
== TC_EGRESS
) {
244 tcmsg
->tcm_handle
= TC_H_MAKE(TC_H_CLSACT
, 0);
245 tcmsg
->tcm_parent
= TC_H_CLSACT
;
246 nl_msg_put_string(&request
, TCA_KIND
, "clsact");
248 tcmsg
->tcm_handle
= TC_H_MAKE(TC_H_INGRESS
, 0);
249 tcmsg
->tcm_parent
= TC_H_INGRESS
;
250 nl_msg_put_string(&request
, TCA_KIND
, "ingress");
253 nl_msg_put_unspec(&request
, TCA_OPTIONS
, NULL
, 0);
254 if (hook
== TC_INGRESS
&& block_id
) {
255 nl_msg_put_u32(&request
, TCA_INGRESS_BLOCK
, block_id
);
258 error
= tc_transact(&request
, NULL
);
260 /* If we're deleting the qdisc, don't worry about some of the
261 * error conditions. */
262 if (!add
&& (error
== ENOENT
|| error
== EINVAL
)) {
271 static const struct nl_policy tca_policy
[] = {
272 [TCA_KIND
] = { .type
= NL_A_STRING
, .optional
= false, },
273 [TCA_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= false, },
274 [TCA_STATS
] = { .type
= NL_A_UNSPEC
,
275 .min_len
= sizeof(struct tc_stats
), .optional
= true, },
276 [TCA_STATS2
] = { .type
= NL_A_NESTED
, .optional
= true, },
279 static const struct nl_policy tca_flower_policy
[] = {
280 [TCA_FLOWER_CLASSID
] = { .type
= NL_A_U32
, .optional
= true, },
281 [TCA_FLOWER_INDEV
] = { .type
= NL_A_STRING
, .max_len
= IFNAMSIZ
,
283 [TCA_FLOWER_KEY_ETH_SRC
] = { .type
= NL_A_UNSPEC
,
284 .min_len
= ETH_ALEN
, .optional
= true, },
285 [TCA_FLOWER_KEY_ETH_DST
] = { .type
= NL_A_UNSPEC
,
286 .min_len
= ETH_ALEN
, .optional
= true, },
287 [TCA_FLOWER_KEY_ETH_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
290 [TCA_FLOWER_KEY_ETH_DST_MASK
] = { .type
= NL_A_UNSPEC
,
293 [TCA_FLOWER_KEY_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= false, },
294 [TCA_FLOWER_FLAGS
] = { .type
= NL_A_U32
, .optional
= false, },
295 [TCA_FLOWER_ACT
] = { .type
= NL_A_NESTED
, .optional
= false, },
296 [TCA_FLOWER_KEY_IP_PROTO
] = { .type
= NL_A_U8
, .optional
= true, },
297 [TCA_FLOWER_KEY_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
298 [TCA_FLOWER_KEY_IPV4_DST
] = {.type
= NL_A_U32
, .optional
= true, },
299 [TCA_FLOWER_KEY_IPV4_SRC_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
300 [TCA_FLOWER_KEY_IPV4_DST_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
301 [TCA_FLOWER_KEY_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
302 .min_len
= sizeof(struct in6_addr
),
304 [TCA_FLOWER_KEY_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
305 .min_len
= sizeof(struct in6_addr
),
307 [TCA_FLOWER_KEY_IPV6_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
308 .min_len
= sizeof(struct in6_addr
),
310 [TCA_FLOWER_KEY_IPV6_DST_MASK
] = { .type
= NL_A_UNSPEC
,
311 .min_len
= sizeof(struct in6_addr
),
313 [TCA_FLOWER_KEY_TCP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
314 [TCA_FLOWER_KEY_TCP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
315 [TCA_FLOWER_KEY_TCP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
316 [TCA_FLOWER_KEY_TCP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
317 [TCA_FLOWER_KEY_UDP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
318 [TCA_FLOWER_KEY_UDP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
319 [TCA_FLOWER_KEY_UDP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
320 [TCA_FLOWER_KEY_UDP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
321 [TCA_FLOWER_KEY_SCTP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
322 [TCA_FLOWER_KEY_SCTP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
323 [TCA_FLOWER_KEY_SCTP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
324 [TCA_FLOWER_KEY_SCTP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
325 [TCA_FLOWER_KEY_MPLS_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
326 [TCA_FLOWER_KEY_MPLS_TC
] = { .type
= NL_A_U8
, .optional
= true, },
327 [TCA_FLOWER_KEY_MPLS_BOS
] = { .type
= NL_A_U8
, .optional
= true, },
328 [TCA_FLOWER_KEY_MPLS_LABEL
] = { .type
= NL_A_U32
, .optional
= true, },
329 [TCA_FLOWER_KEY_VLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
330 [TCA_FLOWER_KEY_VLAN_PRIO
] = { .type
= NL_A_U8
, .optional
= true, },
331 [TCA_FLOWER_KEY_VLAN_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= true, },
332 [TCA_FLOWER_KEY_ENC_KEY_ID
] = { .type
= NL_A_U32
, .optional
= true, },
333 [TCA_FLOWER_KEY_ENC_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
334 [TCA_FLOWER_KEY_ENC_IPV4_DST
] = { .type
= NL_A_U32
, .optional
= true, },
335 [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
] = { .type
= NL_A_U32
,
337 [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
] = { .type
= NL_A_U32
,
339 [TCA_FLOWER_KEY_ENC_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
340 .min_len
= sizeof(struct in6_addr
),
342 [TCA_FLOWER_KEY_ENC_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
343 .min_len
= sizeof(struct in6_addr
),
345 [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
346 .min_len
= sizeof(struct in6_addr
),
348 [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
] = { .type
= NL_A_UNSPEC
,
349 .min_len
= sizeof(struct in6_addr
),
351 [TCA_FLOWER_KEY_ENC_UDP_DST_PORT
] = { .type
= NL_A_U16
,
353 [TCA_FLOWER_KEY_FLAGS
] = { .type
= NL_A_BE32
, .optional
= true, },
354 [TCA_FLOWER_KEY_FLAGS_MASK
] = { .type
= NL_A_BE32
, .optional
= true, },
355 [TCA_FLOWER_KEY_IP_TTL
] = { .type
= NL_A_U8
,
357 [TCA_FLOWER_KEY_IP_TTL_MASK
] = { .type
= NL_A_U8
,
359 [TCA_FLOWER_KEY_IP_TOS
] = { .type
= NL_A_U8
,
361 [TCA_FLOWER_KEY_IP_TOS_MASK
] = { .type
= NL_A_U8
,
363 [TCA_FLOWER_KEY_TCP_FLAGS
] = { .type
= NL_A_U16
,
365 [TCA_FLOWER_KEY_TCP_FLAGS_MASK
] = { .type
= NL_A_U16
,
367 [TCA_FLOWER_KEY_CVLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
368 [TCA_FLOWER_KEY_CVLAN_PRIO
] = { .type
= NL_A_U8
, .optional
= true, },
369 [TCA_FLOWER_KEY_CVLAN_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= true, },
370 [TCA_FLOWER_KEY_ENC_IP_TOS
] = { .type
= NL_A_U8
,
372 [TCA_FLOWER_KEY_ENC_IP_TOS_MASK
] = { .type
= NL_A_U8
,
374 [TCA_FLOWER_KEY_ENC_IP_TTL
] = { .type
= NL_A_U8
,
376 [TCA_FLOWER_KEY_ENC_IP_TTL_MASK
] = { .type
= NL_A_U8
,
378 [TCA_FLOWER_KEY_ENC_OPTS
] = { .type
= NL_A_NESTED
, .optional
= true, },
379 [TCA_FLOWER_KEY_ENC_OPTS_MASK
] = { .type
= NL_A_NESTED
,
384 nl_parse_flower_eth(struct nlattr
**attrs
, struct tc_flower
*flower
)
386 const struct eth_addr
*eth
;
388 if (attrs
[TCA_FLOWER_KEY_ETH_SRC_MASK
]) {
389 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_SRC
], ETH_ALEN
);
390 memcpy(&flower
->key
.src_mac
, eth
, sizeof flower
->key
.src_mac
);
392 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_SRC_MASK
], ETH_ALEN
);
393 memcpy(&flower
->mask
.src_mac
, eth
, sizeof flower
->mask
.src_mac
);
395 if (attrs
[TCA_FLOWER_KEY_ETH_DST_MASK
]) {
396 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_DST
], ETH_ALEN
);
397 memcpy(&flower
->key
.dst_mac
, eth
, sizeof flower
->key
.dst_mac
);
399 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_DST_MASK
], ETH_ALEN
);
400 memcpy(&flower
->mask
.dst_mac
, eth
, sizeof flower
->mask
.dst_mac
);
405 nl_parse_flower_mpls(struct nlattr
**attrs
, struct tc_flower
*flower
)
407 uint8_t ttl
, tc
, bos
;
410 if (!eth_type_mpls(flower
->key
.eth_type
)) {
414 flower
->key
.encap_eth_type
[0] =
415 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ETH_TYPE
]);
416 flower
->key
.mpls_lse
= 0;
417 flower
->mask
.mpls_lse
= 0;
419 if (attrs
[TCA_FLOWER_KEY_MPLS_TTL
]) {
420 ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_MPLS_TTL
]);
421 set_mpls_lse_ttl(&flower
->key
.mpls_lse
, ttl
);
422 set_mpls_lse_ttl(&flower
->mask
.mpls_lse
, 0xff);
425 if (attrs
[TCA_FLOWER_KEY_MPLS_BOS
]) {
426 bos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_MPLS_BOS
]);
427 set_mpls_lse_bos(&flower
->key
.mpls_lse
, bos
);
428 set_mpls_lse_ttl(&flower
->mask
.mpls_lse
, 0xff);
431 if (attrs
[TCA_FLOWER_KEY_MPLS_TC
]) {
432 tc
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_MPLS_TC
]);
433 set_mpls_lse_tc(&flower
->key
.mpls_lse
, tc
);
434 set_mpls_lse_tc(&flower
->mask
.mpls_lse
, 0xff);
437 if (attrs
[TCA_FLOWER_KEY_MPLS_LABEL
]) {
438 label
= nl_attr_get_u32(attrs
[TCA_FLOWER_KEY_MPLS_LABEL
]);
439 set_mpls_lse_label(&flower
->key
.mpls_lse
, htonl(label
));
440 set_mpls_lse_label(&flower
->mask
.mpls_lse
, OVS_BE32_MAX
);
445 nl_parse_flower_vlan(struct nlattr
**attrs
, struct tc_flower
*flower
)
447 ovs_be16 encap_ethtype
;
449 if (!eth_type_vlan(flower
->key
.eth_type
)) {
453 flower
->key
.encap_eth_type
[0] =
454 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ETH_TYPE
]);
456 if (attrs
[TCA_FLOWER_KEY_VLAN_ID
]) {
457 flower
->key
.vlan_id
[0] =
458 nl_attr_get_u16(attrs
[TCA_FLOWER_KEY_VLAN_ID
]);
459 flower
->mask
.vlan_id
[0] = 0xffff;
461 if (attrs
[TCA_FLOWER_KEY_VLAN_PRIO
]) {
462 flower
->key
.vlan_prio
[0] =
463 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_VLAN_PRIO
]);
464 flower
->mask
.vlan_prio
[0] = 0xff;
467 if (!attrs
[TCA_FLOWER_KEY_VLAN_ETH_TYPE
]) {
471 encap_ethtype
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_VLAN_ETH_TYPE
]);
472 if (!eth_type_vlan(encap_ethtype
)) {
476 flower
->key
.encap_eth_type
[1] = flower
->key
.encap_eth_type
[0];
477 flower
->key
.encap_eth_type
[0] = encap_ethtype
;
479 if (attrs
[TCA_FLOWER_KEY_CVLAN_ID
]) {
480 flower
->key
.vlan_id
[1] =
481 nl_attr_get_u16(attrs
[TCA_FLOWER_KEY_CVLAN_ID
]);
482 flower
->mask
.vlan_id
[1] = 0xffff;
484 if (attrs
[TCA_FLOWER_KEY_CVLAN_PRIO
]) {
485 flower
->key
.vlan_prio
[1] =
486 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_CVLAN_PRIO
]);
487 flower
->mask
.vlan_prio
[1] = 0xff;
492 nl_parse_geneve_key(const struct nlattr
*in_nlattr
,
493 struct tun_metadata
*metadata
)
495 struct geneve_opt
*opt
= NULL
;
496 const struct ofpbuf
*msg
;
497 uint16_t last_opt_type
;
503 nl_attr_get_nested(in_nlattr
, &buf
);
506 last_opt_type
= TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC
;
508 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
509 uint16_t type
= nl_attr_type(nla
);
512 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
:
513 if (cnt
&& last_opt_type
!= TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
) {
514 VLOG_ERR_RL(&error_rl
, "failed to parse tun options class");
518 opt
= &metadata
->opts
.gnv
[cnt
];
519 opt
->opt_class
= nl_attr_get_be16(nla
);
520 cnt
+= sizeof(struct geneve_opt
) / 4;
521 metadata
->present
.len
+= sizeof(struct geneve_opt
);
522 last_opt_type
= TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
;
524 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
:
525 if (last_opt_type
!= TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
) {
526 VLOG_ERR_RL(&error_rl
, "failed to parse tun options type");
530 opt
->type
= nl_attr_get_u8(nla
);
531 last_opt_type
= TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
;
533 case TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
:
534 if (last_opt_type
!= TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
) {
535 VLOG_ERR_RL(&error_rl
, "failed to parse tun options data");
539 opt
->length
= nl_attr_get_size(nla
) / 4;
540 memcpy(opt
+ 1, nl_attr_get_unspec(nla
, 1), opt
->length
* 4);
542 metadata
->present
.len
+= opt
->length
* 4;
543 last_opt_type
= TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
;
548 if (last_opt_type
!= TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
) {
549 VLOG_ERR_RL(&error_rl
, "failed to parse tun options without data");
557 nl_parse_flower_tunnel_opts(struct nlattr
*options
,
558 struct tun_metadata
*metadata
)
560 const struct ofpbuf
*msg
;
566 nl_attr_get_nested(options
, &buf
);
569 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
570 uint16_t type
= nl_attr_type(nla
);
572 case TCA_FLOWER_KEY_ENC_OPTS_GENEVE
:
573 err
= nl_parse_geneve_key(nla
, metadata
);
586 flower_tun_geneve_opt_check_len(struct tun_metadata
*key
,
587 struct tun_metadata
*mask
)
589 const struct geneve_opt
*opt
, *opt_mask
;
592 len
= key
->present
.len
;
594 opt
= &key
->opts
.gnv
[cnt
];
595 opt_mask
= &mask
->opts
.gnv
[cnt
];
597 if (opt
->length
!= opt_mask
->length
) {
598 VLOG_ERR_RL(&error_rl
,
599 "failed to parse tun options; key/mask length differ");
603 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
604 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
611 nl_parse_flower_tunnel(struct nlattr
**attrs
, struct tc_flower
*flower
)
615 if (attrs
[TCA_FLOWER_KEY_ENC_KEY_ID
]) {
616 ovs_be32 id
= nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_KEY_ID
]);
618 flower
->key
.tunnel
.id
= be32_to_be64(id
);
619 flower
->mask
.tunnel
.id
= OVS_BE64_MAX
;
621 if (attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
]) {
622 flower
->key
.tunnel
.ipv4
.ipv4_src
=
623 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC
]);
625 if (attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
]) {
626 flower
->key
.tunnel
.ipv4
.ipv4_dst
=
627 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST
]);
629 if (attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
]) {
630 flower
->key
.tunnel
.ipv6
.ipv6_src
=
631 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC
]);
633 if (attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
]) {
634 flower
->key
.tunnel
.ipv6
.ipv6_dst
=
635 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST
]);
637 if (attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]) {
638 flower
->key
.tunnel
.tp_dst
=
639 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]);
641 if (attrs
[TCA_FLOWER_KEY_ENC_IP_TOS_MASK
]) {
642 flower
->key
.tunnel
.tos
=
643 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TOS
]);
644 flower
->mask
.tunnel
.tos
=
645 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TOS_MASK
]);
647 if (attrs
[TCA_FLOWER_KEY_ENC_IP_TTL_MASK
]) {
648 flower
->key
.tunnel
.ttl
=
649 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TTL
]);
650 flower
->mask
.tunnel
.ttl
=
651 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TTL_MASK
]);
653 if (attrs
[TCA_FLOWER_KEY_ENC_OPTS
] &&
654 attrs
[TCA_FLOWER_KEY_ENC_OPTS_MASK
]) {
655 err
= nl_parse_flower_tunnel_opts(attrs
[TCA_FLOWER_KEY_ENC_OPTS
],
656 &flower
->key
.tunnel
.metadata
);
661 err
= nl_parse_flower_tunnel_opts(attrs
[TCA_FLOWER_KEY_ENC_OPTS_MASK
],
662 &flower
->mask
.tunnel
.metadata
);
667 err
= flower_tun_geneve_opt_check_len(&flower
->key
.tunnel
.metadata
,
668 &flower
->mask
.tunnel
.metadata
);
672 } else if (attrs
[TCA_FLOWER_KEY_ENC_OPTS
]) {
673 VLOG_ERR_RL(&error_rl
,
674 "failed to parse tun options; no mask supplied");
676 } else if (attrs
[TCA_FLOWER_KEY_ENC_OPTS_MASK
]) {
677 VLOG_ERR_RL(&error_rl
, "failed to parse tun options; no key supplied");
685 nl_parse_flower_ip(struct nlattr
**attrs
, struct tc_flower
*flower
) {
686 uint8_t ip_proto
= 0;
687 struct tc_flower_key
*key
= &flower
->key
;
688 struct tc_flower_key
*mask
= &flower
->mask
;
690 if (attrs
[TCA_FLOWER_KEY_IP_PROTO
]) {
691 ip_proto
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_PROTO
]);
692 key
->ip_proto
= ip_proto
;
693 mask
->ip_proto
= UINT8_MAX
;
696 if (attrs
[TCA_FLOWER_KEY_FLAGS_MASK
]) {
697 key
->flags
= ntohl(nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_FLAGS
]));
699 ntohl(nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_FLAGS_MASK
]));
702 if (attrs
[TCA_FLOWER_KEY_IPV4_SRC_MASK
]) {
704 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_SRC
]);
705 mask
->ipv4
.ipv4_src
=
706 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_SRC_MASK
]);
708 if (attrs
[TCA_FLOWER_KEY_IPV4_DST_MASK
]) {
710 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_DST
]);
711 mask
->ipv4
.ipv4_dst
=
712 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_DST_MASK
]);
714 if (attrs
[TCA_FLOWER_KEY_IPV6_SRC_MASK
]) {
715 struct nlattr
*attr
= attrs
[TCA_FLOWER_KEY_IPV6_SRC
];
716 struct nlattr
*attr_mask
= attrs
[TCA_FLOWER_KEY_IPV6_SRC_MASK
];
718 key
->ipv6
.ipv6_src
= nl_attr_get_in6_addr(attr
);
719 mask
->ipv6
.ipv6_src
= nl_attr_get_in6_addr(attr_mask
);
721 if (attrs
[TCA_FLOWER_KEY_IPV6_DST_MASK
]) {
722 struct nlattr
*attr
= attrs
[TCA_FLOWER_KEY_IPV6_DST
];
723 struct nlattr
*attr_mask
= attrs
[TCA_FLOWER_KEY_IPV6_DST_MASK
];
725 key
->ipv6
.ipv6_dst
= nl_attr_get_in6_addr(attr
);
726 mask
->ipv6
.ipv6_dst
= nl_attr_get_in6_addr(attr_mask
);
729 if (ip_proto
== IPPROTO_TCP
) {
730 if (attrs
[TCA_FLOWER_KEY_TCP_SRC_MASK
]) {
732 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_SRC
]);
734 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_SRC_MASK
]);
736 if (attrs
[TCA_FLOWER_KEY_TCP_DST_MASK
]) {
738 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_DST
]);
740 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_DST_MASK
]);
742 if (attrs
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]) {
744 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_FLAGS
]);
746 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]);
748 } else if (ip_proto
== IPPROTO_UDP
) {
749 if (attrs
[TCA_FLOWER_KEY_UDP_SRC_MASK
]) {
750 key
->udp_src
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_SRC
]);
752 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_SRC_MASK
]);
754 if (attrs
[TCA_FLOWER_KEY_UDP_DST_MASK
]) {
755 key
->udp_dst
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_DST
]);
757 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_DST_MASK
]);
759 } else if (ip_proto
== IPPROTO_SCTP
) {
760 if (attrs
[TCA_FLOWER_KEY_SCTP_SRC_MASK
]) {
761 key
->sctp_src
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_SRC
]);
763 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_SRC_MASK
]);
765 if (attrs
[TCA_FLOWER_KEY_SCTP_DST_MASK
]) {
766 key
->sctp_dst
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_DST
]);
768 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_DST_MASK
]);
772 if (attrs
[TCA_FLOWER_KEY_IP_TTL_MASK
]) {
773 key
->ip_ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TTL
]);
774 mask
->ip_ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TTL_MASK
]);
777 if (attrs
[TCA_FLOWER_KEY_IP_TOS_MASK
]) {
778 key
->ip_tos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TOS
]);
779 mask
->ip_tos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TOS_MASK
]);
783 static enum tc_offloaded_state
784 nl_get_flower_offloaded_state(struct nlattr
**attrs
)
786 uint32_t flower_flags
= 0;
788 if (attrs
[TCA_FLOWER_FLAGS
]) {
789 flower_flags
= nl_attr_get_u32(attrs
[TCA_FLOWER_FLAGS
]);
790 if (flower_flags
& TCA_CLS_FLAGS_NOT_IN_HW
) {
791 return TC_OFFLOADED_STATE_NOT_IN_HW
;
792 } else if (flower_flags
& TCA_CLS_FLAGS_IN_HW
) {
793 return TC_OFFLOADED_STATE_IN_HW
;
796 return TC_OFFLOADED_STATE_UNDEFINED
;
800 nl_parse_flower_flags(struct nlattr
**attrs
, struct tc_flower
*flower
)
802 flower
->offloaded_state
= nl_get_flower_offloaded_state(attrs
);
805 static const struct nl_policy pedit_policy
[] = {
806 [TCA_PEDIT_PARMS_EX
] = { .type
= NL_A_UNSPEC
,
807 .min_len
= sizeof(struct tc_pedit
),
808 .optional
= false, },
809 [TCA_PEDIT_KEYS_EX
] = { .type
= NL_A_NESTED
,
810 .optional
= false, },
814 nl_parse_act_pedit(struct nlattr
*options
, struct tc_flower
*flower
)
816 struct tc_action
*action
;
817 struct nlattr
*pe_attrs
[ARRAY_SIZE(pedit_policy
)];
818 const struct tc_pedit
*pe
;
819 const struct tc_pedit_key
*keys
;
820 const struct nlattr
*nla
, *keys_ex
, *ex_type
;
821 const void *keys_attr
;
822 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
823 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
824 size_t keys_ex_size
, left
;
825 int type
, i
= 0, err
;
827 if (!nl_parse_nested(options
, pedit_policy
, pe_attrs
,
828 ARRAY_SIZE(pedit_policy
))) {
829 VLOG_ERR_RL(&error_rl
, "failed to parse pedit action options");
833 pe
= nl_attr_get_unspec(pe_attrs
[TCA_PEDIT_PARMS_EX
], sizeof *pe
);
835 keys_attr
= pe_attrs
[TCA_PEDIT_KEYS_EX
];
836 keys_ex
= nl_attr_get(keys_attr
);
837 keys_ex_size
= nl_attr_get_size(keys_attr
);
839 NL_ATTR_FOR_EACH (nla
, left
, keys_ex
, keys_ex_size
) {
840 if (i
>= pe
->nkeys
) {
844 if (nl_attr_type(nla
) != TCA_PEDIT_KEY_EX
) {
845 VLOG_ERR_RL(&error_rl
, "unable to parse legacy pedit type: %d",
850 ex_type
= nl_attr_find_nested(nla
, TCA_PEDIT_KEY_EX_HTYPE
);
851 type
= nl_attr_get_u16(ex_type
);
853 err
= csum_update_flag(flower
, type
);
858 for (int j
= 0; j
< ARRAY_SIZE(flower_pedit_map
); j
++) {
859 struct flower_key_to_pedit
*m
= &flower_pedit_map
[j
];
860 int flower_off
= m
->flower_offset
;
864 if (m
->htype
!= type
) {
868 /* check overlap between current pedit key, which is always
869 * 4 bytes (range [off, off + 3]), and a map entry in
870 * flower_pedit_map (range [mf, mf + sz - 1]) */
871 if ((keys
->off
>= mf
&& keys
->off
< mf
+ sz
)
872 || (keys
->off
+ 3 >= mf
&& keys
->off
+ 3 < mf
+ sz
)) {
873 int diff
= flower_off
+ (keys
->off
- mf
);
874 ovs_be32
*dst
= (void *) (rewrite_key
+ diff
);
875 ovs_be32
*dst_m
= (void *) (rewrite_mask
+ diff
);
876 ovs_be32 mask
, mask_word
, data_word
;
879 mask_word
= htonl(ntohl(keys
->mask
) << m
->boundary_shift
);
880 data_word
= htonl(ntohl(keys
->val
) << m
->boundary_shift
);
883 if (keys
->off
< mf
) {
884 zero_bits
= 8 * (mf
- keys
->off
);
885 mask
&= htonl(UINT32_MAX
>> zero_bits
);
886 } else if (keys
->off
+ 4 > mf
+ m
->size
) {
887 zero_bits
= 8 * (keys
->off
+ 4 - mf
- m
->size
);
888 mask
&= htonl(UINT32_MAX
<< zero_bits
);
892 *dst
|= data_word
& mask
;
900 action
= &flower
->actions
[flower
->action_count
++];
901 action
->type
= TC_ACT_PEDIT
;
906 static const struct nl_policy tunnel_key_policy
[] = {
907 [TCA_TUNNEL_KEY_PARMS
] = { .type
= NL_A_UNSPEC
,
908 .min_len
= sizeof(struct tc_tunnel_key
),
909 .optional
= false, },
910 [TCA_TUNNEL_KEY_ENC_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
911 [TCA_TUNNEL_KEY_ENC_IPV4_DST
] = { .type
= NL_A_U32
, .optional
= true, },
912 [TCA_TUNNEL_KEY_ENC_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
913 .min_len
= sizeof(struct in6_addr
),
915 [TCA_TUNNEL_KEY_ENC_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
916 .min_len
= sizeof(struct in6_addr
),
918 [TCA_TUNNEL_KEY_ENC_KEY_ID
] = { .type
= NL_A_U32
, .optional
= true, },
919 [TCA_TUNNEL_KEY_ENC_DST_PORT
] = { .type
= NL_A_U16
, .optional
= true, },
920 [TCA_TUNNEL_KEY_ENC_TOS
] = { .type
= NL_A_U8
, .optional
= true, },
921 [TCA_TUNNEL_KEY_ENC_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
922 [TCA_TUNNEL_KEY_ENC_OPTS
] = { .type
= NL_A_NESTED
, .optional
= true, },
923 [TCA_TUNNEL_KEY_NO_CSUM
] = { .type
= NL_A_U8
, .optional
= true, },
927 nl_parse_act_geneve_opts(const struct nlattr
*in_nlattr
,
928 struct tc_action
*action
)
930 struct geneve_opt
*opt
= NULL
;
931 const struct ofpbuf
*msg
;
932 uint16_t last_opt_type
;
938 nl_attr_get_nested(in_nlattr
, &buf
);
941 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_UNSPEC
;
943 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
944 uint16_t type
= nl_attr_type(nla
);
947 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
:
948 if (cnt
&& last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
) {
949 VLOG_ERR_RL(&error_rl
,
950 "failed to parse action geneve options class");
954 opt
= &action
->encap
.data
.opts
.gnv
[cnt
];
955 opt
->opt_class
= nl_attr_get_be16(nla
);
956 cnt
+= sizeof(struct geneve_opt
) / 4;
957 action
->encap
.data
.present
.len
+= sizeof(struct geneve_opt
);
958 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
;
960 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
:
961 if (last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
) {
962 VLOG_ERR_RL(&error_rl
,
963 "failed to parse action geneve options type");
967 opt
->type
= nl_attr_get_u8(nla
);
968 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
;
970 case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
:
971 if (last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
) {
972 VLOG_ERR_RL(&error_rl
,
973 "failed to parse action geneve options data");
977 opt
->length
= nl_attr_get_size(nla
) / 4;
978 memcpy(opt
+ 1, nl_attr_get_unspec(nla
, 1), opt
->length
* 4);
980 action
->encap
.data
.present
.len
+= opt
->length
* 4;
981 last_opt_type
= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
;
986 if (last_opt_type
!= TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
) {
987 VLOG_ERR_RL(&error_rl
,
988 "failed to parse action geneve options without data");
996 nl_parse_act_tunnel_opts(struct nlattr
*options
, struct tc_action
*action
)
998 const struct ofpbuf
*msg
;
1008 nl_attr_get_nested(options
, &buf
);
1011 NL_ATTR_FOR_EACH (nla
, left
, ofpbuf_at(msg
, 0, 0), msg
->size
) {
1012 uint16_t type
= nl_attr_type(nla
);
1014 case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
:
1015 err
= nl_parse_act_geneve_opts(nla
, action
);
1028 nl_parse_act_tunnel_key(struct nlattr
*options
, struct tc_flower
*flower
)
1030 struct nlattr
*tun_attrs
[ARRAY_SIZE(tunnel_key_policy
)];
1031 const struct nlattr
*tun_parms
;
1032 const struct tc_tunnel_key
*tun
;
1033 struct tc_action
*action
;
1036 if (!nl_parse_nested(options
, tunnel_key_policy
, tun_attrs
,
1037 ARRAY_SIZE(tunnel_key_policy
))) {
1038 VLOG_ERR_RL(&error_rl
, "failed to parse tunnel_key action options");
1042 tun_parms
= tun_attrs
[TCA_TUNNEL_KEY_PARMS
];
1043 tun
= nl_attr_get_unspec(tun_parms
, sizeof *tun
);
1044 if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_SET
) {
1045 struct nlattr
*id
= tun_attrs
[TCA_TUNNEL_KEY_ENC_KEY_ID
];
1046 struct nlattr
*dst_port
= tun_attrs
[TCA_TUNNEL_KEY_ENC_DST_PORT
];
1047 struct nlattr
*ipv4_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_SRC
];
1048 struct nlattr
*ipv4_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_DST
];
1049 struct nlattr
*ipv6_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_SRC
];
1050 struct nlattr
*ipv6_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_DST
];
1051 struct nlattr
*tos
= tun_attrs
[TCA_TUNNEL_KEY_ENC_TOS
];
1052 struct nlattr
*ttl
= tun_attrs
[TCA_TUNNEL_KEY_ENC_TTL
];
1053 struct nlattr
*tun_opt
= tun_attrs
[TCA_TUNNEL_KEY_ENC_OPTS
];
1054 struct nlattr
*no_csum
= tun_attrs
[TCA_TUNNEL_KEY_NO_CSUM
];
1056 action
= &flower
->actions
[flower
->action_count
++];
1057 action
->type
= TC_ACT_ENCAP
;
1058 action
->encap
.ipv4
.ipv4_src
= ipv4_src
? nl_attr_get_be32(ipv4_src
) : 0;
1059 action
->encap
.ipv4
.ipv4_dst
= ipv4_dst
? nl_attr_get_be32(ipv4_dst
) : 0;
1061 action
->encap
.ipv6
.ipv6_src
= nl_attr_get_in6_addr(ipv6_src
);
1064 action
->encap
.ipv6
.ipv6_dst
= nl_attr_get_in6_addr(ipv6_dst
);
1066 action
->encap
.id
= id
? be32_to_be64(nl_attr_get_be32(id
)) : 0;
1067 action
->encap
.id_present
= id
? true : false;
1068 action
->encap
.tp_dst
= dst_port
? nl_attr_get_be16(dst_port
) : 0;
1069 action
->encap
.tos
= tos
? nl_attr_get_u8(tos
) : 0;
1070 action
->encap
.ttl
= ttl
? nl_attr_get_u8(ttl
) : 0;
1071 action
->encap
.no_csum
= no_csum
? nl_attr_get_u8(no_csum
) : 0;
1073 err
= nl_parse_act_tunnel_opts(tun_opt
, action
);
1077 } else if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_RELEASE
) {
1078 flower
->tunnel
= true;
1080 VLOG_ERR_RL(&error_rl
, "unknown tunnel actions: %d, %d",
1081 tun
->action
, tun
->t_action
);
1087 static const struct nl_policy gact_policy
[] = {
1088 [TCA_GACT_PARMS
] = { .type
= NL_A_UNSPEC
,
1089 .min_len
= sizeof(struct tc_gact
),
1090 .optional
= false, },
1091 [TCA_GACT_TM
] = { .type
= NL_A_UNSPEC
,
1092 .min_len
= sizeof(struct tcf_t
),
1093 .optional
= false, },
1099 static struct ovsthread_once once
= OVSTHREAD_ONCE_INITIALIZER
;
1100 static int user_hz
= 100;
1102 if (ovsthread_once_start(&once
)) {
1103 user_hz
= sysconf(_SC_CLK_TCK
);
1104 ovsthread_once_done(&once
);
1111 nl_parse_tcf(const struct tcf_t
*tm
, struct tc_flower
*flower
)
1113 flower
->lastused
= time_msec() - (tm
->lastuse
* 1000 / get_user_hz());
1117 nl_parse_act_drop(struct nlattr
*options
, struct tc_flower
*flower
)
1119 struct nlattr
*gact_attrs
[ARRAY_SIZE(gact_policy
)];
1120 const struct tc_gact
*p
;
1121 struct nlattr
*gact_parms
;
1122 const struct tcf_t
*tm
;
1124 if (!nl_parse_nested(options
, gact_policy
, gact_attrs
,
1125 ARRAY_SIZE(gact_policy
))) {
1126 VLOG_ERR_RL(&error_rl
, "failed to parse gact action options");
1130 gact_parms
= gact_attrs
[TCA_GACT_PARMS
];
1131 p
= nl_attr_get_unspec(gact_parms
, sizeof *p
);
1133 if (p
->action
!= TC_ACT_SHOT
) {
1134 VLOG_ERR_RL(&error_rl
, "unknown gact action: %d", p
->action
);
1138 tm
= nl_attr_get_unspec(gact_attrs
[TCA_GACT_TM
], sizeof *tm
);
1139 nl_parse_tcf(tm
, flower
);
1144 static const struct nl_policy mirred_policy
[] = {
1145 [TCA_MIRRED_PARMS
] = { .type
= NL_A_UNSPEC
,
1146 .min_len
= sizeof(struct tc_mirred
),
1147 .optional
= false, },
1148 [TCA_MIRRED_TM
] = { .type
= NL_A_UNSPEC
,
1149 .min_len
= sizeof(struct tcf_t
),
1150 .optional
= false, },
1154 nl_parse_act_mirred(struct nlattr
*options
, struct tc_flower
*flower
)
1157 struct nlattr
*mirred_attrs
[ARRAY_SIZE(mirred_policy
)];
1158 const struct tc_mirred
*m
;
1159 const struct nlattr
*mirred_parms
;
1160 const struct tcf_t
*tm
;
1161 struct nlattr
*mirred_tm
;
1162 struct tc_action
*action
;
1164 if (!nl_parse_nested(options
, mirred_policy
, mirred_attrs
,
1165 ARRAY_SIZE(mirred_policy
))) {
1166 VLOG_ERR_RL(&error_rl
, "failed to parse mirred action options");
1170 mirred_parms
= mirred_attrs
[TCA_MIRRED_PARMS
];
1171 m
= nl_attr_get_unspec(mirred_parms
, sizeof *m
);
1173 if (m
->eaction
!= TCA_EGRESS_REDIR
&& m
->eaction
!= TCA_EGRESS_MIRROR
&&
1174 m
->eaction
!= TCA_INGRESS_REDIR
&& m
->eaction
!= TCA_INGRESS_MIRROR
) {
1175 VLOG_ERR_RL(&error_rl
, "unknown mirred action: %d, %d, %d",
1176 m
->action
, m
->eaction
, m
->ifindex
);
1180 action
= &flower
->actions
[flower
->action_count
++];
1181 action
->out
.ifindex_out
= m
->ifindex
;
1182 if (m
->eaction
== TCA_INGRESS_REDIR
|| m
->eaction
== TCA_INGRESS_MIRROR
) {
1183 action
->out
.ingress
= true;
1185 action
->out
.ingress
= false;
1187 action
->type
= TC_ACT_OUTPUT
;
1189 mirred_tm
= mirred_attrs
[TCA_MIRRED_TM
];
1190 tm
= nl_attr_get_unspec(mirred_tm
, sizeof *tm
);
1191 nl_parse_tcf(tm
, flower
);
1196 static const struct nl_policy vlan_policy
[] = {
1197 [TCA_VLAN_PARMS
] = { .type
= NL_A_UNSPEC
,
1198 .min_len
= sizeof(struct tc_vlan
),
1199 .optional
= false, },
1200 [TCA_VLAN_PUSH_VLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
1201 [TCA_VLAN_PUSH_VLAN_PROTOCOL
] = { .type
= NL_A_U16
, .optional
= true, },
1202 [TCA_VLAN_PUSH_VLAN_PRIORITY
] = { .type
= NL_A_U8
, .optional
= true, },
1206 nl_parse_act_vlan(struct nlattr
*options
, struct tc_flower
*flower
)
1208 struct nlattr
*vlan_attrs
[ARRAY_SIZE(vlan_policy
)];
1209 const struct tc_vlan
*v
;
1210 const struct nlattr
*vlan_parms
;
1211 struct tc_action
*action
;
1213 if (!nl_parse_nested(options
, vlan_policy
, vlan_attrs
,
1214 ARRAY_SIZE(vlan_policy
))) {
1215 VLOG_ERR_RL(&error_rl
, "failed to parse vlan action options");
1219 action
= &flower
->actions
[flower
->action_count
++];
1220 vlan_parms
= vlan_attrs
[TCA_VLAN_PARMS
];
1221 v
= nl_attr_get_unspec(vlan_parms
, sizeof *v
);
1222 if (v
->v_action
== TCA_VLAN_ACT_PUSH
) {
1223 struct nlattr
*vlan_tpid
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PROTOCOL
];
1224 struct nlattr
*vlan_id
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_ID
];
1225 struct nlattr
*vlan_prio
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PRIORITY
];
1227 action
->vlan
.vlan_push_tpid
= nl_attr_get_be16(vlan_tpid
);
1228 action
->vlan
.vlan_push_id
= nl_attr_get_u16(vlan_id
);
1229 action
->vlan
.vlan_push_prio
= vlan_prio
? nl_attr_get_u8(vlan_prio
) : 0;
1230 action
->type
= TC_ACT_VLAN_PUSH
;
1231 } else if (v
->v_action
== TCA_VLAN_ACT_POP
) {
1232 action
->type
= TC_ACT_VLAN_POP
;
1234 VLOG_ERR_RL(&error_rl
, "unknown vlan action: %d, %d",
1235 v
->action
, v
->v_action
);
1241 static const struct nl_policy mpls_policy
[] = {
1242 [TCA_MPLS_PARMS
] = { .type
= NL_A_UNSPEC
,
1243 .min_len
= sizeof(struct tc_mpls
),
1244 .optional
= false, },
1245 [TCA_MPLS_PROTO
] = { .type
= NL_A_U16
, .optional
= true, },
1246 [TCA_MPLS_LABEL
] = { .type
= NL_A_U32
, .optional
= true, },
1247 [TCA_MPLS_TC
] = { .type
= NL_A_U8
, .optional
= true, },
1248 [TCA_MPLS_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
1249 [TCA_MPLS_BOS
] = { .type
= NL_A_U8
, .optional
= true, },
1253 nl_parse_act_mpls(struct nlattr
*options
, struct tc_flower
*flower
)
1255 struct nlattr
*mpls_attrs
[ARRAY_SIZE(mpls_policy
)];
1256 const struct nlattr
*mpls_parms
;
1257 struct nlattr
*mpls_proto
;
1258 struct nlattr
*mpls_label
;
1259 struct tc_action
*action
;
1260 const struct tc_mpls
*m
;
1261 struct nlattr
*mpls_ttl
;
1262 struct nlattr
*mpls_bos
;
1263 struct nlattr
*mpls_tc
;
1265 if (!nl_parse_nested(options
, mpls_policy
, mpls_attrs
,
1266 ARRAY_SIZE(mpls_policy
))) {
1267 VLOG_ERR_RL(&error_rl
, "failed to parse mpls action options");
1271 action
= &flower
->actions
[flower
->action_count
++];
1272 mpls_parms
= mpls_attrs
[TCA_MPLS_PARMS
];
1273 m
= nl_attr_get_unspec(mpls_parms
, sizeof *m
);
1275 switch (m
->m_action
) {
1276 case TCA_MPLS_ACT_POP
:
1277 mpls_proto
= mpls_attrs
[TCA_MPLS_PROTO
];
1279 action
->mpls
.proto
= nl_attr_get_be16(mpls_proto
);
1281 action
->type
= TC_ACT_MPLS_POP
;
1283 case TCA_MPLS_ACT_PUSH
:
1284 mpls_proto
= mpls_attrs
[TCA_MPLS_PROTO
];
1286 action
->mpls
.proto
= nl_attr_get_be16(mpls_proto
);
1288 mpls_label
= mpls_attrs
[TCA_MPLS_LABEL
];
1290 action
->mpls
.label
= nl_attr_get_u32(mpls_label
);
1292 mpls_tc
= mpls_attrs
[TCA_MPLS_TC
];
1294 action
->mpls
.tc
= nl_attr_get_u8(mpls_tc
);
1296 mpls_ttl
= mpls_attrs
[TCA_MPLS_TTL
];
1298 action
->mpls
.ttl
= nl_attr_get_u8(mpls_ttl
);
1300 mpls_bos
= mpls_attrs
[TCA_MPLS_BOS
];
1302 action
->mpls
.bos
= nl_attr_get_u8(mpls_bos
);
1304 action
->type
= TC_ACT_MPLS_PUSH
;
1306 case TCA_MPLS_ACT_MODIFY
:
1307 mpls_label
= mpls_attrs
[TCA_MPLS_LABEL
];
1309 action
->mpls
.label
= nl_attr_get_u32(mpls_label
);
1311 mpls_tc
= mpls_attrs
[TCA_MPLS_TC
];
1313 action
->mpls
.tc
= nl_attr_get_u8(mpls_tc
);
1315 mpls_ttl
= mpls_attrs
[TCA_MPLS_TTL
];
1317 action
->mpls
.ttl
= nl_attr_get_u8(mpls_ttl
);
1319 mpls_bos
= mpls_attrs
[TCA_MPLS_BOS
];
1321 action
->mpls
.bos
= nl_attr_get_u8(mpls_bos
);
1323 action
->type
= TC_ACT_MPLS_SET
;
1326 VLOG_ERR_RL(&error_rl
, "unknown mpls action: %d, %d",
1327 m
->action
, m
->m_action
);
1334 static const struct nl_policy csum_policy
[] = {
1335 [TCA_CSUM_PARMS
] = { .type
= NL_A_UNSPEC
,
1336 .min_len
= sizeof(struct tc_csum
),
1337 .optional
= false, },
1341 nl_parse_act_csum(struct nlattr
*options
, struct tc_flower
*flower
)
1343 struct nlattr
*csum_attrs
[ARRAY_SIZE(csum_policy
)];
1344 const struct tc_csum
*c
;
1345 const struct nlattr
*csum_parms
;
1347 if (!nl_parse_nested(options
, csum_policy
, csum_attrs
,
1348 ARRAY_SIZE(csum_policy
))) {
1349 VLOG_ERR_RL(&error_rl
, "failed to parse csum action options");
1353 csum_parms
= csum_attrs
[TCA_CSUM_PARMS
];
1354 c
= nl_attr_get_unspec(csum_parms
, sizeof *c
);
1357 if (c
->update_flags
!= flower
->csum_update_flags
) {
1358 VLOG_WARN_RL(&error_rl
,
1359 "expected different act csum flags: 0x%x != 0x%x",
1360 flower
->csum_update_flags
, c
->update_flags
);
1363 flower
->csum_update_flags
= 0; /* so we know csum was handled */
1365 if (flower
->needs_full_ip_proto_mask
1366 && flower
->mask
.ip_proto
!= UINT8_MAX
) {
1367 VLOG_WARN_RL(&error_rl
, "expected full matching on flower ip_proto");
1374 static const struct nl_policy act_policy
[] = {
1375 [TCA_ACT_KIND
] = { .type
= NL_A_STRING
, .optional
= false, },
1376 [TCA_ACT_COOKIE
] = { .type
= NL_A_UNSPEC
, .optional
= true, },
1377 [TCA_ACT_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= false, },
1378 [TCA_ACT_STATS
] = { .type
= NL_A_NESTED
, .optional
= false, },
1381 static const struct nl_policy stats_policy
[] = {
1382 [TCA_STATS_BASIC
] = { .type
= NL_A_UNSPEC
,
1383 .min_len
= sizeof(struct gnet_stats_basic
),
1384 .optional
= false, },
1388 nl_parse_single_action(struct nlattr
*action
, struct tc_flower
*flower
)
1390 struct nlattr
*act_options
;
1391 struct nlattr
*act_stats
;
1392 struct nlattr
*act_cookie
;
1393 const char *act_kind
;
1394 struct nlattr
*action_attrs
[ARRAY_SIZE(act_policy
)];
1395 struct nlattr
*stats_attrs
[ARRAY_SIZE(stats_policy
)];
1396 struct ovs_flow_stats
*stats
= &flower
->stats
;
1397 const struct gnet_stats_basic
*bs
;
1400 if (!nl_parse_nested(action
, act_policy
, action_attrs
,
1401 ARRAY_SIZE(act_policy
))) {
1402 VLOG_ERR_RL(&error_rl
, "failed to parse single action options");
1406 act_kind
= nl_attr_get_string(action_attrs
[TCA_ACT_KIND
]);
1407 act_options
= action_attrs
[TCA_ACT_OPTIONS
];
1408 act_cookie
= action_attrs
[TCA_ACT_COOKIE
];
1410 if (!strcmp(act_kind
, "gact")) {
1411 err
= nl_parse_act_drop(act_options
, flower
);
1412 } else if (!strcmp(act_kind
, "mirred")) {
1413 err
= nl_parse_act_mirred(act_options
, flower
);
1414 } else if (!strcmp(act_kind
, "vlan")) {
1415 err
= nl_parse_act_vlan(act_options
, flower
);
1416 } else if (!strcmp(act_kind
, "mpls")) {
1417 err
= nl_parse_act_mpls(act_options
, flower
);
1418 } else if (!strcmp(act_kind
, "tunnel_key")) {
1419 err
= nl_parse_act_tunnel_key(act_options
, flower
);
1420 } else if (!strcmp(act_kind
, "pedit")) {
1421 err
= nl_parse_act_pedit(act_options
, flower
);
1422 } else if (!strcmp(act_kind
, "csum")) {
1423 nl_parse_act_csum(act_options
, flower
);
1424 } else if (!strcmp(act_kind
, "skbedit")) {
1425 /* Added for TC rule only (not in OvS rule) so ignore. */
1427 VLOG_ERR_RL(&error_rl
, "unknown tc action kind: %s", act_kind
);
1436 flower
->act_cookie
.data
= nl_attr_get(act_cookie
);
1437 flower
->act_cookie
.len
= nl_attr_get_size(act_cookie
);
1440 act_stats
= action_attrs
[TCA_ACT_STATS
];
1442 if (!nl_parse_nested(act_stats
, stats_policy
, stats_attrs
,
1443 ARRAY_SIZE(stats_policy
))) {
1444 VLOG_ERR_RL(&error_rl
, "failed to parse action stats policy");
1448 bs
= nl_attr_get_unspec(stats_attrs
[TCA_STATS_BASIC
], sizeof *bs
);
1449 put_32aligned_u64(&stats
->n_packets
, bs
->packets
);
1450 put_32aligned_u64(&stats
->n_bytes
, bs
->bytes
);
1455 #define TCA_ACT_MIN_PRIO 1
1458 nl_parse_flower_actions(struct nlattr
**attrs
, struct tc_flower
*flower
)
1460 const struct nlattr
*actions
= attrs
[TCA_FLOWER_ACT
];
1461 static struct nl_policy actions_orders_policy
[TCA_ACT_MAX_PRIO
+ 1] = {};
1462 struct nlattr
*actions_orders
[ARRAY_SIZE(actions_orders_policy
)];
1463 const int max_size
= ARRAY_SIZE(actions_orders_policy
);
1465 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
1466 actions_orders_policy
[i
].type
= NL_A_NESTED
;
1467 actions_orders_policy
[i
].optional
= true;
1470 if (!nl_parse_nested(actions
, actions_orders_policy
, actions_orders
,
1471 ARRAY_SIZE(actions_orders_policy
))) {
1472 VLOG_ERR_RL(&error_rl
, "failed to parse flower order of actions");
1476 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
1477 if (actions_orders
[i
]) {
1480 if (flower
->action_count
>= TCA_ACT_MAX_PRIO
) {
1481 VLOG_DBG_RL(&error_rl
, "Can only support %d actions", flower
->action_count
);
1484 err
= nl_parse_single_action(actions_orders
[i
], flower
);
1492 if (flower
->csum_update_flags
) {
1493 VLOG_WARN_RL(&error_rl
,
1494 "expected act csum with flags: 0x%x",
1495 flower
->csum_update_flags
);
1503 nl_parse_flower_options(struct nlattr
*nl_options
, struct tc_flower
*flower
)
1505 struct nlattr
*attrs
[ARRAY_SIZE(tca_flower_policy
)];
1508 if (!nl_parse_nested(nl_options
, tca_flower_policy
,
1509 attrs
, ARRAY_SIZE(tca_flower_policy
))) {
1510 VLOG_ERR_RL(&error_rl
, "failed to parse flower classifier options");
1514 nl_parse_flower_eth(attrs
, flower
);
1515 nl_parse_flower_mpls(attrs
, flower
);
1516 nl_parse_flower_vlan(attrs
, flower
);
1517 nl_parse_flower_ip(attrs
, flower
);
1518 err
= nl_parse_flower_tunnel(attrs
, flower
);
1523 nl_parse_flower_flags(attrs
, flower
);
1524 return nl_parse_flower_actions(attrs
, flower
);
1528 parse_netlink_to_tc_flower(struct ofpbuf
*reply
, struct tc_flower
*flower
)
1531 struct nlattr
*ta
[ARRAY_SIZE(tca_policy
)];
1534 if (NLMSG_HDRLEN
+ sizeof *tc
> reply
->size
) {
1538 memset(flower
, 0, sizeof *flower
);
1540 tc
= ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
1541 flower
->handle
= tc
->tcm_handle
;
1542 flower
->key
.eth_type
= (OVS_FORCE ovs_be16
) tc_get_minor(tc
->tcm_info
);
1543 flower
->mask
.eth_type
= OVS_BE16_MAX
;
1544 flower
->prio
= tc_get_major(tc
->tcm_info
);
1546 if (flower
->prio
== TC_RESERVED_PRIORITY_POLICE
) {
1550 if (!flower
->handle
) {
1554 if (!nl_policy_parse(reply
, NLMSG_HDRLEN
+ sizeof *tc
,
1555 tca_policy
, ta
, ARRAY_SIZE(ta
))) {
1556 VLOG_ERR_RL(&error_rl
, "failed to parse tca policy");
1560 kind
= nl_attr_get_string(ta
[TCA_KIND
]);
1561 if (strcmp(kind
, "flower")) {
1562 VLOG_DBG_ONCE("Unsupported filter: %s", kind
);
1566 return nl_parse_flower_options(ta
[TCA_OPTIONS
], flower
);
1570 tc_dump_flower_start(int ifindex
, struct nl_dump
*dump
, uint32_t block_id
,
1571 enum tc_qdisc_hook hook
)
1573 struct ofpbuf request
;
1574 struct tcmsg
*tcmsg
;
1577 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1578 tcmsg
= tc_make_request(index
, RTM_GETTFILTER
, NLM_F_DUMP
, &request
);
1579 tcmsg
->tcm_parent
= (hook
== TC_EGRESS
) ?
1580 TC_EGRESS_PARENT
: (block_id
? : TC_INGRESS_PARENT
);
1581 tcmsg
->tcm_info
= TC_H_UNSPEC
;
1582 tcmsg
->tcm_handle
= 0;
1584 nl_dump_start(dump
, NETLINK_ROUTE
, &request
);
1585 ofpbuf_uninit(&request
);
1591 tc_flush(int ifindex
, uint32_t block_id
, enum tc_qdisc_hook hook
)
1593 struct ofpbuf request
;
1594 struct tcmsg
*tcmsg
;
1597 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1598 tcmsg
= tc_make_request(index
, RTM_DELTFILTER
, NLM_F_ACK
, &request
);
1599 tcmsg
->tcm_parent
= (hook
== TC_EGRESS
) ?
1600 TC_EGRESS_PARENT
: (block_id
? : TC_INGRESS_PARENT
);
1601 tcmsg
->tcm_info
= TC_H_UNSPEC
;
1603 return tc_transact(&request
, NULL
);
1607 tc_del_filter(int ifindex
, int prio
, int handle
, uint32_t block_id
,
1608 enum tc_qdisc_hook hook
)
1610 struct ofpbuf request
;
1611 struct tcmsg
*tcmsg
;
1612 struct ofpbuf
*reply
;
1616 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1617 tcmsg
= tc_make_request(index
, RTM_DELTFILTER
, NLM_F_ECHO
, &request
);
1618 tcmsg
->tcm_parent
= (hook
== TC_EGRESS
) ?
1619 TC_EGRESS_PARENT
: (block_id
? : TC_INGRESS_PARENT
);
1620 tcmsg
->tcm_info
= tc_make_handle(prio
, 0);
1621 tcmsg
->tcm_handle
= handle
;
1623 error
= tc_transact(&request
, &reply
);
1625 ofpbuf_delete(reply
);
1631 tc_get_flower(int ifindex
, int prio
, int handle
, struct tc_flower
*flower
,
1632 uint32_t block_id
, enum tc_qdisc_hook hook
)
1634 struct ofpbuf request
;
1635 struct tcmsg
*tcmsg
;
1636 struct ofpbuf
*reply
;
1640 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1641 tcmsg
= tc_make_request(index
, RTM_GETTFILTER
, NLM_F_ECHO
, &request
);
1642 tcmsg
->tcm_parent
= (hook
== TC_EGRESS
) ?
1643 TC_EGRESS_PARENT
: (block_id
? : TC_INGRESS_PARENT
);
1644 tcmsg
->tcm_info
= tc_make_handle(prio
, 0);
1645 tcmsg
->tcm_handle
= handle
;
1647 error
= tc_transact(&request
, &reply
);
1652 error
= parse_netlink_to_tc_flower(reply
, flower
);
1653 ofpbuf_delete(reply
);
1658 tc_get_tc_cls_policy(enum tc_offload_policy policy
)
1660 if (policy
== TC_POLICY_SKIP_HW
) {
1661 return TCA_CLS_FLAGS_SKIP_HW
;
1662 } else if (policy
== TC_POLICY_SKIP_SW
) {
1663 return TCA_CLS_FLAGS_SKIP_SW
;
1670 nl_msg_put_act_csum(struct ofpbuf
*request
, uint32_t flags
)
1674 nl_msg_put_string(request
, TCA_ACT_KIND
, "csum");
1675 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1677 struct tc_csum parm
= { .action
= TC_ACT_PIPE
,
1678 .update_flags
= flags
};
1680 nl_msg_put_unspec(request
, TCA_CSUM_PARMS
, &parm
, sizeof parm
);
1682 nl_msg_end_nested(request
, offset
);
1686 nl_msg_put_act_pedit(struct ofpbuf
*request
, struct tc_pedit
*parm
,
1687 struct tc_pedit_key_ex
*ex
)
1689 size_t ksize
= sizeof *parm
+ parm
->nkeys
* sizeof(struct tc_pedit_key
);
1690 size_t offset
, offset_keys_ex
, offset_key
;
1693 nl_msg_put_string(request
, TCA_ACT_KIND
, "pedit");
1694 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1696 parm
->action
= TC_ACT_PIPE
;
1698 nl_msg_put_unspec(request
, TCA_PEDIT_PARMS_EX
, parm
, ksize
);
1699 offset_keys_ex
= nl_msg_start_nested(request
, TCA_PEDIT_KEYS_EX
);
1700 for (i
= 0; i
< parm
->nkeys
; i
++, ex
++) {
1701 offset_key
= nl_msg_start_nested(request
, TCA_PEDIT_KEY_EX
);
1702 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_HTYPE
, ex
->htype
);
1703 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_CMD
, ex
->cmd
);
1704 nl_msg_end_nested(request
, offset_key
);
1706 nl_msg_end_nested(request
, offset_keys_ex
);
1708 nl_msg_end_nested(request
, offset
);
1712 nl_msg_put_act_push_vlan(struct ofpbuf
*request
, ovs_be16 tpid
,
1713 uint16_t vid
, uint8_t prio
)
1717 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1718 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1720 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1721 .v_action
= TCA_VLAN_ACT_PUSH
};
1723 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1724 nl_msg_put_be16(request
, TCA_VLAN_PUSH_VLAN_PROTOCOL
, tpid
);
1725 nl_msg_put_u16(request
, TCA_VLAN_PUSH_VLAN_ID
, vid
);
1726 nl_msg_put_u8(request
, TCA_VLAN_PUSH_VLAN_PRIORITY
, prio
);
1728 nl_msg_end_nested(request
, offset
);
1732 nl_msg_put_act_pop_vlan(struct ofpbuf
*request
)
1736 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1737 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1739 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1740 .v_action
= TCA_VLAN_ACT_POP
};
1742 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1744 nl_msg_end_nested(request
, offset
);
1748 nl_msg_put_act_pop_mpls(struct ofpbuf
*request
, ovs_be16 proto
)
1752 nl_msg_put_string(request
, TCA_ACT_KIND
, "mpls");
1753 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
1755 struct tc_mpls parm
= { .action
= TC_ACT_PIPE
,
1756 .m_action
= TCA_MPLS_ACT_POP
};
1758 nl_msg_put_unspec(request
, TCA_MPLS_PARMS
, &parm
, sizeof parm
);
1759 nl_msg_put_be16(request
, TCA_MPLS_PROTO
, proto
);
1761 nl_msg_end_nested(request
, offset
);
1765 nl_msg_put_act_push_mpls(struct ofpbuf
*request
, ovs_be16 proto
,
1766 uint32_t label
, uint8_t tc
, uint8_t ttl
, uint8_t bos
)
1770 nl_msg_put_string(request
, TCA_ACT_KIND
, "mpls");
1771 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
1773 struct tc_mpls parm
= { .action
= TC_ACT_PIPE
,
1774 .m_action
= TCA_MPLS_ACT_PUSH
};
1776 nl_msg_put_unspec(request
, TCA_MPLS_PARMS
, &parm
, sizeof parm
);
1777 nl_msg_put_be16(request
, TCA_MPLS_PROTO
, proto
);
1778 nl_msg_put_u32(request
, TCA_MPLS_LABEL
, label
);
1779 nl_msg_put_u8(request
, TCA_MPLS_TC
, tc
);
1780 nl_msg_put_u8(request
, TCA_MPLS_TTL
, ttl
);
1781 nl_msg_put_u8(request
, TCA_MPLS_BOS
, bos
);
1783 nl_msg_end_nested(request
, offset
);
1787 nl_msg_put_act_set_mpls(struct ofpbuf
*request
, uint32_t label
, uint8_t tc
,
1788 uint8_t ttl
, uint8_t bos
)
1792 nl_msg_put_string(request
, TCA_ACT_KIND
, "mpls");
1793 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
| NLA_F_NESTED
);
1795 struct tc_mpls parm
= { .action
= TC_ACT_PIPE
,
1796 .m_action
= TCA_MPLS_ACT_MODIFY
};
1798 nl_msg_put_unspec(request
, TCA_MPLS_PARMS
, &parm
, sizeof parm
);
1799 nl_msg_put_u32(request
, TCA_MPLS_LABEL
, label
);
1800 nl_msg_put_u8(request
, TCA_MPLS_TC
, tc
);
1801 nl_msg_put_u8(request
, TCA_MPLS_TTL
, ttl
);
1802 nl_msg_put_u8(request
, TCA_MPLS_BOS
, bos
);
1804 nl_msg_end_nested(request
, offset
);
1808 nl_msg_put_act_tunnel_key_release(struct ofpbuf
*request
)
1812 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
1813 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1815 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
1816 .t_action
= TCA_TUNNEL_KEY_ACT_RELEASE
};
1818 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
1820 nl_msg_end_nested(request
, offset
);
1824 nl_msg_put_act_tunnel_geneve_option(struct ofpbuf
*request
,
1825 struct tun_metadata tun_metadata
)
1827 const struct geneve_opt
*opt
;
1828 size_t outer
, inner
;
1831 len
= tun_metadata
.present
.len
;
1836 outer
= nl_msg_start_nested(request
, TCA_TUNNEL_KEY_ENC_OPTS
);
1839 opt
= &tun_metadata
.opts
.gnv
[cnt
];
1840 inner
= nl_msg_start_nested(request
, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE
);
1842 nl_msg_put_be16(request
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS
,
1844 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE
, opt
->type
);
1845 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA
, opt
+ 1,
1848 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
1849 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
1851 nl_msg_end_nested(request
, inner
);
1854 nl_msg_end_nested(request
, outer
);
1858 nl_msg_put_act_tunnel_key_set(struct ofpbuf
*request
, bool id_present
,
1859 ovs_be64 id
, ovs_be32 ipv4_src
,
1860 ovs_be32 ipv4_dst
, struct in6_addr
*ipv6_src
,
1861 struct in6_addr
*ipv6_dst
,
1862 ovs_be16 tp_dst
, uint8_t tos
, uint8_t ttl
,
1863 struct tun_metadata tun_metadata
,
1868 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
1869 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1871 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
1872 .t_action
= TCA_TUNNEL_KEY_ACT_SET
};
1874 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
1876 ovs_be32 id32
= be64_to_be32(id
);
1878 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_KEY_ID
, id32
);
1881 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_SRC
, ipv4_src
);
1882 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_DST
, ipv4_dst
);
1883 } else if (!is_all_zeros(ipv6_dst
, sizeof *ipv6_dst
)) {
1884 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_DST
,
1886 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_SRC
,
1890 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_TOS
, tos
);
1893 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_TTL
, ttl
);
1896 nl_msg_put_be16(request
, TCA_TUNNEL_KEY_ENC_DST_PORT
, tp_dst
);
1898 nl_msg_put_act_tunnel_geneve_option(request
, tun_metadata
);
1899 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_NO_CSUM
, no_csum
);
1901 nl_msg_end_nested(request
, offset
);
1905 nl_msg_put_act_drop(struct ofpbuf
*request
)
1909 nl_msg_put_string(request
, TCA_ACT_KIND
, "gact");
1910 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1912 struct tc_gact p
= { .action
= TC_ACT_SHOT
};
1914 nl_msg_put_unspec(request
, TCA_GACT_PARMS
, &p
, sizeof p
);
1916 nl_msg_end_nested(request
, offset
);
1920 nl_msg_put_act_skbedit_to_host(struct ofpbuf
*request
)
1924 nl_msg_put_string(request
, TCA_ACT_KIND
, "skbedit");
1925 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1927 struct tc_skbedit s
= { .action
= TC_ACT_PIPE
};
1929 nl_msg_put_unspec(request
, TCA_SKBEDIT_PARMS
, &s
, sizeof s
);
1930 nl_msg_put_be16(request
, TCA_SKBEDIT_PTYPE
, PACKET_HOST
);
1932 nl_msg_end_nested(request
, offset
);
1936 nl_msg_put_act_mirred(struct ofpbuf
*request
, int ifindex
, int action
,
1941 nl_msg_put_string(request
, TCA_ACT_KIND
, "mirred");
1942 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1944 struct tc_mirred m
= { .action
= action
,
1946 .ifindex
= ifindex
};
1948 nl_msg_put_unspec(request
, TCA_MIRRED_PARMS
, &m
, sizeof m
);
1950 nl_msg_end_nested(request
, offset
);
1954 nl_msg_put_act_cookie(struct ofpbuf
*request
, struct tc_cookie
*ck
) {
1956 nl_msg_put_unspec(request
, TCA_ACT_COOKIE
, ck
->data
, ck
->len
);
1960 /* Given flower, a key_to_pedit map entry, calculates the rest,
1963 * mask, data - pointers of where read the first word of flower->key/mask.
1964 * current_offset - which offset to use for the first pedit action.
1965 * cnt - max pedits actions to use.
1966 * first_word_mask/last_word_mask - the mask to use for the first/last read
1967 * (as we read entire words). */
1969 calc_offsets(struct tc_flower
*flower
, struct flower_key_to_pedit
*m
,
1970 int *cur_offset
, int *cnt
, ovs_be32
*last_word_mask
,
1971 ovs_be32
*first_word_mask
, ovs_be32
**mask
, ovs_be32
**data
)
1973 int start_offset
, max_offset
, total_size
;
1974 int diff
, right_zero_bits
, left_zero_bits
;
1975 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
1976 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
1978 max_offset
= m
->offset
+ m
->size
;
1979 start_offset
= ROUND_DOWN(m
->offset
, 4);
1980 diff
= m
->offset
- start_offset
;
1981 total_size
= max_offset
- start_offset
;
1982 right_zero_bits
= 8 * (4 - ((max_offset
% 4) ? : 4));
1983 left_zero_bits
= 8 * (m
->offset
- start_offset
);
1985 *cur_offset
= start_offset
;
1986 *cnt
= (total_size
/ 4) + (total_size
% 4 ? 1 : 0);
1987 *last_word_mask
= htonl(UINT32_MAX
<< right_zero_bits
);
1988 *first_word_mask
= htonl(UINT32_MAX
>> left_zero_bits
);
1989 *data
= (void *) (rewrite_key
+ m
->flower_offset
- diff
);
1990 *mask
= (void *) (rewrite_mask
+ m
->flower_offset
- diff
);
1994 csum_update_flag(struct tc_flower
*flower
,
1995 enum pedit_header_type htype
) {
1996 /* Explictily specifiy the csum flags so HW can return EOPNOTSUPP
1997 * if it doesn't support a checksum recalculation of some headers.
1998 * And since OVS allows a flow such as
1999 * eth(dst=<mac>),eth_type(0x0800) actions=set(ipv4(src=<new_ip>))
2000 * we need to force a more specific flow as this can, for example,
2001 * need a recalculation of icmp checksum if the packet that passes
2002 * is ICMPv6 and tcp checksum if its tcp. */
2005 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
:
2006 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_IPV4HDR
;
2008 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
:
2009 case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
:
2010 case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
:
2011 if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
2012 flower
->needs_full_ip_proto_mask
= true;
2013 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_TCP
;
2014 } else if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
2015 flower
->needs_full_ip_proto_mask
= true;
2016 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_UDP
;
2017 } else if (flower
->key
.ip_proto
== IPPROTO_ICMP
) {
2018 flower
->needs_full_ip_proto_mask
= true;
2019 } else if (flower
->key
.ip_proto
== IPPROTO_ICMPV6
) {
2020 flower
->needs_full_ip_proto_mask
= true;
2021 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_ICMP
;
2023 VLOG_WARN_RL(&error_rl
,
2024 "can't offload rewrite of IP/IPV6 with ip_proto: %d",
2025 flower
->key
.ip_proto
);
2029 case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
:
2030 return 0; /* success */
2032 case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK
:
2033 case __PEDIT_HDR_TYPE_MAX
:
2042 nl_msg_put_flower_rewrite_pedits(struct ofpbuf
*request
,
2043 struct tc_flower
*flower
)
2046 struct tc_pedit sel
;
2047 struct tc_pedit_key keys
[MAX_PEDIT_OFFSETS
];
2048 struct tc_pedit_key_ex keys_ex
[MAX_PEDIT_OFFSETS
];
2056 for (i
= 0; i
< ARRAY_SIZE(flower_pedit_map
); i
++) {
2057 struct flower_key_to_pedit
*m
= &flower_pedit_map
[i
];
2058 struct tc_pedit_key
*pedit_key
= NULL
;
2059 struct tc_pedit_key_ex
*pedit_key_ex
= NULL
;
2060 ovs_be32
*mask
, *data
, first_word_mask
, last_word_mask
;
2061 int cnt
= 0, cur_offset
= 0;
2067 calc_offsets(flower
, m
, &cur_offset
, &cnt
, &last_word_mask
,
2068 &first_word_mask
, &mask
, &data
);
2070 for (j
= 0; j
< cnt
; j
++, mask
++, data
++, cur_offset
+= 4) {
2071 ovs_be32 mask_word
= *mask
;
2072 ovs_be32 data_word
= *data
;
2075 mask_word
&= first_word_mask
;
2078 mask_word
&= last_word_mask
;
2083 if (sel
.sel
.nkeys
== MAX_PEDIT_OFFSETS
) {
2084 VLOG_WARN_RL(&error_rl
, "reached too many pedit offsets: %d",
2089 pedit_key
= &sel
.keys
[sel
.sel
.nkeys
];
2090 pedit_key_ex
= &sel
.keys_ex
[sel
.sel
.nkeys
];
2091 pedit_key_ex
->cmd
= TCA_PEDIT_KEY_EX_CMD_SET
;
2092 pedit_key_ex
->htype
= m
->htype
;
2093 pedit_key
->off
= cur_offset
;
2094 mask_word
= htonl(ntohl(mask_word
) >> m
->boundary_shift
);
2095 data_word
= htonl(ntohl(data_word
) >> m
->boundary_shift
);
2096 pedit_key
->mask
= ~mask_word
;
2097 pedit_key
->val
= data_word
& mask_word
;
2100 err
= csum_update_flag(flower
, m
->htype
);
2105 if (flower
->needs_full_ip_proto_mask
) {
2106 flower
->mask
.ip_proto
= UINT8_MAX
;
2110 nl_msg_put_act_pedit(request
, &sel
.sel
, sel
.keys_ex
);
2116 nl_msg_put_flower_acts(struct ofpbuf
*request
, struct tc_flower
*flower
)
2120 uint16_t act_index
= 1;
2121 struct tc_action
*action
;
2125 offset
= nl_msg_start_nested(request
, TCA_FLOWER_ACT
);
2129 if (flower
->tunnel
) {
2130 act_offset
= nl_msg_start_nested(request
, act_index
++);
2131 nl_msg_put_act_tunnel_key_release(request
);
2132 nl_msg_end_nested(request
, act_offset
);
2135 action
= flower
->actions
;
2136 for (i
= 0; i
< flower
->action_count
; i
++, action
++) {
2137 switch (action
->type
) {
2138 case TC_ACT_PEDIT
: {
2139 act_offset
= nl_msg_start_nested(request
, act_index
++);
2140 error
= nl_msg_put_flower_rewrite_pedits(request
, flower
);
2144 nl_msg_end_nested(request
, act_offset
);
2146 if (flower
->csum_update_flags
) {
2147 act_offset
= nl_msg_start_nested(request
, act_index
++);
2148 nl_msg_put_act_csum(request
, flower
->csum_update_flags
);
2149 nl_msg_end_nested(request
, act_offset
);
2153 case TC_ACT_ENCAP
: {
2154 act_offset
= nl_msg_start_nested(request
, act_index
++);
2155 nl_msg_put_act_tunnel_key_set(request
, action
->encap
.id_present
,
2157 action
->encap
.ipv4
.ipv4_src
,
2158 action
->encap
.ipv4
.ipv4_dst
,
2159 &action
->encap
.ipv6
.ipv6_src
,
2160 &action
->encap
.ipv6
.ipv6_dst
,
2161 action
->encap
.tp_dst
,
2165 action
->encap
.no_csum
);
2166 nl_msg_end_nested(request
, act_offset
);
2169 case TC_ACT_VLAN_POP
: {
2170 act_offset
= nl_msg_start_nested(request
, act_index
++);
2171 nl_msg_put_act_pop_vlan(request
);
2172 nl_msg_end_nested(request
, act_offset
);
2175 case TC_ACT_VLAN_PUSH
: {
2176 act_offset
= nl_msg_start_nested(request
, act_index
++);
2177 nl_msg_put_act_push_vlan(request
,
2178 action
->vlan
.vlan_push_tpid
,
2179 action
->vlan
.vlan_push_id
,
2180 action
->vlan
.vlan_push_prio
);
2181 nl_msg_end_nested(request
, act_offset
);
2184 case TC_ACT_MPLS_POP
: {
2185 act_offset
= nl_msg_start_nested(request
, act_index
++);
2186 nl_msg_put_act_pop_mpls(request
, action
->mpls
.proto
);
2187 nl_msg_end_nested(request
, act_offset
);
2190 case TC_ACT_MPLS_PUSH
: {
2191 act_offset
= nl_msg_start_nested(request
, act_index
++);
2192 nl_msg_put_act_push_mpls(request
, action
->mpls
.proto
,
2193 action
->mpls
.label
, action
->mpls
.tc
,
2194 action
->mpls
.ttl
, action
->mpls
.bos
);
2195 nl_msg_end_nested(request
, act_offset
);
2198 case TC_ACT_MPLS_SET
: {
2199 act_offset
= nl_msg_start_nested(request
, act_index
++);
2200 nl_msg_put_act_set_mpls(request
, action
->mpls
.label
,
2201 action
->mpls
.tc
, action
->mpls
.ttl
,
2203 nl_msg_end_nested(request
, act_offset
);
2206 case TC_ACT_OUTPUT
: {
2207 ingress
= action
->out
.ingress
;
2208 ifindex
= action
->out
.ifindex_out
;
2210 VLOG_ERR_RL(&error_rl
, "%s: invalid ifindex: %d, type: %d",
2211 __func__
, ifindex
, action
->type
);
2216 /* If redirecting to ingress (internal port) ensure
2217 * pkt_type on skb is set to PACKET_HOST. */
2218 act_offset
= nl_msg_start_nested(request
, act_index
++);
2219 nl_msg_put_act_skbedit_to_host(request
);
2220 nl_msg_end_nested(request
, act_offset
);
2223 act_offset
= nl_msg_start_nested(request
, act_index
++);
2224 if (i
== flower
->action_count
- 1) {
2226 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_STOLEN
,
2229 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_STOLEN
,
2234 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_PIPE
,
2235 TCA_INGRESS_MIRROR
);
2237 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_PIPE
,
2241 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2242 nl_msg_end_nested(request
, act_offset
);
2249 act_offset
= nl_msg_start_nested(request
, act_index
++);
2250 nl_msg_put_act_drop(request
);
2251 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
2252 nl_msg_end_nested(request
, act_offset
);
2254 nl_msg_end_nested(request
, offset
);
2260 nl_msg_put_masked_value(struct ofpbuf
*request
, uint16_t type
,
2261 uint16_t mask_type
, const void *data
,
2262 const void *mask_data
, size_t len
)
2264 if (mask_type
!= TCA_FLOWER_UNSPEC
) {
2265 if (is_all_zeros(mask_data
, len
)) {
2268 nl_msg_put_unspec(request
, mask_type
, mask_data
, len
);
2270 nl_msg_put_unspec(request
, type
, data
, len
);
2274 nl_msg_put_flower_tunnel_opts(struct ofpbuf
*request
, uint16_t type
,
2275 struct tun_metadata metadata
)
2277 struct geneve_opt
*opt
;
2278 size_t outer
, inner
;
2281 len
= metadata
.present
.len
;
2286 outer
= nl_msg_start_nested(request
, type
);
2288 opt
= &metadata
.opts
.gnv
[cnt
];
2289 inner
= nl_msg_start_nested(request
, TCA_FLOWER_KEY_ENC_OPTS_GENEVE
);
2291 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS
,
2293 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE
, opt
->type
);
2294 nl_msg_put_unspec(request
, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA
, opt
+ 1,
2297 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
2298 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
2300 nl_msg_end_nested(request
, inner
);
2302 nl_msg_end_nested(request
, outer
);
2306 nl_msg_put_flower_tunnel(struct ofpbuf
*request
, struct tc_flower
*flower
)
2308 ovs_be32 ipv4_src
= flower
->key
.tunnel
.ipv4
.ipv4_src
;
2309 ovs_be32 ipv4_dst
= flower
->key
.tunnel
.ipv4
.ipv4_dst
;
2310 struct in6_addr
*ipv6_src
= &flower
->key
.tunnel
.ipv6
.ipv6_src
;
2311 struct in6_addr
*ipv6_dst
= &flower
->key
.tunnel
.ipv6
.ipv6_dst
;
2312 ovs_be16 tp_dst
= flower
->key
.tunnel
.tp_dst
;
2313 ovs_be32 id
= be64_to_be32(flower
->key
.tunnel
.id
);
2314 uint8_t tos
= flower
->key
.tunnel
.tos
;
2315 uint8_t ttl
= flower
->key
.tunnel
.ttl
;
2316 uint8_t tos_mask
= flower
->mask
.tunnel
.tos
;
2317 uint8_t ttl_mask
= flower
->mask
.tunnel
.ttl
;
2318 ovs_be64 id_mask
= flower
->mask
.tunnel
.id
;
2321 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_SRC
, ipv4_src
);
2322 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_DST
, ipv4_dst
);
2323 } else if (!is_all_zeros(ipv6_dst
, sizeof *ipv6_dst
)) {
2324 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_SRC
, ipv6_src
);
2325 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_DST
, ipv6_dst
);
2328 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TOS
, tos
);
2329 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TOS_MASK
, tos_mask
);
2332 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TTL
, ttl
);
2333 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TTL_MASK
, ttl_mask
);
2336 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_UDP_DST_PORT
, tp_dst
);
2339 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_KEY_ID
, id
);
2341 nl_msg_put_flower_tunnel_opts(request
, TCA_FLOWER_KEY_ENC_OPTS
,
2342 flower
->key
.tunnel
.metadata
);
2343 nl_msg_put_flower_tunnel_opts(request
, TCA_FLOWER_KEY_ENC_OPTS_MASK
,
2344 flower
->mask
.tunnel
.metadata
);
2347 #define FLOWER_PUT_MASKED_VALUE(member, type) \
2348 nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \
2349 &flower->mask.member, sizeof flower->key.member)
2352 nl_msg_put_flower_options(struct ofpbuf
*request
, struct tc_flower
*flower
)
2355 uint16_t host_eth_type
= ntohs(flower
->key
.eth_type
);
2356 bool is_vlan
= eth_type_vlan(flower
->key
.eth_type
);
2357 bool is_qinq
= is_vlan
&& eth_type_vlan(flower
->key
.encap_eth_type
[0]);
2358 bool is_mpls
= eth_type_mpls(flower
->key
.eth_type
);
2361 /* need to parse acts first as some acts require changing the matching
2362 * see csum_update_flag() */
2363 err
= nl_msg_put_flower_acts(request
, flower
);
2370 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[1]);
2372 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[0]);
2377 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[0]);
2380 FLOWER_PUT_MASKED_VALUE(dst_mac
, TCA_FLOWER_KEY_ETH_DST
);
2381 FLOWER_PUT_MASKED_VALUE(src_mac
, TCA_FLOWER_KEY_ETH_SRC
);
2383 if (host_eth_type
== ETH_P_IP
|| host_eth_type
== ETH_P_IPV6
) {
2384 FLOWER_PUT_MASKED_VALUE(ip_ttl
, TCA_FLOWER_KEY_IP_TTL
);
2385 FLOWER_PUT_MASKED_VALUE(ip_tos
, TCA_FLOWER_KEY_IP_TOS
);
2387 if (flower
->mask
.ip_proto
&& flower
->key
.ip_proto
) {
2388 nl_msg_put_u8(request
, TCA_FLOWER_KEY_IP_PROTO
,
2389 flower
->key
.ip_proto
);
2392 if (flower
->mask
.flags
) {
2393 nl_msg_put_be32(request
, TCA_FLOWER_KEY_FLAGS
,
2394 htonl(flower
->key
.flags
));
2395 nl_msg_put_be32(request
, TCA_FLOWER_KEY_FLAGS_MASK
,
2396 htonl(flower
->mask
.flags
));
2399 if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
2400 FLOWER_PUT_MASKED_VALUE(udp_src
, TCA_FLOWER_KEY_UDP_SRC
);
2401 FLOWER_PUT_MASKED_VALUE(udp_dst
, TCA_FLOWER_KEY_UDP_DST
);
2402 } else if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
2403 FLOWER_PUT_MASKED_VALUE(tcp_src
, TCA_FLOWER_KEY_TCP_SRC
);
2404 FLOWER_PUT_MASKED_VALUE(tcp_dst
, TCA_FLOWER_KEY_TCP_DST
);
2405 FLOWER_PUT_MASKED_VALUE(tcp_flags
, TCA_FLOWER_KEY_TCP_FLAGS
);
2406 } else if (flower
->key
.ip_proto
== IPPROTO_SCTP
) {
2407 FLOWER_PUT_MASKED_VALUE(sctp_src
, TCA_FLOWER_KEY_SCTP_SRC
);
2408 FLOWER_PUT_MASKED_VALUE(sctp_dst
, TCA_FLOWER_KEY_SCTP_DST
);
2412 if (host_eth_type
== ETH_P_IP
) {
2413 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_src
, TCA_FLOWER_KEY_IPV4_SRC
);
2414 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_dst
, TCA_FLOWER_KEY_IPV4_DST
);
2415 } else if (host_eth_type
== ETH_P_IPV6
) {
2416 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_src
, TCA_FLOWER_KEY_IPV6_SRC
);
2417 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_dst
, TCA_FLOWER_KEY_IPV6_DST
);
2420 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ETH_TYPE
, flower
->key
.eth_type
);
2423 if (mpls_lse_to_ttl(flower
->mask
.mpls_lse
)) {
2424 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_TTL
,
2425 mpls_lse_to_ttl(flower
->key
.mpls_lse
));
2427 if (mpls_lse_to_tc(flower
->mask
.mpls_lse
)) {
2428 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_TC
,
2429 mpls_lse_to_tc(flower
->key
.mpls_lse
));
2431 if (mpls_lse_to_bos(flower
->mask
.mpls_lse
)) {
2432 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_BOS
,
2433 mpls_lse_to_bos(flower
->key
.mpls_lse
));
2435 if (mpls_lse_to_label(flower
->mask
.mpls_lse
)) {
2436 nl_msg_put_u32(request
, TCA_FLOWER_KEY_MPLS_LABEL
,
2437 mpls_lse_to_label(flower
->key
.mpls_lse
));
2442 if (flower
->mask
.vlan_id
[0]) {
2443 nl_msg_put_u16(request
, TCA_FLOWER_KEY_VLAN_ID
,
2444 flower
->key
.vlan_id
[0]);
2446 if (flower
->mask
.vlan_prio
[0]) {
2447 nl_msg_put_u8(request
, TCA_FLOWER_KEY_VLAN_PRIO
,
2448 flower
->key
.vlan_prio
[0]);
2450 if (flower
->key
.encap_eth_type
[0]) {
2451 nl_msg_put_be16(request
, TCA_FLOWER_KEY_VLAN_ETH_TYPE
,
2452 flower
->key
.encap_eth_type
[0]);
2456 if (flower
->mask
.vlan_id
[1]) {
2457 nl_msg_put_u16(request
, TCA_FLOWER_KEY_CVLAN_ID
,
2458 flower
->key
.vlan_id
[1]);
2460 if (flower
->mask
.vlan_prio
[1]) {
2461 nl_msg_put_u8(request
, TCA_FLOWER_KEY_CVLAN_PRIO
,
2462 flower
->key
.vlan_prio
[1]);
2464 if (flower
->key
.encap_eth_type
[1]) {
2465 nl_msg_put_be16(request
, TCA_FLOWER_KEY_CVLAN_ETH_TYPE
,
2466 flower
->key
.encap_eth_type
[1]);
2471 nl_msg_put_u32(request
, TCA_FLOWER_FLAGS
, tc_get_tc_cls_policy(tc_policy
));
2473 if (flower
->tunnel
) {
2474 nl_msg_put_flower_tunnel(request
, flower
);
2481 tc_replace_flower(int ifindex
, uint16_t prio
, uint32_t handle
,
2482 struct tc_flower
*flower
, uint32_t block_id
,
2483 enum tc_qdisc_hook hook
)
2485 struct ofpbuf request
;
2486 struct tcmsg
*tcmsg
;
2487 struct ofpbuf
*reply
;
2489 size_t basic_offset
;
2490 uint16_t eth_type
= (OVS_FORCE
uint16_t) flower
->key
.eth_type
;
2493 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
2494 tcmsg
= tc_make_request(index
, RTM_NEWTFILTER
, NLM_F_CREATE
| NLM_F_ECHO
,
2496 tcmsg
->tcm_parent
= (hook
== TC_EGRESS
) ?
2497 TC_EGRESS_PARENT
: (block_id
? : TC_INGRESS_PARENT
);
2498 tcmsg
->tcm_info
= tc_make_handle(prio
, eth_type
);
2499 tcmsg
->tcm_handle
= handle
;
2501 nl_msg_put_string(&request
, TCA_KIND
, "flower");
2502 basic_offset
= nl_msg_start_nested(&request
, TCA_OPTIONS
);
2504 error
= nl_msg_put_flower_options(&request
, flower
);
2507 ofpbuf_uninit(&request
);
2511 nl_msg_end_nested(&request
, basic_offset
);
2513 error
= tc_transact(&request
, &reply
);
2516 ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
2518 flower
->prio
= tc_get_major(tc
->tcm_info
);
2519 flower
->handle
= tc
->tcm_handle
;
2520 ofpbuf_delete(reply
);
2527 tc_set_policy(const char *policy
)
2533 if (!strcmp(policy
, "skip_sw")) {
2534 tc_policy
= TC_POLICY_SKIP_SW
;
2535 } else if (!strcmp(policy
, "skip_hw")) {
2536 tc_policy
= TC_POLICY_SKIP_HW
;
2537 } else if (!strcmp(policy
, "none")) {
2538 tc_policy
= TC_POLICY_NONE
;
2540 VLOG_WARN("tc: Invalid policy '%s'", policy
);
2544 VLOG_INFO("tc: Using policy '%s'", policy
);