missed a few: make default, local-loop routes have metric 1,
[unix-history] / usr / src / sbin / routed / tables.c
CommitLineData
5ff67f98 1/*
9c2cb70b 2 * Copyright (c) 1983, 1988 Regents of the University of California.
0eb85d71
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that this notice is preserved and that due credit is given
7 * to the University of California at Berkeley. The name of the University
8 * may not be used to endorse or promote products derived from this
9 * software without specific prior written permission. This software
10 * is provided ``as is'' without express or implied warranty.
5ff67f98
DF
11 */
12
b9b7b06a 13#ifndef lint
09b9aef2 14static char sccsid[] = "@(#)tables.c 5.13 (Berkeley) %G%";
0eb85d71 15#endif /* not lint */
b9b7b06a
SL
16
17/*
18 * Routing Table Management Daemon
19 */
7fe7fe74 20#include "defs.h"
b9b7b06a
SL
21#include <sys/ioctl.h>
22#include <errno.h>
9c2cb70b 23#include <sys/syslog.h>
b9b7b06a
SL
24
25#ifndef DEBUG
26#define DEBUG 0
27#endif
28
29int install = !DEBUG; /* if 1 call kernel */
30
31/*
32 * Lookup dst in the tables for an exact match.
33 */
34struct rt_entry *
35rtlookup(dst)
36 struct sockaddr *dst;
37{
38 register struct rt_entry *rt;
39 register struct rthash *rh;
d5568f13 40 register u_int hash;
b9b7b06a
SL
41 struct afhash h;
42 int doinghost = 1;
43
17fe297f 44 if (dst->sa_family >= af_max)
b9b7b06a
SL
45 return (0);
46 (*afswitch[dst->sa_family].af_hash)(dst, &h);
47 hash = h.afh_hosthash;
49139b80 48 rh = &hosthash[hash & ROUTEHASHMASK];
b9b7b06a
SL
49again:
50 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
51 if (rt->rt_hash != hash)
52 continue;
53 if (equal(&rt->rt_dst, dst))
54 return (rt);
55 }
56 if (doinghost) {
57 doinghost = 0;
58 hash = h.afh_nethash;
49139b80 59 rh = &nethash[hash & ROUTEHASHMASK];
b9b7b06a
SL
60 goto again;
61 }
62 return (0);
63}
64
9c2cb70b
MK
65struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
66
b9b7b06a
SL
67/*
68 * Find a route to dst as the kernel would.
69 */
70struct rt_entry *
71rtfind(dst)
72 struct sockaddr *dst;
73{
74 register struct rt_entry *rt;
75 register struct rthash *rh;
d5568f13 76 register u_int hash;
b9b7b06a
SL
77 struct afhash h;
78 int af = dst->sa_family;
79 int doinghost = 1, (*match)();
80
17fe297f 81 if (af >= af_max)
b9b7b06a
SL
82 return (0);
83 (*afswitch[af].af_hash)(dst, &h);
84 hash = h.afh_hosthash;
49139b80 85 rh = &hosthash[hash & ROUTEHASHMASK];
b9b7b06a
SL
86
87again:
88 for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
89 if (rt->rt_hash != hash)
90 continue;
91 if (doinghost) {
92 if (equal(&rt->rt_dst, dst))
93 return (rt);
94 } else {
95 if (rt->rt_dst.sa_family == af &&
96 (*match)(&rt->rt_dst, dst))
97 return (rt);
98 }
99 }
100 if (doinghost) {
101 doinghost = 0;
102 hash = h.afh_nethash;
49139b80 103 rh = &nethash[hash & ROUTEHASHMASK];
b9b7b06a
SL
104 match = afswitch[af].af_netmatch;
105 goto again;
106 }
9c2cb70b
MK
107#ifdef notyet
108 /*
109 * Check for wildcard gateway, by convention network 0.
110 */
111 if (dst != &wildcard) {
112 dst = &wildcard, hash = 0;
113 goto again;
114 }
115#endif
b9b7b06a
SL
116 return (0);
117}
118
119rtadd(dst, gate, metric, state)
120 struct sockaddr *dst, *gate;
121 int metric, state;
122{
123 struct afhash h;
124 register struct rt_entry *rt;
125 struct rthash *rh;
7892134c 126 int af = dst->sa_family, flags;
d5568f13 127 u_int hash;
b9b7b06a 128
17fe297f 129 if (af >= af_max)
b9b7b06a
SL
130 return;
131 (*afswitch[af].af_hash)(dst, &h);
4fad5a6e
MK
132 flags = (*afswitch[af].af_rtflags)(dst);
133 /*
134 * Subnet flag isn't visible to kernel, move to state. XXX
135 */
136 if (flags & RTF_SUBNET) {
137 state |= RTS_SUBNET;
138 flags &= ~RTF_SUBNET;
139 }
b9b7b06a
SL
140 if (flags & RTF_HOST) {
141 hash = h.afh_hosthash;
49139b80 142 rh = &hosthash[hash & ROUTEHASHMASK];
b9b7b06a
SL
143 } else {
144 hash = h.afh_nethash;
49139b80 145 rh = &nethash[hash & ROUTEHASHMASK];
b9b7b06a
SL
146 }
147 rt = (struct rt_entry *)malloc(sizeof (*rt));
148 if (rt == 0)
149 return;
150 rt->rt_hash = hash;
151 rt->rt_dst = *dst;
152 rt->rt_router = *gate;
b9b7b06a
SL
153 rt->rt_timer = 0;
154 rt->rt_flags = RTF_UP | flags;
155 rt->rt_state = state | RTS_CHANGED;
4fad5a6e
MK
156 rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
157 if (rt->rt_ifp == 0)
158 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
88709531 159 if ((state & RTS_INTERFACE) == 0)
b9b7b06a 160 rt->rt_flags |= RTF_GATEWAY;
7892134c 161 rt->rt_metric = metric;
b9b7b06a 162 insque(rt, rh);
9c2cb70b 163 TRACE_ACTION("ADD", rt);
a8d9e287
SL
164 /*
165 * If the ioctl fails because the gateway is unreachable
166 * from this host, discard the entry. This should only
167 * occur because of an incorrect entry in /etc/gateways.
168 */
4fad5a6e
MK
169 if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
170 ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
7892134c 171 if (errno != EEXIST && gate->sa_family < af_max)
c766cf31
MK
172 syslog(LOG_ERR,
173 "adding route to net/host %s through gateway %s: %m\n",
174 (*afswitch[dst->sa_family].af_format)(dst),
175 (*afswitch[gate->sa_family].af_format)(gate));
b9b7b06a 176 perror("SIOCADDRT");
a8d9e287 177 if (errno == ENETUNREACH) {
9c2cb70b 178 TRACE_ACTION("DELETE", rt);
a8d9e287
SL
179 remque(rt);
180 free((char *)rt);
181 }
182 }
b9b7b06a
SL
183}
184
185rtchange(rt, gate, metric)
186 struct rt_entry *rt;
187 struct sockaddr *gate;
188 short metric;
189{
9c2cb70b 190 int add = 0, delete = 0;
b9b7b06a
SL
191 struct rtentry oldroute;
192
7892134c
MK
193 if ((rt->rt_state & RTS_INTERNAL) == 0) {
194 /*
195 * If changing to different router, we need to add
196 * new route and delete old one if in the kernel.
197 * If the router is the same, we need to delete
198 * the route if has become unreachable, or re-add
199 * it if it had been unreachable.
200 */
201 if (!equal(&rt->rt_router, gate)) {
202 add++;
203 if (rt->rt_metric != HOPCNT_INFINITY)
204 delete++;
205 } else if (metric == HOPCNT_INFINITY)
eb39c032 206 delete++;
7892134c
MK
207 else if (rt->rt_metric == HOPCNT_INFINITY)
208 add++;
eb39c032 209 }
9c2cb70b
MK
210 if (!equal(&rt->rt_router, gate)) {
211 TRACE_ACTION("CHANGE FROM ", rt);
212 } else if (metric != rt->rt_metric)
213 TRACE_NEWMETRIC(rt, metric);
214 if (delete)
215 oldroute = rt->rt_rt;
7892134c
MK
216 if ((rt->rt_state & RTS_INTERFACE) && delete) {
217 rt->rt_state &= ~RTS_INTERFACE;
9c2cb70b
MK
218 rt->rt_flags |= RTF_GATEWAY;
219 if (metric > rt->rt_metric && delete)
220 syslog(LOG_ERR, "%s route to interface %s (timed out)",
221 add? "changing" : "deleting",
222 rt->rt_ifp->int_name);
b9b7b06a 223 }
7892134c
MK
224 if (add) {
225 rt->rt_router = *gate;
226 rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
227 if (rt->rt_ifp == 0)
228 rt->rt_ifp = if_ifwithnet(&rt->rt_router);
229 }
230 rt->rt_metric = metric;
231 rt->rt_state |= RTS_CHANGED;
9c2cb70b
MK
232 if (add)
233 TRACE_ACTION("CHANGE TO ", rt);
7892134c 234 if (add && install)
b7e4f8be
MK
235 if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
236 perror("SIOCADDRT");
7892134c 237 if (delete && install)
b7e4f8be
MK
238 if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
239 perror("SIOCDELRT");
b9b7b06a
SL
240}
241
242rtdelete(rt)
243 struct rt_entry *rt;
244{
a8d9e287 245
9c2cb70b
MK
246 TRACE_ACTION("DELETE", rt);
247 if (rt->rt_metric < HOPCNT_INFINITY) {
248 if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
249 syslog(LOG_ERR,
250 "deleting route to interface %s? (timed out?)",
251 rt->rt_ifp->int_name);
252 if (install &&
253 (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
254 ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
255 perror("SIOCDELRT");
256 }
b9b7b06a
SL
257 remque(rt);
258 free((char *)rt);
259}
260
7892134c
MK
261rtdeleteall(s)
262 int s;
263{
264 register struct rthash *rh;
265 register struct rt_entry *rt;
266 struct rthash *base = hosthash;
267 int doinghost = 1;
268
269again:
270 for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
271 rt = rh->rt_forw;
272 for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
9c2cb70b
MK
273 if (rt->rt_state & RTS_INTERFACE ||
274 rt->rt_metric >= HOPCNT_INFINITY)
7892134c 275 continue;
9c2cb70b 276 TRACE_ACTION("DELETE", rt);
7892134c
MK
277 if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
278 ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
279 perror("SIOCDELRT");
280 }
281 }
282 if (doinghost) {
283 doinghost = 0;
284 base = nethash;
285 goto again;
286 }
9c2cb70b 287 exit(s);
7892134c
MK
288}
289
ad34083f
MK
290/*
291 * If we have an interface to the wide, wide world,
292 * add an entry for an Internet default route (wildcard) to the internal
293 * tables and advertise it. This route is not added to the kernel routes,
294 * but this entry prevents us from listening to other people's defaults
295 * and installing them in the kernel here.
296 */
297rtdefault()
298{
ad34083f
MK
299 extern struct sockaddr inet_default;
300
09b9aef2 301 rtadd(&inet_default, &inet_default, 1,
4fad5a6e 302 RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
ad34083f
MK
303}
304
b9b7b06a
SL
305rtinit()
306{
307 register struct rthash *rh;
308
309 for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
310 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
311 for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
312 rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
313}