Netdev List
 help / color / mirror / Atom feed
* [PATCH net 4/7] qlcnic: Allow vlan0 traffic
From: Shahed Shaikh @ 2014-02-21 13:19 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept-HSGLinuxNICDev, Rajesh Borundia
In-Reply-To: <1392988795-19380-1-git-send-email-shahed.shaikh@qlogic.com>

From: Rajesh Borundia <rajesh.borundia@qlogic.com>

o Adapter allows vlan0 traffic in case of SR-IOV after setting
  QLC_SRIOV_ALLOW_VLAN0 bit even though we do not add vlan0 filters.

Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
index 09acf15..a28460c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -17,6 +17,7 @@
 #define QLC_MAC_STAR_DEL	7
 #define QLC_VF_FLOOD_BIT	BIT_16
 #define QLC_FLOOD_MODE		0x5
+#define QLC_SRIOV_ALLOW_VLAN0	BIT_19
 
 static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8);
 
@@ -337,8 +338,11 @@ static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter,
 		return err;
 
 	cmd.req.arg[1] = 0x4;
-	if (enable)
+	if (enable) {
 		cmd.req.arg[1] |= BIT_16;
+		if (qlcnic_84xx_check(adapter))
+			cmd.req.arg[1] |= QLC_SRIOV_ALLOW_VLAN0;
+	}
 
 	err = qlcnic_issue_cmd(adapter, &cmd);
 	if (err)
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net 3/7] qlcnic: Enhance driver message in failed state.
From: Shahed Shaikh @ 2014-02-21 13:19 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept-HSGLinuxNICDev, Sucheta Chakraborty
In-Reply-To: <1392988795-19380-1-git-send-email-shahed.shaikh@qlogic.com>

From: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>

Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 964ba45..a335472 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -2450,8 +2450,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		if (err) {
 			switch (err) {
 			case -ENOTRECOVERABLE:
-				dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware. Please reboot\n");
-				dev_err(&pdev->dev, "If reboot doesn't help, please replace the adapter with new one and return the faulty adapter for repair\n");
+				dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware\n");
+				dev_err(&pdev->dev, "Please replace the adapter with new one and return the faulty adapter for repair\n");
 				goto err_out_free_hw;
 			case -ENOMEM:
 				dev_err(&pdev->dev, "Adapter initialization failed. Please reboot\n");
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net 1/7] qlcnic: Re-factor firmware minidump template header handling
From: Shahed Shaikh @ 2014-02-21 13:19 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept-HSGLinuxNICDev, Shahed Shaikh
In-Reply-To: <1392988795-19380-1-git-send-email-shahed.shaikh@qlogic.com>

From: Shahed Shaikh <shahed.shaikh@qlogic.com>

Treat firmware minidump template headers for 82xx and 83xx/84xx adapters separately,
as it may change for 82xx and 83xx/84xx adapter type independently.

Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h        |  73 ++++++-
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c    |   7 +-
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h    |   8 +
 .../net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c    |  17 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h     |   8 +
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c   |   7 +-
 .../net/ethernet/qlogic/qlcnic/qlcnic_minidump.c   | 233 ++++++++++++++++-----
 7 files changed, 287 insertions(+), 66 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index f19f81c..6ad1bce 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -394,7 +394,7 @@ struct qlcnic_nic_intr_coalesce {
 	u32	timer_out;
 };
 
-struct qlcnic_dump_template_hdr {
+struct qlcnic_83xx_dump_template_hdr {
 	u32	type;
 	u32	offset;
 	u32	size;
@@ -411,15 +411,42 @@ struct qlcnic_dump_template_hdr {
 	u32	rsvd[0];
 };
 
+struct qlcnic_82xx_dump_template_hdr {
+	u32	type;
+	u32	offset;
+	u32	size;
+	u32	cap_mask;
+	u32	num_entries;
+	u32	version;
+	u32	timestamp;
+	u32	checksum;
+	u32	drv_cap_mask;
+	u32	sys_info[3];
+	u32	saved_state[16];
+	u32	cap_sizes[8];
+	u32	rsvd[7];
+	u32	capabilities;
+	u32	rsvd1[0];
+};
+
 struct qlcnic_fw_dump {
 	u8	clr;	/* flag to indicate if dump is cleared */
 	bool	enable; /* enable/disable dump */
 	u32	size;	/* total size of the dump */
+	u32	cap_mask; /* Current capture mask */
 	void	*data;	/* dump data area */
-	struct	qlcnic_dump_template_hdr *tmpl_hdr;
+	void	*tmpl_hdr;
 	dma_addr_t phys_addr;
 	void	*dma_buffer;
 	bool	use_pex_dma;
+	/* Read only elements which are common between 82xx and 83xx
+	 * template header. Update these values immediately after we read
+	 * template header from Firmware
+	 */
+	u32	tmpl_hdr_size;
+	u32	version;
+	u32	num_entries;
+	u32	offset;
 };
 
 /*
@@ -1769,6 +1796,12 @@ struct qlcnic_hardware_ops {
 				struct qlcnic_host_tx_ring *);
 	void (*disable_tx_intr) (struct qlcnic_adapter *,
 				 struct qlcnic_host_tx_ring *);
+	u32 (*get_saved_state)(void *, u32);
+	void (*set_saved_state)(void *, u32, u32);
+	void (*cache_tmpl_hdr_values)(struct qlcnic_fw_dump *);
+	u32 (*get_cap_size)(void *, int);
+	void (*set_sys_info)(void *, int, u32);
+	void (*store_cap_mask)(void *, u32);
 };
 
 extern struct qlcnic_nic_template qlcnic_vf_ops;
@@ -2007,6 +2040,42 @@ static inline void qlcnic_read_phys_port_id(struct qlcnic_adapter *adapter)
 		adapter->ahw->hw_ops->read_phys_port_id(adapter);
 }
 
+static inline u32 qlcnic_get_saved_state(struct qlcnic_adapter *adapter,
+					 void *t_hdr, u32 index)
+{
+	return adapter->ahw->hw_ops->get_saved_state(t_hdr, index);
+}
+
+static inline void qlcnic_set_saved_state(struct qlcnic_adapter *adapter,
+					  void *t_hdr, u32 index, u32 value)
+{
+	adapter->ahw->hw_ops->set_saved_state(t_hdr, index, value);
+}
+
+static inline void qlcnic_cache_tmpl_hdr_values(struct qlcnic_adapter *adapter,
+						struct qlcnic_fw_dump *fw_dump)
+{
+	adapter->ahw->hw_ops->cache_tmpl_hdr_values(fw_dump);
+}
+
+static inline u32 qlcnic_get_cap_size(struct qlcnic_adapter *adapter,
+				      void *tmpl_hdr, int index)
+{
+	return adapter->ahw->hw_ops->get_cap_size(tmpl_hdr, index);
+}
+
+static inline void qlcnic_set_sys_info(struct qlcnic_adapter *adapter,
+				       void *tmpl_hdr, int idx, u32 value)
+{
+	adapter->ahw->hw_ops->set_sys_info(tmpl_hdr, idx, value);
+}
+
+static inline void qlcnic_store_cap_mask(struct qlcnic_adapter *adapter,
+					 void *tmpl_hdr, u32 mask)
+{
+	adapter->ahw->hw_ops->store_cap_mask(tmpl_hdr, mask);
+}
+
 static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
 					    u32 key)
 {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index 4146664..0f39778e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -203,7 +203,12 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
 	.disable_sds_intr		= qlcnic_83xx_disable_sds_intr,
 	.enable_tx_intr			= qlcnic_83xx_enable_tx_intr,
 	.disable_tx_intr		= qlcnic_83xx_disable_tx_intr,
-
+	.get_saved_state		= qlcnic_83xx_get_saved_state,
+	.set_saved_state		= qlcnic_83xx_set_saved_state,
+	.cache_tmpl_hdr_values		= qlcnic_83xx_cache_tmpl_hdr_values,
+	.get_cap_size			= qlcnic_83xx_get_cap_size,
+	.set_sys_info			= qlcnic_83xx_set_sys_info,
+	.store_cap_mask			= qlcnic_83xx_store_cap_mask,
 };
 
 static struct qlcnic_nic_template qlcnic_83xx_ops = {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index f92485c..81c1889 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -308,6 +308,8 @@ struct qlc_83xx_reset {
 #define QLC_83XX_IDC_FLASH_PARAM_ADDR			0x3e8020
 
 struct qlcnic_adapter;
+struct qlcnic_fw_dump;
+
 struct qlc_83xx_idc {
 	int (*state_entry) (struct qlcnic_adapter *);
 	u64		sec_counter;
@@ -650,4 +652,10 @@ int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *);
 void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *);
 int qlcnic_83xx_aer_reset(struct qlcnic_adapter *);
 void qlcnic_83xx_aer_start_poll_work(struct qlcnic_adapter *);
+u32 qlcnic_83xx_get_saved_state(void *, u32);
+void qlcnic_83xx_set_saved_state(void *, u32, u32);
+void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *);
+u32 qlcnic_83xx_get_cap_size(void *, int);
+void qlcnic_83xx_set_sys_info(void *, int, u32);
+void qlcnic_83xx_store_cap_mask(void *, u32);
 #endif
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index acee1a5..1960609 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -1639,14 +1639,14 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
 	}
 
 	if (fw_dump->clr)
-		dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
+		dump->len = fw_dump->tmpl_hdr_size + fw_dump->size;
 	else
 		dump->len = 0;
 
 	if (!qlcnic_check_fw_dump_state(adapter))
 		dump->flag = ETH_FW_DUMP_DISABLE;
 	else
-		dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
+		dump->flag = fw_dump->cap_mask;
 
 	dump->version = adapter->fw_version;
 	return 0;
@@ -1671,9 +1671,10 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
 		netdev_info(netdev, "Dump not available\n");
 		return -EINVAL;
 	}
+
 	/* Copy template header first */
-	copy_sz = fw_dump->tmpl_hdr->size;
-	hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
+	copy_sz = fw_dump->tmpl_hdr_size;
+	hdr_ptr = (u32 *)fw_dump->tmpl_hdr;
 	data = buffer;
 	for (i = 0; i < copy_sz/sizeof(u32); i++)
 		*data++ = cpu_to_le32(*hdr_ptr++);
@@ -1681,7 +1682,7 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
 	/* Copy captured dump data */
 	memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
 	dump->len = copy_sz + fw_dump->size;
-	dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
+	dump->flag = fw_dump->cap_mask;
 
 	/* Free dump area once data has been captured */
 	vfree(fw_dump->data);
@@ -1703,7 +1704,11 @@ static int qlcnic_set_dump_mask(struct qlcnic_adapter *adapter, u32 mask)
 		return -EOPNOTSUPP;
 	}
 
-	fw_dump->tmpl_hdr->drv_cap_mask = mask;
+	fw_dump->cap_mask = mask;
+
+	/* Store new capture mask in template header as well*/
+	qlcnic_store_cap_mask(adapter, fw_dump->tmpl_hdr, mask);
+
 	netdev_info(netdev, "Driver mask changed to: 0x%x\n", mask);
 	return 0;
 }
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
index 63d7561..576b301 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -161,6 +161,7 @@ struct qlcnic_host_sds_ring;
 struct qlcnic_host_tx_ring;
 struct qlcnic_hardware_context;
 struct qlcnic_adapter;
+struct qlcnic_fw_dump;
 
 int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong, int *);
 int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);
@@ -213,4 +214,11 @@ int qlcnic_82xx_shutdown(struct pci_dev *);
 int qlcnic_82xx_resume(struct qlcnic_adapter *);
 void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed);
 void qlcnic_fw_poll_work(struct work_struct *work);
+
+u32 qlcnic_82xx_get_saved_state(void *, u32);
+void qlcnic_82xx_set_saved_state(void *, u32, u32);
+void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *);
+u32 qlcnic_82xx_get_cap_size(void *, int);
+void qlcnic_82xx_set_sys_info(void *, int, u32);
+void qlcnic_82xx_store_cap_mask(void *, u32);
 #endif				/* __QLCNIC_HW_H_ */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index e07fd94..964ba45 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -90,7 +90,6 @@ static void qlcnic_82xx_io_resume(struct pci_dev *);
 static void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *);
 static pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *,
 						      pci_channel_state_t);
