Below there are the semantics for each defined BPF instruction, where: A - the accumulator,
X - the index register, P[...] - packet data, and M[...] - the scratch memory store.
P[i:n]
gives the data at byte offset i in the packet, interpreted as a word (n=4), unsigned halfword
(n=2), or unsigned byte (n=1).
M[i]
gives the i'th word in the scratch memory store, which is only addressed in word units. The
memory store is indexed from 0 to BPF_MEMWORDS-1.
k, jt, and jf
#pktlen
pseudovariable containing the length of the packet.
In all instructions of the BPF Assembler, which are used in
BPF programs compiled by
HNUserFilter.CompileBPFAsmFromStr and
HNUserFilter.CompileBPFAsmFromFile
functions, the value of k is a number, predefined constant, or an arithmetic expression
containing numbers, prefefined constants, and symbols '(', ')', '+', '-',
'*', and '/'.
 | Registers names, packets addresses, and scratch memory addresses (A, X, P[...], and M[...]) must be uppercase. |
BPF_LD
These instructions copy a value into the accumulator. The type of the source operand is
specified by an "addressing mode" and can be a constant (BPF_IMM), packet data at a fixed offset
(BPF_ABS), packet data at a variable offset (BPF_IND), the packet length (BPF_LEN), or a word in the
scratch memory store (BPF_MEM).
For BPF_IND and BPF_ABS, the data size must be specified as a word (BPF_W), halfword (BPF_H),
or byte (BPF_B). The semantics of all the recognized BPF_LD instructions follow.
| Numeric value of a command to be used in
HNUserFilter.AddCmd and
HNUserFilter.AddJmp functions | Command action | BPF Assembler instruction |
|---|
| BPF_LD+BPF_W+BPF_ABS | A <- P[k:4] | ld P[k:4] |
| BPF_LD+BPF_H+BPF_ABS | A <- P[k:2] | ld P[k:2] |
| BPF_LD+BPF_B+BPF_ABS | A <- P[k:1] | ld P[k:1] or ld P[k] |
| BPF_LD+BPF_W+BPF_IND | A <- P[X+k:4] | ld P[X+k:4] |
| BPF_LD+BPF_H+BPF_IND | A <- P[X+k:2] | ld P[X+k:2] |
| BPF_LD+BPF_B+BPF_IND | A <- P[X+k:1] | ld P[X+k:1] or ld P[X+k] |
| BPF_LD+BPF_W+BPF_LEN | A <- packet length | ld #pktlen |
| BPF_LD+BPF_IMM | A <- k | ld k |
| BPF_LD+BPF_MEM | A <- M[k] | ld M[k] |
BPF_LDX
These instructions load a value into the index register.
| Numeric value of a command to be used in
HNUserFilter.AddCmd and
HNUserFilter.AddJmp functions | Command action | BPF Assembler instruction |
|---|
| BPF_LDX+BPF_W+BPF_IMM | X <- k | ldx k |
| BPF_LDX+BPF_W+BPF_MEM | X <- M[k] | ldx M[k] |
| BPF_LDX+BPF_W+BPF_LEN | X <- packet length | ldx #pktlen |
| BPF_LDX+BPF_B+BPF_MSH | X <- 4*(P[k:1]&0xf) | ldxm P[k:1] or ldxm P[k] |
BPF_ST
This instruction stores the accumulator into the scratch memory.
BPF_STX
This instruction stores the index register in the scratch memory store.
BPF_ALU
The ALU instructions perform operations between the accumulator and index register or constant,
and store the result back in the accumulator. For two-operand instructions source mode must be set
(BPF_K or BPF_X).
| Numeric value of a command to be used in
HNUserFilter.AddCmd and
HNUserFilter.AddJmp functions | Command action | BPF Assembler instruction |
|---|
| PF_ALU+BPF_ADD+BPF_K | A <- A + k | add k |
| PF_ALU+BPF_SUB+BPF_K | A <- A – k | sub k |
| PF_ALU+BPF_MUL+BPF_K | A <- A * k | mul k |
| PF_ALU+BPF_DIV+BPF_K | A <- A / k | div k |
| PF_ALU+BPF_AND+BPF_K | A <- A & k | and k |
| PF_ALU+BPF_OR+BPF_K | A <- A | k | or k |
| PF_ALU+BPF_LSH+BPF_K | A <- A << k | lsh k |
| PF_ALU+BPF_RSH+BPF_K | A <- A >> k | rsh k |
| PF_ALU+BPF_ADD+BPF_X | A <- A + X | add X |
| PF_ALU+BPF_SUB+BPF_X | A <- A – X | sub X |
| PF_ALU+BPF_MUL+BPF_X | A <- A * X | mul X |
| PF_ALU+BPF_DIV+BPF_X | A <- A / X | div X |
| PF_ALU+BPF_AND+BPF_X | A <- A & X | and X |
| PF_ALU+BPF_OR+BPF_X | A <- A | X | or X |
| PF_ALU+BPF_LSH+BPF_X | A <- A << X | lsh X |
| PF_ALU+BPF_RSH+BPF_X | A <- A >> X | rsh X |
| PF_ALU+BPF_NEG | A <- -A | neg |
BPF_JMP
The jump instructions alter flow of control. Conditional jumps compare the accumulator against
a constant (BPF_K) or the index register (BPF_X). If the result is true (or non-zero), the true branch
is taken, otherwise the false branch is taken. Jump offsets are encoded in 8 bits, so the longest jump
is 256 instructions. However, unconditional jump (BPF_JA) always uses the 32 bit k field as the
offset, allowing far jumps. All conditionals use unsigned jump offsets.
jt (Jump If True) and jf (Jump If False) values are a number or expression with
the result value from 0 to 255 jumps forward for all BPF_JMP commands. This value also
may contain a label ID of a command we want to jump to. This rule is also effective for the
jmp (BPF_JA) k command.
 | Backward jumps are not allowed. |
| Numeric value of a command to be used in
HNUserFilter.AddCmd and
HNUserFilter.AddJmp functions | Command action | BPF Assembler instruction |
|---|
| BPF_JMP+BPF_JA | pc += k | jmp k |
| BPF_JMP+BPF_JGT+BPF_K | pc += (A > k) ? jt : jf | jg k, jt, jf |
| BPF_JMP+BPF_JGE+BPF_K | pc += (A >= k) ? jt : jf | jge k, jt, jf |
| BPF_JMP+BPF_JEQ+BPF_K | pc += (A == k) ? jt : jf | jeq k, jt, jf |
| BPF_JMP+BPF_JSET+BPF_K | pc += (A & k) ? jt : jf | jset k, jt, jf |
| BPF_JMP+BPF_JGT+BPF_X | pc += (A > X) ? jt : jf | jg X, jt, jf |
| BPF_JMP+BPF_JGE+BPF_X | pc += (A >= X) ? jt : jf | jge X, jt, jf |
| BPF_JMP+BPF_JEQ+BPF_X | pc += (A == X) ? jt : jf | jeq X, jt, jf |
| BPF_JMP+BPF_JSET+BPF_X | pc += (A & X) ? jt : jf | jset X, jt, jf |
BPF_RET
The return instructions terminate the filter program and specify the amount of packets to
accept (i.e. they return the truncation amount). A return value of zero indicates that the packet
should be ignored. The return value is either a constant (BPF_K) or the accumulator (BPF_A).
If a returned value of these commands is greater than 0, this means that this packet
must be accepted (1), and specifies the number of the bytes that must be passed to the application (2).
This feature can be used in billing solutions to increase performance, in case the application
doesn't need the whole packet and the packet header is enough.
If you want to pass to the application the whole packet, the return value must be equal to
-1 (please see also HNPacket.IncPacketSize).
| Numeric value of a command to be used in
HNUserFilter.AddCmd and
HNUserFilter.AddJmp functions | Command action | BPF Assembler instruction |
|---|
| BPF_RET+BPF_A | accept A bytes | ret A |
| BPF_RET+BPF_K | accept k bytes | ret k |
BPF_MISC
The miscellaneous category was created for anything that does not fit into the above classes
and for any new instructions that might be added. Currently, these are the register transfer
instructions that copy the index register to the accumulator or vice versa.
| Numeric value of a command to be used in
HNUserFilter.AddCmd and
HNUserFilter.AddJmp functions | Command action | BPF Assembler instruction |
|---|
| BPF_MISC+BPF_TAX | X <- A | tax |
| BPF_MISC+BPF_TXA | A <- X | txa |
| BPF_MISC+BPF_HTONL | A <- htonl(A) | ex_htonl A |
| BPF_MISC+BPF_HTONS | A <- htons(A) | ex_htons A |
| BPF_MISC+BPF_MARK+BPF_A | Marks packet with the register A content. | ex_mark A |
| BPF_MISC+BPF_MARK+BPF_X | Marks packet with the register X content. | ex_mark X |
| BPF_MISC+BPF_MARK+BPF_K | Marks packet with the constant value k. | ex_mark k |