unet-cli: strip initial newline in usage message
[project/unetd.git] / mss-bpf.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
4 */
5 #define KBUILD_MODNAME "foo"
6 #include <uapi/linux/bpf.h>
7 #include <uapi/linux/if_ether.h>
8 #include <uapi/linux/if_packet.h>
9 #include <uapi/linux/ip.h>
10 #include <uapi/linux/ipv6.h>
11 #include <uapi/linux/in.h>
12 #include <uapi/linux/tcp.h>
13 #include <uapi/linux/filter.h>
14 #include <uapi/linux/pkt_cls.h>
15 #include <linux/ip.h>
16 #include <net/ipv6.h>
17 #include <net/tcp.h>
18 #include <bpf/bpf_helpers.h>
19 #include <bpf/bpf_endian.h>
20 #include "bpf_skb_utils.h"
21
22 const volatile static uint32_t mtu = 1420;
23
24 static __always_inline unsigned int
25 optlen(const u_int8_t *opt)
26 {
27 if (opt[0] <= TCPOPT_NOP || opt[1] == 0)
28 return 1;
29
30 return opt[1];
31 }
32
33 static __always_inline void
34 fixup_tcp(struct skb_parser_info *info, __u16 mss)
35 {
36 struct tcphdr *tcph;
37 __u32 end, offset = info->offset + sizeof(*tcph);
38 __u16 oldmss;
39 __u8 flags;
40 __u8 *opt;
41 int i;
42
43 tcph = skb_parse_tcp(info);
44 if (!tcph)
45 return;
46
47 flags = tcp_flag_byte(tcph);
48 if (!(flags & TCPHDR_SYN))
49 return;
50
51 end = info->offset;
52
53 #pragma unroll
54 for (i = 0; i < 5; i++) {
55 if (offset + 4 > end)
56 return;
57
58 opt = skb_ptr(info->skb, offset, 4);
59 if (!opt)
60 return;
61
62 offset += optlen(opt);
63 if (opt[0] != TCPOPT_MSS || opt[1] != TCPOLEN_MSS)
64 continue;
65
66 goto found;
67 }
68 return;
69
70 found:
71 oldmss = (opt[2] << 8) | opt[3];
72 if (oldmss <= mss)
73 return;
74
75 opt[2] = mss >> 8;
76 opt[3] = mss & 0xff;
77 csum_replace2(&tcph->check, bpf_htons(oldmss), bpf_htons(mss));
78 }
79
80 SEC("tc")
81 int mssfix(struct __sk_buff *skb)
82 {
83 struct skb_parser_info info;
84 __u16 mss;
85 int type;
86
87 skb_parse_init(&info, skb);
88 if (!skb_parse_ethernet(&info))
89 return TC_ACT_UNSPEC;
90
91 skb_parse_vlan(&info);
92 skb_parse_vlan(&info);
93
94 if (!skb_parse_ipv4(&info, 60) && !skb_parse_ipv6(&info, 60))
95 return TC_ACT_UNSPEC;
96
97 if (info.proto != IPPROTO_TCP)
98 return TC_ACT_UNSPEC;
99
100 mss = mtu;
101 mss -= info.offset + sizeof(struct tcphdr);
102 fixup_tcp(&info, mss);
103
104 return TC_ACT_UNSPEC;
105 }