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/] [in_rmx.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/in_rmx.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 1994, 1995 Massachusetts Institute of Technology
22
 *
23
 * Permission to use, copy, modify, and distribute this software and
24
 * its documentation for any purpose and without fee is hereby
25
 * granted, provided that both the above copyright notice and this
26
 * permission notice appear in all copies, that both the above
27
 * copyright notice and this permission notice appear in all
28
 * supporting documentation, and that the name of M.I.T. not be used
29
 * in advertising or publicity pertaining to distribution of the
30
 * software without specific, written prior permission.  M.I.T. makes
31
 * no representations about the suitability of this software for any
32
 * purpose.  It is provided "as is" without express or implied
33
 * warranty.
34
 *
35
 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
36
 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
37
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
38
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
39
 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46
 * SUCH DAMAGE.
47
 *
48
 * $FreeBSD: src/sys/netinet/in_rmx.c,v 1.37.2.1 2001/05/14 08:23:49 ru Exp $
49
 */
50
 
51
/*
52
 * This code does two things necessary for the enhanced TCP metrics to
53
 * function in a useful manner:
54
 *  1) It marks all non-host routes as `cloning', thus ensuring that
55
 *     every actual reference to such a route actually gets turned
56
 *     into a reference to a host route to the specific destination
57
 *     requested.
58
 *  2) When such routes lose all their references, it arranges for them
59
 *     to be deleted in some random collection of circumstances, so that
60
 *     a large quantity of stale routing data is not kept in kernel memory
61
 *     indefinitely.  See in_rtqtimo() below for the exact mechanism.
62
 */
63
 
64
#include <sys/param.h>
65
#include <sys/sysctl.h>
66
#include <sys/socket.h>
67
#include <sys/mbuf.h>
68
 
69
#include <net/if.h>
70
#include <net/route.h>
71
#include <netinet/in.h>
72
#include <netinet/in_var.h>
73
 
74
extern int      in_inithead __P((void **head, int off));
75
 
76
#define RTPRF_OURS              RTF_PROTO3      /* set on routes we manage */
77
 
78
/*
79
 * Do what we need to do when inserting a route.
80
 */
81
static struct radix_node *
82
in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
83
            struct radix_node *treenodes)
84
{
85
        struct rtentry *rt = (struct rtentry *)treenodes;
86
        struct sockaddr_in *sin = (struct sockaddr_in *)rt_key(rt);
87
        struct radix_node *ret;
88
 
89
        /*
90
         * For IP, all unicast non-host routes are automatically cloning.
91
         */
92
        if(IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
93
                rt->rt_flags |= RTF_MULTICAST;
94
 
95
        if(!(rt->rt_flags & (RTF_HOST | RTF_CLONING | RTF_MULTICAST))) {
96
                rt->rt_flags |= RTF_PRCLONING;
97
        }
98
 
99
        /*
100
         * A little bit of help for both IP output and input:
101
         *   For host routes, we make sure that RTF_BROADCAST
102
         *   is set for anything that looks like a broadcast address.
103
         *   This way, we can avoid an expensive call to in_broadcast()
104
         *   in ip_output() most of the time (because the route passed
105
         *   to ip_output() is almost always a host route).
106
         *
107
         *   We also do the same for local addresses, with the thought
108
         *   that this might one day be used to speed up ip_input().
109
         *
110
         * We also mark routes to multicast addresses as such, because
111
         * it's easy to do and might be useful (but this is much more
112
         * dubious since it's so easy to inspect the address).  (This
113
         * is done above.)
114
         */
115
        if (rt->rt_flags & RTF_HOST) {
116
                if (in_broadcast(sin->sin_addr, rt->rt_ifp)) {
117
                        rt->rt_flags |= RTF_BROADCAST;
118
                } else {
119
#define satosin(sa) ((struct sockaddr_in *)sa)
120
                        if (satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr
121
                            == sin->sin_addr.s_addr)
122
                                rt->rt_flags |= RTF_LOCAL;
123
#undef satosin
124
                }
125
        }
126
 
127
        if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU)
128
            && rt->rt_ifp)
