DPDK patches and discussions
 help / color / mirror / Atom feed
From: wangyunjian <wangyunjian@huawei.com>
To: <dev@dpdk.org>
Cc: <xudingke@huawei.com>, Yunjian Wang <wangyunjian@huawei.com>,
	<stable@dpdk.org>
Subject: [dpdk-dev] [PATCH] net/i40e: fix crash when calling i40e_vsi_delete_mac
Date: Sat, 13 Apr 2019 17:54:51 +0800	[thread overview]
Message-ID: <1555149291-12432-1-git-send-email-wangyunjian@huawei.com> (raw)

From: Yunjian Wang <wangyunjian@huawei.com>

Now the macvlan filter list may be accessed in the same time by two
different threads and may cause a lot of optional errors. This patch
protects the macvlan filter access with a spinlock.

Call Trace:
  #1  0x00007ffb4cbe2e3c in i40e_vsi_delete_mac (vsi=vsi@entry=
      0x400052804b40, addr=addr@entry=0x7ffb47672244) at /usr/src/
      debug/dpdk-18.11/drivers/net/i40e/i40e_ethdev.c:7266
  #2  0x00007ffb4cbe342b in i40e_set_default_mac_addr (dev=<optimized out>,
      mac_addr=0x400052a6618d) at /usr/src/debug/dpdk-18.11/drivers/net/
	  i40e/i40e_ethdev.c:11893
  #3  0x00007ffb4f569d4a in rte_eth_dev_default_mac_addr_set (port_id=
      <optimized out>, addr=addr@entry=0x400052a6618d) at /usr/src/debug/
	  dpdk-18.11/lib/librte_ethdev/rte_ethdev.c:3366
  #4  0x00007ffb4d0bb403 in mac_address_slaves_update (bonded_eth_dev=
      bonded_eth_dev@entry=0xacf8c0 <rte_eth_devices>) at /usr/src/debug/
	  dpdk-18.11/drivers/net/bonding/rte_eth_bond_pmd.c:1854
  #5  0x00007ffb4d0bd221 in bond_ethdev_lsc_event_callback (port_id=
      <optimized out>, type=<optimized out>, param=<optimized out>,
      ret_param= <optimized out>) at /usr/src/debug/dpdk-18.11/drivers/
      net/bonding/rte_eth_bond_pmd.c:3076
  #6  0x00007ffb4f56aa09 in _rte_eth_dev_callback_process (dev=dev@entry=
      0xad3940 <rte_eth_devices+16512>, event=event@entry=
      RTE_ETH_EVENT_INTR_LSC, ret_param=ret_param@entry=0x0)
      at /usr/src/debug/dpdk-18.11/lib/librte_ethdev/rte_ethdev.c:3699
  #7  0x00007ffb4cbb99f1 in i40e_dev_handle_aq_msg (dev=dev@entry=0xad3940
      <rte_eth_devices+16512>) at /usr/src/debug/dpdk-18.11/drivers/net/
      i40e/i40e_ethdev.c:6573
  #8  0x00007ffb4cbdfbed in i40e_dev_alarm_handler (param=0xad3940
      <rte_eth_devices+16512>) at /usr/src/debug/dpdk-18.11/drivers/net/
      i40e/i40e_ethdev.c:6681
  #9  0x00007ffb4fb9766f in eal_alarm_callback (arg=<optimized out>) at
      /usr/src/debug/dpdk-18.11/lib/librte_eal/linuxapp/eal/eal_alarm.c:90
  #10 0x00007ffb4fb95dd2 in eal_intr_process_interrupts (nfds=<optimized
      out>, events=<optimized out>) at /usr/src/debug/dpdk-18.11/lib/
      librte_eal/linuxapp/eal/eal_interrupts.c:886
  #11 eal_intr_handle_interrupts (totalfds=<optimized out>, pfd=20) at
      /usr/src/debug/dpdk-18.11/lib/librte_eal/linuxapp/eal/
      eal_interrupts.c:946
  #12 eal_intr_thread_main (arg=<optimized out>) at /usr/src/debug/
      dpdk-18.11/lib/librte_eal/linuxapp/eal/eal_interrupts.c:1035
  #13 0x00007ffb4b208dd5 in start_thread () from /usr/lib64/libpthread.so.0
  #14 0x00007ffb4981659d in clone () from /usr/lib64/libc.so.6

Fixes: 4861cde46116 ("i40e: new poll mode driver")
Cc: stable@dpdk.org

