netlink.channelModule
Generic netlink channel: a generic netlink family with one multicast group whose multicast/unicast are safe from softirq (netfilter hooks, XDP), for kernel-to-userspace delivery.
The message body is built in Lua (e.g. with netlink.message) and sent as-is; request/response netlink is otherwise done in Lua over the socket module. Only this softirq-capable send path needs a dedicated kernel object. A channel is created and used from a process or softirq runtime only, and new refuses a hardirq one: with an nlmon tap up, a send hands a copy of the message todev_queue_xmit, which re-enables bottom halves, and the kernel warns
when that happens in a hardirq. multicast and unicast refuse a call with IRQs disabled,
where a softirq runtime’s callback can run too, as hid’s raw_event does behind a USB host
controller that completes in its interrupt handler.
Usage
-- lunatik run -c softirq <script>: multicasts a notice for each IPv4 packet the host receives
local channel = require("netlink.channel")
local message = require("netlink.message")
local netfilter = require("netfilter")
local nf = require("linux.nf")
local CMD <const> = 1
local NOTICE <const> = 1
local family = channel.new("mychannel")
local notice = message.attrs{[NOTICE] = "packet"}
local function notify(skb)
family:multicast(CMD, notice)
return nf.action.ACCEPT
end
netfilter.register{
hook = notify,
pf = nf.proto.IPV4,
hooknum = nf.inet.PRE_ROUTING,
priority = nf.ip.pri.FILTER,
}
Class netlink.channel
| netlink.channel:multicast (cmd[, payload]) | Multicasts a message to every subscriber of the channel’s group. |
| netlink.channel:stop () | Unregisters the channel’s family. |
| netlink.channel:unicast (portid, cmd[, payload]) | Unicasts a message to a single userspace subscriber by port id. |
netlink.channel
| new (name) | Creates a generic netlink channel. |
Class netlink.channel in detail
A generic netlink channel.
Returned by
netlink.channel.new(). Backed by a generic netlink family with one
multicast group; multicast and unicast are safe from softirq (netfilter
hooks, XDP) and deliver to userspace subscribers of the family.
- netlink.channel:multicast (cmd[, payload])
-
Multicasts a message to every subscriber of the channel’s group.
Safe to call from softirq.
Parameters
- cmd integer Generic netlink command, from 0 to 255.
- payload string Message body (e.g. from netlink.message). (optional)
Returns
-
boolean
whether it reached at least one subscriber.
Raises
“not allowed with IRQs disabled”; “out of bounds” ifcmdis past 8 bits or negative, “closed object” if the channel has been stopped, or on an allocation error. - netlink.channel:stop ()
-
Unregisters the channel’s family.
Userspace no longer resolves the family by name, its subscribers leave the group, and
multicast and unicast raise. Calling it again does nothing, and a to-be-closed variable
holding the channel stops it the same way.
Returns
-
nil
Raises
“not allowed once the runtime is armed” from an interrupt-context runtime past its body; “not allowed under RTNL” from a netdevice callback, in whatever runtime or coroutine its task runs, since the unregistration takes a lock a request holds while it waits on RTNL.Usage
family:stop() - netlink.channel:unicast (portid, cmd[, payload])
-
Unicasts a message to a single userspace subscriber by port id.
Safe to call from softirq.
Parameters
- portid
integer
Destination netlink port id, of a socket in the initial network namespace,
from 1 to
0xffffffff. - cmd integer Generic netlink command, from 0 to 255.
- payload string Message body (e.g. from netlink.message). (optional)
Returns
-
boolean
whether it was queued to the port id (
falseif the port id is gone or its receive buffer is full).Raises
“not allowed with IRQs disabled”; “out of bounds” ifportidis 0, negative or past 32 bits, orcmdis past 8 bits or negative, “closed object” if the channel has been stopped, or on an allocation error. - portid
integer
Destination netlink port id, of a socket in the initial network namespace,
from 1 to
netlink.channel in detail
- new (name)
-
Creates a generic netlink channel.
Registers a generic netlink family
namewith a single multicast group, named lunatik; userspace resolves the family by name (e.g. via netlink.genl, orgenl ctrl get name <name>) to learn that group’s id, and joins it withNETLINK_ADD_MEMBERSHIP. Like a netfilter hook, it must be created at script load (process context); its multicast/unicast may then be called from softirq.Parameters
- name
string
Generic netlink family name (up to
GENL_NAMSIZ-1bytes).
Returns
-
netlink.channel
the channel, which new keeps for its runtime: dropping it stops
nothing, and the family stays registered until stop or the end of the runtime.
Raises
“not allowed once the runtime is armed” from an interrupt-context runtime past its body; “not allowed in a percpu runtime”; “not allowed in a hardirq runtime”; “not allowed under RTNL” from a netdevice callback, in whatever runtime or coroutine its task runs, since the registration takes a lock a request holds while it waits on RTNL; if the name is empty or too long, or if family registration fails. - name
string
Generic netlink family name (up to