From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wj0-f174.google.com (mail-wj0-f174.google.com [209.85.210.174]) by dpdk.org (Postfix) with ESMTP id 1FAB810C5C for ; Wed, 21 Dec 2016 15:52:13 +0100 (CET) Received: by mail-wj0-f174.google.com with SMTP id xy5so204171436wjc.0 for ; Wed, 21 Dec 2016 06:52:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=6wind-com.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:in-reply-to:references; bh=Ra7aACVD86oqHoco694YucDlh6Vb+ntxBi3J0Ve82zM=; b=M90miOhD8NzWjaPl1RHXdM+sT3pbVTnypkp0h8pKJB5Oent/zkvyKGnA1Ob+sWZI7v p8MnxqFBUxQGBmrocQieEAQTyYJjlydEEA1NbaNQdUbMYAQ3PkGt0yFxaWg587A/Jx+w SnD6J+XrjTTw20Ey1/UH6RNBJYJN3CioByQ6Fr6lk1o2PT2Yok3Ofjr7F0rk9UcmBynz 3tBoHHo1zwgCOSbDB83DQatgJa7hf6sgOv7pEwRUeskkwsa4APjD353Kn2KHEG4OIVKZ 7DydWHgvZZFkzs6a5z2wK1qy+dtH0v6Z4NaTirvTYu2qvyAhf0BM2HZQaEnQbWfzX9ib zPRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=Ra7aACVD86oqHoco694YucDlh6Vb+ntxBi3J0Ve82zM=; b=qACpmFCxEQNz2omfgQlO8iAW4YL22+x3nnR7UJPivAkpmuBLSbG19anbblKpVfSz5a 2Z9F9dC+iWYoaadnP5aA2k3hpxS7D2+5fPF/YzTQ7dPagYUG0ky0MVWP6Bw+z9pASYdB HHsnWj4CYtWYugCcOMcUOcWhmfXyJM7m1y56BB5vGmlnpL4UMMcg0liorv6UjV0hqxs7 Dtu9GEmZd8Sr5NmlztoBiWO+kn7pcbn+ypgLZ1nndyqSwYnJk6myuK95i5ZpasiW4Okk gWoeK7srm0uK6iilahzL8UaP85uxXlZ7yyE2CgSvP0E/rJAGRmgEir1M0nZ52DC357C8 1eVg== X-Gm-Message-State: AIkVDXKiUg5Zv7FMfXds5sQ9+k2dc7LElMGTR9uiJ82Sn04Bz0I62Ctdqf6G4JaAky8vP4JG X-Received: by 10.195.18.201 with SMTP id go9mr4756372wjd.200.1482331932147; Wed, 21 Dec 2016 06:52:12 -0800 (PST) Received: from 6wind.com (guy78-3-82-239-227-177.fbx.proxad.net. [82.239.227.177]) by smtp.gmail.com with ESMTPSA id 135sm27559020wmh.14.2016.12.21.06.52.09 for (version=TLS1_2 cipher=AES128-SHA bits=128/128); Wed, 21 Dec 2016 06:52:11 -0800 (PST) From: Adrien Mazarguil To: dev@dpdk.org Date: Wed, 21 Dec 2016 15:51:22 +0100 Message-Id: <74fd1c930fc9e1766b76fe2d436ad5e6fb93672a.1482331076.git.adrien.mazarguil@6wind.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: References: Subject: [dpdk-dev] [PATCH v5 06/26] app/testpmd: implement basic support for rte_flow 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: , X-List-Received-Date: Wed, 21 Dec 2016 14:52:13 -0000 Add basic management functions for the generic flow API (validate, create, destroy, flush, query and list). Flow rule objects and properties are arranged in lists associated with each port. Signed-off-by: Adrien Mazarguil Acked-by: Olga Shern --- app/test-pmd/cmdline.c | 1 + app/test-pmd/config.c | 498 ++++++++++++++++++++++++++++++++++++++++ app/test-pmd/csumonly.c | 1 + app/test-pmd/flowgen.c | 1 + app/test-pmd/icmpecho.c | 1 + app/test-pmd/ieee1588fwd.c | 1 + app/test-pmd/iofwd.c | 1 + app/test-pmd/macfwd.c | 1 + app/test-pmd/macswap.c | 1 + app/test-pmd/parameters.c | 1 + app/test-pmd/rxonly.c | 1 + app/test-pmd/testpmd.c | 6 + app/test-pmd/testpmd.h | 27 +++ app/test-pmd/txonly.c | 1 + 14 files changed, 542 insertions(+) diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index d03a592..5d1c0dd 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -75,6 +75,7 @@ #include #include #include +#include #include #include diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index 8cf537d..9716ce7 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -92,6 +92,8 @@ #include #include #include +#include +#include #include "testpmd.h" @@ -751,6 +753,502 @@ port_mtu_set(portid_t port_id, uint16_t mtu) printf("Set MTU failed. diag=%d\n", diag); } +/* Generic flow management functions. */ + +/** Generate flow_item[] entry. */ +#define MK_FLOW_ITEM(t, s) \ + [RTE_FLOW_ITEM_TYPE_ ## t] = { \ + .name = # t, \ + .size = s, \ + } + +/** Information about known flow pattern items. */ +static const struct { + const char *name; + size_t size; +} flow_item[] = { + MK_FLOW_ITEM(END, 0), + MK_FLOW_ITEM(VOID, 0), + MK_FLOW_ITEM(INVERT, 0), + MK_FLOW_ITEM(ANY, sizeof(struct rte_flow_item_any)), + MK_FLOW_ITEM(PF, 0), + MK_FLOW_ITEM(VF, sizeof(struct rte_flow_item_vf)), + MK_FLOW_ITEM(PORT, sizeof(struct rte_flow_item_port)), + MK_FLOW_ITEM(RAW, sizeof(struct rte_flow_item_raw)), /* +pattern[] */ + MK_FLOW_ITEM(ETH, sizeof(struct rte_flow_item_eth)), + MK_FLOW_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)), + MK_FLOW_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)), + MK_FLOW_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)), + MK_FLOW_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)), + MK_FLOW_ITEM(UDP, sizeof(struct rte_flow_item_udp)), + MK_FLOW_ITEM(TCP, sizeof(struct rte_flow_item_tcp)), + MK_FLOW_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)), + MK_FLOW_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)), +}; + +/** Compute storage space needed by item specification. */ +static void +flow_item_spec_size(const struct rte_flow_item *item, + size_t *size, size_t *pad) +{ + if (!item->spec) + goto empty; + switch (item->type) { + union { + const struct rte_flow_item_raw *raw; + } spec; + + case RTE_FLOW_ITEM_TYPE_RAW: + spec.raw = item->spec; + *size = offsetof(struct rte_flow_item_raw, pattern) + + spec.raw->length * sizeof(*spec.raw->pattern); + break; + default: +empty: + *size = 0; + break; + } + *pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size; +} + +/** Generate flow_action[] entry. */ +#define MK_FLOW_ACTION(t, s) \ + [RTE_FLOW_ACTION_TYPE_ ## t] = { \ + .name = # t, \ + .size = s, \ + } + +/** Information about known flow actions. */ +static const struct { + const char *name; + size_t size; +} flow_action[] = { + MK_FLOW_ACTION(END, 0), + MK_FLOW_ACTION(VOID, 0), + MK_FLOW_ACTION(PASSTHRU, 0), + MK_FLOW_ACTION(MARK, sizeof(struct rte_flow_action_mark)), + MK_FLOW_ACTION(FLAG, 0), + MK_FLOW_ACTION(QUEUE, sizeof(struct rte_flow_action_queue)), + MK_FLOW_ACTION(DROP, 0), + MK_FLOW_ACTION(COUNT, 0), + MK_FLOW_ACTION(DUP, sizeof(struct rte_flow_action_dup)), + MK_FLOW_ACTION(RSS, sizeof(struct rte_flow_action_rss)), /* +queue[] */ + MK_FLOW_ACTION(PF, 0), + MK_FLOW_ACTION(VF, sizeof(struct rte_flow_action_vf)), +}; + +/** Compute storage space needed by action configuration. */ +static void +flow_action_conf_size(const struct rte_flow_action *action, + size_t *size, size_t *pad) +{ + if (!action->conf) + goto empty; + switch (action->type) { + union { + const struct rte_flow_action_rss *rss; + } conf; + + case RTE_FLOW_ACTION_TYPE_RSS: + conf.rss = action->conf; + *size = offsetof(struct rte_flow_action_rss, queue) + + conf.rss->num * sizeof(*conf.rss->queue); + break; + default: +empty: + *size = 0; + break; + } + *pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size; +} + +/** Generate a port_flow entry from attributes/pattern/actions. */ +static struct port_flow * +port_flow_new(const struct rte_flow_attr *attr, + const struct rte_flow_item *pattern, + const struct rte_flow_action *actions) +{ + const struct rte_flow_item *item; + const struct rte_flow_action *action; + struct port_flow *pf = NULL; + size_t tmp; + size_t pad; + size_t off1 = 0; + size_t off2 = 0; + int err = ENOTSUP; + +store: + item = pattern; + if (pf) + pf->pattern = (void *)&pf->data[off1]; + do { + struct rte_flow_item *dst = NULL; + + if ((unsigned int)item->type > RTE_DIM(flow_item) || + !flow_item[item->type].name) + goto notsup; + if (pf) + dst = memcpy(pf->data + off1, item, sizeof(*item)); + off1 += sizeof(*item); + flow_item_spec_size(item, &tmp, &pad); + if (item->spec) { + if (pf) + dst->spec = memcpy(pf->data + off2, + item->spec, tmp); + off2 += tmp + pad; + } + if (item->last) { + if (pf) + dst->last = memcpy(pf->data + off2, + item->last, tmp); + off2 += tmp + pad; + } + if (item->mask) { + if (pf) + dst->mask = memcpy(pf->data + off2, + item->mask, tmp); + off2 += tmp + pad; + } + off2 = RTE_ALIGN_CEIL(off2, sizeof(double)); + } while ((item++)->type != RTE_FLOW_ITEM_TYPE_END); + off1 = RTE_ALIGN_CEIL(off1, sizeof(double)); + action = actions; + if (pf) + pf->actions = (void *)&pf->data[off1]; + do { + struct rte_flow_action *dst = NULL; + + if ((unsigned int)action->type > RTE_DIM(flow_action) || + !flow_action[action->type].name) + goto notsup; + if (pf) + dst = memcpy(pf->data + off1, action, sizeof(*action)); + off1 += sizeof(*action); + flow_action_conf_size(action, &tmp, &pad); + if (action->conf) { + if (pf) + dst->conf = memcpy(pf->data + off2, + action->conf, tmp); + off2 += tmp + pad; + } + off2 = RTE_ALIGN_CEIL(off2, sizeof(double)); + } while ((action++)->type != RTE_FLOW_ACTION_TYPE_END); + if (pf != NULL) + return pf; + off1 = RTE_ALIGN_CEIL(off1, sizeof(double)); + tmp = RTE_ALIGN_CEIL(offsetof(struct port_flow, data), sizeof(double)); + pf = calloc(1, tmp + off1 + off2); + if (pf == NULL) + err = errno; + else { + *pf = (const struct port_flow){ + .size = tmp + off1 + off2, + .attr = *attr, + }; + tmp -= offsetof(struct port_flow, data); + off2 = tmp + off1; + off1 = tmp; + goto store; + } +notsup: + rte_errno = err; + return NULL; +} + +/** Print a message out of a flow error. */ +static int +port_flow_complain(struct rte_flow_error *error) +{ + static const char *const errstrlist[] = { + [RTE_FLOW_ERROR_TYPE_NONE] = "no error", + [RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = "cause unspecified", + [RTE_FLOW_ERROR_TYPE_HANDLE] = "flow rule (handle)", + [RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = "group field", + [RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = "priority field", + [RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = "ingress field", + [RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = "egress field", + [RTE_FLOW_ERROR_TYPE_ATTR] = "attributes structure", + [RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "pattern length", + [RTE_FLOW_ERROR_TYPE_ITEM] = "specific pattern item", + [RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "number of actions", + [RTE_FLOW_ERROR_TYPE_ACTION] = "specific action", + }; + const char *errstr; + char buf[32]; + int err = rte_errno; + + if ((unsigned int)error->type > RTE_DIM(errstrlist) || + !errstrlist[error->type]) + errstr = "unknown type"; + else + errstr = errstrlist[error->type]; + printf("Caught error type %d (%s): %s%s\n", + error->type, errstr, + error->cause ? (snprintf(buf, sizeof(buf), "cause: %p, ", + error->cause), buf) : "", + error->message ? error->message : "(no stated reason)"); + return -err; +} + +/** 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) +{ + struct rte_flow_error error; + + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x11, sizeof(error)); + if (rte_flow_validate(port_id, attr, pattern, actions, &error)) + return port_flow_complain(&error); + printf("Flow rule validated\n"); + return 0; +} + +/** Create flow rule. */ +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) +{ + struct rte_flow *flow; + struct rte_port *port; + struct port_flow *pf; + uint32_t id; + struct rte_flow_error error; + + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x22, sizeof(error)); + flow = rte_flow_create(port_id, attr, pattern, actions, &error); + if (!flow) + return port_flow_complain(&error); + port = &ports[port_id]; + if (port->flow_list) { + if (port->flow_list->id == UINT32_MAX) { + printf("Highest rule ID is already assigned, delete" + " it first"); + rte_flow_destroy(port_id, flow, NULL); + return -ENOMEM; + } + id = port->flow_list->id + 1; + } else + id = 0; + pf = port_flow_new(attr, pattern, actions); + if (!pf) { + int err = rte_errno; + + printf("Cannot allocate flow: %s\n", rte_strerror(err)); + rte_flow_destroy(port_id, flow, NULL); + return -err; + } + pf->next = port->flow_list; + pf->id = id; + pf->flow = flow; + port->flow_list = pf; + printf("Flow rule #%u created\n", pf->id); + return 0; +} + +/** Destroy a number of flow rules. */ +int +port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule) +{ + struct rte_port *port; + struct port_flow **tmp; + uint32_t c = 0; + int ret = 0; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + port = &ports[port_id]; + tmp = &port->flow_list; + while (*tmp) { + uint32_t i; + + for (i = 0; i != n; ++i) { + struct rte_flow_error error; + struct port_flow *pf = *tmp; + + if (rule[i] != pf->id) + continue; + /* + * Poisoning to make sure PMDs update it in case + * of error. + */ + memset(&error, 0x33, sizeof(error)); + if (rte_flow_destroy(port_id, pf->flow, &error)) { + ret = port_flow_complain(&error); + continue; + } + printf("Flow rule #%u destroyed\n", pf->id); + *tmp = pf->next; + free(pf); + break; + } + if (i == n) + tmp = &(*tmp)->next; + ++c; + } + return ret; +} + +/** Remove all flow rules. */ +int +port_flow_flush(portid_t port_id) +{ + struct rte_flow_error error; + struct rte_port *port; + int ret = 0; + + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x44, sizeof(error)); + if (rte_flow_flush(port_id, &error)) { + ret = port_flow_complain(&error); + if (port_id_is_invalid(port_id, DISABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return ret; + } + port = &ports[port_id]; + while (port->flow_list) { + struct port_flow *pf = port->flow_list->next; + + free(port->flow_list); + port->flow_list = pf; + } + return ret; +} + +/** Query a flow rule. */ +int +port_flow_query(portid_t port_id, uint32_t rule, + enum rte_flow_action_type action) +{ + struct rte_flow_error error; + struct rte_port *port; + struct port_flow *pf; + const char *name; + union { + struct rte_flow_query_count count; + } query; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return -EINVAL; + port = &ports[port_id]; + for (pf = port->flow_list; pf; pf = pf->next) + if (pf->id == rule) + break; + if (!pf) { + printf("Flow rule #%u not found\n", rule); + return -ENOENT; + } + if ((unsigned int)action > RTE_DIM(flow_action) || + !flow_action[action].name) + name = "unknown"; + else + name = flow_action[action].name; + switch (action) { + case RTE_FLOW_ACTION_TYPE_COUNT: + break; + default: + printf("Cannot query action type %d (%s)\n", action, name); + return -ENOTSUP; + } + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x55, sizeof(error)); + memset(&query, 0, sizeof(query)); + if (rte_flow_query(port_id, pf->flow, action, &query, &error)) + return port_flow_complain(&error); + switch (action) { + case RTE_FLOW_ACTION_TYPE_COUNT: + printf("%s:\n" + " hits_set: %u\n" + " bytes_set: %u\n" + " hits: %" PRIu64 "\n" + " bytes: %" PRIu64 "\n", + name, + query.count.hits_set, + query.count.bytes_set, + query.count.hits, + query.count.bytes); + break; + default: + printf("Cannot display result for action type %d (%s)\n", + action, name); + break; + } + return 0; +} + +/** List flow rules. */ +void +port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n]) +{ + struct rte_port *port; + struct port_flow *pf; + struct port_flow *list = NULL; + uint32_t i; + + if (port_id_is_invalid(port_id, ENABLED_WARN) || + port_id == (portid_t)RTE_PORT_ALL) + return; + port = &ports[port_id]; + if (!port->flow_list) + return; + /* Sort flows by group, priority and ID. */ + for (pf = port->flow_list; pf != NULL; pf = pf->next) { + struct port_flow **tmp; + + if (n) { + /* Filter out unwanted groups. */ + for (i = 0; i != n; ++i) + if (pf->attr.group == group[i]) + break; + if (i == n) + continue; + } + tmp = &list; + while (*tmp && + (pf->attr.group > (*tmp)->attr.group || + (pf->attr.group == (*tmp)->attr.group && + pf->attr.priority > (*tmp)->attr.priority) || + (pf->attr.group == (*tmp)->attr.group && + pf->attr.priority == (*tmp)->attr.priority && + pf->id > (*tmp)->id))) + tmp = &(*tmp)->tmp; + pf->tmp = *tmp; + *tmp = pf; + } + printf("ID\tGroup\tPrio\tAttr\tRule\n"); + for (pf = list; pf != NULL; pf = pf->tmp) { + const struct rte_flow_item *item = pf->pattern; + const struct rte_flow_action *action = pf->actions; + + printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c\t", + pf->id, + pf->attr.group, + pf->attr.priority, + pf->attr.ingress ? 'i' : '-', + pf->attr.egress ? 'e' : '-'); + while (item->type != RTE_FLOW_ITEM_TYPE_END) { + if (item->type != RTE_FLOW_ITEM_TYPE_VOID) + printf("%s ", flow_item[item->type].name); + ++item; + } + printf("=>"); + while (action->type != RTE_FLOW_ACTION_TYPE_END) { + if (action->type != RTE_FLOW_ACTION_TYPE_VOID) + printf(" %s", flow_action[action->type].name); + ++action; + } + printf("\n"); + } +} + /* * RX/TX ring descriptors display functions. */ diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c index 57e6ae2..dd67ebf 100644 --- a/app/test-pmd/csumonly.c +++ b/app/test-pmd/csumonly.c @@ -70,6 +70,7 @@ #include #include #include +#include #include "testpmd.h" #define IP_DEFTTL 64 /* from RFC 1340. */ diff --git a/app/test-pmd/flowgen.c b/app/test-pmd/flowgen.c index b13ff89..13b4f90 100644 --- a/app/test-pmd/flowgen.c +++ b/app/test-pmd/flowgen.c @@ -68,6 +68,7 @@ #include #include #include +#include #include "testpmd.h" diff --git a/app/test-pmd/icmpecho.c b/app/test-pmd/icmpecho.c index 6a4e750..f25a8f5 100644 --- a/app/test-pmd/icmpecho.c +++ b/app/test-pmd/icmpecho.c @@ -61,6 +61,7 @@ #include #include #include +#include #include "testpmd.h" diff --git a/app/test-pmd/ieee1588fwd.c b/app/test-pmd/ieee1588fwd.c index 0d3b37a..51170ee 100644 --- a/app/test-pmd/ieee1588fwd.c +++ b/app/test-pmd/ieee1588fwd.c @@ -34,6 +34,7 @@ #include #include +#include #include "testpmd.h" diff --git a/app/test-pmd/iofwd.c b/app/test-pmd/iofwd.c index 26936b7..15cb4a2 100644 --- a/app/test-pmd/iofwd.c +++ b/app/test-pmd/iofwd.c @@ -64,6 +64,7 @@ #include #include #include +#include #include "testpmd.h" diff --git a/app/test-pmd/macfwd.c b/app/test-pmd/macfwd.c index 86e01de..d361db1 100644 --- a/app/test-pmd/macfwd.c +++ b/app/test-pmd/macfwd.c @@ -65,6 +65,7 @@ #include #include #include +#include #include "testpmd.h" diff --git a/app/test-pmd/macswap.c b/app/test-pmd/macswap.c index 36e139f..f996039 100644 --- a/app/test-pmd/macswap.c +++ b/app/test-pmd/macswap.c @@ -65,6 +65,7 @@ #include #include #include +#include #include "testpmd.h" diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index 08e5a76..28db8cd 100644 --- a/app/test-pmd/parameters.c +++ b/app/test-pmd/parameters.c @@ -76,6 +76,7 @@ #ifdef RTE_LIBRTE_PMD_BOND #include #endif +#include #include "testpmd.h" diff --git a/app/test-pmd/rxonly.c b/app/test-pmd/rxonly.c index fff815c..cf00576 100644 --- a/app/test-pmd/rxonly.c +++ b/app/test-pmd/rxonly.c @@ -67,6 +67,7 @@ #include #include #include +#include #include "testpmd.h" diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index a0332c2..bfb2f8e 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -78,6 +78,7 @@ #ifdef RTE_LIBRTE_PDUMP #include #endif +#include #include "testpmd.h" @@ -1545,6 +1546,8 @@ close_port(portid_t pid) continue; } + if (port->flow_list) + port_flow_flush(pi); rte_eth_dev_close(pi); if (rte_atomic16_cmpset(&(port->port_status), @@ -1599,6 +1602,9 @@ detach_port(uint8_t port_id) return; } + if (ports[port_id].flow_list) + port_flow_flush(port_id); + if (rte_eth_dev_detach(port_id, name)) return; diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 9c1e703..22ce2d6 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -144,6 +144,19 @@ struct fwd_stream { /** Insert double VLAN header in forward engine */ #define TESTPMD_TX_OFFLOAD_INSERT_QINQ 0x0080 +/** Descriptor for a single flow. */ +struct port_flow { + size_t size; /**< Allocated space including data[]. */ + struct port_flow *next; /**< Next flow in list. */ + struct port_flow *tmp; /**< Temporary linking. */ + uint32_t id; /**< Flow rule ID. */ + struct rte_flow *flow; /**< Opaque flow object returned by PMD. */ + struct rte_flow_attr attr; /**< Attributes. */ + struct rte_flow_item *pattern; /**< Pattern. */ + struct rte_flow_action *actions; /**< Actions. */ + uint8_t data[]; /**< Storage for pattern/actions. */ +}; + /** * The data structure associated with each port. */ @@ -177,6 +190,7 @@ struct rte_port { struct ether_addr *mc_addr_pool; /**< pool of multicast addrs */ 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. */ }; extern portid_t __rte_unused @@ -504,6 +518,19 @@ void port_reg_bit_field_set(portid_t port_id, uint32_t reg_off, uint8_t bit1_pos, uint8_t bit2_pos, uint32_t value); void port_reg_display(portid_t port_id, uint32_t reg_off); void port_reg_set(portid_t port_id, uint32_t reg_off, uint32_t value); +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); +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); +int port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule); +int port_flow_flush(portid_t port_id); +int port_flow_query(portid_t port_id, uint32_t rule, + enum rte_flow_action_type action); +void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group); void rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id); void tx_ring_desc_display(portid_t port_id, queueid_t txq_id, uint16_t txd_id); diff --git a/app/test-pmd/txonly.c b/app/test-pmd/txonly.c index 8513a06..e996f35 100644 --- a/app/test-pmd/txonly.c +++ b/app/test-pmd/txonly.c @@ -68,6 +68,7 @@ #include #include #include +#include #include "testpmd.h" -- 2.1.4