129
                rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu;
130
 
131
        ret = rn_addroute(v_arg, n_arg, head, treenodes);
132
        if (ret == NULL && rt->rt_flags & RTF_HOST) {
133
                struct rtentry *rt2;
134
                /*
135
                 * We are trying to add a host route, but can't.
136
                 * Find out if it is because of an
137
                 * ARP entry and delete it if so.
138
                 */
139
                rt2 = rtalloc1((struct sockaddr *)sin, 0,
140
                                RTF_CLONING | RTF_PRCLONING);
141
                if (rt2) {
142
                        if (rt2->rt_flags & RTF_LLINFO &&
143
                                rt2->rt_flags & RTF_HOST &&
144
                                rt2->rt_gateway &&
145
                                rt2->rt_gateway->sa_family == AF_LINK) {
146
                                rtrequest(RTM_DELETE,
147
                                          (struct sockaddr *)rt_key(rt2),
148
                                          rt2->rt_gateway,
149
                                          rt_mask(rt2), rt2->rt_flags, 0);
150
                                ret = rn_addroute(v_arg, n_arg, head,
151
                                        treenodes);
152
                        }
153
                        RTFREE(rt2);
154
                }
155
        }
156
        return ret;
157
}
158
 
159
/*
160
 * This code is the inverse of in_clsroute: on first reference, if we
161
 * were managing the route, stop doing so and set the expiration timer
162
 * back off again.
163
 */
164
static struct radix_node *
165
in_matroute(void *v_arg, struct radix_node_head *head)
166
{
167
        struct radix_node *rn = rn_match(v_arg, head);
168
        struct rtentry *rt = (struct rtentry *)rn;
169
 
170
        if(rt && rt->rt_refcnt == 0) { /* this is first reference */
171
                if(rt->rt_flags & RTPRF_OURS) {
172
                        rt->rt_flags &= ~RTPRF_OURS;
173
                        rt->rt_rmx.rmx_expire = 0;
174
                }
175
        }
176
        return rn;
177
}
178
 
179
static int rtq_reallyold = 60*60;
180
        /* one hour is ``really old'' */
181
SYSCTL_INT(_net_inet_ip, IPCTL_RTEXPIRE, rtexpire, CTLFLAG_RW,
182
    &rtq_reallyold , 0,
183
    "Default expiration time on dynamically learned routes");
184
 
185
static int rtq_minreallyold = 10;
186
        /* never automatically crank down to less */
187
SYSCTL_INT(_net_inet_ip, IPCTL_RTMINEXPIRE, rtminexpire, CTLFLAG_RW,
188
    &rtq_minreallyold , 0,
189
    "Minimum time to attempt to hold onto dynamically learned routes");
190
 
191
static int rtq_toomany = 128;
192
        /* 128 cached routes is ``too many'' */
193
SYSCTL_INT(_net_inet_ip, IPCTL_RTMAXCACHE, rtmaxcache, CTLFLAG_RW,
194
    &rtq_toomany , 0, "Upper limit on dynamically learned routes");
195
 
196
/*
197
 * On last reference drop, mark the route as belong to us so that it can be
198
 * timed out.
199
 */
