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
]);
406 flower
->mask
.vlan_id
[0] = 0xffff;
408 if (attrs
[TCA_FLOWER_KEY_VLAN_PRIO
]) {
409 flower
->key
.vlan_prio
[0] =
410 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_VLAN_PRIO
]);
411 flower
->mask
.vlan_prio
[0] = 0xff;
414 if (!attrs
[TCA_FLOWER_KEY_VLAN_ETH_TYPE
]) {
418 encap_ethtype
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_VLAN_ETH_TYPE
]);
419 if (!eth_type_vlan(encap_ethtype
)) {
423 flower
->key
.encap_eth_type
[1] = flower
->key
.encap_eth_type
[0];
424 flower
->key
.encap_eth_type
[0] = encap_ethtype
;
426 if (attrs
[TCA_FLOWER_KEY_CVLAN_ID
]) {
427 flower
->key
.vlan_id
[1] =
428 nl_attr_get_u16(attrs
[TCA_FLOWER_KEY_CVLAN_ID
]);
429 flower
->mask
.vlan_id
[1] = 0xffff;
431 if (attrs
[TCA_FLOWER_KEY_CVLAN_PRIO
]) {
432 flower
->key
.vlan_prio
[1] =
433 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_CVLAN_PRIO
]);
434 flower
->mask
.vlan_prio
[1] = 0xff;
439 nl_parse_flower_tunnel(struct nlattr
**attrs
, struct tc_flower
*flower
)
441 if (attrs
[TCA_FLOWER_KEY_ENC_KEY_ID
]) {
442 ovs_be32 id
= nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_KEY_ID
]);
444 flower
->key
.tunnel
.id
= be32_to_be64(id
);
446 if (attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
]) {
447 flower
->key
.tunnel
.ipv4
.ipv4_src
=
448 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC
]);
450 if (attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
]) {
451 flower
->key
.tunnel
.ipv4
.ipv4_dst
=
452 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST
]);
454 if (attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
]) {
455 flower
->key
.tunnel
.ipv6
.ipv6_src
=
456 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC
]);
458 if (attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
]) {
459 flower
->key
.tunnel
.ipv6
.ipv6_dst
=
460 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST
]);
462 if (attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]) {
463 flower
->key
.tunnel
.tp_dst
=
464 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]);
466 if (attrs
[TCA_FLOWER_KEY_ENC_IP_TOS_MASK
]) {
467 flower
->key
.tunnel
.tos
=
468 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TOS
]);
469 flower
->mask
.tunnel
.tos
=
470 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TOS_MASK
]);
472 if (attrs
[TCA_FLOWER_KEY_ENC_IP_TTL_MASK
]) {
473 flower
->key
.tunnel
.ttl
=
474 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TTL
]);
475 flower
->mask
.tunnel
.ttl
=
476 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_ENC_IP_TTL_MASK
]);
481 nl_parse_flower_ip(struct nlattr
**attrs
, struct tc_flower
*flower
) {
482 uint8_t ip_proto
= 0;
483 struct tc_flower_key
*key
= &flower
->key
;
484 struct tc_flower_key
*mask
= &flower
->mask
;
486 if (attrs
[TCA_FLOWER_KEY_IP_PROTO
]) {
487 ip_proto
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_PROTO
]);
488 key
->ip_proto
= ip_proto
;
489 mask
->ip_proto
= UINT8_MAX
;
492 if (attrs
[TCA_FLOWER_KEY_FLAGS_MASK
]) {
493 key
->flags
= ntohl(nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_FLAGS
]));
495 ntohl(nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_FLAGS_MASK
]));
498 if (attrs
[TCA_FLOWER_KEY_IPV4_SRC_MASK
]) {
500 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_SRC
]);
501 mask
->ipv4
.ipv4_src
=
502 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_SRC_MASK
]);
504 if (attrs
[TCA_FLOWER_KEY_IPV4_DST_MASK
]) {
506 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_DST
]);
507 mask
->ipv4
.ipv4_dst
=
508 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_DST_MASK
]);
510 if (attrs
[TCA_FLOWER_KEY_IPV6_SRC_MASK
]) {
511 struct nlattr
*attr
= attrs
[TCA_FLOWER_KEY_IPV6_SRC
];
512 struct nlattr
*attr_mask
= attrs
[TCA_FLOWER_KEY_IPV6_SRC_MASK
];
514 key
->ipv6
.ipv6_src
= nl_attr_get_in6_addr(attr
);
515 mask
->ipv6
.ipv6_src
= nl_attr_get_in6_addr(attr_mask
);
517 if (attrs
[TCA_FLOWER_KEY_IPV6_DST_MASK
]) {
518 struct nlattr
*attr
= attrs
[TCA_FLOWER_KEY_IPV6_DST
];
519 struct nlattr
*attr_mask
= attrs
[TCA_FLOWER_KEY_IPV6_DST_MASK
];
521 key
->ipv6
.ipv6_dst
= nl_attr_get_in6_addr(attr
);
522 mask
->ipv6
.ipv6_dst
= nl_attr_get_in6_addr(attr_mask
);
525 if (ip_proto
== IPPROTO_TCP
) {
526 if (attrs
[TCA_FLOWER_KEY_TCP_SRC_MASK
]) {
528 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_SRC
]);
530 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_SRC_MASK
]);
532 if (attrs
[TCA_FLOWER_KEY_TCP_DST_MASK
]) {
534 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_DST
]);
536 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_DST_MASK
]);
538 if (attrs
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]) {
540 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_FLAGS
]);
542 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]);
544 } else if (ip_proto
== IPPROTO_UDP
) {
545 if (attrs
[TCA_FLOWER_KEY_UDP_SRC_MASK
]) {
546 key
->udp_src
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_SRC
]);
548 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_SRC_MASK
]);
550 if (attrs
[TCA_FLOWER_KEY_UDP_DST_MASK
]) {
551 key
->udp_dst
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_DST
]);
553 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_DST_MASK
]);
555 } else if (ip_proto
== IPPROTO_SCTP
) {
556 if (attrs
[TCA_FLOWER_KEY_SCTP_SRC_MASK
]) {
557 key
->sctp_src
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_SRC
]);
559 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_SRC_MASK
]);
561 if (attrs
[TCA_FLOWER_KEY_SCTP_DST_MASK
]) {
562 key
->sctp_dst
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_DST
]);
564 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_DST_MASK
]);
568 if (attrs
[TCA_FLOWER_KEY_IP_TTL_MASK
]) {
569 key
->ip_ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TTL
]);
570 mask
->ip_ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TTL_MASK
]);
573 if (attrs
[TCA_FLOWER_KEY_IP_TOS_MASK
]) {
574 key
->ip_tos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TOS
]);
575 mask
->ip_tos
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TOS_MASK
]);
579 static enum tc_offloaded_state
580 nl_get_flower_offloaded_state(struct nlattr
**attrs
)
582 uint32_t flower_flags
= 0;
584 if (attrs
[TCA_FLOWER_FLAGS
]) {
585 flower_flags
= nl_attr_get_u32(attrs
[TCA_FLOWER_FLAGS
]);
586 if (flower_flags
& TCA_CLS_FLAGS_NOT_IN_HW
) {
587 return TC_OFFLOADED_STATE_NOT_IN_HW
;
588 } else if (flower_flags
& TCA_CLS_FLAGS_IN_HW
) {
589 return TC_OFFLOADED_STATE_IN_HW
;
592 return TC_OFFLOADED_STATE_UNDEFINED
;
596 nl_parse_flower_flags(struct nlattr
**attrs
, struct tc_flower
*flower
)
598 flower
->offloaded_state
= nl_get_flower_offloaded_state(attrs
);
601 static const struct nl_policy pedit_policy
[] = {
602 [TCA_PEDIT_PARMS_EX
] = { .type
= NL_A_UNSPEC
,
603 .min_len
= sizeof(struct tc_pedit
),
604 .optional
= false, },
605 [TCA_PEDIT_KEYS_EX
] = { .type
= NL_A_NESTED
,
606 .optional
= false, },
610 nl_parse_act_pedit(struct nlattr
*options
, struct tc_flower
*flower
)
612 struct tc_action
*action
;
613 struct nlattr
*pe_attrs
[ARRAY_SIZE(pedit_policy
)];
614 const struct tc_pedit
*pe
;
615 const struct tc_pedit_key
*keys
;
616 const struct nlattr
*nla
, *keys_ex
, *ex_type
;
617 const void *keys_attr
;
618 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
619 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
620 size_t keys_ex_size
, left
;
621 int type
, i
= 0, err
;
623 if (!nl_parse_nested(options
, pedit_policy
, pe_attrs
,
624 ARRAY_SIZE(pedit_policy
))) {
625 VLOG_ERR_RL(&error_rl
, "failed to parse pedit action options");
629 pe
= nl_attr_get_unspec(pe_attrs
[TCA_PEDIT_PARMS_EX
], sizeof *pe
);
631 keys_attr
= pe_attrs
[TCA_PEDIT_KEYS_EX
];
632 keys_ex
= nl_attr_get(keys_attr
);
633 keys_ex_size
= nl_attr_get_size(keys_attr
);
635 NL_ATTR_FOR_EACH (nla
, left
, keys_ex
, keys_ex_size
) {
636 if (i
>= pe
->nkeys
) {
640 if (nl_attr_type(nla
) != TCA_PEDIT_KEY_EX
) {
641 VLOG_ERR_RL(&error_rl
, "unable to parse legacy pedit type: %d",
646 ex_type
= nl_attr_find_nested(nla
, TCA_PEDIT_KEY_EX_HTYPE
);
647 type
= nl_attr_get_u16(ex_type
);
649 err
= csum_update_flag(flower
, type
);
654 for (int j
= 0; j
< ARRAY_SIZE(flower_pedit_map
); j
++) {
655 struct flower_key_to_pedit
*m
= &flower_pedit_map
[j
];
656 int flower_off
= m
->flower_offset
;
660 if (m
->htype
!= type
) {
664 /* check overlap between current pedit key, which is always
665 * 4 bytes (range [off, off + 3]), and a map entry in
666 * flower_pedit_map (range [mf, mf + sz - 1]) */
667 if ((keys
->off
>= mf
&& keys
->off
< mf
+ sz
)
668 || (keys
->off
+ 3 >= mf
&& keys
->off
+ 3 < mf
+ sz
)) {
669 int diff
= flower_off
+ (keys
->off
- mf
);
670 uint32_t *dst
= (void *) (rewrite_key
+ diff
);
671 uint32_t *dst_m
= (void *) (rewrite_mask
+ diff
);
672 uint32_t mask
= ~(keys
->mask
);
675 if (keys
->off
< mf
) {
676 zero_bits
= 8 * (mf
- keys
->off
);
677 mask
&= UINT32_MAX
<< zero_bits
;
678 } else if (keys
->off
+ 4 > mf
+ m
->size
) {
679 zero_bits
= 8 * (keys
->off
+ 4 - mf
- m
->size
);
680 mask
&= UINT32_MAX
>> zero_bits
;
684 *dst
|= keys
->val
& mask
;
692 action
= &flower
->actions
[flower
->action_count
++];
693 action
->type
= TC_ACT_PEDIT
;
698 static const struct nl_policy tunnel_key_policy
[] = {
699 [TCA_TUNNEL_KEY_PARMS
] = { .type
= NL_A_UNSPEC
,
700 .min_len
= sizeof(struct tc_tunnel_key
),
701 .optional
= false, },
702 [TCA_TUNNEL_KEY_ENC_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
703 [TCA_TUNNEL_KEY_ENC_IPV4_DST
] = { .type
= NL_A_U32
, .optional
= true, },
704 [TCA_TUNNEL_KEY_ENC_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
705 .min_len
= sizeof(struct in6_addr
),
707 [TCA_TUNNEL_KEY_ENC_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
708 .min_len
= sizeof(struct in6_addr
),
710 [TCA_TUNNEL_KEY_ENC_KEY_ID
] = { .type
= NL_A_U32
, .optional
= true, },
711 [TCA_TUNNEL_KEY_ENC_DST_PORT
] = { .type
= NL_A_U16
, .optional
= true, },
712 [TCA_TUNNEL_KEY_ENC_TOS
] = { .type
= NL_A_U8
, .optional
= true, },
713 [TCA_TUNNEL_KEY_ENC_TTL
] = { .type
= NL_A_U8
, .optional
= true, },
717 nl_parse_act_tunnel_key(struct nlattr
*options
, struct tc_flower
*flower
)
719 struct nlattr
*tun_attrs
[ARRAY_SIZE(tunnel_key_policy
)];
720 const struct nlattr
*tun_parms
;
721 const struct tc_tunnel_key
*tun
;
722 struct tc_action
*action
;
724 if (!nl_parse_nested(options
, tunnel_key_policy
, tun_attrs
,
725 ARRAY_SIZE(tunnel_key_policy
))) {
726 VLOG_ERR_RL(&error_rl
, "failed to parse tunnel_key action options");
730 tun_parms
= tun_attrs
[TCA_TUNNEL_KEY_PARMS
];
731 tun
= nl_attr_get_unspec(tun_parms
, sizeof *tun
);
732 if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_SET
) {
733 struct nlattr
*id
= tun_attrs
[TCA_TUNNEL_KEY_ENC_KEY_ID
];
734 struct nlattr
*dst_port
= tun_attrs
[TCA_TUNNEL_KEY_ENC_DST_PORT
];
735 struct nlattr
*ipv4_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_SRC
];
736 struct nlattr
*ipv4_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_DST
];
737 struct nlattr
*ipv6_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_SRC
];
738 struct nlattr
*ipv6_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_DST
];
739 struct nlattr
*tos
= tun_attrs
[TCA_TUNNEL_KEY_ENC_TOS
];
740 struct nlattr
*ttl
= tun_attrs
[TCA_TUNNEL_KEY_ENC_TTL
];
742 action
= &flower
->actions
[flower
->action_count
++];
743 action
->type
= TC_ACT_ENCAP
;
744 action
->encap
.ipv4
.ipv4_src
= ipv4_src
? nl_attr_get_be32(ipv4_src
) : 0;
745 action
->encap
.ipv4
.ipv4_dst
= ipv4_dst
? nl_attr_get_be32(ipv4_dst
) : 0;
747 action
->encap
.ipv6
.ipv6_src
= nl_attr_get_in6_addr(ipv6_src
);
750 action
->encap
.ipv6
.ipv6_dst
= nl_attr_get_in6_addr(ipv6_dst
);
752 action
->encap
.id
= id
? be32_to_be64(nl_attr_get_be32(id
)) : 0;
753 action
->encap
.tp_dst
= dst_port
? nl_attr_get_be16(dst_port
) : 0;
754 action
->encap
.tos
= tos
? nl_attr_get_u8(tos
) : 0;
755 action
->encap
.ttl
= ttl
? nl_attr_get_u8(ttl
) : 0;
756 } else if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_RELEASE
) {
757 flower
->tunnel
= true;
759 VLOG_ERR_RL(&error_rl
, "unknown tunnel actions: %d, %d",
760 tun
->action
, tun
->t_action
);
766 static const struct nl_policy gact_policy
[] = {
767 [TCA_GACT_PARMS
] = { .type
= NL_A_UNSPEC
,
768 .min_len
= sizeof(struct tc_gact
),
769 .optional
= false, },
770 [TCA_GACT_TM
] = { .type
= NL_A_UNSPEC
,
771 .min_len
= sizeof(struct tcf_t
),
772 .optional
= false, },
778 static struct ovsthread_once once
= OVSTHREAD_ONCE_INITIALIZER
;
779 static int user_hz
= 100;
781 if (ovsthread_once_start(&once
)) {
782 user_hz
= sysconf(_SC_CLK_TCK
);
783 ovsthread_once_done(&once
);
790 nl_parse_tcf(const struct tcf_t
*tm
, struct tc_flower
*flower
)
792 flower
->lastused
= time_msec() - (tm
->lastuse
* 1000 / get_user_hz());
796 nl_parse_act_drop(struct nlattr
*options
, struct tc_flower
*flower
)
798 struct nlattr
*gact_attrs
[ARRAY_SIZE(gact_policy
)];
799 const struct tc_gact
*p
;
800 struct nlattr
*gact_parms
;
801 const struct tcf_t
*tm
;
803 if (!nl_parse_nested(options
, gact_policy
, gact_attrs
,
804 ARRAY_SIZE(gact_policy
))) {
805 VLOG_ERR_RL(&error_rl
, "failed to parse gact action options");
809 gact_parms
= gact_attrs
[TCA_GACT_PARMS
];
810 p
= nl_attr_get_unspec(gact_parms
, sizeof *p
);
812 if (p
->action
!= TC_ACT_SHOT
) {
813 VLOG_ERR_RL(&error_rl
, "unknown gact action: %d", p
->action
);
817 tm
= nl_attr_get_unspec(gact_attrs
[TCA_GACT_TM
], sizeof *tm
);
818 nl_parse_tcf(tm
, flower
);
823 static const struct nl_policy mirred_policy
[] = {
824 [TCA_MIRRED_PARMS
] = { .type
= NL_A_UNSPEC
,
825 .min_len
= sizeof(struct tc_mirred
),
826 .optional
= false, },
827 [TCA_MIRRED_TM
] = { .type
= NL_A_UNSPEC
,
828 .min_len
= sizeof(struct tcf_t
),
829 .optional
= false, },
833 nl_parse_act_mirred(struct nlattr
*options
, struct tc_flower
*flower
)
836 struct nlattr
*mirred_attrs
[ARRAY_SIZE(mirred_policy
)];
837 const struct tc_mirred
*m
;
838 const struct nlattr
*mirred_parms
;
839 const struct tcf_t
*tm
;
840 struct nlattr
*mirred_tm
;
841 struct tc_action
*action
;
843 if (!nl_parse_nested(options
, mirred_policy
, mirred_attrs
,
844 ARRAY_SIZE(mirred_policy
))) {
845 VLOG_ERR_RL(&error_rl
, "failed to parse mirred action options");
849 mirred_parms
= mirred_attrs
[TCA_MIRRED_PARMS
];
850 m
= nl_attr_get_unspec(mirred_parms
, sizeof *m
);
852 if (m
->eaction
!= TCA_EGRESS_REDIR
&& m
->eaction
!= TCA_EGRESS_MIRROR
) {
853 VLOG_ERR_RL(&error_rl
, "unknown mirred action: %d, %d, %d",
854 m
->action
, m
->eaction
, m
->ifindex
);
858 action
= &flower
->actions
[flower
->action_count
++];
859 action
->ifindex_out
= m
->ifindex
;
860 action
->type
= TC_ACT_OUTPUT
;
862 mirred_tm
= mirred_attrs
[TCA_MIRRED_TM
];
863 tm
= nl_attr_get_unspec(mirred_tm
, sizeof *tm
);
864 nl_parse_tcf(tm
, flower
);
869 static const struct nl_policy vlan_policy
[] = {
870 [TCA_VLAN_PARMS
] = { .type
= NL_A_UNSPEC
,
871 .min_len
= sizeof(struct tc_vlan
),
872 .optional
= false, },
873 [TCA_VLAN_PUSH_VLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
874 [TCA_VLAN_PUSH_VLAN_PROTOCOL
] = { .type
= NL_A_U16
, .optional
= true, },
875 [TCA_VLAN_PUSH_VLAN_PRIORITY
] = { .type
= NL_A_U8
, .optional
= true, },
879 nl_parse_act_vlan(struct nlattr
*options
, struct tc_flower
*flower
)
881 struct nlattr
*vlan_attrs
[ARRAY_SIZE(vlan_policy
)];
882 const struct tc_vlan
*v
;
883 const struct nlattr
*vlan_parms
;
884 struct tc_action
*action
;
886 if (!nl_parse_nested(options
, vlan_policy
, vlan_attrs
,
887 ARRAY_SIZE(vlan_policy
))) {
888 VLOG_ERR_RL(&error_rl
, "failed to parse vlan action options");
892 action
= &flower
->actions
[flower
->action_count
++];
893 vlan_parms
= vlan_attrs
[TCA_VLAN_PARMS
];
894 v
= nl_attr_get_unspec(vlan_parms
, sizeof *v
);
895 if (v
->v_action
== TCA_VLAN_ACT_PUSH
) {
896 struct nlattr
*vlan_tpid
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PROTOCOL
];
897 struct nlattr
*vlan_id
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_ID
];
898 struct nlattr
*vlan_prio
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PRIORITY
];
900 action
->vlan
.vlan_push_tpid
= nl_attr_get_be16(vlan_tpid
);
901 action
->vlan
.vlan_push_id
= nl_attr_get_u16(vlan_id
);
902 action
->vlan
.vlan_push_prio
= vlan_prio
? nl_attr_get_u8(vlan_prio
) : 0;
903 action
->type
= TC_ACT_VLAN_PUSH
;
904 } else if (v
->v_action
== TCA_VLAN_ACT_POP
) {
905 action
->type
= TC_ACT_VLAN_POP
;
907 VLOG_ERR_RL(&error_rl
, "unknown vlan action: %d, %d",
908 v
->action
, v
->v_action
);
914 static const struct nl_policy csum_policy
[] = {
915 [TCA_CSUM_PARMS
] = { .type
= NL_A_UNSPEC
,
916 .min_len
= sizeof(struct tc_csum
),
917 .optional
= false, },
921 nl_parse_act_csum(struct nlattr
*options
, struct tc_flower
*flower
)
923 struct nlattr
*csum_attrs
[ARRAY_SIZE(csum_policy
)];
924 const struct tc_csum
*c
;
925 const struct nlattr
*csum_parms
;
927 if (!nl_parse_nested(options
, csum_policy
, csum_attrs
,
928 ARRAY_SIZE(csum_policy
))) {
929 VLOG_ERR_RL(&error_rl
, "failed to parse csum action options");
933 csum_parms
= csum_attrs
[TCA_CSUM_PARMS
];
934 c
= nl_attr_get_unspec(csum_parms
, sizeof *c
);
937 if (c
->update_flags
!= flower
->csum_update_flags
) {
938 VLOG_WARN_RL(&error_rl
,
939 "expected different act csum flags: 0x%x != 0x%x",
940 flower
->csum_update_flags
, c
->update_flags
);
943 flower
->csum_update_flags
= 0; /* so we know csum was handled */
945 if (flower
->needs_full_ip_proto_mask
946 && flower
->mask
.ip_proto
!= UINT8_MAX
) {
947 VLOG_WARN_RL(&error_rl
, "expected full matching on flower ip_proto");
954 static const struct nl_policy act_policy
[] = {
955 [TCA_ACT_KIND
] = { .type
= NL_A_STRING
, .optional
= false, },
956 [TCA_ACT_COOKIE
] = { .type
= NL_A_UNSPEC
, .optional
= true, },
957 [TCA_ACT_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= false, },
958 [TCA_ACT_STATS
] = { .type
= NL_A_NESTED
, .optional
= false, },
961 static const struct nl_policy stats_policy
[] = {
962 [TCA_STATS_BASIC
] = { .type
= NL_A_UNSPEC
,
963 .min_len
= sizeof(struct gnet_stats_basic
),
964 .optional
= false, },
968 nl_parse_single_action(struct nlattr
*action
, struct tc_flower
*flower
)
970 struct nlattr
*act_options
;
971 struct nlattr
*act_stats
;
972 struct nlattr
*act_cookie
;
973 const char *act_kind
;
974 struct nlattr
*action_attrs
[ARRAY_SIZE(act_policy
)];
975 struct nlattr
*stats_attrs
[ARRAY_SIZE(stats_policy
)];
976 struct ovs_flow_stats
*stats
= &flower
->stats
;
977 const struct gnet_stats_basic
*bs
;
980 if (!nl_parse_nested(action
, act_policy
, action_attrs
,
981 ARRAY_SIZE(act_policy
))) {
982 VLOG_ERR_RL(&error_rl
, "failed to parse single action options");
986 act_kind
= nl_attr_get_string(action_attrs
[TCA_ACT_KIND
]);
987 act_options
= action_attrs
[TCA_ACT_OPTIONS
];
988 act_cookie
= action_attrs
[TCA_ACT_COOKIE
];
990 if (!strcmp(act_kind
, "gact")) {
991 err
= nl_parse_act_drop(act_options
, flower
);
992 } else if (!strcmp(act_kind
, "mirred")) {
993 err
= nl_parse_act_mirred(act_options
, flower
);
994 } else if (!strcmp(act_kind
, "vlan")) {
995 err
= nl_parse_act_vlan(act_options
, flower
);
996 } else if (!strcmp(act_kind
, "tunnel_key")) {
997 err
= nl_parse_act_tunnel_key(act_options
, flower
);
998 } else if (!strcmp(act_kind
, "pedit")) {
999 err
= nl_parse_act_pedit(act_options
, flower
);
1000 } else if (!strcmp(act_kind
, "csum")) {
1001 nl_parse_act_csum(act_options
, flower
);
1003 VLOG_ERR_RL(&error_rl
, "unknown tc action kind: %s", act_kind
);
1012 flower
->act_cookie
.data
= nl_attr_get(act_cookie
);
1013 flower
->act_cookie
.len
= nl_attr_get_size(act_cookie
);
1016 act_stats
= action_attrs
[TCA_ACT_STATS
];
1018 if (!nl_parse_nested(act_stats
, stats_policy
, stats_attrs
,
1019 ARRAY_SIZE(stats_policy
))) {
1020 VLOG_ERR_RL(&error_rl
, "failed to parse action stats policy");
1024 bs
= nl_attr_get_unspec(stats_attrs
[TCA_STATS_BASIC
], sizeof *bs
);
1025 put_32aligned_u64(&stats
->n_packets
, bs
->packets
);
1026 put_32aligned_u64(&stats
->n_bytes
, bs
->bytes
);
1031 #define TCA_ACT_MIN_PRIO 1
1034 nl_parse_flower_actions(struct nlattr
**attrs
, struct tc_flower
*flower
)
1036 const struct nlattr
*actions
= attrs
[TCA_FLOWER_ACT
];
1037 static struct nl_policy actions_orders_policy
[TCA_ACT_MAX_PRIO
+ 1] = {};
1038 struct nlattr
*actions_orders
[ARRAY_SIZE(actions_orders_policy
)];
1039 const int max_size
= ARRAY_SIZE(actions_orders_policy
);
1041 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
1042 actions_orders_policy
[i
].type
= NL_A_NESTED
;
1043 actions_orders_policy
[i
].optional
= true;
1046 if (!nl_parse_nested(actions
, actions_orders_policy
, actions_orders
,
1047 ARRAY_SIZE(actions_orders_policy
))) {
1048 VLOG_ERR_RL(&error_rl
, "failed to parse flower order of actions");
1052 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
1053 if (actions_orders
[i
]) {
1056 if (flower
->action_count
>= TCA_ACT_MAX_PRIO
) {
1057 VLOG_DBG_RL(&error_rl
, "Can only support %d actions", flower
->action_count
);
1060 err
= nl_parse_single_action(actions_orders
[i
], flower
);
1068 if (flower
->csum_update_flags
) {
1069 VLOG_WARN_RL(&error_rl
,
1070 "expected act csum with flags: 0x%x",
1071 flower
->csum_update_flags
);
1079 nl_parse_flower_options(struct nlattr
*nl_options
, struct tc_flower
*flower
)
1081 struct nlattr
*attrs
[ARRAY_SIZE(tca_flower_policy
)];
1083 if (!nl_parse_nested(nl_options
, tca_flower_policy
,
1084 attrs
, ARRAY_SIZE(tca_flower_policy
))) {
1085 VLOG_ERR_RL(&error_rl
, "failed to parse flower classifier options");
1089 nl_parse_flower_eth(attrs
, flower
);
1090 nl_parse_flower_mpls(attrs
, flower
);
1091 nl_parse_flower_vlan(attrs
, flower
);
1092 nl_parse_flower_ip(attrs
, flower
);
1093 nl_parse_flower_tunnel(attrs
, flower
);
1094 nl_parse_flower_flags(attrs
, flower
);
1095 return nl_parse_flower_actions(attrs
, flower
);
1099 parse_netlink_to_tc_flower(struct ofpbuf
*reply
, struct tc_flower
*flower
)
1102 struct nlattr
*ta
[ARRAY_SIZE(tca_policy
)];
1105 if (NLMSG_HDRLEN
+ sizeof *tc
> reply
->size
) {
1109 memset(flower
, 0, sizeof *flower
);
1111 tc
= ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
1112 flower
->handle
= tc
->tcm_handle
;
1113 flower
->key
.eth_type
= (OVS_FORCE ovs_be16
) tc_get_minor(tc
->tcm_info
);
1114 flower
->mask
.eth_type
= OVS_BE16_MAX
;
1115 flower
->prio
= tc_get_major(tc
->tcm_info
);
1117 if (!flower
->handle
) {
1121 if (!nl_policy_parse(reply
, NLMSG_HDRLEN
+ sizeof *tc
,
1122 tca_policy
, ta
, ARRAY_SIZE(ta
))) {
1123 VLOG_ERR_RL(&error_rl
, "failed to parse tca policy");
1127 kind
= nl_attr_get_string(ta
[TCA_KIND
]);
1128 if (strcmp(kind
, "flower")) {
1129 VLOG_DBG_ONCE("Unsupported filter: %s", kind
);
1133 return nl_parse_flower_options(ta
[TCA_OPTIONS
], flower
);
1137 tc_dump_flower_start(int ifindex
, struct nl_dump
*dump
, uint32_t block_id
)
1139 struct ofpbuf request
;
1140 struct tcmsg
*tcmsg
;
1143 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1144 tcmsg
= tc_make_request(index
, RTM_GETTFILTER
, NLM_F_DUMP
, &request
);
1145 tcmsg
->tcm_parent
= block_id
? : TC_INGRESS_PARENT
;
1146 tcmsg
->tcm_info
= TC_H_UNSPEC
;
1147 tcmsg
->tcm_handle
= 0;
1149 nl_dump_start(dump
, NETLINK_ROUTE
, &request
);
1150 ofpbuf_uninit(&request
);
1156 tc_flush(int ifindex
, uint32_t block_id
)
1158 struct ofpbuf request
;
1159 struct tcmsg
*tcmsg
;
1162 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1163 tcmsg
= tc_make_request(index
, RTM_DELTFILTER
, NLM_F_ACK
, &request
);
1164 tcmsg
->tcm_parent
= block_id
? : TC_INGRESS_PARENT
;
1165 tcmsg
->tcm_info
= TC_H_UNSPEC
;
1167 return tc_transact(&request
, NULL
);
1171 tc_del_filter(int ifindex
, int prio
, int handle
, uint32_t block_id
)
1173 struct ofpbuf request
;
1174 struct tcmsg
*tcmsg
;
1175 struct ofpbuf
*reply
;
1179 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1180 tcmsg
= tc_make_request(index
, RTM_DELTFILTER
, NLM_F_ECHO
, &request
);
1181 tcmsg
->tcm_parent
= block_id
? : TC_INGRESS_PARENT
;
1182 tcmsg
->tcm_info
= tc_make_handle(prio
, 0);
1183 tcmsg
->tcm_handle
= handle
;
1185 error
= tc_transact(&request
, &reply
);
1187 ofpbuf_delete(reply
);
1193 tc_get_flower(int ifindex
, int prio
, int handle
, struct tc_flower
*flower
,
1196 struct ofpbuf request
;
1197 struct tcmsg
*tcmsg
;
1198 struct ofpbuf
*reply
;
1202 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1203 tcmsg
= tc_make_request(index
, RTM_GETTFILTER
, NLM_F_ECHO
, &request
);
1204 tcmsg
->tcm_parent
= block_id
? : TC_INGRESS_PARENT
;
1205 tcmsg
->tcm_info
= tc_make_handle(prio
, 0);
1206 tcmsg
->tcm_handle
= handle
;
1208 error
= tc_transact(&request
, &reply
);
1213 error
= parse_netlink_to_tc_flower(reply
, flower
);
1214 ofpbuf_delete(reply
);
1219 tc_get_tc_cls_policy(enum tc_offload_policy policy
)
1221 if (policy
== TC_POLICY_SKIP_HW
) {
1222 return TCA_CLS_FLAGS_SKIP_HW
;
1223 } else if (policy
== TC_POLICY_SKIP_SW
) {
1224 return TCA_CLS_FLAGS_SKIP_SW
;
1231 nl_msg_put_act_csum(struct ofpbuf
*request
, uint32_t flags
)
1235 nl_msg_put_string(request
, TCA_ACT_KIND
, "csum");
1236 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1238 struct tc_csum parm
= { .action
= TC_ACT_PIPE
,
1239 .update_flags
= flags
};
1241 nl_msg_put_unspec(request
, TCA_CSUM_PARMS
, &parm
, sizeof parm
);
1243 nl_msg_end_nested(request
, offset
);
1247 nl_msg_put_act_pedit(struct ofpbuf
*request
, struct tc_pedit
*parm
,
1248 struct tc_pedit_key_ex
*ex
)
1250 size_t ksize
= sizeof *parm
+ parm
->nkeys
* sizeof(struct tc_pedit_key
);
1251 size_t offset
, offset_keys_ex
, offset_key
;
1254 nl_msg_put_string(request
, TCA_ACT_KIND
, "pedit");
1255 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1257 parm
->action
= TC_ACT_PIPE
;
1259 nl_msg_put_unspec(request
, TCA_PEDIT_PARMS_EX
, parm
, ksize
);
1260 offset_keys_ex
= nl_msg_start_nested(request
, TCA_PEDIT_KEYS_EX
);
1261 for (i
= 0; i
< parm
->nkeys
; i
++, ex
++) {
1262 offset_key
= nl_msg_start_nested(request
, TCA_PEDIT_KEY_EX
);
1263 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_HTYPE
, ex
->htype
);
1264 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_CMD
, ex
->cmd
);
1265 nl_msg_end_nested(request
, offset_key
);
1267 nl_msg_end_nested(request
, offset_keys_ex
);
1269 nl_msg_end_nested(request
, offset
);
1273 nl_msg_put_act_push_vlan(struct ofpbuf
*request
, ovs_be16 tpid
,
1274 uint16_t vid
, uint8_t prio
)
1278 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1279 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1281 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1282 .v_action
= TCA_VLAN_ACT_PUSH
};
1284 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1285 nl_msg_put_be16(request
, TCA_VLAN_PUSH_VLAN_PROTOCOL
, tpid
);
1286 nl_msg_put_u16(request
, TCA_VLAN_PUSH_VLAN_ID
, vid
);
1287 nl_msg_put_u8(request
, TCA_VLAN_PUSH_VLAN_PRIORITY
, prio
);
1289 nl_msg_end_nested(request
, offset
);
1293 nl_msg_put_act_pop_vlan(struct ofpbuf
*request
)
1297 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1298 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1300 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1301 .v_action
= TCA_VLAN_ACT_POP
};
1303 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1305 nl_msg_end_nested(request
, offset
);
1309 nl_msg_put_act_tunnel_key_release(struct ofpbuf
*request
)
1313 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
1314 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1316 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
1317 .t_action
= TCA_TUNNEL_KEY_ACT_RELEASE
};
1319 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
1321 nl_msg_end_nested(request
, offset
);
1325 nl_msg_put_act_tunnel_key_set(struct ofpbuf
*request
, ovs_be64 id
,
1326 ovs_be32 ipv4_src
, ovs_be32 ipv4_dst
,
1327 struct in6_addr
*ipv6_src
,
1328 struct in6_addr
*ipv6_dst
,
1330 uint8_t tos
, uint8_t ttl
)
1334 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
1335 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1337 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
1338 .t_action
= TCA_TUNNEL_KEY_ACT_SET
};
1340 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
1342 ovs_be32 id32
= be64_to_be32(id
);
1343 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_KEY_ID
, id32
);
1345 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_SRC
, ipv4_src
);
1346 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_DST
, ipv4_dst
);
1347 } else if (!is_all_zeros(ipv6_dst
, sizeof *ipv6_dst
)) {
1348 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_DST
,
1350 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_SRC
,
1354 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_TOS
, tos
);
1357 nl_msg_put_u8(request
, TCA_TUNNEL_KEY_ENC_TTL
, ttl
);
1359 nl_msg_put_be16(request
, TCA_TUNNEL_KEY_ENC_DST_PORT
, tp_dst
);
1361 nl_msg_end_nested(request
, offset
);
1365 nl_msg_put_act_drop(struct ofpbuf
*request
)
1369 nl_msg_put_string(request
, TCA_ACT_KIND
, "gact");
1370 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1372 struct tc_gact p
= { .action
= TC_ACT_SHOT
};
1374 nl_msg_put_unspec(request
, TCA_GACT_PARMS
, &p
, sizeof p
);
1376 nl_msg_end_nested(request
, offset
);
1380 nl_msg_put_act_mirred(struct ofpbuf
*request
, int ifindex
, int action
,
1385 nl_msg_put_string(request
, TCA_ACT_KIND
, "mirred");
1386 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1388 struct tc_mirred m
= { .action
= action
,
1390 .ifindex
= ifindex
};
1392 nl_msg_put_unspec(request
, TCA_MIRRED_PARMS
, &m
, sizeof m
);
1394 nl_msg_end_nested(request
, offset
);
1398 nl_msg_put_act_cookie(struct ofpbuf
*request
, struct tc_cookie
*ck
) {
1400 nl_msg_put_unspec(request
, TCA_ACT_COOKIE
, ck
->data
, ck
->len
);
1404 /* Given flower, a key_to_pedit map entry, calculates the rest,
1407 * mask, data - pointers of where read the first word of flower->key/mask.
1408 * current_offset - which offset to use for the first pedit action.
1409 * cnt - max pedits actions to use.
1410 * first_word_mask/last_word_mask - the mask to use for the first/last read
1411 * (as we read entire words). */
1413 calc_offsets(struct tc_flower
*flower
, struct flower_key_to_pedit
*m
,
1414 int *cur_offset
, int *cnt
, uint32_t *last_word_mask
,
1415 uint32_t *first_word_mask
, uint32_t **mask
, uint32_t **data
)
1417 int start_offset
, max_offset
, total_size
;
1418 int diff
, right_zero_bits
, left_zero_bits
;
1419 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
1420 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
1422 max_offset
= m
->offset
+ m
->size
;
1423 start_offset
= ROUND_DOWN(m
->offset
, 4);
1424 diff
= m
->offset
- start_offset
;
1425 total_size
= max_offset
- start_offset
;
1426 right_zero_bits
= 8 * (4 - (max_offset
% 4));
1427 left_zero_bits
= 8 * (m
->offset
- start_offset
);
1429 *cur_offset
= start_offset
;
1430 *cnt
= (total_size
/ 4) + (total_size
% 4 ? 1 : 0);
1431 *last_word_mask
= UINT32_MAX
>> right_zero_bits
;
1432 *first_word_mask
= UINT32_MAX
<< left_zero_bits
;
1433 *data
= (void *) (rewrite_key
+ m
->flower_offset
- diff
);
1434 *mask
= (void *) (rewrite_mask
+ m
->flower_offset
- diff
);
1438 csum_update_flag(struct tc_flower
*flower
,
1439 enum pedit_header_type htype
) {
1440 /* Explictily specifiy the csum flags so HW can return EOPNOTSUPP
1441 * if it doesn't support a checksum recalculation of some headers.
1442 * And since OVS allows a flow such as
1443 * eth(dst=<mac>),eth_type(0x0800) actions=set(ipv4(src=<new_ip>))
1444 * we need to force a more specific flow as this can, for example,
1445 * need a recalculation of icmp checksum if the packet that passes
1446 * is ICMPv6 and tcp checksum if its tcp. */
1449 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
:
1450 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_IPV4HDR
;
1452 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
:
1453 case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
:
1454 case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
:
1455 if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
1456 flower
->needs_full_ip_proto_mask
= true;
1457 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_TCP
;
1458 } else if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
1459 flower
->needs_full_ip_proto_mask
= true;
1460 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_UDP
;
1461 } else if (flower
->key
.ip_proto
== IPPROTO_ICMP
) {
1462 flower
->needs_full_ip_proto_mask
= true;
1463 } else if (flower
->key
.ip_proto
== IPPROTO_ICMPV6
) {
1464 flower
->needs_full_ip_proto_mask
= true;
1465 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_ICMP
;
1467 VLOG_WARN_RL(&error_rl
,
1468 "can't offload rewrite of IP/IPV6 with ip_proto: %d",
1469 flower
->key
.ip_proto
);
1473 case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
:
1474 return 0; /* success */
1476 case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK
:
1477 case __PEDIT_HDR_TYPE_MAX
:
1486 nl_msg_put_flower_rewrite_pedits(struct ofpbuf
*request
,
1487 struct tc_flower
*flower
)
1490 struct tc_pedit sel
;
1491 struct tc_pedit_key keys
[MAX_PEDIT_OFFSETS
];
1492 struct tc_pedit_key_ex keys_ex
[MAX_PEDIT_OFFSETS
];
1500 for (i
= 0; i
< ARRAY_SIZE(flower_pedit_map
); i
++) {
1501 struct flower_key_to_pedit
*m
= &flower_pedit_map
[i
];
1502 struct tc_pedit_key
*pedit_key
= NULL
;
1503 struct tc_pedit_key_ex
*pedit_key_ex
= NULL
;
1504 uint32_t *mask
, *data
, first_word_mask
, last_word_mask
;
1505 int cnt
= 0, cur_offset
= 0;
1511 calc_offsets(flower
, m
, &cur_offset
, &cnt
, &last_word_mask
,
1512 &first_word_mask
, &mask
, &data
);
1514 for (j
= 0; j
< cnt
; j
++, mask
++, data
++, cur_offset
+= 4) {
1515 uint32_t mask_word
= *mask
;
1518 mask_word
&= first_word_mask
;
1521 mask_word
&= last_word_mask
;
1526 if (sel
.sel
.nkeys
== MAX_PEDIT_OFFSETS
) {
1527 VLOG_WARN_RL(&error_rl
, "reached too many pedit offsets: %d",
1532 pedit_key
= &sel
.keys
[sel
.sel
.nkeys
];
1533 pedit_key_ex
= &sel
.keys_ex
[sel
.sel
.nkeys
];
1534 pedit_key_ex
->cmd
= TCA_PEDIT_KEY_EX_CMD_SET
;
1535 pedit_key_ex
->htype
= m
->htype
;
1536 pedit_key
->off
= cur_offset
;
1537 pedit_key
->mask
= ~mask_word
;
1538 pedit_key
->val
= *data
& mask_word
;
1541 err
= csum_update_flag(flower
, m
->htype
);
1546 if (flower
->needs_full_ip_proto_mask
) {
1547 flower
->mask
.ip_proto
= UINT8_MAX
;
1551 nl_msg_put_act_pedit(request
, &sel
.sel
, sel
.keys_ex
);
1557 nl_msg_put_flower_acts(struct ofpbuf
*request
, struct tc_flower
*flower
)
1561 uint16_t act_index
= 1;
1562 struct tc_action
*action
;
1565 offset
= nl_msg_start_nested(request
, TCA_FLOWER_ACT
);
1569 if (flower
->tunnel
) {
1570 act_offset
= nl_msg_start_nested(request
, act_index
++);
1571 nl_msg_put_act_tunnel_key_release(request
);
1572 nl_msg_end_nested(request
, act_offset
);
1575 action
= flower
->actions
;
1576 for (i
= 0; i
< flower
->action_count
; i
++, action
++) {
1577 switch (action
->type
) {
1578 case TC_ACT_PEDIT
: {
1579 act_offset
= nl_msg_start_nested(request
, act_index
++);
1580 error
= nl_msg_put_flower_rewrite_pedits(request
, flower
);
1584 nl_msg_end_nested(request
, act_offset
);
1586 if (flower
->csum_update_flags
) {
1587 act_offset
= nl_msg_start_nested(request
, act_index
++);
1588 nl_msg_put_act_csum(request
, flower
->csum_update_flags
);
1589 nl_msg_end_nested(request
, act_offset
);
1593 case TC_ACT_ENCAP
: {
1594 act_offset
= nl_msg_start_nested(request
, act_index
++);
1595 nl_msg_put_act_tunnel_key_set(request
, action
->encap
.id
,
1596 action
->encap
.ipv4
.ipv4_src
,
1597 action
->encap
.ipv4
.ipv4_dst
,
1598 &action
->encap
.ipv6
.ipv6_src
,
1599 &action
->encap
.ipv6
.ipv6_dst
,
1600 action
->encap
.tp_dst
,
1603 nl_msg_end_nested(request
, act_offset
);
1606 case TC_ACT_VLAN_POP
: {
1607 act_offset
= nl_msg_start_nested(request
, act_index
++);
1608 nl_msg_put_act_pop_vlan(request
);
1609 nl_msg_end_nested(request
, act_offset
);
1612 case TC_ACT_VLAN_PUSH
: {
1613 act_offset
= nl_msg_start_nested(request
, act_index
++);
1614 nl_msg_put_act_push_vlan(request
,
1615 action
->vlan
.vlan_push_tpid
,
1616 action
->vlan
.vlan_push_id
,
1617 action
->vlan
.vlan_push_prio
);
1618 nl_msg_end_nested(request
, act_offset
);
1621 case TC_ACT_OUTPUT
: {
1622 ifindex
= action
->ifindex_out
;
1624 VLOG_ERR_RL(&error_rl
, "%s: invalid ifindex: %d, type: %d",
1625 __func__
, ifindex
, action
->type
);
1628 act_offset
= nl_msg_start_nested(request
, act_index
++);
1629 if (i
== flower
->action_count
- 1) {
1630 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_STOLEN
,
1633 nl_msg_put_act_mirred(request
, ifindex
, TC_ACT_PIPE
,
1636 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
1637 nl_msg_end_nested(request
, act_offset
);
1644 act_offset
= nl_msg_start_nested(request
, act_index
++);
1645 nl_msg_put_act_drop(request
);
1646 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
1647 nl_msg_end_nested(request
, act_offset
);
1649 nl_msg_end_nested(request
, offset
);
1655 nl_msg_put_masked_value(struct ofpbuf
*request
, uint16_t type
,
1656 uint16_t mask_type
, const void *data
,
1657 const void *mask_data
, size_t len
)
1659 if (mask_type
!= TCA_FLOWER_UNSPEC
) {
1660 if (is_all_zeros(mask_data
, len
)) {
1663 nl_msg_put_unspec(request
, mask_type
, mask_data
, len
);
1665 nl_msg_put_unspec(request
, type
, data
, len
);
1669 nl_msg_put_flower_tunnel(struct ofpbuf
*request
, struct tc_flower
*flower
)
1671 ovs_be32 ipv4_src
= flower
->key
.tunnel
.ipv4
.ipv4_src
;
1672 ovs_be32 ipv4_dst
= flower
->key
.tunnel
.ipv4
.ipv4_dst
;
1673 struct in6_addr
*ipv6_src
= &flower
->key
.tunnel
.ipv6
.ipv6_src
;
1674 struct in6_addr
*ipv6_dst
= &flower
->key
.tunnel
.ipv6
.ipv6_dst
;
1675 ovs_be16 tp_dst
= flower
->key
.tunnel
.tp_dst
;
1676 ovs_be32 id
= be64_to_be32(flower
->key
.tunnel
.id
);
1677 uint8_t tos
= flower
->key
.tunnel
.tos
;
1678 uint8_t ttl
= flower
->key
.tunnel
.ttl
;
1679 uint8_t tos_mask
= flower
->mask
.tunnel
.tos
;
1680 uint8_t ttl_mask
= flower
->mask
.tunnel
.ttl
;
1683 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_SRC
, ipv4_src
);
1684 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_DST
, ipv4_dst
);
1685 } else if (!is_all_zeros(ipv6_dst
, sizeof *ipv6_dst
)) {
1686 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_SRC
, ipv6_src
);
1687 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_DST
, ipv6_dst
);
1690 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TOS
, tos
);
1691 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TOS_MASK
, tos_mask
);
1694 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TTL
, ttl
);
1695 nl_msg_put_u8(request
, TCA_FLOWER_KEY_ENC_IP_TTL_MASK
, ttl_mask
);
1697 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_UDP_DST_PORT
, tp_dst
);
1698 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_KEY_ID
, id
);
1701 #define FLOWER_PUT_MASKED_VALUE(member, type) \
1702 nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \
1703 &flower->mask.member, sizeof flower->key.member)
1706 nl_msg_put_flower_options(struct ofpbuf
*request
, struct tc_flower
*flower
)
1709 uint16_t host_eth_type
= ntohs(flower
->key
.eth_type
);
1710 bool is_vlan
= eth_type_vlan(flower
->key
.eth_type
);
1711 bool is_qinq
= is_vlan
&& eth_type_vlan(flower
->key
.encap_eth_type
[0]);
1712 bool is_mpls
= eth_type_mpls(flower
->key
.eth_type
);
1715 /* need to parse acts first as some acts require changing the matching
1716 * see csum_update_flag() */
1717 err
= nl_msg_put_flower_acts(request
, flower
);
1724 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[1]);
1726 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[0]);
1731 host_eth_type
= ntohs(flower
->key
.encap_eth_type
[0]);
1734 FLOWER_PUT_MASKED_VALUE(dst_mac
, TCA_FLOWER_KEY_ETH_DST
);
1735 FLOWER_PUT_MASKED_VALUE(src_mac
, TCA_FLOWER_KEY_ETH_SRC
);
1737 if (host_eth_type
== ETH_P_IP
|| host_eth_type
== ETH_P_IPV6
) {
1738 FLOWER_PUT_MASKED_VALUE(ip_ttl
, TCA_FLOWER_KEY_IP_TTL
);
1739 FLOWER_PUT_MASKED_VALUE(ip_tos
, TCA_FLOWER_KEY_IP_TOS
);
1741 if (flower
->mask
.ip_proto
&& flower
->key
.ip_proto
) {
1742 nl_msg_put_u8(request
, TCA_FLOWER_KEY_IP_PROTO
,
1743 flower
->key
.ip_proto
);
1746 if (flower
->mask
.flags
) {
1747 nl_msg_put_be32(request
, TCA_FLOWER_KEY_FLAGS
,
1748 htonl(flower
->key
.flags
));
1749 nl_msg_put_be32(request
, TCA_FLOWER_KEY_FLAGS_MASK
,
1750 htonl(flower
->mask
.flags
));
1753 if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
1754 FLOWER_PUT_MASKED_VALUE(udp_src
, TCA_FLOWER_KEY_UDP_SRC
);
1755 FLOWER_PUT_MASKED_VALUE(udp_dst
, TCA_FLOWER_KEY_UDP_DST
);
1756 } else if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
1757 FLOWER_PUT_MASKED_VALUE(tcp_src
, TCA_FLOWER_KEY_TCP_SRC
);
1758 FLOWER_PUT_MASKED_VALUE(tcp_dst
, TCA_FLOWER_KEY_TCP_DST
);
1759 FLOWER_PUT_MASKED_VALUE(tcp_flags
, TCA_FLOWER_KEY_TCP_FLAGS
);
1760 } else if (flower
->key
.ip_proto
== IPPROTO_SCTP
) {
1761 FLOWER_PUT_MASKED_VALUE(sctp_src
, TCA_FLOWER_KEY_SCTP_SRC
);
1762 FLOWER_PUT_MASKED_VALUE(sctp_dst
, TCA_FLOWER_KEY_SCTP_DST
);
1766 if (host_eth_type
== ETH_P_IP
) {
1767 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_src
, TCA_FLOWER_KEY_IPV4_SRC
);
1768 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_dst
, TCA_FLOWER_KEY_IPV4_DST
);
1769 } else if (host_eth_type
== ETH_P_IPV6
) {
1770 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_src
, TCA_FLOWER_KEY_IPV6_SRC
);
1771 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_dst
, TCA_FLOWER_KEY_IPV6_DST
);
1774 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ETH_TYPE
, flower
->key
.eth_type
);
1777 if (mpls_lse_to_ttl(flower
->mask
.mpls_lse
)) {
1778 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_TTL
,
1779 mpls_lse_to_ttl(flower
->key
.mpls_lse
));
1781 if (mpls_lse_to_tc(flower
->mask
.mpls_lse
)) {
1782 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_TC
,
1783 mpls_lse_to_tc(flower
->key
.mpls_lse
));
1785 if (mpls_lse_to_bos(flower
->mask
.mpls_lse
)) {
1786 nl_msg_put_u8(request
, TCA_FLOWER_KEY_MPLS_BOS
,
1787 mpls_lse_to_bos(flower
->key
.mpls_lse
));
1789 if (mpls_lse_to_label(flower
->mask
.mpls_lse
)) {
1790 nl_msg_put_u32(request
, TCA_FLOWER_KEY_MPLS_LABEL
,
1791 mpls_lse_to_label(flower
->key
.mpls_lse
));
1796 if (flower
->mask
.vlan_id
[0]) {
1797 nl_msg_put_u16(request
, TCA_FLOWER_KEY_VLAN_ID
,
1798 flower
->key
.vlan_id
[0]);
1800 if (flower
->mask
.vlan_prio
[0]) {
1801 nl_msg_put_u8(request
, TCA_FLOWER_KEY_VLAN_PRIO
,
1802 flower
->key
.vlan_prio
[0]);
1804 if (flower
->key
.encap_eth_type
[0]) {
1805 nl_msg_put_be16(request
, TCA_FLOWER_KEY_VLAN_ETH_TYPE
,
1806 flower
->key
.encap_eth_type
[0]);
1810 if (flower
->mask
.vlan_id
[1]) {
1811 nl_msg_put_u16(request
, TCA_FLOWER_KEY_CVLAN_ID
,
1812 flower
->key
.vlan_id
[1]);
1814 if (flower
->mask
.vlan_prio
[1]) {
1815 nl_msg_put_u8(request
, TCA_FLOWER_KEY_CVLAN_PRIO
,
1816 flower
->key
.vlan_prio
[1]);
1818 if (flower
->key
.encap_eth_type
[1]) {
1819 nl_msg_put_be16(request
, TCA_FLOWER_KEY_CVLAN_ETH_TYPE
,
1820 flower
->key
.encap_eth_type
[1]);
1825 nl_msg_put_u32(request
, TCA_FLOWER_FLAGS
, tc_get_tc_cls_policy(tc_policy
));
1827 if (flower
->tunnel
) {
1828 nl_msg_put_flower_tunnel(request
, flower
);
1835 tc_replace_flower(int ifindex
, uint16_t prio
, uint32_t handle
,
1836 struct tc_flower
*flower
, uint32_t block_id
)
1838 struct ofpbuf request
;
1839 struct tcmsg
*tcmsg
;
1840 struct ofpbuf
*reply
;
1842 size_t basic_offset
;
1843 uint16_t eth_type
= (OVS_FORCE
uint16_t) flower
->key
.eth_type
;
1846 index
= block_id
? TCM_IFINDEX_MAGIC_BLOCK
: ifindex
;
1847 tcmsg
= tc_make_request(index
, RTM_NEWTFILTER
, NLM_F_CREATE
| NLM_F_ECHO
,
1849 tcmsg
->tcm_parent
= block_id
? : TC_INGRESS_PARENT
;
1850 tcmsg
->tcm_info
= tc_make_handle(prio
, eth_type
);
1851 tcmsg
->tcm_handle
= handle
;
1853 nl_msg_put_string(&request
, TCA_KIND
, "flower");
1854 basic_offset
= nl_msg_start_nested(&request
, TCA_OPTIONS
);
1856 error
= nl_msg_put_flower_options(&request
, flower
);
1859 ofpbuf_uninit(&request
);
1863 nl_msg_end_nested(&request
, basic_offset
);
1865 error
= tc_transact(&request
, &reply
);
1868 ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
1870 flower
->prio
= tc_get_major(tc
->tcm_info
);
1871 flower
->handle
= tc
->tcm_handle
;
1872 ofpbuf_delete(reply
);
1879 tc_set_policy(const char *policy
)
1885 if (!strcmp(policy
, "skip_sw")) {
1886 tc_policy
= TC_POLICY_SKIP_SW
;
1887 } else if (!strcmp(policy
, "skip_hw")) {
1888 tc_policy
= TC_POLICY_SKIP_HW
;
1889 } else if (!strcmp(policy
, "none")) {
1890 tc_policy
= TC_POLICY_NONE
;
1892 VLOG_WARN("tc: Invalid policy '%s'", policy
);
1896 VLOG_INFO("tc: Using policy '%s'", policy
);