Source file
src/github.com/cilium/ebpf/example_sock_extract_dist_test.go
1 package ebpf_test
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 import (
34 "fmt"
35 "net"
36 "syscall"
37
38 "github.com/cilium/ebpf"
39 "github.com/cilium/ebpf/asm"
40 )
41
42
43
44 func Example_extractDistance() {
45 filter, TTLs, err := newDistanceFilter()
46 if err != nil {
47 panic(err)
48 }
49 defer filter.Close()
50 defer TTLs.Close()
51
52
53 dialer := net.Dialer{
54 Control: func(network, address string, c syscall.RawConn) (err error) {
55 const SO_ATTACH_BPF = 50
56
57 err = c.Control(func(fd uintptr) {
58 err = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, SO_ATTACH_BPF, filter.FD())
59 })
60 return err
61 },
62 }
63
64 conn, err := dialer.Dial("tcp", "1.1.1.1:53")
65 if err != nil {
66 panic(err)
67 }
68 conn.Close()
69
70 minDist, err := minDistance(TTLs)
71 if err != nil {
72 panic(err)
73 }
74
75 fmt.Println("1.1.1.1:53 is", minDist, "hops away")
76 }
77
78 func newDistanceFilter() (*ebpf.Program, *ebpf.Map, error) {
79 const ETH_P_IPV6 uint16 = 0x86DD
80
81 ttls, err := ebpf.NewMap(&ebpf.MapSpec{
82 Type: ebpf.Hash,
83 KeySize: 4,
84 ValueSize: 8,
85 MaxEntries: 4,
86 })
87 if err != nil {
88 return nil, nil, err
89 }
90
91 insns := asm.Instructions{
92
93
94 asm.LoadMem(asm.R0, asm.R1, 16, asm.Word),
95
96
97 asm.LoadImm(asm.R2, int64(ETH_P_IPV6), asm.DWord),
98 asm.HostTo(asm.BE, asm.R2, asm.Half),
99 asm.JEq.Reg(asm.R0, asm.R2, "ipv6"),
100
101
102
103
104 asm.Mov.Reg(asm.R6, asm.R1),
105 asm.LoadAbs(-0x100000+8, asm.Byte),
106 asm.Ja.Label("store-ttl"),
107
108
109
110 asm.Mov.Reg(asm.R6, asm.R1).WithSymbol("ipv6"),
111 asm.LoadAbs(-0x100000+7, asm.Byte),
112
113
114 asm.StoreMem(asm.RFP, -4, asm.R0, asm.Word).WithSymbol("store-ttl"),
115
116 asm.Mov.Reg(asm.R2, asm.RFP),
117 asm.Add.Imm(asm.R2, -4),
118
119
120 asm.LoadMapPtr(asm.R1, ttls.FD()),
121 asm.FnMapLookupElem.Call(),
122
123
124 asm.JEq.Imm(asm.R0, 0, "update-map"),
125 asm.Mov.Imm(asm.R1, 1),
126 asm.StoreXAdd(asm.R0, asm.R1, asm.DWord),
127 asm.Ja.Label("exit"),
128
129
130
131 asm.LoadMapPtr(asm.R1, ttls.FD()).WithSymbol("update-map"),
132
133 asm.Mov.Reg(asm.R2, asm.RFP),
134 asm.Add.Imm(asm.R2, -4),
135
136 asm.StoreImm(asm.RFP, -16, 1, asm.DWord),
137 asm.Mov.Reg(asm.R3, asm.RFP),
138 asm.Add.Imm(asm.R3, -16),
139
140 asm.Mov.Imm(asm.R4, 0),
141 asm.FnMapUpdateElem.Call(),
142
143
144 asm.Mov.Imm(asm.R0, -1).WithSymbol("exit"),
145 asm.Return(),
146 }
147
148 prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
149 Name: "distance_filter",
150 Type: ebpf.SocketFilter,
151 License: "GPL",
152 Instructions: insns,
153 })
154 if err != nil {
155 ttls.Close()
156 return nil, nil, err
157 }
158
159 return prog, ttls, nil
160 }
161
162 func minDistance(TTLs *ebpf.Map) (int, error) {
163 var (
164 entries = TTLs.Iterate()
165 ttl uint32
166 minDist uint32 = 255
167 count uint64
168 )
169 for entries.Next(&ttl, &count) {
170 var dist uint32
171 switch {
172 case ttl > 128:
173 dist = 255 - ttl
174 case ttl > 64:
175 dist = 128 - ttl
176 case ttl > 32:
177 dist = 64 - ttl
178 default:
179 dist = 32 - ttl
180 }
181 if minDist > dist {
182 minDist = dist
183 }
184 }
185 return int(minDist), entries.Err()
186 }
187
View as plain text