diff options
author | Kristof Provost <kp@FreeBSD.org> | 2023-03-15 12:31:45 +0000 |
---|---|---|
committer | Kristof Provost <kp@FreeBSD.org> | 2023-03-20 13:37:09 +0000 |
commit | 137818006de5bb0be0b6562a0d601977f85c6867 (patch) | |
tree | 2ae84bcb3d05cc2abe8948317fec3f798a4b2499 | |
parent | 3afba490c1266200e9fd899f2494aa47f71c6095 (diff) | |
download | src-137818006de5.tar.gz src-137818006de5.zip |
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
-rw-r--r-- | lib/libifconfig/libifconfig.h | 2 | ||||
-rw-r--r-- | lib/libifconfig/libifconfig_carp.c | 7 | ||||
-rw-r--r-- | sbin/ifconfig/carp.c | 63 | ||||
-rw-r--r-- | sys/netinet/ip_carp.c | 117 | ||||
-rw-r--r-- | sys/netinet/ip_carp_nl.h | 2 | ||||
-rw-r--r-- | sys/netlink/netlink_message_parser.c | 25 | ||||
-rw-r--r-- | sys/netlink/netlink_message_parser.h | 4 | ||||
-rw-r--r-- | sys/netlink/netlink_message_writer.c | 14 | ||||
-rw-r--r-- | sys/netlink/netlink_message_writer.h | 7 | ||||
-rw-r--r-- | sys/netlink/netlink_snl.h | 1 | ||||
-rw-r--r-- | 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 |