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 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 void 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 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 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 115 rt_init(void) 116 { 117 RB_INIT(&rt); 118 } 119 120 int 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 * 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 * 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 * 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 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 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 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 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 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 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