[PATCH net-next 2/2] pppoe: drop sock reference counting on fast path

From: Qingfang Deng
Date: Mon Aug 25 2025 - 22:34:35 EST


Now that PPPoE sockets are freed via RCU (SOCK_RCU_FREE), it is no longer
necessary to take a reference count when looking up sockets on the receive
path. Readers are protected by RCU, so the socket memory remains valid
until after a grace period.

Convert fast-path lookups to avoid refcounting:
- Replace get_item() and sk_receive_skb() in pppoe_rcv() with
__get_item() and __sk_receive_skb().
- Rework get_item_by_addr() into __get_item_by_addr() (no refcount)
and add check_item_by_addr() for existence checks in pppoe_ioctl().
- Remove unnecessary sock_put() calls.

This avoids cacheline bouncing from atomic reference counting and improves
performance on the receive fast path.

Signed-off-by: Qingfang Deng <dqfext@xxxxxxxxx>
---
drivers/net/ppp/pppoe.c | 54 +++++++++++++++++++++++------------------
1 file changed, 31 insertions(+), 23 deletions(-)

diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index f99533c80b66..70a7e1e88799 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -237,13 +237,30 @@ static inline struct pppox_sock *get_item(struct pppoe_net *pn, __be16 sid,
return po;
}

-static inline struct pppox_sock *get_item_by_addr(struct net *net,
- struct sockaddr_pppox *sp)
+static inline struct pppox_sock *__get_item_by_addr(struct net *net,
+ struct sockaddr_pppox *sp)
{
struct net_device *dev;
struct pppoe_net *pn;
struct pppox_sock *pppox_sock = NULL;
+ int ifindex;
+
+ dev = dev_get_by_name_rcu(net, sp->sa_addr.pppoe.dev);
+ if (dev) {
+ ifindex = dev->ifindex;
+ pn = pppoe_pernet(net);
+ pppox_sock = __get_item(pn, sp->sa_addr.pppoe.sid,
+ sp->sa_addr.pppoe.remote, ifindex);
+ }
+ return pppox_sock;
+}

+static inline bool check_item_by_addr(struct net *net,
+ struct sockaddr_pppox *sp)
+{
+ struct net_device *dev;
+ struct pppoe_net *pn;
+ bool ret = false;
int ifindex;

rcu_read_lock();
@@ -251,11 +268,11 @@ static inline struct pppox_sock *get_item_by_addr(struct net *net,
if (dev) {
ifindex = dev->ifindex;
pn = pppoe_pernet(net);
- pppox_sock = get_item(pn, sp->sa_addr.pppoe.sid,
- sp->sa_addr.pppoe.remote, ifindex);
+ ret = !!__get_item(pn, sp->sa_addr.pppoe.sid,
+ sp->sa_addr.pppoe.remote, ifindex);
}
rcu_read_unlock();
- return pppox_sock;
+ return ret;
}

static inline void delete_item(struct pppoe_net *pn, __be16 sid,
@@ -381,18 +398,16 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
if (sk->sk_state & PPPOX_BOUND) {
ppp_input(&po->chan, skb);
} else if (sk->sk_state & PPPOX_RELAY) {
- relay_po = get_item_by_addr(sock_net(sk),
- &po->pppoe_relay);
+ relay_po = __get_item_by_addr(sock_net(sk),
+ &po->pppoe_relay);
if (relay_po == NULL)
goto abort_kfree;

if ((sk_pppox(relay_po)->sk_state & PPPOX_CONNECTED) == 0)
- goto abort_put;
+ goto abort_kfree;

if (!__pppoe_xmit(sk_pppox(relay_po), skb))
- goto abort_put;
-
- sock_put(sk_pppox(relay_po));
+ goto abort_kfree;
} else {
if (sock_queue_rcv_skb(sk, skb))
goto abort_kfree;
@@ -400,9 +415,6 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)

return NET_RX_SUCCESS;

-abort_put:
- sock_put(sk_pppox(relay_po));
-
abort_kfree:
kfree_skb(skb);
return NET_RX_DROP;
@@ -447,14 +459,11 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,
ph = pppoe_hdr(skb);
pn = pppoe_pernet(dev_net(dev));

- /* Note that get_item does a sock_hold(), so sk_pppox(po)
- * is known to be safe.
- */
- po = get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
+ po = __get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
if (!po)
goto drop;

- return sk_receive_skb(sk_pppox(po), skb, 0);
+ return __sk_receive_skb(sk_pppox(po), skb, 0, 1, false);

drop:
kfree_skb(skb);
@@ -790,7 +799,7 @@ static int pppoe_ioctl(struct socket *sock, unsigned int cmd,

case PPPOEIOCSFWD:
{
- struct pppox_sock *relay_po;
+ bool ret;

err = -EBUSY;
if (sk->sk_state & (PPPOX_BOUND | PPPOX_DEAD))
@@ -815,11 +824,10 @@ static int pppoe_ioctl(struct socket *sock, unsigned int cmd,

/* Check that the socket referenced by the address
actually exists. */
- relay_po = get_item_by_addr(sock_net(sk), &po->pppoe_relay);
- if (!relay_po)
+ ret = check_item_by_addr(sock_net(sk), &po->pppoe_relay);
+ if (!ret)
break;

- sock_put(sk_pppox(relay_po));
sk->sk_state |= PPPOX_RELAY;
err = 0;
break;
--
2.43.0