git: 94ed4c1903cf - main - libifconfig: Add netlink based helper to bring the interface up/down

From: Aymeric Wibo <obiwac_at_FreeBSD.org>
Date: Fri, 29 Aug 2025 15:40:24 UTC
The branch main has been updated by obiwac:

URL: https://cgit.FreeBSD.org/src/commit/?id=94ed4c1903cf846a3f484373b8aae136762e9d09

commit 94ed4c1903cf846a3f484373b8aae136762e9d09
Author:     Muhammad Saheed <saheed@FreeBSD.org>
AuthorDate: 2025-08-29 15:36:10 +0000
Commit:     Aymeric Wibo <obiwac@FreeBSD.org>
CommitDate: 2025-08-29 15:39:39 +0000

    libifconfig: Add netlink based helper to bring the interface up/down
    
    Adds `ifconfig_set_up()` to set and unset the `IFF_UP`
    on a network interface using `RTM_NEWLINK`.
    
    Sponsored by:   Google LLC (GSoC)
    Reviewed by:    obiwac, mckusick (mentor), kp
    Approved by:    obiwac, mckusick (mentor), kp
    Differential Revision:  https://reviews.freebsd.org/D52128
---
 lib/libifconfig/Makefile         |  1 +
 lib/libifconfig/libifconfig.h    | 11 ++++++
 lib/libifconfig/libifconfig_nl.c | 72 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)

diff --git a/lib/libifconfig/Makefile b/lib/libifconfig/Makefile
index fb7c659e068c..02629eb88f25 100644
--- a/lib/libifconfig/Makefile
+++ b/lib/libifconfig/Makefile
@@ -17,6 +17,7 @@ SRCS=		libifconfig.c \
 		libifconfig_internal.c \
 		libifconfig_lagg.c \
 		libifconfig_media.c \
+		libifconfig_nl.c \
 		libifconfig_sfp.c
 
 GEN=		libifconfig_sfp_tables.h \
diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
index a5ce7b375830..817f52bd094e 100644
--- a/lib/libifconfig/libifconfig.h
+++ b/lib/libifconfig/libifconfig.h
@@ -35,6 +35,8 @@
 #include <netinet/ip_carp.h>
 #include <netinet6/in6_var.h>
 
+#include <stdbool.h>
+
 #define ND6_IFF_DEFAULTIF    0x8000
 
 typedef enum {
@@ -381,3 +383,12 @@ int ifconfig_set_vlantag(ifconfig_handle_t *h, const char *name,
  * 		length of *lenp * IFNAMSIZ bytes.
  */
 int ifconfig_list_cloners(ifconfig_handle_t *h, char **bufp, size_t *lenp);
+
+/** Brings the interface up/down
+ * @param h	    An open ifconfig state object
+ * @param ifname    The interface name
+ * @param up	    true to bring the interface up, false to bring it down
+ * @return	    0 on success, nonzero on failure.
+ *		    On failure, the error info on the handle is set.
+ */
+int ifconfig_set_up(ifconfig_handle_t *h, const char *ifname, bool up);
diff --git a/lib/libifconfig/libifconfig_nl.c b/lib/libifconfig/libifconfig_nl.c
new file mode 100644
index 000000000000..7d9decabe26f
--- /dev/null
+++ b/lib/libifconfig/libifconfig_nl.c
@@ -0,0 +1,72 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025, Muhammad Saheed <saheed@FreeBSD.org>
+ */
+
+#include <netlink/netlink.h>
+#include <netlink/netlink_snl.h>
+#include <netlink/route/common.h>
+#include <netlink/route/interface.h>
+
+#include "libifconfig.h"
+#include "libifconfig_internal.h"
+
+static int ifconfig_modify_flags(ifconfig_handle_t *h, const char *ifname,
+    int ifi_flags, int ifi_change);
+
+static int
+ifconfig_modify_flags(ifconfig_handle_t *h, const char *ifname, int ifi_flags,
+    int ifi_change)
+{
+	int ret = 0;
+	struct snl_state ss;
+	struct snl_writer nw;
+	struct nlmsghdr *hdr;
+	struct ifinfomsg *ifi;
+	struct snl_errmsg_data e = { 0 };
+
+	if (!snl_init(&ss, NETLINK_ROUTE)) {
+		ifconfig_error(h, NETLINK, ENOTSUP);
+		return (-1);
+	}
+
+	snl_init_writer(&ss, &nw);
+	hdr = snl_create_msg_request(&nw, NL_RTM_NEWLINK);
+	ifi = snl_reserve_msg_object(&nw, struct ifinfomsg);
+	snl_add_msg_attr_string(&nw, IFLA_IFNAME, ifname);
+
+	ifi->ifi_flags = ifi_flags;
+	ifi->ifi_change = ifi_change;
+
+	hdr = snl_finalize_msg(&nw);
+	if (hdr == NULL) {
+		ifconfig_error(h, NETLINK, ENOMEM);
+		ret = -1;
+		goto out;
+	}
+
+	if (!snl_send_message(&ss, hdr)) {
+		ifconfig_error(h, NETLINK, EIO);
+		ret = -1;
+		goto out;
+	}
+
+	if (!snl_read_reply_code(&ss, hdr->nlmsg_seq, &e)) {
+		ifconfig_error(h, NETLINK, e.error);
+		ret = -1;
+		goto out;
+	}
+
+out:
+	snl_free(&ss);
+	return (ret);
+}
+
+int
+ifconfig_set_up(ifconfig_handle_t *h, const char *ifname, bool up)
+{
+	int flag = up ? IFF_UP : ~IFF_UP;
+
+	return (ifconfig_modify_flags(h, ifname, flag, IFF_UP));
+}