[libc-commits] [libc] [libc] Add if_nameindex and if_freenameindex as an experimental entrypoint (PR #208438)
Jeff Bailey via libc-commits
libc-commits at lists.llvm.org
Fri Jul 24 07:42:09 PDT 2026
================
@@ -0,0 +1,164 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_IMPL_H
+#define LLVM_LIBC_SRC_NET_LINUX_IF_NAMEINDEX_IMPL_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 {
+
+namespace detail {
+/// Sends a RTM_GETLINK dump request packet on the given socket. The kernel will
+/// respond with one or more messages containing the list of network interfaces
+/// and their attributes.
+template <typename Policy>
+ErrorOr<ssize_t> send_netlink_dump_request(int sockfd) {
+ // The message consists of a standard netlink header followed by the
+ // RTM_GETLINK payload.
+ 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;
+
+ return Policy::sendto(sockfd, &req, req.nlh.nlmsg_len, 0, nullptr, 0);
+}
+
+/// A reasonable buffer size for netlink messages (see NLMSG_GOODSIZE in the
+/// kernel).
+constexpr size_t NLMSG_BUFFER_SIZE = 8192;
+} // namespace detail
+
+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); });
+
+ ErrorOr<ssize_t> send_res = detail::send_netlink_dump_request<Policy>(fd);
+ if (!send_res.has_value())
+ return Error(send_res.error());
+
+ // TODO: Figure out if we need to dynamically allocate a buffer.
+ alignas(struct nlmsghdr) uint8_t buf[detail::NLMSG_BUFFER_SIZE];
+ 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),
----------------
kaladron wrote:
Is <linux/if_link.h> includable in this? If yes, you could replace the span and rta definition with IFLA_RTA(ifm) since it's provided for us.
https://github.com/llvm/llvm-project/pull/208438
More information about the libc-commits
mailing list