Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/netinet6 Pull nexthop determination routine from nd6_output
details: https://anonhg.NetBSD.org/src/rev/7050690f32eb
branches: trunk
changeset: 340421:7050690f32eb
user: ozaki-r <ozaki-r%NetBSD.org@localhost>
date: Fri Sep 04 05:33:23 2015 +0000
description:
Pull nexthop determination routine from nd6_output
It simplifies nd6_output and the nexthop determination routine slightly.
diffstat:
sys/netinet6/nd6.c | 179 +++++++++++++++++++++++++++++++---------------------
1 files changed, 108 insertions(+), 71 deletions(-)
diffs (217 lines):
diff -r 8753fab53bd8 -r 7050690f32eb sys/netinet6/nd6.c
--- a/sys/netinet6/nd6.c Fri Sep 04 05:24:57 2015 +0000
+++ b/sys/netinet6/nd6.c Fri Sep 04 05:33:23 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: nd6.c,v 1.175 2015/09/03 00:54:39 ozaki-r Exp $ */
+/* $NetBSD: nd6.c,v 1.176 2015/09/04 05:33:23 ozaki-r Exp $ */
/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */
/*
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.175 2015/09/03 00:54:39 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.176 2015/09/04 05:33:23 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@@ -2145,92 +2145,129 @@
mutex_exit(softnet_lock);
}
-#define senderr(e) { error = (e); goto bad;}
-int
-nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
- const struct sockaddr_in6 *dst, struct rtentry *rt00)
+/*
+ * Next hop determination. This routine was derived from ether_output.
+ */
+static int
+nd6_determine_nexthop(struct ifnet *ifp, const struct sockaddr_in6 *dst,
+ struct rtentry *rt00, struct rtentry **ret_rt, bool *sendpkt)
{
- struct mbuf *m = m0;
struct rtentry *rt, *rt0;
- struct sockaddr_in6 *gw6 = NULL;
- struct llinfo_nd6 *ln = NULL;
- int error = 0;
+ struct rtentry *gwrt;
+ struct sockaddr_in6 *gw6;
#define RTFREE_IF_NEEDED(_rt) \
if ((_rt) != NULL && (_rt) != rt00) \
rtfree((_rt));
+ KASSERT(rt00 != NULL);
+
rt = rt0 = rt00;
+ if ((rt->rt_flags & RTF_UP) == 0) {
+ rt0 = rt = rtalloc1(sin6tocsa(dst), 1);
+ if (rt == NULL)
+ goto hostunreach;
+ if (rt->rt_ifp != ifp)
+ goto hostunreach;
+ }
+
+ if ((rt->rt_flags & RTF_GATEWAY) == 0)
+ goto out;
+
+ gw6 = (struct sockaddr_in6 *)rt->rt_gateway;
+
+ /*
+ * We skip link-layer address resolution and NUD
+ * if the gateway is not a neighbor from ND point
+ * of view, regardless of the value of nd_ifinfo.flags.
+ * The second condition is a bit tricky; we skip
+ * if the gateway is our own address, which is
+ * sometimes used to install a route to a p2p link.
+ */
+ if (!nd6_is_addr_neighbor(gw6, ifp) ||
+ in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) {
+ /*
+ * We allow this kind of tricky route only
+ * when the outgoing interface is p2p.
+ * XXX: we may need a more generic rule here.
+ */
+ if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+ goto hostunreach;
+
+ *sendpkt = true;
+ goto out;
+ }
+
+ /* Try to use a cached nexthop route (gwroute) if exists */
+ gwrt = rt_get_gwroute(rt);
+ if (gwrt == NULL)
+ goto lookup;
+
+ RTFREE_IF_NEEDED(rt);
+ rt = gwrt;
+ if ((rt->rt_flags & RTF_UP) == 0) {
+ RTFREE_IF_NEEDED(rt);
+ rt = rt0;
+ lookup:
+ /* Look up a nexthop route */
+ gwrt = rtalloc1(rt->rt_gateway, 1);
+ rt_set_gwroute(rt, gwrt);
+ RTFREE_IF_NEEDED(rt);
+ rt = gwrt;
+ if (rt == NULL)
+ goto hostunreach;
+ /* the "G" test below also prevents rt == rt0 */
+ if ((rt->rt_flags & RTF_GATEWAY) ||
+ (rt->rt_ifp != ifp)) {
+ if (rt0->rt_gwroute != NULL)
+ rtfree(rt0->rt_gwroute);
+ rt0->rt_gwroute = NULL;
+ goto hostunreach;
+ }
+ }
+
+out:
+ *ret_rt = rt;
+ return 0;
+
+hostunreach:
+ RTFREE_IF_NEEDED(rt);
+
+ return EHOSTUNREACH;
+#undef RTFREE_IF_NEEDED
+}
+
+#define senderr(e) { error = (e); goto bad;}
+int
+nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
+ const struct sockaddr_in6 *dst, struct rtentry *rt0)
+{
+ struct mbuf *m = m0;
+ struct rtentry *rt = rt0;
+ struct llinfo_nd6 *ln = NULL;
+ int error = 0;
+
+#define RTFREE_IF_NEEDED(_rt) \
+ if ((_rt) != NULL && (_rt) != rt0) \
+ rtfree((_rt));
+
if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
goto sendpkt;
if (nd6_need_cache(ifp) == 0)
goto sendpkt;
- /*
- * next hop determination. This routine is derived from ether_output.
- */
if (rt) {
- if ((rt->rt_flags & RTF_UP) == 0) {
- if ((rt0 = rt = rtalloc1(sin6tocsa(dst), 1)) != NULL) {
- if (rt->rt_ifp != ifp)
- senderr(EHOSTUNREACH);
- } else
- senderr(EHOSTUNREACH);
- }
-
- if (rt->rt_flags & RTF_GATEWAY) {
- struct rtentry *gwrt;
- gw6 = (struct sockaddr_in6 *)rt->rt_gateway;
+ struct rtentry *nexthop = NULL;
+ bool sendpkt = false;
- /*
- * We skip link-layer address resolution and NUD
- * if the gateway is not a neighbor from ND point
- * of view, regardless of the value of nd_ifinfo.flags.
- * The second condition is a bit tricky; we skip
- * if the gateway is our own address, which is
- * sometimes used to install a route to a p2p link.
- */
- if (!nd6_is_addr_neighbor(gw6, ifp) ||
- in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) {
- /*
- * We allow this kind of tricky route only
- * when the outgoing interface is p2p.
- * XXX: we may need a more generic rule here.
- */
- if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
- senderr(EHOSTUNREACH);
-
- goto sendpkt;
- }
-
- gwrt = rt_get_gwroute(rt);
- if (gwrt == NULL)
- goto lookup;
-
- RTFREE_IF_NEEDED(rt);
- rt = gwrt;
- if ((rt->rt_flags & RTF_UP) == 0) {
- RTFREE_IF_NEEDED(rt);
- rt = rt0;
- lookup:
- gwrt = rtalloc1(rt->rt_gateway, 1);
- rt_set_gwroute(rt, gwrt);
- RTFREE_IF_NEEDED(rt);
- rt = gwrt;
- if (rt == NULL)
- senderr(EHOSTUNREACH);
- /* the "G" test below also prevents rt == rt0 */
- if ((rt->rt_flags & RTF_GATEWAY) ||
- (rt->rt_ifp != ifp)) {
- if (rt0->rt_gwroute != NULL)
- rtfree(rt0->rt_gwroute);
- rt0->rt_gwroute = NULL;
- senderr(EHOSTUNREACH);
- }
- }
- }
+ error = nd6_determine_nexthop(ifp, dst, rt, &nexthop, &sendpkt);
+ if (error != 0)
+ senderr(error);
+ rt = nexthop;
+ if (sendpkt)
+ goto sendpkt;
}
/*
Home |
Main Index |
Thread Index |
Old Index