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 VLOG_DEFINE_THIS_MODULE(tc
);
48 static struct vlog_rate_limit error_rl
= VLOG_RATE_LIMIT_INIT(60, 5);
50 enum tc_offload_policy
{
56 static enum tc_offload_policy tc_policy
= TC_POLICY_NONE
;
58 struct tc_pedit_key_ex
{
59 enum pedit_header_type htype
;
63 struct flower_key_to_pedit
{
64 enum pedit_header_type htype
;
70 static struct flower_key_to_pedit flower_pedit_map
[] = {
72 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
74 offsetof(struct tc_flower_key
, ipv4
.ipv4_src
),
75 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.ipv4_src
)
77 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
79 offsetof(struct tc_flower_key
, ipv4
.ipv4_dst
),
80 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.ipv4_dst
)
82 TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
,
84 offsetof(struct tc_flower_key
, ipv4
.rewrite_ttl
),
85 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.rewrite_ttl
)
87 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
89 offsetof(struct tc_flower_key
, ipv6
.ipv6_src
),
90 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.ipv6_src
)
92 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
,
94 offsetof(struct tc_flower_key
, ipv6
.ipv6_dst
),
95 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.ipv6_dst
)
97 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
99 offsetof(struct tc_flower_key
, src_mac
),
100 MEMBER_SIZEOF(struct tc_flower_key
, src_mac
)
102 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
104 offsetof(struct tc_flower_key
, dst_mac
),
105 MEMBER_SIZEOF(struct tc_flower_key
, dst_mac
)
107 TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
,
109 offsetof(struct tc_flower_key
, eth_type
),
110 MEMBER_SIZEOF(struct tc_flower_key
, eth_type
)
112 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
,
114 offsetof(struct tc_flower_key
, tcp_src
),
115 MEMBER_SIZEOF(struct tc_flower_key
, tcp_src
)
117 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
,
119 offsetof(struct tc_flower_key
, tcp_dst
),
120 MEMBER_SIZEOF(struct tc_flower_key
, tcp_dst
)
122 TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
,
124 offsetof(struct tc_flower_key
, udp_src
),
125 MEMBER_SIZEOF(struct tc_flower_key
, udp_src
)
127 TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
,
129 offsetof(struct tc_flower_key
, udp_dst
),
130 MEMBER_SIZEOF(struct tc_flower_key
, udp_dst
)
135 csum_update_flag(struct tc_flower
*flower
,
136 enum pedit_header_type htype
);
139 tc_make_request(int ifindex
, int type
, unsigned int flags
,
140 struct ofpbuf
*request
)
144 ofpbuf_init(request
, 512);
145 nl_msg_put_nlmsghdr(request
, sizeof *tcmsg
, type
, NLM_F_REQUEST
| flags
);
146 tcmsg
= ofpbuf_put_zeros(request
, sizeof *tcmsg
);
147 tcmsg
->tcm_family
= AF_UNSPEC
;
148 tcmsg
->tcm_ifindex
= ifindex
;
149 /* Caller should fill in tcmsg->tcm_handle. */
150 /* Caller should fill in tcmsg->tcm_parent. */
156 tc_transact(struct ofpbuf
*request
, struct ofpbuf
**replyp
)
158 int error
= nl_transact(NETLINK_ROUTE
, request
, replyp
);
159 ofpbuf_uninit(request
);
163 /* Adds or deletes a root ingress qdisc on device with specified ifindex.
165 * This function is equivalent to running the following when 'add' is true:
166 * /sbin/tc qdisc add dev <devname> handle ffff: ingress
168 * This function is equivalent to running the following when 'add' is false:
169 * /sbin/tc qdisc del dev <devname> handle ffff: ingress
171 * Where dev <devname> is the device with specified ifindex name.
173 * The configuration and stats may be seen with the following command:
174 * /sbin/tc -s qdisc show dev <devname>
176 * Returns 0 if successful, otherwise a positive errno value.
179 tc_add_del_ingress_qdisc(int ifindex
, bool add
)
181 struct ofpbuf request
;
184 int type
= add
? RTM_NEWQDISC
: RTM_DELQDISC
;
185 int flags
= add
? NLM_F_EXCL
| NLM_F_CREATE
: 0;
187 tcmsg
= tc_make_request(ifindex
, type
, flags
, &request
);
188 tcmsg
->tcm_handle
= TC_H_MAKE(TC_H_INGRESS
, 0);
189 tcmsg
->tcm_parent
= TC_H_INGRESS
;
190 nl_msg_put_string(&request
, TCA_KIND
, "ingress");
191 nl_msg_put_unspec(&request
, TCA_OPTIONS
, NULL
, 0);
193 error
= tc_transact(&request
, NULL
);
195 /* If we're deleting the qdisc, don't worry about some of the
196 * error conditions. */
197 if (!add
&& (error
== ENOENT
|| error
== EINVAL
)) {
206 static const struct nl_policy tca_policy
[] = {
207 [TCA_KIND
] = { .type
= NL_A_STRING
, .optional
= false, },
208 [TCA_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= false, },
209 [TCA_STATS
] = { .type
= NL_A_UNSPEC
,
210 .min_len
= sizeof(struct tc_stats
), .optional
= true, },
211 [TCA_STATS2
] = { .type
= NL_A_NESTED
, .optional
= true, },
214 static const struct nl_policy tca_flower_policy
[] = {
215 [TCA_FLOWER_CLASSID
] = { .type
= NL_A_U32
, .optional
= true, },
216 [TCA_FLOWER_INDEV
] = { .type
= NL_A_STRING
, .max_len
= IFNAMSIZ
,
218 [TCA_FLOWER_KEY_ETH_SRC
] = { .type
= NL_A_UNSPEC
,
219 .min_len
= ETH_ALEN
, .optional
= true, },
220 [TCA_FLOWER_KEY_ETH_DST
] = { .type
= NL_A_UNSPEC
,
221 .min_len
= ETH_ALEN
, .optional
= true, },
222 [TCA_FLOWER_KEY_ETH_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
225 [TCA_FLOWER_KEY_ETH_DST_MASK
] = { .type
= NL_A_UNSPEC
,
228 [TCA_FLOWER_KEY_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= false, },
229 [TCA_FLOWER_FLAGS
] = { .type
= NL_A_U32
, .optional
= false, },
230 [TCA_FLOWER_ACT
] = { .type
= NL_A_NESTED
, .optional
= false, },
231 [TCA_FLOWER_KEY_IP_PROTO
] = { .type
= NL_A_U8
, .optional
= true, },
232 [TCA_FLOWER_KEY_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
233 [TCA_FLOWER_KEY_IPV4_DST
] = {.type
= NL_A_U32
, .optional
= true, },
234 [TCA_FLOWER_KEY_IPV4_SRC_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
235 [TCA_FLOWER_KEY_IPV4_DST_MASK
] = { .type
= NL_A_U32
, .optional
= true, },
236 [TCA_FLOWER_KEY_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
237 .min_len
= sizeof(struct in6_addr
),
239 [TCA_FLOWER_KEY_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
240 .min_len
= sizeof(struct in6_addr
),
242 [TCA_FLOWER_KEY_IPV6_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
243 .min_len
= sizeof(struct in6_addr
),
245 [TCA_FLOWER_KEY_IPV6_DST_MASK
] = { .type
= NL_A_UNSPEC
,
246 .min_len
= sizeof(struct in6_addr
),
248 [TCA_FLOWER_KEY_TCP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
249 [TCA_FLOWER_KEY_TCP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
250 [TCA_FLOWER_KEY_TCP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
251 [TCA_FLOWER_KEY_TCP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
252 [TCA_FLOWER_KEY_UDP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
253 [TCA_FLOWER_KEY_UDP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
254 [TCA_FLOWER_KEY_UDP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
255 [TCA_FLOWER_KEY_UDP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
256 [TCA_FLOWER_KEY_SCTP_SRC
] = { .type
= NL_A_U16
, .optional
= true, },
257 [TCA_FLOWER_KEY_SCTP_DST
] = { .type
= NL_A_U16
, .optional
= true, },
258 [TCA_FLOWER_KEY_SCTP_SRC_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
259 [TCA_FLOWER_KEY_SCTP_DST_MASK
] = { .type
= NL_A_U16
, .optional
= true, },
260 [TCA_FLOWER_KEY_VLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
261 [TCA_FLOWER_KEY_VLAN_PRIO
] = { .type
= NL_A_U8
, .optional
= true, },
262 [TCA_FLOWER_KEY_VLAN_ETH_TYPE
] = { .type
= NL_A_U16
, .optional
= true, },
263 [TCA_FLOWER_KEY_ENC_KEY_ID
] = { .type
= NL_A_U32
, .optional
= true, },
264 [TCA_FLOWER_KEY_ENC_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
265 [TCA_FLOWER_KEY_ENC_IPV4_DST
] = { .type
= NL_A_U32
, .optional
= true, },
266 [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
] = { .type
= NL_A_U32
,
268 [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
] = { .type
= NL_A_U32
,
270 [TCA_FLOWER_KEY_ENC_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
271 .min_len
= sizeof(struct in6_addr
),
273 [TCA_FLOWER_KEY_ENC_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
274 .min_len
= sizeof(struct in6_addr
),
276 [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
] = { .type
= NL_A_UNSPEC
,
277 .min_len
= sizeof(struct in6_addr
),
279 [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
] = { .type
= NL_A_UNSPEC
,
280 .min_len
= sizeof(struct in6_addr
),
282 [TCA_FLOWER_KEY_ENC_UDP_DST_PORT
] = { .type
= NL_A_U16
,
284 [TCA_FLOWER_KEY_FLAGS
] = { .type
= NL_A_BE32
, .optional
= true, },
285 [TCA_FLOWER_KEY_FLAGS_MASK
] = { .type
= NL_A_BE32
, .optional
= true, },
286 [TCA_FLOWER_KEY_IP_TTL
] = { .type
= NL_A_U8
,
288 [TCA_FLOWER_KEY_IP_TTL_MASK
] = { .type
= NL_A_U8
,
290 [TCA_FLOWER_KEY_TCP_FLAGS
] = { .type
= NL_A_U16
,
292 [TCA_FLOWER_KEY_TCP_FLAGS_MASK
] = { .type
= NL_A_U16
,
297 nl_parse_flower_eth(struct nlattr
**attrs
, struct tc_flower
*flower
)
299 const struct eth_addr
*eth
;
301 if (attrs
[TCA_FLOWER_KEY_ETH_SRC_MASK
]) {
302 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_SRC
], ETH_ALEN
);
303 memcpy(&flower
->key
.src_mac
, eth
, sizeof flower
->key
.src_mac
);
305 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_SRC_MASK
], ETH_ALEN
);
306 memcpy(&flower
->mask
.src_mac
, eth
, sizeof flower
->mask
.src_mac
);
308 if (attrs
[TCA_FLOWER_KEY_ETH_DST_MASK
]) {
309 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_DST
], ETH_ALEN
);
310 memcpy(&flower
->key
.dst_mac
, eth
, sizeof flower
->key
.dst_mac
);
312 eth
= nl_attr_get_unspec(attrs
[TCA_FLOWER_KEY_ETH_DST_MASK
], ETH_ALEN
);
313 memcpy(&flower
->mask
.dst_mac
, eth
, sizeof flower
->mask
.dst_mac
);
318 nl_parse_flower_vlan(struct nlattr
**attrs
, struct tc_flower
*flower
)
320 if (flower
->key
.eth_type
!= htons(ETH_TYPE_VLAN
)) {
324 flower
->key
.encap_eth_type
=
325 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ETH_TYPE
]);
327 if (attrs
[TCA_FLOWER_KEY_VLAN_ID
]) {
328 flower
->key
.vlan_id
=
329 nl_attr_get_u16(attrs
[TCA_FLOWER_KEY_VLAN_ID
]);
331 if (attrs
[TCA_FLOWER_KEY_VLAN_PRIO
]) {
332 flower
->key
.vlan_prio
=
333 nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_VLAN_PRIO
]);
338 nl_parse_flower_tunnel(struct nlattr
**attrs
, struct tc_flower
*flower
)
340 if (attrs
[TCA_FLOWER_KEY_ENC_KEY_ID
]) {
341 ovs_be32 id
= nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_KEY_ID
]);
343 flower
->tunnel
.id
= be32_to_be64(id
);
345 if (attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK
]) {
346 flower
->tunnel
.ipv4
.ipv4_src
=
347 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_SRC
]);
349 if (attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK
]) {
350 flower
->tunnel
.ipv4
.ipv4_dst
=
351 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_ENC_IPV4_DST
]);
353 if (attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK
]) {
354 flower
->tunnel
.ipv6
.ipv6_src
=
355 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_SRC
]);
357 if (attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK
]) {
358 flower
->tunnel
.ipv6
.ipv6_dst
=
359 nl_attr_get_in6_addr(attrs
[TCA_FLOWER_KEY_ENC_IPV6_DST
]);
361 if (attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]) {
362 flower
->tunnel
.tp_dst
=
363 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT
]);
368 nl_parse_flower_ip(struct nlattr
**attrs
, struct tc_flower
*flower
) {
369 uint8_t ip_proto
= 0;
370 struct tc_flower_key
*key
= &flower
->key
;
371 struct tc_flower_key
*mask
= &flower
->mask
;
373 if (attrs
[TCA_FLOWER_KEY_IP_PROTO
]) {
374 ip_proto
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_PROTO
]);
375 key
->ip_proto
= ip_proto
;
376 mask
->ip_proto
= UINT8_MAX
;
379 if (attrs
[TCA_FLOWER_KEY_FLAGS_MASK
]) {
380 key
->flags
= ntohl(nl_attr_get_u32(attrs
[TCA_FLOWER_KEY_FLAGS
]));
381 mask
->flags
= ntohl(nl_attr_get_u32(attrs
[TCA_FLOWER_KEY_FLAGS_MASK
]));
384 if (attrs
[TCA_FLOWER_KEY_IPV4_SRC_MASK
]) {
386 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_SRC
]);
387 mask
->ipv4
.ipv4_src
=
388 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_SRC_MASK
]);
390 if (attrs
[TCA_FLOWER_KEY_IPV4_DST_MASK
]) {
392 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_DST
]);
393 mask
->ipv4
.ipv4_dst
=
394 nl_attr_get_be32(attrs
[TCA_FLOWER_KEY_IPV4_DST_MASK
]);
396 if (attrs
[TCA_FLOWER_KEY_IPV6_SRC_MASK
]) {
397 struct nlattr
*attr
= attrs
[TCA_FLOWER_KEY_IPV6_SRC
];
398 struct nlattr
*attr_mask
= attrs
[TCA_FLOWER_KEY_IPV6_SRC_MASK
];
400 key
->ipv6
.ipv6_src
= nl_attr_get_in6_addr(attr
);
401 mask
->ipv6
.ipv6_src
= nl_attr_get_in6_addr(attr_mask
);
403 if (attrs
[TCA_FLOWER_KEY_IPV6_DST_MASK
]) {
404 struct nlattr
*attr
= attrs
[TCA_FLOWER_KEY_IPV6_DST
];
405 struct nlattr
*attr_mask
= attrs
[TCA_FLOWER_KEY_IPV6_DST_MASK
];
407 key
->ipv6
.ipv6_dst
= nl_attr_get_in6_addr(attr
);
408 mask
->ipv6
.ipv6_dst
= nl_attr_get_in6_addr(attr_mask
);
411 if (ip_proto
== IPPROTO_TCP
) {
412 if (attrs
[TCA_FLOWER_KEY_TCP_SRC_MASK
]) {
414 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_SRC
]);
416 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_SRC_MASK
]);
418 if (attrs
[TCA_FLOWER_KEY_TCP_DST_MASK
]) {
420 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_DST
]);
422 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_DST_MASK
]);
424 if (attrs
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]) {
426 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_FLAGS
]);
428 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_TCP_FLAGS_MASK
]);
430 } else if (ip_proto
== IPPROTO_UDP
) {
431 if (attrs
[TCA_FLOWER_KEY_UDP_SRC_MASK
]) {
432 key
->udp_src
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_SRC
]);
434 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_SRC_MASK
]);
436 if (attrs
[TCA_FLOWER_KEY_UDP_DST_MASK
]) {
437 key
->udp_dst
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_DST
]);
439 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_UDP_DST_MASK
]);
441 } else if (ip_proto
== IPPROTO_SCTP
) {
442 if (attrs
[TCA_FLOWER_KEY_SCTP_SRC_MASK
]) {
443 key
->sctp_src
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_SRC
]);
445 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_SRC_MASK
]);
447 if (attrs
[TCA_FLOWER_KEY_SCTP_DST_MASK
]) {
448 key
->sctp_dst
= nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_DST
]);
450 nl_attr_get_be16(attrs
[TCA_FLOWER_KEY_SCTP_DST_MASK
]);
454 if (attrs
[TCA_FLOWER_KEY_IP_TTL_MASK
]) {
455 key
->ip_ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TTL
]);
456 mask
->ip_ttl
= nl_attr_get_u8(attrs
[TCA_FLOWER_KEY_IP_TTL_MASK
]);
460 static const struct nl_policy pedit_policy
[] = {
461 [TCA_PEDIT_PARMS_EX
] = { .type
= NL_A_UNSPEC
,
462 .min_len
= sizeof(struct tc_pedit
),
463 .optional
= false, },
464 [TCA_PEDIT_KEYS_EX
] = { .type
= NL_A_NESTED
,
465 .optional
= false, },
469 nl_parse_act_pedit(struct nlattr
*options
, struct tc_flower
*flower
)
471 struct nlattr
*pe_attrs
[ARRAY_SIZE(pedit_policy
)];
472 const struct tc_pedit
*pe
;
473 const struct tc_pedit_key
*keys
;
474 const struct nlattr
*nla
, *keys_ex
, *ex_type
;
475 const void *keys_attr
;
476 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
477 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
478 size_t keys_ex_size
, left
;
479 int type
, i
= 0, err
;
481 if (!nl_parse_nested(options
, pedit_policy
, pe_attrs
,
482 ARRAY_SIZE(pedit_policy
))) {
483 VLOG_ERR_RL(&error_rl
, "failed to parse pedit action options");
487 pe
= nl_attr_get_unspec(pe_attrs
[TCA_PEDIT_PARMS_EX
], sizeof *pe
);
489 keys_attr
= pe_attrs
[TCA_PEDIT_KEYS_EX
];
490 keys_ex
= nl_attr_get(keys_attr
);
491 keys_ex_size
= nl_attr_get_size(keys_attr
);
493 NL_ATTR_FOR_EACH (nla
, left
, keys_ex
, keys_ex_size
) {
494 if (i
>= pe
->nkeys
) {
498 if (nl_attr_type(nla
) != TCA_PEDIT_KEY_EX
) {
499 VLOG_ERR_RL(&error_rl
, "unable to parse legacy pedit type: %d",
504 ex_type
= nl_attr_find_nested(nla
, TCA_PEDIT_KEY_EX_HTYPE
);
505 type
= nl_attr_get_u16(ex_type
);
507 err
= csum_update_flag(flower
, type
);
512 for (int j
= 0; j
< ARRAY_SIZE(flower_pedit_map
); j
++) {
513 struct flower_key_to_pedit
*m
= &flower_pedit_map
[j
];
514 int flower_off
= m
->flower_offset
;
518 if (m
->htype
!= type
) {
522 /* check overlap between current pedit key, which is always
523 * 4 bytes (range [off, off + 3]), and a map entry in
524 * flower_pedit_map (range [mf, mf + sz - 1]) */
525 if ((keys
->off
>= mf
&& keys
->off
< mf
+ sz
)
526 || (keys
->off
+ 3 >= mf
&& keys
->off
+ 3 < mf
+ sz
)) {
527 int diff
= flower_off
+ (keys
->off
- mf
);
528 uint32_t *dst
= (void *) (rewrite_key
+ diff
);
529 uint32_t *dst_m
= (void *) (rewrite_mask
+ diff
);
530 uint32_t mask
= ~(keys
->mask
);
533 if (keys
->off
< mf
) {
534 zero_bits
= 8 * (mf
- keys
->off
);
535 mask
&= UINT32_MAX
<< zero_bits
;
536 } else if (keys
->off
+ 4 > mf
+ m
->size
) {
537 zero_bits
= 8 * (keys
->off
+ 4 - mf
- m
->size
);
538 mask
&= UINT32_MAX
>> zero_bits
;
542 *dst
|= keys
->val
& mask
;
550 flower
->rewrite
.rewrite
= true;
555 static const struct nl_policy tunnel_key_policy
[] = {
556 [TCA_TUNNEL_KEY_PARMS
] = { .type
= NL_A_UNSPEC
,
557 .min_len
= sizeof(struct tc_tunnel_key
),
558 .optional
= false, },
559 [TCA_TUNNEL_KEY_ENC_IPV4_SRC
] = { .type
= NL_A_U32
, .optional
= true, },
560 [TCA_TUNNEL_KEY_ENC_IPV4_DST
] = { .type
= NL_A_U32
, .optional
= true, },
561 [TCA_TUNNEL_KEY_ENC_IPV6_SRC
] = { .type
= NL_A_UNSPEC
,
562 .min_len
= sizeof(struct in6_addr
),
564 [TCA_TUNNEL_KEY_ENC_IPV6_DST
] = { .type
= NL_A_UNSPEC
,
565 .min_len
= sizeof(struct in6_addr
),
567 [TCA_TUNNEL_KEY_ENC_KEY_ID
] = { .type
= NL_A_U32
, .optional
= true, },
568 [TCA_TUNNEL_KEY_ENC_DST_PORT
] = { .type
= NL_A_U16
, .optional
= true, },
572 nl_parse_act_tunnel_key(struct nlattr
*options
, struct tc_flower
*flower
)
574 struct nlattr
*tun_attrs
[ARRAY_SIZE(tunnel_key_policy
)];
575 const struct nlattr
*tun_parms
;
576 const struct tc_tunnel_key
*tun
;
578 if (!nl_parse_nested(options
, tunnel_key_policy
, tun_attrs
,
579 ARRAY_SIZE(tunnel_key_policy
))) {
580 VLOG_ERR_RL(&error_rl
, "failed to parse tunnel_key action options");
584 tun_parms
= tun_attrs
[TCA_TUNNEL_KEY_PARMS
];
585 tun
= nl_attr_get_unspec(tun_parms
, sizeof *tun
);
586 if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_SET
) {
587 struct nlattr
*id
= tun_attrs
[TCA_TUNNEL_KEY_ENC_KEY_ID
];
588 struct nlattr
*dst_port
= tun_attrs
[TCA_TUNNEL_KEY_ENC_DST_PORT
];
589 struct nlattr
*ipv4_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_SRC
];
590 struct nlattr
*ipv4_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV4_DST
];
591 struct nlattr
*ipv6_src
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_SRC
];
592 struct nlattr
*ipv6_dst
= tun_attrs
[TCA_TUNNEL_KEY_ENC_IPV6_DST
];
594 flower
->set
.set
= true;
595 flower
->set
.ipv4
.ipv4_src
= ipv4_src
? nl_attr_get_be32(ipv4_src
) : 0;
596 flower
->set
.ipv4
.ipv4_dst
= ipv4_dst
? nl_attr_get_be32(ipv4_dst
) : 0;
598 flower
->set
.ipv6
.ipv6_src
= nl_attr_get_in6_addr(ipv6_src
);
601 flower
->set
.ipv6
.ipv6_dst
= nl_attr_get_in6_addr(ipv6_dst
);
603 flower
->set
.id
= id
? be32_to_be64(nl_attr_get_be32(id
)) : 0;
604 flower
->set
.tp_dst
= dst_port
? nl_attr_get_be16(dst_port
) : 0;
605 } else if (tun
->t_action
== TCA_TUNNEL_KEY_ACT_RELEASE
) {
606 flower
->tunnel
.tunnel
= true;
608 VLOG_ERR_RL(&error_rl
, "unknown tunnel actions: %d, %d",
609 tun
->action
, tun
->t_action
);
615 static const struct nl_policy gact_policy
[] = {
616 [TCA_GACT_PARMS
] = { .type
= NL_A_UNSPEC
,
617 .min_len
= sizeof(struct tc_gact
),
618 .optional
= false, },
619 [TCA_GACT_TM
] = { .type
= NL_A_UNSPEC
,
620 .min_len
= sizeof(struct tcf_t
),
621 .optional
= false, },
627 static struct ovsthread_once once
= OVSTHREAD_ONCE_INITIALIZER
;
628 static int user_hz
= 100;
630 if (ovsthread_once_start(&once
)) {
631 user_hz
= sysconf(_SC_CLK_TCK
);
632 ovsthread_once_done(&once
);
639 nl_parse_tcf(const struct tcf_t
*tm
, struct tc_flower
*flower
)
641 flower
->lastused
= time_msec() - (tm
->lastuse
* 1000 / get_user_hz());
645 nl_parse_act_drop(struct nlattr
*options
, struct tc_flower
*flower
)
647 struct nlattr
*gact_attrs
[ARRAY_SIZE(gact_policy
)];
648 const struct tc_gact
*p
;
649 struct nlattr
*gact_parms
;
650 const struct tcf_t
*tm
;
652 if (!nl_parse_nested(options
, gact_policy
, gact_attrs
,
653 ARRAY_SIZE(gact_policy
))) {
654 VLOG_ERR_RL(&error_rl
, "failed to parse gact action options");
658 gact_parms
= gact_attrs
[TCA_GACT_PARMS
];
659 p
= nl_attr_get_unspec(gact_parms
, sizeof *p
);
661 if (p
->action
!= TC_ACT_SHOT
) {
662 VLOG_ERR_RL(&error_rl
, "unknown gact action: %d", p
->action
);
666 tm
= nl_attr_get_unspec(gact_attrs
[TCA_GACT_TM
], sizeof *tm
);
667 nl_parse_tcf(tm
, flower
);
672 static const struct nl_policy mirred_policy
[] = {
673 [TCA_MIRRED_PARMS
] = { .type
= NL_A_UNSPEC
,
674 .min_len
= sizeof(struct tc_mirred
),
675 .optional
= false, },
676 [TCA_MIRRED_TM
] = { .type
= NL_A_UNSPEC
,
677 .min_len
= sizeof(struct tcf_t
),
678 .optional
= false, },
682 nl_parse_act_mirred(struct nlattr
*options
, struct tc_flower
*flower
)
685 struct nlattr
*mirred_attrs
[ARRAY_SIZE(mirred_policy
)];
686 const struct tc_mirred
*m
;
687 const struct nlattr
*mirred_parms
;
688 const struct tcf_t
*tm
;
689 struct nlattr
*mirred_tm
;
691 if (!nl_parse_nested(options
, mirred_policy
, mirred_attrs
,
692 ARRAY_SIZE(mirred_policy
))) {
693 VLOG_ERR_RL(&error_rl
, "failed to parse mirred action options");
697 mirred_parms
= mirred_attrs
[TCA_MIRRED_PARMS
];
698 m
= nl_attr_get_unspec(mirred_parms
, sizeof *m
);
700 if (m
->action
!= TC_ACT_STOLEN
|| m
->eaction
!= TCA_EGRESS_REDIR
) {
701 VLOG_ERR_RL(&error_rl
, "unknown mirred action: %d, %d, %d",
702 m
->action
, m
->eaction
, m
->ifindex
);
706 flower
->ifindex_out
= m
->ifindex
;
708 mirred_tm
= mirred_attrs
[TCA_MIRRED_TM
];
709 tm
= nl_attr_get_unspec(mirred_tm
, sizeof *tm
);
710 nl_parse_tcf(tm
, flower
);
715 static const struct nl_policy vlan_policy
[] = {
716 [TCA_VLAN_PARMS
] = { .type
= NL_A_UNSPEC
,
717 .min_len
= sizeof(struct tc_vlan
),
718 .optional
= false, },
719 [TCA_VLAN_PUSH_VLAN_ID
] = { .type
= NL_A_U16
, .optional
= true, },
720 [TCA_VLAN_PUSH_VLAN_PROTOCOL
] = { .type
= NL_A_U16
, .optional
= true, },
721 [TCA_VLAN_PUSH_VLAN_PRIORITY
] = { .type
= NL_A_U8
, .optional
= true, },
725 nl_parse_act_vlan(struct nlattr
*options
, struct tc_flower
*flower
)
727 struct nlattr
*vlan_attrs
[ARRAY_SIZE(vlan_policy
)];
728 const struct tc_vlan
*v
;
729 const struct nlattr
*vlan_parms
;
731 if (!nl_parse_nested(options
, vlan_policy
, vlan_attrs
,
732 ARRAY_SIZE(vlan_policy
))) {
733 VLOG_ERR_RL(&error_rl
, "failed to parse vlan action options");
737 vlan_parms
= vlan_attrs
[TCA_VLAN_PARMS
];
738 v
= nl_attr_get_unspec(vlan_parms
, sizeof *v
);
739 if (v
->v_action
== TCA_VLAN_ACT_PUSH
) {
740 struct nlattr
*vlan_id
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_ID
];
741 struct nlattr
*vlan_prio
= vlan_attrs
[TCA_VLAN_PUSH_VLAN_PRIORITY
];
743 flower
->vlan_push_id
= nl_attr_get_u16(vlan_id
);
744 flower
->vlan_push_prio
= vlan_prio
? nl_attr_get_u8(vlan_prio
) : 0;
745 } else if (v
->v_action
== TCA_VLAN_ACT_POP
) {
746 flower
->vlan_pop
= 1;
748 VLOG_ERR_RL(&error_rl
, "unknown vlan action: %d, %d",
749 v
->action
, v
->v_action
);
755 static const struct nl_policy csum_policy
[] = {
756 [TCA_CSUM_PARMS
] = { .type
= NL_A_UNSPEC
,
757 .min_len
= sizeof(struct tc_csum
),
758 .optional
= false, },
762 nl_parse_act_csum(struct nlattr
*options
, struct tc_flower
*flower
)
764 struct nlattr
*csum_attrs
[ARRAY_SIZE(csum_policy
)];
765 const struct tc_csum
*c
;
766 const struct nlattr
*csum_parms
;
768 if (!nl_parse_nested(options
, csum_policy
, csum_attrs
,
769 ARRAY_SIZE(csum_policy
))) {
770 VLOG_ERR_RL(&error_rl
, "failed to parse csum action options");
774 csum_parms
= csum_attrs
[TCA_CSUM_PARMS
];
775 c
= nl_attr_get_unspec(csum_parms
, sizeof *c
);
778 if (c
->update_flags
!= flower
->csum_update_flags
) {
779 VLOG_WARN_RL(&error_rl
,
780 "expected different act csum flags: 0x%x != 0x%x",
781 flower
->csum_update_flags
, c
->update_flags
);
784 flower
->csum_update_flags
= 0; /* so we know csum was handled */
786 if (flower
->needs_full_ip_proto_mask
787 && flower
->mask
.ip_proto
!= UINT8_MAX
) {
788 VLOG_WARN_RL(&error_rl
, "expected full matching on flower ip_proto");
795 static const struct nl_policy act_policy
[] = {
796 [TCA_ACT_KIND
] = { .type
= NL_A_STRING
, .optional
= false, },
797 [TCA_ACT_COOKIE
] = { .type
= NL_A_UNSPEC
, .optional
= true, },
798 [TCA_ACT_OPTIONS
] = { .type
= NL_A_NESTED
, .optional
= false, },
799 [TCA_ACT_STATS
] = { .type
= NL_A_NESTED
, .optional
= false, },
802 static const struct nl_policy stats_policy
[] = {
803 [TCA_STATS_BASIC
] = { .type
= NL_A_UNSPEC
,
804 .min_len
= sizeof(struct gnet_stats_basic
),
805 .optional
= false, },
809 nl_parse_single_action(struct nlattr
*action
, struct tc_flower
*flower
)
811 struct nlattr
*act_options
;
812 struct nlattr
*act_stats
;
813 struct nlattr
*act_cookie
;
814 const char *act_kind
;
815 struct nlattr
*action_attrs
[ARRAY_SIZE(act_policy
)];
816 struct nlattr
*stats_attrs
[ARRAY_SIZE(stats_policy
)];
817 struct ovs_flow_stats
*stats
= &flower
->stats
;
818 const struct gnet_stats_basic
*bs
;
821 if (!nl_parse_nested(action
, act_policy
, action_attrs
,
822 ARRAY_SIZE(act_policy
))) {
823 VLOG_ERR_RL(&error_rl
, "failed to parse single action options");
827 act_kind
= nl_attr_get_string(action_attrs
[TCA_ACT_KIND
]);
828 act_options
= action_attrs
[TCA_ACT_OPTIONS
];
829 act_cookie
= action_attrs
[TCA_ACT_COOKIE
];
831 if (!strcmp(act_kind
, "gact")) {
832 err
= nl_parse_act_drop(act_options
, flower
);
833 } else if (!strcmp(act_kind
, "mirred")) {
834 err
= nl_parse_act_mirred(act_options
, flower
);
835 } else if (!strcmp(act_kind
, "vlan")) {
836 err
= nl_parse_act_vlan(act_options
, flower
);
837 } else if (!strcmp(act_kind
, "tunnel_key")) {
838 err
= nl_parse_act_tunnel_key(act_options
, flower
);
839 } else if (!strcmp(act_kind
, "pedit")) {
840 err
= nl_parse_act_pedit(act_options
, flower
);
841 } else if (!strcmp(act_kind
, "csum")) {
842 nl_parse_act_csum(act_options
, flower
);
844 VLOG_ERR_RL(&error_rl
, "unknown tc action kind: %s", act_kind
);
853 flower
->act_cookie
.data
= nl_attr_get(act_cookie
);
854 flower
->act_cookie
.len
= nl_attr_get_size(act_cookie
);
857 act_stats
= action_attrs
[TCA_ACT_STATS
];
859 if (!nl_parse_nested(act_stats
, stats_policy
, stats_attrs
,
860 ARRAY_SIZE(stats_policy
))) {
861 VLOG_ERR_RL(&error_rl
, "failed to parse action stats policy");
865 bs
= nl_attr_get_unspec(stats_attrs
[TCA_STATS_BASIC
], sizeof *bs
);
866 put_32aligned_u64(&stats
->n_packets
, bs
->packets
);
867 put_32aligned_u64(&stats
->n_bytes
, bs
->bytes
);
872 #define TCA_ACT_MIN_PRIO 1
875 nl_parse_flower_actions(struct nlattr
**attrs
, struct tc_flower
*flower
)
877 const struct nlattr
*actions
= attrs
[TCA_FLOWER_ACT
];
878 static struct nl_policy actions_orders_policy
[TCA_ACT_MAX_PRIO
+ 1] = {};
879 struct nlattr
*actions_orders
[ARRAY_SIZE(actions_orders_policy
)];
880 const int max_size
= ARRAY_SIZE(actions_orders_policy
);
882 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
883 actions_orders_policy
[i
].type
= NL_A_NESTED
;
884 actions_orders_policy
[i
].optional
= true;
887 if (!nl_parse_nested(actions
, actions_orders_policy
, actions_orders
,
888 ARRAY_SIZE(actions_orders_policy
))) {
889 VLOG_ERR_RL(&error_rl
, "failed to parse flower order of actions");
893 for (int i
= TCA_ACT_MIN_PRIO
; i
< max_size
; i
++) {
894 if (actions_orders
[i
]) {
895 int err
= nl_parse_single_action(actions_orders
[i
], flower
);
903 if (flower
->csum_update_flags
) {
904 VLOG_WARN_RL(&error_rl
,
905 "expected act csum with flags: 0x%x",
906 flower
->csum_update_flags
);
914 nl_parse_flower_options(struct nlattr
*nl_options
, struct tc_flower
*flower
)
916 struct nlattr
*attrs
[ARRAY_SIZE(tca_flower_policy
)];
918 if (!nl_parse_nested(nl_options
, tca_flower_policy
,
919 attrs
, ARRAY_SIZE(tca_flower_policy
))) {
920 VLOG_ERR_RL(&error_rl
, "failed to parse flower classifier options");
924 nl_parse_flower_eth(attrs
, flower
);
925 nl_parse_flower_vlan(attrs
, flower
);
926 nl_parse_flower_ip(attrs
, flower
);
927 nl_parse_flower_tunnel(attrs
, flower
);
928 return nl_parse_flower_actions(attrs
, flower
);
932 parse_netlink_to_tc_flower(struct ofpbuf
*reply
, struct tc_flower
*flower
)
935 struct nlattr
*ta
[ARRAY_SIZE(tca_policy
)];
938 if (NLMSG_HDRLEN
+ sizeof *tc
> reply
->size
) {
942 memset(flower
, 0, sizeof *flower
);
944 tc
= ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
945 flower
->handle
= tc
->tcm_handle
;
946 flower
->key
.eth_type
= (OVS_FORCE ovs_be16
) tc_get_minor(tc
->tcm_info
);
947 flower
->mask
.eth_type
= OVS_BE16_MAX
;
948 flower
->prio
= tc_get_major(tc
->tcm_info
);
950 if (!flower
->handle
) {
954 if (!nl_policy_parse(reply
, NLMSG_HDRLEN
+ sizeof *tc
,
955 tca_policy
, ta
, ARRAY_SIZE(ta
))) {
956 VLOG_ERR_RL(&error_rl
, "failed to parse tca policy");
960 kind
= nl_attr_get_string(ta
[TCA_KIND
]);
961 if (strcmp(kind
, "flower")) {
962 VLOG_ERR_RL(&error_rl
, "failed to parse filter: %s", kind
);
966 return nl_parse_flower_options(ta
[TCA_OPTIONS
], flower
);
970 tc_dump_flower_start(int ifindex
, struct nl_dump
*dump
)
972 struct ofpbuf request
;
975 tcmsg
= tc_make_request(ifindex
, RTM_GETTFILTER
, NLM_F_DUMP
, &request
);
976 tcmsg
->tcm_parent
= TC_INGRESS_PARENT
;
977 tcmsg
->tcm_info
= TC_H_UNSPEC
;
978 tcmsg
->tcm_handle
= 0;
980 nl_dump_start(dump
, NETLINK_ROUTE
, &request
);
981 ofpbuf_uninit(&request
);
987 tc_flush(int ifindex
)
989 struct ofpbuf request
;
992 tcmsg
= tc_make_request(ifindex
, RTM_DELTFILTER
, NLM_F_ACK
, &request
);
993 tcmsg
->tcm_parent
= TC_INGRESS_PARENT
;
994 tcmsg
->tcm_info
= TC_H_UNSPEC
;
996 return tc_transact(&request
, NULL
);
1000 tc_del_filter(int ifindex
, int prio
, int handle
)
1002 struct ofpbuf request
;
1003 struct tcmsg
*tcmsg
;
1004 struct ofpbuf
*reply
;
1007 tcmsg
= tc_make_request(ifindex
, RTM_DELTFILTER
, NLM_F_ECHO
, &request
);
1008 tcmsg
->tcm_parent
= TC_INGRESS_PARENT
;
1009 tcmsg
->tcm_info
= tc_make_handle(prio
, 0);
1010 tcmsg
->tcm_handle
= handle
;
1012 error
= tc_transact(&request
, &reply
);
1014 ofpbuf_delete(reply
);
1020 tc_get_flower(int ifindex
, int prio
, int handle
, struct tc_flower
*flower
)
1022 struct ofpbuf request
;
1023 struct tcmsg
*tcmsg
;
1024 struct ofpbuf
*reply
;
1027 tcmsg
= tc_make_request(ifindex
, RTM_GETTFILTER
, NLM_F_ECHO
, &request
);
1028 tcmsg
->tcm_parent
= TC_INGRESS_PARENT
;
1029 tcmsg
->tcm_info
= tc_make_handle(prio
, 0);
1030 tcmsg
->tcm_handle
= handle
;
1032 error
= tc_transact(&request
, &reply
);
1037 error
= parse_netlink_to_tc_flower(reply
, flower
);
1038 ofpbuf_delete(reply
);
1043 tc_get_tc_cls_policy(enum tc_offload_policy policy
)
1045 if (policy
== TC_POLICY_SKIP_HW
) {
1046 return TCA_CLS_FLAGS_SKIP_HW
;
1047 } else if (policy
== TC_POLICY_SKIP_SW
) {
1048 return TCA_CLS_FLAGS_SKIP_SW
;
1055 nl_msg_put_act_csum(struct ofpbuf
*request
, uint32_t flags
)
1059 nl_msg_put_string(request
, TCA_ACT_KIND
, "csum");
1060 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1062 struct tc_csum parm
= { .action
= TC_ACT_PIPE
,
1063 .update_flags
= flags
};
1065 nl_msg_put_unspec(request
, TCA_CSUM_PARMS
, &parm
, sizeof parm
);
1067 nl_msg_end_nested(request
, offset
);
1071 nl_msg_put_act_pedit(struct ofpbuf
*request
, struct tc_pedit
*parm
,
1072 struct tc_pedit_key_ex
*ex
)
1074 size_t ksize
= sizeof *parm
+ parm
->nkeys
* sizeof(struct tc_pedit_key
);
1075 size_t offset
, offset_keys_ex
, offset_key
;
1078 nl_msg_put_string(request
, TCA_ACT_KIND
, "pedit");
1079 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1081 parm
->action
= TC_ACT_PIPE
;
1083 nl_msg_put_unspec(request
, TCA_PEDIT_PARMS_EX
, parm
, ksize
);
1084 offset_keys_ex
= nl_msg_start_nested(request
, TCA_PEDIT_KEYS_EX
);
1085 for (i
= 0; i
< parm
->nkeys
; i
++, ex
++) {
1086 offset_key
= nl_msg_start_nested(request
, TCA_PEDIT_KEY_EX
);
1087 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_HTYPE
, ex
->htype
);
1088 nl_msg_put_u16(request
, TCA_PEDIT_KEY_EX_CMD
, ex
->cmd
);
1089 nl_msg_end_nested(request
, offset_key
);
1091 nl_msg_end_nested(request
, offset_keys_ex
);
1093 nl_msg_end_nested(request
, offset
);
1097 nl_msg_put_act_push_vlan(struct ofpbuf
*request
, uint16_t vid
, uint8_t prio
)
1101 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1102 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1104 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1105 .v_action
= TCA_VLAN_ACT_PUSH
};
1107 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1108 nl_msg_put_u16(request
, TCA_VLAN_PUSH_VLAN_ID
, vid
);
1109 nl_msg_put_u8(request
, TCA_VLAN_PUSH_VLAN_PRIORITY
, prio
);
1111 nl_msg_end_nested(request
, offset
);
1115 nl_msg_put_act_pop_vlan(struct ofpbuf
*request
)
1119 nl_msg_put_string(request
, TCA_ACT_KIND
, "vlan");
1120 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1122 struct tc_vlan parm
= { .action
= TC_ACT_PIPE
,
1123 .v_action
= TCA_VLAN_ACT_POP
};
1125 nl_msg_put_unspec(request
, TCA_VLAN_PARMS
, &parm
, sizeof parm
);
1127 nl_msg_end_nested(request
, offset
);
1131 nl_msg_put_act_tunnel_key_release(struct ofpbuf
*request
)
1135 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
1136 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1138 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
1139 .t_action
= TCA_TUNNEL_KEY_ACT_RELEASE
};
1141 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
1143 nl_msg_end_nested(request
, offset
);
1147 nl_msg_put_act_tunnel_key_set(struct ofpbuf
*request
, ovs_be64 id
,
1148 ovs_be32 ipv4_src
, ovs_be32 ipv4_dst
,
1149 struct in6_addr
*ipv6_src
,
1150 struct in6_addr
*ipv6_dst
,
1155 nl_msg_put_string(request
, TCA_ACT_KIND
, "tunnel_key");
1156 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1158 struct tc_tunnel_key tun
= { .action
= TC_ACT_PIPE
,
1159 .t_action
= TCA_TUNNEL_KEY_ACT_SET
};
1161 nl_msg_put_unspec(request
, TCA_TUNNEL_KEY_PARMS
, &tun
, sizeof tun
);
1163 ovs_be32 id32
= be64_to_be32(id
);
1164 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_KEY_ID
, id32
);
1166 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_SRC
, ipv4_src
);
1167 nl_msg_put_be32(request
, TCA_TUNNEL_KEY_ENC_IPV4_DST
, ipv4_dst
);
1168 } else if (!is_all_zeros(ipv6_dst
, sizeof *ipv6_dst
)) {
1169 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_DST
,
1171 nl_msg_put_in6_addr(request
, TCA_TUNNEL_KEY_ENC_IPV6_SRC
,
1174 nl_msg_put_be16(request
, TCA_TUNNEL_KEY_ENC_DST_PORT
, tp_dst
);
1176 nl_msg_end_nested(request
, offset
);
1180 nl_msg_put_act_drop(struct ofpbuf
*request
)
1184 nl_msg_put_string(request
, TCA_ACT_KIND
, "gact");
1185 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1187 struct tc_gact p
= { .action
= TC_ACT_SHOT
};
1189 nl_msg_put_unspec(request
, TCA_GACT_PARMS
, &p
, sizeof p
);
1191 nl_msg_end_nested(request
, offset
);
1195 nl_msg_put_act_redirect(struct ofpbuf
*request
, int ifindex
)
1199 nl_msg_put_string(request
, TCA_ACT_KIND
, "mirred");
1200 offset
= nl_msg_start_nested(request
, TCA_ACT_OPTIONS
);
1202 struct tc_mirred m
= { .action
= TC_ACT_STOLEN
,
1203 .eaction
= TCA_EGRESS_REDIR
,
1204 .ifindex
= ifindex
};
1206 nl_msg_put_unspec(request
, TCA_MIRRED_PARMS
, &m
, sizeof m
);
1208 nl_msg_end_nested(request
, offset
);
1212 nl_msg_put_act_cookie(struct ofpbuf
*request
, struct tc_cookie
*ck
) {
1214 nl_msg_put_unspec(request
, TCA_ACT_COOKIE
, ck
->data
, ck
->len
);
1218 /* Given flower, a key_to_pedit map entry, calculates the rest,
1221 * mask, data - pointers of where read the first word of flower->key/mask.
1222 * current_offset - which offset to use for the first pedit action.
1223 * cnt - max pedits actions to use.
1224 * first_word_mask/last_word_mask - the mask to use for the first/last read
1225 * (as we read entire words). */
1227 calc_offsets(struct tc_flower
*flower
, struct flower_key_to_pedit
*m
,
1228 int *cur_offset
, int *cnt
, uint32_t *last_word_mask
,
1229 uint32_t *first_word_mask
, uint32_t **mask
, uint32_t **data
)
1231 int start_offset
, max_offset
, total_size
;
1232 int diff
, right_zero_bits
, left_zero_bits
;
1233 char *rewrite_key
= (void *) &flower
->rewrite
.key
;
1234 char *rewrite_mask
= (void *) &flower
->rewrite
.mask
;
1236 max_offset
= m
->offset
+ m
->size
;
1237 start_offset
= ROUND_DOWN(m
->offset
, 4);
1238 diff
= m
->offset
- start_offset
;
1239 total_size
= max_offset
- start_offset
;
1240 right_zero_bits
= 8 * (4 - (max_offset
% 4));
1241 left_zero_bits
= 8 * (m
->offset
- start_offset
);
1243 *cur_offset
= start_offset
;
1244 *cnt
= (total_size
/ 4) + (total_size
% 4 ? 1 : 0);
1245 *last_word_mask
= UINT32_MAX
>> right_zero_bits
;
1246 *first_word_mask
= UINT32_MAX
<< left_zero_bits
;
1247 *data
= (void *) (rewrite_key
+ m
->flower_offset
- diff
);
1248 *mask
= (void *) (rewrite_mask
+ m
->flower_offset
- diff
);
1252 csum_update_flag(struct tc_flower
*flower
,
1253 enum pedit_header_type htype
) {
1254 /* Explictily specifiy the csum flags so HW can return EOPNOTSUPP
1255 * if it doesn't support a checksum recalculation of some headers.
1256 * And since OVS allows a flow such as
1257 * eth(dst=<mac>),eth_type(0x0800) actions=set(ipv4(src=<new_ip>))
1258 * we need to force a more specific flow as this can, for example,
1259 * need a recalculation of icmp checksum if the packet that passes
1260 * is icmp and tcp checksum if its tcp. */
1263 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4
:
1264 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_IPV4HDR
;
1266 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6
:
1267 case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP
:
1268 case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP
:
1269 if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
1270 flower
->needs_full_ip_proto_mask
= true;
1271 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_TCP
;
1272 } else if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
1273 flower
->needs_full_ip_proto_mask
= true;
1274 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_UDP
;
1275 } else if (flower
->key
.ip_proto
== IPPROTO_ICMP
1276 || flower
->key
.ip_proto
== IPPROTO_ICMPV6
) {
1277 flower
->needs_full_ip_proto_mask
= true;
1278 flower
->csum_update_flags
|= TCA_CSUM_UPDATE_FLAG_ICMP
;
1280 VLOG_WARN_RL(&error_rl
,
1281 "can't offload rewrite of IP/IPV6 with ip_proto: %d",
1282 flower
->key
.ip_proto
);
1286 case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH
:
1287 return 0; /* success */
1289 case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK
:
1290 case __PEDIT_HDR_TYPE_MAX
:
1299 nl_msg_put_flower_rewrite_pedits(struct ofpbuf
*request
,
1300 struct tc_flower
*flower
)
1303 struct tc_pedit sel
;
1304 struct tc_pedit_key keys
[MAX_PEDIT_OFFSETS
];
1305 struct tc_pedit_key_ex keys_ex
[MAX_PEDIT_OFFSETS
];
1313 for (i
= 0; i
< ARRAY_SIZE(flower_pedit_map
); i
++) {
1314 struct flower_key_to_pedit
*m
= &flower_pedit_map
[i
];
1315 struct tc_pedit_key
*pedit_key
= NULL
;
1316 struct tc_pedit_key_ex
*pedit_key_ex
= NULL
;
1317 uint32_t *mask
, *data
, first_word_mask
, last_word_mask
;
1318 int cnt
= 0, cur_offset
= 0;
1324 calc_offsets(flower
, m
, &cur_offset
, &cnt
, &last_word_mask
,
1325 &first_word_mask
, &mask
, &data
);
1327 for (j
= 0; j
< cnt
; j
++, mask
++, data
++, cur_offset
+= 4) {
1328 uint32_t mask_word
= *mask
;
1331 mask_word
&= first_word_mask
;
1334 mask_word
&= last_word_mask
;
1339 if (sel
.sel
.nkeys
== MAX_PEDIT_OFFSETS
) {
1340 VLOG_WARN_RL(&error_rl
, "reached too many pedit offsets: %d",
1345 pedit_key
= &sel
.keys
[sel
.sel
.nkeys
];
1346 pedit_key_ex
= &sel
.keys_ex
[sel
.sel
.nkeys
];
1347 pedit_key_ex
->cmd
= TCA_PEDIT_KEY_EX_CMD_SET
;
1348 pedit_key_ex
->htype
= m
->htype
;
1349 pedit_key
->off
= cur_offset
;
1350 pedit_key
->mask
= ~mask_word
;
1351 pedit_key
->val
= *data
& mask_word
;
1354 err
= csum_update_flag(flower
, m
->htype
);
1359 if (flower
->needs_full_ip_proto_mask
) {
1360 flower
->mask
.ip_proto
= UINT8_MAX
;
1364 nl_msg_put_act_pedit(request
, &sel
.sel
, sel
.keys_ex
);
1370 nl_msg_put_flower_acts(struct ofpbuf
*request
, struct tc_flower
*flower
)
1375 offset
= nl_msg_start_nested(request
, TCA_FLOWER_ACT
);
1377 uint16_t act_index
= 1;
1380 if (flower
->rewrite
.rewrite
) {
1381 act_offset
= nl_msg_start_nested(request
, act_index
++);
1382 error
= nl_msg_put_flower_rewrite_pedits(request
, flower
);
1386 nl_msg_end_nested(request
, act_offset
);
1388 if (flower
->csum_update_flags
) {
1389 act_offset
= nl_msg_start_nested(request
, act_index
++);
1390 nl_msg_put_act_csum(request
, flower
->csum_update_flags
);
1391 nl_msg_end_nested(request
, act_offset
);
1394 if (flower
->tunnel
.tunnel
) {
1395 act_offset
= nl_msg_start_nested(request
, act_index
++);
1396 nl_msg_put_act_tunnel_key_release(request
);
1397 nl_msg_end_nested(request
, act_offset
);
1399 if (flower
->set
.set
) {
1400 act_offset
= nl_msg_start_nested(request
, act_index
++);
1401 nl_msg_put_act_tunnel_key_set(request
, flower
->set
.id
,
1402 flower
->set
.ipv4
.ipv4_src
,
1403 flower
->set
.ipv4
.ipv4_dst
,
1404 &flower
->set
.ipv6
.ipv6_src
,
1405 &flower
->set
.ipv6
.ipv6_dst
,
1406 flower
->set
.tp_dst
);
1407 nl_msg_end_nested(request
, act_offset
);
1409 if (flower
->vlan_pop
) {
1410 act_offset
= nl_msg_start_nested(request
, act_index
++);
1411 nl_msg_put_act_pop_vlan(request
);
1412 nl_msg_end_nested(request
, act_offset
);
1414 if (flower
->vlan_push_id
) {
1415 act_offset
= nl_msg_start_nested(request
, act_index
++);
1416 nl_msg_put_act_push_vlan(request
,
1417 flower
->vlan_push_id
,
1418 flower
->vlan_push_prio
);
1419 nl_msg_end_nested(request
, act_offset
);
1421 if (flower
->ifindex_out
) {
1422 act_offset
= nl_msg_start_nested(request
, act_index
++);
1423 nl_msg_put_act_redirect(request
, flower
->ifindex_out
);
1424 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
1425 nl_msg_end_nested(request
, act_offset
);
1427 act_offset
= nl_msg_start_nested(request
, act_index
++);
1428 nl_msg_put_act_drop(request
);
1429 nl_msg_put_act_cookie(request
, &flower
->act_cookie
);
1430 nl_msg_end_nested(request
, act_offset
);
1433 nl_msg_end_nested(request
, offset
);
1439 nl_msg_put_masked_value(struct ofpbuf
*request
, uint16_t type
,
1440 uint16_t mask_type
, const void *data
,
1441 const void *mask_data
, size_t len
)
1443 if (mask_type
!= TCA_FLOWER_UNSPEC
) {
1444 if (is_all_zeros(mask_data
, len
)) {
1447 nl_msg_put_unspec(request
, mask_type
, mask_data
, len
);
1449 nl_msg_put_unspec(request
, type
, data
, len
);
1453 nl_msg_put_flower_tunnel(struct ofpbuf
*request
, struct tc_flower
*flower
)
1455 ovs_be32 ipv4_src
= flower
->tunnel
.ipv4
.ipv4_src
;
1456 ovs_be32 ipv4_dst
= flower
->tunnel
.ipv4
.ipv4_dst
;
1457 struct in6_addr
*ipv6_src
= &flower
->tunnel
.ipv6
.ipv6_src
;
1458 struct in6_addr
*ipv6_dst
= &flower
->tunnel
.ipv6
.ipv6_dst
;
1459 ovs_be16 tp_dst
= flower
->tunnel
.tp_dst
;
1460 ovs_be32 id
= be64_to_be32(flower
->tunnel
.id
);
1462 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_KEY_ID
, id
);
1464 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_SRC
, ipv4_src
);
1465 nl_msg_put_be32(request
, TCA_FLOWER_KEY_ENC_IPV4_DST
, ipv4_dst
);
1466 } else if (!is_all_zeros(ipv6_dst
, sizeof *ipv6_dst
)) {
1467 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_SRC
, ipv6_src
);
1468 nl_msg_put_in6_addr(request
, TCA_FLOWER_KEY_ENC_IPV6_DST
, ipv6_dst
);
1470 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ENC_UDP_DST_PORT
, tp_dst
);
1473 #define FLOWER_PUT_MASKED_VALUE(member, type) \
1474 nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \
1475 &flower->mask.member, sizeof flower->key.member)
1478 nl_msg_put_flower_options(struct ofpbuf
*request
, struct tc_flower
*flower
)
1481 uint16_t host_eth_type
= ntohs(flower
->key
.eth_type
);
1482 bool is_vlan
= (host_eth_type
== ETH_TYPE_VLAN
);
1485 /* need to parse acts first as some acts require changing the matching
1486 * see csum_update_flag() */
1487 err
= nl_msg_put_flower_acts(request
, flower
);
1493 host_eth_type
= ntohs(flower
->key
.encap_eth_type
);
1496 FLOWER_PUT_MASKED_VALUE(dst_mac
, TCA_FLOWER_KEY_ETH_DST
);
1497 FLOWER_PUT_MASKED_VALUE(src_mac
, TCA_FLOWER_KEY_ETH_SRC
);
1499 if (host_eth_type
== ETH_P_IP
|| host_eth_type
== ETH_P_IPV6
) {
1500 if (flower
->mask
.ip_proto
&& flower
->key
.ip_proto
) {
1501 nl_msg_put_u8(request
, TCA_FLOWER_KEY_IP_PROTO
,
1502 flower
->key
.ip_proto
);
1505 if (flower
->mask
.flags
) {
1506 nl_msg_put_u32(request
, TCA_FLOWER_KEY_FLAGS
,
1507 htonl(flower
->key
.flags
));
1508 nl_msg_put_u32(request
, TCA_FLOWER_KEY_FLAGS_MASK
,
1509 htonl(flower
->mask
.flags
));
1512 if (flower
->key
.ip_proto
== IPPROTO_UDP
) {
1513 FLOWER_PUT_MASKED_VALUE(udp_src
, TCA_FLOWER_KEY_UDP_SRC
);
1514 FLOWER_PUT_MASKED_VALUE(udp_dst
, TCA_FLOWER_KEY_UDP_DST
);
1515 } else if (flower
->key
.ip_proto
== IPPROTO_TCP
) {
1516 FLOWER_PUT_MASKED_VALUE(tcp_src
, TCA_FLOWER_KEY_TCP_SRC
);
1517 FLOWER_PUT_MASKED_VALUE(tcp_dst
, TCA_FLOWER_KEY_TCP_DST
);
1518 FLOWER_PUT_MASKED_VALUE(tcp_flags
, TCA_FLOWER_KEY_TCP_FLAGS
);
1519 } else if (flower
->key
.ip_proto
== IPPROTO_SCTP
) {
1520 FLOWER_PUT_MASKED_VALUE(sctp_src
, TCA_FLOWER_KEY_SCTP_SRC
);
1521 FLOWER_PUT_MASKED_VALUE(sctp_dst
, TCA_FLOWER_KEY_SCTP_DST
);
1525 if (host_eth_type
== ETH_P_IP
) {
1526 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_src
, TCA_FLOWER_KEY_IPV4_SRC
);
1527 FLOWER_PUT_MASKED_VALUE(ipv4
.ipv4_dst
, TCA_FLOWER_KEY_IPV4_DST
);
1528 FLOWER_PUT_MASKED_VALUE(ip_ttl
, TCA_FLOWER_KEY_IP_TTL
);
1529 } else if (host_eth_type
== ETH_P_IPV6
) {
1530 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_src
, TCA_FLOWER_KEY_IPV6_SRC
);
1531 FLOWER_PUT_MASKED_VALUE(ipv6
.ipv6_dst
, TCA_FLOWER_KEY_IPV6_DST
);
1534 nl_msg_put_be16(request
, TCA_FLOWER_KEY_ETH_TYPE
, flower
->key
.eth_type
);
1537 if (flower
->key
.vlan_id
|| flower
->key
.vlan_prio
) {
1538 nl_msg_put_u16(request
, TCA_FLOWER_KEY_VLAN_ID
,
1539 flower
->key
.vlan_id
);
1540 nl_msg_put_u8(request
, TCA_FLOWER_KEY_VLAN_PRIO
,
1541 flower
->key
.vlan_prio
);
1543 if (flower
->key
.encap_eth_type
) {
1544 nl_msg_put_be16(request
, TCA_FLOWER_KEY_VLAN_ETH_TYPE
,
1545 flower
->key
.encap_eth_type
);
1549 nl_msg_put_u32(request
, TCA_FLOWER_FLAGS
, tc_get_tc_cls_policy(tc_policy
));
1551 if (flower
->tunnel
.tunnel
) {
1552 nl_msg_put_flower_tunnel(request
, flower
);
1559 tc_replace_flower(int ifindex
, uint16_t prio
, uint32_t handle
,
1560 struct tc_flower
*flower
)
1562 struct ofpbuf request
;
1563 struct tcmsg
*tcmsg
;
1564 struct ofpbuf
*reply
;
1566 size_t basic_offset
;
1567 uint16_t eth_type
= (OVS_FORCE
uint16_t) flower
->key
.eth_type
;
1569 tcmsg
= tc_make_request(ifindex
, RTM_NEWTFILTER
,
1570 NLM_F_CREATE
| NLM_F_ECHO
, &request
);
1571 tcmsg
->tcm_parent
= TC_INGRESS_PARENT
;
1572 tcmsg
->tcm_info
= tc_make_handle(prio
, eth_type
);
1573 tcmsg
->tcm_handle
= handle
;
1575 nl_msg_put_string(&request
, TCA_KIND
, "flower");
1576 basic_offset
= nl_msg_start_nested(&request
, TCA_OPTIONS
);
1578 error
= nl_msg_put_flower_options(&request
, flower
);
1581 ofpbuf_uninit(&request
);
1585 nl_msg_end_nested(&request
, basic_offset
);
1587 error
= tc_transact(&request
, &reply
);
1590 ofpbuf_at_assert(reply
, NLMSG_HDRLEN
, sizeof *tc
);
1592 flower
->prio
= tc_get_major(tc
->tcm_info
);
1593 flower
->handle
= tc
->tcm_handle
;
1594 ofpbuf_delete(reply
);
1601 tc_set_policy(const char *policy
)
1607 if (!strcmp(policy
, "skip_sw")) {
1608 tc_policy
= TC_POLICY_SKIP_SW
;
1609 } else if (!strcmp(policy
, "skip_hw")) {
1610 tc_policy
= TC_POLICY_SKIP_HW
;
1611 } else if (!strcmp(policy
, "none")) {
1612 tc_policy
= TC_POLICY_NONE
;
1614 VLOG_WARN("tc: Invalid policy '%s'", policy
);
1618 VLOG_INFO("tc: Using policy '%s'", policy
);