From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 71F9EA04B1; Tue, 8 Sep 2020 22:17:02 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B16921C0CA; Tue, 8 Sep 2020 22:16:48 +0200 (CEST) Received: from hqnvemgate26.nvidia.com (hqnvemgate26.nvidia.com [216.228.121.65]) by dpdk.org (Postfix) with ESMTP id 2BBB71C0CA for ; Tue, 8 Sep 2020 22:16:47 +0200 (CEST) Received: from hqpgpgate101.nvidia.com (Not Verified[216.228.121.13]) by hqnvemgate26.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Tue, 08 Sep 2020 13:16:33 -0700 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate101.nvidia.com (PGP Universal service); Tue, 08 Sep 2020 13:16:46 -0700 X-PGP-Universal: processed; by hqpgpgate101.nvidia.com on Tue, 08 Sep 2020 13:16:46 -0700 Received: from nvidia.com (10.124.1.5) by HQMAIL107.nvidia.com (172.20.187.13) with Microsoft SMTP Server (TLS) id 15.0.1473.3; Tue, 8 Sep 2020 20:16:28 +0000 From: Gregory Etelson To: CC: , , , Ori Kam , Wenzhuo Lu , Beilei Xing , Bernard Iremonger Date: Tue, 8 Sep 2020 23:15:51 +0300 Message-ID: <20200908201552.14423-5-getelson@nvidia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200908201552.14423-1-getelson@nvidia.com> References: <20200625160348.26220-1-getelson@mellanox.com> <20200908201552.14423-1-getelson@nvidia.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain X-Originating-IP: [10.124.1.5] X-ClientProxiedBy: HQMAIL101.nvidia.com (172.20.187.10) To HQMAIL107.nvidia.com (172.20.187.13) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1599596193; bh=UmqsGd3nkRGKbKGN34zJmTDUWPiUuU/CASLTbQB43pw=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding: Content-Type:X-Originating-IP:X-ClientProxiedBy; b=j7tBLWTlMiqb7oYA2EjTLdv+49ufyGqWzocikQprha9cBY8Q26QbJUOfaJPhAgjm1 qHJqL88tW/VYBRHsUwqAD7GuqMOO0b3AFQr4chYFS2bBDCjWDEqaNdmTWhU5d2PLS8 dMDqgqvw2Y/cBUWVkgUNjem81BYhnFAmzqJx0lh67x6bA1GeJ4H/vmN54jpN+YHi/m cLLgsypi5xXwz1Nj+8t+syeuEDGsUKQ121QF60PIcBwA2MhldXwqkPyL3/RuHVEEEw ZxlZ95pIp1un7alV9q/x2uT/u8OlNOghgTSq3L9LJs4BeGNSN12fsEGymONnKdTqpH 3pfAvv0qdS18A== Subject: [dpdk-dev] [PATCH v2 4/4] app/testpmd: support tunnel offload API X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Tunnel Offload API provides hardware independent, unified model to offload tunneled traffic. Key model elements are: - apply matches to both outer and inner packet headers during entire offload procedure; - restore outer header of partially offloaded packet; - model is implemented as a set of helper functions. Implementation details: * Create application tunnel: flow tunnel type On success, the command creates application tunnel object and returns the tunnel descriptor. Tunnel descriptor is used in subsequent flow creation commands to reference the tunnel. * Create tunnel steering flow rule: tunnel_set parameter used with steering rule template. * Create tunnel matching flow rule: tunnel_match used with matching rule template. * If tunnel steering rule was offloaded, outer header of a partially offloaded packet is restored after miss. Example: test packet=3D >>= >>>> >>> len(packet) 92 testpmd> flow flush 0 testpmd> port 0/queue 0: received 1 packets src=3D50:6B:4B:CC:FC:E2 - dst=3D24:8A:07:8D:AE:D6 - type=3D0x0800 - length=3D92 testpmd> flow tunnel 0 type vxlan port 0: flow tunnel #1 type vxlan testpmd> flow create 0 ingress group 0 tunnel_set 1 pattern eth /ipv4 / udp dst is 4789 / vxlan / end actions jump group 0 / end Flow rule #0 created testpmd> port 0/queue 0: received 1 packets tunnel restore info: - vxlan tunnel - outer header present # <-- src=3D50:6B:4B:CC:FC:E2 - dst=3D24:8A:07:8D:AE:D6 - type=3D0x0800 - length=3D92 testpmd> flow create 0 ingress group 0 tunnel_match 1 pattern eth / ipv4 / udp dst is 4789 / vxlan / eth / ipv4 / end actions set_mac_dst mac_addr 02:CA:FE:CA:FA:80 / queue index 0 / end Flow rule #1 created testpmd> port 0/queue 0: received 1 packets src=3D50:BB:BB:BB:BB:E2 - dst=3D02:CA:FE:CA:FA:80 - type=3D0x0800 - length=3D42 TODO: add tunnel destruction command. Signed-off-by: Gregory Etelson --- v2: * introduce testpmd support for tunnel offload API --- app/test-pmd/cmdline_flow.c | 102 ++++++++++++++++++++++++- app/test-pmd/config.c | 147 +++++++++++++++++++++++++++++++++++- app/test-pmd/testpmd.c | 5 +- app/test-pmd/testpmd.h | 27 ++++++- app/test-pmd/util.c | 30 +++++++- 5 files changed, 302 insertions(+), 9 deletions(-) diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index 6263d307ed..f0a7a4a9ea 100644 --- a/app/test-pmd/cmdline_flow.c +++ b/app/test-pmd/cmdline_flow.c @@ -69,6 +69,10 @@ enum index { LIST, AGED, ISOLATE, + TUNNEL, + + /* Tunnel argumens. */ + TUNNEL_RULE, =20 /* Destroy arguments. */ DESTROY_RULE, @@ -88,6 +92,8 @@ enum index { INGRESS, EGRESS, TRANSFER, + TUNNEL_SET, + TUNNEL_MATCH, =20 /* Validate/create pattern. */ PATTERN, @@ -653,6 +659,7 @@ struct buffer { union { struct { struct rte_flow_attr attr; + struct tunnel_ops tunnel_ops; struct rte_flow_item *pattern; struct rte_flow_action *actions; uint32_t pattern_n; @@ -713,10 +720,18 @@ static const enum index next_vc_attr[] =3D { INGRESS, EGRESS, TRANSFER, + TUNNEL_SET, + TUNNEL_MATCH, PATTERN, ZERO, }; =20 +static const enum index next_tunnel_attr[] =3D { + TUNNEL_RULE, + END, + ZERO, +}; + static const enum index next_destroy_attr[] =3D { DESTROY_RULE, END, @@ -1516,6 +1531,9 @@ static int parse_aged(struct context *, const struct = token *, static int parse_isolate(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); +static int parse_tunnel(struct context *, const struct token *, + const char *, unsigned int, + void *, unsigned int); static int parse_int(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); @@ -1698,7 +1716,8 @@ static const struct token token_list[] =3D { LIST, AGED, QUERY, - ISOLATE)), + ISOLATE, + TUNNEL)), .call =3D parse_init, }, /* Sub-level commands. */ @@ -1772,6 +1791,21 @@ static const struct token token_list[] =3D { ARGS_ENTRY(struct buffer, port)), .call =3D parse_isolate, }, + [TUNNEL] =3D { + .name =3D "tunnel", + .help =3D "new tunnel API", + .next =3D NEXT(NEXT_ENTRY(TUNNEL_RULE), NEXT_ENTRY(PORT_ID)), + .args =3D ARGS(ARGS_ENTRY(struct buffer, port)), + .call =3D parse_tunnel, + }, + /* Tunnel arguments. */ + [TUNNEL_RULE]{ + .name =3D "type", + .help =3D "specify tunnel type", + .next =3D NEXT(next_tunnel_attr, NEXT_ENTRY(FILE_PATH)), + .args =3D ARGS(ARGS_ENTRY(struct tunnel_ops, type)), + .call =3D parse_tunnel, + }, /* Destroy arguments. */ [DESTROY_RULE] =3D { .name =3D "rule", @@ -1835,6 +1869,20 @@ static const struct token token_list[] =3D { .next =3D NEXT(next_vc_attr), .call =3D parse_vc, }, + [TUNNEL_SET] =3D { + .name =3D "tunnel_set", + .help =3D "tunnel steer rule", + .next =3D NEXT(next_vc_attr, NEXT_ENTRY(UNSIGNED)), + .args =3D ARGS(ARGS_ENTRY(struct tunnel_ops, id)), + .call =3D parse_vc, + }, + [TUNNEL_MATCH] =3D { + .name =3D "tunnel_match", + .help =3D "tunnel match rule", + .next =3D NEXT(next_vc_attr, NEXT_ENTRY(UNSIGNED)), + .args =3D ARGS(ARGS_ENTRY(struct tunnel_ops, id)), + .call =3D parse_vc, + }, /* Validate/create pattern. */ [PATTERN] =3D { .name =3D "pattern", @@ -4054,12 +4102,28 @@ parse_vc(struct context *ctx, const struct token *t= oken, return len; } ctx->objdata =3D 0; - ctx->object =3D &out->args.vc.attr; + switch (ctx->curr) { + default: + ctx->object =3D &out->args.vc.attr; + break; + case TUNNEL_SET: + case TUNNEL_MATCH: + ctx->object =3D &out->args.vc.tunnel_ops; + break; + } ctx->objmask =3D NULL; switch (ctx->curr) { case GROUP: case PRIORITY: return len; + case TUNNEL_SET: + out->args.vc.tunnel_ops.enabled =3D 1; + out->args.vc.tunnel_ops.actions =3D 1; + return len; + case TUNNEL_MATCH: + out->args.vc.tunnel_ops.enabled =3D 1; + out->args.vc.tunnel_ops.items =3D 1; + return len; case INGRESS: out->args.vc.attr.ingress =3D 1; return len; @@ -5597,6 +5661,34 @@ parse_isolate(struct context *ctx, const struct toke= n *token, return len; } =20 +static int +parse_tunnel(struct context *ctx, const struct token *token, + const char *str, unsigned int len, + void *buf, unsigned int size) +{ + struct buffer *out =3D buf; + + /* Token name must match. */ + if (parse_default(ctx, token, str, len, NULL, 0) < 0) + return -1; + /* Nothing else to do if there is no buffer. */ + if (!out) + return len; + if (!out->command) { + if (ctx->curr !=3D TUNNEL) + return -1; + if (sizeof(*out) > size) + return -1; + out->command =3D ctx->curr; + ctx->objdata =3D 0; + ctx->object =3D out; + ctx->objmask =3D NULL; + } + if (ctx->curr =3D=3D TUNNEL_RULE) + ctx->object =3D &out->args.vc.tunnel_ops; + return len; +} + /** * Parse signed/unsigned integers 8 to 64-bit long. * @@ -6547,7 +6639,8 @@ cmd_flow_parsed(const struct buffer *in) break; case CREATE: port_flow_create(in->port, &in->args.vc.attr, - in->args.vc.pattern, in->args.vc.actions); + in->args.vc.pattern, in->args.vc.actions, + &in->args.vc.tunnel_ops); break; case DESTROY: port_flow_destroy(in->port, in->args.destroy.rule_n, @@ -6573,6 +6666,9 @@ cmd_flow_parsed(const struct buffer *in) case AGED: port_flow_aged(in->port, in->args.aged.destroy); break; + case TUNNEL: + port_flow_add_tunnel(in->port, &in->args.vc.tunnel_ops); + break; default: break; } diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index 30bee33248..b90927f451 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -1337,6 +1337,58 @@ port_mtu_set(portid_t port_id, uint16_t mtu) =20 /* Generic flow management functions. */ =20 +static struct port_flow_tunnel * +port_flow_locate_tunnel(struct rte_port *port, uint32_t port_tunnel_id) +{ + struct port_flow_tunnel *flow_tunnel; + + LIST_FOREACH(flow_tunnel, &port->flow_tunnel_list, chain) { + if (flow_tunnel->id =3D=3D port_tunnel_id) + goto out; + } + flow_tunnel =3D NULL; + +out: + return flow_tunnel; +} + +void port_flow_release_tunnel(struct port_flow_tunnel *flow_tunnel) +{ + LIST_REMOVE(flow_tunnel, chain); + free(flow_tunnel); +} + +void port_flow_add_tunnel(portid_t port_id, const struct tunnel_ops *ops) +{ + struct rte_port *port =3D &ports[port_id]; + enum rte_flow_item_type type; + struct port_flow_tunnel *flow_tunnel; + + if (!strncmp(ops->type, "vxlan", strlen("vxlan"))) + type =3D RTE_FLOW_ITEM_TYPE_VXLAN; + else { + printf("cannot offload \"%s\" tunnel type\n", ops->type); + return; + } + LIST_FOREACH(flow_tunnel, &port->flow_tunnel_list, chain) { + if (flow_tunnel->tunnel.type =3D=3D type) + break; + } + if (!flow_tunnel) { + flow_tunnel =3D calloc(1, sizeof(*flow_tunnel)); + if (!flow_tunnel) { + printf("failed to allocate port flow_tunnel object\n"); + return; + } + flow_tunnel->tunnel.type =3D type; + flow_tunnel->id =3D LIST_EMPTY(&port->flow_tunnel_list) ? 1 : + LIST_FIRST(&port->flow_tunnel_list)->id + 1; + LIST_INSERT_HEAD(&port->flow_tunnel_list, flow_tunnel, chain); + } + printf("port %d: flow tunnel #%u type %s\n", + port_id, flow_tunnel->id, ops->type); +} + /** Generate a port_flow entry from attributes/pattern/actions. */ static struct port_flow * port_flow_new(const struct rte_flow_attr *attr, @@ -1503,13 +1555,15 @@ int port_flow_create(portid_t port_id, const struct rte_flow_attr *attr, const struct rte_flow_item *pattern, - const struct rte_flow_action *actions) + const struct rte_flow_action *actions, + const struct tunnel_ops *tunnel_ops) { struct rte_flow *flow; struct rte_port *port; struct port_flow *pf; uint32_t id =3D 0; struct rte_flow_error error; + struct port_flow_tunnel *pft; =20 port =3D &ports[port_id]; if (port->flow_list) { @@ -1520,6 +1574,75 @@ port_flow_create(portid_t port_id, } id =3D port->flow_list->id + 1; } + if (tunnel_ops->enabled) { + int ret; + pft =3D port_flow_locate_tunnel(port, tunnel_ops->id); + if (!pft) { + printf("failed to locate port flow tunnel #%u\n", + tunnel_ops->id); + return -ENOENT; + } + if (tunnel_ops->actions) { + uint32_t num_actions; + const struct rte_flow_action *aptr; + + ret =3D rte_flow_tunnel_decap_set(port_id, &pft->tunnel, + &pft->pmd_actions, + &pft->num_pmd_actions, + &error); + if (ret) { + port_flow_complain(&error); + return -EINVAL; + } + for (aptr =3D actions, num_actions =3D 1; + aptr->type !=3D RTE_FLOW_ACTION_TYPE_END; + aptr++, num_actions++); + pft->actions =3D malloc( + (num_actions + pft->num_pmd_actions) * + sizeof(actions[0])); + if (!pft->actions) { + rte_flow_tunnel_action_decap_release( + port_id, pft->actions, + pft->num_pmd_actions, &error); + return -ENOMEM; + } + rte_memcpy(pft->actions, pft->pmd_actions, + pft->num_pmd_actions * sizeof(actions[0])); + rte_memcpy(pft->actions + pft->num_pmd_actions, actions, + num_actions * sizeof(actions[0])); + actions =3D pft->actions; + } + if (tunnel_ops->items) { + uint32_t num_items; + const struct rte_flow_item *iptr; + + ret =3D rte_flow_tunnel_match(port_id, &pft->tunnel, + &pft->pmd_items, + &pft->num_pmd_items, + &error); + if (ret) { + port_flow_complain(&error); + return -EINVAL; + } + for (iptr =3D pattern, num_items =3D 1; + iptr->type !=3D RTE_FLOW_ITEM_TYPE_END; + iptr++, num_items++); + pft->items =3D malloc((num_items + pft->num_pmd_items) * + sizeof(pattern[0])); + if (!pft->items) { + rte_flow_tunnel_item_release( + port_id, pft->pmd_items, + pft->num_pmd_items, &error); + return -ENOMEM; + } + rte_memcpy(pft->items, pft->pmd_items, + pft->num_pmd_items * sizeof(pattern[0])); + rte_memcpy(pft->items + pft->num_pmd_items, pattern, + num_items * sizeof(pattern[0])); + pattern =3D pft->items; + } + + } pf =3D port_flow_new(attr, pattern, actions, &error); if (!pf) return port_flow_complain(&error); @@ -1535,6 +1658,20 @@ port_flow_create(portid_t port_id, pf->id =3D id; pf->flow =3D flow; port->flow_list =3D pf; + if (tunnel_ops->enabled) { + if (tunnel_ops->actions) { + free(pft->actions); + rte_flow_tunnel_action_decap_release( + port_id, pft->pmd_actions, + pft->num_pmd_actions, &error); + } + if (tunnel_ops->items) { + free(pft->items); + rte_flow_tunnel_item_release(port_id, pft->pmd_items, + pft->num_pmd_items, + &error); + } + } printf("Flow rule #%u created\n", pf->id); return 0; } @@ -1829,7 +1966,9 @@ port_flow_list(portid_t port_id, uint32_t n, const ui= nt32_t group[n]) pf->rule.attr->egress ? 'e' : '-', pf->rule.attr->transfer ? 't' : '-'); while (item->type !=3D RTE_FLOW_ITEM_TYPE_END) { - if (rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_NAME_PTR, + if ((uint32_t)item->type > INT_MAX) + name =3D "PMD_INTERNAL"; + else if (rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_NAME_PTR, &name, sizeof(name), (void *)(uintptr_t)item->type, NULL) <=3D 0) @@ -1840,7 +1979,9 @@ port_flow_list(portid_t port_id, uint32_t n, const ui= nt32_t group[n]) } printf("=3D>"); while (action->type !=3D RTE_FLOW_ACTION_TYPE_END) { - if (rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR, + if ((uint32_t)action->type > INT_MAX) + name =3D "PMD_INTERNAL"; + else if (rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR, &name, sizeof(name), (void *)(uintptr_t)action->type, NULL) <=3D 0) diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index 7842c3b781..e2330116e1 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -3591,6 +3591,8 @@ init_port_dcb_config(portid_t pid, static void init_port(void) { + int i; + /* Configuration of Ethernet ports. */ ports =3D rte_zmalloc("testpmd: ports", sizeof(struct rte_port) * RTE_MAX_ETHPORTS, @@ -3600,7 +3602,8 @@ init_port(void) "rte_zmalloc(%d struct rte_port) failed\n", RTE_MAX_ETHPORTS); } - + for (i =3D 0; i < RTE_MAX_ETHPORTS; i++) + LIST_INIT(&ports[i].flow_tunnel_list); /* Initialize ports NUMA structures */ memset(port_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS); memset(rxring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS); diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 25a12b14f2..9c47533c68 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -12,6 +12,7 @@ #include #include #include +#include =20 #define RTE_PORT_ALL (~(portid_t)0x0) =20 @@ -148,6 +149,26 @@ struct port_flow { uint8_t data[]; /**< Storage for flow rule description */ }; =20 +struct port_flow_tunnel { + LIST_ENTRY(port_flow_tunnel) chain; + struct rte_flow_action *pmd_actions; + struct rte_flow_item *pmd_items; + uint32_t id; + uint32_t num_pmd_actions; + uint32_t num_pmd_items; + struct rte_flow_tunnel tunnel; + struct rte_flow_action *actions; + struct rte_flow_item *items; +}; + +struct tunnel_ops { + uint32_t id; + char type[16]; + uint32_t enabled:1; + uint32_t actions:1; + uint32_t items:1; +}; + /** * The data structure associated with each port. */ @@ -178,6 +199,7 @@ struct rte_port { uint32_t mc_addr_nb; /**< nb. of addr. in mc_addr_pool */ uint8_t slave_flag; /**< bonding slave port */ struct port_flow *flow_list; /**< Associated flows. */ + LIST_HEAD(, port_flow_tunnel) flow_tunnel_list; const struct rte_eth_rxtx_callback *rx_dump_cb[RTE_MAX_QUEUES_PER_PORT+1]= ; const struct rte_eth_rxtx_callback *tx_dump_cb[RTE_MAX_QUEUES_PER_PORT+1]= ; /**< metadata value to insert in Tx packets. */ @@ -729,7 +751,8 @@ int port_flow_validate(portid_t port_id, int port_flow_create(portid_t port_id, const struct rte_flow_attr *attr, const struct rte_flow_item *pattern, - const struct rte_flow_action *actions); + const struct rte_flow_action *actions, + const struct tunnel_ops *tunnel_ops); void update_age_action_context(const struct rte_flow_action *actions, struct port_flow *pf); int port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule); @@ -739,6 +762,8 @@ int port_flow_query(portid_t port_id, uint32_t rule, const struct rte_flow_action *action); void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group); void port_flow_aged(portid_t port_id, uint8_t destroy); +void port_flow_release_tunnel(struct port_flow_tunnel *flow_tunnel); +void port_flow_add_tunnel(portid_t port_id, const struct tunnel_ops *ops); int port_flow_isolate(portid_t port_id, int set); =20 void rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd= _id); diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c index 8488fa1a8f..6757acde9a 100644 --- a/app/test-pmd/util.c +++ b/app/test-pmd/util.c @@ -22,6 +22,12 @@ print_ether_addr(const char *what, const struct rte_ethe= r_addr *eth_addr) printf("%s%s", what, buf); } =20 +static bool tunnel_missed_packet(struct rte_mbuf *mb) +{ + uint64_t mask =3D PKT_RX_FDIR | PKT_RX_FDIR_ID; + return (mb->ol_flags & mask) =3D=3D mask; +} + static inline void dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[], uint16_t nb_pkts, int is_rx) @@ -51,15 +57,37 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct= rte_mbuf *pkts[], mb =3D pkts[i]; eth_hdr =3D rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr); eth_type =3D RTE_BE_TO_CPU_16(eth_hdr->ether_type); - ol_flags =3D mb->ol_flags; packet_type =3D mb->packet_type; is_encapsulation =3D RTE_ETH_IS_TUNNEL_PKT(packet_type); =20 + if (tunnel_missed_packet(mb)) { + int ret; + struct rte_flow_error error; + struct rte_flow_restore_info info =3D { 0, }; + + ret =3D rte_flow_tunnel_get_restore_info(port_id, mb, + &info, &error); + if (!ret) { + printf("tunnel restore info:"); + if (info.flags & RTE_FLOW_RESTORE_INFO_TUNNEL) + if (info.tunnel.type =3D=3D + RTE_FLOW_ITEM_TYPE_VXLAN) + printf(" - vxlan tunnel"); + if (info.flags & + RTE_FLOW_RESTORE_INFO_ENCAPSULATED) + printf(" - outer header present"); + if (info.flags & RTE_FLOW_RESTORE_INFO_GROUP_ID) + printf(" - miss group %u", + info.group_id); + } + printf("\n"); + } print_ether_addr(" src=3D", ð_hdr->s_addr); print_ether_addr(" - dst=3D", ð_hdr->d_addr); printf(" - type=3D0x%04x - length=3D%u - nb_segs=3D%d", eth_type, (unsigned int) mb->pkt_len, (int)mb->nb_segs); + ol_flags =3D mb->ol_flags; if (ol_flags & PKT_RX_RSS_HASH) { printf(" - RSS hash=3D0x%x", (unsigned int) mb->hash.rss); printf(" - RSS queue=3D0x%x", (unsigned int) queue); --=20 2.25.1