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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [sys/] [netinet/] [ip_flow.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet/ip_flow.c
4
//
5
//==========================================================================
6
//####BSDCOPYRIGHTBEGIN####
7
//
8
// -------------------------------------------
9
//
10
// Portions of this software may have been derived from OpenBSD, 
11
// FreeBSD or other sources, and are covered by the appropriate
12
// copyright disclaimers included herein.
13
//
14
// Portions created by Red Hat are
15
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16
//
17
// -------------------------------------------
18
//
19
//####BSDCOPYRIGHTEND####
20
//==========================================================================
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
 * $FreeBSD: src/sys/netinet/ip_flow.c,v 1.9.2.1 2001/08/08 08:20:35 ru Exp $
58
 */
59
 
60
#include <sys/param.h>
61
#include <sys/malloc.h>
62
#include <sys/mbuf.h>
63
#include <sys/protosw.h>
64
#include <sys/socket.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
 
85
static unsigned
86
ipflow_hash(
87
        struct in_addr dst,
88
        struct in_addr src,
89
        unsigned tos)
90
{
91
        unsigned hash = tos;
92
        int idx;
93
        for (idx = 0; idx < 32; idx += IPFLOW_HASHBITS)
94
                hash += (dst.s_addr >> (32 - idx)) + (src.s_addr >> idx);
95
        return hash & (IPFLOW_HASHSIZE-1);
96
}
97
 
98
static struct ipflow *
99
ipflow_lookup(
100
        const struct ip *ip)
101
{
102
        unsigned hash;
103
        struct ipflow *ipf;
104
 
105
        hash = ipflow_hash(ip->ip_dst, ip->ip_src, ip->ip_tos);
106
 
107
        ipf = LIST_FIRST(&ipflows[hash]);
108
        while (ipf != NULL) {
109
                if (ip->ip_dst.s_addr == ipf->ipf_dst.s_addr
110
                    && ip->ip_src.s_addr == ipf->ipf_src.s_addr
111
                    && ip->ip_tos == ipf->ipf_tos)
112
                        break;
113
                ipf = LIST_NEXT(ipf, ipf_next);
114
        }
115
        return ipf;
116
}
117
 
118
int
119
ipflow_fastforward(
120
        struct mbuf *m)
121
{
122
        struct ip *ip;
123
        struct ipflow *ipf;
124
        struct rtentry *rt;
125
        struct sockaddr *dst;
126
        int error;
127
 
128
        /*
129
         * Are we forwarding packets?  Big enough for an IP packet?
130
         */
131
        if (!ipforwarding || !ipflow_active || m->m_len < sizeof(struct ip))
132
                return 0;
133
        /*
134
         * IP header with no option and valid version and length
135
         */
136
        ip = mtod(m, struct ip *);
137
        if (ip->ip_v != IPVERSION || ip->ip_hl != (sizeof(struct ip) >> 2)
138
            || ntohs(ip->ip_len) > m->m_pkthdr.len)
139
                return 0;
140
        /*
141
         * Find a flow.
142
         */
143
        if ((ipf = ipflow_lookup(ip)) == NULL)
144
                return 0;
145
 
146
        /*
147
         * Route and interface still up?
148
         */
149
        rt = ipf->ipf_ro.ro_rt;
150
        if ((rt->rt_flags & RTF_UP) == 0 || (rt->rt_ifp->if_flags & IFF_UP) == 0)
151
                return 0;
152
 
153
        /*
154
         * Packet size OK?  TTL?
155
         */
156
        if (m->m_pkthdr.len > rt->rt_ifp->if_mtu || ip->ip_ttl <= IPTTLDEC)
157
                return 0;
158
 
159
        /*
160
         * Everything checks out and so we can forward this packet.
161
         * Modify the TTL and incrementally change the checksum.
162
         */
163
        ip->ip_ttl -= IPTTLDEC;
164
        if (ip->ip_sum >= htons(0xffff - (IPTTLDEC << 8))) {
165
                ip->ip_sum += htons(IPTTLDEC << 8) + 1;
166
        } else {
167
                ip->ip_sum += htons(IPTTLDEC << 8);
168
        }
169
 
170
        /*
171
         * Send the packet on its way.  All we can get back is ENOBUFS
172
         */
173
        ipf->ipf_uses++;
174
        ipf->ipf_timer = IPFLOW_TIMER;
175
 
176
        if (rt->rt_flags & RTF_GATEWAY)
177
                dst = rt->rt_gateway;
178
        else
179
                dst = &ipf->ipf_ro.ro_dst;
180
        if ((error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m, dst, rt)) != 0) {
181
                if (error == ENOBUFS)
182
                        ipf->ipf_dropped++;
183
                else
184
                        ipf->ipf_errors++;
185
        }
186
        return 1;
187
}
188
 
189
static void
190
ipflow_addstats(
191
        struct ipflow *ipf)
192
{
193
        ipf->ipf_ro.ro_rt->rt_use += ipf->ipf_uses;
194
        ipstat.ips_cantforward += ipf->ipf_errors + ipf->ipf_dropped;
195
        ipstat.ips_forward += ipf->ipf_uses;
196
        ipstat.ips_fastforward += ipf->ipf_uses;
197
}
198
 
199
static void
200
ipflow_free(
201
        struct ipflow *ipf)
