Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 20 Mar 2023 14:14:24 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 137818006de5 - main - carp: support unicast
Message-ID:  <202303201414.32KEEOgC039811@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=137818006de5bb0be0b6562a0d601977f85c6867

commit 137818006de5bb0be0b6562a0d601977f85c6867
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2023-03-15 12:31:45 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-03-20 13:37:09 +0000

    carp: support unicast
    
    Allow users to configure the address to send carp messages to. This
    allows carp to be used in unicast mode, which is useful in certain
    virtual configurations (e.g. AWS, VMWare ESXi, ...)
    
    Reviewed by:    melifaro
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D38940
---
 lib/libifconfig/libifconfig.h        |   2 +
 lib/libifconfig/libifconfig_carp.c   |   7 +++
 sbin/ifconfig/carp.c                 |  63 +++++++++++++++++++
 sys/netinet/ip_carp.c                | 117 ++++++++++++++++++++++++-----------
 sys/netinet/ip_carp_nl.h             |   2 +
 sys/netlink/netlink_message_parser.c |  25 ++++++++
 sys/netlink/netlink_message_parser.h |   4 ++
 sys/netlink/netlink_message_writer.c |  14 +++++
 sys/netlink/netlink_message_writer.h |   7 +++
 sys/netlink/netlink_snl.h            |   1 -
 sys/netlink/netlink_snl_route.h      |  23 +++++++
 11 files changed, 229 insertions(+), 36 deletions(-)

diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
index 64a61af0708c..861d2bc93f80 100644
--- a/lib/libifconfig/libifconfig.h
+++ b/lib/libifconfig/libifconfig.h
@@ -287,6 +287,8 @@ struct ifconfig_carp {
 	int32_t		carpr_advbase;
 	int32_t		carpr_advskew;
 	uint8_t		carpr_key[CARP_KEY_LEN];
+	struct in_addr	carpr_addr;
+	struct in6_addr	carpr_addr6;
 };
 
 int ifconfig_carp_get_vhid(ifconfig_handle_t *h, const char *name,
diff --git a/lib/libifconfig/libifconfig_carp.c b/lib/libifconfig/libifconfig_carp.c
index ffc497590aaa..5729362ffef9 100644
--- a/lib/libifconfig/libifconfig_carp.c
+++ b/lib/libifconfig/libifconfig_carp.c
@@ -39,6 +39,7 @@
 #include <netlink/netlink_generic.h>
 #include <netlink/netlink_snl.h>
 #include <netlink/netlink_snl_generic.h>
+#include <netlink/netlink_snl_route.h>
 
 #include <string.h>
 #include <strings.h>
@@ -55,6 +56,8 @@ static struct snl_attr_parser ap_carp_get[] = {
 	{ .type = CARP_NL_ADVBASE, .off = _OUT(carpr_advbase), .cb = snl_attr_get_int32 },
 	{ .type = CARP_NL_ADVSKEW, .off = _OUT(carpr_advskew), .cb = snl_attr_get_int32 },
 	{ .type = CARP_NL_KEY, .off = _OUT(carpr_key), .cb = snl_attr_get_string },
+	{ .type = CARP_NL_ADDR, .off = _OUT(carpr_addr), .cb = snl_attr_get_in_addr },
+	{ .type = CARP_NL_ADDR6, .off = _OUT(carpr_addr6), .cb = snl_attr_get_in6_addr },
 };
 #undef _OUT
 
@@ -181,6 +184,10 @@ ifconfig_carp_set_info(ifconfig_handle_t *h, const char *name,
 	snl_add_msg_attr_s32(&nw, CARP_NL_ADVBASE, carpr->carpr_advbase);
 	snl_add_msg_attr_s32(&nw, CARP_NL_ADVSKEW, carpr->carpr_advskew);
 	snl_add_msg_attr_u32(&nw, CARP_NL_IFINDEX, ifindex);
+	snl_add_msg_attr(&nw, CARP_NL_ADDR, sizeof(carpr->carpr_addr),
+	    &carpr->carpr_addr);
+	snl_add_msg_attr(&nw, CARP_NL_ADDR6, sizeof(carpr->carpr_addr6),
+	    &carpr->carpr_addr6);
 
 	hdr = snl_finalize_msg(&nw);
 	if (hdr == NULL) {
diff --git a/sbin/ifconfig/carp.c b/sbin/ifconfig/carp.c
index 3fa6f3ac269d..0dc3facdaf79 100644
--- a/sbin/ifconfig/carp.c
+++ b/sbin/ifconfig/carp.c
@@ -42,13 +42,17 @@
 #include <netinet/in_var.h>
 #include <netinet/ip_carp.h>
 
+#include <arpa/inet.h>
+
 #include <ctype.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <err.h>
 #include <errno.h>
+#include <netdb.h>
 
 #include <libifconfig.h>
 
@@ -67,12 +71,15 @@ static int carpr_vhid = -1;
 static int carpr_advskew = -1;
 static int carpr_advbase = -1;
 static int carpr_state = -1;
+static struct in_addr carp_addr;
+static struct in6_addr carp_addr6;
 static unsigned char const *carpr_key;
 
 static void
 carp_status(int s)
 {
 	struct ifconfig_carp carpr[CARP_MAXVHID];
+	char addr_buf[NI_MAXHOST];
 
 	if (ifconfig_carp_get_info(lifh, name, carpr, CARP_MAXVHID) == -1)
 		return;
@@ -85,6 +92,12 @@ carp_status(int s)
 			printf(" key \"%s\"\n", carpr[i].carpr_key);
 		else
 			printf("\n");
+
+		inet_ntop(AF_INET6, &carpr[i].carpr_addr6, addr_buf,
+		    sizeof(addr_buf));
+
+		printf("\t      peer %s peer6 %s\n",
+		    inet_ntoa(carpr[i].carpr_addr), addr_buf);
 	}
 }
 
@@ -146,6 +159,11 @@ setcarp_callback(int s, void *arg __unused)
 		carpr.carpr_advbase = carpr_advbase;
 	if (carpr_state > -1)
 		carpr.carpr_state = carpr_state;
+	if (carp_addr.s_addr != INADDR_ANY)
+		carpr.carpr_addr = carp_addr;
+	if (! IN6_IS_ADDR_UNSPECIFIED(&carp_addr6))
+		memcpy(&carpr.carpr_addr6, &carp_addr6,
+		    sizeof(carp_addr6));
 
 	if (ifconfig_carp_set_info(lifh, name, &carpr))
 		err(1, "SIOCSVH");
@@ -198,12 +216,53 @@ setcarp_state(const char *val, int d, int s, const struct afswtch *afp)
 	errx(1, "unknown state");
 }
 
+static void
+setcarp_peer(const char *val, int d, int s, const struct afswtch *afp)
+{
+	carp_addr.s_addr = inet_addr(val);
+}
+
+static void
+setcarp_mcast(const char *val, int d, int s, const struct afswtch *afp)
+{
+	carp_addr.s_addr = htonl(INADDR_CARP_GROUP);
+}
+
+static void
+setcarp_peer6(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct addrinfo hints, *res;
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_INET6;
+	hints.ai_flags = AI_NUMERICHOST;
+
+	if (getaddrinfo(val, NULL, &hints, &res) == 1)
+		errx(1, "Invalid IPv6 address %s", val);
+
+	memcpy(&carp_addr6, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
+	    sizeof(carp_addr6));
+}
+
+static void
+setcarp_mcast6(const char *val, int d, int s, const struct afswtch *afp)
+{
+	bzero(&carp_addr6, sizeof(carp_addr6));
+	carp_addr6.s6_addr[0] = 0xff;
+	carp_addr6.s6_addr[1] = 0x02;
+	carp_addr6.s6_addr[15] = 0x12;
+}
+
 static struct cmd carp_cmds[] = {
 	DEF_CMD_ARG("advbase",	setcarp_advbase),
 	DEF_CMD_ARG("advskew",	setcarp_advskew),
 	DEF_CMD_ARG("pass",	setcarp_passwd),
 	DEF_CMD_ARG("vhid",	setcarp_vhid),
 	DEF_CMD_ARG("state",	setcarp_state),
+	DEF_CMD_ARG("peer",	setcarp_peer),
+	DEF_CMD_ARG("mcast",	setcarp_mcast),
+	DEF_CMD_ARG("peer6",	setcarp_peer6),
+	DEF_CMD_ARG("mcast6",	setcarp_mcast6),
 };
 static struct afswtch af_carp = {
 	.af_name	= "af_carp",
@@ -216,6 +275,10 @@ carp_ctor(void)
 {
 	int i;
 
+	/* Default to multicast. */
+	setcarp_mcast(NULL, 0, 0, NULL);
+	setcarp_mcast6(NULL, 0, 0, NULL);
+
 	for (i = 0; i < nitems(carp_cmds);  i++)
 		cmd_register(&carp_cmds[i]);
 	af_register(&af_carp);
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index 78bc6d312abb..2219e00140b1 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -110,6 +110,8 @@ struct carp_softc {
 	int			sc_vhid;
 	int			sc_advskew;
 	int			sc_advbase;
+	struct in_addr		sc_carpaddr;
+	struct in6_addr		sc_carpaddr6;
 
 	int			sc_naddrs;
 	int			sc_naddrs6;
@@ -154,6 +156,20 @@ struct carp_if {
 #define	CIF_PROMISC	0x00000001
 };
 
+/* Kernel equivalent of struct carpreq, but with more fields for new features.
+ * */
+struct carpkreq {
+	int		carpr_count;
+	int		carpr_vhid;
+	int		carpr_state;
+	int		carpr_advskew;
+	int		carpr_advbase;
+	unsigned char	carpr_key[CARP_KEY_LEN];
+	/* Everything above this is identical to carpreq */
+	struct in_addr	carpr_addr;
+	struct in6_addr	carpr_addr6;
+};
+
 /*
  * Brief design of carp(4).
  *
@@ -310,7 +326,7 @@ SYSCTL_VNET_PCPUSTAT(_net_inet_carp, OID_AUTO, stats, struct carpstats,
         (((sc)->sc_advskew + V_carp_demotion < 0) ?		\
         0 : ((sc)->sc_advskew + V_carp_demotion)))
 
-static void	carp_input_c(struct mbuf *, struct carp_header *, sa_family_t);
+static void	carp_input_c(struct mbuf *, struct carp_header *, sa_family_t, int);
 static struct carp_softc
 		*carp_alloc(struct ifnet *);
 static void	carp_destroy(struct carp_softc *);
@@ -488,16 +504,6 @@ carp_input(struct mbuf **mp, int *offp, int proto)
 		return (IPPROTO_DONE);
 	}
 
-	/* verify that the IP TTL is 255.  */
-	if (ip->ip_ttl != CARP_DFLTTL) {
-		CARPSTATS_INC(carps_badttl);
-		CARP_DEBUG("%s: received ttl %d != 255 on %s\n", __func__,
-		    ip->ip_ttl,
-		    m->m_pkthdr.rcvif->if_xname);
-		m_freem(m);
-		return (IPPROTO_DONE);
-	}
-
 	iplen = ip->ip_hl << 2;
 
 	if (m->m_pkthdr.len < iplen + sizeof(*ch)) {
@@ -551,7 +557,7 @@ carp_input(struct mbuf **mp, int *offp, int proto)
 	}
 	m->m_data -= iplen;
 
-	carp_input_c(m, ch, AF_INET);
+	carp_input_c(m, ch, AF_INET, ip->ip_ttl);
 	return (IPPROTO_DONE);
 }
 #endif
@@ -581,15 +587,6 @@ carp6_input(struct mbuf **mp, int *offp, int proto)
 		return (IPPROTO_DONE);
 	}
 
-	/* verify that the IP TTL is 255 */
-	if (ip6->ip6_hlim != CARP_DFLTTL) {
-		CARPSTATS_INC(carps_badttl);
-		CARP_DEBUG("%s: received ttl %d != 255 on %s\n", __func__,
-		    ip6->ip6_hlim, m->m_pkthdr.rcvif->if_xname);
-		m_freem(m);
-		return (IPPROTO_DONE);
-	}
-
 	/* verify that we have a complete carp packet */
 	if (m->m_len < *offp + sizeof(*ch)) {
 		len = m->m_len;
@@ -599,6 +596,7 @@ carp6_input(struct mbuf **mp, int *offp, int proto)
 			CARP_DEBUG("%s: packet size %u too small\n", __func__, len);
 			return (IPPROTO_DONE);
 		}
+		ip6 = mtod(m, struct ip6_hdr *);
 	}
 	ch = (struct carp_header *)(mtod(m, char *) + *offp);
 
@@ -613,7 +611,7 @@ carp6_input(struct mbuf **mp, int *offp, int proto)
 	}
 	m->m_data -= *offp;
 
