Skip to content

Commit 78a50a5

Browse files
Hans Westgaard Rydledford
authored andcommitted
IB/ipoib: Add handling for sending of skb with many frags
IPoIB converts skb-fragments to sge adding 1 extra sge when SG is enabled. Current codepath assumes that the max number of sge a device support is at least MAX_SKB_FRAGS+1, there is no interaction with upper layers to limit number of fragments in an skb if a device suports fewer sges. The assumptions also lead to requesting a fixed number of sge when IPoIB creates queue-pairs with SG enabled. A fallback/slowpath is implemented using skb_linearize to handle cases where the conversion would result in more sges than supported. Signed-off-by: Hans Westgaard Ry <[email protected]> Reviewed-by: Håkon Bugge <[email protected]> Reviewed-by: Wei Lin Guay <[email protected]> Reviewed-by: Yuval Shaia <[email protected]> Signed-off-by: Doug Ledford <[email protected]>
1 parent fc77dbd commit 78a50a5

File tree

4 files changed

+45
-3
lines changed

4 files changed

+45
-3
lines changed

drivers/infiniband/ulp/ipoib/ipoib.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ struct ipoib_cm_tx {
244244
unsigned tx_tail;
245245
unsigned long flags;
246246
u32 mtu;
247+
unsigned max_send_sge;
247248
};
248249

249250
struct ipoib_cm_rx_buf {
@@ -390,6 +391,7 @@ struct ipoib_dev_priv {
390391
int hca_caps;
391392
struct ipoib_ethtool_st ethtool;
392393
struct timer_list poll_timer;
394+
unsigned max_send_sge;
393395
};
394396

395397
struct ipoib_ah {

drivers/infiniband/ulp/ipoib/ipoib_cm.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
710710
struct ipoib_dev_priv *priv = netdev_priv(dev);
711711
struct ipoib_tx_buf *tx_req;
712712
int rc;
713+
unsigned usable_sge = tx->max_send_sge - !!skb_headlen(skb);
713714

714715
if (unlikely(skb->len > tx->mtu)) {
715716
ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
@@ -719,7 +720,23 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
719720
ipoib_cm_skb_too_long(dev, skb, tx->mtu - IPOIB_ENCAP_LEN);
720721
return;
721722
}
722-
723+
if (skb_shinfo(skb)->nr_frags > usable_sge) {
724+
if (skb_linearize(skb) < 0) {
725+
ipoib_warn(priv, "skb could not be linearized\n");
726+
++dev->stats.tx_dropped;
727+
++dev->stats.tx_errors;
728+
dev_kfree_skb_any(skb);
729+
return;
730+
}
731+
/* Does skb_linearize return ok without reducing nr_frags? */
732+
if (skb_shinfo(skb)->nr_frags > usable_sge) {
733+
ipoib_warn(priv, "too many frags after skb linearize\n");
734+
++dev->stats.tx_dropped;
735+
++dev->stats.tx_errors;
736+
dev_kfree_skb_any(skb);
737+
return;
738+
}
739+
}
723740
ipoib_dbg_data(priv, "sending packet: head 0x%x length %d connection 0x%x\n",
724741
tx->tx_head, skb->len, tx->qp->qp_num);
725742

@@ -1031,7 +1048,8 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
10311048
struct ib_qp *tx_qp;
10321049

10331050
if (dev->features & NETIF_F_SG)
1034-
attr.cap.max_send_sge = MAX_SKB_FRAGS + 1;
1051+
attr.cap.max_send_sge =
1052+
min_t(u32, priv->ca->attrs.max_sge, MAX_SKB_FRAGS + 1);
10351053

10361054
tx_qp = ib_create_qp(priv->pd, &attr);
10371055
if (PTR_ERR(tx_qp) == -EINVAL) {
@@ -1040,6 +1058,7 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
10401058
attr.create_flags &= ~IB_QP_CREATE_USE_GFP_NOIO;
10411059
tx_qp = ib_create_qp(priv->pd, &attr);
10421060
}
1061+
tx->max_send_sge = attr.cap.max_send_sge;
10431062
return tx_qp;
10441063
}
10451064

drivers/infiniband/ulp/ipoib/ipoib_ib.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
538538
struct ipoib_tx_buf *tx_req;
539539
int hlen, rc;
540540
void *phead;
541+
unsigned usable_sge = priv->max_send_sge - !!skb_headlen(skb);
541542

542543
if (skb_is_gso(skb)) {
543544
hlen = skb_transport_offset(skb) + tcp_hdrlen(skb);
@@ -561,6 +562,23 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
561562
phead = NULL;
562563
hlen = 0;
563564
}
565+
if (skb_shinfo(skb)->nr_frags > usable_sge) {
566+
if (skb_linearize(skb) < 0) {
567+
ipoib_warn(priv, "skb could not be linearized\n");
568+
++dev->stats.tx_dropped;
569+
++dev->stats.tx_errors;
570+
dev_kfree_skb_any(skb);
571+
return;
572+
}
573+
/* Does skb_linearize return ok without reducing nr_frags? */
574+
if (skb_shinfo(skb)->nr_frags > usable_sge) {
575+
ipoib_warn(priv, "too many frags after skb linearize\n");
576+
++dev->stats.tx_dropped;
577+
++dev->stats.tx_errors;
578+
dev_kfree_skb_any(skb);
579+
return;
580+
}
581+
}
564582

565583
ipoib_dbg_data(priv, "sending packet, length=%d address=%p qpn=0x%06x\n",
566584
skb->len, address, qpn);

drivers/infiniband/ulp/ipoib/ipoib_verbs.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,8 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
206206
init_attr.create_flags |= IB_QP_CREATE_NETIF_QP;
207207

208208
if (dev->features & NETIF_F_SG)
209-
init_attr.cap.max_send_sge = MAX_SKB_FRAGS + 1;
209+
init_attr.cap.max_send_sge =
210+
min_t(u32, priv->ca->attrs.max_sge, MAX_SKB_FRAGS + 1);
210211

211212
priv->qp = ib_create_qp(priv->pd, &init_attr);
212213
if (IS_ERR(priv->qp)) {
@@ -233,6 +234,8 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
233234
priv->rx_wr.next = NULL;
234235
priv->rx_wr.sg_list = priv->rx_sge;
235236

237+
priv->max_send_sge = init_attr.cap.max_send_sge;
238+
236239
return 0;
237240

238241
out_free_send_cq:

0 commit comments

Comments
 (0)