rtnetlink(7)
๐ธ NAME ๐ธ
rtnetlink โ the Linux routing socket, aka rtnetlink(7), aka the girl who runs the whole network stack's group chat ๐
โจ SYNOPSIS โจ
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
rtnetlink_socket = socket(AF_NETLINK, int socket_type, NETLINK_ROUTE);
๐ฆ DESCRIPTION ๐ฆ
okay so BESTIE. rtnetlink is the thing that lets you read the kernel's routing tables and also alter them. main character behavior honestly. It gets used inside the kernel itself so all the different subsystems can gossip with each other (that internal usage is not documented here, so don't @ me), and it's also how user-space programs get to talk to the kernel.
What can you control through NETLINK_ROUTE sockets? Literally all of this:
- network routes
- IP addresses
- link parameters
- neighbor setups
- queueing disciplines
- traffic classes
- packet classifiers
It's built on top of netlink messages, so if you want the full lore go read netlink(7).
๐ Routing attributes
Some rtnetlink messages carry optional attributes chilling right after the initial header:
struct rtattr {
unsigned short rta_len; /* Length of option */
unsigned short rta_type; /* Type of option */
/* Data follows */
};
โ ๏ธ Bestie, listen: you should manipulate these attributes only with theRTA_*macros or withlibnetlink. Seertnetlink(3). No freestyling, no touching the bytes yourself. ๐
๐ซ Messages
Rtnetlink is made up of these message types (on top of the standard netlink messages, obviously):
RTM_NEWLINKRTM_DELLINKRTM_GETLINKโ create, remove, or get info about a specific network interface. These messages contain anifinfomsgstructure, followed by a series ofrtattrstructures.
struct ifinfomsg {
unsigned char ifi_family; /* AF_UNSPEC */
unsigned short ifi_type; /* Device type */
int ifi_index; /* Interface index */
unsigned int ifi_flags; /* Device flags */
unsigned int ifi_change; /* change mask */
};
ifi_flags holds the device flags โ go look at netdevice(7) for those. ifi_index is the unique interface index (and since Linux 3.7 you can feed a nonzero value along with the RTM_NEWLINK message to create a link with that given ifindex, which is lowkey iconic). ifi_change is a mask that says which bits of ifi_flags should actually be applied to the device. ๐
Routing attributes:
IFLA_UNSPECโ value type-โ unspecifiedIFLA_ADDRESSโ value type hardware address โ interface L2 addressIFLA_BROADCASTโ value type hardware address โ L2 broadcast addressIFLA_IFNAMEโ value type asciiz string โ Device nameIFLA_MTUโ value typeunsigned intโ MTU of the deviceIFLA_LINKโ value typeintโ Link typeIFLA_QDISCโ value type asciiz string โ Queueing disciplineIFLA_STATSโ value type see below โ Interface StatisticsIFLA_PERM_ADDRESSโ value type hardware address โ hardware address provided by device (since Linux 5.5)
The value type for IFLA_STATS is struct rtnl_link_stats (which was struct net_device_stats back in Linux 2.4 and earlier, if you're feeling vintage ๐).
RTM_NEWADDRRTM_DELADDRRTM_GETADDRโ add, remove, or receive info about an IP address tied to an interface.
History lesson real quick: in Linux 2.2 an interface can carry multiple IP addresses, which replaces the alias device concept from Linux 2.0. And in Linux 2.2 these messages support both IPv4 and IPv6 addresses. They contain an ifaddrmsg structure, optionally followed by rtattr routing attributes.
struct ifaddrmsg {
unsigned char ifa_family; /* Address type */
unsigned char ifa_prefixlen; /* Prefixlength of address */
unsigned char ifa_flags; /* Address flags */
unsigned char ifa_scope; /* Address scope */
unsigned int ifa_index; /* Interface index */
};
So: ifa_family is the address family type (right now that's AF_INET or AF_INET6). ifa_prefixlen is the length of the address mask of the address, if one is defined for that family (like for IPv4). ifa_scope is the address scope. ifa_index is the interface index of the interface the address is associated with. And ifa_flags is a flag word containing IFA_F_SECONDARY for a secondary address (that's the old alias interface) and IFA_F_PERMANENT for a permanent address set by the user โ plus other undocumented flags, which, sure. ๐
Attributes:
IFA_UNSPECโ value type-โ unspecifiedIFA_ADDRESSโ value type raw protocol address โ interface addressIFA_LOCALโ value type raw protocol address โ local addressIFA_LABELโ value type asciiz string โ name of the interfaceIFA_BROADCASTโ value type raw protocol address โ broadcast addressIFA_ANYCASTโ value type raw protocol address โ anycast addressIFA_CACHEINFOโ value typestruct ifa_cacheinfoโ Address information
struct ifa_cacheinfo {
__u32 ifa_prefered; // Preferred lifetime remaining, in seconds
__u32 ifa_valid; // Valid lifetime remaining, in seconds
__u32 cstamp; // Creation timestamp, in centiseconds
__u32 tstamp; // Update timestamp, in centiseconds
};
๐จ Rules of the cacheinfo house:ifa_validcannot be zero, andifa_preferedcannot be greater thanifa_valid. A value ofUINT32_MAXmeans an infinite lifetime. Periodt.
RTM_NEWROUTERTM_DELROUTERTM_GETROUTEโ create, remove, or receive info about a network route. These messages contain anrtmsgstructure with an optional sequence ofrtattrstructures following it.
For RTM_GETROUTE: setting rtm_dst_len and rtm_src_len to 0 means you get all entries for the specified routing table. For the other fields โ except rtm_table and rtm_protocol โ 0 is the wildcard. โจ
struct rtmsg {
unsigned char rtm_family; /* Address family of route */
unsigned char rtm_dst_len; /* Length of destination */
unsigned char rtm_src_len; /* Length of source */
unsigned char rtm_tos; /* TOS filter */
unsigned char rtm_table; /* Routing table ID;
see RTA_TABLE below */
unsigned char rtm_protocol; /* Routing protocol; see below */
unsigned char rtm_scope; /* See below */
unsigned char rtm_type; /* See below */
unsigned int rtm_flags;
};
rtm_type โ Route type:
RTN_UNSPECโ unknown routeRTN_UNICASTโ a gateway or direct routeRTN_LOCALโ a local interface routeRTN_BROADCASTโ a local broadcast route (sent as a broadcast)RTN_ANYCASTโ a local broadcast route (sent as a unicast)RTN_MULTICASTโ a multicast routeRTN_BLACKHOLEโ a packet dropping routeRTN_UNREACHABLEโ an unreachable destinationRTN_PROHIBITโ a packet rejection routeRTN_THROWโ continue routing lookup in another tableRTN_NATโ a network address translation ruleRTN_XRESOLVEโ refer to an external resolver (not implemented)
rtm_protocol โ Route origin:
RTPROT_UNSPECโ unknownRTPROT_REDIRECTโ by an ICMP redirect (currently unused)RTPROT_KERNELโ by the kernelRTPROT_BOOTโ during bootRTPROT_STATICโ by the administrator
Values larger than RTPROT_STATIC are not interpreted by the kernel โ they're just there for your user-space info. You can use them to tag where a piece of routing info came from, or to tell multiple routing daemons apart. Check <linux/rtnetlink.h> for the routing daemon identifiers that are already assigned. ๐ซถ
rtm_scope is the distance to the destination:
RT_SCOPE_UNIVERSEโ global routeRT_SCOPE_SITEโ interior route in the local autonomous systemRT_SCOPE_LINKโ route on this linkRT_SCOPE_HOSTโ route on the local hostRT_SCOPE_NOWHEREโ destination doesn't exist
The values between RT_SCOPE_UNIVERSE and RT_SCOPE_SITE are available to the user.
The rtm_flags have the following meanings:
RTM_F_NOTIFYโ if the route changes, notify the user via rtnetlinkRTM_F_CLONEDโ route is cloned from another routeRTM_F_EQUALIZEโ a multipath equalizer (not yet implemented)
rtm_table specifies the routing table:
RT_TABLE_UNSPECโ an unspecified routing tableRT_TABLE_DEFAULTโ the default tableRT_TABLE_MAINโ the main tableRT_TABLE_LOCALโ the local table
...you can legitimately drop any arbitrary value you want in there, anywhere between RT_TABLE_UNSPEC and RT_TABLE_DEFAULT ๐
the kernel is not gonna police that, bestie.
๐ Attributes ๐
okay so here's the whole roster of rta_type values you might see riding along in the message, with what they hold and what they mean:
RTA_UNSPECโ - โ literally just ignored, it's giving placeholder energy ๐RTA_DSTโ protocol address โ Route destination addressRTA_SRCโ protocol address โ Route source addressRTA_IIFโ int โ Input interface indexRTA_OIFโ int โ Output interface indexRTA_GATEWAYโ protocol address โ The gateway of the route ๐RTA_PRIORITYโ int โ Priority of routeRTA_PREFSRCโ protocol address โ Preferred source addressRTA_METRICSโ Route metrics (see below ๐)RTA_MULTIPATHโ Multipath nexthop data (see below ๐)RTA_PROTOINFOโ No longer used ๐RTA_FLOWโ int โ Route realmRTA_CACHEINFOโstruct rta_cacheinfo(peeplinux/rtnetlink.h)RTA_SESSIONโ No longer used ๐RTA_MP_ALGOโ No longer used ๐RTA_TABLEโ int โ Routing table ID; if you set this one,rtm_tablegets straight up ignored, no capRTA_MARKโ intRTA_MFC_STATSโstruct rta_mfc_stats(peeplinux/rtnetlink.h)RTA_VIAโstruct rtviaโ Gateway in a different AF (see below ๐)RTA_NEWDSTโ protocol address โ Change packet destination addressRTA_PREFโ char โ RFC4191 IPv6 router preference (see below ๐)RTA_ENCAP_TYPEโ short โ Encapsulation type for lwtunnels (see below ๐)RTA_ENCAPโ Defined byRTA_ENCAP_TYPERTA_EXPIRESโ int โ Expire time for IPv6 routes (in seconds)
so RTA_METRICS is not just one little value, bestie โ it's an array of struct rtattr, each one carrying its own attribute, and they go a lil something like this:
RTAX_UNSPECโ - โ unspecified ๐คทRTAX_LOCKโ__u32โ Bit field indicating whichRTAX_*attributes are locked.RTAX_MTUโ__u32โ Maximum Transmission Unit for this route.RTAX_WINDOWโ__u32โ Maximum size of the receive window for this route.RTAX_RTTโ__u32โ Estimated round-trip time for this route.RTAX_RTTVARโ__u32โ Estimated round-trip time variation for this route.RTAX_SSTHRESHโ__u32โ Slow start threshold to use for this route.RTAX_CWNDโ__u32โ Maximum size of the congestion window for this route.RTAX_ADVMSSโ__u32โ Maximum Segment Size to advertise for this route.RTAX_REORDERINGโ__u32โ Initial reordering level of packets for this route.RTAX_HOPLIMITโ__u32โ Hop limit (TTL) to use for this route.RTAX_INITCWNDโ__u32โ Initial congestion window to use for this route.RTAX_FEATURESโ__u32โ Features to enable for this route specifically.RTAX_RTO_MINโ__u32โ Minimum Retransmission TimeOut to use for this route.RTAX_INITRWNDโ__u32โ Initial size of the receive window for this route.RTAX_QUICKACKโ__u32โ Use quick ack for this route.RTAX_CC_ALGOโ asciiz string โ Congestion Control algorithm to use for this route.RTAX_FASTOPEN_NO_COOKIEโ__u32โ Allow TCP Fast Open without cookie.
โ ๏ธ okay important one: metrics that are locked withRTAX_LOCKtake precedence over the values the kernel would normally use (the ones it computed, or that something set via a sysctl orsetsockopt(2)). So lowkey some metrics โRTAX_RTO_MINis the classic example โ do absolutely nothing unless their bit is set inRTAX_LOCK. Set the bit or it's not happening. ๐
and now for RTA_MULTIPATH โจ it's a bunch of packed instances of struct rtnexthop hanging out together, plus nested RTAs (RTA_GATEWAY) tucked inside:
struct rtnexthop {
unsigned short rtnh_len; /* Length of struct + length
of RTAs */
unsigned char rtnh_flags; /* Flags (see
linux/rtnetlink.h) */
unsigned char rtnh_hops; /* Nexthop priority */
int rtnh_ifindex; /* Interface index for this
nexthop */
};
there's a whole squad of RTNH_* macros that look just like the RTA_* and NLHDR_* macros, and they're the ones you want for wrangling these structures ๐ซถ
struct rtvia {
unsigned short rtvia_family;
unsigned char rtvia_addr[0];
};
rtvia_addr is the address itself, and rtvia_family is its family type. periodt.
RTA_PREF can hold the values ICMPV6_ROUTER_PREF_LOW, ICMPV6_ROUTER_PREF_MEDIUM, and ICMPV6_ROUTER_PREF_HIGH, all defined in <linux/icmpv6.h>.
RTA_ENCAP_TYPE can hold the values LWTUNNEL_ENCAP_MPLS, LWTUNNEL_ENCAP_IP, LWTUNNEL_ENCAP_ILA, or LWTUNNEL_ENCAP_IP6, defined in <linux/lwtunnel.h>.
Fill these values in! ๐ซก
๐ RTM_NEWNEIGH ๐
๐ RTM_DELNEIGH ๐
๐ RTM_GETNEIGH ๐
These three add, remove, or hand you info about a neighbor table entry (think: an ARP entry, the classic). The message is packing an ndmsg structure:
struct ndmsg {
unsigned char ndm_family;
int ndm_ifindex; /* Interface index */
__u16 ndm_state; /* State */
__u8 ndm_flags; /* Flags */
__u8 ndm_type;
};
struct nda_cacheinfo {
__u32 ndm_confirmed;
__u32 ndm_used;
__u32 ndm_updated;
__u32 ndm_refcnt;
};
so ndm_state is a bit mask, and here's everything it can be masking, bestie:
NUD_INCOMPLETEโ a currently resolving cache entryNUD_REACHABLEโ a confirmed working cache entry ๐NUD_STALEโ an expired cache entryNUD_DELAYโ an entry waiting for a timer โณNUD_PROBEโ a cache entry that is currently reprobedNUD_FAILEDโ an invalid cache entry ๐NUD_NOARPโ a device with no destination cacheNUD_PERMANENTโ a static entry
and the valid ndm_flags are:
NTF_PROXYโ a proxy arp entryNTF_ROUTERโ an IPv6 router
meanwhile the rtattr struct has these meanings for its rta_type field:
NDA_UNSPECโ unknown type ๐NDA_DSTโ a neighbor cache n/w layer destination addressNDA_LLADDRโ a neighbor cache link layer addressNDA_CACHEINFOโ cache statistics
and FYI: if that rta_type field is NDA_CACHEINFO, then a struct nda_cacheinfo header follows it. ๐ซถ
๐ RTM_NEWRULE ๐
๐ RTM_DELRULE ๐
๐ RTM_GETRULE ๐
Add, delete, or retrieve a routing rule. Carries a struct rtmsg
๐ the qdisc ops, bestie
RTM_NEWQDISC, RTM_DELQDISC, RTM_GETQDISC โ these three are literally the add / remove / get trio for a queueing discipline. So if you wanna slide a new qdisc in, yeet one out, or just peek at what's there? Yeah. These.
Every one of these messages carries a struct tcmsg, and it may have a whole parade of attributes tagging along after it. Observe, bestie:
struct tcmsg {
unsigned char tcm_family;
int tcm_ifindex; /* interface index */
__u32 tcm_handle; /* Qdisc handle */
__u32 tcm_parent; /* Parent qdisc */
__u32 tcm_info;
};
โจ now the attributes, slay:
TCA_UNSPECโ value type:-โ it's justโฆ unspecified. vibes only, no meaning ๐TCA_KINDโ anasciizstring โ the name of the queueing discipline ๐TCA_OPTIONSโ a byte sequence โ the qdisc-specific options come right after this oneTCA_STATSโ astruct tc_statsโ the qdisc's statistics, the receipts, the math ๐งฎTCA_XSTATSโ qdisc-specific โ module-specific statistics, iykykTCA_RATEโ astruct tc_estimatorโ rate limit, keep it cute, keep it capped ๐ธ
and ALSO, on top of all that: a whole bunch of other qdisc-module-specific attributes are allowed too. Wanna know what those are? Go read the appropriate include files, bestie, I can't read them for you ๐ซถ
๐ฆ the class ops
RTM_NEWTCLASS, RTM_DELTCLASS, RTM_GETTCLASS โ add, remove, or get a traffic class. Same energy, class edition. These messages carry a struct tcmsg exactly like the one I described up above, no cap. ๐
๐ the filter ops
RTM_NEWTFILTER, RTM_DELTFILTER, RTM_GETTFILTER โ add, remove, or receive info about a traffic filter. And you already know what's inside: a struct tcmsg, as described above. consistent queen โจ
๐ VERSIONS
rtnetlink is a new feature of Linux 2.2. baby of the family fr fr ๐ถ
๐ BUGS
This manual page is incomplete. Not me being honest โ the page itself says so. The audacity. ๐ญ
๐ฆ SEE ALSO
okay that's a wrap on rtnetlink(7), hope u learned something bestie ๐ This lil page came from Linux man-pages 6.20, dated 2026-02-08, and yeah โ that's the whole rtnetlink(7) saga, all three parts, finished. go forth and route some packets, main character ๐
๐ฆ where this page comes from
- arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- ๐ the page's license: Linux-man-pages-1-para
- Copyright 1999, Andi Kleen <andi@firstfloor.org>
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms