Skip to content

Commit

Permalink
IB/IPoIB: Add destination address when re-queue packet
Browse files Browse the repository at this point in the history
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: fc791b6 ("IB/ipoib: move back IB LL address into the hard header")
Cc: <[email protected]> # v4.8+
Signed-off-by: Erez Shitrit <[email protected]>
Signed-off-by: Noa Osherovich <[email protected]>
Signed-off-by: Leon Romanovsky <[email protected]>
Tested-by: Yuval Shaia <[email protected]>
Signed-off-by: Doug Ledford <[email protected]>
  • Loading branch information
Erez Shitrit authored and dledford committed Feb 15, 2017
1 parent 592e8b3 commit 2b08417
Showing 1 changed file with 17 additions and 13 deletions.
30 changes: 17 additions & 13 deletions drivers/infiniband/ulp/ipoib/ipoib_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,14 @@ int ipoib_check_sm_sendonly_fullmember_support(struct ipoib_dev_priv *priv)
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)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
Expand Down Expand Up @@ -947,8 +955,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
}
if (skb_queue_len(&neigh->queue) <
IPOIB_MAX_PATH_REC_QUEUE) {
/* put pseudoheader back on for next time */
skb_push(skb, IPOIB_PSEUDO_LEN);
push_pseudo_header(skb, neigh->daddr);
__skb_queue_tail(&neigh->queue, skb);
} else {
ipoib_warn(priv, "queue length limit %d. Packet drop.\n",
Expand All @@ -966,10 +973,12 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,

if (!path->query && path_rec_start(dev, 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);
else
} else {
goto err_drop;
}
}

spin_unlock_irqrestore(&priv->lock, flags);
Expand Down Expand Up @@ -1005,8 +1014,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
}
if (path) {
if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
/* put pseudoheader back on for next time */
skb_push(skb, IPOIB_PSEUDO_LEN);
push_pseudo_header(skb, phdr->hwaddr);
__skb_queue_tail(&path->queue, skb);
} else {
++dev->stats.tx_dropped;
Expand Down Expand Up @@ -1038,8 +1046,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
return;
} else if ((path->query || !path_rec_start(dev, path)) &&
skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
/* put pseudoheader back on for next time */
skb_push(skb, IPOIB_PSEUDO_LEN);
push_pseudo_header(skb, phdr->hwaddr);
__skb_queue_tail(&path->queue, skb);
} else {
++dev->stats.tx_dropped;
Expand Down Expand Up @@ -1120,8 +1127,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) {
/* put pseudoheader back on for next time */
skb_push(skb, sizeof(*phdr));
push_pseudo_header(skb, phdr->hwaddr);
spin_lock_irqsave(&priv->lock, flags);
__skb_queue_tail(&neigh->queue, skb);
spin_unlock_irqrestore(&priv->lock, flags);
Expand Down Expand Up @@ -1153,7 +1159,6 @@ static int ipoib_hard_header(struct sk_buff *skb,
unsigned short type,
const void *daddr, const void *saddr, unsigned len)
{
struct ipoib_pseudo_header *phdr;
struct ipoib_header *header;

header = (struct ipoib_header *) skb_push(skb, sizeof *header);
Expand All @@ -1166,8 +1171,7 @@ static int ipoib_hard_header(struct sk_buff *skb,
* destination address into skb hard header so we can figure out where
* to send the packet later.
*/
phdr = (struct ipoib_pseudo_header *) skb_push(skb, sizeof(*phdr));
memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
push_pseudo_header(skb, daddr);

return IPOIB_HARD_LEN;
}
Expand Down

0 comments on commit 2b08417

Please sign in to comment.