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.
This commit is contained in:
Garrett Wollman 1997-02-13 19:46:45 +00:00
parent 30f700e9c7
commit 39191c8eb8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=22672
6 changed files with 117 additions and 5 deletions

View File

@ -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;

View File

@ -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,
},

View File

@ -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;
}

View File

@ -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 */

View File

@ -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));

View File

@ -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 ? */