Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 Nov 2004 21:24:05 +0100
From:      Max Laier <max@love2party.net>
To:        freebsd-arch@freebsd.org
Cc:        freebsd-net@freebsd.org
Subject:   in.c autoadding prefix route
Message-ID:  <200411112124.12616.max@love2party.net>

next in thread | raw e-mail | index | archive | help
--nextPart4509686.Ad4VYY4PBk
Content-Type: multipart/mixed;
  boundary="Boundary-01=_np8kBd92qNtmEHy"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

--Boundary-01=_np8kBd92qNtmEHy
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

All,

I know I have sent this a couple of times before, but never got anywhere. T=
his=20
time I am set to commit!

The attached patch (http://people.freebsd.org/~mlaier/in.c.patch) derived f=
rom=20
WIDE via OpenBSD in.c, rev 1.21 improves the handling of automatic prefix=20
routes.

Right now you can't have two legs into the same network. If you want to, yo=
u=20
must give on of the interfaces a host address only (netmask /32). This way =
it=20
is not possible to hand over the route if one of the interfaces is=20
"removed" (however this is done in the special case).

The patch allows to add more than on IPv4 address with the same prefix. In =
the=20
case that there is a route already, we leave it alone and add the new addre=
ss=20
without the IFA_ROUTE flag. When we remove an address later on, that has a=
=20
route associated, we try to find an alternative address to use for the rout=
e=20
and hand it over.

This is required for CARP, but should be helpful for other situations as we=
ll.

Any objections?

I also plan to merge this back to RELENG_5 after some time. I don't see thi=
s=20
breaking assumptions (it was an error case before) - please tell me if you=
=20
see something.

=2D-=20
/"\  Best regards,                      | mlaier@freebsd.org
\ /  Max Laier                          | ICQ #67774661
 X   http://pf4freebsd.love2party.net/  | mlaier@EFnet
/ \  ASCII Ribbon Campaign              | Against HTML Mail and News

--Boundary-01=_np8kBd92qNtmEHy
Content-Type: text/x-diff;
  charset="us-ascii";
  name="in.c.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="in.c.patch"

=2D-- ../dist/sys/netinet/in.c	Sat Nov  6 21:01:08 2004
+++ sys/netinet/in.c	Mon Nov  8 02:05:17 2004
@@ -1,4 +1,32 @@
 /*
+ * Copyright (C) 2001 WIDE Project.  All rights reserved.
+ *=20
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *=20
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURP=
OSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENT=
IAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STR=
ICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY W=
AY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
  * Copyright (c) 1982, 1986, 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
@@ -55,6 +83,8 @@
 static int in_lifaddr_ioctl(struct socket *, u_long, caddr_t,
 	struct ifnet *, struct thread *);
=20
+static int	in_addprefix(struct in_ifaddr *, int);
+static int	in_scrubprefix(struct in_ifaddr *);
 static void	in_socktrim(struct sockaddr_in *);
 static int	in_ifinit(struct ifnet *,
 	    struct in_ifaddr *, struct sockaddr_in *, int);
@@ -654,14 +684,7 @@
 	register struct ifnet *ifp;
 	register struct in_ifaddr *ia;
 {
=2D
=2D	if ((ia->ia_flags & IFA_ROUTE) =3D=3D 0)
=2D		return;
=2D	if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
=2D		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
=2D	else
=2D		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
=2D	ia->ia_flags &=3D ~IFA_ROUTE;
+	in_scrubprefix(ia);
 }
=20
 /*
@@ -743,26 +766,7 @@
 			return (0);
 		flags |=3D RTF_HOST;
 	}
=2D
=2D	/*-
=2D	 * Don't add host routes for interface addresses of
=2D	 * 0.0.0.0 --> 0.255.255.255 netmask 255.0.0.0.  This makes it
=2D	 * possible to assign several such address pairs with consistent
=2D	 * results (no host route) and is required by BOOTP.
=2D	 *
=2D	 * XXX: This is ugly !  There should be a way for the caller to
=2D	 *      say that they don't want a host route.
=2D	 */
=2D	if (ia->ia_addr.sin_addr.s_addr !=3D INADDR_ANY ||
=2D	    ia->ia_netmask !=3D IN_CLASSA_NET ||
=2D	    ia->ia_dstaddr.sin_addr.s_addr !=3D htonl(IN_CLASSA_HOST)) {
=2D		if ((error =3D rtinit(&ia->ia_ifa, (int)RTM_ADD, flags)) !=3D 0) {
=2D			ia->ia_addr =3D oldaddr;
=2D			return (error);
=2D		}
=2D		ia->ia_flags |=3D IFA_ROUTE;
=2D	}
=2D
+	error =3D in_addprefix(ia, flags);
 	/*
 	 * If the interface supports multicast, join the "all hosts"
 	 * multicast group on that interface.
@@ -776,6 +780,118 @@
 	return (error);
 }
=20
+#define rtinitflags(x) \
+	((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) !=3D 0) \
+	    ? RTF_HOST : 0)
+/*
+ * add a route to prefix ("connected route" in cisco terminology).
+ * does nothing if there's some interface address with the same prefix alr=
eady.
+ */
+static int
+in_addprefix(target, flags)
+	struct in_ifaddr *target;
+	int flags;
+{
+	struct in_ifaddr *ia;
+	struct in_addr prefix, mask, p;
+	int error;
+
+	if ((flags & RTF_HOST) !=3D 0)
+		prefix =3D target->ia_dstaddr.sin_addr;
+	else {
+		prefix =3D target->ia_addr.sin_addr;
+		mask =3D target->ia_sockmask.sin_addr;
+		prefix.s_addr &=3D mask.s_addr;
+	}
+
+	TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
+			if (rtinitflags(ia))
+			p =3D ia->ia_dstaddr.sin_addr;
+		else {
+			p =3D ia->ia_addr.sin_addr;
+			p.s_addr &=3D ia->ia_sockmask.sin_addr.s_addr;
+		}
+
+		if (prefix.s_addr !=3D p.s_addr)
+			continue;
+
+		/*
+		 * if we got a matching prefix route inserted by other
+		 * interface adderss, we don't need to bother
+		 */
+		if (ia->ia_flags & IFA_ROUTE)
+			return 0;
+	}
+
+	/*
+	 * noone seem to have prefix route.  insert it.
+	 */
+	error =3D rtinit(&target->ia_ifa, (int)RTM_ADD, flags);
+	if (!error)
+		target->ia_flags |=3D IFA_ROUTE;
+	return error;
+}
+
+/*
+ * remove a route to prefix ("connected route" in cisco terminology).
+ * re-installs the route by using another interface address, if there's one
+ * with the same prefix (otherwise we lose the route mistakenly).
+ */
+static int
+in_scrubprefix(target)
+	struct in_ifaddr *target;
+{
+	struct in_ifaddr *ia;
+	struct in_addr prefix, mask, p;
+	int error;
+
+	if ((target->ia_flags & IFA_ROUTE) =3D=3D 0)
+		return 0;
+
+	if (rtinitflags(target))
+		prefix =3D target->ia_dstaddr.sin_addr;
+	else {
+		prefix =3D target->ia_addr.sin_addr;
+		mask =3D target->ia_sockmask.sin_addr;
+		prefix.s_addr &=3D mask.s_addr;
+	}
+
+	TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
+		if (rtinitflags(ia))
+			p =3D ia->ia_dstaddr.sin_addr;
+		else {
+			p =3D ia->ia_addr.sin_addr;
+			p.s_addr &=3D ia->ia_sockmask.sin_addr.s_addr;
+		}
+
+		if (prefix.s_addr !=3D p.s_addr)
+			continue;
+
+		/*
+		 * if we got a matching prefix route, move IFA_ROUTE to him
+		 */
+		if ((ia->ia_flags & IFA_ROUTE) =3D=3D 0) {
+			rtinit(&(target->ia_ifa), (int)RTM_DELETE,
+			    rtinitflags(target));
+			target->ia_flags &=3D ~IFA_ROUTE;
+
+			error =3D rtinit(&ia->ia_ifa, (int)RTM_ADD,
+			    rtinitflags(ia) | RTF_UP);
+			if (error =3D=3D 0)
+				ia->ia_flags |=3D IFA_ROUTE;
+			return error;
+		}
+	}
+
+	/*
+	 * noone seem to have prefix route.  remove it.
+	 */
+	rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target));
+	target->ia_flags &=3D ~IFA_ROUTE;
+	return 0;
+}
+
+#undef rtinitflags
=20
 /*
  * Return 1 if the address might be a local broadcast address.

--Boundary-01=_np8kBd92qNtmEHy--

--nextPart4509686.Ad4VYY4PBk
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (FreeBSD)

iD8DBQBBk8psXyyEoT62BG0RAmutAJ9z6WB3K1FYiXIDsa/gGY/QjISOYACggWA3
o3PCXKZ60jN3t6bk6VWdkXk=
=DccO
-----END PGP SIGNATURE-----

--nextPart4509686.Ad4VYY4PBk--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200411112124.12616.max>