Commit 2e539fa4 authored by Erez Shitrit's avatar Erez Shitrit Committed by Greg Kroah-Hartman

IB/IPoIB: Add destination address when re-queue packet

commit 2b084176 upstream.

When sending packet to destination that was not resolved yet
via path query, the driver keeps the skb and tries to re-send it
again when the path is resolved.

But when re-sending via dev_queue_xmit the kernel doesn't call
to dev_hard_header, so IPoIB needs to keep 20 bytes in the skb
and to put the destination address inside them.

In that way the dev_start_xmit will have the correct destination,
and the driver won't take the destination from the skb->data, while
nothing exists there, which causes to packet be be dropped.

The test flow is:
1. Run the SM on remote node,
2. Restart the driver.
4. Ping some destination,
3. Observe that first ICMP request will be dropped.

Fixes: fc791b63 ("IB/ipoib: move back IB LL address into the hard header")
Signed-off-by: default avatarErez Shitrit <erezsh@mellanox.com>
Signed-off-by: default avatarNoa Osherovich <noaos@mellanox.com>
Signed-off-by: default avatarLeon Romanovsky <leon@kernel.org>
Tested-by: default avatarYuval Shaia <yuval.shaia@oracle.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1626076b
...@@ -701,6 +701,14 @@ int ipoib_check_sm_sendonly_fullmember_support(struct ipoib_dev_priv *priv) ...@@ -701,6 +701,14 @@ int ipoib_check_sm_sendonly_fullmember_support(struct ipoib_dev_priv *priv)
return ret; return ret;
} }
static void push_pseudo_header(struct sk_buff *skb, const char *daddr)
{
struct ipoib_pseudo_header *phdr;
phdr = (struct ipoib_pseudo_header *)skb_push(skb, sizeof(*phdr));
memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
}
void ipoib_flush_paths(struct net_device *dev) void ipoib_flush_paths(struct net_device *dev)
{ {
struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_dev_priv *priv = netdev_priv(dev);
...@@ -925,8 +933,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, ...@@ -925,8 +933,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
} }
if (skb_queue_len(&neigh->queue) < if (skb_queue_len(&neigh->queue) <
IPOIB_MAX_PATH_REC_QUEUE) { IPOIB_MAX_PATH_REC_QUEUE) {
/* put pseudoheader back on for next time */ push_pseudo_header(skb, neigh->daddr);
skb_push(skb, IPOIB_PSEUDO_LEN);
__skb_queue_tail(&neigh->queue, skb); __skb_queue_tail(&neigh->queue, skb);
} else { } else {
ipoib_warn(priv, "queue length limit %d. Packet drop.\n", ipoib_warn(priv, "queue length limit %d. Packet drop.\n",
...@@ -944,11 +951,13 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, ...@@ -944,11 +951,13 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
if (!path->query && path_rec_start(dev, path)) if (!path->query && path_rec_start(dev, path))
goto err_path; goto err_path;
if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
push_pseudo_header(skb, neigh->daddr);
__skb_queue_tail(&neigh->queue, skb); __skb_queue_tail(&neigh->queue, skb);
else } else {
goto err_drop; goto err_drop;
} }
}
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
ipoib_neigh_put(neigh); ipoib_neigh_put(neigh);
...@@ -983,8 +992,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, ...@@ -983,8 +992,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
} }
if (path) { if (path) {
if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
/* put pseudoheader back on for next time */ push_pseudo_header(skb, phdr->hwaddr);
skb_push(skb, IPOIB_PSEUDO_LEN);
__skb_queue_tail(&path->queue, skb); __skb_queue_tail(&path->queue, skb);
} else { } else {
++dev->stats.tx_dropped; ++dev->stats.tx_dropped;
...@@ -1016,8 +1024,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, ...@@ -1016,8 +1024,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
return; return;
} else if ((path->query || !path_rec_start(dev, path)) && } else if ((path->query || !path_rec_start(dev, path)) &&
skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
/* put pseudoheader back on for next time */ push_pseudo_header(skb, phdr->hwaddr);
skb_push(skb, IPOIB_PSEUDO_LEN);
__skb_queue_tail(&path->queue, skb); __skb_queue_tail(&path->queue, skb);
} else { } else {
++dev->stats.tx_dropped; ++dev->stats.tx_dropped;
...@@ -1098,8 +1105,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1098,8 +1105,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
} }
if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
/* put pseudoheader back on for next time */ push_pseudo_header(skb, phdr->hwaddr);
skb_push(skb, sizeof(*phdr));
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
__skb_queue_tail(&neigh->queue, skb); __skb_queue_tail(&neigh->queue, skb);
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
...@@ -1131,7 +1137,6 @@ static int ipoib_hard_header(struct sk_buff *skb, ...@@ -1131,7 +1137,6 @@ static int ipoib_hard_header(struct sk_buff *skb,
unsigned short type, unsigned short type,
const void *daddr, const void *saddr, unsigned len) const void *daddr, const void *saddr, unsigned len)
{ {
struct ipoib_pseudo_header *phdr;
struct ipoib_header *header; struct ipoib_header *header;
header = (struct ipoib_header *) skb_push(skb, sizeof *header); header = (struct ipoib_header *) skb_push(skb, sizeof *header);
...@@ -1144,8 +1149,7 @@ static int ipoib_hard_header(struct sk_buff *skb, ...@@ -1144,8 +1149,7 @@ static int ipoib_hard_header(struct sk_buff *skb,
* destination address into skb hard header so we can figure out where * destination address into skb hard header so we can figure out where
* to send the packet later. * to send the packet later.
*/ */
phdr = (struct ipoib_pseudo_header *) skb_push(skb, sizeof(*phdr)); push_pseudo_header(skb, daddr);
memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
return IPOIB_HARD_LEN; return IPOIB_HARD_LEN;
} }
......
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