app/testpmd: add commands for tunnel offload
authorGregory Etelson <getelson@nvidia.com>
Fri, 16 Oct 2020 12:51:07 +0000 (15:51 +0300)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 16 Oct 2020 17:48:19 +0000 (19:48 +0200)
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 <port> type <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 <tunnel descriptor> parameter used with steering rule
template.

* Create tunnel matching flow rule:
tunnel_match <tunnel descriptor> 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=
<Ether  dst=24:8a:07:8d:ae:d6 src=50:6b:4b:cc:fc:e2 type=IPv4 |
<IP  version=4 ihl=5 proto=udp src=1.1.1.1 dst=1.1.1.10 |
<UDP  sport=4789 dport=4789 len=58 chksum=0x7f7b |
<VXLAN  NextProtocol=Ethernet vni=0x0 |
<Ether  dst=24:aa:aa:aa:aa:d6 src=50:bb:bb:bb:bb:e2 type=IPv4 |
<IP  version=4 ihl=5 proto=icmp src=2.2.2.2 dst=2.2.2.200 |
<ICMP  type=echo-request code=0 chksum=0xf7ff id=0x0 seq=0x0 |>>>>>>>
>>> len(packet)
92

testpmd> flow flush 0
testpmd> port 0/queue 0: received 1 packets
src=50:6B:4B:CC:FC:E2 - dst=24:8A:07:8D:AE:D6 - type=0x0800 -
length=92

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=50:6B:4B:CC:FC:E2 - dst=24:8A:07:8D:AE:D6 - type=0x0800 -
length=92

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=50:BB:BB:BB:BB:E2 - dst=02:CA:FE:CA:FA:80 - type=0x0800 -
length=42

* Destroy flow tunnel
flow tunnel destroy <port> id <tunnel id>

* Show existing flow tunnels
flow tunnel list <port>

Signed-off-by: Gregory Etelson <getelson@nvidia.com>
app/test-pmd/cmdline_flow.c
app/test-pmd/config.c
app/test-pmd/testpmd.c
app/test-pmd/testpmd.h
app/test-pmd/util.c
doc/guides/testpmd_app_ug/testpmd_funcs.rst

