1 /* $OpenBSD: rde_rib.c,v 1.6 2023/03/08 04:43:14 guenther 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
route_start_timeout(struct rt_node * rn)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
route_start_garbage(struct rt_node * rn)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 void
route_action_timeout(int fd,short event,void * arg)76 route_action_timeout(int fd, short event, void *arg)
77 {
78 struct rt_node *r = arg;
79 struct timeval tv;
80
81 timerclear(&tv);
82 r->metric = INFINITY;
83 tv.tv_sec = ROUTE_GARBAGE;
84
85 if (evtimer_add(&r->garbage_timer, &tv) == -1)
86 fatal("route_action_timeout");
87
88 rde_send_change_kroute(r);
89 }
90
91 void
route_action_garbage(int fd,short event,void * arg)92 route_action_garbage(int fd, short event, void *arg)
93 {
94 struct rt_node *r = arg;
95
96 rde_send_delete_kroute(r);
97 rt_remove(r);
98 }
99
100 void
route_reset_timers(struct rt_node * r)101 route_reset_timers(struct rt_node *r)
102 {
103 struct timeval tv;
104
105 timerclear(&tv);
106 tv.tv_sec = ROUTE_TIMEOUT;
107 evtimer_del(&r->timeout_timer);
108 evtimer_del(&r->garbage_timer);
109
110 evtimer_add(&r->timeout_timer, &tv);
111 }
112
113 /* route table */
114 void
rt_init(void)115 rt_init(void)
116 {
117 RB_INIT(&rt);
118 }
119
120 int
rt_compare(struct rt_node * a,struct rt_node * b)121 rt_compare(struct rt_node *a, struct rt_node *b)
122 {
123 if (ntohl(a->prefix.s_addr) < ntohl(b->prefix.s_addr))
124 return (-1);
125 if (ntohl(a->prefix.s_addr) > ntohl(b->prefix.s_addr))
126 return (1);
127 if (ntohl(a->netmask.s_addr) < ntohl(b->netmask.s_addr))
128 return (-1);
129 if (ntohl(a->netmask.s_addr) > ntohl(b->netmask.s_addr))
130 return (1);
131
132 return (0);
133 }
134
135 struct rt_node *
rt_find(in_addr_t prefix,in_addr_t netmask)136 rt_find(in_addr_t prefix, in_addr_t netmask)
137 {
138 struct rt_node s;
139
140 s.prefix.s_addr = prefix;
141 s.netmask.s_addr = netmask;
142
143 return (RB_FIND(rt_tree, &rt, &s));
144 }
145
146 struct rt_node *
rt_new_kr(struct kroute * kr)147 rt_new_kr(struct kroute *kr)
148 {
149 struct rt_node *rn;
150
151 if ((rn = calloc(1, sizeof(*rn))) == NULL)
152 fatal("rt_new_kr");
153
154 evtimer_set(&rn->timeout_timer, route_action_timeout, rn);
155 evtimer_set(&rn->garbage_timer, route_action_garbage, rn);
156
157 rn->prefix.s_addr = kr->prefix.s_addr;
158 rn->netmask.s_addr = kr->netmask.s_addr;
159 rn->nexthop.s_addr = kr->nexthop.s_addr;
160 rn->metric = kr->metric;
161 rn->ifindex = kr->ifindex;
162 rn->flags = F_KERNEL;
163
164 return (rn);
165 }
166
167 struct rt_node *
rt_new_rr(struct rip_route * e,u_int8_t metric)168 rt_new_rr(struct rip_route *e, u_int8_t metric)
169 {
170 struct rt_node *rn;
171
172 if ((rn = calloc(1, sizeof(*rn))) == NULL)
173 fatal("rt_new_rr");
174
175 evtimer_set(&rn->timeout_timer, route_action_timeout, rn);
176 evtimer_set(&rn->garbage_timer, route_action_garbage, rn);
177
178 rn->prefix.s_addr = e->address.s_addr;
179 rn->netmask.s_addr = e->mask.s_addr;
180 rn->nexthop.s_addr = e->nexthop.s_addr;
181 rn->metric = metric;
182 rn->ifindex = e->ifindex;
183 rn->flags = F_RIPD_INSERTED;
184
185 return (rn);
186 }
187
188 int
rt_insert(struct rt_node * r)189 rt_insert(struct rt_node *r)
190 {
191 if (RB_INSERT(rt_tree, &rt, r) != NULL) {
192 log_warnx("rt_insert failed for %s/%u",
193 inet_ntoa(r->prefix), mask2prefixlen(r->netmask.s_addr));
194 free(r);
195 return (-1);
196 }
197
198 return (0);
199 }
200
201 int
rt_remove(struct rt_node * r)202 rt_remove(struct rt_node *r)
203 {
204 if (RB_REMOVE(rt_tree, &rt, r) == NULL) {
205 log_warnx("rt_remove failed for %s/%u",
206 inet_ntoa(r->prefix), mask2prefixlen(r->netmask.s_addr));
207 return (-1);
208 }
209
210 free(r);
211 return (0);
212 }
213
214 void
rt_snap(u_int32_t peerid)215 rt_snap(u_int32_t peerid)
216 {
217 struct rt_node *r;
218 struct rip_route rr;
219
220 bzero(&rr, sizeof(rr));
221
222 RB_FOREACH(r, rt_tree, &rt) {
223 rr.address = r->prefix;
224 rr.mask = r->netmask;
225 rr.nexthop = r->nexthop;
226 rr.metric = r->metric;
227 rr.ifindex = r->ifindex;
228
229 rde_imsg_compose_ripe(IMSG_RESPONSE_ADD, peerid, 0, &rr,
230 sizeof(rr));
231 }
232 }
233
234 void
rt_dump(pid_t pid)235 rt_dump(pid_t pid)
236 {
237 struct rt_node *r;
238 static struct ctl_rt rtctl;
239
240 RB_FOREACH(r, rt_tree, &rt) {
241 rtctl.prefix.s_addr = r->prefix.s_addr;
242 rtctl.netmask.s_addr = r->netmask.s_addr;
243 rtctl.nexthop.s_addr = r->nexthop.s_addr;
244 rtctl.metric = r->metric;
245 rtctl.flags = r->flags;
246
247 rde_imsg_compose_ripe(IMSG_CTL_SHOW_RIB, 0, pid, &rtctl,
248 sizeof(rtctl));
249 }
250 }
251
252 void
rt_complete(struct rip_route * rr)253 rt_complete(struct rip_route *rr)
254 {
255 struct rt_node *rn;
256
257 if ((rn = rt_find(rr->address.s_addr, rr->mask.s_addr)) == NULL)
258 rr->metric = INFINITY;
259 else
260 rr->metric = rn->metric;
261 }
262
263 void
rt_clear(void)264 rt_clear(void)
265 {
266 struct rt_node *r;
267
268 while ((r = RB_MIN(rt_tree, &rt)) != NULL)
269 rt_remove(r);
270 }
271