mss-bpf.c 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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. const volatile static uint32_t mtu = 1420;
  22. static __always_inline unsigned int
  23. optlen(const u_int8_t *opt)
  24. {
  25. if (opt[0] <= TCPOPT_NOP || opt[1] == 0)
  26. return 1;
  27. return opt[1];
  28. }
  29. static __always_inline void
  30. fixup_tcp(struct skb_parser_info *info, __u16 mss)
  31. {
  32. struct tcphdr *tcph;
  33. __u32 end, offset = info->offset + sizeof(*tcph);
  34. __u16 oldmss;
  35. __u8 flags;
  36. __u8 *opt;
  37. int i;
  38. tcph = skb_parse_tcp(info);
  39. if (!tcph)
  40. return;
  41. flags = tcp_flag_byte(tcph);
  42. if (!(flags & TCPHDR_SYN))
  43. return;
  44. end = info->offset;
  45. #pragma unroll
  46. for (i = 0; i < 5; i++) {
  47. if (offset + 4 > end)
  48. return;
  49. opt = skb_ptr(info->skb, offset, 4);
  50. if (!opt)
  51. return;
  52. offset += optlen(opt);
  53. if (opt[0] != TCPOPT_MSS || opt[1] != TCPOLEN_MSS)
  54. continue;
  55. goto found;
  56. }
  57. return;
  58. found:
  59. oldmss = (opt[2] << 8) | opt[3];
  60. if (oldmss <= mss)
  61. return;
  62. opt[2] = mss >> 8;
  63. opt[3] = mss & 0xff;
  64. csum_replace2(&tcph->check, bpf_htons(oldmss), bpf_htons(mss));
  65. }
  66. SEC("tc")
  67. int mssfix(struct __sk_buff *skb)
  68. {
  69. struct skb_parser_info info;
  70. __u16 mss;
  71. int type;
  72. skb_parse_init(&info, skb);
  73. if (!skb_parse_ethernet(&info))
  74. return TC_ACT_UNSPEC;
  75. skb_parse_vlan(&info);
  76. skb_parse_vlan(&info);
  77. if (!skb_parse_ipv4(&info, 60) && !skb_parse_ipv6(&info, 60))
  78. return TC_ACT_UNSPEC;
  79. if (info.proto != IPPROTO_TCP)
  80. return TC_ACT_UNSPEC;
  81. mss = mtu;
  82. mss -= info.offset + sizeof(struct tcphdr);
  83. fixup_tcp(&info, mss);
  84. return TC_ACT_UNSPEC;
  85. }