Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/nd6_rtr.c
Show First 20 Lines • Show All 2,014 Lines • ▼ Show 20 Lines | CK_STAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
IN6_IFADDR_RUNLOCK(&in6_ifa_tracker); | IN6_IFADDR_RUNLOCK(&in6_ifa_tracker); | ||||
ND6_RUNLOCK(); | ND6_RUNLOCK(); | ||||
ND6_ONLINK_UNLOCK(); | ND6_ONLINK_UNLOCK(); | ||||
} | } | ||||
/* | |||||
* | |||||
* ifa can be NULL | |||||
*/ | |||||
static int | static int | ||||
nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) | nd6_prefix_rtrequest(uint32_t fibnum, int cmd, struct sockaddr_in6 *dst, | ||||
struct sockaddr_in6 *netmask, struct ifnet *ifp, struct ifaddr *ifa) | |||||
{ | { | ||||
struct sockaddr_dl_short sdl; | struct epoch_tracker et; | ||||
struct sockaddr_in6 mask6; | int error; | ||||
u_long rtflags; | |||||
int error, a_failure, fibnum, maxfib; | |||||
bzero(&mask6, sizeof(mask6)); | /* Prepare gateway */ | ||||
mask6.sin6_len = sizeof(mask6); | struct sockaddr_dl_short sdl = { | ||||
mask6.sin6_addr = pr->ndpr_mask; | .sdl_family = AF_LINK, | ||||
rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP; | .sdl_len = sizeof(struct sockaddr_dl_short), | ||||
.sdl_type = ifp->if_type, | |||||
.sdl_index = ifp->if_index, | |||||
}; | |||||
bzero(&sdl, sizeof(struct sockaddr_dl_short)); | struct rt_addrinfo info = { | ||||
sdl.sdl_len = sizeof(struct sockaddr_dl_short); | .rti_ifa = ifa, | ||||
sdl.sdl_family = AF_LINK; | .rti_flags = RTF_PINNED | ((netmask != NULL) ? 0 : RTF_HOST), | ||||
sdl.sdl_type = ifa->ifa_ifp->if_type; | .rti_info = { | ||||
sdl.sdl_index = ifa->ifa_ifp->if_index; | [RTAX_DST] = (struct sockaddr *)dst, | ||||
[RTAX_NETMASK] = (struct sockaddr *)netmask, | |||||
[RTAX_GATEWAY] = (struct sockaddr *)&sdl, | |||||
}, | |||||
}; | |||||
/* Don't set additional per-gw filters on removal */ | |||||
if(V_rt_add_addr_allfibs) { | NET_EPOCH_ENTER(et); | ||||
fibnum = 0; | error = rib_handle_ifaddr_info(fibnum, cmd, &info); | ||||
maxfib = rt_numfibs; | NET_EPOCH_EXIT(et); | ||||
} else { | return (error); | ||||
fibnum = ifa->ifa_ifp->if_fib; | |||||
maxfib = fibnum + 1; | |||||
} | } | ||||
a_failure = 0; | |||||
for (; fibnum < maxfib; fibnum++) { | |||||
struct rt_addrinfo info; | |||||
struct rib_cmd_info rc; | |||||
bzero((caddr_t)&info, sizeof(info)); | static int | ||||
info.rti_flags = rtflags; | nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) | ||||
info.rti_info[RTAX_DST] = (struct sockaddr *)&pr->ndpr_prefix; | { | ||||
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&sdl; | uint32_t fibnum; | ||||
info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask6; | int error; | ||||
NET_EPOCH_ASSERT(); | struct sockaddr_in6 mask6 = { | ||||
error = rib_action(fibnum, RTM_ADD, &info, &rc); | .sin6_family = AF_INET6, | ||||
if (error != 0) { | .sin6_len = sizeof(struct sockaddr_in6), | ||||
char ip6buf[INET6_ADDRSTRLEN]; | .sin6_addr = pr->ndpr_mask, | ||||
char ip6bufg[INET6_ADDRSTRLEN]; | }; | ||||
char ip6bufm[INET6_ADDRSTRLEN]; | |||||
struct sockaddr_in6 *sin6; | |||||
sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; | struct sockaddr_in6 *pmask6 = (pr->ndpr_plen != 128) ? &mask6 : NULL; | ||||
nd6log((LOG_ERR, "%s: failed to add " | |||||
"route for a prefix (%s/%d) on %s, gw=%s, mask=%s, " | |||||
"flags=%lx errno = %d\n", __func__, | |||||
ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), | |||||
pr->ndpr_plen, if_name(pr->ndpr_ifp), | |||||
ip6_sprintf(ip6bufg, &sin6->sin6_addr), | |||||
ip6_sprintf(ip6bufm, &mask6.sin6_addr), | |||||
rtflags, error)); | |||||
/* Save last error to return, see rtinit(). */ | fibnum = ifa->ifa_ifp->if_fib; | ||||
a_failure = error; | error = nd6_prefix_rtrequest(fibnum, RTM_ADD, &pr->ndpr_prefix, pmask6, | ||||
continue; | pr->ndpr_ifp, ifa); | ||||
} | if (error == 0) | ||||
pr->ndpr_stateflags |= NDPRF_ONLINK; | pr->ndpr_stateflags |= NDPRF_ONLINK; | ||||
struct nhop_object *nh = nhop_select(rc.rc_nh_new, 0); | |||||
rt_routemsg(RTM_ADD, rc.rc_rt, nh, fibnum); | |||||
} | |||||
/* Return the last error we got. */ | return (error); | ||||
return (a_failure); | |||||
} | } | ||||
static int | static int | ||||
nd6_prefix_onlink(struct nd_prefix *pr) | nd6_prefix_onlink(struct nd_prefix *pr) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct ifnet *ifp = pr->ndpr_ifp; | struct ifnet *ifp = pr->ndpr_ifp; | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
int | int | ||||
nd6_prefix_offlink(struct nd_prefix *pr) | nd6_prefix_offlink(struct nd_prefix *pr) | ||||
{ | { | ||||
int error = 0; | int error = 0; | ||||
struct ifnet *ifp = pr->ndpr_ifp; | struct ifnet *ifp = pr->ndpr_ifp; | ||||
struct nd_prefix *opr; | struct nd_prefix *opr; | ||||
struct sockaddr_in6 sa6, mask6; | struct sockaddr_in6 sa6; | ||||
char ip6buf[INET6_ADDRSTRLEN]; | char ip6buf[INET6_ADDRSTRLEN]; | ||||
uint64_t genid; | uint64_t genid; | ||||
int fibnum, maxfib, a_failure; | int a_failure; | ||||
struct epoch_tracker et; | |||||
ND6_ONLINK_LOCK_ASSERT(); | ND6_ONLINK_LOCK_ASSERT(); | ||||
ND6_UNLOCK_ASSERT(); | ND6_UNLOCK_ASSERT(); | ||||
if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) | if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) | ||||
return (EEXIST); | return (EEXIST); | ||||
bzero(&sa6, sizeof(sa6)); | struct sockaddr_in6 mask6 = { | ||||
sa6.sin6_family = AF_INET6; | .sin6_family = AF_INET6, | ||||
sa6.sin6_len = sizeof(sa6); | .sin6_len = sizeof(struct sockaddr_in6), | ||||
bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr, | .sin6_addr = pr->ndpr_mask, | ||||
sizeof(struct in6_addr)); | }; | ||||
bzero(&mask6, sizeof(mask6)); | struct sockaddr_in6 *pmask6 = (pr->ndpr_plen != 128) ? &mask6 : NULL; | ||||
mask6.sin6_family = AF_INET6; | |||||
mask6.sin6_len = sizeof(sa6); | |||||
bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); | |||||
if (V_rt_add_addr_allfibs) { | error = nd6_prefix_rtrequest(ifp->if_fib, RTM_DELETE, | ||||
fibnum = 0; | &pr->ndpr_prefix, pmask6, ifp, NULL); | ||||
maxfib = rt_numfibs; | |||||
} else { | |||||
fibnum = ifp->if_fib; | |||||
maxfib = fibnum + 1; | |||||
} | |||||
a_failure = 0; | |||||
NET_EPOCH_ENTER(et); | |||||
for (; fibnum < maxfib; fibnum++) { | |||||
struct rt_addrinfo info; | |||||
struct rib_cmd_info rc; | |||||
bzero((caddr_t)&info, sizeof(info)); | |||||
info.rti_flags = RTF_GATEWAY; | |||||
info.rti_info[RTAX_DST] = (struct sockaddr *)&sa6; | |||||
info.rti_info[RTAX_GATEWAY] = NULL; | |||||
info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask6; | |||||
NET_EPOCH_ASSERT(); | |||||
error = rib_action(fibnum, RTM_DELETE, &info, &rc); | |||||
if (error != 0) { | |||||
/* Save last error to return, see rtinit(). */ | |||||
a_failure = error; | |||||
continue; | |||||
} | |||||
/* report route deletion to the routing socket. */ | |||||
struct nhop_object *nh = nhop_select(rc.rc_nh_old, 0); | |||||
rt_routemsg(RTM_DELETE, rc.rc_rt, nh, fibnum); | |||||
} | |||||
NET_EPOCH_EXIT(et); | |||||
error = a_failure; | |||||
a_failure = 1; | a_failure = 1; | ||||
if (error == 0) { | if (error == 0) { | ||||
pr->ndpr_stateflags &= ~NDPRF_ONLINK; | pr->ndpr_stateflags &= ~NDPRF_ONLINK; | ||||
/* | /* | ||||
* There might be the same prefix on another interface, | * There might be the same prefix on another interface, | ||||
* the prefix which could not be on-link just because we have | * the prefix which could not be on-link just because we have | ||||
* the interface route (see comments in nd6_prefix_onlink). | * the interface route (see comments in nd6_prefix_onlink). | ||||
Show All 33 Lines | LIST_FOREACH(opr, &V_nd_prefix, ndpr_entry) { | ||||
goto restart; | goto restart; | ||||
} | } | ||||
} | } | ||||
ND6_RUNLOCK(); | ND6_RUNLOCK(); | ||||
} else { | } else { | ||||
/* XXX: can we still set the NDPRF_ONLINK flag? */ | /* XXX: can we still set the NDPRF_ONLINK flag? */ | ||||
nd6log((LOG_ERR, | nd6log((LOG_ERR, | ||||
"%s: failed to delete route: %s/%d on %s (errno=%d)\n", | "%s: failed to delete route: %s/%d on %s (errno=%d)\n", | ||||
__func__, ip6_sprintf(ip6buf, &sa6.sin6_addr), | __func__, ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), | ||||
pr->ndpr_plen, if_name(ifp), error)); | pr->ndpr_plen, if_name(ifp), error)); | ||||
} | } | ||||
if (a_failure) | if (a_failure) | ||||
lltable_prefix_free(AF_INET6, (struct sockaddr *)&sa6, | lltable_prefix_free(AF_INET6, (struct sockaddr *)&sa6, | ||||
(struct sockaddr *)&mask6, LLE_STATIC); | (struct sockaddr *)&mask6, LLE_STATIC); | ||||
return (error); | return (error); | ||||
▲ Show 20 Lines • Show All 332 Lines • Show Last 20 Lines |