-
 static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter)
 {
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
@@ -561,6 +560,12 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = {
 	.disable_sds_intr		= qlcnic_82xx_disable_sds_intr,
 	.enable_tx_intr			= qlcnic_82xx_enable_tx_intr,
 	.disable_tx_intr		= qlcnic_82xx_disable_tx_intr,
+	.get_saved_state		= qlcnic_82xx_get_saved_state,
+	.set_saved_state		= qlcnic_82xx_set_saved_state,
+	.cache_tmpl_hdr_values		= qlcnic_82xx_cache_tmpl_hdr_values,
+	.get_cap_size			= qlcnic_82xx_get_cap_size,
+	.set_sys_info			= qlcnic_82xx_set_sys_info,
+	.store_cap_mask			= qlcnic_82xx_store_cap_mask,
 };
 
 static int qlcnic_check_multi_tx_capability(struct qlcnic_adapter *adapter)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
index 7763962..37b979b 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
@@ -211,6 +211,107 @@ enum qlcnic_minidump_opcode {
 	QLCNIC_DUMP_RDEND	= 255
 };
 
+inline u32 qlcnic_82xx_get_saved_state(void *t_hdr, u32 index)
+{
+	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
+
+	return hdr->saved_state[index];
+}
+
+inline void qlcnic_82xx_set_saved_state(void *t_hdr, u32 index,
+					u32 value)
+{
+	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
+
+	hdr->saved_state[index] = value;
+}
+
+void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump)
+{
+	struct qlcnic_82xx_dump_template_hdr *hdr;
+
+	hdr = fw_dump->tmpl_hdr;
+	fw_dump->tmpl_hdr_size = hdr->size;
+	fw_dump->version = hdr->version;
+	fw_dump->num_entries = hdr->num_entries;
+	fw_dump->offset = hdr->offset;
+
+	hdr->drv_cap_mask = hdr->cap_mask;
+	fw_dump->cap_mask = hdr->cap_mask;
+}
+
+inline u32 qlcnic_82xx_get_cap_size(void *t_hdr, int index)
+{
+	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
+
+	return hdr->cap_sizes[index];
+}
+
+void qlcnic_82xx_set_sys_info(void *t_hdr, int idx, u32 value)
+{
+	struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
+
+	hdr->sys_info[idx] = value;
+}
+
+void qlcnic_82xx_store_cap_mask(void *tmpl_hdr, u32 mask)
+{
+	struct qlcnic_82xx_dump_template_hdr *hdr = tmpl_hdr;
+
+	hdr->drv_cap_mask = mask;
+}
+
+inline u32 qlcnic_83xx_get_saved_state(void *t_hdr, u32 index)
+{
+	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
+
+	return hdr->saved_state[index];
+}
+
+inline void qlcnic_83xx_set_saved_state(void *t_hdr, u32 index,
+					u32 value)
+{
+	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
+
+	hdr->saved_state[index] = value;
+}
+
+void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump)
+{
+	struct qlcnic_83xx_dump_template_hdr *hdr;
+
+	hdr = fw_dump->tmpl_hdr;
+	fw_dump->tmpl_hdr_size = hdr->size;
+	fw_dump->version = hdr->version;
+	fw_dump->num_entries = hdr->num_entries;
+	fw_dump->offset = hdr->offset;
+
+	hdr->drv_cap_mask = hdr->cap_mask;
+	fw_dump->cap_mask = hdr->cap_mask;
+}
+
+inline u32 qlcnic_83xx_get_cap_size(void *t_hdr, int index)
+{
+	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
+
+	return hdr->cap_sizes[index];
+}
+
+void qlcnic_83xx_set_sys_info(void *t_hdr, int idx, u32 value)
+{
+	struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
+
+	hdr->sys_info[idx] = value;
+}
+
+void qlcnic_83xx_store_cap_mask(void *tmpl_hdr, u32 mask)
+{
+	struct qlcnic_83xx_dump_template_hdr *hdr;
+
+	hdr = tmpl_hdr;
+	hdr->drv_cap_mask = mask;
+}
+
 struct qlcnic_dump_operations {
 	enum qlcnic_minidump_opcode opcode;
 	u32 (*handler)(struct qlcnic_adapter *, struct qlcnic_dump_entry *,
@@ -238,11 +339,11 @@ static u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter,
 static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
 			    struct qlcnic_dump_entry *entry, __le32 *buffer)
 {
+	void *hdr = adapter->ahw->fw_dump.tmpl_hdr;
+	struct __ctrl *ctr = &entry->region.ctrl;
 	int i, k, timeout = 0;
-	u32 addr, data;
+	u32 addr, data, temp;
 	u8 no_ops;
-	struct __ctrl *ctr = &entry->region.ctrl;
-	struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;
 
 	addr = ctr->addr;
 	no_ops = ctr->no_ops;
@@ -285,29 +386,42 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
 				}
 				break;
 			case QLCNIC_DUMP_RD_SAVE:
-				if (ctr->index_a)
-					addr = t_hdr->saved_state[ctr->index_a];
+				temp = ctr->index_a;
+				if (temp)
+					addr = qlcnic_get_saved_state(adapter,
+								      hdr,
+								      temp);
 				data = qlcnic_ind_rd(adapter, addr);
-				t_hdr->saved_state[ctr->index_v] = data;
+				qlcnic_set_saved_state(adapter, hdr,
+						       ctr->index_v, data);
 				break;
 			case QLCNIC_DUMP_WRT_SAVED:
-				if (ctr->index_v)
-					data = t_hdr->saved_state[ctr->index_v];
+				temp = ctr->index_v;
+				if (temp)
+					data = qlcnic_get_saved_state(adapter,
+								      hdr,
+								      temp);
 				else
 					data = ctr->val1;
-				if (ctr->index_a)
-					addr = t_hdr->saved_state[ctr->index_a];
+
+				temp = ctr->index_a;
+				if (temp)
+					addr = qlcnic_get_saved_state(adapter,
+								      hdr,
+								      temp);
 				qlcnic_ind_wr(adapter, addr, data);
 				break;
 			case QLCNIC_DUMP_MOD_SAVE_ST:
-				data = t_hdr->saved_state[ctr->index_v];
+				data = qlcnic_get_saved_state(adapter, hdr,
+							      ctr->index_v);
 				data <<= ctr->shl_val;
 				data >>= ctr->shr_val;
 				if (ctr->val2)
 					data &= ctr->val2;
 				data |= ctr->val3;
 				data += ctr->val1;
-				t_hdr->saved_state[ctr->index_v] = data;
+				qlcnic_set_saved_state(adapter, hdr,
+						       ctr->index_v, data);
 				break;
 			default:
 				dev_info(&adapter->pdev->dev,
@@ -544,7 +658,7 @@ out:
 static int qlcnic_start_pex_dma(struct qlcnic_adapter *adapter,
 				struct __mem *mem)
 {
-	struct qlcnic_dump_template_hdr *tmpl_hdr;
+	struct qlcnic_83xx_dump_template_hdr *tmpl_hdr;
 	struct device *dev = &adapter->pdev->dev;
 	u32 dma_no, dma_base_addr, temp_addr;
 	int i, ret, dma_sts;
@@ -596,7 +710,7 @@ static u32 qlcnic_read_memory_pexdma(struct qlcnic_adapter *adapter,
 	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
 	u32 temp, dma_base_addr, size = 0, read_size = 0;
 	struct qlcnic_pex_dma_descriptor *dma_descr;
-	struct qlcnic_dump_template_hdr *tmpl_hdr;
+	struct qlcnic_83xx_dump_template_hdr *tmpl_hdr;
 	struct device *dev = &adapter->pdev->dev;
 	dma_addr_t dma_phys_addr;
 	void *dma_buffer;
@@ -938,8 +1052,8 @@ static int
 qlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter,
 				       struct qlcnic_cmd_args *cmd)
 {
-	struct qlcnic_dump_template_hdr tmp_hdr;
-	u32 size = sizeof(struct qlcnic_dump_template_hdr) / sizeof(u32);
+	struct qlcnic_83xx_dump_template_hdr tmp_hdr;
+	u32 size = sizeof(tmp_hdr) / sizeof(u32);
 	int ret = 0;
 
 	if (qlcnic_82xx_check(adapter))
@@ -1027,17 +1141,19 @@ free_mem:
 	return err;
 }
 
+#define QLCNIC_TEMPLATE_VERSION (0x20001)
+
 int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
 {
-	int err;
-	u32 temp_size = 0;
-	u32 version, csum, *tmp_buf;
 	struct qlcnic_hardware_context *ahw;
-	struct qlcnic_dump_template_hdr *tmpl_hdr;
+	struct qlcnic_fw_dump *fw_dump;
+	u32 version, csum, *tmp_buf;
 	u8 use_flash_temp = 0;
+	u32 temp_size = 0;
+	int err;
 
 	ahw = adapter->ahw;
-
+	fw_dump = &ahw->fw_dump;
 	err = qlcnic_fw_get_minidump_temp_size(adapter, &version, &temp_size,
 					       &use_flash_temp);
 	if (err) {
@@ -1046,11 +1162,11 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
 		return -EIO;
 	}
 
-	ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
-	if (!ahw->fw_dump.tmpl_hdr)
+	fw_dump->tmpl_hdr = vzalloc(temp_size);
+	if (!fw_dump->tmpl_hdr)
 		return -ENOMEM;
 
-	tmp_buf = (u32 *)ahw->fw_dump.tmpl_hdr;
+	tmp_buf = (u32 *)fw_dump->tmpl_hdr;
 	if (use_flash_temp)
 		goto flash_temp;
 
@@ -1065,8 +1181,8 @@ flash_temp:
 			dev_err(&adapter->pdev->dev,
 				"Failed to get minidump template header %d\n",
 				err);
-			vfree(ahw->fw_dump.tmpl_hdr);
-			ahw->fw_dump.tmpl_hdr = NULL;
+			vfree(fw_dump->tmpl_hdr);
+			fw_dump->tmpl_hdr = NULL;
 			return -EIO;
 		}
 	}
@@ -1076,21 +1192,22 @@ flash_temp:
 	if (csum) {
 		dev_err(&adapter->pdev->dev,
 			"Template header checksum validation failed\n");
-		vfree(ahw->fw_dump.tmpl_hdr);
-		ahw->fw_dump.tmpl_hdr = NULL;
+		vfree(fw_dump->tmpl_hdr);
+		fw_dump->tmpl_hdr = NULL;
 		return -EIO;
 	}
 
-	tmpl_hdr = ahw->fw_dump.tmpl_hdr;
-	tmpl_hdr->drv_cap_mask = tmpl_hdr->cap_mask;
+	qlcnic_cache_tmpl_hdr_values(adapter, fw_dump);
+
 	dev_info(&adapter->pdev->dev,
 		 "Default minidump capture mask 0x%x\n",
-		 tmpl_hdr->cap_mask);
+		 fw_dump->cap_mask);
 
-	if ((tmpl_hdr->version & 0xfffff) >= 0x20001)
-		ahw->fw_dump.use_pex_dma = true;
+	if (qlcnic_83xx_check(adapter) &&
+	    (fw_dump->version & 0xfffff) >= QLCNIC_TEMPLATE_VERSION)
+		fw_dump->use_pex_dma = true;
 	else
-		ahw->fw_dump.use_pex_dma = false;
+		fw_dump->use_pex_dma = false;
 
 	qlcnic_enable_fw_dump_state(adapter);
 
@@ -1099,21 +1216,22 @@ flash_temp:
 
 int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
 {
-	__le32 *buffer;
-	u32 ocm_window;
-	char mesg[64];
-	char *msg[] = {mesg, NULL};
-	int i, k, ops_cnt, ops_index, dump_size = 0;
-	u32 entry_offset, dump, no_entries, buf_offset = 0;
-	struct qlcnic_dump_entry *entry;
 	struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
-	struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
 	static const struct qlcnic_dump_operations *fw_dump_ops;
+	struct qlcnic_83xx_dump_template_hdr *hdr_83xx;
+	u32 entry_offset, dump, no_entries, buf_offset = 0;
+	int i, k, ops_cnt, ops_index, dump_size = 0;
 	struct device *dev = &adapter->pdev->dev;
 	struct qlcnic_hardware_context *ahw;
-	void *temp_buffer;
+	struct qlcnic_dump_entry *entry;
+	void *temp_buffer, *tmpl_hdr;
+	u32 ocm_window;
+	__le32 *buffer;
+	char mesg[64];
+	char *msg[] = {mesg, NULL};
 
 	ahw = adapter->ahw;
+	tmpl_hdr = fw_dump->tmpl_hdr;
 
 	/* Return if we don't have firmware dump template header */
 	if (!tmpl_hdr)
@@ -1133,8 +1251,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
 	netif_info(adapter->ahw, drv, adapter->netdev, "Take FW dump\n");
 	/* Calculate the size for dump data area only */
 	for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
-		if (i & tmpl_hdr->drv_cap_mask)
-			dump_size += tmpl_hdr->cap_sizes[k];
+		if (i & fw_dump->cap_mask)
+			dump_size += qlcnic_get_cap_size(adapter, tmpl_hdr, k);
+
 	if (!dump_size)
 		return -EIO;
 
@@ -1144,10 +1263,10 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
 
 	buffer = fw_dump->data;
 	fw_dump->size = dump_size;
-	no_entries = tmpl_hdr->num_entries;
-	entry_offset = tmpl_hdr->offset;
-	tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
-	tmpl_hdr->sys_info[1] = adapter->fw_version;
+	no_entries = fw_dump->num_entries;
+	entry_offset = fw_dump->offset;
+	qlcnic_set_sys_info(adapter, tmpl_hdr, 0, QLCNIC_DRIVER_VERSION);
+	qlcnic_set_sys_info(adapter, tmpl_hdr, 1, adapter->fw_version);
 
 	if (fw_dump->use_pex_dma) {
 		temp_buffer = dma_alloc_coherent(dev, QLC_PEX_DMA_READ_SIZE,
@@ -1163,16 +1282,17 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
 		ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);
 		fw_dump_ops = qlcnic_fw_dump_ops;
 	} else {
+		hdr_83xx = tmpl_hdr;
 		ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops);
 		fw_dump_ops = qlcnic_83xx_fw_dump_ops;
-		ocm_window = tmpl_hdr->ocm_wnd_reg[adapter->ahw->pci_func];
-		tmpl_hdr->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
-		tmpl_hdr->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
+		ocm_window = hdr_83xx->ocm_wnd_reg[ahw->pci_func];
+		hdr_83xx->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
+		hdr_83xx->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
 	}
 
 	for (i = 0; i < no_entries; i++) {
-		entry = (void *)tmpl_hdr + entry_offset;
-		if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
+		entry = tmpl_hdr + entry_offset;
+		if (!(entry->hdr.mask & fw_dump->cap_mask)) {
 			entry->hdr.flags |= QLCNIC_DUMP_SKIP;
 			entry_offset += entry->hdr.offset;
 			continue;
@@ -1209,8 +1329,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
 
 	fw_dump->clr = 1;
 	snprintf(mesg, sizeof(mesg), "FW_DUMP=%s", adapter->netdev->name);
-	dev_info(dev, "%s: Dump data %d bytes captured, template header size %d bytes\n",
-		 adapter->netdev->name, fw_dump->size, tmpl_hdr->size);
+	netdev_info(adapter->netdev,
+		    "Dump data %d bytes captured, template header size %d bytes\n",
+		    fw_dump->size, fw_dump->tmpl_hdr_size);
 	/* Send a udev event to notify availability of FW dump */
 	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, msg);
 
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net 2/7] qlcnic: Updates to QLogic application/driver interface for virtual NIC configuration
From: Shahed Shaikh @ 2014-02-21 13:19 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept-HSGLinuxNICDev, Jitendra Kalsaria
In-Reply-To: <1392988795-19380-1-git-send-email-shahed.shaikh@qlogic.com>

From: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>

Qlogic application interface in the driver which has larger than 8 vNIC
configuration support has been updated to handle the following cases:

o Only 8 or lower total vNICs were enabled within the vNIC 0-7 range
o vNICs were enabled in the vNIC 0-15 range such that enabled vNICs were
  not contiguous and only 8 or lower number of total VNICs were enabled
o Disconnect in the vNIC mapping between application and driver when the
  enabled VNICs were dis contiguous

Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c | 102 ++++++++--------------
 1 file changed, 37 insertions(+), 65 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
index 3d64113..448d156 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
@@ -350,33 +350,15 @@ static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
 	return size;
 }
 
