提交 8a7f7521 编写于 作者: M Michael S. Tsirkin 提交者: Roland Dreier

IB/ipoib: Fix packet loss after hardware address update

The neighbour ha field may get updated without destroying the
neighbour.  In this case, the ha field gets out of sync with the
address handle stored in ipoib_neigh->ah, with the result that
the ah field would point to an incorrect path, resulting in all
packets being lost.
Signed-off-by: NMichael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: NRoland Dreier <rolandd@cisco.com>
上级 624d01f8
...@@ -212,6 +212,7 @@ struct ipoib_path { ...@@ -212,6 +212,7 @@ struct ipoib_path {
struct ipoib_neigh { struct ipoib_neigh {
struct ipoib_ah *ah; struct ipoib_ah *ah;
union ib_gid dgid;
struct sk_buff_head queue; struct sk_buff_head queue;
struct neighbour *neighbour; struct neighbour *neighbour;
......
...@@ -404,6 +404,8 @@ static void path_rec_completion(int status, ...@@ -404,6 +404,8 @@ static void path_rec_completion(int status,
list_for_each_entry(neigh, &path->neigh_list, list) { list_for_each_entry(neigh, &path->neigh_list, list) {
kref_get(&path->ah->ref); kref_get(&path->ah->ref);
neigh->ah = path->ah; neigh->ah = path->ah;
memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw,
sizeof(union ib_gid));
while ((skb = __skb_dequeue(&neigh->queue))) while ((skb = __skb_dequeue(&neigh->queue)))
__skb_queue_tail(&skqueue, skb); __skb_queue_tail(&skqueue, skb);
...@@ -510,6 +512,8 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) ...@@ -510,6 +512,8 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
if (path->ah) { if (path->ah) {
kref_get(&path->ah->ref); kref_get(&path->ah->ref);
neigh->ah = path->ah; neigh->ah = path->ah;
memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw,
sizeof(union ib_gid));
ipoib_send(dev, skb, path->ah, ipoib_send(dev, skb, path->ah,
be32_to_cpup((__be32 *) skb->dst->neighbour->ha)); be32_to_cpup((__be32 *) skb->dst->neighbour->ha));
...@@ -633,6 +637,25 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -633,6 +637,25 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
neigh = *to_ipoib_neigh(skb->dst->neighbour); neigh = *to_ipoib_neigh(skb->dst->neighbour);
if (likely(neigh->ah)) { if (likely(neigh->ah)) {
if (unlikely(memcmp(&neigh->dgid.raw,
skb->dst->neighbour->ha + 4,
sizeof(union ib_gid)))) {
spin_lock(&priv->lock);
/*
* It's safe to call ipoib_put_ah() inside
* priv->lock here, because we know that
* path->ah will always hold one more reference,
* so ipoib_put_ah() will never do more than
* decrement the ref count.
*/
ipoib_put_ah(neigh->ah);
list_del(&neigh->list);
ipoib_neigh_free(neigh);
spin_unlock(&priv->lock);
ipoib_path_lookup(skb, dev);
goto out;
}
ipoib_send(dev, skb, neigh->ah, ipoib_send(dev, skb, neigh->ah,
be32_to_cpup((__be32 *) skb->dst->neighbour->ha)); be32_to_cpup((__be32 *) skb->dst->neighbour->ha));
goto out; goto out;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册