Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 20 Sep 2009 05:06:42 +0000 (UTC)
From:      Kip Macy <kmacy@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r197339 - user/kmacy/releng_8_fcs/sys/netinet
Message-ID:  <200909200506.n8K56gke044601@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kmacy
Date: Sun Sep 20 05:06:42 2009
New Revision: 197339
URL: http://svn.freebsd.org/changeset/base/197339

Log:
  cache lle and rtentry in connected sockets

Modified:
  user/kmacy/releng_8_fcs/sys/netinet/in_pcb.c
  user/kmacy/releng_8_fcs/sys/netinet/in_pcb.h
  user/kmacy/releng_8_fcs/sys/netinet/ip_output.c
  user/kmacy/releng_8_fcs/sys/netinet/tcp_usrreq.c

Modified: user/kmacy/releng_8_fcs/sys/netinet/in_pcb.c
==============================================================================
--- user/kmacy/releng_8_fcs/sys/netinet/in_pcb.c	Sun Sep 20 05:04:23 2009	(r197338)
+++ user/kmacy/releng_8_fcs/sys/netinet/in_pcb.c	Sun Sep 20 05:06:42 2009	(r197339)
@@ -59,6 +59,8 @@ __FBSDID("$FreeBSD$");
 #include <vm/uma.h>
 
 #include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_llatbl.h>
 #include <net/if_types.h>
 #include <net/route.h>
 #include <net/vnet.h>
