20
20
import time
21
21
from glob import glob
22
22
from pathlib import Path
23
+ from typing import Optional
23
24
24
25
from .ebpfenv import Bridge
25
26
from .target import EBPFTarget
33
34
34
35
35
36
class Target (EBPFTarget ):
36
- EBPF_MAP_PATH = "/sys/fs/bpf/tc/globals"
37
+ EBPF_PATH = Path ( "/sys/fs/bpf" )
37
38
38
39
def __init__ (self , tmpdir , options , template ):
39
40
EBPFTarget .__init__ (self , tmpdir , options , template )
41
+ self .bpftool = self .runtimedir .joinpath ("install/bpftool" )
42
+ if self .options .target == "xdp" :
43
+ self .ebpf_map_path = self .EBPF_PATH .joinpath (f"xdp/globals" )
44
+ else :
45
+ self .ebpf_map_path = self .EBPF_PATH .joinpath (f"tc/globals" )
40
46
41
47
def compile_dataplane (self ):
42
48
# Use clang to compile the generated C code to a LLVM IR
@@ -68,30 +74,33 @@ def _create_runtime(self):
68
74
args += "CFLAGS+=-DCONTROL_PLANE "
69
75
# add the folder local to the P4 file to the list of includes
70
76
args += f"INCLUDES+=-I{ os .path .dirname (self .options .p4filename )} "
71
- # some kernel specific includes for libbpf
72
- args += f"INCLUDES+=-I{ self .runtimedir } /usr/include "
73
- args += f"INCLUDES+=-I{ self .runtimedir } /contrib/libbpf/include/uapi "
74
- args += f"LIBS+={ self .runtimedir } /usr/lib64/libbpf.a "
77
+ args += f"LIBS+={ self .runtimedir } /install/libbpf/libbpf.a "
75
78
args += "LIBS+=-lz "
76
79
args += "LIBS+=-lelf "
77
80
result = testutils .exec_process (args )
78
81
if result .returncode != testutils .SUCCESS :
79
82
testutils .log .error ("Failed to build the filter" )
80
83
return result .returncode
81
84
82
- def _create_bridge (self ):
85
+ def _create_bridge (self ) -> Optional [ Bridge ] :
83
86
# The namespace is the id of the process
84
87
namespace = str (os .getpid ())
85
88
# Number of input files
86
89
direction = "in"
87
90
num_files = len (glob (self .filename ("*" , direction )))
88
91
# Create the namespace and the bridge with all its ports
89
- br = Bridge (namespace )
90
- result = br .create_virtual_env (num_files )
92
+ bridge = Bridge (namespace )
93
+ result = bridge .create_virtual_env (num_files )
91
94
if result != testutils .SUCCESS :
92
- br .ns_del ()
95
+ bridge .ns_del ()
93
96
return None
94
- return br
97
+ if self .options .target != "xdp" :
98
+ # Add the qdisc. MUST be clsact layer.
99
+ for port_name in bridge .edge_ports :
100
+ result = bridge .ns_exec (f"tc qdisc add dev { port_name } clsact" )
101
+ if result != testutils .SUCCESS :
102
+ return None
103
+ return bridge
95
104
96
105
def _get_run_cmd (self ):
97
106
direction = "in"
@@ -108,7 +117,7 @@ def _get_run_cmd(self):
108
117
cmd += "-d"
109
118
return cmd
110
119
111
- def _kill_processes (self , procs ):
120
+ def _kill_processes (self , procs ) -> None :
112
121
for proc in procs :
113
122
# kill process, 15 is SIGTERM
114
123
os .kill (proc .pid , 15 )
@@ -127,7 +136,7 @@ def _load_filter(self, bridge, proc, port_name):
127
136
bridge .ns_exec (f"tc qdisc add dev { port_name } clsact" )
128
137
cmd = (
129
138
f"tc filter add dev { port_name } egress"
130
- f" bpf da obj { self .template } .o section prog verbose"
139
+ f" bpf da obj { self .template } .o section tc verbose "
131
140
)
132
141
return bridge .ns_proc_write (proc , cmd )
133
142
@@ -145,6 +154,44 @@ def _attach_filters(self, bridge, proc):
145
154
return result
146
155
return testutils .SUCCESS
147
156
157
+ # def _attach_filters(self, bridge: Bridge, proc: subprocess.Popen) -> int:
158
+ # # Is this a XDP or TC (ebpf_filter) program?
159
+ # p_result = testutils.exec_process(f"objdump -hj xdp {self.template}.o").returncode
160
+ # is_xdp = p_result == testutils.SUCCESS
161
+ # # Load the specified eBPF object to "port_name" egress
162
+ # # As a side-effect, this may create maps in /sys/fs/bpf/
163
+ # # Get the command to load eBPF code to all the attached ports
164
+ # result = bridge.ns_proc_write(proc, f"mount -t bpf none {self.EBPF_PATH}")
165
+ # if result != testutils.SUCCESS:
166
+ # return result
167
+ # result = bridge.ns_proc_append(proc, f"mkdir -p {self.ebpf_map_path}")
168
+ # if result != testutils.SUCCESS:
169
+ # return result
170
+ # load_type = "xdp" if is_xdp else "tc"
171
+ # cmd = f"{self.bpftool} prog load {self.template}.o {self.EBPF_PATH}/ebpf_filter pinmaps {self.ebpf_map_path} type {load_type}"
172
+ # result = bridge.ns_proc_append(proc, cmd)
173
+ # if result != testutils.SUCCESS:
174
+ # return result
175
+
176
+ # attach_type = "xdp" if is_xdp else "tcx_egress"
177
+ # ports = bridge.br_ports if is_xdp else bridge.edge_ports
178
+ # if len(ports) > 0:
179
+ # for port_name in ports:
180
+ # result = bridge.ns_proc_append(
181
+ # proc,
182
+ # f"{self.bpftool} net attach {attach_type} pinned {self.EBPF_PATH}/ebpf_filter dev {port_name}",
183
+ # )
184
+ # if result != testutils.SUCCESS:
185
+ # return result
186
+ # else:
187
+ # # No ports attached (no pcap files), load to bridge instead
188
+ # result = bridge.ns_proc_append(
189
+ # proc,
190
+ # f"{self.bpftool} net attach {attach_type} pinned {self.EBPF_PATH}/ebpf_filter dev {bridge.br_name}",
191
+ # )
192
+
193
+ # return result
194
+
148
195
def _run_tcpdump (self , bridge , filename , port ):
149
196
cmd = f"{ bridge .get_ns_prefix ()} tcpdump -w { filename } -i { port } "
150
197
return subprocess .Popen (cmd .split ())
@@ -166,14 +213,10 @@ def _run_in_namespace(self, bridge):
166
213
return testutils .FAILURE
167
214
dump_procs = self ._init_tcpdump_listeners (bridge )
168
215
result = self ._attach_filters (bridge , proc )
169
- if result != testutils .SUCCESS :
170
- return result
171
- # Check if eBPF maps have actually been created
172
- result = bridge .ns_proc_write (proc , f"ls -1 { self .EBPF_MAP_PATH } " )
173
216
if result != testutils .SUCCESS :
174
217
return result
175
218
# Finally, append the actual runtime command to the process
176
- result = bridge .ns_proc_append (proc , self ._get_run_cmd ())
219
+ result = bridge .ns_proc_write (proc , self ._get_run_cmd ())
177
220
if result != testutils .SUCCESS :
178
221
return result
179
222
# Execute the command queue and close the process, retrieve result
0 commit comments