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/rtnetlink.h>
24 #include <linux/tc_act/tc_csum.h>
25 #include <linux/tc_act/tc_gact.h>
26 #include <linux/tc_act/tc_mirred.h>
27 #include <linux/tc_act/tc_pedit.h>
28 #include <linux/tc_act/tc_tunnel_key.h>
29 #include <linux/tc_act/tc_vlan.h>
30 #include <linux/gen_stats.h>
34 #include "byte-order.h"
35 #include "netlink-socket.h"
37 #include "openvswitch/ofpbuf.h"
38 #include "openvswitch/util.h"
39 #include "openvswitch/vlog.h"
42 #include "unaligned.h"
44 #define MAX_PEDIT_OFFSETS 32
46 #ifndef TCM_IFINDEX_MAGIC_BLOCK
47 #define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
51 #define TCA_INGRESS_BLOCK 13
54 VLOG_DEFINE_THIS_MODULE(tc
);
56 static struct vlog_rate_limit error_rl
= VLOG_RATE_LIMIT_INIT(60, 5);
58 enum tc_offload_policy
{
64 static enum tc_offload_policy tc_policy
= TC_POLICY_NONE
;
66 struct tc_pedit_key_ex
{
67 enum pedit_header_type htype
;
71 struct flower_key_to_pedit
{
72 enum pedit_header_type htype
;
78 static struct flower_key_to_pedit flower_pedit_map
[] = {
80 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
82 offsetof(struct tc_flower_key
, ipv4
.ipv4_src
),
83 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.ipv4_src
)
85 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
87 offsetof(struct tc_flower_key
, ipv4
.ipv4_dst
),
88 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.ipv4_dst
)
90 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
92 offsetof(struct tc_flower_key
, ipv4
.rewrite_ttl
),
93 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.rewrite_ttl
)
95 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
97 offsetof(struct tc_flower_key
, ipv6
.ipv6_src
),
98 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.ipv6_src
)
100 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
102 offsetof(struct tc_flower_key
, ipv6
.ipv6_dst
),
103 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.ipv6_dst
)
105 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
107 offsetof(struct tc_flower_key
, src_mac
),
108 MEMBER_SIZEOF(struct tc_flower_key
, src_mac
)
110 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
112 offsetof(struct tc_flower_key
, dst_mac
),
113 MEMBER_SIZEOF(struct tc_flower_key
, dst_mac
)
115 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
117 offsetof(struct tc_flower_key
, eth_type
),
118 MEMBER_SIZEOF(struct tc_flower_key
, eth_type
)
120 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
,
122 offsetof(struct tc_flower_key
, tcp_src
),
123 MEMBER_SIZEOF(struct tc_flower_key
, tcp_src
)
125 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
,
127 offsetof(struct tc_flower_key
, tcp_dst
),
128 MEMBER_SIZEOF(struct tc_flower_key
, tcp_dst
)
130 TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
,
132 offsetof(struct tc_flower_key
, udp_src
),
133 MEMBER_SIZEOF(struct tc_flower_key
, udp_src
)
135 TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
,
137 offsetof(struct tc_flower_key
, udp_dst
),
138 MEMBER_SIZEOF(struct tc_flower_key
, udp_dst
)
143 csum_update_flag(struct tc_flower
*flower
,
144 enum pedit_header_type htype
);
147 tc_make_request(int ifindex
, int type
, unsigned int flags
,
148 struct ofpbuf
*request
)
152 ofpbuf_init(request
, 512);
153 nl_msg_put_nlmsghdr(request
, sizeof *tcmsg
, type
, NLM_F_REQUEST
| flags
);
154 tcmsg
= ofpbuf_put_zeros(request
, sizeof *tcmsg
);
155 tcmsg
->tcm_family
= AF_UNSPEC
;
156 tcmsg
->tcm_ifindex
= ifindex
;
157 /* Caller should fill in tcmsg->tcm_handle. */
158 /* Caller should fill in tcmsg->tcm_parent. */
164 tc_transact(struct ofpbuf
*request
, struct ofpbuf
**replyp
)
166 int error
= nl_transact(NETLINK_ROUTE
, request
, replyp
);
167 ofpbuf_uninit(request
);
171 /* Adds or deletes a root ingress qdisc on device with specified ifindex.
173 * This function is equivalent to running the following when 'add' is true:
174 * /sbin/tc qdisc add dev <devname> handle ffff: ingress
176 * This function is equivalent to running the following when 'add' is false:
177 * /sbin/tc qdisc del dev <devname> handle ffff: ingress
179 * Where dev <devname> is the device with specified ifindex name.
181 * The configuration and stats may be seen with the following command:
182 * /sbin/tc -s qdisc show dev <devname>
184 * If block_id is greater than 0, then the ingress qdisc is added to a block.
185 * In this case, it is equivalent to running (when 'add' is true):
186 * /sbin/tc qdisc add dev <devname> ingress_block <block_id> ingress
188 * Returns 0 if successful, otherwise a positive errno value.
191 tc_add_del_ingress_qdisc(int ifindex
, bool add
, uint32_t block_id
)
193 struct ofpbuf request
;
196 int type
= add
? RTM_NEWQDISC
: RTM_DELQDISC
;
197 int flags
= add
? NLM_F_EXCL
| NLM_F_CREATE
: 0;
199 tcmsg
= tc_make_request(ifindex
, type
, flags
, &request
);
200 tcmsg
->tcm_handle
= TC_H_MAKE(TC_H_INGRESS
, 0);
201 tcmsg
->tcm_parent
= TC_H_INGRESS
;
202 nl_msg_put_string(&request
, TCA_KIND
, "ingress");
203 nl_msg_put_unspec(&request
, TCA_OPTIONS
, NULL
, 0);
205 nl_msg_put_u32(&request
, TCA_INGRESS_BLOCK
, block_id
);
208 error
= tc_transact(&request
, NULL
);
210 /* If we're deleting the qdisc, don't worry about some of the
211 * error conditions. */
212 if (!add
&& (error
== ENOENT
|| error
== EINVAL
)) {
221 static const struct nl_policy tca_policy
[] = {
222 [TCA_KIND
] = { .type
= NL_A_STRING
, .optional
= false, },
223 [TCA_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= false, },
224 [TCA_STATS
] = { .type
= NL_A_UNSPEC
,
225 .min_len
= sizeof(struct tc_stats
), .optional
= true, },
226 [TCA_STATS2
] = { .type
= NL_A_NESTED
, .optional
= true, },
229 static const struct nl_policy tca_flower_policy
[] = {
230 [TCA_FLOWER_CLASSID
] = { .type
= NL_A_U32
, .optional
= true, },
231 [TCA_FLOWER_INDEV
] = { .type
= NL_A_STRING
, .max_len
= IFNAMSIZ
,
233 [TCA_FLOWER_KEY_ETH_SRC
] = { .type
= NL_A_UNSPEC
,
234 .min_len
= ETH_ALEN
, .optional
= true, },
235 [TCA_FLOWER_KEY_ETH_DST
] = { .type
= NL_A_UNSPEC
,
236 .min_len
= ETH_ALEN
, .optional
= true, },
237 [TCA_FLOWER_KEY_ETH_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
240 [TCA_FLOWER_KEY_ETH_DST_MASK
] = { .type
= NL_A_UNSPEC
,
243 [TCA_FLOWER_KEY_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= false, },
244 [TCA_FLOWER_FLAGS
] = { .type
= NL_A_U32
, .optional
= false, },
245 [TCA_FLOWER_ACT
] = { .type
= NL_A_NESTED
, .optional
= false, },
246 [TCA_FLOWER_KEY_IP_PROTO
] = { .type
= NL_A_U8
, .optional
= true, },
247 [TCA_FLOWER_KEY_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
248 [TCA_FLOWER_KEY_IPV4_DST
] = {.type
= NL_A_U32
, .optional
= true, },
249 [TCA_FLOWER_KEY_IPV4_SRC_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
250 [TCA_FLOWER_KEY_IPV4_DST_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
251 [TCA_FLOWER_KEY_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
252 .min_len
= sizeof(struct in6_addr
),
254 [TCA_FLOWER_KEY_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
255 .min_len
= sizeof(struct in6_addr
),
257 [TCA_FLOWER_KEY_IPV6_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
258 .min_len
= sizeof(struct in6_addr
),
260 [TCA_FLOWER_KEY_IPV6_DST_MASK
] = { .type
= NL_A_UNSPEC
,
261 .min_len
= sizeof(struct in6_addr
),
263 [TCA_FLOWER_KEY_TCP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
264 [TCA_FLOWER_KEY_TCP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
265 [TCA_FLOWER_KEY_TCP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
266 [TCA_FLOWER_KEY_TCP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
267 [TCA_FLOWER_KEY_UDP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
268 [TCA_FLOWER_KEY_UDP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
269 [TCA_FLOWER_KEY_UDP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
270 [TCA_FLOWER_KEY_UDP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
271 [TCA_FLOWER_KEY_SCTP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
272 [TCA_FLOWER_KEY_SCTP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
273 [TCA_FLOWER_KEY_SCTP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
274 [TCA_FLOWER_KEY_SCTP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
275 [TCA_FLOWER_KEY_MPLS_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
276 [TCA_FLOWER_KEY_MPLS_TC
] = { .type
= NL_A_U8
, .optional
= true, },
277 [TCA_FLOWER_KEY_MPLS_BOS
] = { .type
= NL_A_U8
, .optional
= true, },
278 [TCA_FLOWER_KEY_MPLS_LABEL
] = { .type
= NL_A_U32
, .optional
= true, },
279 [TCA_FLOWER_KEY_VLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
280 [TCA_FLOWER_KEY_VLAN_PRIO
] = { .type
= NL_A_U8
, .optional
= true, },
281 [TCA_FLOWER_KEY_VLAN_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= true, },
282 [TCA_FLOWER_KEY_ENC_KEY_ID
] = { .type
= NL_A_U32
, .optional
= true, },
283 [TCA_FLOWER_KEY_ENC_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
284 [TCA_FLOWER_KEY_ENC_IPV4_DST
] = { .type
= NL_A_U32
, .optional
= true, },
285 [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
] = { .type
= NL_A_U32
,
287 [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
] = { .type
= NL_A_U32
,
289 [TCA_FLOWER_KEY_ENC_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
290 .min_len
= sizeof(struct in6_addr
),
292 [TCA_FLOWER_KEY_ENC_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
293 .min_len
= sizeof(struct in6_addr
),
295 [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
296 .min_len
= sizeof(struct in6_addr
),
298 [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
] = { .type
= NL_A_UNSPEC
,
299 .min_len
= sizeof(struct in6_addr
),
301 [TCA_FLOWER_KEY_ENC_UDP_DST_PORT
] = { .type
= NL_A_U16
,
303 [TCA_FLOWER_KEY_FLAGS
] = { .type
= NL_A_BE32
, .optional
= true, },
304 [TCA_FLOWER_KEY_FLAGS_MASK
] = { .type
= NL_A_BE32
, .optional
= true, },
305 [TCA_FLOWER_KEY_IP_TTL
] = { .type
= NL_A_U8
,
307 [TCA_FLOWER_KEY_IP_TTL_MASK
] = { .type
= NL_A_U8
,
309 [TCA_FLOWER_KEY_IP_TOS
] = { .type
= NL_A_U8
,
311 [TCA_FLOWER_KEY_IP_TOS_MASK
] = { .type
= NL_A_U8
,
313 [TCA_FLOWER_KEY_TCP_FLAGS
] = { .type
= NL_A_U16
,
315 [TCA_FLOWER_KEY_TCP_FLAGS_MASK
] = { .type
= NL_A_U16
,
317 [TCA_FLOWER_KEY_CVLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
318 [TCA_FLOWER_KEY_CVLAN_PRIO
] = { .type
= NL_A_U8
, .optional
= true, },
319 [TCA_FLOWER_KEY_CVLAN_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= true, },
320 [TCA_FLOWER_KEY_ENC_IP_TOS
] = { .type
= NL_A_U8
,
322 [TCA_FLOWER_KEY_ENC_IP_TOS_MASK
] = { .type
= NL_A_U8
,
324 [TCA_FLOWER_KEY_ENC_IP_TTL
] = { .type
= NL_A_U8
,
326 [TCA_FLOWER_KEY_ENC_IP_TTL_MASK
] = { .type
= NL_A_U8
,
331 nl_parse_flower_eth(struct nlattr
**attrs
, struct tc_flower
*flower
)
333 const struct eth_addr
*eth
;
335 if (attrs
[TCA_FLOWER_KEY_ETH_SRC_MASK
]) {
336 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_SRC
], ETH_ALEN
);
337 memcpy(&flower
->key
.src_mac
, eth
, sizeof flower
->key
.src_mac
);
339 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_SRC_MASK
], ETH_ALEN
);
340 memcpy(&flower
->mask
.src_mac
, eth
, sizeof flower
->mask
.src_mac
);
342 if (attrs
[TCA_FLOWER_KEY_ETH_DST_MASK
]) {
343 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_DST
], ETH_ALEN
);
344 memcpy(&flower
->key
.dst_mac
, eth
, sizeof flower
->key
.dst_mac
);
346 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_DST_MASK
], ETH_ALEN
);
347 memcpy(&flower
->mask
.dst_mac
, eth
, sizeof flower
->mask
.dst_mac
);
352 nl_parse_flower_mpls(struct nlattr
**attrs
, struct tc_flower
*flower
)
354 uint8_t ttl
, tc
, bos
;
357 if (!eth_type_mpls(flower
->key
.eth_type
)) {
361 flower
->key
.encap_eth_type
[0] =
362 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ETH_TYPE
]);
363 flower
->key
.mpls_lse
= 0;
364 flower
->mask
.mpls_lse
= 0;
366 if (attrs
[TCA_FLOWER_KEY_MPLS_TTL
]) {
367 ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_MPLS_TTL
]);
368 set_mpls_lse_ttl(&flower
->key
.mpls_lse
, ttl
);
369 set_mpls_lse_ttl(&flower
->mask
.mpls_lse
, 0xff);
372 if (attrs
[TCA_FLOWER_KEY_MPLS_BOS
]) {
373 bos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_MPLS_BOS
]);
374 set_mpls_lse_bos(&flower
->key
.mpls_lse
, bos
);
375 set_mpls_lse_ttl(&flower
->mask
.mpls_lse
, 0xff);
378 if (attrs
[TCA_FLOWER_KEY_MPLS_TC
]) {
379 tc
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_MPLS_TC
]);
380 set_mpls_lse_tc(&flower
->key
.mpls_lse
, tc
);
381 set_mpls_lse_tc(&flower
->mask
.mpls_lse
, 0xff);
384 if (attrs
[TCA_FLOWER_KEY_MPLS_LABEL
]) {
385 label
= nl_attr_get_u32(attrs
[TCA_FLOWER_KEY_MPLS_LABEL
]);
386 set_mpls_lse_label(&flower
->key
.mpls_lse
, htonl(label
));
387 set_mpls_lse_label(&flower
->mask
.mpls_lse
, OVS_BE32_MAX
);
392 nl_parse_flower_vlan(struct nlattr
**attrs
, struct tc_flower
*flower
)
394 ovs_be16 encap_ethtype
;
396 if (!eth_type_vlan(flower
->key
.eth_type
)) {
400 flower
->key
.encap_eth_type
[0] =
401 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ETH_TYPE
]);
403 if (attrs
[TCA_FLOWER_KEY_VLAN_ID
]) {
404 flower
->key
.vlan_id
[0] =
405 nl_attr_get_u16(attrs
[TCA_FLOWER_KEY_VLAN_ID
]);
407 if (attrs
[TCA_FLOWER_KEY_VLAN_PRIO
]) {
408 flower
->key
.vlan_prio
[0] =
409 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_VLAN_PRIO
]);
412 if (!attrs
[TCA_FLOWER_KEY_VLAN_ETH_TYPE
]) {
416 encap_ethtype
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_VLAN_ETH_TYPE
]);
417 if (!eth_type_vlan(encap_ethtype
)) {
421 flower
->key
.encap_eth_type
[1] = flower
->key
.encap_eth_type
[0];
422 flower
->key
.encap_eth_type
[0] = encap_ethtype
;
424 if (attrs
[TCA_FLOWER_KEY_CVLAN_ID
]) {
425 flower
->key
.vlan_id
[1] =
426 nl_attr_get_u16(attrs
[TCA_FLOWER_KEY_CVLAN_ID
]);
428 if (attrs
[TCA_FLOWER_KEY_CVLAN_PRIO
]) {
429 flower
->key
.vlan_prio
[1] =
430 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_CVLAN_PRIO
]);
435 nl_parse_flower_tunnel(struct nlattr
**attrs
, struct tc_flower
*flower
)
437 if (attrs
[TCA_FLOWER_KEY_ENC_KEY_ID
]) {
438 ovs_be32 id
= nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_KEY_ID
]);
440 flower
->key
.tunnel
.id
= be32_to_be64(id
);
442 if (attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
]) {
443 flower
->key
.tunnel
.ipv4
.ipv4_src
=
444 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC
]);
446 if (attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
]) {
447 flower
->key
.tunnel
.ipv4
.ipv4_dst
=
448 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST
]);
450 if (attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
]) {
451 flower
->key
.tunnel
.ipv6
.ipv6_src
=
452 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC
]);
454 if (attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
]) {
455 flower
->key
.tunnel
.ipv6
.ipv6_dst
=
456 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST
]);
458 if (attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]) {
459 flower
->key
.tunnel
.tp_dst
=
460 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]);
462 if (attrs
[TCA_FLOWER_KEY_ENC_IP_TOS_MASK
]) {
463 flower
->key
.tunnel
.tos
=
464 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TOS
]);
465 flower
->mask
.tunnel
.tos
=
466 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TOS_MASK
]);
468 if (attrs
[TCA_FLOWER_KEY_ENC_IP_TTL_MASK
]) {
469 flower
->key
.tunnel
.ttl
=
470 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TTL
]);
471 flower
->mask
.tunnel
.ttl
=
472 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TTL_MASK
]);
477 nl_parse_flower_ip(struct nlattr
**attrs
, struct tc_flower
*flower
) {
478 uint8_t ip_proto
= 0;
479 struct tc_flower_key
*key
= &flower
->key
;
480 struct tc_flower_key
*mask
= &flower
->mask
;
482 if (attrs
[TCA_FLOWER_KEY_IP_PROTO
]) {
483 ip_proto
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_PROTO
]);
484 key
->ip_proto
= ip_proto
;
485 mask
->ip_proto
= UINT8_MAX
;
488 if (attrs
[TCA_FLOWER_KEY_FLAGS_MASK
]) {
489 key
->flags
= ntohl(nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_FLAGS
]));
491 ntohl(nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_FLAGS_MASK
]));
494 if (attrs
[TCA_FLOWER_KEY_IPV4_SRC_MASK
]) {
496 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_SRC
]);
497 mask
->ipv4
.ipv4_src
=
498 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_SRC_MASK
]);
500 if (attrs
[TCA_FLOWER_KEY_IPV4_DST_MASK
]) {
502 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_DST
]);
503 mask
->ipv4
.ipv4_dst
=
504 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_DST_MASK
]);
506 if (attrs
[TCA_FLOWER_KEY_IPV6_SRC_MASK
]) {
507 struct nlattr
*attr
= attrs
[TCA_FLOWER_KEY_IPV6_SRC
];
508 struct nlattr
*attr_mask
= attrs
[TCA_FLOWER_KEY_IPV6_SRC_MASK
];
510 key
->ipv6
.ipv6_src
= nl_attr_get_in6_addr(attr
);
511 mask
->ipv6
.ipv6_src
= nl_attr_get_in6_addr(attr_mask
);
513 if (attrs
[TCA_FLOWER_KEY_IPV6_DST_MASK
]) {
514 struct nlattr
*attr
= attrs
[TCA_FLOWER_KEY_IPV6_DST
];
515 struct nlattr
*attr_mask
= attrs
[TCA_FLOWER_KEY_IPV6_DST_MASK
];
517 key
->ipv6
.ipv6_dst
= nl_attr_get_in6_addr(attr
);
518 mask
->ipv6
.ipv6_dst
= nl_attr_get_in6_addr(attr_mask
);
521 if (ip_proto
== IPPROTO_TCP
) {
522 if (attrs
[TCA_FLOWER_KEY_TCP_SRC_MASK
]) {
524 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_SRC
]);
526 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_SRC_MASK
]);
528 if (attrs
[TCA_FLOWER_KEY_TCP_DST_MASK
]) {
530 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_DST
]);
532 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_DST_MASK
]);
534 if (attrs
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]) {
536 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_FLAGS
]);
538 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]);
540 } else if (ip_proto
== IPPROTO_UDP
) {
541 if (attrs
[TCA_FLOWER_KEY_UDP_SRC_MASK
]) {
542 key
->udp_src
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_SRC
]);
544 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_SRC_MASK
]);
546 if (attrs
[TCA_FLOWER_KEY_UDP_DST_MASK
]) {
547 key
->udp_dst
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_DST
]);
549 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_DST_MASK
]);
551 } else if (ip_proto
== IPPROTO_SCTP
) {
552 if (attrs
[TCA_FLOWER_KEY_SCTP_SRC_MASK
]) {
553 key
->sctp_src
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_SRC
]);
555 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_SRC_MASK
]);
557 if (attrs
[TCA_FLOWER_KEY_SCTP_DST_MASK
]) {
558 key
->sctp_dst
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_DST
]);
560 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_DST_MASK
]);
564 if (attrs
[TCA_FLOWER_KEY_IP_TTL_MASK
]) {
565 key
->ip_ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TTL
]);
566 mask
->ip_ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TTL_MASK
]);
569 if (attrs
[TCA_FLOWER_KEY_IP_TOS_MASK
]) {
570 key
->ip_tos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TOS
]);
571 mask
->ip_tos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TOS_MASK
]);
575 static enum tc_offloaded_state
576 nl_get_flower_offloaded_state(struct nlattr
**attrs
)
578 uint32_t flower_flags
= 0;
580 if (attrs
[TCA_FLOWER_FLAGS
]) {
581 flower_flags
= nl_attr_get_u32(attrs
[TCA_FLOWER_FLAGS
]);
582 if (flower_flags
& TCA_CLS_FLAGS_NOT_IN_HW
) {
583 return TC_OFFLOADED_STATE_NOT_IN_HW
;
584 } else if (flower_flags
& TCA_CLS_FLAGS_IN_HW
) {
585 return TC_OFFLOADED_STATE_IN_HW
;
588 return TC_OFFLOADED_STATE_UNDEFINED
;
592 nl_parse_flower_flags(struct nlattr
**attrs
, struct tc_flower
*flower
)
594 flower
->offloaded_state
= nl_get_flower_offloaded_state(attrs
);
597 static const struct nl_policy pedit_policy
[] = {
598 [TCA_PEDIT_PARMS_EX
] = { .type
= NL_A_UNSPEC
,
599 .min_len
= sizeof(struct tc_pedit
),
600 .optional
= false, },
601 [TCA_PEDIT_KEYS_EX
] = { .type
= NL_A_NESTED
,
602 .optional
= false, },
606 nl_parse_act_pedit(struct nlattr
*options
, struct tc_flower
*flower
)
608 struct tc_action
*action
;
609 struct nlattr
*pe_attrs
[ARRAY_SIZE(pedit_policy
)];
610 const struct tc_pedit
*pe
;
611 const struct tc_pedit_key
*keys
;
612 const struct nlattr
*nla
, *keys_ex
, *ex_type
;
613 const void *keys_attr
;
614 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
615 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
616 size_t keys_ex_size
, left
;
617 int type
, i
= 0, err
;
619 if (!nl_parse_nested(options
, pedit_policy
, pe_attrs
,
620 ARRAY_SIZE(pedit_policy
))) {
621 VLOG_ERR_RL(&error_rl
, "failed to parse pedit action options");
625 pe
= nl_attr_get_unspec(pe_attrs
[TCA_PEDIT_PARMS_EX
], sizeof *pe
);
627 keys_attr
= pe_attrs
[TCA_PEDIT_KEYS_EX
];
628 keys_ex
= nl_attr_get(keys_attr
);
629 keys_ex_size
= nl_attr_get_size(keys_attr
);
631 NL_ATTR_FOR_EACH (nla
, left
, keys_ex
, keys_ex_size
) {
632 if (i
>= pe
->nkeys
) {
636 if (nl_attr_type(nla
) != TCA_PEDIT_KEY_EX
) {
637 VLOG_ERR_RL(&error_rl
, "unable to parse legacy pedit type: %d",
642 ex_type
= nl_attr_find_nested(nla
, TCA_PEDIT_KEY_EX_HTYPE
);
643 type
= nl_attr_get_u16(ex_type
);
645 err
= csum_update_flag(flower
, type
);
650 for (int j
= 0; j
< ARRAY_SIZE(flower_pedit_map
); j
++) {
651 struct flower_key_to_pedit
*m
= &flower_pedit_map
[j
];
652 int flower_off
= m
->flower_offset
;
656 if (m
->htype
!= type
) {
660 /* check overlap between current pedit key, which is always
661 * 4 bytes (range [off, off + 3]), and a map entry in
662 * flower_pedit_map (range [mf, mf + sz - 1]) */
663 if ((keys
->off
>= mf
&& keys
->off
< mf
+ sz
)
664 || (keys
->off
+ 3 >= mf
&& keys
->off
+ 3 < mf
+ sz
)) {
665 int diff
= flower_off
+ (keys
->off
- mf
);
666 uint32_t *dst
= (void *) (rewrite_key
+ diff
);
667 uint32_t *dst_m
= (void *) (rewrite_mask
+ diff
);
668 uint32_t mask
= ~(keys
->mask
);
671 if (keys
->off
< mf
) {
672 zero_bits
= 8 * (mf
- keys
->off
);
673 mask
&= UINT32_MAX
<< zero_bits
;
674 } else if (keys
->off
+ 4 > mf
+ m
->size
) {
675 zero_bits
= 8 * (keys
->off
+ 4 - mf
- m
->size
);
676 mask
&= UINT32_MAX
>> zero_bits
;
680 *dst
|= keys
->val
& mask
;
688 action
= &flower
->actions
[flower
->action_count
++];
689 action
->type
= TC_ACT_PEDIT
;
694 static const struct nl_policy tunnel_key_policy
[] = {
695 [TCA_TUNNEL_KEY_PARMS
] = { .type
= NL_A_UNSPEC
,
696 .min_len
= sizeof(struct tc_tunnel_key
),
697 .optional
= false, },
698 [TCA_TUNNEL_KEY_ENC_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
699 [TCA_TUNNEL_KEY_ENC_IPV4_DST
] = { .type
= NL_A_U32
, .optional
= true, },
700 [TCA_TUNNEL_KEY_ENC_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
701 .min_len
= sizeof(struct in6_addr
),
703 [TCA_TUNNEL_KEY_ENC_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
704 .min_len
= sizeof(struct in6_addr
),
706 [TCA_TUNNEL_KEY_ENC_KEY_ID
] = { .type
= NL_A_U32
, .optional
= true, },
707 [TCA_TUNNEL_KEY_ENC_DST_PORT
] = { .type
= NL_A_U16
, .optional
= true, },
708 [TCA_TUNNEL_KEY_ENC_TOS
] = { .type
= NL_A_U8
, .optional
= true, },
709 [TCA_TUNNEL_KEY_ENC_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
713 nl_parse_act_tunnel_key(struct nlattr
*options
, struct tc_flower
*flower
)
715 struct nlattr
*tun_attrs
[ARRAY_SIZE(tunnel_key_policy
)];
716 const struct nlattr
*tun_parms
;
717 const struct tc_tunnel_key
*tun
;
718 struct tc_action
*action
;
720 if (!nl_parse_nested(options
, tunnel_key_policy
, tun_attrs
,
721 ARRAY_SIZE(tunnel_key_policy
))) {
722 VLOG_ERR_RL(&error_rl
, "failed to parse tunnel_key action options");
726 tun_parms
= tun_attrs
[TCA_TUNNEL_KEY_PARMS
];
727 tun
= nl_attr_get_unspec(tun_parms
, sizeof *tun
);
728 if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_SET
) {
729 struct nlattr
*id
= tun_attrs
[TCA_TUNNEL_KEY_ENC_KEY_ID
];
730 struct nlattr
*dst_port
= tun_attrs
[TCA_TUNNEL_KEY_ENC_DST_PORT
];
731 struct nlattr
*ipv4_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_SRC
];
732 struct nlattr
*ipv4_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_DST
];
733 struct nlattr
*ipv6_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_SRC
];
734 struct nlattr
*ipv6_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_DST
];
735 struct nlattr
*tos
= tun_attrs
[TCA_TUNNEL_KEY_ENC_TOS
];
736 struct nlattr
*ttl
= tun_attrs
[TCA_TUNNEL_KEY_ENC_TTL
];
738 action
= &flower
->actions
[flower
->action_count
++];
739 action
->type
= TC_ACT_ENCAP
;
740 action
->encap
.ipv4
.ipv4_src
= ipv4_src
? nl_attr_get_be32(ipv4_src
) : 0;
741 action
->encap
.ipv4
.ipv4_dst
= ipv4_dst
? nl_attr_get_be32(ipv4_dst
) : 0;
743 action
->encap
.ipv6
.ipv6_src
= nl_attr_get_in6_addr(ipv6_src
);
746 action
->encap
.ipv6
.ipv6_dst
= nl_attr_get_in6_addr(ipv6_dst
);
748 action
->encap
.id
= id
? be32_to_be64(nl_attr_get_be32(id
)) : 0;
749 action
->encap
.tp_dst
= dst_port
? nl_attr_get_be16(dst_port
) : 0;
750 action
->encap
.tos
= tos
? nl_attr_get_u8(tos
) : 0;
751 action
->encap
.ttl
= ttl
? nl_attr_get_u8(ttl
) : 0;
752 } else if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_RELEASE
) {
753 flower
->tunnel
= true;
755 VLOG_ERR_RL(&error_rl
, "unknown tunnel actions: %d, %d",
756 tun
->action
, tun
->t_action
);
762 static const struct nl_policy gact_policy
[] = {
763 [TCA_GACT_PARMS
] = { .type
= NL_A_UNSPEC
,
764 .min_len
= sizeof(struct tc_gact
),
765 .optional
= false, },
766 [TCA_GACT_TM
] = { .type
= NL_A_UNSPEC
,
767 .min_len
= sizeof(struct tcf_t
),
768 .optional
= false, },
774 static struct ovsthread_once once
= OVSTHREAD_ONCE_INITIALIZER
;
775 static int user_hz
= 100;
777 if (ovsthread_once_start(&once
)) {
778 user_hz
= sysconf(_SC_CLK_TCK
);
779 ovsthread_once_done(&once
);
786 nl_parse_tcf(const struct tcf_t
*tm
, struct tc_flower
*flower
)
788 flower
->lastused
= time_msec() - (tm
->lastuse
* 1000 / get_user_hz());
792 nl_parse_act_drop(struct nlattr
*options
, struct tc_flower
*flower
)
794 struct nlattr
*gact_attrs
[ARRAY_SIZE(gact_policy
)];
795 const struct tc_gact
*p
;
796 struct nlattr
*gact_parms
;
797 const struct tcf_t
*tm
;
799 if (!nl_parse_nested(options
, gact_policy
, gact_attrs
,
800 ARRAY_SIZE(gact_policy
))) {
801 VLOG_ERR_RL(&error_rl
, "failed to parse gact action options");
805 gact_parms
= gact_attrs
[TCA_GACT_PARMS
];
806 p
= nl_attr_get_unspec(gact_parms
, sizeof *p
);
808 if (p
->action
!= TC_ACT_SHOT
) {
809 VLOG_ERR_RL(&error_rl
, "unknown gact action: %d", p
->action
);
813 tm
= nl_attr_get_unspec(gact_attrs
[TCA_GACT_TM
], sizeof *tm
);
814 nl_parse_tcf(tm
, flower
);
819 static const struct nl_policy mirred_policy
[] = {
820 [TCA_MIRRED_PARMS
] = { .type
= NL_A_UNSPEC
,
821 .min_len
= sizeof(struct tc_mirred
),
822 .optional
= false, },
823 [TCA_MIRRED_TM
] = { .type
= NL_A_UNSPEC
,
824 .min_len
= sizeof(struct tcf_t
),
825 .optional
= false, },
829 nl_parse_act_mirred(struct nlattr
*options
, struct tc_flower
*flower
)
832 struct nlattr
*mirred_attrs
[ARRAY_SIZE(mirred_policy
)];
833 const struct tc_mirred
*m
;
834 const struct nlattr
*mirred_parms
;
835 const struct tcf_t
*tm
;
836 struct nlattr
*mirred_tm
;
837 struct tc_action
*action
;
839 if (!nl_parse_nested(options
, mirred_policy
, mirred_attrs
,
840 ARRAY_SIZE(mirred_policy
))) {
841 VLOG_ERR_RL(&error_rl
, "failed to parse mirred action options");
845 mirred_parms
= mirred_attrs
[TCA_MIRRED_PARMS
];
846 m
= nl_attr_get_unspec(mirred_parms
, sizeof *m
);
848 if (m
->eaction
!= TCA_EGRESS_REDIR
&& m
->eaction
!= TCA_EGRESS_MIRROR
) {
849 VLOG_ERR_RL(&error_rl
, "unknown mirred action: %d, %d, %d",
850 m
->action
, m
->eaction
, m
->ifindex
);
854 action
= &flower
->actions
[flower
->action_count
++];
855 action
->ifindex_out
= m
->ifindex
;
856 action
->type
= TC_ACT_OUTPUT
;
858 mirred_tm
= mirred_attrs
[TCA_MIRRED_TM
];
859 tm
= nl_attr_get_unspec(mirred_tm
, sizeof *tm
);
860 nl_parse_tcf(tm
, flower
);
865 static const struct nl_policy vlan_policy
[] = {
866 [TCA_VLAN_PARMS
] = { .type
= NL_A_UNSPEC
,
867 .min_len
= sizeof(struct tc_vlan
),
868 .optional
= false, },
869 [TCA_VLAN_PUSH_VLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
870 [TCA_VLAN_PUSH_VLAN_PROTOCOL
] = { .type
= NL_A_U16
, .optional
= true, },
871 [TCA_VLAN_PUSH_VLAN_PRIORITY
] = { .type
= NL_A_U8
, .optional
= true, },
875 nl_parse_act_vlan(struct nlattr
*options
, struct tc_flower
*flower
)
877 struct nlattr
*vlan_attrs
[ARRAY_SIZE(vlan_policy
)];
878 const struct tc_vlan
*v
;
879 const struct nlattr
*vlan_parms
;
880 struct tc_action
*action
;
882 if (!nl_parse_nested(options
, vlan_policy
, vlan_attrs
,
883 ARRAY_SIZE(vlan_policy
))) {
884 VLOG_ERR_RL(&error_rl
, "failed to parse vlan action options");
888 action
= &flower
->actions
[flower
->action_count
++];
889 vlan_parms
= vlan_attrs
[TCA_VLAN_PARMS
];
890 v
= nl_attr_get_unspec(vlan_parms
, sizeof *v
);
891 if (v
->v_action
== TCA_VLAN_ACT_PUSH
) {
892 struct nlattr
*vlan_tpid
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PROTOCOL
];
893 struct nlattr
*vlan_id
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_ID
];
894 struct nlattr
*vlan_prio
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PRIORITY
];
896 action
->vlan
.vlan_push_tpid
= nl_attr_get_be16(vlan_tpid
);
897 action
->vlan
.vlan_push_id
= nl_attr_get_u16(vlan_id
);
898 action
->vlan
.vlan_push_prio
= vlan_prio
? nl_attr_get_u8(vlan_prio
) : 0;
899 action
->type
= TC_ACT_VLAN_PUSH
;
900 } else if (v
->v_action
== TCA_VLAN_ACT_POP
) {
901 action
->type
= TC_ACT_VLAN_POP
;
903 VLOG_ERR_RL(&error_rl
, "unknown vlan action: %d, %d",
904 v
->action
, v
->v_action
);
910 static const struct nl_policy csum_policy
[] = {
911 [TCA_CSUM_PARMS
] = { .type
= NL_A_UNSPEC
,
912 .min_len
= sizeof(struct tc_csum
),
913 .optional
= false, },
917 nl_parse_act_csum(struct nlattr
*options
, struct tc_flower
*flower
)
919 struct nlattr
*csum_attrs
[ARRAY_SIZE(csum_policy
)];
920 const struct tc_csum
*c
;
921 const struct nlattr
*csum_parms
;
923 if (!nl_parse_nested(options
, csum_policy
, csum_attrs
,
924 ARRAY_SIZE(csum_policy
))) {
925 VLOG_ERR_RL(&error_rl
, "failed to parse csum action options");
929 csum_parms
= csum_attrs
[TCA_CSUM_PARMS
];
930 c
= nl_attr_get_unspec(csum_parms
, sizeof *c
);
933 if (c
->update_flags
!= flower
->csum_update_flags
) {
934 VLOG_WARN_RL(&error_rl
,
935 "expected different act csum flags: 0x%x != 0x%x",
936 flower
->csum_update_flags
, c
->update_flags
);
939 flower
->csum_update_flags
= 0; /* so we know csum was handled */
941 if (flower
->needs_full_ip_proto_mask
942 && flower
->mask
.ip_proto
!= UINT8_MAX
) {
943 VLOG_WARN_RL(&error_rl
, "expected full matching on flower ip_proto");
950 static const struct nl_policy act_policy
[] = {
951 [TCA_ACT_KIND
] = { .type
= NL_A_STRING
, .optional
= false, },
952 [TCA_ACT_COOKIE
] = { .type
= NL_A_UNSPEC
, .optional
= true, },
953 [TCA_ACT_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= false, },
954 [TCA_ACT_STATS
] = { .type
= NL_A_NESTED
, .optional
= false, },
957 static const struct nl_policy stats_policy
[] = {
958 [TCA_STATS_BASIC
] = { .type
= NL_A_UNSPEC
,
959 .min_len
= sizeof(struct gnet_stats_basic
),
960 .optional
= false, },
964 nl_parse_single_action(struct nlattr
*action
, struct tc_flower
*flower
)
966 struct nlattr
*act_options
;
967 struct nlattr
*act_stats
;
968 struct nlattr
*act_cookie
;
969 const char *act_kind
;
970 struct nlattr
*action_attrs
[ARRAY_SIZE(act_policy
)];
971 struct nlattr
*stats_attrs
[ARRAY_SIZE(stats_policy
)];
972 struct ovs_flow_stats
*stats
= &flower
->stats
;
973 const struct gnet_stats_basic
*bs
;
976 if (!nl_parse_nested(action
, act_policy
, action_attrs
,
977 ARRAY_SIZE(act_policy
))) {
978 VLOG_ERR_RL(&error_rl
, "failed to parse single action options");
982 act_kind
= nl_attr_get_string(action_attrs
[TCA_ACT_KIND
]);
983 act_options
= action_attrs
[TCA_ACT_OPTIONS
];
984 act_cookie
= action_attrs
[TCA_ACT_COOKIE
];
986 if (!strcmp(act_kind
, "gact")) {
987 err
= nl_parse_act_drop(act_options
, flower
);
988 } else if (!strcmp(act_kind
, "mirred")) {
989 err
= nl_parse_act_mirred(act_options
, flower
);
990 } else if (!strcmp(act_kind
, "vlan")) {
991 err
= nl_parse_act_vlan(act_options
, flower
);
992 } else if (!strcmp(act_kind
, "tunnel_key")) {
993 err
= nl_parse_act_tunnel_key(act_options
, flower
);
994 } else if (!strcmp(act_kind
, "pedit")) {
995 err
= nl_parse_act_pedit(act_options
, flower
);
996 } else if (!strcmp(act_kind
, "csum")) {
997 nl_parse_act_csum(act_options
, flower
);
999 VLOG_ERR_RL(&error_rl
, "unknown tc action kind: %s", act_kind
);
1008 flower
->act_cookie
.data
= nl_attr_get(act_cookie
);
1009 flower
->act_cookie
.len
= nl_attr_get_size(act_cookie
);
1012 act_stats
= action_attrs
[TCA_ACT_STATS
];
1014 if (!nl_parse_nested(act_stats
, stats_policy
, stats_attrs
,
1015 ARRAY_SIZE(stats_policy
))) {
1016 VLOG_ERR_RL(&error_rl
, "failed to parse action stats policy");
1020 bs
= nl_attr_get_unspec(stats_attrs
[TCA_STATS_BASIC
], sizeof *bs
);
1021 put_32aligned_u64(&stats
->n_packets
, bs
->packets
);
1022 put_32aligned_u64(&stats
->n_bytes
, bs
->bytes
);
1027 #define TCA_ACT_MIN_PRIO 1
1030 nl_parse_flower_actions(struct nlattr
**attrs
, struct tc_flower
*flower
)
1032 const struct nlattr
*actions
= attrs
[TCA_FLOWER_ACT
];
1033 static struct nl_policy actions_orders_policy
[TCA_ACT_MAX_PRIO
+ 1] = {};
1034 struct nlattr
*actions_orders
[ARRAY_SIZE(actions_orders_policy
)];
1035 const int max_size
= ARRAY_SIZE(actions_orders_policy
);
1037 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
1038 actions_orders_policy
[i
].type
= NL_A_NESTED
;
1039 actions_orders_policy
[i
].optional
= true;
1042 if (!nl_parse_nested(actions
, actions_orders_policy
, actions_orders
,
1043 ARRAY_SIZE(actions_orders_policy
))) {
1044 VLOG_ERR_RL(&error_rl
, "failed to parse flower order of actions");
1048 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
1049 if (actions_orders
[i
]) {
1052 if (flower
->action_count
>= TCA_ACT_MAX_PRIO
) {
1053 VLOG_DBG_RL(&error_rl
, "Can only support %d actions", flower
->action_count
);
1056 err
= nl_parse_single_action(actions_orders
[i
], flower
);
1064 if (flower
->csum_update_flags
) {
1065 VLOG_WARN_RL(&error_rl
,
1066 "expected act csum with flags: 0x%x",
1067 flower
->csum_update_flags
);
1075 nl_parse_flower_options(struct nlattr
*nl_options
, struct tc_flower
*flower
)
1077 struct nlattr
*attrs
[ARRAY_SIZE(tca_flower_policy
)];
1079 if (!nl_parse_nested(nl_options
, tca_flower_policy
,
1080 attrs
, ARRAY_SIZE(tca_flower_policy
))) {
1081 VLOG_ERR_RL(&error_rl
, "failed to parse flower classifier options");
1085 nl_parse_flower_eth(attrs
, flower
);
1086 nl_parse_flower_mpls(attrs
, flower
);
1087 nl_parse_flower_vlan(attrs
, flower
);
1088 nl_parse_flower_ip(attrs
, flower
);
1089 nl_parse_flower_tunnel(attrs
, flower
);
1090 nl_parse_flower_flags(attrs
, flower
);
1091 return nl_parse_flower_actions(attrs
, flower
);
1095 parse_netlink_to_tc_flower(struct ofpbuf
*reply
, struct tc_flower
*flower
)
1098 struct nlattr
*ta
[ARRAY_SIZE(tca_policy
)];
1101 if (NLMSG_HDRLEN
+ sizeof *tc
> reply
->size
) {
1105 memset(flower
, 0, sizeof *flower
);
1107 tc
= ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
1108 flower
->handle
= tc
->tcm_handle
;
1109 flower
->key
.eth_type
= (OVS_FORCE ovs_be16
) tc_get_minor(tc
->tcm_info
);
1110 flower
->mask
.eth_type
= OVS_BE16_MAX
;
1111 flower
->prio
= tc_get_major(tc
->tcm_info
);
1113 if (!flower
->handle
) {
1117 if (!nl_policy_parse(reply
, NLMSG_HDRLEN
+ sizeof *tc
,
1118 tca_policy
, ta
, ARRAY_SIZE(ta
))) {
1119 VLOG_ERR_RL(&error_rl
, "failed to parse tca policy");
1123 kind
= nl_attr_get_string(ta
[TCA_KIND
]);
1124 if (strcmp(kind
, "flower")) {
1125 VLOG_DBG_ONCE("Unsupported filter: %s", kind
);
1129 return nl_parse_flower_options(ta
[TCA_OPTIONS
], flower
);
1133 tc_dump_flower_start(int ifindex
, struct nl_dump
*dump
, uint32_t block_id
)
1135 struct ofpbuf request
;
1136 struct tcmsg
*tcmsg
;
1139 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1140 tcmsg
= tc_make_request(index
, RTM_GETTFILTER
, NLM_F_DUMP
, &request
);
1141 tcmsg
->tcm_parent
= block_id
? : TC_INGRESS_PARENT
;
1142 tcmsg
->tcm_info
= TC_H_UNSPEC
;
1143 tcmsg
->tcm_handle
= 0;
1145 nl_dump_start(dump
, NETLINK_ROUTE
, &request
);
1146 ofpbuf_uninit(&request
);
1152 tc_flush(int ifindex
, uint32_t block_id
)
1154 struct ofpbuf request
;
1155 struct tcmsg
*tcmsg
;
1158 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1159 tcmsg
= tc_make_request(index
, RTM_DELTFILTER
, NLM_F_ACK
, &request
);
1160 tcmsg
->tcm_parent
= block_id
? : TC_INGRESS_PARENT
;
1161 tcmsg
->tcm_info
= TC_H_UNSPEC
;
1163 return tc_transact(&request
, NULL
);
1167 tc_del_filter(int ifindex
, int prio
, int handle
, uint32_t block_id
)
1169 struct ofpbuf request
;
1170 struct tcmsg
*tcmsg
;
1171 struct ofpbuf
*reply
;
1175 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1176 tcmsg
= tc_make_request(index
, RTM_DELTFILTER
, NLM_F_ECHO
, &request
);
1177 tcmsg
->tcm_parent
= block_id
? : TC_INGRESS_PARENT
;
1178 tcmsg
->tcm_info
= tc_make_handle(prio
, 0);
1179 tcmsg
->tcm_handle
= handle
;
1181 error
= tc_transact(&request
, &reply
);
1183 ofpbuf_delete(reply
);
1189 tc_get_flower(int ifindex
, int prio
, int handle
, struct tc_flower
*flower
,
1192 struct ofpbuf request
;
1193 struct tcmsg
*tcmsg
;
1194 struct ofpbuf
*reply
;
1198 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1199 tcmsg
= tc_make_request(index
, RTM_GETTFILTER
, NLM_F_ECHO
, &request
);
1200 tcmsg
->tcm_parent
= block_id
? : TC_INGRESS_PARENT
;
1201 tcmsg
->tcm_info
= tc_make_handle(prio
, 0);
1202 tcmsg
->tcm_handle
= handle
;
1204 error
= tc_transact(&request
, &reply
);
1209 error
= parse_netlink_to_tc_flower(reply
, flower
);
1210 ofpbuf_delete(reply
);
1215 tc_get_tc_cls_policy(enum tc_offload_policy policy
)
1217 if (policy
== TC_POLICY_SKIP_HW
) {
1218 return TCA_CLS_FLAGS_SKIP_HW
;
1219 } else if (policy
== TC_POLICY_SKIP_SW
) {
1220 return TCA_CLS_FLAGS_SKIP_SW
;
1227 nl_msg_put_act_csum(struct ofpbuf
*request
, uint32_t flags
)
1231 nl_msg_put_string(request
, TCA_ACT_KIND
, "csum");
1232 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1234 struct tc_csum parm
= { .action
= TC_ACT_PIPE
,
1235 .update_flags
= flags
};
1237 nl_msg_put_unspec(request
, TCA_CSUM_PARMS
, &parm
, sizeof parm
);
1239 nl_msg_end_nested(request
, offset
);
1243 nl_msg_put_act_pedit(struct ofpbuf
*request
, struct tc_pedit
*parm
,
1244 struct tc_pedit_key_ex
*ex
)
1246 size_t ksize
= sizeof *parm
+ parm
->nkeys
* sizeof(struct tc_pedit_key
);
1247 size_t offset
, offset_keys_ex
, offset_key
;
1250 nl_msg_put_string(request
, TCA_ACT_KIND
, "pedit");
1251 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1253 parm
->action
= TC_ACT_PIPE
;
1255 nl_msg_put_unspec(request
, TCA_PEDIT_PARMS_EX
, parm
, ksize
);
1256 offset_keys_ex
= nl_msg_start_nested(request
, TCA_PEDIT_KEYS_EX
);
1257 for (i
= 0; i
< parm
->nkeys
; i
++, ex
++) {
1258 offset_key
= nl_msg_start_nested(request
, TCA_PEDIT_KEY_EX
);
1259 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_HTYPE
, ex
->htype
);
1260 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_CMD
, ex
->cmd
);
1261 nl_msg_end_nested(request
, offset_key
);
1263 nl_msg_end_nested(request
, offset_keys_ex
);
1265 nl_msg_end_nested(request
, offset
);
1269 nl_msg_put_act_push_vlan(struct ofpbuf
*request
, ovs_be16 tpid
,
1270 uint16_t vid
, uint8_t prio
)
1274 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1275 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1277 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1278 .v_action
= TCA_VLAN_ACT_PUSH
};
1280 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1281 nl_msg_put_be16(request
, TCA_VLAN_PUSH_VLAN_PROTOCOL
, tpid
);
1282 nl_msg_put_u16(request
, TCA_VLAN_PUSH_VLAN_ID
, vid
);
1283 nl_msg_put_u8(request
, TCA_VLAN_PUSH_VLAN_PRIORITY
, prio
);
1285 nl_msg_end_nested(request
, offset
);
1289 nl_msg_put_act_pop_vlan(struct ofpbuf
*request
)
1293 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1294 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1296 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1297 .v_action
= TCA_VLAN_ACT_POP
};
1299 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1301 nl_msg_end_nested(request
, offset
);
1305 nl_msg_put_act_tunnel_key_release(struct ofpbuf
*request
)
1309 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
1310 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1312 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
1313 .t_action
= TCA_TUNNEL_KEY_ACT_RELEASE
};
1315 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
1317 nl_msg_end_nested(request
, offset
);
1321 nl_msg_put_act_tunnel_key_set(struct ofpbuf
*request
, ovs_be64 id
,
1322 ovs_be32 ipv4_src
, ovs_be32 ipv4_dst
,
1323 struct in6_addr
*ipv6_src
,
1324 struct in6_addr
*ipv6_dst
,
1326 uint8_t tos
, uint8_t ttl
)
1330 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
1331 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1333 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
1334 .t_action
= TCA_TUNNEL_KEY_ACT_SET
};
1336 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
1338 ovs_be32 id32
= be64_to_be32(id
);
1339 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_KEY_ID
, id32
);
1341 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_SRC
, ipv4_src
);
1342 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_DST
, ipv4_dst
);
1343 } else if (!is_all_zeros(ipv6_dst
, sizeof *ipv6_dst
)) {
1344 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_DST
,
1346 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_SRC
,
1350 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_TOS
, tos
);
1353 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_TTL
, ttl
);
1355 nl_msg_put_be16(request
, TCA_TUNNEL_KEY_ENC_DST_PORT
, tp_dst
);
1357 nl_msg_end_nested(request
, offset
);
1361 nl_msg_put_act_drop(struct ofpbuf
*request
)
1365 nl_msg_put_string(request
, TCA_ACT_KIND
, "gact");
1366 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1368 struct tc_gact p
= { .action
= TC_ACT_SHOT
};
1370 nl_msg_put_unspec(request
, TCA_GACT_PARMS
, &p
, sizeof p
);
1372 nl_msg_end_nested(request
, offset
);
1376 nl_msg_put_act_mirred(struct ofpbuf
*request
, int ifindex
, int action
,
1381 nl_msg_put_string(request
, TCA_ACT_KIND
, "mirred");
1382 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1384 struct tc_mirred m
= { .action
= action
,
1386 .ifindex
= ifindex
};
1388 nl_msg_put_unspec(request
, TCA_MIRRED_PARMS
, &m
, sizeof m
);
1390 nl_msg_end_nested(request
, offset
);
1394 nl_msg_put_act_cookie(struct ofpbuf
*request
, struct tc_cookie
*ck
) {
1396 nl_msg_put_unspec(request
, TCA_ACT_COOKIE
, ck
->data
, ck
->len
);
1400 /* Given flower, a key_to_pedit map entry, calculates the rest,
1403 * mask, data - pointers of where read the first word of flower->key/mask.
1404 * current_offset - which offset to use for the first pedit action.
1405 * cnt - max pedits actions to use.
1406 * first_word_mask/last_word_mask - the mask to use for the first/last read
1407 * (as we read entire words). */
1409 calc_offsets(struct tc_flower
*flower
, struct flower_key_to_pedit
*m
,
1410 int *cur_offset
, int *cnt
, uint32_t *last_word_mask
,
1411 uint32_t *first_word_mask
, uint32_t **mask
, uint32_t **data
)
1413 int start_offset
, max_offset
, total_size
;
1414 int diff
, right_zero_bits
, left_zero_bits
;
1415 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
1416 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
1418 max_offset
= m
->offset
+ m
->size
;
1419 start_offset
= ROUND_DOWN(m
->offset
, 4);
1420 diff
= m
->offset
- start_offset
;
1421 total_size
= max_offset
- start_offset
;
1422 right_zero_bits
= 8 * (4 - (max_offset
% 4));
1423 left_zero_bits
= 8 * (m
->offset
- start_offset
);
1425 *cur_offset
= start_offset
;
1426 *cnt
= (total_size
/ 4) + (total_size
% 4 ? 1 : 0);
1427 *last_word_mask
= UINT32_MAX
>> right_zero_bits
;
1428 *first_word_mask
= UINT32_MAX
<< left_zero_bits
;
1429 *data
= (void *) (rewrite_key
+ m
->flower_offset
- diff
);
1430 *mask
= (void *) (rewrite_mask
+ m
->flower_offset
- diff
);
1434 csum_update_flag(struct tc_flower
*flower
,
1435 enum pedit_header_type htype
) {
1436 /* Explictily specifiy the csum flags so HW can return EOPNOTSUPP
1437 * if it doesn't support a checksum recalculation of some headers.
1438 * And since OVS allows a flow such as
1439 * eth(dst=<mac>),eth_type(0x0800) actions=set(ipv4(src=<new_ip>))
1440 * we need to force a more specific flow as this can, for example,
1441 * need a recalculation of icmp checksum if the packet that passes
1442 * is ICMPv6 and tcp checksum if its tcp. */
1445 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
:
1446 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_IPV4HDR
;
1448 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
:
1449 case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
:
1450 case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
:
1451 if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
1452 flower
->needs_full_ip_proto_mask
= true;
1453 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_TCP
;
1454 } else if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
1455 flower
->needs_full_ip_proto_mask
= true;
1456 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_UDP
;
1457 } else if (flower
->key
.ip_proto
== IPPROTO_ICMP
) {
1458 flower
->needs_full_ip_proto_mask
= true;
1459 } else if (flower
->key
.ip_proto
== IPPROTO_ICMPV6
) {
1460 flower
->needs_full_ip_proto_mask
= true;
1461 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_ICMP
;
1463 VLOG_WARN_RL(&error_rl
,
1464 "can't offload rewrite of IP/IPV6 with ip_proto: %d",
1465 flower
->key
.ip_proto
);
1469 case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
:
1470 return 0; /* success */
1472 case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK
:
1473 case __PEDIT_HDR_TYPE_MAX
:
1482 nl_msg_put_flower_rewrite_pedits(struct ofpbuf
*request
,
1483 struct tc_flower
*flower
)
1486 struct tc_pedit sel
;
1487 struct tc_pedit_key keys
[MAX_PEDIT_OFFSETS
];
1488 struct tc_pedit_key_ex keys_ex
[MAX_PEDIT_OFFSETS
];
1496 for (i
= 0; i
< ARRAY_SIZE(flower_pedit_map
); i
++) {
1497 struct flower_key_to_pedit
*m
= &flower_pedit_map
[i
];
1498 struct tc_pedit_key
*pedit_key
= NULL
;
1499 struct tc_pedit_key_ex
*pedit_key_ex
= NULL
;
1500 uint32_t *mask
, *data
, first_word_mask
, last_word_mask
;
1501 int cnt
= 0, cur_offset
= 0;
1507 calc_offsets(flower
, m
, &cur_offset
, &cnt
, &last_word_mask
,
1508 &first_word_mask
, &mask
, &data
);
1510 for (j
= 0; j
< cnt
; j
++, mask
++, data
++, cur_offset
+= 4) {
1511 uint32_t mask_word
= *mask
;
1514 mask_word
&= first_word_mask
;
1517 mask_word
&= last_word_mask
;
1522 if (sel
.sel
.nkeys
== MAX_PEDIT_OFFSETS
) {
1523 VLOG_WARN_RL(&error_rl
, "reached too many pedit offsets: %d",
1528 pedit_key
= &sel
.keys
[sel
.sel
.nkeys
];
1529 pedit_key_ex
= &sel
.keys_ex
[sel
.sel
.nkeys
];
1530 pedit_key_ex
->cmd
= TCA_PEDIT_KEY_EX_CMD_SET
;
1531 pedit_key_ex
->htype
= m
->htype
;
1532 pedit_key
->off
= cur_offset
;
1533 pedit_key
->mask
= ~mask_word
;
1534 pedit_key
->val
= *data
& mask_word
;
1537 err
= csum_update_flag(flower
, m
->htype
);
1542 if (flower
->needs_full_ip_proto_mask
) {
1543 flower
->mask
.ip_proto
= UINT8_MAX
;
1547 nl_msg_put_act_pedit(request
, &sel
.sel
, sel
.keys_ex
);
1553 nl_msg_put_flower_acts(struct ofpbuf
*request
, struct tc_flower
*flower
)
1557 uint16_t act_index
= 1;
1558 struct tc_action
*action
;
1561 offset
= nl_msg_start_nested(request
, TCA_FLOWER_ACT
);
1565 if (flower
->tunnel
) {
1566 act_offset
= nl_msg_start_nested(request
, act_index
++);
1567 nl_msg_put_act_tunnel_key_release(request
);
1568 nl_msg_end_nested(request
, act_offset
);
1571 action
= flower
->actions
;
1572 for (i
= 0; i
< flower
->action_count
; i
++, action
++) {
1573 switch (action
->type
) {
1574 case TC_ACT_PEDIT
: {
1575 act_offset
= nl_msg_start_nested(request
, act_index
++);
1576 error
= nl_msg_put_flower_rewrite_pedits(request
, flower
);
1580 nl_msg_end_nested(request
, act_offset
);
1582 if (flower
->csum_update_flags
) {
1583 act_offset
= nl_msg_start_nested(request
, act_index
++);
1584 nl_msg_put_act_csum(request
, flower
->csum_update_flags
);
1585 nl_msg_end_nested(request
, act_offset
);
1589 case TC_ACT_ENCAP
: {
1590 act_offset
= nl_msg_start_nested(request
, act_index
++);
1591 nl_msg_put_act_tunnel_key_set(request
, action
->encap
.id
,
1592 action
->encap
.ipv4
.ipv4_src
,
1593 action
->encap
.ipv4
.ipv4_dst
,
1594 &action
->encap
.ipv6
.ipv6_src
,
1595 &action
->encap
.ipv6
.ipv6_dst
,
1596 action
->encap
.tp_dst
,
1599 nl_msg_end_nested(request
, act_offset
);
1602 case TC_ACT_VLAN_POP
: {
1603 act_offset
= nl_msg_start_nested(request
, act_index
++);
1604 nl_msg_put_act_pop_vlan(request
);
1605 nl_msg_end_nested(request
, act_offset
);
1608 case TC_ACT_VLAN_PUSH
: {
1609 act_offset
= nl_msg_start_nested(request
, act_index
++);
1610 nl_msg_put_act_push_vlan(request
,
1611 action
->vlan
.vlan_push_tpid
,
1612 action
->vlan
.vlan_push_id
,
1613 action
->vlan
.vlan_push_prio
);
1614 nl_msg_end_nested(request
, act_offset
);
1617 case TC_ACT_OUTPUT
: {
1618 ifindex
= action
->ifindex_out
;
1620 VLOG_ERR_RL(&error_rl
, "%s: invalid ifindex: %d, type: %d",
1621 __func__
, ifindex
, action
->type
);
1624 act_offset
= nl_msg_start_nested(request
, act_index
++);
1625 if (i
== flower
->action_count
- 1) {
1626 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_STOLEN
,
1629 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_PIPE
,
1632 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
1633 nl_msg_end_nested(request
, act_offset
);
1640 act_offset
= nl_msg_start_nested(request
, act_index
++);
1641 nl_msg_put_act_drop(request
);
1642 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
1643 nl_msg_end_nested(request
, act_offset
);
1645 nl_msg_end_nested(request
, offset
);
1651 nl_msg_put_masked_value(struct ofpbuf
*request
, uint16_t type
,
1652 uint16_t mask_type
, const void *data
,
1653 const void *mask_data
, size_t len
)
1655 if (mask_type
!= TCA_FLOWER_UNSPEC
) {
1656 if (is_all_zeros(mask_data
, len
)) {
1659 nl_msg_put_unspec(request
, mask_type
, mask_data
, len
);
1661 nl_msg_put_unspec(request
, type
, data
, len
);
1665 nl_msg_put_flower_tunnel(struct ofpbuf
*request
, struct tc_flower
*flower
)
1667 ovs_be32 ipv4_src
= flower
->key
.tunnel
.ipv4
.ipv4_src
;
1668 ovs_be32 ipv4_dst
= flower
->key
.tunnel
.ipv4
.ipv4_dst
;
1669 struct in6_addr
*ipv6_src
= &flower
->key
.tunnel
.ipv6
.ipv6_src
;
1670 struct in6_addr
*ipv6_dst
= &flower
->key
.tunnel
.ipv6
.ipv6_dst
;
1671 ovs_be16 tp_dst
= flower
->key
.tunnel
.tp_dst
;
1672 ovs_be32 id
= be64_to_be32(flower
->key
.tunnel
.id
);
1673 uint8_t tos
= flower
->key
.tunnel
.tos
;
1674 uint8_t ttl
= flower
->key
.tunnel
.ttl
;
1675 uint8_t tos_mask
= flower
->mask
.tunnel
.tos
;
1676 uint8_t ttl_mask
= flower
->mask
.tunnel
.ttl
;
1679 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_SRC
, ipv4_src
);
1680 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_DST
, ipv4_dst
);
1681 } else if (!is_all_zeros(ipv6_dst
, sizeof *ipv6_dst
)) {
1682 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_SRC
, ipv6_src
);
1683 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_DST
, ipv6_dst
);
1686 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TOS
, tos
);
1687 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TOS_MASK
, tos_mask
);
1690 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TTL
, ttl
);
1691 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TTL_MASK
, ttl_mask
);
1693 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_UDP_DST_PORT
, tp_dst
);
1694 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_KEY_ID
, id
);
1697 #define FLOWER_PUT_MASKED_VALUE(member, type) \
1698 nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \
1699 &flower->mask.member, sizeof flower->key.member)
1702 nl_msg_put_flower_options(struct ofpbuf
*request
, struct tc_flower
*flower
)
1705 uint16_t host_eth_type
= ntohs(flower
->key
.eth_type
);
1706 bool is_vlan
= eth_type_vlan(flower
->key
.eth_type
);
1707 bool is_qinq
= is_vlan
&& eth_type_vlan(flower
->key
.encap_eth_type
[0]);
1708 bool is_mpls
= eth_type_mpls(flower
->key
.eth_type
);
1711 /* need to parse acts first as some acts require changing the matching
1712 * see csum_update_flag() */
1713 err
= nl_msg_put_flower_acts(request
, flower
);
1720 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[1]);
1722 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[0]);
1727 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[0]);
1730 FLOWER_PUT_MASKED_VALUE(dst_mac
, TCA_FLOWER_KEY_ETH_DST
);
1731 FLOWER_PUT_MASKED_VALUE(src_mac
, TCA_FLOWER_KEY_ETH_SRC
);
1733 if (host_eth_type
== ETH_P_IP
|| host_eth_type
== ETH_P_IPV6
) {
1734 FLOWER_PUT_MASKED_VALUE(ip_ttl
, TCA_FLOWER_KEY_IP_TTL
);
1735 FLOWER_PUT_MASKED_VALUE(ip_tos
, TCA_FLOWER_KEY_IP_TOS
);
1737 if (flower
->mask
.ip_proto
&& flower
->key
.ip_proto
) {
1738 nl_msg_put_u8(request
, TCA_FLOWER_KEY_IP_PROTO
,
1739 flower
->key
.ip_proto
);
1742 if (flower
->mask
.flags
) {
1743 nl_msg_put_be32(request
, TCA_FLOWER_KEY_FLAGS
,
1744 htonl(flower
->key
.flags
));
1745 nl_msg_put_be32(request
, TCA_FLOWER_KEY_FLAGS_MASK
,
1746 htonl(flower
->mask
.flags
));
1749 if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
1750 FLOWER_PUT_MASKED_VALUE(udp_src
, TCA_FLOWER_KEY_UDP_SRC
);
1751 FLOWER_PUT_MASKED_VALUE(udp_dst
, TCA_FLOWER_KEY_UDP_DST
);
1752 } else if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
1753 FLOWER_PUT_MASKED_VALUE(tcp_src
, TCA_FLOWER_KEY_TCP_SRC
);
1754 FLOWER_PUT_MASKED_VALUE(tcp_dst
, TCA_FLOWER_KEY_TCP_DST
);
1755 FLOWER_PUT_MASKED_VALUE(tcp_flags
, TCA_FLOWER_KEY_TCP_FLAGS
);
1756 } else if (flower
->key
.ip_proto
== IPPROTO_SCTP
) {
1757 FLOWER_PUT_MASKED_VALUE(sctp_src
, TCA_FLOWER_KEY_SCTP_SRC
);
1758 FLOWER_PUT_MASKED_VALUE(sctp_dst
, TCA_FLOWER_KEY_SCTP_DST
);
1762 if (host_eth_type
== ETH_P_IP
) {
1763 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_src
, TCA_FLOWER_KEY_IPV4_SRC
);
1764 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_dst
, TCA_FLOWER_KEY_IPV4_DST
);
1765 } else if (host_eth_type
== ETH_P_IPV6
) {
1766 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_src
, TCA_FLOWER_KEY_IPV6_SRC
);
1767 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_dst
, TCA_FLOWER_KEY_IPV6_DST
);
1770 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ETH_TYPE
, flower
->key
.eth_type
);
1773 if (mpls_lse_to_ttl(flower
->mask
.mpls_lse
)) {
1774 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_TTL
,
1775 mpls_lse_to_ttl(flower
->key
.mpls_lse
));
1777 if (mpls_lse_to_tc(flower
->mask
.mpls_lse
)) {
1778 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_TC
,
1779 mpls_lse_to_tc(flower
->key
.mpls_lse
));
1781 if (mpls_lse_to_bos(flower
->mask
.mpls_lse
)) {
1782 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_BOS
,
1783 mpls_lse_to_bos(flower
->key
.mpls_lse
));
1785 if (mpls_lse_to_label(flower
->mask
.mpls_lse
)) {
1786 nl_msg_put_u32(request
, TCA_FLOWER_KEY_MPLS_LABEL
,
1787 mpls_lse_to_label(flower
->key
.mpls_lse
));
1792 if (flower
->key
.vlan_id
[0] || flower
->key
.vlan_prio
[0]) {
1793 nl_msg_put_u16(request
, TCA_FLOWER_KEY_VLAN_ID
,
1794 flower
->key
.vlan_id
[0]);
1795 nl_msg_put_u8(request
, TCA_FLOWER_KEY_VLAN_PRIO
,
1796 flower
->key
.vlan_prio
[0]);
1798 if (flower
->key
.encap_eth_type
[0]) {
1799 nl_msg_put_be16(request
, TCA_FLOWER_KEY_VLAN_ETH_TYPE
,
1800 flower
->key
.encap_eth_type
[0]);
1804 if (flower
->key
.vlan_id
[1] || flower
->key
.vlan_prio
[1]) {
1805 nl_msg_put_u16(request
, TCA_FLOWER_KEY_CVLAN_ID
,
1806 flower
->key
.vlan_id
[1]);
1807 nl_msg_put_u8(request
, TCA_FLOWER_KEY_CVLAN_PRIO
,
1808 flower
->key
.vlan_prio
[1]);
1810 if (flower
->key
.encap_eth_type
[1]) {
1811 nl_msg_put_be16(request
, TCA_FLOWER_KEY_CVLAN_ETH_TYPE
,
1812 flower
->key
.encap_eth_type
[1]);
1817 nl_msg_put_u32(request
, TCA_FLOWER_FLAGS
, tc_get_tc_cls_policy(tc_policy
));
1819 if (flower
->tunnel
) {
1820 nl_msg_put_flower_tunnel(request
, flower
);
1827 tc_replace_flower(int ifindex
, uint16_t prio
, uint32_t handle
,
1828 struct tc_flower
*flower
, uint32_t block_id
)
1830 struct ofpbuf request
;
1831 struct tcmsg
*tcmsg
;
1832 struct ofpbuf
*reply
;
1834 size_t basic_offset
;
1835 uint16_t eth_type
= (OVS_FORCE
uint16_t) flower
->key
.eth_type
;
1838 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1839 tcmsg
= tc_make_request(index
, RTM_NEWTFILTER
, NLM_F_CREATE
| NLM_F_ECHO
,
1841 tcmsg
->tcm_parent
= block_id
? : TC_INGRESS_PARENT
;
1842 tcmsg
->tcm_info
= tc_make_handle(prio
, eth_type
);
1843 tcmsg
->tcm_handle
= handle
;
1845 nl_msg_put_string(&request
, TCA_KIND
, "flower");
1846 basic_offset
= nl_msg_start_nested(&request
, TCA_OPTIONS
);
1848 error
= nl_msg_put_flower_options(&request
, flower
);
1851 ofpbuf_uninit(&request
);
1855 nl_msg_end_nested(&request
, basic_offset
);
1857 error
= tc_transact(&request
, &reply
);
1860 ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
1862 flower
->prio
= tc_get_major(tc
->tcm_info
);
1863 flower
->handle
= tc
->tcm_handle
;
1864 ofpbuf_delete(reply
);
1871 tc_set_policy(const char *policy
)
1877 if (!strcmp(policy
, "skip_sw")) {
1878 tc_policy
= TC_POLICY_SKIP_SW
;
1879 } else if (!strcmp(policy
, "skip_hw")) {
1880 tc_policy
= TC_POLICY_SKIP_HW
;
1881 } else if (!strcmp(policy
, "none")) {
1882 tc_policy
= TC_POLICY_NONE
;
1884 VLOG_WARN("tc: Invalid policy '%s'", policy
);
1888 VLOG_INFO("tc: Using policy '%s'", policy
);