Subject: Re: [RFC PATCH net-next] net: ppp: convert to IFF_NO_QUEUE

From: Simon Horman <[email-masked]>
Date: Mon, 4 Nov 2024 11:50:04 +0000

+ Toke

On Tue, Oct 29, 2024 at 06:36:56PM +0800, Qingfang Deng wrote:
> When testing the parallel TX performance of a single PPPoE interface
> over a 2.5GbE link with multiple hardware queues, the throughput could
> not exceed 1.9Gbps, even with low CPU usage.
> 
> This issue arises because the PPP interface is registered with a single
> queue and a tx_queue_len of 3. This default behavior dates back to Linux
> 2.3.13, which was suitable for slower serial ports. However, in modern
> devices with multiple processors and hardware queues, this configuration
> can lead to congestion.
> 
> For PPPoE/PPTP, the lower interface should handle qdisc, so we need to
> set IFF_NO_QUEUE. For PPP over a serial port, we don't benefit from a
> qdisc with such a short TX queue, so handling TX queueing in the driver
> and setting IFF_NO_QUEUE is more effective.
> 
> With this change, PPPoE interfaces can now fully saturate a 2.5GbE link.
> 
> Signed-off-by: Qingfang Deng <[email-masked]>

Hi Toke,

I'm wondering if you could offer an opinion on this.

> ---
>  drivers/net/ppp/ppp_generic.c | 27 ++++++++++++---------------
>  1 file changed, 12 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
> index 4b2971e2bf48..5470e0fe1f9b 100644
> --- a/drivers/net/ppp/ppp_generic.c
> +++ b/drivers/net/ppp/ppp_generic.c
> @@ -236,8 +236,8 @@ struct ppp_net {
>  /* Get the PPP protocol number from a skb */
>  #define PPP_PROTO(skb)	get_unaligned_be16((skb)->data)
>  
> -/* We limit the length of ppp->file.rq to this (arbitrary) value */
> -#define PPP_MAX_RQLEN	32
> +/* We limit the length of ppp->file.rq/xq to this (arbitrary) value */
> +#define PPP_MAX_QLEN	32
>  
>  /*
>   * Maximum number of multilink fragments queued up.
> @@ -920,8 +920,6 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>  				break;
>  		} else {
>  			ppp->npmode[i] = npi.mode;
> -			/* we may be able to transmit more packets now (??) */
> -			netif_wake_queue(ppp->dev);
>  		}
>  		err = 0;
>  		break;
> @@ -1639,6 +1637,7 @@ static void ppp_setup(struct net_device *dev)
>  	dev->tx_queue_len = 3;
>  	dev->type = ARPHRD_PPP;
>  	dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
> +	dev->priv_flags |= IFF_NO_QUEUE;
>  	dev->priv_destructor = ppp_dev_priv_destructor;
>  	netif_keep_dst(dev);
>  }
> @@ -1654,17 +1653,15 @@ static void __ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb)
>  	if (!ppp->closing) {
>  		ppp_push(ppp);
>  
> -		if (skb)
> -			skb_queue_tail(&ppp->file.xq, skb);
> +		if (skb) {
> +			if (ppp->file.xq.qlen > PPP_MAX_QLEN)
> +				kfree_skb(skb);
> +			else
> +				skb_queue_tail(&ppp->file.xq, skb);
> +		}
>  		while (!ppp->xmit_pending &&
>  		       (skb = skb_dequeue(&ppp->file.xq)))
>  			ppp_send_frame(ppp, skb);
> -		/* If there's no work left to do, tell the core net
> -		   code that we can accept some more. */
> -		if (!ppp->xmit_pending && !skb_peek(&ppp->file.xq))
> -			netif_wake_queue(ppp->dev);
> -		else
> -			netif_stop_queue(ppp->dev);
>  	} else {
>  		kfree_skb(skb);
>  	}
> @@ -1850,7 +1847,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
>  	 * queue it up for pppd to receive.
>  	 */
>  	if (ppp->flags & SC_LOOP_TRAFFIC) {
> -		if (ppp->file.rq.qlen > PPP_MAX_RQLEN)
> +		if (ppp->file.rq.qlen > PPP_MAX_QLEN)
>  			goto drop;
>  		skb_queue_tail(&ppp->file.rq, skb);
>  		wake_up_interruptible(&ppp->file.rwait);
> @@ -2319,7 +2316,7 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
>  		/* put it on the channel queue */
>  		skb_queue_tail(&pch->file.rq, skb);
>  		/* drop old frames if queue too long */
> -		while (pch->file.rq.qlen > PPP_MAX_RQLEN &&
> +		while (pch->file.rq.qlen > PPP_MAX_QLEN &&
>  		       (skb = skb_dequeue(&pch->file.rq)))
>  			kfree_skb(skb);
>  		wake_up_interruptible(&pch->file.rwait);
> @@ -2472,7 +2469,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
>  		/* control or unknown frame - pass it to pppd */
>  		skb_queue_tail(&ppp->file.rq, skb);
>  		/* limit queue length by dropping old frames */
> -		while (ppp->file.rq.qlen > PPP_MAX_RQLEN &&
> +		while (ppp->file.rq.qlen > PPP_MAX_QLEN &&
>  		       (skb = skb_dequeue(&ppp->file.rq)))
>  			kfree_skb(skb);
>  		/* wake up any process polling or blocking on read */
> -- 
> 2.34.1
> 
>