svn commit: r195254 - user/kmacy/head_ppacket/sys/netinet

Kip Macy kmacy at FreeBSD.org
Wed Jul 1 19:55:08 UTC 2009


Author: kmacy
Date: Wed Jul  1 19:55:07 2009
New Revision: 195254
URL: http://svn.freebsd.org/changeset/base/195254

Log:
  Cache rtentry and llentry in the inpcb

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

Modified: user/kmacy/head_ppacket/sys/netinet/in_pcb.c
==============================================================================
--- user/kmacy/head_ppacket/sys/netinet/in_pcb.c	Wed Jul  1 19:46:53 2009	(r195253)
+++ user/kmacy/head_ppacket/sys/netinet/in_pcb.c	Wed Jul  1 19:55:07 2009	(r195254)
@@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
 
 #include <net/if.h>
 #include <net/if_types.h>
+#include <net/if_llatbl.h>
 #include <net/route.h>
 
 #include <netinet/in.h>
@@ -494,6 +495,76 @@ 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;
+	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.
@@ -529,6 +600,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;
@@ -888,6 +960,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);
@@ -925,6 +1008,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/head_ppacket/sys/netinet/in_pcb.h
==============================================================================
--- user/kmacy/head_ppacket/sys/netinet/in_pcb.h	Wed Jul  1 19:46:53 2009	(r195253)
+++ user/kmacy/head_ppacket/sys/netinet/in_pcb.h	Wed Jul  1 19:55:07 2009	(r195254)
@@ -46,6 +46,7 @@
 #define	in6pcb		inpcb	/* for KAME src sync over BSD*'s */
 #define	in6p_sp		inp_sp	/* for KAME src sync over BSD*'s */
 struct inpcbpolicy;
+struct route;
 
 /*
  * struct inpcb is the common protocol control block structure used in most
@@ -481,6 +482,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/head_ppacket/sys/netinet/ip_output.c
==============================================================================
--- user/kmacy/head_ppacket/sys/netinet/ip_output.c	Wed Jul  1 19:46:53 2009	(r195253)
+++ user/kmacy/head_ppacket/sys/netinet/ip_output.c	Wed Jul  1 19:55:07 2009	(r195254)
@@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/vimage.h>
 
 #include <net/if.h>
+#include <net/if_llatbl.h>
 #include <net/netisr.h>
 #include <net/pfil.h>
 #include <net/route.h>
@@ -129,11 +130,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
@@ -207,7 +210,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;
 	}
@@ -422,6 +425,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;
+               }
 	}
 
 	/*
@@ -666,7 +685,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/head_ppacket/sys/netinet/tcp_usrreq.c
==============================================================================
--- user/kmacy/head_ppacket/sys/netinet/tcp_usrreq.c	Wed Jul  1 19:46:53 2009	(r195253)
+++ user/kmacy/head_ppacket/sys/netinet/tcp_usrreq.c	Wed Jul  1 19:55:07 2009	(r195254)
@@ -1109,6 +1109,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.


More information about the svn-src-user mailing list