Signed-off-by: Yunjian Wang <wangyunjian@huawei.com>
---
 drivers/net/i40e/i40e_ethdev.c  | 28 +++++++++++++++++++++++++---
 drivers/net/i40e/i40e_ethdev.h  |  1 +
 drivers/net/i40e/i40e_pf.c      |  6 ++++++
 drivers/net/i40e/rte_pmd_i40e.c | 12 ++++++++++++
 4 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 5b01dc1..e4f6818 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -4036,8 +4036,9 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 		vsi = pf->main_vsi;
 	else
 		vsi = pf->vmdq[pool - 1].vsi;
-
+	rte_spinlock_lock(&vsi->mac_list_lock);
 	ret = i40e_vsi_add_mac(vsi, &mac_filter);
+	rte_spinlock_unlock(&vsi->mac_list_lock);
 	if (ret != I40E_SUCCESS) {
 		PMD_DRV_LOG(ERR, "Failed to add MACVLAN filter");
 		return -ENODEV;
@@ -4075,7 +4076,9 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 				}
 				vsi = pf->vmdq[i - 1].vsi;
 			}
+			rte_spinlock_lock(&vsi->mac_list_lock);
 			ret = i40e_vsi_delete_mac(vsi, macaddr);
+			rte_spinlock_unlock(&vsi->mac_list_lock);
 
 			if (ret) {
 				PMD_DRV_LOG(ERR, "Failed to remove MACVLAN filter");
@@ -4138,7 +4141,9 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 				 ETHER_ADDR_LEN);
 
 		mac_filter.filter_type = filter->filter_type;
+		rte_spinlock_lock(&vf->vsi->mac_list_lock);
 		ret = i40e_vsi_add_mac(vf->vsi, &mac_filter);
+		rte_spinlock_unlock(&vf->vsi->mac_list_lock);
 		if (ret != I40E_SUCCESS) {
 			PMD_DRV_LOG(ERR, "Failed to add MAC filter.");
 			return -1;
@@ -4147,7 +4152,9 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	} else {
 		rte_memcpy(hw->mac.addr, hw->mac.perm_addr,
 				ETHER_ADDR_LEN);
+		rte_spinlock_lock(&vf->vsi->mac_list_lock);
 		ret = i40e_vsi_delete_mac(vf->vsi, &filter->mac_addr);
+		rte_spinlock_unlock(&vf->vsi->mac_list_lock);
 		if (ret != I40E_SUCCESS) {
 			PMD_DRV_LOG(ERR, "Failed to delete MAC filter.");
 			return -1;
@@ -5266,9 +5273,11 @@ static int i40e_pf_config_vf_rxq_number(struct rte_eth_dev *dev)
 	}
 
 	/* Remove all macvlan filters of the VSI */
+	rte_spinlock_lock(&vsi->mac_list_lock);
 	i40e_vsi_remove_all_macvlan_filter(vsi);
 	TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp)
 		rte_free(f);
+	rte_spinlock_unlock(&vsi->mac_list_lock);
 
 	if (vsi->type != I40E_VSI_MAIN &&
 	    ((vsi->type != I40E_VSI_SRIOV) ||
@@ -5346,7 +5355,9 @@ static int i40e_pf_config_vf_rxq_number(struct rte_eth_dev *dev)
 		rte_memcpy(&mac->addr_bytes, hw->mac.perm_addr,
 				ETH_ADDR_LEN);
 		f->mac_info.filter_type = RTE_MACVLAN_PERFECT_MATCH;
+		rte_spinlock_lock(&vsi->mac_list_lock);
 		TAILQ_INSERT_TAIL(&vsi->mac_list, f, next);
+		rte_spinlock_unlock(&vsi->mac_list_lock);
 		vsi->mac_num++;
 
 		return ret;
@@ -5354,7 +5365,10 @@ static int i40e_pf_config_vf_rxq_number(struct rte_eth_dev *dev)
 	rte_memcpy(&filter.mac_addr,
 		(struct ether_addr *)(hw->mac.perm_addr), ETH_ADDR_LEN);
 	filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
-	return i40e_vsi_add_mac(vsi, &filter);
+	rte_spinlock_lock(&vsi->mac_list_lock);
+	ret = i40e_vsi_add_mac(vsi, &filter);
+	rte_spinlock_unlock(&vsi->mac_list_lock);
+	return ret;
 }
 
 /*
@@ -5521,6 +5535,7 @@ struct i40e_vsi *
 		return NULL;
 	}
 	TAILQ_INIT(&vsi->mac_list);
+	rte_spinlock_init(&vsi->mac_list_lock);
 	vsi->type = type;
 	vsi->adapter = I40E_PF_TO_ADAPTER(pf);
 	vsi->max_macaddrs = I40E_NUM_MACADDR_MAX;
@@ -5816,8 +5831,9 @@ struct i40e_vsi *
 	/* MAC/VLAN configuration */
 	rte_memcpy(&filter.mac_addr, &broadcast, ETHER_ADDR_LEN);
 	filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
-
+	rte_spinlock_lock(&vsi->mac_list_lock);
 	ret = i40e_vsi_add_mac(vsi, &filter);
+	rte_spinlock_unlock(&vsi->mac_list_lock);
 	if (ret != I40E_SUCCESS) {
 		PMD_DRV_LOG(ERR, "Failed to add MACVLAN filter");
 		goto fail_msix_alloc;
@@ -5866,6 +5882,7 @@ struct i40e_vsi *
 	i = 0;
 
 	/* Remove all existing mac */
+	rte_spinlock_lock(&vsi->mac_list_lock);
 	TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
 		mac_filter[i] = f->mac_info;
 		ret = i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr);
@@ -5889,6 +5906,7 @@ struct i40e_vsi *
 	}
 
 DONE:
