linux arpの内部データ
arpの統計情報が欲しかったのでnetlink経由で取得するものを作った NDTA_PARMSはrtattrが入れ子になっている。
#include <asm/types.h> #include <sys/socket.h> #include <linux/netlink.h> #include <linux/neighbour.h> #include <linux/rtnetlink.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <stdint.h> static int seq; void msg_receive(int sock) { char buf[4096]; int n = read(sock, buf, sizeof(buf)); if ( n <= 0 ) { perror("read error\n"); exit(1); } struct nlmsghdr *nh = (struct nlmsghdr *)buf; // printf("read size: %d\n", n); if ( nh->nlmsg_seq != seq ) { printf("seq error\n"); exit(1); } if ( nh->nlmsg_type == NLMSG_ERROR ) { printf("error\n"); exit(1); } else if ( nh->nlmsg_type == RTM_NEWNEIGHTBL ) { NLMSG_ALIGN(nh->nlmsg_len); struct ndtmsg *ndtm = NLMSG_DATA(nh); if ( ndtm->ndtm_family != AF_INET ) { printf("ndgm_family is not AF_INET\n"); exit(1); } struct rtattr *rta; int len = nh->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndtmsg)); for (rta = (struct rtattr*)((char *)ndtm + sizeof(struct ndtmsg)); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { switch(rta->rta_type) { case NDTA_NAME: printf("NAME: %s\n", (char*)RTA_DATA(rta)); break; case NDTA_THRESH1: printf("THRESH1 %d\n", *(uint32_t*)RTA_DATA(rta)); break; case NDTA_THRESH2: printf("THRESH2 %d\n", *(uint32_t*)RTA_DATA(rta)); break; case NDTA_THRESH3: printf("THRESH3 %d\n", *(uint32_t*)RTA_DATA(rta)); break; case NDTA_CONFIG: { struct ndt_config *config = (struct ndt_config*)RTA_DATA(rta); printf("CONFIG:\n"); printf("\tkey_len: %d\n", config->ndtc_key_len); printf("\tentry_size: %d\n", config->ndtc_entry_size); printf("\tentries: %d\n", config->ndtc_entries); printf("\tlast_flush: %d\n", config->ndtc_last_flush); printf("\tlast_rand: %d\n", config->ndtc_last_rand); printf("\thash_rnd: %d\n", config->ndtc_hash_rnd); printf("\thash_mask: %d\n", config->ndtc_hash_mask); printf("\thash_chain_gc: %d\n", config->ndtc_hash_chain_gc); printf("\tproxy_qlen: %d\n", config->ndtc_proxy_qlen); } break; case NDTA_PARMS: { printf("PARAMS:\n"); struct rtattr *parm_rta; int parm_len = rta->rta_len; for (parm_rta = rta + 1; RTA_OK(parm_rta, parm_len); parm_rta = RTA_NEXT(parm_rta, parm_len)) { switch(parm_rta->rta_type) { case NDTPA_IFINDEX: printf("\tifindex: %d\n", *(uint32_t*)RTA_DATA(parm_rta)); break; case NDTPA_REFCNT: printf("\trefcnt: %d\n", *(uint32_t*)RTA_DATA(parm_rta)); break; case NDTPA_REACHABLE_TIME: printf("\treachable_time: %lld\n", *(uint64_t*)RTA_DATA(parm_rta)); break; case NDTPA_BASE_REACHABLE_TIME: printf("\tbase_reachable_time: %lld\n", *(uint64_t*)RTA_DATA(parm_rta)); break; case NDTPA_RETRANS_TIME: printf("\tretrans_time: %lld\n", *(uint64_t*)RTA_DATA(parm_rta)); break; case NDTPA_GC_STALETIME: printf("\tgc_staletime: %lld\n", *(uint64_t*)RTA_DATA(parm_rta)); break; case NDTPA_DELAY_PROBE_TIME: printf("\tdelay_probe_time: %lld\n", *(uint64_t*)RTA_DATA(parm_rta)); break; case NDTPA_QUEUE_LEN: printf("\tqueue_len: %d\n", *(uint32_t*)RTA_DATA(parm_rta)); break; case NDTPA_APP_PROBES: printf("\tapp_probes: %d\n", *(uint32_t*)RTA_DATA(parm_rta)); break; case NDTPA_UCAST_PROBES: printf("\tucast_probes: %d\n", *(uint32_t*)RTA_DATA(parm_rta)); break; case NDTPA_MCAST_PROBES: printf("\tmcast_probes: %d\n", *(uint32_t*)RTA_DATA(parm_rta)); break; case NDTPA_ANYCAST_DELAY: printf("\tanycast_delay: %lld\n", *(uint64_t*)RTA_DATA(parm_rta)); break; case NDTPA_PROXY_DELAY: printf("\tproxy_delay: %d\n", *(uint64_t*)RTA_DATA(parm_rta)); break; case NDTPA_PROXY_QLEN: printf("\tproxy_qlen: %d\n", *(uint32_t*)RTA_DATA(parm_rta)); break; case NDTPA_LOCKTIME: printf("\tlocktime: %d\n", *(uint64_t*)RTA_DATA(parm_rta)); break; } } } break; case NDTA_STATS: { struct ndt_stats *stats = (struct ndt_stats*)RTA_DATA(rta); printf("STATS:\n"); printf("\tallocs: %d\n", stats->ndts_allocs); printf("\tdestorys: %d\n", stats->ndts_destroys); printf("\tgrow: %d\n", stats->ndts_hash_grows); printf("\tres_failed: %d\n", stats->ndts_res_failed); printf("\tlookups %d\n", stats->ndts_lookups); printf("\thits: %d\n", stats->ndts_hits); printf("\trcv_probes_mcast: %d\n", stats->ndts_rcv_probes_mcast); printf("\trcv_probes_ucast: %d\n", stats->ndts_rcv_probes_ucast); printf("\tperiodic_gc_runs: %d\n", stats->ndts_periodic_gc_runs); printf("\tforced_gc_runs: %d\n", stats->ndts_forced_gc_runs); } break; case NDTA_GC_INTERVAL: printf("GC_INTERVAL %lld\n", *(uint64_t*)RTA_DATA(rta)); break; } } } } void main() { srand(time(NULL)); seq = rand(); int sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); if ( sock == -1 ) { perror("sock error\n"); exit(1); } struct { struct nlmsghdr nh; struct rtgenmsg rt; } h; struct sockaddr_nl nl; memset(&nl, 0, sizeof(nl)); nl.nl_family = AF_NETLINK; if ( bind(sock, (struct sockaddr*)&nl, sizeof(nl)) == -1 ) { perror("bind error\n"); exit(1); } memset(&h, 0, sizeof(h)); h.nh.nlmsg_type = RTM_GETNEIGHTBL; h.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; h.nh.nlmsg_len = NLMSG_LENGTH(sizeof(h.rt)); h.nh.nlmsg_seq = seq; h.rt.rtgen_family = AF_INET; int n = write(sock, &h, sizeof(h)); if ( n <= 0 ) { perror("write error\n"); exit(1); } msg_receive(sock); }
出力はこんな感じ
NAME: arp_cache GC_INTERVAL 10000 THRESH1 128 THRESH2 512 THRESH3 1024 CONFIG: key_len: 4 entry_size: 260 entries: 3 last_flush: 27997298 last_rand: 63783 hash_rnd: 398501669 hash_mask: 7 hash_chain_gc: 0 proxy_qlen: 0 STATS: allocs: 49 destorys: 46 grow: 0 res_failed: 25 lookups 61661 hits: 48360 rcv_probes_mcast: 0 rcv_probes_ucast: 0 periodic_gc_runs: 2274 forced_gc_runs: 0 PARAMS: refcnt: 1 queue_len: 3 proxy_qlen: 64 app_probes: 0 ucast_probes: 3 mcast_probes: 3 reachable_time: 18336 base_reachable_time: 20000 gc_staletime: 60000 delay_probe_time: 5000 retrans_time: 1000 anycast_delay: 1000 proxy_delay: 800 locktime: 1000