xdp_router_ipv4.bpf.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /* Copyright (C) 2017 Cavium, Inc.
  2. *
  3. * This program is free software; you can redistribute it and/or modify it
  4. * under the terms of version 2 of the GNU General Public License
  5. * as published by the Free Software Foundation.
  6. */
  7. #include "vmlinux.h"
  8. #include "xdp_sample.bpf.h"
  9. #include "xdp_sample_shared.h"
  10. #define ETH_ALEN 6
  11. #define ETH_P_8021Q 0x8100
  12. #define ETH_P_8021AD 0x88A8
  13. struct trie_value {
  14. __u8 prefix[4];
  15. __be64 value;
  16. int ifindex;
  17. int metric;
  18. __be32 gw;
  19. };
  20. /* Key for lpm_trie */
  21. union key_4 {
  22. u32 b32[2];
  23. u8 b8[8];
  24. };
  25. struct arp_entry {
  26. __be64 mac;
  27. __be32 dst;
  28. };
  29. struct direct_map {
  30. struct arp_entry arp;
  31. int ifindex;
  32. __be64 mac;
  33. };
  34. /* Map for trie implementation */
  35. struct {
  36. __uint(type, BPF_MAP_TYPE_LPM_TRIE);
  37. __uint(key_size, 8);
  38. __uint(value_size, sizeof(struct trie_value));
  39. __uint(max_entries, 50);
  40. __uint(map_flags, BPF_F_NO_PREALLOC);
  41. } lpm_map SEC(".maps");
  42. /* Map for ARP table */
  43. struct {
  44. __uint(type, BPF_MAP_TYPE_HASH);
  45. __type(key, __be32);
  46. __type(value, __be64);
  47. __uint(max_entries, 50);
  48. } arp_table SEC(".maps");
  49. /* Map to keep the exact match entries in the route table */
  50. struct {
  51. __uint(type, BPF_MAP_TYPE_HASH);
  52. __type(key, __be32);
  53. __type(value, struct direct_map);
  54. __uint(max_entries, 50);
  55. } exact_match SEC(".maps");
  56. struct {
  57. __uint(type, BPF_MAP_TYPE_DEVMAP);
  58. __uint(key_size, sizeof(int));
  59. __uint(value_size, sizeof(int));
  60. __uint(max_entries, 100);
  61. } tx_port SEC(".maps");
  62. SEC("xdp")
  63. int xdp_router_ipv4_prog(struct xdp_md *ctx)
  64. {
  65. void *data_end = (void *)(long)ctx->data_end;
  66. void *data = (void *)(long)ctx->data;
  67. struct ethhdr *eth = data;
  68. u64 nh_off = sizeof(*eth);
  69. struct datarec *rec;
  70. __be16 h_proto;
  71. u32 key = 0;
  72. rec = bpf_map_lookup_elem(&rx_cnt, &key);
  73. if (rec)
  74. NO_TEAR_INC(rec->processed);
  75. if (data + nh_off > data_end)
  76. goto drop;
  77. h_proto = eth->h_proto;
  78. if (h_proto == bpf_htons(ETH_P_8021Q) ||
  79. h_proto == bpf_htons(ETH_P_8021AD)) {
  80. struct vlan_hdr *vhdr;
  81. vhdr = data + nh_off;
  82. nh_off += sizeof(struct vlan_hdr);
  83. if (data + nh_off > data_end)
  84. goto drop;
  85. h_proto = vhdr->h_vlan_encapsulated_proto;
  86. }
  87. switch (bpf_ntohs(h_proto)) {
  88. case ETH_P_ARP:
  89. if (rec)
  90. NO_TEAR_INC(rec->xdp_pass);
  91. return XDP_PASS;
  92. case ETH_P_IP: {
  93. struct iphdr *iph = data + nh_off;
  94. struct direct_map *direct_entry;
  95. __be64 *dest_mac, *src_mac;
  96. int forward_to;
  97. if (iph + 1 > data_end)
  98. goto drop;
  99. direct_entry = bpf_map_lookup_elem(&exact_match, &iph->daddr);
  100. /* Check for exact match, this would give a faster lookup */
  101. if (direct_entry && direct_entry->mac &&
  102. direct_entry->arp.mac) {
  103. src_mac = &direct_entry->mac;
  104. dest_mac = &direct_entry->arp.mac;
  105. forward_to = direct_entry->ifindex;
  106. } else {
  107. struct trie_value *prefix_value;
  108. union key_4 key4;
  109. /* Look up in the trie for lpm */
  110. key4.b32[0] = 32;
  111. key4.b8[4] = iph->daddr & 0xff;
  112. key4.b8[5] = (iph->daddr >> 8) & 0xff;
  113. key4.b8[6] = (iph->daddr >> 16) & 0xff;
  114. key4.b8[7] = (iph->daddr >> 24) & 0xff;
  115. prefix_value = bpf_map_lookup_elem(&lpm_map, &key4);
  116. if (!prefix_value)
  117. goto drop;
  118. forward_to = prefix_value->ifindex;
  119. src_mac = &prefix_value->value;
  120. if (!src_mac)
  121. goto drop;
  122. dest_mac = bpf_map_lookup_elem(&arp_table, &iph->daddr);
  123. if (!dest_mac) {
  124. if (!prefix_value->gw)
  125. goto drop;
  126. dest_mac = bpf_map_lookup_elem(&arp_table,
  127. &prefix_value->gw);
  128. if (!dest_mac) {
  129. /* Forward the packet to the kernel in
  130. * order to trigger ARP discovery for
  131. * the default gw.
  132. */
  133. if (rec)
  134. NO_TEAR_INC(rec->xdp_pass);
  135. return XDP_PASS;
  136. }
  137. }
  138. }
  139. if (src_mac && dest_mac) {
  140. int ret;
  141. __builtin_memcpy(eth->h_dest, dest_mac, ETH_ALEN);
  142. __builtin_memcpy(eth->h_source, src_mac, ETH_ALEN);
  143. ret = bpf_redirect_map(&tx_port, forward_to, 0);
  144. if (ret == XDP_REDIRECT) {
  145. if (rec)
  146. NO_TEAR_INC(rec->xdp_redirect);
  147. return ret;
  148. }
  149. }
  150. }
  151. default:
  152. break;
  153. }
  154. drop:
  155. if (rec)
  156. NO_TEAR_INC(rec->xdp_drop);
  157. return XDP_DROP;
  158. }
  159. char _license[] SEC("license") = "GPL";