1*f1b790a5Sclaudio /* $OpenBSD: rde.c,v 1.31 2024/11/21 13:38:15 claudio Exp $ */ 2ddeeec14Snorby 3ddeeec14Snorby /* 4ddeeec14Snorby * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it> 5ddeeec14Snorby * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org> 6ddeeec14Snorby * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 7ddeeec14Snorby * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 8ddeeec14Snorby * 9ddeeec14Snorby * Permission to use, copy, modify, and distribute this software for any 10ddeeec14Snorby * purpose with or without fee is hereby granted, provided that the above 11ddeeec14Snorby * copyright notice and this permission notice appear in all copies. 12ddeeec14Snorby * 13ddeeec14Snorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14ddeeec14Snorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15ddeeec14Snorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16ddeeec14Snorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17ddeeec14Snorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18ddeeec14Snorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19ddeeec14Snorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20ddeeec14Snorby */ 21ddeeec14Snorby 22ddeeec14Snorby #include <sys/socket.h> 23ddeeec14Snorby #include <sys/queue.h> 24ddeeec14Snorby #include <netinet/in.h> 25ddeeec14Snorby #include <arpa/inet.h> 26ddeeec14Snorby #include <err.h> 27ddeeec14Snorby #include <errno.h> 28ddeeec14Snorby #include <stdlib.h> 29ddeeec14Snorby #include <signal.h> 30ddeeec14Snorby #include <string.h> 31ddeeec14Snorby #include <pwd.h> 32ddeeec14Snorby #include <unistd.h> 33ddeeec14Snorby #include <event.h> 34ddeeec14Snorby 35ddeeec14Snorby #include "ripd.h" 36ddeeec14Snorby #include "rip.h" 37ddeeec14Snorby #include "ripe.h" 38ddeeec14Snorby #include "log.h" 39ddeeec14Snorby #include "rde.h" 40ddeeec14Snorby 41b9fc9a72Sderaadt #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 42b9fc9a72Sderaadt 43ddeeec14Snorby struct ripd_conf *rdeconf = NULL; 445434bd38Sclaudio static struct imsgev *iev_ripe; 455434bd38Sclaudio static struct imsgev *iev_main; 46ddeeec14Snorby 47ddeeec14Snorby void rde_sig_handler(int, short, void *); 48f6798567Srenato __dead void rde_shutdown(void); 49ddeeec14Snorby void rde_dispatch_imsg(int, short, void *); 50ddeeec14Snorby void rde_dispatch_parent(int, short, void *); 51ddeeec14Snorby int rde_imsg_compose_ripe(int, u_int32_t, pid_t, void *, u_int16_t); 52ddeeec14Snorby int rde_check_route(struct rip_route *); 53ddeeec14Snorby void triggered_update(struct rt_node *); 54ddeeec14Snorby 55ddeeec14Snorby void 56ddeeec14Snorby rde_sig_handler(int sig, short event, void *arg) 57ddeeec14Snorby { 58ddeeec14Snorby /* 59ddeeec14Snorby * signal handler rules don't apply, libevent decouples for us 60ddeeec14Snorby */ 61ddeeec14Snorby 62ddeeec14Snorby switch (sig) { 63ddeeec14Snorby case SIGINT: 64ddeeec14Snorby case SIGTERM: 65ddeeec14Snorby rde_shutdown(); 66ddeeec14Snorby /* NOTREACHED */ 67ddeeec14Snorby default: 68ddeeec14Snorby fatalx("unexpected signal"); 69ddeeec14Snorby } 70ddeeec14Snorby } 71ddeeec14Snorby 72ddeeec14Snorby /* route decision engine */ 73ddeeec14Snorby pid_t 74ddeeec14Snorby rde(struct ripd_conf *xconf, int pipe_parent2rde[2], int pipe_ripe2rde[2], 75ddeeec14Snorby int pipe_parent2ripe[2]) 76ddeeec14Snorby { 77ddeeec14Snorby struct event ev_sigint, ev_sigterm; 789bb9ec63Sclaudio struct passwd *pw; 799bb9ec63Sclaudio struct redistribute *r; 80ddeeec14Snorby pid_t pid; 81ddeeec14Snorby 82ddeeec14Snorby switch (pid = fork()) { 83ddeeec14Snorby case -1: 84ddeeec14Snorby fatal("cannot fork"); 85ddeeec14Snorby /* NOTREACHED */ 86ddeeec14Snorby case 0: 87ddeeec14Snorby break; 88ddeeec14Snorby default: 89ddeeec14Snorby return (pid); 90ddeeec14Snorby } 91ddeeec14Snorby 92ddeeec14Snorby rdeconf = xconf; 93ddeeec14Snorby 94ddeeec14Snorby if ((pw = getpwnam(RIPD_USER)) == NULL) 95ddeeec14Snorby fatal("getpwnam"); 96ddeeec14Snorby 97ddeeec14Snorby if (chroot(pw->pw_dir) == -1) 98ddeeec14Snorby fatal("chroot"); 99ddeeec14Snorby if (chdir("/") == -1) 100ddeeec14Snorby fatal("chdir(\"/\")"); 101ddeeec14Snorby 102ddeeec14Snorby setproctitle("route decision engine"); 10379911490Sclaudio log_procname = "rde"; 104ddeeec14Snorby 105ddeeec14Snorby if (setgroups(1, &pw->pw_gid) || 106ddeeec14Snorby setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 107ddeeec14Snorby setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 108ddeeec14Snorby fatal("can't drop privileges"); 109ddeeec14Snorby 110e0f3cc49Sremi if (pledge("stdio", NULL) == -1) 111e0f3cc49Sremi fatal("pledge"); 112e0f3cc49Sremi 113ddeeec14Snorby event_init(); 114ddeeec14Snorby 115ddeeec14Snorby /* setup signal handler */ 116ddeeec14Snorby signal_set(&ev_sigint, SIGINT, rde_sig_handler, NULL); 117ddeeec14Snorby signal_set(&ev_sigterm, SIGTERM, rde_sig_handler, NULL); 118ddeeec14Snorby signal_add(&ev_sigint, NULL); 119ddeeec14Snorby signal_add(&ev_sigterm, NULL); 120bfb3864dSclaudio signal(SIGPIPE, SIG_IGN); 1212a8226daSclaudio signal(SIGHUP, SIG_IGN); 122ddeeec14Snorby 123ddeeec14Snorby /* setup pipes */ 124ddeeec14Snorby close(pipe_ripe2rde[0]); 125ddeeec14Snorby close(pipe_parent2rde[0]); 126ddeeec14Snorby close(pipe_parent2ripe[0]); 127ddeeec14Snorby close(pipe_parent2ripe[1]); 128ddeeec14Snorby 129f7ce36daSeric if ((iev_ripe = malloc(sizeof(struct imsgev))) == NULL || 130f7ce36daSeric (iev_main = malloc(sizeof(struct imsgev))) == NULL) 131ddeeec14Snorby fatal(NULL); 132*f1b790a5Sclaudio if (imsgbuf_init(&iev_ripe->ibuf, pipe_ripe2rde[1]) == -1) 133*f1b790a5Sclaudio fatal(NULL); 134f7ce36daSeric iev_ripe->handler = rde_dispatch_imsg; 135*f1b790a5Sclaudio if (imsgbuf_init(&iev_main->ibuf, pipe_parent2rde[1]) == -1) 136*f1b790a5Sclaudio fatal(NULL); 137f7ce36daSeric iev_main->handler = rde_dispatch_parent; 138ddeeec14Snorby 139ddeeec14Snorby /* setup event handler */ 140f7ce36daSeric iev_ripe->events = EV_READ; 141f7ce36daSeric event_set(&iev_ripe->ev, iev_ripe->ibuf.fd, iev_ripe->events, 142f7ce36daSeric iev_ripe->handler, iev_ripe); 143f7ce36daSeric event_add(&iev_ripe->ev, NULL); 144ddeeec14Snorby 145f7ce36daSeric iev_main->events = EV_READ; 146f7ce36daSeric event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 147f7ce36daSeric iev_main->handler, iev_main); 148f7ce36daSeric event_add(&iev_main->ev, NULL); 149ddeeec14Snorby rt_init(); 1509bb9ec63Sclaudio 1519bb9ec63Sclaudio /* remove unneeded config stuff */ 1529bb9ec63Sclaudio while ((r = SIMPLEQ_FIRST(&rdeconf->redist_list)) != NULL) { 1539bb9ec63Sclaudio SIMPLEQ_REMOVE_HEAD(&rdeconf->redist_list, entry); 1549bb9ec63Sclaudio free(r); 1559bb9ec63Sclaudio } 1569bb9ec63Sclaudio 157ddeeec14Snorby event_dispatch(); 158ddeeec14Snorby 159ddeeec14Snorby rde_shutdown(); 160ddeeec14Snorby /* NOTREACHED */ 161ddeeec14Snorby 162ddeeec14Snorby return (0); 163ddeeec14Snorby } 164ddeeec14Snorby 165f6798567Srenato __dead void 166ddeeec14Snorby rde_shutdown(void) 167ddeeec14Snorby { 168f6798567Srenato /* close pipes */ 1699cbf9e90Sclaudio imsgbuf_clear(&iev_ripe->ibuf); 170f6798567Srenato close(iev_ripe->ibuf.fd); 1719cbf9e90Sclaudio imsgbuf_clear(&iev_main->ibuf); 172f6798567Srenato close(iev_main->ibuf.fd); 173f6798567Srenato 174f6798567Srenato rt_clear(); 175f6798567Srenato free(iev_ripe); 176f7ce36daSeric free(iev_main); 177ddeeec14Snorby free(rdeconf); 178ddeeec14Snorby 179ddeeec14Snorby log_info("route decision engine exiting"); 180ddeeec14Snorby _exit(0); 181ddeeec14Snorby } 182ddeeec14Snorby 183ddeeec14Snorby int 184ddeeec14Snorby rde_imsg_compose_ripe(int type, u_int32_t peerid, pid_t pid, void *data, 185ddeeec14Snorby u_int16_t datalen) 186ddeeec14Snorby { 187f7ce36daSeric return (imsg_compose_event(iev_ripe, type, peerid, pid, -1, 188f7ce36daSeric data, datalen)); 189ddeeec14Snorby } 190ddeeec14Snorby 191ddeeec14Snorby void 192ddeeec14Snorby rde_dispatch_imsg(int fd, short event, void *bula) 193ddeeec14Snorby { 194f7ce36daSeric struct imsgev *iev = bula; 195f7ce36daSeric struct imsgbuf *ibuf = &iev->ibuf; 196ddeeec14Snorby struct rip_route rr; 197ddeeec14Snorby struct imsg imsg; 1982a8226daSclaudio ssize_t n; 199dce97bddSclaudio int shut = 0, verbose; 200ddeeec14Snorby 201bd6053efSclaudio if (event & EV_READ) { 202668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 203dd7efffeSclaudio fatal("imsgbuf_read error"); 204ddeeec14Snorby if (n == 0) /* connection closed */ 2052a8226daSclaudio shut = 1; 206bd6053efSclaudio } 207bd6053efSclaudio if (event & EV_WRITE) { 208dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 209c1aa9554Sclaudio if (errno == EPIPE) /* connection closed */ 2101203692fSkrw shut = 1; 211c1aa9554Sclaudio else 212dd7efffeSclaudio fatal("imsgbuf_write"); 213c1aa9554Sclaudio } 214ddeeec14Snorby } 215ddeeec14Snorby 216ddeeec14Snorby for (;;) { 217ddeeec14Snorby if ((n = imsg_get(ibuf, &imsg)) == -1) 21879e8bbf6Sclaudio fatal("rde_dispatch_imsg: imsg_get error"); 219ddeeec14Snorby if (n == 0) 220ddeeec14Snorby break; 221ddeeec14Snorby 222ddeeec14Snorby switch (imsg.hdr.type) { 223ddeeec14Snorby case IMSG_ROUTE_FEED: 224ddeeec14Snorby if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rr)) 225ddeeec14Snorby fatalx("invalid size of RDE request"); 226ddeeec14Snorby 227ddeeec14Snorby memcpy(&rr, imsg.data, sizeof(rr)); 228ddeeec14Snorby 229ddeeec14Snorby if (rde_check_route(&rr) == -1) 230ddeeec14Snorby log_debug("rde_dispatch_imsg: " 231ddeeec14Snorby "packet malformed\n"); 232ddeeec14Snorby break; 233ddeeec14Snorby case IMSG_FULL_REQUEST: 234ddeeec14Snorby bzero(&rr, sizeof(rr)); 235726964a1Sderaadt /* 236726964a1Sderaadt * AFI == 0 && metric == INFINITY request the 237726964a1Sderaadt * whole routing table 238ddeeec14Snorby */ 239ddeeec14Snorby rr.metric = INFINITY; 240ddeeec14Snorby rde_imsg_compose_ripe(IMSG_REQUEST_ADD, 0, 241ddeeec14Snorby 0, &rr, sizeof(rr)); 242ddeeec14Snorby rde_imsg_compose_ripe(IMSG_SEND_REQUEST, 0, 243ddeeec14Snorby 0, NULL, 0); 244ddeeec14Snorby break; 245ddeeec14Snorby case IMSG_FULL_RESPONSE: 246ddeeec14Snorby rt_snap(imsg.hdr.peerid); 247ddeeec14Snorby rde_imsg_compose_ripe(IMSG_SEND_RESPONSE, 248ddeeec14Snorby imsg.hdr.peerid, 0, NULL, 0); 249ddeeec14Snorby break; 250ddeeec14Snorby case IMSG_ROUTE_REQUEST: 251ddeeec14Snorby if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rr)) 252ddeeec14Snorby fatalx("invalid size of RDE request"); 253ddeeec14Snorby 254ddeeec14Snorby memcpy(&rr, imsg.data, sizeof(rr)); 255ddeeec14Snorby 256ddeeec14Snorby rt_complete(&rr); 257ddeeec14Snorby rde_imsg_compose_ripe(IMSG_RESPONSE_ADD, 258ddeeec14Snorby imsg.hdr.peerid, 0, &rr, sizeof(rr)); 259ddeeec14Snorby 260ddeeec14Snorby break; 261ddeeec14Snorby case IMSG_ROUTE_REQUEST_END: 262ddeeec14Snorby rde_imsg_compose_ripe(IMSG_SEND_RESPONSE, 263ddeeec14Snorby imsg.hdr.peerid, 0, NULL, 0); 264ddeeec14Snorby break; 265ddeeec14Snorby case IMSG_CTL_SHOW_RIB: 266ddeeec14Snorby rt_dump(imsg.hdr.pid); 267ddeeec14Snorby 268f7ce36daSeric imsg_compose_event(iev_ripe, IMSG_CTL_END, 0, 269f7ce36daSeric imsg.hdr.pid, -1, NULL, 0); 270ddeeec14Snorby 271ddeeec14Snorby break; 272dce97bddSclaudio case IMSG_CTL_LOG_VERBOSE: 273dce97bddSclaudio /* already checked by ripe */ 274dce97bddSclaudio memcpy(&verbose, imsg.data, sizeof(verbose)); 275dce97bddSclaudio log_verbose(verbose); 276dce97bddSclaudio break; 277ddeeec14Snorby default: 278ddeeec14Snorby log_debug("rde_dispatch_msg: unexpected imsg %d", 279ddeeec14Snorby imsg.hdr.type); 280ddeeec14Snorby break; 281ddeeec14Snorby } 282ddeeec14Snorby imsg_free(&imsg); 283ddeeec14Snorby } 2842a8226daSclaudio if (!shut) 285f7ce36daSeric imsg_event_add(iev); 2862a8226daSclaudio else { 2872a8226daSclaudio /* this pipe is dead, so remove the event handler */ 288f7ce36daSeric event_del(&iev->ev); 2892a8226daSclaudio event_loopexit(NULL); 2902a8226daSclaudio } 291ddeeec14Snorby } 292ddeeec14Snorby 293ddeeec14Snorby void 294ddeeec14Snorby rde_dispatch_parent(int fd, short event, void *bula) 295ddeeec14Snorby { 296ddeeec14Snorby struct imsg imsg; 297ddeeec14Snorby struct rt_node *rt; 298ddeeec14Snorby struct kroute kr; 299f7ce36daSeric struct imsgev *iev = bula; 300f7ce36daSeric struct imsgbuf *ibuf = &iev->ibuf; 301ddeeec14Snorby ssize_t n; 3022a8226daSclaudio int shut = 0; 303ddeeec14Snorby 304bd6053efSclaudio if (event & EV_READ) { 305668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 306dd7efffeSclaudio fatal("imsgbuf_read error"); 307ddeeec14Snorby if (n == 0) /* connection closed */ 3082a8226daSclaudio shut = 1; 309bd6053efSclaudio } 310bd6053efSclaudio if (event & EV_WRITE) { 311dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 312c1aa9554Sclaudio if (errno == EPIPE) /* connection closed */ 3131203692fSkrw shut = 1; 314c1aa9554Sclaudio else 315dd7efffeSclaudio fatal("imsgbuf_write"); 316c1aa9554Sclaudio } 317ddeeec14Snorby } 318ddeeec14Snorby 319ddeeec14Snorby for (;;) { 320ddeeec14Snorby if ((n = imsg_get(ibuf, &imsg)) == -1) 32179e8bbf6Sclaudio fatal("rde_dispatch_parent: imsg_get error"); 322ddeeec14Snorby if (n == 0) 323ddeeec14Snorby break; 324ddeeec14Snorby 325ddeeec14Snorby switch (imsg.hdr.type) { 326ddeeec14Snorby case IMSG_NETWORK_ADD: 327ddeeec14Snorby if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(kr)) { 328ddeeec14Snorby log_warnx("rde_dispatch: wrong imsg len"); 329ddeeec14Snorby break; 330ddeeec14Snorby } 331ddeeec14Snorby 332ddeeec14Snorby memcpy(&kr, imsg.data, sizeof(kr)); 333ddeeec14Snorby 334ddeeec14Snorby rt = rt_new_kr(&kr); 335ddeeec14Snorby rt_insert(rt); 336ddeeec14Snorby break; 337ddeeec14Snorby case IMSG_NETWORK_DEL: 338ddeeec14Snorby if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(kr)) { 339ddeeec14Snorby log_warnx("rde_dispatch: wrong imsg len"); 340ddeeec14Snorby break; 341ddeeec14Snorby } 342ddeeec14Snorby memcpy(&kr, imsg.data, sizeof(kr)); 343ddeeec14Snorby 344ddeeec14Snorby if ((rt = rt_find(kr.prefix.s_addr, 345ddeeec14Snorby kr.netmask.s_addr)) != NULL) 346ddeeec14Snorby rt_remove(rt); 347ddeeec14Snorby break; 348ddeeec14Snorby default: 349ddeeec14Snorby log_debug("rde_dispatch_parent: unexpected imsg %d", 350ddeeec14Snorby imsg.hdr.type); 351ddeeec14Snorby break; 352ddeeec14Snorby } 353ddeeec14Snorby imsg_free(&imsg); 354ddeeec14Snorby } 3552a8226daSclaudio if (!shut) 356f7ce36daSeric imsg_event_add(iev); 3572a8226daSclaudio else { 3582a8226daSclaudio /* this pipe is dead, so remove the event handler */ 359f7ce36daSeric event_del(&iev->ev); 3602a8226daSclaudio event_loopexit(NULL); 3612a8226daSclaudio } 362ddeeec14Snorby } 363ddeeec14Snorby 364ddeeec14Snorby void 365ddeeec14Snorby rde_send_change_kroute(struct rt_node *r) 366ddeeec14Snorby { 367ddeeec14Snorby struct kroute kr; 368ddeeec14Snorby 369ddeeec14Snorby bzero(&kr, sizeof(kr)); 370ddeeec14Snorby kr.prefix.s_addr = r->prefix.s_addr; 371ddeeec14Snorby kr.nexthop.s_addr = r->nexthop.s_addr; 372ddeeec14Snorby kr.netmask.s_addr = r->netmask.s_addr; 373ddeeec14Snorby kr.metric = r->metric; 374ddeeec14Snorby kr.flags = r->flags; 375ddeeec14Snorby kr.ifindex = r->ifindex; 376ddeeec14Snorby 377f7ce36daSeric imsg_compose_event(iev_main, IMSG_KROUTE_CHANGE, 0, 0, -1, 378f7ce36daSeric &kr, sizeof(kr)); 379ddeeec14Snorby } 380ddeeec14Snorby 381ddeeec14Snorby void 382ddeeec14Snorby rde_send_delete_kroute(struct rt_node *r) 383ddeeec14Snorby { 384ddeeec14Snorby struct kroute kr; 385ddeeec14Snorby 386ddeeec14Snorby bzero(&kr, sizeof(kr)); 387ddeeec14Snorby kr.prefix.s_addr = r->prefix.s_addr; 388ddeeec14Snorby kr.nexthop.s_addr = r->nexthop.s_addr; 389ddeeec14Snorby kr.netmask.s_addr = r->netmask.s_addr; 390ddeeec14Snorby kr.metric = r->metric; 391ddeeec14Snorby kr.flags = r->flags; 392ddeeec14Snorby kr.ifindex = r->ifindex; 393ddeeec14Snorby 394f7ce36daSeric imsg_compose_event(iev_main, IMSG_KROUTE_DELETE, 0, 0, -1, 395f7ce36daSeric &kr, sizeof(kr)); 396ddeeec14Snorby } 397ddeeec14Snorby 398ddeeec14Snorby int 399ddeeec14Snorby rde_check_route(struct rip_route *e) 400ddeeec14Snorby { 401960f8542Smichele struct timeval tv, now; 402ddeeec14Snorby struct rt_node *rn; 403ddeeec14Snorby struct iface *iface; 4041d57a832Sclaudio u_int8_t metric; 405ddeeec14Snorby 406ddeeec14Snorby if ((e->nexthop.s_addr & htonl(IN_CLASSA_NET)) == 407ddeeec14Snorby htonl(INADDR_LOOPBACK & IN_CLASSA_NET) || 4082a8226daSclaudio e->nexthop.s_addr == INADDR_ANY) 409ddeeec14Snorby return (-1); 410ddeeec14Snorby 411ddeeec14Snorby if ((iface = if_find_index(e->ifindex)) == NULL) 412ddeeec14Snorby return (-1); 413ddeeec14Snorby 414b9fc9a72Sderaadt metric = MINIMUM(INFINITY, e->metric + iface->cost); 415ddeeec14Snorby 416ddeeec14Snorby if ((rn = rt_find(e->address.s_addr, e->mask.s_addr)) == NULL) { 417960f8542Smichele if (metric >= INFINITY) 418960f8542Smichele return (0); 419ddeeec14Snorby rn = rt_new_rr(e, metric); 420ddeeec14Snorby rt_insert(rn); 421ddeeec14Snorby rde_send_change_kroute(rn); 422ddeeec14Snorby route_start_timeout(rn); 423ddeeec14Snorby triggered_update(rn); 424ddeeec14Snorby } else { 425ddeeec14Snorby /* 426b8bbf4e7Sdavid * XXX don't we have to track all incoming routes? 427ddeeec14Snorby * what happens if the kernel route is removed later. 428ddeeec14Snorby */ 429ddeeec14Snorby if (rn->flags & F_KERNEL) 430ddeeec14Snorby return (0); 431ddeeec14Snorby 432ddeeec14Snorby if (metric < rn->metric) { 433ddeeec14Snorby rn->metric = metric; 434ddeeec14Snorby rn->nexthop.s_addr = e->nexthop.s_addr; 435ddeeec14Snorby rn->ifindex = e->ifindex; 436ddeeec14Snorby rde_send_change_kroute(rn); 437ddeeec14Snorby triggered_update(rn); 438ddeeec14Snorby } else if (e->nexthop.s_addr == rn->nexthop.s_addr && 439960f8542Smichele metric > rn->metric) { 440ddeeec14Snorby rn->metric = metric; 441ddeeec14Snorby rde_send_change_kroute(rn); 442ddeeec14Snorby triggered_update(rn); 443960f8542Smichele if (rn->metric == INFINITY) 444960f8542Smichele route_start_garbage(rn); 445960f8542Smichele } else if (e->nexthop.s_addr != rn->nexthop.s_addr && 446960f8542Smichele metric == rn->metric) { 447960f8542Smichele /* If the new metric is the same as the old one, 448960f8542Smichele * examine the timeout for the existing route. If it 449960f8542Smichele * is at least halfway to the expiration point, switch 450960f8542Smichele * to the new route. 451960f8542Smichele */ 452960f8542Smichele timerclear(&tv); 453960f8542Smichele gettimeofday(&now, NULL); 454960f8542Smichele evtimer_pending(&rn->timeout_timer, &tv); 455960f8542Smichele if (tv.tv_sec - now.tv_sec < ROUTE_TIMEOUT / 2) { 456960f8542Smichele rn->nexthop.s_addr = e->nexthop.s_addr; 457960f8542Smichele rn->ifindex = e->ifindex; 458960f8542Smichele rde_send_change_kroute(rn); 459960f8542Smichele } 460ddeeec14Snorby } 461ddeeec14Snorby 462960f8542Smichele if (e->nexthop.s_addr == rn->nexthop.s_addr && 463960f8542Smichele rn->metric < INFINITY) 464ddeeec14Snorby route_reset_timers(rn); 465ddeeec14Snorby } 466ddeeec14Snorby 467ddeeec14Snorby return (0); 468ddeeec14Snorby } 469ddeeec14Snorby 470ddeeec14Snorby void 471ddeeec14Snorby triggered_update(struct rt_node *rn) 472ddeeec14Snorby { 473ddeeec14Snorby struct rip_route rr; 474ddeeec14Snorby 475ddeeec14Snorby rr.address.s_addr = rn->prefix.s_addr; 476ddeeec14Snorby rr.mask.s_addr = rn->netmask.s_addr; 477ddeeec14Snorby rr.nexthop.s_addr = rn->nexthop.s_addr; 478ddeeec14Snorby rr.metric = rn->metric; 479ddeeec14Snorby rr.ifindex = rn->ifindex; 480ddeeec14Snorby 481ddeeec14Snorby rde_imsg_compose_ripe(IMSG_SEND_TRIGGERED_UPDATE, 0, 0, &rr, 482ddeeec14Snorby sizeof(struct rip_route)); 483ddeeec14Snorby } 484