diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2019-01-20 23:43:14 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2019-01-20 23:43:14 +0000 |
commit | bbdc35a0a0cdc2bcacf7b1decabf58de829f7922 (patch) | |
tree | e53125e0691b4925657bd790b05d9a07c059ffeb /sys | |
parent | c3b184c88a7ace5328f8e02108a5eb66e5b77501 (diff) |
Refresh arp entries that are about to expire. Once their life time is less
then 1/8 of net.inet.ip.arptimeout the system will send out a arp request
about every 30 seconds until either the entry is updated or expired.
Not refreshing arp entries will result in packet drop every time a entry
expires which is not ideal for important gateway entries.
Came up with this after a discussion with deraadt@. OK benno@ deraadt@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/if_ether.c | 64 |
1 files changed, 32 insertions, 32 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index 21b133233cd..130d107e820 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ether.c,v 1.237 2018/11/30 09:27:56 claudio Exp $ */ +/* $OpenBSD: if_ether.c,v 1.238 2019/01/20 23:43:13 claudio Exp $ */ /* $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $ */ /* @@ -67,8 +67,9 @@ struct llinfo_arp { LIST_ENTRY(llinfo_arp) la_list; struct rtentry *la_rt; /* backpointer to rtentry */ - long la_asked; /* last time we QUERIED */ struct mbuf_list la_ml; /* packet hold queue */ + time_t la_refreshed; /* when was refresh sent */ + int la_asked; /* number of queries sent */ }; #define LA_HOLD_QUEUE 10 #define LA_HOLD_TOTAL 100 @@ -119,7 +120,7 @@ arptimer(void *arg) LIST_FOREACH_SAFE(la, &arp_list, la_list, nla) { struct rtentry *rt = la->la_rt; - if (rt->rt_expire && rt->rt_expire <= time_uptime) + if (rt->rt_expire && rt->rt_expire < time_uptime) arptfree(rt); /* timer has expired; clear */ } NET_UNLOCK(); @@ -130,7 +131,6 @@ arp_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt) { struct sockaddr *gate = rt->rt_gateway; struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo; - struct ifaddr *ifa; if (!arpinit_done) { static struct timeout arptimer_to; @@ -140,7 +140,7 @@ arp_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt) IPL_SOFTNET, 0, "arp", NULL); timeout_set_proc(&arptimer_to, arptimer, &arptimer_to); - timeout_add_sec(&arptimer_to, 1); + timeout_add_sec(&arptimer_to, arpt_prune); } if (ISSET(rt->rt_flags, RTF_GATEWAY|RTF_BROADCAST|RTF_MULTICAST)) @@ -149,17 +149,12 @@ arp_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt) switch (req) { case RTM_ADD: - if (rt->rt_flags & RTF_CLONING || - ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && !la)) { - /* - * 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. - */ - rt->rt_expire = time_uptime; - if ((rt->rt_flags & RTF_CLONING) != 0) - break; + if (rt->rt_flags & RTF_CLONING) { + rt->rt_expire = 0; + break; } + if ((rt->rt_flags & RTF_LOCAL) && !la) + rt->rt_expire = 0; /* * Announce a new entry if requested or warn the user * if another station has this IP address. @@ -179,7 +174,7 @@ arp_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt) } satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; - if (la != 0) + if (la != NULL) break; /* This happens on a route change */ /* * Case 2: This route may come from cloning, or a manual route @@ -195,18 +190,9 @@ arp_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt) ml_init(&la->la_ml); la->la_rt = rt; rt->rt_flags |= RTF_LLINFO; + if ((rt->rt_flags & RTF_LOCAL) == 0) + rt->rt_expire = time_uptime; LIST_INSERT_HEAD(&arp_list, la, la_list); - - TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { - if ((ifa->ifa_addr->sa_family == AF_INET) && - ifatoia(ifa)->ia_addr.sin_addr.s_addr == - satosin(rt_key(rt))->sin_addr.s_addr) - break; - } - if (ifa) { - KASSERT(ifa == rt->rt_ifa); - rt->rt_expire = 0; - } break; case RTM_DELETE: @@ -314,7 +300,7 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, struct sockaddr *dst, u_char *desten) { struct arpcom *ac = (struct arpcom *)ifp; - struct llinfo_arp *la = NULL; + struct llinfo_arp *la; struct sockaddr_dl *sdl; struct rtentry *rt = NULL; char addr[INET_ADDRSTRLEN]; @@ -331,7 +317,7 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, rt = rt_getll(rt0); if (ISSET(rt->rt_flags, RTF_REJECT) && - (rt->rt_expire == 0 || time_uptime < rt->rt_expire)) { + (rt->rt_expire == 0 || rt->rt_expire > time_uptime )) { m_freem(m); return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); } @@ -352,6 +338,9 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, goto bad; } + la = (struct llinfo_arp *)rt->rt_llinfo; + KASSERT(la != NULL); + /* * Check the address family and length is valid, the address * is resolved; otherwise, try to resolve. @@ -359,6 +348,17 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, if ((rt->rt_expire == 0 || rt->rt_expire > time_uptime) && sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { memcpy(desten, LLADDR(sdl), sdl->sdl_alen); + + /* refresh ARP entry when timeout gets close */ + if (rt->rt_expire != 0 && + rt->rt_expire - arpt_keep / 8 < time_uptime && + la->la_refreshed + 30 < time_uptime) { + la->la_refreshed = time_uptime; + arprequest(ifp, + &satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr, + &satosin(dst)->sin_addr.s_addr, + ac->ac_enaddr); + } return (0); } @@ -370,9 +370,7 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, * response yet. Insert mbuf in hold queue if below limit * if above the limit free the queue without queuing the new packet. */ - la = (struct llinfo_arp *)rt->rt_llinfo; - KASSERT(la != NULL); - if (la_hold_total < LA_HOLD_TOTAL && la_hold_total < nmbclust / 64) { + if (la_hold_total < LA_HOLD_TOTAL) { struct mbuf *mh; if (ml_len(&la->la_ml) >= LA_HOLD_QUEUE) { @@ -411,6 +409,7 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, rt->rt_flags |= RTF_REJECT; rt->rt_expire += arpt_down; la->la_asked = 0; + la->la_refreshed = 0; la_hold_total -= ml_purge(&la->la_ml); } } @@ -668,6 +667,7 @@ arpcache(struct ifnet *ifp, struct ether_arp *ea, struct rtentry *rt) } la->la_asked = 0; + la->la_refreshed = 0; while ((len = ml_len(&la->la_ml)) != 0) { struct mbuf *mh; |