Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next 2/6] net/mlx4_core: Initialize all mailbox buffers to zero before use
From: Amir Vadai @ 2013-11-07 10:19 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Amir Vadai, Yevgeny Petrilin, Or Gerlitz,
	Jack Morgenstein, Majd Dibbiny
In-Reply-To: <1383819594-24070-1-git-send-email-amirv@mellanox.com>

From: Jack Morgenstein <jackm@dev.mellanox.co.il>

To guarantee that all unused fields in all FW commands for both inboxes
and outboxes are zeroed out, initialize the mailbox buffer to all zeroes.

This is especially important for SRIOV comm-channel virtual commands
(such as QUERY_FUNC_CAP), where if new fields are added to support new
features, the driver can depend on older kernels passing zeroes in these
fields.

In addition to zeroing out the mailbox buffer at allocation time, all
(now unnecessary) calls to memset by the callers of
mlx4_alloc_cmd_mailbox() are removed.


Signed-off-by: Majd Dibbiny <majd@mellanox.com>
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/infiniband/hw/mlx4/main.c            |  6 ------
 drivers/net/ethernet/mellanox/mlx4/cmd.c     |  2 ++
 drivers/net/ethernet/mellanox/mlx4/cq.c      |  6 ------
 drivers/net/ethernet/mellanox/mlx4/en_port.c |  3 ---
 drivers/net/ethernet/mellanox/mlx4/eq.c      |  1 -
 drivers/net/ethernet/mellanox/mlx4/fw.c      |  7 -------
 drivers/net/ethernet/mellanox/mlx4/mcg.c     |  2 --
 drivers/net/ethernet/mellanox/mlx4/mr.c      |  5 -----
 drivers/net/ethernet/mellanox/mlx4/port.c    | 11 -----------
 drivers/net/ethernet/mellanox/mlx4/srq.c     |  2 --
 10 files changed, 2 insertions(+), 43 deletions(-)

diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 7567437..6a0a0d2 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -526,7 +526,6 @@ static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
 	if (IS_ERR(mailbox))
 		return 0;
 
-	memset(mailbox->buf, 0, 256);
 	memcpy(mailbox->buf, props->node_desc, 64);
 	mlx4_cmd(to_mdev(ibdev)->dev, mailbox->dma, 1, 0,
 		 MLX4_CMD_SET_NODE, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
@@ -547,8 +546,6 @@ static int mlx4_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_viols,
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
 
-	memset(mailbox->buf, 0, 256);
-
 	if (dev->dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
 		*(u8 *) mailbox->buf	     = !!reset_qkey_viols << 6;
 		((__be32 *) mailbox->buf)[2] = cpu_to_be32(cap_mask);
@@ -879,8 +876,6 @@ static int __mlx4_ib_create_flow(struct ib_qp *qp, struct ib_flow_attr *flow_att
 	struct mlx4_ib_dev *mdev = to_mdev(qp->device);
 	struct mlx4_cmd_mailbox *mailbox;
 	struct mlx4_net_trans_rule_hw_ctrl *ctrl;
-	size_t rule_size = sizeof(struct mlx4_net_trans_rule_hw_ctrl) +
-			   (sizeof(struct _rule_hw) * flow_attr->num_of_specs);
 
 	static const u16 __mlx4_domain[] = {
 		[IB_FLOW_DOMAIN_USER] = MLX4_DOMAIN_UVERBS,
@@ -905,7 +900,6 @@ static int __mlx4_ib_create_flow(struct ib_qp *qp, struct ib_flow_attr *flow_att
 	mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
-	memset(mailbox->buf, 0, rule_size);
 	ctrl = mailbox->buf;
 
 	ctrl->prio = cpu_to_be16(__mlx4_domain[domain] |
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index 65d41b76..7207dcd 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -2199,6 +2199,8 @@ struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev)
 		return ERR_PTR(-ENOMEM);
 	}
 
+	memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE);
+
 	return mailbox;
 }
 EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox);
diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
index 004e423..22fcbe7 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
@@ -128,8 +128,6 @@ int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq,
 		return PTR_ERR(mailbox);
 
 	cq_context = mailbox->buf;
-	memset(cq_context, 0, sizeof *cq_context);
-
 	cq_context->cq_max_count = cpu_to_be16(count);
 	cq_context->cq_period    = cpu_to_be16(period);
 
@@ -153,8 +151,6 @@ int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq,
 		return PTR_ERR(mailbox);
 
 	cq_context = mailbox->buf;
-	memset(cq_context, 0, sizeof *cq_context);
-
 	cq_context->logsize_usrpage = cpu_to_be32(ilog2(entries) << 24);
 	cq_context->log_page_size   = mtt->page_shift - 12;
 	mtt_addr = mlx4_mtt_addr(dev, mtt);
@@ -274,8 +270,6 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
 	}
 
 	cq_context = mailbox->buf;
-	memset(cq_context, 0, sizeof *cq_context);
-
 	cq_context->flags	    = cpu_to_be32(!!collapsed << 18);
 	if (timestamp_en)
 		cq_context->flags  |= cpu_to_be32(1 << 19);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c
index 3317914..5f8535e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c
@@ -56,7 +56,6 @@ int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, struct mlx4_en_priv *priv)
 		return PTR_ERR(mailbox);
 
 	filter = mailbox->buf;
-	memset(filter, 0, sizeof(*filter));
 	for (i = VLAN_FLTR_SIZE - 1; i >= 0; i--) {
 		entry = 0;
 		for (j = 0; j < 32; j++)
@@ -81,7 +80,6 @@ int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port)
 	mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
-	memset(mailbox->buf, 0, sizeof(*qport_context));
 	err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, port, 0,
 			   MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B,
 			   MLX4_CMD_WRAPPED);
@@ -127,7 +125,6 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
 	mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
-	memset(mailbox->buf, 0, sizeof(*mlx4_en_stats));
 	err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, in_mod, 0,
 			   MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B,
 			   MLX4_CMD_WRAPPED);
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
index 0416c5b..c9cdb2a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
@@ -936,7 +936,6 @@ static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
 	if (err)
 		goto err_out_free_mtt;
 
-	memset(eq_context, 0, sizeof *eq_context);
 	eq_context->flags	  = cpu_to_be32(MLX4_EQ_STATUS_OK   |
 						MLX4_EQ_STATE_ARMED);
 	eq_context->log_eq_size	  = ilog2(eq->nent);
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index c3e70bc..fda2667 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -159,8 +159,6 @@ int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg)
 		return PTR_ERR(mailbox);
 	inbox = mailbox->buf;
 
-	memset(inbox, 0, MOD_STAT_CFG_IN_SIZE);
-
 	MLX4_PUT(inbox, cfg->log_pg_sz, MOD_STAT_CFG_PG_SZ_OFFSET);
 	MLX4_PUT(inbox, cfg->log_pg_sz_m, MOD_STAT_CFG_PG_SZ_M_OFFSET);
 
@@ -967,7 +965,6 @@ int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt)
 	mailbox = mlx4_alloc_cmd_mailbox(dev);
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
-	memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE);
 	pages = mailbox->buf;
 
 	for (mlx4_icm_first(icm, &iter);
@@ -1316,8 +1313,6 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
 		return PTR_ERR(mailbox);
 	inbox = mailbox->buf;
 
-	memset(inbox, 0, INIT_HCA_IN_SIZE);
-
 	*((u8 *) mailbox->buf + INIT_HCA_VERSION_OFFSET) = INIT_HCA_VERSION;
 
 	*((u8 *) mailbox->buf + INIT_HCA_CACHELINE_SZ_OFFSET) =
@@ -1616,8 +1611,6 @@ int mlx4_INIT_PORT(struct mlx4_dev *dev, int port)
 			return PTR_ERR(mailbox);
 		inbox = mailbox->buf;
 
-		memset(inbox, 0, INIT_PORT_IN_SIZE);
-
 		flags = 0;
 		flags |= (dev->caps.vl_cap[port] & 0xf) << INIT_PORT_VL_SHIFT;
 		flags |= (dev->caps.port_width_cap[port] & 0xf) << INIT_PORT_PORT_WIDTH_SHIFT;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index 70f0213..acf9d5f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -506,7 +506,6 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port,
 		goto out_list;
 	}
 	mgm = mailbox->buf;
-	memset(mgm, 0, sizeof *mgm);
 	members_count = 0;
 	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list)
 		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
@@ -857,7 +856,6 @@ int mlx4_flow_attach(struct mlx4_dev *dev,
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
 
-	memset(mailbox->buf, 0, sizeof(struct mlx4_net_trans_rule_hw_ctrl));
 	trans_rule_ctrl_to_hw(rule, mailbox->buf);
 
 	size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c
index 63391a1..b3ee9ba 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mr.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mr.c
@@ -480,9 +480,6 @@ int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr)
 		goto err_table;
 	}
 	mpt_entry = mailbox->buf;
-
-	memset(mpt_entry, 0, sizeof *mpt_entry);
-
 	mpt_entry->flags = cpu_to_be32(MLX4_MPT_FLAG_MIO	 |
 				       MLX4_MPT_FLAG_REGION	 |
 				       mr->access);
@@ -695,8 +692,6 @@ int mlx4_mw_enable(struct mlx4_dev *dev, struct mlx4_mw *mw)
 	}
 	mpt_entry = mailbox->buf;
 
-	memset(mpt_entry, 0, sizeof(*mpt_entry));
-
 	/* Note that the MLX4_MPT_FLAG_REGION bit in mpt_entry->flags is turned
 	 * off, thus creating a memory window and not a memory region.
 	 */
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index caaa154..97d342f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -469,8 +469,6 @@ int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
 
 	inbuf = inmailbox->buf;
 	outbuf = outmailbox->buf;
-	memset(inbuf, 0, 256);
-	memset(outbuf, 0, 256);
 	inbuf[0] = 1;
 	inbuf[1] = 1;
 	inbuf[2] = 1;
@@ -653,8 +651,6 @@ int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz)
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
 
-	memset(mailbox->buf, 0, 256);
-
 	((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port];
 
 	if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) {
@@ -692,8 +688,6 @@ int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
 	context = mailbox->buf;
-	memset(context, 0, sizeof *context);
-
 	context->flags = SET_PORT_GEN_ALL_VALID;
 	context->mtu = cpu_to_be16(mtu);
 	context->pptx = (pptx * (!pfctx)) << 7;
@@ -727,8 +721,6 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
 	context = mailbox->buf;
-	memset(context, 0, sizeof *context);
-
 	context->base_qpn = cpu_to_be32(base_qpn);
 	context->n_mac = dev->caps.log_num_macs;
 	context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT |
@@ -761,8 +753,6 @@ int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc)
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
 	context = mailbox->buf;
-	memset(context, 0, sizeof *context);
-
 	for (i = 0; i < MLX4_NUM_UP; i += 2)
 		context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1];
 
@@ -788,7 +778,6 @@ int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw,
 	if (IS_ERR(mailbox))
 		return PTR_ERR(mailbox);
 	context = mailbox->buf;
-	memset(context, 0, sizeof *context);
 
 	for (i = 0; i < MLX4_NUM_TC; i++) {
 		struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i];
diff --git a/drivers/net/ethernet/mellanox/mlx4/srq.c b/drivers/net/ethernet/mellanox/mlx4/srq.c
index 9e08e35..8fdf237 100644
--- a/drivers/net/ethernet/mellanox/mlx4/srq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/srq.c
@@ -189,8 +189,6 @@ int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd,
 	}
 
 	srq_context = mailbox->buf;
-	memset(srq_context, 0, sizeof *srq_context);
-
 	srq_context->state_logsize_srqn = cpu_to_be32((ilog2(srq->max) << 24) |
 						      srq->srqn);
 	srq_context->logstride          = srq->wqe_shift - 4;
-- 
1.8.3.4

^ permalink raw reply related

* [PATCH net-next 4/6] net/mlx4_en: Datapath resources allocated dynamically
From: Amir Vadai @ 2013-11-07 10:19 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Amir Vadai, Yevgeny Petrilin, Or Gerlitz,
	Eugenia Emantayev
In-Reply-To: <1383819594-24070-1-git-send-email-amirv@mellanox.com>

From: Eugenia Emantayev <eugenia@mellanox.com>

Currently all TX/RX rings and completion queues are part of the
netdev priv structure and are allocated statically. This patch
will change the priv to hold only arrays of pointers and therefore
all TX/RX rings and completetion queues will be allocated
dynamically. This is in preparation for NUMA aware allocations.

Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.com>
Signed-off-by: Eugenia Emantayev <eugenia@mellanox.com>
Reviewed-by: Hadar Hen Zion <hadarh@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_cq.c       | 34 ++++++---
 drivers/net/ethernet/mellanox/mlx4/en_ethtool.c  | 36 +++++-----
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c   | 87 ++++++++++++++----------
 drivers/net/ethernet/mellanox/mlx4/en_port.c     | 14 ++--
 drivers/net/ethernet/mellanox/mlx4/en_rx.c       | 57 ++++++++++------
 drivers/net/ethernet/mellanox/mlx4/en_selftest.c |  2 +-
 drivers/net/ethernet/mellanox/mlx4/en_tx.c       | 32 ++++++---
 drivers/net/ethernet/mellanox/mlx4/mlx4_en.h     | 27 ++++----
 8 files changed, 178 insertions(+), 111 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
index 3e2d504..d203f11 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
@@ -44,12 +44,19 @@ static void mlx4_en_cq_event(struct mlx4_cq *cq, enum mlx4_event event)
 
 
 int mlx4_en_create_cq(struct mlx4_en_priv *priv,
-		      struct mlx4_en_cq *cq,
+		      struct mlx4_en_cq **pcq,
 		      int entries, int ring, enum cq_type mode)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_en_cq *cq;
 	int err;
 
+	cq = kzalloc(sizeof(*cq), GFP_KERNEL);
+	if (!cq) {
+		en_err(priv, "Failed to allocate CQ structure\n");
+		return -ENOMEM;
+	}
+
 	cq->size = entries;
 	cq->buf_size = cq->size * mdev->dev->caps.cqe_size;
 
@@ -60,14 +67,22 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv,
 	err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres,
 				cq->buf_size, 2 * PAGE_SIZE);
 	if (err)
-		return err;
+		goto err_cq;
 
 	err = mlx4_en_map_buffer(&cq->wqres.buf);
 	if (err)
-		mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size);
-	else
-		cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf;
+		goto err_res;
+
+	cq->buf = (struct mlx4_cqe *)cq->wqres.buf.direct.buf;
+	*pcq = cq;
 
+	return 0;
+
+err_res:
+	mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size);
+err_cq:
+	kfree(cq);
+	*pcq = NULL;
 	return err;
 }
 
@@ -117,12 +132,12 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
 		struct mlx4_en_cq *rx_cq;
 
 		cq_idx = cq_idx % priv->rx_ring_num;
-		rx_cq = &priv->rx_cq[cq_idx];
+		rx_cq = priv->rx_cq[cq_idx];
 		cq->vector = rx_cq->vector;
 	}
 
 	if (!cq->is_tx)
-		cq->size = priv->rx_ring[cq->ring].actual_size;
+		cq->size = priv->rx_ring[cq->ring]->actual_size;
 
 	if ((cq->is_tx && priv->hwtstamp_config.tx_type) ||
 	    (!cq->is_tx && priv->hwtstamp_config.rx_filter))
@@ -146,9 +161,10 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
 	return 0;
 }
 
-void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
+void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_en_cq *cq = *pcq;
 
 	mlx4_en_unmap_buffer(&cq->wqres.buf);
 	mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size);
@@ -157,6 +173,8 @@ void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
 	cq->vector = 0;
 	cq->buf_size = 0;
 	cq->buf = NULL;
+	kfree(cq);
+	*pcq = NULL;
 }
 
 void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 0c75098..0596f9f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -51,10 +51,10 @@ static int mlx4_en_moderation_update(struct mlx4_en_priv *priv)
 	int err = 0;
 
 	for (i = 0; i < priv->tx_ring_num; i++) {
-		priv->tx_cq[i].moder_cnt = priv->tx_frames;
-		priv->tx_cq[i].moder_time = priv->tx_usecs;
+		priv->tx_cq[i]->moder_cnt = priv->tx_frames;
+		priv->tx_cq[i]->moder_time = priv->tx_usecs;
 		if (priv->port_up) {
-			err = mlx4_en_set_cq_moder(priv, &priv->tx_cq[i]);
+			err = mlx4_en_set_cq_moder(priv, priv->tx_cq[i]);
 			if (err)
 				return err;
 		}
@@ -64,11 +64,11 @@ static int mlx4_en_moderation_update(struct mlx4_en_priv *priv)
 		return 0;
 
 	for (i = 0; i < priv->rx_ring_num; i++) {
-		priv->rx_cq[i].moder_cnt = priv->rx_frames;
-		priv->rx_cq[i].moder_time = priv->rx_usecs;
+		priv->rx_cq[i]->moder_cnt = priv->rx_frames;
+		priv->rx_cq[i]->moder_time = priv->rx_usecs;
 		priv->last_moder_time[i] = MLX4_EN_AUTO_CONF;
 		if (priv->port_up) {
-			err = mlx4_en_set_cq_moder(priv, &priv->rx_cq[i]);
+			err = mlx4_en_set_cq_moder(priv, priv->rx_cq[i]);
 			if (err)
 				return err;
 		}
@@ -274,16 +274,16 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
 		}
 	}
 	for (i = 0; i < priv->tx_ring_num; i++) {
-		data[index++] = priv->tx_ring[i].packets;
-		data[index++] = priv->tx_ring[i].bytes;
+		data[index++] = priv->tx_ring[i]->packets;
+		data[index++] = priv->tx_ring[i]->bytes;
 	}
 	for (i = 0; i < priv->rx_ring_num; i++) {
-		data[index++] = priv->rx_ring[i].packets;
-		data[index++] = priv->rx_ring[i].bytes;
+		data[index++] = priv->rx_ring[i]->packets;
+		data[index++] = priv->rx_ring[i]->bytes;
 #ifdef CONFIG_NET_RX_BUSY_POLL
-		data[index++] = priv->rx_ring[i].yields;
-		data[index++] = priv->rx_ring[i].misses;
-		data[index++] = priv->rx_ring[i].cleaned;
+		data[index++] = priv->rx_ring[i]->yields;
+		data[index++] = priv->rx_ring[i]->misses;
+		data[index++] = priv->rx_ring[i]->cleaned;
 #endif
 	}
 	spin_unlock_bh(&priv->stats_lock);
@@ -510,9 +510,9 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
 	tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE);
 	tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE);
 
