|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*-
23: * Copyright (c) 1998 The NetBSD Foundation, Inc.
24: * All rights reserved.
25: *
26: * This code is derived from software contributed to The NetBSD Foundation
27: * by the 3am Software Foundry ("3am"). It was developed by Matt Thomas.
28: *
29: * Redistribution and use in source and binary forms, with or without
30: * modification, are permitted provided that the following conditions
31: * are met:
32: * 1. Redistributions of source code must retain the above copyright
33: * notice, this list of conditions and the following disclaimer.
34: * 2. Redistributions in binary form must reproduce the above copyright
35: * notice, this list of conditions and the following disclaimer in the
36: * documentation and/or other materials provided with the distribution.
37: * 3. All advertising materials mentioning features or use of this software
38: * must display the following acknowledgement:
39: * This product includes software developed by the NetBSD
40: * Foundation, Inc. and its contributors.
41: * 4. Neither the name of The NetBSD Foundation nor the names of its
42: * contributors may be used to endorse or promote products derived
43: * from this software without specific prior written permission.
44: *
45: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
46: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
47: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
49: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55: * POSSIBILITY OF SUCH DAMAGE.
56: *
57: */
58:
59: #include <sys/param.h>
60: #include <sys/systm.h>
61: #include <sys/malloc.h>
62: #include <sys/mbuf.h>
63: #include <sys/protosw.h>
64: #include <sys/socket.h>
65: #include <sys/kernel.h>
66:
67: #include <sys/sysctl.h>
68:
69: #include <net/if.h>
70: #include <net/route.h>
71:
72: #include <netinet/in.h>
73: #include <netinet/in_systm.h>
74: #include <netinet/ip.h>
75: #include <netinet/in_var.h>
76: #include <netinet/ip_var.h>
77: #include <netinet/ip_flow.h>
78: #include <net/dlil.h>
79:
80: #define IPFLOW_TIMER (5 * PR_SLOWHZ)
81: #define IPFLOW_HASHBITS 6 /* should not be a multiple of 8 */
82: #define IPFLOW_HASHSIZE (1 << IPFLOW_HASHBITS)
83: static LIST_HEAD(ipflowhead, ipflow) ipflows[IPFLOW_HASHSIZE];
84: static int ipflow_inuse;
85: #define IPFLOW_MAX 256
86:
87: #if ISFB31
88: #else
89: #define M_IPFLOW M_TEMP
90: #endif
91:
92: static int ipflow_active = 0;
93: SYSCTL_INT(_net_inet_ip, IPCTL_FASTFORWARDING, fastforwarding, CTLFLAG_RW,
94: &ipflow_active, 0, "");
95:
96: MALLOC_DEFINE(M_IPFLOW, "ip_flow", "IP flow");
97:
98: static unsigned
99: ipflow_hash(
100: struct in_addr dst,
101: struct in_addr src,
102: unsigned tos)
103: {
104: unsigned hash = tos;
105: int idx;
106: for (idx = 0; idx < 32; idx += IPFLOW_HASHBITS)
107: hash += (dst.s_addr >> (32 - idx)) + (src.s_addr >> idx);
108: return hash & (IPFLOW_HASHSIZE-1);
109: }
110:
111: static struct ipflow *
112: ipflow_lookup(
113: const struct ip *ip)
114: {
115: unsigned hash;
116: struct ipflow *ipf;
117:
118: hash = ipflow_hash(ip->ip_dst, ip->ip_src, ip->ip_tos);
119:
120: ipf = LIST_FIRST(&ipflows[hash]);
121: while (ipf != NULL) {
122: if (ip->ip_dst.s_addr == ipf->ipf_dst.s_addr
123: && ip->ip_src.s_addr == ipf->ipf_src.s_addr
124: && ip->ip_tos == ipf->ipf_tos)
125: break;
126: ipf = LIST_NEXT(ipf, ipf_next);
127: }
128: return ipf;
129: }
130:
131: int
132: ipflow_fastforward(
133: struct mbuf *m)
134: {
135: struct ip *ip;
136: struct ipflow *ipf;
137: struct rtentry *rt;
138: int error;
139:
140: /*
141: * Are we forwarding packets? Big enough for an IP packet?
142: */
143: if (!ipforwarding || !ipflow_active || m->m_len < sizeof(struct ip))
144: return 0;
145: /*
146: * IP header with no option and valid version and length
147: */
148: ip = mtod(m, struct ip *);
149: if (ip->ip_v != IPVERSION || ip->ip_hl != (sizeof(struct ip) >> 2)
150: || ntohs(ip->ip_len) > m->m_pkthdr.len)
151: return 0;
152: /*
153: * Find a flow.
154: */
155: if ((ipf = ipflow_lookup(ip)) == NULL)
156: return 0;
157:
158: /*
159: * Route and interface still up?
160: */
161: rt = ipf->ipf_ro.ro_rt;
162: if ((rt->rt_flags & RTF_UP) == 0 || (rt->rt_ifp->if_flags & IFF_UP) == 0)
163: return 0;
164:
165: /*
166: * Packet size OK? TTL?
167: */
168: if (m->m_pkthdr.len > rt->rt_ifp->if_mtu || ip->ip_ttl <= IPTTLDEC)
169: return 0;
170:
171: /*
172: * Everything checks out and so we can forward this packet.
173: * Modify the TTL and incrementally change the checksum.
174: */
175: ip->ip_ttl -= IPTTLDEC;
176: if (ip->ip_sum >= htons(0xffff - (IPTTLDEC << 8))) {
177: ip->ip_sum += htons(IPTTLDEC << 8) + 1;
178: } else {
179: ip->ip_sum += htons(IPTTLDEC << 8);
180: }
181:
182: /*
183: * Send the packet on its way. All we can get back is ENOBUFS
184: */
185: ipf->ipf_uses++;
186: ipf->ipf_timer = IPFLOW_TIMER;
187:
188: /* Not sure the rt_dlt is valid here !! XXX */
189: if ((error = dlil_output((u_long)rt->rt_dlt, m, (caddr_t) rt, &ipf->ipf_ro.ro_dst, 0)) != 0) {
190: if (error == ENOBUFS)
191: ipf->ipf_dropped++;
192: else
193: ipf->ipf_errors++;
194: }
195: return 1;
196: }
197:
198: static void
199: ipflow_addstats(
200: struct ipflow *ipf)
201: {
202: ipf->ipf_ro.ro_rt->rt_use += ipf->ipf_uses;
203: ipstat.ips_cantforward += ipf->ipf_errors + ipf->ipf_dropped;
204: ipstat.ips_forward += ipf->ipf_uses;
205: ipstat.ips_fastforward += ipf->ipf_uses;
206: }
207:
208: static void
209: ipflow_free(
210: struct ipflow *ipf)
211: {
212: int s;
213: /*
214: * Remove the flow from the hash table (at elevated IPL).
215: * Once it's off the list, we can deal with it at normal
216: * network IPL.
217: */
218: s = splimp();
219: LIST_REMOVE(ipf, ipf_next);
220: splx(s);
221: ipflow_addstats(ipf);
222: RTFREE(ipf->ipf_ro.ro_rt);
223: ipflow_inuse--;
224: FREE(ipf, M_IPFLOW);
225: }
226:
227: static struct ipflow *
228: ipflow_reap(
229: void)
230: {
231: struct ipflow *ipf, *maybe_ipf = NULL;
232: int idx;
233: int s;
234:
235: for (idx = 0; idx < IPFLOW_HASHSIZE; idx++) {
236: ipf = LIST_FIRST(&ipflows[idx]);
237: while (ipf != NULL) {
238: /*
239: * If this no longer points to a valid route
240: * reclaim it.
241: */
242: if ((ipf->ipf_ro.ro_rt->rt_flags & RTF_UP) == 0)
243: goto done;
244: /*
245: * choose the one that's been least recently used
246: * or has had the least uses in the last 1.5
247: * intervals.
248: */
249: if (maybe_ipf == NULL
250: || ipf->ipf_timer < maybe_ipf->ipf_timer
251: || (ipf->ipf_timer == maybe_ipf->ipf_timer
252: && ipf->ipf_last_uses + ipf->ipf_uses <
253: maybe_ipf->ipf_last_uses +
254: maybe_ipf->ipf_uses))
255: maybe_ipf = ipf;
256: ipf = LIST_NEXT(ipf, ipf_next);
257: }
258: }
259: ipf = maybe_ipf;
260: done:
261: /*
262: * Remove the entry from the flow table.
263: */
264: s = splimp();
265: LIST_REMOVE(ipf, ipf_next);
266: splx(s);
267: ipflow_addstats(ipf);
268: RTFREE(ipf->ipf_ro.ro_rt);
269: return ipf;
270: }
271:
272: void
273: ipflow_slowtimo(
274: void)
275: {
276: struct ipflow *ipf;
277: int idx;
278:
279: for (idx = 0; idx < IPFLOW_HASHSIZE; idx++) {
280: ipf = LIST_FIRST(&ipflows[idx]);
281: while (ipf != NULL) {
282: struct ipflow *next_ipf = LIST_NEXT(ipf, ipf_next);
283: if (--ipf->ipf_timer == 0) {
284: ipflow_free(ipf);
285: } else {
286: ipf->ipf_last_uses = ipf->ipf_uses;
287: ipf->ipf_ro.ro_rt->rt_use += ipf->ipf_uses;
288: ipstat.ips_forward += ipf->ipf_uses;
289: ipstat.ips_fastforward += ipf->ipf_uses;
290: ipf->ipf_uses = 0;
291: }
292: ipf = next_ipf;
293: }
294: }
295: }
296:
297: void
298: ipflow_create(
299: const struct route *ro,
300: struct mbuf *m)
301: {
302: const struct ip *const ip = mtod(m, struct ip *);
303: struct ipflow *ipf;
304: unsigned hash;
305: int s;
306:
307: /*
308: * Don't create cache entries for ICMP messages.
309: */
310: if (!ipflow_active || ip->ip_p == IPPROTO_ICMP)
311: return;
312: /*
313: * See if an existing flow struct exists. If so remove it from it's
314: * list and free the old route. If not, try to malloc a new one
315: * (if we aren't at our limit).
316: */
317: ipf = ipflow_lookup(ip);
318: if (ipf == NULL) {
319: if (ipflow_inuse == IPFLOW_MAX) {
320: ipf = ipflow_reap();
321: } else {
322: ipf = (struct ipflow *) _MALLOC(sizeof(*ipf), M_IPFLOW,
323: M_NOWAIT);
324: if (ipf == NULL)
325: return;
326: ipflow_inuse++;
327: }
328: bzero((caddr_t) ipf, sizeof(*ipf));
329: } else {
330: s = splimp();
331: LIST_REMOVE(ipf, ipf_next);
332: splx(s);
333: ipflow_addstats(ipf);
334: RTFREE(ipf->ipf_ro.ro_rt);
335: ipf->ipf_uses = ipf->ipf_last_uses = 0;
336: ipf->ipf_errors = ipf->ipf_dropped = 0;
337: }
338:
339: /*
340: * Fill in the updated information.
341: */
342: ipf->ipf_ro = *ro;
343: ro->ro_rt->rt_refcnt++;
344: ipf->ipf_dst = ip->ip_dst;
345: ipf->ipf_src = ip->ip_src;
346: ipf->ipf_tos = ip->ip_tos;
347: ipf->ipf_timer = IPFLOW_TIMER;
348: /*
349: * Insert into the approriate bucket of the flow table.
350: */
351: hash = ipflow_hash(ip->ip_dst, ip->ip_src, ip->ip_tos);
352: s = splimp();
353: LIST_INSERT_HEAD(&ipflows[hash], ipf, ipf_next);
354: splx(s);
355: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.