Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

netdevsim: a basic test PSP implementation

Provide a PSP implementation for netdevsim.

Use psp_dev_encapsulate() and psp_dev_rcv() to do actual encapsulation
and decapsulation on skbs, but perform no encryption or decryption. In
order to make encryption with a bad key result in a drop on the peer's
rx side, we stash our psd's generation number in the first byte of each
key before handing to the peer.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Co-developed-by: Daniel Zahka <daniel.zahka@gmail.com>
Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
Link: https://patch.msgid.link/20250927225420.1443468-2-kuba@kernel.org
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Jakub Kicinski and committed by
Paolo Abeni
f857478d 9ebef94c

+294 -6
+4
drivers/net/netdevsim/Makefile
··· 18 18 netdevsim-objs += psample.o 19 19 endif 20 20 21 + ifneq ($(CONFIG_INET_PSP),) 22 + netdevsim-objs += psp.o 23 + endif 24 + 21 25 ifneq ($(CONFIG_MACSEC),) 22 26 netdevsim-objs += macsec.o 23 27 endif
+37 -6
drivers/net/netdevsim/netdev.c
··· 103 103 static int nsim_forward_skb(struct net_device *tx_dev, 104 104 struct net_device *rx_dev, 105 105 struct sk_buff *skb, 106 - struct nsim_rq *rq) 106 + struct nsim_rq *rq, 107 + struct skb_ext *psp_ext) 107 108 { 108 - return __dev_forward_skb(rx_dev, skb) ?: 109 - nsim_napi_rx(tx_dev, rx_dev, rq, skb); 109 + int ret; 110 + 111 + ret = __dev_forward_skb(rx_dev, skb); 112 + if (ret) 113 + return ret; 114 + 115 + nsim_psp_handle_ext(skb, psp_ext); 116 + 117 + return nsim_napi_rx(tx_dev, rx_dev, rq, skb); 110 118 } 111 119 112 120 static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev) 113 121 { 114 122 struct netdevsim *ns = netdev_priv(dev); 123 + struct skb_ext *psp_ext = NULL; 115 124 struct net_device *peer_dev; 116 125 unsigned int len = skb->len; 117 126 struct netdevsim *peer_ns; 118 127 struct netdev_config *cfg; 119 128 struct nsim_rq *rq; 120 129 int rxq; 130 + int dr; 121 131 122 132 rcu_read_lock(); 123 133 if (!nsim_ipsec_tx(ns, skb)) 124 - goto out_drop_free; 134 + goto out_drop_any; 125 135 126 136 peer_ns = rcu_dereference(ns->peer); 127 137 if (!peer_ns) 138 + goto out_drop_any; 139 + 140 + dr = nsim_do_psp(skb, ns, peer_ns, &psp_ext); 141 + if (dr) 128 142 goto out_drop_free; 129 143 130 144 peer_dev = peer_ns->netdev; ··· 155 141 skb_linearize(skb); 156 142 157 143 skb_tx_timestamp(skb); 158 - if (unlikely(nsim_forward_skb(dev, peer_dev, skb, rq) == NET_RX_DROP)) 144 + if (unlikely(nsim_forward_skb(dev, peer_dev, 145 + skb, rq, psp_ext) == NET_RX_DROP)) 159 146 goto out_drop_cnt; 160 147 161 148 if (!hrtimer_active(&rq->napi_timer)) ··· 166 151 dev_dstats_tx_add(dev, len); 167 152 return NETDEV_TX_OK; 168 153 154 + out_drop_any: 155 + dr = SKB_DROP_REASON_NOT_SPECIFIED; 169 156 out_drop_free: 170 - dev_kfree_skb(skb); 157 + kfree_skb_reason(skb, dr); 171 158 out_drop_cnt: 172 159 rcu_read_unlock(); 173 160 dev_dstats_tx_dropped(dev); ··· 1019 1002 1020 1003 static int nsim_init_netdevsim(struct netdevsim *ns) 1021 1004 { 1005 + struct netdevsim *peer; 1022 1006 struct mock_phc *phc; 1023 1007 int err; 1024 1008 ··· 1054 1036 goto err_ipsec_teardown; 1055 1037 rtnl_unlock(); 1056 1038 1039 + err = nsim_psp_init(ns); 1040 + if (err) 1041 + goto err_unregister_netdev; 1042 + 1057 1043 if (IS_ENABLED(CONFIG_DEBUG_NET)) { 1058 1044 ns->nb.notifier_call = netdev_debug_event; 1059 1045 if (register_netdevice_notifier_dev_net(ns->netdev, &ns->nb, ··· 1067 1045 1068 1046 return 0; 1069 1047 1048 + err_unregister_netdev: 1049 + rtnl_lock(); 1050 + peer = rtnl_dereference(ns->peer); 1051 + if (peer) 1052 + RCU_INIT_POINTER(peer->peer, NULL); 1053 + RCU_INIT_POINTER(ns->peer, NULL); 1054 + unregister_netdevice(ns->netdev); 1070 1055 err_ipsec_teardown: 1071 1056 nsim_ipsec_teardown(ns); 1072 1057 nsim_macsec_teardown(ns); ··· 1160 1131 if (ns->nb.notifier_call) 1161 1132 unregister_netdevice_notifier_dev_net(ns->netdev, &ns->nb, 1162 1133 &ns->nn); 1134 + 1135 + nsim_psp_uninit(ns); 1163 1136 1164 1137 rtnl_lock(); 1165 1138 peer = rtnl_dereference(ns->peer);
+27
drivers/net/netdevsim/netdevsim.h
··· 108 108 109 109 int rq_reset_mode; 110 110 111 + struct { 112 + struct psp_dev *dev; 113 + u32 spi; 114 + u32 assoc_cnt; 115 + } psp; 116 + 111 117 struct nsim_bus_dev *nsim_bus_dev; 112 118 113 119 struct bpf_prog *bpf_offloaded; ··· 425 419 static inline void nsim_macsec_teardown(struct netdevsim *ns) 426 420 { 427 421 } 422 + #endif 423 + 424 + #if IS_ENABLED(CONFIG_INET_PSP) 425 + int nsim_psp_init(struct netdevsim *ns); 426 + void nsim_psp_uninit(struct netdevsim *ns); 427 + void nsim_psp_handle_ext(struct sk_buff *skb, struct skb_ext *psp_ext); 428 + enum skb_drop_reason 429 + nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns, 430 + struct netdevsim *peer_ns, struct skb_ext **psp_ext); 431 + #else 432 + static inline int nsim_psp_init(struct netdevsim *ns) { return 0; } 433 + static inline void nsim_psp_uninit(struct netdevsim *ns) {} 434 + static inline enum skb_drop_reason 435 + nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns, 436 + struct netdevsim *peer_ns, struct skb_ext **psp_ext) 437 + { 438 + return 0; 439 + } 440 + 441 + static inline void 442 + nsim_psp_handle_ext(struct sk_buff *skb, struct skb_ext *psp_ext) {} 428 443 #endif 429 444 430 445 struct nsim_bus_dev {
+225
drivers/net/netdevsim/psp.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/ip.h> 4 + #include <linux/skbuff.h> 5 + #include <net/ip6_checksum.h> 6 + #include <net/psp.h> 7 + #include <net/sock.h> 8 + 9 + #include "netdevsim.h" 10 + 11 + void nsim_psp_handle_ext(struct sk_buff *skb, struct skb_ext *psp_ext) 12 + { 13 + if (psp_ext) 14 + __skb_ext_set(skb, SKB_EXT_PSP, psp_ext); 15 + } 16 + 17 + enum skb_drop_reason 18 + nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns, 19 + struct netdevsim *peer_ns, struct skb_ext **psp_ext) 20 + { 21 + enum skb_drop_reason rc = 0; 22 + struct psp_assoc *pas; 23 + struct net *net; 24 + void **ptr; 25 + 26 + rcu_read_lock(); 27 + pas = psp_skb_get_assoc_rcu(skb); 28 + if (!pas) { 29 + rc = SKB_NOT_DROPPED_YET; 30 + goto out_unlock; 31 + } 32 + 33 + if (!skb_transport_header_was_set(skb)) { 34 + rc = SKB_DROP_REASON_PSP_OUTPUT; 35 + goto out_unlock; 36 + } 37 + 38 + ptr = psp_assoc_drv_data(pas); 39 + if (*ptr != ns) { 40 + rc = SKB_DROP_REASON_PSP_OUTPUT; 41 + goto out_unlock; 42 + } 43 + 44 + net = sock_net(skb->sk); 45 + if (!psp_dev_encapsulate(net, skb, pas->tx.spi, pas->version, 0)) { 46 + rc = SKB_DROP_REASON_PSP_OUTPUT; 47 + goto out_unlock; 48 + } 49 + 50 + /* Now pretend we just received this frame */ 51 + if (peer_ns->psp.dev->config.versions & (1 << pas->version)) { 52 + bool strip_icv = false; 53 + u8 generation; 54 + 55 + /* We cheat a bit and put the generation in the key. 56 + * In real life if generation was too old, then decryption would 57 + * fail. Here, we just make it so a bad key causes a bad 58 + * generation too, and psp_sk_rx_policy_check() will fail. 59 + */ 60 + generation = pas->tx.key[0]; 61 + 62 + skb_ext_reset(skb); 63 + skb->mac_len = ETH_HLEN; 64 + if (psp_dev_rcv(skb, peer_ns->psp.dev->id, generation, 65 + strip_icv)) { 66 + rc = SKB_DROP_REASON_PSP_OUTPUT; 67 + goto out_unlock; 68 + } 69 + 70 + *psp_ext = skb->extensions; 71 + refcount_inc(&(*psp_ext)->refcnt); 72 + skb->decrypted = 1; 73 + } else { 74 + struct ipv6hdr *ip6h __maybe_unused; 75 + struct iphdr *iph; 76 + struct udphdr *uh; 77 + __wsum csum; 78 + 79 + /* Do not decapsulate. Receive the skb with the udp and psp 80 + * headers still there as if this is a normal udp packet. 81 + * psp_dev_encapsulate() sets udp checksum to 0, so we need to 82 + * provide a valid checksum here, so the skb isn't dropped. 83 + */ 84 + uh = udp_hdr(skb); 85 + csum = skb_checksum(skb, skb_transport_offset(skb), 86 + ntohs(uh->len), 0); 87 + 88 + switch (skb->protocol) { 89 + case htons(ETH_P_IP): 90 + iph = ip_hdr(skb); 91 + uh->check = udp_v4_check(ntohs(uh->len), iph->saddr, 92 + iph->daddr, csum); 93 + break; 94 + #if IS_ENABLED(CONFIG_IPV6) 95 + case htons(ETH_P_IPV6): 96 + ip6h = ipv6_hdr(skb); 97 + uh->check = udp_v6_check(ntohs(uh->len), &ip6h->saddr, 98 + &ip6h->daddr, csum); 99 + break; 100 + #endif 101 + } 102 + 103 + uh->check = uh->check ?: CSUM_MANGLED_0; 104 + skb->ip_summed = CHECKSUM_NONE; 105 + } 106 + 107 + out_unlock: 108 + rcu_read_unlock(); 109 + return rc; 110 + } 111 + 112 + static int 113 + nsim_psp_set_config(struct psp_dev *psd, struct psp_dev_config *conf, 114 + struct netlink_ext_ack *extack) 115 + { 116 + return 0; 117 + } 118 + 119 + static int 120 + nsim_rx_spi_alloc(struct psp_dev *psd, u32 version, 121 + struct psp_key_parsed *assoc, 122 + struct netlink_ext_ack *extack) 123 + { 124 + struct netdevsim *ns = psd->drv_priv; 125 + unsigned int new; 126 + int i; 127 + 128 + new = ++ns->psp.spi & PSP_SPI_KEY_ID; 129 + if (psd->generation & 1) 130 + new |= PSP_SPI_KEY_PHASE; 131 + 132 + assoc->spi = cpu_to_be32(new); 133 + assoc->key[0] = psd->generation; 134 + for (i = 1; i < PSP_MAX_KEY; i++) 135 + assoc->key[i] = ns->psp.spi + i; 136 + 137 + return 0; 138 + } 139 + 140 + static int nsim_assoc_add(struct psp_dev *psd, struct psp_assoc *pas, 141 + struct netlink_ext_ack *extack) 142 + { 143 + struct netdevsim *ns = psd->drv_priv; 144 + void **ptr = psp_assoc_drv_data(pas); 145 + 146 + /* Copy drv_priv from psd to assoc */ 147 + *ptr = psd->drv_priv; 148 + ns->psp.assoc_cnt++; 149 + 150 + return 0; 151 + } 152 + 153 + static int nsim_key_rotate(struct psp_dev *psd, struct netlink_ext_ack *extack) 154 + { 155 + return 0; 156 + } 157 + 158 + static void nsim_assoc_del(struct psp_dev *psd, struct psp_assoc *pas) 159 + { 160 + struct netdevsim *ns = psd->drv_priv; 161 + void **ptr = psp_assoc_drv_data(pas); 162 + 163 + *ptr = NULL; 164 + ns->psp.assoc_cnt--; 165 + } 166 + 167 + static struct psp_dev_ops nsim_psp_ops = { 168 + .set_config = nsim_psp_set_config, 169 + .rx_spi_alloc = nsim_rx_spi_alloc, 170 + .tx_key_add = nsim_assoc_add, 171 + .tx_key_del = nsim_assoc_del, 172 + .key_rotate = nsim_key_rotate, 173 + }; 174 + 175 + static struct psp_dev_caps nsim_psp_caps = { 176 + .versions = 1 << PSP_VERSION_HDR0_AES_GCM_128 | 177 + 1 << PSP_VERSION_HDR0_AES_GMAC_128 | 178 + 1 << PSP_VERSION_HDR0_AES_GCM_256 | 179 + 1 << PSP_VERSION_HDR0_AES_GMAC_256, 180 + .assoc_drv_spc = sizeof(void *), 181 + }; 182 + 183 + void nsim_psp_uninit(struct netdevsim *ns) 184 + { 185 + if (!IS_ERR(ns->psp.dev)) 186 + psp_dev_unregister(ns->psp.dev); 187 + WARN_ON(ns->psp.assoc_cnt); 188 + } 189 + 190 + static ssize_t 191 + nsim_psp_rereg_write(struct file *file, const char __user *data, size_t count, 192 + loff_t *ppos) 193 + { 194 + struct netdevsim *ns = file->private_data; 195 + int err; 196 + 197 + nsim_psp_uninit(ns); 198 + 199 + ns->psp.dev = psp_dev_create(ns->netdev, &nsim_psp_ops, 200 + &nsim_psp_caps, ns); 201 + err = PTR_ERR_OR_ZERO(ns->psp.dev); 202 + return err ?: count; 203 + } 204 + 205 + static const struct file_operations nsim_psp_rereg_fops = { 206 + .open = simple_open, 207 + .write = nsim_psp_rereg_write, 208 + .llseek = generic_file_llseek, 209 + .owner = THIS_MODULE, 210 + }; 211 + 212 + int nsim_psp_init(struct netdevsim *ns) 213 + { 214 + struct dentry *ddir = ns->nsim_dev_port->ddir; 215 + int err; 216 + 217 + ns->psp.dev = psp_dev_create(ns->netdev, &nsim_psp_ops, 218 + &nsim_psp_caps, ns); 219 + err = PTR_ERR_OR_ZERO(ns->psp.dev); 220 + if (err) 221 + return err; 222 + 223 + debugfs_create_file("psp_rereg", 0200, ddir, ns, &nsim_psp_rereg_fops); 224 + return 0; 225 + }
+1
net/core/skbuff.c
··· 7048 7048 skb->active_extensions = 1 << id; 7049 7049 return skb_ext_get_ptr(ext, id); 7050 7050 } 7051 + EXPORT_SYMBOL_NS_GPL(__skb_ext_set, "NETDEV_INTERNAL"); 7051 7052 7052 7053 /** 7053 7054 * skb_ext_add - allocate space for given extension, COW if needed