Commit 42fcb213 authored by Qingfang Deng's avatar Qingfang Deng Committed by Paolo Abeni
Browse files

ppp: enable TX scatter-gather



PPP channels using chan->direct_xmit prepend the PPP header to a skb and
call dev_queue_xmit() directly. In this mode the skb does not need to be
linear, but the PPP netdevice currently does not advertise
scatter-gather features, causing unnecessary linearization and
preventing GSO.

Enable NETIF_F_SG and NETIF_F_FRAGLIST on PPP devices. In case a linear
buffer is required (PPP compression, multilink, and channels without
direct_xmit), call skb_linearize() explicitly.

Signed-off-by: default avatarQingfang Deng <dqfext@gmail.com>
Link: https://patch.msgid.link/20260129012902.941-1-dqfext@gmail.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 3e5aa52b
Loading
Loading
Loading
Loading
+25 −5
Original line number Diff line number Diff line
@@ -1641,6 +1641,8 @@ static void ppp_setup(struct net_device *dev)
	dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
	dev->priv_destructor = ppp_dev_priv_destructor;
	dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST;
	dev->hw_features = dev->features;
	netif_keep_dst(dev);
}

@@ -1710,6 +1712,10 @@ pad_compress_skb(struct ppp *ppp, struct sk_buff *skb)
		ppp->xcomp->comp_extra + ppp->dev->hard_header_len;
	int compressor_skb_size = ppp->dev->mtu +
		ppp->xcomp->comp_extra + PPP_HDRLEN;

	if (skb_linearize(skb))
		return NULL;

	new_skb = alloc_skb(new_skb_size, GFP_ATOMIC);
	if (!new_skb) {
		if (net_ratelimit())
@@ -1797,6 +1803,10 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
	case PPP_IP:
		if (!ppp->vj || (ppp->flags & SC_COMP_TCP) == 0)
			break;

		if (skb_linearize(skb))
			goto drop;

		/* try to do VJ TCP header compression */
		new_skb = alloc_skb(skb->len + ppp->dev->hard_header_len - 2,
				    GFP_ATOMIC);
@@ -1894,19 +1904,26 @@ ppp_push(struct ppp *ppp)
	}

	if ((ppp->flags & SC_MULTILINK) == 0) {
		struct ppp_channel *chan;
		/* not doing multilink: send it down the first channel */
		list = list->next;
		pch = list_entry(list, struct channel, clist);

		spin_lock(&pch->downl);
		if (pch->chan) {
			if (pch->chan->ops->start_xmit(pch->chan, skb))
				ppp->xmit_pending = NULL;
		} else {
			/* channel got unregistered */
		chan = pch->chan;
		if (unlikely(!chan || (!chan->direct_xmit && skb_linearize(skb)))) {
			/* channel got unregistered, or it requires a linear
			 * skb but linearization failed
			 */
			kfree_skb(skb);
			ppp->xmit_pending = NULL;
			goto out;
		}

		if (chan->ops->start_xmit(chan, skb))
			ppp->xmit_pending = NULL;

out:
		spin_unlock(&pch->downl);
		return;
	}
@@ -1991,6 +2008,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
		return 0; /* can't take now, leave it in xmit_pending */

	/* Do protocol field compression */
	if (skb_linearize(skb))
		goto err_linearize;
	p = skb->data;
	len = skb->len;
	if (*p == 0 && mp_protocol_compress) {
@@ -2149,6 +2168,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)

 noskb:
	spin_unlock(&pch->downl);
 err_linearize:
	if (ppp->debug & 1)
		netdev_err(ppp->dev, "PPP: no memory (fragment)\n");
	++ppp->dev->stats.tx_errors;