-	if (rx_size == (priv->port_up ? priv->rx_ring[0].actual_size :
-					priv->rx_ring[0].size) &&
-	    tx_size == priv->tx_ring[0].size)
+	if (rx_size == (priv->port_up ? priv->rx_ring[0]->actual_size :
+					priv->rx_ring[0]->size) &&
+	    tx_size == priv->tx_ring[0]->size)
 		return 0;
 
 	mutex_lock(&mdev->state_lock);
@@ -553,8 +553,8 @@ static void mlx4_en_get_ringparam(struct net_device *dev,
 	param->rx_max_pending = MLX4_EN_MAX_RX_SIZE;
 	param->tx_max_pending = MLX4_EN_MAX_TX_SIZE;
 	param->rx_pending = priv->port_up ?
-		priv->rx_ring[0].actual_size : priv->rx_ring[0].size;
-	param->tx_pending = priv->tx_ring[0].size;
+		priv->rx_ring[0]->actual_size : priv->rx_ring[0]->size;
+	param->tx_pending = priv->tx_ring[0]->size;
 }
 
 static u32 mlx4_en_get_rxfh_indir_size(struct net_device *dev)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index cd61e26..f430788 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -75,7 +75,7 @@ static int mlx4_en_low_latency_recv(struct napi_struct *napi)
 	struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi);
 	struct net_device *dev = cq->dev;
 	struct mlx4_en_priv *priv = netdev_priv(dev);
-	struct mlx4_en_rx_ring *rx_ring = &priv->rx_ring[cq->ring];
+	struct mlx4_en_rx_ring *rx_ring = priv->rx_ring[cq->ring];
 	int done;
 
 	if (!priv->port_up)
@@ -355,8 +355,7 @@ err:
 	return ret;
 }
 
-void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv,
-			     struct mlx4_en_rx_ring *rx_ring)
+void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv)
 {
 	struct mlx4_en_filter *filter, *tmp;
 	LIST_HEAD(del_list);
@@ -1242,7 +1241,7 @@ static void mlx4_en_netpoll(struct net_device *dev)
 	int i;
 
 	for (i = 0; i < priv->rx_ring_num; i++) {
-		cq = &priv->rx_cq[i];
+		cq = priv->rx_cq[i];
 		spin_lock_irqsave(&cq->lock, flags);
 		napi_synchronize(&cq->napi);
 		mlx4_en_process_rx_cq(dev, cq, 0);
@@ -1264,8 +1263,8 @@ static void mlx4_en_tx_timeout(struct net_device *dev)
 		if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, i)))
 			continue;
 		en_warn(priv, "TX timeout on queue: %d, QP: 0x%x, CQ: 0x%x, Cons: 0x%x, Prod: 0x%x\n",
-			i, priv->tx_ring[i].qpn, priv->tx_ring[i].cqn,
-			priv->tx_ring[i].cons, priv->tx_ring[i].prod);
+			i, priv->tx_ring[i]->qpn, priv->tx_ring[i]->cqn,
+			priv->tx_ring[i]->cons, priv->tx_ring[i]->prod);
 	}
 
 	priv->port_stats.tx_timeout++;
@@ -1305,7 +1304,7 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
 
 	/* Setup cq moderation params */
 	for (i = 0; i < priv->rx_ring_num; i++) {
-		cq = &priv->rx_cq[i];
+		cq = priv->rx_cq[i];
 		cq->moder_cnt = priv->rx_frames;
 		cq->moder_time = priv->rx_usecs;
 		priv->last_moder_time[i] = MLX4_EN_AUTO_CONF;
@@ -1314,7 +1313,7 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
 	}
 
 	for (i = 0; i < priv->tx_ring_num; i++) {
-		cq = &priv->tx_cq[i];
+		cq = priv->tx_cq[i];
 		cq->moder_cnt = priv->tx_frames;
 		cq->moder_time = priv->tx_usecs;
 	}
@@ -1348,8 +1347,8 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
 
 	for (ring = 0; ring < priv->rx_ring_num; ring++) {
 		spin_lock_bh(&priv->stats_lock);
-		rx_packets = priv->rx_ring[ring].packets;
-		rx_bytes = priv->rx_ring[ring].bytes;
+		rx_packets = priv->rx_ring[ring]->packets;
+		rx_bytes = priv->rx_ring[ring]->bytes;
 		spin_unlock_bh(&priv->stats_lock);
 
 		rx_pkt_diff = ((unsigned long) (rx_packets -
@@ -1378,7 +1377,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
 
 		if (moder_time != priv->last_moder_time[ring]) {
 			priv->last_moder_time[ring] = moder_time;
-			cq = &priv->rx_cq[ring];
+			cq = priv->rx_cq[ring];
 			cq->moder_time = moder_time;
 			cq->moder_cnt = priv->rx_frames;
 			err = mlx4_en_set_cq_moder(priv, cq);
@@ -1501,7 +1500,7 @@ int mlx4_en_start_port(struct net_device *dev)
 		return err;
 	}
 	for (i = 0; i < priv->rx_ring_num; i++) {
-		cq = &priv->rx_cq[i];
+		cq = priv->rx_cq[i];
 
 		mlx4_en_cq_init_lock(cq);
 
@@ -1519,7 +1518,7 @@ int mlx4_en_start_port(struct net_device *dev)
 			goto cq_err;
 		}
 		mlx4_en_arm_cq(priv, cq);
-		priv->rx_ring[i].cqn = cq->mcq.cqn;
+		priv->rx_ring[i]->cqn = cq->mcq.cqn;
 		++rx_index;
 	}
 
@@ -1545,7 +1544,7 @@ int mlx4_en_start_port(struct net_device *dev)
 	/* Configure tx cq's and rings */
 	for (i = 0; i < priv->tx_ring_num; i++) {
 		/* Configure cq */
-		cq = &priv->tx_cq[i];
+		cq = priv->tx_cq[i];
 		err = mlx4_en_activate_cq(priv, cq, i);
 		if (err) {
 			en_err(priv, "Failed allocating Tx CQ\n");
@@ -1561,7 +1560,7 @@ int mlx4_en_start_port(struct net_device *dev)
 		cq->buf->wqe_index = cpu_to_be16(0xffff);
 
 		/* Configure ring */
-		tx_ring = &priv->tx_ring[i];
+		tx_ring = priv->tx_ring[i];
 		err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn,
 			i / priv->num_tx_rings_p_up);
 		if (err) {
@@ -1631,8 +1630,8 @@ int mlx4_en_start_port(struct net_device *dev)
 
 tx_err:
 	while (tx_index--) {
-		mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[tx_index]);
-		mlx4_en_deactivate_cq(priv, &priv->tx_cq[tx_index]);
+		mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[tx_index]);
+		mlx4_en_deactivate_cq(priv, priv->tx_cq[tx_index]);
 	}
 	mlx4_en_destroy_drop_qp(priv);
 rss_err:
@@ -1641,9 +1640,9 @@ mac_err:
 	mlx4_en_put_qp(priv);
 cq_err:
 	while (rx_index--)
-		mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]);
+		mlx4_en_deactivate_cq(priv, priv->rx_cq[rx_index]);
 	for (i = 0; i < priv->rx_ring_num; i++)
-		mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
+		mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]);
 
 	return err; /* need to close devices */
 }
@@ -1739,13 +1738,13 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
 
 	/* Free TX Rings */
 	for (i = 0; i < priv->tx_ring_num; i++) {
-		mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[i]);
-		mlx4_en_deactivate_cq(priv, &priv->tx_cq[i]);
+		mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[i]);
+		mlx4_en_deactivate_cq(priv, priv->tx_cq[i]);
 	}
 	msleep(10);
 
 	for (i = 0; i < priv->tx_ring_num; i++)
-		mlx4_en_free_tx_buf(dev, &priv->tx_ring[i]);
+		mlx4_en_free_tx_buf(dev, priv->tx_ring[i]);
 
 	/* Free RSS qps */
 	mlx4_en_release_rss_steer(priv);
@@ -1757,7 +1756,7 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
 
 	/* Free RX Rings */
 	for (i = 0; i < priv->rx_ring_num; i++) {
-		struct mlx4_en_cq *cq = &priv->rx_cq[i];
+		struct mlx4_en_cq *cq = priv->rx_cq[i];
 
 		local_bh_disable();
 		while (!mlx4_en_cq_lock_napi(cq)) {
@@ -1768,7 +1767,7 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
 
 		while (test_bit(NAPI_STATE_SCHED, &cq->napi.state))
 			msleep(1);
-		mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
+		mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]);
 		mlx4_en_deactivate_cq(priv, cq);
 	}
 }
@@ -1806,15 +1805,15 @@ static void mlx4_en_clear_stats(struct net_device *dev)
 	memset(&priv->port_stats, 0, sizeof(priv->port_stats));
 
 	for (i = 0; i < priv->tx_ring_num; i++) {
-		priv->tx_ring[i].bytes = 0;
-		priv->tx_ring[i].packets = 0;
-		priv->tx_ring[i].tx_csum = 0;
+		priv->tx_ring[i]->bytes = 0;
+		priv->tx_ring[i]->packets = 0;
+		priv->tx_ring[i]->tx_csum = 0;
 	}
 	for (i = 0; i < priv->rx_ring_num; i++) {
-		priv->rx_ring[i].bytes = 0;
-		priv->rx_ring[i].packets = 0;
-		priv->rx_ring[i].csum_ok = 0;
-		priv->rx_ring[i].csum_none = 0;
+		priv->rx_ring[i]->bytes = 0;
+		priv->rx_ring[i]->packets = 0;
+		priv->rx_ring[i]->csum_ok = 0;
+		priv->rx_ring[i]->csum_none = 0;
 	}
 }
 
@@ -1871,17 +1870,17 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv)
 #endif
 
 	for (i = 0; i < priv->tx_ring_num; i++) {
-		if (priv->tx_ring[i].tx_info)
+		if (priv->tx_ring && priv->tx_ring[i])
 			mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]);
-		if (priv->tx_cq[i].buf)
+		if (priv->tx_cq && priv->tx_cq[i])
 			mlx4_en_destroy_cq(priv, &priv->tx_cq[i]);
 	}
 
 	for (i = 0; i < priv->rx_ring_num; i++) {
-		if (priv->rx_ring[i].rx_info)
+		if (priv->rx_ring[i])
 			mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i],
 				priv->prof->rx_ring_size, priv->stride);
-		if (priv->rx_cq[i].buf)
+		if (priv->rx_cq[i])
 			mlx4_en_destroy_cq(priv, &priv->rx_cq[i]);
 	}
 
@@ -1937,6 +1936,20 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
 
 err:
 	en_err(priv, "Failed to allocate NIC resources\n");
+	for (i = 0; i < priv->rx_ring_num; i++) {
+		if (priv->rx_ring[i])
+			mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i],
+						prof->rx_ring_size,
+						priv->stride);
+		if (priv->rx_cq[i])
+			mlx4_en_destroy_cq(priv, &priv->rx_cq[i]);
+	}
+	for (i = 0; i < priv->tx_ring_num; i++) {
+		if (priv->tx_ring[i])
+			mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]);
+		if (priv->tx_cq[i])
+			mlx4_en_destroy_cq(priv, &priv->tx_cq[i]);
+	}
 	return -ENOMEM;
 }
 
@@ -2230,13 +2243,13 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 	priv->num_tx_rings_p_up = mdev->profile.num_tx_rings_p_up;
 	priv->tx_ring_num = prof->tx_ring_num;
 
-	priv->tx_ring = kzalloc(sizeof(struct mlx4_en_tx_ring) * MAX_TX_RINGS,
+	priv->tx_ring = kzalloc(sizeof(struct mlx4_en_tx_ring *) * MAX_TX_RINGS,
 				GFP_KERNEL);
 	if (!priv->tx_ring) {
 		err = -ENOMEM;
 		goto out;
 	}
-	priv->tx_cq = kzalloc(sizeof(struct mlx4_en_cq) * MAX_TX_RINGS,
+	priv->tx_cq = kzalloc(sizeof(struct mlx4_en_cq *) * MAX_TX_RINGS,
 			      GFP_KERNEL);
 	if (!priv->tx_cq) {
 		err = -ENOMEM;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c
index 5f8535e..dae1a1f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c
@@ -140,18 +140,18 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
 	priv->port_stats.rx_chksum_good = 0;
 	priv->port_stats.rx_chksum_none = 0;
 	for (i = 0; i < priv->rx_ring_num; i++) {
-		stats->rx_packets += priv->rx_ring[i].packets;
-		stats->rx_bytes += priv->rx_ring[i].bytes;
-		priv->port_stats.rx_chksum_good += priv->rx_ring[i].csum_ok;
-		priv->port_stats.rx_chksum_none += priv->rx_ring[i].csum_none;
+		stats->rx_packets += priv->rx_ring[i]->packets;
+		stats->rx_bytes += priv->rx_ring[i]->bytes;
+		priv->port_stats.rx_chksum_good += priv->rx_ring[i]->csum_ok;
+		priv->port_stats.rx_chksum_none += priv->rx_ring[i]->csum_none;
 	}
 	stats->tx_packets = 0;
 	stats->tx_bytes = 0;
 	priv->port_stats.tx_chksum_offload = 0;
 	for (i = 0; i < priv->tx_ring_num; i++) {
-		stats->tx_packets += priv->tx_ring[i].packets;
-		stats->tx_bytes += priv->tx_ring[i].bytes;
-		priv->port_stats.tx_chksum_offload += priv->tx_ring[i].tx_csum;
+		stats->tx_packets += priv->tx_ring[i]->packets;
+		stats->tx_bytes += priv->tx_ring[i]->bytes;
+		priv->port_stats.tx_chksum_offload += priv->tx_ring[i]->tx_csum;
 	}
 
 	stats->rx_errors = be64_to_cpu(mlx4_en_stats->PCS) +
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index afe2efa..1c45f88 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -264,7 +264,7 @@ static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv)
 
 	for (buf_ind = 0; buf_ind < priv->prof->rx_ring_size; buf_ind++) {
 		for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
-			ring = &priv->rx_ring[ring_ind];
+			ring = priv->rx_ring[ring_ind];
 
 			if (mlx4_en_prepare_rx_desc(priv, ring,
 						    ring->actual_size,
@@ -289,7 +289,7 @@ static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv)
 
 reduce_rings:
 	for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
-		ring = &priv->rx_ring[ring_ind];
+		ring = priv->rx_ring[ring_ind];
 		while (ring->actual_size > new_size) {
 			ring->actual_size--;
 			ring->prod--;
@@ -319,12 +319,20 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
 }
 
 int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
-			   struct mlx4_en_rx_ring *ring, u32 size, u16 stride)
+			   struct mlx4_en_rx_ring **pring,
+			   u32 size, u16 stride)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_en_rx_ring *ring;
 	int err = -ENOMEM;
 	int tmp;
 
+	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+	if (!ring) {
+		en_err(priv, "Failed to allocate RX ring structure\n");
+		return -ENOMEM;
+	}
+
 	ring->prod = 0;
 	ring->cons = 0;
 	ring->size = size;
@@ -336,8 +344,10 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
 	tmp = size * roundup_pow_of_two(MLX4_EN_MAX_RX_FRAGS *
 					sizeof(struct mlx4_en_rx_alloc));
 	ring->rx_info = vmalloc(tmp);
-	if (!ring->rx_info)
-		return -ENOMEM;
+	if (!ring->rx_info) {
+		err = -ENOMEM;
+		goto err_ring;
+	}
 
 	en_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d\n",
 		 ring->rx_info, tmp);
@@ -345,7 +355,7 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
 	err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres,
 				 ring->buf_size, 2 * PAGE_SIZE);
 	if (err)
-		goto err_ring;
+		goto err_info;
 
 	err = mlx4_en_map_buffer(&ring->wqres.buf);
 	if (err) {
@@ -356,13 +366,18 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
 
 	ring->hwtstamp_rx_filter = priv->hwtstamp_config.rx_filter;
 
+	*pring = ring;
 	return 0;
 
 err_hwq:
 	mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
-err_ring:
+err_info:
 	vfree(ring->rx_info);
 	ring->rx_info = NULL;
+err_ring:
+	kfree(ring);
+	*pring = NULL;
+
 	return err;
 }
 
@@ -376,12 +391,12 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv)
 					DS_SIZE * priv->num_frags);
 
 	for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
-		ring = &priv->rx_ring[ring_ind];
+		ring = priv->rx_ring[ring_ind];
 
 		ring->prod = 0;
 		ring->cons = 0;
 		ring->actual_size = 0;
-		ring->cqn = priv->rx_cq[ring_ind].mcq.cqn;
+		ring->cqn = priv->rx_cq[ring_ind]->mcq.cqn;
 
 		ring->stride = stride;
 		if (ring->stride <= TXBB_SIZE)
@@ -412,7 +427,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv)
 		goto err_buffers;
 
 	for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
-		ring = &priv->rx_ring[ring_ind];
+		ring = priv->rx_ring[ring_ind];
 
 		ring->size_mask = ring->actual_size - 1;
 		mlx4_en_update_rx_prod_db(ring);
@@ -422,30 +437,34 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv)
 
 err_buffers:
 	for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++)
-		mlx4_en_free_rx_buf(priv, &priv->rx_ring[ring_ind]);
+		mlx4_en_free_rx_buf(priv, priv->rx_ring[ring_ind]);
 
 	ring_ind = priv->rx_ring_num - 1;
 err_allocator:
 	while (ring_ind >= 0) {
-		if (priv->rx_ring[ring_ind].stride <= TXBB_SIZE)
-			priv->rx_ring[ring_ind].buf -= TXBB_SIZE;
-		mlx4_en_destroy_allocator(priv, &priv->rx_ring[ring_ind]);
+		if (priv->rx_ring[ring_ind]->stride <= TXBB_SIZE)
+			priv->rx_ring[ring_ind]->buf -= TXBB_SIZE;
+		mlx4_en_destroy_allocator(priv, priv->rx_ring[ring_ind]);
 		ring_ind--;
 	}
 	return err;
 }
 
 void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv,
-			     struct mlx4_en_rx_ring *ring, u32 size, u16 stride)
+			     struct mlx4_en_rx_ring **pring,
+			     u32 size, u16 stride)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_en_rx_ring *ring = *pring;
 
 	mlx4_en_unmap_buffer(&ring->wqres.buf);
 	mlx4_free_hwq_res(mdev->dev, &ring->wqres, size * stride + TXBB_SIZE);
 	vfree(ring->rx_info);
 	ring->rx_info = NULL;
+	kfree(ring);
+	*pring = NULL;
 #ifdef CONFIG_RFS_ACCEL
