summaryrefslogtreecommitdiff
path: root/dummy_ebpf_2/src/tc_prog_kernel.c
blob: fb8a6ca41405e2e0917fa4e960eefcc4c9deeb12 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <linux/types.h>

#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>
#include <linux/bpf.h>
#include <linux/in.h>
#include <linux/pkt_cls.h>
#include <xdp/parsing_helpers.h>

struct {
  __uint(type, BPF_MAP_TYPE_HASH);
  __type(key, int);
  __type(value, int);
  __uint(max_entries, 256);
} dummy_redirect_map SEC(".maps");

SEC("tc")
int tc_redirect_map_func(struct __sk_buff *skb) {
  int ret = 0;
  int action = TC_ACT_OK;
  void *data = (void *)(long)skb->data;
  void *data_end = (void *)(long)skb->data_end;

  bpf_printk("Receive a packet");

#if 0
  char key;
  unsigned int offset = data_end - data - 1;
  ret = bpf_skb_load_bytes(skb, offset, &key, sizeof(key));
  if (ret < 0) {
    bpf_printk("bpf_skb_load_bytes failed. return code:%d", ret);
    action = TC_ACT_OK;
    goto out;
  }
#endif

  // According to the last character, determine which interface to forward the data packet
  if (data_end - data < sizeof(struct ethhdr) + 1) {
    bpf_printk("Packet length is insufficient");
    goto out;
  }

  /**
   * Why do we need to calculate with 0x3fff here?
   * Because there's a hole here: when getting the last character, the usual way will fail to load.
   * ref:https://github.com/gamemann/Xdp-Access-Last-Byte
   */
  __u32 ofs = (data_end - data - 1) & 0x3fff;
  void *mgc = data + ofs;
  if ((mgc + 1) > data_end) {
    bpf_printk("Offset calculation error");
    goto out;
  }

  int key = (int)*(char *)mgc;

  bpf_printk("key: %d", key);

  // Remove the last character
  ret = bpf_skb_change_tail(skb, skb->len - 1, 0);
  if (ret < 0) {
    bpf_printk("bpf_skb_change_tail failed. return code:%d", ret);
    action = TC_ACT_OK;
    goto out;
  }

  const int *ifindex = bpf_map_lookup_elem(&dummy_redirect_map, &key);
  if (ifindex == NULL) {
    bpf_printk("%d has no corresponding port", key);
    action = TC_ACT_OK;
    goto out;
  }

  // Redirect the packet to the endpoint referenced by map at index key.
  // action = bpf_redirect(*ifindex, BPF_F_INGRESS);
  action = bpf_redirect(*ifindex, 0);
  if (action != TC_ACT_REDIRECT) {
    bpf_printk("bpf_redirect_map failed. return code:%d", ret);
  }

out:
  return action;
}

char _license[] SEC("license") = "GPL";