in_rmx.c revision 4105
1/*
2 * Copyright 1994, Massachusetts Institute of Technology.  All Rights Reserved.
3 *
4 * You may copy this file verbatim until I find the official
5 * Institute boilerplate.
6 *
7 * $Id: in_rmx.c,v 1.1 1994/11/02 04:42:14 wollman Exp $
8 */
9
10/*
11 * This code does two things necessary for the enhanced TCP metrics to
12 * function in a useful manner:
13 *  1) It marks all non-host routes as `cloning', thus ensuring that
14 *     every actual reference to such a route actually gets turned
15 *     into a reference to a host route to the specific destination
16 *     requested.
17 *  2) When such routes lose all their references, it arranges for them
18 *     to be deleted in some random collection of circumstances, so that
19 *     a large quantity of stale routing data is not kept in kernel memory
20 *     indefinitely.  See in_rtqtimo() below for the exact mechanism.
21 *
22 * At least initially, we think that this should have lower overhead than
23 * using the existing `expire' mechanism and walking the radix tree
24 * periodically, deleting things as we go.  That method would be relatively
25 * easy to implement within the framework used here, and in the future
26 * we made code both ways, so that folks with large routing tables can use
27 * the external queue, and the majority with small routing tables can do
28 * the tree-walk.
29 */
30
31/*
32 * XXX - look for races
33 */
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/queue.h>
39#include <sys/socket.h>
40#include <sys/socketvar.h>
41#include <sys/mbuf.h>
42
43#include <net/if.h>
44#include <net/route.h>
45#include <netinet/in.h>
46#include <netinet/in_systm.h>
47#include <netinet/in_var.h>
48
49#define RTPRF_OURS		0x10000	/* set on routes we manage */
50
51/*
52 * Do what we need to do when inserting a route.
53 */
54static struct radix_node *
55in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
56	    struct radix_node *treenodes)
57{
58	struct rtentry *rt = (struct rtentry *)treenodes;
59	struct in_rtq *inr;
60
61	/*
62	 * For IP, all non-host routes are automatically cloning.
63	 */
64	if(!(rt->rt_flags & RTF_HOST))
65		rt->rt_flags |= RTF_CLONING;
66
67	return rn_addroute(v_arg, n_arg, head, treenodes);
68}
69
70/*
71 * This code is the inverse of in_clsroute: on first reference, if we
72 * were managing the route, stop doing so and set the expiration timer
73 * back off again.
74 */
75static struct radix_node *
76in_matroute(void *v_arg, struct radix_node_head *head)
77{
78	struct radix_node *rn = rn_match(v_arg, head);
79	struct rtentry *rt = (struct rtentry *)rn;
80
81	if(rt && rt->rt_refcnt == 0) { /* this is first reference */
82		if(rt->rt_prflags & RTPRF_OURS) {
83			rt->rt_prflags &= ~RTPRF_OURS;
84			rt->rt_rmx.rmx_expire = 0;
85		}
86	}
87	return rn;
88}
89
90#define RTQ_REALLYOLD	4*60*60	/* four hours is ``really old'' */
91
92/*
93 * On last reference drop, add the route to the queue so that it can be
94 * timed out.
95 */
96static void
97in_clsroute(struct radix_node *rn, struct radix_node_head *head)
98{
99	struct rtentry *rt = (struct rtentry *)rn;
100	struct in_rtq *inr;
101
102	if((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST)
103		return;
104
105	if((rt->rt_prflags & (RTPRF_WASCLONED | RTPRF_OURS))
106	   != RTPRF_WASCLONED)
107		return;
108
109	rt->rt_prflags |= RTPRF_OURS;
110	rt->rt_rmx.rmx_expire = time.tv_sec + RTQ_REALLYOLD;
111}
112
113/*
114 * Get rid of everything in the queue, we are short on memory.
115 * Although this looks like an infinite loop, it really isn't;
116 * rtrequest() eventually calls in_delroute() which ends up deleting
117 * the node at the head (or so we hope).  This should be called from
118 * ip_drain().
119 */
120void
121in_rtqdrain(void)
122{
123	/* write me! */
124	;
125}
126
127#define RTQ_TIMEOUT	(60*hz)	/* run once a minute */
128
129/*
130 * Get rid of old routes.
131 */
132static void
133in_rtqtimo(void *rock)
134{
135	/* write me! */
136
137	timeout(in_rtqtimo, rock, RTQ_TIMEOUT);
138}
139
140/*
141 * Initialize our routing tree.
142 */
143int
144in_inithead(void **head, int off)
145{
146	struct radix_node_head *rnh;
147
148	if(!rn_inithead(head, off))
149		return 0;
150
151	rnh = *head;
152	rnh->rnh_addaddr = in_addroute;
153	rnh->rnh_matchaddr = in_matroute;
154	rnh->rnh_close = in_clsroute;
155	in_rtqtimo(rnh);	/* kick off timeout first time */
156	return 1;
157}
158
159