-	mlx4_en_cleanup_filters(priv, ring);
+	mlx4_en_cleanup_filters(priv);
 #endif
 }
 
@@ -592,7 +611,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_cqe *cqe;
-	struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring];
+	struct mlx4_en_rx_ring *ring = priv->rx_ring[cq->ring];
 	struct mlx4_en_rx_alloc *frags;
 	struct mlx4_en_rx_desc *rx_desc;
 	struct sk_buff *skb;
@@ -991,7 +1010,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
 
 	for (i = 0; i < priv->rx_ring_num; i++) {
 		qpn = rss_map->base_qpn + i;
-		err = mlx4_en_config_rss_qp(priv, qpn, &priv->rx_ring[i],
+		err = mlx4_en_config_rss_qp(priv, qpn, priv->rx_ring[i],
 					    &rss_map->state[i],
 					    &rss_map->qps[i]);
 		if (err)
@@ -1008,7 +1027,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
 	}
 	rss_map->indir_qp.event = mlx4_en_sqp_event;
 	mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn,
-				priv->rx_ring[0].cqn, -1, &context);
+				priv->rx_ring[0]->cqn, -1, &context);
 
 	if (!priv->prof->rss_rings || priv->prof->rss_rings > priv->rx_ring_num)
 		rss_rings = priv->rx_ring_num;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
index 2448f0d..4062669 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
@@ -156,7 +156,7 @@ retry_tx:
 		 * since we turned the carrier off */
 		msleep(200);
 		for (i = 0; i < priv->tx_ring_num && carrier_ok; i++) {
-			tx_ring = &priv->tx_ring[i];
+			tx_ring = priv->tx_ring[i];
 			if (tx_ring->prod != (tx_ring->cons + tx_ring->last_nr_txbb))
 				goto retry_tx;
 		}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 0698c82..d4e4cf3 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -54,13 +54,20 @@ module_param_named(inline_thold, inline_thold, int, 0444);
 MODULE_PARM_DESC(inline_thold, "threshold for using inline data");
 
 int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
-			   struct mlx4_en_tx_ring *ring, int qpn, u32 size,
+			   struct mlx4_en_tx_ring **pring, int qpn, u32 size,
 			   u16 stride)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_en_tx_ring *ring;
 	int tmp;
 	int err;
 
+	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+	if (!ring) {
+		en_err(priv, "Failed allocating TX ring\n");
+		return -ENOMEM;
+	}
+
 	ring->size = size;
 	ring->size_mask = size - 1;
 	ring->stride = stride;
@@ -69,8 +76,10 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
 
 	tmp = size * sizeof(struct mlx4_en_tx_info);
 	ring->tx_info = vmalloc(tmp);
-	if (!ring->tx_info)
-		return -ENOMEM;
+	if (!ring->tx_info) {
+		err = -ENOMEM;
+		goto err_ring;
+	}
 
 	en_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n",
 		 ring->tx_info, tmp);
@@ -78,7 +87,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
 	ring->bounce_buf = kmalloc(MAX_DESC_SIZE, GFP_KERNEL);
 	if (!ring->bounce_buf) {
 		err = -ENOMEM;
-		goto err_tx;
+		goto err_info;
 	}
 	ring->buf_size = ALIGN(size * ring->stride, MLX4_EN_PAGE_SIZE);
 
@@ -120,6 +129,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
 
 	ring->hwtstamp_tx_type = priv->hwtstamp_config.tx_type;
 
+	*pring = ring;
 	return 0;
 
 err_map:
@@ -129,16 +139,20 @@ err_hwq_res:
 err_bounce:
 	kfree(ring->bounce_buf);
 	ring->bounce_buf = NULL;
-err_tx:
+err_info:
 	vfree(ring->tx_info);
 	ring->tx_info = NULL;
+err_ring:
+	kfree(ring);
+	*pring = NULL;
 	return err;
 }
 
 void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
-			     struct mlx4_en_tx_ring *ring)
+			     struct mlx4_en_tx_ring **pring)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_en_tx_ring *ring = *pring;
 	en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn);
 
 	if (ring->bf_enabled)
@@ -151,6 +165,8 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
 	ring->bounce_buf = NULL;
 	vfree(ring->tx_info);
 	ring->tx_info = NULL;
+	kfree(ring);
+	*pring = NULL;
 }
 
 int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
@@ -330,7 +346,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
 {
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 	struct mlx4_cq *mcq = &cq->mcq;
-	struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring];
+	struct mlx4_en_tx_ring *ring = priv->tx_ring[cq->ring];
 	struct mlx4_cqe *cqe;
 	u16 index;
 	u16 new_index, ring_index, stamp_index;
@@ -622,7 +638,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 
 	tx_ind = skb->queue_mapping;
-	ring = &priv->tx_ring[tx_ind];
+	ring = priv->tx_ring[tx_ind];
 	if (vlan_tx_tag_present(skb))
 		vlan_tag = vlan_tx_tag_get(skb);
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index bf06e36..b2547ae 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -530,10 +530,10 @@ struct mlx4_en_priv {
 	u16 num_frags;
 	u16 log_rx_info;
 
-	struct mlx4_en_tx_ring *tx_ring;
-	struct mlx4_en_rx_ring rx_ring[MAX_RX_RINGS];
-	struct mlx4_en_cq *tx_cq;
-	struct mlx4_en_cq rx_cq[MAX_RX_RINGS];
+	struct mlx4_en_tx_ring **tx_ring;
+	struct mlx4_en_rx_ring *rx_ring[MAX_RX_RINGS];
+	struct mlx4_en_cq **tx_cq;
+	struct mlx4_en_cq *rx_cq[MAX_RX_RINGS];
 	struct mlx4_qp drop_qp;
 	struct work_struct rx_mode_task;
 	struct work_struct watchdog_task;
@@ -626,7 +626,7 @@ static inline bool mlx4_en_cq_lock_poll(struct mlx4_en_cq *cq)
 	if ((cq->state & MLX4_CQ_LOCKED)) {
 		struct net_device *dev = cq->dev;
 		struct mlx4_en_priv *priv = netdev_priv(dev);
-		struct mlx4_en_rx_ring *rx_ring = &priv->rx_ring[cq->ring];
+		struct mlx4_en_rx_ring *rx_ring = priv->rx_ring[cq->ring];
 
 		cq->state |= MLX4_EN_CQ_STATE_POLL_YIELD;
 		rc = false;
@@ -704,9 +704,9 @@ void mlx4_en_stop_port(struct net_device *dev, int detach);
 void mlx4_en_free_resources(struct mlx4_en_priv *priv);
 int mlx4_en_alloc_resources(struct mlx4_en_priv *priv);
 
-int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
+int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq,
 		      int entries, int ring, enum cq_type mode);
-void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
+void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq);
 int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
 			int cq_idx);
 void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
@@ -717,9 +717,11 @@ void mlx4_en_tx_irq(struct mlx4_cq *mcq);
 u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb);
 netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev);
 
-int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring,
+int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
+			   struct mlx4_en_tx_ring **pring,
 			   int qpn, u32 size, u16 stride);
-void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring);
+void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
+			     struct mlx4_en_tx_ring **pring);
 int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
 			     struct mlx4_en_tx_ring *ring,
 			     int cq, int user_prio);
@@ -727,10 +729,10 @@ void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
 				struct mlx4_en_tx_ring *ring);
 
 int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
-			   struct mlx4_en_rx_ring *ring,
+			   struct mlx4_en_rx_ring **pring,
 			   u32 size, u16 stride);
 void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv,
-			     struct mlx4_en_rx_ring *ring,
+			     struct mlx4_en_rx_ring **pring,
 			     u32 size, u16 stride);
 int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv);
 void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv,
@@ -768,8 +770,7 @@ extern const struct dcbnl_rtnl_ops mlx4_en_dcbnl_pfc_ops;
 int mlx4_en_setup_tc(struct net_device *dev, u8 up);
 
 #ifdef CONFIG_RFS_ACCEL
-void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv,
-			     struct mlx4_en_rx_ring *rx_ring);
+void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv);
 #endif
 
 #define MLX4_EN_NUM_SELF_TEST	5
-- 
1.8.3.4

^ permalink raw reply related

* [PATCH net-next 6/6] net/mlx4_en: Datapath structures are allocated per NUMA node
From: Amir Vadai @ 2013-11-07 10:19 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Amir Vadai, Yevgeny Petrilin, Or Gerlitz,
	Eugenia Emantayev
In-Reply-To: <1383819594-24070-1-git-send-email-amirv@mellanox.com>

From: Eugenia Emantayev <eugenia@mellanox.com>

For each RX/TX ring and its CQ, allocation is done on a NUMA node that
corresponds to the core that the data structure should operate on.
The assumption is that the core number is reflected by the ring index.
The affected allocations are the ring/CQ data structures,
the TX/RX info and the shared HW/SW buffer.
For TX rings, each core has rings of all UPs.

Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.com>
Signed-off-by: Eugenia Emantayev <eugenia@mellanox.com>
Reviewed-by: Hadar Hen Zion <hadarh@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_cq.c     | 17 ++++++++++---
 drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 12 ++++++---
 drivers/net/ethernet/mellanox/mlx4/en_rx.c     | 23 +++++++++++------
 drivers/net/ethernet/mellanox/mlx4/en_tx.c     | 34 +++++++++++++++++---------
 drivers/net/ethernet/mellanox/mlx4/mlx4_en.h   |  6 ++---
 drivers/net/ethernet/mellanox/mlx4/pd.c        | 11 ++++++---
 include/linux/mlx4/device.h                    |  2 +-
 7 files changed, 71 insertions(+), 34 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
index d203f11..3a098cc 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
@@ -45,16 +45,20 @@ static void mlx4_en_cq_event(struct mlx4_cq *cq, enum mlx4_event event)
 
 int mlx4_en_create_cq(struct mlx4_en_priv *priv,
 		      struct mlx4_en_cq **pcq,
-		      int entries, int ring, enum cq_type mode)
+		      int entries, int ring, enum cq_type mode,
+		      int node)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_en_cq *cq;
 	int err;
 
-	cq = kzalloc(sizeof(*cq), GFP_KERNEL);
+	cq = kzalloc_node(sizeof(*cq), GFP_KERNEL, node);
 	if (!cq) {
-		en_err(priv, "Failed to allocate CQ structure\n");
-		return -ENOMEM;
+		cq = kzalloc(sizeof(*cq), GFP_KERNEL);
+		if (!cq) {
+			en_err(priv, "Failed to allocate CQ structure\n");
+			return -ENOMEM;
+		}
 	}
 
 	cq->size = entries;
@@ -64,8 +68,13 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv,
 	cq->is_tx = mode;
 	spin_lock_init(&cq->lock);
 
+	/* Allocate HW buffers on provided NUMA node.
+	 * dev->numa_node is used in mtt range allocation flow.
+	 */
+	set_dev_node(&mdev->dev->pdev->dev, node);
 	err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres,
 				cq->buf_size, 2 * PAGE_SIZE);
+	set_dev_node(&mdev->dev->pdev->dev, mdev->dev->numa_node);
 	if (err)
 		goto err_cq;
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index f430788..e72d8a1 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1895,6 +1895,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
 	struct mlx4_en_port_profile *prof = priv->prof;
 	int i;
 	int err;
+	int node;
 
 	err = mlx4_qp_reserve_range(priv->mdev->dev, priv->tx_ring_num, 256, &priv->base_tx_qpn);
 	if (err) {
@@ -1904,23 +1905,26 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
 
 	/* Create tx Rings */
 	for (i = 0; i < priv->tx_ring_num; i++) {
+		node = cpu_to_node(i % num_online_cpus());
 		if (mlx4_en_create_cq(priv, &priv->tx_cq[i],
-				      prof->tx_ring_size, i, TX))
+				      prof->tx_ring_size, i, TX, node))
 			goto err;
 
 		if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], priv->base_tx_qpn + i,
-					   prof->tx_ring_size, TXBB_SIZE))
+					   prof->tx_ring_size, TXBB_SIZE, node))
 			goto err;
 	}
 
 	/* Create rx Rings */
 	for (i = 0; i < priv->rx_ring_num; i++) {
+		node = cpu_to_node(i % num_online_cpus());
 		if (mlx4_en_create_cq(priv, &priv->rx_cq[i],
-				      prof->rx_ring_size, i, RX))
+				      prof->rx_ring_size, i, RX, node))
 			goto err;
 
 		if (mlx4_en_create_rx_ring(priv, &priv->rx_ring[i],
-					   prof->rx_ring_size, priv->stride))
+					   prof->rx_ring_size, priv->stride,
+					   node))
 			goto err;
 	}
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 1c45f88..07a1d0f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -320,17 +320,20 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
 
 int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
 			   struct mlx4_en_rx_ring **pring,
-			   u32 size, u16 stride)
+			   u32 size, u16 stride, int node)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_en_rx_ring *ring;
 	int err = -ENOMEM;
 	int tmp;
 
-	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+	ring = kzalloc_node(sizeof(*ring), GFP_KERNEL, node);
 	if (!ring) {
-		en_err(priv, "Failed to allocate RX ring structure\n");
-		return -ENOMEM;
+		ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+		if (!ring) {
+			en_err(priv, "Failed to allocate RX ring structure\n");
+			return -ENOMEM;
+		}
 	}
 
 	ring->prod = 0;
@@ -343,17 +346,23 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
 
 	tmp = size * roundup_pow_of_two(MLX4_EN_MAX_RX_FRAGS *
 					sizeof(struct mlx4_en_rx_alloc));
-	ring->rx_info = vmalloc(tmp);
+	ring->rx_info = vmalloc_node(tmp, node);
 	if (!ring->rx_info) {
-		err = -ENOMEM;
-		goto err_ring;
+		ring->rx_info = vmalloc(tmp);
+		if (!ring->rx_info) {
+			err = -ENOMEM;
+			goto err_ring;
+		}
 	}
 
 	en_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d\n",
 		 ring->rx_info, tmp);
 
+	/* Allocate HW buffers on provided NUMA node */
+	set_dev_node(&mdev->dev->pdev->dev, node);
 	err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres,
 				 ring->buf_size, 2 * PAGE_SIZE);
+	set_dev_node(&mdev->dev->pdev->dev, mdev->dev->numa_node);
 	if (err)
 		goto err_info;
 
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index d4e4cf3..f54ebd5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -55,17 +55,20 @@ MODULE_PARM_DESC(inline_thold, "threshold for using inline data");
 
 int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
 			   struct mlx4_en_tx_ring **pring, int qpn, u32 size,
-			   u16 stride)
+			   u16 stride, int node)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_en_tx_ring *ring;
 	int tmp;
 	int err;
 
-	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+	ring = kzalloc_node(sizeof(*ring), GFP_KERNEL, node);
 	if (!ring) {
-		en_err(priv, "Failed allocating TX ring\n");
-		return -ENOMEM;
+		ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+		if (!ring) {
+			en_err(priv, "Failed allocating TX ring\n");
+			return -ENOMEM;
+		}
 	}
 
 	ring->size = size;
@@ -75,24 +78,33 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
 	inline_thold = min(inline_thold, MAX_INLINE);
 
 	tmp = size * sizeof(struct mlx4_en_tx_info);
-	ring->tx_info = vmalloc(tmp);
+	ring->tx_info = vmalloc_node(tmp, node);
 	if (!ring->tx_info) {
-		err = -ENOMEM;
-		goto err_ring;
+		ring->tx_info = vmalloc(tmp);
+		if (!ring->tx_info) {
+			err = -ENOMEM;
+			goto err_ring;
+		}
 	}
 
 	en_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n",
 		 ring->tx_info, tmp);
 
-	ring->bounce_buf = kmalloc(MAX_DESC_SIZE, GFP_KERNEL);
+	ring->bounce_buf = kmalloc_node(MAX_DESC_SIZE, GFP_KERNEL, node);
 	if (!ring->bounce_buf) {
-		err = -ENOMEM;
-		goto err_info;
+		ring->bounce_buf = kmalloc(MAX_DESC_SIZE, GFP_KERNEL);
+		if (!ring->bounce_buf) {
+			err = -ENOMEM;
+			goto err_info;
+		}
 	}
 	ring->buf_size = ALIGN(size * ring->stride, MLX4_EN_PAGE_SIZE);
 
+	/* Allocate HW buffers on provided NUMA node */
+	set_dev_node(&mdev->dev->pdev->dev, node);
 	err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size,
 				 2 * PAGE_SIZE);
+	set_dev_node(&mdev->dev->pdev->dev, mdev->dev->numa_node);
 	if (err) {
 		en_err(priv, "Failed allocating hwq resources\n");
 		goto err_bounce;
@@ -118,7 +130,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
 	}
 	ring->qp.event = mlx4_en_sqp_event;
 
-	err = mlx4_bf_alloc(mdev->dev, &ring->bf);
+	err = mlx4_bf_alloc(mdev->dev, &ring->bf, node);
 	if (err) {
 		en_dbg(DRV, priv, "working without blueflame (%d)", err);
 		ring->bf.uar = &mdev->priv_uar;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index b2547ae..f3758de 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -705,7 +705,7 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv);
 int mlx4_en_alloc_resources(struct mlx4_en_priv *priv);
 
 int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq,
-		      int entries, int ring, enum cq_type mode);
+		      int entries, int ring, enum cq_type mode, int node);
 void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq);
 int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
 			int cq_idx);
@@ -719,7 +719,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev);
 
 int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
 			   struct mlx4_en_tx_ring **pring,
-			   int qpn, u32 size, u16 stride);
+			   int qpn, u32 size, u16 stride, int node);
 void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
 			     struct mlx4_en_tx_ring **pring);
 int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
@@ -730,7 +730,7 @@ void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
 
 int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
 			   struct mlx4_en_rx_ring **pring,
-			   u32 size, u16 stride);
+			   u32 size, u16 stride, int node);
 void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv,
 			     struct mlx4_en_rx_ring **pring,
 			     u32 size, u16 stride);
diff --git a/drivers/net/ethernet/mellanox/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c
index 00f223a..84cfb40 100644
--- a/drivers/net/ethernet/mellanox/mlx4/pd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/pd.c
@@ -168,7 +168,7 @@ void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar)
 }
 EXPORT_SYMBOL_GPL(mlx4_uar_free);
 
-int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf)
+int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	struct mlx4_uar *uar;
@@ -186,10 +186,13 @@ int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf)
 			err = -ENOMEM;
 			goto out;
 		}
