Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
E
ebpfCAT
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
karaboDevices
ebpfCAT
Commits
13ce85cc
Commit
13ce85cc
authored
4 years ago
by
Martin Teichmann
Browse files
Options
Downloads
Patches
Plain Diff
start documenting EBPF
parent
bb36aa7c
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
ebpfcat/ebpf.rst
+97
-0
97 additions, 0 deletions
ebpfcat/ebpf.rst
examples/count.py
+26
-0
26 additions, 0 deletions
examples/count.py
with
123 additions
and
0 deletions
ebpfcat/ebpf.rst
0 → 100644
+
97
−
0
View file @
13ce85cc
A Python-base EBPF code generator
=================================
Getting started
---------------
As a simple example for EBPF we write an XDP program which simply counts
incoming packages.
We start with declaring the variables that we want to see both in the
XDP program and in user space::
from ebpfcat.hashmap import HashMap
from ebpfcat.xdp import XDP, XDPExitCode
class Count(XDP):
license = "GPL" # the Linux kernel wants to know that...
userspace = HashMap()
count = userspace.globalVar() # declare one variable in the map
Next comes the program that we want to run in the kernel. Note that this
program looks as if it was just Python code, but it is not actually.
Instead it generates EBPF code that we can later load into the kernel::
def program(self):
self.count += 1
self.exit(XDPExitCode.PASS) # pass packet on to network stack
Now we can attach this program to a network. We use `asyncio`
for synchronization::
async def main():
c = Count()
await c.attach("eth0")
once attached, we can read the result in a loop::
for i in range(100):
await sleep(0.1)
print(c.count)
Note that here we access the member variable `count` from user space.
While generating EBPF, the code generator knows it needs to write out
commands to access that variable from EBPF, once accessed outside of
generation context, we access it from the user side.
For reference, this is the full example:
.. literalinclude:: /examples/count.py
Conditional statements
----------------------
During code generation, all code needs to be executed. This means that
we cannot use a Python `if` statement, as then the code actually does not
get exxecuted, so no code would be generated. So we replace `if` statements
by Python `with` statements like so::
with self.If(self.some_variable > 6) as cond:
do_someting
with cond.Else():
do_something_else
certainly an `Else` statement is not necessary.
Accessing the packet
--------------------
The entire point of XDP is to react to the arriving network packets.
The EBPF program will be checked statically that it can only access the
contents of the packet, and not beyond. This means an `if` statement
needs to be added that checks that the packet is large enough so every
packet access will be within the packet. To facilitate this, a special
variable `packetSize` is defined, that when compared to will generate
code that the static code checker understands, like so::
with self.packetSize > 100 as p: # assure packet has at least 100 bytes
self.some_variable = p.pH[22] # read word at position 22
with p.Else():
self.exit()
in this code, the variable `p` returned by the `with` statement also
allows to access the content of the packet. There are eight access modes
to access different sizes in the packet, whose naming follows the Python
`struct` module, indicated by the letters "BHIQbhiq".
Knowing this, we can modify the above example code to only count IP
packets::
def program(self):
with self.packetSize > 16 as p:
# position 12 is the EtherType
# 8 is the EtherType for IP, in network byte order
with self.If(p.pH[12] == 8):
self.count += 1
self.exit(XDPExitCode.PASS)
This diff is collapsed.
Click to expand it.
examples/count.py
0 → 100644
+
26
−
0
View file @
13ce85cc
from
asyncio
import
get_event_loop
,
sleep
from
ebpfcat.hashmap
import
HashMap
from
ebpfcat.xdp
import
XDP
,
XDPExitCode
class
Count
(
XDP
):
license
=
"
GPL
"
userspace
=
HashMap
()
count
=
userspace
.
globalVar
()
def
program
(
self
):
self
.
count
+=
1
self
.
exit
(
XDPExitCode
.
PASS
)
async
def
main
():
c
=
Count
()
await
c
.
attach
(
"
eth0
"
)
for
i
in
range
(
100
):
await
sleep
(
0.1
)
print
(
c
.
count
)
if
__name__
==
"
__main__
"
:
get_event_loop
().
run_until_complete
(
main
())
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment