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:
parent
1f8c9c194a
commit
8f1bd632d4
@ -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;
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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 ? */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user