diff --git a/ebpfcat/ebpf.rst b/ebpfcat/ebpf.rst
index e7711836753388dbd04135d7fa7bda86e4d3bad7..a09594efea4f9149c3b6564e5a67723f2fa48ed3 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 4dea9657d40bb7d6c36d44a53c47195a2fcbb207..b450fe285edc0137e6a780e8e89b2ecbc74b57bb 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 db17388715107a27e14d5c1c68a2abeb13c47e0f..0d2b518ae20a81f787d9e469c9666095b31797a8 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