+	rte_spinlock_unlock(&vsi->mac_list_lock);
 	rte_free(mac_filter);
 	return ret;
 }
@@ -11953,12 +11971,14 @@ static int i40e_set_default_mac_addr(struct rte_eth_dev *dev,
 		return -EINVAL;
 	}
 
+	rte_spinlock_lock(&vsi->mac_list_lock);
 	TAILQ_FOREACH(f, &vsi->mac_list, next) {
 		if (is_same_ether_addr(&pf->dev_addr, &f->mac_info.mac_addr))
 			break;
 	}
 
 	if (f == NULL) {
+		rte_spinlock_unlock(&vsi->mac_list_lock);
 		PMD_DRV_LOG(ERR, "Failed to find filter for default mac");
 		return -EIO;
 	}
@@ -11966,11 +11986,13 @@ static int i40e_set_default_mac_addr(struct rte_eth_dev *dev,
 	mac_filter = f->mac_info;
 	ret = i40e_vsi_delete_mac(vsi, &mac_filter.mac_addr);
 	if (ret != I40E_SUCCESS) {
+		rte_spinlock_unlock(&vsi->mac_list_lock);
 		PMD_DRV_LOG(ERR, "Failed to delete mac filter");
 		return -EIO;
 	}
 	memcpy(&mac_filter.mac_addr, mac_addr, ETH_ADDR_LEN);
 	ret = i40e_vsi_add_mac(vsi, &mac_filter);
+	rte_spinlock_unlock(&vsi->mac_list_lock);
 	if (ret != I40E_SUCCESS) {
 		PMD_DRV_LOG(ERR, "Failed to add mac filter");
 		return -EIO;
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 930eb9a..060be26 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -368,6 +368,7 @@ struct i40e_vsi {
 	uint16_t mac_num;        /* Total mac number */
 	uint32_t vfta[I40E_VFTA_SIZE];        /* VLAN bitmap */
 	struct i40e_mac_filter_list mac_list; /* macvlan filter list */
+	rte_spinlock_t mac_list_lock; /* macvlan filter list lock*/
 	/* specific VSI-defined parameters, SRIOV stored the vf_id */
 	uint32_t user_param;
 	uint16_t seid;           /* The seid of VSI itself */
diff --git a/drivers/net/i40e/i40e_pf.c b/drivers/net/i40e/i40e_pf.c
index 91be450..faa80cc 100644
--- a/drivers/net/i40e/i40e_pf.c
+++ b/drivers/net/i40e/i40e_pf.c
@@ -845,11 +845,14 @@
 		mac = (struct ether_addr *)(addr_list->list[i].addr);
 		rte_memcpy(&filter.mac_addr, mac, ETHER_ADDR_LEN);
 		filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
+		rte_spinlock_lock(&vf->vsi->mac_list_lock);
 		if (is_zero_ether_addr(mac) ||
 		    i40e_vsi_add_mac(vf->vsi, &filter)) {
+			rte_spinlock_unlock(&vf->vsi->mac_list_lock);
 			ret = I40E_ERR_INVALID_MAC_ADDR;
 			goto send_msg;
 		}
+		rte_spinlock_unlock(&vf->vsi->mac_list_lock);
 	}
 
 send_msg:
@@ -887,11 +890,14 @@
 
 	for (i = 0; i < addr_list->num_elements; i++) {
 		mac = (struct ether_addr *)(addr_list->list[i].addr);
+		rte_spinlock_lock(&vf->vsi->mac_list_lock);
 		if(is_zero_ether_addr(mac) ||
 			i40e_vsi_delete_mac(vf->vsi, mac)) {
+			rte_spinlock_unlock(&vf->vsi->mac_list_lock);
 			ret = I40E_ERR_INVALID_MAC_ADDR;
 			goto send_msg;
 		}
+		rte_spinlock_unlock(&vf->vsi->mac_list_lock);
 	}
 
 send_msg:
diff --git a/drivers/net/i40e/rte_pmd_i40e.c b/drivers/net/i40e/rte_pmd_i40e.c
index 7ae78e4..c5983c9 100644
--- a/drivers/net/i40e/rte_pmd_i40e.c
+++ b/drivers/net/i40e/rte_pmd_i40e.c
@@ -360,7 +360,9 @@
 	}
 
 	/* remove all the MAC and VLAN first */
+	rte_spinlock_lock(&vsi->mac_list_lock);
 	ret = i40e_vsi_rm_mac_filter(vsi);
+	rte_spinlock_unlock(&vsi->mac_list_lock);
 	if (ret) {
 		PMD_INIT_LOG(ERR, "Failed to remove MAC filters.");
 		return ret;
@@ -390,7 +392,9 @@
 	}
 
 	/* add all the MAC and VLAN back */
+	rte_spinlock_lock(&vsi->mac_list_lock);
 	ret = i40e_vsi_restore_mac_filter(vsi);
+	rte_spinlock_unlock(&vsi->mac_list_lock);
 	if (ret)
 		return ret;
 	if (vsi->vlan_anti_spoof_on || vsi->vlan_filter_on) {
@@ -563,10 +567,12 @@
 	ether_addr_copy(mac_addr, &vf->mac_addr);
 
 	/* Remove all existing mac */
+	rte_spinlock_lock(&vsi->mac_list_lock);
 	TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp)
 		if (i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr)
 				!= I40E_SUCCESS)
 			PMD_DRV_LOG(WARNING, "Delete MAC failed");
