git: 30d0fc6f3391 - main - netlink: export more IPv6 ifa info

From: Alexander V. Chernikov <melifaro_at_FreeBSD.org>
Date: Wed, 10 May 2023 09:57:51 UTC
The branch main has been updated by melifaro:

URL: https://cgit.FreeBSD.org/src/commit/?id=30d0fc6f339132990da7989bb102b01338b0d749

commit 30d0fc6f339132990da7989bb102b01338b0d749
Author:     Alexander V. Chernikov <melifaro@FreeBSD.org>
AuthorDate: 2023-05-10 08:52:31 +0000
Commit:     Alexander V. Chernikov <melifaro@FreeBSD.org>
CommitDate: 2023-05-10 09:57:01 +0000

    netlink: export more IPv6 ifa info
    
    * Fill in IFA_CACHEINFO with prefix lifetime data
    * Map IPv6 IN6_IFF_ flags to Netlink IFA_F_ flags
    * Store original ia6_flags in the FreeBSD-specific IFAF_FLAGS field
    
    MFC after:      2 weeks
---
 sys/netlink/netlink_snl_route_parsers.h |  4 ++
 sys/netlink/route/iface.c               | 68 ++++++++++++++++++++++++++++++++-
 sys/netlink/route/ifaddrs.h             |  9 +++--
 3 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/sys/netlink/netlink_snl_route_parsers.h b/sys/netlink/netlink_snl_route_parsers.h
index e50ad717e17f..a4877a4d7939 100644
--- a/sys/netlink/netlink_snl_route_parsers.h
+++ b/sys/netlink/netlink_snl_route_parsers.h
@@ -302,13 +302,16 @@ struct snl_parsed_addr {
 	struct sockaddr	*ifa_address;
 	struct sockaddr	*ifa_broadcast;
 	char		*ifa_label;
+	struct ifa_cacheinfo	*ifa_cacheinfo;
 	uint32_t	ifaf_vhid;
+	uint32_t	ifaf_flags;
 };
 
 #define	_IN(_field)	offsetof(struct ifaddrmsg, _field)
 #define	_OUT(_field)	offsetof(struct snl_parsed_addr, _field)
 static const struct snl_attr_parser _nla_p_addr_fbsd[] = {
 	{ .type = IFAF_VHID, .off = _OUT(ifaf_vhid), .cb = snl_attr_get_uint32 },
+	{ .type = IFAF_FLAGS, .off = _OUT(ifaf_flags), .cb = snl_attr_get_uint32 },
 };
 SNL_DECLARE_ATTR_PARSER(_addr_fbsd_parser, _nla_p_addr_fbsd);
 
@@ -317,6 +320,7 @@ static const struct snl_attr_parser _nla_p_addr_s[] = {
 	{ .type = IFA_LOCAL, .off = _OUT(ifa_local), .cb = snl_attr_get_ip },
 	{ .type = IFA_LABEL, .off = _OUT(ifa_label), .cb = snl_attr_dup_string },
 	{ .type = IFA_BROADCAST, .off = _OUT(ifa_broadcast), .cb = snl_attr_get_ip },
+	{ .type = IFA_CACHEINFO, .off = _OUT(ifa_cacheinfo), .cb = snl_attr_dup_struct },
 	{ .type = IFA_FREEBSD, .arg = &_addr_fbsd_parser, .cb = snl_attr_get_nested },
 };
 static const struct snl_field_parser _fp_p_addr_s[] = {
diff --git a/sys/netlink/route/iface.c b/sys/netlink/route/iface.c
index cc76410550f4..edcf8b635f50 100644
--- a/sys/netlink/route/iface.c
+++ b/sys/netlink/route/iface.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
 #include <net/route.h>
 #include <net/route/nhop.h>
 #include <net/route/route_ctl.h>
+#include <netinet6/in6_var.h>
 #include <netlink/netlink.h>
 #include <netlink/netlink_ctl.h>
 #include <netlink/netlink_route.h>
@@ -749,6 +750,52 @@ get_sa_plen(const struct sockaddr *sa)
         return (0);
 }
 
