Skip to content

Commit

Permalink
Self pointing routes are installed for configured interface addresses
Browse files Browse the repository at this point in the history
and address aliases. After an interface is brought down and brought
back up again, those self pointing routes disappeared. This patch
ensures after an interface is brought back up, the loopback routes
are reinstalled properly.

Reviewed by:	bz
MFC after:	immediately
  • Loading branch information
Qing Li authored and Qing Li committed Sep 15, 2009
1 parent cd29a77 commit 9bb7d0f
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 76 deletions.
53 changes: 53 additions & 0 deletions sys/net/if.c
Expand Up @@ -1414,6 +1414,59 @@ ifa_free(struct ifaddr *ifa)
}
}

int
ifa_add_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
{
int error = 0;
struct rtentry *rt = NULL;
struct rt_addrinfo info;
static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};

bzero(&info, sizeof(info));
info.rti_ifp = V_loif;
info.rti_flags = ifa->ifa_flags | RTF_HOST | RTF_STATIC;
info.rti_info[RTAX_DST] = ia;
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl;
error = rtrequest1_fib(RTM_ADD, &info, &rt, 0);

if (error == 0 && rt != NULL) {
RT_LOCK(rt);
((struct sockaddr_dl *)rt->rt_gateway)->sdl_type =
rt->rt_ifp->if_type;
((struct sockaddr_dl *)rt->rt_gateway)->sdl_index =
rt->rt_ifp->if_index;
RT_REMREF(rt);
RT_UNLOCK(rt);
} else if (error != 0)
log(LOG_INFO, "ifa_add_loopback_route: insertion failed\n");

return (error);
}

int
ifa_del_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
{
int error = 0;
struct rt_addrinfo info;
struct sockaddr_dl null_sdl;

bzero(&null_sdl, sizeof(null_sdl));
null_sdl.sdl_len = sizeof(null_sdl);
null_sdl.sdl_family = AF_LINK;
null_sdl.sdl_type = ifa->ifa_ifp->if_type;
null_sdl.sdl_index = ifa->ifa_ifp->if_index;
bzero(&info, sizeof(info));
info.rti_flags = ifa->ifa_flags | RTF_HOST | RTF_STATIC;
info.rti_info[RTAX_DST] = ia;
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl;
error = rtrequest1_fib(RTM_DELETE, &info, NULL, 0);

if (error != 0)
log(LOG_INFO, "ifa_del_loopback_route: deletion failed\n");

return (error);
}

/*
* XXX: Because sockaddr_dl has deeper structure than the sockaddr
* structs used to represent other address families, it is necessary
Expand Down
3 changes: 3 additions & 0 deletions sys/net/if_var.h
Expand Up @@ -854,6 +854,9 @@ struct ifnet *ifunit_ref(const char *);
void ifq_init(struct ifaltq *, struct ifnet *ifp);
void ifq_delete(struct ifaltq *);

int ifa_add_loopback_route(struct ifaddr *, struct sockaddr *);
int ifa_del_loopback_route(struct ifaddr *, struct sockaddr *);

struct ifaddr *ifa_ifwithaddr(struct sockaddr *);
int ifa_ifwithaddr_check(struct sockaddr *);
struct ifaddr *ifa_ifwithbroadaddr(struct sockaddr *);
Expand Down
42 changes: 5 additions & 37 deletions sys/netinet/in.c
Expand Up @@ -827,9 +827,6 @@ in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
{
register u_long i = ntohl(sin->sin_addr.s_addr);
struct sockaddr_in oldaddr;
struct rtentry *rt = NULL;
struct rt_addrinfo info;
static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
int s = splimp(), flags = RTF_UP, error = 0;

oldaddr = ia->ia_addr;
Expand Down Expand Up @@ -927,25 +924,9 @@ in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
/*
* add a loopback route to self
*/
if (V_useloopback && !(ifp->if_flags & IFF_LOOPBACK)) {
bzero(&info, sizeof(info));
info.rti_ifp = V_loif;
info.rti_flags = ia->ia_flags | RTF_HOST | RTF_STATIC;
info.rti_info[RTAX_DST] = (struct sockaddr *)&ia->ia_addr;
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl;
error = rtrequest1_fib(RTM_ADD, &info, &rt, 0);

if (error == 0 && rt != NULL) {
RT_LOCK(rt);
((struct sockaddr_dl *)rt->rt_gateway)->sdl_type =
rt->rt_ifp->if_type;
((struct sockaddr_dl *)rt->rt_gateway)->sdl_index =
rt->rt_ifp->if_index;
RT_REMREF(rt);
RT_UNLOCK(rt);
} else if (error != 0)
log(LOG_INFO, "in_ifinit: insertion failed\n");
}
if (V_useloopback && !(ifp->if_flags & IFF_LOOPBACK))
error = ifa_add_loopback_route((struct ifaddr *)ia,
(struct sockaddr *)&ia->ia_addr);

