- Zig 94.9%
- Python 5.1%
|
Jordan Griege
d3726ac3ea
Print conntrack counters
Also adds endian-specific integer functions to Attr |
||
|---|---|---|
| bin | Print conntrack counters | |
| lib | Print conntrack counters | |
| .gitignore | Fix .gitignore for new cache directory | |
| build.zig | implement nflog | |
| build.zig.zon | update to zig 0.14.0 | |
| gen.py | Fix enum entries with non-alpha leading character | |
| LICENSE | add license | |
| README.md | Refactor Client | |
netlink
A low-level library for creating and parsing netlink messages. Inspired by libmnl.
While this library is a decent replacement for libmnl, it is nowhere near the scope of libraries like libnl.
There is also a program that reimplements some functionality of iproute2, but
its primary purpose is to verify that the library works.
Usage
Request and Response are comptime functions that wrap a type which is
transferred over an AF_NETLINK socket, e.g. rtgenmsg and ifinfomsg. Both
are backed by a buffer so that appending nlattrs does not require allocation.
So to create a new link, create a new type for that specific request:
conststd=@import("std");constnl=@import("netlink");constlinux=std.os.linux;constLinkNewRequest=nl.Request(linux.NetlinkMessageType.RTM_NEWLINK,linux.ifinfomsg);varbuf=[_]u8{0}**128;varreq=LinkListRequest.init(&buf);req.nlh.*.flags|=(linux.NLM_F_CREATE|linux.NLM_F_EXCL);constname:[:0]u8="asdf";_=tryreq.add_str(@intFromEnum(linux.IFLA.IFNAME),name);_=req.done();// Finalize the request by setting its length.The Response type is created similarly, but supports an iterator pattern
for traversing multiple messages in a single response and each message's
attributes.
constLinkListResponse=nl.Response(linux.NetlinkMessageType.RTM_NEWLINK,linux.ifinfomsg);constseq=0;constbuf:[]u8="";// say this contains a netlink responsevarres=LinkListResponse.init(seq,buf);while(true){varmsg=tryres.next();switch(msg){// No more messages in this sequence are expected, and all future calls// of `res.next()` will return `.done`..done=>{},// There are more messages, but not in the current buffer. You need to// call `std.os.recv()` on the netlink socket again and recreate `res`..more=>{},// The message contained the `Response`'s inner message type (e.g.// `ifinfomsg`).// The capture should _always_ be a pointer..payload=>|*payload|{while(trypayload.next())|attr|{if(attr.type==@intFromEnum(linux.IFLA.IFNAME))std.debug.print("{s}\n",.{attr.read_slice()});}},}}The Handle structure wraps a netlink socket and byte buffer and reduces
boilerplate required when receiving and parsing messages. Because when using
NLM_F_ACK, the client should check that a message sequence is terminated by a
NLMSG_DONE or NLMSG_ERROR message.
Example
conststd=@import("std");constnl=@import("netlink");constrtgenmsg=externstruct{rtgen_family:u8,};constLinkListRequest=nl.message.Request(linux.NetlinkMessageType.RTM_GETLINK,rtgenmsg);constLinkResponse=nl.message.Response(linux.NetlinkMessageType.RTM_NEWLINK,std.os.linux.ifinfomsg);varbuf=[_]u8{0}**4096;varsk=trystd.os.socket(std.os.linux.AF.NETLINK,std.os.linux.SOCK.RAW,std.os.linux.NETLINK.ROUTE);deferstd.os.close(sk);varnlh=nl.Handle.init(sk,&buf);varreq=trynlh.new_req(LinkListRequest);req.hdr.*.rtgen_family=std.os.AF.PACKET;req.nlh.*.flags|=std.os.linux.NLM_F_DUMP;trynlh.send(req);varres=nlh.recv_all(LinkResponse);while(tryres.next())|payload|{std.debug.print("{}\n",.{payload.value.index});}There is plenty more example code in the bin/ directory.
Code Generation
$ export KERNEL_PATH=...
$ export PYTHONPATH="${KERNEL_PATH}/tools/net/ynl/lib"
$ for name in rt_addr rt_link rt_route; do ./gen.py ${KERNEL_PATH}/Documentation/netlink/specs/${name}.yaml > lib/${name}.zig && zig fmt lib/${name}.zig; done