Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b084176 authored by Erez Shitrit's avatar Erez Shitrit Committed by Doug Ledford
Browse files

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



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")
Cc: <stable@vger.kernel.org> # v4.8+
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>
parent 592e8b32
Loading
Loading
Loading
Loading
+17 −13
Original line number Diff line number Diff line
@@ -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);
@@ -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",
@@ -966,11 +973,13 @@ 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);
	ipoib_neigh_put(neigh);
@@ -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;
@@ -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;
@@ -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);
@@ -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);
@@ -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;
}