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