svn commit: r186620 - user/kmacy/HEAD_fast_net/sys/netinet
Kip Macy
kmacy at FreeBSD.org
Wed Dec 31 01:42:25 UTC 2008
Author: kmacy
Date: Wed Dec 31 01:42:24 2008
New Revision: 186620
URL: http://svn.freebsd.org/changeset/base/186620
Log:
Add ip_output_fast for handling ip transmit in the common case
Modified:
user/kmacy/HEAD_fast_net/sys/netinet/ip_output.c
Modified: user/kmacy/HEAD_fast_net/sys/netinet/ip_output.c
==============================================================================
--- user/kmacy/HEAD_fast_net/sys/netinet/ip_output.c Tue Dec 30 23:49:54 2008 (r186619)
+++ user/kmacy/HEAD_fast_net/sys/netinet/ip_output.c Wed Dec 31 01:42:24 2008 (r186620)
@@ -104,6 +104,92 @@ static void ip_mloopback
extern struct protosw inetsw[];
extern struct flowtable *ipv4_ft;
+static int
+ip_output_fast(struct mbuf *m, struct route *ro, int flags, int hlen,
+ struct inpcb *inp)
+{
+ struct ifnet *ifp = NULL; /* keep compiler happy */
+ struct ip *ip;
+ struct in_ifaddr *ia = NULL;
+ int sw_csum;
+
+ ia = ifatoia(ro->ro_rt->rt_ifa);
+ ifp = ro->ro_rt->rt_ifp;
+ ro->ro_rt->rt_rmx.rmx_pksent++;
+
+ if (ro->ro_rt->rt_flags & RTF_GATEWAY)
+ bcopy(ro->ro_rt->rt_gateway, &ro->ro_dst,
+ sizeof(struct sockaddr));
+
+ ip = mtod(m, struct ip *);
+ /*
+ * If the source address is not specified yet, use the address
+ * of the outoing interface.
+ */
+ if (ip->ip_src.s_addr == INADDR_ANY) {
+ /* Interface may have no addresses. */
+ if (ia != NULL) {
+ ip->ip_src = IA_SIN(ia)->sin_addr;
+ }
+ }
+
+#ifdef IPSEC
+ switch(ip_ipsec_output(&m, inp, &flags, &error, &ro, &iproute, &dst, &ia, &ifp)) {
+ case 1:
+ m_freem(m);
+ return (0);
+ case -1:
+ return (0);
+ case 0:
+ default:
+ break; /* Continue with packet processing. */
+ }
+ /* Update variables that are affected by ipsec4_output(). */
+ ip = mtod(m, struct ip *);
+ hlen = ip->ip_hl << 2;
+#endif /* IPSEC */
+
+ m->m_pkthdr.csum_flags |= CSUM_IP;
+ sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_hwassist;
+ if (sw_csum & CSUM_DELAY_DATA) {
+ in_delayed_cksum(m);
+ sw_csum &= ~CSUM_DELAY_DATA;
+ }
+ m->m_pkthdr.csum_flags &= ifp->if_hwassist;
+
+ ip->ip_len = htons(ip->ip_len);
+ ip->ip_off = htons(ip->ip_off);
+ ip->ip_sum = 0;
+ if (sw_csum & CSUM_DELAY_IP)
+ ip->ip_sum = in_cksum(m, hlen);
+
+ /*
+ * Record statistics for this interface address.
+ * With CSUM_TSO the byte/packet count will be slightly
+ * incorrect because we count the IP+TCP headers only
+ * once instead of for every generated packet.
+ */
+ if (!(flags & IP_FORWARDING) && ia) {
+ if (m->m_pkthdr.csum_flags & CSUM_TSO)
+ ia->ia_ifa.if_opackets +=
+ m->m_pkthdr.len / m->m_pkthdr.tso_segsz;
+ else
+ ia->ia_ifa.if_opackets++;
+ ia->ia_ifa.if_obytes += m->m_pkthdr.len;
+ }
+#ifdef MBUF_STRESS_TEST
+ if (mbuf_frag_size && m->m_pkthdr.len > mbuf_frag_size)
+ m = m_fragment(m, M_DONTWAIT, mbuf_frag_size);
+#endif
+ /*
+ * Reset layer specific mbuf flags
+ * to avoid confusing lower layers.
+ */
+ m->m_flags &= ~(M_PROTOFLAGS);
+
+ return ((*ifp->if_output)(ifp, m, ro));
+}
+
/*
* IP output. The packet in mbuf chain m contains a skeletal IP
* header (with len, off, ttl, proto, tos, src, dst).
@@ -121,16 +207,15 @@ ip_output(struct mbuf *m, struct mbuf *o
struct ip *ip;
struct ifnet *ifp = NULL; /* keep compiler happy */
struct mbuf *m0;
+ struct in_ifaddr *ia = NULL;
int hlen = sizeof (struct ip);
int mtu;
int len, error = 0;
int neednewroute = 0, neednewlle = 0, nortfree = 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
@@ -144,33 +229,8 @@ ip_output(struct mbuf *m, struct mbuf *o
if (inp != NULL) {
M_SETFIB(m, inp->inp_inc.inc_fibnum);
INP_LOCK_ASSERT(inp);
- if (inp->inp_flags & (INP_HW_FLOWID|INP_SW_FLOWID)) {
- m->m_pkthdr.flowid = inp->inp_flowid;
- m->m_flags |= M_FLOWID;
- }
- if ((ro == &iproute) && (inp->inp_vflag & 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_flags & INP_LLE_VALID)) {
- if (inp->inp_lle->la_flags & LLE_VALID) {
- ro->ro_lle = inp->inp_lle;
- } else
- neednewlle = 1;
- }
- }
- if ((ro == &iproute) && (ro->ro_rt == NULL) && (ro->ro_lle == NULL)) {
- if (flowtable_lookup(ipv4_ft, m, ro) == 0)
- nortfree = 1;
}
-
if (opt) {
len = 0;
m = ip_insertoptions(m, opt, &len);
@@ -208,13 +268,16 @@ again:
* The address family should also be checked in case of sharing the
* cache with IPv6.
*/
- if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
+ if (ro->ro_rt != NULL && ((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 == 0) &&
- (inp == NULL || (ro->ro_rt != inp->inp_rt)))
- RTFREE(ro->ro_rt);
- ro->ro_rt = (struct rtentry *)NULL;
+ /*
+ * XXX need to check that ro->ro_rt isn't coming from a flow
+ * lookup in ip_forward ... perhaps pass in a new flag
+ *
+ */
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = NULL;
}
#ifdef IPFIREWALL_FORWARD
if (ro->ro_rt == NULL && fwd_tag == NULL) {
@@ -226,6 +289,65 @@ again:
dst->sin_len = sizeof(*dst);
dst->sin_addr = ip->ip_dst;
}
+ if (ro != &iproute)
+ goto skipcachecheck;
+ if (inp != NULL) {
+ if (inp->inp_flags & (INP_HW_FLOWID|INP_SW_FLOWID)) {
+ m->m_pkthdr.flowid = inp->inp_flowid;
+ m->m_flags |= M_FLOWID;
+ }
+ if (inp->inp_vflag & INP_RT_VALID) {
+ if (inp->inp_rt->rt_flags & RTF_UP) {
+ ro->ro_rt = inp->inp_rt;
+ } else
+ neednewroute = 1;
+ }
+ if (inp->inp_flags & INP_LLE_VALID) {
+ if (inp->inp_lle->la_flags & LLE_VALID) {
+ ro->ro_lle = inp->inp_lle;
+ } else
+ neednewlle = 1;
+ }
+ }
+ if ((ro->ro_rt == NULL) && (ro->ro_lle == NULL)) {
+ if (flowtable_lookup(ipv4_ft, m, ro) == 0)
+ nortfree = 1;
+ }
+skipcachecheck:
+
+ /*
+ * Check if we can take a huge shortcut
+ */
+ if (ro->ro_rt != NULL && (ro->ro_rt->rt_flags & RTF_UP) &&
+ ro->ro_lle != NULL && (ro->ro_lle->la_flags & LLE_VALID) &&
+ (flags & (IP_SENDONES|IP_ROUTETOIF)) == 0 &&
+ !PFIL_HOOKED(&inet_pfil_hook) &&
+ !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+ ifp = ro->ro_rt->rt_ifp;
+
+ if (ro->ro_rt->rt_flags & (RTF_UP|RTF_HOST)) {
+ if (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)
+ ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu;
+ mtu = ro->ro_rt->rt_rmx.rmx_mtu;
+ } else
+ mtu = ifp->if_mtu;
+
+ if (ro->ro_rt->rt_flags & RTF_GATEWAY)
+ dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
+ else
+ dst = (struct sockaddr_in *)&ro->ro_dst;
+ if (ro->ro_rt->rt_flags & RTF_HOST)
+ isbroadcast = (ro->ro_rt->rt_flags & RTF_BROADCAST);
+ else
+ isbroadcast = in_broadcast(dst->sin_addr, ifp);
+
+ if (!isbroadcast && (ip->ip_len <= mtu ||
+ (m->m_pkthdr.csum_flags & ifp->if_hwassist & CSUM_TSO) != 0
+ || ((ip->ip_off & IP_DF) == 0
+ && (ifp->if_hwassist & CSUM_FRAGMENT))))
+ return (ip_output_fast(m, ro, flags, hlen, inp));
+ }
+
/*
* If routing to interface only, short circuit routing lookup.
* The use of an all-ones broadcast address implies this; an
More information about the svn-src-user
mailing list