xref: /openbmc/linux/tools/testing/selftests/bpf/generate_udp_fragments.py (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1*c313eae7SDaniel Xu#!/bin/env python3
2*c313eae7SDaniel Xu# SPDX-License-Identifier: GPL-2.0
3*c313eae7SDaniel Xu
4*c313eae7SDaniel Xu"""
5*c313eae7SDaniel XuThis script helps generate fragmented UDP packets.
6*c313eae7SDaniel Xu
7*c313eae7SDaniel XuWhile it is technically possible to dynamically generate
8*c313eae7SDaniel Xufragmented packets in C, it is much harder to read and write
9*c313eae7SDaniel Xusaid code. `scapy` is relatively industry standard and really
10*c313eae7SDaniel Xueasy to read / write.
11*c313eae7SDaniel Xu
12*c313eae7SDaniel XuSo we choose to write this script that generates a valid C
13*c313eae7SDaniel Xuheader. Rerun script and commit generated file after any
14*c313eae7SDaniel Xumodifications.
15*c313eae7SDaniel Xu"""
16*c313eae7SDaniel Xu
17*c313eae7SDaniel Xuimport argparse
18*c313eae7SDaniel Xuimport os
19*c313eae7SDaniel Xu
20*c313eae7SDaniel Xufrom scapy.all import *
21*c313eae7SDaniel Xu
22*c313eae7SDaniel Xu
23*c313eae7SDaniel Xu# These constants must stay in sync with `ip_check_defrag.c`
24*c313eae7SDaniel XuVETH1_ADDR = "172.16.1.200"
25*c313eae7SDaniel XuVETH0_ADDR6 = "fc00::100"
26*c313eae7SDaniel XuVETH1_ADDR6 = "fc00::200"
27*c313eae7SDaniel XuCLIENT_PORT = 48878
28*c313eae7SDaniel XuSERVER_PORT = 48879
29*c313eae7SDaniel XuMAGIC_MESSAGE = "THIS IS THE ORIGINAL MESSAGE, PLEASE REASSEMBLE ME"
30*c313eae7SDaniel Xu
31*c313eae7SDaniel Xu
32*c313eae7SDaniel Xudef print_header(f):
33*c313eae7SDaniel Xu    f.write("// SPDX-License-Identifier: GPL-2.0\n")
34*c313eae7SDaniel Xu    f.write("/* DO NOT EDIT -- this file is generated */\n")
35*c313eae7SDaniel Xu    f.write("\n")
36*c313eae7SDaniel Xu    f.write("#ifndef _IP_CHECK_DEFRAG_FRAGS_H\n")
37*c313eae7SDaniel Xu    f.write("#define _IP_CHECK_DEFRAG_FRAGS_H\n")
38*c313eae7SDaniel Xu    f.write("\n")
39*c313eae7SDaniel Xu    f.write("#include <stdint.h>\n")
40*c313eae7SDaniel Xu    f.write("\n")
41*c313eae7SDaniel Xu
42*c313eae7SDaniel Xu
43*c313eae7SDaniel Xudef print_frags(f, frags, v6):
44*c313eae7SDaniel Xu    for idx, frag in enumerate(frags):
45*c313eae7SDaniel Xu        # 10 bytes per line to keep width in check
46*c313eae7SDaniel Xu        chunks = [frag[i : i + 10] for i in range(0, len(frag), 10)]
47*c313eae7SDaniel Xu        chunks_fmted = [", ".join([str(hex(b)) for b in chunk]) for chunk in chunks]
48*c313eae7SDaniel Xu        suffix = "6" if v6 else ""
49*c313eae7SDaniel Xu
50*c313eae7SDaniel Xu        f.write(f"static uint8_t frag{suffix}_{idx}[] = {{\n")
51*c313eae7SDaniel Xu        for chunk in chunks_fmted:
52*c313eae7SDaniel Xu            f.write(f"\t{chunk},\n")
53*c313eae7SDaniel Xu        f.write(f"}};\n")
54*c313eae7SDaniel Xu
55*c313eae7SDaniel Xu
56*c313eae7SDaniel Xudef print_trailer(f):
57*c313eae7SDaniel Xu    f.write("\n")
58*c313eae7SDaniel Xu    f.write("#endif /* _IP_CHECK_DEFRAG_FRAGS_H */\n")
59*c313eae7SDaniel Xu
60*c313eae7SDaniel Xu
61*c313eae7SDaniel Xudef main(f):
62*c313eae7SDaniel Xu    # srcip of 0 is filled in by IP_HDRINCL
63*c313eae7SDaniel Xu    sip = "0.0.0.0"
64*c313eae7SDaniel Xu    sip6 = VETH0_ADDR6
65*c313eae7SDaniel Xu    dip = VETH1_ADDR
66*c313eae7SDaniel Xu    dip6 = VETH1_ADDR6
67*c313eae7SDaniel Xu    sport = CLIENT_PORT
68*c313eae7SDaniel Xu    dport = SERVER_PORT
69*c313eae7SDaniel Xu    payload = MAGIC_MESSAGE.encode()
70*c313eae7SDaniel Xu
71*c313eae7SDaniel Xu    # Disable UDPv4 checksums to keep code simpler
72*c313eae7SDaniel Xu    pkt = IP(src=sip,dst=dip) / UDP(sport=sport,dport=dport,chksum=0) / Raw(load=payload)
73*c313eae7SDaniel Xu    # UDPv6 requires a checksum
74*c313eae7SDaniel Xu    # Also pin the ipv6 fragment header ID, otherwise it's a random value
75*c313eae7SDaniel Xu    pkt6 = IPv6(src=sip6,dst=dip6) / IPv6ExtHdrFragment(id=0xBEEF) / UDP(sport=sport,dport=dport) / Raw(load=payload)
76*c313eae7SDaniel Xu
77*c313eae7SDaniel Xu    frags = [f.build() for f in pkt.fragment(24)]
78*c313eae7SDaniel Xu    frags6 = [f.build() for f in fragment6(pkt6, 72)]
79*c313eae7SDaniel Xu
80*c313eae7SDaniel Xu    print_header(f)
81*c313eae7SDaniel Xu    print_frags(f, frags, False)
82*c313eae7SDaniel Xu    print_frags(f, frags6, True)
83*c313eae7SDaniel Xu    print_trailer(f)
84*c313eae7SDaniel Xu
85*c313eae7SDaniel Xu
86*c313eae7SDaniel Xuif __name__ == "__main__":
87*c313eae7SDaniel Xu    dir = os.path.dirname(os.path.realpath(__file__))
88*c313eae7SDaniel Xu    header = f"{dir}/ip_check_defrag_frags.h"
89*c313eae7SDaniel Xu    with open(header, "w") as f:
90*c313eae7SDaniel Xu        main(f)
91