-		uar = kmalloc(sizeof *uar, GFP_KERNEL);
+		uar = kmalloc_node(sizeof(*uar), GFP_KERNEL, node);
 		if (!uar) {
-			err = -ENOMEM;
-			goto out;
+			uar = kmalloc(sizeof(*uar), GFP_KERNEL);
+			if (!uar) {
+				err = -ENOMEM;
+				goto out;
+			}
 		}
 		err = mlx4_uar_alloc(dev, uar);
 		if (err)
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 4cf0b01..7d3a523 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -835,7 +835,7 @@ void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn);
 
 int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar);
 void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar);
-int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf);
+int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node);
 void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf);
 
 int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift,
-- 
1.8.3.4

^ permalink raw reply related

* [PATCH net-next 5/6] net/mlx4_core: ICM pages are allocated on device NUMA node
From: Amir Vadai @ 2013-11-07 10:19 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Amir Vadai, Yevgeny Petrilin, Or Gerlitz,
	Eugenia Emantayev
In-Reply-To: <1383819594-24070-1-git-send-email-amirv@mellanox.com>

From: Eugenia Emantayev <eugenia@mellanox.com>

>From now ICM pages will be allocated on device NUMA node.
This is done to optimize FW/HW access to host memory.

Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.com>
Signed-off-by: Eugenia Emantayev <eugenia@mellanox.com>
Reviewed-by: Hadar Hen Zion <hadarh@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/icm.c  | 42 ++++++++++++++++++++++---------
 drivers/net/ethernet/mellanox/mlx4/main.c |  1 +
 include/linux/mlx4/device.h               |  1 +
 3 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c
index 31d0264..5fbf492 100644
--- a/drivers/net/ethernet/mellanox/mlx4/icm.c
+++ b/drivers/net/ethernet/mellanox/mlx4/icm.c
@@ -93,13 +93,17 @@ void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent)
 	kfree(icm);
 }
 
-static int mlx4_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask)
+static int mlx4_alloc_icm_pages(struct scatterlist *mem, int order,
+				gfp_t gfp_mask, int node)
 {
 	struct page *page;
 
-	page = alloc_pages(gfp_mask, order);
-	if (!page)
-		return -ENOMEM;
+	page = alloc_pages_node(node, gfp_mask, order);
+	if (!page) {
+		page = alloc_pages(gfp_mask, order);
+		if (!page)
+			return -ENOMEM;
+	}
 
 	sg_set_page(mem, page, PAGE_SIZE << order, 0);
 	return 0;
@@ -130,9 +134,15 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
 	/* We use sg_set_buf for coherent allocs, which assumes low memory */
 	BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM));
 
-	icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
-	if (!icm)
-		return NULL;
+	icm = kmalloc_node(sizeof(*icm),
+			   gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN),
+			   dev->numa_node);
+	if (!icm) {
+		icm = kmalloc(sizeof(*icm),
+			      gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
+		if (!icm)
+			return NULL;
+	}
 
 	icm->refcount = 0;
 	INIT_LIST_HEAD(&icm->chunk_list);
@@ -141,10 +151,17 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
 
 	while (npages > 0) {
 		if (!chunk) {
-			chunk = kmalloc(sizeof *chunk,
-					gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
-			if (!chunk)
-				goto fail;
+			chunk = kmalloc_node(sizeof(*chunk),
+					     gfp_mask & ~(__GFP_HIGHMEM |
+							  __GFP_NOWARN),
+					     dev->numa_node);
+			if (!chunk) {
+				chunk = kmalloc(sizeof(*chunk),
+						gfp_mask & ~(__GFP_HIGHMEM |
+							     __GFP_NOWARN));
+				if (!chunk)
+					goto fail;
+			}
 
 			sg_init_table(chunk->mem, MLX4_ICM_CHUNK_LEN);
 			chunk->npages = 0;
@@ -161,7 +178,8 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
 						      cur_order, gfp_mask);
 		else
 			ret = mlx4_alloc_icm_pages(&chunk->mem[chunk->npages],
-						   cur_order, gfp_mask);
+						   cur_order, gfp_mask,
+						   dev->numa_node);
 
 		if (ret) {
 			if (--cur_order < 0)
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 7d2628d..5789ea2 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -2191,6 +2191,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
 	mutex_init(&priv->bf_mutex);
 
 	dev->rev_id = pdev->revision;
+	dev->numa_node = dev_to_node(&pdev->dev);
 	/* Detect if this device is a virtual function */
 	if (pci_dev_data & MLX4_PCI_DEV_IS_VF) {
 		/* When acting as pf, we normally skip vfs unless explicitly
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index f6f5927..4cf0b01 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -662,6 +662,7 @@ struct mlx4_dev {
 	u8			rev_id;
 	char			board_id[MLX4_BOARD_ID_LEN];
 	int			num_vfs;
+	int			numa_node;
 	int			oper_log_mgm_entry_size;
 	u64			regid_promisc_array[MLX4_MAX_PORTS + 1];
 	u64			regid_allmulti_array[MLX4_MAX_PORTS + 1];
-- 
1.8.3.4

^ permalink raw reply related

* [PATCH net-next 3/6] net/mlx4_core: Add immediate activate for VGT->VST->VGT
From: Amir Vadai @ 2013-11-07 10:19 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Amir Vadai, Yevgeny Petrilin, Or Gerlitz, Rony Efraim,
	Jack Morgenstein
In-Reply-To: <1383819594-24070-1-git-send-email-amirv@mellanox.com>

From: Rony Efraim <ronye@mellanox.com>

Allow immediate activate of VGT->VST and VST->VGT transitions, without
the need of rebinding in mlx4_master_immediate_activate_vlan_qos().

Also in struct res_qp: add qp parameters (vlan_index,fvl,vlan_cntrol..)
to the saved set, in order to restore when move to VGT.
 - Clear at mlx4_RST2INIT_QP_wrapper()
 - Save at mlx4_INIT2RTR_QP_wrapper()
 - Restore at mlx4_vf_immed_vlan_work_handler()

Update mlx4_vf_immed_vlan_work_handler() to support VGT.


Signed-off-by: Rony Efraim <ronye@mellanox.com>
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Reviewed-by: Hadar Hen Zion <hadarh@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/cmd.c           | 34 ++++------
 .../net/ethernet/mellanox/mlx4/resource_tracker.c  | 79 ++++++++++++++++++----
 2 files changed, 81 insertions(+), 32 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index 7207dcd..1e9970d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -1539,11 +1539,6 @@ out:
 	return ret;
 }
 
-static int calculate_transition(u16 oper_vlan, u16 admin_vlan)
-{
-	return (2 * (oper_vlan == MLX4_VGT) + (admin_vlan == MLX4_VGT));
-}
-
 static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv,
 					    int slave, int port)
 {
@@ -1553,7 +1548,6 @@ static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv,
 	struct mlx4_dev *dev = &(priv->dev);
 	int err;
 	int admin_vlan_ix = NO_INDX;
-	enum mlx4_vlan_transition vlan_trans;
 
 	vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
 	vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
@@ -1563,12 +1557,8 @@ static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv,
 	    vp_oper->state.link_state == vp_admin->link_state)
 		return 0;
 
-	vlan_trans = calculate_transition(vp_oper->state.default_vlan,
-					  vp_admin->default_vlan);
-
 	if (!(priv->mfunc.master.slave_state[slave].active &&
-	      dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP &&
-	      vlan_trans == MLX4_VLAN_TRANSITION_VST_VST)) {
+	      dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP)) {
 		/* even if the UPDATE_QP command isn't supported, we still want
 		 * to set this VF link according to the admin directive
 		 */
@@ -1586,15 +1576,19 @@ static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv,
 		return -ENOMEM;
 
 	if (vp_oper->state.default_vlan != vp_admin->default_vlan) {
-		err = __mlx4_register_vlan(&priv->dev, port,
-					   vp_admin->default_vlan,
-					   &admin_vlan_ix);
-		if (err) {
-			kfree(work);
-			mlx4_warn((&priv->dev),
-				  "No vlan resources slave %d, port %d\n",
-				  slave, port);
-			return err;
+		if (MLX4_VGT != vp_admin->default_vlan) {
+			err = __mlx4_register_vlan(&priv->dev, port,
+						   vp_admin->default_vlan,
+						   &admin_vlan_ix);
+			if (err) {
+				kfree(work);
+				mlx4_warn((&priv->dev),
+					  "No vlan resources slave %d, port %d\n",
+					  slave, port);
+				return err;
+			}
+		} else {
+			admin_vlan_ix = NO_INDX;
 		}
 		work->flags |= MLX4_VF_IMMED_VLAN_FLAG_VLAN;
 		mlx4_dbg((&(priv->dev)),
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index b1603e2..2f3f2bc 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -110,7 +110,14 @@ struct res_qp {
 	int			local_qpn;
 	atomic_t		ref_count;
 	u32			qpc_flags;
+	/* saved qp params before VST enforcement in order to restore on VGT */
 	u8			sched_queue;
+	__be32			param3;
+	u8			vlan_control;
+	u8			fvl_rx;
+	u8			pri_path_fl;
+	u8			vlan_index;
+	u8			feup;
 };
 
 enum res_mtt_states {
@@ -2568,6 +2575,12 @@ int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,
 		return err;
 	qp->local_qpn = local_qpn;
 	qp->sched_queue = 0;
+	qp->param3 = 0;
+	qp->vlan_control = 0;
+	qp->fvl_rx = 0;
+	qp->pri_path_fl = 0;
+	qp->vlan_index = 0;
+	qp->feup = 0;
 	qp->qpc_flags = be32_to_cpu(qpc->flags);
 
 	err = get_res(dev, slave, mtt_base, RES_MTT, &mtt);
@@ -3294,6 +3307,12 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
 	int qpn = vhcr->in_modifier & 0x7fffff;
 	struct res_qp *qp;
 	u8 orig_sched_queue;
+	__be32	orig_param3 = qpc->param3;
+	u8 orig_vlan_control = qpc->pri_path.vlan_control;
+	u8 orig_fvl_rx = qpc->pri_path.fvl_rx;
+	u8 orig_pri_path_fl = qpc->pri_path.fl;
+	u8 orig_vlan_index = qpc->pri_path.vlan_index;
+	u8 orig_feup = qpc->pri_path.feup;
 
 	err = verify_qp_parameters(dev, inbox, QP_TRANS_INIT2RTR, slave);
 	if (err)
@@ -3321,9 +3340,15 @@ out:
 	 * essentially the QOS value provided by the VF. This will be useful
 	 * if we allow dynamic changes from VST back to VGT
 	 */
-	if (!err)
+	if (!err) {
 		qp->sched_queue = orig_sched_queue;
-
+		qp->param3	= orig_param3;
+		qp->vlan_control = orig_vlan_control;
+		qp->fvl_rx	=  orig_fvl_rx;
+		qp->pri_path_fl = orig_pri_path_fl;
+		qp->vlan_index  = orig_vlan_index;
+		qp->feup	= orig_feup;
+	}
 	put_res(dev, slave, qpn, RES_QP);
 	return err;
 }
@@ -4437,13 +4462,20 @@ void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work)
 		&tracker->slave_list[work->slave].res_list[RES_QP];
 	struct res_qp *qp;
 	struct res_qp *tmp;
-	u64 qp_mask = ((1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED) |
+	u64 qp_path_mask_vlan_ctrl =
+		       ((1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED) |
 		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_1P) |
 		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_TAGGED) |
 		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_UNTAGGED) |
 		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_1P) |
-		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED) |
-		       (1ULL << MLX4_UPD_QP_PATH_MASK_VLAN_INDEX) |
+		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED));
+
+	u64 qp_path_mask = ((1ULL << MLX4_UPD_QP_PATH_MASK_VLAN_INDEX) |
+		       (1ULL << MLX4_UPD_QP_PATH_MASK_FVL) |
+		       (1ULL << MLX4_UPD_QP_PATH_MASK_CV) |
+		       (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_HIDE_CQE_VLAN) |
+		       (1ULL << MLX4_UPD_QP_PATH_MASK_FEUP) |
+		       (1ULL << MLX4_UPD_QP_PATH_MASK_FVL_RX) |
 		       (1ULL << MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE));
 
 	int err;
@@ -4475,9 +4507,7 @@ void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work)
 			MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
 
 	upd_context = mailbox->buf;
-	upd_context->primary_addr_path_mask = cpu_to_be64(qp_mask);
-	upd_context->qp_context.pri_path.vlan_control = vlan_control;
-	upd_context->qp_context.pri_path.vlan_index = work->vlan_ix;
+	upd_context->qp_mask = cpu_to_be64(MLX4_UPD_QP_MASK_VSD);
 
 	spin_lock_irq(mlx4_tlock(dev));
 	list_for_each_entry_safe(qp, tmp, qp_list, com.list) {
@@ -4495,10 +4525,35 @@ void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work)
 				spin_lock_irq(mlx4_tlock(dev));
 				continue;
 			}
-			upd_context->qp_context.pri_path.sched_queue =
-				qp->sched_queue & 0xC7;
-			upd_context->qp_context.pri_path.sched_queue |=
-				((work->qos & 0x7) << 3);
+			if (MLX4_QP_ST_RC == ((qp->qpc_flags >> 16) & 0xff))
+				upd_context->primary_addr_path_mask = cpu_to_be64(qp_path_mask);
+			else
+				upd_context->primary_addr_path_mask =
+					cpu_to_be64(qp_path_mask | qp_path_mask_vlan_ctrl);
+			if (work->vlan_id == MLX4_VGT) {
+				upd_context->qp_context.param3 = qp->param3;
+				upd_context->qp_context.pri_path.vlan_control = qp->vlan_control;
+				upd_context->qp_context.pri_path.fvl_rx = qp->fvl_rx;
+				upd_context->qp_context.pri_path.vlan_index = qp->vlan_index;
+				upd_context->qp_context.pri_path.fl = qp->pri_path_fl;
+				upd_context->qp_context.pri_path.feup = qp->feup;
+				upd_context->qp_context.pri_path.sched_queue =
+					qp->sched_queue;
+			} else {
+				upd_context->qp_context.param3 = qp->param3 & ~cpu_to_be32(MLX4_STRIP_VLAN);
+				upd_context->qp_context.pri_path.vlan_control = vlan_control;
+				upd_context->qp_context.pri_path.vlan_index = work->vlan_ix;
+				upd_context->qp_context.pri_path.fvl_rx =
+					qp->fvl_rx | MLX4_FVL_RX_FORCE_ETH_VLAN;
+				upd_context->qp_context.pri_path.fl =
+					qp->pri_path_fl | MLX4_FL_CV | MLX4_FL_ETH_HIDE_CQE_VLAN;
+				upd_context->qp_context.pri_path.feup =
+					qp->feup | MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN;
+				upd_context->qp_context.pri_path.sched_queue =
+					qp->sched_queue & 0xC7;
+				upd_context->qp_context.pri_path.sched_queue |=
+					((work->qos & 0x7) << 3);
+			}
 
 			err = mlx4_cmd(dev, mailbox->dma,
 				       qp->local_qpn & 0xffffff,
-- 
1.8.3.4

^ permalink raw reply related

* ipv6: a question about ECMP
From: Duan Jiong @ 2013-11-07 10:33 UTC (permalink / raw)
  To: hannes, David Miller, nicolas.dichtel; +Cc: netdev

Hi,

  After reading the ip6_pol_route(), i have a question about ECMP. Why we call
the rt6_multipath_select() after calling rt6_select()?
  In my opinion, the route returned by rt6_select() has a highest score, but the route
returned by rt6_multipath_select() may has a lower score than the former, because the
ECMP don't take the route preference into consideration. That means that the kernel will
choose a less-desirable route.

Thanks,
  Duan
  

^ permalink raw reply

* [PATCH iproute2] Add more supoprt for bonding netlink attributes
From: Scott Feldman @ 2013-11-07 10:36 UTC (permalink / raw)
  To: stephen; +Cc: netdev, shm

Add get/set support for the following bonding attributes:

miimon
updelay
downdelay
use_carrier
arp_interval
arp_ip_target
arp_validate
arp_all_targets

Signed-off-by: Scott Feldman <sfeldma@cumulusnetworks.com>
---
 include/linux/if_link.h |    8 +++
 ip/iplink_bond.c        |  134 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 140 insertions(+), 2 deletions(-)

diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index a485920..69e0353 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -329,6 +329,14 @@ enum {
 	IFLA_BOND_UNSPEC,
 	IFLA_BOND_MODE,
 	IFLA_BOND_ACTIVE_SLAVE,
+        IFLA_BOND_MIIMON,
+        IFLA_BOND_UPDELAY,
+        IFLA_BOND_DOWNDELAY,
+        IFLA_BOND_USE_CARRIER,
+        IFLA_BOND_ARP_INTERVAL,
+        IFLA_BOND_ARP_IP_TARGET,
+        IFLA_BOND_ARP_VALIDATE,
+        IFLA_BOND_ARP_ALL_TARGETS,
 	__IFLA_BOND_MAX,
 };
 
diff --git a/ip/iplink_bond.c b/ip/iplink_bond.c
index 3fb7f4f..9ca6bdb 100644
--- a/ip/iplink_bond.c
+++ b/ip/iplink_bond.c
@@ -7,6 +7,7 @@
  *              2 of the License, or (at your option) any later version.
  *
  * Authors:     Jiri Pirko <jiri@resnulli.us>
+ *              Scott Feldman <sfeldma@cumulusnetworks.com>
  */
 
 #include <stdio.h>
@@ -19,11 +20,19 @@
 #include "utils.h"
 #include "ip_common.h"
 
+#define BOND_MAX_ARP_TARGETS    16
+
 static void explain(void)
 {
 	fprintf(stderr,
 		"Usage: ... bond [ mode BONDMODE ] [ active_slave SLAVE_DEV ]\n"
-		"                [ clear_active_slave ]\n"
+		"                [ clear_active_slave ] [ miimon MIIMON ]\n"
+		"                [ updelay UPDELAY ] [ downdelay DOWNDELAY ]\n"
+		"                [ use_carrier USE_CARRIER ]\n"
+		"                [ arp_interval ARP_INTERVAL ]\n"
+		"                [ arp_validate ARP_VALIDATE ]\n"
+		"                [ arp_all_targets ARP_ALL_TARGETS ]\n"
+		"                [ arp_ip_target [ ARP_IP_TARGET, ... ] ]\n"
 		"\n"
 		"BONDMODE := 0-6\n"
 	);
@@ -32,7 +41,9 @@ static void explain(void)
 static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
 			  struct nlmsghdr *n)
 {
-	__u8 mode;
+	__u8 mode, use_carrier;
+	__u32 miimon, updelay, downdelay, arp_interval, arp_validate;
+	__u32 arp_all_targets;
 	unsigned ifindex;
 
 	while (argc > 0) {
@@ -51,6 +62,72 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
 			addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, ifindex);
 		} else if (matches(*argv, "clear_active_slave") == 0) {
 			addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, 0);
+		} else if (matches(*argv, "miimon") == 0) {
+			NEXT_ARG();
+			if (get_u32(&miimon, *argv, 0)) {
+				invarg("miimon %s is invalid", *argv);
+				return -1;
+			}
+			addattr32(n, 1024, IFLA_BOND_MIIMON, miimon);
+		} else if (matches(*argv, "updelay") == 0) {
+			NEXT_ARG();
+			if (get_u32(&updelay, *argv, 0)) {
+				invarg("updelay %s is invalid", *argv);
+				return -1;
+			}
+			addattr32(n, 1024, IFLA_BOND_UPDELAY, updelay);
+		} else if (matches(*argv, "downdelay") == 0) {
+			NEXT_ARG();
+			if (get_u32(&downdelay, *argv, 0)) {
+				invarg("downdelay %s is invalid", *argv);
+				return -1;
+			}
+			addattr32(n, 1024, IFLA_BOND_DOWNDELAY, downdelay);
+		} else if (matches(*argv, "use_carrier") == 0) {
+			NEXT_ARG();
+			if (get_u8(&use_carrier, *argv, 0)) {
+				invarg("use_carrier %s is invalid", *argv);
+				return -1;
+			}
+			addattr8(n, 1024, IFLA_BOND_USE_CARRIER, use_carrier);
+		} else if (matches(*argv, "arp_interval") == 0) {
+			NEXT_ARG();
+			if (get_u32(&arp_interval, *argv, 0)) {
+				invarg("arp_interval %s is invalid", *argv);
+				return -1;
+			}
+			addattr32(n, 1024, IFLA_BOND_ARP_INTERVAL, arp_interval);
+		} else if (matches(*argv, "arp_ip_target") == 0) {
+			struct rtattr * nest = addattr_nest(n, 1024,
+				IFLA_BOND_ARP_IP_TARGET);
+			if (NEXT_ARG_OK()) {
+				NEXT_ARG();
+				char *targets = strdupa(*argv);
+				char *target = strtok(targets, ",");
+				int i;
+
+				for(i = 0; target && i < BOND_MAX_ARP_TARGETS; i++) {
+					__u32 addr = get_addr32(target);
+					addattr32(n, 1024, i, addr);
+					target = strtok(NULL, ",");
+				}
+				addattr_nest_end(n, nest);
+			}
+			addattr_nest_end(n, nest);
+		} else if (matches(*argv, "arp_validate") == 0) {
+			NEXT_ARG();
+			if (get_u32(&arp_validate, *argv, 0)) {
+				invarg("arp_validate %s is invalid", *argv);
+				return -1;
+			}
+			addattr32(n, 1024, IFLA_BOND_ARP_VALIDATE, arp_validate);
+		} else if (matches(*argv, "arp_all_targets") == 0) {
+			NEXT_ARG();
+			if (get_u32(&arp_all_targets, *argv, 0)) {
+				invarg("arp_all_targets %s is invalid", *argv);
+				return -1;
+			}
+			addattr32(n, 1024, IFLA_BOND_ARP_ALL_TARGETS, arp_all_targets);
 		} else {
 			fprintf(stderr, "bond: unknown command \"%s\"?\n", *argv);
 			explain();
@@ -82,6 +159,59 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 		else
 			fprintf(f, "active_slave %u ", ifindex);
 	}
