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