ARP: Use ND rather than our own.

This brings the benefit of Neighbour Unreachability Detection which is
something ARP sorely lacks.

The new timings mirror those of IPv6 and are adjustable via sysctl(8).
Unlike IPv6 ND, these are global and not per interface.
This commit is contained in:
roy 2020-09-11 15:16:00 +00:00
parent e4cfbe4044
commit caccb5729a
4 changed files with 310 additions and 283 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_llatbl.c,v 1.32 2020/09/11 15:01:26 roy Exp $ */
/* $NetBSD: if_llatbl.c,v 1.33 2020/09/11 15:16:00 roy Exp $ */
/*
* Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
* Copyright (c) 2004-2008 Qing Li. All rights reserved.
@ -717,6 +717,11 @@ lla_rt_output(const u_char rtm_type, const int rtm_flags, const time_t rtm_expir
lle->la_flags |= LLE_PUB;
lle->la_flags |= LLE_VALID;
switch (dst->sa_family) {
#ifdef INET
case AF_INET:
lle->ln_state = ND_LLINFO_REACHABLE;
break;
#endif
#ifdef INET6
case AF_INET6:
lle->ln_state = ND_LLINFO_REACHABLE;

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_arp.c,v 1.294 2020/03/09 21:20:55 roy Exp $ */
/* $NetBSD: if_arp.c,v 1.295 2020/09/11 15:16:00 roy Exp $ */
/*
* Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc.
@ -68,7 +68,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.294 2020/03/09 21:20:55 roy Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.295 2020/09/11 15:16:00 roy Exp $");
#ifdef _KERNEL_OPT
#include "opt_ddb.h"
@ -108,6 +108,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.294 2020/03/09 21:20:55 roy Exp $");
#include <net/if_types.h>
#include <net/if_ether.h>
#include <net/if_llatbl.h>
#include <net/nd.h>
#include <net/route.h>
#include <net/net_stats.h>
@ -132,12 +133,36 @@ __KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.294 2020/03/09 21:20:55 roy Exp $");
*/
#define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
/* timer values */
static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
static int arpt_down = 20; /* once declared down, don't send for 20 secs */
static int arp_maxhold = 1; /* number of packets to hold per ARP entry */
#define rt_expire rt_rmx.rmx_expire
#define rt_pksent rt_rmx.rmx_pksent
/* timers */
static int arp_reachable = REACHABLE_TIME;
static int arp_retrans = RETRANS_TIMER;
static int arp_perform_nud = 1;
static bool arp_nud_enabled(struct ifnet *);
static unsigned int arp_llinfo_reachable(struct ifnet *);
static unsigned int arp_llinfo_retrans(struct ifnet *);
static union nd_addr *arp_llinfo_holdsrc(struct llentry *, union nd_addr *);
static void arp_llinfo_output(struct ifnet *, const union nd_addr *,
const union nd_addr *, const uint8_t *, const union nd_addr *);
static void arp_llinfo_missed(struct ifnet *, const union nd_addr *,
struct mbuf *);
static void arp_free(struct llentry *, int);
static struct nd_domain arp_nd_domain = {
.nd_family = AF_INET,
.nd_delay = 5, /* delay first probe time 5 second */
.nd_mmaxtries = 3, /* maximum broadcast query */
.nd_umaxtries = 3, /* maximum unicast query */
.nd_maxnudhint = 0, /* max # of subsequent upper layer hints */
.nd_maxqueuelen = 1, /* max # of packets in unresolved ND entries */
.nd_nud_enabled = arp_nud_enabled,
.nd_reachable = arp_llinfo_reachable,
.nd_retrans = arp_llinfo_retrans,
.nd_holdsrc = arp_llinfo_holdsrc,
.nd_output = arp_llinfo_output,
.nd_missed = arp_llinfo_missed,
.nd_free = arp_free,
};
int ip_dad_count = PROBE_NUM;
#ifdef ARP_DEBUG
@ -151,14 +176,10 @@ static void arp_dad_init(void);
static void arprequest(struct ifnet *,
const struct in_addr *, const struct in_addr *,
const uint8_t *);
const uint8_t *, const uint8_t *);
static void arpannounce1(struct ifaddr *);
static struct sockaddr *arp_setgate(struct rtentry *, struct sockaddr *,
const struct sockaddr *);
static void arptimer(void *);
static void arp_settimer(struct llentry *, int);
static struct llentry *arplookup(struct ifnet *,
const struct in_addr *, const struct sockaddr *, int);
static struct llentry *arpcreate(struct ifnet *,
const struct in_addr *, const struct sockaddr *, int);
static void in_arpinput(struct mbuf *);
@ -173,8 +194,6 @@ static void arp_dad_start(struct ifaddr *);
static void arp_dad_stop(struct ifaddr *);
static void arp_dad_duplicated(struct ifaddr *, const struct sockaddr_dl *);
static void arp_init_llentry(struct ifnet *, struct llentry *);
struct ifqueue arpintrq = {
.ifq_head = NULL,
.ifq_tail = NULL,
@ -182,7 +201,6 @@ struct ifqueue arpintrq = {
.ifq_maxlen = 50,
.ifq_drops = 0,
};
static int arp_maxtries = 5;
static int useloopback = 1; /* use loopback interface for local traffic */
static percpu_t *arpstat_percpu;
@ -257,6 +275,7 @@ arp_init(void)
MOWNER_ATTACH(&arpdomain.dom_mowner);
#endif
nd_attach_domain(&arp_nd_domain);
arp_dad_init();
}
@ -278,98 +297,6 @@ arp_drain(void)
lltable_drain(AF_INET);
}
static void
arptimer(void *arg)
{
struct llentry *lle = arg;
struct ifnet *ifp;
KASSERT((lle->la_flags & LLE_STATIC) == 0);
LLE_WLOCK(lle);
/*
* This shortcut is required to avoid trying to touch ifp that may be
* being destroyed.
*/
if ((lle->la_flags & LLE_LINKED) == 0) {
LLE_FREE_LOCKED(lle);
return;
}
ifp = lle->lle_tbl->llt_ifp;
/* XXX: LOR avoidance. We still have ref on lle. */
LLE_WUNLOCK(lle);
IF_AFDATA_LOCK(ifp);
LLE_WLOCK(lle);
/* Guard against race with other llentry_free(). */
if (lle->la_flags & LLE_LINKED) {
int rt_cmd;
struct in_addr *in;
struct sockaddr_in dsin, ssin;
struct sockaddr *sa;
const char *lladdr;
size_t pkts_dropped;
in = &lle->r_l3addr.addr4;
sockaddr_in_init(&dsin, in, 0);
if (lle->la_flags & LLE_VALID) {
rt_cmd = RTM_DELETE;
sa = NULL;
lladdr = (const char *)&lle->ll_addr;
} else {
if (lle->la_hold != NULL) {
struct mbuf *m = lle->la_hold;
const struct ip *ip = mtod(m, const struct ip *);
sockaddr_in_init(&ssin, &ip->ip_src, 0);
sa = sintosa(&ssin);
} else
sa = NULL;
rt_cmd = RTM_MISS;
lladdr = NULL;
}
rt_clonedmsg(rt_cmd, sa, sintosa(&dsin), lladdr, ifp);
LLE_REMREF(lle);
pkts_dropped = llentry_free(lle);
ARP_STATADD(ARP_STAT_DFRDROPPED, pkts_dropped);
ARP_STATADD(ARP_STAT_DFRTOTAL, pkts_dropped);
} else {
LLE_FREE_LOCKED(lle);
}
IF_AFDATA_UNLOCK(ifp);
}
static void
arp_settimer(struct llentry *la, int sec)
{
LLE_WLOCK_ASSERT(la);
KASSERT((la->la_flags & LLE_STATIC) == 0);
/*
* We have to take care of a reference leak which occurs if
* callout_reset overwrites a pending callout schedule. Unfortunately
* we don't have a mean to know the overwrite, so we need to know it
* using callout_stop. We need to call callout_pending first to exclude
* the case that the callout has never been scheduled.
*/
if (callout_pending(&la->la_timer)) {
bool expired = callout_stop(&la->la_timer);
if (!expired)
/* A pending callout schedule is canceled. */
LLE_REMREF(la);
}
LLE_ADDREF(la);
callout_reset(&la->la_timer, hz * sec, arptimer, la);
}
/*
* We set the gateway for RTF_CLONING routes to a "prototype"
* link-layer sockaddr whose interface type (if_type) and interface
@ -409,17 +336,6 @@ arp_setgate(struct rtentry *rt, struct sockaddr *gate,
return gate;
}
static void
arp_init_llentry(struct ifnet *ifp, struct llentry *lle)
{
switch (ifp->if_type) {
default:
/* Nothing. */
break;
}
}
/*
* Parallel to llc_rtrequest.
*/
@ -477,13 +393,6 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
}
if ((rt->rt_flags & RTF_CONNECTED) ||
(rt->rt_flags & RTF_LOCAL)) {
/*
* Give this route an expiration time, even though
* it's a "permanent" route, so that routes cloned
* from it do not need their expiration time set.
*/
KASSERT(time_uptime != 0);
rt->rt_expire = time_uptime;
/*
* linklayers with particular link MTU limitation.
*/
@ -552,7 +461,6 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
* interface. So check RTF_LOCAL instead.
*/
if (rt->rt_flags & RTF_LOCAL) {
rt->rt_expire = 0;
if (useloopback) {
rt->rt_ifp = lo0ifp;
rt->rt_rmx.rmx_mtu = 0;
@ -567,7 +475,6 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
goto out;
}
rt->rt_expire = 0;
if (useloopback) {
rt->rt_ifp = lo0ifp;
rt->rt_rmx.rmx_mtu = 0;
@ -603,7 +510,7 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
static void
arprequest(struct ifnet *ifp,
const struct in_addr *sip, const struct in_addr *tip,
const uint8_t *enaddr)
const uint8_t *saddr, const uint8_t *taddr)
{
struct mbuf *m;
struct arphdr *ah;
@ -612,7 +519,7 @@ arprequest(struct ifnet *ifp,
KASSERT(sip != NULL);
KASSERT(tip != NULL);
KASSERT(enaddr != NULL);
KASSERT(saddr != NULL);
if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
return;
@ -644,12 +551,15 @@ arprequest(struct ifnet *ifp,
ah->ar_hln = ifp->if_addrlen; /* hardware address length */
ah->ar_pln = sizeof(struct in_addr); /* protocol address length */
ah->ar_op = htons(ARPOP_REQUEST);
memcpy(ar_sha(ah), enaddr, ah->ar_hln);
memcpy(ar_sha(ah), saddr, ah->ar_hln);
if (taddr == NULL)
m->m_flags |= M_BCAST;
else
memcpy(ar_tha(ah), taddr, ah->ar_hln);
memcpy(ar_spa(ah), sip, ah->ar_pln);
memcpy(ar_tpa(ah), tip, ah->ar_pln);
sa.sa_family = AF_ARP;
sa.sa_len = 2;
m->m_flags |= M_BCAST;
arps = ARP_STAT_GETREF();
arps[ARP_STAT_SNDTOTAL]++;
arps[ARP_STAT_SENDREQUEST]++;
@ -667,7 +577,7 @@ arpannounce(struct ifnet *ifp, struct ifaddr *ifa, const uint8_t *enaddr)
ARPLOG(LOG_DEBUG, "%s not ready\n", ARPLOGADDR(ip));
return;
}
arprequest(ifp, ip, ip, enaddr);
arprequest(ifp, ip, ip, enaddr, NULL);
}
static void
@ -694,9 +604,7 @@ arpresolve(struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m,
{
struct llentry *la;
const char *create_lookup;
bool renew;
int error;
struct ifnet *origifp = ifp;
#if NCARP > 0
if (rt != NULL && rt->rt_ifp->if_type == IFT_CARP)
@ -709,8 +617,7 @@ arpresolve(struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m,
if (la == NULL)
goto notfound;
if ((la->la_flags & LLE_VALID) &&
((la->la_flags & LLE_STATIC) || la->la_expire > time_uptime)) {
if (la->la_flags & LLE_VALID && la->ln_state == ND_LLINFO_REACHABLE) {
KASSERT(destlen >= ifp->if_addrlen);
memcpy(desten, &la->ll_addr, ifp->if_addrlen);
LLE_RUNLOCK(la);
@ -738,7 +645,7 @@ notfound:
if (la == NULL)
ARP_STATINC(ARP_STAT_ALLOCFAIL);
else
arp_init_llentry(ifp, la);
la->ln_state = ND_LLINFO_NOSTATE;
} else if (LLE_TRY_UPGRADE(la) == 0) {
create_lookup = "lookup";
LLE_RUNLOCK(la);
@ -756,126 +663,7 @@ notfound:
goto bad;
}
if ((la->la_flags & LLE_VALID) &&
((la->la_flags & LLE_STATIC) || la->la_expire > time_uptime))
{
KASSERT(destlen >= ifp->if_addrlen);
memcpy(desten, &la->ll_addr, ifp->if_addrlen);
renew = false;
/*
* If entry has an expiry time and it is approaching,
* see if we need to send an ARP request within this
* arpt_down interval.
*/
if (!(la->la_flags & LLE_STATIC) &&
time_uptime + la->la_preempt > la->la_expire)
{
renew = true;
la->la_preempt--;
}
LLE_WUNLOCK(la);
if (renew) {
const uint8_t *enaddr = CLLADDR(ifp->if_sadl);
arprequest(origifp,
&satocsin(rt->rt_ifa->ifa_addr)->sin_addr,
&satocsin(dst)->sin_addr, enaddr);
}
return 0;
}
if (la->la_flags & LLE_STATIC) { /* should not happen! */
LLE_RUNLOCK(la);
log(LOG_DEBUG, "%s: ouch, empty static llinfo for %s\n",
__func__, inet_ntoa(satocsin(dst)->sin_addr));
error = EINVAL;
goto bad;
}
renew = (la->la_asked == 0 || la->la_expire != time_uptime);
/*
* There is an arptab entry, but no ethernet address
* response yet. Add the mbuf to the list, dropping
* the oldest packet if we have exceeded the system
* setting.
*/
LLE_WLOCK_ASSERT(la);
if (la->la_numheld >= arp_maxhold) {
if (la->la_hold != NULL) {
struct mbuf *next = la->la_hold->m_nextpkt;
m_freem(la->la_hold);
la->la_hold = next;
la->la_numheld--;
ARP_STATINC(ARP_STAT_DFRDROPPED);
ARP_STATINC(ARP_STAT_DFRTOTAL);
}
}
if (la->la_hold != NULL) {
struct mbuf *curr = la->la_hold;
while (curr->m_nextpkt != NULL)
curr = curr->m_nextpkt;
curr->m_nextpkt = m;
} else
la->la_hold = m;
la->la_numheld++;
if (!renew)
LLE_DOWNGRADE(la);
/*
* Return EWOULDBLOCK if we have tried less than arp_maxtries. It
* will be masked by ether_output(). Return EHOSTDOWN/EHOSTUNREACH
* if we have already sent arp_maxtries ARP requests. Retransmit the
* ARP request, but not faster than one request per second.
*/
if (la->la_asked < arp_maxtries)
error = EWOULDBLOCK; /* First request. */
else
error = (rt != NULL && rt->rt_flags & RTF_GATEWAY) ?
EHOSTUNREACH : EHOSTDOWN;
if (renew) {
const uint8_t *enaddr = CLLADDR(ifp->if_sadl);
struct sockaddr_in sin;
la->la_expire = time_uptime;
arp_settimer(la, arpt_down);
la->la_asked++;
sockaddr_in_init(&sin, &la->r_l3addr.addr4, 0);
if (error != EWOULDBLOCK) {
const struct ip *ip = mtod(m, const struct ip *);
struct sockaddr_in ssin;
sockaddr_in_init(&ssin, &ip->ip_src, 0);
rt_clonedmsg(RTM_MISS, sintosa(&ssin), sintosa(&sin),
NULL, ifp);
}
LLE_WUNLOCK(la);
if (rt != NULL) {
arprequest(origifp,
&satocsin(rt->rt_ifa->ifa_addr)->sin_addr,
&satocsin(dst)->sin_addr, enaddr);
} else {
struct rtentry *_rt;
/* XXX */
_rt = rtalloc1((struct sockaddr *)&sin, 0);
if (_rt == NULL)
goto bad;
arprequest(origifp,
&satocsin(_rt->rt_ifa->ifa_addr)->sin_addr,
&satocsin(dst)->sin_addr, enaddr);
rt_unref(_rt);
}
return error;
}
LLE_RUNLOCK(la);
error = nd_resolve(la, rt, m, desten, destlen);
return error;
bad:
@ -1003,7 +791,7 @@ in_arpinput(struct mbuf *m)
#endif
struct sockaddr sa;
struct in_addr isaddr, itaddr, myaddr;
int op, rt_cmd;
int op, rt_cmd, new_state = 0;
void *tha;
uint64_t *arps;
struct psref psref, psref_ia;
@ -1234,20 +1022,35 @@ again:
IN_PRINT(ipbuf, &isaddr), llastr);
}
rt_cmd = RTM_CHANGE;
} else
new_state = ND_LLINFO_STALE;
} else {
if (op == ARPOP_REPLY && in_hosteq(itaddr, myaddr)) {
/* This was a solicited ARP reply. */
la->ln_byhint = 0;
new_state = ND_LLINFO_REACHABLE;
}
rt_cmd = la->la_flags & LLE_VALID ? 0 : RTM_ADD;
}
KASSERT(ifp->if_sadl->sdl_alen == ifp->if_addrlen);
KASSERT(sizeof(la->ll_addr) >= ifp->if_addrlen);
memcpy(&la->ll_addr, ar_sha(ah), ifp->if_addrlen);
la->la_flags |= LLE_VALID;
if ((la->la_flags & LLE_STATIC) == 0) {
la->la_expire = time_uptime + arpt_keep;
arp_settimer(la, arpt_keep);
la->ln_asked = 0;
if (new_state != 0) {
la->ln_state = new_state;
if (new_state != ND_LLINFO_REACHABLE ||
!(la->la_flags & LLE_STATIC))
{
int timer = ND_TIMER_GC;
if (new_state == ND_LLINFO_REACHABLE)
timer = ND_TIMER_REACHABLE;
nd_set_timer(la, timer);
}
}
la->la_asked = 0;
/* rt->rt_flags &= ~RTF_REJECT; */
if (rt_cmd != 0) {
struct sockaddr_in sin;
@ -1390,7 +1193,7 @@ out:
/*
* Lookup or a new address in arptab.
*/
static struct llentry *
struct llentry *
arplookup(struct ifnet *ifp, const struct in_addr *addr,
const struct sockaddr *sa, int wlock)
{
@ -1438,7 +1241,7 @@ arpcreate(struct ifnet *ifp, const struct in_addr *addr,
rt_unref(rt);
if (la != NULL)
arp_init_llentry(ifp, la);
la->ln_state = ND_LLINFO_NOSTATE;
}
return la;
@ -1476,6 +1279,178 @@ arp_ifinit(struct ifnet *ifp, struct ifaddr *ifa)
}
}
static bool
arp_nud_enabled(__unused struct ifnet *ifp)
{
return arp_perform_nud != 0;
}
static unsigned int
arp_llinfo_reachable(__unused struct ifnet *ifp)
{
return arp_reachable;
}
static unsigned int
arp_llinfo_retrans(__unused struct ifnet *ifp)
{
return arp_retrans;
}
/*
* Gets source address of the first packet in hold queue
* and stores it in @src.
* Returns pointer to @src (if hold queue is not empty) or NULL.
*/
static union nd_addr *
arp_llinfo_holdsrc(struct llentry *ln, union nd_addr *src)
{
struct ip *ip;
if (ln == NULL || ln->ln_hold == NULL)
return NULL;
/*
* assuming every packet in ln_hold has the same IP header
*/
ip = mtod(ln->ln_hold, struct ip *);
/* XXX pullup? */
if (sizeof(*ip) < ln->ln_hold->m_len)
src->nd_addr4 = ip->ip_src;
else
src = NULL;
return src;
}
static void
arp_llinfo_output(struct ifnet *ifp, __unused const union nd_addr *daddr,
const union nd_addr *taddr, const uint8_t *tlladdr,
const union nd_addr *hsrc)
{
struct in_addr tip = taddr->nd_addr4, sip = zeroin_addr;
const uint8_t *slladdr = CLLADDR(ifp->if_sadl);
if (hsrc != NULL) {
struct in_ifaddr *ia;
struct psref psref;
ia = in_get_ia_on_iface_psref(hsrc->nd_addr4, ifp, &psref);
if (ia != NULL) {
sip = hsrc->nd_addr4;
ia4_release(ia, &psref);
}
}
if (sip.s_addr == INADDR_ANY) {
struct sockaddr_in dst;
struct rtentry *rt;
sockaddr_in_init(&dst, &tip, 0);
rt = rtalloc1(sintosa(&dst), 0);
if (rt != NULL) {
if (rt->rt_ifp == ifp &&
rt->rt_ifa != NULL &&
rt->rt_ifa->ifa_addr->sa_family == AF_INET)
sip = satosin(rt->rt_ifa->ifa_addr)->sin_addr;
rt_unref(rt);
}
if (sip.s_addr == INADDR_ANY) {
char ipbuf[INET_ADDRSTRLEN];
log(LOG_DEBUG, "source can't be "
"determined: dst=%s\n",
IN_PRINT(ipbuf, &tip));
return;
}
}
arprequest(ifp, &sip, &tip, slladdr, tlladdr);
}
static void
arp_llinfo_missed(struct ifnet *ifp, const union nd_addr *taddr, struct mbuf *m)
{
struct in_addr mdaddr = zeroin_addr;
struct sockaddr_in dsin, tsin;
struct sockaddr *sa;
if (m != NULL) {
struct ip *ip = mtod(m, struct ip *);
if (sizeof(*ip) < m->m_len)
mdaddr = ip->ip_src;
/* ip_input() will send ICMP_UNREACH_HOST, not us. */
m_free(m);
}
if (mdaddr.s_addr != INADDR_ANY) {
sockaddr_in_init(&dsin, &mdaddr, 0);
sa = sintosa(&dsin);
} else
sa = NULL;
sockaddr_in_init(&tsin, &taddr->nd_addr4, 0);
rt_clonedmsg(RTM_MISS, sa, sintosa(&tsin), NULL, ifp);
}
static void
arp_free(struct llentry *ln, int gc)
{
struct ifnet *ifp;
KASSERT(ln != NULL);
LLE_WLOCK_ASSERT(ln);
ifp = ln->lle_tbl->llt_ifp;
if (ln->la_flags & LLE_VALID || gc) {
struct sockaddr_in sin;
const char *lladdr;
sockaddr_in_init(&sin, &ln->r_l3addr.addr4, 0);
lladdr = ln->la_flags & LLE_VALID ?
(const char *)&ln->ll_addr : NULL;
rt_clonedmsg(RTM_DELETE, NULL, sintosa(&sin), lladdr, ifp);
}
/*
* Save to unlock. We still hold an extra reference and will not
* free(9) in llentry_free() if someone else holds one as well.
*/
LLE_WUNLOCK(ln);
IF_AFDATA_LOCK(ifp);
LLE_WLOCK(ln);
lltable_free_entry(LLTABLE(ifp), ln);
IF_AFDATA_UNLOCK(ifp);
}
/*
* Upper-layer reachability hint for Neighbor Unreachability Detection.
*
* XXX cost-effective methods?
*/
void
arp_nud_hint(struct rtentry *rt)
{
struct llentry *ln;
struct ifnet *ifp;
if (rt == NULL)
return;
ifp = rt->rt_ifp;
ln = arplookup(ifp, NULL, rt_getkey(rt), 1);
nd_nud_hint(ln);
}
TAILQ_HEAD(dadq_head, dadq);
struct dadq {
TAILQ_ENTRY(dadq) dad_list;
@ -1561,7 +1536,7 @@ arp_dad_output(struct dadq *dp, struct ifaddr *ifa)
memset(&sip, 0, sizeof(sip));
arprequest(ifa->ifa_ifp, &sip, &ia->ia_addr.sin_addr,
CLLADDR(ifa->ifa_ifp->if_sadl));
CLLADDR(ifa->ifa_ifp->if_sadl), NULL);
}
/*
@ -2026,18 +2001,53 @@ sysctl_net_inet_arp_setup(struct sysctllog **clog)
CTL_NET, PF_INET, CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "keep",
SYSCTL_DESCR("Valid ARP entry lifetime in seconds"),
NULL, 0, &arpt_keep, 0,
CTL_NET,PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "nd_delay",
SYSCTL_DESCR("First probe delay time"),
NULL, 0, &arp_nd_domain.nd_delay, 0,
CTL_NET, PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "down",
SYSCTL_DESCR("Failed ARP entry lifetime in seconds"),
NULL, 0, &arpt_down, 0,
CTL_NET,PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "nd_bmaxtries",
SYSCTL_DESCR("Number of broadcast discovery attempts"),
NULL, 0, &arp_nd_domain.nd_mmaxtries, 0,
CTL_NET, PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "nd_umaxtries",
SYSCTL_DESCR("Number of unicast discovery attempts"),
NULL, 0, &arp_nd_domain.nd_umaxtries, 0,
CTL_NET, PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "nd_reachable",
SYSCTL_DESCR("Reachable time"),
NULL, 0, &arp_reachable, 0,
CTL_NET, PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "nd_retrans",
SYSCTL_DESCR("Retransmission time"),
NULL, 0, &arp_retrans, 0,
CTL_NET, PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "nd_nud",
SYSCTL_DESCR("Perform neighbour unreachability detection"),
NULL, 0, &arp_perform_nud, 0,
CTL_NET, PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "nd_maxnudhint",
SYSCTL_DESCR("Maximum neighbor unreachable hint count"),
NULL, 0, &arp_nd_domain.nd_maxnudhint, 0,
CTL_NET, PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "maxqueuelen",
SYSCTL_DESCR("max packet queue len for a unresolved ARP"),
NULL, 1, &arp_nd_domain.nd_maxqueuelen, 0,
CTL_NET, PF_INET, node->sysctl_num, CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_inarp.h,v 1.51 2017/02/21 03:58:24 ozaki-r Exp $ */
/* $NetBSD: if_inarp.h,v 1.52 2020/09/11 15:16:00 roy Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@ -76,9 +76,12 @@ int arpresolve(struct ifnet *, const struct rtentry *, struct mbuf *,
const struct sockaddr *, void *, size_t);
void arpintr(void);
void arpannounce(struct ifnet *, struct ifaddr *, const uint8_t *);
struct llentry *arplookup(struct ifnet *,
const struct in_addr *, const struct sockaddr *, int);
void arp_drain(void);
int arpioctl(u_long, void *);
void arpwhohas(struct ifnet *, struct in_addr *);
void arp_nud_hint(struct rtentry *);
void revarpinput(struct mbuf *);
int revarpwhoarewe(struct ifnet *, struct in_addr *, struct in_addr *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: tcp_input.c,v 1.421 2020/09/11 15:08:25 roy Exp $ */
/* $NetBSD: tcp_input.c,v 1.422 2020/09/11 15:16:00 roy Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -148,7 +148,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.421 2020/09/11 15:08:25 roy Exp $");
__KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.422 2020/09/11 15:16:00 roy Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -186,6 +186,9 @@ __KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.421 2020/09/11 15:08:25 roy Exp $");
#include <netinet/ip_var.h>
#include <netinet/in_offload.h>
#ifdef INET
#include <netinet/if_inarp.h>
#endif
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
@ -263,6 +266,12 @@ nd_hint(struct tcpcb *tp)
return;
switch (tp->t_family) {
#ifdef INET
case AF_INET:
if (tp->t_inpcb != NULL)
ro = &tp->t_inpcb->inp_route;
break;
#endif
#ifdef INET6
case AF_INET6:
if (tp->t_in6pcb != NULL)