From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wi0-f169.google.com (mail-wi0-f169.google.com [209.85.212.169]) by dpdk.org (Postfix) with ESMTP id E49DDC40A for ; Sat, 6 Jun 2015 01:16:28 +0200 (CEST) Received: by wibut5 with SMTP id ut5so34659357wib.1 for ; Fri, 05 Jun 2015 16:16:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=JcBynnduIm7zt2tH+4byh+BSUw4fr1pCCVgIDhjchMI=; b=dK2S3LtQTr6MBJsJvok9g3sz6YEBeZe4VALpSKlsVauEjHInJAM4yHB6vY+VcR3S4N VAm2wYkgg225SNn2MFlpcmv+2D7Od5sbd+hIMnk+pGr9PEqF3PcfBgf4F1VWwSiCro/G u8KZmcMJDq8ZnYhOmM8Q6erSYt4RHfhPTVgYU/fvUJ+VXROSV6FpVCK0WA3EwjVuvkjS fwOVljA3m+p2G/nUbXSaOvaUa6mFUMZ4phAJPuzSO6qzsts/9OwbStXv1ODbOLnLDY4o Zrm5uEu1Hwrrex55jaF8fWGpSc8q6/MVhm/A3a/9bj2nBnVTPYFanPbuHrBQtUr3a0+H LvYg== X-Gm-Message-State: ALoCoQn9HjViq/ZwVs4JTIHgWPX6UqrL7RKbHkGLSy0cxLrysZEEuQ8MBsB2+qJlBV7zJ0/UYGzU X-Received: by 10.194.176.201 with SMTP id ck9mr10405361wjc.108.1433546188831; Fri, 05 Jun 2015 16:16:28 -0700 (PDT) Received: from 6wind.com (guy78-3-82-239-227-177.fbx.proxad.net. [82.239.227.177]) by mx.google.com with ESMTPSA id d3sm3992011wjs.21.2015.06.05.16.16.27 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 05 Jun 2015 16:16:28 -0700 (PDT) From: Adrien Mazarguil To: dev@dpdk.org Date: Sat, 6 Jun 2015 01:15:19 +0200 Message-Id: <1433546120-2254-16-git-send-email-adrien.mazarguil@6wind.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1433546120-2254-1-git-send-email-adrien.mazarguil@6wind.com> References: <1433546120-2254-1-git-send-email-adrien.mazarguil@6wind.com> Subject: [dpdk-dev] [PATCH 15/16] mlx4: fix support for multiple VLAN filters X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 05 Jun 2015 23:16:29 -0000 From: Olga Shern This commit fixes the "Multiple RX VLAN filters can be configured, but only the first one works" bug. Since a single flow specification cannot contain several VLAN definitions, the flows table is extended with MLX4_MAX_VLAN_IDS possible specifications per configured MAC address. Signed-off-by: Olga Shern Signed-off-by: Or Ami Signed-off-by: Adrien Mazarguil --- drivers/net/mlx4/mlx4.c | 174 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 115 insertions(+), 59 deletions(-) diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c index 4c0294a..4c4f693 100644 --- a/drivers/net/mlx4/mlx4.c +++ b/drivers/net/mlx4/mlx4.c @@ -33,8 +33,6 @@ /* * Known limitations: - * - Multiple RX VLAN filters can be configured, but only the first one - * works properly. * - RSS hash key and options cannot be modified. * - Hardware counters aren't implemented. */ @@ -227,11 +225,10 @@ struct rxq { /* Faster callbacks that bypass Verbs. */ drv_exp_poll_cq_func ibv_exp_poll_cq; /* - * There is exactly one flow configured per MAC address. Each flow - * may contain several specifications, one per configured VLAN ID. + * Each VLAN ID requires a separate flow steering rule. */ BITFIELD_DECLARE(mac_configured, uint32_t, MLX4_MAX_MAC_ADDRESSES); - struct mlx_flow *mac_flow[MLX4_MAX_MAC_ADDRESSES]; + struct mlx_flow *mac_flow[MLX4_MAX_MAC_ADDRESSES][MLX4_MAX_VLAN_IDS]; struct mlx_flow *promisc_flow; /* Promiscuous flow. */ struct mlx_flow *allmulti_flow; /* Multicast flow. */ unsigned int port_id; /* Port ID for incoming packets. */ @@ -1880,15 +1877,17 @@ rxq_free_elts(struct rxq *rxq) } /** - * Unregister a MAC address from a RX queue. + * Delete flow steering rule. * * @param rxq * Pointer to RX queue structure. * @param mac_index * MAC address index. + * @param vlan_index + * VLAN index. */ static void -rxq_mac_addr_del(struct rxq *rxq, unsigned int mac_index) +rxq_del_flow(struct rxq *rxq, unsigned int mac_index, unsigned int vlan_index) { #ifndef NDEBUG struct priv *priv = rxq->priv; @@ -1896,20 +1895,43 @@ rxq_mac_addr_del(struct rxq *rxq, unsigned int mac_index) (const uint8_t (*)[ETHER_ADDR_LEN]) priv->mac[mac_index].addr_bytes; #endif + assert(rxq->mac_flow[mac_index][vlan_index] != NULL); + DEBUG("%p: removing MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u" + " (VLAN ID %" PRIu16 ")", + (void *)rxq, + (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5], + mac_index, priv->vlan_filter[vlan_index].id); + claim_zero(mlx_destroy_flow(rxq->mac_flow[mac_index][vlan_index])); + rxq->mac_flow[mac_index][vlan_index] = NULL; +} + +/** + * Unregister a MAC address from a RX queue. + * + * @param rxq + * Pointer to RX queue structure. + * @param mac_index + * MAC address index. + */ +static void +rxq_mac_addr_del(struct rxq *rxq, unsigned int mac_index) +{ + struct priv *priv = rxq->priv; + unsigned int i; + unsigned int vlans = 0; assert(mac_index < elemof(priv->mac)); - if (!BITFIELD_ISSET(rxq->mac_configured, mac_index)) { - assert(rxq->mac_flow[mac_index] == NULL); + if (!BITFIELD_ISSET(rxq->mac_configured, mac_index)) return; + for (i = 0; (i != elemof(priv->vlan_filter)); ++i) { + if (!priv->vlan_filter[i].enabled) + continue; + rxq_del_flow(rxq, mac_index, i); + vlans++; + } + if (!vlans) { + rxq_del_flow(rxq, mac_index, 0); } - DEBUG("%p: removing MAC address %02x:%02x:%02x:%02x:%02x:%02x" - " index %u", - (void *)rxq, - (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5], - mac_index); - assert(rxq->mac_flow[mac_index] != NULL); - claim_zero(mlx_destroy_flow(rxq->mac_flow[mac_index])); - rxq->mac_flow[mac_index] = NULL; BITFIELD_RESET(rxq->mac_configured, mac_index); } @@ -1933,47 +1955,37 @@ static int rxq_promiscuous_enable(struct rxq *); static void rxq_promiscuous_disable(struct rxq *); /** - * Register a MAC address in a RX queue. + * Add single flow steering rule. * * @param rxq * Pointer to RX queue structure. * @param mac_index * MAC address index to register. + * @param vlan_index + * VLAN index. Use -1 for a flow without VLAN. * * @return * 0 on success, errno value on failure. */ static int -rxq_mac_addr_add(struct rxq *rxq, unsigned int mac_index) +rxq_add_flow(struct rxq *rxq, unsigned int mac_index, unsigned int vlan_index) { + struct mlx_flow *flow; struct priv *priv = rxq->priv; const uint8_t (*mac)[ETHER_ADDR_LEN] = - (const uint8_t (*)[ETHER_ADDR_LEN]) - priv->mac[mac_index].addr_bytes; - unsigned int vlans = 0; - unsigned int specs = 0; - unsigned int i, j; - struct mlx_flow *flow; - - assert(mac_index < elemof(priv->mac)); - if (BITFIELD_ISSET(rxq->mac_configured, mac_index)) - rxq_mac_addr_del(rxq, mac_index); - /* Number of configured VLANs. */ - for (i = 0; (i != elemof(priv->vlan_filter)); ++i) - if (priv->vlan_filter[i].enabled) - ++vlans; - specs = (vlans ? vlans : 1); + (const uint8_t (*)[ETHER_ADDR_LEN]) + priv->mac[mac_index].addr_bytes; /* Allocate flow specification on the stack. */ - struct mlx_flow_attr data - [1 + - (sizeof(struct mlx_flow_spec_eth[specs]) / - sizeof(struct mlx_flow_attr)) + - !!(sizeof(struct mlx_flow_spec_eth[specs]) % - sizeof(struct mlx_flow_attr))]; - struct mlx_flow_attr *attr = (void *)&data[0]; - struct mlx_flow_spec_eth *spec = (void *)&data[1]; + struct __attribute__((packed)) { + struct mlx_flow_attr attr; + struct mlx_flow_spec_eth spec; + } data; + struct mlx_flow_attr *attr = &data.attr; + struct mlx_flow_spec_eth *spec = &data.spec; + assert(mac_index < elemof(priv->mac)); + assert((vlan_index < elemof(priv->vlan_filter)) || (vlan_index == -1u)); /* * No padding must be inserted by the compiler between attr and spec. * This layout is expected by libibverbs. @@ -1981,7 +1993,7 @@ rxq_mac_addr_add(struct rxq *rxq, unsigned int mac_index) assert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec); *attr = (struct mlx_flow_attr) { .type = MLX_FLOW_ATTR_NORMAL, - .num_of_specs = specs, + .num_of_specs = 1, .port = priv->port, .flags = 0 }; @@ -1992,29 +2004,23 @@ rxq_mac_addr_add(struct rxq *rxq, unsigned int mac_index) .dst_mac = { (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5] - } + }, + .vlan_tag = ((vlan_index != -1u) ? + htons(priv->vlan_filter[vlan_index].id) : + 0), }, .mask = { .dst_mac = "\xff\xff\xff\xff\xff\xff", - .vlan_tag = (vlans ? htons(0xfff) : 0) + .vlan_tag = ((vlan_index != -1u) ? htons(0xfff) : 0), } }; - /* Fill VLAN specifications. */ - for (i = 0, j = 0; (i != elemof(priv->vlan_filter)); ++i) { - if (!priv->vlan_filter[i].enabled) - continue; - assert(j != vlans); - if (j) - spec[j] = spec[0]; - spec[j].val.vlan_tag = htons(priv->vlan_filter[i].id); - ++j; - } DEBUG("%p: adding MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u" - " (%u VLAN(s) configured)", + " (VLAN %s %" PRIu16 ")", (void *)rxq, (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5], mac_index, - vlans); + ((vlan_index != -1u) ? "ID" : "index"), + ((vlan_index != -1u) ? priv->vlan_filter[vlan_index].id : -1u)); /* Create related flow. */ errno = 0; flow = mlx_create_flow(rxq->qp, attr); @@ -2027,8 +2033,58 @@ rxq_mac_addr_add(struct rxq *rxq, unsigned int mac_index) return errno; return EINVAL; } - assert(rxq->mac_flow[mac_index] == NULL); - rxq->mac_flow[mac_index] = flow; + if (vlan_index == -1u) + vlan_index = 0; + assert(rxq->mac_flow[mac_index][vlan_index] == NULL); + rxq->mac_flow[mac_index][vlan_index] = flow; + return 0; +} + +/** + * Register a MAC address in a RX queue. + * + * @param rxq + * Pointer to RX queue structure. + * @param mac_index + * MAC address index to register. + * + * @return + * 0 on success, errno value on failure. + */ +static int +rxq_mac_addr_add(struct rxq *rxq, unsigned int mac_index) +{ + struct priv *priv = rxq->priv; + unsigned int i; + unsigned int vlans = 0; + int ret; + + assert(mac_index < elemof(priv->mac)); + if (BITFIELD_ISSET(rxq->mac_configured, mac_index)) + rxq_mac_addr_del(rxq, mac_index); + /* Fill VLAN specifications. */ + for (i = 0; (i != elemof(priv->vlan_filter)); ++i) { + if (!priv->vlan_filter[i].enabled) + continue; + /* Create related flow. */ + ret = rxq_add_flow(rxq, mac_index, i); + if (!ret) { + vlans++; + continue; + } + /* Failure, rollback. */ + while (i != 0) + if (priv->vlan_filter[--i].enabled) + rxq_del_flow(rxq, mac_index, i); + assert(ret > 0); + return ret; + } + /* In case there is no VLAN filter. */ + if (!vlans) { + ret = rxq_add_flow(rxq, mac_index, -1); + if (ret) + return ret; + } BITFIELD_SET(rxq->mac_configured, mac_index); return 0; } -- 2.1.0