Thank you for your contribution! Sashiko AI review found 7 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 0 · Low: 7

- [Low] `struct psphdr { ... } __packed;` in
  tools/testing/selftests/net/lib/gro.c uses the `__packed` macro, but…
- [Low] The `psp_ver_diff` sub-test claims to verify that 'different PSP
  version doesn't coalesce', but it is implemented by the same…
- [Low] The file-level comment block of
  tools/testing/selftests/net/lib/gro.c enumerates every test case and…
- [Low] Concern (validated as NOT a defect): gro.c gains `--psp-assoc`
  and three psp_* sub-tests with no in-tree caller, making the feature…
- [Low] Concern (validated as NOT a defect): psp_encapsulate() hardcodes
  IPv6 header length and does not walk extension headers or reject…
- [Low] Concern (validated as NOT a defect): psp_encapsulate() recomputes
  the IPv4 header checksum from scratch, repairing the deliberately…
- [Low] Concern (validated as NOT a defect): each parsed PSP association
  allocates an EVP_CIPHER_CTX that is never freed, on error paths and at…

--

selftests: net: gro: Add PSP encapsulation and encryption

This adds an optional PSP transport mode to the gro selftest helper: frames
are encapsulated and encrypted in software with OpenSSL before being sent,
and the receiving NIC is expected to decrypt and decapsulate them. Three
PSP-only sub-tests (psp_spi_diff, psp_ver_diff, psp_mixed) and a new
--psp-assoc option are added, with libcrypto detection scoped to the gro
binary in the Makefile.

A few questions below.

> diff --git a/tools/testing/selftests/net/lib/gro.c 
> b/tools/testing/selftests/net/lib/gro.c
> index 7a333155de1a..fe4a4c0e17ae 100644
> --- a/tools/testing/selftests/net/lib/gro.c
> +++ b/tools/testing/selftests/net/lib/gro.c

[ ... ]

> @@ -110,6 +119,38 @@
>  
>  #define EXIT_OVER_COALESCE   42
>  
> +/* PSP transport mode encapsulation, as built by the sender:
> + *
> + *   [eth][IP][UDP dport=1000][PSP hdr][encrypted L4][ICV]
> + *
> + * Can't use the kernel-only include/net/psp/types.h header, so copy the
> + * encoding here.
> + */
> +struct psphdr {
> +     uint8_t         nexthdr;
> +     uint8_t         hdrlen;
> +     uint8_t         crypt_offset;
> +     uint8_t         verfl;
> +     uint32_t        spi;            /* big endian */
> +     uint64_t        iv;             /* big endian */
> +} __packed;

[Severity: Low]

Where does __packed come from in this translation unit?

The include path for this binary is only:

  CFLAGS += -I../../../../../usr/include/ $(KHDR_INCLUDES)
  CFLAGS += -I../../

scripts/headers_install.sh textually rewrites the macro when exporting uapi
headers:

  s/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g

so the installed headers (including linux/psp.h) never define __packed, and
kselftest.h plus net/lib/ksft.h only pull in libc headers. In tools/ the
macro is defined by tools/include/linux/compiler.h and
tools/include/linux/compiler-gcc.h, neither of which is on this include
path.

Doesn't that make the declaration parse as a file-scope tentative definition
of an object named __packed of type struct psphdr, leaving the struct
unpacked?

The layouts happen to agree today (spi at offset 4, iv at offset 8,
sizeof == 16), so PSP_HDR_LEN and the offsetof() used for the nonce are
still right. But the unpacked struct carries 8-byte alignment while psph
lands at ETH_HLEN + 20 + 8 == 42 inside psp_scratch, i.e. 2 mod 8, so:

        psph->spi = htonl(assoc->spi);
        psph->iv = htobe64(psp_next_iv++);

are stores the compiler is entitled to treat as aligned. Would using
__attribute__((packed)) directly, or defining __packed locally as the sgx
and bpf selftests do, be preferable here?

> +
> +#define PSP_UDP_PORT         1000
> +#define PSP_UDP_LEN          sizeof(struct udphdr)
> +#define PSP_HDR_LEN          sizeof(struct psphdr)

[ ... ]