index 00c70a1..cd35d5b 100644 (file)
@@ -74,6 +74,14 @@ enum index {
        LIST,
        AGED,
        ISOLATE,
+       TUNNEL,
+
+       /* Tunnel arguments. */
+       TUNNEL_CREATE,
+       TUNNEL_CREATE_TYPE,
+       TUNNEL_LIST,
+       TUNNEL_DESTROY,
+       TUNNEL_DESTROY_ID,
 
        /* Destroy arguments. */
        DESTROY_RULE,
@@ -93,6 +101,8 @@ enum index {
        INGRESS,
        EGRESS,
        TRANSFER,
+       TUNNEL_SET,
+       TUNNEL_MATCH,
 
        /* 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[] = {
        INGRESS,
        EGRESS,
        TRANSFER,
+       TUNNEL_SET,
+       TUNNEL_MATCH,
        PATTERN,
        ZERO,
 };
 
+static const enum index tunnel_create_attr[] = {
+       TUNNEL_CREATE,
+       TUNNEL_CREATE_TYPE,
+       END,
+       ZERO,
+};
+
+static const enum index tunnel_destroy_attr[] = {
+       TUNNEL_DESTROY,
+       TUNNEL_DESTROY_ID,
+       END,
+       ZERO,
+};
+
+static const enum index tunnel_list_attr[] = {
+       TUNNEL_LIST,
+       END,
+       ZERO,
+};
+
 static const enum index next_destroy_attr[] = {
        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[] = {
                              LIST,
                              AGED,
                              QUERY,
-                             ISOLATE)),
+                             ISOLATE,
+                             TUNNEL)),
                .call = parse_init,
        },
        /* Top-level command. */
@@ -1955,6 +1992,49 @@ static const struct token token_list[] = {
                             ARGS_ENTRY(struct buffer, port)),
                .call = parse_isolate,
        },
+       [TUNNEL] = {
+               .name = "tunnel",
+               .help = "new tunnel API",
+               .next = NEXT(NEXT_ENTRY
+                            (TUNNEL_CREATE, TUNNEL_LIST, TUNNEL_DESTROY)),
+               .call = parse_tunnel,
+       },
+       /* Tunnel arguments. */
+       [TUNNEL_CREATE] = {
+               .name = "create",
+               .help = "create new tunnel object",
+               .next = NEXT(tunnel_create_attr, NEXT_ENTRY(PORT_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+               .call = parse_tunnel,
+       },
+       [TUNNEL_CREATE_TYPE] = {
+               .name = "type",
+               .help = "create new tunnel",
+               .next = NEXT(tunnel_create_attr, NEXT_ENTRY(FILE_PATH)),
+               .args = ARGS(ARGS_ENTRY(struct tunnel_ops, type)),
+               .call = parse_tunnel,
+       },
+       [TUNNEL_DESTROY] = {
+               .name = "destroy",
+               .help = "destroy tunel",
+               .next = NEXT(tunnel_destroy_attr, NEXT_ENTRY(PORT_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+               .call = parse_tunnel,
+       },
+       [TUNNEL_DESTROY_ID] = {
+               .name = "id",
+               .help = "tunnel identifier to testroy",
+               .next = NEXT(tunnel_destroy_attr, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY(struct tunnel_ops, id)),
+               .call = parse_tunnel,
+       },
+       [TUNNEL_LIST] = {
+               .name = "list",
+               .help = "list existing tunnels",
+               .next = NEXT(tunnel_list_attr, NEXT_ENTRY(PORT_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+               .call = parse_tunnel,
+       },
        /* Destroy arguments. */
        [DESTROY_RULE] = {
                .name = "rule",
@@ -2018,6 +2098,20 @@ static const struct token token_list[] = {
                .next = NEXT(next_vc_attr),
                .call = parse_vc,
        },
+       [TUNNEL_SET] = {
+               .name = "tunnel_set",
+               .help = "tunnel steer rule",
+               .next = NEXT(next_vc_attr, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY(struct tunnel_ops, id)),
+               .call = parse_vc,
+       },
+       [TUNNEL_MATCH] = {
+               .name = "tunnel_match",
+               .help = "tunnel match rule",
+               .next = NEXT(next_vc_attr, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY(struct tunnel_ops, id)),
+               .call = parse_vc,
+       },
        /* Validate/create pattern. */
        [PATTERN] = {
                .name = "pattern",
@@ -4495,12 +4589,28 @@ parse_vc(struct context *ctx, const struct token *token,
                return len;
        }
        ctx->objdata = 0;
-       ctx->object = &out->args.vc.attr;
+       switch (ctx->curr) {
+       default:
+               ctx->object = &out->args.vc.attr;
+               break;
+       case TUNNEL_SET:
+       case TUNNEL_MATCH:
+               ctx->object = &out->args.vc.tunnel_ops;
+               break;
+       }
        ctx->objmask = NULL;
        switch (ctx->curr) {
        case GROUP:
        case PRIORITY:
                return len;
+       case TUNNEL_SET:
+               out->args.vc.tunnel_ops.enabled = 1;
+               out->args.vc.tunnel_ops.actions = 1;
+               return len;
+       case TUNNEL_MATCH:
+               out->args.vc.tunnel_ops.enabled = 1;
+               out->args.vc.tunnel_ops.items = 1;
+               return len;
        case INGRESS:
                out->args.vc.attr.ingress = 1;
                return len;
@@ -6108,6 +6218,47 @@ parse_isolate(struct context *ctx, const struct token *token,
        return len;
 }
 
+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 = 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 != TUNNEL)
+                       return -1;
+               if (sizeof(*out) > size)
+                       return -1;
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+       } else {
+               switch (ctx->curr) {
+               default:
+                       break;
+               case TUNNEL_CREATE:
+               case TUNNEL_DESTROY:
+               case TUNNEL_LIST:
+                       out->command = ctx->curr;
+                       break;
+               case TUNNEL_CREATE_TYPE:
+               case TUNNEL_DESTROY_ID:
+                       ctx->object = &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;
        }
index c783108..2dfef81 100644 (file)
@@ -1521,6 +1521,115 @@ port_mtu_set(portid_t port_id, uint16_t mtu)
 
 /* Generic flow management functions. */
 
+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 == port_tunnel_id)
+                       goto out;
+       }
+       flow_tunnel = NULL;
+
+out:
+       return flow_tunnel;
+}
+
+const char *
+port_flow_tunnel_type(struct rte_flow_tunnel *tunnel)
+{
+       const char *type;
+       switch (tunnel->type) {
+       default:
+               type = "unknown";
+               break;
+       case RTE_FLOW_ITEM_TYPE_VXLAN:
+               type = "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 = &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 = NULL;
+
+out:
+       return flow_tunnel;
+}
+
+void port_flow_tunnel_list(portid_t port_id)
+{
+       struct rte_port *port = &ports[port_id];
+       struct port_flow_tunnel *flt;
+
+       LIST_FOREACH(flt, &port->flow_tunnel_list, chain) {
+               printf("port %u tunnel #%u type=%s",
+                       port_id, flt->id, port_flow_tunnel_type(&flt->tunnel));
+               if (flt->tunnel.tun_id)
+                       printf(" id=%" PRIu64, flt->tunnel.tun_id);
+               printf("\n");
+       }
+}
+
+void port_flow_tunnel_destroy(portid_t port_id, uint32_t tunnel_id)
+{
+       struct rte_port *port = &ports[port_id];
+       struct port_flow_tunnel *flt;
+
+       LIST_FOREACH(flt, &port->flow_tunnel_list, chain) {
+               if (flt->id == 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 *ops)
+{
+       struct rte_port *port = &ports[port_id];
+       enum rte_flow_item_type type;
+       struct port_flow_tunnel *flt;
+
+       if (!strcmp(ops->type, "vxlan"))
+               type = 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 == type)
+                       break;
+       }
+       if (!flt) {
+               flt = calloc(1, sizeof(*flt));
+               if (!flt) {
+                       printf("failed to allocate port flt object\n");
+                       return;
+               }
+               flt->tunnel.type = type;
+               flt->id = 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 = &ports[port_id];
+       pft = 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 = 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 = actions, num_actions = 1;
+                    aptr->type != RTE_FLOW_ACTION_TYPE_END;
+                    aptr++, num_actions++);
+               pft->actions = 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 = 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 = pattern, num_items = 1;
+                    iptr->type != RTE_FLOW_ITEM_TYPE_END;
+                    iptr++, num_items++);
+               pft->items = 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 = NULL;
+               pft->pmd_actions = 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 = NULL;
+               pft->pmd_items = NULL;
+       }
+}
 
 /** 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 = NULL;
 
        /* Poisoning to make sure PMDs update it in case of error. */
        memset(&error, 0x11, sizeof(error));
+       if (tunnel_ops->enabled) {
+               pft = port_flow_tunnel_offload_cmd_prep(port_id, pattern,
+                                                       actions, tunnel_ops);
+               if (!pft)
+                       return -ENOENT;
+               if (pft->items)
+                       pattern = pft->items;
+               if (pft->actions)
+                       actions = 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 = 0;
        struct rte_flow_error error;
+       struct port_flow_tunnel *pft = NULL;
 
        port = &ports[port_id];
        if (port->flow_list) {
@@ -1920,6 +2148,16 @@ port_flow_create(portid_t port_id,
                }
                id = port->flow_list->id + 1;
        }
+       if (tunnel_ops->enabled) {
+               pft = port_flow_tunnel_offload_cmd_prep(port_id, pattern,
+                                                       actions, tunnel_ops);
+               if (!pft)
+                       return -ENOENT;
+               if (pft->items)
+                       pattern = pft->items;
+               if (pft->actions)
+                       actions = pft->actions;
+       }
        pf = 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 = id;
        pf->flow = flow;
        port->flow_list = 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;
 }
@@ -2247,7 +2487,9 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group)
                       pf->rule.attr->egress ? 'e' : '-',
                       pf->rule.attr->transfer ? 't' : '-');
                while (item->type != RTE_FLOW_ITEM_TYPE_END) {
-                       if (rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_NAME_PTR,
+                       if ((uint32_t)item->type > INT_MAX)
+                               name = "PMD_INTERNAL";
+                       else if (rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_NAME_PTR,
                                          &name, sizeof(name),
                                          (void *)(uintptr_t)item->type,
                                          NULL) <= 0)
@@ -2258,7 +2500,9 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group)
                }
                printf("=>");
                while (action->type != RTE_FLOW_ACTION_TYPE_END) {
-                       if (rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR,
+                       if ((uint32_t)action->type > INT_MAX)
+                               name = "PMD_INTERNAL";
+                       else if (rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR,
                                          &name, sizeof(name),
                                          (void *)(uintptr_t)action->type,
                                          NULL) <= 0)
index 6caba60..333904d 100644 (file)
@@ -3684,6 +3684,8 @@ init_port_dcb_config(portid_t pid,
 static void
 init_port(void)
 {
+       int i;
+
        /* Configuration of Ethernet ports. */
        ports = 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 = 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);
index f8b0a35..5238ac3 100644 (file)
@@ -12,6 +12,7 @@
 #include <rte_gro.h>
 #include <rte_gso.h>
 #include <cmdline.h>
+#include <sys/queue.h>
 
 #define RTE_PORT_ALL            (~(portid_t)0x0)
 
@@ -150,6 +151,26 @@ struct port_shared_action {
        struct rte_flow_shared_action *action;  /**< Shared action handle. */
 };
 
+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, uint32_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 *ops);
 int port_flow_isolate(portid_t port_id, int set);
 
 void rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id);
index 8488fa1..781a813 100644 (file)
@@ -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 = 0; i < nb_pkts; i++) {
+               int ret;
+               struct rte_flow_error error;
+               struct rte_flow_restore_info info = { 0, };
+
                mb = pkts[i];
                eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);
                eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
-               ol_flags = mb->ol_flags;
                packet_type = mb->packet_type;
                is_encapsulation = RTE_ETH_IS_TUNNEL_PKT(packet_type);
-
+               ret = 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 = 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=", &eth_hdr->s_addr);
                print_ether_addr(" - dst=", &eth_hdr->d_addr);
                printf(" - type=0x%04x - length=%u - nb_segs=%d",
                       eth_type, (unsigned int) mb->pkt_len,
                       (int)mb->nb_segs);
+               ol_flags = mb->ol_flags;
                if (ol_flags & PKT_RX_RSS_HASH) {
                        printf(" - RSS hash=0x%x", (unsigned int) mb->hash.rss);
                        printf(" - RSS queue=0x%x", (unsigned int) queue);
index 43c0ea0..05a4446 100644 (file)
@@ -3749,6 +3749,45 @@ following sections.
 
    flow aged {port_id} [destroy]
 
+- 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
 ~~~~~~~~~~~~~~~~~~~~~
 
@@ -3795,6 +3834,7 @@ to ``rte_flow_create()``::
 
    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
 
@@ -3809,6 +3849,7 @@ Otherwise it will show an error message of the form::
 Parameters describe in the following order:
 
 - 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::
 
    testpmd> flow create 0 ingress pattern [...]
 
+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
 ^^^^^^^^^^^^^^^^