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 69C11A04DB; Fri, 16 Oct 2020 12:35:04 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 913F11ECE6; Fri, 16 Oct 2020 12:34:42 +0200 (CEST) Received: from hqnvemgate25.nvidia.com (hqnvemgate25.nvidia.com [216.228.121.64]) by dpdk.org (Postfix) with ESMTP id 7AC7A2B82 for ; Fri, 16 Oct 2020 12:34:39 +0200 (CEST) Received: from hqmail.nvidia.com (Not Verified[216.228.121.13]) by hqnvemgate25.nvidia.com (using TLS: TLSv1.2, AES256-SHA) id ; Fri, 16 Oct 2020 03:33:54 -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; Fri, 16 Oct 2020 10:34:26 +0000 From: Gregory Etelson To: CC: , , , , , , , Ori Kam , Wenzhuo Lu , Beilei Xing , "Bernard Iremonger" Date: Fri, 16 Oct 2020 13:34:00 +0300 Message-ID: <20201016103400.21311-4-getelson@nvidia.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201016103400.21311-1-getelson@nvidia.com> References: <20200625160348.26220-1-getelson@mellanox.com> <20201016103400.21311-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: HQMAIL111.nvidia.com (172.20.187.18) To HQMAIL107.nvidia.com (172.20.187.13) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1602844434; bh=V8mcI9lzWLXbWMvnyKkA7ODvnZzeuMZQMirtOIswZic=; h=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=kZ/YnzT0+4OlffjV2N/aJSB0C1lcLgr7YMDok5o4+iM/ju6Gru7f9DJzhQeBf1Oqe 3+UKSXHVUtRpUtVOEUVJQTSSPs2MBOb+Qr6wKfDs0oq6rrv46pvQLo/yCXIllLn6M5 PDmR2JZj/gg1aInWzDduW4faACnCWqx4peQEDRwOneRtrpxkj23++qob6xxtr/c5/x GkQaqMSF9FyF7dYmOcS3woDgEPO3lDzn1R5wUN3nOdJqyfFJt69F5jzFPe3+cfxnem z0Ug3a54cwV7ok+BNcIZ69OYyJnmOiqnLjLVlqNUM0+G2yGRm29XhAGxqKgDRH8vwZ Wn7prRVKQOPJg== Subject: [dpdk-dev] [PATCH v7 3/3] app/testpmd: add commands for 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 create 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 * Destroy flow tunnel flow tunnel destroy id * Show existing flow tunnels flow tunnel list Signed-off-by: Gregory Etelson --- v2: * introduce testpmd support for tunnel offload API v3: * update flow tunnel commands v5: * rebase to next-net v7: * resolve "%lu" differences in ubuntu 32 & 64 --- app/test-pmd/cmdline_flow.c | 170 ++++++++++++- app/test-pmd/config.c | 252 +++++++++++++++++++- app/test-pmd/testpmd.c | 5 +- app/test-pmd/testpmd.h | 34 ++- app/test-pmd/util.c | 35 ++- doc/guides/testpmd_app_ug/testpmd_funcs.rst | 49 ++++ 6 files changed, 532 insertions(+), 13 deletions(-) diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index 00c70a144a..b9a1f7178a 100644 --- a/app/test-pmd/cmdline_flow.c +++ b/app/test-pmd/cmdline_flow.c @@ -74,6 +74,14 @@ enum index { LIST, AGED, ISOLATE, + TUNNEL, + + /* Tunnel arguments. */ + TUNNEL_CREATE, + TUNNEL_CREATE_TYPE, + TUNNEL_LIST, + TUNNEL_DESTROY, + TUNNEL_DESTROY_ID, =20 /* Destroy arguments. */ DESTROY_RULE, @@ -93,6 +101,8 @@ enum index { INGRESS, EGRESS, TRANSFER, + TUNNEL_SET, + TUNNEL_MATCH, =20 /* Shared action arguments */ SHARED_ACTION_CREATE, @@ -713,6 +723,7 @@ struct buffer { } sa; /* Shared action query arguments */ 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; @@ -789,10 +800,32 @@ static const enum index next_vc_attr[] =3D { INGRESS, EGRESS, TRANSFER, + TUNNEL_SET, + TUNNEL_MATCH, PATTERN, ZERO, }; =20 +static const enum index tunnel_create_attr[] =3D { + TUNNEL_CREATE, + TUNNEL_CREATE_TYPE, + END, + ZERO, +}; + +static const enum index tunnel_destroy_attr[] =3D { + TUNNEL_DESTROY, + TUNNEL_DESTROY_ID, + END, + ZERO, +}; + +static const enum index tunnel_list_attr[] =3D { + TUNNEL_LIST, + END, + ZERO, +}; + static const enum index next_destroy_attr[] =3D { DESTROY_RULE, END, @@ -1643,6 +1676,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); @@ -1844,7 +1880,8 @@ static const struct token token_list[] =3D { LIST, AGED, QUERY, - ISOLATE)), + ISOLATE, + TUNNEL)), .call =3D parse_init, }, /* Top-level command. */ @@ -1955,6 +1992,49 @@ 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_CREATE, TUNNEL_LIST, TUNNEL_DESTROY)), + .call =3D parse_tunnel, + }, + /* Tunnel arguments. */ + [TUNNEL_CREATE] =3D { + .name =3D "create", + .help =3D "create new tunnel object", + .next =3D NEXT(tunnel_create_attr, NEXT_ENTRY(PORT_ID)), + .args =3D ARGS(ARGS_ENTRY(struct buffer, port)), + .call =3D parse_tunnel, + }, + [TUNNEL_CREATE_TYPE] =3D { + .name =3D "type", + .help =3D "create new tunnel", + .next =3D NEXT(tunnel_create_attr, NEXT_ENTRY(FILE_PATH)), + .args =3D ARGS(ARGS_ENTRY(struct tunnel_ops, type)), + .call =3D parse_tunnel, + }, + [TUNNEL_DESTROY] =3D { + .name =3D "destroy", + .help =3D "destroy tunel", + .next =3D NEXT(tunnel_destroy_attr, NEXT_ENTRY(PORT_ID)), + .args =3D ARGS(ARGS_ENTRY(struct buffer, port)), + .call =3D parse_tunnel, + }, + [TUNNEL_DESTROY_ID] =3D { + .name =3D "id", + .help =3D "tunnel identifier to testroy", + .next =3D NEXT(tunnel_destroy_attr, NEXT_ENTRY(UNSIGNED)), + .args =3D ARGS(ARGS_ENTRY(struct tunnel_ops, id)), + .call =3D parse_tunnel, + }, + [TUNNEL_LIST] =3D { + .name =3D "list", + .help =3D "list existing tunnels", + .next =3D NEXT(tunnel_list_attr, NEXT_ENTRY(PORT_ID)), + .args =3D ARGS(ARGS_ENTRY(struct buffer, port)), + .call =3D parse_tunnel, + }, /* Destroy arguments. */ [DESTROY_RULE] =3D { .name =3D "rule", @@ -2018,6 +2098,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", @@ -4495,12 +4589,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; @@ -6108,6 +6218,47 @@ 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; + } else { + switch (ctx->curr) { + default: + break; + case TUNNEL_CREATE: + case TUNNEL_DESTROY: + case TUNNEL_LIST: + out->command =3D ctx->curr; + break; + case TUNNEL_CREATE_TYPE: + case TUNNEL_DESTROY_ID: + ctx->object =3D &out->args.vc.tunnel_ops; + break; + } + } + + return len; +} + /** * Parse signed/unsigned integers 8 to 64-bit long. * @@ -7148,11 +7299,13 @@ cmd_flow_parsed(const struct buffer *in) break; case VALIDATE: port_flow_validate(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 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, @@ -7178,6 +7331,15 @@ cmd_flow_parsed(const struct buffer *in) case AGED: port_flow_aged(in->port, in->args.aged.destroy); break; + case TUNNEL_CREATE: + port_flow_tunnel_create(in->port, &in->args.vc.tunnel_ops); + break; + case TUNNEL_DESTROY: + port_flow_tunnel_destroy(in->port, in->args.vc.tunnel_ops.id); + break; + case TUNNEL_LIST: + port_flow_tunnel_list(in->port); + break; default: break; } diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index 2c00b55440..660eb5af97 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -1521,6 +1521,115 @@ 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_id(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; +} + +const char * +port_flow_tunnel_type(struct rte_flow_tunnel *tunnel) +{ + const char *type; + switch (tunnel->type) { + default: + type =3D "unknown"; + break; + case RTE_FLOW_ITEM_TYPE_VXLAN: + type =3D "vxlan"; + break; + } + + return type; +} + +struct port_flow_tunnel * +port_flow_locate_tunnel(uint16_t port_id, struct rte_flow_tunnel *tun) +{ + struct rte_port *port =3D &ports[port_id]; + struct port_flow_tunnel *flow_tunnel; + + LIST_FOREACH(flow_tunnel, &port->flow_tunnel_list, chain) { + if (!memcmp(&flow_tunnel->tunnel, tun, sizeof(*tun))) + goto out; + } + flow_tunnel =3D NULL; + +out: + return flow_tunnel; +} + +void port_flow_tunnel_list(portid_t port_id) +{ + struct rte_port *port =3D &ports[port_id]; + struct port_flow_tunnel *flt; + + LIST_FOREACH(flt, &port->flow_tunnel_list, chain) { + printf("port %u tunnel #%u type=3D%s", + port_id, flt->id, port_flow_tunnel_type(&flt->tunnel)); + if (flt->tunnel.tun_id) + printf(" id=3D%lu", (unsigned long)flt->tunnel.tun_id); + printf("\n"); + } +} + +void port_flow_tunnel_destroy(portid_t port_id, uint32_t tunnel_id) +{ + struct rte_port *port =3D &ports[port_id]; + struct port_flow_tunnel *flt; + + LIST_FOREACH(flt, &port->flow_tunnel_list, chain) { + if (flt->id =3D=3D tunnel_id) + break; + } + if (flt) { + LIST_REMOVE(flt, chain); + free(flt); + printf("port %u: flow tunnel #%u destroyed\n", + port_id, tunnel_id); + } +} + +void port_flow_tunnel_create(portid_t port_id, const struct tunnel_ops *op= s) +{ + struct rte_port *port =3D &ports[port_id]; + enum rte_flow_item_type type; + struct port_flow_tunnel *flt; + + if (!strcmp(ops->type, "vxlan")) + type =3D RTE_FLOW_ITEM_TYPE_VXLAN; + else { + printf("cannot offload \"%s\" tunnel type\n", ops->type); + return; + } + LIST_FOREACH(flt, &port->flow_tunnel_list, chain) { + if (flt->tunnel.type =3D=3D type) + break; + } + if (!flt) { + flt =3D calloc(1, sizeof(*flt)); + if (!flt) { + printf("failed to allocate port flt object\n"); + return; + } + flt->tunnel.type =3D type; + flt->id =3D LIST_EMPTY(&port->flow_tunnel_list) ? 1 : + LIST_FIRST(&port->flow_tunnel_list)->id + 1; + LIST_INSERT_HEAD(&port->flow_tunnel_list, flt, chain); + } + printf("port %d: flow tunnel #%u type %s\n", + port_id, flt->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, @@ -1860,20 +1969,137 @@ port_shared_action_query(portid_t port_id, uint32_= t id) } return ret; } +static struct port_flow_tunnel * +port_flow_tunnel_offload_cmd_prep(portid_t port_id, + const struct rte_flow_item *pattern, + const struct rte_flow_action *actions, + const struct tunnel_ops *tunnel_ops) +{ + int ret; + struct rte_port *port; + struct port_flow_tunnel *pft; + struct rte_flow_error error; + + port =3D &ports[port_id]; + pft =3D port_flow_locate_tunnel_id(port, tunnel_ops->id); + if (!pft) { + printf("failed to locate port flow tunnel #%u\n", + tunnel_ops->id); + return NULL; + } + 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 NULL; + } + 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 NULL; + } + 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])); + } + 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 NULL; + } + 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 NULL; + } + 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])); + } + + return pft; +} + +static void +port_flow_tunnel_offload_cmd_release(portid_t port_id, + const struct tunnel_ops *tunnel_ops, + struct port_flow_tunnel *pft) +{ + struct rte_flow_error error; + + if (tunnel_ops->actions) { + free(pft->actions); + rte_flow_tunnel_action_decap_release( + port_id, pft->pmd_actions, + pft->num_pmd_actions, &error); + pft->actions =3D NULL; + pft->pmd_actions =3D NULL; + } + if (tunnel_ops->items) { + free(pft->items); + rte_flow_tunnel_item_release(port_id, pft->pmd_items, + pft->num_pmd_items, + &error); + pft->items =3D NULL; + pft->pmd_items =3D NULL; + } +} =20 /** Validate flow rule. */ int port_flow_validate(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_error error; + struct port_flow_tunnel *pft =3D NULL; =20 /* Poisoning to make sure PMDs update it in case of error. */ memset(&error, 0x11, sizeof(error)); + if (tunnel_ops->enabled) { + pft =3D port_flow_tunnel_offload_cmd_prep(port_id, pattern, + actions, tunnel_ops); + if (!pft) + return -ENOENT; + if (pft->items) + pattern =3D pft->items; + if (pft->actions) + actions =3D pft->actions; + } if (rte_flow_validate(port_id, attr, pattern, actions, &error)) return port_flow_complain(&error); + if (tunnel_ops->enabled) + port_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft); printf("Flow rule validated\n"); return 0; } @@ -1903,13 +2129,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 =3D NULL; =20 port =3D &ports[port_id]; if (port->flow_list) { @@ -1920,6 +2148,16 @@ port_flow_create(portid_t port_id, } id =3D port->flow_list->id + 1; } + if (tunnel_ops->enabled) { + pft =3D port_flow_tunnel_offload_cmd_prep(port_id, pattern, + actions, tunnel_ops); + if (!pft) + return -ENOENT; + if (pft->items) + pattern =3D pft->items; + if (pft->actions) + actions =3D pft->actions; + } pf =3D port_flow_new(attr, pattern, actions, &error); if (!pf) return port_flow_complain(&error); @@ -1935,6 +2173,8 @@ port_flow_create(portid_t port_id, pf->id =3D id; pf->flow =3D flow; port->flow_list =3D pf; + if (tunnel_ops->enabled) + port_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft); printf("Flow rule #%u created\n", pf->id); return 0; } @@ -2244,7 +2484,9 @@ port_flow_list(portid_t port_id, uint32_t n, const ui= nt32_t *group) 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) @@ -2255,7 +2497,9 @@ port_flow_list(portid_t port_id, uint32_t n, const ui= nt32_t *group) } 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 6caba60988..333904d686 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -3684,6 +3684,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, @@ -3693,7 +3695,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 f8b0a3517d..5238ac3dd5 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 @@ -150,6 +151,26 @@ struct port_shared_action { struct rte_flow_shared_action *action; /**< Shared action handle. */ }; =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. */ @@ -182,6 +203,7 @@ struct rte_port { struct port_flow *flow_list; /**< Associated flows. */ struct port_shared_action *actions_list; /**< Associated shared actions. */ + 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. */ @@ -773,11 +795,13 @@ int port_shared_action_update(portid_t port_id, uint3= 2_t id, int port_flow_validate(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); 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); int port_shared_action_query(portid_t port_id, uint32_t id); void update_age_action_context(const struct rte_flow_action *actions, struct port_flow *pf); @@ -788,6 +812,12 @@ 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); +const char *port_flow_tunnel_type(struct rte_flow_tunnel *tunnel); +struct port_flow_tunnel * +port_flow_locate_tunnel(uint16_t port_id, struct rte_flow_tunnel *tun); +void port_flow_tunnel_list(portid_t port_id); +void port_flow_tunnel_destroy(portid_t port_id, uint32_t tunnel_id); +void port_flow_tunnel_create(portid_t port_id, const struct tunnel_ops *op= s); 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..781a813759 100644 --- a/app/test-pmd/util.c +++ b/app/test-pmd/util.c @@ -48,18 +48,49 @@ dump_pkt_burst(uint16_t port_id, uint16_t queue, struct= rte_mbuf *pkts[], is_rx ? "received" : "sent", (unsigned int) nb_pkts); for (i =3D 0; i < nb_pkts; i++) { + int ret; + struct rte_flow_error error; + struct rte_flow_restore_info info =3D { 0, }; + 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); - + ret =3D rte_flow_get_restore_info(port_id, mb, &info, &error); + if (!ret) { + printf("restore info:"); + if (info.flags & RTE_FLOW_RESTORE_INFO_TUNNEL) { + struct port_flow_tunnel *port_tunnel; + + port_tunnel =3D port_flow_locate_tunnel + (port_id, &info.tunnel); + printf(" - tunnel"); + if (port_tunnel) + printf(" #%u", port_tunnel->id); + else + printf(" %s", "-none-"); + printf(" type %s", + port_flow_tunnel_type(&info.tunnel)); + } else { + printf(" - no tunnel info"); + } + if (info.flags & RTE_FLOW_RESTORE_INFO_ENCAPSULATED) + printf(" - outer header present"); + else + printf(" - no outer header"); + if (info.flags & RTE_FLOW_RESTORE_INFO_GROUP_ID) + printf(" - miss group %u", info.group_id); + else + printf(" - no miss group"); + 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); diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testp= md_app_ug/testpmd_funcs.rst index 43c0ea0599..05a4446757 100644 --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst @@ -3749,6 +3749,45 @@ following sections. =20 flow aged {port_id} [destroy] =20 +- Tunnel offload - create a tunnel stub:: + + flow tunnel create {port_id} type {tunnel_type} + +- Tunnel offload - destroy a tunnel stub:: + + flow tunnel destroy {port_id} id {tunnel_id} + +- Tunnel offload - list port tunnel stubs:: + + flow tunnel list {port_id} + +Creating a tunnel stub for offload +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``flow tunnel create`` setup a tunnel stub for tunnel offload flow rules:: + + flow tunnel create {port_id} type {tunnel_type} + +If successful, it will return a tunnel stub ID usable with other commands:= : + + port [...]: flow tunnel #[...] type [...] + +Tunnel stub ID is relative to a port. + +Destroying tunnel offload stub +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``flow tunnel destroy`` destroy port tunnel stub:: + + flow tunnel destroy {port_id} id {tunnel_id} + +Listing tunnel offload stubs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``flow tunnel list`` list port tunnel offload stubs:: + + flow tunnel list {port_id} + Validating flow rules ~~~~~~~~~~~~~~~~~~~~~ =20 @@ -3795,6 +3834,7 @@ to ``rte_flow_create()``:: =20 flow create {port_id} [group {group_id}] [priority {level}] [ingress] [egress] [transfer] + [tunnel_set {tunnel_id}] [tunnel_match {tunnel_id}] pattern {item} [/ {item} [...]] / end actions {action} [/ {action} [...]] / end =20 @@ -3809,6 +3849,7 @@ Otherwise it will show an error message of the form:: Parameters describe in the following order: =20 - Attributes (*group*, *priority*, *ingress*, *egress*, *transfer* tokens)= . +- Tunnel offload specification (tunnel_set, tunnel_match) - A matching pattern, starting with the *pattern* token and terminated by = an *end* pattern item. - Actions, starting with the *actions* token and terminated by an *end* @@ -3852,6 +3893,14 @@ Most rules affect RX therefore contain the ``ingress= `` token:: =20 testpmd> flow create 0 ingress pattern [...] =20 +Tunnel offload +^^^^^^^^^^^^^^ + +Indicate tunnel offload rule type + +- ``tunnel_set {tunnel_id}``: mark rule as tunnel offload decap_set type. +- ``tunnel_match {tunnel_id}``: mark rule as tunel offload match type. + Matching pattern ^^^^^^^^^^^^^^^^ =20 --=20 2.28.0