[PATCH net-next 3/6] netdevsim: psp: move rx processing into nsim_poll()
From: Daniel Zahka
Date: Fri May 08 2026 - 10:57:36 EST
nsim_do_psp() does PSP decap and skb extension creation in the tx
path. This has the slightly undesirable property of not allowing the
psp rx code to run on PSP packets cooked up in userspace and
transmitted on a packet socket from the peer dev (e.g. packetdrill).
This commit instead triggers the psp rx path just based on parsing the
received skb. The current code relies on a bit of a hack to simulate
authentication with the proper key: the peer's psd->generation was
placed into the tx key, and during decap used to fill out the
extension the packet before being sent up the psp rx path. This commit
removes that hack, which creates a transient break in psp.py test
cases that rely on this behavior (e.g. data_send_bad_key). Subsequent
commits which introduce real aes-gcm crypto will restore the correct
behavior.
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Daniel Zahka <daniel.zahka@xxxxxxxxx>
---
drivers/net/netdevsim/netdev.c | 18 ++---
drivers/net/netdevsim/netdevsim.h | 14 ++--
drivers/net/netdevsim/psp.c | 143 ++++++++++++++++++++++++++------------
3 files changed, 113 insertions(+), 62 deletions(-)
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index a750768912b5..9c0db7b91fd6 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -103,19 +103,13 @@ static int nsim_napi_rx(struct net_device *tx_dev, struct net_device *rx_dev,
static int nsim_forward_skb(struct net_device *tx_dev,
struct net_device *rx_dev,
struct sk_buff *skb,
- struct nsim_rq *rq,
- struct skb_ext *psp_ext)
+ struct nsim_rq *rq)
{
int ret;
ret = __dev_forward_skb(rx_dev, skb);
- if (ret) {
- if (psp_ext)
- __skb_ext_put(psp_ext);
+ if (ret)
return ret;
- }
-
- nsim_psp_handle_ext(skb, psp_ext);
return nsim_napi_rx(tx_dev, rx_dev, rq, skb);
}
@@ -123,7 +117,6 @@ static int nsim_forward_skb(struct net_device *tx_dev,
static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct netdevsim *ns = netdev_priv(dev);
- struct skb_ext *psp_ext = NULL;
struct net_device *peer_dev;
unsigned int len = skb->len;
struct netdevsim *peer_ns;
@@ -147,7 +140,7 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
peer_dev = peer_ns->netdev;
}
- dr = nsim_do_psp(skb, ns, peer_ns, &psp_ext);
+ dr = nsim_psp_handle_tx(skb, ns);
if (dr)
goto out_drop_free;
@@ -165,7 +158,7 @@ static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb_tx_timestamp(skb);
if (unlikely(nsim_forward_skb(dev, peer_dev,
- skb, rq, psp_ext) == NET_RX_DROP))
+ skb, rq) == NET_RX_DROP))
goto out_drop_cnt;
if (!hrtimer_active(&rq->napi_timer))
@@ -379,6 +372,9 @@ static int nsim_rcv(struct nsim_rq *rq, int budget)
skb = skb_dequeue(&rq->skb_queue);
+ if (nsim_psp_handle_rx(ns, skb))
+ continue;
+
if (xdp_prog) {
/* skb might be freed directly by XDP, save the len */
skblen = skb->len;
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index d909c4160ea1..dcea76429bac 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -451,22 +451,22 @@ static inline void nsim_macsec_teardown(struct netdevsim *ns)
#if IS_ENABLED(CONFIG_INET_PSP)
int nsim_psp_init(struct netdevsim *ns);
void nsim_psp_uninit(struct netdevsim *ns);
-void nsim_psp_handle_ext(struct sk_buff *skb, struct skb_ext *psp_ext);
enum skb_drop_reason
-nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns,
- struct netdevsim *peer_ns, struct skb_ext **psp_ext);
+nsim_psp_handle_tx(struct sk_buff *skb, struct netdevsim *ns);
+bool nsim_psp_handle_rx(struct netdevsim *ns, struct sk_buff *skb);
#else
static inline int nsim_psp_init(struct netdevsim *ns) { return 0; }
static inline void nsim_psp_uninit(struct netdevsim *ns) {}
static inline enum skb_drop_reason
-nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns,
- struct netdevsim *peer_ns, struct skb_ext **psp_ext)
+nsim_psp_handle_tx(struct sk_buff *skb, struct netdevsim *ns)
{
return 0;
}
-static inline void
-nsim_psp_handle_ext(struct sk_buff *skb, struct skb_ext *psp_ext) {}
+static inline bool nsim_psp_handle_rx(struct netdevsim *ns, struct sk_buff *skb)
+{
+ return false;
+}
#endif
int nsim_setup_tc(struct net_device *dev, enum tc_setup_type type,
diff --git a/drivers/net/netdevsim/psp.c b/drivers/net/netdevsim/psp.c
index 75740e2a731f..e8831d4bf394 100644
--- a/drivers/net/netdevsim/psp.c
+++ b/drivers/net/netdevsim/psp.c
@@ -6,18 +6,10 @@
#include "netdevsim.h"
-void nsim_psp_handle_ext(struct sk_buff *skb, struct skb_ext *psp_ext)
-{
- if (psp_ext)
- __skb_ext_set(skb, SKB_EXT_PSP, psp_ext);
-}
-
enum skb_drop_reason
-nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns,
- struct netdevsim *peer_ns, struct skb_ext **psp_ext)
+nsim_psp_handle_tx(struct sk_buff *skb, struct netdevsim *ns)
{
enum skb_drop_reason rc = 0;
- struct psp_dev *peer_psd;
struct psp_assoc *pas;
struct net *net;
void **ptr;
@@ -46,47 +38,110 @@ nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns,
goto out_unlock;
}
- /* Now pretend we just received this frame */
- peer_psd = rcu_dereference(peer_ns->psp.dev);
- if (peer_psd && peer_psd->config.versions & (1 << pas->version)) {
- bool strip_icv = false;
- u8 generation;
-
- /* We cheat a bit and put the generation in the key.
- * In real life if generation was too old, then decryption would
- * fail. Here, we just make it so a bad key causes a bad
- * generation too, and psp_sk_rx_policy_check() will fail.
- */
- generation = pas->tx.key[0];
-
- skb_ext_reset(skb);
- skb->mac_len = ETH_HLEN;
- if (psp_dev_rcv(skb, peer_psd->id, generation, strip_icv)) {
- rc = SKB_DROP_REASON_PSP_OUTPUT;
- goto out_unlock;
- }
-
- *psp_ext = skb->extensions;
- refcount_inc(&(*psp_ext)->refcnt);
- skb->decrypted = 1;
-
- u64_stats_update_begin(&ns->psp.syncp);
- u64_stats_inc(&ns->psp.tx_packets);
- u64_stats_inc(&ns->psp.rx_packets);
- u64_stats_add(&ns->psp.tx_bytes,
- skb->len - skb_inner_transport_offset(skb));
- u64_stats_add(&ns->psp.rx_bytes,
- skb->len - skb_inner_transport_offset(skb));
- u64_stats_update_end(&ns->psp.syncp);
- } else {
- skb->ip_summed = CHECKSUM_NONE;
- }
+ skb->decrypted = 0;
+ u64_stats_update_begin(&ns->psp.syncp);
+ u64_stats_inc(&ns->psp.tx_packets);
+ u64_stats_add(&ns->psp.tx_bytes,
+ skb->len - skb_inner_transport_offset(skb));
+ u64_stats_update_end(&ns->psp.syncp);
out_unlock:
rcu_read_unlock();
return rc;
}
+/* Returns true if skb was consumed, false otherwise. */
+bool nsim_psp_handle_rx(struct netdevsim *ns, struct sk_buff *skb)
+{
+ struct psp_dev *psd;
+ struct psphdr *psph;
+ struct udphdr *uh;
+ int payload_len;
+ u32 versions;
+ int psp_off;
+ bool is_udp;
+ int l3_hlen;
+ u8 version;
+ u32 psd_id;
+ int err;
+
+ if (skb->protocol == htons(ETH_P_IP)) {
+ struct iphdr *iph;
+
+ if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ return false;
+
+ iph = (struct iphdr *)skb->data;
+ if (iph->ihl < 5)
+ return false;
+
+ is_udp = iph->protocol == IPPROTO_UDP;
+ l3_hlen = iph->ihl * 4;
+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ struct ipv6hdr *ip6h;
+
+ if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+ return false;
+ ip6h = (struct ipv6hdr *)skb->data;
+ is_udp = ip6h->nexthdr == IPPROTO_UDP;
+ l3_hlen = sizeof(struct ipv6hdr);
+ } else {
+ return false;
+ }
+
+ if (!is_udp)
+ return false;
+
+ if (!pskb_may_pull(skb, l3_hlen + sizeof(struct udphdr) + PSP_HDR_SIZE))
+ return false;
+
+ uh = (struct udphdr *)(skb->data + l3_hlen);
+ if (uh->dest != htons(PSP_DEFAULT_UDP_PORT))
+ return false;
+
+ psph = (struct psphdr *)(uh + 1);
+ version = FIELD_GET(PSPHDR_VERFL_VERSION, psph->verfl);
+
+ rcu_read_lock();
+ psd = rcu_dereference(ns->psp.dev);
+ if (psd) {
+ versions = READ_ONCE(psd->config.versions);
+ psd_id = psd->id;
+ }
+ rcu_read_unlock();
+
+ if (!psd || !(versions & (1 << version))) {
+ skb->ip_summed = CHECKSUM_NONE;
+ return false;
+ }
+
+ psp_off = l3_hlen + sizeof(struct udphdr);
+ payload_len = skb->len - psp_off - PSP_HDR_SIZE - PSP_TRL_SIZE;
+ if (payload_len < 0)
+ goto drop;
+
+ skb_push(skb, ETH_HLEN);
+ skb->mac_len = ETH_HLEN;
+ err = psp_dev_rcv(skb, psd_id, 0, false);
+ if (err)
+ goto drop;
+
+ skb_reset_mac_header(skb);
+ skb_pull(skb, ETH_HLEN);
+ skb->decrypted = 1;
+
+ u64_stats_update_begin(&ns->psp.syncp);
+ u64_stats_inc(&ns->psp.rx_packets);
+ u64_stats_add(&ns->psp.rx_bytes, payload_len);
+ u64_stats_update_end(&ns->psp.syncp);
+
+ return false;
+
+drop:
+ kfree_skb_reason(skb, SKB_DROP_REASON_PSP_INPUT);
+ return true;
+}
+
static int
nsim_psp_set_config(struct psp_dev *psd, struct psp_dev_config *conf,
struct netlink_ext_ack *extack)
--
2.52.0