svn commit: r293159 - in head/sys: net netinet netinet6

Alexander V. Chernikov melifaro at FreeBSD.org
Mon Jan 4 15:03:22 UTC 2016


Author: melifaro
Date: Mon Jan  4 15:03:20 2016
New Revision: 293159
URL: https://svnweb.freebsd.org/changeset/base/293159

Log:
  Add rib_lookup_info() to provide API for retrieving individual route
    entries data in unified format.
  
  There are control plane functions that require information other than
    just next-hop data (e.g. individual rtentry fields like flags or
    prefix/mask). Given that the goal is to avoid rte reference/refcounting,
    re-use rt_addrinfo structure to store most rte fields. If caller wants
    to retrieve key/mask or gateway (which are sockaddrs and are allocated
    separately), it needs to provide sufficient-sized sockaddrs structures
    w/ ther pointers saved in passed rt_addrinfo.
  
  Convert:
    * lltable new records checks (in_lltable_rtcheck(),
      nd6_is_new_addr_neighbor().
    * rtsock pre-add/change route check.
    * IPv6 NS ND-proxy check (RADIX_MPATH code was eliminated because
       1) we don't support RTF_ANNOUNCE ND-proxy for networks and there should
         not be multiple host routes for such hosts 2) if we have multiple
         routes we should inspect them (which is not done). 3) the entire idea
         of abusing KRT as storage for ND proxy seems odd. Userland programs
         should be used for that purpose).

Modified:
  head/sys/net/route.c
  head/sys/net/route.h
  head/sys/net/rtsock.c
  head/sys/netinet/in.c
  head/sys/netinet6/nd6.c
  head/sys/netinet6/nd6_nbr.c