@@ -203,6 +205,7 @@ in_pcballoc(struct socket *so, struct in
 	inp->inp_socket = so;
 	inp->inp_cred = crhold(so->so_cred);
 	inp->inp_inc.inc_fibnum = so->so_fibnum;
+	inp->inp_flowid = arc4random();
 #ifdef MAC
 	error = mac_inpcb_init(inp, M_NOWAIT);
 	if (error != 0)
@@ -489,6 +492,80 @@ in_pcbbind_setup(struct inpcb *inp, stru
 	return (0);
 }
 
+void
+in_pcbrtalloc(struct inpcb *inp, in_addr_t faddr, struct route *sro)
+{
+	struct sockaddr_in *sin;
+	struct sockaddr *dst;
+	struct llentry *la;
+	struct rtentry *rt;
+	struct ifnet *ifp;
+	int flags = LLE_EXCLUSIVE;
+	struct route iproute;
+	
+	INP_WLOCK_ASSERT(inp);
+	if (sro == NULL)
+		sro = &iproute;
+
+	bzero(sro, sizeof(*sro));
+	sin = (struct sockaddr_in *)&sro->ro_dst;
+	sin->sin_family = AF_INET;
+	sin->sin_len = sizeof(struct sockaddr_in);
+	sin->sin_addr.s_addr = faddr;
+	/*
+	 * If route is known our src addr is taken from the i/f,
+	 * else punt.
+	 *
+	 * Find out route to destination.
+	 */
+	if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0) {
+#ifdef RADIX_MPATH
+		rtalloc_mpath_fib(sro, ntohl(faddr->s_addr),
+		    inp->inp_inc.inc_fibnum);
+#else		
+		in_rtalloc_ign(sro, 0, inp->inp_inc.inc_fibnum);
+#endif		
+	}
+
+	rt = sro->ro_rt;
+	/*
+	 * Don't cache route in pcb if this is a per-packet
+	 * route
+	 */
+	if (rt == NULL)
+		return;
+	
+	inp->inp_rt = rt;
+	inp->inp_flags2 |= INP_RT_VALID;
+
+	if (rt->rt_ifp == NULL)
+		return;
+	
+	ifp = rt->rt_ifp;
+	dst = &sro->ro_dst;
+	if (rt->rt_flags & RTF_GATEWAY)
+		dst = rt->rt_gateway;
+		
+	IF_AFDATA_RLOCK(ifp);	
+	la = lla_lookup(LLTABLE(ifp), flags, dst);
+	IF_AFDATA_RUNLOCK(ifp);
+	if ((la == NULL) && 
+	    (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
+		flags |= (LLE_CREATE | LLE_EXCLUSIVE);
+		IF_AFDATA_WLOCK(ifp);
+		la = lla_lookup(LLTABLE(ifp), flags, dst);
+		IF_AFDATA_WUNLOCK(ifp);	
+	}
+	if (la == NULL)
+		return;
+	
+	LLE_ADDREF(la);
+	LLE_WUNLOCK(la);
+
+	inp->inp_lle = la;
+	inp->inp_flags2 |= INP_LLE_VALID;
+}
+
 /*
  * Connect from a socket to a specified address.
  * Both address and port must be specified in argument sin.
@@ -524,6 +601,7 @@ in_pcbconnect(struct inpcb *inp, struct 
 		}
 	}
 
+	in_pcbrtalloc(inp, faddr, NULL);
 	/* Commit the remaining changes. */
 	inp->inp_lport = lport;
 	inp->inp_laddr.s_addr = laddr;
@@ -884,6 +962,17 @@ in_pcbdisconnect(struct inpcb *inp)
 	INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
 	INP_WLOCK_ASSERT(inp);
 
+	if (inp->inp_flags2 & INP_RT_VALID) {
+		inp->inp_flags2 &= ~INP_RT_VALID;
+		RTFREE(inp->inp_rt);
+		inp->inp_rt = NULL;
+	}
+	if (inp->inp_flags2 & INP_LLE_VALID) {
+		inp->inp_flags2 &= ~INP_LLE_VALID;
+		LLE_FREE(inp->inp_lle);
+		inp->inp_lle = NULL;
+	}
+	
 	inp->inp_faddr.s_addr = INADDR_ANY;
 	inp->inp_fport = 0;
 	in_pcbrehash(inp);
@@ -921,6 +1010,17 @@ in_pcbfree_internal(struct inpcb *inp)
 	INP_INFO_WLOCK_ASSERT(ipi);
 	INP_WLOCK_ASSERT(inp);
 
+	if (inp->inp_flags2 & INP_RT_VALID) {		
+		inp->inp_flags2 &= ~INP_RT_VALID;
+		RTFREE(inp->inp_rt);
+		inp->inp_rt = NULL;
+	}
+	if (inp->inp_flags2 & INP_LLE_VALID) {
+		inp->inp_flags2 &= ~INP_LLE_VALID;
+		LLE_FREE(inp->inp_lle);
+		inp->inp_lle = NULL;
+	}
+
 #ifdef IPSEC
 	if (inp->inp_sp != NULL)
 		ipsec_delete_pcbpolicy(inp);

Modified: user/kmacy/releng_8_fcs/sys/netinet/in_pcb.h
==============================================================================
--- user/kmacy/releng_8_fcs/sys/netinet/in_pcb.h	Sun Sep 20 05:04:23 2009	(r197338)
+++ user/kmacy/releng_8_fcs/sys/netinet/in_pcb.h	Sun Sep 20 05:06:42 2009	(r197339)
@@ -452,6 +452,8 @@ void 	inp_4tuple_get(struct inpcb *inp, 
 #define	INP_CHECK_SOCKAF(so, af)	(INP_SOCKAF(so) == af)
 
 #ifdef _KERNEL
+struct route;
+
 VNET_DECLARE(int, ipport_reservedhigh);
 VNET_DECLARE(int, ipport_reservedlow);
 VNET_DECLARE(int, ipport_lowfirstauto);
@@ -496,6 +498,7 @@ void	in_pcbdisconnect(struct inpcb *);
 void	in_pcbdrop(struct inpcb *);
 void	in_pcbfree(struct inpcb *);
 int	in_pcbinshash(struct inpcb *);
+void	in_pcbrtalloc(struct inpcb *inp, in_addr_t faddr, struct route *sro);
 struct inpcb *
 	in_pcblookup_local(struct inpcbinfo *,
 	    struct in_addr, u_short, int, struct ucred *);

Modified: user/kmacy/releng_8_fcs/sys/netinet/ip_output.c
==============================================================================
--- user/kmacy/releng_8_fcs/sys/netinet/ip_output.c	Sun Sep 20 05:04:23 2009	(r197338)
+++ user/kmacy/releng_8_fcs/sys/netinet/ip_output.c	Sun Sep 20 05:06:42 2009	(r197339)
@@ -124,11 +124,13 @@ ip_output(struct mbuf *m, struct mbuf *o
 	int mtu;
 	int len, error = 0;
 	int nortfree = 0;
+	int neednewroute = 0, neednewlle = 0;
 	struct sockaddr_in *dst = NULL;	/* keep compiler happy */
 	struct in_ifaddr *ia = NULL;
 	int isbroadcast, sw_csum;
 	struct route iproute;
 	struct in_addr odst;
+	struct sockaddr_in *sin;
 #ifdef IPFIREWALL_FORWARD
 	struct m_tag *fwd_tag = NULL;
 #endif
@@ -202,7 +204,7 @@ again:
 	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
 			  dst->sin_family != AF_INET ||
 			  dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
-		if (!nortfree)
+		if (!nortfree && (inp == NULL || (ro->ro_rt != inp->inp_rt)))
 			RTFREE(ro->ro_rt);
 		ro->ro_rt = (struct rtentry *)NULL;
 		ro->ro_lle = (struct llentry *)NULL;
@@ -236,13 +238,17 @@ again:
 		ip->ip_ttl = 1;
 		isbroadcast = 1;
 	} else if (flags & IP_ROUTETOIF) {
-		if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == NULL &&
+		if (!nortfree &&
+		    (ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == NULL &&
 		    (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == NULL) {
 			IPSTAT_INC(ips_noroute);
 			error = ENETUNREACH;
 			goto bad;
 		}
-		ifp = ia->ia_ifp;
+		if (nortfree)
+			ifp = ro->ro_rt->rt_ifp;
+		else
+			ifp = ia->ia_ifp;
 		ip->ip_ttl = 1;
 		isbroadcast = in_broadcast(dst->sin_addr, ifp);
 	} else if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) &&
@@ -418,6 +424,22 @@ again:
 		if (ia != NULL) {
 			ip->ip_src = IA_SIN(ia)->sin_addr;
 		}
+		if ((ro == &iproute) && (inp->inp_flags2 & INP_RT_VALID)) {
+                       if (inp->inp_rt->rt_flags & RTF_UP) {
+                               sin = (struct sockaddr_in *)&ro->ro_dst;
+                               sin->sin_family = AF_INET;
+                               sin->sin_len = sizeof(struct sockaddr_in);
+                               sin->sin_addr.s_addr = inp->inp_faddr.s_addr;
+                               ro->ro_rt = inp->inp_rt;
+                       } else
+                               neednewroute = 1;
+               }
+               if ((ro == &iproute) && (inp->inp_flags2 & INP_LLE_VALID)) {
+                       if (inp->inp_lle->la_flags & LLE_VALID) {
+                               ro->ro_lle = inp->inp_lle;
+                       } else
+                               neednewlle = 1;
+               }
 	}
 
 	/*
@@ -662,7 +684,45 @@ passout:
 
 done:
 	if (ro == &iproute && ro->ro_rt && !nortfree) {
-		RTFREE(ro->ro_rt);
+		int wlocked = 0;		
+		struct llentry *la;
+		
+		if (neednewlle || neednewroute) {
+			wlocked = INP_WLOCKED(inp);
+			if (!wlocked && INP_TRY_UPGRADE(inp) == 0)
+				return (error);
+		}
+
+		if ((nortfree == 0) &&
+		    (inp == NULL || (inp->inp_vflag & INP_RT_VALID) == 0))
+			RTFREE(ro->ro_rt);
+		else if (neednewroute && ro->ro_rt != inp->inp_rt) {
+			RTFREE(inp->inp_rt);
+			inp->inp_rt = ro->ro_rt;
+		}
+		if (neednewlle) {
+			IF_AFDATA_RLOCK(ifp);	
+			la = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE,
+			    (struct sockaddr *)dst);
+			IF_AFDATA_RUNLOCK(ifp);
+			if ((la == NULL) && 
+			    (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
+				IF_AFDATA_WLOCK(ifp);
+				la = lla_lookup(LLTABLE(ifp),
+				    (LLE_CREATE | LLE_EXCLUSIVE),
+				    (struct sockaddr *)dst);
+				IF_AFDATA_WUNLOCK(ifp);	
+			}
+			if (la != NULL && (inp->inp_lle != la)) {
+				LLE_FREE(inp->inp_lle);
+				LLE_ADDREF(la);
+				LLE_WUNLOCK(la);
+				inp->inp_lle = la;
+			} else if (la != NULL)
+				LLE_WUNLOCK(la);
+		}
+		if ((neednewlle || neednewroute) && !wlocked)
+			INP_DOWNGRADE(inp);
 	}
 	if (ia != NULL)
 		ifa_free(&ia->ia_ifa);

Modified: user/kmacy/releng_8_fcs/sys/netinet/tcp_usrreq.c
==============================================================================
--- user/kmacy/releng_8_fcs/sys/netinet/tcp_usrreq.c	Sun Sep 20 05:04:23 2009	(r197338)
+++ user/kmacy/releng_8_fcs/sys/netinet/tcp_usrreq.c	Sun Sep 20 05:06:42 2009	(r197339)
@@ -1091,6 +1091,7 @@ tcp_connect(struct tcpcb *tp, struct soc
 	inp->inp_laddr = laddr;
 	in_pcbrehash(inp);
 
+	in_pcbrtalloc(inp, inp->inp_faddr.s_addr, NULL);
 	/*
 	 * Compute window scaling to request:
 	 * Scale to fit into sweet spot.  See tcp_syncache.c.



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