Index: ../share/man/man7/sysctl.7 =================================================================== RCS file: /cvsroot/src/share/man/man7/sysctl.7,v retrieving revision 1.4 diff -u -r1.4 sysctl.7 --- ../share/man/man7/sysctl.7 2 Feb 2007 02:39:13 -0000 1.4 +++ ../share/man/man7/sysctl.7 28 Feb 2007 19:57:27 -0000 @@ -1073,8 +1073,8 @@ be smaller than .Li ip.lowportmax . .It Li ip.maxflows -IP Fast Forwarding is enabled by default. -If set to 0, IP Fast Forwarding is disabled. +IPv4 Fast Forwarding is enabled by default. +If set to 0, IPv4 Fast Forwarding is disabled. .Li ip.maxflows controls the maximum amount of flows which can be created. The default value is 256. @@ -1295,6 +1295,7 @@ .It ip6 log_interval integer yes .It ip6 lowportmax integer yes .It ip6 lowportmin integer yes +.It ip6 maxflows integer yes .It ip6 maxfragpackets integer yes .It ip6 maxfrags integer yes .It ip6 redirect integer yes @@ -1385,6 +1386,11 @@ This cannot be set to less than 0 or greater than 1024, and must be smaller than .Li ip6.lowportmax . +.It Li ip6.maxflows +IPv6 Fast Forwarding is enabled by default. +If set to 0, IPv6 Fast Forwarding is disabled. +.Li ip6.maxflows +controls the maximum amount of flows which can be created. .It Li ip6.maxfragpackets The maximum number of fragmented packets the node will accept. 0 means that the node will not accept any fragmented packets. Index: netinet6/files.netinet6 =================================================================== RCS file: /cvsroot/src/sys/netinet6/files.netinet6,v retrieving revision 1.6 diff -u -r1.6 files.netinet6 --- netinet6/files.netinet6 25 Nov 2006 18:41:36 -0000 1.6 +++ netinet6/files.netinet6 28 Feb 2007 19:57:28 -0000 @@ -14,6 +14,7 @@ file netinet6/in6_pcb.c inet6 file netinet6/in6_proto.c inet6 file netinet6/in6_src.c inet6 +file netinet6/ip6_flow.c inet6 file netinet6/ip6_forward.c inet6 file netinet6/ip6_id.c inet6 file netinet6/ip6_input.c inet6 Index: netinet6/in6_proto.c =================================================================== RCS file: /cvsroot/src/sys/netinet6/in6_proto.c,v retrieving revision 1.72 diff -u -r1.72 in6_proto.c --- netinet6/in6_proto.c 19 Feb 2007 07:28:58 -0000 1.72 +++ netinet6/in6_proto.c 28 Feb 2007 19:57:28 -0000 @@ -204,6 +204,12 @@ .pr_flags = PR_ATOMIC|PR_ADDR, .pr_input = dest6_input, }, +#ifdef GATEWAY +{ .pr_domain = &inet6domain, + .pr_protocol = IPPROTO_IPV6, + .pr_slowtimo = ip6flow_slowtimo, +}, +#endif { .pr_type = SOCK_RAW, .pr_domain = &inet6domain, .pr_protocol = IPPROTO_ROUTING, Index: netinet6/in6_var.h =================================================================== RCS file: /cvsroot/src/sys/netinet6/in6_var.h,v retrieving revision 1.49 diff -u -r1.49 in6_var.h --- netinet6/in6_var.h 17 Feb 2007 22:34:13 -0000 1.49 +++ netinet6/in6_var.h 28 Feb 2007 19:57:28 -0000 @@ -650,6 +650,8 @@ void in6_prefixlen2mask(struct in6_addr *, int); void in6_purgeprefix(struct ifnet *); +int ip6flow_fastforward(struct mbuf *); /* IPv6 fast forward routine */ + int in6_src_ioctl(u_long, caddr_t); int in6_is_addr_deprecated(struct sockaddr_in6 *); struct in6pcb; Index: netinet6/ip6_flow.c =================================================================== RCS file: netinet6/ip6_flow.c diff -N netinet6/ip6_flow.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ netinet6/ip6_flow.c 28 Feb 2007 19:57:29 -0000 @@ -0,0 +1,483 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by the 3am Software Foundry ("3am"). It was developed by Liam J. Foy + * and Matt Thomas . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * IPv6 version was developed by Liam J. Foy. Original source existed in IPv4 + * format developed by Matt Thomas. Thanks to Joerg Sonnenberger, Matt + * Thomas and Christos Zoulas. + * + * Thanks to Liverpool John Moores University, especially Dr. David Llewellyn-Jones + * for providing resources (to test) and Professor Madjid Merabti. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +POOL_INIT(ip6flow_pool, sizeof(struct ip6flow), 0, 0, 0, "ip6flowpl", NULL); + +LIST_HEAD(ip6flowhead, ip6flow); + +/* + * We could use IPv4 defines (IPFLOW_HASHBITS) but we'll + * use our own (possibly for future expansion). + */ +#define IP6FLOW_TIMER (5 * PR_SLOWHZ) +#define IP6FLOW_HASHSIZE (1 << IP6FLOW_HASHBITS) + +static struct ip6flowhead ip6flowtable[IP6FLOW_HASHSIZE]; +static struct ip6flowhead ip6flowlist; +static int ip6flow_inuse; + +/* + * Insert an ipflow into the list. + */ +#define IP6FLOW_INSERT(bucket, ip6f) \ +do { \ + LIST_INSERT_HEAD((bucket), (ip6f), ip6f_hash); \ + LIST_INSERT_HEAD(&ip6flowlist, (ip6f), ip6f_list); \ +} while (/*CONSTCOND*/ 0) + +/* + * Remove an ipflow from the list. + */ +#define IP6FLOW_REMOVE(ip6f) \ +do { \ + LIST_REMOVE((ip6f), ip6f_hash); \ + LIST_REMOVE((ip6f), ip6f_list); \ +} while (/*CONSTCOND*/ 0) + +#ifndef IP6FLOW_DEFAULT +#define IP6FLOW_DEFAULT 256 +#endif + +int ip6_maxflows = IP6FLOW_DEFAULT; + +/* + * Calculate hash table position. + */ +static size_t +ip6flow_hash(struct ip6_hdr *ip6) +{ + size_t hash; + uint32_t dst_sum, src_sum; + int idx; + + src_sum = ip6->ip6_src.s6_addr32[0] + ip6->ip6_src.s6_addr32[1] + + ip6->ip6_src.s6_addr32[2] + ip6->ip6_src.s6_addr32[3]; + dst_sum = ip6->ip6_dst.s6_addr32[0] + ip6->ip6_dst.s6_addr32[1] + + ip6->ip6_dst.s6_addr32[2] + ip6->ip6_dst.s6_addr32[3]; + + hash = ip6->ip6_flow; + + for (idx = 0; idx < 32; idx += IP6FLOW_HASHBITS) + hash += (dst_sum >> (32 - idx)) + (src_sum >> idx); + + return hash & (IP6FLOW_HASHSIZE-1); +} + +/* + * Check to see if a flow already exists - if so return it. + */ +static struct ip6flow * +ip6flow_lookup(struct ip6_hdr *ip6) +{ + size_t hash; + struct ip6flow *ip6f; + + hash = ip6flow_hash(ip6); + + LIST_FOREACH(ip6f, &ip6flowlist, ip6f_list) { + if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &ip6f->ip6f_dst) + && IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6f->ip6f_src) + && ip6f->ip6f_flow == ip6->ip6_flow) { + /* A cached flow has been found. */ + break; + } + } + + return ip6f; +} + +/* + * Initalise lists. + */ +void +ip6flow_init(void) +{ + size_t i; + + LIST_INIT(&ip6flowlist); + for (i = 0; i < IP6FLOW_HASHSIZE; i++) + LIST_INIT(&ip6flowtable[i]); +} + +/* + * IPv6 Fast Forward routine. Attempt to forward the packet - + * if any problems are found return to the main IPv6 input + * routine to deal with. + */ +int +ip6flow_fastforward(struct mbuf *m) +{ + struct ip6flow *ip6f; + struct ip6_hdr *ip6; + struct rtentry *rt; + struct sockaddr_in6 *dst; + int error; + + /* + * Are we forwarding packets and have flows? + */ + if (!ip6_forwarding || ip6flow_inuse == 0) + return 0; + + /* + * At least size of IPv6 Header? + */ + if (m->m_len < sizeof(struct ip6_hdr)) + return 0; + /* + * Was packet received as a link-level multicast or broadcast? + * If so, don't try to fast forward.. + */ + if ((m->m_flags & (M_BCAST|M_MCAST)) != 0) + return 0; + + if (IP6_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) { + if ((m = m_copyup(m, sizeof(struct ip6_hdr), + (max_linkhdr + 3) & ~3)) == NULL) { + return 0; + } + } else if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) { + if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { + return 0; + } + } + + ip6 = mtod(m, struct ip6_hdr *); + + if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { + /* Bad version. */ + return 0; + } + + /* + * If we have a hop-by-hop extension we must process it. + * We just leave this up to ip6_input to deal with. + */ + if (ip6->ip6_nxt == IPPROTO_HOPOPTS) + return 0; + + /* + * Attempt to find a flow. + */ + if ((ip6f = ip6flow_lookup(ip6)) == NULL) { + /* No flow found. */ + return 0; + } + + /* + * Route and interface still up? + */ + rtcache_check((struct route *)&ip6f->ip6f_ro); + rt = ip6f->ip6f_ro.ro_rt; + if (rt == NULL || (rt->rt_ifp->if_flags & IFF_UP) == 0) { + /* Route or interface is down */ + return 0; + } + + /* + * Packet size greater than MTU? + */ + if (m->m_pkthdr.len > rt->rt_ifp->if_mtu) { + /* Return to main IPv6 input function. */ + return 0; + } + + if (ip6->ip6_hlim <= IPV6_HLIMDEC) + return 0; + + /* Decrement hop limit (same as TTL) */ + ip6->ip6_hlim -= IPV6_HLIMDEC; + + if (rt->rt_flags & RTF_GATEWAY) + dst = (struct sockaddr_in6 *)rt->rt_gateway; + else + dst = &ip6f->ip6f_ro.ro_dst; + + PRT_SLOW_ARM(ip6f->ip6f_timer, IP6FLOW_TIMER); + + ip6f->ip6f_uses++; + + /* Send on its way - straight to the interface output routine. */ + if ((error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m, + (struct sockaddr *)dst, rt)) != 0) { + ip6f->ip6f_dropped++; + } else { + ip6f->ip6f_forwarded++; + } + + return 1; +} + +/* + * Add the IPv6 flow statistics to the main IPv6 statistics. + */ +static void +ip6flow_addstats(struct ip6flow *ip6f) +{ + rtcache_check((struct route *)&ip6f->ip6f_ro); + if (ip6f->ip6f_ro.ro_rt != NULL) + ip6f->ip6f_ro.ro_rt->rt_use += ip6f->ip6f_uses; + ip6stat.ip6s_fastforwardflows = ip6flow_inuse; + ip6stat.ip6s_cantforward += ip6f->ip6f_dropped; + ip6stat.ip6s_odropped += ip6f->ip6f_dropped; + ip6stat.ip6s_total += ip6f->ip6f_uses; + ip6stat.ip6s_forward += ip6f->ip6f_forwarded; + ip6stat.ip6s_fastforward += ip6f->ip6f_forwarded; +} + +/* + * Add statistics and free the flow. + */ +static void +ip6flow_free(struct ip6flow *ip6f) +{ + int s; + + /* + * Remove the flow from the hash table (at elevated IPL). + * Once it's off the list, we can deal with it at normal + * network IPL. + */ + s = splnet(); + IP6FLOW_REMOVE(ip6f); + splx(s); + ip6flow_addstats(ip6f); + rtcache_free((struct route *)&ip6f->ip6f_ro); + ip6flow_inuse--; + pool_put(&ip6flow_pool, ip6f); +} + +/* + * Reap one or more flows - ip6flow_reap may remove + * multiple flows if net.inet6.ip6.maxflows is reduced. + */ +struct ip6flow * +ip6flow_reap(int just_one) +{ + while (just_one || ip6flow_inuse > ip6_maxflows) { + struct ip6flow *ip6f, *maybe_ip6f = NULL; + int s; + + ip6f = LIST_FIRST(&ip6flowlist); + while (ip6f != NULL) { + /* + * If this no longer points to a valid route - + * reclaim it. + */ + rtcache_check((struct route *)&ip6f->ip6f_ro); + if (ip6f->ip6f_ro.ro_rt == NULL) + goto done; + /* + * choose the one that's been least recently + * used or has had the least uses in the + * last 1.5 intervals. + */ + if (maybe_ip6f == NULL || + ip6f->ip6f_timer < maybe_ip6f->ip6f_timer || + (ip6f->ip6f_timer == maybe_ip6f->ip6f_timer && + ip6f->ip6f_last_uses + ip6f->ip6f_uses < + maybe_ip6f->ip6f_last_uses + + maybe_ip6f->ip6f_uses)) + maybe_ip6f = ip6f; + ip6f = LIST_NEXT(ip6f, ip6f_list); + } + ip6f = maybe_ip6f; + done: + /* + * Remove the entry from the flow table + */ + s = splnet(); + IP6FLOW_REMOVE(ip6f); + splx(s); + ip6flow_addstats(ip6f); + rtcache_free((struct route *)&ip6f->ip6f_ro); + if (just_one) + return ip6f; + pool_put(&ip6flow_pool, ip6f); + ip6flow_inuse--; + } + return NULL; +} + +void +ip6flow_slowtimo(void) +{ + struct ip6flow *ip6f, *next_ip6f; + + for (ip6f = LIST_FIRST(&ip6flowlist); ip6f != NULL; ip6f = next_ip6f) { + next_ip6f = LIST_NEXT(ip6f, ip6f_list); + rtcache_check((struct route *)&ip6f->ip6f_ro); + if (PRT_SLOW_ISEXPIRED(ip6f->ip6f_timer) || + ip6f->ip6f_ro.ro_rt == NULL) { + ip6flow_free(ip6f); + } else { + ip6f->ip6f_last_uses = ip6f->ip6f_uses; + ip6flow_addstats(ip6f); + ip6f->ip6f_uses = 0; + ip6f->ip6f_dropped = 0; + ip6f->ip6f_forwarded = 0; + } + } +} + +/* + * We have successfully forwarded a packet using the normal + * IPv6 stack. Now create/update a flow. + */ +void +ip6flow_create(const struct route_in6 *ro, struct mbuf *m) +{ + struct ip6_hdr *ip6; + struct ip6flow *ip6f; + size_t hash; + int s; + + ip6 = mtod(m, struct ip6_hdr *); + + /* + * If IPv6 Fast Forward is disabled, don't create a flow. + * It can be disabled by setting net.inet6.ip6.maxflows to 0. + * + * Don't create a flow for ICMPv6 messages. + */ + if (ip6_maxflows == 0 || ip6->ip6_nxt == IPPROTO_IPV6_ICMP) + return; + + /* + * See if an existing flow exists. If so: + * - Remove the flow + * - Add flow statistics + * - Free the route + * - Reset statistics + * + * If a flow doesn't exist allocate a new one if + * ip6_maxflows hasn't reached its limit. If it has + * been reached, reap some flows. + */ + ip6f = ip6flow_lookup(ip6); + if (ip6f == NULL) { + if (ip6flow_inuse >= ip6_maxflows) { + ip6f = ip6flow_reap(1); + } else { + ip6f = pool_get(&ip6flow_pool, PR_NOWAIT); + if (ip6f == NULL) + return; + ip6flow_inuse++; + } + memset(ip6f, 0, sizeof(*ip6f)); + } else { + s = splnet(); + IP6FLOW_REMOVE(ip6f); + splx(s); + ip6flow_addstats(ip6f); + RTFREE(ip6f->ip6f_ro.ro_rt); + ip6f->ip6f_uses = 0; + ip6f->ip6f_last_uses = 0; + ip6f->ip6f_dropped = 0; + ip6f->ip6f_forwarded = 0; + } + + /* + * Fill in the updated/new details. + */ + rtcache_copy((struct route *)&ip6f->ip6f_ro, (const struct route *)ro, + sizeof(ip6f->ip6f_ro)); + ip6f->ip6f_dst = ip6->ip6_dst; + ip6f->ip6f_src = ip6->ip6_src; + ip6f->ip6f_flow = ip6->ip6_flow; + PRT_SLOW_ARM(ip6f->ip6f_timer, IP6FLOW_TIMER); + ip6f->ip6f_start = time_uptime; + + /* + * Insert into the approriate bucket of the flow table. + */ + hash = ip6flow_hash(ip6); + s = splnet(); + IP6FLOW_INSERT(&ip6flowtable[hash], ip6f); + splx(s); +} + +/* + * Invalidate/remove all flows. + */ +void +ip6flow_invalidate_all(void) +{ + struct ip6flow *ip6f; + int s; + + s = splnet(); + LIST_FOREACH(ip6f, &ip6flowlist, ip6f_list) + ip6flow_free(ip6f); + splx(s); +} Index: netinet6/ip6_forward.c =================================================================== RCS file: /cvsroot/src/sys/netinet6/ip6_forward.c,v retrieving revision 1.55 diff -u -r1.55 ip6_forward.c --- netinet6/ip6_forward.c 17 Feb 2007 22:34:13 -0000 1.55 +++ netinet6/ip6_forward.c 28 Feb 2007 19:57:29 -0000 @@ -644,6 +644,10 @@ if (type) ip6stat.ip6s_redirectsent++; else { +#ifdef GATEWAY + if (m->m_flags & M_CANFASTFWD) + ip6flow_create(&ip6_forward_rt, m); +#endif if (mcopy) goto freecopy; } Index: netinet6/ip6_input.c =================================================================== RCS file: /cvsroot/src/sys/netinet6/ip6_input.c,v retrieving revision 1.96 diff -u -r1.96 ip6_input.c --- netinet6/ip6_input.c 22 Feb 2007 08:39:27 -0000 1.96 +++ netinet6/ip6_input.c 28 Feb 2007 19:57:30 -0000 @@ -182,6 +182,9 @@ ip6_desync_factor = arc4random() % MAX_TEMP_DESYNC_FACTOR; ip6_init2((void *)0); +#ifdef GATEWAY + ip6flow_init(); +#endif #ifdef PFIL_HOOKS /* Register our Packet Filter hook. */ @@ -324,6 +327,17 @@ goto bad; } +#if defined(IPSEC) + /* IPv6 fast forwarding is not compatible with IPsec. */ + m->m_flags &= ~M_CANFASTFWD; +#else + /* + * Assume that we can create a fast-forward IP flow entry + * based on this packet. + */ + m->m_flags |= M_CANFASTFWD; +#endif + #ifdef PFIL_HOOKS /* * Run through list of hooks for input packets. If there are any @@ -1591,6 +1605,28 @@ m_tag_delete(m, mtag); } +#ifdef GATEWAY +/* + * sysctl helper routine for net.inet.ip6.maxflows. Since + * we could reduce this value, call ip6flow_reap(); + */ +static int +sysctl_net_inet_ip6_maxflows(SYSCTLFN_ARGS) +{ + int s; + + s = sysctl_lookup(SYSCTLFN_CALL(rnode)); + if (s) + return (s); + + s = splsoftnet(); + ip6flow_reap(0); + splx(s); + + return (0); +} +#endif /* GATEWAY */ + /* * System control for IP6 */ @@ -1874,4 +1910,13 @@ NULL, 0, &ip6_mcast_pmtu, 0, CTL_NET, PF_INET6, IPPROTO_IPV6, CTL_CREATE, CTL_EOL); +#ifdef GATEWAY + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "maxflows", + SYSCTL_DESCR("Number of flows for fast forwarding (IPv6)"), + sysctl_net_inet_ip6_maxflows, 0, &ip6_maxflows, 0, + CTL_NET, PF_INET6, IPPROTO_IPV6, + CTL_CREATE, CTL_EOL); +#endif } Index: netinet6/ip6_var.h =================================================================== RCS file: /cvsroot/src/sys/netinet6/ip6_var.h,v retrieving revision 1.38 diff -u -r1.38 ip6_var.h --- netinet6/ip6_var.h 17 Feb 2007 22:34:14 -0000 1.38 +++ netinet6/ip6_var.h 28 Feb 2007 19:57:31 -0000 @@ -213,6 +213,29 @@ u_quad_t ip6s_forward_cachehit; u_quad_t ip6s_forward_cachemiss; + + u_quad_t ip6s_fastforward; /* packets fast forwarded */ + u_quad_t ip6s_fastforwardflows; /* number of fast forward flows*/ +}; + +#define IP6FLOW_HASHBITS 6 /* should not be a multiple of 8 */ + +/* + * Structure for an IPv6 flow (ip6_fastforward). + */ +struct ip6flow { + LIST_ENTRY(ip6flow) ip6f_list; /* next in active list */ + LIST_ENTRY(ip6flow) ip6f_hash; /* next ip6flow in bucket */ + struct in6_addr ip6f_dst; /* destination address */ + struct in6_addr ip6f_src; /* source address */ + struct route_in6 ip6f_ro; /* associated route entry */ + u_int32_t ip6f_flow; /* flow (tos) */ + u_quad_t ip6f_uses; /* number of uses in this period */ + u_quad_t ip6f_last_uses; /* number of uses in last period */ + u_quad_t ip6f_dropped; /* ENOBUFS returned by if_output */ + u_quad_t ip6f_forwarded; /* packets forwarded */ + u_int ip6f_timer; /* lifetime timer */ + time_t ip6f_start; /* creation time */ }; #ifdef _KERNEL @@ -277,6 +300,10 @@ extern int ip6_use_defzone; /* whether to use the default scope zone when unspecified */ +#ifdef GATEWAY +extern int ip6_maxflows; /* maximum amount of flows for ip6ff */ +#endif + struct in6pcb; int icmp6_ctloutput(int, struct socket *, int, int, struct mbuf **); @@ -329,6 +356,12 @@ void frag6_slowtimo(void); void frag6_drain(void); +void ip6flow_init(void); +struct ip6flow *ip6flow_reap(int); +void ip6flow_create(const struct route_in6 *, struct mbuf *); +void ip6flow_slowtimo(void); +void ip6flow_invalidate_all(void); + void rip6_init(void); int rip6_input(struct mbuf **, int *, int); void rip6_ctlinput(int, const struct sockaddr *, void *); Index: net/if_atmsubr.c =================================================================== RCS file: /cvsroot/src/sys/net/if_atmsubr.c,v retrieving revision 1.38 diff -u -r1.38 if_atmsubr.c --- net/if_atmsubr.c 17 Feb 2007 22:34:08 -0000 1.38 +++ net/if_atmsubr.c 28 Feb 2007 19:57:31 -0000 @@ -297,6 +297,10 @@ #endif /* INET */ #ifdef INET6 case ETHERTYPE_IPV6: +#ifdef GATEWAY + if (ip6flow_fastforward(m)) + return; +#endif schednetisr(NETISR_IPV6); inq = &ip6intrq; break; Index: net/if_ethersubr.c =================================================================== RCS file: /cvsroot/src/sys/net/if_ethersubr.c,v retrieving revision 1.146 diff -u -r1.146 if_ethersubr.c --- net/if_ethersubr.c 20 Feb 2007 08:55:54 -0000 1.146 +++ net/if_ethersubr.c 28 Feb 2007 19:57:31 -0000 @@ -880,6 +880,10 @@ #endif #ifdef INET6 case ETHERTYPE_IPV6: +#ifdef GATEWAY + if (ip6flow_fastforward(m)) + return; +#endif schednetisr(NETISR_IPV6); inq = &ip6intrq; break; Index: net/if_fddisubr.c =================================================================== RCS file: /cvsroot/src/sys/net/if_fddisubr.c,v retrieving revision 1.66 diff -u -r1.66 if_fddisubr.c --- net/if_fddisubr.c 17 Feb 2007 22:34:08 -0000 1.66 +++ net/if_fddisubr.c 28 Feb 2007 19:57:31 -0000 @@ -651,6 +651,10 @@ #endif #ifdef INET6 case ETHERTYPE_IPV6: +#ifdef GATEWAY + if (ip6flow_fastforward(m)) + return; +#endif schednetisr(NETISR_IPV6); inq = &ip6intrq; break; Index: net/if_ppp.c =================================================================== RCS file: /cvsroot/src/sys/net/if_ppp.c,v retrieving revision 1.112 diff -u -r1.112 if_ppp.c --- net/if_ppp.c 17 Feb 2007 22:34:08 -0000 1.112 +++ net/if_ppp.c 28 Feb 2007 19:57:32 -0000 @@ -1712,6 +1712,10 @@ m->m_pkthdr.len -= PPP_HDRLEN; m->m_data += PPP_HDRLEN; m->m_len -= PPP_HDRLEN; +#ifdef GATEWAY + if (ip6flow_fastforward(m)) + return; +#endif schednetisr(NETISR_IPV6); inq = &ip6intrq; break; Index: netipsec/key.c =================================================================== RCS file: /cvsroot/src/sys/netipsec/key.c,v retrieving revision 1.37 diff -u -r1.37 key.c --- netipsec/key.c 18 Feb 2007 13:55:25 -0000 1.37 +++ netipsec/key.c 28 Feb 2007 19:57:36 -0000 @@ -1931,6 +1931,7 @@ #if defined(GATEWAY) /* Invalidate the ipflow cache, as well. */ ipflow_invalidate_all(); + ip6flow_invalidate_all(); #endif #endif /* __NetBSD__ */ Index: ../usr.bin/netstat/inet6.c =================================================================== RCS file: /cvsroot/src/usr.bin/netstat/inet6.c,v retrieving revision 1.41 diff -u -r1.41 inet6.c --- ../usr.bin/netstat/inet6.c 17 Jan 2007 00:21:43 -0000 1.41 +++ ../usr.bin/netstat/inet6.c 28 Feb 2007 19:57:40 -0000 @@ -615,6 +615,8 @@ p(ip6s_reassembled, "\t%llu packet%s reassembled ok\n"); p(ip6s_delivered, "\t%llu packet%s for this host\n"); p(ip6s_forward, "\t%llu packet%s forwarded\n"); + p(ip6s_fastforward, "\t%llu packet%s fast forwarded\n"); + p1(ip6s_fastforwardflows, "\t%llu fast forward flows\n"); p(ip6s_cantforward, "\t%llu packet%s not forwardable\n"); p(ip6s_redirectsent, "\t%llu redirect%s sent\n"); p(ip6s_localout, "\t%llu packet%s sent from this host\n");