tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: RTF_LOCAL support
On 24/02/2015 15:46, Roy Marples wrote:
> I have created a patch to do this for NetBSD which also moves the bulk
> of the in6_if{add,rem}loop() functions into more generic
> rt_ifa_{add,rem}local() functions and also renamed to
> in6_if{add,rem}local(). in_if{add,rem}local() functions have also been
> added to achieve the same functionality for IPv4.
I have made more changes to the patch, based on today's sources.
* rtinit() now only announces network route changes, not the address
* rt_ifa_{add,rem}local() will always announce the address change
even if there is no corresponding local route change
Due to the above changes, some comments regarding potential secondary
reports for new addresses have been removed as this is no longer the case.
On 24/02/2015 19:09, Christos Zoulas wrote:> On Feb 24, 6:40pm,
> | It's the same value used by the other OSes, no other reason.
> | I note that where each has the same flag, the value is also the same,
> | hence keeping it the same here.
>
> I don't think that making the values the same matters (unless we
> consider binary emulation), so I'd rather allocate the next one
sequentially.
> What do others think?
We're talking about the value of RTF_LOCAL in route.h
Anyone else have an opinion on this before it goes into the tree?
Maybe add some comment in route.h to state the rationale?
Thanks
Roy
Index: sys/net/route.c
===================================================================
RCS file: /cvsroot/src/sys/net/route.c,v
retrieving revision 1.135
diff -u -p -r1.135 route.c
--- sys/net/route.c 25 Feb 2015 12:45:34 -0000 1.135
+++ sys/net/route.c 25 Feb 2015 20:16:25 -0000
@@ -90,6 +90,7 @@
* @(#)route.c 8.3 (Berkeley) 1/9/95
*/
+#include "opt_inet.h"
#include "opt_route.h"
#include <sys/cdefs.h>
@@ -960,7 +961,7 @@ rtinit(struct ifaddr *ifa, int cmd, int
;
else switch (cmd) {
case RTM_DELETE:
- rt_newaddrmsg(cmd, ifa, error, nrt);
+ rt_newmsg(cmd, nrt);
if (rt->rt_refcnt <= 0) {
rt->rt_refcnt++;
rtfree(rt);
@@ -984,7 +985,7 @@ rtinit(struct ifaddr *ifa, int cmd, int
if (cmd == RTM_LLINFO_UPD && ifa->ifa_rtrequest != NULL)
ifa->ifa_rtrequest(RTM_LLINFO_UPD, rt, &info);
- rt_newaddrmsg(RTM_CHANGE, ifa, error, nrt);
+ rt_newmsg(RTM_CHANGE, nrt);
break;
case RTM_ADD:
rt->rt_refcnt--;
@@ -1000,12 +1001,132 @@ rtinit(struct ifaddr *ifa, int cmd, int
if (ifa->ifa_rtrequest != NULL)
ifa->ifa_rtrequest(RTM_ADD, rt, &info);
}
- rt_newaddrmsg(cmd, ifa, error, nrt);
+ rt_newmsg(cmd, nrt);
break;
}
return error;
}
+static const struct in_addr inmask32 = {.s_addr = INADDR_BROADCAST};
+
+/* Subrotine for rt_ifa_addlocal() and rt_ifa_remlocal() */
+static int
+rt_ifa_localrequest(int cmd, struct ifaddr *ifa)
+{
+ struct sockaddr *all1_sa;
+ struct sockaddr_in all1_sin;
+#ifdef INET6
+ struct sockaddr_in6 all1_sin6;
+#endif
+ struct rtentry *nrt = NULL;
+ int flags, e;
+
+ switch(ifa->ifa_addr->sa_family) {
+ case AF_INET:
+ sockaddr_in_init(&all1_sin, &inmask32, 0);
+ all1_sa = (struct sockaddr *)&all1_sin;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ sockaddr_in6_init(&all1_sin6, &in6mask128, 0, 0, 0);
+ all1_sa = (struct sockaddr *)&all1_sin6;
+ break;
+#endif
+ default:
+ return 0;
+ }
+
+ flags = RTF_UP | RTF_HOST | RTF_LOCAL;
+ if (!(ifa->ifa_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)))
+ flags |= RTF_LLINFO;
+ e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr, all1_sa, flags, &nrt);
+
+ /* Make sure rt_ifa be equal to IFA, the second argument of the
+ * function. */
+ if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa)
+ rt_replace_ifa(nrt, ifa);
+
+ rt_newaddrmsg(cmd, ifa, e, nrt);
+ if (nrt) {
+ if (cmd == RTM_DELETE) {
+ if (nrt->rt_refcnt <= 0) {
+ /* XXX: we should free the entry ourselves. */
+ nrt->rt_refcnt++;
+ rtfree(nrt);
+ }
+ } else {
+ /* the cmd must be RTM_ADD here */
+ nrt->rt_refcnt--;
+ }
+ }
+ return e;
+}
+
+/*
+ * Create a local route entry for the address.
+ * Announce the addition of the address and the route to the routing socket.
+ */
+int
+rt_ifa_addlocal(struct ifaddr *ifa)
+{
+ struct rtentry *rt;
+ int e;
+
+ /* If there is no loopback entry, allocate one. */
+ rt = rtalloc1(ifa->ifa_addr, 0);
+ if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
+ (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
+ e = rt_ifa_localrequest(RTM_ADD, ifa);
+ else {
+ e = 0;
+ rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
+ }
+ if (rt != NULL)
+ rt->rt_refcnt--;
+ return e;
+}
+
+/*
+ * Remove the local route entry for the address.
+ * Announce the removal of the eddress and the route to the routing socket.
+ */
+int
+rt_ifa_remlocal(struct ifaddr *ifa, struct ifaddr *alt_ifa)
+{
+ struct rtentry *rt;
+ int e = 0;
+
+ rt = rtalloc1(ifa->ifa_addr, 0);
+
+ /*
+ * Before deleting, check if a corresponding loopbacked
+ * host route surely exists. With this check, we can avoid
+ * deleting an interface direct route whose destination is
+ * the same as the address being removed. This can happen
+ * when removing a subnet-router anycast address on an
+ * interface attached to a shared medium.
+ */
+ if (rt != NULL &&
+ (rt->rt_flags & RTF_HOST) &&
+ (rt->rt_ifp->if_flags & IFF_LOOPBACK))
+ {
+ /* If we cannot replace the route's ifaddr with the equivalent
+ * ifaddr of another interface, I believe it is safest to
+ * delete the route.
+ */
+ if (alt_ifa == NULL)
+ e = rt_ifa_localrequest(RTM_DELETE, ifa);
+ else {
+ rt_replace_ifa(rt, alt_ifa);
+ rt_newmsg(RTM_CHANGE, rt);
+ }
+ } else
+ rt_newaddrmsg(RTM_DELADDR, ifa, 0, NULL);
+ if (rt != NULL)
+ rt->rt_refcnt--;
+ return e;
+}
+
/*
* Route timer routines. These routes allow functions to be called
* for various routes at any time. This is useful in supporting
Index: sys/net/route.h
===================================================================
RCS file: /cvsroot/src/sys/net/route.h,v
retrieving revision 1.86
diff -u -p -r1.86 route.h
--- sys/net/route.h 25 Feb 2015 12:45:34 -0000 1.86
+++ sys/net/route.h 25 Feb 2015 20:16:25 -0000
@@ -155,6 +155,7 @@ struct ortentry {
#define RTF_PROTO1 0x8000 /* protocol specific routing flag */
#define RTF_SRC 0x10000 /* route has fixed source address */
#define RTF_ANNOUNCE 0x20000 /* announce new ARP or NDP entry */
+#define RTF_LOCAL 0x200000 /* route represents a local address */
/*
* Routing statistics.
@@ -504,6 +505,8 @@ struct rtentry *rt_lookup(rtbl_t *, cons
struct rtentry *rt_deladdr(rtbl_t *, const struct sockaddr *,
const struct sockaddr *);
void rtbl_init(void);
+int rt_ifa_addlocal(struct ifaddr *);
+int rt_ifa_remlocal(struct ifaddr *, struct ifaddr *);
rtbl_t *rt_gettable(sa_family_t);
void rt_assert_inactive(const struct rtentry *);
Index: sys/netinet/if_arp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/if_arp.c,v
retrieving revision 1.160
diff -u -p -r1.160 if_arp.c
--- sys/netinet/if_arp.c 13 Nov 2014 16:11:18 -0000 1.160
+++ sys/netinet/if_arp.c 25 Feb 2015 20:16:26 -0000
@@ -453,7 +453,9 @@ arp_setgate(struct rtentry *rt, struct s
if ((rt->rt_flags & RTF_HOST) == 0 && netmask != NULL &&
satocsin(netmask)->sin_addr.s_addr != 0xffffffff)
rt->rt_flags |= RTF_CLONING;
- if (rt->rt_flags & RTF_CLONING) {
+ if (rt->rt_flags & RTF_CLONING ||
+ ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && !rt->rt_llinfo))
+ {
union {
struct sockaddr sa;
struct sockaddr_storage ss;
@@ -554,7 +556,9 @@ arp_rtrequest(int req, struct rtentry *r
break;
case RTM_ADD:
gate = arp_setgate(rt, gate, info->rti_info[RTAX_NETMASK]);
- if (rt->rt_flags & RTF_CLONING) {
+ if (rt->rt_flags & RTF_CLONING ||
+ ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && !la))
+ {
/*
* Give this route an expiration time, even though
* it's a "permanent" route, so that routes cloned
@@ -592,7 +596,8 @@ arp_rtrequest(int req, struct rtentry *r
}
#endif
}
- break;
+ if (rt->rt_flags & RTF_CLONING)
+ break;
}
/* Announce a new entry if requested. */
if (rt->rt_flags & RTF_ANNOUNCE) {
Index: sys/netinet/in.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.c,v
retrieving revision 1.149
diff -u -p -r1.149 in.c
--- sys/netinet/in.c 1 Dec 2014 17:07:43 -0000 1.149
+++ sys/netinet/in.c 25 Feb 2015 20:16:26 -0000
@@ -602,6 +602,40 @@ in_control(struct socket *so, u_long cmd
return error;
}
+/* Add ownaddr as loopback rtentry. */
+static void
+in_ifaddlocal(struct ifaddr *ifa)
+{
+
+ rt_ifa_addlocal(ifa);
+}
+
+/* Rempve loopback entry of ownaddr */
+static void
+in_ifremlocal(struct ifaddr *ifa)
+{
+ struct in_ifaddr *ia, *p;
+ struct ifaddr *alt_ifa = NULL;
+ int ia_count = 0;
+
+ ia = (struct in_ifaddr *)ifa;
+ /* Delete the entry if exactly one ifaddr matches the
+ * address, ifa->ifa_addr. */
+ TAILQ_FOREACH(p, &in_ifaddrhead, ia_list) {
+ if (!in_hosteq(p->ia_addr.sin_addr, ia->ia_addr.sin_addr))
+ continue;
+ if (p->ia_ifp != ia->ia_ifp)
+ alt_ifa = &p->ia_ifa;
+ if (++ia_count > 1 && alt_ifa != NULL)
+ break;
+ }
+
+ if (ia_count == 0)
+ return;
+
+ rt_ifa_remlocal(ifa, ia_count == 1 ? NULL : alt_ifa);
+}
+
void
in_purgeaddr(struct ifaddr *ifa)
{
@@ -609,6 +643,7 @@ in_purgeaddr(struct ifaddr *ifa)
struct in_ifaddr *ia = (void *) ifa;
in_ifscrub(ifp, ia);
+ in_ifremlocal(ifa);
LIST_REMOVE(ia, ia_hash);
ifa_remove(ifp, &ia->ia_ifa);
TAILQ_REMOVE(&in_ifaddrhead, ia, ia_list);
@@ -857,6 +892,9 @@ in_ifinit(struct ifnet *ifp, struct in_i
ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
}
+ /* Add the local route to the address */
+ in_ifaddlocal(&ia->ia_ifa);
+
i = ia->ia_addr.sin_addr.s_addr;
if (IN_CLASSA(i))
ia->ia_netmask = IN_CLASSA_NET;
@@ -958,13 +996,9 @@ in_addprefix(struct in_ifaddr *target, i
* interface address, we don't need to bother
*
* XXX RADIX_MPATH implications here? -dyoung
- *
- * But we should still notify userland of the new address
*/
- if (ia->ia_flags & IFA_ROUTE) {
- rt_newaddrmsg(RTM_NEWADDR, &target->ia_ifa, 0, NULL);
+ if (ia->ia_flags & IFA_ROUTE)
return 0;
- }
}
/*
@@ -974,9 +1008,9 @@ in_addprefix(struct in_ifaddr *target, i
if (error == 0)
target->ia_flags |= IFA_ROUTE;
else if (error == EEXIST) {
- /*
+ /*
* the fact the route already exists is not an error.
- */
+ */
error = 0;
}
return error;
@@ -995,10 +1029,8 @@ in_scrubprefix(struct in_ifaddr *target)
int error;
/* If we don't have IFA_ROUTE we should still inform userland */
- if ((target->ia_flags & IFA_ROUTE) == 0) {
- rt_newaddrmsg(RTM_DELADDR, &target->ia_ifa, 0, NULL);
+ if ((target->ia_flags & IFA_ROUTE) == 0)
return 0;
- }
if (rtinitflags(target))
prefix = target->ia_dstaddr.sin_addr;
Index: sys/netinet/ip_carp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_carp.c,v
retrieving revision 1.59
diff -u -p -r1.59 ip_carp.c
--- sys/netinet/ip_carp.c 31 Jul 2014 02:37:25 -0000 1.59
+++ sys/netinet/ip_carp.c 25 Feb 2015 20:16:26 -0000
@@ -446,9 +446,9 @@ carp_setroute(struct carp_softc *sc, int
#ifdef INET6
case AF_INET6:
if (cmd == RTM_ADD)
- in6_ifaddloop(ifa);
+ in6_ifaddlocal(ifa);
else
- in6_ifremloop(ifa);
+ in6_ifremlocal(ifa);
break;
#endif /* INET6 */
default:
Index: sys/netinet6/in6.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6.c,v
retrieving revision 1.183
diff -u -p -r1.183 in6.c
--- sys/netinet6/in6.c 25 Feb 2015 00:26:58 -0000 1.183
+++ sys/netinet6/in6.c 25 Feb 2015 20:16:26 -0000
@@ -145,70 +145,6 @@ static int in6_ifinit(struct ifnet *, st
static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
/*
- * Subroutine for in6_ifaddloop() and in6_ifremloop().
- * This routine does actual work.
- */
-static void
-in6_ifloop_request(int cmd, struct ifaddr *ifa)
-{
- struct sockaddr_in6 all1_sa;
- struct rtentry *nrt = NULL;
- int e;
-
- sockaddr_in6_init(&all1_sa, &in6mask128, 0, 0, 0);
-
- /*
- * We specify the address itself as the gateway, and set the
- * RTF_LLINFO flag, so that the corresponding host route would have
- * the flag, and thus applications that assume traditional behavior
- * would be happy. Note that we assume the caller of the function
- * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest,
- * which changes the outgoing interface to the loopback interface.
- */
- e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr,
- (struct sockaddr *)&all1_sa, RTF_UP|RTF_HOST|RTF_LLINFO, &nrt);
- if (e != 0) {
- log(LOG_ERR, "in6_ifloop_request: "
- "%s operation failed for %s (errno=%d)\n",
- cmd == RTM_ADD ? "ADD" : "DELETE",
- ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr),
- e);
- }
-
- /*
- * Make sure rt_ifa be equal to IFA, the second argument of the
- * function.
- * We need this because when we refer to rt_ifa->ia6_flags in
- * ip6_input, we assume that the rt_ifa points to the address instead
- * of the loopback address.
- */
- if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa)
- rt_replace_ifa(nrt, ifa);
-
- /*
- * Report the addition/removal of the address to the routing socket
- * unless the address is marked tentative, where it will be reported
- * once DAD completes.
- * XXX: since we called rtinit for a p2p interface with a destination,
- * we end up reporting twice in such a case. Should we rather
- * omit the second report?
- */
- if (nrt) {
- rt_newaddrmsg(cmd, ifa, e, nrt);
- if (cmd == RTM_DELETE) {
- if (nrt->rt_refcnt <= 0) {
- /* XXX: we should free the entry ourselves. */
- nrt->rt_refcnt++;
- rtfree(nrt);
- }
- } else {
- /* the cmd must be RTM_ADD here */
- nrt->rt_refcnt--;
- }
- }
-}
-
-/*
* Add ownaddr as loopback rtentry. We previously add the route only if
* necessary (ex. on a p2p link). However, since we now manage addresses
* separately from prefixes, we should always add the route. We can't
@@ -216,28 +152,21 @@ in6_ifloop_request(int cmd, struct ifadd
* any more.
*/
void
-in6_ifaddloop(struct ifaddr *ifa)
+in6_ifaddlocal(struct ifaddr *ifa)
{
- struct rtentry *rt;
- /* If there is no loopback entry, allocate one. */
- rt = rtalloc1(ifa->ifa_addr, 0);
- if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
- (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
- in6_ifloop_request(RTM_ADD, ifa);
- if (rt != NULL)
- rt->rt_refcnt--;
+ rt_ifa_addlocal(ifa);
}
/*
- * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(),
+ * Remove loopback rtentry of ownaddr generated by in6_ifaddlocal(),
* if it exists.
*/
void
-in6_ifremloop(struct ifaddr *ifa)
+in6_ifremlocal(struct ifaddr *ifa)
{
- struct in6_ifaddr *alt_ia = NULL, *ia;
- struct rtentry *rt;
+ struct in6_ifaddr *ia;
+ struct ifaddr *alt_ifa = NULL;
int ia_count = 0;
/*
@@ -272,38 +201,15 @@ in6_ifremloop(struct ifaddr *ifa)
if (!IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr))
continue;
if (ia->ia_ifp != ifa->ifa_ifp)
- alt_ia = ia;
- if (++ia_count > 1 && alt_ia != NULL)
+ alt_ifa = &ia->ia_ifa;
+ if (++ia_count > 1 && alt_ifa != NULL)
break;
}
if (ia_count == 0)
return;
- if ((rt = rtalloc1(ifa->ifa_addr, 0)) == NULL)
- return;
- rt->rt_refcnt--;
-
- /*
- * Before deleting, check if a corresponding loopbacked
- * host route surely exists. With this check, we can avoid
- * deleting an interface direct route whose destination is
- * the same as the address being removed. This can happen
- * when removing a subnet-router anycast address on an
- * interface attached to a shared medium.
- */
- if ((rt->rt_flags & RTF_HOST) == 0 ||
- (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
- return;
-
- /* If we cannot replace the route's ifaddr with the equivalent
- * ifaddr of another interface, I believe it is safest to
- * delete the route.
- */
- if (ia_count == 1 || alt_ia == NULL)
- in6_ifloop_request(RTM_DELETE, ifa);
- else
- rt_replace_ifa(rt, &alt_ia->ia_ifa);
+ rt_ifa_remlocal(ifa, ia_count == 1 ? NULL : alt_ifa);
}
int
@@ -1383,7 +1289,7 @@ in6_purgeaddr(struct ifaddr *ifa)
}
/* Remove ownaddr's loopback rtentry, if it exists. */
- in6_ifremloop(&(ia->ia_ifa));
+ in6_ifremlocal(&(ia->ia_ifa));
/*
* leave from multicast groups we have joined for the interface
@@ -1781,8 +1687,9 @@ in6_ifinit(struct ifnet *ifp, struct in6
/* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */
if (newhost) {
/* set the rtrequest function to create llinfo */
- ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
- in6_ifaddloop(&ia->ia_ifa);
+ if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0)
+ ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
+ in6_ifaddlocal(&ia->ia_ifa);
} else {
/* Inform the routing socket of new flags/timings */
rt_newaddrmsg(RTM_NEWADDR, &ia->ia_ifa, 0, NULL);
Index: sys/netinet6/in6_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6_var.h,v
retrieving revision 1.71
diff -u -p -r1.71 in6_var.h
--- sys/netinet6/in6_var.h 5 Sep 2014 06:06:31 -0000 1.71
+++ sys/netinet6/in6_var.h 25 Feb 2015 20:16:26 -0000
@@ -693,8 +693,8 @@ int in6_if2idlen (struct ifnet *);
void *in6_domifattach(struct ifnet *);
void in6_domifdetach(struct ifnet *, void *);
void in6_restoremkludge(struct in6_ifaddr *, struct ifnet *);
-void in6_ifremloop(struct ifaddr *);
-void in6_ifaddloop(struct ifaddr *);
+void in6_ifremlocal(struct ifaddr *);
+void in6_ifaddlocal(struct ifaddr *);
void in6_createmkludge(struct ifnet *);
void in6_purgemkludge(struct ifnet *);
struct in6_ifaddr *in6ifa_ifpforlinklocal(const struct ifnet *, int);
Index: share/man/man4/route.4
===================================================================
RCS file: /cvsroot/src/share/man/man4/route.4,v
retrieving revision 1.23
diff -u -p -r1.23 route.4
--- share/man/man4/route.4 24 Feb 2015 19:11:13 -0000 1.23
+++ share/man/man4/route.4 25 Feb 2015 20:16:27 -0000
@@ -310,6 +310,7 @@ Flags include the values:
#define RTF_PROTO1 0x8000 /* protocol specific routing flag */
#define RTF_SRC 0x10000 /* route has fixed source address */
#define RTF_ANNOUNCE 0x20000 /* announce new ARP or NDP entry */
+#define RTF_LOCAL 0x200000 /* route represents a local address */
.Ed
.Pp
Specifiers for metric values in rmx_locks and rtm_inits are:
Home |
Main Index |
Thread Index |
Old Index