+	rte_spinlock_unlock(&vf->vsi->mac_list_lock);
 
 	return 0;
 }
@@ -609,7 +615,9 @@
 		ether_addr_copy(&null_mac_addr, &vf->mac_addr);
 
 	/* Remove the mac */
+	rte_spinlock_lock(&vsi->mac_list_lock);
 	i40e_vsi_delete_mac(vsi, mac_addr);
+	rte_spinlock_unlock(&vsi->mac_list_lock);
 
 	return 0;
 }
@@ -764,6 +772,7 @@ int rte_pmd_i40e_set_vf_broadcast(uint16_t port, uint16_t vf_id,
 		return -EINVAL;
 	}
 
+	rte_spinlock_lock(&vsi->mac_list_lock);
 	if (on) {
 		rte_memcpy(&filter.mac_addr, &broadcast, ETHER_ADDR_LEN);
 		filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
@@ -771,6 +780,7 @@ int rte_pmd_i40e_set_vf_broadcast(uint16_t port, uint16_t vf_id,
 	} else {
 		ret = i40e_vsi_delete_mac(vsi, &broadcast);
 	}
+	rte_spinlock_unlock(&vsi->mac_list_lock);
 
 	if (ret != I40E_SUCCESS && ret != I40E_ERR_PARAM) {
 		ret = -ENOTSUP;
@@ -2388,7 +2398,9 @@ int rte_pmd_i40e_ptype_mapping_replace(uint16_t port,
 
 	mac_filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
 	ether_addr_copy(mac_addr, &mac_filter.mac_addr);
+	rte_spinlock_lock(&vf->vsi->mac_list_lock);
 	ret = i40e_vsi_add_mac(vsi, &mac_filter);
+	rte_spinlock_unlock(&vf->vsi->mac_list_lock);
 	if (ret != I40E_SUCCESS) {
 		PMD_DRV_LOG(ERR, "Failed to add MAC filter.");
 		return -1;
-- 
1.8.3.1

             reply	other threads:[~2019-04-13  9:55 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-04-13  9:54 wangyunjian [this message]
2019-04-13  9:54 ` wangyunjian
2019-04-15 12:21 ` Ananyev, Konstantin
2019-04-15 12:21   ` Ananyev, Konstantin
2019-04-15 12:50   ` Zhang, Qi Z
2019-04-15 12:50     ` Zhang, Qi Z
2019-04-16  2:05   ` wangyunjian
2019-04-16  2:05     ` wangyunjian
2019-04-23  3:39     ` Zhang, Qi Z
2019-04-23  3:39       ` Zhang, Qi Z

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1555149291-12432-1-git-send-email-wangyunjian@huawei.com \
    --to=wangyunjian@huawei.com \
    --cc=dev@dpdk.org \
    --cc=stable@dpdk.org \
    --cc=xudingke@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).