+
+	if (tb[IFLA_BOND_MIIMON])
+		fprintf(f, "miimon %u ", rta_getattr_u32(tb[IFLA_BOND_MIIMON]));
+
+	if (tb[IFLA_BOND_UPDELAY])
+		fprintf(f, "updelay %u ", rta_getattr_u32(tb[IFLA_BOND_UPDELAY]));
+
+	if (tb[IFLA_BOND_DOWNDELAY])
+		fprintf(f, "downdelay %u ",
+			rta_getattr_u32(tb[IFLA_BOND_DOWNDELAY]));
+
+	if (tb[IFLA_BOND_USE_CARRIER])
+		fprintf(f, "use_carrier %u ",
+			rta_getattr_u8(tb[IFLA_BOND_USE_CARRIER]));
+
+	if (tb[IFLA_BOND_ARP_INTERVAL])
+		fprintf(f, "arp_interval %u ",
+			rta_getattr_u32(tb[IFLA_BOND_ARP_INTERVAL]));
+
+	if (tb[IFLA_BOND_ARP_IP_TARGET]) {
+		struct rtattr *iptb[BOND_MAX_ARP_TARGETS];
+		char buf[INET_ADDRSTRLEN];
+		int i;
+
+		parse_rtattr_nested(iptb, BOND_MAX_ARP_TARGETS,
+			tb[IFLA_BOND_ARP_IP_TARGET]);
+
+		if (iptb[0])
+			fprintf(f, "arp_ip_target ");
+
+		for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
+			if (iptb[i])
+				fprintf(f, "%s",
+					rt_addr_n2a(AF_INET,
+						    RTA_PAYLOAD(iptb[i]),
+						    RTA_DATA(iptb[i]),
+						    buf,
+						    INET_ADDRSTRLEN));
+			if (i < BOND_MAX_ARP_TARGETS- 1 && iptb[i+1])
+				fprintf(f, ",");
+		}
+
+		if (iptb[0])
+			fprintf(f, " ");
+	}
+
+	if (tb[IFLA_BOND_ARP_VALIDATE])
+		fprintf(f, "arp_validate %u ",
+			rta_getattr_u32(tb[IFLA_BOND_ARP_VALIDATE]));
+
+	if (tb[IFLA_BOND_ARP_ALL_TARGETS])
+		fprintf(f, "arp_all_target %u ",
+			rta_getattr_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]));
 }
 
 struct link_util bond_link_util = {

^ permalink raw reply related

* Re: [PATCH net-next RFC 0/5] xen-netback: TX grant mapping instead of copy
From: Ian Campbell @ 2013-11-07 10:52 UTC (permalink / raw)
  To: Zoltan Kiss; +Cc: wei.liu2, xen-devel, netdev, linux-kernel, jonathan.davies
In-Reply-To: <5273FA37.6020903@citrix.com>

On Fri, 2013-11-01 at 19:00 +0000, Zoltan Kiss wrote:
> On 01/11/13 10:50, Ian Campbell wrote:
> > Does this always avoid copying when bridging/openvswitching/forwarding
> > (e.g. masquerading etc)? For both domU->domU and domU->physical NIC?
> I've tested the domU->domU, domU->physical with bridge and openvswitch 
> usecase, and now I've created a new stat counter to see how often copy 
> happens (the callback's second parameter tells you whether the skb was 
> freed or copied). It doesn't do copy in all of these scenarios.
> What do you mean by forwarding? The scenario when you use bridge and 
> iptables mangling with the packet, not just filtering?

I mean using L3 routing rather L2 bridging. Which might involve
NAT/MASQUERADE or might just be normal IP routing.

> > How does it deal with broadcast traffic?
> Most of the real broadcast traffic actually small packets fit in the 
> PKT_PROT_LEN sized linear space, so it doesn't make any difference, 
> apart from doing a mapping before copy. But that will be eliminated 
> later on, I plan to add an incremental improvement to grant copy the 
> linear part.

OK. If I were a malicious guest and decided to start sending out loads
of huge broadcasts would that lead to a massive spike of activity in
dom0?

> I haven't spent too much time on that, but I couldn't find any broadcast 
> protocol which use large enough packets and easy to test, so I'm open to 
> ideas.

I guess you could hack something up using raw sockets?

> What I already know, skb_clone trigger a copy, and if the caller use the 
> original skb for every cloning, it will do several copy. I think that 
> could be fixed by using the first clone to do any further clones.

Yes. I suppose doing this automatically might be an interesting
extension to SKBTX_DEV_ZEROCOPY?

Ian.

^ permalink raw reply

* Re: [PATCH net-next 6/8] bonding: add arp_ip_target netlink support
From: Scott Feldman @ 2013-11-07 10:56 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: vfalico, fubar, andy, netdev, shm
In-Reply-To: <20131107101640.GA2463@minipsycho.orion>


On Nov 7, 2013, at 12:16 AM, Jiri Pirko <jiri@resnulli.us> wrote:

> Thu, Nov 07, 2013 at 10:43:30AM CET, sfeldma@cumulusnetworks.com wrote:
>> Add IFLA_BOND_ARP_IP_TARGET to allow get/set of bonding parameter
>> arp_ip_target via netlink.
>> 
>> Signed-off-by: Scott Feldman <sfeldma@cumulusnetworks.com>
>> ---
>> drivers/net/bonding/bond_netlink.c |   43 ++++++++++++++-
>> drivers/net/bonding/bond_options.c |  102 ++++++++++++++++++++++++++++++++++++
>> drivers/net/bonding/bond_sysfs.c   |   77 +++------------------------
>> drivers/net/bonding/bonding.h      |    3 +
>> include/uapi/linux/if_link.h       |    1 
>> 5 files changed, 155 insertions(+), 71 deletions(-)
>> 
>> diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
>> index 9c50165..e4673ba 100644
>> --- a/drivers/net/bonding/bond_netlink.c
>> +++ b/drivers/net/bonding/bond_netlink.c
>> @@ -29,6 +29,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
>> 	[IFLA_BOND_DOWNDELAY]		= { .type = NLA_U32 },
>> 	[IFLA_BOND_USE_CARRIER]		= { .type = NLA_U8 },
>> 	[IFLA_BOND_ARP_INTERVAL]	= { .type = NLA_U32 },
>> +	[IFLA_BOND_ARP_IP_TARGET]	= { .type = NLA_NESTED },
>> };
>> 
>> static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
>> @@ -109,6 +110,21 @@ static int bond_changelink(struct net_device *bond_dev,
>> 		if (err)
>> 			return err;
>> 	}
>> +	if (data[IFLA_BOND_ARP_IP_TARGET]) {
>> +		struct nlattr *attr;
>> +		int rem;
>> +
>> +		err = bond_option_arp_ip_target_clear_all(bond);
>> +		if (err)
>> +			return err;
>> +
> 
> Hmm. I think this is not correct. I think you should not clear all. They
> might be needed to be used but for a brief moment, they disappear.
> 
> Just set or unset them one by one.

That’s a good catch.  I should compare existing set with new set and retain entries entries common to both sets (and add/remove uncommon ones).

Just to be clear, for netlink, the idea is to push a set of ip targets addrs as a nested attribute and process as a set.  This is consistent with arp_ip_target documentation in Documentation/networking/bonding.txt where arp_ip_target is passed as a comma-separated list of addrs.  However, it’s not consistent with the sysfs interface where addrs are added/removed one at a time using “+” or “-“ prefix.

e.g.:

ip link add bond7 type bond mode 1
ip link set dev bond7 type bond arp_ip_target 10.0.0.1,10.0.0.5
ip link set dev bond7 type bond arp_ip_target 10.0.0.1


>> @@ -141,6 +159,8 @@ static int bond_fill_info(struct sk_buff *skb,
>> {
>> 	struct bonding *bond = netdev_priv(bond_dev);
>> 	struct net_device *slave_dev = bond_option_active_slave_get(bond);
>> +	struct nlattr *targets;
>> +	int i, targets_added;
>> 
>> 	if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode))
>> 		goto nla_put_failure;
>> @@ -152,10 +172,12 @@ static int bond_fill_info(struct sk_buff *skb,
>> 	if (nla_put_u32(skb, IFLA_BOND_MIIMON, bond->params.miimon))
>> 		goto nla_put_failure;
>> 
>> -	if (nla_put_u32(skb, IFLA_BOND_UPDELAY, bond->params.updelay))
>> +	if (nla_put_u32(skb, IFLA_BOND_UPDELAY,
>> +		bond->params.updelay * bond->params.miimon))
>> 		goto nla_put_failure;
> 
> 	This bit should probably no be here :)

Drats, that change goes with earlier patch.  I’ll fix on patch set resend for issue above.

-scott

^ permalink raw reply

* Re: [PATCH net-next 1/8] bonding: add miimon netlink support
From: Veaceslav Falico @ 2013-11-07 10:59 UTC (permalink / raw)
  To: Scott Feldman; +Cc: fubar, andy, netdev, shm
In-Reply-To: <20131107094254.15846.53456.stgit@monster-03.cumulusnetworks.com>

On Thu, Nov 07, 2013 at 01:42:54AM -0800, Scott Feldman wrote:
>Add IFLA_BOND_MIIMON to allow get/set of bonding parameter
>miimon via netlink.
>
>Signed-off-by: Scott Feldman <sfeldma@cumulusnetworks.com>

As it seems you're going to send a V2, so some nitpicks.

>---
> drivers/net/bonding/bond_netlink.c |   32 ++++++++++++++++++----
> drivers/net/bonding/bond_options.c |   42 +++++++++++++++++++++++++++++
> drivers/net/bonding/bond_sysfs.c   |   53 +++++++-----------------------------
> drivers/net/bonding/bonding.h      |    1 +
> include/uapi/linux/if_link.h       |    1 +
> 5 files changed, 80 insertions(+), 49 deletions(-)
>
>diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
>index 40e7b1c..38dd2f1 100644
>--- a/drivers/net/bonding/bond_netlink.c
>+++ b/drivers/net/bonding/bond_netlink.c
>@@ -1,6 +1,7 @@
> /*
>  * drivers/net/bond/bond_netlink.c - Netlink interface for bonding
>  * Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us>
>+ * Copyright (c) 2013 Scott Feldman <sfeldma@cumulusnetworks.com>
>  *
>  * This program is free software; you can redistribute it and/or modify
>  * it under the terms of the GNU General Public License as published by
>@@ -23,6 +24,7 @@
> static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
> 	[IFLA_BOND_MODE]		= { .type = NLA_U8 },
> 	[IFLA_BOND_ACTIVE_SLAVE]	= { .type = NLA_U32 },
>+	[IFLA_BOND_MIIMON]		= { .type = NLA_U32 },
> };
>
> static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
>@@ -42,14 +44,17 @@ static int bond_changelink(struct net_device *bond_dev,
> 	struct bonding *bond = netdev_priv(bond_dev);
> 	int err;
>
>-	if (data && data[IFLA_BOND_MODE]) {
>+	if (!data)
>+		return 0;
>+
>+	if (data[IFLA_BOND_MODE]) {
> 		int mode = nla_get_u8(data[IFLA_BOND_MODE]);
>
> 		err = bond_option_mode_set(bond, mode);
> 		if (err)
> 			return err;
> 	}
>-	if (data && data[IFLA_BOND_ACTIVE_SLAVE]) {
>+	if (data[IFLA_BOND_ACTIVE_SLAVE]) {
> 		int ifindex = nla_get_u32(data[IFLA_BOND_ACTIVE_SLAVE]);
> 		struct net_device *slave_dev;
>
>@@ -65,6 +70,13 @@ static int bond_changelink(struct net_device *bond_dev,
> 		if (err)
> 			return err;
> 	}
>+	if (data[IFLA_BOND_MIIMON]) {
>+		int miimon = nla_get_u32(data[IFLA_BOND_MIIMON]);
>+
>+		err = bond_option_miimon_set(bond, miimon);
>+		if (err)
>+			return err;
>+	}
> 	return 0;
> }
>
>@@ -83,7 +95,9 @@ static int bond_newlink(struct net *src_net, struct net_device *bond_dev,
> static size_t bond_get_size(const struct net_device *bond_dev)
> {
> 	return nla_total_size(sizeof(u8)) +	/* IFLA_BOND_MODE */
>-		nla_total_size(sizeof(u32));	/* IFLA_BOND_ACTIVE_SLAVE */
>+		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_ACTIVE_SLAVE */
>+		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_MIIMON */
>+		0;
> }
>
> static int bond_fill_info(struct sk_buff *skb,
>@@ -92,10 +106,16 @@ static int bond_fill_info(struct sk_buff *skb,
> 	struct bonding *bond = netdev_priv(bond_dev);
> 	struct net_device *slave_dev = bond_option_active_slave_get(bond);
>
>-	if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode) ||
>-	    (slave_dev &&
>-	     nla_put_u32(skb, IFLA_BOND_ACTIVE_SLAVE, slave_dev->ifindex)))
>+	if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode))
> 		goto nla_put_failure;
>+
>+	if (slave_dev &&
>+	     nla_put_u32(skb, IFLA_BOND_ACTIVE_SLAVE, slave_dev->ifindex))
	    ^^^^^^^^^^
Alignment.