200
static void
201
in_clsroute(struct radix_node *rn, struct radix_node_head *head)
202
{
203
        struct rtentry *rt = (struct rtentry *)rn;
204
 
205
        if(!(rt->rt_flags & RTF_UP))
206
                return;         /* prophylactic measures */
207
 
208
        if((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST)
209
                return;
210
 
211
        if((rt->rt_flags & (RTF_WASCLONED | RTPRF_OURS))
212
           != RTF_WASCLONED)
213
                return;
214
 
215
        /*
216
         * As requested by David Greenman:
217
         * If rtq_reallyold is 0, just delete the route without
218
         * waiting for a timeout cycle to kill it.
219
         */
220
        if(rtq_reallyold != 0) {
221
                rt->rt_flags |= RTPRF_OURS;
222
                rt->rt_rmx.rmx_expire = time_second + rtq_reallyold;
223
        } else {
224
                rtrequest(RTM_DELETE,
225
                          (struct sockaddr *)rt_key(rt),
226
                          rt->rt_gateway, rt_mask(rt),
227
                          rt->rt_flags, 0);
228
        }
229
}
230
 
231
struct rtqk_arg {
232
        struct radix_node_head *rnh;
233
        int draining;
234
        int killed;
235
        int found;
236
        int updating;
237
        time_t nextstop;
238
};
239
 
240
/*
241
 * Get rid of old routes.  When draining, this deletes everything, even when
242
 * the timeout is not expired yet.  When updating, this makes sure that
243
 * nothing has a timeout longer than the current value of rtq_reallyold.
244
 */
245
static int
246
in_rtqkill(struct radix_node *rn, void *rock)
247
{
248
        struct rtqk_arg *ap = rock;
249
        struct rtentry *rt = (struct rtentry *)rn;
250
        int err;
251
 
252
        if(rt->rt_flags & RTPRF_OURS) {
253
                ap->found++;
254
 
255
                if(ap->draining || rt->rt_rmx.rmx_expire <= time_second) {
256
                        if(rt->rt_refcnt > 0)
257
                                panic("rtqkill route really not free");
258
 
259
                        err = rtrequest(RTM_DELETE,
260
                                        (struct sockaddr *)rt_key(rt),
261
                                        rt->rt_gateway, rt_mask(rt),
262
                                        rt->rt_flags, 0);
263
                        if(err) {
264
                                log(LOG_WARNING, "in_rtqkill: error %d\n", err);
265
                        } else {
266
                                ap->killed++;
267
                        }
268
                } else {
269
                        if(ap->updating
270
                           && (rt->rt_rmx.rmx_expire - time_second
271
                               > rtq_reallyold)) {
272
                                rt->rt_rmx.rmx_expire = time_second
273
                                        + rtq_reallyold;
274
                        }
275
                        ap->nextstop = lmin(ap->nextstop,
276
                                            rt->rt_rmx.rmx_expire);
277
                }
278
        }
279
 
280
        return 0;
281
}
282
 
283
#define RTQ_TIMEOUT     60*10   /* run no less than once every ten minutes */
284
static int rtq_timeout = RTQ_TIMEOUT;
285
 
286
static void
287
in_rtqtimo(void *rock)
288
{
289
        struct radix_node_head *rnh = rock;
290
        struct rtqk_arg arg;
291
        struct timeval atv;
292
        static time_t last_adjusted_timeout = 0;
293
        int s;
294
 
295
        arg.found = arg.killed = 0;
296
        arg.rnh = rnh;
297
        arg.nextstop = time_second + rtq_timeout;
298
        arg.draining = arg.updating = 0;
299
        s = splnet();
300
        rnh->rnh_walktree(rnh, in_rtqkill, &arg);
301
        splx(s);
302
 
303
        /*
304
         * Attempt to be somewhat dynamic about this:
305
         * If there are ``too many'' routes sitting around taking up space,
306
         * then crank down the timeout, and see if we can't make some more
307
         * go away.  However, we make sure that we will never adjust more
308
         * than once in rtq_timeout seconds, to keep from cranking down too
309
         * hard.
310
         */
311
        if((arg.found - arg.killed > rtq_toomany)
312
           && (time_second - last_adjusted_timeout >= rtq_timeout)
313
           && rtq_reallyold > rtq_minreallyold) {
314
                rtq_reallyold = 2*rtq_reallyold / 3;
315
                if(rtq_reallyold < rtq_minreallyold) {
316
                        rtq_reallyold = rtq_minreallyold;
317
                }
318
 
319
                last_adjusted_timeout = time_second;
320
#ifdef DIAGNOSTIC
321
                log(LOG_DEBUG, "in_rtqtimo: adjusted rtq_reallyold to %d\n",
322
                    rtq_reallyold);
323
#endif
324
                arg.found = arg.killed = 0;
325
                arg.updating = 1;
326
                s = splnet();
327
                rnh->rnh_walktree(rnh, in_rtqkill, &arg);
328
                splx(s);
329
        }
330
 
331
        atv.tv_usec = 0;
332
        atv.tv_sec = arg.nextstop - time_second;
333
        timeout(in_rtqtimo, rock, tvtohz(&atv));
334
}
335
 
336
void
337
in_rtqdrain(void)
338
{
339
        struct radix_node_head *rnh = rt_tables[AF_INET];
340
        struct rtqk_arg arg;
341
        int s;
342
        arg.found = arg.killed = 0;
343
        arg.rnh = rnh;
344
        arg.nextstop = 0;
345
        arg.draining = 1;
346
        arg.updating = 0;
347
        s = splnet();
348
        rnh->rnh_walktree(rnh, in_rtqkill, &arg);
349
        splx(s);
350
}
351
 
352
/*
353
 * Initialize our routing tree.
354
 */
355
int
356
in_inithead(void **head, int off)
357
{
358
        struct radix_node_head *rnh;
359
 
360
        if(!rn_inithead(head, off))
361
                return 0;
362
 
363
        if(head != (void **)&rt_tables[AF_INET]) /* BOGUS! */
364
                return 1;       /* only do this for the real routing table */
365
 
366
        rnh = *head;
367
        rnh->rnh_addaddr = in_addroute;
368
        rnh->rnh_matchaddr = in_matroute;
369
        rnh->rnh_close = in_clsroute;
370
        in_rtqtimo(rnh);        /* kick off timeout first time */
371
        return 1;
372
}
373
 
374
 
375
/*
376
 * This zaps old routes when the interface goes down or interface
377
 * address is deleted.  In the latter case, it deletes static routes
378
 * that point to this address.  If we don't do this, we may end up
379
 * using the old address in the future.  The ones we always want to
380
 * get rid of are things like ARP entries, since the user might down
381
 * the interface, walk over to a completely different network, and
382
 * plug back in.
383
 */
384
struct in_ifadown_arg {
385
        struct radix_node_head *rnh;
386
        struct ifaddr *ifa;
387
        int del;
388
};
389
 
390
static int
391
in_ifadownkill(struct radix_node *rn, void *xap)
392
{
393
        struct in_ifadown_arg *ap = xap;
394
        struct rtentry *rt = (struct rtentry *)rn;
395
        int err;
396
 
397
        if (rt->rt_ifa == ap->ifa &&
398
            (ap->del || !(rt->rt_flags & RTF_STATIC))) {
399
                /*
400
                 * We need to disable the automatic prune that happens
401
                 * in this case in rtrequest() because it will blow
402
                 * away the pointers that rn_walktree() needs in order
403
                 * continue our descent.  We will end up deleting all
404
                 * the routes that rtrequest() would have in any case,
405
                 * so that behavior is not needed there.
406
                 */
407
                rt->rt_flags &= ~(RTF_CLONING | RTF_PRCLONING);
408
                err = rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
409
                                rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
410
                if (err) {
411
                        log(LOG_WARNING, "in_ifadownkill: error %d\n", err);
412
                }
413
        }
414
        return 0;
415
}
416
 
417
int
418
in_ifadown(struct ifaddr *ifa, int delete)
419
{
420
        struct in_ifadown_arg arg;
421
        struct radix_node_head *rnh;
422
 
423
        if (ifa->ifa_addr->sa_family != AF_INET)
424
                return 1;
425
 
426
        arg.rnh = rnh = rt_tables[AF_INET];
427
        arg.ifa = ifa;
428
        arg.del = delete;
429
        rnh->rnh_walktree(rnh, in_ifadownkill, &arg);
430
        ifa->ifa_flags &= ~IFA_ROUTE;
431
        return 0;
432
}

powered by: WebSVN 2.1.0

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