4 * Copyright 2017 6WIND S.A.
5 * Copyright 2017 Mellanox.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of 6WIND S.A. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include <sys/queue.h>
38 #include <rte_byteorder.h>
39 #include <rte_jhash.h>
40 #include <rte_malloc.h>
41 #include <rte_eth_tap.h>
43 #include <tap_autoconf.h>
44 #include <tap_tcmsgs.h>
46 #ifndef HAVE_TC_FLOWER
48 * For kernels < 4.2, this enum is not defined. Runtime checks will be made to
49 * avoid sending TC messages the kernel cannot understand.
56 TCA_FLOWER_KEY_ETH_DST, /* ETH_ALEN */
57 TCA_FLOWER_KEY_ETH_DST_MASK, /* ETH_ALEN */
58 TCA_FLOWER_KEY_ETH_SRC, /* ETH_ALEN */
59 TCA_FLOWER_KEY_ETH_SRC_MASK, /* ETH_ALEN */
60 TCA_FLOWER_KEY_ETH_TYPE, /* be16 */
61 TCA_FLOWER_KEY_IP_PROTO, /* u8 */
62 TCA_FLOWER_KEY_IPV4_SRC, /* be32 */
63 TCA_FLOWER_KEY_IPV4_SRC_MASK, /* be32 */
64 TCA_FLOWER_KEY_IPV4_DST, /* be32 */
65 TCA_FLOWER_KEY_IPV4_DST_MASK, /* be32 */
66 TCA_FLOWER_KEY_IPV6_SRC, /* struct in6_addr */
67 TCA_FLOWER_KEY_IPV6_SRC_MASK, /* struct in6_addr */
68 TCA_FLOWER_KEY_IPV6_DST, /* struct in6_addr */
69 TCA_FLOWER_KEY_IPV6_DST_MASK, /* struct in6_addr */
70 TCA_FLOWER_KEY_TCP_SRC, /* be16 */
71 TCA_FLOWER_KEY_TCP_DST, /* be16 */
72 TCA_FLOWER_KEY_UDP_SRC, /* be16 */
73 TCA_FLOWER_KEY_UDP_DST, /* be16 */
76 #ifndef HAVE_TC_VLAN_ID
78 /* TCA_FLOWER_FLAGS, */
79 TCA_FLOWER_KEY_VLAN_ID = TCA_FLOWER_KEY_UDP_DST + 2, /* be16 */
80 TCA_FLOWER_KEY_VLAN_PRIO, /* u8 */
81 TCA_FLOWER_KEY_VLAN_ETH_TYPE, /* be16 */
85 #define ISOLATE_HANDLE 1
88 LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
89 struct rte_flow *remote_flow; /* associated remote flow */
97 struct rte_flow *flow;
101 struct rte_flow_attr attr;
102 struct rte_flow_item items[2];
103 struct rte_flow_action actions[2];
107 static int tap_flow_create_eth(const struct rte_flow_item *item, void *data);
108 static int tap_flow_create_vlan(const struct rte_flow_item *item, void *data);
109 static int tap_flow_create_ipv4(const struct rte_flow_item *item, void *data);
110 static int tap_flow_create_ipv6(const struct rte_flow_item *item, void *data);
111 static int tap_flow_create_udp(const struct rte_flow_item *item, void *data);
112 static int tap_flow_create_tcp(const struct rte_flow_item *item, void *data);
114 tap_flow_validate(struct rte_eth_dev *dev,
115 const struct rte_flow_attr *attr,
116 const struct rte_flow_item items[],
117 const struct rte_flow_action actions[],
118 struct rte_flow_error *error);
120 static struct rte_flow *
121 tap_flow_create(struct rte_eth_dev *dev,
122 const struct rte_flow_attr *attr,
123 const struct rte_flow_item items[],
124 const struct rte_flow_action actions[],
125 struct rte_flow_error *error);
128 tap_flow_destroy(struct rte_eth_dev *dev,
129 struct rte_flow *flow,
130 struct rte_flow_error *error);
133 tap_flow_isolate(struct rte_eth_dev *dev,
135 struct rte_flow_error *error);
137 static const struct rte_flow_ops tap_flow_ops = {
138 .validate = tap_flow_validate,
139 .create = tap_flow_create,
140 .destroy = tap_flow_destroy,
141 .flush = tap_flow_flush,
142 .isolate = tap_flow_isolate,
145 /* Static initializer for items. */
147 (const enum rte_flow_item_type []){ \
148 __VA_ARGS__, RTE_FLOW_ITEM_TYPE_END, \
151 /* Structure to generate a simple graph of layers supported by the NIC. */
152 struct tap_flow_items {
153 /* Bit-mask corresponding to what is supported for this item. */
155 const unsigned int mask_sz; /* Bit-mask size in bytes. */
157 * Bit-mask corresponding to the default mask, if none is provided
158 * along with the item.
160 const void *default_mask;
162 * Conversion function from rte_flow to netlink attributes.
165 * rte_flow item to convert.
167 * Internal structure to store the conversion.
170 * 0 on success, negative value otherwise.
172 int (*convert)(const struct rte_flow_item *item, void *data);
173 /** List of possible following items. */
174 const enum rte_flow_item_type *const items;
177 /* Graph of supported items and associated actions. */
178 static const struct tap_flow_items tap_flow_items[] = {
179 [RTE_FLOW_ITEM_TYPE_END] = {
180 .items = ITEMS(RTE_FLOW_ITEM_TYPE_ETH),
182 [RTE_FLOW_ITEM_TYPE_ETH] = {
184 RTE_FLOW_ITEM_TYPE_VLAN,
185 RTE_FLOW_ITEM_TYPE_IPV4,
186 RTE_FLOW_ITEM_TYPE_IPV6),
187 .mask = &(const struct rte_flow_item_eth){
188 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
189 .src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
192 .mask_sz = sizeof(struct rte_flow_item_eth),
193 .default_mask = &rte_flow_item_eth_mask,
194 .convert = tap_flow_create_eth,
196 [RTE_FLOW_ITEM_TYPE_VLAN] = {
197 .items = ITEMS(RTE_FLOW_ITEM_TYPE_IPV4,
198 RTE_FLOW_ITEM_TYPE_IPV6),
199 .mask = &(const struct rte_flow_item_vlan){
201 /* DEI matching is not supported */
202 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
208 .mask_sz = sizeof(struct rte_flow_item_vlan),
209 .default_mask = &rte_flow_item_vlan_mask,
210 .convert = tap_flow_create_vlan,
212 [RTE_FLOW_ITEM_TYPE_IPV4] = {
213 .items = ITEMS(RTE_FLOW_ITEM_TYPE_UDP,
214 RTE_FLOW_ITEM_TYPE_TCP),
215 .mask = &(const struct rte_flow_item_ipv4){
222 .mask_sz = sizeof(struct rte_flow_item_ipv4),
223 .default_mask = &rte_flow_item_ipv4_mask,
224 .convert = tap_flow_create_ipv4,
226 [RTE_FLOW_ITEM_TYPE_IPV6] = {
227 .items = ITEMS(RTE_FLOW_ITEM_TYPE_UDP,
228 RTE_FLOW_ITEM_TYPE_TCP),
229 .mask = &(const struct rte_flow_item_ipv6){
232 "\xff\xff\xff\xff\xff\xff\xff\xff"
233 "\xff\xff\xff\xff\xff\xff\xff\xff",
236 "\xff\xff\xff\xff\xff\xff\xff\xff"
237 "\xff\xff\xff\xff\xff\xff\xff\xff",
242 .mask_sz = sizeof(struct rte_flow_item_ipv6),
243 .default_mask = &rte_flow_item_ipv6_mask,
244 .convert = tap_flow_create_ipv6,
246 [RTE_FLOW_ITEM_TYPE_UDP] = {
247 .mask = &(const struct rte_flow_item_udp){
253 .mask_sz = sizeof(struct rte_flow_item_udp),
254 .default_mask = &rte_flow_item_udp_mask,
255 .convert = tap_flow_create_udp,
257 [RTE_FLOW_ITEM_TYPE_TCP] = {
258 .mask = &(const struct rte_flow_item_tcp){
264 .mask_sz = sizeof(struct rte_flow_item_tcp),
265 .default_mask = &rte_flow_item_tcp_mask,
266 .convert = tap_flow_create_tcp,
271 * TC rules, by growing priority
273 * Remote netdevice Tap netdevice
274 * +-------------+-------------+ +-------------+-------------+
275 * | Ingress | Egress | | Ingress | Egress |
276 * |-------------|-------------| |-------------|-------------|
277 * | | \ / | | | REMOTE TX | prio 1
278 * | | \ / | | | \ / | prio 2
279 * | EXPLICIT | \ / | | EXPLICIT | \ / | .
280 * | | \ / | | | \ / | .
281 * | RULES | X | | RULES | X | .
282 * | . | / \ | | . | / \ | .
283 * | . | / \ | | . | / \ | .
284 * | . | / \ | | . | / \ | .
285 * | . | / \ | | . | / \ | .
287 * .... .... .... ....
289 * | . | \ / | | . | \ / | .
290 * | . | \ / | | . | \ / | .
291 * | | \ / | | | \ / |
292 * | LOCAL_MAC | \ / | | \ / | \ / | last prio - 5
293 * | PROMISC | X | | \ / | X | last prio - 4
294 * | ALLMULTI | / \ | | X | / \ | last prio - 3
295 * | BROADCAST | / \ | | / \ | / \ | last prio - 2
296 * | BROADCASTV6 | / \ | | / \ | / \ | last prio - 1
297 * | xx | / \ | | ISOLATE | / \ | last prio
298 * +-------------+-------------+ +-------------+-------------+
300 * The implicit flow rules are stored in a list in with mandatorily the last two
301 * being the ISOLATE and REMOTE_TX rules. e.g.:
303 * LOCAL_MAC -> BROADCAST -> BROADCASTV6 -> REMOTE_TX -> ISOLATE -> NULL
305 * That enables tap_flow_isolate() to remove implicit rules by popping the list
306 * head and remove it as long as it applies on the remote netdevice. The
307 * implicit rule for TX redirection is not removed, as isolate concerns only
311 static struct remote_rule implicit_rte_flows[TAP_REMOTE_MAX_IDX] = {
312 [TAP_REMOTE_LOCAL_MAC] = {
315 .priority = PRIORITY_MASK - TAP_REMOTE_LOCAL_MAC,
319 .type = RTE_FLOW_ITEM_TYPE_ETH,
320 .mask = &(const struct rte_flow_item_eth){
321 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
325 .type = RTE_FLOW_ITEM_TYPE_END,
327 .mirred = TCA_EGRESS_REDIR,
329 [TAP_REMOTE_BROADCAST] = {
332 .priority = PRIORITY_MASK - TAP_REMOTE_BROADCAST,
336 .type = RTE_FLOW_ITEM_TYPE_ETH,
337 .mask = &(const struct rte_flow_item_eth){
338 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
340 .spec = &(const struct rte_flow_item_eth){
341 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
345 .type = RTE_FLOW_ITEM_TYPE_END,
347 .mirred = TCA_EGRESS_MIRROR,
349 [TAP_REMOTE_BROADCASTV6] = {
352 .priority = PRIORITY_MASK - TAP_REMOTE_BROADCASTV6,
356 .type = RTE_FLOW_ITEM_TYPE_ETH,
357 .mask = &(const struct rte_flow_item_eth){
358 .dst.addr_bytes = "\x33\x33\x00\x00\x00\x00",
360 .spec = &(const struct rte_flow_item_eth){
361 .dst.addr_bytes = "\x33\x33\x00\x00\x00\x00",
365 .type = RTE_FLOW_ITEM_TYPE_END,
367 .mirred = TCA_EGRESS_MIRROR,
369 [TAP_REMOTE_PROMISC] = {
372 .priority = PRIORITY_MASK - TAP_REMOTE_PROMISC,
376 .type = RTE_FLOW_ITEM_TYPE_VOID,
379 .type = RTE_FLOW_ITEM_TYPE_END,
381 .mirred = TCA_EGRESS_MIRROR,
383 [TAP_REMOTE_ALLMULTI] = {
386 .priority = PRIORITY_MASK - TAP_REMOTE_ALLMULTI,
390 .type = RTE_FLOW_ITEM_TYPE_ETH,
391 .mask = &(const struct rte_flow_item_eth){
392 .dst.addr_bytes = "\x01\x00\x00\x00\x00\x00",
394 .spec = &(const struct rte_flow_item_eth){
395 .dst.addr_bytes = "\x01\x00\x00\x00\x00\x00",
399 .type = RTE_FLOW_ITEM_TYPE_END,
401 .mirred = TCA_EGRESS_MIRROR,
406 .priority = TAP_REMOTE_TX,
410 .type = RTE_FLOW_ITEM_TYPE_VOID,
413 .type = RTE_FLOW_ITEM_TYPE_END,
415 .mirred = TCA_EGRESS_MIRROR,
420 .priority = PRIORITY_MASK - TAP_ISOLATE,
424 .type = RTE_FLOW_ITEM_TYPE_VOID,
427 .type = RTE_FLOW_ITEM_TYPE_END,
433 * Make as much checks as possible on an Ethernet item, and if a flow is
434 * provided, fill it appropriately with Ethernet info.
437 * Item specification.
438 * @param[in, out] data
439 * Additional data structure to tell next layers we've been here.
442 * 0 if checks are alright, -1 otherwise.
445 tap_flow_create_eth(const struct rte_flow_item *item, void *data)
447 struct convert_data *info = (struct convert_data *)data;
448 const struct rte_flow_item_eth *spec = item->spec;
449 const struct rte_flow_item_eth *mask = item->mask;
450 struct rte_flow *flow = info->flow;
453 /* use default mask if none provided */
455 mask = tap_flow_items[RTE_FLOW_ITEM_TYPE_ETH].default_mask;
456 /* TC does not support eth_type masking. Only accept if exact match. */
457 if (mask->type && mask->type != 0xffff)
461 /* store eth_type for consistency if ipv4/6 pattern item comes next */
462 if (spec->type & mask->type)
463 info->eth_type = spec->type;
467 if (!is_zero_ether_addr(&spec->dst)) {
468 tap_nlattr_add(&msg->nh, TCA_FLOWER_KEY_ETH_DST, ETHER_ADDR_LEN,
469 &spec->dst.addr_bytes);
470 tap_nlattr_add(&msg->nh,
471 TCA_FLOWER_KEY_ETH_DST_MASK, ETHER_ADDR_LEN,
472 &mask->dst.addr_bytes);
474 if (!is_zero_ether_addr(&mask->src)) {
475 tap_nlattr_add(&msg->nh, TCA_FLOWER_KEY_ETH_SRC, ETHER_ADDR_LEN,
476 &spec->src.addr_bytes);
477 tap_nlattr_add(&msg->nh,
478 TCA_FLOWER_KEY_ETH_SRC_MASK, ETHER_ADDR_LEN,
479 &mask->src.addr_bytes);
485 * Make as much checks as possible on a VLAN item, and if a flow is provided,
486 * fill it appropriately with VLAN info.
489 * Item specification.
490 * @param[in, out] data
491 * Additional data structure to tell next layers we've been here.
494 * 0 if checks are alright, -1 otherwise.
497 tap_flow_create_vlan(const struct rte_flow_item *item, void *data)
499 struct convert_data *info = (struct convert_data *)data;
500 const struct rte_flow_item_vlan *spec = item->spec;
501 const struct rte_flow_item_vlan *mask = item->mask;
502 struct rte_flow *flow = info->flow;
505 /* use default mask if none provided */
507 mask = tap_flow_items[RTE_FLOW_ITEM_TYPE_VLAN].default_mask;
508 /* TC does not support tpid masking. Only accept if exact match. */
509 if (mask->tpid && mask->tpid != 0xffff)
511 /* Double-tagging not supported. */
512 if (spec && mask->tpid && spec->tpid != htons(ETH_P_8021Q))
518 msg->t.tcm_info = TC_H_MAKE(msg->t.tcm_info, htons(ETH_P_8021Q));
519 #define VLAN_PRIO(tci) ((tci) >> 13)
520 #define VLAN_ID(tci) ((tci) & 0xfff)
524 uint16_t tci = ntohs(spec->tci) & mask->tci;
525 uint16_t prio = VLAN_PRIO(tci);
526 uint8_t vid = VLAN_ID(tci);
529 tap_nlattr_add8(&msg->nh,
530 TCA_FLOWER_KEY_VLAN_PRIO, prio);
532 tap_nlattr_add16(&msg->nh,
533 TCA_FLOWER_KEY_VLAN_ID, vid);
539 * Make as much checks as possible on an IPv4 item, and if a flow is provided,
540 * fill it appropriately with IPv4 info.
543 * Item specification.
544 * @param[in, out] data
545 * Additional data structure to tell next layers we've been here.
548 * 0 if checks are alright, -1 otherwise.
551 tap_flow_create_ipv4(const struct rte_flow_item *item, void *data)
553 struct convert_data *info = (struct convert_data *)data;
554 const struct rte_flow_item_ipv4 *spec = item->spec;
555 const struct rte_flow_item_ipv4 *mask = item->mask;
556 struct rte_flow *flow = info->flow;
559 /* use default mask if none provided */
561 mask = tap_flow_items[RTE_FLOW_ITEM_TYPE_IPV4].default_mask;
562 /* check that previous eth type is compatible with ipv4 */
563 if (info->eth_type && info->eth_type != htons(ETH_P_IP))
565 /* store ip_proto for consistency if udp/tcp pattern item comes next */
567 info->ip_proto = spec->hdr.next_proto_id;
572 info->eth_type = htons(ETH_P_IP);
575 if (spec->hdr.dst_addr) {
576 tap_nlattr_add32(&msg->nh, TCA_FLOWER_KEY_IPV4_DST,
578 tap_nlattr_add32(&msg->nh, TCA_FLOWER_KEY_IPV4_DST_MASK,
581 if (spec->hdr.src_addr) {
582 tap_nlattr_add32(&msg->nh, TCA_FLOWER_KEY_IPV4_SRC,
584 tap_nlattr_add32(&msg->nh, TCA_FLOWER_KEY_IPV4_SRC_MASK,
587 if (spec->hdr.next_proto_id)
588 tap_nlattr_add8(&msg->nh, TCA_FLOWER_KEY_IP_PROTO,
589 spec->hdr.next_proto_id);
594 * Make as much checks as possible on an IPv6 item, and if a flow is provided,
595 * fill it appropriately with IPv6 info.
598 * Item specification.
599 * @param[in, out] data
600 * Additional data structure to tell next layers we've been here.
603 * 0 if checks are alright, -1 otherwise.
606 tap_flow_create_ipv6(const struct rte_flow_item *item, void *data)
608 struct convert_data *info = (struct convert_data *)data;
609 const struct rte_flow_item_ipv6 *spec = item->spec;
610 const struct rte_flow_item_ipv6 *mask = item->mask;
611 struct rte_flow *flow = info->flow;
612 uint8_t empty_addr[16] = { 0 };
615 /* use default mask if none provided */
617 mask = tap_flow_items[RTE_FLOW_ITEM_TYPE_IPV6].default_mask;
618 /* check that previous eth type is compatible with ipv6 */
619 if (info->eth_type && info->eth_type != htons(ETH_P_IPV6))
621 /* store ip_proto for consistency if udp/tcp pattern item comes next */
623 info->ip_proto = spec->hdr.proto;
628 info->eth_type = htons(ETH_P_IPV6);
631 if (memcmp(spec->hdr.dst_addr, empty_addr, 16)) {
632 tap_nlattr_add(&msg->nh, TCA_FLOWER_KEY_IPV6_DST,
633 sizeof(spec->hdr.dst_addr), &spec->hdr.dst_addr);
634 tap_nlattr_add(&msg->nh, TCA_FLOWER_KEY_IPV6_DST_MASK,
635 sizeof(mask->hdr.dst_addr), &mask->hdr.dst_addr);
637 if (memcmp(spec->hdr.src_addr, empty_addr, 16)) {
638 tap_nlattr_add(&msg->nh, TCA_FLOWER_KEY_IPV6_SRC,
639 sizeof(spec->hdr.src_addr), &spec->hdr.src_addr);
640 tap_nlattr_add(&msg->nh, TCA_FLOWER_KEY_IPV6_SRC_MASK,
641 sizeof(mask->hdr.src_addr), &mask->hdr.src_addr);
644 tap_nlattr_add8(&msg->nh,
645 TCA_FLOWER_KEY_IP_PROTO, spec->hdr.proto);
650 * Make as much checks as possible on a UDP item, and if a flow is provided,
651 * fill it appropriately with UDP info.
654 * Item specification.
655 * @param[in, out] data
656 * Additional data structure to tell next layers we've been here.
659 * 0 if checks are alright, -1 otherwise.
662 tap_flow_create_udp(const struct rte_flow_item *item, void *data)
664 struct convert_data *info = (struct convert_data *)data;
665 const struct rte_flow_item_udp *spec = item->spec;
666 const struct rte_flow_item_udp *mask = item->mask;
667 struct rte_flow *flow = info->flow;
670 /* use default mask if none provided */
672 mask = tap_flow_items[RTE_FLOW_ITEM_TYPE_UDP].default_mask;
673 /* check that previous ip_proto is compatible with udp */
674 if (info->ip_proto && info->ip_proto != IPPROTO_UDP)
676 /* TC does not support UDP port masking. Only accept if exact match. */
677 if ((mask->hdr.src_port && mask->hdr.src_port != 0xffff) ||
678 (mask->hdr.dst_port && mask->hdr.dst_port != 0xffff))
683 tap_nlattr_add8(&msg->nh, TCA_FLOWER_KEY_IP_PROTO, IPPROTO_UDP);
686 if (spec->hdr.dst_port & mask->hdr.dst_port)
687 tap_nlattr_add16(&msg->nh, TCA_FLOWER_KEY_UDP_DST,
689 if (spec->hdr.src_port & mask->hdr.src_port)
690 tap_nlattr_add16(&msg->nh, TCA_FLOWER_KEY_UDP_SRC,
696 * Make as much checks as possible on a TCP item, and if a flow is provided,
697 * fill it appropriately with TCP info.
700 * Item specification.
701 * @param[in, out] data
702 * Additional data structure to tell next layers we've been here.
705 * 0 if checks are alright, -1 otherwise.
708 tap_flow_create_tcp(const struct rte_flow_item *item, void *data)
710 struct convert_data *info = (struct convert_data *)data;
711 const struct rte_flow_item_tcp *spec = item->spec;
712 const struct rte_flow_item_tcp *mask = item->mask;
713 struct rte_flow *flow = info->flow;
716 /* use default mask if none provided */
718 mask = tap_flow_items[RTE_FLOW_ITEM_TYPE_TCP].default_mask;
719 /* check that previous ip_proto is compatible with tcp */
720 if (info->ip_proto && info->ip_proto != IPPROTO_TCP)
722 /* TC does not support TCP port masking. Only accept if exact match. */
723 if ((mask->hdr.src_port && mask->hdr.src_port != 0xffff) ||
724 (mask->hdr.dst_port && mask->hdr.dst_port != 0xffff))
729 tap_nlattr_add8(&msg->nh, TCA_FLOWER_KEY_IP_PROTO, IPPROTO_TCP);
732 if (spec->hdr.dst_port & mask->hdr.dst_port)
733 tap_nlattr_add16(&msg->nh, TCA_FLOWER_KEY_TCP_DST,
735 if (spec->hdr.src_port & mask->hdr.src_port)
736 tap_nlattr_add16(&msg->nh, TCA_FLOWER_KEY_TCP_SRC,
742 * Check support for a given item.
745 * Item specification.
747 * Bit-Mask size in bytes.
748 * @param[in] supported_mask
749 * Bit-mask covering supported fields to compare with spec, last and mask in
751 * @param[in] default_mask
752 * Bit-mask default mask if none is provided in \item.
758 tap_flow_item_validate(const struct rte_flow_item *item,
760 const uint8_t *supported_mask,
761 const uint8_t *default_mask)
765 /* An empty layer is allowed, as long as all fields are NULL */
766 if (!item->spec && (item->mask || item->last))
768 /* Is the item spec compatible with what the NIC supports? */
769 if (item->spec && !item->mask) {
771 const uint8_t *spec = item->spec;
773 for (i = 0; i < size; ++i)
774 if ((spec[i] | supported_mask[i]) != supported_mask[i])
776 /* Is the default mask compatible with what the NIC supports? */
777 for (i = 0; i < size; i++)
778 if ((default_mask[i] | supported_mask[i]) !=
782 /* Is the item last compatible with what the NIC supports? */
783 if (item->last && !item->mask) {
785 const uint8_t *spec = item->last;
787 for (i = 0; i < size; ++i)
788 if ((spec[i] | supported_mask[i]) != supported_mask[i])
791 /* Is the item mask compatible with what the NIC supports? */
794 const uint8_t *spec = item->mask;
796 for (i = 0; i < size; ++i)
797 if ((spec[i] | supported_mask[i]) != supported_mask[i])
801 * Once masked, Are item spec and item last equal?
802 * TC does not support range so anything else is invalid.
804 if (item->spec && item->last) {
807 const uint8_t *apply = default_mask;
812 for (i = 0; i < size; ++i) {
813 spec[i] = ((const uint8_t *)item->spec)[i] & apply[i];
814 last[i] = ((const uint8_t *)item->last)[i] & apply[i];
816 ret = memcmp(spec, last, size);
822 * Transform a DROP/PASSTHRU action item in the provided flow for TC.
824 * @param[in, out] flow
827 * Appropriate action to be set in the TCA_GACT_PARMS structure.
830 * 0 if checks are alright, -1 otherwise.
833 add_action_gact(struct rte_flow *flow, int action)
835 struct nlmsg *msg = &flow->msg;
836 size_t act_index = 1;
841 if (tap_nlattr_nested_start(msg, TCA_FLOWER_ACT) < 0)
843 if (tap_nlattr_nested_start(msg, act_index++) < 0)
845 tap_nlattr_add(&msg->nh, TCA_ACT_KIND, sizeof("gact"), "gact");
846 if (tap_nlattr_nested_start(msg, TCA_ACT_OPTIONS) < 0)
848 tap_nlattr_add(&msg->nh, TCA_GACT_PARMS, sizeof(p), &p);
849 tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
850 tap_nlattr_nested_finish(msg); /* nested act_index */
851 tap_nlattr_nested_finish(msg); /* nested TCA_FLOWER_ACT */
856 * Transform a MIRRED action item in the provided flow for TC.
858 * @param[in, out] flow
861 * Netdevice ifindex, where to mirror/redirect packet to.
862 * @param[in] action_type
863 * Either TCA_EGRESS_REDIR for redirection or TCA_EGRESS_MIRROR for mirroring.
866 * 0 if checks are alright, -1 otherwise.
869 add_action_mirred(struct rte_flow *flow, uint16_t ifindex, uint16_t action_type)
871 struct nlmsg *msg = &flow->msg;
872 size_t act_index = 1;
873 struct tc_mirred p = {
874 .eaction = action_type,
878 if (tap_nlattr_nested_start(msg, TCA_FLOWER_ACT) < 0)
880 if (tap_nlattr_nested_start(msg, act_index++) < 0)
882 tap_nlattr_add(&msg->nh, TCA_ACT_KIND, sizeof("mirred"), "mirred");
883 if (tap_nlattr_nested_start(msg, TCA_ACT_OPTIONS) < 0)
885 if (action_type == TCA_EGRESS_MIRROR)
886 p.action = TC_ACT_PIPE;
888 p.action = TC_ACT_STOLEN;
889 tap_nlattr_add(&msg->nh, TCA_MIRRED_PARMS, sizeof(p), &p);
890 tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
891 tap_nlattr_nested_finish(msg); /* nested act_index */
892 tap_nlattr_nested_finish(msg); /* nested TCA_FLOWER_ACT */
897 * Transform a QUEUE action item in the provided flow for TC.
899 * @param[in, out] flow
905 * 0 if checks are alright, -1 otherwise.
908 add_action_skbedit(struct rte_flow *flow, uint16_t queue)
910 struct nlmsg *msg = &flow->msg;
911 size_t act_index = 1;
912 struct tc_skbedit p = {
913 .action = TC_ACT_PIPE
916 if (tap_nlattr_nested_start(msg, TCA_FLOWER_ACT) < 0)
918 if (tap_nlattr_nested_start(msg, act_index++) < 0)
920 tap_nlattr_add(&msg->nh, TCA_ACT_KIND, sizeof("skbedit"), "skbedit");
921 if (tap_nlattr_nested_start(msg, TCA_ACT_OPTIONS) < 0)
923 tap_nlattr_add(&msg->nh, TCA_SKBEDIT_PARMS, sizeof(p), &p);
924 tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING, queue);
925 tap_nlattr_nested_finish(msg); /* nested TCA_ACT_OPTIONS */
926 tap_nlattr_nested_finish(msg); /* nested act_index */
927 tap_nlattr_nested_finish(msg); /* nested TCA_FLOWER_ACT */
932 * Validate a flow supported by TC.
933 * If flow param is not NULL, then also fill the netlink message inside.
936 * Pointer to private structure.
938 * Flow rule attributes.
940 * Pattern specification (list terminated by the END pattern item).
942 * Associated actions (list terminated by the END action).
944 * Perform verbose error reporting if not NULL.
945 * @param[in, out] flow
946 * Flow structure to update.
948 * If set to TCA_EGRESS_REDIR, provided actions will be replaced with a
949 * redirection to the tap netdevice, and the TC rule will be configured
950 * on the remote netdevice in pmd.
951 * If set to TCA_EGRESS_MIRROR, provided actions will be replaced with a
952 * mirroring to the tap netdevice, and the TC rule will be configured
953 * on the remote netdevice in pmd. Matching packets will thus be duplicated.
954 * If set to 0, the standard behavior is to be used: set correct actions for
955 * the TC rule, and apply it on the tap netdevice.
958 * 0 on success, a negative errno value otherwise and rte_errno is set.
961 priv_flow_process(struct pmd_internals *pmd,
962 const struct rte_flow_attr *attr,
963 const struct rte_flow_item items[],
964 const struct rte_flow_action actions[],
965 struct rte_flow_error *error,
966 struct rte_flow *flow,
969 const struct tap_flow_items *cur_item = tap_flow_items;
970 struct convert_data data = {
975 int action = 0; /* Only one action authorized for now */
977 if (attr->group > MAX_GROUP) {
979 error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
980 NULL, "group value too big: cannot exceed 15");
983 if (attr->priority > MAX_PRIORITY) {
985 error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
986 NULL, "priority value too big");
989 uint16_t group = attr->group << GROUP_SHIFT;
990 uint16_t prio = group | (attr->priority + PRIORITY_OFFSET);
991 flow->msg.t.tcm_info = TC_H_MAKE(prio << 16,
992 flow->msg.t.tcm_info);
997 * If attr->ingress, the rule applies on remote ingress
998 * to match incoming packets
999 * If attr->egress, the rule applies on tap ingress (as
1000 * seen from the kernel) to deal with packets going out
1001 * from the DPDK app.
1003 flow->msg.t.tcm_parent = TC_H_MAKE(TC_H_INGRESS, 0);
1005 /* Standard rule on tap egress (kernel standpoint). */
1006 flow->msg.t.tcm_parent =
1007 TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
1009 /* use flower filter type */
1010 tap_nlattr_add(&flow->msg.nh, TCA_KIND, sizeof("flower"), "flower");
1011 if (tap_nlattr_nested_start(&flow->msg, TCA_OPTIONS) < 0)
1012 goto exit_item_not_supported;
1014 for (; items->type != RTE_FLOW_ITEM_TYPE_END; ++items) {
1015 const struct tap_flow_items *token = NULL;
1019 if (items->type == RTE_FLOW_ITEM_TYPE_VOID)
1023 cur_item->items[i] != RTE_FLOW_ITEM_TYPE_END;
1025 if (cur_item->items[i] == items->type) {
1026 token = &tap_flow_items[items->type];
1031 goto exit_item_not_supported;
1033 err = tap_flow_item_validate(
1034 items, cur_item->mask_sz,
1035 (const uint8_t *)cur_item->mask,
1036 (const uint8_t *)cur_item->default_mask);
1038 goto exit_item_not_supported;
1039 if (flow && cur_item->convert) {
1040 err = cur_item->convert(items, &data);
1042 goto exit_item_not_supported;
1047 tap_nlattr_add16(&flow->msg.nh, TCA_FLOWER_KEY_ETH_TYPE,
1048 htons(ETH_P_8021Q));
1049 tap_nlattr_add16(&flow->msg.nh,
1050 TCA_FLOWER_KEY_VLAN_ETH_TYPE,
1052 data.eth_type : htons(ETH_P_ALL));
1053 } else if (data.eth_type) {
1054 tap_nlattr_add16(&flow->msg.nh, TCA_FLOWER_KEY_ETH_TYPE,
1058 if (mirred && flow) {
1059 uint16_t if_index = pmd->if_index;
1062 * If attr->egress && mirred, then this is a special
1063 * case where the rule must be applied on the tap, to
1064 * redirect packets coming from the DPDK App, out
1065 * through the remote netdevice.
1068 if_index = pmd->remote_if_index;
1069 if (add_action_mirred(flow, if_index, mirred) < 0)
1070 goto exit_action_not_supported;
1074 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) {
1077 if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) {
1079 } else if (actions->type == RTE_FLOW_ACTION_TYPE_DROP) {
1081 goto exit_action_not_supported;
1084 err = add_action_gact(flow, TC_ACT_SHOT);
1085 } else if (actions->type == RTE_FLOW_ACTION_TYPE_PASSTHRU) {
1087 goto exit_action_not_supported;
1090 err = add_action_gact(flow, TC_ACT_UNSPEC);
1091 } else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
1092 const struct rte_flow_action_queue *queue =
1093 (const struct rte_flow_action_queue *)
1097 goto exit_action_not_supported;
1100 (queue->index > pmd->dev->data->nb_rx_queues - 1))
1101 goto exit_action_not_supported;
1103 err = add_action_skbedit(flow, queue->index);
1104 } else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
1105 /* Fake RSS support. */
1106 const struct rte_flow_action_rss *rss =
1107 (const struct rte_flow_action_rss *)
1111 goto exit_action_not_supported;
1113 if (!rss || rss->num < 1 ||
1114 (rss->queue[0] > pmd->dev->data->nb_rx_queues - 1))
1115 goto exit_action_not_supported;
1117 err = add_action_skbedit(flow, rss->queue[0]);
1119 goto exit_action_not_supported;
1122 goto exit_action_not_supported;
1126 tap_nlattr_nested_finish(&flow->msg); /* nested TCA_OPTIONS */
1128 exit_item_not_supported:
1129 rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
1130 items, "item not supported");
1132 exit_action_not_supported:
1133 rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
1134 actions, "action not supported");
1143 * @see rte_flow_validate()
1147 tap_flow_validate(struct rte_eth_dev *dev,
1148 const struct rte_flow_attr *attr,
1149 const struct rte_flow_item items[],
1150 const struct rte_flow_action actions[],
1151 struct rte_flow_error *error)
1153 struct pmd_internals *pmd = dev->data->dev_private;
1155 return priv_flow_process(pmd, attr, items, actions, error, NULL, 0);
1159 * Set a unique handle in a flow.
1161 * The kernel supports TC rules with equal priority, as long as they use the
1162 * same matching fields (e.g.: dst mac and ipv4) with different values (and
1163 * full mask to ensure no collision is possible).
1164 * In those rules, the handle (uint32_t) is the part that would identify
1165 * specifically each rule.
1167 * On 32-bit architectures, the handle can simply be the flow's pointer address.
1168 * On 64-bit architectures, we rely on jhash(flow) to find a (sufficiently)
1171 * @param[in, out] flow
1172 * The flow that needs its handle set.
1175 tap_flow_set_handle(struct rte_flow *flow)
1177 uint32_t handle = 0;
1179 if (sizeof(flow) > 4)
1180 handle = rte_jhash(&flow, sizeof(flow), 1);
1182 handle = (uintptr_t)flow;
1183 /* must be at least 1 to avoid letting the kernel choose one for us */
1186 flow->msg.t.tcm_handle = handle;
1192 * @see rte_flow_create()
1195 static struct rte_flow *
1196 tap_flow_create(struct rte_eth_dev *dev,
1197 const struct rte_flow_attr *attr,
1198 const struct rte_flow_item items[],
1199 const struct rte_flow_action actions[],
1200 struct rte_flow_error *error)
1202 struct pmd_internals *pmd = dev->data->dev_private;
1203 struct rte_flow *remote_flow = NULL;
1204 struct rte_flow *flow = NULL;
1205 struct nlmsg *msg = NULL;
1208 if (!pmd->if_index) {
1209 rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
1211 "can't create rule, ifindex not found");
1215 * No rules configured through standard rte_flow should be set on the
1216 * priorities used by implicit rules.
1218 if ((attr->group == MAX_GROUP) &&
1219 attr->priority > (MAX_PRIORITY - TAP_REMOTE_MAX_IDX)) {
1221 error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
1222 NULL, "priority value too big");
1225 flow = rte_malloc(__func__, sizeof(struct rte_flow), 0);
1227 rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1228 NULL, "cannot allocate memory for rte_flow");
1232 tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER,
1233 NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
1234 msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
1235 tap_flow_set_handle(flow);
1236 if (priv_flow_process(pmd, attr, items, actions, error, flow, 0))
1238 err = tap_nl_send(pmd->nlsk_fd, &msg->nh);
1240 rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
1241 NULL, "couldn't send request to kernel");
1244 err = tap_nl_recv_ack(pmd->nlsk_fd);
1247 "Kernel refused TC filter rule creation (%d): %s\n",
1248 errno, strerror(errno));
1249 rte_flow_error_set(error, EEXIST, RTE_FLOW_ERROR_TYPE_HANDLE,
1251 "overlapping rules or Kernel too old for flower support");
1254 LIST_INSERT_HEAD(&pmd->flows, flow, next);
1256 * If a remote device is configured, a TC rule with identical items for
1257 * matching must be set on that device, with a single action: redirect
1258 * to the local pmd->if_index.
1260 if (pmd->remote_if_index) {
1261 remote_flow = rte_malloc(__func__, sizeof(struct rte_flow), 0);
1264 error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
1265 "cannot allocate memory for rte_flow");
1268 msg = &remote_flow->msg;
1269 /* set the rule if_index for the remote netdevice */
1271 msg, pmd->remote_if_index, RTM_NEWTFILTER,
1272 NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
1273 msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
1274 tap_flow_set_handle(remote_flow);
1275 if (priv_flow_process(pmd, attr, items, NULL,
1276 error, remote_flow, TCA_EGRESS_REDIR)) {
1278 error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1279 NULL, "rte flow rule validation failed");
1282 err = tap_nl_send(pmd->nlsk_fd, &msg->nh);
1285 error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1286 NULL, "Failure sending nl request");
1289 err = tap_nl_recv_ack(pmd->nlsk_fd);
1292 "Kernel refused TC filter rule creation (%d): %s\n",
1293 errno, strerror(errno));
1295 error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1297 "overlapping rules or Kernel too old for flower support");
1300 flow->remote_flow = remote_flow;
1305 rte_free(remote_flow);
1312 * Destroy a flow using pointer to pmd_internal.
1314 * @param[in, out] pmd
1315 * Pointer to private structure.
1317 * Pointer to the flow to destroy.
1318 * @param[in, out] error
1319 * Pointer to the flow error handler
1321 * @return 0 if the flow could be destroyed, -1 otherwise.
1324 tap_flow_destroy_pmd(struct pmd_internals *pmd,
1325 struct rte_flow *flow,
1326 struct rte_flow_error *error)
1328 struct rte_flow *remote_flow = flow->remote_flow;
1331 LIST_REMOVE(flow, next);
1332 flow->msg.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1333 flow->msg.nh.nlmsg_type = RTM_DELTFILTER;
1335 ret = tap_nl_send(pmd->nlsk_fd, &flow->msg.nh);
1337 rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
1338 NULL, "couldn't send request to kernel");
1341 ret = tap_nl_recv_ack(pmd->nlsk_fd);
1342 /* If errno is ENOENT, the rule is already no longer in the kernel. */
1343 if (ret < 0 && errno == ENOENT)
1347 "Kernel refused TC filter rule deletion (%d): %s\n",
1348 errno, strerror(errno));
1350 error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
1351 "couldn't receive kernel ack to our request");
1355 remote_flow->msg.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1356 remote_flow->msg.nh.nlmsg_type = RTM_DELTFILTER;
1358 ret = tap_nl_send(pmd->nlsk_fd, &remote_flow->msg.nh);
1361 error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1362 NULL, "Failure sending nl request");
1365 ret = tap_nl_recv_ack(pmd->nlsk_fd);
1366 if (ret < 0 && errno == ENOENT)
1370 "Kernel refused TC filter rule deletion (%d): %s\n",
1371 errno, strerror(errno));
1373 error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1374 NULL, "Failure trying to receive nl ack");
1380 rte_free(remote_flow);
1388 * @see rte_flow_destroy()
1392 tap_flow_destroy(struct rte_eth_dev *dev,
1393 struct rte_flow *flow,
1394 struct rte_flow_error *error)
1396 struct pmd_internals *pmd = dev->data->dev_private;
1398 return tap_flow_destroy_pmd(pmd, flow, error);
1402 * Enable/disable flow isolation.
1404 * @see rte_flow_isolate()
1408 tap_flow_isolate(struct rte_eth_dev *dev,
1410 struct rte_flow_error *error __rte_unused)
1412 struct pmd_internals *pmd = dev->data->dev_private;
1415 pmd->flow_isolate = 1;
1417 pmd->flow_isolate = 0;
1419 * If netdevice is there, setup appropriate flow rules immediately.
1420 * Otherwise it will be set when bringing up the netdevice (tun_alloc).
1422 if (!pmd->rxq[0].fd)
1425 struct rte_flow *flow;
1428 flow = LIST_FIRST(&pmd->implicit_flows);
1432 * Remove all implicit rules on the remote.
1433 * Keep the local rule to redirect packets on TX.
1434 * Keep also the last implicit local rule: ISOLATE.
1436 if (flow->msg.t.tcm_ifindex == pmd->if_index)
1438 if (tap_flow_destroy_pmd(pmd, flow, NULL) < 0)
1441 /* Switch the TC rule according to pmd->flow_isolate */
1442 if (tap_flow_implicit_create(pmd, TAP_ISOLATE) == -1)
1445 /* Switch the TC rule according to pmd->flow_isolate */
1446 if (tap_flow_implicit_create(pmd, TAP_ISOLATE) == -1)
1448 if (!pmd->remote_if_index)
1450 if (tap_flow_implicit_create(pmd, TAP_REMOTE_TX) < 0)
1452 if (tap_flow_implicit_create(pmd, TAP_REMOTE_LOCAL_MAC) < 0)
1454 if (tap_flow_implicit_create(pmd, TAP_REMOTE_BROADCAST) < 0)
1456 if (tap_flow_implicit_create(pmd, TAP_REMOTE_BROADCASTV6) < 0)
1458 if (dev->data->promiscuous &&
1459 tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC) < 0)
1461 if (dev->data->all_multicast &&
1462 tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI) < 0)
1467 pmd->flow_isolate = 0;
1468 return rte_flow_error_set(
1469 error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1470 "TC rule creation failed");
1474 * Destroy all flows.
1476 * @see rte_flow_flush()
1480 tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
1482 struct pmd_internals *pmd = dev->data->dev_private;
1483 struct rte_flow *flow;
1485 while (!LIST_EMPTY(&pmd->flows)) {
1486 flow = LIST_FIRST(&pmd->flows);
1487 if (tap_flow_destroy(dev, flow, error) < 0)
1494 * Add an implicit flow rule on the remote device to make sure traffic gets to
1495 * the tap netdevice from there.
1498 * Pointer to private structure.
1500 * The idx in the implicit_rte_flows array specifying which rule to apply.
1502 * @return -1 if the rule couldn't be applied, 0 otherwise.
1504 int tap_flow_implicit_create(struct pmd_internals *pmd,
1505 enum implicit_rule_index idx)
1507 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
1508 struct rte_flow_action *actions = implicit_rte_flows[idx].actions;
1509 struct rte_flow_action isolate_actions[2] = {
1511 .type = RTE_FLOW_ACTION_TYPE_END,
1514 struct rte_flow_item *items = implicit_rte_flows[idx].items;
1515 struct rte_flow_attr *attr = &implicit_rte_flows[idx].attr;
1516 struct rte_flow_item_eth eth_local = { .type = 0 };
1517 uint16_t if_index = pmd->remote_if_index;
1518 struct rte_flow *remote_flow = NULL;
1519 struct nlmsg *msg = NULL;
1521 struct rte_flow_item items_local[2] = {
1523 .type = items[0].type,
1525 .mask = items[0].mask,
1528 .type = items[1].type,
1532 remote_flow = rte_malloc(__func__, sizeof(struct rte_flow), 0);
1534 RTE_LOG(ERR, PMD, "Cannot allocate memory for rte_flow\n");
1537 msg = &remote_flow->msg;
1538 if (idx == TAP_REMOTE_TX) {
1539 if_index = pmd->if_index;
1540 } else if (idx == TAP_ISOLATE) {
1541 if_index = pmd->if_index;
1542 /* Don't be exclusive for this rule, it can be changed later. */
1543 flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE;
1544 isolate_actions[0].type = pmd->flow_isolate ?
1545 RTE_FLOW_ACTION_TYPE_DROP :
1546 RTE_FLOW_ACTION_TYPE_PASSTHRU;
1547 actions = isolate_actions;
1548 } else if (idx == TAP_REMOTE_LOCAL_MAC) {
1550 * eth addr couldn't be set in implicit_rte_flows[] as it is not
1551 * known at compile time.
1553 memcpy(ð_local.dst, &pmd->eth_addr, sizeof(pmd->eth_addr));
1554 items = items_local;
1556 tc_init_msg(msg, if_index, RTM_NEWTFILTER, flags);
1557 msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
1559 * The ISOLATE rule is always present and must have a static handle, as
1560 * the action is changed whether the feature is enabled (DROP) or
1561 * disabled (PASSTHRU).
1563 if (idx == TAP_ISOLATE)
1564 remote_flow->msg.t.tcm_handle = ISOLATE_HANDLE;
1566 tap_flow_set_handle(remote_flow);
1567 if (priv_flow_process(pmd, attr, items, actions, NULL,
1568 remote_flow, implicit_rte_flows[idx].mirred)) {
1569 RTE_LOG(ERR, PMD, "rte flow rule validation failed\n");
1572 err = tap_nl_send(pmd->nlsk_fd, &msg->nh);
1574 RTE_LOG(ERR, PMD, "Failure sending nl request\n");
1577 err = tap_nl_recv_ack(pmd->nlsk_fd);
1580 "Kernel refused TC filter rule creation (%d): %s\n",
1581 errno, strerror(errno));
1584 LIST_INSERT_HEAD(&pmd->implicit_flows, remote_flow, next);
1588 rte_free(remote_flow);
1593 * Remove specific implicit flow rule on the remote device.
1595 * @param[in, out] pmd
1596 * Pointer to private structure.
1598 * The idx in the implicit_rte_flows array specifying which rule to remove.
1600 * @return -1 if one of the implicit rules couldn't be created, 0 otherwise.
1602 int tap_flow_implicit_destroy(struct pmd_internals *pmd,
1603 enum implicit_rule_index idx)
1605 struct rte_flow *remote_flow;
1607 int idx_prio = implicit_rte_flows[idx].attr.priority + PRIORITY_OFFSET;
1609 for (remote_flow = LIST_FIRST(&pmd->implicit_flows);
1611 remote_flow = LIST_NEXT(remote_flow, next)) {
1612 cur_prio = (remote_flow->msg.t.tcm_info >> 16) & PRIORITY_MASK;
1613 if (cur_prio != idx_prio)
1615 return tap_flow_destroy_pmd(pmd, remote_flow, NULL);
1621 * Destroy all implicit flows.
1623 * @see rte_flow_flush()
1626 tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
1628 struct rte_flow *remote_flow;
1630 while (!LIST_EMPTY(&pmd->implicit_flows)) {
1631 remote_flow = LIST_FIRST(&pmd->implicit_flows);
1632 if (tap_flow_destroy_pmd(pmd, remote_flow, error) < 0)
1639 * Manage filter operations.
1642 * Pointer to Ethernet device structure.
1643 * @param filter_type
1646 * Operation to perform.
1648 * Pointer to operation-specific structure.
1651 * 0 on success, negative errno value on failure.
1654 tap_dev_filter_ctrl(struct rte_eth_dev *dev,
1655 enum rte_filter_type filter_type,
1656 enum rte_filter_op filter_op,
1659 switch (filter_type) {
1660 case RTE_ETH_FILTER_GENERIC:
1661 if (filter_op != RTE_ETH_FILTER_GET)
1663 *(const void **)arg = &tap_flow_ops;
1666 RTE_LOG(ERR, PMD, "%p: filter type (%d) not supported\n",
1667 (void *)dev, filter_type);