summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorwollman <wollman@FreeBSD.org>1997-02-13 19:46:45 +0000
committerwollman <wollman@FreeBSD.org>1997-02-13 19:46:45 +0000
commit8f1bd632d4528e09dc9ca0ed45397ded3364d354 (patch)
tree754e6568b416e501652bc6bb3e1c72d391ec0257 /sys
parent1f8c9c194a905535c832a0021936cf4734355267 (diff)
downloadFreeBSD-src-8f1bd632d4528e09dc9ca0ed45397ded3364d354.zip
FreeBSD-src-8f1bd632d4528e09dc9ca0ed45397ded3364d354.tar.gz
Provide PRC_IFDOWN and PRC_IFUP support for IP. Now, when an interface
is administratively downed, all routes to that interface (including the interface route itself) which are not static will be deleted. When it comes back up, and addresses remaining will have their interface routes re-added. This solves the problem where, for example, an Ethernet interface is downed by traffic continues to flow by way of ARP entries.
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/in.c3
-rw-r--r--sys/netinet/in_proto.c2
-rw-r--r--sys/netinet/in_rmx.c50
-rw-r--r--sys/netinet/in_var.h2
-rw-r--r--sys/netinet/ip_var.h1
-rw-r--r--sys/netinet/raw_ip.c64
6 files changed, 117 insertions, 5 deletions
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index a52ec77..60bf97a 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -58,7 +58,6 @@
static void in_socktrim __P((struct sockaddr_in *));
static int in_ifinit __P((struct ifnet *,
struct in_ifaddr *, struct sockaddr_in *, int));
-static void in_ifscrub __P((struct ifnet *, struct in_ifaddr *));
static int subnetsarelocal = 0;
SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW,
@@ -366,7 +365,7 @@ in_control(so, cmd, data, ifp)
/*
* Delete any existing route for an interface.
*/
-static void
+void
in_ifscrub(ifp, ia)
register struct ifnet *ifp;
register struct in_ifaddr *ia;
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index 5b66e0d..9a80959 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -116,7 +116,7 @@ struct protosw inetsw[] = {
&tcp_usrreqs
},
{ SOCK_RAW, &inetdomain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR,
- rip_input, 0, 0, rip_ctloutput,
+ rip_input, 0, rip_ctlinput, rip_ctloutput,
rip_usrreq,
0, 0, 0, 0,
},
diff --git a/sys/netinet/in_rmx.c b/sys/netinet/in_rmx.c
index 095afc9..a302c1a 100644
--- a/sys/netinet/in_rmx.c
+++ b/sys/netinet/in_rmx.c
@@ -26,7 +26,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
+ * $Id$
*/
/*
@@ -382,3 +382,51 @@ in_inithead(void **head, int off)
return 1;
}
+
+/*
+ * This zaps old routes when the interface goes down.
+ * Currently it doesn't delete static routes; there are
+ * arguments one could make for both behaviors. For the moment,
+ * we will adopt the Principle of Least Surprise and leave them
+ * alone (with the knowledge that this will not be enough for some
+ * people). The ones we really want to get rid of are things like ARP
+ * entries, since the user might down the interface, walk over to a completely
+ * different network, and plug back in.
+ */
+struct in_ifadown_arg {
+ struct radix_node_head *rnh;
+ struct ifaddr *ifa;
+};
+
+static int
+in_ifadownkill(struct radix_node *rn, void *xap)
+{
+ struct in_ifadown_arg *ap = xap;
+ struct rtentry *rt = (struct rtentry *)rn;
+ int err;
+
+ if (rt->rt_ifa == ap->ifa && !(rt->rt_flags & RTF_STATIC)) {
+ err = rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
+ rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
+ if (err) {
+ log(LOG_WARNING, "in_ifadownkill: error %d\n", err);
+ }
+ }
+ return 0;
+}
+
+int
+in_ifadown(struct ifaddr *ifa)
+{
+ struct in_ifadown_arg arg;
+ struct radix_node_head *rnh;
+
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ return 1;
+
+ arg.rnh = rnh = rt_tables[AF_INET];
+ arg.ifa = ifa;
+ rnh->rnh_walktree(rnh, in_ifadownkill, &arg);
+ ifa->ifa_flags &= ~IFA_ROUTE;
+ return 0;
+}
diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h
index f760956..dfc08ca 100644
--- a/sys/netinet/in_var.h
+++ b/sys/netinet/in_var.h
@@ -219,6 +219,8 @@ void in_delmulti __P((struct in_multi *));
int in_control __P((struct socket *, u_long, caddr_t, struct ifnet *));
void in_rtqdrain __P((void));
void ip_input __P((struct mbuf *));
+int in_ifadown __P((struct ifaddr *ifa));
+void in_ifscrub __P((struct ifnet *, struct in_ifaddr *));
#endif /* KERNEL */
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index 5f595b5..75a60fc 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -186,6 +186,7 @@ struct mbuf *
ip_srcroute __P((void));
void ip_stripoptions __P((struct mbuf *, struct mbuf *));
int rip_ctloutput __P((int, struct socket *, int, int, struct mbuf **));
+void rip_ctlinput __P((int, struct sockaddr *, void *));
void rip_init __P((void));
void rip_input __P((struct mbuf *, int));
int rip_output __P((struct mbuf *, struct socket *, u_long));
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index c5382e0..0011ab2 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)raw_ip.c 8.7 (Berkeley) 5/15/95
- * $FreeBSD$
+ * $Id$
*/
#include <sys/param.h>
@@ -314,6 +314,68 @@ rip_ctloutput(op, so, level, optname, m)
return (ip_ctloutput(op, so, level, optname, m));
}
+/*
+ * This function exists solely to receive the PRC_IFDOWN messages which
+ * are sent by if_down(). It looks for an ifaddr whose ifa_addr is sa,
+ * and calls in_ifadown() to remove all routes corresponding to that address.
+ * It also receives the PRC_IFUP messages from if_up() and reinstalls the
+ * interface routes.
+ */
+void
+rip_ctlinput(cmd, sa, vip)
+ int cmd;
+ struct sockaddr *sa;
+ void *vip;
+{
+ struct in_ifaddr *ia;
+ struct ifnet *ifp;
+ int err;
+ int flags;
+
+ switch(cmd) {
+ case PRC_IFDOWN:
+ for (ia = in_ifaddrhead.tqh_first; ia;
+ ia = ia->ia_link.tqe_next) {
+ if (ia->ia_ifa.ifa_addr == sa
+ && (ia->ia_flags & IFA_ROUTE)) {
+ /*
+ * in_ifscrub kills the interface route.
+ */
+ in_ifscrub(ia->ia_ifp, ia);
+ /*
+ * in_ifadown gets rid of all the rest of
+ * the routes. This is not quite the right
+ * thing to do, but at least if we are running
+ * a routing process they will come back.
+ */
+ in_ifadown(&ia->ia_ifa);
+ break;
+ }
+ }
+ break;
+
+ case PRC_IFUP:
+ for (ia = in_ifaddrhead.tqh_first; ia;
+ ia = ia->ia_link.tqe_next) {
+ if (ia->ia_ifa.ifa_addr == sa)
+ break;
+ }
+ if (ia == 0 || (ia->ia_flags & IFA_ROUTE))
+ return;
+ flags = RTF_UP;
+ ifp = ia->ia_ifa.ifa_ifp;
+
+ if ((ifp->if_flags & IFF_LOOPBACK)
+ || (ifp->if_flags & IFF_POINTOPOINT))
+ flags |= RTF_HOST;
+
+ err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
+ if (err == 0)
+ ia->ia_flags |= IFA_ROUTE;
+ break;
+ }
+}
+
static u_long rip_sendspace = RIPSNDQ; /* XXX sysctl ? */
static u_long rip_recvspace = RIPRCVQ; /* XXX sysctl ? */
OpenPOWER on IntegriCloud