1
0
Fork
You've already forked netlink
0
No description
  • Zig 94.9%
  • Python 5.1%
Jordan Griege d3726ac3ea Print conntrack counters
Also adds endian-specific integer functions to Attr
2025年06月04日 16:07:35 -05:00
bin Print conntrack counters 2025年06月04日 16:07:35 -05:00
lib Print conntrack counters 2025年06月04日 16:07:35 -05:00
.gitignore Fix .gitignore for new cache directory 2024年06月07日 13:50:52 -05:00
build.zig implement nflog 2025年03月01日 15:57:51 -06:00
build.zig.zon update to zig 0.14.0 2025年04月05日 21:17:19 -05:00
gen.py Fix enum entries with non-alpha leading character 2024年09月14日 11:41:25 -05:00
LICENSE add license 2023年10月09日 20:32:18 -05:00
README.md Refactor Client 2025年02月02日 20:48:20 -06:00

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