> @@ -1111,6 +1374,39 @@ static void send_changed_pppoe_sid(int fd, struct 
> sockaddr_ll *daddr)
>       write_packet(fd, buf, pkt_size, daddr);
>  }
>  
> +/* PSP packets don't coalesce across SPIs or versions. */
> +static void send_psp_assoc_switch(int fd, struct sockaddr_ll *daddr)
> +{
> +     static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
> +     int pkt_size = total_hdr_len + PAYLOAD_LEN;
> +
> +     if (psp_num_assoc < 2)
> +             error(1, 0, "%s needs two PSP associations", testname);
> +
> +     create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
> +     write_packet(fd, buf, pkt_size, daddr);
> +
> +     create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
> +     psp_idx = 1;
> +     write_packet(fd, buf, pkt_size, daddr);
> +     psp_idx = 0;
> +}

[Severity: Low]

Does psp_ver_diff actually exercise the version dimension?

Both psp_spi_diff and psp_ver_diff dispatch to send_psp_assoc_switch(),
which only flips psp_idx from association 0 to association 1. Since the two
RX associations always carry distinct device-allocated SPIs, the second
frame differs in SPI as well as version.

The kernel side compares the whole extension:

include/net/psp/functions.h:__psp_skb_coalesce_diff() {
        ...
        diffs |= memcmp(a, b, sizeof(*a));
        ...
}

over struct psp_skb_ext { __be32 spi; u16 dev_id; u8 generation;
u8 version; }, so the differing SPI alone already forces the flush.

Wouldn't psp_ver_diff then keep passing even if the version field were
dropped from the software or hardware comparison, making it a duplicate of
psp_spi_diff? Since SPIs are allocated by the device and two associations
cannot share one, would it make sense to at least assert
psp_assocs[0].version != psp_assocs[1].version in the sender, or note in a
comment that this case mainly exercises multi-version decap?

>  static void bind_packetsocket(int fd)
>  {
>       struct sockaddr_ll daddr = {};

[ ... ]

> @@ -1559,6 +1855,16 @@ static void gro_sender(void)
>               usleep(fin_delay_us);
>               write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
>  
> +     /* PSP sub-tests */
> +     } else if (strcmp(testname, "psp_spi_diff") == 0 ||
> +                strcmp(testname, "psp_ver_diff") == 0) {
> +             send_psp_assoc_switch(txfd, &daddr);
> +             usleep(fin_delay_us);
> +             write_packet(txfd, fin_pkt, total_hdr_len, &daddr);

[ ... ]

> @@ -1782,6 +2088,22 @@ static void gro_receiver(void)
>               printf("different PPPoE session ID doesn't coalesce: ");
>               check_recv_pkts(rxfd, correct_payload, 2);
>  
> +     /* PSP sub-tests */
> +     } else if (strcmp(testname, "psp_spi_diff") == 0) {
> +             correct_payload[0] = PAYLOAD_LEN;
> +             correct_payload[1] = PAYLOAD_LEN;
> +             printf("different PSP SPI doesn't coalesce: ");
> +             check_recv_pkts(rxfd, correct_payload, 2);
> +     } else if (strcmp(testname, "psp_ver_diff") == 0) {
> +             correct_payload[0] = PAYLOAD_LEN;
> +             correct_payload[1] = PAYLOAD_LEN;
> +             printf("different PSP version doesn't coalesce: ");
> +             check_recv_pkts(rxfd, correct_payload, 2);

[ ... ]

> @@ -1802,6 +2124,7 @@ static void parse_args(int argc, char **argv)
>               { "ip6ip6", no_argument, NULL, 'E' },
>               { "pppoev4", no_argument, NULL, 'p' },
>               { "pppoev6", no_argument, NULL, 'P' },
> +             { "psp-assoc", required_argument, NULL, OPT_PSP_ASSOC },

[Severity: Low]

Should the file-level comment block at the top of gro.c be extended too?

It enumerates every sub-test family (data_*, flags_*, tcp_*, ip_*, large_*,
single, capacity), but psp_spi_diff, psp_ver_diff, psp_mixed and the new
--psp-assoc version,spi,key option are not listed there, and the last patch
of the series does not touch gro.c either.

The requirement that both sides be invoked with the same --psp-assoc
arguments is also undocumented, even though the receiver's expected sizes
depend on it:

static int calc_mss(void)
{
        return ASSUMED_MTU - (total_hdr_len - ETH_HLEN) -
                (psp_enabled ? PSP_ENCAP_LEN : 0);
}

Could that coupling be spelled out next to the other test descriptions?

-- 
Sashiko AI review · 
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260908065244.3799142-1-tariqt%40nvidia.com

Reply via email to