-	carp_input_c(m, ch, AF_INET6);
+	carp_input_c(m, ch, AF_INET6, ip6->ip6_hlim);
 	return (IPPROTO_DONE);
 }
 #endif /* INET6 */
@@ -664,7 +662,7 @@ carp_source_is_self(struct mbuf *m, struct ifaddr *ifa, sa_family_t af)
 }
 
 static void
-carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
+carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af, int ttl)
 {
 	struct ifnet *ifp = m->m_pkthdr.rcvif;
 	struct ifaddr *ifa, *match;
@@ -672,6 +670,7 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
 	uint64_t tmp_counter;
 	struct timeval sc_tv, ch_tv;
 	int error;
+	bool multicast = false;
 
 	NET_EPOCH_ASSERT();
 
@@ -724,8 +723,21 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
 
 	sc = ifa->ifa_carp;
 	CARP_LOCK(sc);
+	if (ifa->ifa_addr->sa_family == AF_INET) {
+		multicast = IN_MULTICAST(sc->sc_carpaddr.s_addr);
+	} else {
+		multicast = IN6_IS_ADDR_MULTICAST(&sc->sc_carpaddr6);
+	}
 	ifa_free(ifa);
 
+	/* verify that the IP TTL is 255, but only if we're not in unicast mode. */
+	if (multicast && ttl != CARP_DFLTTL) {
+		CARPSTATS_INC(carps_badttl);
+		CARP_DEBUG("%s: received ttl %d != 255 on %s\n", __func__,
+		    ttl, m->m_pkthdr.rcvif->if_xname);
+		goto out;
+	}
+
 	if (carp_hmac_verify(sc, ch->carp_counter, ch->carp_md)) {
 		CARPSTATS_INC(carps_badauth);
 		CARP_DEBUG("%s: incorrect hash for VHID %u@%s\n", __func__,
@@ -978,7 +990,8 @@ carp_send_ad_locked(struct carp_softc *sc)
 		m->m_pkthdr.rcvif = NULL;
 		m->m_len = len;
 		M_ALIGN(m, m->m_len);
-		m->m_flags |= M_MCAST;
+		if (IN_MULTICAST(sc->sc_carpaddr.s_addr))
+			m->m_flags |= M_MCAST;
 		ip = mtod(m, struct ip *);
 		ip->ip_v = IPVERSION;
 		ip->ip_hl = sizeof(*ip) >> 2;
@@ -997,7 +1010,7 @@ carp_send_ad_locked(struct carp_softc *sc)
 			ifa_free(ifa);
 		} else
 			ip->ip_src.s_addr = 0;
-		ip->ip_dst.s_addr = htonl(INADDR_CARP_GROUP);
+		ip->ip_dst = sc->sc_carpaddr;
 
 		ch_ptr = (struct carp_header *)(&ip[1]);
 		bcopy(&ch, ch_ptr, sizeof(ch));
@@ -1028,7 +1041,6 @@ carp_send_ad_locked(struct carp_softc *sc)
 		m->m_pkthdr.rcvif = NULL;
 		m->m_len = len;
 		M_ALIGN(m, m->m_len);
-		m->m_flags |= M_MCAST;
 		ip6 = mtod(m, struct ip6_hdr *);
 		bzero(ip6, sizeof(*ip6));
 		ip6->ip6_vfc |= IPV6_VERSION;
@@ -1050,12 +1062,13 @@ carp_send_ad_locked(struct carp_softc *sc)
 			bzero(&ip6->ip6_src, sizeof(struct in6_addr));
 
 		/* Set the multicast destination. */
-		ip6->ip6_dst.s6_addr16[0] = htons(0xff02);
-		ip6->ip6_dst.s6_addr8[15] = 0x12;
-		if (in6_setscope(&ip6->ip6_dst, sc->sc_carpdev, NULL) != 0) {
-			m_freem(m);
-			CARP_DEBUG("%s: in6_setscope failed\n", __func__);
-			goto resched;
+		memcpy(&ip6->ip6_dst, &sc->sc_carpaddr6, sizeof(ip6->ip6_dst));
+		if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
+			if (in6_setscope(&ip6->ip6_dst, sc->sc_carpdev, NULL) != 0) {
+				m_freem(m);
+				CARP_DEBUG("%s: in6_setscope failed\n", __func__);
+				goto resched;
+			}
 		}
 
 		ch_ptr = (struct carp_header *)(&ip6[1]);
@@ -1571,6 +1584,19 @@ carp_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa)
 
 	bcopy(mtag + 1, &sc, sizeof(sc));
 
+	switch (sa->sa_family) {
+	case AF_INET:
+		if (! IN_MULTICAST(sc->sc_carpaddr.s_addr))
+			return (0);
+		break;
+	case AF_INET6:
+		if (! IN6_IS_ADDR_MULTICAST(&sc->sc_carpaddr6))
+			return (0);
+		break;
+	default:
+		panic("Unknown af");
+	}
+
 	/* Set the source MAC address to the Virtual Router MAC Address. */
 	switch (ifp->if_type) {
 	case IFT_ETHER:
@@ -1618,6 +1644,10 @@ carp_alloc(struct ifnet *ifp)
 	sc->sc_ifas = malloc(sc->sc_ifasiz, M_CARP, M_WAITOK|M_ZERO);
 	sc->sc_carpdev = ifp;
 
+	sc->sc_carpaddr.s_addr = htonl(INADDR_CARP_GROUP);
+	sc->sc_carpaddr6.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
+	sc->sc_carpaddr6.s6_addr8[15] = 0x12;
+
 	CARP_LOCK_INIT(sc);
 #ifdef INET
 	callout_init_mtx(&sc->sc_md_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED);
@@ -1753,7 +1783,7 @@ carp_carprcp(void *arg, struct carp_softc *sc, int priv)
 }
 
 static int
-carp_ioctl_set(if_t ifp, struct carpreq *carpr)
+carp_ioctl_set(if_t ifp, struct carpkreq *carpr)
 {
 	struct epoch_tracker et;
 	struct carp_softc *sc = NULL;
@@ -1795,6 +1825,12 @@ carp_ioctl_set(if_t ifp, struct carpreq *carpr)
 		goto out;
 	}
 	sc->sc_advskew = carpr->carpr_advskew;
+	if (carpr->carpr_addr.s_addr != INADDR_ANY)
+		sc->sc_carpaddr = carpr->carpr_addr;
+	if (! IN6_IS_ADDR_UNSPECIFIED(&carpr->carpr_addr6)) {
+		memcpy(&sc->sc_carpaddr6, &carpr->carpr_addr6,
+		    sizeof(sc->sc_carpaddr6));
+	}
 	if (carpr->carpr_key[0] != '\0') {
 		bcopy(carpr->carpr_key, sc->sc_key, sizeof(sc->sc_key));
 		carp_hmac_prepare(sc);
@@ -1875,6 +1911,7 @@ int
 carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
 {
 	struct carpreq carpr;
+	struct carpkreq carprk = { };
 	struct ifnet *ifp;
 	int error = 0;
 
@@ -1896,7 +1933,8 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
 		if ((error = priv_check(td, PRIV_NETINET_CARP)))
 			break;
 
-		error = carp_ioctl_set(ifp, &carpr);
+		memcpy(&carprk, &carpr, sizeof(carpr));
+		error = carp_ioctl_set(ifp, &carprk);
 		break;
 
 	case SIOCGVH:
@@ -2243,6 +2281,8 @@ carp_nl_send(void *arg, struct carp_softc *sc, int priv)
 	nlattr_add_u32(nw, CARP_NL_STATE, sc->sc_state);
 	nlattr_add_s32(nw, CARP_NL_ADVBASE, sc->sc_advbase);
 	nlattr_add_s32(nw, CARP_NL_ADVSKEW, sc->sc_advskew);
+	nlattr_add_in_addr(nw, CARP_NL_ADDR, &sc->sc_carpaddr);
+	nlattr_add_in6_addr(nw, CARP_NL_ADDR6, &sc->sc_carpaddr6);
 
 	if (priv)
 		nlattr_add(nw, CARP_NL_KEY, sizeof(sc->sc_key), sc->sc_key);
@@ -2264,6 +2304,8 @@ struct nl_carp_parsed {
 	int32_t		advbase;
 	int32_t		advskew;
 	char		key[CARP_KEY_LEN];
+	struct in_addr	addr;
+	struct in6_addr	addr6;
 };
 
 #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
@@ -2276,6 +2318,8 @@ static const struct nlattr_parser nla_p_set[] = {
 	{ .type = CARP_NL_ADVSKEW, .off = _OUT(advskew), .cb = nlattr_get_uint32 },
 	{ .type = CARP_NL_KEY, .off = _OUT(key), .cb = nlattr_get_carp_key },
 	{ .type = CARP_NL_IFINDEX, .off = _OUT(ifindex), .cb = nlattr_get_uint32 },
+	{ .type = CARP_NL_ADDR, .off = _OUT(addr), .cb = nlattr_get_in_addr },
+	{ .type = CARP_NL_ADDR6, .off = _OUT(addr6), .cb = nlattr_get_in6_addr },
 };
 static const struct nlfield_parser nlf_p_set[] = {
 };
@@ -2331,7 +2375,7 @@ static int
 carp_nl_set(struct nlmsghdr *hdr, struct nl_pstate *npt)
 {
 	struct nl_carp_parsed attrs = { };
-	struct carpreq carpr;
+	struct carpkreq carpr;
 	struct epoch_tracker et;
 	if_t ifp;
 	int error;
@@ -2368,6 +2412,9 @@ carp_nl_set(struct nlmsghdr *hdr, struct nl_pstate *npt)
 	carpr.carpr_state = attrs.state;
 	carpr.carpr_advbase = attrs.advbase;
 	carpr.carpr_advskew = attrs.advskew;
+	carpr.carpr_addr = attrs.addr;
+	carpr.carpr_addr6 = attrs.addr6;
+
 	memcpy(&carpr.carpr_key, &attrs.key, sizeof(attrs.key));
 
 	sx_xlock(&carp_sx);
diff --git a/sys/netinet/ip_carp_nl.h b/sys/netinet/ip_carp_nl.h
index ffb7c1ef5aae..60e8c569a05d 100644
--- a/sys/netinet/ip_carp_nl.h
+++ b/sys/netinet/ip_carp_nl.h
@@ -29,6 +29,8 @@ enum carp_nl_type_t {
 	CARP_NL_ADVSKEW		= 4,	/* s32 */
 	CARP_NL_KEY		= 5,	/* byte array */
 	CARP_NL_IFINDEX		= 6,	/* u32 */
+	CARP_NL_ADDR		= 7,	/* in_addr_t */
+	CARP_NL_ADDR6		= 8,	/* in6_addr_t */
 };
 
 #endif
diff --git a/sys/netlink/netlink_message_parser.c b/sys/netlink/netlink_message_parser.c
index e30138266d9d..d0aaf4301872 100644
--- a/sys/netlink/netlink_message_parser.c
+++ b/sys/netlink/netlink_message_parser.c
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
 #include <net/route/nhop.h>
 
 #include <net/route/route_ctl.h>
+#include <netinet/in.h>
 #include <netlink/netlink.h>
 #include <netlink/netlink_ctl.h>
 #include <netlink/netlink_var.h>
@@ -349,6 +350,30 @@ nlattr_get_uint64(struct nlattr *nla, struct nl_pstate *npt, const void *arg, vo
 	return (0);
 }
 
+int
+nlattr_get_in_addr(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
+{
+	if (__predict_false(NLA_DATA_LEN(nla) != sizeof(in_addr_t))) {
+		NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not in_addr_t",
+		    nla->nla_type, NLA_DATA_LEN(nla));
+		return (EINVAL);
+	}
+	memcpy(target, NLA_DATA_CONST(nla), sizeof(in_addr_t));
+	return (0);
+}
+
+int
+nlattr_get_in6_addr(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
+{
+	if (__predict_false(NLA_DATA_LEN(nla) != sizeof(struct in6_addr))) {
+		NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not struct in6_addr",
+		    nla->nla_type, NLA_DATA_LEN(nla));
+		return (EINVAL);
+	}
+	memcpy(target, NLA_DATA_CONST(nla), sizeof(struct in6_addr));
+	return (0);
+}
+
 static int
 nlattr_get_ifp_internal(struct nlattr *nla, struct nl_pstate *npt,
     void *target, bool zero_ok)
diff --git a/sys/netlink/netlink_message_parser.h b/sys/netlink/netlink_message_parser.h
index 083c93dcbf8d..067d25dae7d8 100644
--- a/sys/netlink/netlink_message_parser.h
+++ b/sys/netlink/netlink_message_parser.h
@@ -175,6 +175,10 @@ int nlattr_get_uint32(struct nlattr *nla, struct nl_pstate *npt,
     const void *arg, void *target);
 int nlattr_get_uint64(struct nlattr *nla, struct nl_pstate *npt,
     const void *arg, void *target);
+int nlattr_get_in_addr(struct nlattr *nla, struct nl_pstate *npt,
+    const void *arg, void *target);
+int nlattr_get_in6_addr(struct nlattr *nla, struct nl_pstate *npt,
+    const void *arg, void *target);
 int nlattr_get_ifp(struct nlattr *nla, struct nl_pstate *npt,
     const void *arg, void *target);
 int nlattr_get_ifpz(struct nlattr *nla, struct nl_pstate *npt,
diff --git a/sys/netlink/netlink_message_writer.c b/sys/netlink/netlink_message_writer.c
index 8a9315eedd1b..85cf5695643c 100644
--- a/sys/netlink/netlink_message_writer.c
+++ b/sys/netlink/netlink_message_writer.c
@@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/socketvar.h>
 #include <sys/syslog.h>
 
+#include <netinet/in.h>
+
 #include <netlink/netlink.h>
 #include <netlink/netlink_ctl.h>
 #include <netlink/netlink_linux.h>
@@ -686,3 +688,15 @@ nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr)
 
 	return (true);
 }
+
+bool
+nlattr_add_in_addr(struct nl_writer *nw, int attrtype, const struct in_addr *in)
+{
+	return (nlattr_add(nw, attrtype, sizeof(*in), in));
+}
+
+bool
+nlattr_add_in6_addr(struct nl_writer *nw, int attrtype, const struct in6_addr *in6)
+{
+	return (nlattr_add(nw, attrtype, sizeof(*in6), in6));
+}
diff --git a/sys/netlink/netlink_message_writer.h b/sys/netlink/netlink_message_writer.h
index 13acf5add559..2f007e9a2b14 100644
--- a/sys/netlink/netlink_message_writer.h
+++ b/sys/netlink/netlink_message_writer.h
@@ -30,6 +30,7 @@
 #define _NETLINK_NETLINK_MESSAGE_WRITER_H_
 
 #ifdef _KERNEL
+
 /*
  * It is not meant to be included directly
  */
@@ -248,6 +249,12 @@ nlattr_add_s64(struct nl_writer *nw, int attrtype, int64_t value)
 	return (nlattr_add(nw, attrtype, sizeof(int64_t), &value));
 }
 
+struct in_addr;
+bool nlattr_add_in_addr(struct nl_writer *nw, int attrtype, const struct in_addr *in);
+
+struct in6_addr;
+bool nlattr_add_in6_addr(struct nl_writer *nw, int attrtype, const struct in6_addr *in6);
+
 static inline bool
 nlattr_add_flag(struct nl_writer *nw, int attrtype)
 {
diff --git a/sys/netlink/netlink_snl.h b/sys/netlink/netlink_snl.h
index 935012885362..399e1d6781c8 100644
--- a/sys/netlink/netlink_snl.h
+++ b/sys/netlink/netlink_snl.h
@@ -44,7 +44,6 @@
 #include <sys/socket.h>
 #include <netlink/netlink.h>
 
-
 #define _roundup2(x, y)         (((x)+((y)-1))&(~((y)-1)))
 
 #define NETLINK_ALIGN_SIZE      sizeof(uint32_t)
diff --git a/sys/netlink/netlink_snl_route.h b/sys/netlink/netlink_snl_route.h
index e67bffde215e..3a80854c947c 100644
--- a/sys/netlink/netlink_snl_route.h
+++ b/sys/netlink/netlink_snl_route.h
@@ -163,4 +163,27 @@ snl_add_msg_attr_ipvia(struct snl_writer *nw, int attrtype, const struct sockadd
 	return (false);
 }
 
+static inline bool
+snl_attr_get_in_addr(struct snl_state *ss __unused, struct nlattr *nla,
+    const void *arg __unused, void *target)
+{
+	if (NLA_DATA_LEN(nla) != sizeof(struct in_addr))
+		return (false);
+
+	memcpy(target, NLA_DATA_CONST(nla), sizeof(struct in_addr));
+	return (true);
+}
+
+static inline bool
+snl_attr_get_in6_addr(struct snl_state *ss __unused, struct nlattr *nla,
+    const void *arg __unused, void *target)
+{
+	if (NLA_DATA_LEN(nla) != sizeof(struct in6_addr))
+		return (false);
+
+	memcpy(target, NLA_DATA_CONST(nla), sizeof(struct in6_addr));
+	return (true);
+}
+
+
 #endif



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202303201414.32KEEOgC039811>