Modified: head/sys/net/route.c
==============================================================================
--- head/sys/net/route.c	Mon Jan  4 09:58:16 2016	(r293158)
+++ head/sys/net/route.c	Mon Jan  4 15:03:20 2016	(r293159)
@@ -147,6 +147,8 @@ static void rt_notifydelete(struct rtent
 static struct radix_node *rt_mpath_unlink(struct radix_node_head *rnh,
     struct rt_addrinfo *info, struct rtentry *rto, int *perror);
 #endif
+static int rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info,
+    int flags);
 
 struct if_mtuinfo
 {
@@ -832,6 +834,147 @@ rtrequest_fib(int req,
 
 
 /*
+ * Copy most of @rt data into @info.
+ *
+ * If @flags contains NHR_COPY, copies dst,netmask and gw to the
+ * pointers specified by @info structure. Assume such pointers
+ * are zeroed sockaddr-like structures with sa_len field initialized
+ * to reflect size of the provided buffer. if no NHR_COPY is specified,
+ * point dst,netmask and gw @info fields to appropriate @rt values.
+ *
+ * if @flags contains NHR_REF, do refcouting on rt_ifp.
+ *
+ * Returns 0 on success.
+ */
+int
+rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, int flags)
+{
+	struct rt_metrics *rmx;
+	struct sockaddr *src, *dst;
+	int sa_len;
+
+	if (flags & NHR_COPY) {
+		/* Copy destination if dst is non-zero */
+		src = rt_key(rt);
+		dst = info->rti_info[RTAX_DST];
+		sa_len = src->sa_len;
+		if (src != NULL && dst != NULL) {
+			if (src->sa_len > dst->sa_len)
+				return (ENOMEM);
+			memcpy(dst, src, src->sa_len);
+			info->rti_addrs |= RTA_DST;
+		}
+
+		/* Copy mask if set && dst is non-zero */
+		src = rt_mask(rt);
+		dst = info->rti_info[RTAX_NETMASK];
+		if (src != NULL && dst != NULL) {
+
+			/*
+			 * Radix stores different value in sa_len,
+			 * assume rt_mask() to have the same length
+			 * as rt_key()
+			 */
+			if (sa_len > dst->sa_len)
+				return (ENOMEM);
+			memcpy(dst, src, src->sa_len);
+			info->rti_addrs |= RTA_NETMASK;
+		}
+
+		/* Copy gateway is set && dst is non-zero */
+		src = rt->rt_gateway;
+		dst = info->rti_info[RTAX_GATEWAY];
+		if ((rt->rt_flags & RTF_GATEWAY) && src != NULL && dst != NULL){
+			if (src->sa_len > dst->sa_len)
+				return (ENOMEM);
+			memcpy(dst, src, src->sa_len);
+			info->rti_addrs |= RTA_GATEWAY;
+		}
+	} else {
+		info->rti_info[RTAX_DST] = rt_key(rt);
+		info->rti_addrs |= RTA_DST;
+		if (rt_mask(rt) != NULL) {
+			info->rti_info[RTAX_NETMASK] = rt_mask(rt);
+			info->rti_addrs |= RTA_NETMASK;
+		}
+		if (rt->rt_flags & RTF_GATEWAY) {
+			info->rti_info[RTAX_GATEWAY] = rt->rt_gateway;
+			info->rti_addrs |= RTA_GATEWAY;
+		}
+	}
+
+	rmx = info->rti_rmx;
+	if (rmx != NULL) {
+		info->rti_mflags |= RTV_MTU;
+		rmx->rmx_mtu = rt->rt_mtu;
+	}
+
+	info->rti_flags = rt->rt_flags;
+	info->rti_ifp = rt->rt_ifp;
+	info->rti_ifa = rt->rt_ifa;
+
+	if (flags & NHR_REF) {
+		/* Do 'traditional' refcouting */
+		if_ref(info->rti_ifp);
+	}
+
+	return (0);
+}
+
+/*
+ * Lookups up route entry for @dst in RIB database for fib @fibnum.
+ * Exports entry data to @info using rt_exportinfo().
+ *
+ * if @flags contains NHR_REF, refcouting is performed on rt_ifp.
+ *   All references can be released later by calling rib_free_info()
+ *
+ * Returns 0 on success.
+ * Returns ENOENT for lookup failure, ENOMEM for export failure.
+ */
+int
+rib_lookup_info(uint32_t fibnum, const struct sockaddr *dst, uint32_t flags,
+    uint32_t flowid, struct rt_addrinfo *info)
+{
+	struct radix_node_head *rh;
+	struct radix_node *rn;
+	struct rtentry *rt;
+	int error;
+
+	KASSERT((fibnum < rt_numfibs), ("rib_lookup_rte: bad fibnum"));
+	rh = rt_tables_get_rnh(fibnum, dst->sa_family);
+	if (rh == NULL)
+		return (ENOENT);
+
+	RADIX_NODE_HEAD_RLOCK(rh);
+	rn = rh->rnh_matchaddr(__DECONST(void *, dst), rh);
+	if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
+		rt = RNTORT(rn);
+		/* Ensure route & ifp is UP */
+		if (RT_LINK_IS_UP(rt->rt_ifp)) {
+			flags = (flags & NHR_REF) | NHR_COPY;
+			error = rt_exportinfo(rt, info, flags);
+			RADIX_NODE_HEAD_RUNLOCK(rh);
+
+			return (error);
+		}
+	}
+	RADIX_NODE_HEAD_RUNLOCK(rh);
+
+	return (ENOENT);
+}
+
+/*
+ * Releases all references acquired by rib_lookup_info() when
+ * called with NHR_REF flags.
+ */
+void
+rib_free_info(struct rt_addrinfo *info)
+{
+
+	if_rele(info->rti_ifp);
+}
+
+/*
  * Iterates over all existing fibs in system calling
  *  @setwa_f function prior to traversing each fib.
  *  Calls @wa_f function for each element in current fib.

Modified: head/sys/net/route.h
==============================================================================
--- head/sys/net/route.h	Mon Jan  4 09:58:16 2016	(r293158)
+++ head/sys/net/route.h	Mon Jan  4 15:03:20 2016	(r293159)
@@ -197,6 +197,9 @@ struct rtentry {
 #define	NHR_IFAIF		0x01	/* Return ifa_ifp interface */
 #define	NHR_REF			0x02	/* For future use */
 
+/* Control plane route request flags */
+#define	NHR_COPY		0x100	/* Copy rte data */
+
 /* rte<>nhop translation */
 static inline uint16_t
 fib_rte_to_nh_flags(int rt_flags)
