[libc-commits] [libc] [libc] Add if_nameindex and if_freenameindex as an experimental entrypoint (PR #208438)
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Tue Jul 14 13:46:08 PDT 2026
================
@@ -0,0 +1,148 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Internal templatized implementation of if_nameindex for Linux.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_NET_LINUX_IF_NAMEINDEX_H
+#define LLVM_LIBC_SRC_NET_LINUX_IF_NAMEINDEX_H
+
+#include "hdr/errno_macros.h"
+#include "hdr/net_if_macros.h"
+#include "hdr/sys_socket_macros.h"
+#include "hdr/types/socklen_t.h"
+#include "hdr/types/ssize_t.h"
+#include "hdr/types/struct_if_nameindex.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/CPP/span.h"
+#include "src/__support/alloc-checker.h"
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/string/memory_utils/inline_memcpy.h"
+#include "src/string/string_utils.h"
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+namespace LIBC_NAMESPACE_DECL {
+namespace net {
+
+template <typename Policy> ErrorOr<struct if_nameindex *> if_nameindex() {
+ ErrorOr<int> fd_or_err =
+ Policy::socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
+ if (!fd_or_err.has_value())
+ return Error(fd_or_err.error());
+ int fd = *fd_or_err;
+ cpp::scope_exit close_fd([fd]() { Policy::close(fd); });
+
+ struct {
+ struct nlmsghdr nlh;
+ struct ifinfomsg ifm;
+ } req = {};
+ static_assert(sizeof(req) >= NLMSG_LENGTH(sizeof(req.ifm)));
+ req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifm));
+ req.nlh.nlmsg_type = RTM_GETLINK;
+ req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ req.ifm.ifi_family = AF_UNSPEC;
+
+ ErrorOr<ssize_t> send_res =
+ Policy::sendto(fd, &req, req.nlh.nlmsg_len, 0, nullptr, 0);
+ if (!send_res.has_value())
+ return Error(send_res.error());
+
+ alignas(struct nlmsghdr) uint8_t buf[4096];
+ ErrorOr<ssize_t> recv_res =
+ Policy::recvfrom(fd, buf, sizeof(buf), 0, nullptr, nullptr);
+ if (!recv_res.has_value())
+ return Error(recv_res.error());
+
+ close_fd.release();
+ if (ErrorOr<int> close_res = Policy::close(fd); !close_res.has_value())
+ return Error(close_res.error());
+
+ // TODO: Read more than one message.
+ // TODO: Read more than one interface per message.
+ // TODO: Deduplicate interfaces to handle restarts.
+ auto len = static_cast<size_t>(*recv_res);
+ for (auto *nh = reinterpret_cast<struct nlmsghdr *>(buf); NLMSG_OK(nh, len);
+ nh = NLMSG_NEXT(nh, len)) {
+ if (nh->nlmsg_type == NLMSG_DONE)
+ break;
+ if (nh->nlmsg_type == NLMSG_ERROR) {
+ if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+ return Error(EINVAL);
+ auto *err = reinterpret_cast<struct nlmsgerr *>(NLMSG_DATA(nh));
+ if (err->error == 0) {
+ // Zero means an ACK, which we shouldn't get because we didn't ask for
+ // it...
+ continue;
+ }
+ return Error(-err->error);
+ }
+ if (nh->nlmsg_type != RTM_NEWLINK)
+ continue;
+ if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
+ continue;
+
+ auto *ifm = reinterpret_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
+ size_t attrlen = nh->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
+
+ cpp::span<uint8_t> ifm_payload(reinterpret_cast<uint8_t *>(ifm),
+ nh->nlmsg_len - NLMSG_LENGTH(0));
+ auto *rta = reinterpret_cast<struct rtattr *>(
+ ifm_payload.subspan(NLMSG_ALIGN(sizeof(struct ifinfomsg))).data());
+ for (; RTA_OK(rta, attrlen); rta = RTA_NEXT(rta, attrlen)) {
+ if (rta->rta_type == IFLA_IFNAME) {
----------------
michaelrj-google wrote:
given that everything inside the loop is also in this `if`, it would be cleaner to replace with
```suggestion
if (rta->rta_type != IFLA_IFNAME) {
continue;
}
...
```
https://github.com/llvm/llvm-project/pull/208438
More information about the libc-commits
mailing list