OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [bsd_tcpip/] [current/] [src/] [sys/] [netinet/] [ip_flow.c] - Blame information for rev 786

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.