From 27f0ffa39a24b169b6138f1974c123fa6df2bad2 Mon Sep 17 00:00:00 2001
From: Martin Teichmann <martin.teichmann@gmail.com>
Date: Fri, 24 Feb 2023 12:15:05 +0000
Subject: [PATCH] add PacketVar also to XDP proper

this is not actually related to the ebpfcat PacketVar, but kinda
similar.
---
 ebpfcat/ebpf.rst     | 16 ++++++++++++++++
 ebpfcat/ebpf_test.py | 11 +++++++----
 ebpfcat/xdp.py       | 13 ++++++++++++-
 3 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/ebpfcat/ebpf.rst b/ebpfcat/ebpf.rst
index e771183..a09594e 100644
--- a/ebpfcat/ebpf.rst
+++ b/ebpfcat/ebpf.rst
@@ -141,6 +141,22 @@ is too small (by default ``XDPExitCode.PASS``). So the above example becomes::
             with self.pH[12] == 8:
                 self.count += 1
 
+With the ``PacketVar`` descriptor it is possible to declare certain positions
+in the packet as variables. As parameters it takes the position within the
+packet, and the data format, following the conventions from the Python
+``struct`` package. So the above example simplifies to::
+
+    class Program(XDP):
+        minimumPacketSize = 16
+        userspace = HashMap()
+        count = userspace.globalVar()
+        etherType = PacketVar(12, "H")
+
+        def program(self):
+            with self.etherType == 8:
+                self.count += 1
+
+
 Maps
 ----
 
diff --git a/ebpfcat/ebpf_test.py b/ebpfcat/ebpf_test.py
index 4dea965..b450fe2 100644
--- a/ebpfcat/ebpf_test.py
+++ b/ebpfcat/ebpf_test.py
@@ -23,7 +23,7 @@ from .ebpf import (
     AssembleError, EBPF, FuncId, Opcode, OpcodeFlags, Opcode as O, LocalVar,
     SubProgram, ktime)
 from .hashmap import HashMap
-from .xdp import XDP
+from .xdp import XDP, PacketVar
 from .bpf import ProgType, prog_test_run
 
 
@@ -903,8 +903,10 @@ class Tests(TestCase):
         class P(XDP):
             minimumPacketSize = 100
 
+            pv = PacketVar(20, "H")
+
             def program(self):
-                self.r3 = self.pH[22]
+                self.pv = self.pH[22]
 
         p = P(license="GPL")
         p.assemble()
@@ -913,8 +915,9 @@ class Tests(TestCase):
             Instruction(opcode=O.W+O.LD, dst=0, src=1, off=4, imm=0),
             Instruction(opcode=O.W+O.LD, dst=2, src=1, off=0, imm=0),
             Instruction(opcode=O.LONG+O.ADD, dst=2, src=0, off=0, imm=100),
-            Instruction(opcode=O.JLE+O.REG, dst=0, src=2, off=1, imm=0),
-            Instruction(opcode=O.REG+O.LD, dst=3, src=9, off=22, imm=0),
+            Instruction(opcode=O.JLE+O.REG, dst=0, src=2, off=2, imm=0),
+            Instruction(opcode=O.REG+O.LD, dst=0, src=9, off=22, imm=0),
+            Instruction(opcode=O.REG+O.STX, dst=9, src=0, off=20, imm=0),
             Instruction(opcode=O.LONG+O.MOV, dst=0, src=0, off=0, imm=2),
             Instruction(opcode=O.EXIT, dst=0, src=0, off=0, imm=0),
         ])
diff --git a/ebpfcat/xdp.py b/ebpfcat/xdp.py
index db17388..0d2b518 100644
--- a/ebpfcat/xdp.py
+++ b/ebpfcat/xdp.py
@@ -24,7 +24,7 @@ from socket import AF_NETLINK, NETLINK_ROUTE, if_nametoindex
 import socket
 from struct import pack, unpack
 
-from .ebpf import EBPF
+from .ebpf import EBPF, MemoryDesc
 from .bpf import ProgType
 from .util import sub
 
@@ -152,6 +152,17 @@ class PacketSize:
         return self > value - 1
 
 
+class PacketVar(MemoryDesc):
+    base_register = 9
+
+    def __init__(self, address, fmt):
+        self.address = address
+        self.fmt = fmt
+
+    def fmt_addr(self, instance):
+        return self.fmt, self.address
+
+
 class XDP(EBPF):
     """the base class for XDP programs"""
     minimumPacketSize = None
-- 
GitLab