Commit dd57c930 authored by Alex Estrin's avatar Alex Estrin Committed by Roland Dreier

IB/ipoib: Avoid multicast join attempts with invalid P_key

Currently, the parent interface keeps sending broadcast group join
requests even if p_key index 0 is invalid, which is possible/common in
virtualized environments where a VF has been probed to VM but the
actual P_key configuration has not yet been assigned by the management
software. This creates unnecessary noise on the fabric and in the
kernel logs:

    ib0: multicast join failed for ff12:401b:8000:0000:0000:0000:ffff:ffff, status -22

The original code run the multicast task regardless of the actual
P_key value, which can be avoided. The fix is to re-init resources and
bring interface up only if P_key index 0 is valid either when starting
up or on PKEY_CHANGE event.

Fixes: c2904141 ("IPoIB: Fix pkey change flow for virtualization environments")
Reviewed-by: default avatarIra Weiny <ira.weiny@intel.com>
Signed-off-by: default avatarAlex Estrin <alex.estrin@intel.com>
Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
parent 4eae3748
...@@ -669,12 +669,13 @@ int ipoib_ib_dev_open(struct net_device *dev, int flush) ...@@ -669,12 +669,13 @@ int ipoib_ib_dev_open(struct net_device *dev, int flush)
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
int ret; int ret;
if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &priv->pkey_index)) { ipoib_pkey_dev_check_presence(dev);
ipoib_warn(priv, "P_Key 0x%04x not found\n", priv->pkey);
clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) {
ipoib_warn(priv, "P_Key 0x%04x is %s\n", priv->pkey,
(!(priv->pkey & 0x7fff) ? "Invalid" : "not found"));
return -1; return -1;
} }
set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
ret = ipoib_init_qp(dev); ret = ipoib_init_qp(dev);
if (ret) { if (ret) {
...@@ -712,9 +713,10 @@ int ipoib_ib_dev_open(struct net_device *dev, int flush) ...@@ -712,9 +713,10 @@ int ipoib_ib_dev_open(struct net_device *dev, int flush)
void ipoib_pkey_dev_check_presence(struct net_device *dev) void ipoib_pkey_dev_check_presence(struct net_device *dev)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
u16 pkey_index = 0;
if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &pkey_index)) if (!(priv->pkey & 0x7fff) ||
ib_find_pkey(priv->ca, priv->port, priv->pkey,
&priv->pkey_index))
clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
else else
set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
...@@ -958,13 +960,27 @@ static inline int update_parent_pkey(struct ipoib_dev_priv *priv) ...@@ -958,13 +960,27 @@ static inline int update_parent_pkey(struct ipoib_dev_priv *priv)
return 1; return 1;
} }
/*
* returns 0 if pkey value was found in a different slot.
*/
static inline int update_child_pkey(struct ipoib_dev_priv *priv)
{
u16 old_index = priv->pkey_index;
priv->pkey_index = 0;
ipoib_pkey_dev_check_presence(priv->dev);
if (test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) &&
(old_index == priv->pkey_index))
return 1;
return 0;
}
static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
enum ipoib_flush_level level) enum ipoib_flush_level level)
{ {
struct ipoib_dev_priv *cpriv; struct ipoib_dev_priv *cpriv;
struct net_device *dev = priv->dev; struct net_device *dev = priv->dev;
u16 new_index;
int result; int result;
down_read(&priv->vlan_rwsem); down_read(&priv->vlan_rwsem);
...@@ -978,19 +994,20 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, ...@@ -978,19 +994,20 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
up_read(&priv->vlan_rwsem); up_read(&priv->vlan_rwsem);
if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) { if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags) &&
/* for non-child devices must check/update the pkey value here */ level != IPOIB_FLUSH_HEAVY) {
if (level == IPOIB_FLUSH_HEAVY) {
if (test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags))
ipoib_pkey_open(priv);
else
update_parent_pkey(priv);
}
ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n"); ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n");
return; return;
} }
if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) { if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) {
/* interface is down. update pkey and leave. */
if (level == IPOIB_FLUSH_HEAVY) {
if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags))
update_parent_pkey(priv);
else
update_child_pkey(priv);
}
ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_ADMIN_UP not set.\n"); ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_ADMIN_UP not set.\n");
return; return;
} }
...@@ -1000,19 +1017,13 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, ...@@ -1000,19 +1017,13 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
* (parent) devices should always takes what present in pkey index 0 * (parent) devices should always takes what present in pkey index 0
*/ */
if (test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { if (test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) { result = update_child_pkey(priv);
clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); if (result) {
ipoib_ib_dev_down(dev, 0); /* restart QP only if P_Key index is changed */
ipoib_ib_dev_stop(dev, 0);
return;
}
/* restart QP only if P_Key index is changed */
if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) &&
new_index == priv->pkey_index) {
ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n"); ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
return; return;
} }
priv->pkey_index = new_index;
} else { } else {
result = update_parent_pkey(priv); result = update_parent_pkey(priv);
/* restart QP only if P_Key value changed */ /* restart QP only if P_Key value changed */
...@@ -1032,8 +1043,12 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, ...@@ -1032,8 +1043,12 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
ipoib_ib_dev_down(dev, 0); ipoib_ib_dev_down(dev, 0);
if (level == IPOIB_FLUSH_HEAVY) { if (level == IPOIB_FLUSH_HEAVY) {
ipoib_ib_dev_stop(dev, 0); if (test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags))
ipoib_ib_dev_open(dev, 0); ipoib_ib_dev_stop(dev, 0);
if (ipoib_ib_dev_open(dev, 0) != 0)
return;
if (netif_queue_stopped(dev))
netif_start_queue(dev);
} }
/* /*
...@@ -1088,15 +1103,4 @@ void ipoib_ib_dev_cleanup(struct net_device *dev) ...@@ -1088,15 +1103,4 @@ void ipoib_ib_dev_cleanup(struct net_device *dev)
ipoib_transport_dev_cleanup(dev); ipoib_transport_dev_cleanup(dev);
} }
void ipoib_pkey_open(struct ipoib_dev_priv *priv)
{
if (test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags))
return;
ipoib_pkey_dev_check_presence(priv->dev);
if (test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags))
ipoib_open(priv->dev);
}
...@@ -108,14 +108,11 @@ int ipoib_open(struct net_device *dev) ...@@ -108,14 +108,11 @@ int ipoib_open(struct net_device *dev)
set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
if (ipoib_ib_dev_open(dev, 1)) {
ipoib_pkey_dev_check_presence(dev); if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags))
return 0;
if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags))
return 0;
if (ipoib_ib_dev_open(dev, 1))
goto err_disable; goto err_disable;
}
if (ipoib_ib_dev_up(dev)) if (ipoib_ib_dev_up(dev))
goto err_stop; goto err_stop;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment