From 553a7dec4b4e11bbb3257f5daa92ce594740fedc Mon Sep 17 00:00:00 2001 From: Qing Li Date: Tue, 15 Sep 2009 22:46:06 +0000 Subject: [PATCH] MFC r197227 Self pointing routes are installed for configured interface addresses 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 Approved by: re --- sys/net/if.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ sys/net/if_var.h | 3 +++ sys/netinet/in.c | 42 +++++------------------------------ sys/netinet/raw_ip.c | 1 + sys/netinet6/in6.c | 44 +++++------------------------------- 5 files changed, 67 insertions(+), 76 deletions(-) diff --git a/sys/net/if.c b/sys/net/if.c index 36c0d037b9a..c0ff443d6dc 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -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 diff --git a/sys/net/if_var.h b/sys/net/if_var.h index 3ab620816a4..523b9e8a813 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -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 *); diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 626f63e2243..b22d2737f92 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -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; @@ -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); } @@ -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. @@ -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) { diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 3df2ec3562d..b40ceb28b79 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -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; } diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index c832305b162..aef2908abd2 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -1195,24 +1196,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); @@ -1771,27 +1756,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). */