>+		goto nla_put_failure;
>+
>+	if (nla_put_u32(skb, IFLA_BOND_MIIMON, bond->params.miimon))
>+		goto nla_put_failure;
>+
> 	return 0;
>
> nla_put_failure:
>diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
>index 9a5223c..eaafab9 100644
>--- a/drivers/net/bonding/bond_options.c
>+++ b/drivers/net/bonding/bond_options.c
>@@ -1,6 +1,7 @@
> /*
>  * drivers/net/bond/bond_options.c - bonding options
>  * Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us>
>+ * Copyright (c) 2013 Scott Feldman <sfeldma@cumulusnetworks.com>
>  *
>  * This program is free software; you can redistribute it and/or modify
>  * it under the terms of the GNU General Public License as published by
>@@ -140,3 +141,44 @@ int bond_option_active_slave_set(struct bonding *bond,
> 	unblock_netpoll_tx();
> 	return ret;
> }
>+
>+int bond_option_miimon_set(struct bonding *bond, int miimon)
>+{
>+	if (miimon < 0) {
>+		pr_err("%s: Invalid miimon value %d not in range %d-%d; rejected.\n",
>+		       bond->dev->name, miimon, 0, INT_MAX);
>+		return -EINVAL;
>+	}
>+	pr_info("%s: Setting MII monitoring interval to %d.\n",
>+		bond->dev->name, miimon);
>+	bond->params.miimon = miimon;
>+	if (bond->params.updelay)
>+		pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n",
>+			bond->dev->name,
>+			bond->params.updelay * bond->params.miimon);
>+	if (bond->params.downdelay)
>+		pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n",
>+			bond->dev->name,
>+			bond->params.downdelay * bond->params.miimon);
>+	if (miimon && bond->params.arp_interval) {
>+		pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n",
>+			bond->dev->name);
>+		bond->params.arp_interval = 0;
>+		if (bond->params.arp_validate)
>+			bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
>+	}
>+	if (bond->dev->flags & IFF_UP) {
>+		/* If the interface is up, we may need to fire off
>+		 * the MII timer. If the interface is down, the
>+		 * timer will get fired off when the open function
>+		 * is called.
>+		 */
>+		if (!miimon) {
>+			cancel_delayed_work_sync(&bond->mii_work);
>+		} else {
>+			cancel_delayed_work_sync(&bond->arp_work);
>+			queue_delayed_work(bond->wq, &bond->mii_work, 0);
>+		}
>+	}
>+	return 0;
>+}
>diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
>index 47749c9..2fb9777 100644
>--- a/drivers/net/bonding/bond_sysfs.c
>+++ b/drivers/net/bonding/bond_sysfs.c
>@@ -981,55 +981,22 @@ static ssize_t bonding_store_miimon(struct device *d,
> 				    struct device_attribute *attr,
> 				    const char *buf, size_t count)
> {
>-	int new_value, ret = count;
>+	int new_value, ret;
> 	struct bonding *bond = to_bond(d);
>
>-	if (!rtnl_trylock())
>-		return restart_syscall();
> 	if (sscanf(buf, "%d", &new_value) != 1) {
> 		pr_err("%s: no miimon value specified.\n",
> 		       bond->dev->name);
>-		ret = -EINVAL;
>-		goto out;
>-	}
>-	if (new_value < 0) {
>-		pr_err("%s: Invalid miimon value %d not in range %d-%d; rejected.\n",
>-		       bond->dev->name, new_value, 0, INT_MAX);
>-		ret = -EINVAL;
>-		goto out;
>-	}
>-	pr_info("%s: Setting MII monitoring interval to %d.\n",
>-		bond->dev->name, new_value);
>-	bond->params.miimon = new_value;
>-	if (bond->params.updelay)
>-		pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n",
>-			bond->dev->name,
>-			bond->params.updelay * bond->params.miimon);
>-	if (bond->params.downdelay)
>-		pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n",
>-			bond->dev->name,
>-			bond->params.downdelay * bond->params.miimon);
>-	if (new_value && bond->params.arp_interval) {
>-		pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n",
>-			bond->dev->name);
>-		bond->params.arp_interval = 0;
>-		if (bond->params.arp_validate)
>-			bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
>-	}
>-	if (bond->dev->flags & IFF_UP) {
>-		/* If the interface is up, we may need to fire off
>-		 * the MII timer. If the interface is down, the
>-		 * timer will get fired off when the open function
>-		 * is called.
>-		 */
>-		if (!new_value) {
>-			cancel_delayed_work_sync(&bond->mii_work);
>-		} else {
>-			cancel_delayed_work_sync(&bond->arp_work);
>-			queue_delayed_work(bond->wq, &bond->mii_work, 0);
>-		}
>+		return -EINVAL;
> 	}
>-out:
>+
>+	if (!rtnl_trylock())
>+		return restart_syscall();
>+
>+	ret = bond_option_miimon_set(bond, new_value);
>+	if (!ret)
>+		ret = count;
>+
> 	rtnl_unlock();
> 	return ret;
> }
>diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
>index 046a605..91d7eae 100644
>--- a/drivers/net/bonding/bonding.h
>+++ b/drivers/net/bonding/bonding.h
>@@ -428,6 +428,7 @@ int bond_netlink_init(void);
> void bond_netlink_fini(void);
> int bond_option_mode_set(struct bonding *bond, int mode);
> int bond_option_active_slave_set(struct bonding *bond, struct net_device *slave_dev);
>+int bond_option_miimon_set(struct bonding *bond, int miimon);
> struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
> struct net_device *bond_option_active_slave_get(struct bonding *bond);
>
>diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
>index b78566f..b38472b 100644
>--- a/include/uapi/linux/if_link.h
>+++ b/include/uapi/linux/if_link.h
>@@ -331,6 +331,7 @@ enum {
> 	IFLA_BOND_UNSPEC,
> 	IFLA_BOND_MODE,
> 	IFLA_BOND_ACTIVE_SLAVE,
>+	IFLA_BOND_MIIMON,
> 	__IFLA_BOND_MAX,
> };
>
>

^ permalink raw reply

* Re: [PATCH net-next 3/8] bonding: add downdelay netlink support
From: Veaceslav Falico @ 2013-11-07 11:02 UTC (permalink / raw)
  To: Scott Feldman; +Cc: fubar, andy, netdev, shm
In-Reply-To: <20131107094308.15846.58301.stgit@monster-03.cumulusnetworks.com>

On Thu, Nov 07, 2013 at 01:43:08AM -0800, Scott Feldman wrote:
>Add IFLA_BOND_DOWNDELAY to allow get/set of bonding parameter
>downdelay via netlink.
>
>Signed-off-by: Scott Feldman <sfeldma@cumulusnetworks.com>
>---
> drivers/net/bonding/bond_netlink.c |   12 +++++++++++
> drivers/net/bonding/bond_options.c |   29 +++++++++++++++++++++++++++
> drivers/net/bonding/bond_sysfs.c   |   38 +++++++++---------------------------
> drivers/net/bonding/bonding.h      |    1 +
> include/uapi/linux/if_link.h       |    1 +
> 5 files changed, 52 insertions(+), 29 deletions(-)
>
>diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
>index 9ba5431..e684713 100644
>--- a/drivers/net/bonding/bond_netlink.c
>+++ b/drivers/net/bonding/bond_netlink.c
>@@ -26,6 +26,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
> 	[IFLA_BOND_ACTIVE_SLAVE]	= { .type = NLA_U32 },
> 	[IFLA_BOND_MIIMON]		= { .type = NLA_U32 },
> 	[IFLA_BOND_UPDELAY]		= { .type = NLA_U32 },
>+	[IFLA_BOND_DOWNDELAY]		= { .type = NLA_U32 },
> };
>
> static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
>@@ -85,6 +86,13 @@ static int bond_changelink(struct net_device *bond_dev,
> 		if (err)
> 			return err;
> 	}
>+	if (data[IFLA_BOND_DOWNDELAY]) {
>+		int downdelay = nla_get_u32(data[IFLA_BOND_DOWNDELAY]);
>+
>+		err = bond_option_downdelay_set(bond, downdelay);
>+		if (err)
>+			return err;
>+	}
> 	return 0;
> }
>
>@@ -106,6 +114,7 @@ static size_t bond_get_size(const struct net_device *bond_dev)
> 		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_ACTIVE_SLAVE */
> 		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_MIIMON */
> 		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_UPDELAY */
>+		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_DOWNDELAY */
> 		0;
> }
>
>@@ -128,6 +137,9 @@ static int bond_fill_info(struct sk_buff *skb,
> 	if (nla_put_u32(skb, IFLA_BOND_UPDELAY, bond->params.updelay))
> 		goto nla_put_failure;
>
>+	if (nla_put_u32(skb, IFLA_BOND_DOWNDELAY, bond->params.downdelay))
>+		goto nla_put_failure;
>+
> 	return 0;
>
> nla_put_failure:
>diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
>index c0fea66..738be5f 100644
>--- a/drivers/net/bonding/bond_options.c
>+++ b/drivers/net/bonding/bond_options.c
>@@ -211,3 +211,32 @@ int bond_option_updelay_set(struct bonding *bond, int updelay)
>
> 	return 0;
> }
>+
>+int bond_option_downdelay_set(struct bonding *bond, int downdelay)
>+{
>+	if (!(bond->params.miimon)) {
>+		pr_err("%s: Unable to set down delay as MII monitoring is disabled\n", bond->dev->name);

Maybe get bond->dev->name on the next line?

>+		return -EPERM;
>+	}
>+
>+	if (downdelay < 0) {
>+		pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n",
>+		       bond->dev->name, downdelay, 0, INT_MAX);
>+		return -EINVAL;
>+	} else {
>+		if ((downdelay % bond->params.miimon) != 0) {
>+			pr_warn("%s: Warning: down delay (%d) is not a multiple of miimon (%d), delay rounded to %d ms\n",
>+				bond->dev->name, downdelay,
>+				bond->params.miimon,
>+				(downdelay / bond->params.miimon) *
>+				bond->params.miimon);
>+		}
>+		bond->params.downdelay = downdelay / bond->params.miimon;
>+		pr_info("%s: Setting down delay to %d.\n",
>+			bond->dev->name,
>+			bond->params.downdelay * bond->params.miimon);
>+
>+	}
>+
>+	return 0;
>+}
>diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
>index 1125bef..41a62ac 100644
>--- a/drivers/net/bonding/bond_sysfs.c
>+++ b/drivers/net/bonding/bond_sysfs.c
>@@ -706,42 +706,22 @@ static ssize_t bonding_store_downdelay(struct device *d,
> 				       struct device_attribute *attr,
> 				       const char *buf, size_t count)
> {
>-	int new_value, ret = count;
>+	int new_value, ret;
> 	struct bonding *bond = to_bond(d);
>
>-	if (!(bond->params.miimon)) {
>-		pr_err("%s: Unable to set down delay as MII monitoring is disabled\n",
>-		       bond->dev->name);
>-		ret = -EPERM;
>-		goto out;
>-	}
>-
> 	if (sscanf(buf, "%d", &new_value) != 1) {
> 		pr_err("%s: no down delay value specified.\n", bond->dev->name);
>-		ret = -EINVAL;
>-		goto out;
>+		return -EINVAL;
> 	}
>-	if (new_value < 0) {
>-		pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n",
>-		       bond->dev->name, new_value, 0, INT_MAX);
>-		ret = -EINVAL;
>-		goto out;
>-	} else {
>-		if ((new_value % bond->params.miimon) != 0) {
>-			pr_warning("%s: Warning: down delay (%d) is not a multiple of miimon (%d), delay rounded to %d ms\n",
>-				   bond->dev->name, new_value,
>-				   bond->params.miimon,
>-				   (new_value / bond->params.miimon) *
>-				   bond->params.miimon);
>-		}
>-		bond->params.downdelay = new_value / bond->params.miimon;
>-		pr_info("%s: Setting down delay to %d.\n",
>-			bond->dev->name,
>-			bond->params.downdelay * bond->params.miimon);
>
>-	}
>+	if (!rtnl_trylock())
>+		return restart_syscall();
>
>-out:
>+	ret = bond_option_downdelay_set(bond, new_value);
>+	if (!ret)
>+		ret = count;
>+
>+	rtnl_unlock();
> 	return ret;
> }
> static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR,
>diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
>index 408e6c2..40987f3 100644
>--- a/drivers/net/bonding/bonding.h
>+++ b/drivers/net/bonding/bonding.h
>@@ -430,6 +430,7 @@ int bond_option_mode_set(struct bonding *bond, int mode);
> int bond_option_active_slave_set(struct bonding *bond, struct net_device *slave_dev);
> int bond_option_miimon_set(struct bonding *bond, int miimon);
> int bond_option_updelay_set(struct bonding *bond, int updelay);
>+int bond_option_downdelay_set(struct bonding *bond, int downdelay);
> struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
> struct net_device *bond_option_active_slave_get(struct bonding *bond);
>
>diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
>index 361414e..a372831 100644
>--- a/include/uapi/linux/if_link.h
>+++ b/include/uapi/linux/if_link.h
>@@ -333,6 +333,7 @@ enum {
> 	IFLA_BOND_ACTIVE_SLAVE,
> 	IFLA_BOND_MIIMON,
> 	IFLA_BOND_UPDELAY,
>+	IFLA_BOND_DOWNDELAY,
> 	__IFLA_BOND_MAX,
> };
>
>

^ permalink raw reply

* [PATCH v2] net: calxedaxgmac: Fix panic caused by MTU change of active interface
From: Andreas Herrmann @ 2013-11-07 11:07 UTC (permalink / raw)
  To: Rob Herring; +Cc: Ben Hutchings, Grant Likely, David S. Miller, netdev
In-Reply-To: <20131106133126.GL22917@alberich>

Changing MTU size of an xgmac network interface while it is active can
cause a panic like

  skbuff: skb_over_panic: text:c03bc62c len:1090 put:1090 head:edfb6900 data:edfb6942 tail:0xedfb6d84 end:0xedfb6bc0 dev:eth0
  ------------[ cut here ]------------
  kernel BUG at net/core/skbuff.c:126!
  Internal error: Oops - BUG: 0 [#1] SMP ARM
  Modules linked in:
  CPU: 0 PID: 762 Comm: python Tainted: G        W    3.10.0-00015-g3e33cd7 #309
  task: edcfe000 ti: ed67e000 task.ti: ed67e000
  PC is at skb_panic+0x64/0x70
  LR is at wake_up_klogd+0x5c/0x68

This happens because xgmac_change_mtu modifies dev->mtu before the
network interface is quiesced. And thus there still might be buffers
in use which have a buffer size based on the old MTU.

To fix this I moved the change of dev->mtu after the call to
xgmac_stop.

Another modification is required (in xgmac_stop) to ensure that
xgmac_xmit is really not called anymore (xgmac_tx_complete might wake
up the queue again).

I've tested the fix by switching MTU size every second between 600 and
1500 while network traffic was going on. The test box survived a test
of several hours (until I've stopped it) whereas w/o this fix above
panic occurs after several minutes (at most).

Change since v1:
- remove call to netif_stop_queue at beginning of xgmac_stop
- use netif_tx_disable instead of locking+netif_stop_queue

Signed-off-by: Andreas Herrmann <andreas.herrmann@calxeda.com>
---
 drivers/net/ethernet/calxeda/xgmac.c |   10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

Patch is against v3.12-1714-gaafc090.


Regards,
Andreas

diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index 48f5288..4fc5c8e 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -1060,13 +1060,13 @@ static int xgmac_stop(struct net_device *dev)
 {
 	struct xgmac_priv *priv = netdev_priv(dev);
 
-	netif_stop_queue(dev);
-
 	if (readl(priv->base + XGMAC_DMA_INTR_ENA))
 		napi_disable(&priv->napi);
 
 	writel(0, priv->base + XGMAC_DMA_INTR_ENA);
 
+	netif_tx_disable(dev);
+
 	/* Disable the MAC core */
 	xgmac_mac_disable(priv->base);
 
@@ -1370,11 +1370,8 @@ static int xgmac_change_mtu(struct net_device *dev, int new_mtu)
 	}
 
 	old_mtu = dev->mtu;
-	dev->mtu = new_mtu;
 
 	/* return early if the buffer sizes will not change */
-	if (old_mtu <= ETH_DATA_LEN && new_mtu <= ETH_DATA_LEN)
-		return 0;
 	if (old_mtu == new_mtu)
 		return 0;
 
@@ -1382,8 +1379,9 @@ static int xgmac_change_mtu(struct net_device *dev, int new_mtu)
 	if (!netif_running(dev))
 		return 0;
 
-	/* Bring the interface down and then back up */
+	/* Bring interface down, change mtu and bring interface back up */
 	xgmac_stop(dev);
+	dev->mtu = new_mtu;
 	return xgmac_open(dev);
 }
 
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH net-next 8/8] bonding: add arp_all_targets netlink support
From: Veaceslav Falico @ 2013-11-07 11:08 UTC (permalink / raw)
  To: Scott Feldman; +Cc: fubar, andy, netdev, shm
In-Reply-To: <20131107094344.15846.93348.stgit@monster-03.cumulusnetworks.com>