return (error);
}
Expand Down Expand Up @@ -1064,8 +1045,6 @@ in_scrubprefix(struct in_ifaddr *target)
struct in_addr prefix, mask, p;
int error;
struct sockaddr_in prefix0, mask0;
struct rt_addrinfo info;
struct sockaddr_dl null_sdl;

/*
* Remove the loopback route to the interface address.
Expand All @@ -1079,19 +1058,8 @@ in_scrubprefix(struct in_ifaddr *target)
*/
if ((target->ia_addr.sin_addr.s_addr != INADDR_ANY) &&
!(target->ia_ifp->if_flags & IFF_LOOPBACK)) {
bzero(&null_sdl, sizeof(null_sdl));
null_sdl.sdl_len = sizeof(null_sdl);
null_sdl.sdl_family = AF_LINK;
null_sdl.sdl_type = V_loif->if_type;
null_sdl.sdl_index = V_loif->if_index;
bzero(&info, sizeof(info));
info.rti_flags = target->ia_flags | RTF_HOST | RTF_STATIC;
info.rti_info[RTAX_DST] = (struct sockaddr *)&target->ia_addr;
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl;
error = rtrequest1_fib(RTM_DELETE, &info, NULL, 0);

if (error != 0)
log(LOG_INFO, "in_scrubprefix: deletion failed\n");
error = ifa_del_loopback_route((struct ifaddr *)target,
(struct sockaddr *)&target->ia_addr);
}

if ((target->ia_flags & IFA_ROUTE) == 0) {
Expand Down
1 change: 1 addition & 0 deletions sys/netinet/raw_ip.c
Expand Up @@ -715,6 +715,7 @@ rip_ctlinput(int cmd, struct sockaddr *sa, void *vip)
err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
if (err == 0)
ia->ia_flags |= IFA_ROUTE;
err = ifa_add_loopback_route((struct ifaddr *)ia, sa);
ifa_free(&ia->ia_ifa);
break;
}
Expand Down
44 changes: 5 additions & 39 deletions sys/netinet6/in6.c
Expand Up @@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$");
#include <sys/syslog.h>

#include <net/if.h>
#include <net/if_var.h>
#include <net/if_types.h>
#include <net/route.h>
#include <net/if_dl.h>
Expand Down Expand Up @@ -1199,24 +1200,8 @@ in6_purgeaddr(struct ifaddr *ifa)
* The check for the current setting of "nd6_useloopback"
* is not needed.
*/
{
struct rt_addrinfo info;
struct sockaddr_dl null_sdl;

bzero(&null_sdl, sizeof(null_sdl));
null_sdl.sdl_len = sizeof(null_sdl);
null_sdl.sdl_family = AF_LINK;
null_sdl.sdl_type = ia->ia_ifp->if_type;
null_sdl.sdl_index = ia->ia_ifp->if_index;
bzero(&info, sizeof(info));
info.rti_flags = ia->ia_flags | RTF_HOST | RTF_STATIC;
info.rti_info[RTAX_DST] = (struct sockaddr *)&ia->ia_addr;
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl;
error = rtrequest1_fib(RTM_DELETE, &info, NULL, 0);

if (error != 0)
log(LOG_INFO, "in6_purgeaddr: deletion failed\n");
}
error = ifa_del_loopback_route((struct ifaddr *)ia,
(struct sockaddr *)&ia->ia_addr);

/* stop DAD processing */
nd6_dad_stop(ifa);
Expand Down Expand Up @@ -1775,27 +1760,8 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
if (!(ia->ia_flags & IFA_ROUTE)
&& (V_nd6_useloopback
|| (ifp->if_flags & IFF_LOOPBACK))) {
struct rt_addrinfo info;
struct rtentry *rt = NULL;
static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};

bzero(&info, sizeof(info));
info.rti_ifp = V_loif;
info.rti_flags = ia->ia_flags | RTF_HOST | RTF_STATIC;
info.rti_info[RTAX_DST] = (struct sockaddr *)&ia->ia_addr;
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl;
error = rtrequest1_fib(RTM_ADD, &info, &rt, 0);

if (error == 0 && rt != NULL) {
RT_LOCK(rt);
((struct sockaddr_dl *)rt->rt_gateway)->sdl_type =
ifp->if_type;
((struct sockaddr_dl *)rt->rt_gateway)->sdl_index =
ifp->if_index;
RT_REMREF(rt);
RT_UNLOCK(rt);
} else if (error != 0)
log(LOG_INFO, "in6_ifinit: error = %d, insertion failed\n", error);
error = ifa_add_loopback_route((struct ifaddr *)ia,
(struct sockaddr *)&ia->ia_addr);
}

/* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */
Expand Down

0 comments on commit 9bb7d0f

Please sign in to comment.