diff options
author | Alex Estrin <alex.estrin@intel.com> | 2014-08-06 14:40:32 -0400 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2014-08-10 22:53:56 -0400 |
commit | dd57c9308afff61e4c157d0a7260695fe2f9a98c (patch) | |
tree | 3b3660782cced2f44ea7abdd7d1a14044ccf6028 /drivers/infiniband | |
parent | 4eae374845affc3ebf8ccfc38d554a86adc95003 (diff) |
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: c290414169 ("IPoIB: Fix pkey change flow for virtualization environments")
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Alex Estrin <alex.estrin@intel.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_ib.c | 80 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_main.c | 11 |
2 files changed, 46 insertions, 45 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 9dcb2c9e758a..72626c348174 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c | |||
@@ -669,12 +669,13 @@ int ipoib_ib_dev_open(struct net_device *dev, int flush) | |||
669 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 669 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
670 | int ret; | 670 | int ret; |
671 | 671 | ||
672 | if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &priv->pkey_index)) { | 672 | ipoib_pkey_dev_check_presence(dev); |
673 | ipoib_warn(priv, "P_Key 0x%04x not found\n", priv->pkey); | 673 | |
674 | clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); | 674 | if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) { |
675 | ipoib_warn(priv, "P_Key 0x%04x is %s\n", priv->pkey, | ||
676 | (!(priv->pkey & 0x7fff) ? "Invalid" : "not found")); | ||
675 | return -1; | 677 | return -1; |
676 | } | 678 | } |
677 | set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); | ||
678 | 679 | ||
679 | ret = ipoib_init_qp(dev); | 680 | ret = ipoib_init_qp(dev); |
680 | if (ret) { | 681 | if (ret) { |
@@ -712,9 +713,10 @@ dev_stop: | |||
712 | void ipoib_pkey_dev_check_presence(struct net_device *dev) | 713 | void ipoib_pkey_dev_check_presence(struct net_device *dev) |
713 | { | 714 | { |
714 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 715 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
715 | u16 pkey_index = 0; | ||
716 | 716 | ||
717 | if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &pkey_index)) | 717 | if (!(priv->pkey & 0x7fff) || |
718 | ib_find_pkey(priv->ca, priv->port, priv->pkey, | ||
719 | &priv->pkey_index)) | ||
718 | clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); | 720 | clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); |
719 | else | 721 | else |
720 | set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); | 722 | set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); |
@@ -958,13 +960,27 @@ static inline int update_parent_pkey(struct ipoib_dev_priv *priv) | |||
958 | 960 | ||
959 | return 1; | 961 | return 1; |
960 | } | 962 | } |
963 | /* | ||
964 | * returns 0 if pkey value was found in a different slot. | ||
965 | */ | ||
966 | static inline int update_child_pkey(struct ipoib_dev_priv *priv) | ||
967 | { | ||
968 | u16 old_index = priv->pkey_index; | ||
969 | |||
970 | priv->pkey_index = 0; | ||
971 | ipoib_pkey_dev_check_presence(priv->dev); | ||
972 | |||
973 | if (test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) && | ||
974 | (old_index == priv->pkey_index)) | ||
975 | return 1; | ||
976 | return 0; | ||
977 | } | ||
961 | 978 | ||
962 | static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, | 979 | static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, |
963 | enum ipoib_flush_level level) | 980 | enum ipoib_flush_level level) |
964 | { | 981 | { |
965 | struct ipoib_dev_priv *cpriv; | 982 | struct ipoib_dev_priv *cpriv; |
966 | struct net_device *dev = priv->dev; | 983 | struct net_device *dev = priv->dev; |
967 | u16 new_index; | ||
968 | int result; | 984 | int result; |
969 | 985 | ||
970 | down_read(&priv->vlan_rwsem); | 986 | down_read(&priv->vlan_rwsem); |
@@ -978,19 +994,20 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, | |||
978 | 994 | ||
979 | up_read(&priv->vlan_rwsem); | 995 | up_read(&priv->vlan_rwsem); |
980 | 996 | ||
981 | if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) { | 997 | if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags) && |
982 | /* for non-child devices must check/update the pkey value here */ | 998 | level != IPOIB_FLUSH_HEAVY) { |
983 | if (level == IPOIB_FLUSH_HEAVY) { | ||
984 | if (test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) | ||
985 | ipoib_pkey_open(priv); | ||
986 | else | ||
987 | update_parent_pkey(priv); | ||
988 | } | ||
989 | ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n"); | 999 | ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n"); |
990 | return; | 1000 | return; |
991 | } | 1001 | } |
992 | 1002 | ||
993 | if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) { | 1003 | if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) { |
1004 | /* interface is down. update pkey and leave. */ | ||
1005 | if (level == IPOIB_FLUSH_HEAVY) { | ||
1006 | if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) | ||
1007 | update_parent_pkey(priv); | ||
1008 | else | ||
1009 | update_child_pkey(priv); | ||
1010 | } | ||
994 | ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_ADMIN_UP not set.\n"); | 1011 | ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_ADMIN_UP not set.\n"); |
995 | return; | 1012 | return; |
996 | } | 1013 | } |
@@ -1000,19 +1017,13 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, | |||
1000 | * (parent) devices should always takes what present in pkey index 0 | 1017 | * (parent) devices should always takes what present in pkey index 0 |
1001 | */ | 1018 | */ |
1002 | if (test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { | 1019 | if (test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { |
1003 | if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) { | 1020 | result = update_child_pkey(priv); |
1004 | clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); | 1021 | if (result) { |
1005 | ipoib_ib_dev_down(dev, 0); | 1022 | /* restart QP only if P_Key index is changed */ |
1006 | ipoib_ib_dev_stop(dev, 0); | ||
1007 | return; | ||
1008 | } | ||
1009 | /* restart QP only if P_Key index is changed */ | ||
1010 | if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) && | ||
1011 | new_index == priv->pkey_index) { | ||
1012 | ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n"); | 1023 | ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n"); |
1013 | return; | 1024 | return; |
1014 | } | 1025 | } |
1015 | priv->pkey_index = new_index; | 1026 | |
1016 | } else { | 1027 | } else { |
1017 | result = update_parent_pkey(priv); | 1028 | result = update_parent_pkey(priv); |
1018 | /* restart QP only if P_Key value changed */ | 1029 | /* restart QP only if P_Key value changed */ |
@@ -1032,8 +1043,12 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, | |||
1032 | ipoib_ib_dev_down(dev, 0); | 1043 | ipoib_ib_dev_down(dev, 0); |
1033 | 1044 | ||
1034 | if (level == IPOIB_FLUSH_HEAVY) { | 1045 | if (level == IPOIB_FLUSH_HEAVY) { |
1035 | ipoib_ib_dev_stop(dev, 0); | 1046 | if (test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) |
1036 | ipoib_ib_dev_open(dev, 0); | 1047 | ipoib_ib_dev_stop(dev, 0); |
1048 | if (ipoib_ib_dev_open(dev, 0) != 0) | ||
1049 | return; | ||
1050 | if (netif_queue_stopped(dev)) | ||
1051 | netif_start_queue(dev); | ||
1037 | } | 1052 | } |
1038 | 1053 | ||
1039 | /* | 1054 | /* |
@@ -1088,15 +1103,4 @@ void ipoib_ib_dev_cleanup(struct net_device *dev) | |||
1088 | ipoib_transport_dev_cleanup(dev); | 1103 | ipoib_transport_dev_cleanup(dev); |
1089 | } | 1104 | } |
1090 | 1105 | ||
1091 | void ipoib_pkey_open(struct ipoib_dev_priv *priv) | ||
1092 | { | ||
1093 | |||
1094 | if (test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) | ||
1095 | return; | ||
1096 | |||
1097 | ipoib_pkey_dev_check_presence(priv->dev); | ||
1098 | |||
1099 | if (test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) | ||
1100 | ipoib_open(priv->dev); | ||
1101 | } | ||
1102 | 1106 | ||
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 1bf994a96860..217cb77157d8 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c | |||
@@ -108,14 +108,11 @@ int ipoib_open(struct net_device *dev) | |||
108 | 108 | ||
109 | set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); | 109 | set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); |
110 | 110 | ||
111 | 111 | if (ipoib_ib_dev_open(dev, 1)) { | |
112 | ipoib_pkey_dev_check_presence(dev); | 112 | if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) |
113 | 113 | return 0; | |
114 | if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) | ||
115 | return 0; | ||
116 | |||
117 | if (ipoib_ib_dev_open(dev, 1)) | ||
118 | goto err_disable; | 114 | goto err_disable; |
115 | } | ||
119 | 116 | ||
120 | if (ipoib_ib_dev_up(dev)) | 117 | if (ipoib_ib_dev_up(dev)) |
121 | goto err_stop; | 118 | goto err_stop; |