Index: sys/netinet/raw_ip.c =================================================================== --- sys/netinet/raw_ip.c (revision 224705) +++ sys/netinet/raw_ip.c (working copy) @@ -761,17 +761,69 @@ || (ifp->if_flags & IFF_POINTOPOINT)) flags |= RTF_HOST; - err = ifa_del_loopback_route((struct ifaddr *)ia, sa); - if (err == 0) - ia->ia_flags &= ~IFA_RTSELF; + /* + * Try to install our prefix. The prefix already can be + * installed by another interface, so error can be ignored. + */ err = rtinit(&ia->ia_ifa, RTM_ADD, flags); if (err == 0) ia->ia_flags |= IFA_ROUTE; + /* + * Installed loopback route isn't deleted when interface + * is going down. So, here only check V_useloopback flag + * and act according to it. + */ + + if (!V_useloopback) { + if (ia->ia_flags & IFA_RTSELF) { + struct route ia_ro; + int freeit = 0; + + bzero(&ia_ro, sizeof(ia_ro)); + ia_ro.ro_dst = *sa; + rtalloc_ign_fib(&ia_ro, 0, 0); + if ((ia_ro.ro_rt != NULL) && (ia_ro.ro_rt->rt_ifp != NULL) && + (ia_ro.ro_rt->rt_ifp == V_loif)) { + RT_LOCK(ia_ro.ro_rt); + if (ia_ro.ro_rt->rt_refcnt <= 1) + freeit = 1; + else { + RT_REMREF(ia_ro.ro_rt); + ia->ia_flags &= ~IFA_RTSELF; + } + RTFREE_LOCKED(ia_ro.ro_rt); + } + if (freeit) { + err = ifa_del_loopback_route((struct ifaddr *)ia, + sa); + if (err == 0) + ia->ia_flags &= ~IFA_RTSELF; + } + } + } + else if (!(ia->ia_flags & IFA_RTSELF) && + !(ifp->if_flags & IFF_LOOPBACK)) { + struct route ia_ro; + + bzero(&ia_ro, sizeof(ia_ro)); + *((struct sockaddr_in *)(&ia_ro.ro_dst)) = ia->ia_addr; + rtalloc_ign_fib(&ia_ro, 0, 0); + if ((ia_ro.ro_rt != NULL) && (ia_ro.ro_rt->rt_ifp != NULL) && + (ia_ro.ro_rt->rt_ifp == V_loif)) { + RT_LOCK(ia_ro.ro_rt); + RT_ADDREF(ia_ro.ro_rt); + RTFREE_LOCKED(ia_ro.ro_rt); + ia->ia_flags |= IFA_RTSELF; + } else { err = ifa_add_loopback_route((struct ifaddr *)ia, sa); if (err == 0) ia->ia_flags |= IFA_RTSELF; + } + if (ia_ro.ro_rt != NULL) + RTFREE(ia_ro.ro_rt); + } ifa_free(&ia->ia_ifa); break;