Blame view

samples/bpf/xdp2_kern.c 2.37 KB
764cbccef   Brenden Blanco   bpf: add sample f...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /* Copyright (c) 2016 PLUMgrid
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of version 2 of the GNU General Public
   * License as published by the Free Software Foundation.
   */
  #define KBUILD_MODNAME "foo"
  #include <uapi/linux/bpf.h>
  #include <linux/in.h>
  #include <linux/if_ether.h>
  #include <linux/if_packet.h>
  #include <linux/if_vlan.h>
  #include <linux/ip.h>
  #include <linux/ipv6.h>
  #include "bpf_helpers.h"
d9094bda5   Brenden Blanco   bpf: make xdp sam...
16
  struct bpf_map_def SEC("maps") rxcnt = {
764cbccef   Brenden Blanco   bpf: add sample f...
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
  	.type = BPF_MAP_TYPE_PERCPU_ARRAY,
  	.key_size = sizeof(u32),
  	.value_size = sizeof(long),
  	.max_entries = 256,
  };
  
  static void swap_src_dst_mac(void *data)
  {
  	unsigned short *p = data;
  	unsigned short dst[3];
  
  	dst[0] = p[0];
  	dst[1] = p[1];
  	dst[2] = p[2];
  	p[0] = p[3];
  	p[1] = p[4];
  	p[2] = p[5];
  	p[3] = dst[0];
  	p[4] = dst[1];
  	p[5] = dst[2];
  }
  
  static int parse_ipv4(void *data, u64 nh_off, void *data_end)
  {
  	struct iphdr *iph = data + nh_off;
  
  	if (iph + 1 > data_end)
  		return 0;
  	return iph->protocol;
  }
  
  static int parse_ipv6(void *data, u64 nh_off, void *data_end)
  {
  	struct ipv6hdr *ip6h = data + nh_off;
  
  	if (ip6h + 1 > data_end)
  		return 0;
  	return ip6h->nexthdr;
  }
  
  SEC("xdp1")
  int xdp_prog1(struct xdp_md *ctx)
  {
  	void *data_end = (void *)(long)ctx->data_end;
  	void *data = (void *)(long)ctx->data;
  	struct ethhdr *eth = data;
  	int rc = XDP_DROP;
  	long *value;
  	u16 h_proto;
  	u64 nh_off;
d9094bda5   Brenden Blanco   bpf: make xdp sam...
67
  	u32 ipproto;
764cbccef   Brenden Blanco   bpf: add sample f...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  
  	nh_off = sizeof(*eth);
  	if (data + nh_off > data_end)
  		return rc;
  
  	h_proto = eth->h_proto;
  
  	if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
  		struct vlan_hdr *vhdr;
  
  		vhdr = data + nh_off;
  		nh_off += sizeof(struct vlan_hdr);
  		if (data + nh_off > data_end)
  			return rc;
  		h_proto = vhdr->h_vlan_encapsulated_proto;
  	}
  	if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
  		struct vlan_hdr *vhdr;
  
  		vhdr = data + nh_off;
  		nh_off += sizeof(struct vlan_hdr);
  		if (data + nh_off > data_end)
  			return rc;
  		h_proto = vhdr->h_vlan_encapsulated_proto;
  	}
  
  	if (h_proto == htons(ETH_P_IP))
d9094bda5   Brenden Blanco   bpf: make xdp sam...
95
  		ipproto = parse_ipv4(data, nh_off, data_end);
764cbccef   Brenden Blanco   bpf: add sample f...
96
  	else if (h_proto == htons(ETH_P_IPV6))
d9094bda5   Brenden Blanco   bpf: make xdp sam...
97
  		ipproto = parse_ipv6(data, nh_off, data_end);
764cbccef   Brenden Blanco   bpf: add sample f...
98
  	else
d9094bda5   Brenden Blanco   bpf: make xdp sam...
99
  		ipproto = 0;
764cbccef   Brenden Blanco   bpf: add sample f...
100

d9094bda5   Brenden Blanco   bpf: make xdp sam...
101
  	value = bpf_map_lookup_elem(&rxcnt, &ipproto);
764cbccef   Brenden Blanco   bpf: add sample f...
102
103
  	if (value)
  		*value += 1;
d9094bda5   Brenden Blanco   bpf: make xdp sam...
104
  	if (ipproto == IPPROTO_UDP) {
764cbccef   Brenden Blanco   bpf: add sample f...
105
106
107
108
109
110
111
112
  		swap_src_dst_mac(data);
  		rc = XDP_TX;
  	}
  
  	return rc;
  }
  
  char _license[] SEC("license") = "GPL";