1*f1b790a5Sclaudio /* $OpenBSD: ospf6d.c,v 1.61 2024/11/21 13:38:14 claudio Exp $ */ 2a1a4e97bSnorby 3a1a4e97bSnorby /* 4a1a4e97bSnorby * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5a1a4e97bSnorby * Copyright (c) 2004, 2007 Esben Norby <norby@openbsd.org> 6a1a4e97bSnorby * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 7a1a4e97bSnorby * 8a1a4e97bSnorby * Permission to use, copy, modify, and distribute this software for any 9a1a4e97bSnorby * purpose with or without fee is hereby granted, provided that the above 10a1a4e97bSnorby * copyright notice and this permission notice appear in all copies. 11a1a4e97bSnorby * 12a1a4e97bSnorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13a1a4e97bSnorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14a1a4e97bSnorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15a1a4e97bSnorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16a1a4e97bSnorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17a1a4e97bSnorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18a1a4e97bSnorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19a1a4e97bSnorby */ 20a1a4e97bSnorby 21a1a4e97bSnorby #include <sys/types.h> 22a1a4e97bSnorby #include <sys/socket.h> 23a1a4e97bSnorby #include <sys/queue.h> 24a1a4e97bSnorby #include <sys/time.h> 25a1a4e97bSnorby #include <sys/stat.h> 26a1a4e97bSnorby #include <sys/wait.h> 27a1a4e97bSnorby #include <sys/sysctl.h> 28189fd1ceSbenno #include <syslog.h> 29a1a4e97bSnorby 30a1a4e97bSnorby #include <netinet/in.h> 31a1a4e97bSnorby #include <arpa/inet.h> 32a66c91f2Sremi #include <net/if_types.h> 33a1a4e97bSnorby 34a1a4e97bSnorby #include <event.h> 35a1a4e97bSnorby #include <err.h> 36a1a4e97bSnorby #include <errno.h> 37a1a4e97bSnorby #include <pwd.h> 38a1a4e97bSnorby #include <stdio.h> 39a1a4e97bSnorby #include <stdlib.h> 40a1a4e97bSnorby #include <string.h> 41a1a4e97bSnorby #include <signal.h> 42a1a4e97bSnorby #include <unistd.h> 43a1a4e97bSnorby 44a1a4e97bSnorby #include "ospf6d.h" 45a1a4e97bSnorby #include "ospf6.h" 46a1a4e97bSnorby #include "ospfe.h" 47a1a4e97bSnorby #include "control.h" 48a1a4e97bSnorby #include "log.h" 49a1a4e97bSnorby #include "rde.h" 50a1a4e97bSnorby 51a1a4e97bSnorby void main_sig_handler(int, short, void *); 52a1a4e97bSnorby __dead void usage(void); 53ee103ef4Srenato __dead void ospfd_shutdown(void); 54a1a4e97bSnorby 55a1a4e97bSnorby void main_dispatch_ospfe(int, short, void *); 56a1a4e97bSnorby void main_dispatch_rde(int, short, void *); 57a1a4e97bSnorby 58a1a4e97bSnorby int ospf_reload(void); 59a1a4e97bSnorby int ospf_sendboth(enum imsg_type, void *, u_int16_t); 60a1a4e97bSnorby int merge_interfaces(struct area *, struct area *); 61a1a4e97bSnorby struct iface *iface_lookup(struct area *, struct iface *); 62a1a4e97bSnorby 63a1a4e97bSnorby int pipe_parent2ospfe[2]; 64a1a4e97bSnorby int pipe_parent2rde[2]; 65a1a4e97bSnorby int pipe_ospfe2rde[2]; 66a1a4e97bSnorby 6778c7f53fSclaudio enum ospfd_process ospfd_process; 68a1a4e97bSnorby struct ospfd_conf *ospfd_conf = NULL; 69ccbb71f5Sclaudio static struct imsgev *iev_ospfe; 70ccbb71f5Sclaudio static struct imsgev *iev_rde; 71a1a4e97bSnorby char *conffile; 72a1a4e97bSnorby 73a1a4e97bSnorby pid_t ospfe_pid = 0; 74a1a4e97bSnorby pid_t rde_pid = 0; 75a1a4e97bSnorby 76a1a4e97bSnorby void 77a1a4e97bSnorby main_sig_handler(int sig, short event, void *arg) 78a1a4e97bSnorby { 79ee103ef4Srenato /* signal handler rules don't apply, libevent decouples for us */ 80a1a4e97bSnorby switch (sig) { 81a1a4e97bSnorby case SIGTERM: 82a1a4e97bSnorby case SIGINT: 83a1a4e97bSnorby ospfd_shutdown(); 84ee103ef4Srenato /* NOTREACHED */ 85a1a4e97bSnorby case SIGHUP: 86a1a4e97bSnorby if (ospf_reload() == -1) 87a1a4e97bSnorby log_warnx("configuration reload failed"); 88a1a4e97bSnorby else 89a1a4e97bSnorby log_debug("configuration reloaded"); 90a1a4e97bSnorby break; 91a1a4e97bSnorby default: 92a1a4e97bSnorby fatalx("unexpected signal"); 93a1a4e97bSnorby /* NOTREACHED */ 94a1a4e97bSnorby } 95a1a4e97bSnorby } 96a1a4e97bSnorby 97a1a4e97bSnorby __dead void 98a1a4e97bSnorby usage(void) 99a1a4e97bSnorby { 100a1a4e97bSnorby extern char *__progname; 101a1a4e97bSnorby 102c2ca8945Ssthen fprintf(stderr, "usage: %s [-dnv] [-D macro=value]" 103c2ca8945Ssthen " [-f file] [-s socket]\n", 104e5b5b453Sclaudio __progname); 105a1a4e97bSnorby exit(1); 106a1a4e97bSnorby } 107a1a4e97bSnorby 108a1a4e97bSnorby int 109a1a4e97bSnorby main(int argc, char *argv[]) 110a1a4e97bSnorby { 111ee103ef4Srenato struct event ev_sigint, ev_sigterm, ev_sighup; 112a1a4e97bSnorby int ch, opts = 0; 113a1a4e97bSnorby int debug = 0; 114a1a4e97bSnorby int ipforwarding; 115a1a4e97bSnorby int mib[4]; 116a1a4e97bSnorby size_t len; 1175d393f89Sremi char *sockname = NULL; 118cb75d791Sremi int control_fd; 119a1a4e97bSnorby 120a1a4e97bSnorby conffile = CONF_FILE; 121a1a4e97bSnorby ospfd_process = PROC_MAIN; 122a1a4e97bSnorby 123189fd1ceSbenno log_init(1, LOG_DAEMON); /* log to stderr until daemonized */ 124189fd1ceSbenno log_procinit(log_procnames[ospfd_process]); 1256fa930c9Spyr 126c2ca8945Ssthen while ((ch = getopt(argc, argv, "cdD:f:s:nv")) != -1) { 127a1a4e97bSnorby switch (ch) { 128a1a4e97bSnorby case 'c': 129a1a4e97bSnorby opts |= OSPFD_OPT_FORCE_DEMOTE; 130a1a4e97bSnorby break; 131a1a4e97bSnorby case 'd': 132a1a4e97bSnorby debug = 1; 133a1a4e97bSnorby break; 134e5b5b453Sclaudio case 'D': 135e5b5b453Sclaudio if (cmdline_symset(optarg) < 0) 136e5b5b453Sclaudio log_warnx("could not parse macro definition %s", 137e5b5b453Sclaudio optarg); 138e5b5b453Sclaudio break; 139a1a4e97bSnorby case 'f': 140a1a4e97bSnorby conffile = optarg; 141a1a4e97bSnorby break; 142a1a4e97bSnorby case 'n': 143a1a4e97bSnorby opts |= OSPFD_OPT_NOACTION; 144a1a4e97bSnorby break; 145c2ca8945Ssthen case 's': 146c2ca8945Ssthen sockname = optarg; 147c2ca8945Ssthen break; 148a1a4e97bSnorby case 'v': 149a1a4e97bSnorby if (opts & OSPFD_OPT_VERBOSE) 150a1a4e97bSnorby opts |= OSPFD_OPT_VERBOSE2; 151a1a4e97bSnorby opts |= OSPFD_OPT_VERBOSE; 152189fd1ceSbenno log_setverbose(1); 153a1a4e97bSnorby break; 154a1a4e97bSnorby default: 155a1a4e97bSnorby usage(); 156a1a4e97bSnorby /* NOTREACHED */ 157a1a4e97bSnorby } 158a1a4e97bSnorby } 159a1a4e97bSnorby 160fde55bc4Spyr argc -= optind; 161fde55bc4Spyr argv += optind; 162fde55bc4Spyr if (argc > 0) 163fde55bc4Spyr usage(); 164fde55bc4Spyr 165a1a4e97bSnorby mib[0] = CTL_NET; 166a1a4e97bSnorby mib[1] = PF_INET6; 167a1a4e97bSnorby mib[2] = IPPROTO_IPV6; 168a1a4e97bSnorby mib[3] = IPCTL_FORWARDING; 169a1a4e97bSnorby len = sizeof(ipforwarding); 170a1a4e97bSnorby if (sysctl(mib, 4, &ipforwarding, &len, NULL, 0) == -1) 171a1a4e97bSnorby err(1, "sysctl"); 172a1a4e97bSnorby 173a1a4e97bSnorby if (ipforwarding != 1) { 174a1a4e97bSnorby log_warnx("WARNING: IPv6 forwarding NOT enabled, " 175a1a4e97bSnorby "running as stub router"); 176a1a4e97bSnorby opts |= OSPFD_OPT_STUB_ROUTER; 177a1a4e97bSnorby } 178a1a4e97bSnorby 1796c9e7a5bSclaudio /* prepare and fetch interfaces early */ 1806c9e7a5bSclaudio if_init(); 181a1a4e97bSnorby 182a1a4e97bSnorby /* parse config file */ 183a1a4e97bSnorby if ((ospfd_conf = parse_config(conffile, opts)) == NULL ) 184a1a4e97bSnorby exit(1); 1855d393f89Sremi 1865d393f89Sremi if (sockname == NULL) { 1875d393f89Sremi if (asprintf(&sockname, "%s.%d", OSPF6D_SOCKET, 1885d393f89Sremi ospfd_conf->rdomain) == -1) 1895d393f89Sremi err(1, "asprintf"); 1905d393f89Sremi } 1915d393f89Sremi 192c2ca8945Ssthen ospfd_conf->csock = sockname; 193a1a4e97bSnorby 194a1a4e97bSnorby if (ospfd_conf->opts & OSPFD_OPT_NOACTION) { 195a1a4e97bSnorby if (ospfd_conf->opts & OSPFD_OPT_VERBOSE) 196a1a4e97bSnorby print_config(ospfd_conf); 197a1a4e97bSnorby else 198a1a4e97bSnorby fprintf(stderr, "configuration OK\n"); 199a1a4e97bSnorby exit(0); 200a1a4e97bSnorby } 201a1a4e97bSnorby 202a1a4e97bSnorby /* check for root privileges */ 203a1a4e97bSnorby if (geteuid()) 204a1a4e97bSnorby errx(1, "need root privileges"); 205a1a4e97bSnorby 206a1a4e97bSnorby /* check for ospfd user */ 207a1a4e97bSnorby if (getpwnam(OSPF6D_USER) == NULL) 208a1a4e97bSnorby errx(1, "unknown user %s", OSPF6D_USER); 209a1a4e97bSnorby 210189fd1ceSbenno log_init(debug, LOG_DAEMON); 211189fd1ceSbenno log_setverbose(ospfd_conf->opts & OSPFD_OPT_VERBOSE); 2126fa930c9Spyr 213cb75d791Sremi if ((control_check(ospfd_conf->csock)) == -1) 2140347b698Sflorian fatalx("ospf6d already running"); 215cb75d791Sremi 216a1a4e97bSnorby if (!debug) 217a1a4e97bSnorby daemon(1, 0); 218a1a4e97bSnorby 219a1a4e97bSnorby log_info("startup"); 220a1a4e97bSnorby 22135251ca5Sclaudio if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 22235251ca5Sclaudio PF_UNSPEC, pipe_parent2ospfe) == -1) 223a1a4e97bSnorby fatal("socketpair"); 22435251ca5Sclaudio if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 22535251ca5Sclaudio PF_UNSPEC, pipe_parent2rde) == -1) 226a1a4e97bSnorby fatal("socketpair"); 22735251ca5Sclaudio if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 22835251ca5Sclaudio PF_UNSPEC, pipe_ospfe2rde) == -1) 229a1a4e97bSnorby fatal("socketpair"); 230a1a4e97bSnorby 231a1a4e97bSnorby /* start children */ 232a1a4e97bSnorby rde_pid = rde(ospfd_conf, pipe_parent2rde, pipe_ospfe2rde, 233a1a4e97bSnorby pipe_parent2ospfe); 234a1a4e97bSnorby ospfe_pid = ospfe(ospfd_conf, pipe_parent2ospfe, pipe_ospfe2rde, 235a1a4e97bSnorby pipe_parent2rde); 236a1a4e97bSnorby 237a1a4e97bSnorby event_init(); 238a1a4e97bSnorby 239a1a4e97bSnorby /* setup signal handler */ 240a1a4e97bSnorby signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 241a1a4e97bSnorby signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 242a1a4e97bSnorby signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); 243a1a4e97bSnorby signal_add(&ev_sigint, NULL); 244a1a4e97bSnorby signal_add(&ev_sigterm, NULL); 245a1a4e97bSnorby signal_add(&ev_sighup, NULL); 246a1a4e97bSnorby signal(SIGPIPE, SIG_IGN); 247a1a4e97bSnorby 248a1a4e97bSnorby /* setup pipes to children */ 249a1a4e97bSnorby close(pipe_parent2ospfe[1]); 250a1a4e97bSnorby close(pipe_parent2rde[1]); 251a1a4e97bSnorby close(pipe_ospfe2rde[0]); 252a1a4e97bSnorby close(pipe_ospfe2rde[1]); 253a1a4e97bSnorby 254f78850efSeric if ((iev_ospfe = malloc(sizeof(struct imsgev))) == NULL || 255f78850efSeric (iev_rde = malloc(sizeof(struct imsgev))) == NULL) 256a1a4e97bSnorby fatal(NULL); 257*f1b790a5Sclaudio if (imsgbuf_init(&iev_ospfe->ibuf, pipe_parent2ospfe[0]) == -1) 258*f1b790a5Sclaudio fatal(NULL); 259*f1b790a5Sclaudio imsgbuf_allow_fdpass(&iev_ospfe->ibuf); 260f78850efSeric iev_ospfe->handler = main_dispatch_ospfe; 261*f1b790a5Sclaudio if (imsgbuf_init(&iev_rde->ibuf, pipe_parent2rde[0]) == -1) 262*f1b790a5Sclaudio fatal(NULL); 263f78850efSeric iev_rde->handler = main_dispatch_rde; 264a1a4e97bSnorby 265a1a4e97bSnorby /* setup event handler */ 266f78850efSeric iev_ospfe->events = EV_READ; 267f78850efSeric event_set(&iev_ospfe->ev, iev_ospfe->ibuf.fd, iev_ospfe->events, 268f78850efSeric iev_ospfe->handler, iev_ospfe); 269f78850efSeric event_add(&iev_ospfe->ev, NULL); 270a1a4e97bSnorby 271f78850efSeric iev_rde->events = EV_READ; 272f78850efSeric event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events, 273f78850efSeric iev_rde->handler, iev_rde); 274f78850efSeric event_add(&iev_rde->ev, NULL); 275a1a4e97bSnorby 276cb75d791Sremi if ((control_fd = control_init(ospfd_conf->csock)) == -1) 277cb75d791Sremi fatalx("control socket setup failed"); 278cb75d791Sremi main_imsg_compose_ospfe_fd(IMSG_CONTROLFD, 0, control_fd); 279cb75d791Sremi 280faef135eSremi /* no filesystem visibility */ 281faef135eSremi if (unveil("/", "") == -1) 282025f8c0aSderaadt fatal("unveil /"); 28327dccea9Sremi if (unveil(NULL, NULL) == -1) 28427dccea9Sremi fatal("unveil"); 28527dccea9Sremi 2865d393f89Sremi if (kr_init(!(ospfd_conf->flags & OSPFD_FLAG_NO_FIB_UPDATE), 2874cf51530Sdenis ospfd_conf->rdomain, ospfd_conf->redist_label_or_prefix, 2884cf51530Sdenis ospfd_conf->fib_priority) == -1) 289a1a4e97bSnorby fatalx("kr_init failed"); 290a1a4e97bSnorby 291a1a4e97bSnorby event_dispatch(); 292a1a4e97bSnorby 293a1a4e97bSnorby ospfd_shutdown(); 294a1a4e97bSnorby /* NOTREACHED */ 295a1a4e97bSnorby return (0); 296a1a4e97bSnorby } 297a1a4e97bSnorby 298ee103ef4Srenato __dead void 299a1a4e97bSnorby ospfd_shutdown(void) 300a1a4e97bSnorby { 301a1a4e97bSnorby pid_t pid; 302ee103ef4Srenato int status; 303a1a4e97bSnorby 304ee103ef4Srenato /* close pipes */ 3059cbf9e90Sclaudio imsgbuf_clear(&iev_ospfe->ibuf); 306ee103ef4Srenato close(iev_ospfe->ibuf.fd); 3079cbf9e90Sclaudio imsgbuf_clear(&iev_rde->ibuf); 308ee103ef4Srenato close(iev_rde->ibuf.fd); 309a1a4e97bSnorby 310faef135eSremi control_cleanup(); 311a1a4e97bSnorby kr_shutdown(); 312a1a4e97bSnorby carp_demote_shutdown(); 313a1a4e97bSnorby 314ee103ef4Srenato log_debug("waiting for children to terminate"); 315a1a4e97bSnorby do { 316ee103ef4Srenato pid = wait(&status); 317ee103ef4Srenato if (pid == -1) { 318ee103ef4Srenato if (errno != EINTR && errno != ECHILD) 319a1a4e97bSnorby fatal("wait"); 320ee103ef4Srenato } else if (WIFSIGNALED(status)) 321ee103ef4Srenato log_warnx("%s terminated; signal %d", 322ee103ef4Srenato (pid == rde_pid) ? "route decision engine" : 323ee103ef4Srenato "ospf engine", WTERMSIG(status)); 324a1a4e97bSnorby } while (pid != -1 || (pid == -1 && errno == EINTR)); 325a1a4e97bSnorby 326f78850efSeric free(iev_ospfe); 327f78850efSeric free(iev_rde); 328a1a4e97bSnorby free(ospfd_conf); 329a1a4e97bSnorby 330a1a4e97bSnorby log_info("terminating"); 331a1a4e97bSnorby exit(0); 332a1a4e97bSnorby } 333a1a4e97bSnorby 334a1a4e97bSnorby /* imsg handling */ 335a1a4e97bSnorby void 336a1a4e97bSnorby main_dispatch_ospfe(int fd, short event, void *bula) 337a1a4e97bSnorby { 338f78850efSeric struct imsgev *iev = bula; 339f78850efSeric struct imsgbuf *ibuf = &iev->ibuf; 340a1a4e97bSnorby struct imsg imsg; 341a1a4e97bSnorby struct demote_msg dmsg; 342a1a4e97bSnorby ssize_t n; 343a97e7964Sclaudio int shut = 0, verbose; 344a1a4e97bSnorby 34541e7b05eSclaudio if (event & EV_READ) { 346668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 347dd7efffeSclaudio fatal("imsgbuf_read error"); 348a1a4e97bSnorby if (n == 0) /* connection closed */ 349a1a4e97bSnorby shut = 1; 35041e7b05eSclaudio } 35141e7b05eSclaudio if (event & EV_WRITE) { 352dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 353c1aa9554Sclaudio if (errno == EPIPE) /* connection closed */ 3541203692fSkrw shut = 1; 355c1aa9554Sclaudio else 356dd7efffeSclaudio fatal("imsgbuf_write"); 357c1aa9554Sclaudio } 358a1a4e97bSnorby } 359a1a4e97bSnorby 360a1a4e97bSnorby for (;;) { 361a1a4e97bSnorby if ((n = imsg_get(ibuf, &imsg)) == -1) 362a1a4e97bSnorby fatal("imsg_get"); 363a1a4e97bSnorby 364a1a4e97bSnorby if (n == 0) 365a1a4e97bSnorby break; 366a1a4e97bSnorby 367a1a4e97bSnorby switch (imsg.hdr.type) { 368a1a4e97bSnorby case IMSG_CTL_RELOAD: 369a1a4e97bSnorby if (ospf_reload() == -1) 370a1a4e97bSnorby log_warnx("configuration reload failed"); 371a1a4e97bSnorby else 372a1a4e97bSnorby log_debug("configuration reloaded"); 373a1a4e97bSnorby break; 374a1a4e97bSnorby case IMSG_CTL_FIB_COUPLE: 375a1a4e97bSnorby kr_fib_couple(); 376a1a4e97bSnorby break; 377a1a4e97bSnorby case IMSG_CTL_FIB_DECOUPLE: 378a1a4e97bSnorby kr_fib_decouple(); 379a1a4e97bSnorby break; 380dd3b9a80Ssthen case IMSG_CTL_FIB_RELOAD: 381dd3b9a80Ssthen kr_fib_reload(); 382dd3b9a80Ssthen break; 383a1a4e97bSnorby case IMSG_CTL_KROUTE: 384a1a4e97bSnorby case IMSG_CTL_KROUTE_ADDR: 385a1a4e97bSnorby kr_show_route(&imsg); 386a1a4e97bSnorby break; 387a1a4e97bSnorby case IMSG_DEMOTE: 388a1a4e97bSnorby if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(dmsg)) 389a1a4e97bSnorby fatalx("invalid size of OE request"); 390a1a4e97bSnorby memcpy(&dmsg, imsg.data, sizeof(dmsg)); 391a1a4e97bSnorby carp_demote_set(dmsg.demote_group, dmsg.level); 392a1a4e97bSnorby break; 393a97e7964Sclaudio case IMSG_CTL_LOG_VERBOSE: 394a97e7964Sclaudio /* already checked by ospfe */ 395a97e7964Sclaudio memcpy(&verbose, imsg.data, sizeof(verbose)); 396189fd1ceSbenno log_setverbose(verbose); 397a97e7964Sclaudio break; 398a1a4e97bSnorby default: 399a1a4e97bSnorby log_debug("main_dispatch_ospfe: error handling imsg %d", 400a1a4e97bSnorby imsg.hdr.type); 401a1a4e97bSnorby break; 402a1a4e97bSnorby } 403a1a4e97bSnorby imsg_free(&imsg); 404a1a4e97bSnorby } 405a1a4e97bSnorby if (!shut) 406f78850efSeric imsg_event_add(iev); 407a1a4e97bSnorby else { 408a1a4e97bSnorby /* this pipe is dead, so remove the event handler */ 409f78850efSeric event_del(&iev->ev); 410a1a4e97bSnorby event_loopexit(NULL); 411a1a4e97bSnorby } 412a1a4e97bSnorby } 413a1a4e97bSnorby 414a1a4e97bSnorby void 415a1a4e97bSnorby main_dispatch_rde(int fd, short event, void *bula) 416a1a4e97bSnorby { 417f78850efSeric struct imsgev *iev = bula; 418f78850efSeric struct imsgbuf *ibuf = &iev->ibuf; 419a1a4e97bSnorby struct imsg imsg; 420a1a4e97bSnorby ssize_t n; 421722a4e30Sfriehm int count, shut = 0; 422a1a4e97bSnorby 42341e7b05eSclaudio if (event & EV_READ) { 424668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 425dd7efffeSclaudio fatal("imsgbuf_read error"); 426a1a4e97bSnorby if (n == 0) /* connection closed */ 427a1a4e97bSnorby shut = 1; 42841e7b05eSclaudio } 42941e7b05eSclaudio if (event & EV_WRITE) { 430dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 431c1aa9554Sclaudio if (errno == EPIPE) /* connection closed */ 4321203692fSkrw shut = 1; 433c1aa9554Sclaudio else 434dd7efffeSclaudio fatal("imsgbuf_write"); 435c1aa9554Sclaudio } 436a1a4e97bSnorby } 437a1a4e97bSnorby 438a1a4e97bSnorby for (;;) { 439a1a4e97bSnorby if ((n = imsg_get(ibuf, &imsg)) == -1) 440a1a4e97bSnorby fatal("imsg_get"); 441a1a4e97bSnorby 442a1a4e97bSnorby if (n == 0) 443a1a4e97bSnorby break; 444a1a4e97bSnorby 445a1a4e97bSnorby switch (imsg.hdr.type) { 446a1a4e97bSnorby case IMSG_KROUTE_CHANGE: 447722a4e30Sfriehm count = (imsg.hdr.len - IMSG_HEADER_SIZE) / 448722a4e30Sfriehm sizeof(struct kroute); 449722a4e30Sfriehm if (kr_change(imsg.data, count)) 450a1a4e97bSnorby log_warn("main_dispatch_rde: error changing " 451a1a4e97bSnorby "route"); 452a1a4e97bSnorby break; 453a1a4e97bSnorby case IMSG_KROUTE_DELETE: 454a1a4e97bSnorby if (kr_delete(imsg.data)) 455a1a4e97bSnorby log_warn("main_dispatch_rde: error deleting " 456a1a4e97bSnorby "route"); 457a1a4e97bSnorby break; 458a1a4e97bSnorby default: 459a1a4e97bSnorby log_debug("main_dispatch_rde: error handling imsg %d", 460a1a4e97bSnorby imsg.hdr.type); 461a1a4e97bSnorby break; 462a1a4e97bSnorby } 463a1a4e97bSnorby imsg_free(&imsg); 464a1a4e97bSnorby } 465a1a4e97bSnorby if (!shut) 466f78850efSeric imsg_event_add(iev); 467a1a4e97bSnorby else { 468a1a4e97bSnorby /* this pipe is dead, so remove the event handler */ 469f78850efSeric event_del(&iev->ev); 470a1a4e97bSnorby event_loopexit(NULL); 471a1a4e97bSnorby } 472a1a4e97bSnorby } 473a1a4e97bSnorby 474a1a4e97bSnorby void 475a1a4e97bSnorby main_imsg_compose_ospfe(int type, pid_t pid, void *data, u_int16_t datalen) 476a1a4e97bSnorby { 4778e1674f3Sbluhm if (iev_ospfe == NULL) 4788e1674f3Sbluhm return; 479f78850efSeric imsg_compose_event(iev_ospfe, type, 0, pid, -1, data, datalen); 480a1a4e97bSnorby } 481a1a4e97bSnorby 482a1a4e97bSnorby void 483cb75d791Sremi main_imsg_compose_ospfe_fd(int type, pid_t pid, int fd) 484cb75d791Sremi { 485cb75d791Sremi if (iev_ospfe == NULL) 486cb75d791Sremi return; 487cb75d791Sremi imsg_compose_event(iev_ospfe, type, 0, pid, fd, NULL, 0); 488cb75d791Sremi } 489cb75d791Sremi 490cb75d791Sremi void 491a1a4e97bSnorby main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen) 492a1a4e97bSnorby { 493787da5a7Sbluhm if (iev_rde == NULL) 494787da5a7Sbluhm return; 495f78850efSeric imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen); 496a1a4e97bSnorby } 497a1a4e97bSnorby 498a1a4e97bSnorby void 499f78850efSeric imsg_event_add(struct imsgev *iev) 500a1a4e97bSnorby { 501f78850efSeric iev->events = EV_READ; 50231be28caSclaudio if (imsgbuf_queuelen(&iev->ibuf) > 0) 503f78850efSeric iev->events |= EV_WRITE; 504a1a4e97bSnorby 505f78850efSeric event_del(&iev->ev); 506f78850efSeric event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 507f78850efSeric event_add(&iev->ev, NULL); 508f78850efSeric } 509f78850efSeric 510f78850efSeric int 511f78850efSeric imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, 512f78850efSeric pid_t pid, int fd, void *data, u_int16_t datalen) 513f78850efSeric { 514f78850efSeric int ret; 515f78850efSeric 516f78850efSeric if ((ret = imsg_compose(&iev->ibuf, type, peerid, 517f78850efSeric pid, fd, data, datalen)) != -1) 518f78850efSeric imsg_event_add(iev); 519f78850efSeric return (ret); 520a1a4e97bSnorby } 521a1a4e97bSnorby 522a1a4e97bSnorby int 523a1a4e97bSnorby ospf_redistribute(struct kroute *kr, u_int32_t *metric) 524a1a4e97bSnorby { 525a1a4e97bSnorby struct redistribute *r; 526f8efa005Sclaudio struct in6_addr ina, inb; 527a66c91f2Sremi struct iface *iface; 52893c5cf97Sbluhm u_int8_t is_default = 0; 529a66c91f2Sremi int depend_ok; 530a1a4e97bSnorby 53193c5cf97Sbluhm /* only allow ::/0 via REDIST_DEFAULT */ 532f8efa005Sclaudio if (IN6_IS_ADDR_UNSPECIFIED(&kr->prefix) && kr->prefixlen == 0) 53393c5cf97Sbluhm is_default = 1; 534a1a4e97bSnorby 535a1a4e97bSnorby SIMPLEQ_FOREACH(r, &ospfd_conf->redist_list, entry) { 536a66c91f2Sremi if (r->dependon[0] != '\0') { 537a66c91f2Sremi if ((iface = if_findname(r->dependon))) 538a66c91f2Sremi depend_ok = ifstate_is_up(iface); 539a66c91f2Sremi else 540a66c91f2Sremi depend_ok = 0; 541a66c91f2Sremi } else 542a66c91f2Sremi depend_ok = 1; 543a66c91f2Sremi 544a1a4e97bSnorby switch (r->type & ~REDIST_NO) { 545a1a4e97bSnorby case REDIST_LABEL: 546a1a4e97bSnorby if (kr->rtlabel == r->label) { 54717e34b32Sremi *metric = depend_ok ? r->metric : 54817e34b32Sremi r->metric | MAX_METRIC; 549a1a4e97bSnorby return (r->type & REDIST_NO ? 0 : 1); 550a1a4e97bSnorby } 551a1a4e97bSnorby break; 552a1a4e97bSnorby case REDIST_STATIC: 553a1a4e97bSnorby /* 554a1a4e97bSnorby * Dynamic routes are not redistributable. Placed here 555a1a4e97bSnorby * so that link local addresses can be redistributed 556a1a4e97bSnorby * via a rtlabel. 557a1a4e97bSnorby */ 55893c5cf97Sbluhm if (is_default) 55993c5cf97Sbluhm continue; 560a1a4e97bSnorby if (kr->flags & F_DYNAMIC) 561a1a4e97bSnorby continue; 562a1a4e97bSnorby if (kr->flags & F_STATIC) { 56317e34b32Sremi *metric = depend_ok ? r->metric : 56417e34b32Sremi r->metric | MAX_METRIC; 565a1a4e97bSnorby return (r->type & REDIST_NO ? 0 : 1); 566a1a4e97bSnorby } 567a1a4e97bSnorby break; 568a1a4e97bSnorby case REDIST_CONNECTED: 56993c5cf97Sbluhm if (is_default) 57093c5cf97Sbluhm continue; 571a1a4e97bSnorby if (kr->flags & F_DYNAMIC) 572a1a4e97bSnorby continue; 573a1a4e97bSnorby if (kr->flags & F_CONNECTED) { 57417e34b32Sremi *metric = depend_ok ? r->metric : 57517e34b32Sremi r->metric | MAX_METRIC; 576a1a4e97bSnorby return (r->type & REDIST_NO ? 0 : 1); 577a1a4e97bSnorby } 578a1a4e97bSnorby break; 579a1a4e97bSnorby case REDIST_ADDR: 580a1a4e97bSnorby if (kr->flags & F_DYNAMIC) 581a1a4e97bSnorby continue; 58293c5cf97Sbluhm 58393c5cf97Sbluhm if (IN6_IS_ADDR_UNSPECIFIED(&r->addr) && 58493c5cf97Sbluhm r->prefixlen == 0) { 58593c5cf97Sbluhm if (is_default) { 586a66c91f2Sremi *metric = depend_ok ? r->metric : 58717e34b32Sremi r->metric | MAX_METRIC; 58893c5cf97Sbluhm return (r->type & REDIST_NO ? 0 : 1); 58993c5cf97Sbluhm } else 59093c5cf97Sbluhm return (0); 59193c5cf97Sbluhm } 59293c5cf97Sbluhm 59393c5cf97Sbluhm inet6applymask(&ina, &kr->prefix, r->prefixlen); 594f8efa005Sclaudio inet6applymask(&inb, &r->addr, r->prefixlen); 595f8efa005Sclaudio if (IN6_ARE_ADDR_EQUAL(&ina, &inb) && 596f8efa005Sclaudio kr->prefixlen >= r->prefixlen) { 59717e34b32Sremi *metric = depend_ok ? r->metric : 59817e34b32Sremi r->metric | MAX_METRIC; 599a1a4e97bSnorby return (r->type & REDIST_NO ? 0 : 1); 600a1a4e97bSnorby } 601a1a4e97bSnorby break; 60293c5cf97Sbluhm case REDIST_DEFAULT: 60393c5cf97Sbluhm if (is_default) { 60417e34b32Sremi *metric = depend_ok ? r->metric : 60517e34b32Sremi r->metric | MAX_METRIC; 60693c5cf97Sbluhm return (r->type & REDIST_NO ? 0 : 1); 60793c5cf97Sbluhm } 60893c5cf97Sbluhm break; 609a1a4e97bSnorby } 610a1a4e97bSnorby } 611a1a4e97bSnorby 612a1a4e97bSnorby return (0); 613a1a4e97bSnorby } 614a1a4e97bSnorby 615a1a4e97bSnorby int 616a1a4e97bSnorby ospf_reload(void) 617a1a4e97bSnorby { 6188bf9509aSjca #ifdef notyet 619a1a4e97bSnorby struct area *area; 620a1a4e97bSnorby struct ospfd_conf *xconf; 621a1a4e97bSnorby 622a1a4e97bSnorby if ((xconf = parse_config(conffile, ospfd_conf->opts)) == NULL) 623a1a4e97bSnorby return (-1); 624a1a4e97bSnorby 62544dcc3eeSjca /* XXX bail out if router-id changed */ 62644dcc3eeSjca 627a1a4e97bSnorby /* send config to childs */ 628a1a4e97bSnorby if (ospf_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 629a1a4e97bSnorby return (-1); 630a1a4e97bSnorby 6316c9e7a5bSclaudio /* send areas, interfaces happen out of band */ 632a1a4e97bSnorby LIST_FOREACH(area, &xconf->area_list, entry) { 633a1a4e97bSnorby if (ospf_sendboth(IMSG_RECONF_AREA, area, sizeof(*area)) == -1) 634a1a4e97bSnorby return (-1); 635a1a4e97bSnorby } 636a1a4e97bSnorby 637a1a4e97bSnorby if (ospf_sendboth(IMSG_RECONF_END, NULL, 0) == -1) 638a1a4e97bSnorby return (-1); 639a1a4e97bSnorby 6406c9e7a5bSclaudio /* XXX send newly available interfaces to the childs */ 6416c9e7a5bSclaudio 642a1a4e97bSnorby merge_config(ospfd_conf, xconf); 643a1a4e97bSnorby /* update redistribute lists */ 6444cf51530Sdenis kr_reload(ospfd_conf->redist_label_or_prefix); 645a1a4e97bSnorby return (0); 6468bf9509aSjca #else 6478bf9509aSjca return (-1); 6488bf9509aSjca #endif 649a1a4e97bSnorby } 650a1a4e97bSnorby 651a1a4e97bSnorby int 652a1a4e97bSnorby ospf_sendboth(enum imsg_type type, void *buf, u_int16_t len) 653a1a4e97bSnorby { 654f78850efSeric if (imsg_compose_event(iev_ospfe, type, 0, 0, -1, buf, len) == -1) 655a1a4e97bSnorby return (-1); 656f78850efSeric if (imsg_compose_event(iev_rde, type, 0, 0, -1, buf, len) == -1) 657a1a4e97bSnorby return (-1); 658a1a4e97bSnorby return (0); 659a1a4e97bSnorby } 660a1a4e97bSnorby 661a1a4e97bSnorby void 662a1a4e97bSnorby merge_config(struct ospfd_conf *conf, struct ospfd_conf *xconf) 663a1a4e97bSnorby { 664a1a4e97bSnorby struct area *a, *xa, *na; 665a1a4e97bSnorby struct iface *iface; 666a1a4e97bSnorby struct redistribute *r; 6674cf51530Sdenis int rchange = 0; 668a1a4e97bSnorby 669a1a4e97bSnorby /* change of rtr_id needs a restart */ 670a1a4e97bSnorby conf->flags = xconf->flags; 671a1a4e97bSnorby conf->spf_delay = xconf->spf_delay; 672a1a4e97bSnorby conf->spf_hold_time = xconf->spf_hold_time; 6734cf51530Sdenis if (SIMPLEQ_EMPTY(&conf->redist_list) != 6744cf51530Sdenis SIMPLEQ_EMPTY(&xconf->redist_list)) 6754cf51530Sdenis rchange = 1; 6764cf51530Sdenis conf->redist_label_or_prefix = xconf->redist_label_or_prefix; 677a1a4e97bSnorby 678a1a4e97bSnorby if (ospfd_process == PROC_MAIN) { 679a1a4e97bSnorby /* main process does neither use areas nor interfaces */ 680a1a4e97bSnorby while ((r = SIMPLEQ_FIRST(&conf->redist_list)) != NULL) { 681a1a4e97bSnorby SIMPLEQ_REMOVE_HEAD(&conf->redist_list, entry); 682a1a4e97bSnorby free(r); 683a1a4e97bSnorby } 68461b37dc2Sbket SIMPLEQ_CONCAT(&conf->redist_list, &xconf->redist_list); 6854cf51530Sdenis 6864cf51530Sdenis /* adjust FIB priority if changed */ 6874cf51530Sdenis if (conf->fib_priority != xconf->fib_priority) { 6884cf51530Sdenis kr_fib_decouple(); 6894cf51530Sdenis kr_fib_update_prio(xconf->fib_priority); 6904cf51530Sdenis conf->fib_priority = xconf->fib_priority; 6914cf51530Sdenis kr_fib_couple(); 6924cf51530Sdenis } 6934cf51530Sdenis 694a1a4e97bSnorby goto done; 695a1a4e97bSnorby } 696a1a4e97bSnorby 697a1a4e97bSnorby /* merge areas and interfaces */ 698a1a4e97bSnorby for (a = LIST_FIRST(&conf->area_list); a != NULL; a = na) { 699a1a4e97bSnorby na = LIST_NEXT(a, entry); 700a1a4e97bSnorby /* find deleted areas */ 701a1a4e97bSnorby if ((xa = area_find(xconf, a->id)) == NULL) { 702a1a4e97bSnorby if (ospfd_process == PROC_OSPF_ENGINE) { 703a1a4e97bSnorby LIST_FOREACH(iface, &a->iface_list, entry) 704a1a4e97bSnorby if_fsm(iface, IF_EVT_DOWN); 705a1a4e97bSnorby } 706a1a4e97bSnorby LIST_REMOVE(a, entry); 707a1a4e97bSnorby area_del(a); 708a1a4e97bSnorby } 709a1a4e97bSnorby } 710a1a4e97bSnorby 711a1a4e97bSnorby for (xa = LIST_FIRST(&xconf->area_list); xa != NULL; xa = na) { 712a1a4e97bSnorby na = LIST_NEXT(xa, entry); 713a1a4e97bSnorby if ((a = area_find(conf, xa->id)) == NULL) { 714a1a4e97bSnorby LIST_REMOVE(xa, entry); 715a1a4e97bSnorby LIST_INSERT_HEAD(&conf->area_list, xa, entry); 716a1a4e97bSnorby if (ospfd_process == PROC_OSPF_ENGINE) { 717a1a4e97bSnorby /* start interfaces */ 718a1a4e97bSnorby ospfe_demote_area(xa, 0); 7196c9e7a5bSclaudio LIST_FOREACH(iface, &xa->iface_list, entry) 7206c9e7a5bSclaudio if_start(conf, iface); 721a1a4e97bSnorby } 722a1a4e97bSnorby /* no need to merge interfaces */ 723a1a4e97bSnorby continue; 724a1a4e97bSnorby } 725a1a4e97bSnorby /* 726a1a4e97bSnorby * stub is not yet used but switching between stub and normal 727a1a4e97bSnorby * will be another painful job. 728a1a4e97bSnorby */ 729a1a4e97bSnorby a->stub = xa->stub; 730a1a4e97bSnorby a->stub_default_cost = xa->stub_default_cost; 731a1a4e97bSnorby if (ospfd_process == PROC_RDE_ENGINE) 732a1a4e97bSnorby a->dirty = 1; /* force SPF tree recalculation */ 733a1a4e97bSnorby 734a1a4e97bSnorby /* merge interfaces */ 735a1a4e97bSnorby if (merge_interfaces(a, xa) && 736a1a4e97bSnorby ospfd_process == PROC_OSPF_ENGINE) 737a1a4e97bSnorby a->dirty = 1; /* force rtr LSA update */ 738a1a4e97bSnorby } 739a1a4e97bSnorby 740a1a4e97bSnorby if (ospfd_process == PROC_OSPF_ENGINE) { 741a1a4e97bSnorby LIST_FOREACH(a, &conf->area_list, entry) { 742a1a4e97bSnorby LIST_FOREACH(iface, &a->iface_list, entry) { 743a1a4e97bSnorby if (iface->state == IF_STA_NEW) { 744a1a4e97bSnorby iface->state = IF_STA_DOWN; 7456c9e7a5bSclaudio if_start(conf, iface); 746a1a4e97bSnorby } 747a1a4e97bSnorby } 7485aa580cfSnaddy if (a->dirty || rchange) { 749a1a4e97bSnorby a->dirty = 0; 750d18517d2Sdenis orig_rtr_lsa(LIST_FIRST(&a->iface_list)->area); 751a1a4e97bSnorby } 752a1a4e97bSnorby } 753a1a4e97bSnorby } 754a1a4e97bSnorby 755a1a4e97bSnorby done: 756a1a4e97bSnorby while ((a = LIST_FIRST(&xconf->area_list)) != NULL) { 757a1a4e97bSnorby LIST_REMOVE(a, entry); 758a1a4e97bSnorby area_del(a); 759a1a4e97bSnorby } 760a1a4e97bSnorby free(xconf); 761a1a4e97bSnorby } 762a1a4e97bSnorby 763a1a4e97bSnorby int 764a1a4e97bSnorby merge_interfaces(struct area *a, struct area *xa) 765a1a4e97bSnorby { 766a1a4e97bSnorby struct iface *i, *xi, *ni; 767a1a4e97bSnorby int dirty = 0; 768a1a4e97bSnorby 769a1a4e97bSnorby /* problems: 770a1a4e97bSnorby * - new interfaces (easy) 771a1a4e97bSnorby * - deleted interfaces (needs to be done via fsm?) 772a1a4e97bSnorby * - changing passive (painful?) 773a1a4e97bSnorby */ 774a1a4e97bSnorby for (i = LIST_FIRST(&a->iface_list); i != NULL; i = ni) { 775a1a4e97bSnorby ni = LIST_NEXT(i, entry); 776a1a4e97bSnorby if (iface_lookup(xa, i) == NULL) { 77760657642Smichele log_debug("merge_interfaces: proc %d area %s removing " 778a1a4e97bSnorby "interface %s", ospfd_process, inet_ntoa(a->id), 779a1a4e97bSnorby i->name); 780a1a4e97bSnorby if (ospfd_process == PROC_OSPF_ENGINE) 781a1a4e97bSnorby if_fsm(i, IF_EVT_DOWN); 782a1a4e97bSnorby LIST_REMOVE(i, entry); 783a1a4e97bSnorby if_del(i); 784a1a4e97bSnorby } 785a1a4e97bSnorby } 786a1a4e97bSnorby 787a1a4e97bSnorby for (xi = LIST_FIRST(&xa->iface_list); xi != NULL; xi = ni) { 788a1a4e97bSnorby ni = LIST_NEXT(xi, entry); 789a1a4e97bSnorby if ((i = iface_lookup(a, xi)) == NULL) { 790a1a4e97bSnorby /* new interface but delay initialisation */ 79160657642Smichele log_debug("merge_interfaces: proc %d area %s adding " 792a1a4e97bSnorby "interface %s", ospfd_process, inet_ntoa(a->id), 793a1a4e97bSnorby xi->name); 794a1a4e97bSnorby LIST_REMOVE(xi, entry); 795a1a4e97bSnorby LIST_INSERT_HEAD(&a->iface_list, xi, entry); 796a1a4e97bSnorby if (ospfd_process == PROC_OSPF_ENGINE) 797a1a4e97bSnorby xi->state = IF_STA_NEW; 798a1a4e97bSnorby continue; 799a1a4e97bSnorby } 80060657642Smichele log_debug("merge_interfaces: proc %d area %s merging " 80160657642Smichele "interface %s", ospfd_process, inet_ntoa(a->id), i->name); 802a1a4e97bSnorby i->addr = xi->addr; 803a1a4e97bSnorby i->dst = xi->dst; 804a1a4e97bSnorby i->abr_id = xi->abr_id; 805a1a4e97bSnorby i->baudrate = xi->baudrate; 806a1a4e97bSnorby i->dead_interval = xi->dead_interval; 807a1a4e97bSnorby i->mtu = xi->mtu; 808a1a4e97bSnorby i->transmit_delay = xi->transmit_delay; 809a1a4e97bSnorby i->hello_interval = xi->hello_interval; 810a1a4e97bSnorby i->rxmt_interval = xi->rxmt_interval; 811a1a4e97bSnorby if (i->metric != xi->metric) 812a1a4e97bSnorby dirty = 1; 813a1a4e97bSnorby i->metric = xi->metric; 814a1a4e97bSnorby i->priority = xi->priority; 8154cf51530Sdenis if (i->self) 8164cf51530Sdenis i->self->priority = i->priority; 817a1a4e97bSnorby i->flags = xi->flags; /* needed? */ 818a1a4e97bSnorby i->type = xi->type; /* needed? */ 81918ffdd94Sstsp i->if_type = xi->if_type; /* needed? */ 820a1a4e97bSnorby i->linkstate = xi->linkstate; /* needed? */ 821a1a4e97bSnorby 8226c9e7a5bSclaudio #if 0 /* XXX needs some kind of love */ 823a1a4e97bSnorby if (i->passive != xi->passive) { 824a1a4e97bSnorby /* need to restart interface to cope with this change */ 825a1a4e97bSnorby if (ospfd_process == PROC_OSPF_ENGINE) 826a1a4e97bSnorby if_fsm(i, IF_EVT_DOWN); 827a1a4e97bSnorby i->passive = xi->passive; 828a1a4e97bSnorby if (ospfd_process == PROC_OSPF_ENGINE) 829a1a4e97bSnorby if_fsm(i, IF_EVT_UP); 830a1a4e97bSnorby } 8316c9e7a5bSclaudio #endif 832a1a4e97bSnorby } 833a1a4e97bSnorby return (dirty); 834a1a4e97bSnorby } 835a1a4e97bSnorby 836a1a4e97bSnorby struct iface * 837a1a4e97bSnorby iface_lookup(struct area *area, struct iface *iface) 838a1a4e97bSnorby { 839a1a4e97bSnorby struct iface *i; 840a1a4e97bSnorby 841a1a4e97bSnorby LIST_FOREACH(i, &area->iface_list, entry) 842a1a4e97bSnorby if (i->ifindex == iface->ifindex) 843a1a4e97bSnorby return (i); 844a1a4e97bSnorby return (NULL); 845a1a4e97bSnorby } 846a66c91f2Sremi 847a66c91f2Sremi int 848a66c91f2Sremi ifstate_is_up(struct iface *iface) 849a66c91f2Sremi { 850a66c91f2Sremi if (!(iface->flags & IFF_UP)) 851a66c91f2Sremi return (0); 852a66c91f2Sremi if (iface->if_type == IFT_CARP && 853a66c91f2Sremi iface->linkstate == LINK_STATE_UNKNOWN) 854a66c91f2Sremi return (0); 855a66c91f2Sremi return LINK_STATE_IS_UP(iface->linkstate); 856a66c91f2Sremi } 857