Thu Jan 19 13:13:48 2012 UTC ()
Remove ipf_start from ipf struct


(liamjfoy)
diff -r1.59 -r1.60 src/sys/netinet/ip_flow.c

cvs diff -r1.59 -r1.60 src/sys/netinet/ip_flow.c (switch to unified diff)

--- src/sys/netinet/ip_flow.c 2010/04/01 00:24:41 1.59
+++ src/sys/netinet/ip_flow.c 2012/01/19 13:13:48 1.60
@@ -1,512 +1,511 @@ @@ -1,512 +1,511 @@
1/* $NetBSD: ip_flow.c,v 1.59 2010/04/01 00:24:41 tls Exp $ */ 1/* $NetBSD: ip_flow.c,v 1.60 2012/01/19 13:13:48 liamjfoy Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by the 3am Software Foundry ("3am"). It was developed by Matt Thomas. 8 * by the 3am Software Foundry ("3am"). It was developed by Matt Thomas.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: ip_flow.c,v 1.59 2010/04/01 00:24:41 tls Exp $"); 33__KERNEL_RCSID(0, "$NetBSD: ip_flow.c,v 1.60 2012/01/19 13:13:48 liamjfoy Exp $");
34 34
35#include <sys/param.h> 35#include <sys/param.h>
36#include <sys/systm.h> 36#include <sys/systm.h>
37#include <sys/malloc.h> 37#include <sys/malloc.h>
38#include <sys/mbuf.h> 38#include <sys/mbuf.h>
39#include <sys/domain.h> 39#include <sys/domain.h>
40#include <sys/protosw.h> 40#include <sys/protosw.h>
41#include <sys/socket.h> 41#include <sys/socket.h>
42#include <sys/socketvar.h> 42#include <sys/socketvar.h>
43#include <sys/errno.h> 43#include <sys/errno.h>
44#include <sys/time.h> 44#include <sys/time.h>
45#include <sys/kernel.h> 45#include <sys/kernel.h>
46#include <sys/pool.h> 46#include <sys/pool.h>
47#include <sys/sysctl.h> 47#include <sys/sysctl.h>
48 48
49#include <net/if.h> 49#include <net/if.h>
50#include <net/if_dl.h> 50#include <net/if_dl.h>
51#include <net/route.h> 51#include <net/route.h>
52#include <net/pfil.h> 52#include <net/pfil.h>
53 53
54#include <netinet/in.h> 54#include <netinet/in.h>
55#include <netinet/in_systm.h> 55#include <netinet/in_systm.h>
56#include <netinet/ip.h> 56#include <netinet/ip.h>
57#include <netinet/in_pcb.h> 57#include <netinet/in_pcb.h>
58#include <netinet/in_var.h> 58#include <netinet/in_var.h>
59#include <netinet/ip_var.h> 59#include <netinet/ip_var.h>
60#include <netinet/ip_private.h> 60#include <netinet/ip_private.h>
61 61
62/* 62/*
63 * Similar code is very well commented in netinet6/ip6_flow.c 63 * Similar code is very well commented in netinet6/ip6_flow.c
64 */  64 */
65 65
66struct ipflow { 66struct ipflow {
67 LIST_ENTRY(ipflow) ipf_list; /* next in active list */ 67 LIST_ENTRY(ipflow) ipf_list; /* next in active list */
68 LIST_ENTRY(ipflow) ipf_hash; /* next ipflow in bucket */ 68 LIST_ENTRY(ipflow) ipf_hash; /* next ipflow in bucket */
69 struct in_addr ipf_dst; /* destination address */ 69 struct in_addr ipf_dst; /* destination address */
70 struct in_addr ipf_src; /* source address */ 70 struct in_addr ipf_src; /* source address */
71 uint8_t ipf_tos; /* type-of-service */ 71 uint8_t ipf_tos; /* type-of-service */
72 struct route ipf_ro; /* associated route entry */ 72 struct route ipf_ro; /* associated route entry */
73 u_long ipf_uses; /* number of uses in this period */ 73 u_long ipf_uses; /* number of uses in this period */
74 u_long ipf_last_uses; /* number of uses in last period */ 74 u_long ipf_last_uses; /* number of uses in last period */
75 u_long ipf_dropped; /* ENOBUFS retured by if_output */ 75 u_long ipf_dropped; /* ENOBUFS retured by if_output */
76 u_long ipf_errors; /* other errors returned by if_output */ 76 u_long ipf_errors; /* other errors returned by if_output */
77 u_int ipf_timer; /* lifetime timer */ 77 u_int ipf_timer; /* lifetime timer */
78 time_t ipf_start; /* creation time */ 
79}; 78};
80 79
81#define IPFLOW_HASHBITS 6 /* should not be a multiple of 8 */ 80#define IPFLOW_HASHBITS 6 /* should not be a multiple of 8 */
82 81
83static struct pool ipflow_pool; 82static struct pool ipflow_pool;
84 83
85LIST_HEAD(ipflowhead, ipflow); 84LIST_HEAD(ipflowhead, ipflow);
86 85
87#define IPFLOW_TIMER (5 * PR_SLOWHZ) 86#define IPFLOW_TIMER (5 * PR_SLOWHZ)
88#define IPFLOW_DEFAULT_HASHSIZE (1 << IPFLOW_HASHBITS) 87#define IPFLOW_DEFAULT_HASHSIZE (1 << IPFLOW_HASHBITS)
89 88
90static struct ipflowhead *ipflowtable = NULL; 89static struct ipflowhead *ipflowtable = NULL;
91static struct ipflowhead ipflowlist; 90static struct ipflowhead ipflowlist;
92static int ipflow_inuse; 91static int ipflow_inuse;
93 92
94#define IPFLOW_INSERT(bucket, ipf) \ 93#define IPFLOW_INSERT(bucket, ipf) \
95do { \ 94do { \
96 LIST_INSERT_HEAD((bucket), (ipf), ipf_hash); \ 95 LIST_INSERT_HEAD((bucket), (ipf), ipf_hash); \
97 LIST_INSERT_HEAD(&ipflowlist, (ipf), ipf_list); \ 96 LIST_INSERT_HEAD(&ipflowlist, (ipf), ipf_list); \
98} while (/*CONSTCOND*/ 0) 97} while (/*CONSTCOND*/ 0)
99 98
100#define IPFLOW_REMOVE(ipf) \ 99#define IPFLOW_REMOVE(ipf) \
101do { \ 100do { \
102 LIST_REMOVE((ipf), ipf_hash); \ 101 LIST_REMOVE((ipf), ipf_hash); \
103 LIST_REMOVE((ipf), ipf_list); \ 102 LIST_REMOVE((ipf), ipf_list); \
104} while (/*CONSTCOND*/ 0) 103} while (/*CONSTCOND*/ 0)
105 104
106#ifndef IPFLOW_MAX 105#ifndef IPFLOW_MAX
107#define IPFLOW_MAX 256 106#define IPFLOW_MAX 256
108#endif 107#endif
109int ip_maxflows = IPFLOW_MAX; 108int ip_maxflows = IPFLOW_MAX;
110int ip_hashsize = IPFLOW_DEFAULT_HASHSIZE; 109int ip_hashsize = IPFLOW_DEFAULT_HASHSIZE;
111 110
112static size_t  111static size_t
113ipflow_hash(const struct ip *ip) 112ipflow_hash(const struct ip *ip)
114{ 113{
115 size_t hash = ip->ip_tos; 114 size_t hash = ip->ip_tos;
116 size_t idx; 115 size_t idx;
117 116
118 for (idx = 0; idx < 32; idx += IPFLOW_HASHBITS) { 117 for (idx = 0; idx < 32; idx += IPFLOW_HASHBITS) {
119 hash += (ip->ip_dst.s_addr >> (32 - idx)) + 118 hash += (ip->ip_dst.s_addr >> (32 - idx)) +
120 (ip->ip_src.s_addr >> idx); 119 (ip->ip_src.s_addr >> idx);
121 } 120 }
122 121
123 return hash & (ip_hashsize-1); 122 return hash & (ip_hashsize-1);
124} 123}
125 124
126static struct ipflow * 125static struct ipflow *
127ipflow_lookup(const struct ip *ip) 126ipflow_lookup(const struct ip *ip)
128{ 127{
129 size_t hash; 128 size_t hash;
130 struct ipflow *ipf; 129 struct ipflow *ipf;
131 130
132 hash = ipflow_hash(ip); 131 hash = ipflow_hash(ip);
133 132
134 LIST_FOREACH(ipf, &ipflowtable[hash], ipf_hash) { 133 LIST_FOREACH(ipf, &ipflowtable[hash], ipf_hash) {
135 if (ip->ip_dst.s_addr == ipf->ipf_dst.s_addr 134 if (ip->ip_dst.s_addr == ipf->ipf_dst.s_addr
136 && ip->ip_src.s_addr == ipf->ipf_src.s_addr 135 && ip->ip_src.s_addr == ipf->ipf_src.s_addr
137 && ip->ip_tos == ipf->ipf_tos) 136 && ip->ip_tos == ipf->ipf_tos)
138 break; 137 break;
139 } 138 }
140 return ipf; 139 return ipf;
141} 140}
142 141
143void 142void
144ipflow_poolinit(void) 143ipflow_poolinit(void)
145{ 144{
146 145
147 pool_init(&ipflow_pool, sizeof(struct ipflow), 0, 0, 0, "ipflowpl", 146 pool_init(&ipflow_pool, sizeof(struct ipflow), 0, 0, 0, "ipflowpl",
148 NULL, IPL_NET); 147 NULL, IPL_NET);
149} 148}
150 149
151int 150int
152ipflow_init(int table_size) 151ipflow_init(int table_size)
153{ 152{
154 struct ipflowhead *new_table; 153 struct ipflowhead *new_table;
155 size_t i; 154 size_t i;
156 155
157 new_table = (struct ipflowhead *)malloc(sizeof(struct ipflowhead) * 156 new_table = (struct ipflowhead *)malloc(sizeof(struct ipflowhead) *
158 table_size, M_RTABLE, M_NOWAIT); 157 table_size, M_RTABLE, M_NOWAIT);
159 158
160 if (new_table == NULL) 159 if (new_table == NULL)
161 return 1; 160 return 1;
162 161
163 if (ipflowtable != NULL) 162 if (ipflowtable != NULL)
164 free(ipflowtable, M_RTABLE); 163 free(ipflowtable, M_RTABLE);
165 164
166 ipflowtable = new_table; 165 ipflowtable = new_table;
167 ip_hashsize = table_size; 166 ip_hashsize = table_size;
168 167
169 LIST_INIT(&ipflowlist); 168 LIST_INIT(&ipflowlist);
170 for (i = 0; i < ip_hashsize; i++) 169 for (i = 0; i < ip_hashsize; i++)
171 LIST_INIT(&ipflowtable[i]); 170 LIST_INIT(&ipflowtable[i]);
172 171
173 return 0; 172 return 0;
174} 173}
175 174
176int 175int
177ipflow_fastforward(struct mbuf *m) 176ipflow_fastforward(struct mbuf *m)
178{ 177{
179 struct ip *ip; 178 struct ip *ip;
180 struct ip ip_store; 179 struct ip ip_store;
181 struct ipflow *ipf; 180 struct ipflow *ipf;
182 struct rtentry *rt; 181 struct rtentry *rt;
183 const struct sockaddr *dst; 182 const struct sockaddr *dst;
184 int error; 183 int error;
185 int iplen; 184 int iplen;
186 185
187 /* 186 /*
188 * Are we forwarding packets? Big enough for an IP packet? 187 * Are we forwarding packets? Big enough for an IP packet?
189 */ 188 */
190 if (!ipforwarding || ipflow_inuse == 0 || m->m_len < sizeof(struct ip)) 189 if (!ipforwarding || ipflow_inuse == 0 || m->m_len < sizeof(struct ip))
191 return 0; 190 return 0;
192 191
193 /* 192 /*
194 * Was packet received as a link-level multicast or broadcast? 193 * Was packet received as a link-level multicast or broadcast?
195 * If so, don't try to fast forward.. 194 * If so, don't try to fast forward..
196 */ 195 */
197 if ((m->m_flags & (M_BCAST|M_MCAST)) != 0) 196 if ((m->m_flags & (M_BCAST|M_MCAST)) != 0)
198 return 0; 197 return 0;
199 198
200 /* 199 /*
201 * IP header with no option and valid version and length 200 * IP header with no option and valid version and length
202 */ 201 */
203 if (IP_HDR_ALIGNED_P(mtod(m, const void *))) 202 if (IP_HDR_ALIGNED_P(mtod(m, const void *)))
204 ip = mtod(m, struct ip *); 203 ip = mtod(m, struct ip *);
205 else { 204 else {
206 memcpy(&ip_store, mtod(m, const void *), sizeof(ip_store)); 205 memcpy(&ip_store, mtod(m, const void *), sizeof(ip_store));
207 ip = &ip_store; 206 ip = &ip_store;
208 } 207 }
209 iplen = ntohs(ip->ip_len); 208 iplen = ntohs(ip->ip_len);
210 if (ip->ip_v != IPVERSION || ip->ip_hl != (sizeof(struct ip) >> 2) || 209 if (ip->ip_v != IPVERSION || ip->ip_hl != (sizeof(struct ip) >> 2) ||
211 iplen < sizeof(struct ip) || iplen > m->m_pkthdr.len) 210 iplen < sizeof(struct ip) || iplen > m->m_pkthdr.len)
212 return 0; 211 return 0;
213 /* 212 /*
214 * Find a flow. 213 * Find a flow.
215 */ 214 */
216 if ((ipf = ipflow_lookup(ip)) == NULL) 215 if ((ipf = ipflow_lookup(ip)) == NULL)
217 return 0; 216 return 0;
218 217
219 /* 218 /*
220 * Verify the IP header checksum. 219 * Verify the IP header checksum.
221 */ 220 */
222 switch (m->m_pkthdr.csum_flags & 221 switch (m->m_pkthdr.csum_flags &
223 ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_IPv4) | 222 ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_IPv4) |
224 M_CSUM_IPv4_BAD)) { 223 M_CSUM_IPv4_BAD)) {
225 case M_CSUM_IPv4|M_CSUM_IPv4_BAD: 224 case M_CSUM_IPv4|M_CSUM_IPv4_BAD:
226 return (0); 225 return (0);
227 226
228 case M_CSUM_IPv4: 227 case M_CSUM_IPv4:
229 /* Checksum was okay. */ 228 /* Checksum was okay. */
230 break; 229 break;
231 230
232 default: 231 default:
233 /* Must compute it ourselves. */ 232 /* Must compute it ourselves. */
234 if (in_cksum(m, sizeof(struct ip)) != 0) 233 if (in_cksum(m, sizeof(struct ip)) != 0)
235 return (0); 234 return (0);
236 break; 235 break;
237 } 236 }
238 237
239 /* 238 /*
240 * Route and interface still up? 239 * Route and interface still up?
241 */ 240 */
242 if ((rt = rtcache_validate(&ipf->ipf_ro)) == NULL || 241 if ((rt = rtcache_validate(&ipf->ipf_ro)) == NULL ||
243 (rt->rt_ifp->if_flags & IFF_UP) == 0) 242 (rt->rt_ifp->if_flags & IFF_UP) == 0)
244 return 0; 243 return 0;
245 244
246 /* 245 /*
247 * Packet size OK? TTL? 246 * Packet size OK? TTL?
248 */ 247 */
249 if (m->m_pkthdr.len > rt->rt_ifp->if_mtu || ip->ip_ttl <= IPTTLDEC) 248 if (m->m_pkthdr.len > rt->rt_ifp->if_mtu || ip->ip_ttl <= IPTTLDEC)
250 return 0; 249 return 0;
251 250
252 /* 251 /*
253 * Clear any in-bound checksum flags for this packet. 252 * Clear any in-bound checksum flags for this packet.
254 */ 253 */
255 m->m_pkthdr.csum_flags = 0; 254 m->m_pkthdr.csum_flags = 0;
256 255
257 /* 256 /*
258 * Everything checks out and so we can forward this packet. 257 * Everything checks out and so we can forward this packet.
259 * Modify the TTL and incrementally change the checksum. 258 * Modify the TTL and incrementally change the checksum.
260 * 259 *
261 * This method of adding the checksum works on either endian CPU. 260 * This method of adding the checksum works on either endian CPU.
262 * If htons() is inlined, all the arithmetic is folded; otherwise 261 * If htons() is inlined, all the arithmetic is folded; otherwise
263 * the htons()s are combined by CSE due to the const attribute. 262 * the htons()s are combined by CSE due to the const attribute.
264 * 263 *
265 * Don't bother using HW checksumming here -- the incremental 264 * Don't bother using HW checksumming here -- the incremental
266 * update is pretty fast. 265 * update is pretty fast.
267 */ 266 */
268 ip->ip_ttl -= IPTTLDEC; 267 ip->ip_ttl -= IPTTLDEC;
269 if (ip->ip_sum >= (u_int16_t) ~htons(IPTTLDEC << 8)) 268 if (ip->ip_sum >= (u_int16_t) ~htons(IPTTLDEC << 8))
270 ip->ip_sum -= ~htons(IPTTLDEC << 8); 269 ip->ip_sum -= ~htons(IPTTLDEC << 8);
271 else 270 else
272 ip->ip_sum += htons(IPTTLDEC << 8); 271 ip->ip_sum += htons(IPTTLDEC << 8);
273 272
274 /* 273 /*
275 * Done modifying the header; copy it back, if necessary. 274 * Done modifying the header; copy it back, if necessary.
276 * 275 *
277 * XXX Use m_copyback_cow(9) here? --dyoung 276 * XXX Use m_copyback_cow(9) here? --dyoung
278 */ 277 */
279 if (IP_HDR_ALIGNED_P(mtod(m, void *)) == 0) 278 if (IP_HDR_ALIGNED_P(mtod(m, void *)) == 0)
280 memcpy(mtod(m, void *), &ip_store, sizeof(ip_store)); 279 memcpy(mtod(m, void *), &ip_store, sizeof(ip_store));
281 280
282 /* 281 /*
283 * Trim the packet in case it's too long.. 282 * Trim the packet in case it's too long..
284 */ 283 */
285 if (m->m_pkthdr.len > iplen) { 284 if (m->m_pkthdr.len > iplen) {
286 if (m->m_len == m->m_pkthdr.len) { 285 if (m->m_len == m->m_pkthdr.len) {
287 m->m_len = iplen; 286 m->m_len = iplen;
288 m->m_pkthdr.len = iplen; 287 m->m_pkthdr.len = iplen;
289 } else 288 } else
290 m_adj(m, iplen - m->m_pkthdr.len); 289 m_adj(m, iplen - m->m_pkthdr.len);
291 } 290 }
292 291
293 /* 292 /*
294 * Send the packet on it's way. All we can get back is ENOBUFS 293 * Send the packet on it's way. All we can get back is ENOBUFS
295 */ 294 */
296 ipf->ipf_uses++; 295 ipf->ipf_uses++;
297 PRT_SLOW_ARM(ipf->ipf_timer, IPFLOW_TIMER); 296 PRT_SLOW_ARM(ipf->ipf_timer, IPFLOW_TIMER);
298 297
299 if (rt->rt_flags & RTF_GATEWAY) 298 if (rt->rt_flags & RTF_GATEWAY)
300 dst = rt->rt_gateway; 299 dst = rt->rt_gateway;
301 else 300 else
302 dst = rtcache_getdst(&ipf->ipf_ro); 301 dst = rtcache_getdst(&ipf->ipf_ro);
303 302
304 KERNEL_LOCK(1, NULL); 303 KERNEL_LOCK(1, NULL);
305 if ((error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m, dst, rt)) != 0) { 304 if ((error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m, dst, rt)) != 0) {
306 if (error == ENOBUFS) 305 if (error == ENOBUFS)
307 ipf->ipf_dropped++; 306 ipf->ipf_dropped++;
308 else 307 else
309 ipf->ipf_errors++; 308 ipf->ipf_errors++;
310 } 309 }
311 KERNEL_UNLOCK_ONE(NULL); 310 KERNEL_UNLOCK_ONE(NULL);
312 return 1; 311 return 1;
313} 312}
314  313
315static void 314static void
316ipflow_addstats(struct ipflow *ipf) 315ipflow_addstats(struct ipflow *ipf)
317{ 316{
318 struct rtentry *rt; 317 struct rtentry *rt;
319 uint64_t *ips; 318 uint64_t *ips;
320 319
321 if ((rt = rtcache_validate(&ipf->ipf_ro)) != NULL) 320 if ((rt = rtcache_validate(&ipf->ipf_ro)) != NULL)
322 rt->rt_use += ipf->ipf_uses; 321 rt->rt_use += ipf->ipf_uses;
323  322
324 ips = IP_STAT_GETREF(); 323 ips = IP_STAT_GETREF();
325 ips[IP_STAT_CANTFORWARD] += ipf->ipf_errors + ipf->ipf_dropped; 324 ips[IP_STAT_CANTFORWARD] += ipf->ipf_errors + ipf->ipf_dropped;
326 ips[IP_STAT_TOTAL] += ipf->ipf_uses; 325 ips[IP_STAT_TOTAL] += ipf->ipf_uses;
327 ips[IP_STAT_FORWARD] += ipf->ipf_uses; 326 ips[IP_STAT_FORWARD] += ipf->ipf_uses;
328 ips[IP_STAT_FASTFORWARD] += ipf->ipf_uses; 327 ips[IP_STAT_FASTFORWARD] += ipf->ipf_uses;
329 IP_STAT_PUTREF(); 328 IP_STAT_PUTREF();
330} 329}
331 330
332static void 331static void
333ipflow_free(struct ipflow *ipf) 332ipflow_free(struct ipflow *ipf)
334{ 333{
335 int s; 334 int s;
336 /* 335 /*
337 * Remove the flow from the hash table (at elevated IPL). 336 * Remove the flow from the hash table (at elevated IPL).
338 * Once it's off the list, we can deal with it at normal 337 * Once it's off the list, we can deal with it at normal
339 * network IPL. 338 * network IPL.
340 */ 339 */
341 s = splnet(); 340 s = splnet();
342 IPFLOW_REMOVE(ipf); 341 IPFLOW_REMOVE(ipf);
343 splx(s); 342 splx(s);
344 ipflow_addstats(ipf); 343 ipflow_addstats(ipf);
345 rtcache_free(&ipf->ipf_ro); 344 rtcache_free(&ipf->ipf_ro);
346 ipflow_inuse--; 345 ipflow_inuse--;
347 s = splnet(); 346 s = splnet();
348 pool_put(&ipflow_pool, ipf); 347 pool_put(&ipflow_pool, ipf);
349 splx(s); 348 splx(s);
350} 349}
351 350
352static struct ipflow * 351static struct ipflow *
353ipflow_reap(bool just_one) 352ipflow_reap(bool just_one)
354{ 353{
355 while (just_one || ipflow_inuse > ip_maxflows) { 354 while (just_one || ipflow_inuse > ip_maxflows) {
356 struct ipflow *ipf, *maybe_ipf = NULL; 355 struct ipflow *ipf, *maybe_ipf = NULL;
357 int s; 356 int s;
358 357
359 ipf = LIST_FIRST(&ipflowlist); 358 ipf = LIST_FIRST(&ipflowlist);
360 while (ipf != NULL) { 359 while (ipf != NULL) {
361 /* 360 /*
362 * If this no longer points to a valid route 361 * If this no longer points to a valid route
363 * reclaim it. 362 * reclaim it.
364 */ 363 */
365 if (rtcache_validate(&ipf->ipf_ro) == NULL) 364 if (rtcache_validate(&ipf->ipf_ro) == NULL)
366 goto done; 365 goto done;
367 /* 366 /*
368 * choose the one that's been least recently 367 * choose the one that's been least recently
369 * used or has had the least uses in the 368 * used or has had the least uses in the
370 * last 1.5 intervals. 369 * last 1.5 intervals.
371 */ 370 */
372 if (maybe_ipf == NULL || 371 if (maybe_ipf == NULL ||
373 ipf->ipf_timer < maybe_ipf->ipf_timer || 372 ipf->ipf_timer < maybe_ipf->ipf_timer ||
374 (ipf->ipf_timer == maybe_ipf->ipf_timer && 373 (ipf->ipf_timer == maybe_ipf->ipf_timer &&
375 ipf->ipf_last_uses + ipf->ipf_uses < 374 ipf->ipf_last_uses + ipf->ipf_uses <
376 maybe_ipf->ipf_last_uses + 375 maybe_ipf->ipf_last_uses +
377 maybe_ipf->ipf_uses)) 376 maybe_ipf->ipf_uses))
378 maybe_ipf = ipf; 377 maybe_ipf = ipf;
379 ipf = LIST_NEXT(ipf, ipf_list); 378 ipf = LIST_NEXT(ipf, ipf_list);
380 } 379 }
381 ipf = maybe_ipf; 380 ipf = maybe_ipf;
382 done: 381 done:
383 /* 382 /*
384 * Remove the entry from the flow table. 383 * Remove the entry from the flow table.
385 */ 384 */
386 s = splnet(); 385 s = splnet();
387 IPFLOW_REMOVE(ipf); 386 IPFLOW_REMOVE(ipf);
388 splx(s); 387 splx(s);
389 ipflow_addstats(ipf); 388 ipflow_addstats(ipf);
390 rtcache_free(&ipf->ipf_ro); 389 rtcache_free(&ipf->ipf_ro);
391 if (just_one) 390 if (just_one)
392 return ipf; 391 return ipf;
393 pool_put(&ipflow_pool, ipf); 392 pool_put(&ipflow_pool, ipf);
394 ipflow_inuse--; 393 ipflow_inuse--;
395 } 394 }
396 return NULL; 395 return NULL;
397} 396}
398 397
399void 398void
400ipflow_prune(void) 399ipflow_prune(void)
401{ 400{
402 401
403 (void) ipflow_reap(false); 402 (void) ipflow_reap(false);
404} 403}
405 404
406void 405void
407ipflow_slowtimo(void) 406ipflow_slowtimo(void)
408{ 407{
409 struct rtentry *rt; 408 struct rtentry *rt;
410 struct ipflow *ipf, *next_ipf; 409 struct ipflow *ipf, *next_ipf;
411 uint64_t *ips; 410 uint64_t *ips;
412 411
413 mutex_enter(softnet_lock); 412 mutex_enter(softnet_lock);
414 KERNEL_LOCK(1, NULL); 413 KERNEL_LOCK(1, NULL);
415 for (ipf = LIST_FIRST(&ipflowlist); ipf != NULL; ipf = next_ipf) { 414 for (ipf = LIST_FIRST(&ipflowlist); ipf != NULL; ipf = next_ipf) {
416 next_ipf = LIST_NEXT(ipf, ipf_list); 415 next_ipf = LIST_NEXT(ipf, ipf_list);
417 if (PRT_SLOW_ISEXPIRED(ipf->ipf_timer) || 416 if (PRT_SLOW_ISEXPIRED(ipf->ipf_timer) ||
418 (rt = rtcache_validate(&ipf->ipf_ro)) == NULL) { 417 (rt = rtcache_validate(&ipf->ipf_ro)) == NULL) {
419 ipflow_free(ipf); 418 ipflow_free(ipf);
420 } else { 419 } else {
421 ipf->ipf_last_uses = ipf->ipf_uses; 420 ipf->ipf_last_uses = ipf->ipf_uses;
422 rt->rt_use += ipf->ipf_uses; 421 rt->rt_use += ipf->ipf_uses;
423 ips = IP_STAT_GETREF(); 422 ips = IP_STAT_GETREF();
424 ips[IP_STAT_TOTAL] += ipf->ipf_uses; 423 ips[IP_STAT_TOTAL] += ipf->ipf_uses;
425 ips[IP_STAT_FORWARD] += ipf->ipf_uses; 424 ips[IP_STAT_FORWARD] += ipf->ipf_uses;
426 ips[IP_STAT_FASTFORWARD] += ipf->ipf_uses; 425 ips[IP_STAT_FASTFORWARD] += ipf->ipf_uses;
427 IP_STAT_PUTREF(); 426 IP_STAT_PUTREF();
428 ipf->ipf_uses = 0; 427 ipf->ipf_uses = 0;
429 } 428 }
430 } 429 }
431 KERNEL_UNLOCK_ONE(NULL); 430 KERNEL_UNLOCK_ONE(NULL);
432 mutex_exit(softnet_lock); 431 mutex_exit(softnet_lock);
433} 432}
434 433
435void 434void
436ipflow_create(const struct route *ro, struct mbuf *m) 435ipflow_create(const struct route *ro, struct mbuf *m)
437{ 436{
438 const struct ip *const ip = mtod(m, const struct ip *); 437 const struct ip *const ip = mtod(m, const struct ip *);
439 struct ipflow *ipf; 438 struct ipflow *ipf;
440 size_t hash; 439 size_t hash;
441 int s; 440 int s;
442 441
443 /* 442 /*
444 * Don't create cache entries for ICMP messages. 443 * Don't create cache entries for ICMP messages.
445 */ 444 */
446 if (ip_maxflows == 0 || ip->ip_p == IPPROTO_ICMP) 445 if (ip_maxflows == 0 || ip->ip_p == IPPROTO_ICMP)
447 return; 446 return;
448 /* 447 /*
449 * See if an existing flow struct exists. If so remove it from it's 448 * See if an existing flow struct exists. If so remove it from it's
450 * list and free the old route. If not, try to malloc a new one 449 * list and free the old route. If not, try to malloc a new one
451 * (if we aren't at our limit). 450 * (if we aren't at our limit).
452 */ 451 */
453 ipf = ipflow_lookup(ip); 452 ipf = ipflow_lookup(ip);
454 if (ipf == NULL) { 453 if (ipf == NULL) {
455 if (ipflow_inuse >= ip_maxflows) { 454 if (ipflow_inuse >= ip_maxflows) {
456 ipf = ipflow_reap(true); 455 ipf = ipflow_reap(true);
457 } else { 456 } else {
458 s = splnet(); 457 s = splnet();
459 ipf = pool_get(&ipflow_pool, PR_NOWAIT); 458 ipf = pool_get(&ipflow_pool, PR_NOWAIT);
460 splx(s); 459 splx(s);
461 if (ipf == NULL) 460 if (ipf == NULL)
462 return; 461 return;
463 ipflow_inuse++; 462 ipflow_inuse++;
464 } 463 }
465 memset(ipf, 0, sizeof(*ipf)); 464 memset(ipf, 0, sizeof(*ipf));
466 } else { 465 } else {
467 s = splnet(); 466 s = splnet();
468 IPFLOW_REMOVE(ipf); 467 IPFLOW_REMOVE(ipf);
469 splx(s); 468 splx(s);
470 ipflow_addstats(ipf); 469 ipflow_addstats(ipf);
471 rtcache_free(&ipf->ipf_ro); 470 rtcache_free(&ipf->ipf_ro);
472 ipf->ipf_uses = ipf->ipf_last_uses = 0; 471 ipf->ipf_uses = ipf->ipf_last_uses = 0;
473 ipf->ipf_errors = ipf->ipf_dropped = 0; 472 ipf->ipf_errors = ipf->ipf_dropped = 0;
474 } 473 }
475 474
476 /* 475 /*
477 * Fill in the updated information. 476 * Fill in the updated information.
478 */ 477 */
479 rtcache_copy(&ipf->ipf_ro, ro); 478 rtcache_copy(&ipf->ipf_ro, ro);
480 ipf->ipf_dst = ip->ip_dst; 479 ipf->ipf_dst = ip->ip_dst;
481 ipf->ipf_src = ip->ip_src; 480 ipf->ipf_src = ip->ip_src;
482 ipf->ipf_tos = ip->ip_tos; 481 ipf->ipf_tos = ip->ip_tos;
483 PRT_SLOW_ARM(ipf->ipf_timer, IPFLOW_TIMER); 482 PRT_SLOW_ARM(ipf->ipf_timer, IPFLOW_TIMER);
484 ipf->ipf_start = time_uptime; 483
485 /* 484 /*
486 * Insert into the approriate bucket of the flow table. 485 * Insert into the approriate bucket of the flow table.
487 */ 486 */
488 hash = ipflow_hash(ip); 487 hash = ipflow_hash(ip);
489 s = splnet(); 488 s = splnet();
490 IPFLOW_INSERT(&ipflowtable[hash], ipf); 489 IPFLOW_INSERT(&ipflowtable[hash], ipf);
491 splx(s); 490 splx(s);
492} 491}
493 492
494int 493int
495ipflow_invalidate_all(int new_size) 494ipflow_invalidate_all(int new_size)
496{ 495{
497 struct ipflow *ipf, *next_ipf; 496 struct ipflow *ipf, *next_ipf;
498 int s, error; 497 int s, error;
499 498
500 error = 0; 499 error = 0;
501 s = splnet(); 500 s = splnet();
502 for (ipf = LIST_FIRST(&ipflowlist); ipf != NULL; ipf = next_ipf) { 501 for (ipf = LIST_FIRST(&ipflowlist); ipf != NULL; ipf = next_ipf) {
503 next_ipf = LIST_NEXT(ipf, ipf_list); 502 next_ipf = LIST_NEXT(ipf, ipf_list);
504 ipflow_free(ipf); 503 ipflow_free(ipf);
505 } 504 }
506 505
507 if (new_size) 506 if (new_size)
508 error = ipflow_init(new_size); 507 error = ipflow_init(new_size);
509 splx(s); 508 splx(s);
510 509
511 return error; 510 return error;
512} 511}