$NetBSD: patch-src_libs_zbxsysinfo_netbsd_net.c,v 1.2 2023/01/03 13:59:15 otis Exp $ Rework interface statistics code from using kvm to using sysctl interface. --- src/libs/zbxsysinfo/netbsd/net.c.orig 2023-01-02 20:56:14.314793522 +0000 +++ src/libs/zbxsysinfo/netbsd/net.c @@ -22,6 +22,9 @@ #include "zbxjson.h" #include "log.h" +#include +#include + static struct nlist kernel_symbols[] = { {"_ifnet", N_UNDF, 0, 0, 0}, @@ -31,42 +34,91 @@ static struct nlist kernel_symbols[] = #define IFNET_ID 0 +static void +get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) +{ + int i; + + for (i = 0; i < RTAX_MAX; i++) { + if (addrs & (1 << i)) { + rti_info[i] = sa; + sa = (struct sockaddr *)((char *)(sa) + + RT_ROUNDUP(sa->sa_len)); + } else + rti_info[i] = NULL; + } +} + static int get_ifdata(const char *if_name, zbx_uint64_t *ibytes, zbx_uint64_t *ipackets, zbx_uint64_t *ierrors, zbx_uint64_t *idropped, zbx_uint64_t *obytes, zbx_uint64_t *opackets, zbx_uint64_t *oerrors, zbx_uint64_t *tbytes, zbx_uint64_t *tpackets, zbx_uint64_t *terrors, zbx_uint64_t *icollisions, char **error) { - struct ifnet_head head; - struct ifnet *ifp; - struct ifnet v; + struct if_msghdr *ifm; + int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; + char *buf = NULL; + char *lim, *next; + struct rt_msghdr *rtm; + struct if_data *ifd = NULL; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + struct sockaddr_dl *sdl; - kvm_t *kp; + size_t len = 0; + size_t olen = 0; int ret = SYSINFO_RET_FAIL; + static char name[IFNAMSIZ]; + if (NULL == if_name || '\0' == *if_name) { *error = zbx_strdup(NULL, "Network interface name cannot be empty."); - return FAIL; + ret = FAIL; + goto out; } - - if (NULL == (kp = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL))) /* requires root privileges */ - { - *error = zbx_strdup(NULL, "Cannot obtain a descriptor to access kernel virtual memory."); - return FAIL; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) { + *error = zbx_strdup(NULL, "Failed to read network interfaces data"); + ret = FAIL; + goto out; } - if (N_UNDF == kernel_symbols[IFNET_ID].n_type) - if (0 != kvm_nlist(kp, &kernel_symbols[0])) - kernel_symbols[IFNET_ID].n_type = N_UNDF; - - if (N_UNDF != kernel_symbols[IFNET_ID].n_type) - { - int len = sizeof(struct ifnet_head); - - if (kvm_read(kp, kernel_symbols[IFNET_ID].n_value, &head, len) >= len) - { - len = sizeof(struct ifnet); + if (len > olen) { + free(buf); + if ((buf = zbx_malloc(NULL, len)) == NULL) { + *error = zbx_strdup(NULL, "Failed to allocate buffer for network interfaces data"); + ret = FAIL; + goto out; + } + olen = len; + } + if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) { + *error = zbx_strdup(NULL, "Failed to read network interfaces data"); + ret = FAIL; + goto out; + } + + lim = buf + len; + + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + if ((rtm->rtm_version == RTM_VERSION) && + (rtm->rtm_type == RTM_IFINFO)) { + ifm = (struct if_msghdr *)next; + ifd = &ifm->ifm_data; + + sa = (struct sockaddr *)(ifm + 1); + get_rtaddrs(ifm->ifm_addrs, sa, rti_info); + + sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; + if (sdl == NULL || sdl->sdl_family != AF_LINK) { + continue; + } + bzero(name, sizeof(name)); + if (sdl->sdl_nlen >= IFNAMSIZ) + memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); + else if (sdl->sdl_nlen > 0) + memcpy(name, sdl->sdl_data, sdl->sdl_nlen); /* if_ibytes; total number of octets received */ /* if_ipackets; packets received on interface */ @@ -100,42 +152,38 @@ static int get_ifdata(const char *if_nam if (icollisions) *icollisions = 0; - for (ifp = head.tqh_first; ifp; ifp = v.if_list.tqe_next) + if (0 == strcmp(if_name, name)) { - if (kvm_read(kp, (u_long)ifp, &v, len) < len) - break; - - if (0 == strcmp(if_name, v.if_xname)) - { - if (ibytes) - *ibytes += v.if_ibytes; - if (ipackets) - *ipackets += v.if_ipackets; - if (ierrors) - *ierrors += v.if_ierrors; - if (idropped) - *idropped += v.if_iqdrops; - if (obytes) - *obytes += v.if_obytes; - if (opackets) - *opackets += v.if_opackets; - if (oerrors) - *oerrors += v.if_oerrors; - if (tbytes) - *tbytes += v.if_ibytes + v.if_obytes; - if (tpackets) - *tpackets += v.if_ipackets + v.if_opackets; - if (terrors) - *terrors += v.if_ierrors + v.if_oerrors; - if (icollisions) - *icollisions += v.if_collisions; - ret = SYSINFO_RET_OK; - } + if (ibytes) + *ibytes += ifd->ifi_ibytes; + if (ipackets) + *ipackets += ifd->ifi_ipackets; + if (ierrors) + *ierrors += ifd->ifi_ierrors; + if (idropped) + *idropped += ifd->ifi_iqdrops; + if (obytes) + *obytes += ifd->ifi_obytes; + if (opackets) + *opackets += ifd->ifi_opackets; + if (oerrors) + *oerrors += ifd->ifi_oerrors; + if (tbytes) + *tbytes += ifd->ifi_ibytes + ifd->ifi_obytes; + if (tpackets) + *tpackets += ifd->ifi_ipackets + ifd->ifi_opackets; + if (terrors) + *terrors += ifd->ifi_ierrors + ifd->ifi_oerrors; + if (icollisions) + *icollisions += ifd->ifi_collisions; + ret = SYSINFO_RET_OK; + goto out; } } } - kvm_close(kp); +out: + free(buf); if (SYSINFO_RET_FAIL == ret) {