diff options
author | qingli <qingli@FreeBSD.org> | 2009-09-15 19:18:34 +0000 |
---|---|---|
committer | qingli <qingli@FreeBSD.org> | 2009-09-15 19:18:34 +0000 |
commit | 3a82e44273f4a5c05d848c2959b2a9d8188b1ba0 (patch) | |
tree | 8e25508f7a40afe500dc06cba8d3a6b18f4d7335 /sys/net | |
parent | 620c678111a81c88256575cb8a1e9fff36f90003 (diff) | |
download | FreeBSD-src-3a82e44273f4a5c05d848c2959b2a9d8188b1ba0.zip FreeBSD-src-3a82e44273f4a5c05d848c2959b2a9d8188b1ba0.tar.gz |
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
MFC after: immediately
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if.c | 53 | ||||
-rw-r--r-- | sys/net/if_var.h | 3 |
2 files changed, 56 insertions, 0 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index 36c0d03..c0ff443 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 3ab6208..523b9e8 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 *); |