202
{
203
        int s;
204
        /*
205
         * Remove the flow from the hash table (at elevated IPL).
206
         * Once it's off the list, we can deal with it at normal
207
         * network IPL.
208
         */
209
        s = splimp();
210
        LIST_REMOVE(ipf, ipf_next);
211
        splx(s);
212
        ipflow_addstats(ipf);
213
        RTFREE(ipf->ipf_ro.ro_rt);
214
        ipflow_inuse--;
215
        FREE(ipf, M_IPFLOW);
216
}
217
 
218
static struct ipflow *
219
ipflow_reap(
220
        void)
221
{
222
        struct ipflow *ipf, *maybe_ipf = NULL;
223
        int idx;
224
        int s;
225
 
226
        for (idx = 0; idx < IPFLOW_HASHSIZE; idx++) {
227
                ipf = LIST_FIRST(&ipflows[idx]);
228
                while (ipf != NULL) {
229
                        /*
230
                         * If this no longer points to a valid route
231
                         * reclaim it.
232
                         */
233
                        if ((ipf->ipf_ro.ro_rt->rt_flags & RTF_UP) == 0)
234
                                goto done;
235
                        /*
236
                         * choose the one that's been least recently used
237
                         * or has had the least uses in the last 1.5
238
                         * intervals.
239
                         */
240
                        if (maybe_ipf == NULL
241
                            || ipf->ipf_timer < maybe_ipf->ipf_timer
242
                            || (ipf->ipf_timer == maybe_ipf->ipf_timer
243
                                && ipf->ipf_last_uses + ipf->ipf_uses <
244
                                      maybe_ipf->ipf_last_uses +
245
                                        maybe_ipf->ipf_uses))
246
                                maybe_ipf = ipf;
247
                        ipf = LIST_NEXT(ipf, ipf_next);
248
                }
249
        }
250
        ipf = maybe_ipf;
251
    done:
252
        /*
253
         * Remove the entry from the flow table.
254
         */
255
        s = splimp();
256
        LIST_REMOVE(ipf, ipf_next);
257
        splx(s);
258
        ipflow_addstats(ipf);
259
        RTFREE(ipf->ipf_ro.ro_rt);
260
        return ipf;
261
}
262
 
263
void
264
ipflow_slowtimo(
265
        void)
266
{
267
        struct ipflow *ipf;
268
        int idx;
269
 
270
        for (idx = 0; idx < IPFLOW_HASHSIZE; idx++) {
271
                ipf = LIST_FIRST(&ipflows[idx]);
272
                while (ipf != NULL) {
273
                        struct ipflow *next_ipf = LIST_NEXT(ipf, ipf_next);
274
                        if (--ipf->ipf_timer == 0) {
275
                                ipflow_free(ipf);
276
                        } else {
277
                                ipf->ipf_last_uses = ipf->ipf_uses;
278
                                ipf->ipf_ro.ro_rt->rt_use += ipf->ipf_uses;
279
                                ipstat.ips_forward += ipf->ipf_uses;
280
                                ipstat.ips_fastforward += ipf->ipf_uses;
281
                                ipf->ipf_uses = 0;
282
                        }
283
                        ipf = next_ipf;
284
                }
285
        }
286
}
287
 
288
void
289
ipflow_create(
290
        const struct route *ro,
291
        struct mbuf *m)
292
{
293
        const struct ip *const ip = mtod(m, struct ip *);
294
        struct ipflow *ipf;
295
        unsigned hash;
296
        int s;
297
 
298
        /*
299
         * Don't create cache entries for ICMP messages.
300
         */
301
        if (!ipflow_active || ip->ip_p == IPPROTO_ICMP)
302
                return;
303
        /*
304
         * See if an existing flow struct exists.  If so remove it from it's
305
         * list and free the old route.  If not, try to malloc a new one
306
         * (if we aren't at our limit).
307
         */
308
        ipf = ipflow_lookup(ip);
309
        if (ipf == NULL) {
310
                if (ipflow_inuse == IPFLOW_MAX) {
311
                        ipf = ipflow_reap();
312
                } else {
313
                        ipf = (struct ipflow *) malloc(sizeof(*ipf), M_IPFLOW,
314
                                                       M_NOWAIT);
315
                        if (ipf == NULL)
316
                                return;
317
                        ipflow_inuse++;
318
                }
319
                bzero((caddr_t) ipf, sizeof(*ipf));
320
        } else {
321
                s = splimp();
322
                LIST_REMOVE(ipf, ipf_next);
323
                splx(s);
324
                ipflow_addstats(ipf);
325
                RTFREE(ipf->ipf_ro.ro_rt);
326
                ipf->ipf_uses = ipf->ipf_last_uses = 0;
327
                ipf->ipf_errors = ipf->ipf_dropped = 0;
328
        }
329
 
330
        /*
331
         * Fill in the updated information.
332
         */
333
        ipf->ipf_ro = *ro;
334
        ro->ro_rt->rt_refcnt++;
335
        ipf->ipf_dst = ip->ip_dst;
336
        ipf->ipf_src = ip->ip_src;
337
        ipf->ipf_tos = ip->ip_tos;
338
        ipf->ipf_timer = IPFLOW_TIMER;
339
        /*
340
         * Insert into the approriate bucket of the flow table.
341
         */
342
        hash = ipflow_hash(ip->ip_dst, ip->ip_src, ip->ip_tos);
343
        s = splimp();
344
        LIST_INSERT_HEAD(&ipflows[hash], ipf, ipf_next);
345
        splx(s);
346
}

powered by: WebSVN 2.1.0

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