diff options
author | Erez Shitrit <erezsh@mellanox.com> | 2017-02-01 12:10:05 -0500 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2017-02-15 09:51:28 -0500 |
commit | 2b0841766a898aba84630fb723989a77a9d3b4e6 (patch) | |
tree | 7e0d03f6b923886ebcee28915e9a65706fee32ec | |
parent | 592e8b3226a2b6d116589908d96c45fa13302ad7 (diff) |
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: fc791b633515 ("IB/ipoib: move back IB LL address into the hard header")
Cc: <stable@vger.kernel.org> # v4.8+
Signed-off-by: Erez Shitrit <erezsh@mellanox.com>
Signed-off-by: Noa Osherovich <noaos@mellanox.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Tested-by: Yuval Shaia <yuval.shaia@oracle.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_main.c | 30 |
1 files changed, 17 insertions, 13 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index e3bfa8a99ad2..259c59f67394 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c | |||
@@ -721,6 +721,14 @@ int ipoib_check_sm_sendonly_fullmember_support(struct ipoib_dev_priv *priv) | |||
721 | return ret; | 721 | return ret; |
722 | } | 722 | } |
723 | 723 | ||
724 | static void push_pseudo_header(struct sk_buff *skb, const char *daddr) | ||
725 | { | ||
726 | struct ipoib_pseudo_header *phdr; | ||
727 | |||
728 | phdr = (struct ipoib_pseudo_header *)skb_push(skb, sizeof(*phdr)); | ||
729 | memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); | ||
730 | } | ||
731 | |||
724 | void ipoib_flush_paths(struct net_device *dev) | 732 | void ipoib_flush_paths(struct net_device *dev) |
725 | { | 733 | { |
726 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 734 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
@@ -947,8 +955,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, | |||
947 | } | 955 | } |
948 | if (skb_queue_len(&neigh->queue) < | 956 | if (skb_queue_len(&neigh->queue) < |
949 | IPOIB_MAX_PATH_REC_QUEUE) { | 957 | IPOIB_MAX_PATH_REC_QUEUE) { |
950 | /* put pseudoheader back on for next time */ | 958 | push_pseudo_header(skb, neigh->daddr); |
951 | skb_push(skb, IPOIB_PSEUDO_LEN); | ||
952 | __skb_queue_tail(&neigh->queue, skb); | 959 | __skb_queue_tail(&neigh->queue, skb); |
953 | } else { | 960 | } else { |
954 | ipoib_warn(priv, "queue length limit %d. Packet drop.\n", | 961 | ipoib_warn(priv, "queue length limit %d. Packet drop.\n", |
@@ -966,10 +973,12 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, | |||
966 | 973 | ||
967 | if (!path->query && path_rec_start(dev, path)) | 974 | if (!path->query && path_rec_start(dev, path)) |
968 | goto err_path; | 975 | goto err_path; |
969 | if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) | 976 | if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { |
977 | push_pseudo_header(skb, neigh->daddr); | ||
970 | __skb_queue_tail(&neigh->queue, skb); | 978 | __skb_queue_tail(&neigh->queue, skb); |
971 | else | 979 | } else { |
972 | goto err_drop; | 980 | goto err_drop; |
981 | } | ||
973 | } | 982 | } |
974 | 983 | ||
975 | spin_unlock_irqrestore(&priv->lock, flags); | 984 | spin_unlock_irqrestore(&priv->lock, flags); |
@@ -1005,8 +1014,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, | |||
1005 | } | 1014 | } |
1006 | if (path) { | 1015 | if (path) { |
1007 | if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { | 1016 | if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { |
1008 | /* put pseudoheader back on for next time */ | 1017 | push_pseudo_header(skb, phdr->hwaddr); |
1009 | skb_push(skb, IPOIB_PSEUDO_LEN); | ||
1010 | __skb_queue_tail(&path->queue, skb); | 1018 | __skb_queue_tail(&path->queue, skb); |
1011 | } else { | 1019 | } else { |
1012 | ++dev->stats.tx_dropped; | 1020 | ++dev->stats.tx_dropped; |
@@ -1038,8 +1046,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, | |||
1038 | return; | 1046 | return; |
1039 | } else if ((path->query || !path_rec_start(dev, path)) && | 1047 | } else if ((path->query || !path_rec_start(dev, path)) && |
1040 | skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { | 1048 | skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { |
1041 | /* put pseudoheader back on for next time */ | 1049 | push_pseudo_header(skb, phdr->hwaddr); |
1042 | skb_push(skb, IPOIB_PSEUDO_LEN); | ||
1043 | __skb_queue_tail(&path->queue, skb); | 1050 | __skb_queue_tail(&path->queue, skb); |
1044 | } else { | 1051 | } else { |
1045 | ++dev->stats.tx_dropped; | 1052 | ++dev->stats.tx_dropped; |
@@ -1120,8 +1127,7 @@ send_using_neigh: | |||
1120 | } | 1127 | } |
1121 | 1128 | ||
1122 | if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { | 1129 | if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { |
1123 | /* put pseudoheader back on for next time */ | 1130 | push_pseudo_header(skb, phdr->hwaddr); |
1124 | skb_push(skb, sizeof(*phdr)); | ||
1125 | spin_lock_irqsave(&priv->lock, flags); | 1131 | spin_lock_irqsave(&priv->lock, flags); |
1126 | __skb_queue_tail(&neigh->queue, skb); | 1132 | __skb_queue_tail(&neigh->queue, skb); |
1127 | spin_unlock_irqrestore(&priv->lock, flags); | 1133 | spin_unlock_irqrestore(&priv->lock, flags); |
@@ -1153,7 +1159,6 @@ static int ipoib_hard_header(struct sk_buff *skb, | |||
1153 | unsigned short type, | 1159 | unsigned short type, |
1154 | const void *daddr, const void *saddr, unsigned len) | 1160 | const void *daddr, const void *saddr, unsigned len) |
1155 | { | 1161 | { |
1156 | struct ipoib_pseudo_header *phdr; | ||
1157 | struct ipoib_header *header; | 1162 | struct ipoib_header *header; |
1158 | 1163 | ||
1159 | header = (struct ipoib_header *) skb_push(skb, sizeof *header); | 1164 | header = (struct ipoib_header *) skb_push(skb, sizeof *header); |
@@ -1166,8 +1171,7 @@ static int ipoib_hard_header(struct sk_buff *skb, | |||
1166 | * destination address into skb hard header so we can figure out where | 1171 | * destination address into skb hard header so we can figure out where |
1167 | * to send the packet later. | 1172 | * to send the packet later. |
1168 | */ | 1173 | */ |
1169 | phdr = (struct ipoib_pseudo_header *) skb_push(skb, sizeof(*phdr)); | 1174 | push_pseudo_header(skb, daddr); |
1170 | memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); | ||
1171 | 1175 | ||
1172 | return IPOIB_HARD_LEN; | 1176 | return IPOIB_HARD_LEN; |
1173 | } | 1177 | } |