2 * Copyright (c) 2016 Mellanox Technologies, Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <linux/if_ether.h>
24 #include "openvswitch/hmap.h"
25 #include "openvswitch/match.h"
26 #include "openvswitch/ofpbuf.h"
27 #include "openvswitch/thread.h"
28 #include "openvswitch/types.h"
29 #include "openvswitch/util.h"
30 #include "openvswitch/vlog.h"
31 #include "netdev-linux.h"
32 #include "netdev-offload-provider.h"
33 #include "netdev-provider.h"
35 #include "netlink-socket.h"
36 #include "odp-netlink.h"
39 #include "unaligned.h"
41 #include "dpif-provider.h"
43 VLOG_DEFINE_THIS_MODULE(netdev_offload_tc
);
45 static struct vlog_rate_limit error_rl
= VLOG_RATE_LIMIT_INIT(60, 5);
47 static struct hmap ufid_to_tc
= HMAP_INITIALIZER(&ufid_to_tc
);
48 static struct hmap tc_to_ufid
= HMAP_INITIALIZER(&tc_to_ufid
);
49 static bool multi_mask_per_prio
= false;
50 static bool block_support
= false;
52 struct netlink_field
{
59 is_internal_port(const char *type
)
61 return !strcmp(type
, "internal");
64 static enum tc_qdisc_hook
65 get_tc_qdisc_hook(struct netdev
*netdev
)
67 return is_internal_port(netdev_get_type(netdev
)) ? TC_EGRESS
: TC_INGRESS
;
70 static struct netlink_field set_flower_map
[][4] = {
71 [OVS_KEY_ATTR_IPV4
] = {
72 { offsetof(struct ovs_key_ipv4
, ipv4_src
),
73 offsetof(struct tc_flower_key
, ipv4
.ipv4_src
),
74 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.ipv4_src
)
76 { offsetof(struct ovs_key_ipv4
, ipv4_dst
),
77 offsetof(struct tc_flower_key
, ipv4
.ipv4_dst
),
78 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.ipv4_dst
)
80 { offsetof(struct ovs_key_ipv4
, ipv4_ttl
),
81 offsetof(struct tc_flower_key
, ipv4
.rewrite_ttl
),
82 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.rewrite_ttl
)
84 { offsetof(struct ovs_key_ipv4
, ipv4_tos
),
85 offsetof(struct tc_flower_key
, ipv4
.rewrite_tos
),
86 MEMBER_SIZEOF(struct tc_flower_key
, ipv4
.rewrite_tos
)
89 [OVS_KEY_ATTR_IPV6
] = {
90 { offsetof(struct ovs_key_ipv6
, ipv6_src
),
91 offsetof(struct tc_flower_key
, ipv6
.ipv6_src
),
92 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.ipv6_src
)
94 { offsetof(struct ovs_key_ipv6
, ipv6_dst
),
95 offsetof(struct tc_flower_key
, ipv6
.ipv6_dst
),
96 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.ipv6_dst
)
98 { offsetof(struct ovs_key_ipv6
, ipv6_hlimit
),
99 offsetof(struct tc_flower_key
, ipv6
.rewrite_hlimit
),
100 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.rewrite_hlimit
)
102 { offsetof(struct ovs_key_ipv6
, ipv6_tclass
),
103 offsetof(struct tc_flower_key
, ipv6
.rewrite_tclass
),
104 MEMBER_SIZEOF(struct tc_flower_key
, ipv6
.rewrite_tclass
)
107 [OVS_KEY_ATTR_ETHERNET
] = {
108 { offsetof(struct ovs_key_ethernet
, eth_src
),
109 offsetof(struct tc_flower_key
, src_mac
),
110 MEMBER_SIZEOF(struct tc_flower_key
, src_mac
)
112 { offsetof(struct ovs_key_ethernet
, eth_dst
),
113 offsetof(struct tc_flower_key
, dst_mac
),
114 MEMBER_SIZEOF(struct tc_flower_key
, dst_mac
)
117 [OVS_KEY_ATTR_ETHERTYPE
] = {
119 offsetof(struct tc_flower_key
, eth_type
),
120 MEMBER_SIZEOF(struct tc_flower_key
, eth_type
)
123 [OVS_KEY_ATTR_TCP
] = {
124 { offsetof(struct ovs_key_tcp
, tcp_src
),
125 offsetof(struct tc_flower_key
, tcp_src
),
126 MEMBER_SIZEOF(struct tc_flower_key
, tcp_src
)
128 { offsetof(struct ovs_key_tcp
, tcp_dst
),
129 offsetof(struct tc_flower_key
, tcp_dst
),
130 MEMBER_SIZEOF(struct tc_flower_key
, tcp_dst
)
133 [OVS_KEY_ATTR_UDP
] = {
134 { offsetof(struct ovs_key_udp
, udp_src
),
135 offsetof(struct tc_flower_key
, udp_src
),
136 MEMBER_SIZEOF(struct tc_flower_key
, udp_src
)
138 { offsetof(struct ovs_key_udp
, udp_dst
),
139 offsetof(struct tc_flower_key
, udp_dst
),
140 MEMBER_SIZEOF(struct tc_flower_key
, udp_dst
)
145 static struct ovs_mutex ufid_lock
= OVS_MUTEX_INITIALIZER
;
148 * struct ufid_tc_data - data entry for ufid-tc hashmaps.
149 * @ufid_to_tc_node: Element in @ufid_to_tc hash table by ufid key.
150 * @tc_to_ufid_node: Element in @tc_to_ufid hash table by tcf_id key.
151 * @ufid: ufid assigned to the flow
152 * @id: tc filter id (tcf_id)
153 * @netdev: netdev associated with the tc rule
155 struct ufid_tc_data
{
156 struct hmap_node ufid_to_tc_node
;
157 struct hmap_node tc_to_ufid_node
;
160 struct netdev
*netdev
;
164 del_ufid_tc_mapping_unlocked(const ovs_u128
*ufid
)
166 size_t ufid_hash
= hash_bytes(ufid
, sizeof *ufid
, 0);
167 struct ufid_tc_data
*data
;
169 HMAP_FOR_EACH_WITH_HASH (data
, ufid_to_tc_node
, ufid_hash
, &ufid_to_tc
) {
170 if (ovs_u128_equals(*ufid
, data
->ufid
)) {
179 hmap_remove(&ufid_to_tc
, &data
->ufid_to_tc_node
);
180 hmap_remove(&tc_to_ufid
, &data
->tc_to_ufid_node
);
181 netdev_close(data
->netdev
);
185 /* Remove matching ufid entry from ufid-tc hashmaps. */
187 del_ufid_tc_mapping(const ovs_u128
*ufid
)
189 ovs_mutex_lock(&ufid_lock
);
190 del_ufid_tc_mapping_unlocked(ufid
);
191 ovs_mutex_unlock(&ufid_lock
);
194 /* Wrapper function to delete filter and ufid tc mapping */
196 del_filter_and_ufid_mapping(struct tcf_id
*id
, const ovs_u128
*ufid
)
200 err
= tc_del_filter(id
);
201 del_ufid_tc_mapping(ufid
);
205 /* Add ufid entry to ufid_to_tc hashmap. */
207 add_ufid_tc_mapping(struct netdev
*netdev
, const ovs_u128
*ufid
,
210 struct ufid_tc_data
*new_data
= xzalloc(sizeof *new_data
);
211 size_t ufid_hash
= hash_bytes(ufid
, sizeof *ufid
, 0);
214 tc_hash
= hash_int(hash_int(id
->prio
, id
->handle
), id
->ifindex
);
215 tc_hash
= hash_int(id
->chain
, tc_hash
);
217 new_data
->ufid
= *ufid
;
219 new_data
->netdev
= netdev_ref(netdev
);
221 ovs_mutex_lock(&ufid_lock
);
222 hmap_insert(&ufid_to_tc
, &new_data
->ufid_to_tc_node
, ufid_hash
);
223 hmap_insert(&tc_to_ufid
, &new_data
->tc_to_ufid_node
, tc_hash
);
224 ovs_mutex_unlock(&ufid_lock
);
227 /* Get tc id from ufid_to_tc hashmap.
229 * Returns 0 if successful and fills id.
230 * Otherwise returns the error.
233 get_ufid_tc_mapping(const ovs_u128
*ufid
, struct tcf_id
*id
)
235 size_t ufid_hash
= hash_bytes(ufid
, sizeof *ufid
, 0);
236 struct ufid_tc_data
*data
;
238 ovs_mutex_lock(&ufid_lock
);
239 HMAP_FOR_EACH_WITH_HASH (data
, ufid_to_tc_node
, ufid_hash
, &ufid_to_tc
) {
240 if (ovs_u128_equals(*ufid
, data
->ufid
)) {
242 ovs_mutex_unlock(&ufid_lock
);
246 ovs_mutex_unlock(&ufid_lock
);
251 /* Find ufid entry in ufid_to_tc hashmap using tcf_id id.
252 * The result is saved in ufid.
254 * Returns true on success.
257 find_ufid(struct netdev
*netdev
, struct tcf_id
*id
, ovs_u128
*ufid
)
259 struct ufid_tc_data
*data
;
262 tc_hash
= hash_int(hash_int(id
->prio
, id
->handle
), id
->ifindex
);
263 tc_hash
= hash_int(id
->chain
, tc_hash
);
265 ovs_mutex_lock(&ufid_lock
);
266 HMAP_FOR_EACH_WITH_HASH (data
, tc_to_ufid_node
, tc_hash
, &tc_to_ufid
) {
267 if (netdev
== data
->netdev
&& is_tcf_id_eq(&data
->id
, id
)) {
272 ovs_mutex_unlock(&ufid_lock
);
274 return (data
!= NULL
);
277 struct prio_map_data
{
278 struct hmap_node node
;
279 struct tc_flower_key mask
;
284 /* Get free prio for tc flower
285 * If prio is already allocated for mask/eth_type combination then return it.
286 * If not assign new prio.
288 * Return prio on success or 0 if we are out of prios.
291 get_prio_for_tc_flower(struct tc_flower
*flower
)
293 static struct hmap prios
= HMAP_INITIALIZER(&prios
);
294 static struct ovs_mutex prios_lock
= OVS_MUTEX_INITIALIZER
;
295 static uint16_t last_prio
= TC_RESERVED_PRIORITY_MAX
;
296 size_t key_len
= sizeof(struct tc_flower_key
);
297 size_t hash
= hash_int((OVS_FORCE
uint32_t) flower
->key
.eth_type
, 0);
298 struct prio_map_data
*data
;
299 struct prio_map_data
*new_data
;
301 if (!multi_mask_per_prio
) {
302 hash
= hash_bytes(&flower
->mask
, key_len
, hash
);
305 /* We can use the same prio for same mask/eth combination but must have
306 * different prio if not. Flower classifier will reject same prio for
307 * different mask combination unless multi mask per prio is supported. */
308 ovs_mutex_lock(&prios_lock
);
309 HMAP_FOR_EACH_WITH_HASH (data
, node
, hash
, &prios
) {
310 if ((multi_mask_per_prio
311 || !memcmp(&flower
->mask
, &data
->mask
, key_len
))
312 && data
->protocol
== flower
->key
.eth_type
) {
313 ovs_mutex_unlock(&prios_lock
);
318 if (last_prio
== UINT16_MAX
) {
319 /* last_prio can overflow if there will be many different kinds of
320 * flows which shouldn't happen organically. */
321 ovs_mutex_unlock(&prios_lock
);
325 new_data
= xzalloc(sizeof *new_data
);
326 memcpy(&new_data
->mask
, &flower
->mask
, key_len
);
327 new_data
->prio
= ++last_prio
;
328 new_data
->protocol
= flower
->key
.eth_type
;
329 hmap_insert(&prios
, &new_data
->node
, hash
);
330 ovs_mutex_unlock(&prios_lock
);
332 return new_data
->prio
;
336 get_block_id_from_netdev(struct netdev
*netdev
)
339 return netdev_get_block_id(netdev
);
346 netdev_tc_flow_flush(struct netdev
*netdev
)
348 struct ufid_tc_data
*data
, *next
;
351 ovs_mutex_lock(&ufid_lock
);
352 HMAP_FOR_EACH_SAFE (data
, next
, tc_to_ufid_node
, &tc_to_ufid
) {
353 if (data
->netdev
!= netdev
) {
357 err
= tc_del_filter(&data
->id
);
359 del_ufid_tc_mapping_unlocked(&data
->ufid
);
362 ovs_mutex_unlock(&ufid_lock
);
368 netdev_tc_flow_dump_create(struct netdev
*netdev
,
369 struct netdev_flow_dump
**dump_out
,
372 enum tc_qdisc_hook hook
= get_tc_qdisc_hook(netdev
);
373 struct netdev_flow_dump
*dump
;
374 uint32_t block_id
= 0;
379 ifindex
= netdev_get_ifindex(netdev
);
381 VLOG_ERR_RL(&error_rl
, "dump_create: failed to get ifindex for %s: %s",
382 netdev_get_name(netdev
), ovs_strerror(-ifindex
));
386 block_id
= get_block_id_from_netdev(netdev
);
387 dump
= xzalloc(sizeof *dump
);
388 dump
->nl_dump
= xzalloc(sizeof *dump
->nl_dump
);
389 dump
->netdev
= netdev_ref(netdev
);
392 id
= tc_make_tcf_id(ifindex
, block_id
, prio
, hook
);
393 tc_dump_flower_start(&id
, dump
->nl_dump
);
401 netdev_tc_flow_dump_destroy(struct netdev_flow_dump
*dump
)
403 nl_dump_done(dump
->nl_dump
);
404 netdev_close(dump
->netdev
);
411 parse_flower_rewrite_to_netlink_action(struct ofpbuf
*buf
,
412 struct tc_flower
*flower
)
414 char *mask
= (char *) &flower
->rewrite
.mask
;
415 char *data
= (char *) &flower
->rewrite
.key
;
417 for (int type
= 0; type
< ARRAY_SIZE(set_flower_map
); type
++) {
420 int len
= ovs_flow_key_attr_lens
[type
].len
;
426 for (int j
= 0; j
< ARRAY_SIZE(set_flower_map
[type
]); j
++) {
427 struct netlink_field
*f
= &set_flower_map
[type
][j
];
433 if (!is_all_zeros(mask
+ f
->flower_offset
, f
->size
)) {
435 nested
= nl_msg_start_nested(buf
,
436 OVS_ACTION_ATTR_SET_MASKED
);
437 put
= nl_msg_put_unspec_zero(buf
, type
, len
* 2);
440 memcpy(put
+ f
->offset
, data
+ f
->flower_offset
, f
->size
);
441 memcpy(put
+ len
+ f
->offset
,
442 mask
+ f
->flower_offset
, f
->size
);
447 nl_msg_end_nested(buf
, nested
);
452 static void parse_tc_flower_geneve_opts(struct tc_action
*action
,
455 int tun_opt_len
= action
->encap
.data
.present
.len
;
463 geneve_off
= nl_msg_start_nested(buf
, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS
);
464 while (tun_opt_len
) {
465 struct geneve_opt
*opt
;
467 opt
= &action
->encap
.data
.opts
.gnv
[idx
];
468 nl_msg_put(buf
, opt
, sizeof(struct geneve_opt
) + opt
->length
* 4);
469 idx
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
470 tun_opt_len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
472 nl_msg_end_nested(buf
, geneve_off
);
476 flower_tun_opt_to_match(struct match
*match
, struct tc_flower
*flower
)
478 struct geneve_opt
*opt
, *opt_mask
;
481 memcpy(match
->flow
.tunnel
.metadata
.opts
.gnv
,
482 flower
->key
.tunnel
.metadata
.opts
.gnv
,
483 flower
->key
.tunnel
.metadata
.present
.len
);
484 match
->flow
.tunnel
.metadata
.present
.len
=
485 flower
->key
.tunnel
.metadata
.present
.len
;
486 match
->flow
.tunnel
.flags
|= FLOW_TNL_F_UDPIF
;
487 memcpy(match
->wc
.masks
.tunnel
.metadata
.opts
.gnv
,
488 flower
->mask
.tunnel
.metadata
.opts
.gnv
,
489 flower
->mask
.tunnel
.metadata
.present
.len
);
491 len
= flower
->key
.tunnel
.metadata
.present
.len
;
493 opt
= &match
->flow
.tunnel
.metadata
.opts
.gnv
[cnt
];
494 opt_mask
= &match
->wc
.masks
.tunnel
.metadata
.opts
.gnv
[cnt
];
496 opt_mask
->length
= 0x1f;
498 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
499 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
502 match
->wc
.masks
.tunnel
.metadata
.present
.len
=
503 flower
->mask
.tunnel
.metadata
.present
.len
;
504 match
->wc
.masks
.tunnel
.flags
|= FLOW_TNL_F_UDPIF
;
508 parse_tc_flower_to_stats(struct tc_flower
*flower
,
509 struct dpif_flow_stats
*stats
)
515 memset(stats
, 0, sizeof *stats
);
516 stats
->n_packets
= get_32aligned_u64(&flower
->stats
.n_packets
);
517 stats
->n_bytes
= get_32aligned_u64(&flower
->stats
.n_bytes
);
518 stats
->used
= flower
->lastused
;
522 parse_tc_flower_to_attrs(struct tc_flower
*flower
,
523 struct dpif_flow_attrs
*attrs
)
525 attrs
->offloaded
= (flower
->offloaded_state
== TC_OFFLOADED_STATE_IN_HW
||
526 flower
->offloaded_state
==
527 TC_OFFLOADED_STATE_UNDEFINED
);
528 attrs
->dp_layer
= "tc";
529 attrs
->dp_extra_info
= NULL
;
533 parse_tc_flower_terse_to_match(struct tc_flower
*flower
,
535 struct dpif_flow_stats
*stats
,
536 struct dpif_flow_attrs
*attrs
)
538 match_init_catchall(match
);
540 parse_tc_flower_to_stats(flower
, stats
);
541 parse_tc_flower_to_attrs(flower
, attrs
);
547 parse_tc_flower_to_match(struct tc_flower
*flower
,
549 struct nlattr
**actions
,
550 struct dpif_flow_stats
*stats
,
551 struct dpif_flow_attrs
*attrs
,
556 struct tc_flower_key
*key
= &flower
->key
;
557 struct tc_flower_key
*mask
= &flower
->mask
;
558 odp_port_t outport
= 0;
559 struct tc_action
*action
;
563 return parse_tc_flower_terse_to_match(flower
, match
, stats
, attrs
);
568 match_init_catchall(match
);
569 match_set_dl_src_masked(match
, key
->src_mac
, mask
->src_mac
);
570 match_set_dl_dst_masked(match
, key
->dst_mac
, mask
->dst_mac
);
572 if (eth_type_vlan(key
->eth_type
)) {
573 match
->flow
.vlans
[0].tpid
= key
->eth_type
;
574 match
->wc
.masks
.vlans
[0].tpid
= OVS_BE16_MAX
;
575 match_set_dl_vlan(match
, htons(key
->vlan_id
[0]), 0);
576 match_set_dl_vlan_pcp(match
, key
->vlan_prio
[0], 0);
578 if (eth_type_vlan(key
->encap_eth_type
[0])) {
579 match_set_dl_vlan(match
, htons(key
->vlan_id
[1]), 1);
580 match_set_dl_vlan_pcp(match
, key
->vlan_prio
[1], 1);
581 match_set_dl_type(match
, key
->encap_eth_type
[1]);
582 match
->flow
.vlans
[1].tpid
= key
->encap_eth_type
[0];
583 match
->wc
.masks
.vlans
[1].tpid
= OVS_BE16_MAX
;
585 match_set_dl_type(match
, key
->encap_eth_type
[0]);
587 flow_fix_vlan_tpid(&match
->flow
);
588 } else if (eth_type_mpls(key
->eth_type
)) {
589 match
->flow
.mpls_lse
[0] = key
->mpls_lse
& mask
->mpls_lse
;
590 match
->wc
.masks
.mpls_lse
[0] = mask
->mpls_lse
;
591 match_set_dl_type(match
, key
->encap_eth_type
[0]);
593 match_set_dl_type(match
, key
->eth_type
);
596 if (is_ip_any(&match
->flow
)) {
598 match_set_nw_proto(match
, key
->ip_proto
);
601 match_set_nw_tos_masked(match
, key
->ip_tos
, mask
->ip_tos
);
602 match_set_nw_ttl_masked(match
, key
->ip_ttl
, mask
->ip_ttl
);
606 uint8_t flags_mask
= 0;
608 if (mask
->flags
& TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT
) {
609 if (key
->flags
& TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT
) {
610 flags
|= FLOW_NW_FRAG_ANY
;
612 flags_mask
|= FLOW_NW_FRAG_ANY
;
615 if (mask
->flags
& TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST
) {
616 if (!(key
->flags
& TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST
)) {
617 flags
|= FLOW_NW_FRAG_LATER
;
619 flags_mask
|= FLOW_NW_FRAG_LATER
;
622 match_set_nw_frag_masked(match
, flags
, flags_mask
);
625 match_set_nw_src_masked(match
, key
->ipv4
.ipv4_src
, mask
->ipv4
.ipv4_src
);
626 match_set_nw_dst_masked(match
, key
->ipv4
.ipv4_dst
, mask
->ipv4
.ipv4_dst
);
628 match_set_ipv6_src_masked(match
,
629 &key
->ipv6
.ipv6_src
, &mask
->ipv6
.ipv6_src
);
630 match_set_ipv6_dst_masked(match
,
631 &key
->ipv6
.ipv6_dst
, &mask
->ipv6
.ipv6_dst
);
633 if (key
->ip_proto
== IPPROTO_TCP
) {
634 match_set_tp_dst_masked(match
, key
->tcp_dst
, mask
->tcp_dst
);
635 match_set_tp_src_masked(match
, key
->tcp_src
, mask
->tcp_src
);
636 match_set_tcp_flags_masked(match
, key
->tcp_flags
, mask
->tcp_flags
);
637 } else if (key
->ip_proto
== IPPROTO_UDP
) {
638 match_set_tp_dst_masked(match
, key
->udp_dst
, mask
->udp_dst
);
639 match_set_tp_src_masked(match
, key
->udp_src
, mask
->udp_src
);
640 } else if (key
->ip_proto
== IPPROTO_SCTP
) {
641 match_set_tp_dst_masked(match
, key
->sctp_dst
, mask
->sctp_dst
);
642 match_set_tp_src_masked(match
, key
->sctp_src
, mask
->sctp_src
);
645 if (mask
->ct_state
) {
646 uint8_t ct_statev
= 0, ct_statem
= 0;
648 if (mask
->ct_state
& TCA_FLOWER_KEY_CT_FLAGS_NEW
) {
649 if (key
->ct_state
& TCA_FLOWER_KEY_CT_FLAGS_NEW
) {
650 ct_statev
|= OVS_CS_F_NEW
;
652 ct_statem
|= OVS_CS_F_NEW
;
655 if (mask
->ct_state
& TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED
) {
656 if (key
->ct_state
& TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED
) {
657 ct_statev
|= OVS_CS_F_ESTABLISHED
;
659 ct_statem
|= OVS_CS_F_ESTABLISHED
;
662 if (mask
->ct_state
& TCA_FLOWER_KEY_CT_FLAGS_TRACKED
) {
663 if (key
->ct_state
& TCA_FLOWER_KEY_CT_FLAGS_TRACKED
) {
664 ct_statev
|= OVS_CS_F_TRACKED
;
666 ct_statem
|= OVS_CS_F_TRACKED
;
669 match_set_ct_state_masked(match
, ct_statev
, ct_statem
);
672 match_set_ct_zone_masked(match
, key
->ct_zone
, mask
->ct_zone
);
673 match_set_ct_mark_masked(match
, key
->ct_mark
, mask
->ct_mark
);
674 match_set_ct_label_masked(match
, key
->ct_label
, mask
->ct_label
);
677 if (flower
->tunnel
) {
678 if (flower
->mask
.tunnel
.id
) {
679 match_set_tun_id(match
, flower
->key
.tunnel
.id
);
680 match
->flow
.tunnel
.flags
|= FLOW_TNL_F_KEY
;
682 if (flower
->mask
.tunnel
.ipv4
.ipv4_dst
||
683 flower
->mask
.tunnel
.ipv4
.ipv4_src
) {
684 match_set_tun_dst_masked(match
,
685 flower
->key
.tunnel
.ipv4
.ipv4_dst
,
686 flower
->mask
.tunnel
.ipv4
.ipv4_dst
);
687 match_set_tun_src_masked(match
,
688 flower
->key
.tunnel
.ipv4
.ipv4_src
,
689 flower
->mask
.tunnel
.ipv4
.ipv4_src
);
690 } else if (ipv6_addr_is_set(&flower
->mask
.tunnel
.ipv6
.ipv6_dst
) ||
691 ipv6_addr_is_set(&flower
->mask
.tunnel
.ipv6
.ipv6_src
)) {
692 match_set_tun_ipv6_dst_masked(match
,
693 &flower
->key
.tunnel
.ipv6
.ipv6_dst
,
694 &flower
->mask
.tunnel
.ipv6
.ipv6_dst
);
695 match_set_tun_ipv6_src_masked(match
,
696 &flower
->key
.tunnel
.ipv6
.ipv6_src
,
697 &flower
->mask
.tunnel
.ipv6
.ipv6_src
);
699 if (flower
->key
.tunnel
.tos
) {
700 match_set_tun_tos_masked(match
, flower
->key
.tunnel
.tos
,
701 flower
->mask
.tunnel
.tos
);
703 if (flower
->key
.tunnel
.ttl
) {
704 match_set_tun_ttl_masked(match
, flower
->key
.tunnel
.ttl
,
705 flower
->mask
.tunnel
.ttl
);
707 if (flower
->mask
.tunnel
.tp_dst
) {
708 match_set_tun_tp_dst_masked(match
,
709 flower
->key
.tunnel
.tp_dst
,
710 flower
->mask
.tunnel
.tp_dst
);
712 if (flower
->mask
.tunnel
.tp_src
) {
713 match_set_tun_tp_src_masked(match
,
714 flower
->key
.tunnel
.tp_src
,
715 flower
->mask
.tunnel
.tp_src
);
717 if (flower
->key
.tunnel
.metadata
.present
.len
) {
718 flower_tun_opt_to_match(match
, flower
);
722 act_off
= nl_msg_start_nested(buf
, OVS_FLOW_ATTR_ACTIONS
);
724 action
= flower
->actions
;
725 for (i
= 0; i
< flower
->action_count
; i
++, action
++) {
726 switch (action
->type
) {
727 case TC_ACT_VLAN_POP
: {
728 nl_msg_put_flag(buf
, OVS_ACTION_ATTR_POP_VLAN
);
731 case TC_ACT_VLAN_PUSH
: {
732 struct ovs_action_push_vlan
*push
;
734 push
= nl_msg_put_unspec_zero(buf
, OVS_ACTION_ATTR_PUSH_VLAN
,
736 push
->vlan_tpid
= action
->vlan
.vlan_push_tpid
;
737 push
->vlan_tci
= htons(action
->vlan
.vlan_push_id
738 | (action
->vlan
.vlan_push_prio
<< 13)
742 case TC_ACT_MPLS_POP
: {
743 nl_msg_put_be16(buf
, OVS_ACTION_ATTR_POP_MPLS
,
747 case TC_ACT_MPLS_PUSH
: {
748 struct ovs_action_push_mpls
*push
;
749 ovs_be32 mpls_lse
= 0;
751 flow_set_mpls_lse_label(&mpls_lse
, action
->mpls
.label
);
752 flow_set_mpls_lse_tc(&mpls_lse
, action
->mpls
.tc
);
753 flow_set_mpls_lse_ttl(&mpls_lse
, action
->mpls
.ttl
);
754 flow_set_mpls_lse_bos(&mpls_lse
, action
->mpls
.bos
);
756 push
= nl_msg_put_unspec_zero(buf
, OVS_ACTION_ATTR_PUSH_MPLS
,
758 push
->mpls_ethertype
= action
->mpls
.proto
;
759 push
->mpls_lse
= mpls_lse
;
762 case TC_ACT_MPLS_SET
: {
763 size_t set_offset
= nl_msg_start_nested(buf
,
764 OVS_ACTION_ATTR_SET
);
765 struct ovs_key_mpls
*set_mpls
;
766 ovs_be32 mpls_lse
= 0;
768 flow_set_mpls_lse_label(&mpls_lse
, action
->mpls
.label
);
769 flow_set_mpls_lse_tc(&mpls_lse
, action
->mpls
.tc
);
770 flow_set_mpls_lse_ttl(&mpls_lse
, action
->mpls
.ttl
);
771 flow_set_mpls_lse_bos(&mpls_lse
, action
->mpls
.bos
);
773 set_mpls
= nl_msg_put_unspec_zero(buf
, OVS_KEY_ATTR_MPLS
,
775 set_mpls
->mpls_lse
= mpls_lse
;
776 nl_msg_end_nested(buf
, set_offset
);
780 parse_flower_rewrite_to_netlink_action(buf
, flower
);
784 size_t set_offset
= nl_msg_start_nested(buf
, OVS_ACTION_ATTR_SET
);
785 size_t tunnel_offset
=
786 nl_msg_start_nested(buf
, OVS_KEY_ATTR_TUNNEL
);
788 if (action
->encap
.id_present
) {
789 nl_msg_put_be64(buf
, OVS_TUNNEL_KEY_ATTR_ID
, action
->encap
.id
);
791 if (action
->encap
.ipv4
.ipv4_src
) {
792 nl_msg_put_be32(buf
, OVS_TUNNEL_KEY_ATTR_IPV4_SRC
,
793 action
->encap
.ipv4
.ipv4_src
);
795 if (action
->encap
.ipv4
.ipv4_dst
) {
796 nl_msg_put_be32(buf
, OVS_TUNNEL_KEY_ATTR_IPV4_DST
,
797 action
->encap
.ipv4
.ipv4_dst
);
799 if (ipv6_addr_is_set(&action
->encap
.ipv6
.ipv6_src
)) {
800 nl_msg_put_in6_addr(buf
, OVS_TUNNEL_KEY_ATTR_IPV6_SRC
,
801 &action
->encap
.ipv6
.ipv6_src
);
803 if (ipv6_addr_is_set(&action
->encap
.ipv6
.ipv6_dst
)) {
804 nl_msg_put_in6_addr(buf
, OVS_TUNNEL_KEY_ATTR_IPV6_DST
,
805 &action
->encap
.ipv6
.ipv6_dst
);
807 if (action
->encap
.tos
) {
808 nl_msg_put_u8(buf
, OVS_TUNNEL_KEY_ATTR_TOS
,
811 if (action
->encap
.ttl
) {
812 nl_msg_put_u8(buf
, OVS_TUNNEL_KEY_ATTR_TTL
,
815 if (action
->encap
.tp_dst
) {
816 nl_msg_put_be16(buf
, OVS_TUNNEL_KEY_ATTR_TP_DST
,
817 action
->encap
.tp_dst
);
819 if (!action
->encap
.no_csum
) {
820 nl_msg_put_u8(buf
, OVS_TUNNEL_KEY_ATTR_CSUM
,
821 !action
->encap
.no_csum
);
824 parse_tc_flower_geneve_opts(action
, buf
);
825 nl_msg_end_nested(buf
, tunnel_offset
);
826 nl_msg_end_nested(buf
, set_offset
);
829 case TC_ACT_OUTPUT
: {
830 if (action
->out
.ifindex_out
) {
832 netdev_ifindex_to_odp_port(action
->out
.ifindex_out
);
837 nl_msg_put_u32(buf
, OVS_ACTION_ATTR_OUTPUT
, odp_to_u32(outport
));
843 if (action
->ct
.clear
) {
844 nl_msg_put_flag(buf
, OVS_ACTION_ATTR_CT_CLEAR
);
848 ct_offset
= nl_msg_start_nested(buf
, OVS_ACTION_ATTR_CT
);
850 if (action
->ct
.commit
) {
851 nl_msg_put_flag(buf
, OVS_CT_ATTR_COMMIT
);
854 if (action
->ct
.zone
) {
855 nl_msg_put_u16(buf
, OVS_CT_ATTR_ZONE
, action
->ct
.zone
);
858 if (action
->ct
.mark_mask
) {
859 uint32_t mark_and_mask
[2] = { action
->ct
.mark
,
860 action
->ct
.mark_mask
};
861 nl_msg_put_unspec(buf
, OVS_CT_ATTR_MARK
, &mark_and_mask
,
862 sizeof mark_and_mask
);
865 if (!ovs_u128_is_zero(action
->ct
.label_mask
)) {
871 ct_label
= nl_msg_put_unspec_uninit(buf
,
874 ct_label
->key
= action
->ct
.label
;
875 ct_label
->mask
= action
->ct
.label_mask
;
878 if (action
->ct
.nat_type
) {
879 size_t nat_offset
= nl_msg_start_nested(buf
,
882 if (action
->ct
.nat_type
== TC_NAT_SRC
) {
883 nl_msg_put_flag(buf
, OVS_NAT_ATTR_SRC
);
884 } else if (action
->ct
.nat_type
== TC_NAT_DST
) {
885 nl_msg_put_flag(buf
, OVS_NAT_ATTR_DST
);
888 if (action
->ct
.range
.ip_family
== AF_INET
) {
889 nl_msg_put_be32(buf
, OVS_NAT_ATTR_IP_MIN
,
890 action
->ct
.range
.ipv4
.min
);
891 nl_msg_put_be32(buf
, OVS_NAT_ATTR_IP_MAX
,
892 action
->ct
.range
.ipv4
.max
);
893 } else if (action
->ct
.range
.ip_family
== AF_INET6
) {
894 nl_msg_put_in6_addr(buf
, OVS_NAT_ATTR_IP_MIN
,
895 &action
->ct
.range
.ipv6
.min
);
896 nl_msg_put_in6_addr(buf
, OVS_NAT_ATTR_IP_MAX
,
897 &action
->ct
.range
.ipv6
.max
);
900 if (action
->ct
.range
.port
.min
) {
901 nl_msg_put_u16(buf
, OVS_NAT_ATTR_PROTO_MIN
,
902 ntohs(action
->ct
.range
.port
.min
));
903 if (action
->ct
.range
.port
.max
) {
904 nl_msg_put_u16(buf
, OVS_NAT_ATTR_PROTO_MAX
,
905 ntohs(action
->ct
.range
.port
.max
));
909 nl_msg_end_nested(buf
, nat_offset
);
912 nl_msg_end_nested(buf
, ct_offset
);
916 nl_msg_put_u32(buf
, OVS_ACTION_ATTR_RECIRC
, action
->chain
);
922 nl_msg_end_nested(buf
, act_off
);
924 *actions
= ofpbuf_at_assert(buf
, act_off
, sizeof(struct nlattr
));
926 parse_tc_flower_to_stats(flower
, stats
);
927 parse_tc_flower_to_attrs(flower
, attrs
);
933 netdev_tc_flow_dump_next(struct netdev_flow_dump
*dump
,
935 struct nlattr
**actions
,
936 struct dpif_flow_stats
*stats
,
937 struct dpif_flow_attrs
*attrs
,
939 struct ofpbuf
*rbuffer
,
940 struct ofpbuf
*wbuffer
)
942 struct netdev
*netdev
= dump
->netdev
;
943 struct ofpbuf nl_flow
;
946 id
= tc_make_tcf_id(netdev_get_ifindex(netdev
),
947 get_block_id_from_netdev(netdev
),
949 get_tc_qdisc_hook(netdev
));
951 while (nl_dump_next(dump
->nl_dump
, &nl_flow
, rbuffer
)) {
952 struct tc_flower flower
;
954 if (parse_netlink_to_tc_flower(&nl_flow
, &id
, &flower
)) {
958 if (parse_tc_flower_to_match(&flower
, match
, actions
, stats
, attrs
,
959 wbuffer
, dump
->terse
)) {
963 if (flower
.act_cookie
.len
) {
964 *ufid
= *((ovs_u128
*) flower
.act_cookie
.data
);
965 } else if (!find_ufid(netdev
, &id
, ufid
)) {
969 match
->wc
.masks
.in_port
.odp_port
= u32_to_odp(UINT32_MAX
);
970 match
->flow
.in_port
.odp_port
= dump
->port
;
971 match_set_recirc_id(match
, id
.chain
);
980 parse_mpls_set_action(struct tc_flower
*flower
, struct tc_action
*action
,
981 const struct nlattr
*set
)
983 const struct ovs_key_mpls
*mpls_set
= nl_attr_get(set
);
985 action
->mpls
.label
= mpls_lse_to_label(mpls_set
->mpls_lse
);
986 action
->mpls
.tc
= mpls_lse_to_tc(mpls_set
->mpls_lse
);
987 action
->mpls
.ttl
= mpls_lse_to_ttl(mpls_set
->mpls_lse
);
988 action
->mpls
.bos
= mpls_lse_to_bos(mpls_set
->mpls_lse
);
989 action
->type
= TC_ACT_MPLS_SET
;
990 flower
->action_count
++;
996 parse_put_flow_nat_action(struct tc_action
*action
,
997 const struct nlattr
*nat
,
1000 const struct nlattr
*nat_attr
;
1003 action
->ct
.nat_type
= TC_NAT_RESTORE
;
1004 NL_ATTR_FOR_EACH_UNSAFE (nat_attr
, nat_left
, nat
, nat_len
) {
1005 switch (nl_attr_type(nat_attr
)) {
1006 case OVS_NAT_ATTR_SRC
: {
1007 action
->ct
.nat_type
= TC_NAT_SRC
;
1010 case OVS_NAT_ATTR_DST
: {
1011 action
->ct
.nat_type
= TC_NAT_DST
;
1014 case OVS_NAT_ATTR_IP_MIN
: {
1015 if (nl_attr_get_size(nat_attr
) == sizeof(ovs_be32
)) {
1016 ovs_be32 addr
= nl_attr_get_be32(nat_attr
);
1018 action
->ct
.range
.ipv4
.min
= addr
;
1019 action
->ct
.range
.ip_family
= AF_INET
;
1021 struct in6_addr addr
= nl_attr_get_in6_addr(nat_attr
);
1023 action
->ct
.range
.ipv6
.min
= addr
;
1024 action
->ct
.range
.ip_family
= AF_INET6
;
1028 case OVS_NAT_ATTR_IP_MAX
: {
1029 if (nl_attr_get_size(nat_attr
) == sizeof(ovs_be32
)) {
1030 ovs_be32 addr
= nl_attr_get_be32(nat_attr
);
1032 action
->ct
.range
.ipv4
.max
= addr
;
1033 action
->ct
.range
.ip_family
= AF_INET
;
1035 struct in6_addr addr
= nl_attr_get_in6_addr(nat_attr
);
1037 action
->ct
.range
.ipv6
.max
= addr
;
1038 action
->ct
.range
.ip_family
= AF_INET6
;
1042 case OVS_NAT_ATTR_PROTO_MIN
: {
1043 action
->ct
.range
.port
.min
= htons(nl_attr_get_u16(nat_attr
));
1046 case OVS_NAT_ATTR_PROTO_MAX
: {
1047 action
->ct
.range
.port
.max
= htons(nl_attr_get_u16(nat_attr
));
1056 parse_put_flow_ct_action(struct tc_flower
*flower
,
1057 struct tc_action
*action
,
1058 const struct nlattr
*ct
,
1061 const struct nlattr
*ct_attr
;
1065 NL_ATTR_FOR_EACH_UNSAFE (ct_attr
, ct_left
, ct
, ct_len
) {
1066 switch (nl_attr_type(ct_attr
)) {
1067 case OVS_CT_ATTR_COMMIT
: {
1068 action
->ct
.commit
= true;
1071 case OVS_CT_ATTR_ZONE
: {
1072 action
->ct
.zone
= nl_attr_get_u16(ct_attr
);
1075 case OVS_CT_ATTR_NAT
: {
1076 const struct nlattr
*nat
= nl_attr_get(ct_attr
);
1077 const size_t nat_len
= nl_attr_get_size(ct_attr
);
1079 err
= parse_put_flow_nat_action(action
, nat
, nat_len
);
1085 case OVS_CT_ATTR_MARK
: {
1091 ct_mark
= nl_attr_get_unspec(ct_attr
, sizeof *ct_mark
);
1092 action
->ct
.mark
= ct_mark
->key
;
1093 action
->ct
.mark_mask
= ct_mark
->mask
;
1096 case OVS_CT_ATTR_LABELS
: {
1102 ct_label
= nl_attr_get_unspec(ct_attr
, sizeof *ct_label
);
1103 action
->ct
.label
= ct_label
->key
;
1104 action
->ct
.label_mask
= ct_label
->mask
;
1110 action
->type
= TC_ACT_CT
;
1111 flower
->action_count
++;
1116 parse_put_flow_set_masked_action(struct tc_flower
*flower
,
1117 struct tc_action
*action
,
1118 const struct nlattr
*set
,
1122 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 20);
1123 uint64_t set_stub
[1024 / 8];
1124 struct ofpbuf set_buf
= OFPBUF_STUB_INITIALIZER(set_stub
);
1125 char *set_data
, *set_mask
;
1126 char *key
= (char *) &flower
->rewrite
.key
;
1127 char *mask
= (char *) &flower
->rewrite
.mask
;
1128 const struct nlattr
*attr
;
1132 /* copy so we can set attr mask to 0 for used ovs key struct members */
1133 attr
= ofpbuf_put(&set_buf
, set
, set_len
);
1135 type
= nl_attr_type(attr
);
1136 size
= nl_attr_get_size(attr
) / 2;
1137 set_data
= CONST_CAST(char *, nl_attr_get(attr
));
1138 set_mask
= set_data
+ size
;
1140 if (type
>= ARRAY_SIZE(set_flower_map
)
1141 || !set_flower_map
[type
][0].size
) {
1142 VLOG_DBG_RL(&rl
, "unsupported set action type: %d", type
);
1143 ofpbuf_uninit(&set_buf
);
1147 for (i
= 0; i
< ARRAY_SIZE(set_flower_map
[type
]); i
++) {
1148 struct netlink_field
*f
= &set_flower_map
[type
][i
];
1154 /* copy masked value */
1155 for (j
= 0; j
< f
->size
; j
++) {
1156 char maskval
= hasmask
? set_mask
[f
->offset
+ j
] : 0xFF;
1158 key
[f
->flower_offset
+ j
] = maskval
& set_data
[f
->offset
+ j
];
1159 mask
[f
->flower_offset
+ j
] = maskval
;
1163 /* set its mask to 0 to show it's been used. */
1165 memset(set_mask
+ f
->offset
, 0, f
->size
);
1169 if (!is_all_zeros(&flower
->rewrite
, sizeof flower
->rewrite
)) {
1170 if (flower
->rewrite
.rewrite
== false) {
1171 flower
->rewrite
.rewrite
= true;
1172 action
->type
= TC_ACT_PEDIT
;
1173 flower
->action_count
++;
1177 if (hasmask
&& !is_all_zeros(set_mask
, size
)) {
1178 VLOG_DBG_RL(&rl
, "unsupported sub attribute of set action type %d",
1180 ofpbuf_uninit(&set_buf
);
1184 ofpbuf_uninit(&set_buf
);
1189 parse_put_flow_set_action(struct tc_flower
*flower
, struct tc_action
*action
,
1190 const struct nlattr
*set
, size_t set_len
)
1192 const struct nlattr
*tunnel
;
1193 const struct nlattr
*tun_attr
;
1194 size_t tun_left
, tunnel_len
;
1196 if (nl_attr_type(set
) == OVS_KEY_ATTR_MPLS
) {
1197 return parse_mpls_set_action(flower
, action
, set
);
1200 if (nl_attr_type(set
) != OVS_KEY_ATTR_TUNNEL
) {
1201 return parse_put_flow_set_masked_action(flower
, action
, set
,
1205 tunnel
= nl_attr_get(set
);
1206 tunnel_len
= nl_attr_get_size(set
);
1208 action
->type
= TC_ACT_ENCAP
;
1209 action
->encap
.id_present
= false;
1210 flower
->action_count
++;
1211 NL_ATTR_FOR_EACH_UNSAFE(tun_attr
, tun_left
, tunnel
, tunnel_len
) {
1212 switch (nl_attr_type(tun_attr
)) {
1213 case OVS_TUNNEL_KEY_ATTR_ID
: {
1214 action
->encap
.id
= nl_attr_get_be64(tun_attr
);
1215 action
->encap
.id_present
= true;
1218 case OVS_TUNNEL_KEY_ATTR_IPV4_SRC
: {
1219 action
->encap
.ipv4
.ipv4_src
= nl_attr_get_be32(tun_attr
);
1222 case OVS_TUNNEL_KEY_ATTR_IPV4_DST
: {
1223 action
->encap
.ipv4
.ipv4_dst
= nl_attr_get_be32(tun_attr
);
1226 case OVS_TUNNEL_KEY_ATTR_TOS
: {
1227 action
->encap
.tos
= nl_attr_get_u8(tun_attr
);
1230 case OVS_TUNNEL_KEY_ATTR_TTL
: {
1231 action
->encap
.ttl
= nl_attr_get_u8(tun_attr
);
1234 case OVS_TUNNEL_KEY_ATTR_IPV6_SRC
: {
1235 action
->encap
.ipv6
.ipv6_src
=
1236 nl_attr_get_in6_addr(tun_attr
);
1239 case OVS_TUNNEL_KEY_ATTR_IPV6_DST
: {
1240 action
->encap
.ipv6
.ipv6_dst
=
1241 nl_attr_get_in6_addr(tun_attr
);
1244 case OVS_TUNNEL_KEY_ATTR_TP_SRC
: {
1245 action
->encap
.tp_src
= nl_attr_get_be16(tun_attr
);
1248 case OVS_TUNNEL_KEY_ATTR_TP_DST
: {
1249 action
->encap
.tp_dst
= nl_attr_get_be16(tun_attr
);
1252 case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS
: {
1253 memcpy(action
->encap
.data
.opts
.gnv
, nl_attr_get(tun_attr
),
1254 nl_attr_get_size(tun_attr
));
1255 action
->encap
.data
.present
.len
= nl_attr_get_size(tun_attr
);
1265 test_key_and_mask(struct match
*match
)
1267 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 20);
1268 const struct flow
*key
= &match
->flow
;
1269 struct flow
*mask
= &match
->wc
.masks
;
1271 if (mask
->pkt_mark
) {
1272 VLOG_DBG_RL(&rl
, "offloading attribute pkt_mark isn't supported");
1276 if (mask
->dp_hash
) {
1277 VLOG_DBG_RL(&rl
, "offloading attribute dp_hash isn't supported");
1281 if (mask
->conj_id
) {
1282 VLOG_DBG_RL(&rl
, "offloading attribute conj_id isn't supported");
1286 if (mask
->skb_priority
) {
1287 VLOG_DBG_RL(&rl
, "offloading attribute skb_priority isn't supported");
1291 if (mask
->actset_output
) {
1293 "offloading attribute actset_output isn't supported");
1297 if (mask
->packet_type
&& key
->packet_type
) {
1298 VLOG_DBG_RL(&rl
, "offloading attribute packet_type isn't supported");
1301 mask
->packet_type
= 0;
1303 for (int i
= 0; i
< FLOW_N_REGS
; i
++) {
1304 if (mask
->regs
[i
]) {
1306 "offloading attribute regs[%d] isn't supported", i
);
1311 if (mask
->metadata
) {
1312 VLOG_DBG_RL(&rl
, "offloading attribute metadata isn't supported");
1317 VLOG_DBG_RL(&rl
, "offloading attribute nw_tos isn't supported");
1321 for (int i
= 1; i
< FLOW_MAX_MPLS_LABELS
; i
++) {
1322 if (mask
->mpls_lse
[i
]) {
1323 VLOG_DBG_RL(&rl
, "offloading multiple mpls_lses isn't supported");
1328 if (key
->dl_type
== htons(ETH_TYPE_IP
) &&
1329 key
->nw_proto
== IPPROTO_ICMP
) {
1332 "offloading attribute icmp_type isn't supported");
1337 "offloading attribute icmp_code isn't supported");
1340 } else if (key
->dl_type
== htons(ETH_TYPE_IP
) &&
1341 key
->nw_proto
== IPPROTO_IGMP
) {
1344 "offloading attribute igmp_type isn't supported");
1349 "offloading attribute igmp_code isn't supported");
1352 } else if (key
->dl_type
== htons(ETH_TYPE_IPV6
) &&
1353 key
->nw_proto
== IPPROTO_ICMPV6
) {
1356 "offloading attribute icmpv6_type isn't supported");
1361 "offloading attribute icmpv6_code isn't supported");
1364 } else if (key
->dl_type
== htons(OFP_DL_TYPE_NOT_ETH_TYPE
)) {
1366 "offloading of non-ethernet packets isn't supported");
1370 if (!is_all_zeros(mask
, sizeof *mask
)) {
1371 VLOG_DBG_RL(&rl
, "offloading isn't supported, unknown attribute");
1379 flower_match_to_tun_opt(struct tc_flower
*flower
, const struct flow_tnl
*tnl
,
1380 const struct flow_tnl
*tnl_mask
)
1382 struct geneve_opt
*opt
, *opt_mask
;
1385 memcpy(flower
->key
.tunnel
.metadata
.opts
.gnv
, tnl
->metadata
.opts
.gnv
,
1386 tnl
->metadata
.present
.len
);
1387 flower
->key
.tunnel
.metadata
.present
.len
= tnl
->metadata
.present
.len
;
1389 memcpy(flower
->mask
.tunnel
.metadata
.opts
.gnv
, tnl_mask
->metadata
.opts
.gnv
,
1390 tnl
->metadata
.present
.len
);
1392 len
= flower
->key
.tunnel
.metadata
.present
.len
;
1394 opt
= &flower
->key
.tunnel
.metadata
.opts
.gnv
[cnt
];
1395 opt_mask
= &flower
->mask
.tunnel
.metadata
.opts
.gnv
[cnt
];
1397 opt_mask
->length
= opt
->length
;
1399 cnt
+= sizeof(struct geneve_opt
) / 4 + opt
->length
;
1400 len
-= sizeof(struct geneve_opt
) + opt
->length
* 4;
1403 flower
->mask
.tunnel
.metadata
.present
.len
= tnl
->metadata
.present
.len
;
1407 netdev_tc_flow_put(struct netdev
*netdev
, struct match
*match
,
1408 struct nlattr
*actions
, size_t actions_len
,
1409 const ovs_u128
*ufid
, struct offload_info
*info
,
1410 struct dpif_flow_stats
*stats
)
1412 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 20);
1413 enum tc_qdisc_hook hook
= get_tc_qdisc_hook(netdev
);
1414 struct tc_flower flower
;
1415 const struct flow
*key
= &match
->flow
;
1416 struct flow
*mask
= &match
->wc
.masks
;
1417 const struct flow_tnl
*tnl
= &match
->flow
.tunnel
;
1418 const struct flow_tnl
*tnl_mask
= &mask
->tunnel
;
1419 struct tc_action
*action
;
1420 bool recirc_act
= false;
1421 uint32_t block_id
= 0;
1430 ifindex
= netdev_get_ifindex(netdev
);
1432 VLOG_ERR_RL(&error_rl
, "flow_put: failed to get ifindex for %s: %s",
1433 netdev_get_name(netdev
), ovs_strerror(-ifindex
));
1437 memset(&flower
, 0, sizeof flower
);
1439 chain
= key
->recirc_id
;
1440 mask
->recirc_id
= 0;
1442 if (flow_tnl_dst_is_set(&key
->tunnel
) ||
1443 flow_tnl_src_is_set(&key
->tunnel
)) {
1445 "tunnel: id %#" PRIx64
" src " IP_FMT
1446 " dst " IP_FMT
" tp_src %d tp_dst %d",
1447 ntohll(tnl
->tun_id
),
1448 IP_ARGS(tnl
->ip_src
), IP_ARGS(tnl
->ip_dst
),
1449 ntohs(tnl
->tp_src
), ntohs(tnl
->tp_dst
));
1450 flower
.key
.tunnel
.id
= tnl
->tun_id
;
1451 flower
.key
.tunnel
.ipv4
.ipv4_src
= tnl
->ip_src
;
1452 flower
.key
.tunnel
.ipv4
.ipv4_dst
= tnl
->ip_dst
;
1453 flower
.key
.tunnel
.ipv6
.ipv6_src
= tnl
->ipv6_src
;
1454 flower
.key
.tunnel
.ipv6
.ipv6_dst
= tnl
->ipv6_dst
;
1455 flower
.key
.tunnel
.tos
= tnl
->ip_tos
;
1456 flower
.key
.tunnel
.ttl
= tnl
->ip_ttl
;
1457 flower
.key
.tunnel
.tp_src
= tnl
->tp_src
;
1458 flower
.key
.tunnel
.tp_dst
= tnl
->tp_dst
;
1459 flower
.mask
.tunnel
.ipv4
.ipv4_src
= tnl_mask
->ip_src
;
1460 flower
.mask
.tunnel
.ipv4
.ipv4_dst
= tnl_mask
->ip_dst
;
1461 flower
.mask
.tunnel
.ipv6
.ipv6_src
= tnl_mask
->ipv6_src
;
1462 flower
.mask
.tunnel
.ipv6
.ipv6_dst
= tnl_mask
->ipv6_dst
;
1463 flower
.mask
.tunnel
.tos
= tnl_mask
->ip_tos
;
1464 flower
.mask
.tunnel
.ttl
= tnl_mask
->ip_ttl
;
1465 flower
.mask
.tunnel
.tp_src
= tnl_mask
->tp_src
;
1466 flower
.mask
.tunnel
.tp_dst
= tnl_mask
->tp_dst
;
1467 flower
.mask
.tunnel
.id
= (tnl
->flags
& FLOW_TNL_F_KEY
) ? tnl_mask
->tun_id
: 0;
1468 flower_match_to_tun_opt(&flower
, tnl
, tnl_mask
);
1469 flower
.tunnel
= true;
1471 memset(&mask
->tunnel
, 0, sizeof mask
->tunnel
);
1473 flower
.key
.eth_type
= key
->dl_type
;
1474 flower
.mask
.eth_type
= mask
->dl_type
;
1475 if (mask
->mpls_lse
[0]) {
1476 flower
.key
.mpls_lse
= key
->mpls_lse
[0];
1477 flower
.mask
.mpls_lse
= mask
->mpls_lse
[0];
1478 flower
.key
.encap_eth_type
[0] = flower
.key
.eth_type
;
1480 mask
->mpls_lse
[0] = 0;
1482 if (mask
->vlans
[0].tpid
&& eth_type_vlan(key
->vlans
[0].tpid
)) {
1483 flower
.key
.encap_eth_type
[0] = flower
.key
.eth_type
;
1484 flower
.mask
.encap_eth_type
[0] = flower
.mask
.eth_type
;
1485 flower
.key
.eth_type
= key
->vlans
[0].tpid
;
1486 flower
.mask
.eth_type
= mask
->vlans
[0].tpid
;
1488 if (mask
->vlans
[0].tci
) {
1489 ovs_be16 vid_mask
= mask
->vlans
[0].tci
& htons(VLAN_VID_MASK
);
1490 ovs_be16 pcp_mask
= mask
->vlans
[0].tci
& htons(VLAN_PCP_MASK
);
1491 ovs_be16 cfi
= mask
->vlans
[0].tci
& htons(VLAN_CFI
);
1493 if (cfi
&& key
->vlans
[0].tci
& htons(VLAN_CFI
)
1494 && (!vid_mask
|| vid_mask
== htons(VLAN_VID_MASK
))
1495 && (!pcp_mask
|| pcp_mask
== htons(VLAN_PCP_MASK
))
1496 && (vid_mask
|| pcp_mask
)) {
1498 flower
.key
.vlan_id
[0] = vlan_tci_to_vid(key
->vlans
[0].tci
);
1499 flower
.mask
.vlan_id
[0] = vlan_tci_to_vid(mask
->vlans
[0].tci
);
1500 VLOG_DBG_RL(&rl
, "vlan_id[0]: %d\n", flower
.key
.vlan_id
[0]);
1503 flower
.key
.vlan_prio
[0] = vlan_tci_to_pcp(key
->vlans
[0].tci
);
1504 flower
.mask
.vlan_prio
[0] = vlan_tci_to_pcp(mask
->vlans
[0].tci
);
1505 VLOG_DBG_RL(&rl
, "vlan_prio[0]: %d\n",
1506 flower
.key
.vlan_prio
[0]);
1508 } else if (mask
->vlans
[0].tci
== htons(0xffff) &&
1509 ntohs(key
->vlans
[0].tci
) == 0) {
1510 /* exact && no vlan */
1517 if (mask
->vlans
[1].tpid
&& eth_type_vlan(key
->vlans
[1].tpid
)) {
1518 flower
.key
.encap_eth_type
[1] = flower
.key
.encap_eth_type
[0];
1519 flower
.mask
.encap_eth_type
[1] = flower
.mask
.encap_eth_type
[0];
1520 flower
.key
.encap_eth_type
[0] = key
->vlans
[1].tpid
;
1521 flower
.mask
.encap_eth_type
[0] = mask
->vlans
[1].tpid
;
1523 if (mask
->vlans
[1].tci
) {
1524 ovs_be16 vid_mask
= mask
->vlans
[1].tci
& htons(VLAN_VID_MASK
);
1525 ovs_be16 pcp_mask
= mask
->vlans
[1].tci
& htons(VLAN_PCP_MASK
);
1526 ovs_be16 cfi
= mask
->vlans
[1].tci
& htons(VLAN_CFI
);
1528 if (cfi
&& key
->vlans
[1].tci
& htons(VLAN_CFI
)
1529 && (!vid_mask
|| vid_mask
== htons(VLAN_VID_MASK
))
1530 && (!pcp_mask
|| pcp_mask
== htons(VLAN_PCP_MASK
))
1531 && (vid_mask
|| pcp_mask
)) {
1533 flower
.key
.vlan_id
[1] = vlan_tci_to_vid(key
->vlans
[1].tci
);
1534 flower
.mask
.vlan_id
[1] = vlan_tci_to_vid(mask
->vlans
[1].tci
);
1535 VLOG_DBG_RL(&rl
, "vlan_id[1]: %d", flower
.key
.vlan_id
[1]);
1538 flower
.key
.vlan_prio
[1] = vlan_tci_to_pcp(key
->vlans
[1].tci
);
1539 flower
.mask
.vlan_prio
[1] = vlan_tci_to_pcp(mask
->vlans
[1].tci
);
1540 VLOG_DBG_RL(&rl
, "vlan_prio[1]: %d", flower
.key
.vlan_prio
[1]);
1542 } else if (mask
->vlans
[1].tci
== htons(0xffff) &&
1543 ntohs(key
->vlans
[1].tci
) == 0) {
1544 /* exact && no vlan */
1550 memset(mask
->vlans
, 0, sizeof mask
->vlans
);
1552 flower
.key
.dst_mac
= key
->dl_dst
;
1553 flower
.mask
.dst_mac
= mask
->dl_dst
;
1554 flower
.key
.src_mac
= key
->dl_src
;
1555 flower
.mask
.src_mac
= mask
->dl_src
;
1556 memset(&mask
->dl_dst
, 0, sizeof mask
->dl_dst
);
1557 memset(&mask
->dl_src
, 0, sizeof mask
->dl_src
);
1559 mask
->in_port
.odp_port
= 0;
1561 if (is_ip_any(key
)) {
1562 flower
.key
.ip_proto
= key
->nw_proto
;
1563 flower
.mask
.ip_proto
= mask
->nw_proto
;
1565 flower
.key
.ip_tos
= key
->nw_tos
;
1566 flower
.mask
.ip_tos
= mask
->nw_tos
;
1568 flower
.key
.ip_ttl
= key
->nw_ttl
;
1569 flower
.mask
.ip_ttl
= mask
->nw_ttl
;
1572 if (mask
->nw_frag
& FLOW_NW_FRAG_ANY
) {
1573 flower
.mask
.flags
|= TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT
;
1575 if (key
->nw_frag
& FLOW_NW_FRAG_ANY
) {
1576 flower
.key
.flags
|= TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT
;
1578 if (mask
->nw_frag
& FLOW_NW_FRAG_LATER
) {
1579 flower
.mask
.flags
|= TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST
;
1581 if (!(key
->nw_frag
& FLOW_NW_FRAG_LATER
)) {
1582 flower
.key
.flags
|= TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST
;
1590 if (key
->nw_proto
== IPPROTO_TCP
) {
1591 flower
.key
.tcp_dst
= key
->tp_dst
;
1592 flower
.mask
.tcp_dst
= mask
->tp_dst
;
1593 flower
.key
.tcp_src
= key
->tp_src
;
1594 flower
.mask
.tcp_src
= mask
->tp_src
;
1595 flower
.key
.tcp_flags
= key
->tcp_flags
;
1596 flower
.mask
.tcp_flags
= mask
->tcp_flags
;
1599 mask
->tcp_flags
= 0;
1600 } else if (key
->nw_proto
== IPPROTO_UDP
) {
1601 flower
.key
.udp_dst
= key
->tp_dst
;
1602 flower
.mask
.udp_dst
= mask
->tp_dst
;
1603 flower
.key
.udp_src
= key
->tp_src
;
1604 flower
.mask
.udp_src
= mask
->tp_src
;
1607 } else if (key
->nw_proto
== IPPROTO_SCTP
) {
1608 flower
.key
.sctp_dst
= key
->tp_dst
;
1609 flower
.mask
.sctp_dst
= mask
->tp_dst
;
1610 flower
.key
.sctp_src
= key
->tp_src
;
1611 flower
.mask
.sctp_src
= mask
->tp_src
;
1616 if (key
->dl_type
== htons(ETH_P_IP
)) {
1617 flower
.key
.ipv4
.ipv4_src
= key
->nw_src
;
1618 flower
.mask
.ipv4
.ipv4_src
= mask
->nw_src
;
1619 flower
.key
.ipv4
.ipv4_dst
= key
->nw_dst
;
1620 flower
.mask
.ipv4
.ipv4_dst
= mask
->nw_dst
;
1623 } else if (key
->dl_type
== htons(ETH_P_IPV6
)) {
1624 flower
.key
.ipv6
.ipv6_src
= key
->ipv6_src
;
1625 flower
.mask
.ipv6
.ipv6_src
= mask
->ipv6_src
;
1626 flower
.key
.ipv6
.ipv6_dst
= key
->ipv6_dst
;
1627 flower
.mask
.ipv6
.ipv6_dst
= mask
->ipv6_dst
;
1628 memset(&mask
->ipv6_src
, 0, sizeof mask
->ipv6_src
);
1629 memset(&mask
->ipv6_dst
, 0, sizeof mask
->ipv6_dst
);
1633 if (mask
->ct_state
) {
1634 if (mask
->ct_state
& OVS_CS_F_NEW
) {
1635 if (key
->ct_state
& OVS_CS_F_NEW
) {
1636 flower
.key
.ct_state
|= TCA_FLOWER_KEY_CT_FLAGS_NEW
;
1638 flower
.mask
.ct_state
|= TCA_FLOWER_KEY_CT_FLAGS_NEW
;
1641 if (mask
->ct_state
& OVS_CS_F_ESTABLISHED
) {
1642 if (key
->ct_state
& OVS_CS_F_ESTABLISHED
) {
1643 flower
.key
.ct_state
|= TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED
;
1645 flower
.mask
.ct_state
|= TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED
;
1648 if (mask
->ct_state
& OVS_CS_F_TRACKED
) {
1649 if (key
->ct_state
& OVS_CS_F_TRACKED
) {
1650 flower
.key
.ct_state
|= TCA_FLOWER_KEY_CT_FLAGS_TRACKED
;
1652 flower
.mask
.ct_state
|= TCA_FLOWER_KEY_CT_FLAGS_TRACKED
;
1655 if (flower
.key
.ct_state
& TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED
) {
1656 flower
.key
.ct_state
&= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW
);
1657 flower
.mask
.ct_state
&= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW
);
1663 if (mask
->ct_zone
) {
1664 flower
.key
.ct_zone
= key
->ct_zone
;
1665 flower
.mask
.ct_zone
= mask
->ct_zone
;
1669 if (mask
->ct_mark
) {
1670 flower
.key
.ct_mark
= key
->ct_mark
;
1671 flower
.mask
.ct_mark
= mask
->ct_mark
;
1675 if (!ovs_u128_is_zero(mask
->ct_label
)) {
1676 flower
.key
.ct_label
= key
->ct_label
;
1677 flower
.mask
.ct_label
= mask
->ct_label
;
1678 mask
->ct_label
= OVS_U128_ZERO
;
1681 /* ignore exact match on skb_mark of 0. */
1682 if (mask
->pkt_mark
== UINT32_MAX
&& !key
->pkt_mark
) {
1686 err
= test_key_and_mask(match
);
1691 NL_ATTR_FOR_EACH(nla
, left
, actions
, actions_len
) {
1692 if (flower
.action_count
>= TCA_ACT_MAX_NUM
) {
1693 VLOG_DBG_RL(&rl
, "Can only support %d actions", TCA_ACT_MAX_NUM
);
1696 action
= &flower
.actions
[flower
.action_count
];
1697 if (nl_attr_type(nla
) == OVS_ACTION_ATTR_OUTPUT
) {
1698 odp_port_t port
= nl_attr_get_odp_port(nla
);
1699 struct netdev
*outdev
= netdev_ports_get(port
, info
->dpif_class
);
1702 VLOG_DBG_RL(&rl
, "Can't find netdev for output port %d", port
);
1705 action
->out
.ifindex_out
= netdev_get_ifindex(outdev
);
1706 action
->out
.ingress
= is_internal_port(netdev_get_type(outdev
));
1707 action
->type
= TC_ACT_OUTPUT
;
1708 flower
.action_count
++;
1709 netdev_close(outdev
);
1710 } else if (nl_attr_type(nla
) == OVS_ACTION_ATTR_PUSH_VLAN
) {
1711 const struct ovs_action_push_vlan
*vlan_push
= nl_attr_get(nla
);
1713 action
->vlan
.vlan_push_tpid
= vlan_push
->vlan_tpid
;
1714 action
->vlan
.vlan_push_id
= vlan_tci_to_vid(vlan_push
->vlan_tci
);
1715 action
->vlan
.vlan_push_prio
= vlan_tci_to_pcp(vlan_push
->vlan_tci
);
1716 action
->type
= TC_ACT_VLAN_PUSH
;
1717 flower
.action_count
++;
1718 } else if (nl_attr_type(nla
) == OVS_ACTION_ATTR_POP_VLAN
) {
1719 action
->type
= TC_ACT_VLAN_POP
;
1720 flower
.action_count
++;
1721 } else if (nl_attr_type(nla
) == OVS_ACTION_ATTR_PUSH_MPLS
) {
1722 const struct ovs_action_push_mpls
*mpls_push
= nl_attr_get(nla
);
1724 action
->mpls
.proto
= mpls_push
->mpls_ethertype
;
1725 action
->mpls
.label
= mpls_lse_to_label(mpls_push
->mpls_lse
);
1726 action
->mpls
.tc
= mpls_lse_to_tc(mpls_push
->mpls_lse
);
1727 action
->mpls
.ttl
= mpls_lse_to_ttl(mpls_push
->mpls_lse
);
1728 action
->mpls
.bos
= mpls_lse_to_bos(mpls_push
->mpls_lse
);
1729 action
->type
= TC_ACT_MPLS_PUSH
;
1730 flower
.action_count
++;
1731 } else if (nl_attr_type(nla
) == OVS_ACTION_ATTR_POP_MPLS
) {
1732 action
->mpls
.proto
= nl_attr_get_be16(nla
);
1733 action
->type
= TC_ACT_MPLS_POP
;
1734 flower
.action_count
++;
1735 } else if (nl_attr_type(nla
) == OVS_ACTION_ATTR_SET
) {
1736 const struct nlattr
*set
= nl_attr_get(nla
);
1737 const size_t set_len
= nl_attr_get_size(nla
);
1739 err
= parse_put_flow_set_action(&flower
, action
, set
, set_len
);
1743 if (action
->type
== TC_ACT_ENCAP
) {
1744 action
->encap
.tp_dst
= info
->tp_dst_port
;
1745 action
->encap
.no_csum
= !info
->tunnel_csum_on
;
1747 } else if (nl_attr_type(nla
) == OVS_ACTION_ATTR_SET_MASKED
) {
1748 const struct nlattr
*set
= nl_attr_get(nla
);
1749 const size_t set_len
= nl_attr_get_size(nla
);
1751 err
= parse_put_flow_set_masked_action(&flower
, action
, set
,
1756 } else if (nl_attr_type(nla
) == OVS_ACTION_ATTR_CT
) {
1757 const struct nlattr
*ct
= nl_attr_get(nla
);
1758 const size_t ct_len
= nl_attr_get_size(nla
);
1760 err
= parse_put_flow_ct_action(&flower
, action
, ct
, ct_len
);
1764 } else if (nl_attr_type(nla
) == OVS_ACTION_ATTR_CT_CLEAR
) {
1765 action
->type
= TC_ACT_CT
;
1766 action
->ct
.clear
= true;
1767 flower
.action_count
++;
1768 } else if (nl_attr_type(nla
) == OVS_ACTION_ATTR_RECIRC
) {
1769 action
->type
= TC_ACT_GOTO
;
1770 action
->chain
= nl_attr_get_u32(nla
);
1771 flower
.action_count
++;
1774 VLOG_DBG_RL(&rl
, "unsupported put action type: %d",
1780 if ((chain
|| recirc_act
) && !info
->recirc_id_shared_with_tc
) {
1781 VLOG_ERR_RL(&error_rl
, "flow_put: recirc_id sharing not supported");
1785 if (get_ufid_tc_mapping(ufid
, &id
) == 0) {
1786 VLOG_DBG_RL(&rl
, "updating old handle: %d prio: %d",
1787 id
.handle
, id
.prio
);
1788 info
->tc_modify_flow_deleted
= !del_filter_and_ufid_mapping(&id
, ufid
);
1791 prio
= get_prio_for_tc_flower(&flower
);
1793 VLOG_ERR_RL(&rl
, "couldn't get tc prio: %s", ovs_strerror(ENOSPC
));
1797 flower
.act_cookie
.data
= ufid
;
1798 flower
.act_cookie
.len
= sizeof *ufid
;
1800 block_id
= get_block_id_from_netdev(netdev
);
1801 id
= tc_make_tcf_id_chain(ifindex
, block_id
, chain
, prio
, hook
);
1802 err
= tc_replace_flower(&id
, &flower
);
1805 memset(stats
, 0, sizeof *stats
);
1807 add_ufid_tc_mapping(netdev
, ufid
, &id
);
1814 netdev_tc_flow_get(struct netdev
*netdev
,
1815 struct match
*match
,
1816 struct nlattr
**actions
,
1817 const ovs_u128
*ufid
,
1818 struct dpif_flow_stats
*stats
,
1819 struct dpif_flow_attrs
*attrs
,
1822 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 20);
1823 struct tc_flower flower
;
1828 err
= get_ufid_tc_mapping(ufid
, &id
);
1833 VLOG_DBG_RL(&rl
, "flow get (dev %s prio %d handle %d block_id %d)",
1834 netdev_get_name(netdev
), id
.prio
, id
.handle
, id
.block_id
);
1836 err
= tc_get_flower(&id
, &flower
);
1838 VLOG_ERR_RL(&error_rl
, "flow get failed (dev %s prio %d handle %d): %s",
1839 netdev_get_name(netdev
), id
.prio
, id
.handle
,
1844 in_port
= netdev_ifindex_to_odp_port(id
.ifindex
);
1845 parse_tc_flower_to_match(&flower
, match
, actions
, stats
, attrs
, buf
, false);
1847 match
->wc
.masks
.in_port
.odp_port
= u32_to_odp(UINT32_MAX
);
1848 match
->flow
.in_port
.odp_port
= in_port
;
1849 match_set_recirc_id(match
, id
.chain
);
1855 netdev_tc_flow_del(struct netdev
*netdev OVS_UNUSED
,
1856 const ovs_u128
*ufid
,
1857 struct dpif_flow_stats
*stats
)
1859 struct tc_flower flower
;
1863 error
= get_ufid_tc_mapping(ufid
, &id
);
1869 memset(stats
, 0, sizeof *stats
);
1870 if (!tc_get_flower(&id
, &flower
)) {
1871 stats
->n_packets
= get_32aligned_u64(&flower
.stats
.n_packets
);
1872 stats
->n_bytes
= get_32aligned_u64(&flower
.stats
.n_bytes
);
1873 stats
->used
= flower
.lastused
;
1877 error
= del_filter_and_ufid_mapping(&id
, ufid
);
1883 probe_multi_mask_per_prio(int ifindex
)
1885 struct tc_flower flower
;
1886 struct tcf_id id1
, id2
;
1891 error
= tc_add_del_qdisc(ifindex
, true, block_id
, TC_INGRESS
);
1896 memset(&flower
, 0, sizeof flower
);
1898 flower
.key
.eth_type
= htons(ETH_P_IP
);
1899 flower
.mask
.eth_type
= OVS_BE16_MAX
;
1900 memset(&flower
.key
.dst_mac
, 0x11, sizeof flower
.key
.dst_mac
);
1901 memset(&flower
.mask
.dst_mac
, 0xff, sizeof flower
.mask
.dst_mac
);
1903 id1
= tc_make_tcf_id(ifindex
, block_id
, prio
, TC_INGRESS
);
1904 error
= tc_replace_flower(&id1
, &flower
);
1909 memset(&flower
.key
.src_mac
, 0x11, sizeof flower
.key
.src_mac
);
1910 memset(&flower
.mask
.src_mac
, 0xff, sizeof flower
.mask
.src_mac
);
1912 id2
= tc_make_tcf_id(ifindex
, block_id
, prio
, TC_INGRESS
);
1913 error
= tc_replace_flower(&id2
, &flower
);
1914 tc_del_filter(&id1
);
1920 tc_del_filter(&id2
);
1922 multi_mask_per_prio
= true;
1923 VLOG_INFO("probe tc: multiple masks on single tc prio is supported.");
1926 tc_add_del_qdisc(ifindex
, false, block_id
, TC_INGRESS
);
1930 probe_tc_block_support(int ifindex
)
1932 struct tc_flower flower
;
1933 uint32_t block_id
= 1;
1938 error
= tc_add_del_qdisc(ifindex
, true, block_id
, TC_INGRESS
);
1943 memset(&flower
, 0, sizeof flower
);
1945 flower
.key
.eth_type
= htons(ETH_P_IP
);
1946 flower
.mask
.eth_type
= OVS_BE16_MAX
;
1947 memset(&flower
.key
.dst_mac
, 0x11, sizeof flower
.key
.dst_mac
);
1948 memset(&flower
.mask
.dst_mac
, 0xff, sizeof flower
.mask
.dst_mac
);
1950 id
= tc_make_tcf_id(ifindex
, block_id
, prio
, TC_INGRESS
);
1951 error
= tc_replace_flower(&id
, &flower
);
1953 tc_add_del_qdisc(ifindex
, false, block_id
, TC_INGRESS
);
1956 block_support
= true;
1957 VLOG_INFO("probe tc: block offload is supported.");
1962 netdev_tc_init_flow_api(struct netdev
*netdev
)
1964 static struct ovsthread_once multi_mask_once
= OVSTHREAD_ONCE_INITIALIZER
;
1965 static struct ovsthread_once block_once
= OVSTHREAD_ONCE_INITIALIZER
;
1966 enum tc_qdisc_hook hook
= get_tc_qdisc_hook(netdev
);
1967 uint32_t block_id
= 0;
1972 ifindex
= netdev_get_ifindex(netdev
);
1974 VLOG_INFO("init: failed to get ifindex for %s: %s",
1975 netdev_get_name(netdev
), ovs_strerror(-ifindex
));
1979 block_id
= get_block_id_from_netdev(netdev
);
1981 /* Flush rules explicitly needed when we work with ingress_block,
1982 * so we will not fail with reattaching block to bond iface, for ex.
1984 id
= tc_make_tcf_id(ifindex
, block_id
, 0, hook
);
1987 /* make sure there is no ingress/egress qdisc */
1988 tc_add_del_qdisc(ifindex
, false, 0, hook
);
1990 if (ovsthread_once_start(&block_once
)) {
1991 probe_tc_block_support(ifindex
);
1992 /* Need to re-fetch block id as it depends on feature availability. */
1993 block_id
= get_block_id_from_netdev(netdev
);
1994 ovsthread_once_done(&block_once
);
1997 if (ovsthread_once_start(&multi_mask_once
)) {
1998 probe_multi_mask_per_prio(ifindex
);
1999 ovsthread_once_done(&multi_mask_once
);
2002 error
= tc_add_del_qdisc(ifindex
, true, block_id
, hook
);
2004 if (error
&& error
!= EEXIST
) {
2005 VLOG_INFO("failed adding ingress qdisc required for offloading: %s",
2006 ovs_strerror(error
));
2010 VLOG_INFO("added ingress qdisc to %s", netdev_get_name(netdev
));
2015 const struct netdev_flow_api netdev_offload_tc
= {
2017 .flow_flush
= netdev_tc_flow_flush
,
2018 .flow_dump_create
= netdev_tc_flow_dump_create
,
2019 .flow_dump_destroy
= netdev_tc_flow_dump_destroy
,
2020 .flow_dump_next
= netdev_tc_flow_dump_next
,
2021 .flow_put
= netdev_tc_flow_put
,
2022 .flow_get
= netdev_tc_flow_get
,
2023 .flow_del
= netdev_tc_flow_del
,
2024 .init_flow_api
= netdev_tc_init_flow_api
,