@@ -460,6 +463,9 @@ void	 rtredirect_fib(struct sockaddr *, 
 int	 rtrequest_fib(int, struct sockaddr *,
 	    struct sockaddr *, struct sockaddr *, int, struct rtentry **, u_int);
 int	 rtrequest1_fib(int, struct rt_addrinfo *, struct rtentry **, u_int);
+int	rib_lookup_info(uint32_t, const struct sockaddr *, uint32_t, uint32_t,
+	    struct rt_addrinfo *);
+void	rib_free_info(struct rt_addrinfo *info);
 
 #include <sys/eventhandler.h>
 typedef void (*rtevent_redirect_fn)(void *, struct rtentry *, struct rtentry *, struct sockaddr *);

Modified: head/sys/net/rtsock.c
==============================================================================
--- head/sys/net/rtsock.c	Mon Jan  4 09:58:16 2016	(r293158)
+++ head/sys/net/rtsock.c	Mon Jan  4 15:03:20 2016	(r293159)
@@ -614,11 +614,16 @@ route_output(struct mbuf *m, struct sock
 	 */
 	if (info.rti_info[RTAX_GATEWAY] != NULL &&
 	    info.rti_info[RTAX_GATEWAY]->sa_family != AF_LINK) {
-		struct route gw_ro;
+		struct rt_addrinfo ginfo;
+		struct sockaddr *gdst;
+
+		bzero(&ginfo, sizeof(ginfo));
+		bzero(&ss, sizeof(ss));
+		ss.ss_len = sizeof(ss);
+
+		ginfo.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&ss;
+		gdst = info.rti_info[RTAX_GATEWAY];
 
-		bzero(&gw_ro, sizeof(gw_ro));
-		gw_ro.ro_dst = *info.rti_info[RTAX_GATEWAY];
-		rtalloc_ign_fib(&gw_ro, 0, fibnum);
 		/* 
 		 * A host route through the loopback interface is 
 		 * installed for each interface adddress. In pre 8.0
@@ -629,14 +634,14 @@ route_output(struct mbuf *m, struct sock
 		 * AF_LINK sa_family type of the rt_gateway, and the
 		 * rt_ifp has the IFF_LOOPBACK flag set.
 		 */
-		if (gw_ro.ro_rt != NULL &&
-		    gw_ro.ro_rt->rt_gateway->sa_family == AF_LINK &&
-		    gw_ro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) {
-			info.rti_flags &= ~RTF_GATEWAY;
-			info.rti_flags |= RTF_GWFLAG_COMPAT;
+		if (rib_lookup_info(fibnum, gdst, NHR_REF, 0, &ginfo) == 0) {
+			if (ss.ss_family == AF_LINK &&
+			    ginfo.rti_ifp->if_flags & IFF_LOOPBACK) {
+				info.rti_flags &= ~RTF_GATEWAY;
+				info.rti_flags |= RTF_GWFLAG_COMPAT;
+			}
+			rib_free_info(&ginfo);
 		}
-		if (gw_ro.ro_rt != NULL)
-			RTFREE(gw_ro.ro_rt);
 	}
 
 	switch (rtm->rtm_type) {

Modified: head/sys/netinet/in.c
==============================================================================
--- head/sys/netinet/in.c	Mon Jan  4 09:58:16 2016	(r293158)
+++ head/sys/netinet/in.c	Mon Jan  4 15:03:20 2016	(r293159)
@@ -1106,34 +1106,48 @@ in_lltable_free_entry(struct lltable *ll
 static int
 in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr)
 {
-	struct rtentry *rt;
+	struct rt_addrinfo info;
+	struct sockaddr_in rt_key, rt_mask;
+	struct sockaddr rt_gateway;
+	int rt_flags;
 
 	KASSERT(l3addr->sa_family == AF_INET,
 	    ("sin_family %d", l3addr->sa_family));
 
-	/* XXX rtalloc1_fib should take a const param */
-	rt = rtalloc1_fib(__DECONST(struct sockaddr *, l3addr), 0, 0,
-	    ifp->if_fib);
+	bzero(&rt_key, sizeof(rt_key));
+	rt_key.sin_len = sizeof(rt_key);
+	bzero(&rt_mask, sizeof(rt_mask));
+	rt_mask.sin_len = sizeof(rt_mask);
+	bzero(&rt_gateway, sizeof(rt_gateway));
+	rt_gateway.sa_len = sizeof(rt_gateway);
+
+	bzero(&info, sizeof(info));
+	info.rti_info[RTAX_DST] = (struct sockaddr *)&rt_key;
+	info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&rt_mask;
+	info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&rt_gateway;
 
-	if (rt == NULL)
+	if (rib_lookup_info(ifp->if_fib, l3addr, NHR_REF, 0, &info) != 0)
 		return (EINVAL);
 
+	rt_flags = info.rti_flags;
+
 	/*
 	 * If the gateway for an existing host route matches the target L3
 	 * address, which is a special route inserted by some implementation
 	 * such as MANET, and the interface is of the correct type, then
 	 * allow for ARP to proceed.
 	 */
-	if (rt->rt_flags & RTF_GATEWAY) {
-		if (!(rt->rt_flags & RTF_HOST) || !rt->rt_ifp ||
-		    rt->rt_ifp->if_type != IFT_ETHER ||
-		    (rt->rt_ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) != 0 ||
-		    memcmp(rt->rt_gateway->sa_data, l3addr->sa_data,
+	if (rt_flags & RTF_GATEWAY) {
+		if (!(rt_flags & RTF_HOST) || !info.rti_ifp ||
+		    info.rti_ifp->if_type != IFT_ETHER ||
+		    (info.rti_ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) != 0 ||
+		    memcmp(rt_gateway.sa_data, l3addr->sa_data,
 		    sizeof(in_addr_t)) != 0) {
-			RTFREE_LOCKED(rt);
+			rib_free_info(&info);
 			return (EINVAL);
 		}
 	}
+	rib_free_info(&info);
 
 	/*
 	 * Make sure that at least the destination address is covered
@@ -1142,21 +1156,19 @@ in_lltable_rtcheck(struct ifnet *ifp, u_
 	 * on one interface and the corresponding outgoing packet leaves
 	 * another interface.
 	 */
-	if (!(rt->rt_flags & RTF_HOST) && rt->rt_ifp != ifp) {
+	if (!(rt_flags & RTF_HOST) && info.rti_ifp != ifp) {
 		const char *sa, *mask, *addr, *lim;
 		int len;
 
-		mask = (const char *)rt_mask(rt);
+		mask = (const char *)&rt_mask;
 		/*
 		 * Just being extra cautious to avoid some custom
 		 * code getting into trouble.
 		 */
-		if (mask == NULL) {
-			RTFREE_LOCKED(rt);
+		if ((info.rti_addrs & RTA_NETMASK) == 0)
 			return (EINVAL);
-		}
 
-		sa = (const char *)rt_key(rt);
+		sa = (const char *)&rt_key;
 		addr = (const char *)l3addr;
 		len = ((const struct sockaddr_in *)l3addr)->sin_len;
 		lim = addr + len;
@@ -1167,13 +1179,11 @@ in_lltable_rtcheck(struct ifnet *ifp, u_
 				log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n",
 				    inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr));
 #endif
-				RTFREE_LOCKED(rt);
 				return (EINVAL);
 			}
 		}
 	}
 
-	RTFREE_LOCKED(rt);
 	return (0);
 }
 

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c	Mon Jan  4 09:58:16 2016	(r293158)
+++ head/sys/netinet6/nd6.c	Mon Jan  4 15:03:20 2016	(r293159)
@@ -1210,6 +1210,10 @@ nd6_is_new_addr_neighbor(const struct so
 {
 	struct nd_prefix *pr;
 	struct ifaddr *dstaddr;
+	struct rt_addrinfo info;
+	struct sockaddr_in6 rt_key;
+	struct sockaddr *dst6;
+	int fibnum;
 
 	/*
 	 * A link-local address is always a neighbor.
@@ -1234,6 +1238,13 @@ nd6_is_new_addr_neighbor(const struct so
 			return (0);
 	}
 
+	bzero(&rt_key, sizeof(rt_key));
+	bzero(&info, sizeof(info));
+	info.rti_info[RTAX_DST] = (struct sockaddr *)&rt_key;
+
+	/* Always use the default FIB here. XXME - why? */
+	fibnum = RT_DEFAULT_FIB;
+
 	/*
 	 * If the address matches one of our addresses,
 	 * it should be a neighbor.
@@ -1245,12 +1256,13 @@ nd6_is_new_addr_neighbor(const struct so
 			continue;
 
 		if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) {
-			struct rtentry *rt;
 
 			/* Always use the default FIB here. */
-			rt = in6_rtalloc1((struct sockaddr *)&pr->ndpr_prefix,
-			    0, 0, RT_DEFAULT_FIB);
-			if (rt == NULL)
+			dst6 = (struct sockaddr *)&pr->ndpr_prefix;
+
+			/* Restore length field before retrying lookup */
+			rt_key.sin6_len = sizeof(rt_key);
+			if (rib_lookup_info(fibnum, dst6, 0, 0, &info) != 0)
 				continue;
 			/*
 			 * This is the case where multiple interfaces
@@ -1263,11 +1275,8 @@ nd6_is_new_addr_neighbor(const struct so
 			 * differ.
 			 */
 			if (!IN6_ARE_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr,
-			       &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr)) {
-				RTFREE_LOCKED(rt);
+			       &rt_key.sin6_addr))
 				continue;
-			}
-			RTFREE_LOCKED(rt);
 		}
 
 		if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr,

Modified: head/sys/netinet6/nd6_nbr.c
==============================================================================
--- head/sys/netinet6/nd6_nbr.c	Mon Jan  4 09:58:16 2016	(r293158)
+++ head/sys/netinet6/nd6_nbr.c	Mon Jan  4 15:03:20 2016	(r293159)
@@ -248,37 +248,35 @@ nd6_ns_input(struct mbuf *m, int off, in
 
 	/* (2) check. */
 	if (ifa == NULL) {
-		struct route_in6 ro;
-		int need_proxy;
-
-		bzero(&ro, sizeof(ro));
-		ro.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
-		ro.ro_dst.sin6_family = AF_INET6;
-		ro.ro_dst.sin6_addr = taddr6;
+		struct sockaddr_dl rt_gateway;
+		struct rt_addrinfo info;
+		struct sockaddr_in6 dst6;
+
+		bzero(&dst6, sizeof(dst6));
+		dst6.sin6_len = sizeof(struct sockaddr_in6);
+		dst6.sin6_family = AF_INET6;
+		dst6.sin6_addr = taddr6;
+
+		bzero(&rt_gateway, sizeof(rt_gateway));
+		rt_gateway.sdl_len = sizeof(rt_gateway);
+		bzero(&info, sizeof(info));
+		info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&rt_gateway;
 
 		/* Always use the default FIB. */
-#ifdef RADIX_MPATH
-		rtalloc_mpath_fib((struct route *)&ro, ntohl(taddr6.s6_addr32[3]),
-		    RT_DEFAULT_FIB);
-#else
-		in6_rtalloc(&ro, RT_DEFAULT_FIB);
-#endif
-		need_proxy = (ro.ro_rt &&
-		    (ro.ro_rt->rt_flags & RTF_ANNOUNCE) != 0 &&
-		    ro.ro_rt->rt_gateway->sa_family == AF_LINK);
-		if (ro.ro_rt != NULL) {
-			if (need_proxy)
-				proxydl = *SDL(ro.ro_rt->rt_gateway);
-			RTFREE(ro.ro_rt);
-		}
-		if (need_proxy) {
-			/*
-			 * proxy NDP for single entry
-			 */
-			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
-				IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
-			if (ifa)
-				proxy = 1;
+		if (rib_lookup_info(RT_DEFAULT_FIB, (struct sockaddr *)&dst6,
+		    0, 0, &info) == 0) {
+			if ((info.rti_flags & RTF_ANNOUNCE) != 0 &&
+			    rt_gateway.sdl_family == AF_LINK) {
+
+				/*
+				 * proxy NDP for single entry
+				 */
+				proxydl = *SDL(&rt_gateway);
+				ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(
+				    ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
+				if (ifa)
+					proxy = 1;
+			}
 		}
 	}
 	if (ifa == NULL) {


More information about the svn-src-all mailing list