On Thu, Nov 07, 2013 at 01:43:44AM -0800, Scott Feldman wrote:
>Add IFLA_BOND_ARP_ALL_TARGETS to allow get/set of bonding parameter
>arp_all_targets via netlink.
>
>Signed-off-by: Scott Feldman <sfeldma@cumulusnetworks.com>
>---
> drivers/net/bonding/bond_netlink.c |   14 ++++++++++++++
> drivers/net/bonding/bond_options.c |   11 +++++++++++
> drivers/net/bonding/bond_sysfs.c   |   16 ++++++++++------
> drivers/net/bonding/bonding.h      |    1 +
> include/uapi/linux/if_link.h       |    1 +
> 5 files changed, 37 insertions(+), 6 deletions(-)
>
>diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
>index a5ca6e0..818a7ba 100644
>--- a/drivers/net/bonding/bond_netlink.c
>+++ b/drivers/net/bonding/bond_netlink.c
>@@ -31,6 +31,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
> 	[IFLA_BOND_ARP_INTERVAL]	= { .type = NLA_U32 },
> 	[IFLA_BOND_ARP_IP_TARGET]	= { .type = NLA_NESTED },
> 	[IFLA_BOND_ARP_VALIDATE]	= { .type = NLA_U32 },
>+	[IFLA_BOND_ARP_ALL_TARGETS]	= { .type = NLA_U32 },
> };
>
> static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
>@@ -133,6 +134,14 @@ static int bond_changelink(struct net_device *bond_dev,
> 		if (err)
> 			return err;
> 	}
>+	if (data[IFLA_BOND_ARP_ALL_TARGETS]) {
>+		int arp_all_targets =
>+			nla_get_u32(data[IFLA_BOND_ARP_ALL_TARGETS]);
>+
>+		err = bond_option_arp_all_targets_set(bond, arp_all_targets);
>+		if (err)
>+			return err;
>+	}
> 	return 0;
> }
>
>@@ -160,6 +169,7 @@ static size_t bond_get_size(const struct net_device *bond_dev)
> 						/* IFLA_BOND_ARP_IP_TARGET */
> 		nla_total_size(sizeof(u32)) * BOND_MAX_ARP_TARGETS +
> 		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_ARP_VALIDATE */
>+		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_ARP_ALL_TARGETS */
> 		0;
> }
>
>@@ -215,6 +225,10 @@ static int bond_fill_info(struct sk_buff *skb,
> 	if (nla_put_u32(skb, IFLA_BOND_ARP_VALIDATE, bond->params.arp_validate))
> 		goto nla_put_failure;
>
>+	if (nla_put_u32(skb, IFLA_BOND_ARP_ALL_TARGETS,
>+		bond->params.arp_all_targets))

One more tab to align?

>+		goto nla_put_failure;
>+
> 	return 0;
>
> nla_put_failure:
>diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
>index 9c36215..543a318 100644
>--- a/drivers/net/bonding/bond_options.c
>+++ b/drivers/net/bonding/bond_options.c
>@@ -426,3 +426,14 @@ int bond_option_arp_validate_set(struct bonding *bond, int arp_validate)
>
> 	return 0;
> }
>+
>+int bond_option_arp_all_targets_set(struct bonding *bond, int arp_all_targets)
>+{
>+	pr_info("%s: setting arp_all_targets to %s (%d).\n",
>+		bond->dev->name, arp_all_targets_tbl[arp_all_targets].modename,
>+		arp_all_targets);
>+
>+	bond->params.arp_all_targets = arp_all_targets;
>+
>+	return 0;
>+}
>diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
>index 8a35440..a3cd27e 100644
>--- a/drivers/net/bonding/bond_sysfs.c
>+++ b/drivers/net/bonding/bond_sysfs.c
>@@ -408,7 +408,7 @@ static ssize_t bonding_store_arp_all_targets(struct device *d,
> 					  const char *buf, size_t count)
> {
> 	struct bonding *bond = to_bond(d);
>-	int new_value;
>+	int new_value, ret;
>
> 	new_value = bond_parse_parm(buf, arp_all_targets_tbl);
> 	if (new_value < 0) {
>@@ -416,13 +416,17 @@ static ssize_t bonding_store_arp_all_targets(struct device *d,
> 		       bond->dev->name, buf);
> 		return -EINVAL;
> 	}
>-	pr_info("%s: setting arp_all_targets to %s (%d).\n",
>-		bond->dev->name, arp_all_targets_tbl[new_value].modename,
>-		new_value);
>
>-	bond->params.arp_all_targets = new_value;
>+	if (!rtnl_trylock())
>+		return restart_syscall();
>
>-	return count;
>+	ret = bond_option_arp_all_targets_set(bond, new_value);
>+	if (!ret)
>+		ret = count;
>+
>+	rtnl_unlock();
>+
>+	return ret;
> }
>
> static DEVICE_ATTR(arp_all_targets, S_IRUGO | S_IWUSR,
>diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
>index 77bbd71..ed35c8c 100644
>--- a/drivers/net/bonding/bonding.h
>+++ b/drivers/net/bonding/bonding.h
>@@ -437,6 +437,7 @@ int bond_option_arp_ip_target_set(struct bonding *bond, __be32 target);
> int bond_option_arp_ip_target_unset(struct bonding *bond, __be32 target);
> int bond_option_arp_ip_target_clear_all(struct bonding *bond);
> int bond_option_arp_validate_set(struct bonding *bond, int arp_validate);
>+int bond_option_arp_all_targets_set(struct bonding *bond, int arp_all_targets);
> struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
> struct net_device *bond_option_active_slave_get(struct bonding *bond);
>
>diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
>index c17f801..ca01850 100644
>--- a/include/uapi/linux/if_link.h
>+++ b/include/uapi/linux/if_link.h
>@@ -338,6 +338,7 @@ enum {
> 	IFLA_BOND_ARP_INTERVAL,
> 	IFLA_BOND_ARP_IP_TARGET,
> 	IFLA_BOND_ARP_VALIDATE,
>+	IFLA_BOND_ARP_ALL_TARGETS,
> 	__IFLA_BOND_MAX,
> };
>
>

^ permalink raw reply

* BCM57786 driver
From: Joshua Richenhagen @ 2013-11-07 11:12 UTC (permalink / raw)
  To: netdev

Hello everyone,

I recently bought a Acer Aspire E1-572 notebook with the gigabit
ethernet controller Broadcom Corporation NetXtreme BCM57786 builtin.
However I can't get it working under Ubuntu, neither with standard
kernel nor with newest mainline kernel 3.12 final. I doesn't seem to
be recognized at all, does a driver for this chip exists, or do I have
to wait till one gets released? How far is the developmend process?

Thanks in advance
Joshua

^ permalink raw reply

* [PATCH iproute2] bridge: trivial: Fix typo in error message (hairpin)
From: Guillaume Nault @ 2013-11-07 11:09 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev

Option name is hairpin (without 'g').

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
---
 bridge/link.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bridge/link.c b/bridge/link.c
index 38dfaea..a82cce0 100644
--- a/bridge/link.c
+++ b/bridge/link.c
@@ -271,7 +271,7 @@ static int brlink_modify(int argc, char **argv)
 				exit(-1);
 		} else if (strcmp(*argv, "hairpin") == 0) {
 			NEXT_ARG();
-			if (!on_off("hairping", &hairpin, *argv))
+			if (!on_off("hairpin", &hairpin, *argv))
 				exit(-1);
 		} else if (strcmp(*argv, "fastleave") == 0) {
 			NEXT_ARG();
-- 
1.8.4.2

^ permalink raw reply related

* Re: [PATCH net v3] vti: fix spd lookup: match plaintext pkt, not ipsec pkt
From: Steffen Klassert @ 2013-11-07 11:25 UTC (permalink / raw)
  To: Christophe Gouault
  Cc: David S. Miller, Herbert Xu, netdev, Saurabh Mohan,
	Sergei Shtylyov, Eric Dumazet
In-Reply-To: <1383725153-26298-1-git-send-email-christophe.gouault@6wind.com>

On Wed, Nov 06, 2013 at 09:05:53AM +0100, Christophe Gouault wrote:
> The vti interface inbound and outbound SPD lookups are based on the
> ipsec packet instead of the plaintext packet.
> 
> Not only is it counterintuitive, it also restricts vti interfaces
> to a single policy (whose selector must match the tunnel local and
> remote addresses).
> 
> The policy selector is supposed to match the plaintext packet, before
> encryption or after decryption.
> 
> This patch performs the SPD lookup based on the plaintext packet. It
> enables to create several polices bound to the vti interface (via a
> mark equal to the vti interface okey).
> 
> It remains possible to apply the same policy to all packets entering
> the vti interface, by setting an any-to-any selector (src 0.0.0.0/0
> dst 0.0.0.0/0 proto any mark OKEY).
> 
> Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>

Hm, this patch breaks my current vti test setup. I would need to
configure the policies and states dependent on the kernel version
if we apply this patch...

It would be good to hear from the original author of the vti code
whether the current behaviour is intentional before we do anything
here.

^ permalink raw reply

* Re: [patch] net: make ndev->irq signed for error handling
From: Mugunthan V N @ 2013-11-07 12:14 UTC (permalink / raw)
  To: Dan Carpenter, David S. Miller; +Cc: netdev, linux-kernel, kernel-janitors
In-Reply-To: <20131107074849.GF21844@elgon.mountain>

On Thursday 07 November 2013 01:18 PM, Dan Carpenter wrote:
> There is a bug in cpsw_probe() where we do:
>
> 	ndev->irq = platform_get_irq(pdev, 0);
> 	if (ndev->irq < 0) {
>
> The problem is that "ndev->irq" is unsigned so the error handling
> doesn't work.  I have changed it to a regular int.
>
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
ndev->irq is never used any where in the driver, I think its better to
remove this part of code from probe. If every one is ok, I can send a
patch to remove the code.

Regards
Mugunthan V N

^ permalink raw reply

* xen-netback stable backport requests
From: Ian Campbell @ 2013-11-07 12:15 UTC (permalink / raw)
  To: David Miller; +Cc: xen-devel, netdev, stable

Hi Dave,

279f438e36c0 "xen-netback: Don't destroy the netdev until the vif is
shut down" has hit stable but unfortunately is causing regressions. 

This should be fixed by dc62ccaccfb1 "xen-netback: transition to CLOSED
when removing a VIF" which depends on ea732dff5cfa "xen-netback: Handle
backend state transitions in a more robust way".

Please could you queue hose two for stable.

Thanks,
Ian.

^ permalink raw reply

* xen-netback regression in 3.10.18
From: David Vrabel @ 2013-11-07 12:15 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: stable@vger.kernel.org, David S. Miller, Paul Durrant,
	Ian Campbell, Wei Liu

3.10.18 included 279f438e36c0 (xen-netback: Don't destroy the netdev
until the vif is shut down) but this has a regression that was fixed by
dc62ccaccfb1 (xen-netback: transition to CLOSED when removing a VIF)

dc62ccaccfb1 depends on ea732dff5cfa (xen-netback: Handle backend state
transitions in a more robust way) which is also a bug fix for certain
Windows frontend drivers and is thus also a stable candidate.

Dave can you ensure these two commits are tagged for the next 3.10.y
stable release?

  ea732dff5cfa10789007bf4a5b935388a0bb2a8f
  dc62ccaccfb139d9b04bbc5a2688a4402adbfab3

Thanks.

David

^ permalink raw reply

* Re: ipv6: a question about ECMP
From: Hannes Frederic Sowa @ 2013-11-07 12:16 UTC (permalink / raw)
  To: Duan Jiong; +Cc: David Miller, nicolas.dichtel, netdev
In-Reply-To: <527B6C70.3010507@cn.fujitsu.com>

Hi Duan!

On Thu, Nov 07, 2013 at 06:33:20PM +0800, Duan Jiong wrote:
>   After reading the ip6_pol_route(), i have a question about ECMP. Why we call
> the rt6_multipath_select() after calling rt6_select()?
>   In my opinion, the route returned by rt6_select() has a highest score, but the route
> returned by rt6_multipath_select() may has a lower score than the former, because the
> ECMP don't take the route preference into consideration. That means that the kernel will
> choose a less-desirable route.

ECMP routes only differ in the gateway the specify, so I doubt there will be
any change in the score they woud receive. rt6_multipath_select does merly
make sure we don't select the same route again and again.

Please note, the rt6_info's siblings fields were added for the solely purpose
of ECMP and the insertion only updates the siblings list if the above criteria
did hold. They make sure the routes lookup up do differ on each lookup, so it
does actually do multipath and does not depend on the order the routes where
inserted.

Hope that helps,

  Hannes

^ permalink raw reply

* Re: [PATCH] ipv6: replace RTF_ROUTEINFO with RTF_ADDRCONF in  rt6_get_route_info()
From: Hannes Frederic Sowa @ 2013-11-07 12:19 UTC (permalink / raw)
  To: Duan Jiong; +Cc: David Miller, netdev
In-Reply-To: <527B14B9.7040305@cn.fujitsu.com>

On Thu, Nov 07, 2013 at 12:19:05PM +0800, Duan Jiong wrote:
> 于 2013年11月07日 10:42, Hannes Frederic Sowa 写道:
> > On Thu, Nov 07, 2013 at 10:01:27AM +0800, Duan Jiong wrote:
> >> 于 2013年11月07日 09:51, Hannes Frederic Sowa 写道:
> >>> On Wed, Nov 06, 2013 at 03:26:41PM +0800, Duan Jiong wrote:
> >>>>
> >>>> As the rfc 4191 said, the Router Preference and Lifetime values in a
> >>>> ::/0 Route Information Option should override the preference and lifetime
> >>>> values in the Router Advertisement header. But when the kernel deals with
> >>>> a ::/0 Route Information Option, the rt6_get_route_info() always return
> >>>> NULL, that means that overriding will not happen, because those default
> >>>> routers were added without flag RTF_ROUTEINFO in rt6_add_dflt_router().
> >>>>
> >>>> In order to match those default routers, we can replace RTF_ROUTEINFO 
> >>>> with RTF_ADDRCONF in rt6_get_route_info().
> >>>>
> >>>> Signed-off-by: Duan Jiong <duanj.fnst@cn.fujitsu.com>
> >>>
> >>> Hmm, that looks like a bug. Nice catch!
> >>>
> >>> Couldn't we just replace the rt6_get_route_info in rt6_route_rcv with a call
> >>> to rt6_get_dflt_router? Seems easier, already handles the ::/0 case and also
> >>> does preserve the check for the RTF_ROUTEINFO flag in rt6_add_route_info.
> >>
> >> Yeah, your idea is better. I will modify my patch.
> > 
> > Stop, stop, stop, sorry that suggestion is plain wrong and stupid.
> > 
> 
> In my opinion, i think that is well. According to your suggestion, we can 
> call the rt6_get_dflt_router or rt6_get_route_info in different situation.
> 
> if (rinfo->prefix_len == 0)
> 	rt = rt6_get_dflt_router(gwaddr, dev);
> else
> 	rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr,
> 				dev->ifindex);

That's perfect.

Greetings,

  Hannes

^ permalink raw reply

* Re: [patch] net: make ndev->irq signed for error handling
From: Dan Carpenter @ 2013-11-07 12:22 UTC (permalink / raw)
  To: Mugunthan V N; +Cc: David S. Miller, netdev, linux-kernel, kernel-janitors
In-Reply-To: <527B842E.2060909@ti.com>

On Thu, Nov 07, 2013 at 05:44:38PM +0530, Mugunthan V N wrote:
> On Thursday 07 November 2013 01:18 PM, Dan Carpenter wrote:
> > There is a bug in cpsw_probe() where we do:
> >
> > 	ndev->irq = platform_get_irq(pdev, 0);
> > 	if (ndev->irq < 0) {
> >
> > The problem is that "ndev->irq" is unsigned so the error handling
> > doesn't work.  I have changed it to a regular int.
> >
> > Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ndev->irq is never used any where in the driver, I think its better to
> remove this part of code from probe. If every one is ok, I can send a
> patch to remove the code.

It seems like cpsw_ndo_poll_controller() uses it.

regards,
dan carpenter

^ permalink raw reply

* Re: BCM57786 driver
From: Peter Meerwald @ 2013-11-07 12:36 UTC (permalink / raw)
  To: Joshua Richenhagen; +Cc: netdev
In-Reply-To: <CAJZ9B5s87PHb3=eAxOy1dDo59Tq8pQbR78-=_zyKt8-0g5tGdg@mail.gmail.com>

Hi,

> I recently bought a Acer Aspire E1-572 notebook with the gigabit
> ethernet controller Broadcom Corporation NetXtreme BCM57786 builtin.
> However I can't get it working under Ubuntu, neither with standard
> kernel nor with newest mainline kernel 3.12 final. I doesn't seem to
> be recognized at all, does a driver for this chip exists, or do I have
> to wait till one gets released? How far is the developmend process?

I have the same notebook and reported to the Ubuntu bug tracker 
(https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1182868)
solution for me is to add the PCI vendor/product IDs to the tg3 driver

there seems to be a fix in the upstream kernel, see 
http://patchwork.ozlabs.org/patch/276813/
already

hope the Ubuntu folk act on this

regards, p.


-- 

Peter Meerwald
+43-664-2444418 (mobile)

^ permalink raw reply

* Re: [patch net-next 2/2] netfilter: push reasm skb through instead of original frag skbs
From: Marcelo Ricardo Leitner @ 2013-11-07 12:52 UTC (permalink / raw)
  To: Jiri Pirko, netdev
  Cc: davem, pablo, netfilter-devel, yoshfuji, kadlec, kaber, kuznet,
	jmorris, wensong, horms, ja, edumazet, pshelar, jasowang,
	alexander.h.duyck, fw
In-Reply-To: <1383756740-7392-3-git-send-email-jiri@resnulli.us>

Em 06-11-2013 14:52, Jiri Pirko escreveu:
> Pushing original fragments through causes several problems. For example
> for matching, frags may not be matched correctly. Take following
> example:
>
> <example>
> On HOSTA do:
> ip6tables -I INPUT -p icmpv6 -j DROP
> ip6tables -I INPUT -p icmpv6 -m icmp6 --icmpv6-type 128 -j ACCEPT
>
> and on HOSTB you do:
> ping6 HOSTA -s2000    (MTU is 1500)
>
> Incoming echo requests will be filtered out on HOSTA. This issue does
> not occur with smaller packets than MTU (where fragmentation does not happen)
> </example>
>
> As was discussed previously, the only correct solution seems to be to use
> reassembled skb instead of separete frags. Doing this has positive side
          just a typo here   ------^

> effects in reducing sk_buff by one pointer (nfct_reasm) and also the reams
                                                          and here   ------^

> dances in ipvs and conntrack can be removed.
>
> Future plan is to remove net/ipv6/netfilter/nf_conntrack_reasm.c
> entirely and use code in net/ipv6/reassembly.c instead.
>
> Signed-off-by: Jiri Pirko <jiri@resnulli.us>

Signed-off-by: Marcelo Ricardo Leitner <mleitner@redhat.com>

> ---
>   include/linux/skbuff.h                         | 32 ---------------
>   include/net/ip_vs.h                            | 32 +--------------
>   include/net/netfilter/ipv6/nf_defrag_ipv6.h    |  4 +-
>   net/core/skbuff.c                              |  3 --
>   net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 56 +-------------------------
>   net/ipv6/netfilter/nf_conntrack_reasm.c        | 19 +--------
>   net/ipv6/netfilter/nf_defrag_ipv6_hooks.c      |  7 +++-
>   net/netfilter/ipvs/ip_vs_core.c                | 55 +------------------------
>   net/netfilter/ipvs/ip_vs_pe_sip.c              |  8 +---
>   9 files changed, 13 insertions(+), 203 deletions(-)
>
> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> index 2e153b6..8351614 100644
> --- a/include/linux/skbuff.h
> +++ b/include/linux/skbuff.h
> @@ -337,11 +337,6 @@ typedef unsigned int sk_buff_data_t;
>   typedef unsigned char *sk_buff_data_t;
>   #endif
>
> -#if defined(CONFIG_NF_DEFRAG_IPV4) || defined(CONFIG_NF_DEFRAG_IPV4_MODULE) || \
> -    defined(CONFIG_NF_DEFRAG_IPV6) || defined(CONFIG_NF_DEFRAG_IPV6_MODULE)
> -#define NET_SKBUFF_NF_DEFRAG_NEEDED 1
> -#endif
> -
>   /**
>    *	struct sk_buff - socket buffer
>    *	@next: Next buffer in list
> @@ -374,7 +369,6 @@ typedef unsigned char *sk_buff_data_t;
>    *	@protocol: Packet protocol from driver
>    *	@destructor: Destruct function
>    *	@nfct: Associated connection, if any
> - *	@nfct_reasm: netfilter conntrack re-assembly pointer
>    *	@nf_bridge: Saved data about a bridged frame - see br_netfilter.c
>    *	@skb_iif: ifindex of device we arrived on
>    *	@tc_index: Traffic control index
> @@ -463,9 +457,6 @@ struct sk_buff {
>   #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
>   	struct nf_conntrack	*nfct;
>   #endif
> -#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
> -	struct sk_buff		*nfct_reasm;
> -#endif
>   #ifdef CONFIG_BRIDGE_NETFILTER
>   	struct nf_bridge_info	*nf_bridge;
>   #endif
> @@ -2594,18 +2585,6 @@ static inline void nf_conntrack_get(struct nf_conntrack *nfct)
>   		atomic_inc(&nfct->use);
>   }
>   #endif
> -#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
> -static inline void nf_conntrack_get_reasm(struct sk_buff *skb)
> -{
> -	if (skb)
> -		atomic_inc(&skb->users);
> -}
> -static inline void nf_conntrack_put_reasm(struct sk_buff *skb)
> -{
> -	if (skb)
> -		kfree_skb(skb);
> -}
> -#endif
>   #ifdef CONFIG_BRIDGE_NETFILTER
>   static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge)
>   {
> @@ -2624,10 +2603,6 @@ static inline void nf_reset(struct sk_buff *skb)
>   	nf_conntrack_put(skb->nfct);
>   	skb->nfct = NULL;
>   #endif
> -#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
> -	nf_conntrack_put_reasm(skb->nfct_reasm);
> -	skb->nfct_reasm = NULL;
> -#endif
>   #ifdef CONFIG_BRIDGE_NETFILTER
>   	nf_bridge_put(skb->nf_bridge);
>   	skb->nf_bridge = NULL;
> @@ -2649,10 +2624,6 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
>   	nf_conntrack_get(src->nfct);
>   	dst->nfctinfo = src->nfctinfo;
>   #endif
> -#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
> -	dst->nfct_reasm = src->nfct_reasm;
> -	nf_conntrack_get_reasm(src->nfct_reasm);
> -#endif
>   #ifdef CONFIG_BRIDGE_NETFILTER
>   	dst->nf_bridge  = src->nf_bridge;
>   	nf_bridge_get(src->nf_bridge);
> @@ -2664,9 +2635,6 @@ static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
>   #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
>   	nf_conntrack_put(dst->nfct);
>   #endif
> -#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
> -	nf_conntrack_put_reasm(dst->nfct_reasm);
> -#endif
>   #ifdef CONFIG_BRIDGE_NETFILTER
>   	nf_bridge_put(dst->nf_bridge);
>   #endif
> diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
> index cd7275f..5679d92 100644
> --- a/include/net/ip_vs.h
> +++ b/include/net/ip_vs.h
> @@ -109,7 +109,6 @@ extern int ip_vs_conn_tab_size;
>   struct ip_vs_iphdr {
>   	__u32 len;	/* IPv4 simply where L4 starts
>   			   IPv6 where L4 Transport Header starts */
> -	__u32 thoff_reasm; /* Transport Header Offset in nfct_reasm skb */
>   	__u16 fragoffs; /* IPv6 fragment offset, 0 if first frag (or not frag)*/
>   	__s16 protocol;
>   	__s32 flags;
> @@ -117,34 +116,12 @@ struct ip_vs_iphdr {
>   	union nf_inet_addr daddr;
>   };
>
> -/* Dependency to module: nf_defrag_ipv6 */
> -#if defined(CONFIG_NF_DEFRAG_IPV6) || defined(CONFIG_NF_DEFRAG_IPV6_MODULE)
> -static inline struct sk_buff *skb_nfct_reasm(const struct sk_buff *skb)
> -{
> -	return skb->nfct_reasm;
> -}
> -static inline void *frag_safe_skb_hp(const struct sk_buff *skb, int offset,
> -				      int len, void *buffer,
> -				      const struct ip_vs_iphdr *ipvsh)
> -{
> -	if (unlikely(ipvsh->fragoffs && skb_nfct_reasm(skb)))
> -		return skb_header_pointer(skb_nfct_reasm(skb),
> -					  ipvsh->thoff_reasm, len, buffer);
> -
> -	return skb_header_pointer(skb, offset, len, buffer);
> -}
> -#else
> -static inline struct sk_buff *skb_nfct_reasm(const struct sk_buff *skb)
> -{
> -	return NULL;
> -}
>   static inline void *frag_safe_skb_hp(const struct sk_buff *skb, int offset,
>   				      int len, void *buffer,
>   				      const struct ip_vs_iphdr *ipvsh)
>   {
>   	return skb_header_pointer(skb, offset, len, buffer);
>   }
> -#endif
>
>   static inline void
>   ip_vs_fill_ip4hdr(const void *nh, struct ip_vs_iphdr *iphdr)
> @@ -171,19 +148,12 @@ ip_vs_fill_iph_skb(int af, const struct sk_buff *skb, struct ip_vs_iphdr *iphdr)
>   			(struct ipv6hdr *)skb_network_header(skb);
>   		iphdr->saddr.in6 = iph->saddr;
>   		iphdr->daddr.in6 = iph->daddr;
> -		/* ipv6_find_hdr() updates len, flags, thoff_reasm */
> -		iphdr->thoff_reasm = 0;
> +		/* ipv6_find_hdr() updates len, flags */
>   		iphdr->len	 = 0;
>   		iphdr->flags	 = 0;
>   		iphdr->protocol  = ipv6_find_hdr(skb, &iphdr->len, -1,
>   						 &iphdr->fragoffs,
>   						 &iphdr->flags);
> -		/* get proto from re-assembled packet and it's offset */
> -		if (skb_nfct_reasm(skb))
> -			iphdr->protocol = ipv6_find_hdr(skb_nfct_reasm(skb),
> -							&iphdr->thoff_reasm,
> -							-1, NULL, NULL);
> -
>   	} else
>   #endif
>   	{
> diff --git a/include/net/netfilter/ipv6/nf_defrag_ipv6.h b/include/net/netfilter/ipv6/nf_defrag_ipv6.h
> index 5613412..27666d8 100644
> --- a/include/net/netfilter/ipv6/nf_defrag_ipv6.h
> +++ b/include/net/netfilter/ipv6/nf_defrag_ipv6.h
> @@ -6,9 +6,7 @@ void nf_defrag_ipv6_enable(void);
>   int nf_ct_frag6_init(void);
>   void nf_ct_frag6_cleanup(void);
>   struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user);
> -void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
> -			struct net_device *in, struct net_device *out,
> -			int (*okfn)(struct sk_buff *));
> +void nf_ct_frag6_consume_orig(struct sk_buff *skb);
>
>   struct inet_frags_ctl;
>
> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> index 3735fad..e55e10a 100644
> --- a/net/core/skbuff.c
> +++ b/net/core/skbuff.c
> @@ -592,9 +592,6 @@ static void skb_release_head_state(struct sk_buff *skb)
>   #if IS_ENABLED(CONFIG_NF_CONNTRACK)
>   	nf_conntrack_put(skb->nfct);
>   #endif
> -#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
> -	nf_conntrack_put_reasm(skb->nfct_reasm);
> -#endif
>   #ifdef CONFIG_BRIDGE_NETFILTER
>   	nf_bridge_put(skb->nf_bridge);
>   #endif
> diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
> index 486545e..4cbc6b2 100644
> --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
> +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
> @@ -169,64 +169,13 @@ out:
>   	return nf_conntrack_confirm(skb);
>   }
>
> -static unsigned int __ipv6_conntrack_in(struct net *net,
> -					unsigned int hooknum,
> -					struct sk_buff *skb,
> -					const struct net_device *in,
> -					const struct net_device *out,
> -					int (*okfn)(struct sk_buff *))
> -{
> -	struct sk_buff *reasm = skb->nfct_reasm;
> -	const struct nf_conn_help *help;
> -	struct nf_conn *ct;
> -	enum ip_conntrack_info ctinfo;
> -
> -	/* This packet is fragmented and has reassembled packet. */
> -	if (reasm) {
> -		/* Reassembled packet isn't parsed yet ? */
> -		if (!reasm->nfct) {
> -			unsigned int ret;
> -
> -			ret = nf_conntrack_in(net, PF_INET6, hooknum, reasm);
> -			if (ret != NF_ACCEPT)
> -				return ret;
> -		}
> -
> -		/* Conntrack helpers need the entire reassembled packet in the
> -		 * POST_ROUTING hook. In case of unconfirmed connections NAT
> -		 * might reassign a helper, so the entire packet is also
> -		 * required.
> -		 */
> -		ct = nf_ct_get(reasm, &ctinfo);
> -		if (ct != NULL && !nf_ct_is_untracked(ct)) {
> -			help = nfct_help(ct);
> -			if ((help && help->helper) || !nf_ct_is_confirmed(ct)) {
> -				nf_conntrack_get_reasm(reasm);
> -				NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
> -					       (struct net_device *)in,
> -					       (struct net_device *)out,
> -					       okfn, NF_IP6_PRI_CONNTRACK + 1);
> -				return NF_DROP_ERR(-ECANCELED);
> -			}
> -		}
> -
> -		nf_conntrack_get(reasm->nfct);
> -		skb->nfct = reasm->nfct;
> -		skb->nfctinfo = reasm->nfctinfo;
> -		return NF_ACCEPT;
> -	}
> -
> -	return nf_conntrack_in(net, PF_INET6, hooknum, skb);
> -}
> -
>   static unsigned int ipv6_conntrack_in(const struct nf_hook_ops *ops,
>   				      struct sk_buff *skb,
>   				      const struct net_device *in,
>   				      const struct net_device *out,
>   				      int (*okfn)(struct sk_buff *))
>   {
> -	return __ipv6_conntrack_in(dev_net(in), ops->hooknum, skb, in, out,
> -				   okfn);
> +	return nf_conntrack_in(dev_net(in), PF_INET6, ops->hooknum, skb);
>   }
>
>   static unsigned int ipv6_conntrack_local(const struct nf_hook_ops *ops,
> @@ -240,8 +189,7 @@ static unsigned int ipv6_conntrack_local(const struct nf_hook_ops *ops,
>   		net_notice_ratelimited("ipv6_conntrack_local: packet too short\n");
>   		return NF_ACCEPT;
>   	}
> -	return __ipv6_conntrack_in(dev_net(out), ops->hooknum, skb, in, out,
> -				   okfn);
> +	return nf_conntrack_in(dev_net(out), PF_INET6, ops->hooknum, skb);
>   }
>
>   static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
> diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
> index 4a25826..767ab8d 100644
> --- a/net/ipv6/netfilter/nf_conntrack_reasm.c
> +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
> @@ -633,31 +633,16 @@ ret_orig:
>   	return skb;
>   }
>
> -void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
> -			struct net_device *in, struct net_device *out,
> -			int (*okfn)(struct sk_buff *))
> +void nf_ct_frag6_consume_orig(struct sk_buff *skb)
>   {
>   	struct sk_buff *s, *s2;
> -	unsigned int ret = 0;
>
>   	for (s = NFCT_FRAG6_CB(skb)->orig; s;) {
> -		nf_conntrack_put_reasm(s->nfct_reasm);
> -		nf_conntrack_get_reasm(skb);
> -		s->nfct_reasm = skb;
> -
>   		s2 = s->next;
>   		s->next = NULL;
> -
> -		if (ret != -ECANCELED)
> -			ret = NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s,
> -					     in, out, okfn,
> -					     NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
> -		else
> -			kfree_skb(s);
> -
> +		consume_skb(s);
>   		s = s2;
>   	}
> -	nf_conntrack_put_reasm(skb);
>   }
>
>   static int nf_ct_net_init(struct net *net)
> diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
> index ec483aa..7b9a748 100644
> --- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
> +++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
> @@ -75,8 +75,11 @@ static unsigned int ipv6_defrag(const struct nf_hook_ops *ops,
>   	if (reasm == skb)
>   		return NF_ACCEPT;
>
> -	nf_ct_frag6_output(ops->hooknum, reasm, (struct net_device *)in,
> -			   (struct net_device *)out, okfn);
> +	nf_ct_frag6_consume_orig(reasm);
> +
> +	NF_HOOK_THRESH(NFPROTO_IPV6, ops->hooknum, reasm,
> +		       (struct net_device *) in, (struct net_device *) out,
> +		       okfn, NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
>
>   	return NF_STOLEN;
>   }
> diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
> index 34fda62..4f26ee4 100644
> --- a/net/netfilter/ipvs/ip_vs_core.c
> +++ b/net/netfilter/ipvs/ip_vs_core.c
> @@ -1139,12 +1139,6 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
>   	ip_vs_fill_iph_skb(af, skb, &iph);
>   #ifdef CONFIG_IP_VS_IPV6
>   	if (af == AF_INET6) {
> -		if (!iph.fragoffs && skb_nfct_reasm(skb)) {
> -			struct sk_buff *reasm = skb_nfct_reasm(skb);
> -			/* Save fw mark for coming frags */
> -			reasm->ipvs_property = 1;
> -			reasm->mark = skb->mark;
> -		}
>   		if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
>   			int related;
>   			int verdict = ip_vs_out_icmp_v6(skb, &related,
> @@ -1614,12 +1608,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
>
>   #ifdef CONFIG_IP_VS_IPV6
>   	if (af == AF_INET6) {
> -		if (!iph.fragoffs && skb_nfct_reasm(skb)) {
> -			struct sk_buff *reasm = skb_nfct_reasm(skb);
> -			/* Save fw mark for coming frags. */
> -			reasm->ipvs_property = 1;
> -			reasm->mark = skb->mark;
> -		}
>   		if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
>   			int related;
>   			int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum,
> @@ -1671,9 +1659,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
>   		/* sorry, all this trouble for a no-hit :) */
>   		IP_VS_DBG_PKT(12, af, pp, skb, 0,
>   			      "ip_vs_in: packet continues traversal as normal");
> -		if (iph.fragoffs && !skb_nfct_reasm(skb)) {
> +		if (iph.fragoffs) {
>   			/* Fragment that couldn't be mapped to a conn entry
> -			 * and don't have any pointer to a reasm skb
>   			 * is missing module nf_defrag_ipv6
>   			 */
>   			IP_VS_DBG_RL("Unhandled frag, load nf_defrag_ipv6\n");
> @@ -1756,38 +1743,6 @@ ip_vs_local_request4(const struct nf_hook_ops *ops, struct sk_buff *skb,
>   #ifdef CONFIG_IP_VS_IPV6
>
>   /*
> - * AF_INET6 fragment handling
> - * Copy info from first fragment, to the rest of them.
> - */
> -static unsigned int
> -ip_vs_preroute_frag6(const struct nf_hook_ops *ops, struct sk_buff *skb,
> -		     const struct net_device *in,
> -		     const struct net_device *out,
> -		     int (*okfn)(struct sk_buff *))
> -{
> -	struct sk_buff *reasm = skb_nfct_reasm(skb);
> -	struct net *net;
> -
> -	/* Skip if not a "replay" from nf_ct_frag6_output or first fragment.
> -	 * ipvs_property is set when checking first fragment
> -	 * in ip_vs_in() and ip_vs_out().
> -	 */
> -	if (reasm)
> -		IP_VS_DBG(2, "Fragment recv prop:%d\n", reasm->ipvs_property);
> -	if (!reasm || !reasm->ipvs_property)
> -		return NF_ACCEPT;
> -
> -	net = skb_net(skb);
> -	if (!net_ipvs(net)->enable)
> -		return NF_ACCEPT;
> -
> -	/* Copy stored fw mark, saved in ip_vs_{in,out} */
> -	skb->mark = reasm->mark;
> -
> -	return NF_ACCEPT;
> -}
> -
> -/*
>    *	AF_INET6 handler in NF_INET_LOCAL_IN chain
>    *	Schedule and forward packets from remote clients
>    */
> @@ -1924,14 +1879,6 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
>   		.priority	= 100,
>   	},
>   #ifdef CONFIG_IP_VS_IPV6
> -	/* After mangle & nat fetch 2:nd fragment and following */
> -	{
> -		.hook		= ip_vs_preroute_frag6,
> -		.owner		= THIS_MODULE,
> -		.pf		= NFPROTO_IPV6,
> -		.hooknum	= NF_INET_PRE_ROUTING,
> -		.priority	= NF_IP6_PRI_NAT_DST + 1,
> -	},
>   	/* After packet filtering, change source only for VS/NAT */
>   	{
>   		.hook		= ip_vs_reply6,
> diff --git a/net/netfilter/ipvs/ip_vs_pe_sip.c b/net/netfilter/ipvs/ip_vs_pe_sip.c
> index 9ef22bd..bed5f70 100644
> --- a/net/netfilter/ipvs/ip_vs_pe_sip.c
> +++ b/net/netfilter/ipvs/ip_vs_pe_sip.c
> @@ -65,7 +65,6 @@ static int get_callid(const char *dptr, unsigned int dataoff,
>   static int
>   ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
>   {
> -	struct sk_buff *reasm = skb_nfct_reasm(skb);
>   	struct ip_vs_iphdr iph;
>   	unsigned int dataoff, datalen, matchoff, matchlen;
>   	const char *dptr;
> @@ -79,15 +78,10 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
>   	/* todo: IPv6 fragments:
>   	 *       I think this only should be done for the first fragment. /HS
>   	 */
> -	if (reasm) {
> -		skb = reasm;
> -		dataoff = iph.thoff_reasm + sizeof(struct udphdr);
> -	} else
> -		dataoff = iph.len + sizeof(struct udphdr);
> +	dataoff = iph.len + sizeof(struct udphdr);
>
>   	if (dataoff >= skb->len)
>   		return -EINVAL;
> -	/* todo: Check if this will mess-up the reasm skb !!! /HS */
>   	retc = skb_linearize(skb);
>   	if (retc < 0)
>   		return retc;
>


^ permalink raw reply

* Re: [PATCH net v3] vti: fix spd lookup: match plaintext pkt, not ipsec pkt
From: Christophe Gouault @ 2013-11-07 12:55 UTC (permalink / raw)
  To: Steffen Klassert
  Cc: David S. Miller, Herbert Xu, netdev, Saurabh Mohan,
	Sergei Shtylyov, Eric Dumazet
In-Reply-To: <20131107112549.GP31491@secunet.com>

Hello Steffen,

I am also interested in knowing Saurabh's intentions regarding the 
behavior of policies bound to vti interfaces.

However, please note that setting a policy with a wildcard selector 
works in both cases (before or after this patch), so a common test case 
can be defined.

Actually the *previous* patch on vti (7263a5187f9e vti: get rid of nf 
mark rule in prerouting) introduced significant changes, and implies 
behaviors dependant on the kernel version, but it seemed to meet 
Saurabh's agreement, as the following thread witnesses:

http://www.spinics.net/lists/netdev/msg253134.html

Best Regards,
Christophe

On 11/07/2013 12:25 PM, Steffen Klassert wrote:
> On Wed, Nov 06, 2013 at 09:05:53AM +0100, Christophe Gouault wrote:
>> The vti interface inbound and outbound SPD lookups are based on the
>> ipsec packet instead of the plaintext packet.
>>
>> Not only is it counterintuitive, it also restricts vti interfaces
>> to a single policy (whose selector must match the tunnel local and
>> remote addresses).
>>
>> The policy selector is supposed to match the plaintext packet, before
>> encryption or after decryption.
>>
>> This patch performs the SPD lookup based on the plaintext packet. It
>> enables to create several polices bound to the vti interface (via a
>> mark equal to the vti interface okey).
>>
>> It remains possible to apply the same policy to all packets entering
>> the vti interface, by setting an any-to-any selector (src 0.0.0.0/0
>> dst 0.0.0.0/0 proto any mark OKEY).
>>
>> Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
> Hm, this patch breaks my current vti test setup. I would need to
> configure the policies and states dependent on the kernel version
> if we apply this patch...
>
> It would be good to hear from the original author of the vti code
> whether the current behaviour is intentional before we do anything
> here.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox