Index: ../share/man/man7/sysctl.7 =================================================================== RCS file: /cvsroot/src/share/man/man7/sysctl.7,v retrieving revision 1.6 diff -u -r1.6 sysctl.7 --- ../share/man/man7/sysctl.7 12 Mar 2007 14:37:28 -0000 1.6 +++ ../share/man/man7/sysctl.7 20 Mar 2007 23:25:08 -0000 @@ -1288,6 +1288,7 @@ .It ip6 defmcasthlim integer yes .It ip6 forwarding integer yes .It ip6 gifhlim integer yes +.It ip6 hashsize integer yes .It ip6 hlim integer yes .It ip6 hdrnestlimit integer yes .It ip6 kame_version string no @@ -1356,6 +1357,12 @@ .It Li ip6.hdrnestlimit The number of IPv6 extension headers permitted on incoming IPv6 packets. If set to 0, the node will accept as many extension headers as possible. +.It Li ip6.hashsize +The size of IPv6 Fast Forward hash table. +This value must be a power of 2 (64, 256...). +A larger hash table size results in fewer collisions. +Also see +.Li ip6.maxflows . .It Li ip6.hlim The default hop limit value for an IPv6 unicast packet sourced by the node. This value applies to all the transport protocols on top of IPv6. Index: netinet6/ip6_flow.c =================================================================== RCS file: /cvsroot/src/sys/netinet6/ip6_flow.c,v retrieving revision 1.3 diff -u -r1.3 ip6_flow.c --- netinet6/ip6_flow.c 12 Mar 2007 18:18:36 -0000 1.3 +++ netinet6/ip6_flow.c 20 Mar 2007 23:25:18 -0000 @@ -93,9 +93,9 @@ * use our own (possibly for future expansion). */ #define IP6FLOW_TIMER (5 * PR_SLOWHZ) -#define IP6FLOW_HASHSIZE (1 << IP6FLOW_HASHBITS) +#define IP6FLOW_DEFAULT_HASHSIZE (1 << IP6FLOW_HASHBITS) -static struct ip6flowhead ip6flowtable[IP6FLOW_HASHSIZE]; +static struct ip6flowhead *ip6flowtable = NULL; static struct ip6flowhead ip6flowlist; static int ip6flow_inuse; @@ -122,6 +122,7 @@ #endif int ip6_maxflows = IP6FLOW_DEFAULT; +int ip6_hashsize = IP6FLOW_DEFAULT_HASHSIZE; /* * Calculate hash table position. @@ -143,7 +144,7 @@ for (idx = 0; idx < 32; idx += IP6FLOW_HASHBITS) hash += (dst_sum >> (32 - idx)) + (src_sum >> idx); - return hash & (IP6FLOW_HASHSIZE-1); + return hash & (ip6_hashsize-1); } /* @@ -170,16 +171,34 @@ } /* - * Initalise lists. + * Allocate memory and initialise lists. This function is called + * from ip6_init and called there after to resize the hash table. + * If a newly sized table cannot be malloc'ed we just continue + * to use the old one. */ -void -ip6flow_init(void) +int +ip6flow_init(int table_size) { + struct ip6flowhead *new_table; size_t i; + new_table = (struct ip6flowhead *)malloc(sizeof(struct ip6flowhead) * + table_size, M_RTABLE, M_NOWAIT); + + if (new_table == NULL) + return 1; + + if (ip6flowtable != NULL) + free(ip6flowtable, M_RTABLE); + + ip6flowtable = new_table; + ip6_hashsize = table_size; + LIST_INIT(&ip6flowlist); - for (i = 0; i < IP6FLOW_HASHSIZE; i++) + for (i = 0; i < ip6_hashsize; i++) LIST_INIT(&ip6flowtable[i]); + + return 0; } /* @@ -483,18 +502,25 @@ } /* - * Invalidate/remove all flows. + * Invalidate/remove all flows - if new_size is positive we + * resize the hash table. */ -void -ip6flow_invalidate_all(void) +int +ip6flow_invalidate_all(int new_size) { struct ip6flow *ip6f, *next_ip6f; - int s; + int s, error; + error = 0; s = splnet(); for (ip6f = LIST_FIRST(&ip6flowlist); ip6f != NULL; ip6f = next_ip6f) { next_ip6f = LIST_NEXT(ip6f, ip6f_list); ip6flow_free(ip6f); } + + if (new_size) + error = ip6flow_init(new_size); splx(s); + + return error; } Index: netinet6/ip6_input.c =================================================================== RCS file: /cvsroot/src/sys/netinet6/ip6_input.c,v retrieving revision 1.98 diff -u -r1.98 ip6_input.c --- netinet6/ip6_input.c 7 Mar 2007 22:20:04 -0000 1.98 +++ netinet6/ip6_input.c 20 Mar 2007 23:25:21 -0000 @@ -183,7 +183,7 @@ ip6_init2((void *)0); #ifdef GATEWAY - ip6flow_init(); + ip6flow_init(ip6_hashsize); #endif #ifdef PFIL_HOOKS @@ -1610,6 +1610,7 @@ * 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) { @@ -1625,6 +1626,35 @@ return (0); } + +static int +sysctl_net_inet6_ip6_hashsize(SYSCTLFN_ARGS) +{ + int error, tmp; + struct sysctlnode node; + + node = *rnode; + tmp = ip6_hashsize; + node.sysctl_data = &tmp; + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error || newp == NULL) + return (error); + + if ((tmp & (tmp - 1)) == 0 && tmp != 0) { + /* + * Can only fail due to malloc() + */ + if (ip6flow_invalidate_all(tmp)) + return ENOMEM; + } else { + /* + * EINVAL if not a power of 2 + */ + return EINVAL; + } + + return (0); +} #endif /* GATEWAY */ /* @@ -1918,5 +1948,12 @@ sysctl_net_inet_ip6_maxflows, 0, &ip6_maxflows, 0, CTL_NET, PF_INET6, IPPROTO_IPV6, CTL_CREATE, CTL_EOL); + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "hashsize", + SYSCTL_DESCR("Size of hash table for fast forwarding (IPv6)"), + sysctl_net_inet6_ip6_hashsize, 0, &ip6_hashsize, 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.39 diff -u -r1.39 ip6_var.h --- netinet6/ip6_var.h 7 Mar 2007 22:20:04 -0000 1.39 +++ netinet6/ip6_var.h 20 Mar 2007 23:25:25 -0000 @@ -302,6 +302,7 @@ #ifdef GATEWAY extern int ip6_maxflows; /* maximum amount of flows for ip6ff */ +extern int ip6_hashsize; /* size of hash table */ #endif struct in6pcb; @@ -356,11 +357,11 @@ void frag6_slowtimo(void); void frag6_drain(void); -void ip6flow_init(void); +int ip6flow_init(int); struct ip6flow *ip6flow_reap(int); void ip6flow_create(const struct route_in6 *, struct mbuf *); void ip6flow_slowtimo(void); -void ip6flow_invalidate_all(void); +int ip6flow_invalidate_all(int); void rip6_init(void); int rip6_input(struct mbuf **, int *, int);