Bir NETLINK_ROUTE soketinden RTM_NEWLINK (veya herhangi bir rtnetlink yanıtı) mesajı aldığında, sabit header’ı (link mesajları için struct ifinfomsg, adres mesajları için struct ifaddrmsg vb.) değişken uzunluklu bir route attribute dizisi (struct rtattr) takip eder.
Her rtattr, 16-bit rta_type (IFLA_IFNAME veya IFLA_MTU gibi protokole özgü bir sabit) ve uzunluğu rta_len ile belirtilen bir payload taşır. Attribute’ların boyutları hepsi aynı değildir, bu yüzden kernel’in sağladığı makrolarla tek tek gezmen gerekir.
Iterate etme deseni
Standart deyim, <linux/rtnetlink.h>‘dan üç makro etrafında kurulu bir for döngüsü:
RTA_OK(rta, remaining)—remainingbayt hâlâ geçerli bir attribute tuttuğu sürece true döndürür.RTA_NEXT(rta, remaining)—rta‘yı sonraki attribute’a ilerletir veremaining‘i azaltır.RTA_DATA(rta)/RTA_PAYLOAD(rta)— attribute’un payload baytlarına ve uzunluğuna erişir.
Attribute’lar sabit mesaj header’ının hemen ardından başlar. Link mesajları için kernel IFLA_RTA(ifi) verir (NLMSG_DATA(nlh) + sizeof(ifinfomsg)‘in tipli cast’i) ve kalan baytlar için IFLA_PAYLOAD(nlh); adres mesajları için eşdeğerleri IFA_RTA(ifa) ve IFA_PAYLOAD(nlh)‘dir.
Kısmi örnek
#include <iostream>
#include <cstdint>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
// ... soket kurulumu, RTM_GETLINK dump isteği gönder, buf'a recv ...
auto* nlh = reinterpret_cast<struct nlmsghdr*>(buf);
for (; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) {
if (nlh->nlmsg_type != RTM_NEWLINK) continue;
auto* ifi = reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(nlh));
int attr_len = IFLA_PAYLOAD(nlh);
struct rtattr* rta = IFLA_RTA(ifi);
// Mesajdaki her rtattr'ı gez
for (; RTA_OK(rta, attr_len); rta = RTA_NEXT(rta, attr_len)) {
switch (rta->rta_type) {
case IFLA_IFNAME:
std::cout << "Name: "
<< reinterpret_cast<char*>(RTA_DATA(rta)) << "\n";
break;
case IFLA_MTU:
std::cout << "MTU: "
<< *reinterpret_cast<uint32_t*>(RTA_DATA(rta)) << "\n";
break;
// ...burada daha fazla IFLA_* türünü işle...
}
}
}attr_len‘in iç for‘un dışında bildirildiğine ve RTA_NEXT tarafından yerinde değiştirildiğine dikkat et — bir döngü sayacı değil, attribute bloğundaki kalan baytları izler. Döngü header’ında bildirmek veya ikinci bir değişkene kopyalamak iterasyonu bozar.
Tipli payload’ları okuma
RTA_DATA(rta) void* döndürür; kernel’in o rta_type için belgelediği türe cast edersin. Link attribute’ları için yaygın durumlar:
rta_type | Payload türü | Notlar |
|---|---|---|
IFLA_IFNAME | char[] | NUL-sonlandırmalı arayüz adı |
IFLA_MTU | uint32_t | |
IFLA_ADDRESS | unsigned char[6] | L2 adresi; uzunluk RTA_PAYLOAD(rta) |
IFLA_OPERSTATE | uint8_t | IF_OPER_* değeri |
IFLA_STATS64 | struct rtnl_link_stats64 |
IFLA_ADDRESS gibi değişken uzunluklu payload’ları okumadan önce her zaman RTA_PAYLOAD(rta)‘yı kontrol et — uzunluk link türüne bağlıdır (Ethernet 6 bayt, ama diğer link katmanları farklıdır).
İç içe attribute’lar
Bazı attribute’lar (ör. IFLA_LINKINFO) kendileri konteynerdir: payload’ları başka bir rtattr dizisidir. RTA_DATA(rta)‘yı yeni bir attribute bloğunun başlangıcı, RTA_PAYLOAD(rta)‘yı da uzunluğu olarak değerlendirip recurslarsın:
case IFLA_LINKINFO: {
int sub_len = RTA_PAYLOAD(rta);
auto* sub = reinterpret_cast<struct rtattr*>(RTA_DATA(rta));
for (; RTA_OK(sub, sub_len); sub = RTA_NEXT(sub, sub_len)) {
if (sub->rta_type == IFLA_INFO_KIND)
std::cout << "Kind: "
<< reinterpret_cast<char*>(RTA_DATA(sub)) << "\n";
}
break;
}Aynı RTA_OK / RTA_NEXT çifti her iç içe seviyeyi yönetir — değişen yalnızca başlangıç pointer’ı ve uzunluktur.
Ayrıca bu deyimi kullanarak tüm link attribute’larını dump’layan tam bir program için rtnetlink API ile tüm ağ linklerini listeleme, fiziksel kablolu NIC’leri filtreleme için rtnetlink ile fiziksel ethernet linklerini filtreleme ve VLAN arayüzlerini filtreleme için rtnetlink ile VLAN arayüzlerini filtreleme yazılarına bak.