Skip to content

Support PSP in wire server mode#100

Open
danieldzahka wants to merge 12 commits into
google:masterfrom
danieldzahka:master
Open

Support PSP in wire server mode#100
danieldzahka wants to merge 12 commits into
google:masterfrom
danieldzahka:master

Conversation

@danieldzahka
Copy link
Copy Markdown

Hello,

As of 6.16, linux has support for PSP transport mode for tcp. Packetdrill is very useful for reaching the different tcp states that can happen around key exchange. Additionally, we see packetdrill support and tests as something we will require for any future psp features in linux e.g. rekeying, so I hope that we can find a way of getting this upstream, as opposed to needing to carry a fork.

Here is how the series works:
There is no support for tun mode. This is mostly a consequence of not being able to land code in the TUN driver to do mock psp encap and decap. So, instead the series just implements wire server mode, where we can target real NIC + driver stacks.

The series has four main parts:

  1. Support for parsing/building psp packets, adding psp to the .pkt script language, etc. This code came mostly from https://github.com/wdebruij/packetdrill
  2. Code for dispatching psp netlink ops, keeping track of spi + key state, and mapping from script to live values, and synchronizing that state on the wireserver.
  3. Using a vendored version of the kernel's aesgcm crypto library to form packets that can be decrypted by a real NIC.
  4. Some .pkt test cases for psp

Let me know what you think.

  • Daniel

wdebruij and others added 8 commits May 1, 2026 07:48
Add PSP header definitions and packet parsing code. PSP udp dport
defaults to 0 (inactive), and can be enabled to work on any udp
dport. This commit only supports what the spec calls "transport mode",
where the transport is tcp.

This code was originally authored by Dimitris Michailidis
<dmichail@google.com> and Willem de Bruijn <willemb@google.com>.

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
Add parser and lexer support for PSP encapsulation of TCP packets
in packetdrill scripts using the 'encap psp spi <N>' syntax. E.g:

+0 < encap psp spi 12 . 1:1001(1000) ack 1

L4 checksums for PSP transport mode should be performed using
non-encapsulated l4 length.

This code was originally authored by Dimitris Michailidis
<dmichail@google.com> and Willem de Bruijn <willemb@google.com>.

Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
psp_state is an associative container for mapping between PSP SPIs
from the .pkt script, and SPIs obtained from PSP uapi at runtime.

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
Add ynl-c (YNL for C) as a git submodule and wire it into the Linux
build system. Makefile.Linux sets up include paths for the generated
headers and links libynl.a as a static library. Makefile.common is
updated to support platform-specific extra CFLAGS, objects, and static
libraries.

To initialize after cloning:
  git submodule update --init

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
This code is adapted from
tools/testing/selftests/drivers/net/psp_responder.c in the linux
source tree. It simplifies using the linux PSP uapi.

On the wire_server side we disable psp rx on the NIC, so that we can
see un-decapsulated, un-decrypted frames.

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
These are not truly system calls, but rather correspond to PSP netlink
operations. syscall_psp_tx_assoc() can use the script SPI value as is
without issue.

syscall_psp_rx_assoc() needs to record the script SPI -> live SPI
mapping after generating a SPI from the uapi.

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
Embed psp_state in the wire_packets_start message so the wire client
sends the current script-to-live SPI mapping to the wire server before
each batch of packet events. The server copies the received mapping
into its own state so that outbound injected packets use the correct
live SPIs.

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
Add psp_map_to_live() which translates the script SPI in a PSP packet
header to the kernel-assigned live SPI and recomputes the outer UDP
checksum. Call it from send_live_ip_packet() so that all injected PSP
packets carry the correct live SPI before reaching the kernel.

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
@google-cla
Copy link
Copy Markdown

google-cla Bot commented May 1, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

* "ip src 1.2.3.4 and "
* "(src port 0xaabb or dst port 0xccdd or icmp)"
* "(src port 0xaabb or dst port 0xccdd or "
* " dst port 0x03e8 or icmp)"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dst port 1000 (PSP)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the dst port 0x03e8 for psp. Do you mean just format in decimal?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, or in parentheses or just say psp in parentheses. It's an easy to remember number. 0x3e8 does not immediately signal psp.

{ 0x28, 0, 0, 0x00000014 },
{ 0x45, 7, 0, 0x00001fff },
{ 0xb1, 0, 0, 0x0000000e },
{ 0x48, 0, 0, 0x0000000e },
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid all these whitespace changes?

Copy link
Copy Markdown
Contributor

@wdebruij wdebruij left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not use a library for AES?

+.1 < S 0:0(0) win 50000 <mss 1000,nop,wscale 0>
+0 > S. 0:0(0) ack 1 <mss MSS,nop,wscale 8>
+.1 < . 1:1(0) ack 1 win 50000
+0 accept(3, ..., ...) = 4
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

different indentation than above than below

+0 < encap psp spi 7 . 1:1(0) ack 1 win 50000

// retransmit as cleartext
+0.3 > P. 1:501(500) ack 1
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does it retrans as cleartext here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because 1:501 was added to the write queue before tx-assoc netlink call

Copy link
Copy Markdown
Contributor

@wdebruij wdebruij left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice, thanks!

@wdebruij
Copy link
Copy Markdown
Contributor

wdebruij commented May 4, 2026

Please do note the CLA request from the bot:

"Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA)."

@danieldzahka
Copy link
Copy Markdown
Author

Please do note the CLA request from the bot:

"Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA)."

Thanks. I believe it is good to go and green now.

Extend the packet socket BPF filters (both IPv4 and IPv6) to also
capture UDP packets destined to the PSP port, so the wire server
receives PSP-encapsulated traffic.

Add matching iptables rules in wire_server_netdev to drop and later
re-permit PSP UDP traffic, preventing the server kernel from
processing test packets.

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
Daniel Zahka added 3 commits May 4, 2026 07:52
wireserver mode is unlikely to work if this command fails, because a
TCP RST will be sent in response to packets generated from linux ->
wireserver, and thus the socket under test will die.

Emit a warning when the iptables command fails. This can happen when
running kernels without iptables module support.

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
Perform real aes-gcm. For the packetdrill -> linux path, we need to
keep track of what the live key to use for each spi is. On the reverse
path we can just use a key derived from things in the script.

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
Assisted-by: Claude Code:claude-opus-4-7
Add packetdrill test scripts exercising PSP transport-mode
functionality. Each test begins with a comment explaining the scenario
being covered.

server:
./packetdrill --wire_server --ip_version=ipv6 --wire_server_dev=eth0

client:
./packetdrill \
            --wire_server_dev=eth0 \
            --wire_client_dev=eth0 \
            --wire_server_at=<ip6 addr> \
            --local_ip=<ip6 addr> \
            --remote_ip=<ip6 addr> \
            --ip_version=ipv6 \
            -D MSS=1440 \
            ../psp/psp-basic.pkt

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants