pub const BPF_LD: u8 = 0x00;
pub const BPF_LDX: u8 = 0x01;
pub const BPF_ST: u8 = 0x02;
pub const BPF_STX: u8 = 0x03;
pub const BPF_ALU: u8 = 0x04; pub const BPF_JMP: u8 = 0x05;
pub const BPF_JMP32: u8 = 0x06;
pub const BPF_ALU64: u8 = 0x07;
pub const BPF_W: u8 = 0x00; pub const BPF_H: u8 = 0x08; pub const BPF_B: u8 = 0x10; pub const BPF_DW: u8 = 0x18;
pub const BPF_MEM: u8 = 0x60;
pub const BPF_K: u8 = 0x00; pub const BPF_X: u8 = 0x08;
pub const BPF_ADD: u8 = 0x00;
pub const BPF_SUB: u8 = 0x10;
pub const BPF_MUL: u8 = 0x20;
pub const BPF_AND: u8 = 0x50;
pub const BPF_LSH: u8 = 0x60;
pub const BPF_RSH: u8 = 0x70;
pub const BPF_MOV: u8 = 0xb0;
pub const BPF_JA: u8 = 0x00;
pub const BPF_JEQ: u8 = 0x10;
pub const BPF_JGT: u8 = 0x20;
pub const BPF_JGE: u8 = 0x30;
pub const BPF_JSET: u8 = 0x40;
pub const BPF_JNE: u8 = 0x50;
pub const BPF_JLT: u8 = 0xa0;
pub const BPF_JLE: u8 = 0xb0;
pub const BPF_EXIT: u8 = 0x90;
pub const R0: u8 = 0;
pub const R1: u8 = 1;
pub const R2: u8 = 2;
pub const R3: u8 = 3;
pub const R4: u8 = 4;
pub const R5: u8 = 5;
pub const R6: u8 = 6;
pub const R10: u8 = 10;
pub const XDP_DROP: i32 = 1;
pub const XDP_PASS: i32 = 2;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct Insn {
pub code: u8,
pub regs: u8,
pub off: i16,
pub imm: i32,
}
impl Insn {
#[inline]
pub fn new(code: u8, dst: u8, src: u8, off: i16, imm: i32) -> Self {
Self {
code,
regs: (dst & 0xf) | ((src & 0xf) << 4),
off,
imm,
}
}
#[inline]
pub fn dst(&self) -> u8 {
self.regs & 0xf
}
#[inline]
pub fn src(&self) -> u8 {
(self.regs >> 4) & 0xf
}
pub fn mov64_reg(dst: u8, src: u8) -> Self {
Self::new(BPF_ALU64 | BPF_MOV | BPF_X, dst, src, 0, 0)
}
pub fn mov64_imm(dst: u8, imm: i32) -> Self {
Self::new(BPF_ALU64 | BPF_MOV | BPF_K, dst, 0, 0, imm)
}
pub fn add64_reg(dst: u8, src: u8) -> Self {
Self::new(BPF_ALU64 | BPF_ADD | BPF_X, dst, src, 0, 0)
}
pub fn add64_imm(dst: u8, imm: i32) -> Self {
Self::new(BPF_ALU64 | BPF_ADD | BPF_K, dst, 0, 0, imm)
}
pub fn and32_imm(dst: u8, imm: i32) -> Self {
Self::new(BPF_ALU | BPF_AND | BPF_K, dst, 0, 0, imm)
}
pub fn rsh32_imm(dst: u8, imm: i32) -> Self {
Self::new(BPF_ALU | BPF_RSH | BPF_K, dst, 0, 0, imm)
}
pub fn lsh32_imm(dst: u8, imm: i32) -> Self {
Self::new(BPF_ALU | BPF_LSH | BPF_K, dst, 0, 0, imm)
}
pub fn ldx_b(dst: u8, src: u8, off: i16) -> Self {
Self::new(BPF_LDX | BPF_MEM | BPF_B, dst, src, off, 0)
}
pub fn ldx_h(dst: u8, src: u8, off: i16) -> Self {
Self::new(BPF_LDX | BPF_MEM | BPF_H, dst, src, off, 0)
}
pub fn ldx_w(dst: u8, src: u8, off: i16) -> Self {
Self::new(BPF_LDX | BPF_MEM | BPF_W, dst, src, off, 0)
}
pub fn ja(off: i16) -> Self {
Self::new(BPF_JMP | BPF_JA, 0, 0, off, 0)
}
pub fn jeq_imm(dst: u8, imm: i32, off: i16) -> Self {
Self::new(BPF_JMP | BPF_JEQ | BPF_K, dst, 0, off, imm)
}
pub fn jne_imm(dst: u8, imm: i32, off: i16) -> Self {
Self::new(BPF_JMP | BPF_JNE | BPF_K, dst, 0, off, imm)
}
pub fn jgt_imm(dst: u8, imm: i32, off: i16) -> Self {
Self::new(BPF_JMP | BPF_JGT | BPF_K, dst, 0, off, imm)
}
pub fn jge_imm(dst: u8, imm: i32, off: i16) -> Self {
Self::new(BPF_JMP | BPF_JGE | BPF_K, dst, 0, off, imm)
}
pub fn jlt_imm(dst: u8, imm: i32, off: i16) -> Self {
Self::new(BPF_JMP | BPF_JLT | BPF_K, dst, 0, off, imm)
}
pub fn jle_imm(dst: u8, imm: i32, off: i16) -> Self {
Self::new(BPF_JMP | BPF_JLE | BPF_K, dst, 0, off, imm)
}
pub fn jset_imm(dst: u8, imm: i32, off: i16) -> Self {
Self::new(BPF_JMP | BPF_JSET | BPF_K, dst, 0, off, imm)
}
pub fn jgt_reg(dst: u8, src: u8, off: i16) -> Self {
Self::new(BPF_JMP | BPF_JGT | BPF_X, dst, src, off, 0)
}
pub fn exit() -> Self {
Self::new(BPF_JMP | BPF_EXIT, 0, 0, 0, 0)
}
pub fn to_le_bytes(self) -> [u8; 8] {
let mut b = [0u8; 8];
b[0] = self.code;
b[1] = self.regs;
b[2..4].copy_from_slice(&self.off.to_le_bytes());
b[4..8].copy_from_slice(&self.imm.to_le_bytes());
b
}
}
#[derive(Debug, Clone)]
pub struct Program {
insns: Vec<Insn>,
}
impl Program {
pub(crate) fn new(insns: Vec<Insn>) -> Self {
Self { insns }
}
pub fn instructions(&self) -> &[Insn] {
&self.insns
}
pub fn len(&self) -> usize {
self.insns.len()
}
pub fn is_empty(&self) -> bool {
self.insns.is_empty()
}
pub fn to_le_bytes(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(self.insns.len() * 8);
for insn in &self.insns {
out.extend_from_slice(&insn.to_le_bytes());
}
out
}
}