xref: /openbsd/usr.sbin/ripd/rde_rib.c (revision 73471bf0)
1 /*	$OpenBSD: rde_rib.c,v 1.5 2007/10/24 20:38:03 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/ioctl.h>
21 #include <sys/time.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <net/if.h>
26 #include <net/if_types.h>
27 #include <ctype.h>
28 #include <err.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <event.h>
34 
35 #include "ripd.h"
36 #include "rip.h"
37 #include "log.h"
38 #include "rde.h"
39 
40 extern struct ripd_conf		*rdeconf;
41 RB_HEAD(rt_tree, rt_node)	 rt;
42 RB_PROTOTYPE(rt_tree, rt_node, entry, rt_compare)
43 RB_GENERATE(rt_tree, rt_node, entry, rt_compare)
44 
45 void	 route_action_timeout(int, short, void *);
46 void	 route_action_garbage(int, short, void *);
47 
48 /* timers */
49 int
50 route_start_timeout(struct rt_node *rn)
51 {
52 	struct timeval	 tv;
53 
54 	timerclear(&tv);
55 	tv.tv_sec = ROUTE_TIMEOUT;
56 
57 	return (evtimer_add(&rn->timeout_timer, &tv));
58 }
59 
60 void
61 route_start_garbage(struct rt_node *rn)
62 {
63 	struct timeval	 tv;
64 
65 	timerclear(&tv);
66 	tv.tv_sec = ROUTE_GARBAGE;
67 
68 	if (evtimer_pending(&rn->timeout_timer, NULL)) {
69 		if (evtimer_del(&rn->timeout_timer) == -1)
70 			fatal("route_start_garbage");
71 		evtimer_add(&rn->garbage_timer, &tv);
72 	}
73 }
74 
75 /* ARGSUSED */
76 void
77 route_action_timeout(int fd, short event, void *arg)
78 {
79 	struct rt_node	*r = arg;
80 	struct timeval	 tv;
81 
82 	timerclear(&tv);
83 	r->metric = INFINITY;
84 	tv.tv_sec = ROUTE_GARBAGE;
85 
86 	if (evtimer_add(&r->garbage_timer, &tv) == -1)
87 		fatal("route_action_timeout");
88 
89 	rde_send_change_kroute(r);
90 }
91 
92 /* ARGSUSED */
93 void
94 route_action_garbage(int fd, short event, void *arg)
95 {
96 	struct rt_node	*r = arg;
97 
98 	rde_send_delete_kroute(r);
99 	rt_remove(r);
100 }
101 
102 void
103 route_reset_timers(struct rt_node *r)
104 {
105 	struct timeval	 tv;
106 
107 	timerclear(&tv);
108 	tv.tv_sec = ROUTE_TIMEOUT;
109 	evtimer_del(&r->timeout_timer);
110 	evtimer_del(&r->garbage_timer);
111 
112 	evtimer_add(&r->timeout_timer, &tv);
113 }
114 
115 /* route table */
116 void
117 rt_init(void)
118 {
119 	RB_INIT(&rt);
120 }
121 
122 int
123 rt_compare(struct rt_node *a, struct rt_node *b)
124 {
125 	if (ntohl(a->prefix.s_addr) < ntohl(b->prefix.s_addr))
126 		return (-1);
127 	if (ntohl(a->prefix.s_addr) > ntohl(b->prefix.s_addr))
128 		return (1);
129 	if (ntohl(a->netmask.s_addr) < ntohl(b->netmask.s_addr))
130 		return (-1);
131 	if (ntohl(a->netmask.s_addr) > ntohl(b->netmask.s_addr))
132 		return (1);
133 
134 	return (0);
135 }
136 
137 struct rt_node *
138 rt_find(in_addr_t prefix, in_addr_t netmask)
139 {
140 	struct rt_node	 s;
141 
142 	s.prefix.s_addr = prefix;
143 	s.netmask.s_addr = netmask;
144 
145 	return (RB_FIND(rt_tree, &rt, &s));
146 }
147 
148 struct rt_node *
149 rt_new_kr(struct kroute *kr)
150 {
151 	struct rt_node	*rn;
152 
153 	if ((rn = calloc(1, sizeof(*rn))) == NULL)
154 		fatal("rt_new_kr");
155 
156 	evtimer_set(&rn->timeout_timer, route_action_timeout, rn);
157 	evtimer_set(&rn->garbage_timer, route_action_garbage, rn);
158 
159 	rn->prefix.s_addr = kr->prefix.s_addr;
160 	rn->netmask.s_addr = kr->netmask.s_addr;
161 	rn->nexthop.s_addr = kr->nexthop.s_addr;
162 	rn->metric = kr->metric;
163 	rn->ifindex = kr->ifindex;
164 	rn->flags = F_KERNEL;
165 
166 	return (rn);
167 }
168 
169 struct rt_node *
170 rt_new_rr(struct rip_route *e, u_int8_t metric)
171 {
172 	struct rt_node	*rn;
173 
174 	if ((rn = calloc(1, sizeof(*rn))) == NULL)
175 		fatal("rt_new_rr");
176 
177 	evtimer_set(&rn->timeout_timer, route_action_timeout, rn);
178 	evtimer_set(&rn->garbage_timer, route_action_garbage, rn);
179 
180 	rn->prefix.s_addr = e->address.s_addr;
181 	rn->netmask.s_addr = e->mask.s_addr;
182 	rn->nexthop.s_addr = e->nexthop.s_addr;
183 	rn->metric = metric;
184 	rn->ifindex = e->ifindex;
185 	rn->flags = F_RIPD_INSERTED;
186 
187 	return (rn);
188 }
189 
190 int
191 rt_insert(struct rt_node *r)
192 {
193 	if (RB_INSERT(rt_tree, &rt, r) != NULL) {
194 		log_warnx("rt_insert failed for %s/%u",
195 		    inet_ntoa(r->prefix), mask2prefixlen(r->netmask.s_addr));
196 		free(r);
197 		return (-1);
198 	}
199 
200 	return (0);
201 }
202 
203 int
204 rt_remove(struct rt_node *r)
205 {
206 	if (RB_REMOVE(rt_tree, &rt, r) == NULL) {
207 		log_warnx("rt_remove failed for %s/%u",
208 		    inet_ntoa(r->prefix), mask2prefixlen(r->netmask.s_addr));
209 		return (-1);
210 	}
211 
212 	free(r);
213 	return (0);
214 }
215 
216 void
217 rt_snap(u_int32_t peerid)
218 {
219 	struct rt_node		*r;
220 	struct rip_route	 rr;
221 
222 	bzero(&rr, sizeof(rr));
223 
224 	RB_FOREACH(r, rt_tree, &rt) {
225 		rr.address = r->prefix;
226 		rr.mask = r->netmask;
227 		rr.nexthop = r->nexthop;
228 		rr.metric = r->metric;
229 		rr.ifindex = r->ifindex;
230 
231 		rde_imsg_compose_ripe(IMSG_RESPONSE_ADD, peerid, 0, &rr,
232 		    sizeof(rr));
233 	}
234 }
235 
236 void
237 rt_dump(pid_t pid)
238 {
239 	struct rt_node		*r;
240 	static struct ctl_rt	 rtctl;
241 
242 	RB_FOREACH(r, rt_tree, &rt) {
243 		rtctl.prefix.s_addr = r->prefix.s_addr;
244 		rtctl.netmask.s_addr = r->netmask.s_addr;
245 		rtctl.nexthop.s_addr = r->nexthop.s_addr;
246 		rtctl.metric = r->metric;
247 		rtctl.flags = r->flags;
248 
249 		rde_imsg_compose_ripe(IMSG_CTL_SHOW_RIB, 0, pid, &rtctl,
250 		    sizeof(rtctl));
251 	}
252 }
253 
254 void
255 rt_complete(struct rip_route *rr)
256 {
257 	struct rt_node	*rn;
258 
259 	if ((rn = rt_find(rr->address.s_addr, rr->mask.s_addr)) == NULL)
260 		rr->metric = INFINITY;
261 	else
262 		rr->metric = rn->metric;
263 }
264 
265 void
266 rt_clear(void)
267 {
268 	struct rt_node	*r;
269 
270 	while ((r = RB_MIN(rt_tree, &rt)) != NULL)
271 		rt_remove(r);
272 }
273