summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2014-04-03 08:22:11 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2014-04-03 08:22:11 +0000
commit5c9c0f16453c4e53faa6126eb82dc8f69125ffe3 (patch)
tree740314f701df73b18f6c3a2e55a9908e527487c4 /sys/net
parent0dbbe52b63ffab48f521b6d2ba15c468441effd1 (diff)
Introduce rt_ifa_{add,del}loop() to replace in6_{add,rem}loop().
Move these functions to a more generic place and make them reuse existing code, they'll be soon used in IPv4 too. Tested by André Lucas, Vigdis and sthen@, thanks! ok sthen@
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/route.c178
-rw-r--r--sys/net/route.h4
2 files changed, 132 insertions, 50 deletions
diff --git a/sys/net/route.c b/sys/net/route.c
index 2b0e08c8648..d0e80e51646 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.c,v 1.157 2014/03/27 10:39:23 mpi Exp $ */
+/* $OpenBSD: route.c,v 1.158 2014/04/03 08:22:10 mpi Exp $ */
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
/*
@@ -150,6 +150,9 @@ int rtflushclone1(struct radix_node *, void *, u_int);
void rtflushclone(struct radix_node_head *, struct rtentry *);
int rt_if_remove_rtdelete(struct radix_node *, void *, u_int);
+int rt_ifa_add(struct ifaddr *, int, struct sockaddr *);
+int rt_ifa_del(struct ifaddr *, int, struct sockaddr *);
+
#define LABELID_MAX 50000
struct rt_label {
@@ -1083,67 +1086,46 @@ rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst,
int
rtinit(struct ifaddr *ifa, int cmd, int flags)
{
- struct rtentry *rt;
- struct sockaddr *dst, *deldst;
- struct mbuf *m = NULL;
- struct rtentry *nrt = NULL;
- int error;
- struct rt_addrinfo info;
+ struct sockaddr *dst;
+ int error;
+
+ KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE);
+
+ dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
+
+ if (cmd == RTM_ADD)
+ error = rt_ifa_add(ifa, flags, dst);
+ else
+ error = rt_ifa_del(ifa, flags, dst);
+
+ return (error);
+}
+
+int
+rt_ifa_add(struct ifaddr *ifa, int flags, struct sockaddr *dst)
+{
+ struct rtentry *rt, *nrt = NULL;
struct sockaddr_rtlabel sa_rl;
+ struct rt_addrinfo info;
u_short rtableid = ifa->ifa_ifp->if_rdomain;
+ int error;
- dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
- if (cmd == RTM_DELETE) {
- if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
- m = m_get(M_DONTWAIT, MT_SONAME);
- if (m == NULL)
- return (ENOBUFS);
- deldst = mtod(m, struct sockaddr *);
- rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
- dst = deldst;
- }
- if ((rt = rtalloc1(dst, 0, rtableid)) != NULL) {
- rt->rt_refcnt--;
- /* try to find the right route */
- while (rt && rt->rt_ifa != ifa)
- rt = (struct rtentry *)
- ((struct radix_node *)rt)->rn_dupedkey;
- if (!rt) {
- if (m != NULL)
- (void) m_free(m);
- return (flags & RTF_HOST ? EHOSTUNREACH
- : ENETUNREACH);
- }
- }
- }
- bzero(&info, sizeof(info));
+ memset(&info, 0, sizeof(info));
info.rti_ifa = ifa;
info.rti_flags = flags;
info.rti_info[RTAX_DST] = dst;
- if (cmd == RTM_ADD)
- info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
+ info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
info.rti_info[RTAX_LABEL] =
rtlabel_id2sa(ifa->ifa_ifp->if_rtlabelid, &sa_rl);
if ((flags & RTF_HOST) == 0)
info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
- error = rtrequest1(cmd, &info, RTP_CONNECTED, &nrt, rtableid);
- if (cmd == RTM_DELETE) {
- if (error == 0 && (rt = nrt) != NULL) {
- rt_newaddrmsg(cmd, ifa, error, nrt);
- if (rt->rt_refcnt <= 0) {
- rt->rt_refcnt++;
- rtfree(rt);
- }
- }
- if (m != NULL)
- (void) m_free(m);
- }
- if (cmd == RTM_ADD && error == 0 && (rt = nrt) != NULL) {
+ error = rtrequest1(RTM_ADD, &info, RTP_CONNECTED, &nrt, rtableid);
+ if (error == 0 && (rt = nrt) != NULL) {
rt->rt_refcnt--;
if (rt->rt_ifa != ifa) {
- printf("rtinit: wrong ifa (%p) was (%p)\n",
+ printf("%s: wrong ifa (%p) was (%p)\n", __func__,
ifa, rt->rt_ifa);
if (rt->rt_ifa->ifa_rtrequest)
rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt);
@@ -1154,12 +1136,110 @@ rtinit(struct ifaddr *ifa, int cmd, int flags)
if (ifa->ifa_rtrequest)
ifa->ifa_rtrequest(RTM_ADD, rt);
}
- rt_newaddrmsg(cmd, ifa, error, nrt);
+ rt_newaddrmsg(RTM_ADD, ifa, error, nrt);
+ }
+ return (error);
+}
+
+int
+rt_ifa_del(struct ifaddr *ifa, int flags, struct sockaddr *dst)
+{
+ struct rtentry *rt, *nrt = NULL;
+ struct mbuf *m = NULL;
+ struct sockaddr *deldst;
+ struct rt_addrinfo info;
+ struct sockaddr_rtlabel sa_rl;
+ u_short rtableid = ifa->ifa_ifp->if_rdomain;
+ int error;
+
+ if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
+ m = m_get(M_DONTWAIT, MT_SONAME);
+ if (m == NULL)
+ return (ENOBUFS);
+ deldst = mtod(m, struct sockaddr *);
+ rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
+ dst = deldst;
+ }
+ if ((rt = rtalloc1(dst, 0, rtableid)) != NULL) {
+ rt->rt_refcnt--;
+ /* try to find the right route */
+ while (rt && rt->rt_ifa != ifa)
+ rt = (struct rtentry *)
+ ((struct radix_node *)rt)->rn_dupedkey;
+ if (!rt) {
+ if (m != NULL)
+ (void) m_free(m);
+ return (flags & RTF_HOST ? EHOSTUNREACH
+ : ENETUNREACH);
+ }
}
+
+ memset(&info, 0, sizeof(info));
+ info.rti_ifa = ifa;
+ info.rti_flags = flags;
+ info.rti_info[RTAX_DST] = dst;
+ info.rti_info[RTAX_LABEL] =
+ rtlabel_id2sa(ifa->ifa_ifp->if_rtlabelid, &sa_rl);
+
+ if ((flags & RTF_HOST) == 0)
+ info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
+
+ error = rtrequest1(RTM_DELETE, &info, RTP_CONNECTED, &nrt, rtableid);
+ if (error == 0 && (rt = nrt) != NULL) {
+ rt_newaddrmsg(RTM_DELETE, ifa, error, nrt);
+ if (rt->rt_refcnt <= 0) {
+ rt->rt_refcnt++;
+ rtfree(rt);
+ }
+ }
+ if (m != NULL)
+ m_free(m);
+
return (error);
}
/*
+ * Add ifa's address as a loopback rtentry.
+ */
+void
+rt_ifa_addloop(struct ifaddr *ifa)
+{
+ struct rtentry *rt;
+
+ /* If there is no loopback entry, allocate one. */
+ rt = rtalloc1(ifa->ifa_addr, 0, ifa->ifa_ifp->if_rdomain);
+ if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
+ (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
+ rt_ifa_add(ifa, RTF_UP| RTF_HOST | RTF_LLINFO, ifa->ifa_addr);
+ if (rt)
+ rt->rt_refcnt--;
+}
+
+/*
+ * Remove loopback rtentry of ifa's addresss if it exists.
+ */
+void
+rt_ifa_delloop(struct ifaddr *ifa)
+{
+ struct rtentry *rt;
+
+ /*
+ * Before deleting, check if a corresponding loopbacked host
+ * route surely exists. With this check, we can avoid to
+ * delete an interface direct route whose destination is same
+ * as the address being removed. This can happen when removing
+ * a subnet-router anycast address on an interface attached
+ * to a shared medium.
+ */
+ rt = rtalloc1(ifa->ifa_addr, 0, ifa->ifa_ifp->if_rdomain);
+ if (rt != NULL && (rt->rt_flags & RTF_HOST) != 0 &&
+ (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0)
+ rt_ifa_del(ifa, RTF_HOST | RTF_LLINFO, ifa->ifa_addr);
+ if (rt)
+ rt->rt_refcnt--;
+}
+
+/*
* Route timer routines. These routes allow functions to be called
* for various routes at any time. This is useful in supporting
* path MTU discovery and redirect route deletion.
diff --git a/sys/net/route.h b/sys/net/route.h
index 90ef5d5d311..7139dcfe7e6 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.h,v 1.89 2014/03/21 10:44:42 mpi Exp $ */
+/* $OpenBSD: route.h,v 1.90 2014/04/03 08:22:10 mpi Exp $ */
/* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */
/*
@@ -402,6 +402,8 @@ struct rtentry *
void rtfree(struct rtentry *);
int rt_getifa(struct rt_addrinfo *, u_int);
int rtinit(struct ifaddr *, int, int);
+void rt_ifa_addloop(struct ifaddr *);
+void rt_ifa_delloop(struct ifaddr *);
int rtioctl(u_long, caddr_t, struct proc *);
void rtredirect(struct sockaddr *, struct sockaddr *,
struct sockaddr *, int, struct sockaddr *,