From patchwork Mon Jan 20 15:08:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eli Britstein X-Patchwork-Id: 1226015 X-Patchwork-Delegate: i.maximets@samsung.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=silver.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 481Znh6Zhbz9sRk for ; Tue, 21 Jan 2020 02:09:12 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id E30C520464; Mon, 20 Jan 2020 15:09:10 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id KnXa3pKQUK9Z; Mon, 20 Jan 2020 15:08:59 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id D61A61FEED; Mon, 20 Jan 2020 15:08:56 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id BF517C0176; Mon, 20 Jan 2020 15:08:56 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 00DDFC0174 for ; Mon, 20 Jan 2020 15:08:55 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id F15B42045C for ; Mon, 20 Jan 2020 15:08:54 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id yaiRHlrEYCDi for ; Mon, 20 Jan 2020 15:08:50 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by silver.osuosl.org (Postfix) with ESMTP id 16B1B2043E for ; Mon, 20 Jan 2020 15:08:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from elibr@mellanox.com) with ESMTPS (AES256-SHA encrypted); 20 Jan 2020 17:08:44 +0200 Received: from dev-r-vrt-215.mtr.labs.mlnx. (dev-r-vrt-215.mtr.labs.mlnx [10.212.215.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 00KF8hV2013116; Mon, 20 Jan 2020 17:08:44 +0200 From: Eli Britstein To: dev@openvswitch.org, Ilya Maximets Date: Mon, 20 Jan 2020 15:08:17 +0000 Message-Id: <20200120150830.16262-13-elibr@mellanox.com> X-Mailer: git-send-email 2.14.5 In-Reply-To: <20200120150830.16262-1-elibr@mellanox.com> References: <20200120150830.16262-1-elibr@mellanox.com> Cc: Simon Horman , Eli Britstein , Ameer Mahagneh Subject: [ovs-dev] [PATCH 12/25] netdev-offload-dpdk: Introduce map APIs for table id and miss context X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Different vports are differentiated in HW by different tables, as in the SW model. As such we need to map to table ids. Also, as this offload involves multiple tables, a miss might occur in the target table. In such case we need to recover the packet and continue in SW. Introduce a mapping for a miss context for that. Signed-off-by: Eli Britstein Reviewed-by: Roni Bar Yanai --- lib/netdev-offload-dpdk.c | 267 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c index c80f07e77..fc890b915 100644 --- a/lib/netdev-offload-dpdk.c +++ b/lib/netdev-offload-dpdk.c @@ -29,6 +29,8 @@ #include "openvswitch/vlog.h" #include "packets.h" #include "uuid.h" +#include "id-pool.h" +#include "odp-util.h" VLOG_DEFINE_THIS_MODULE(netdev_offload_dpdk); static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(100, 5); @@ -125,6 +127,271 @@ ufid_to_rte_flow_disassociate(const ovs_u128 *ufid) UUID_ARGS((struct uuid *) ufid)); } +/* A generic data structure used for mapping data to id and id to data. The + * elements are reference coutned. As changes are done only from the single + * offload thread, no locks are required. + * "name" and "dump_context_data" are used for log messages. + * "d2i_hmap" is the data-to-id map. + * "i2d_hmap" is the id-to-data map. + * "id_alloc" is used to allocate an id for a new data. + * "id_free" is used to free an id for the last data release. + * "data_size" is the size of the data in the elements. + */ +struct context_metadata { + const char *name; + struct ds *(*dump_context_data)(struct ds *s, void *data); + struct hmap d2i_hmap; + struct hmap i2d_hmap; + uint32_t (*id_alloc)(void); + void (*id_free)(uint32_t id); + size_t data_size; +}; + +struct context_data { + struct hmap_node d2i_node; + struct hmap_node i2d_node; + void *data; + uint32_t id; + uint32_t refcnt; +}; + +static int +get_context_data_id_by_data(struct context_metadata *md, + struct context_data *data_req, + uint32_t *id) +{ + struct context_data *data_cur; + size_t dhash, ihash; + struct ds s; + + ds_init(&s); + dhash = hash_bytes(data_req->data, md->data_size, 0); + HMAP_FOR_EACH_WITH_HASH (data_cur, d2i_node, dhash, &md->d2i_hmap) { + if (!memcmp(data_req->data, data_cur->data, md->data_size)) { + data_cur->refcnt++; + VLOG_DBG_RL(&rl, + "%s: %s: '%s', refcnt=%d, id=%d", __func__, md->name, + ds_cstr(md->dump_context_data(&s, data_cur->data)), + data_cur->refcnt, data_cur->id); + ds_destroy(&s); + *id = data_cur->id; + return 0; + } + } + + data_cur = xzalloc(sizeof *data_cur); + if (!data_cur) { + goto err; + } + data_cur->data = xmalloc(md->data_size); + if (!data_cur->data) { + goto err_data_alloc; + } + memcpy(data_cur->data, data_req->data, md->data_size); + data_cur->refcnt = 1; + data_cur->id = md->id_alloc(); + if (data_cur->id == 0) { + goto err_id_alloc; + } + hmap_insert(&md->d2i_hmap, &data_cur->d2i_node, dhash); + ihash = hash_add(0, data_cur->id); + hmap_insert(&md->i2d_hmap, &data_cur->i2d_node, ihash); + VLOG_DBG_RL(&rl, "%s: %s: '%s', refcnt=%d, id=%d", __func__, md->name, + ds_cstr(md->dump_context_data(&s, data_cur->data)), + data_cur->refcnt, data_cur->id); + *id = data_cur->id; + ds_destroy(&s); + return 0; + +err_id_alloc: + free(data_cur->data); +err_data_alloc: + free(data_cur); +err: + VLOG_ERR_RL(&rl, "%s: %s: error. '%s'", __func__, md->name, + ds_cstr(md->dump_context_data(&s, data_cur->data))); + ds_destroy(&s); + return -1; +} + +static int +get_context_data_by_id(struct context_metadata *md, uint32_t id, void *data) +{ + size_t ihash = hash_add(0, id); + struct context_data *data_cur; + struct ds s; + + ds_init(&s); + HMAP_FOR_EACH_WITH_HASH (data_cur, i2d_node, ihash, &md->i2d_hmap) { + if (data_cur->id == id) { + memcpy(data, data_cur->data, md->data_size); + ds_destroy(&s); + return 0; + } + } + + ds_destroy(&s); + return -1; +} + +static void +put_context_data_by_id(struct context_metadata *md, uint32_t id) +{ + struct context_data *data_cur; + size_t ihash; + struct ds s; + + if (id == 0) { + return; + } + ihash = hash_add(0, id); + HMAP_FOR_EACH_WITH_HASH (data_cur, i2d_node, ihash, &md->i2d_hmap) { + if (data_cur->id == id) { + data_cur->refcnt--; + ds_init(&s); + VLOG_DBG_RL(&rl, + "%s: %s: '%s', refcnt=%d, id=%d", __func__, md->name, + ds_cstr(md->dump_context_data(&s, data_cur->data)), + data_cur->refcnt, data_cur->id); + ds_destroy(&s); + if (data_cur->refcnt == 0) { + hmap_remove(&md->i2d_hmap, &data_cur->i2d_node); + hmap_remove(&md->d2i_hmap, &data_cur->d2i_node); + free(data_cur); + md->id_free(id); + } + return; + } + } + VLOG_ERR_RL(&rl, + "%s: %s: error. id=%d not found", __func__, md->name, id); +} + +struct table_id_data { + odp_port_t vport; +}; + +static struct ds * +dump_table_id(struct ds *s, void *data) +{ + struct table_id_data *table_id_data = data; + + ds_put_format(s, "vport=%"PRIu32, table_id_data->vport); + return s; +} + +#define MIN_TABLE_ID 1 +#define MAX_TABLE_ID 0xFFFF + +static struct id_pool *table_id_pool = NULL; +static uint32_t +table_id_alloc(void) +{ + uint32_t id; + + if (!table_id_pool) { + /* Haven't initiated yet, do it here */ + table_id_pool = id_pool_create(MIN_TABLE_ID, MAX_TABLE_ID); + } + + if (id_pool_alloc_id(table_id_pool, &id)) { + return id; + } + + return 0; +} + +static void +table_id_free(uint32_t id) +{ + id_pool_free_id(table_id_pool, id); +} + +static struct context_metadata table_id_md = { + .name = "table_id", + .dump_context_data = dump_table_id, + .d2i_hmap = HMAP_INITIALIZER(&table_id_md.d2i_hmap), + .i2d_hmap = HMAP_INITIALIZER(&table_id_md.i2d_hmap), + .id_alloc = table_id_alloc, + .id_free = table_id_free, + .data_size = sizeof(struct table_id_data), +}; + +OVS_UNUSED +static int +get_table_id(odp_port_t vport, uint32_t *table_id) +{ + struct table_id_data table_id_data = { .vport = vport }; + struct context_data table_id_context = { + .data = &table_id_data, + }; + + if (vport == ODPP_NONE) { + *table_id = 0; + return 0; + } + + return get_context_data_id_by_data(&table_id_md, &table_id_context, + table_id); +} + +OVS_UNUSED +static void +put_table_id(uint32_t table_id) +{ + put_context_data_by_id(&table_id_md, table_id); +} + +struct flow_miss_ctx { + odp_port_t vport; +}; + +static struct ds * +dump_flow_ctx_id(struct ds *s, void *data) +{ + struct flow_miss_ctx *flow_ctx_data = data; + + ds_put_format(s, "vport=%"PRIu32, flow_ctx_data->vport); + return s; +} + +static struct context_metadata flow_miss_ctx_md = { + .name = "flow_miss_ctx", + .dump_context_data = dump_flow_ctx_id, + .d2i_hmap = HMAP_INITIALIZER(&flow_miss_ctx_md.d2i_hmap), + .i2d_hmap = HMAP_INITIALIZER(&flow_miss_ctx_md.i2d_hmap), + .id_alloc = netdev_offload_flow_mark_alloc, + .id_free = netdev_offload_flow_mark_free, + .data_size = sizeof(struct flow_miss_ctx), +}; + +OVS_UNUSED +static int +get_flow_miss_ctx_id(struct flow_miss_ctx *flow_ctx_data, + uint32_t *miss_ctx_id) +{ + struct context_data flow_ctx = { + .data = flow_ctx_data, + }; + + return get_context_data_id_by_data(&flow_miss_ctx_md, &flow_ctx, + miss_ctx_id); +} + +OVS_UNUSED +static void +put_flow_miss_ctx_id(uint32_t flow_ctx_id) +{ + put_context_data_by_id(&flow_miss_ctx_md, flow_ctx_id); +} + +OVS_UNUSED +static int +find_flow_miss_ctx(int flow_ctx_id, struct flow_miss_ctx *ctx) +{ + return get_context_data_by_id(&flow_miss_ctx_md, flow_ctx_id, ctx); +} + /* * To avoid individual xrealloc calls for each new element, a 'curent_max' * is used to keep track of current allocated number of elements. Starts