summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorqingli <qingli@FreeBSD.org>2009-09-15 19:18:34 +0000
committerqingli <qingli@FreeBSD.org>2009-09-15 19:18:34 +0000
commit3a82e44273f4a5c05d848c2959b2a9d8188b1ba0 (patch)
tree8e25508f7a40afe500dc06cba8d3a6b18f4d7335 /sys/net
parent620c678111a81c88256575cb8a1e9fff36f90003 (diff)
downloadFreeBSD-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.c53
-rw-r--r--sys/net/if_var.h3
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 *);
OpenPOWER on IntegriCloud