Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/nd6.c
Show First 20 Lines • Show All 1,923 Lines • ▼ Show 20 Lines | nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr, | ||||
int olladdr; | int olladdr; | ||||
int llchange; | int llchange; | ||||
int flags; | int flags; | ||||
uint16_t router = 0; | uint16_t router = 0; | ||||
struct sockaddr_in6 sin6; | struct sockaddr_in6 sin6; | ||||
struct mbuf *chain = NULL; | struct mbuf *chain = NULL; | ||||
u_char linkhdr[LLE_MAX_LINKHDR]; | u_char linkhdr[LLE_MAX_LINKHDR]; | ||||
size_t linkhdrsize; | size_t linkhdrsize; | ||||
int lladdr_off; | int count, lladdr_off; | ||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
IF_AFDATA_UNLOCK_ASSERT(ifp); | IF_AFDATA_UNLOCK_ASSERT(ifp); | ||||
KASSERT(ifp != NULL, ("%s: ifp == NULL", __func__)); | KASSERT(ifp != NULL, ("%s: ifp == NULL", __func__)); | ||||
KASSERT(from != NULL, ("%s: from == NULL", __func__)); | KASSERT(from != NULL, ("%s: from == NULL", __func__)); | ||||
/* nothing must be updated for unspecified address */ | /* nothing must be updated for unspecified address */ | ||||
Show All 30 Lines | if (lladdr != NULL) { | ||||
lltable_set_entry_addr(ifp, ln, linkhdr, linkhdrsize, | lltable_set_entry_addr(ifp, ln, linkhdr, linkhdrsize, | ||||
lladdr_off); | lladdr_off); | ||||
} | } | ||||
IF_AFDATA_WLOCK(ifp); | IF_AFDATA_WLOCK(ifp); | ||||
LLE_WLOCK(ln); | LLE_WLOCK(ln); | ||||
/* Prefer any existing lle over newly-created one */ | /* Prefer any existing lle over newly-created one */ | ||||
ln_tmp = nd6_lookup(from, LLE_EXCLUSIVE, ifp); | ln_tmp = nd6_lookup(from, LLE_EXCLUSIVE, ifp); | ||||
if (ln_tmp == NULL) | if (ln_tmp == NULL) { | ||||
lltable_link_entry(LLTABLE6(ifp), ln); | count = lltable_link_entry(LLTABLE6(ifp), ln); | ||||
if (count < 0) { | |||||
IF_AFDATA_WUNLOCK(ifp); | IF_AFDATA_WUNLOCK(ifp); | ||||
lltable_free_entry(LLTABLE6(ifp), ln); | |||||
return; | |||||
} | |||||
} | |||||
IF_AFDATA_WUNLOCK(ifp); | |||||
if (ln_tmp == NULL) { | if (ln_tmp == NULL) { | ||||
/* No existing lle, mark as new entry (6,7) */ | /* No existing lle, mark as new entry (6,7) */ | ||||
is_newentry = 1; | is_newentry = 1; | ||||
if (lladdr != NULL) { /* (7) */ | if (lladdr != NULL) { /* (7) */ | ||||
nd6_llinfo_setstate(ln, ND6_LLINFO_STALE); | nd6_llinfo_setstate(ln, ND6_LLINFO_STALE); | ||||
EVENTHANDLER_INVOKE(lle_event, ln, | EVENTHANDLER_INVOKE(lle_event, ln, | ||||
LLENTRY_RESOLVED); | LLENTRY_RESOLVED); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 290 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static __noinline int | static __noinline int | ||||
nd6_resolve_slow(struct ifnet *ifp, int flags, struct mbuf *m, | nd6_resolve_slow(struct ifnet *ifp, int flags, struct mbuf *m, | ||||
const struct sockaddr_in6 *dst, u_char *desten, uint32_t *pflags, | const struct sockaddr_in6 *dst, u_char *desten, uint32_t *pflags, | ||||
struct llentry **plle) | struct llentry **plle) | ||||
{ | { | ||||
struct llentry *lle = NULL, *lle_tmp; | struct llentry *lle = NULL, *lle_tmp; | ||||
struct in6_addr *psrc, src; | struct in6_addr *psrc, src; | ||||
int send_ns, ll_len; | int count, send_ns, ll_len; | ||||
char *lladdr; | char *lladdr; | ||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
/* | /* | ||||
* Address resolution or Neighbor Unreachability Detection | * Address resolution or Neighbor Unreachability Detection | ||||
* for the next hop. | * for the next hop. | ||||
* At this point, the destination of the packet must be a unicast | * At this point, the destination of the packet must be a unicast | ||||
Show All 13 Lines | if ((lle == NULL) && nd6_is_addr_neighbor(dst, ifp)) { | ||||
log(LOG_DEBUG, | log(LOG_DEBUG, | ||||
"nd6_output: can't allocate llinfo for %s " | "nd6_output: can't allocate llinfo for %s " | ||||
"(ln=%p)\n", | "(ln=%p)\n", | ||||
ip6_sprintf(ip6buf, &dst->sin6_addr), lle); | ip6_sprintf(ip6buf, &dst->sin6_addr), lle); | ||||
m_freem(m); | m_freem(m); | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
} | } | ||||
count = 0; | |||||
IF_AFDATA_WLOCK(ifp); | IF_AFDATA_WLOCK(ifp); | ||||
LLE_WLOCK(lle); | LLE_WLOCK(lle); | ||||
/* Prefer any existing entry over newly-created one */ | /* Prefer any existing entry over newly-created one */ | ||||
lle_tmp = nd6_lookup(&dst->sin6_addr, LLE_EXCLUSIVE, ifp); | lle_tmp = nd6_lookup(&dst->sin6_addr, LLE_EXCLUSIVE, ifp); | ||||
if (lle_tmp == NULL) | if (lle_tmp == NULL) | ||||
lltable_link_entry(LLTABLE6(ifp), lle); | count = lltable_link_entry(LLTABLE6(ifp), lle); | ||||
IF_AFDATA_WUNLOCK(ifp); | IF_AFDATA_WUNLOCK(ifp); | ||||
if (lle_tmp == NULL && count < 0) { | |||||
lltable_free_entry(LLTABLE6(ifp), lle); | |||||
lle = NULL; | |||||
} | |||||
if (lle_tmp != NULL) { | if (lle_tmp != NULL) { | ||||
lltable_free_entry(LLTABLE6(ifp), lle); | lltable_free_entry(LLTABLE6(ifp), lle); | ||||
lle = lle_tmp; | lle = lle_tmp; | ||||
lle_tmp = NULL; | lle_tmp = NULL; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (lle == NULL) { | if (lle == NULL) { | ||||
▲ Show 20 Lines • Show All 168 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
*/ | */ | ||||
int | int | ||||
nd6_add_ifa_lle(struct in6_ifaddr *ia) | nd6_add_ifa_lle(struct in6_ifaddr *ia) | ||||
{ | { | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct llentry *ln, *ln_tmp; | struct llentry *ln, *ln_tmp; | ||||
struct sockaddr *dst; | struct sockaddr *dst; | ||||
int count; | |||||
ifp = ia->ia_ifa.ifa_ifp; | ifp = ia->ia_ifa.ifa_ifp; | ||||
if (nd6_need_cache(ifp) == 0) | if (nd6_need_cache(ifp) == 0) | ||||
return (0); | return (0); | ||||
ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; | ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; | ||||
dst = (struct sockaddr *)&ia->ia_addr; | dst = (struct sockaddr *)&ia->ia_addr; | ||||
ln = lltable_alloc_entry(LLTABLE6(ifp), LLE_IFADDR, dst); | ln = lltable_alloc_entry(LLTABLE6(ifp), LLE_IFADDR, dst); | ||||
if (ln == NULL) | if (ln == NULL) | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
count = 0; | |||||
IF_AFDATA_WLOCK(ifp); | IF_AFDATA_WLOCK(ifp); | ||||
LLE_WLOCK(ln); | LLE_WLOCK(ln); | ||||
/* Unlink any entry if exists */ | /* Unlink any entry if exists */ | ||||
ln_tmp = lla_lookup(LLTABLE6(ifp), LLE_EXCLUSIVE, dst); | ln_tmp = lla_lookup(LLTABLE6(ifp), LLE_EXCLUSIVE, dst); | ||||
count = lltable_link_entry(LLTABLE6(ifp), ln); | |||||
melifaro: Sorry, would it be possible to move this block under the `lltable_unlink_entry()` ?
If we have… | |||||
Done Inline ActionsOh I missed the LLE_EXCLUSIVE; I'll fix that. Thanks a lot for catching this! bz: Oh I missed the LLE_EXCLUSIVE; I'll fix that. Thanks a lot for catching this!
The idea was… | |||||
if (count < 0) { | |||||
IF_AFDATA_WUNLOCK(ifp); | |||||
lltable_free_entry(LLTABLE6(ifp), ln); | |||||
return (ENOBUFS); | |||||
} | |||||
if (ln_tmp != NULL) | if (ln_tmp != NULL) | ||||
donnerUnsubmitted Not Done Inline ActionsMay those lines stay together? donner: May those lines stay together? | |||||
bzAuthorUnsubmitted Done Inline ActionsNot sure what you mean by that? Do you mean if we can link the new before unlinking the old? If that is the question the answer is yes as it is a simple list insert/remove under the same lock. bz: Not sure what you mean by that? Do you mean if we can link the new before unlinking the old? | |||||
donnerUnsubmitted Not Done Inline ActionsThe ln_tmp value is extracted and immediately tested. Now new code is moved upwards between those lines. I do not grasp, why this code needs to stay between those lines of ln_tmp donner: The ln_tmp value is extracted and immediately tested. Now new code is moved upwards between… | |||||
lltable_unlink_entry(LLTABLE6(ifp), ln_tmp); | lltable_unlink_entry(LLTABLE6(ifp), ln_tmp); | ||||
lltable_link_entry(LLTABLE6(ifp), ln); | |||||
IF_AFDATA_WUNLOCK(ifp); | IF_AFDATA_WUNLOCK(ifp); | ||||
if (ln_tmp != NULL) | if (ln_tmp != NULL) | ||||
EVENTHANDLER_INVOKE(lle_event, ln_tmp, LLENTRY_EXPIRED); | EVENTHANDLER_INVOKE(lle_event, ln_tmp, LLENTRY_EXPIRED); | ||||
EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_RESOLVED); | EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_RESOLVED); | ||||
LLE_WUNLOCK(ln); | LLE_WUNLOCK(ln); | ||||
if (ln_tmp != NULL) | if (ln_tmp != NULL) | ||||
▲ Show 20 Lines • Show All 122 Lines • Show Last 20 Lines |
Sorry, would it be possible to move this block under the lltable_unlink_entry() ?
If we have too many entries we may end up locking ln_tmp and then returning without deleting/unlocking it.