Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F115821616
D38940.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
17 KB
Referenced Files
None
Subscribers
None
D38940.diff
View Options
diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
--- a/lib/libifconfig/libifconfig.h
+++ b/lib/libifconfig/libifconfig.h
@@ -287,6 +287,8 @@
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
--- 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 @@
{ .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 @@
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
--- 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_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 @@
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 @@
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 @@
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 @@
{
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
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -110,6 +110,8 @@
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 @@
#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 @@
(((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 @@
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
uint64_t tmp_counter;
struct timeval sc_tv, ch_tv;
int error;
+ bool multicast = false;
NET_EPOCH_ASSERT();
@@ -724,8 +723,21 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{ .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 @@
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 @@
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
--- a/sys/netinet/ip_carp_nl.h
+++ b/sys/netinet/ip_carp_nl.h
@@ -29,6 +29,8 @@
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.h b/sys/netlink/netlink_message_parser.h
--- a/sys/netlink/netlink_message_parser.h
+++ b/sys/netlink/netlink_message_parser.h
@@ -175,6 +175,10 @@
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_parser.c b/sys/netlink/netlink_message_parser.c
--- a/sys/netlink/netlink_message_parser.c
+++ b/sys/netlink/netlink_message_parser.c
@@ -41,6 +41,7 @@
#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 @@
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_writer.h b/sys/netlink/netlink_message_writer.h
--- 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 @@
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_message_writer.c b/sys/netlink/netlink_message_writer.c
--- a/sys/netlink/netlink_message_writer.c
+++ b/sys/netlink/netlink_message_writer.c
@@ -37,6 +37,8 @@
#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 @@
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_snl.h b/sys/netlink/netlink_snl.h
--- 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
--- a/sys/netlink/netlink_snl_route.h
+++ b/sys/netlink/netlink_snl_route.h
@@ -163,4 +163,27 @@
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
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Apr 30, 3:48 AM (12 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17851007
Default Alt Text
D38940.diff (17 KB)
Attached To
Mode
D38940: carp: support unicast
Attached
Detach File
Event Timeline
Log In to Comment