[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