-static u32 qlcnic_get_pci_func_count(struct qlcnic_adapter *adapter)
-{
-	struct qlcnic_hardware_context *ahw = adapter->ahw;
-	u32 count = 0;
-
-	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
-		return ahw->total_nic_func;
-
-	if (ahw->total_pci_func <= QLC_DEFAULT_VNIC_COUNT)
-		count = QLC_DEFAULT_VNIC_COUNT;
-	else
-		count = ahw->max_vnic_func;
-
-	return count;
-}
-
 int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
 {
-	u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
 	int i;
 
-	for (i = 0; i < pci_func_count; i++) {
+	for (i = 0; i < adapter->ahw->max_vnic_func; i++) {
 		if (adapter->npars[i].pci_func == pci_func)
 			return i;
 	}
-
-	return -1;
+	return -EINVAL;
 }
 
 static int validate_pm_config(struct qlcnic_adapter *adapter,
@@ -464,23 +446,21 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,
 {
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-	u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
 	struct qlcnic_pm_func_cfg *pm_cfg;
-	int i, pm_cfg_size;
 	u8 pci_func;
+	u32 count;
+	int i;
 
-	pm_cfg_size = pci_func_count * sizeof(*pm_cfg);
-	if (size != pm_cfg_size)
-		return QL_STATUS_INVALID_PARAM;
-
-	memset(buf, 0, pm_cfg_size);
+	memset(buf, 0, size);
 	pm_cfg = (struct qlcnic_pm_func_cfg *)buf;
-
-	for (i = 0; i < pci_func_count; i++) {
+	count = size / sizeof(struct qlcnic_pm_func_cfg);
+	for (i = 0; i < adapter->ahw->total_nic_func; i++) {
 		pci_func = adapter->npars[i].pci_func;
-		if (!adapter->npars[i].active)
+		if (pci_func >= count) {
+			dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n",
+				__func__, adapter->ahw->total_nic_func, count);
 			continue;
-
+		}
 		if (!adapter->npars[i].eswitch_status)
 			continue;
 
@@ -494,7 +474,6 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,
 static int validate_esw_config(struct qlcnic_adapter *adapter,
 			       struct qlcnic_esw_func_cfg *esw_cfg, int count)
 {
-	u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
 	int i, ret;
 	u32 op_mode;
@@ -507,7 +486,7 @@ static int validate_esw_config(struct qlcnic_adapter *adapter,
 
 	for (i = 0; i < count; i++) {
 		pci_func = esw_cfg[i].pci_func;
-		if (pci_func >= pci_func_count)
+		if (pci_func >= ahw->max_vnic_func)
 			return QL_STATUS_INVALID_PARAM;
 
 		if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
@@ -642,23 +621,21 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file,
 {
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-	u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
 	struct qlcnic_esw_func_cfg *esw_cfg;
-	size_t esw_cfg_size;
-	u8 i, pci_func;
-
-	esw_cfg_size = pci_func_count * sizeof(*esw_cfg);
-	if (size != esw_cfg_size)
-		return QL_STATUS_INVALID_PARAM;
+	u8 pci_func;
+	u32 count;
+	int i;
 
-	memset(buf, 0, esw_cfg_size);
+	memset(buf, 0, size);
 	esw_cfg = (struct qlcnic_esw_func_cfg *)buf;
-
-	for (i = 0; i < pci_func_count; i++) {
+	count = size / sizeof(struct qlcnic_esw_func_cfg);
+	for (i = 0; i < adapter->ahw->total_nic_func; i++) {
 		pci_func = adapter->npars[i].pci_func;
-		if (!adapter->npars[i].active)
+		if (pci_func >= count) {
+			dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n",
+				__func__, adapter->ahw->total_nic_func, count);
 			continue;
-
+		}
 		if (!adapter->npars[i].eswitch_status)
 			continue;
 
@@ -741,23 +718,24 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
 {
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-	u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
 	struct qlcnic_npar_func_cfg *np_cfg;
 	struct qlcnic_info nic_info;
-	size_t np_cfg_size;
 	int i, ret;
-
-	np_cfg_size = pci_func_count * sizeof(*np_cfg);
-	if (size != np_cfg_size)
-		return QL_STATUS_INVALID_PARAM;
+	u32 count;
 
 	memset(&nic_info, 0, sizeof(struct qlcnic_info));
-	memset(buf, 0, np_cfg_size);
+	memset(buf, 0, size);
 	np_cfg = (struct qlcnic_npar_func_cfg *)buf;
 
-	for (i = 0; i < pci_func_count; i++) {
+	count = size / sizeof(struct qlcnic_npar_func_cfg);
+	for (i = 0; i < adapter->ahw->total_nic_func; i++) {
 		if (qlcnic_is_valid_nic_func(adapter, i) < 0)
 			continue;
+		if (adapter->npars[i].pci_func >= count) {
+			dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n",
+				__func__, adapter->ahw->total_nic_func, count);
+			continue;
+		}
 		ret = qlcnic_get_nic_info(adapter, &nic_info, i);
 		if (ret)
 			return ret;
@@ -783,7 +761,6 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file,
 {
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-	u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
 	struct qlcnic_esw_statistics port_stats;
 	int ret;
 
@@ -793,7 +770,7 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file,
 	if (size != sizeof(struct qlcnic_esw_statistics))
 		return QL_STATUS_INVALID_PARAM;
 
-	if (offset >= pci_func_count)
+	if (offset >= adapter->ahw->max_vnic_func)
 		return QL_STATUS_INVALID_PARAM;
 
 	memset(&port_stats, 0, size);
@@ -884,13 +861,12 @@ static ssize_t qlcnic_sysfs_clear_port_stats(struct file *file,
 
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-	u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
 	int ret;
 
 	if (qlcnic_83xx_check(adapter))
 		return QLC_STATUS_UNSUPPORTED_CMD;
 
-	if (offset >= pci_func_count)
+	if (offset >= adapter->ahw->max_vnic_func)
 		return QL_STATUS_INVALID_PARAM;
 
 	ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
@@ -914,17 +890,12 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
 {
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-	u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
 	struct qlcnic_pci_func_cfg *pci_cfg;
 	struct qlcnic_pci_info *pci_info;
-	size_t pci_cfg_sz;
 	int i, ret;
+	u32 count;
 
-	pci_cfg_sz = pci_func_count * sizeof(*pci_cfg);
-	if (size != pci_cfg_sz)
-		return QL_STATUS_INVALID_PARAM;
-
-	pci_info = kcalloc(pci_func_count, sizeof(*pci_info), GFP_KERNEL);
+	pci_info = kcalloc(size, sizeof(*pci_info), GFP_KERNEL);
 	if (!pci_info)
 		return -ENOMEM;
 
@@ -935,7 +906,8 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
 	}
 
 	pci_cfg = (struct qlcnic_pci_func_cfg *)buf;
-	for (i = 0; i < pci_func_count; i++) {
+	count = size / sizeof(struct qlcnic_pci_func_cfg);
+	for (i = 0; i < count; i++) {
 		pci_cfg[i].pci_func = pci_info[i].id;
 		pci_cfg[i].func_type = pci_info[i].type;
 		pci_cfg[i].func_state = 0;
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net 0/7] qlcnic: Re-factoring and enhancements
From: Shahed Shaikh @ 2014-02-21 13:19 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept-HSGLinuxNICDev, Shahed Shaikh

From: Shahed Shaikh <shahed.shaikh@qlogic.com>

Hi David,

This patch series includes following changes -
* Re-factored firmware minidump template header handling
* Support to make 8 vNIC mode application to work with 16 vNIC mode
* Enhance error message logging when adapter is in failed state and
  when adapter lock access fails.
* Allow vlan0 traffic
* update MAINTAINERS

Please apply this series to net-next.

Thanks,
Shahed

Harish Patil (1):
  qlcnic: Enhance semaphore lock access failure error message

Jitendra Kalsaria (1):
  qlcnic: Updates to QLogic application/driver interface for virtual NIC
    configuration

Rajesh Borundia (1):
  qlcnic: Allow vlan0 traffic

Shahed Shaikh (3):
  qlcnic: Re-factor firmware minidump template header handling
  qlcnic: Update version to 5.3.56
  Update MAINTAINERS for qlcnic driver

Sucheta Chakraborty (1):
  qlcnic: Enhance driver message in failed state.

 MAINTAINERS                                        |   7 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h        |  77 ++++++-
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c    |   7 +-
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h    |   8 +
 .../net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c    |  17 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c     |  22 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h     |   8 +
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c   |  11 +-
 .../net/ethernet/qlogic/qlcnic/qlcnic_minidump.c   | 233 ++++++++++++++++-----
 .../net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c   |   6 +-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c  | 102 ++++-----
 11 files changed, 349 insertions(+), 149 deletions(-)

-- 
1.8.1.4

^ permalink raw reply

* Re: [PATCH 1/4] net: rfkill: gpio: remove unused and obsolete platform parameters
From: Marc Dietrich @ 2014-02-21 13:55 UTC (permalink / raw)
  To: Heikki Krogerus
  Cc: Johannes Berg, David S. Miller, Chen-Yu Tsai, Rhyland Klein,
	linux-wireless, netdev, linux-kernel
In-Reply-To: <1392900697-27577-2-git-send-email-heikki.krogerus@linux.intel.com>

Hi Heikki,

Am Donnerstag, 20. Februar 2014, 14:51:34 schrieb Heikki Krogerus:
> After upgrading to descriptor based gpios, the gpio numbers
> are not used anymore. The power_clk_name and the platform
> specific setup and close hooks are not used by anybody, and
> we should not encourage use of such things, so removing them.

arch/arm/mach-tegra/board-paz00.c is still using platform data. Is there some 
prerequisite patch I'm missing (3.14-rc3) or how can this file be converted? 
We are waiting for DT support to arrive so we can finally remove this file.

Marc

> 
> Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> ---
>  include/linux/rfkill-gpio.h | 10 ----------
>  net/rfkill/rfkill-gpio.c    | 15 +--------------
>  2 files changed, 1 insertion(+), 24 deletions(-)
> 
> diff --git a/include/linux/rfkill-gpio.h b/include/linux/rfkill-gpio.h
> index 4d09f6e..20bcb55 100644
> --- a/include/linux/rfkill-gpio.h
> +++ b/include/linux/rfkill-gpio.h
> @@ -27,21 +27,11 @@
>   * struct rfkill_gpio_platform_data - platform data for rfkill gpio device.
> * for unused gpio's, the expected value is -1.
>   * @name:		name for the gpio rf kill instance
> - * @reset_gpio:		GPIO which is used for reseting rfkill switch
> - * @shutdown_gpio:	GPIO which is used for shutdown of rfkill switch
> - * @power_clk_name:	[optional] name of clk to turn off while blocked
> - * @gpio_runtime_close:	clean up platform specific gpio configuration
> - * @gpio_runtime_setup:	set up platform specific gpio configuration
>   */
> 
>  struct rfkill_gpio_platform_data {
>  	char			*name;
> -	int			reset_gpio;
> -	int			shutdown_gpio;
> -	const char		*power_clk_name;
>  	enum rfkill_type	type;
> -	void	(*gpio_runtime_close)(struct platform_device *);
> -	int	(*gpio_runtime_setup)(struct platform_device *);
>  };
> 
>  #endif /* __RFKILL_GPIO_H */
> diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
> index bd2a5b9..0adda44 100644
> --- a/net/rfkill/rfkill-gpio.c
> +++ b/net/rfkill/rfkill-gpio.c
> @@ -87,7 +87,6 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
> {
>  	struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data;
>  	struct rfkill_gpio_data *rfkill;
> -	const char *clk_name = NULL;
>  	struct gpio_desc *gpio;
>  	int ret;
>  	int len;
> @@ -101,7 +100,6 @@ static int rfkill_gpio_probe(struct platform_device
> *pdev) if (ret)
>  			return ret;
>  	} else if (pdata) {
> -		clk_name = pdata->power_clk_name;
>  		rfkill->name = pdata->name;
>  		rfkill->type = pdata->type;
>  	} else {
> @@ -120,7 +118,7 @@ static int rfkill_gpio_probe(struct platform_device
> *pdev) snprintf(rfkill->reset_name, len + 6 , "%s_reset", rfkill->name);
> snprintf(rfkill->shutdown_name, len + 9, "%s_shutdown", rfkill->name);
> 
> -	rfkill->clk = devm_clk_get(&pdev->dev, clk_name);
> +	rfkill->clk = devm_clk_get(&pdev->dev, NULL);
> 
>  	gpio = devm_gpiod_get_index(&pdev->dev, rfkill->reset_name, 0);
>  	if (!IS_ERR(gpio)) {
> @@ -146,14 +144,6 @@ static int rfkill_gpio_probe(struct platform_device
> *pdev) return -EINVAL;
>  	}
> 
> -	if (pdata && pdata->gpio_runtime_setup) {
> -		ret = pdata->gpio_runtime_setup(pdev);
> -		if (ret) {
> -			dev_err(&pdev->dev, "can't set up gpio\n");
> -			return ret;
> -		}
> -	}
> -
>  	rfkill->rfkill_dev = rfkill_alloc(rfkill->name, &pdev->dev,
>  					  rfkill->type, &rfkill_gpio_ops,
>  					  rfkill);
> @@ -174,10 +164,7 @@ static int rfkill_gpio_probe(struct platform_device
> *pdev) static int rfkill_gpio_remove(struct platform_device *pdev)
>  {
>  	struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev);
> -	struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data;
> 
> -	if (pdata && pdata->gpio_runtime_close)
> -		pdata->gpio_runtime_close(pdev);
>  	rfkill_unregister(rfkill->rfkill_dev);
>  	rfkill_destroy(rfkill->rfkill_dev);

^ permalink raw reply

* [patch net] neigh: fix setting of default gc_* values
From: Jiri Pirko @ 2014-02-21 13:52 UTC (permalink / raw)
  To: netdev; +Cc: davem, gaofeng, hannes, joe, vfalico, ffusco

This patch fixes bug introduced by:
commit 1d4c8c29841b9991cdf3c7cc4ba7f96a94f104ca
"neigh: restore old behaviour of default parms values"

The thing is that in neigh_sysctl_register, extra1 and extra2 which were
previously set for NEIGH_VAR_GC_* are overwritten. That leads to
nonsense int limits for gc_* variables. So fix this by not touching
extra* fields for gc_* variables.

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
---
 net/core/neighbour.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index b9e9e0d..e1aa0f3 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -3046,7 +3046,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
 	if (!t)
 		goto err;
 
-	for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) {
+	for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
 		t->neigh_vars[i].data += (long) p;
 		t->neigh_vars[i].extra1 = dev;
 		t->neigh_vars[i].extra2 = p;
-- 
1.8.5.3

^ permalink raw reply related

* (unknown), 
From: raffaello @ 2014-02-21 13:50 UTC (permalink / raw)
  To: netdev

unsubscribe raffaello@erg.abdn.ac.uk

^ permalink raw reply

* RE: [PATCH V4 net-next 2/5] xen-netback: Add support for multiple queues
From: David Laight @ 2014-02-21 13:16 UTC (permalink / raw)
  To: 'Andrew Bennieston', Paul Durrant,
	xen-devel@lists.xenproject.org
  Cc: Ian Campbell, Wei Liu, netdev@vger.kernel.org, David Vrabel
In-Reply-To: <53074490.8030806@citrix.com>

From: Of Andrew  Bennieston
> >> +	char *xspath = NULL;
> >
> > I don't think you need the NULL init here. xspath is set in both branches of the if statement below.
> 
> Indeed, but I prefer to initialise things sanely where possible. It
> makes it easier to spot problems with later modifications of the code,
> e.g. if one of those branches changed.

If you don't initialise it the compiler is likely to detect the
fact than one code path hasn't set it.
If you initialise it, the compiler doesn't.

	David


^ permalink raw reply

* Re: [PATCH 1/1] net: tcp: RTO restart
From: Eric Dumazet @ 2014-02-21 13:14 UTC (permalink / raw)
  To: Per Hurtig
  Cc: Andreas Petlund, netdev, David Miller, Eric Dumazet,
	Anna Brunström, Michael Welzl, Ilpo Järvinen
In-Reply-To: <1250EA19-2144-4AC2-A802-5B1989F74B80@kau.se>

On Fri, 2014-02-21 at 11:49 +0100, Per Hurtig wrote:
> On 19 Feb 2014, at 19:01, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> 
> > On Wed, 2014-02-19 at 18:17 +0100, Andreas Petlund wrote:
> >> I’ve applied and tested the patch on VMs with both 32 bit and 64 bit kernel.
> >> 
> >> Acked-by: Andreas Petlund <apetlund@simula.no>
> >> Tested-by: Andreas Petlund <apetlund@simula.no>
> > 
> > Sure the patch applies, but what experimental results did you get ?
> > 
> > My concern is that TCP_SKB_CB(skb)->when doesn't account for sojourn
> > time in host queues (qdisc and device). 
> > 
> 
> Correct me if I’m wrong, but I was under the impression that the sojourn was
> accounted for in the RTT calculations, and therefore rather inappropriate to
> be accounted for again? If this assumption is wrong, how would you propose that
> we account for the sojourn time?

This is a generic problem. 

Thats why I added LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES snmp counter,
so that we can experiment with the idea of not firing RTO while original
packet is still in the host qdisc.

       struct sk_buff *skb = tcp_write_queue_head(sk);
       const u32 rto_time_stamp = TCP_SKB_CB(skb)->when;
       s32 delta = (s32)(tcp_time_stamp - rto_time_stamp);

       if (delta > 0)
            rto -= delta;

Can trivially gives rto < 0, resulting in a timer of 120 seconds
(TCP_RTO_MAX)

^ permalink raw reply

* Re: Deliver skbs to intermediate interfaces, when using cascaded rx-handlers
From: Jiri Pirko @ 2014-02-21 13:05 UTC (permalink / raw)
  To: Tobias Waldekranz; +Cc: netdev
In-Reply-To: <20140221120244.GB25406@gmail.com>

Fri, Feb 21, 2014 at 01:02:44PM CET, tobias@waldekranz.com wrote:
>On Fri, Feb 21, 2014 at 12:37:53PM +0100, Jiri Pirko wrote:
>> Fri, Feb 21, 2014 at 12:12:57PM CET, tobias@waldekranz.com wrote:
>> >> What "switch driver" are you reffering to?
>> >> 
>> >
>> >The driver that is in charge of multiplexing packets from the switch
>> >chip out to the port interfaces. It registers an rx-handler on eth0
>> >and forwards packets to port[1-4] by reading a custom tag (similar to
>> >802.1Q) inserted by the switch.
>> 
>> Allright, but what's the name? I would like to find it and see the code.
>
>There's not really a name :), but I have made the source available on github:
>
>https://github.com/wkz/switchcore

Are you aware of existing DSA infrastructure?

>
>The relevant parts for this discussion should be in sc_main.c.
>
>> 
>> >
>> >-- 
>> >Thanks
>> > - wkz
>
>-- 
>Thanks
> - wkz

^ permalink raw reply

* Re: [RFC v2 2/4] net: enables interface option to skip IP
From: Zoltan Kiss @ 2014-02-21 13:02 UTC (permalink / raw)
  To: Luis R. Rodriguez
  Cc: Dan Williams, netdev@vger.kernel.org, xen-devel, kvm,
	linux-kernel@vger.kernel.org, David S. Miller, Alexey Kuznetsov,
	James Morris, Hideaki YOSHIFUJI, Patrick McHardy
In-Reply-To: <CAB=NE6VswYVF1BOM+vwEh3MaX7sh0gvLqz0U0JoEFDS-EzO9Pg@mail.gmail.com>

On 20/02/14 20:39, Luis R. Rodriguez wrote:
> On Wed, Feb 19, 2014 at 11:13 AM, Zoltan Kiss <zoltan.kiss@citrix.com> wrote:
>> On 19/02/14 17:20, Luis R. Rodriguez wrote:
>>>>> On 19/02/14 17:20, Luis R. Rodriguez also wrote:
>>>>> Zoltan has noted though some use cases of IPv4 or IPv6 addresses on
>>>>> backends though <...>
>>>
>>> As discussed in the other threads though there *is* some use cases
>>> of assigning IPv4 or IPv6 addresses to the backend interfaces though:
>>> routing them (although its unclear to me if iptables can be used
>>> instead, Zoltan?).
>>
>> Not with OVS, it steals the packet before netfilter hooks.
>
> Got it, thanks! Can't the route be added using a front-end IP address
> instead on the host though ? I just tried that on a Xen system and it
> seems to work. Perhaps I'm not understand the exact topology on the
> routing case. So in my case I have the backend without any IPv4 or
> IPv6 interfaces, the guest has IPv4, IPv6 addresses and even a TUN for
> VPN and I can create routes on the host to the front end by not using
> the backend device name but instead using the front-end target IP.
Check this how current Xen scripts does routed networking:

http://wiki.xen.org/wiki/Xen_Networking#Associating_routes_with_virtual_devices

Note, there are no bridges involved here! As the above page says, the 
backend has to have IP address, maybe it's not true anymore. I'm not too 
familiar with this setup too, I've used it only once.

Zoli

^ permalink raw reply

* Re: [Xen-devel] [RFC v2 1/4] bridge: enable interfaces to opt out from becoming the root bridge
From: Zoltan Kiss @ 2014-02-21 13:02 UTC (permalink / raw)
  To: Luis R. Rodriguez, Stephen Hemminger
  Cc: Ian Campbell, kvm, netdev@vger.kernel.org, bridge,
	linux-kernel@vger.kernel.org, xen-devel
In-Reply-To: <CAB=NE6WnMFkH7JPNt+ROiWEvhvZ03vdGr21STf75DV9fRaK=PA@mail.gmail.com>

On 20/02/14 20:24, Luis R. Rodriguez wrote:
> On Thu, Feb 20, 2014 at 9:19 AM, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
>> On Wed, 19 Feb 2014 09:59:33 -0800 "Luis R. Rodriguez" <mcgrof@do-not-panic.com> wrote:
>>> On Wed, Feb 19, 2014 at 9:08 AM, Stephen Hemminger <stephen@networkplumber.org> wrote:
>>>>
>>>> Please only use the netlink/sysfs flags fields that already exist
>>>> for new features.
>>>
>>> Sure, but what if we know a driver in most cases wants the root block
>>> and we'd want to make it the default, thereby only requiring userspace
>>> for toggling it off.
>>
>> Something in userspace has to put the device into the bridge.
>> Fix the port setup in that tool via the netlink or sysfs flags in
>> the bridge. It should not have to be handled in the bridge looking
>> at magic flags in the device.
>
> Agreed that's the best strategy and I'll work on sending patches to
> brctl to enable the root_block preference. This approach however also
I don't think brctl should deal with any Xen specific stuff. I assume 
there is a misunderstanding in this thread: when I (and possibly other 
Xen folks) talk about "userspace" or "toolstack" here, I mean Xen 
specific tools which use e.g. brctl to set up bridges. Not brctl itself.
> requires a userspace upgrade. I'm trying to see if we can get an
> old-nasty-cryptic-hack practice removed from the kernel and we'd try
> to prevent future drivers from using it -- without requiring userspace
> upgrade. In this case the bad practice is to using a high static MAC
> address for mimicking a root block default preference. In order to
> remove that *without* requiring a userspace upgrade the dev->priv_flag
> approach is the only thing I can think of. If this would go in we'd
> replace the high static MAC address with a random MAC address to
> prevent IPv6 SLAAC / DAD conflicts. I'd document this flag and
> indicate with preference for userspace to be the one tuning these
> knobs.
>
> Without this we'd have to keep the high static MAC address on upstream
> drivers and let userspace do the random'ization if it confirms the
> userspace knob to turn the root block flag is available. Is the
> priv_flag approach worth the compromise to remove the root block hack
> practice?
>
>    Luis
>

^ permalink raw reply

* Re: [Xen-devel] [RFC v2 1/4] bridge: enable interfaces to opt out from becoming the root bridge
From: Zoltan Kiss @ 2014-02-21 13:02 UTC (permalink / raw)
  To: Luis R. Rodriguez
  Cc: Stephen Hemminger, Ian Campbell, kvm, netdev@vger.kernel.org,
	bridge, linux-kernel@vger.kernel.org, xen-devel
In-Reply-To: <CAB=NE6WKhBJyyUO5o8B53J+F4PqF2PHvvbV3=yS3qs0ZDRKH7Q@mail.gmail.com>

On 20/02/14 20:01, Luis R. Rodriguez wrote:
> On Thu, Feb 20, 2014 at 5:19 AM, Zoltan Kiss <zoltan.kiss@citrix.com> wrote:
>> How about this: netback sets the root_block flag and a random MAC by
>> default. So the default behaviour won't change, DAD will be happy, and
>> userspace don't have to do anything unless it's using netback for STP root
>> bridge (I don't think there are too many toolstacks doing that), in which
>> case it has to remove the root_block flag instead of setting a random MAC.
>
> :D that's exactly what I ended up proposing too. I mentioned how
> xen-netback could do this as well, we'd keep or rename the flag I
> added, and then the bridge could would look at it and enable the root
> block if the flag is set. Stephen however does not like having the
> bridge code look at magic flags for this behavior and would prefer for
> us to get the tools to ask for the root block. Let's follow more up on
> that thread
We don't need that new flag, just forget about it. Set that root_block 
flag from netback device init, around the time you generate the random 
MAC, or at the earliest possible time. Nothing else has to be done from 
kernel side. If someone wants netback to be a root port, then remove 
root_block from their tools, instead of changing the the MAC address, as 
it happens now.
Another problem with the random addresses, pointed out by Ian earlier, 
that when adding/removing interfaces, the bridge does recalculate it's 
MAC address, and choose the lowest one. In the general usecase I think 
that's normal, but in case of Xen networking, we would like to keep the 
bridge using the physical interface's MAC, because the local port of the 
bridge is used for Dom0 network traffic, therefore changing the bridge 
MAC when a netback device has lower MAC breaks that traffic. I think the 
best is to address this from userspace: if it set the MAC of the bridge 
explicitly, dev_set_mac_address() does dev->addr_assign_type = 
NET_ADDR_SET;, so br_stp_recalculate_bridge_id() will exit before 
changing anything.
And when I say userspace, I mean Xen specific tools which does 
networking configuration, e.g. xapi in XenServer case. Not brctl, it 
doesn't have to know whether this is a xenbrX device or a bridge used 
for another purposes.

Zoli

^ permalink raw reply

* [PATCH V2] ss: Add support for retrieving SELinux contexts
From: Richard Haines @ 2014-02-21 12:34 UTC (permalink / raw)
  To: netdev, selinux; +Cc: Richard Haines

The process SELinux contexts can be added to the output using the -Z
option. Using the -z option will show the process and socket contexts (see
the man page for details).
For netlink sockets: if valid process show process context, if pid = 0
show kernel initial context, if unknown show "not available".

Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
---
 configure     |  15 +++
 man/man8/ss.8 |  34 ++++++
 misc/Makefile |  12 ++
 misc/ss.c     | 375 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 4 files changed, 386 insertions(+), 50 deletions(-)

diff --git a/configure b/configure
index da01c19..d5170f0 100755
--- a/configure
+++ b/configure
@@ -231,6 +231,18 @@ EOF
     rm -f $TMPDIR/ipsettest.c $TMPDIR/ipsettest
 }
 
+check_selinux()
+# SELinux is a compile time option in the ss utility
+{
+	if ${PKG_CONFIG} libselinux --exists
+	then
+		echo "HAVE_SELINUX:=y" >>Config
+		echo "yes"
+	else
+		echo "no"
+	fi
+}
+
 echo "# Generated config based on" $INCLUDE >Config
 check_toolchain
 
@@ -253,3 +265,6 @@ check_ipt_lib_dir
 
 echo -n "libc has setns: "
 check_setns
+
+echo -n "SELinux support: "
+check_selinux
diff --git a/man/man8/ss.8 b/man/man8/ss.8
index 807d9dc..d6e43ba 100644
--- a/man/man8/ss.8
+++ b/man/man8/ss.8
@@ -53,6 +53,37 @@ Print summary statistics. This option does not parse socket lists obtaining
 summary from various sources. It is useful when amount of sockets is so huge
 that parsing /proc/net/tcp is painful.
 .TP
+.B \-Z, \-\-context
+As the
+.B \-p
+option but also shows process security context.
+.sp
+For
+.BR netlink (7)
+sockets the initiating process context is displayed as follows:
+.RS
+.RS
+.IP "1." 4
+If valid pid show the process context.
+.IP "2." 4
+If destination is kernel (pid = 0) show kernel initial context.
+.IP "3." 4
+If a unique identifier has been allocated by the kernel or netlink user,
+show context as "not available". This will generally indicate that a
+process has more than one netlink socket active.
+.RE
+.RE
+.TP
+.B \-z, \-\-contexts
+As the
+.B \-Z
+option but also shows the socket context. The socket context is
+taken from the associated inode and is not the actual socket
+context held by the kernel. Sockets are typically labeled with the
+context of the creating process, however the context shown will reflect
+any policy role, type and/or range transition rules applied,
+and is therefore a useful reference.
+.TP
 .B \-b, \-\-bpf
 Show socket BPF filters (only administrators are allowed to get these information).
 .TP
@@ -103,6 +134,9 @@ Please take a look at the official documentation (Debian package iproute-doc) fo
 .B ss -t -a
 Display all TCP sockets.
 .TP
+.B ss -t -a -Z
+Display all TCP sockets with process SELinux security contexts.
+.TP
 .B ss -u -a
 Display all UDP sockets.
 .TP
diff --git a/misc/Makefile b/misc/Makefile
index a59ff87..d1f295b 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -8,6 +8,18 @@ include ../Config
 all: $(TARGETS)
 
 ss: $(SSOBJ)
+ifeq ($(HAVE_SELINUX),y)
+	$(CC) $(LDFLAGS) -o $@ $(SSOBJ) $(LDLIBS) $(shell pkg-config --libs libselinux)
+else
+	$(CC) $(LDFLAGS) -o $@ $(SSOBJ) $(LDLIBS)
+endif
+
+ss.o: ss.c
+ifeq ($(HAVE_SELINUX),y)
+	$(CC) $(CFLAGS) $(shell pkg-config --cflags libselinux) -DHAVE_SELINUX -c $+
+else
+	$(CC) $(CFLAGS) -c $+
+endif
 
 nstat: nstat.c
 	$(CC) $(CFLAGS) $(LDFLAGS) -o nstat nstat.c -lm
diff --git a/misc/ss.c b/misc/ss.c
index ce6a0a8..c1b1617 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -40,6 +40,9 @@
 #include <linux/filter.h>
 #include <linux/packet_diag.h>
 #include <linux/netlink_diag.h>
+#if HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
 
 int resolve_hosts = 0;
 int resolve_services = 1;
@@ -50,6 +53,12 @@ int show_users = 0;
 int show_mem = 0;
 int show_tcpinfo = 0;
 int show_bpf = 0;
+#if HAVE_SELINUX
+int show_proc_ctx = 0;
+int show_sock_ctx = 0;
+/* If show_users & show_proc_ctx only do user_ent_hash_build() once */
+int user_ent_hash_build_init = 0;
+#endif
 
 int netid_width;
 int state_width;
@@ -207,7 +216,11 @@ struct user_ent {
 	unsigned int	ino;
 	int		pid;
 	int		fd;
-	char		process[0];
+	char	*process;
+#if HAVE_SELINUX
+	char	*process_ctx;
+	char	*socket_ctx;
+#endif
 };
 
 #define USER_ENT_HASH_SIZE	256
@@ -220,26 +233,58 @@ static int user_ent_hashfn(unsigned int ino)
 	return val & (USER_ENT_HASH_SIZE - 1);
 }
 
-static void user_ent_add(unsigned int ino, const char *process, int pid, int fd)
+#if HAVE_SELINUX
+static void user_ent_add(unsigned int ino, char *process,
+					int pid, int fd,
+					char *proc_ctx,
+					char *sock_ctx)
+#else
+static void user_ent_add(unsigned int ino, char *process, int pid, int fd)
+#endif
 {
 	struct user_ent *p, **pp;
-	int str_len;
 
-	str_len = strlen(process) + 1;
-	p = malloc(sizeof(struct user_ent) + str_len);
-	if (!p)
+	p = malloc(sizeof(struct user_ent));
+	if (!p) {
+		fprintf(stderr, "ss: failed to malloc buffer\n");
 		abort();
+	}
 	p->next = NULL;
 	p->ino = ino;
 	p->pid = pid;
 	p->fd = fd;
-	strcpy(p->process, process);
+	p->process = strdup(process);
+#if HAVE_SELINUX
+	p->process_ctx = strdup(proc_ctx);
+	p->socket_ctx = strdup(sock_ctx);
+#endif
 
 	pp = &user_ent_hash[user_ent_hashfn(ino)];
 	p->next = *pp;
 	*pp = p;
 }
 
+static void user_ent_destroy(void)
+{
+	struct user_ent *p, *p_next;
+	int cnt = 0;
+
+	while (cnt != USER_ENT_HASH_SIZE) {
+		p = user_ent_hash[cnt];
+		while (p) {
+			free(p->process);
+#if HAVE_SELINUX
+			freecon(p->process_ctx);
+			freecon(p->socket_ctx);
+#endif
+			p_next = p->next;
+			free(p);
+			p = p_next;
+		}
+		cnt++;
+	}
+}
+
 static void user_ent_hash_build(void)
 {
 	const char *root = getenv("PROC_ROOT") ? : "/proc/";
@@ -247,6 +292,17 @@ static void user_ent_hash_build(void)
 	char name[1024];
 	int nameoff;
 	DIR *dir;
+#if HAVE_SELINUX
+	char *pid_context;
+	char *sock_context;
+	char *no_ctx = "not available";
+
+	/* If show_users and show_proc_ctx set only do this once */
+	if (user_ent_hash_build_init != 0)
+		return;
+
+	user_ent_hash_build_init = 1;
+#endif
 
 	strcpy(name, root);
 	if (strlen(name) == 0 || name[strlen(name)-1] != '/')
@@ -261,19 +317,24 @@ static void user_ent_hash_build(void)
 	while ((d = readdir(dir)) != NULL) {
 		struct dirent *d1;
 		char process[16];
+		char *p;
 		int pid, pos;
 		DIR *dir1;
 		char crap;
 
 		if (sscanf(d->d_name, "%d%c", &pid, &crap) != 1)
 			continue;
-
+#if HAVE_SELINUX
+		if (getpidcon(pid, &pid_context) != 0)
+			pid_context = strdup(no_ctx);
+#endif
 		sprintf(name + nameoff, "%d/fd/", pid);
 		pos = strlen(name);
 		if ((dir1 = opendir(name)) == NULL)
 			continue;
 
 		process[0] = '\0';
+		p = process;
 
 		while ((d1 = readdir(dir1)) != NULL) {
 			const char *pattern = "socket:[";
@@ -281,6 +342,7 @@ static void user_ent_hash_build(void)
 			char lnk[64];
 			int fd;
 			ssize_t link_len;
+			char tmp[1024];
 
 			if (sscanf(d1->d_name, "%d%c", &fd, &crap) != 1)
 				continue;
@@ -296,56 +358,122 @@ static void user_ent_hash_build(void)
 				continue;
 
 			sscanf(lnk, "socket:[%u]", &ino);
-
-			if (process[0] == '\0') {
-				char tmp[1024];
+#if HAVE_SELINUX
+			snprintf(tmp, sizeof(tmp), "%s/%d/fd/%s",
+					root, pid, d1->d_name);
+
+			if (getfilecon(tmp, &sock_context) < 0)
+				sock_context = strdup(no_ctx);
+#endif
+			if (*p == '\0') {
 				FILE *fp;
 
-				snprintf(tmp, sizeof(tmp), "%s/%d/stat", root, pid);
+				snprintf(tmp, sizeof(tmp), "%s/%d/stat",
+					root, pid);
 				if ((fp = fopen(tmp, "r")) != NULL) {
-					fscanf(fp, "%*d (%[^)])", process);
+					fscanf(fp, "%*d (%[^)])", p);
 					fclose(fp);
 				}
 			}
-
-			user_ent_add(ino, process, pid, fd);
+#if HAVE_SELINUX
+			user_ent_add(ino, p, pid, fd,
+				pid_context, sock_context);
+			freecon(sock_context);
 		}
+		freecon(pid_context);
 		closedir(dir1);
+#else
+			user_ent_add(ino, p, pid, fd);
+		}
+		closedir(dir1);
+#endif
 	}
 	closedir(dir);
 }
 
-static int find_users(unsigned ino, char *buf, int buflen)
+#if HAVE_SELINUX
+enum entry_types {
+	USERS,
+	PROC_CTX,
+	PROC_SOCK_CTX
+};
+#else
+enum entry_types {
+	USERS
+};
+#endif
+
+#define ENTRY_BUF_SIZE 512
+static int find_entry(unsigned ino, char **buf, int type)
 {
 	struct user_ent *p;
 	int cnt = 0;
 	char *ptr;
+	char **new_buf = buf;
+	int len, new_buf_len;
+	int buf_used = 0;
+	int buf_len = 0;
 
 	if (!ino)
 		return 0;
 
 	p = user_ent_hash[user_ent_hashfn(ino)];
-	ptr = buf;
+	ptr = *buf = NULL;
 	while (p) {
 		if (p->ino != ino)
 			goto next;
 
-		if (ptr - buf >= buflen - 1)
-			break;
+		while (1) {
+			ptr = *buf + buf_used;
+			switch (type) {
+			case USERS:
+				len = snprintf(ptr, buf_len - buf_used,
+					"(\"%s\",pid=%d,fd=%d),",
+					p->process, p->pid, p->fd);
+				break;
+#if HAVE_SELINUX
+			case PROC_CTX:
+				len = snprintf(ptr, buf_len - buf_used,
+					"(\"%s\",pid=%d,proc_ctx=%s,fd=%d),",
+					p->process, p->pid,
+					p->process_ctx, p->fd);
+				break;
+			case PROC_SOCK_CTX:
+				len = snprintf(ptr, buf_len - buf_used,
+					"(\"%s\",pid=%d,proc_ctx=%s,fd=%d,sock_ctx=%s),",
+					p->process, p->pid,
+					p->process_ctx, p->fd,
+					p->socket_ctx);
+				break;
+#endif
+			default:
+				fprintf(stderr, "ss: invalid type: %d\n", type);
+				abort();
+			}
 
-		snprintf(ptr, buflen - (ptr - buf),
-			 "(\"%s\",%d,%d),",
-			 p->process, p->pid, p->fd);
-		ptr += strlen(ptr);
+			if (len < 0 || len >= buf_len - buf_used) {
+				new_buf_len = buf_len + ENTRY_BUF_SIZE;
+				*new_buf = realloc(*buf, new_buf_len);
+				if (!new_buf) {
+					fprintf(stderr, "ss: failed to malloc buffer\n");
+					abort();
+				}
+				**buf = **new_buf;
+				buf_len = new_buf_len;
+				continue;
+			} else {
+				buf_used += len;
+				break;
+			}
+		}
 		cnt++;
-
-	next:
+next:
 		p = p->next;
 	}
-
-	if (ptr != buf)
+	if (buf_used) {
+		ptr = *buf + buf_used;
 		ptr[-1] = '\0';
-
+	}
 	return cnt;
 }
 
@@ -1289,11 +1417,25 @@ static int tcp_show_line(char *line, const struct filter *f, int family)
 		if (s.qack&1)
 			printf(" bidir");
 	}
+	char *buf = NULL;
+#if HAVE_SELINUX
+	if (show_proc_ctx || show_sock_ctx) {
+		if (find_entry(s.ino, &buf,
+					(show_proc_ctx & show_sock_ctx) ?
+					PROC_SOCK_CTX : PROC_CTX) > 0) {
+			printf(" users:(%s)", buf);
+			free(buf);
+		}
+	} else if (show_users) {
+#else
 	if (show_users) {
-		char ubuf[4096];
-		if (find_users(s.ino, ubuf, sizeof(ubuf)) > 0)
-			printf(" users:(%s)", ubuf);
+#endif
+		if (find_entry(s.ino, &buf, USERS) > 0) {
+			printf(" users:(%s)", buf);
+			free(buf);
+		}
 	}
+
 	if (show_details) {
 		if (s.uid)
 			printf(" uid:%u", (unsigned)s.uid);
@@ -1527,11 +1669,25 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol)
 			       r->idiag_retrans);
 		}
 	}
+	char *buf = NULL;
+#if HAVE_SELINUX
+	if (show_proc_ctx || show_sock_ctx) {
+		if (find_entry(r->idiag_inode, &buf,
+					(show_proc_ctx & show_sock_ctx) ?
+					PROC_SOCK_CTX : PROC_CTX) > 0) {
+			printf(" users:(%s)", buf);
+			free(buf);
+		}
+	} else if (show_users) {
+#else
 	if (show_users) {
-		char ubuf[4096];
-		if (find_users(r->idiag_inode, ubuf, sizeof(ubuf)) > 0)
-			printf(" users:(%s)", ubuf);
+#endif
+		if (find_entry(r->idiag_inode, &buf, USERS) > 0) {
+			printf(" users:(%s)", buf);
+			free(buf);
+		}
 	}
+
 	if (show_details) {
 		if (r->idiag_uid)
 			printf(" uid:%u", (unsigned)r->idiag_uid);
@@ -2016,10 +2172,23 @@ static int dgram_show_line(char *line, const struct filter *f, int family)
 	formatted_print(&s.local, s.lport, 0);
 	formatted_print(&s.remote, s.rport, 0);
 
+	char *buf = NULL;
+#if HAVE_SELINUX
+	if (show_proc_ctx || show_sock_ctx) {
+		if (find_entry(s.ino, &buf,
+				(show_proc_ctx & show_sock_ctx) ?
+				PROC_SOCK_CTX : PROC_CTX) > 0) {
+			printf(" users:(%s)", buf);
+			free(buf);
+		}
+	} else if (show_users) {
+#else
 	if (show_users) {
-		char ubuf[4096];
-		if (find_users(s.ino, ubuf, sizeof(ubuf)) > 0)
-			printf(" users:(%s)", ubuf);
+#endif
+		if (find_entry(s.ino, &buf, USERS) > 0) {
+			printf(" users:(%s)", buf);
+			free(buf);
+		}
 	}
 
 	if (show_details) {
@@ -2206,10 +2375,23 @@ static void unix_list_print(struct unixstat *list, struct filter *f)
 		printf("%*s %-*d %*s %-*d",
 		       addr_width, s->name ? : "*", serv_width, s->ino,
 		       addr_width, peer, serv_width, s->peer);
+		char *buf = NULL;
+#if HAVE_SELINUX
+		if (show_proc_ctx || show_sock_ctx) {
+			if (find_entry(s->ino, &buf,
+					(show_proc_ctx & show_sock_ctx) ?
+					PROC_SOCK_CTX : PROC_CTX) > 0) {
+				printf(" users:(%s)", buf);
+				free(buf);
+			}
+		} else if (show_users) {
+#else
 		if (show_users) {
-			char ubuf[4096];
-			if (find_users(s->ino, ubuf, sizeof(ubuf)) > 0)
-				printf(" users:(%s)", ubuf);
+#endif
+			if (find_entry(s->ino, &buf, USERS) > 0) {
+				printf(" users:(%s)", buf);
+				free(buf);
+			}
 		}
 		printf("\n");
 	}
@@ -2271,10 +2453,23 @@ static int unix_show_sock(struct nlmsghdr *nlh, struct filter *f)
 			addr_width, "*", /* FIXME */
 			serv_width, peer_ino);
 
+	char *buf = NULL;
+#if HAVE_SELINUX
+	if (show_proc_ctx || show_sock_ctx) {
+		if (find_entry(r->udiag_ino, &buf,
+				(show_proc_ctx & show_sock_ctx) ?
+				PROC_SOCK_CTX : PROC_CTX) > 0) {
+			printf(" users:(%s)", buf);
+			free(buf);
+		}
+	} else if (show_users) {
+#else
 	if (show_users) {
-		char ubuf[4096];
-		if (find_users(r->udiag_ino, ubuf, sizeof(ubuf)) > 0)
-			printf(" users:(%s)", ubuf);
+#endif
+		if (find_entry(r->udiag_ino, &buf, USERS) > 0) {
+			printf(" users:(%s)", buf);
+			free(buf);
+		}
 	}
 
 	if (show_mem) {
@@ -2532,11 +2727,25 @@ static int packet_show_sock(struct nlmsghdr *nlh, struct filter *f)
 	printf("%*s*%-*s",
 	       addr_width, "", serv_width, "");
 
+	char *buf = NULL;
+#if HAVE_SELINUX
+	if (show_proc_ctx || show_sock_ctx) {
+		if (find_entry(r->pdiag_ino, &buf,
+				(show_proc_ctx & show_sock_ctx) ?
+				PROC_SOCK_CTX : PROC_CTX) > 0) {
+			printf(" users:(%s)", buf);
+			free(buf);
+		}
+	} else if (show_users) {
+#else
 	if (show_users) {
-		char ubuf[4096];
-		if (find_users(r->pdiag_ino, ubuf, sizeof(ubuf)) > 0)
-			printf(" users:(%s)", ubuf);
+#endif
+		if (find_entry(r->pdiag_ino, &buf, USERS) > 0) {
+			printf(" users:(%s)", buf);
+			free(buf);
+		}
 	}
+
 	if (show_details) {
 		__u32 uid = 0;
 
@@ -2727,11 +2936,25 @@ static int packet_show(struct filter *f)
 		printf("%*s*%-*s",
 		       addr_width, "", serv_width, "");
 
+		char *buf = NULL;
+#if HAVE_SELINUX
+		if (show_proc_ctx || show_sock_ctx) {
+			if (find_entry(ino, &buf,
+					(show_proc_ctx & show_sock_ctx) ?
+					PROC_SOCK_CTX : PROC_CTX) > 0) {
+				printf(" users:(%s)", buf);
+				free(buf);
+			}
+		} else if (show_users) {
+#else
 		if (show_users) {
-			char ubuf[4096];
-			if (find_users(ino, ubuf, sizeof(ubuf)) > 0)
-				printf(" users:(%s)", ubuf);
+#endif
+			if (find_entry(ino, &buf, USERS) > 0) {
+				printf(" users:(%s)", buf);
+				free(buf);
+			}
 		}
+
 		if (show_details) {
 			printf(" ino=%u uid=%u sk=%llx", ino, uid, sk);
 		}
@@ -2806,6 +3029,29 @@ static void netlink_show_one(struct filter *f,
 		printf("%*s*%-*s",
 		       addr_width, "", serv_width, "");
 	}
+#if HAVE_SELINUX
+	char *pid_context = NULL;
+
+	if (show_proc_ctx) {
+		/* The pid value will either be:
+		 *   0 if destination kernel - show kernel initial context.
+		 *   A valid process pid - use getpidcon.
+		 *   A unique value allocated by the kernel or netlink user
+		 *   to the process - show context as "not available".
+		 */
+		if (!pid)
+			security_get_initial_context("kernel", &pid_context);
+		else if (pid > 0)
+			getpidcon(pid, &pid_context);
+
+		if (pid_context != NULL) {
+			printf("proc_ctx=%-*s ", serv_width, pid_context);
+			freecon(pid_context);
+		} else {
+			printf("proc_ctx=%-*s ", serv_width, "not available");
+		}
+	}
+# endif
 
 	if (show_details) {
 		printf(" sk=%llx cb=%llx groups=0x%08x", sk, cb, groups);
@@ -3081,6 +3327,8 @@ static void _usage(FILE *dest)
 "   -i, --info		show internal TCP information\n"
 "   -s, --summary	show socket usage summary\n"
 "   -b, --bpf           show bpf filter socket information\n"
+"   -Z, --context	display process SELinux security contexts\n"
+"   -z, --contexts	display process and socket SELinux security contexts\n"
 "\n"
 "   -4, --ipv4          display only IP version 4 sockets\n"
 "   -6, --ipv6          display only IP version 6 sockets\n"
@@ -3170,6 +3418,8 @@ static const struct option long_opts[] = {
 	{ "filter", 1, 0, 'F' },
 	{ "version", 0, 0, 'V' },
 	{ "help", 0, 0, 'h' },
+	{ "context", 0, 0, 'Z' },
+	{ "contexts", 0, 0, 'z' },
 	{ 0 }
 
 };
@@ -3188,7 +3438,7 @@ int main(int argc, char *argv[])
 
 	current_filter.states = default_filter.states;
 
-	while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbf:miA:D:F:vV",
+	while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbf:miA:D:F:vVzZ",
 				 long_opts, NULL)) != EOF) {
 		switch(ch) {
 		case 'n':
@@ -3348,6 +3598,23 @@ int main(int argc, char *argv[])
 		case 'V':
 			printf("ss utility, iproute2-ss%s\n", SNAPSHOT);
 			exit(0);
+		case 'z':
+#if HAVE_SELINUX
+			show_sock_ctx++;
+#endif
+		case 'Z':
+#if HAVE_SELINUX
+			if (is_selinux_enabled() <= 0) {
+				fprintf(stderr, "ss: SELinux is not enabled.\n");
+				exit(1);
+			}
+			show_proc_ctx++;
+			user_ent_hash_build();
+#else
+			fprintf(stderr, "ss: version does not support SELinux.\n");
+			exit(1);
+#endif
+			break;
 		case 'h':
 		case '?':
 			help();
@@ -3535,5 +3802,13 @@ int main(int argc, char *argv[])
 		tcp_show(&current_filter, IPPROTO_TCP);
 	if (current_filter.dbs & (1<<DCCP_DB))
 		tcp_show(&current_filter, IPPROTO_DCCP);
+
+#if HAVE_SELINUX
+	if (show_users || show_proc_ctx || show_sock_ctx)
+#else
+	if (show_users)
+#endif
+		user_ent_destroy();
+
 	return 0;
 }
-- 
1.8.5.3

^ permalink raw reply related

* Re: [PATCH] ss: Add support for retrieving SELinux contexts
From: Richard Haines @ 2014-02-21 12:27 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	selinux-+05T5uksL2qpZYMLLGbcSA@public.gmane.org
In-Reply-To: <1392556690.15615.97.camel-nDn/Rdv9kqW9Jme8/bJn5UCKIB8iOfG2tUK59QYPAWc@public.gmane.org>

I've updated the patch with your suggestions and rebuild using the latest git
repository. Will send V2 patch today.

Thanks
Richard



----- Original Message -----
> From: Ben Hutchings <ben-/+tVBieCtBitmTQ+vhA3Yw@public.gmane.org>
> To: Richard Haines <richard_c_haines-FhtRXb7CoQBt1OO0OYaSVA@public.gmane.org>
> Cc: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; selinux-+05T5uksL2qpZYMLLGbcSA@public.gmane.org
> Sent: Sunday, 16 February 2014, 13:18
> Subject: Re: [PATCH] ss: Add support for retrieving SELinux contexts
> 
> On Fri, 2014-02-14 at 15:20 +0000, Richard Haines wrote:
>>  The process SELinux contexts can be added to the output using the -Z
>>  option. Using the -z option will show the process and socket contexts (see
>>  the man page for details).
>>  For netlink sockets: if valid process show process context, if pid = 0
>>  show kernel initial context, if unknown show "not available".
>> 
>>  Signed-off-by: Richard Haines <richard_c_haines-FhtRXb7CoQBt1OO0OYaSVA@public.gmane.org>
>>  ---
>>   configure     |  16 +++
>>   man/man8/ss.8 |  34 ++++++
>>   misc/Makefile |  12 ++
>>   misc/ss.c     | 375 
> ++++++++++++++++++++++++++++++++++++++++++++++++++--------
>>   4 files changed, 387 insertions(+), 50 deletions(-)
>> 
>>  diff --git a/configure b/configure
>>  index da01c19..854837e 100755
>>  --- a/configure
>>  +++ b/configure
>>  @@ -231,6 +231,19 @@ EOF
>>       rm -f $TMPDIR/ipsettest.c $TMPDIR/ipsettest
>>   }
>>   
>>  +check_selinux()
>>  +# SELinux is a compile time option in the ss utility
>>  +{
>>  +    SELINUX_LIB=$(${PKG_CONFIG} --silence-errors libselinux --libs)
>>  +    if [ -n "$SELINUX_LIB" ]
> 
> This should be just:
>     if pkg-config libselinux --exists
> 
>>  +    then
>>  +    echo "HAVE_SELINUX:=y" >>Config
>>  +    echo "yes"
>>  +    else
>>  +    echo "no"
>>  +    fi
>>  +}
> [...]
>>  --- a/misc/Makefile
>>  +++ b/misc/Makefile
>>  @@ -8,6 +8,18 @@ include ../Config
>>   all: $(TARGETS)
>>   
>>   ss: $(SSOBJ)
>>  +ifeq ($(HAVE_SELINUX),y)
>>  +    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(SSOBJ) $(LDLIBS) -lselinux
> 
> This should use the output of 'pkg-config libselinux --libs'.
> 
>>  +else
>>  +    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(SSOBJ) $(LDLIBS)
>>  +endif
>>  +
>>  +ss.o: ss.c
>>  +ifeq ($(HAVE_SELINUX),y)
>>  +    $(CC) $(CFLAGS) -DHAVE_SELINUX -c $+
> 
> This should use the output of 'pkg-config libselinux --cflags'.
> 
>>  +else
>>  +    $(CC) $(CFLAGS) -c $+
>>  +endif
> [...]
> 
> Ben.
> 
> -- 
> Ben Hutchings
> Any sufficiently advanced bug is indistinguishable from a feature.
> 

_______________________________________________
Selinux mailing list
Selinux-+05T5uksL2qpZYMLLGbcSA@public.gmane.org
To unsubscribe, send email to Selinux-leave-+05T5uksL2pAGbPMOrvdOA@public.gmane.org
To get help, send an email containing "help" to Selinux-request-+05T5uksL2pUKDJzkOSz4g@public.gmane.orgov.

^ permalink raw reply

* RE: [PATCH V4 net-next 1/5] xen-netback: Factor queue-specific data into queue struct.
From: Paul Durrant @ 2014-02-21 12:24 UTC (permalink / raw)
  To: Andrew Bennieston, xen-devel@lists.xenproject.org
  Cc: Ian Campbell, Wei Liu, netdev@vger.kernel.org, David Vrabel
In-Reply-To: <53074518.5010506@citrix.com>

> -----Original Message-----
[snip]
> >
> > Any reason why this is not in xenvif_stats? If  it were there then it would
> not need to be atomic.
> The expectation was that it wouldn't be used very often, so an atomic
> op. here wouldn't hurt. I can move it to xenvif_stats if you'd prefer,
> though. I think the use of an atomic pre-dated the xenvif_stats struct,
> so maybe it makes sense to move it there now.
> 

I think so. Seems odd to leave it out on its own.

  Paul

^ permalink raw reply

* Re: [PATCH V4 net-next 2/5] xen-netback: Add support for multiple queues
From: Andrew Bennieston @ 2014-02-21 12:24 UTC (permalink / raw)
  To: David Vrabel
  Cc: Paul Durrant, xen-devel@lists.xenproject.org, Ian Campbell,
	Wei Liu, netdev@vger.kernel.org
In-Reply-To: <53074510.2040408@citrix.com>

On 21/02/14 12:22, David Vrabel wrote:
>>>> +    char *xspath = NULL;
>>>
>>> I don't think you need the NULL init here. xspath is set in both
>>> branches of the if statement below.
>>
>> Indeed, but I prefer to initialise things sanely where possible. It
>> makes it easier to spot problems with later modifications of the code,
>> e.g. if one of those branches changed.
>
> Kernel style (but probably not documented anywhere) is to only
> initialize locals were necessary.
>
> David
>
Ok, I'll remove the NULL initialiser then.

Andrew

^ permalink raw reply

* Re: [PATCH V4 net-next 5/5] xen-net{back,front}: Document multi-queue feature in netif.h
From: Andrew Bennieston @ 2014-02-21 12:24 UTC (permalink / raw)
  To: Paul Durrant, xen-devel@lists.xenproject.org
  Cc: Ian Campbell, Wei Liu, netdev@vger.kernel.org, David Vrabel
In-Reply-To: <9AAE0902D5BC7E449B7C8E4E778ABCD0255359@AMSPEX01CL01.citrite.net>

On 21/02/14 12:22, Paul Durrant wrote:
>> -----Original Message-----
>> From: Andrew J. Bennieston [mailto:andrew.bennieston@citrix.com]
>> Sent: 17 February 2014 17:58
>> To: xen-devel@lists.xenproject.org
>> Cc: Ian Campbell; Wei Liu; Paul Durrant; netdev@vger.kernel.org; David
>> Vrabel; Andrew Bennieston
>> Subject: [PATCH V4 net-next 5/5] xen-net{back,front}: Document multi-
>> queue feature in netif.h
>>
>> From: "Andrew J. Bennieston" <andrew.bennieston@citrix.com>
>>
>> Document the multi-queue feature in terms of XenStore keys to be written
>> by the backend and by the frontend.
>>
>> Signed-off-by: Andrew J. Bennieston <andrew.bennieston@citrix.com>
>> ---
>>   include/xen/interface/io/netif.h |   21 +++++++++++++++++++++
>>   1 file changed, 21 insertions(+)
>>
>> diff --git a/include/xen/interface/io/netif.h
>> b/include/xen/interface/io/netif.h
>> index c50061d..8868c51 100644
>> --- a/include/xen/interface/io/netif.h
>> +++ b/include/xen/interface/io/netif.h
>> @@ -51,6 +51,27 @@
>>    */
>>
>>   /*
>> + * Multiple transmit and receive queues:
>> + * If supported, the backend will write "multi-queue-max-queues" and set
>> its
>> + * value to the maximum supported number of queues.
>> + * Frontends that are aware of this feature and wish to use it can write the
>> + * key "multi-queue-num-queues", set to the number they wish to use.
>> + *
>> + * Queues replicate the shared rings and event channels, and
>> + * "feature-split-event-channels" is required when using multiple queues.
>> + *
>
> Is it? The code in patch 2 appears to cope with the "event-channel" key as well as the split variants regardless of the number of queues being used. Am I missing some other restriction?
>
Hmm, perhaps I just assumed that limitation. I'll check and update the 
doc accordingly.

Andrew

>    Paul
>
>> + * For frontends requesting just one queue, the usual event-channel and
>> + * ring-ref keys are written as before, simplifying the backend processing
>> + * to avoid distinguishing between a frontend that doesn't understand the
>> + * multi-queue feature, and one that does, but requested only one queue.
>> + *
>> + * Frontends requesting two or more queues must not write the toplevel
>> + * event-channel and ring-ref keys, instead writing them under sub-keys
>> having
>> + * the name "queue-N" where N is the integer ID of the queue for which
>> those
>> + * keys belong. Queues are indexed from zero.
>> + */
>> +
>> +/*
>>    * "feature-no-csum-offload" should be used to turn IPv4 TCP/UDP
>> checksum
>>    * offload off or on. If it is missing then the feature is assumed to be on.
>>    * "feature-ipv6-csum-offload" should be used to turn IPv6 TCP/UDP
>> checksum
>> --
>> 1.7.10.4
>

^ permalink raw reply

* Re: [PATCH V4 net-next 2/5] xen-netback: Add support for multiple queues
From: David Vrabel @ 2014-02-21 12:22 UTC (permalink / raw)
  To: Andrew Bennieston
  Cc: Paul Durrant, xen-devel@lists.xenproject.org, Ian Campbell,
	Wei Liu, netdev@vger.kernel.org
In-Reply-To: <53074490.8030806@citrix.com>

>>> +    char *xspath = NULL;
>>
>> I don't think you need the NULL init here. xspath is set in both
>> branches of the if statement below.
> 
> Indeed, but I prefer to initialise things sanely where possible. It
> makes it easier to spot problems with later modifications of the code,
> e.g. if one of those branches changed.

Kernel style (but probably not documented anywhere) is to only
initialize locals were necessary.

David

^ permalink raw reply

* Re: [PATCH V4 net-next 1/5] xen-netback: Factor queue-specific data into queue struct.
From: Andrew Bennieston @ 2014-02-21 12:22 UTC (permalink / raw)
  To: Paul Durrant, xen-devel@lists.xenproject.org
  Cc: Ian Campbell, Wei Liu, netdev@vger.kernel.org, David Vrabel
In-Reply-To: <9AAE0902D5BC7E449B7C8E4E778ABCD02552E8@AMSPEX01CL01.citrite.net>

On 21/02/14 12:08, Paul Durrant wrote:
>> -----Original Message-----
>> From: Andrew J. Bennieston [mailto:andrew.bennieston@citrix.com]
>> Sent: 17 February 2014 17:58
>> To: xen-devel@lists.xenproject.org
>> Cc: Ian Campbell; Wei Liu; Paul Durrant; netdev@vger.kernel.org; David
>> Vrabel; Andrew Bennieston
>> Subject: [PATCH V4 net-next 1/5] xen-netback: Factor queue-specific data
>> into queue struct.
>>
>> From: "Andrew J. Bennieston" <andrew.bennieston@citrix.com>
>>
>> In preparation for multi-queue support in xen-netback, move the
>> queue-specific data from struct xenvif into struct xenvif_queue, and
>> update the rest of the code to use this.
>>
>> Also adds loops over queues where appropriate, even though only one is
>> configured at this point, and uses alloc_netdev_mq() and the
>> corresponding multi-queue netif wake/start/stop functions in preparation
>> for multiple active queues.
>>
>> Finally, implements a trivial queue selection function suitable for
>> ndo_select_queue, which simply returns 0 for a single queue and uses
>> skb_get_hash() to compute the queue index otherwise.
>>
>> Signed-off-by: Andrew J. Bennieston <andrew.bennieston@citrix.com>
>> ---
>>   drivers/net/xen-netback/common.h    |   81 ++++--
>>   drivers/net/xen-netback/interface.c |  314 ++++++++++++++-------
>>   drivers/net/xen-netback/netback.c   |  528 ++++++++++++++++++------------
>> -----
>>   drivers/net/xen-netback/xenbus.c    |   87 ++++--
>>   4 files changed, 593 insertions(+), 417 deletions(-)
>>
>> diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-
>> netback/common.h
>> index ae413a2..2550867 100644
>> --- a/drivers/net/xen-netback/common.h
>> +++ b/drivers/net/xen-netback/common.h
>> @@ -108,17 +108,36 @@ struct xenvif_rx_meta {
>>    */
>>   #define MAX_GRANT_COPY_OPS (MAX_SKB_FRAGS *
>> XEN_NETIF_RX_RING_SIZE)
>>
>> -struct xenvif {
>> -	/* Unique identifier for this interface. */
>> -	domid_t          domid;
>> -	unsigned int     handle;
>> +/* Queue name is interface name with "-qNNN" appended */
>> +#define QUEUE_NAME_SIZE (IFNAMSIZ + 6)
>> +
>
> '-qNNN' is only 5 chars. Are you accounting for a NUL terminator too?

Almost certainly...

>
>> +/* IRQ name is queue name with "-tx" or "-rx" appended */
>> +#define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 4)
>> +
>
> If yes, then you appear to have doubly accounted for it here.

... yup, looks that way. I'll fix this.

>
>> +struct xenvif;
>> +
>> +struct xenvif_stats {
>> +	/* Stats fields to be updated per-queue.
>> +	 * A subset of struct net_device_stats that contains only the
>> +	 * fields that are updated in netback.c for each queue.
>> +	 */
>> +	unsigned int rx_bytes;
>> +	unsigned int rx_packets;
>> +	unsigned int tx_bytes;
>> +	unsigned int tx_packets;
>> +};
>> +
>> +struct xenvif_queue { /* Per-queue data for xenvif */
>> +	unsigned int id; /* Queue ID, 0-based */
>> +	char name[QUEUE_NAME_SIZE]; /* DEVNAME-qN */
>> +	struct xenvif *vif; /* Parent VIF */
>>
>>   	/* Use NAPI for guest TX */
>>   	struct napi_struct napi;
>>   	/* When feature-split-event-channels = 0, tx_irq = rx_irq. */
>>   	unsigned int tx_irq;
>>   	/* Only used when feature-split-event-channels = 1 */
>> -	char tx_irq_name[IFNAMSIZ+4]; /* DEVNAME-tx */
>> +	char tx_irq_name[IRQ_NAME_SIZE]; /* DEVNAME-qN-tx */
>>   	struct xen_netif_tx_back_ring tx;
>>   	struct sk_buff_head tx_queue;
>>   	struct page *mmap_pages[MAX_PENDING_REQS];
>> @@ -140,19 +159,34 @@ struct xenvif {
>>   	/* When feature-split-event-channels = 0, tx_irq = rx_irq. */
>>   	unsigned int rx_irq;
>>   	/* Only used when feature-split-event-channels = 1 */
>> -	char rx_irq_name[IFNAMSIZ+4]; /* DEVNAME-rx */
>> +	char rx_irq_name[IRQ_NAME_SIZE]; /* DEVNAME-qN-rx */
>>   	struct xen_netif_rx_back_ring rx;
>>   	struct sk_buff_head rx_queue;
>>   	RING_IDX rx_last_skb_slots;
>>
>> -	/* This array is allocated seperately as it is large */
>> -	struct gnttab_copy *grant_copy_op;
>> +	struct gnttab_copy grant_copy_op[MAX_GRANT_COPY_OPS];
>>
>>   	/* We create one meta structure per ring request we consume, so
>>   	 * the maximum number is the same as the ring size.
>>   	 */
>>   	struct xenvif_rx_meta meta[XEN_NETIF_RX_RING_SIZE];
>>
>> +	/* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
>> +	unsigned long   credit_bytes;
>> +	unsigned long   credit_usec;
>> +	unsigned long   remaining_credit;
>> +	struct timer_list credit_timeout;
>> +	u64 credit_window_start;
>> +
>> +	/* Statistics */
>> +	struct xenvif_stats stats;
>> +};
>> +
>> +struct xenvif {
>> +	/* Unique identifier for this interface. */
>> +	domid_t          domid;
>> +	unsigned int     handle;
>> +
>>   	u8               fe_dev_addr[6];
>>
>>   	/* Frontend feature information. */
>> @@ -166,15 +200,12 @@ struct xenvif {
>>   	/* Internal feature information. */
>>   	u8 can_queue:1;	    /* can queue packets for receiver? */
>>
>> -	/* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
>> -	unsigned long   credit_bytes;
>> -	unsigned long   credit_usec;
>> -	unsigned long   remaining_credit;
>> -	struct timer_list credit_timeout;
>> -	u64 credit_window_start;
>> +	/* Queues */
>> +	unsigned int num_queues;
>> +	struct xenvif_queue *queues;
>>
>>   	/* Statistics */
>> -	unsigned long rx_gso_checksum_fixup;
>> +	atomic_t rx_gso_checksum_fixup;
>
> Any reason why this is not in xenvif_stats? If  it were there then it would not need to be atomic.
The expectation was that it wouldn't be used very often, so an atomic 
op. here wouldn't hurt. I can move it to xenvif_stats if you'd prefer, 
though. I think the use of an atomic pre-dated the xenvif_stats struct, 
so maybe it makes sense to move it there now.

Andrew.

>
>    Paul
>

^ permalink raw reply

* RE: [PATCH V4 net-next 5/5] xen-net{back,front}: Document multi-queue feature in netif.h
From: Paul Durrant @ 2014-02-21 12:22 UTC (permalink / raw)
  To: Andrew Bennieston, xen-devel@lists.xenproject.org
  Cc: Ian Campbell, Wei Liu, netdev@vger.kernel.org, David Vrabel,
	Andrew Bennieston
In-Reply-To: <1392659880-2538-6-git-send-email-andrew.bennieston@citrix.com>

> -----Original Message-----
> From: Andrew J. Bennieston [mailto:andrew.bennieston@citrix.com]
> Sent: 17 February 2014 17:58
> To: xen-devel@lists.xenproject.org
> Cc: Ian Campbell; Wei Liu; Paul Durrant; netdev@vger.kernel.org; David
> Vrabel; Andrew Bennieston
> Subject: [PATCH V4 net-next 5/5] xen-net{back,front}: Document multi-
> queue feature in netif.h
> 
> From: "Andrew J. Bennieston" <andrew.bennieston@citrix.com>
> 
> Document the multi-queue feature in terms of XenStore keys to be written
> by the backend and by the frontend.
> 
> Signed-off-by: Andrew J. Bennieston <andrew.bennieston@citrix.com>
> ---
>  include/xen/interface/io/netif.h |   21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
> 
> diff --git a/include/xen/interface/io/netif.h
> b/include/xen/interface/io/netif.h
> index c50061d..8868c51 100644
> --- a/include/xen/interface/io/netif.h
> +++ b/include/xen/interface/io/netif.h
> @@ -51,6 +51,27 @@
>   */
> 
>  /*
> + * Multiple transmit and receive queues:
> + * If supported, the backend will write "multi-queue-max-queues" and set
> its
> + * value to the maximum supported number of queues.
> + * Frontends that are aware of this feature and wish to use it can write the
> + * key "multi-queue-num-queues", set to the number they wish to use.
> + *
> + * Queues replicate the shared rings and event channels, and
> + * "feature-split-event-channels" is required when using multiple queues.
> + *

Is it? The code in patch 2 appears to cope with the "event-channel" key as well as the split variants regardless of the number of queues being used. Am I missing some other restriction?

  Paul

> + * For frontends requesting just one queue, the usual event-channel and
> + * ring-ref keys are written as before, simplifying the backend processing
> + * to avoid distinguishing between a frontend that doesn't understand the
> + * multi-queue feature, and one that does, but requested only one queue.
> + *
> + * Frontends requesting two or more queues must not write the toplevel
> + * event-channel and ring-ref keys, instead writing them under sub-keys
> having
> + * the name "queue-N" where N is the integer ID of the queue for which
> those
> + * keys belong. Queues are indexed from zero.
> + */
> +
> +/*
>   * "feature-no-csum-offload" should be used to turn IPv4 TCP/UDP
> checksum
>   * offload off or on. If it is missing then the feature is assumed to be on.
>   * "feature-ipv6-csum-offload" should be used to turn IPv6 TCP/UDP
> checksum
> --
> 1.7.10.4

^ permalink raw reply

* Re: [PATCH V4 net-next 2/5] xen-netback: Add support for multiple queues
From: Andrew Bennieston @ 2014-02-21 12:20 UTC (permalink / raw)
  To: Paul Durrant, xen-devel@lists.xenproject.org
  Cc: Ian Campbell, Wei Liu, netdev@vger.kernel.org, David Vrabel
In-Reply-To: <9AAE0902D5BC7E449B7C8E4E778ABCD0255316@AMSPEX01CL01.citrite.net>

On 21/02/14 12:13, Paul Durrant wrote:
>> -----Original Message-----
>> From: Andrew J. Bennieston [mailto:andrew.bennieston@citrix.com]
>> Sent: 17 February 2014 17:58
>> To: xen-devel@lists.xenproject.org
>> Cc: Ian Campbell; Wei Liu; Paul Durrant; netdev@vger.kernel.org; David
>> Vrabel; Andrew Bennieston
>> Subject: [PATCH V4 net-next 2/5] xen-netback: Add support for multiple
>> queues
>>
>> From: "Andrew J. Bennieston" <andrew.bennieston@citrix.com>
>>
>> Builds on the refactoring of the previous patch to implement multiple
>> queues between xen-netfront and xen-netback.
>>
>> Writes the maximum supported number of queues into XenStore, and reads
>> the values written by the frontend to determine how many queues to use.
>>
>> Ring references and event channels are read from XenStore on a per-queue
>> basis and rings are connected accordingly.
>>
>> Signed-off-by: Andrew J. Bennieston <andrew.bennieston@citrix.com>
>> ---
>>   drivers/net/xen-netback/common.h    |    2 +
>>   drivers/net/xen-netback/interface.c |    7 +++-
>>   drivers/net/xen-netback/netback.c   |    8 ++++
>>   drivers/net/xen-netback/xenbus.c    |   76
>> ++++++++++++++++++++++++++++++-----
>>   4 files changed, 82 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-
>> netback/common.h
>> index 2550867..8180929 100644
>> --- a/drivers/net/xen-netback/common.h
>> +++ b/drivers/net/xen-netback/common.h
>> @@ -261,4 +261,6 @@ void xenvif_carrier_on(struct xenvif *vif);
>>
>>   extern bool separate_tx_rx_irq;
>>
>> +extern unsigned int xenvif_max_queues;
>> +
>>   #endif /* __XEN_NETBACK__COMMON_H__ */
>> diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-
>> netback/interface.c
>> index daf93f6..bc7a82d 100644
>> --- a/drivers/net/xen-netback/interface.c
>> +++ b/drivers/net/xen-netback/interface.c
>> @@ -373,7 +373,12 @@ struct xenvif *xenvif_alloc(struct device *parent,
>> domid_t domid,
>>   	char name[IFNAMSIZ] = {};
>>
>>   	snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
>> -	dev = alloc_netdev_mq(sizeof(struct xenvif), name, ether_setup, 1);
>> +	/* Allocate a netdev with the max. supported number of queues.
>> +	 * When the guest selects the desired number, it will be updated
>> +	 * via netif_set_real_num_tx_queues().
>> +	 */
>> +	dev = alloc_netdev_mq(sizeof(struct xenvif), name, ether_setup,
>> +			      xenvif_max_queues);
>>   	if (dev == NULL) {
>>   		pr_warn("Could not allocate netdev for %s\n", name);
>>   		return ERR_PTR(-ENOMEM);
>> diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-
>> netback/netback.c
>> index 46b2f5b..64d66a1 100644
>> --- a/drivers/net/xen-netback/netback.c
>> +++ b/drivers/net/xen-netback/netback.c
>> @@ -54,6 +54,11 @@
>>   bool separate_tx_rx_irq = 1;
>>   module_param(separate_tx_rx_irq, bool, 0644);
>>
>> +unsigned int xenvif_max_queues;
>> +module_param(xenvif_max_queues, uint, 0644);
>> +MODULE_PARM_DESC(xenvif_max_queues,
>> +		"Maximum number of queues per virtual interface");
>> +
>>   /*
>>    * This is the maximum slots a skb can have. If a guest sends a skb
>>    * which exceeds this limit it is considered malicious.
>> @@ -1585,6 +1590,9 @@ static int __init netback_init(void)
>>   	if (!xen_domain())
>>   		return -ENODEV;
>>
>> +	/* Allow as many queues as there are CPUs, by default */
>> +	xenvif_max_queues = num_online_cpus();
>> +
>>   	if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) {
>>   		pr_info("fatal_skb_slots too small (%d), bump it to
>> XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n",
>>   			fatal_skb_slots, XEN_NETBK_LEGACY_SLOTS_MAX);
>> diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-
>> netback/xenbus.c
>> index f23ea0a..d11f51e 100644
>> --- a/drivers/net/xen-netback/xenbus.c
>> +++ b/drivers/net/xen-netback/xenbus.c
>> @@ -20,6 +20,7 @@
>>
>>   #include "common.h"
>>   #include <linux/vmalloc.h>
>> +#include <linux/rtnetlink.h>
>>
>>   struct backend_info {
>>   	struct xenbus_device *dev;
>> @@ -159,6 +160,12 @@ static int netback_probe(struct xenbus_device *dev,
>>   	if (err)
>>   		pr_debug("Error writing feature-split-event-channels\n");
>>
>> +	/* Multi-queue support: This is an optional feature. */
>> +	err = xenbus_printf(XBT_NIL, dev->nodename,
>> +			"multi-queue-max-queues", "%u",
>> xenvif_max_queues);
>> +	if (err)
>> +		pr_debug("Error writing multi-queue-max-queues\n");
>> +
>>   	err = xenbus_switch_state(dev, XenbusStateInitWait);
>>   	if (err)
>>   		goto fail;
>> @@ -490,6 +497,23 @@ static void connect(struct backend_info *be)
>>   	unsigned long credit_bytes, credit_usec;
>>   	unsigned int queue_index;
>>   	struct xenvif_queue *queue;
>> +	unsigned int requested_num_queues;
>> +
>> +	/* Check whether the frontend requested multiple queues
>> +	 * and read the number requested.
>> +	 */
>> +	err = xenbus_scanf(XBT_NIL, dev->otherend,
>> +			"multi-queue-num-queues",
>> +			"%u", &requested_num_queues);
>> +	if (err < 0) {
>> +		requested_num_queues = 1; /* Fall back to single queue */
>> +	} else if (requested_num_queues > xenvif_max_queues) {
>> +		/* buggy or malicious guest */
>> +		xenbus_dev_fatal(dev, err,
>> +			"guest requested %u queues, exceeding the
>> maximum of %u.",
>> +			requested_num_queues, xenvif_max_queues);
>> +		return;
>> +	}
>>
>>   	err = xen_net_read_mac(dev, be->vif->fe_dev_addr);
>>   	if (err) {
>> @@ -500,9 +524,13 @@ static void connect(struct backend_info *be)
>>   	xen_net_read_rate(dev, &credit_bytes, &credit_usec);
>>   	read_xenbus_vif_flags(be);
>>
>> -	be->vif->num_queues = 1;
>> +	/* Use the number of queues requested by the frontend */
>> +	be->vif->num_queues = requested_num_queues;
>>   	be->vif->queues = vzalloc(be->vif->num_queues *
>>   			sizeof(struct xenvif_queue));
>> +	rtnl_lock();
>> +	netif_set_real_num_tx_queues(be->vif->dev, be->vif-
>>> num_queues);
>> +	rtnl_unlock();
>>
>>   	for (queue_index = 0; queue_index < be->vif->num_queues;
>> ++queue_index) {
>>   		queue = &be->vif->queues[queue_index];
>> @@ -547,29 +575,52 @@ static int connect_rings(struct backend_info *be,
>> struct xenvif_queue *queue)
>>   	unsigned long tx_ring_ref, rx_ring_ref;
>>   	unsigned int tx_evtchn, rx_evtchn;
>>   	int err;
>> +	char *xspath = NULL;
>
> I don't think you need the NULL init here. xspath is set in both branches of the if statement below.

Indeed, but I prefer to initialise things sanely where possible. It 
makes it easier to spot problems with later modifications of the code, 
e.g. if one of those branches changed.

Andrew.
>
>    Paul
>
>> +	size_t xspathsize;
>> +	const size_t xenstore_path_ext_size = 11; /* sufficient for "/queue-
>> NNN" */
>> +
>> +	/* If the frontend requested 1 queue, or we have fallen back
>> +	 * to single queue due to lack of frontend support for multi-
>> +	 * queue, expect the remaining XenStore keys in the toplevel
>> +	 * directory. Otherwise, expect them in a subdirectory called
>> +	 * queue-N.
>> +	 */
>> +	if (queue->vif->num_queues == 1) {
>> +		xspath = (char *)dev->otherend;
>> +	} else {
>> +		xspathsize = strlen(dev->otherend) +
>> xenstore_path_ext_size;
>> +		xspath = kzalloc(xspathsize, GFP_KERNEL);
>> +		if (!xspath) {
>> +			xenbus_dev_fatal(dev, -ENOMEM,
>> +					"reading ring references");
>> +			return -ENOMEM;
>> +		}
>> +		snprintf(xspath, xspathsize, "%s/queue-%u", dev-
>>> otherend,
>> +				 queue->id);
>> +	}
>>
>> -	err = xenbus_gather(XBT_NIL, dev->otherend,
>> +	err = xenbus_gather(XBT_NIL, xspath,
>>   			    "tx-ring-ref", "%lu", &tx_ring_ref,
>>   			    "rx-ring-ref", "%lu", &rx_ring_ref, NULL);
>>   	if (err) {
>>   		xenbus_dev_fatal(dev, err,
>>   				 "reading %s/ring-ref",
>> -				 dev->otherend);
>> -		return err;
>> +				 xspath);
>> +		goto err;
>>   	}
>>
>>   	/* Try split event channels first, then single event channel. */
>> -	err = xenbus_gather(XBT_NIL, dev->otherend,
>> +	err = xenbus_gather(XBT_NIL, xspath,
>>   			    "event-channel-tx", "%u", &tx_evtchn,
>>   			    "event-channel-rx", "%u", &rx_evtchn, NULL);
>>   	if (err < 0) {
>> -		err = xenbus_scanf(XBT_NIL, dev->otherend,
>> +		err = xenbus_scanf(XBT_NIL, xspath,
>>   				   "event-channel", "%u", &tx_evtchn);
>>   		if (err < 0) {
>>   			xenbus_dev_fatal(dev, err,
>>   					 "reading %s/event-channel(-tx/rx)",
>> -					 dev->otherend);
>> -			return err;
>> +					 xspath);
>> +			goto err;
>>   		}
>>   		rx_evtchn = tx_evtchn;
>>   	}
>> @@ -582,10 +633,15 @@ static int connect_rings(struct backend_info *be,
>> struct xenvif_queue *queue)
>>   				 "mapping shared-frames %lu/%lu port tx %u
>> rx %u",
>>   				 tx_ring_ref, rx_ring_ref,
>>   				 tx_evtchn, rx_evtchn);
>> -		return err;
>> +		goto err;
>>   	}
>>
>> -	return 0;
>> +	err = 0;
>> +err: /* Regular return falls through with err == 0 */
>> +	if (xspath != dev->otherend)
>> +		kfree(xspath);
>> +
>> +	return err;
>>   }
>>
>>   static int read_xenbus_vif_flags(struct backend_info *be)
>> --
>> 1.7.10.4
>

^ permalink raw reply

* RE: [PATCH V4 net-next 2/5] xen-netback: Add support for multiple queues
From: Paul Durrant @ 2014-02-21 12:13 UTC (permalink / raw)
  To: Andrew Bennieston, xen-devel@lists.xenproject.org
  Cc: Ian Campbell, Wei Liu, netdev@vger.kernel.org, David Vrabel,
	Andrew Bennieston
In-Reply-To: <1392659880-2538-3-git-send-email-andrew.bennieston@citrix.com>

> -----Original Message-----
> From: Andrew J. Bennieston [mailto:andrew.bennieston@citrix.com]
> Sent: 17 February 2014 17:58
> To: xen-devel@lists.xenproject.org
> Cc: Ian Campbell; Wei Liu; Paul Durrant; netdev@vger.kernel.org; David
> Vrabel; Andrew Bennieston
> Subject: [PATCH V4 net-next 2/5] xen-netback: Add support for multiple
> queues
> 
> From: "Andrew J. Bennieston" <andrew.bennieston@citrix.com>
> 
> Builds on the refactoring of the previous patch to implement multiple
> queues between xen-netfront and xen-netback.
> 
> Writes the maximum supported number of queues into XenStore, and reads
> the values written by the frontend to determine how many queues to use.
> 
> Ring references and event channels are read from XenStore on a per-queue
> basis and rings are connected accordingly.
> 
> Signed-off-by: Andrew J. Bennieston <andrew.bennieston@citrix.com>
> ---
>  drivers/net/xen-netback/common.h    |    2 +
>  drivers/net/xen-netback/interface.c |    7 +++-
>  drivers/net/xen-netback/netback.c   |    8 ++++
>  drivers/net/xen-netback/xenbus.c    |   76
> ++++++++++++++++++++++++++++++-----
>  4 files changed, 82 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-
> netback/common.h
> index 2550867..8180929 100644
> --- a/drivers/net/xen-netback/common.h
> +++ b/drivers/net/xen-netback/common.h
> @@ -261,4 +261,6 @@ void xenvif_carrier_on(struct xenvif *vif);
> 
>  extern bool separate_tx_rx_irq;
> 
> +extern unsigned int xenvif_max_queues;
> +
>  #endif /* __XEN_NETBACK__COMMON_H__ */
> diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-
> netback/interface.c
> index daf93f6..bc7a82d 100644
> --- a/drivers/net/xen-netback/interface.c
> +++ b/drivers/net/xen-netback/interface.c
> @@ -373,7 +373,12 @@ struct xenvif *xenvif_alloc(struct device *parent,
> domid_t domid,
>  	char name[IFNAMSIZ] = {};
> 
>  	snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
> -	dev = alloc_netdev_mq(sizeof(struct xenvif), name, ether_setup, 1);
> +	/* Allocate a netdev with the max. supported number of queues.
> +	 * When the guest selects the desired number, it will be updated
> +	 * via netif_set_real_num_tx_queues().
> +	 */
> +	dev = alloc_netdev_mq(sizeof(struct xenvif), name, ether_setup,
> +			      xenvif_max_queues);
>  	if (dev == NULL) {
>  		pr_warn("Could not allocate netdev for %s\n", name);
>  		return ERR_PTR(-ENOMEM);
> diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-
> netback/netback.c
> index 46b2f5b..64d66a1 100644
> --- a/drivers/net/xen-netback/netback.c
> +++ b/drivers/net/xen-netback/netback.c
> @@ -54,6 +54,11 @@
>  bool separate_tx_rx_irq = 1;
>  module_param(separate_tx_rx_irq, bool, 0644);
> 
> +unsigned int xenvif_max_queues;
> +module_param(xenvif_max_queues, uint, 0644);
> +MODULE_PARM_DESC(xenvif_max_queues,
> +		"Maximum number of queues per virtual interface");
> +
>  /*
>   * This is the maximum slots a skb can have. If a guest sends a skb
>   * which exceeds this limit it is considered malicious.
> @@ -1585,6 +1590,9 @@ static int __init netback_init(void)
>  	if (!xen_domain())
>  		return -ENODEV;
> 
> +	/* Allow as many queues as there are CPUs, by default */
> +	xenvif_max_queues = num_online_cpus();
> +
>  	if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) {
>  		pr_info("fatal_skb_slots too small (%d), bump it to
> XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n",
>  			fatal_skb_slots, XEN_NETBK_LEGACY_SLOTS_MAX);
> diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-
> netback/xenbus.c
> index f23ea0a..d11f51e 100644
> --- a/drivers/net/xen-netback/xenbus.c
> +++ b/drivers/net/xen-netback/xenbus.c
> @@ -20,6 +20,7 @@
> 
>  #include "common.h"
>  #include <linux/vmalloc.h>
> +#include <linux/rtnetlink.h>
> 
>  struct backend_info {
>  	struct xenbus_device *dev;
> @@ -159,6 +160,12 @@ static int netback_probe(struct xenbus_device *dev,
>  	if (err)
>  		pr_debug("Error writing feature-split-event-channels\n");
> 
> +	/* Multi-queue support: This is an optional feature. */
> +	err = xenbus_printf(XBT_NIL, dev->nodename,
> +			"multi-queue-max-queues", "%u",
> xenvif_max_queues);
> +	if (err)
> +		pr_debug("Error writing multi-queue-max-queues\n");
> +
>  	err = xenbus_switch_state(dev, XenbusStateInitWait);
>  	if (err)
>  		goto fail;
> @@ -490,6 +497,23 @@ static void connect(struct backend_info *be)
>  	unsigned long credit_bytes, credit_usec;
>  	unsigned int queue_index;
>  	struct xenvif_queue *queue;
> +	unsigned int requested_num_queues;
> +
> +	/* Check whether the frontend requested multiple queues
> +	 * and read the number requested.
> +	 */
> +	err = xenbus_scanf(XBT_NIL, dev->otherend,
> +			"multi-queue-num-queues",
> +			"%u", &requested_num_queues);
> +	if (err < 0) {
> +		requested_num_queues = 1; /* Fall back to single queue */
> +	} else if (requested_num_queues > xenvif_max_queues) {
> +		/* buggy or malicious guest */
> +		xenbus_dev_fatal(dev, err,
> +			"guest requested %u queues, exceeding the
> maximum of %u.",
> +			requested_num_queues, xenvif_max_queues);
> +		return;
> +	}
> 
>  	err = xen_net_read_mac(dev, be->vif->fe_dev_addr);
>  	if (err) {
> @@ -500,9 +524,13 @@ static void connect(struct backend_info *be)
>  	xen_net_read_rate(dev, &credit_bytes, &credit_usec);
>  	read_xenbus_vif_flags(be);
> 
> -	be->vif->num_queues = 1;
> +	/* Use the number of queues requested by the frontend */
> +	be->vif->num_queues = requested_num_queues;
>  	be->vif->queues = vzalloc(be->vif->num_queues *
>  			sizeof(struct xenvif_queue));
> +	rtnl_lock();
> +	netif_set_real_num_tx_queues(be->vif->dev, be->vif-
> >num_queues);
> +	rtnl_unlock();
> 
>  	for (queue_index = 0; queue_index < be->vif->num_queues;
> ++queue_index) {
>  		queue = &be->vif->queues[queue_index];
> @@ -547,29 +575,52 @@ static int connect_rings(struct backend_info *be,
> struct xenvif_queue *queue)
>  	unsigned long tx_ring_ref, rx_ring_ref;
>  	unsigned int tx_evtchn, rx_evtchn;
>  	int err;
> +	char *xspath = NULL;

I don't think you need the NULL init here. xspath is set in both branches of the if statement below. 

  Paul

> +	size_t xspathsize;
> +	const size_t xenstore_path_ext_size = 11; /* sufficient for "/queue-
> NNN" */
> +
> +	/* If the frontend requested 1 queue, or we have fallen back
> +	 * to single queue due to lack of frontend support for multi-
> +	 * queue, expect the remaining XenStore keys in the toplevel
> +	 * directory. Otherwise, expect them in a subdirectory called
> +	 * queue-N.
> +	 */
> +	if (queue->vif->num_queues == 1) {
> +		xspath = (char *)dev->otherend;
> +	} else {
> +		xspathsize = strlen(dev->otherend) +
> xenstore_path_ext_size;
> +		xspath = kzalloc(xspathsize, GFP_KERNEL);
> +		if (!xspath) {
> +			xenbus_dev_fatal(dev, -ENOMEM,
> +					"reading ring references");
> +			return -ENOMEM;
> +		}
> +		snprintf(xspath, xspathsize, "%s/queue-%u", dev-
> >otherend,
> +				 queue->id);
> +	}
> 
> -	err = xenbus_gather(XBT_NIL, dev->otherend,
> +	err = xenbus_gather(XBT_NIL, xspath,
>  			    "tx-ring-ref", "%lu", &tx_ring_ref,
>  			    "rx-ring-ref", "%lu", &rx_ring_ref, NULL);
>  	if (err) {
>  		xenbus_dev_fatal(dev, err,
>  				 "reading %s/ring-ref",
> -				 dev->otherend);
> -		return err;
> +				 xspath);
> +		goto err;
>  	}
> 
>  	/* Try split event channels first, then single event channel. */
> -	err = xenbus_gather(XBT_NIL, dev->otherend,
> +	err = xenbus_gather(XBT_NIL, xspath,
>  			    "event-channel-tx", "%u", &tx_evtchn,
>  			    "event-channel-rx", "%u", &rx_evtchn, NULL);
>  	if (err < 0) {
> -		err = xenbus_scanf(XBT_NIL, dev->otherend,
> +		err = xenbus_scanf(XBT_NIL, xspath,
>  				   "event-channel", "%u", &tx_evtchn);
>  		if (err < 0) {
>  			xenbus_dev_fatal(dev, err,
>  					 "reading %s/event-channel(-tx/rx)",
> -					 dev->otherend);
> -			return err;
> +					 xspath);
> +			goto err;
>  		}
>  		rx_evtchn = tx_evtchn;
>  	}
> @@ -582,10 +633,15 @@ static int connect_rings(struct backend_info *be,
> struct xenvif_queue *queue)
>  				 "mapping shared-frames %lu/%lu port tx %u
> rx %u",
>  				 tx_ring_ref, rx_ring_ref,
>  				 tx_evtchn, rx_evtchn);
> -		return err;
> +		goto err;
>  	}
> 
> -	return 0;
> +	err = 0;
> +err: /* Regular return falls through with err == 0 */
> +	if (xspath != dev->otherend)
> +		kfree(xspath);
> +
> +	return err;
>  }
> 
>  static int read_xenbus_vif_flags(struct backend_info *be)
> --
> 1.7.10.4

^ permalink raw reply

* Re: [PATCH V4 net-next 1/5] xen-netback: Factor queue-specific data into queue struct.
From: Paul Durrant @ 2014-02-21 12:08 UTC (permalink / raw)
  To: Andrew Bennieston, xen-devel@lists.xenproject.org
  Cc: Andrew Bennieston, netdev@vger.kernel.org, Wei Liu, Ian Campbell,
	David Vrabel
In-Reply-To: <1392659880-2538-2-git-send-email-andrew.bennieston@citrix.com>

> -----Original Message-----
> From: Andrew J. Bennieston [mailto:andrew.bennieston@citrix.com]
> Sent: 17 February 2014 17:58
> To: xen-devel@lists.xenproject.org
> Cc: Ian Campbell; Wei Liu; Paul Durrant; netdev@vger.kernel.org; David
> Vrabel; Andrew Bennieston
> Subject: [PATCH V4 net-next 1/5] xen-netback: Factor queue-specific data
> into queue struct.
> 
> From: "Andrew J. Bennieston" <andrew.bennieston@citrix.com>
> 
> In preparation for multi-queue support in xen-netback, move the
> queue-specific data from struct xenvif into struct xenvif_queue, and
> update the rest of the code to use this.
> 
> Also adds loops over queues where appropriate, even though only one is
> configured at this point, and uses alloc_netdev_mq() and the
> corresponding multi-queue netif wake/start/stop functions in preparation
> for multiple active queues.
> 
> Finally, implements a trivial queue selection function suitable for
> ndo_select_queue, which simply returns 0 for a single queue and uses
> skb_get_hash() to compute the queue index otherwise.
> 
> Signed-off-by: Andrew J. Bennieston <andrew.bennieston@citrix.com>
> ---
>  drivers/net/xen-netback/common.h    |   81 ++++--
>  drivers/net/xen-netback/interface.c |  314 ++++++++++++++-------
>  drivers/net/xen-netback/netback.c   |  528 ++++++++++++++++++------------
> -----
>  drivers/net/xen-netback/xenbus.c    |   87 ++++--
>  4 files changed, 593 insertions(+), 417 deletions(-)
> 
> diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-
> netback/common.h
> index ae413a2..2550867 100644
> --- a/drivers/net/xen-netback/common.h
> +++ b/drivers/net/xen-netback/common.h
> @@ -108,17 +108,36 @@ struct xenvif_rx_meta {
>   */
>  #define MAX_GRANT_COPY_OPS (MAX_SKB_FRAGS *
> XEN_NETIF_RX_RING_SIZE)
> 
> -struct xenvif {
> -	/* Unique identifier for this interface. */
> -	domid_t          domid;
> -	unsigned int     handle;
> +/* Queue name is interface name with "-qNNN" appended */
> +#define QUEUE_NAME_SIZE (IFNAMSIZ + 6)
> +

'-qNNN' is only 5 chars. Are you accounting for a NUL terminator too?

> +/* IRQ name is queue name with "-tx" or "-rx" appended */
> +#define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 4)
> +

If yes, then you appear to have doubly accounted for it here.

> +struct xenvif;
> +
> +struct xenvif_stats {
> +	/* Stats fields to be updated per-queue.
> +	 * A subset of struct net_device_stats that contains only the
> +	 * fields that are updated in netback.c for each queue.
> +	 */
> +	unsigned int rx_bytes;
> +	unsigned int rx_packets;
> +	unsigned int tx_bytes;
> +	unsigned int tx_packets;
> +};
> +
> +struct xenvif_queue { /* Per-queue data for xenvif */
> +	unsigned int id; /* Queue ID, 0-based */
> +	char name[QUEUE_NAME_SIZE]; /* DEVNAME-qN */
> +	struct xenvif *vif; /* Parent VIF */
> 
>  	/* Use NAPI for guest TX */
>  	struct napi_struct napi;
>  	/* When feature-split-event-channels = 0, tx_irq = rx_irq. */
>  	unsigned int tx_irq;
>  	/* Only used when feature-split-event-channels = 1 */
> -	char tx_irq_name[IFNAMSIZ+4]; /* DEVNAME-tx */
> +	char tx_irq_name[IRQ_NAME_SIZE]; /* DEVNAME-qN-tx */
>  	struct xen_netif_tx_back_ring tx;
>  	struct sk_buff_head tx_queue;
>  	struct page *mmap_pages[MAX_PENDING_REQS];
> @@ -140,19 +159,34 @@ struct xenvif {
>  	/* When feature-split-event-channels = 0, tx_irq = rx_irq. */
>  	unsigned int rx_irq;
>  	/* Only used when feature-split-event-channels = 1 */
> -	char rx_irq_name[IFNAMSIZ+4]; /* DEVNAME-rx */
> +	char rx_irq_name[IRQ_NAME_SIZE]; /* DEVNAME-qN-rx */
>  	struct xen_netif_rx_back_ring rx;
>  	struct sk_buff_head rx_queue;
>  	RING_IDX rx_last_skb_slots;
> 
> -	/* This array is allocated seperately as it is large */
> -	struct gnttab_copy *grant_copy_op;
> +	struct gnttab_copy grant_copy_op[MAX_GRANT_COPY_OPS];
> 
>  	/* We create one meta structure per ring request we consume, so
>  	 * the maximum number is the same as the ring size.
>  	 */
>  	struct xenvif_rx_meta meta[XEN_NETIF_RX_RING_SIZE];
> 
> +	/* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
> +	unsigned long   credit_bytes;
> +	unsigned long   credit_usec;
> +	unsigned long   remaining_credit;
> +	struct timer_list credit_timeout;
> +	u64 credit_window_start;
> +
> +	/* Statistics */
> +	struct xenvif_stats stats;
> +};
> +
> +struct xenvif {
> +	/* Unique identifier for this interface. */
> +	domid_t          domid;
> +	unsigned int     handle;
> +
>  	u8               fe_dev_addr[6];
> 
>  	/* Frontend feature information. */
> @@ -166,15 +200,12 @@ struct xenvif {
>  	/* Internal feature information. */
>  	u8 can_queue:1;	    /* can queue packets for receiver? */
> 
> -	/* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
> -	unsigned long   credit_bytes;
> -	unsigned long   credit_usec;
> -	unsigned long   remaining_credit;
> -	struct timer_list credit_timeout;
> -	u64 credit_window_start;
> +	/* Queues */
> +	unsigned int num_queues;
> +	struct xenvif_queue *queues;
> 
>  	/* Statistics */
> -	unsigned long rx_gso_checksum_fixup;
> +	atomic_t rx_gso_checksum_fixup;

Any reason why this is not in xenvif_stats? If  it were there then it would not need to be atomic.

  Paul

^ 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