test_lwt_bpf.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch>
  2. *
  3. * This program is free software; you can redistribute it and/or
  4. * modify it under the terms of version 2 of the GNU General Public
  5. * License as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful, but
  8. * WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. * General Public License for more details.
  11. */
  12. #include "vmlinux.h"
  13. #include "net_shared.h"
  14. #include <bpf/bpf_helpers.h>
  15. #include <string.h>
  16. # define printk(fmt, ...) \
  17. ({ \
  18. char ____fmt[] = fmt; \
  19. bpf_trace_printk(____fmt, sizeof(____fmt), \
  20. ##__VA_ARGS__); \
  21. })
  22. #define CB_MAGIC 1234
  23. /* Test: Pass all packets through */
  24. SEC("nop")
  25. int do_nop(struct __sk_buff *skb)
  26. {
  27. return BPF_OK;
  28. }
  29. /* Test: Verify context information can be accessed */
  30. SEC("test_ctx")
  31. int do_test_ctx(struct __sk_buff *skb)
  32. {
  33. skb->cb[0] = CB_MAGIC;
  34. printk("len %d hash %d protocol %d", skb->len, skb->hash,
  35. skb->protocol);
  36. printk("cb %d ingress_ifindex %d ifindex %d", skb->cb[0],
  37. skb->ingress_ifindex, skb->ifindex);
  38. return BPF_OK;
  39. }
  40. /* Test: Ensure skb->cb[] buffer is cleared */
  41. SEC("test_cb")
  42. int do_test_cb(struct __sk_buff *skb)
  43. {
  44. printk("cb0: %x cb1: %x cb2: %x", skb->cb[0], skb->cb[1],
  45. skb->cb[2]);
  46. printk("cb3: %x cb4: %x", skb->cb[3], skb->cb[4]);
  47. return BPF_OK;
  48. }
  49. /* Test: Verify skb data can be read */
  50. SEC("test_data")
  51. int do_test_data(struct __sk_buff *skb)
  52. {
  53. void *data = (void *)(long)skb->data;
  54. void *data_end = (void *)(long)skb->data_end;
  55. struct iphdr *iph = data;
  56. if (data + sizeof(*iph) > data_end) {
  57. printk("packet truncated");
  58. return BPF_DROP;
  59. }
  60. printk("src: %x dst: %x", iph->saddr, iph->daddr);
  61. return BPF_OK;
  62. }
  63. #define IP_CSUM_OFF offsetof(struct iphdr, check)
  64. #define IP_DST_OFF offsetof(struct iphdr, daddr)
  65. #define IP_SRC_OFF offsetof(struct iphdr, saddr)
  66. #define IP_PROTO_OFF offsetof(struct iphdr, protocol)
  67. #define TCP_CSUM_OFF offsetof(struct tcphdr, check)
  68. #define UDP_CSUM_OFF offsetof(struct udphdr, check)
  69. #define IS_PSEUDO 0x10
  70. static inline int rewrite(struct __sk_buff *skb, uint32_t old_ip,
  71. uint32_t new_ip, int rw_daddr)
  72. {
  73. int ret, off = 0, flags = IS_PSEUDO;
  74. uint8_t proto;
  75. ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1);
  76. if (ret < 0) {
  77. printk("bpf_l4_csum_replace failed: %d", ret);
  78. return BPF_DROP;
  79. }
  80. switch (proto) {
  81. case IPPROTO_TCP:
  82. off = TCP_CSUM_OFF;
  83. break;
  84. case IPPROTO_UDP:
  85. off = UDP_CSUM_OFF;
  86. flags |= BPF_F_MARK_MANGLED_0;
  87. break;
  88. case IPPROTO_ICMPV6:
  89. off = offsetof(struct icmp6hdr, icmp6_cksum);
  90. break;
  91. }
  92. if (off) {
  93. ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip,
  94. flags | sizeof(new_ip));
  95. if (ret < 0) {
  96. printk("bpf_l4_csum_replace failed: %d");
  97. return BPF_DROP;
  98. }
  99. }
  100. ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip));
  101. if (ret < 0) {
  102. printk("bpf_l3_csum_replace failed: %d", ret);
  103. return BPF_DROP;
  104. }
  105. if (rw_daddr)
  106. ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof(new_ip), 0);
  107. else
  108. ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0);
  109. if (ret < 0) {
  110. printk("bpf_skb_store_bytes() failed: %d", ret);
  111. return BPF_DROP;
  112. }
  113. return BPF_OK;
  114. }
  115. /* Test: Verify skb data can be modified */
  116. SEC("test_rewrite")
  117. int do_test_rewrite(struct __sk_buff *skb)
  118. {
  119. uint32_t old_ip, new_ip = 0x3fea8c0;
  120. int ret;
  121. ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4);
  122. if (ret < 0) {
  123. printk("bpf_skb_load_bytes failed: %d", ret);
  124. return BPF_DROP;
  125. }
  126. if (old_ip == 0x2fea8c0) {
  127. printk("out: rewriting from %x to %x", old_ip, new_ip);
  128. return rewrite(skb, old_ip, new_ip, 1);
  129. }
  130. return BPF_OK;
  131. }
  132. static inline int __do_push_ll_and_redirect(struct __sk_buff *skb)
  133. {
  134. uint64_t smac = SRC_MAC, dmac = DST_MAC;
  135. int ret, ifindex = DST_IFINDEX;
  136. struct ethhdr ehdr;
  137. ret = bpf_skb_change_head(skb, 14, 0);
  138. if (ret < 0) {
  139. printk("skb_change_head() failed: %d", ret);
  140. }
  141. ehdr.h_proto = bpf_htons(ETH_P_IP);
  142. memcpy(&ehdr.h_source, &smac, 6);
  143. memcpy(&ehdr.h_dest, &dmac, 6);
  144. ret = bpf_skb_store_bytes(skb, 0, &ehdr, sizeof(ehdr), 0);
  145. if (ret < 0) {
  146. printk("skb_store_bytes() failed: %d", ret);
  147. return BPF_DROP;
  148. }
  149. return bpf_redirect(ifindex, 0);
  150. }
  151. SEC("push_ll_and_redirect_silent")
  152. int do_push_ll_and_redirect_silent(struct __sk_buff *skb)
  153. {
  154. return __do_push_ll_and_redirect(skb);
  155. }
  156. SEC("push_ll_and_redirect")
  157. int do_push_ll_and_redirect(struct __sk_buff *skb)
  158. {
  159. int ret, ifindex = DST_IFINDEX;
  160. ret = __do_push_ll_and_redirect(skb);
  161. if (ret >= 0)
  162. printk("redirected to %d", ifindex);
  163. return ret;
  164. }
  165. static inline void __fill_garbage(struct __sk_buff *skb)
  166. {
  167. uint64_t f = 0xFFFFFFFFFFFFFFFF;
  168. bpf_skb_store_bytes(skb, 0, &f, sizeof(f), 0);
  169. bpf_skb_store_bytes(skb, 8, &f, sizeof(f), 0);
  170. bpf_skb_store_bytes(skb, 16, &f, sizeof(f), 0);
  171. bpf_skb_store_bytes(skb, 24, &f, sizeof(f), 0);
  172. bpf_skb_store_bytes(skb, 32, &f, sizeof(f), 0);
  173. bpf_skb_store_bytes(skb, 40, &f, sizeof(f), 0);
  174. bpf_skb_store_bytes(skb, 48, &f, sizeof(f), 0);
  175. bpf_skb_store_bytes(skb, 56, &f, sizeof(f), 0);
  176. bpf_skb_store_bytes(skb, 64, &f, sizeof(f), 0);
  177. bpf_skb_store_bytes(skb, 72, &f, sizeof(f), 0);
  178. bpf_skb_store_bytes(skb, 80, &f, sizeof(f), 0);
  179. bpf_skb_store_bytes(skb, 88, &f, sizeof(f), 0);
  180. }
  181. SEC("fill_garbage")
  182. int do_fill_garbage(struct __sk_buff *skb)
  183. {
  184. __fill_garbage(skb);
  185. printk("Set initial 96 bytes of header to FF");
  186. return BPF_OK;
  187. }
  188. SEC("fill_garbage_and_redirect")
  189. int do_fill_garbage_and_redirect(struct __sk_buff *skb)
  190. {
  191. int ifindex = DST_IFINDEX;
  192. __fill_garbage(skb);
  193. printk("redirected to %d", ifindex);
  194. return bpf_redirect(ifindex, 0);
  195. }
  196. /* Drop all packets */
  197. SEC("drop_all")
  198. int do_drop_all(struct __sk_buff *skb)
  199. {
  200. printk("dropping with: %d", BPF_DROP);
  201. return BPF_DROP;
  202. }
  203. char _license[] SEC("license") = "GPL";