The statically configured (permanent) ARP entries are removed when an
interface is brought down, even though the interface address is still valid. This patch maintains the permanent ARP entries as long as the interface address (having the same prefix as that of the ARP entries) is valid. Reviewed by: delphij MFC after: 5 days
This commit is contained in:
parent
7ba75dc4e9
commit
5b84dc789a
@ -228,7 +228,8 @@ lltable_drain(int af)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask)
|
lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask,
|
||||||
|
u_int flags)
|
||||||
{
|
{
|
||||||
struct lltable *llt;
|
struct lltable *llt;
|
||||||
|
|
||||||
@ -237,7 +238,7 @@ lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask)
|
|||||||
if (llt->llt_af != af)
|
if (llt->llt_af != af)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
llt->llt_prefix_free(llt, prefix, mask);
|
llt->llt_prefix_free(llt, prefix, mask, flags);
|
||||||
}
|
}
|
||||||
LLTABLE_RUNLOCK();
|
LLTABLE_RUNLOCK();
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,8 @@ struct lltable {
|
|||||||
void (*llt_free)(struct lltable *, struct llentry *);
|
void (*llt_free)(struct lltable *, struct llentry *);
|
||||||
void (*llt_prefix_free)(struct lltable *,
|
void (*llt_prefix_free)(struct lltable *,
|
||||||
const struct sockaddr *prefix,
|
const struct sockaddr *prefix,
|
||||||
const struct sockaddr *mask);
|
const struct sockaddr *mask,
|
||||||
|
u_int flags);
|
||||||
struct llentry * (*llt_lookup)(struct lltable *, u_int flags,
|
struct llentry * (*llt_lookup)(struct lltable *, u_int flags,
|
||||||
const struct sockaddr *l3addr);
|
const struct sockaddr *l3addr);
|
||||||
int (*llt_rtcheck)(struct ifnet *, u_int flags,
|
int (*llt_rtcheck)(struct ifnet *, u_int flags,
|
||||||
@ -184,7 +185,7 @@ MALLOC_DECLARE(M_LLTABLE);
|
|||||||
struct lltable *lltable_init(struct ifnet *, int);
|
struct lltable *lltable_init(struct ifnet *, int);
|
||||||
void lltable_free(struct lltable *);
|
void lltable_free(struct lltable *);
|
||||||
void lltable_prefix_free(int, struct sockaddr *,
|
void lltable_prefix_free(int, struct sockaddr *,
|
||||||
struct sockaddr *);
|
struct sockaddr *, u_int);
|
||||||
#if 0
|
#if 0
|
||||||
void lltable_drain(int);
|
void lltable_drain(int);
|
||||||
#endif
|
#endif
|
||||||
|
@ -70,7 +70,7 @@ static int in_lifaddr_ioctl(struct socket *, u_long, caddr_t,
|
|||||||
struct ifnet *, struct thread *);
|
struct ifnet *, struct thread *);
|
||||||
|
|
||||||
static int in_addprefix(struct in_ifaddr *, int);
|
static int in_addprefix(struct in_ifaddr *, int);
|
||||||
static int in_scrubprefix(struct in_ifaddr *);
|
static int in_scrubprefix(struct in_ifaddr *, u_int);
|
||||||
static void in_socktrim(struct sockaddr_in *);
|
static void in_socktrim(struct sockaddr_in *);
|
||||||
static int in_ifinit(struct ifnet *,
|
static int in_ifinit(struct ifnet *,
|
||||||
struct in_ifaddr *, struct sockaddr_in *, int);
|
struct in_ifaddr *, struct sockaddr_in *, int);
|
||||||
@ -548,7 +548,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
|||||||
* is the same as before, then the call is
|
* is the same as before, then the call is
|
||||||
* un-necessarily executed here.
|
* un-necessarily executed here.
|
||||||
*/
|
*/
|
||||||
in_ifscrub(ifp, ia);
|
in_ifscrub(ifp, ia, 0);
|
||||||
ia->ia_sockmask = ifra->ifra_mask;
|
ia->ia_sockmask = ifra->ifra_mask;
|
||||||
ia->ia_sockmask.sin_family = AF_INET;
|
ia->ia_sockmask.sin_family = AF_INET;
|
||||||
ia->ia_subnetmask =
|
ia->ia_subnetmask =
|
||||||
@ -557,7 +557,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
|||||||
}
|
}
|
||||||
if ((ifp->if_flags & IFF_POINTOPOINT) &&
|
if ((ifp->if_flags & IFF_POINTOPOINT) &&
|
||||||
(ifra->ifra_dstaddr.sin_family == AF_INET)) {
|
(ifra->ifra_dstaddr.sin_family == AF_INET)) {
|
||||||
in_ifscrub(ifp, ia);
|
in_ifscrub(ifp, ia, 0);
|
||||||
ia->ia_dstaddr = ifra->ifra_dstaddr;
|
ia->ia_dstaddr = ifra->ifra_dstaddr;
|
||||||
maskIsNew = 1; /* We lie; but the effect's the same */
|
maskIsNew = 1; /* We lie; but the effect's the same */
|
||||||
}
|
}
|
||||||
@ -585,7 +585,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
|||||||
/*
|
/*
|
||||||
* in_ifscrub kills the interface route.
|
* in_ifscrub kills the interface route.
|
||||||
*/
|
*/
|
||||||
in_ifscrub(ifp, ia);
|
in_ifscrub(ifp, ia, LLE_STATIC);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* in_ifadown gets rid of all the rest of
|
* in_ifadown gets rid of all the rest of
|
||||||
@ -829,10 +829,10 @@ in_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data,
|
|||||||
* Delete any existing route for an interface.
|
* Delete any existing route for an interface.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
in_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia)
|
in_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia, u_int flags)
|
||||||
{
|
{
|
||||||
|
|
||||||
in_scrubprefix(ia);
|
in_scrubprefix(ia, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -887,7 +887,7 @@ in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
|
|||||||
splx(s);
|
splx(s);
|
||||||
if (scrub) {
|
if (scrub) {
|
||||||
ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
|
ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
|
||||||
in_ifscrub(ifp, ia);
|
in_ifscrub(ifp, ia, LLE_STATIC);
|
||||||
ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
|
ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
|
||||||
}
|
}
|
||||||
if (IN_CLASSA(i))
|
if (IN_CLASSA(i))
|
||||||
@ -1095,7 +1095,7 @@ extern void arp_ifscrub(struct ifnet *ifp, uint32_t addr);
|
|||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
in_scrubprefix(struct in_ifaddr *target)
|
in_scrubprefix(struct in_ifaddr *target, u_int flags)
|
||||||
{
|
{
|
||||||
struct in_ifaddr *ia;
|
struct in_ifaddr *ia;
|
||||||
struct in_addr prefix, mask, p;
|
struct in_addr prefix, mask, p;
|
||||||
@ -1130,13 +1130,15 @@ in_scrubprefix(struct in_ifaddr *target)
|
|||||||
RT_REMREF(ia_ro.ro_rt);
|
RT_REMREF(ia_ro.ro_rt);
|
||||||
RTFREE_LOCKED(ia_ro.ro_rt);
|
RTFREE_LOCKED(ia_ro.ro_rt);
|
||||||
}
|
}
|
||||||
if (freeit)
|
if (freeit && (flags & LLE_STATIC)) {
|
||||||
error = ifa_del_loopback_route((struct ifaddr *)target,
|
error = ifa_del_loopback_route((struct ifaddr *)target,
|
||||||
(struct sockaddr *)&target->ia_addr);
|
(struct sockaddr *)&target->ia_addr);
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
target->ia_flags &= ~IFA_RTSELF;
|
target->ia_flags &= ~IFA_RTSELF;
|
||||||
/* remove arp cache */
|
}
|
||||||
arp_ifscrub(target->ia_ifp, IA_SIN(target)->sin_addr.s_addr);
|
if (flags & LLE_STATIC)
|
||||||
|
/* remove arp cache */
|
||||||
|
arp_ifscrub(target->ia_ifp, IA_SIN(target)->sin_addr.s_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtinitflags(target))
|
if (rtinitflags(target))
|
||||||
@ -1203,7 +1205,7 @@ in_scrubprefix(struct in_ifaddr *target)
|
|||||||
mask0.sin_family = AF_INET;
|
mask0.sin_family = AF_INET;
|
||||||
mask0.sin_addr.s_addr = target->ia_subnetmask;
|
mask0.sin_addr.s_addr = target->ia_subnetmask;
|
||||||
lltable_prefix_free(AF_INET, (struct sockaddr *)&prefix0,
|
lltable_prefix_free(AF_INET, (struct sockaddr *)&prefix0,
|
||||||
(struct sockaddr *)&mask0);
|
(struct sockaddr *)&mask0, flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As no-one seem to have this prefix, we can remove the route.
|
* As no-one seem to have this prefix, we can remove the route.
|
||||||
@ -1362,7 +1364,8 @@ in_lltable_free(struct lltable *llt, struct llentry *lle)
|
|||||||
static void
|
static void
|
||||||
in_lltable_prefix_free(struct lltable *llt,
|
in_lltable_prefix_free(struct lltable *llt,
|
||||||
const struct sockaddr *prefix,
|
const struct sockaddr *prefix,
|
||||||
const struct sockaddr *mask)
|
const struct sockaddr *mask,
|
||||||
|
u_int flags)
|
||||||
{
|
{
|
||||||
const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix;
|
const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix;
|
||||||
const struct sockaddr_in *msk = (const struct sockaddr_in *)mask;
|
const struct sockaddr_in *msk = (const struct sockaddr_in *)mask;
|
||||||
@ -1373,8 +1376,13 @@ in_lltable_prefix_free(struct lltable *llt,
|
|||||||
for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
|
for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
|
||||||
LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
|
LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (flags & LLE_STATIC) means deleting all entries
|
||||||
|
* including static ARP entries
|
||||||
|
*/
|
||||||
if (IN_ARE_MASKED_ADDR_EQUAL((struct sockaddr_in *)L3_ADDR(lle),
|
if (IN_ARE_MASKED_ADDR_EQUAL((struct sockaddr_in *)L3_ADDR(lle),
|
||||||
pfx, msk)) {
|
pfx, msk) &&
|
||||||
|
((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))) {
|
||||||
int canceled;
|
int canceled;
|
||||||
|
|
||||||
canceled = callout_drain(&lle->la_timer);
|
canceled = callout_drain(&lle->la_timer);
|
||||||
|
@ -447,7 +447,7 @@ int in_control(struct socket *, u_long, caddr_t, struct ifnet *,
|
|||||||
void in_rtqdrain(void);
|
void in_rtqdrain(void);
|
||||||
void ip_input(struct mbuf *);
|
void ip_input(struct mbuf *);
|
||||||
int in_ifadown(struct ifaddr *ifa, int);
|
int in_ifadown(struct ifaddr *ifa, int);
|
||||||
void in_ifscrub(struct ifnet *, struct in_ifaddr *);
|
void in_ifscrub(struct ifnet *, struct in_ifaddr *, u_int);
|
||||||
struct mbuf *ip_fastforward(struct mbuf *);
|
struct mbuf *ip_fastforward(struct mbuf *);
|
||||||
void *in_domifattach(struct ifnet *);
|
void *in_domifattach(struct ifnet *);
|
||||||
void in_domifdetach(struct ifnet *, void *);
|
void in_domifdetach(struct ifnet *, void *);
|
||||||
|
@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <netinet/in_systm.h>
|
#include <netinet/in_systm.h>
|
||||||
#include <netinet/in_pcb.h>
|
#include <netinet/in_pcb.h>
|
||||||
#include <netinet/in_var.h>
|
#include <netinet/in_var.h>
|
||||||
|
#include <netinet/if_ether.h>
|
||||||
#include <netinet/ip.h>
|
#include <netinet/ip.h>
|
||||||
#include <netinet/ip_var.h>
|
#include <netinet/ip_var.h>
|
||||||
#include <netinet/ip_mroute.h>
|
#include <netinet/ip_mroute.h>
|
||||||
@ -721,7 +722,7 @@ rip_ctlinput(int cmd, struct sockaddr *sa, void *vip)
|
|||||||
/*
|
/*
|
||||||
* in_ifscrub kills the interface route.
|
* in_ifscrub kills the interface route.
|
||||||
*/
|
*/
|
||||||
in_ifscrub(ia->ia_ifp, ia);
|
in_ifscrub(ia->ia_ifp, ia, 0);
|
||||||
/*
|
/*
|
||||||
* in_ifadown gets rid of all the rest of the
|
* in_ifadown gets rid of all the rest of the
|
||||||
* routes. This is not quite the right thing
|
* routes. This is not quite the right thing
|
||||||
@ -756,12 +757,18 @@ rip_ctlinput(int cmd, struct sockaddr *sa, void *vip)
|
|||||||
|| (ifp->if_flags & IFF_POINTOPOINT))
|
|| (ifp->if_flags & IFF_POINTOPOINT))
|
||||||
flags |= RTF_HOST;
|
flags |= RTF_HOST;
|
||||||
|
|
||||||
|
err = ifa_del_loopback_route((struct ifaddr *)ia, sa);
|
||||||
|
if (err == 0)
|
||||||
|
ia->ia_flags &= ~IFA_RTSELF;
|
||||||
|
|
||||||
err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
|
err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
ia->ia_flags |= IFA_ROUTE;
|
ia->ia_flags |= IFA_ROUTE;
|
||||||
|
|
||||||
err = ifa_add_loopback_route((struct ifaddr *)ia, sa);
|
err = ifa_add_loopback_route((struct ifaddr *)ia, sa);
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
ia->ia_flags |= IFA_RTSELF;
|
ia->ia_flags |= IFA_RTSELF;
|
||||||
|
|
||||||
ifa_free(&ia->ia_ifa);
|
ifa_free(&ia->ia_ifa);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2376,19 +2376,25 @@ in6_lltable_free(struct lltable *llt, struct llentry *lle)
|
|||||||
static void
|
static void
|
||||||
in6_lltable_prefix_free(struct lltable *llt,
|
in6_lltable_prefix_free(struct lltable *llt,
|
||||||
const struct sockaddr *prefix,
|
const struct sockaddr *prefix,
|
||||||
const struct sockaddr *mask)
|
const struct sockaddr *mask,
|
||||||
|
u_int flags)
|
||||||
{
|
{
|
||||||
const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix;
|
const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix;
|
||||||
const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask;
|
const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask;
|
||||||
struct llentry *lle, *next;
|
struct llentry *lle, *next;
|
||||||
register int i;
|
register int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (flags & LLE_STATIC) means deleting all entries
|
||||||
|
* including static ND6 entries
|
||||||
|
*/
|
||||||
for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
|
for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
|
||||||
LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
|
LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
|
||||||
if (IN6_ARE_MASKED_ADDR_EQUAL(
|
if (IN6_ARE_MASKED_ADDR_EQUAL(
|
||||||
&((struct sockaddr_in6 *)L3_ADDR(lle))->sin6_addr,
|
&((struct sockaddr_in6 *)L3_ADDR(lle))->sin6_addr,
|
||||||
&pfx->sin6_addr,
|
&pfx->sin6_addr,
|
||||||
&msk->sin6_addr)) {
|
&msk->sin6_addr) &&
|
||||||
|
((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))) {
|
||||||
int canceled;
|
int canceled;
|
||||||
|
|
||||||
canceled = callout_drain(&lle->la_timer);
|
canceled = callout_drain(&lle->la_timer);
|
||||||
|
Loading…
Reference in New Issue
Block a user