// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2021 Felix Fietkau */ #define KBUILD_MODNAME "foo" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bpf_skb_utils.h" const volatile static uint32_t mtu = 1420; static __always_inline unsigned int optlen(const u_int8_t *opt) { if (opt[0] <= TCPOPT_NOP || opt[1] == 0) return 1; return opt[1]; } static __always_inline void fixup_tcp(struct skb_parser_info *info, __u16 mss) { struct tcphdr *tcph; __u32 end, offset = info->offset + sizeof(*tcph); __u16 oldmss; __u8 flags; __u8 *opt; int i; tcph = skb_parse_tcp(info); if (!tcph) return; flags = tcp_flag_byte(tcph); if (!(flags & TCPHDR_SYN)) return; end = info->offset; #pragma unroll for (i = 0; i < 5; i++) { if (offset + 4 > end) return; opt = skb_ptr(info->skb, offset, 4); if (!opt) return; offset += optlen(opt); if (opt[0] != TCPOPT_MSS || opt[1] != TCPOLEN_MSS) continue; goto found; } return; found: oldmss = (opt[2] << 8) | opt[3]; if (oldmss <= mss) return; opt[2] = mss >> 8; opt[3] = mss & 0xff; csum_replace2(&tcph->check, bpf_htons(oldmss), bpf_htons(mss)); } SEC("tc") int mssfix(struct __sk_buff *skb) { struct skb_parser_info info; __u16 mss; int type; skb_parse_init(&info, skb); if (!skb_parse_ethernet(&info)) return TC_ACT_UNSPEC; skb_parse_vlan(&info); skb_parse_vlan(&info); if (!skb_parse_ipv4(&info, 60) && !skb_parse_ipv6(&info, 60)) return TC_ACT_UNSPEC; if (info.proto != IPPROTO_TCP) return TC_ACT_UNSPEC; mss = mtu; mss -= info.offset + sizeof(struct tcphdr); fixup_tcp(&info, mss); return TC_ACT_UNSPEC; }