/*
- * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/domain.h>
+#include <sys/stat.h>
+#include <sys/ubc.h>
+#include <sys/vnode.h>
#include <sys/syslog.h>
#include <sys/queue.h>
#include <sys/mcache.h>
#include <sys/protosw.h>
#include <sys/kernel.h>
-#include <kern/lock.h>
+#include <kern/locks.h>
#include <kern/zalloc.h>
#include <net/dlil.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
-#include <netinet/ip_mroute.h>
#include <netinet/ip_var.h>
#include <netinet/ip6.h>
#define RTD_INUSE 0xFEEDFACE /* entry is in use */
#define RTD_FREED 0xDEADBEEF /* entry is freed */
+#define MAX_SCOPE_ADDR_STR_LEN (MAX_IPv6_STR_LEN + 6)
+
/* For gdb */
__private_extern__ unsigned int ctrace_stack_size = CTRACE_STACK_SIZE;
__private_extern__ unsigned int ctrace_hist_size = CTRACE_HIST_SIZE;
static inline void rte_free_debug(struct rtentry *);
static inline void rte_lock_debug(struct rtentry_dbg *);
static inline void rte_unlock_debug(struct rtentry_dbg *);
-static void rt_maskedcopy(struct sockaddr *,
- struct sockaddr *, struct sockaddr *);
+static void rt_maskedcopy(const struct sockaddr *,
+ struct sockaddr *, const struct sockaddr *);
static void rtable_init(void **);
static inline void rtref_audit(struct rtentry_dbg *);
static inline void rtunref_audit(struct rtentry_dbg *);
static inline void sin6_set_ifscope(struct sockaddr *, unsigned int);
static inline void sin6_set_embedded_ifscope(struct sockaddr *, unsigned int);
static inline unsigned int sin6_get_embedded_ifscope(struct sockaddr *);
-static struct sockaddr *sa_copy(struct sockaddr *, struct sockaddr_storage *,
- unsigned int *);
static struct sockaddr *ma_copy(int, struct sockaddr *,
struct sockaddr_storage *, unsigned int);
static struct sockaddr *sa_trim(struct sockaddr *, int);
#define ASSERT_SIN6IFSCOPE(sa) { \
if ((sa)->sa_family != AF_INET6 || \
(sa)->sa_len < sizeof (struct sockaddr_in6)) \
- panic("%s: bad sockaddr_in %p\n", __func__, sa); \
+ panic("%s: bad sockaddr_in6 %p\n", __func__, sa); \
}
/*
#define RN(r) ((struct radix_node *)r)
#define RT_HOST(r) (RT(r)->rt_flags & RTF_HOST)
+unsigned int rt_verbose = 0;
+#if (DEVELOPMENT || DEBUG)
SYSCTL_DECL(_net_route);
-
-unsigned int rt_verbose; /* verbosity level (0 to disable) */
SYSCTL_UINT(_net_route, OID_AUTO, verbose, CTLFLAG_RW | CTLFLAG_LOCKED,
&rt_verbose, 0, "");
+#endif /* (DEVELOPMENT || DEBUG) */
static void
rtable_init(void **table)
* In any case, the effective scope ID value is returned to the caller via
* pifscope, if it is non-NULL.
*/
-static struct sockaddr *
+struct sockaddr *
sa_copy(struct sockaddr *src, struct sockaddr_storage *dst,
unsigned int *pifscope)
{
eifscope = sin6_get_embedded_ifscope(SA(dst));
if (eifscope != IFSCOPE_NONE && ifscope == IFSCOPE_NONE)
ifscope = eifscope;
- sin6_set_ifscope(SA(dst), ifscope);
+ if (ifscope != IFSCOPE_NONE) {
+ /* Set ifscope from pifscope or eifscope */
+ sin6_set_ifscope(SA(dst), ifscope);
+ } else {
+ /* If sin6_scope_id has a value, use that one */
+ ifscope = sin6_get_ifscope(SA(dst));
+ }
/*
* If sin6_scope_id is set but the address doesn't
* contain the equivalent embedded value, set it.
*/
struct sockaddr *
rtm_scrub(int type, int idx, struct sockaddr *hint, struct sockaddr *sa,
- void *buf, uint32_t buflen, kauth_cred_t *credp)
+ void *buf, uint32_t buflen, kauth_cred_t *credp, uint32_t rtm_hint_flags)
{
struct sockaddr_storage *ss = (struct sockaddr_storage *)buf;
struct sockaddr *ret = sa;
}
break;
}
+ case RTAX_GATEWAY: {
+ /*
+ * Break if the gateway is not AF_LINK type (indirect routes)
+ *
+ * Else, if is, check if it is resolved. If not yet resolved
+ * simply break else scrub the link layer address.
+ */
+ if ((sa->sa_family != AF_LINK) || (SDL(sa)->sdl_alen == 0))
+ break;
+ /* fallthrough */
+ }
case RTAX_IFP: {
- if (sa->sa_family == AF_LINK && credp) {
+ if (sa->sa_family == AF_LINK && credp &&
+ (rtm_hint_flags & RTMF_HIDE_LLADDR)) {
struct sockaddr_dl *sdl = SDL(buf);
const void *bytes;
size_t size;
return (rtalloc1_common_locked(dst, report, ignflags, ifscope));
}
-/*
- * Look up the route that matches the address given
- * Or, at least try.. Create a cloned route if needed.
- */
-static struct rtentry *
+struct rtentry *
rtalloc1_common_locked(struct sockaddr *dst, int report, uint32_t ignflags,
unsigned int ifscope)
{
* reference held during rtrequest.
*/
rtfree_locked(rt);
+
+ /*
+ * If the newly created cloned route is a direct host route
+ * then also check if it is to a router or not.
+ * If it is, then set the RTF_ROUTER flag on the host route
+ * for the gateway.
+ *
+ * XXX It is possible for the default route to be created post
+ * cloned route creation of router's IP.
+ * We can handle that corner case by special handing for RTM_ADD
+ * of default route.
+ */
+ if ((newrt->rt_flags & (RTF_HOST | RTF_LLINFO)) ==
+ (RTF_HOST | RTF_LLINFO)) {
+ struct rtentry *defrt = NULL;
+ struct sockaddr_storage def_key;
+
+ bzero(&def_key, sizeof(def_key));
+ def_key.ss_len = rt_key(newrt)->sa_len;
+ def_key.ss_family = rt_key(newrt)->sa_family;
+
+ defrt = rtalloc1_scoped_locked((struct sockaddr *)&def_key,
+ 0, 0, newrt->rt_ifp->if_index);
+
+ if (defrt) {
+ if (equal(rt_key(newrt), defrt->rt_gateway)) {
+ newrt->rt_flags |= RTF_ROUTER;
+ }
+ rtfree_locked(defrt);
+ }
+ }
+
if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
/*
* If the new route specifies it be
* Which basically means "cant get there from here"
*/
rtstat.rts_unreach++;
+
miss:
if (report) {
/*
* comparison against rt_gateway below.
*/
#if INET6
- if ((af == AF_INET && ip_doscopedroute) ||
- (af == AF_INET6 && ip6_doscopedroute))
+ if ((af == AF_INET) || (af == AF_INET6))
#else
- if (af == AF_INET && ip_doscopedroute)
+ if (af == AF_INET)
#endif /* !INET6 */
src = sa_copy(src, &ss, &ifscope);
int
rtioctl(unsigned long req, caddr_t data, struct proc *p)
{
-#pragma unused(p)
-#if INET && MROUTING
- return (mrt_ioctl(req, data));
-#else
-#pragma unused(req)
-#pragma unused(data)
+#pragma unused(p, req, data)
return (ENXIO);
-#endif
}
struct ifaddr *
*/
#if INET6
if (dst != NULL &&
- ((dst->sa_family == AF_INET && ip_doscopedroute) ||
- (dst->sa_family == AF_INET6 && ip6_doscopedroute)))
+ ((dst->sa_family == AF_INET) ||
+ (dst->sa_family == AF_INET6)))
#else
- if (dst != NULL && dst->sa_family == AF_INET && ip_doscopedroute)
+ if (dst != NULL && dst->sa_family == AF_INET)
#endif /* !INET6 */
dst = sa_copy(SA((uintptr_t)dst), &dst_ss, NULL);
#if INET6
if (gw != NULL &&
- ((gw->sa_family == AF_INET && ip_doscopedroute) ||
- (gw->sa_family == AF_INET6 && ip6_doscopedroute)))
+ ((gw->sa_family == AF_INET) ||
+ (gw->sa_family == AF_INET6)))
#else
- if (gw != NULL && gw->sa_family == AF_INET && ip_doscopedroute)
+ if (gw != NULL && gw->sa_family == AF_INET)
#endif /* !INET6 */
gw = sa_copy(SA((uintptr_t)gw), &gw_ss, NULL);
* routing socket request.
*/
#if INET6
- if (req != RTM_RESOLVE &&
- ((af == AF_INET && ip_doscopedroute) ||
- (af == AF_INET6 && ip6_doscopedroute))) {
+ if (req != RTM_RESOLVE && ((af == AF_INET) || (af == AF_INET6))) {
#else
- if (req != RTM_RESOLVE && af == AF_INET && ip_doscopedroute) {
+ if (req != RTM_RESOLVE && af == AF_INET) {
#endif /* !INET6 */
/* Transform dst into the internal routing table form */
dst = sa_copy(dst, &ss, &ifscope);
if (ifscope != IFSCOPE_NONE)
flags |= RTF_IFSCOPE;
- } else {
- if ((flags & RTF_IFSCOPE) && (af != AF_INET && af != AF_INET6))
- senderr(EINVAL);
-
-#if INET6
- if ((af == AF_INET && !ip_doscopedroute) ||
- (af == AF_INET6 && !ip6_doscopedroute))
-#else
- if (af == AF_INET && !ip_doscopedroute)
-#endif /* !INET6 */
- ifscope = IFSCOPE_NONE;
+ } else if ((flags & RTF_IFSCOPE) &&
+ (af != AF_INET && af != AF_INET6)) {
+ senderr(EINVAL);
}
if (ifscope == IFSCOPE_NONE)
case RTM_RESOLVE:
if (ret_nrt == NULL || (rt = *ret_nrt) == NULL)
senderr(EINVAL);
+ /*
+ * According to the UNIX conformance tests, we need to return
+ * ENETUNREACH when the parent route is RTF_REJECT.
+ * However, there isn't any point in cloning RTF_REJECT
+ * routes, so we immediately return an error.
+ */
+ if (rt->rt_flags & RTF_REJECT) {
+ if (rt->rt_flags & RTF_HOST) {
+ senderr(EHOSTUNREACH);
+ } else {
+ senderr(ENETUNREACH);
+ }
+ }
/*
* If cloning, we have the parent route given by the caller
* and will use its rt_gateway, rt_rmx as part of the cloning
flags |= RTF_HOST;
#if INET6
- if ((af != AF_INET && af != AF_INET6) ||
- (af == AF_INET && !ip_doscopedroute) ||
- (af == AF_INET6 && !ip6_doscopedroute))
+ if (af != AF_INET && af != AF_INET6)
#else
- if (af != AF_INET || !ip_doscopedroute)
+ if (af != AF_INET)
#endif /* !INET6 */
goto makeroute;
rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate)
{
int dlen = SA_SIZE(dst->sa_len), glen = SA_SIZE(gate->sa_len);
- struct radix_node_head *rnh = rt_tables[dst->sa_family];
+ struct radix_node_head *rnh = NULL;
boolean_t loop = FALSE;
+ if (dst->sa_family != AF_INET && dst->sa_family != AF_INET6) {
+ return (EINVAL);
+ }
+
+ rnh = rt_tables[dst->sa_family];
lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
RT_LOCK_ASSERT_HELD(rt);
* If this is for a route that is on its way of being removed,
* or is temporarily frozen, reject the modification request.
*/
- if (rt->rt_flags & RTF_CONDEMNED)
+ if (rt->rt_flags & RTF_CONDEMNED) {
return (EBUSY);
+ }
/* Add an extra ref for ourselves */
RT_ADDREF_LOCKED(rt);
}
static void
-rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst,
- struct sockaddr *netmask)
+rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst,
+ const struct sockaddr *netmask)
{
- u_char *cp1 = (u_char *)src;
- u_char *cp2 = (u_char *)dst;
- u_char *cp3 = (u_char *)netmask;
- u_char *cplim = cp2 + *cp3;
- u_char *cplim2 = cp2 + *cp1;
+ const char *netmaskp = &netmask->sa_data[0];
+ const char *srcp = &src->sa_data[0];
+ char *dstp = &dst->sa_data[0];
+ const char *maskend = (char *)dst
+ + MIN(netmask->sa_len, src->sa_len);
+ const char *srcend = (char *)dst + src->sa_len;
+
+ dst->sa_len = src->sa_len;
+ dst->sa_family = src->sa_family;
- *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
- cp3 += 2;
- if (cplim > cplim2)
- cplim = cplim2;
- while (cp2 < cplim)
- *cp2++ = *cp1++ & *cp3++;
- if (cp2 < cplim2)
- bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
+ while (dstp < maskend)
+ *dstp++ = *srcp++ & *netmaskp++;
+ if (dstp < srcend)
+ memset(dstp, 0, (size_t)(srcend - dstp));
}
/*
rnh->rnh_lookup(&sin6_def, NULL, rnh));
}
+boolean_t
+rt_ifa_is_dst(struct sockaddr *dst, struct ifaddr *ifa)
+{
+ boolean_t result = FALSE;
+
+ if (ifa == NULL || ifa->ifa_addr == NULL)
+ return (result);
+
+ IFA_LOCK_SPIN(ifa);
+
+ if (dst->sa_family == ifa->ifa_addr->sa_family &&
+ ((dst->sa_family == AF_INET &&
+ SIN(dst)->sin_addr.s_addr ==
+ SIN(ifa->ifa_addr)->sin_addr.s_addr) ||
+ (dst->sa_family == AF_INET6 &&
+ SA6_ARE_ADDR_EQUAL(SIN6(dst), SIN6(ifa->ifa_addr)))))
+ result = TRUE;
+
+ IFA_UNLOCK(ifa);
+
+ return (result);
+}
+
/*
* Common routine to lookup/match a route. It invokes the lookup/matchaddr
* callback which could be address family-specific. The main difference
rt_lookup_common(boolean_t lookup_only, boolean_t coarse, struct sockaddr *dst,
struct sockaddr *netmask, struct radix_node_head *rnh, unsigned int ifscope)
{
- struct radix_node *rn0, *rn;
- boolean_t dontcare;
+ struct radix_node *rn0, *rn = NULL;
int af = dst->sa_family;
- struct sockaddr_storage dst_ss, mask_ss;
-
+ struct sockaddr_storage dst_ss;
+ struct sockaddr_storage mask_ss;
+ boolean_t dontcare;
+#if (DEVELOPMENT || DEBUG)
+ char dbuf[MAX_SCOPE_ADDR_STR_LEN], gbuf[MAX_IPv6_STR_LEN];
+ char s_dst[MAX_IPv6_STR_LEN], s_netmask[MAX_IPv6_STR_LEN];
+#endif
VERIFY(!coarse || ifscope == IFSCOPE_NONE);
lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
* Non-scoped route lookup.
*/
#if INET6
- if ((af != AF_INET && af != AF_INET6) ||
- (af == AF_INET && !ip_doscopedroute) ||
- (af == AF_INET6 && !ip6_doscopedroute)) {
+ if (af != AF_INET && af != AF_INET6) {
#else
- if (af != AF_INET || !ip_doscopedroute) {
+ if (af != AF_INET) {
#endif /* !INET6 */
rn = rnh->rnh_matchaddr(dst, rnh);
netmask = ma_copy(af, netmask, &mask_ss, ifscope);
dontcare = (ifscope == IFSCOPE_NONE);
+#if (DEVELOPMENT || DEBUG)
+ if (rt_verbose) {
+ if (af == AF_INET)
+ (void) inet_ntop(af, &SIN(dst)->sin_addr.s_addr,
+ s_dst, sizeof (s_dst));
+ else
+ (void) inet_ntop(af, &SIN6(dst)->sin6_addr,
+ s_dst, sizeof (s_dst));
+
+ if (netmask != NULL && af == AF_INET)
+ (void) inet_ntop(af, &SIN(netmask)->sin_addr.s_addr,
+ s_netmask, sizeof (s_netmask));
+ if (netmask != NULL && af == AF_INET6)
+ (void) inet_ntop(af, &SIN6(netmask)->sin6_addr,
+ s_netmask, sizeof (s_netmask));
+ else
+ *s_netmask = '\0';
+ printf("%s (%d, %d, %s, %s, %u)\n",
+ __func__, lookup_only, coarse, s_dst, s_netmask, ifscope);
+ }
+#endif
+
/*
* Scoped route lookup:
*
*/
if (rn != NULL) {
struct rtentry *rt = RT(rn);
- if (!(rt->rt_ifp->if_flags & IFF_LOOPBACK)) {
+#if (DEVELOPMENT || DEBUG)
+ if (rt_verbose) {
+ rt_str(rt, dbuf, sizeof (dbuf), gbuf, sizeof (gbuf));
+ printf("%s unscoped search %p to %s->%s->%s ifa_ifp %s\n",
+ __func__, rt,
+ dbuf, gbuf,
+ (rt->rt_ifp != NULL) ? rt->rt_ifp->if_xname : "",
+ (rt->rt_ifa->ifa_ifp != NULL) ?
+ rt->rt_ifa->ifa_ifp->if_xname : "");
+ }
+#endif
+ if (!(rt->rt_ifp->if_flags & IFF_LOOPBACK) ||
+ (rt->rt_flags & RTF_GATEWAY)) {
if (rt->rt_ifp->if_index != ifscope) {
/*
* Wrong interface; keep the original result
* and do a more specific scoped search using
* the scope of the found route. Otherwise,
* start again from scratch.
+ *
+ * For loopback scope we keep the unscoped
+ * route for local addresses
*/
rn = NULL;
if (dontcare)
ifscope = rt->rt_ifp->if_index;
- else
+ else if (ifscope != lo_ifp->if_index ||
+ rt_ifa_is_dst(dst, rt->rt_ifa) == FALSE)
rn0 = NULL;
} else if (!(rt->rt_flags & RTF_IFSCOPE)) {
/*
* interface scope as the one requested. The following will result
* in searching for the longest prefix scoped match.
*/
- if (rn == NULL)
+ if (rn == NULL) {
rn = node_lookup(dst, netmask, ifscope);
+#if (DEVELOPMENT || DEBUG)
+ if (rt_verbose && rn != NULL) {
+ struct rtentry *rt = RT(rn);
+ rt_str(rt, dbuf, sizeof (dbuf), gbuf, sizeof (gbuf));
+ printf("%s scoped search %p to %s->%s->%s ifa %s\n",
+ __func__, rt,
+ dbuf, gbuf,
+ (rt->rt_ifp != NULL) ? rt->rt_ifp->if_xname : "",
+ (rt->rt_ifa->ifa_ifp != NULL) ?
+ rt->rt_ifa->ifa_ifp->if_xname : "");
+ }
+#endif
+ }
/*
* Use the original result if either of the following is true:
*
* route as long as the interface portion satistifes the scope.
*/
if (rn == NULL && (rn = node_lookup_default(af)) != NULL &&
- RT(rn)->rt_ifp->if_index != ifscope)
+ RT(rn)->rt_ifp->if_index != ifscope) {
rn = NULL;
+ }
if (rn != NULL) {
/*
rn = NULL;
}
}
+#if (DEVELOPMENT || DEBUG)
+ if (rt_verbose) {
+ if (rn == NULL)
+ printf("%s %u return NULL\n", __func__, ifscope);
+ else {
+ struct rtentry *rt = RT(rn);
+
+ rt_str(rt, dbuf, sizeof (dbuf), gbuf, sizeof (gbuf));
+ printf("%s %u return %p to %s->%s->%s ifa_ifp %s\n",
+ __func__, ifscope, rt,
+ dbuf, gbuf,
+ (rt->rt_ifp != NULL) ? rt->rt_ifp->if_xname : "",
+ (rt->rt_ifa->ifa_ifp != NULL) ?
+ rt->rt_ifa->ifa_ifp->if_xname : "");
+ }
+ }
+#endif
return (RT(rn));
}
{
struct radix_node_head *rnh;
uint8_t nbuf[128]; /* long enough for IPv6 */
+#if (DEVELOPMENT || DEBUG)
char dbuf[MAX_IPv6_STR_LEN], gbuf[MAX_IPv6_STR_LEN];
char abuf[MAX_IPv6_STR_LEN];
+#endif
struct rtentry *rt = NULL;
struct sockaddr *dst;
struct sockaddr *netmask;
goto done;
}
+#if (DEVELOPMENT || DEBUG)
if (dst->sa_family == AF_INET) {
(void) inet_ntop(AF_INET, &SIN(dst)->sin_addr.s_addr,
abuf, sizeof (abuf));
abuf, sizeof (abuf));
}
#endif /* INET6 */
+#endif /* (DEVELOPMENT || DEBUG) */
if ((rnh = rt_tables[dst->sa_family]) == NULL) {
error = EINVAL;
*/
rt = rt_lookup_coarse(TRUE, dst, NULL, rnh);
if (rt != NULL) {
+#if (DEVELOPMENT || DEBUG)
rt_str(rt, dbuf, sizeof (dbuf), gbuf, sizeof (gbuf));
+#endif
/*
* Ok so we found the rtentry. it has an extra reference
* for us at this stage. we won't need that so
* an error. This seems to be the only point
* of this whole RTM_DELETE clause.
*/
+#if (DEVELOPMENT || DEBUG)
if (rt_verbose) {
log(LOG_DEBUG, "%s: not removing "
"route to %s->%s->%s, flags %b, "
rt->rt_ifa),
(uint64_t)VM_KERNEL_ADDRPERM(ifa));
}
+#endif /* (DEVELOPMENT || DEBUG) */
RT_REMREF_LOCKED(rt);
RT_UNLOCK(rt);
rt = NULL;
* Don't remove the subnet/prefix route if
* this was manually added from above.
*/
+#if (DEVELOPMENT || DEBUG)
if (rt_verbose) {
log(LOG_DEBUG, "%s: not removing "
"static route to %s->%s->%s, "
rt->rt_ifp->if_xname : ""),
rt->rt_flags, RTF_BITS, abuf);
}
+#endif /* (DEVELOPMENT || DEBUG) */
RT_REMREF_LOCKED(rt);
RT_UNLOCK(rt);
rt = NULL;
error = EBUSY;
goto done;
}
+#if (DEVELOPMENT || DEBUG)
if (rt_verbose) {
log(LOG_DEBUG, "%s: removing route to "
"%s->%s->%s, flags %b, ifaddr %s\n",
rt->rt_ifp->if_xname : ""),
rt->rt_flags, RTF_BITS, abuf);
}
+#endif /* (DEVELOPMENT || DEBUG) */
RT_REMREF_LOCKED(rt);
RT_UNLOCK(rt);
rt = NULL;
goto done;
VERIFY(rt != NULL);
-
+#if (DEVELOPMENT || DEBUG)
rt_str(rt, dbuf, sizeof (dbuf), gbuf, sizeof (gbuf));
-
+#endif /* (DEVELOPMENT || DEBUG) */
switch (cmd) {
case RTM_DELETE:
/*
RT_LOCK(rt);
rt_newaddrmsg(cmd, ifa, error, rt);
RT_UNLOCK(rt);
+#if (DEVELOPMENT || DEBUG)
if (rt_verbose) {
log(LOG_DEBUG, "%s: removed route to %s->%s->%s, "
"flags %b, ifaddr %s\n", __func__, dbuf, gbuf,
((rt->rt_ifp != NULL) ? rt->rt_ifp->if_xname : ""),
rt->rt_flags, RTF_BITS, abuf);
}
+#endif /* (DEVELOPMENT || DEBUG) */
rtfree_locked(rt);
break;
if (rt->rt_ifa != ifa) {
void (*ifa_rtrequest)
(int, struct rtentry *, struct sockaddr *);
-
- if (!(rt->rt_ifa->ifa_ifp->if_flags &
- (IFF_POINTOPOINT|IFF_LOOPBACK))) {
- log(LOG_ERR, "%s: %s route to %s->%s->%s, "
- "flags %b, ifaddr %s, rt_ifa 0x%llx != "
- "ifa 0x%llx\n", __func__, rtm2str(cmd),
- dbuf, gbuf, ((rt->rt_ifp != NULL) ?
- rt->rt_ifp->if_xname : ""), rt->rt_flags,
- RTF_BITS, abuf,
- (uint64_t)VM_KERNEL_ADDRPERM(rt->rt_ifa),
- (uint64_t)VM_KERNEL_ADDRPERM(ifa));
- }
-
+#if (DEVELOPMENT || DEBUG)
if (rt_verbose) {
+ if (!(rt->rt_ifa->ifa_ifp->if_flags &
+ (IFF_POINTOPOINT|IFF_LOOPBACK))) {
+ log(LOG_ERR, "%s: %s route to %s->%s->%s, "
+ "flags %b, ifaddr %s, rt_ifa 0x%llx != "
+ "ifa 0x%llx\n", __func__, rtm2str(cmd),
+ dbuf, gbuf, ((rt->rt_ifp != NULL) ?
+ rt->rt_ifp->if_xname : ""), rt->rt_flags,
+ RTF_BITS, abuf,
+ (uint64_t)VM_KERNEL_ADDRPERM(rt->rt_ifa),
+ (uint64_t)VM_KERNEL_ADDRPERM(ifa));
+ }
+
log(LOG_DEBUG, "%s: %s route to %s->%s->%s, "
"flags %b, ifaddr %s, rt_ifa was 0x%llx "
"now 0x%llx\n", __func__, rtm2str(cmd),
(uint64_t)VM_KERNEL_ADDRPERM(rt->rt_ifa),
(uint64_t)VM_KERNEL_ADDRPERM(ifa));
}
+#endif /* (DEVELOPMENT || DEBUG) */
/*
* Ask that the protocol in question
if (ifa_rtrequest != NULL)
ifa_rtrequest(RTM_ADD, rt, NULL);
} else {
+#if (DEVELOPMENT || DEBUG)
if (rt_verbose) {
log(LOG_DEBUG, "%s: added route to %s->%s->%s, "
"flags %b, ifaddr %s\n", __func__, dbuf,
rt->rt_ifp->if_xname : ""), rt->rt_flags,
RTF_BITS, abuf);
}
+#endif /* (DEVELOPMENT || DEBUG) */
}
/*
* notify any listenning routing agents of the change
panic("rte_free: rte=%p refcnt=%d non-zero\n", p, p->rt_refcnt);
/* NOTREACHED */
}
+
zfree(rte_zone, p);
}
ev_msg.dv[0].data_length = sizeof (struct net_event_data);
ev_msg.dv[0].data_ptr = &ev_data;
- kev_post_msg(&ev_msg);
+ dlil_post_complete_msg(NULL, &ev_msg);
}
}
void
rt_revalidate_gwroute(struct rtentry *rt, struct rtentry *gwrt)
{
- VERIFY(rt->rt_flags & (RTF_CLONING | RTF_PRCLONING));
VERIFY(gwrt != NULL);
RT_LOCK_SPIN(rt);
rt_key(gwrt)->sa_family && (rt->rt_gwroute == NULL ||
!(rt->rt_gwroute->rt_flags & RTF_UP))) {
boolean_t isequal;
+ VERIFY(rt->rt_flags & (RTF_CLONING | RTF_PRCLONING));
if (rt->rt_gateway->sa_family == AF_INET ||
rt->rt_gateway->sa_family == AF_INET6) {
{
VERIFY(rt_key(rt)->sa_family == AF_INET);
- if (ds != NULL)
+ if (ds != NULL) {
(void) inet_ntop(AF_INET,
&SIN(rt_key(rt))->sin_addr.s_addr, ds, dslen);
+ if (dslen >= MAX_SCOPE_ADDR_STR_LEN &&
+ SINIFSCOPE(rt_key(rt))->sin_scope_id != IFSCOPE_NONE) {
+ char scpstr[16];
+
+ snprintf(scpstr, sizeof(scpstr), "@%u",
+ SINIFSCOPE(rt_key(rt))->sin_scope_id);
+
+ strlcat(ds, scpstr, dslen);
+ }
+ }
+
if (gs != NULL) {
if (rt->rt_flags & RTF_GATEWAY) {
(void) inet_ntop(AF_INET,
{
VERIFY(rt_key(rt)->sa_family == AF_INET6);
- if (ds != NULL)
+ if (ds != NULL) {
(void) inet_ntop(AF_INET6,
&SIN6(rt_key(rt))->sin6_addr, ds, dslen);
+ if (dslen >= MAX_SCOPE_ADDR_STR_LEN &&
+ SIN6IFSCOPE(rt_key(rt))->sin6_scope_id != IFSCOPE_NONE) {
+ char scpstr[16];
+
+ snprintf(scpstr, sizeof(scpstr), "@%u",
+ SIN6IFSCOPE(rt_key(rt))->sin6_scope_id);
+
+ strlcat(ds, scpstr, dslen);
+ }
+ }
+
if (gs != NULL) {
if (rt->rt_flags & RTF_GATEWAY) {
(void) inet_ntop(AF_INET6,