tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Lua in-kernel (lbuf library)



Hi folks,

It has been a long time since my GSoC project and though I have tried
to come back, I've experienced some personal issues. However, now I'm
coding again.

I'm developing a library to handle buffers in Lua, named lbuf. It is
been developed as part of my efforts to perform experimentation in
kernel network stack using Lua. Initially, I intended to bind mbuf to
allow, for example, to write protocols dissectors in Lua. For example,
calling a Lua function to inspect network packets:

function filter(packet)
  if packet.field == value then return DROP end
  return PASS
end

Thus, I started to design a Lua binding to mbuf inspired by '#pragma
pack' and bitfields of C lang. Then, I realized that this Lua library
could be useful to other kernel (and user-space) areas, such as device
drivers and user-level protocols. So, I started to develop this
binding generically as a independent library to give random access to
bits in a buffer. It is just in the early beginning, but I want to
share some thoughts.

Here are a draft of the lbuf API:

C API:

lbuf_new(lua_State L, void * buffer, size_t length, lua_Alloc free, bool net);

* creates a new lbuf userdatum and pushes it on the Lua stack. The net
flag indicates if it is necessary to perform endianness conversion.

Lua API:

- array access (1)

lbuf:mask(alignment [, offset, length])
buf[ix] ~> accesses 'alignment' bits from 'alignment*(ix -1)+offset' position

e.g.:
buf:mask(3)
buf[3] ~> accesses 3 bits from bit-6 position

- array access (2)

buf:mask{ length_pos1, length_pos2, ... }
buf[ix] ~> accesses 'length_pos(ix)' bits from 'length_pos1 + ...
length_pos(ix-1)' position

e.g.:
buf:mask{ 2, 2, 32, 9 }
buf[2] ~> accesses 2 bits from bit-2 position

- fields access

buf:mask{ field = { offset, length }, ... }
buf.field ~> 'field.length' bits from 'offset' position

e.g.:
buf:mask{
  type = { 0, 2 },
  -- 1 bit padding
  flag  = { 4, 1 },
  xyz  = { 15, 17 },
  seg  = {
    flagX = { 32, 1 },
    flagY = { 33, 1 },
    flagZ = { 34, 1 },
  }
}
buf.flag ~> 1 bit from bit-4 position
buf.xyz ~> 17 bits from bit-15 position
buf.seg.flagY ~> 1 bit from bit-34 position

- raw access

buf:rawget(3, 30) ~> gets 30 bits from bit-3 position
buf:rawset(3, 30, value) <~ sets 'value' into 30 bits from bit-3 position

- segment

buf:segment(offset [, length])

returns a new lbuf corresponding a 'buf' segment.

- mask reusing

lbuf.mask{ ... }

creates a mask without associating a specific buffer. Thus, you can
call buf:mask() passing a already created mask. For example:

ethernet_mask = lbuf.mask{ type = { ethertype_offset, ethertype_len }}
lldp_mask = lbuf.mask{ version = { version_offset, version_len }}

function filter(packet)
  packet:mask(ethernet_mask)
  if packet.type == 0x88CC then
    lldp_pdu = packet.segment(payload_offset):mask(lldp_mask)
    if packet.version < 1 return DROP end
  end
  return PASS
end

The code is hosted in https://github.com/lneto/lbuf. Currently, only
array and raw access are working (partially).

I think this API could be useful for device-driver and protocol
prototyping. Looking forward to hearing from you.

Regards,
-- 
Lourival Vieira Neto


Home | Main Index | Thread Index | Old Index