+#ifdef INET6
+static uint32_t
+in6_flags_to_nl(uint32_t flags)
+{
+	uint32_t nl_flags = 0;
+
+	if (flags & IN6_IFF_TEMPORARY)
+		nl_flags |= IFA_F_TEMPORARY;
+	if (flags & IN6_IFF_NODAD)
+		nl_flags |= IFA_F_NODAD;
+	if (flags & IN6_IFF_DEPRECATED)
+		nl_flags |= IFA_F_DEPRECATED;
+	if (flags & IN6_IFF_TENTATIVE)
+		nl_flags |= IFA_F_TENTATIVE;
+	if ((flags & (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) == 0)
+		flags |= IFA_F_PERMANENT;
+	if (flags & IN6_IFF_DUPLICATED)
+		flags |= IFA_F_DADFAILED;
+	return (nl_flags);
+}
+
+static void
+export_cache_info6(struct nl_writer *nw, const struct in6_ifaddr *ia)
+{
+	struct ifa_cacheinfo ci = {
+		.cstamp = ia->ia6_createtime * 1000,
+		.tstamp = ia->ia6_updatetime * 1000,
+		.ifa_prefered = ia->ia6_lifetime.ia6t_pltime,
+		.ifa_valid = ia->ia6_lifetime.ia6t_vltime,
+	};
+
+	nlattr_add(nw, IFA_CACHEINFO, sizeof(ci), &ci);
+}
+#endif
+
+static void
+export_cache_info(struct nl_writer *nw, struct ifaddr *ifa)
+{
+	switch (ifa->ifa_addr->sa_family) {
+#ifdef INET6
+	case AF_INET6:
+		export_cache_info6(nw, (struct in6_ifaddr *)ifa);
+		break;
+#endif
+	}
+}
 
 /*
  * {'attrs': [('IFA_ADDRESS', '12.0.0.1'),
@@ -796,8 +843,17 @@ dump_iface_addr(struct nl_writer *nw, struct ifnet *ifp, struct ifaddr *ifa,
 
         nlattr_add_string(nw, IFA_LABEL, if_name(ifp));
 
-        uint32_t val = 0; // ifa->ifa_flags;
-        nlattr_add_u32(nw, IFA_FLAGS, val);
+        uint32_t nl_ifa_flags = 0;
+#ifdef INET6
+	if (sa->sa_family == AF_INET6) {
+		struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
+		nl_ifa_flags = in6_flags_to_nl(ia->ia6_flags);
+	}
+#endif
+        nlattr_add_u32(nw, IFA_FLAGS, nl_ifa_flags);
+
+	export_cache_info(nw, ifa);
+
 	/* Store FreeBSD-specific attributes */
 	int off = nlattr_add_nested(nw, IFA_FREEBSD);
 	if (off != 0) {
@@ -805,6 +861,14 @@ dump_iface_addr(struct nl_writer *nw, struct ifnet *ifp, struct ifaddr *ifa,
 			uint32_t vhid  = (uint32_t)(*carp_get_vhid_p)(ifa);
 			nlattr_add_u32(nw, IFAF_VHID, vhid);
 		}
+#ifdef INET6
+		if (sa->sa_family == AF_INET6) {
+			uint32_t ifa_flags = ((struct in6_ifaddr *)ifa)->ia6_flags;
+
+			nlattr_add_u32(nw, IFAF_FLAGS, ifa_flags);
+		}
+#endif
+
 		nlattr_set_len(nw, off);
 	}
 
diff --git a/sys/netlink/route/ifaddrs.h b/sys/netlink/route/ifaddrs.h
index cbf23fe54197..4122e2c3793c 100644
--- a/sys/netlink/route/ifaddrs.h
+++ b/sys/netlink/route/ifaddrs.h
@@ -68,6 +68,7 @@ enum {
 enum {
 	IFAF_UNSPEC,
 	IFAF_VHID		= 1, /* u32: carp vhid */
+	IFAF_FLAGS		= 2, /* u32: FreeBSD-specific ifa flags */
 	__IFAF_MAX,
 };
 #define IFAF_MAX	(__IFAF_MAX - 1)
@@ -89,10 +90,10 @@ enum {
 
 /* IFA_CACHEINFO value */
 struct ifa_cacheinfo {
-	uint32_t ifa_prefered;
-	uint32_t ifa_valid;
-	uint32_t cstamp;
-	uint32_t tstamp;
+	uint32_t ifa_prefered;	/* seconds till the end of the prefix considered preferred */
+	uint32_t ifa_valid;	/* seconds till the end of the prefix considered valid */
+	uint32_t cstamp;	/* creation time in 1ms intervals from the boot time */
+	uint32_t tstamp;	/* update time in 1ms intervals from the boot time */
 };
 
 #endif