1 /* $OpenBSD: ospfe.c,v 1.61 2020/01/02 10:16:46 denis Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <sys/queue.h> 24 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 #include <net/if_types.h> 27 #include <stdlib.h> 28 #include <signal.h> 29 #include <string.h> 30 #include <fcntl.h> 31 #include <pwd.h> 32 #include <unistd.h> 33 #include <event.h> 34 #include <err.h> 35 #include <errno.h> 36 #include <stdio.h> 37 38 #include "ospf6.h" 39 #include "ospf6d.h" 40 #include "ospfe.h" 41 #include "rde.h" 42 #include "control.h" 43 #include "log.h" 44 45 void ospfe_sig_handler(int, short, void *); 46 __dead void ospfe_shutdown(void); 47 void orig_rtr_lsa_all(struct area *); 48 struct iface *find_vlink(struct abr_rtr *); 49 50 struct ospfd_conf *oeconf = NULL, *nconf; 51 struct imsgev *iev_main; 52 struct imsgev *iev_rde; 53 int oe_nofib; 54 55 /* ARGSUSED */ 56 void 57 ospfe_sig_handler(int sig, short event, void *bula) 58 { 59 switch (sig) { 60 case SIGINT: 61 case SIGTERM: 62 ospfe_shutdown(); 63 /* NOTREACHED */ 64 default: 65 fatalx("unexpected signal"); 66 } 67 } 68 69 /* ospf engine */ 70 pid_t 71 ospfe(struct ospfd_conf *xconf, int pipe_parent2ospfe[2], int pipe_ospfe2rde[2], 72 int pipe_parent2rde[2]) 73 { 74 struct area *area; 75 struct iface *iface; 76 struct passwd *pw; 77 struct event ev_sigint, ev_sigterm; 78 pid_t pid; 79 80 switch (pid = fork()) { 81 case -1: 82 fatal("cannot fork"); 83 case 0: 84 break; 85 default: 86 return (pid); 87 } 88 89 /* create the raw ip socket */ 90 if ((xconf->ospf_socket = socket(AF_INET6, 91 SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_OSPF)) == -1) 92 fatal("error creating raw socket"); 93 94 /* set some defaults */ 95 if (if_set_mcast_loop(xconf->ospf_socket) == -1) 96 fatal("if_set_mcast_loop"); 97 if (if_set_ipv6_checksum(xconf->ospf_socket) == -1) 98 fatal("if_set_ipv6_checksum"); 99 if (if_set_ipv6_pktinfo(xconf->ospf_socket, 1) == -1) 100 fatal("if_set_ipv6_pktinfo"); 101 if_set_sockbuf(xconf->ospf_socket); 102 103 oeconf = xconf; 104 if (oeconf->flags & OSPFD_FLAG_NO_FIB_UPDATE) 105 oe_nofib = 1; 106 107 if ((pw = getpwnam(OSPF6D_USER)) == NULL) 108 fatal("getpwnam"); 109 110 if (chroot(pw->pw_dir) == -1) 111 fatal("chroot"); 112 if (chdir("/") == -1) 113 fatal("chdir(\"/\")"); 114 115 setproctitle("ospf engine"); 116 /* 117 * XXX needed with fork+exec 118 * log_init(debug, LOG_DAEMON); 119 * log_setverbose(verbose); 120 */ 121 122 ospfd_process = PROC_OSPF_ENGINE; 123 log_procinit(log_procnames[ospfd_process]); 124 125 if (setgroups(1, &pw->pw_gid) || 126 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 127 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 128 fatal("can't drop privileges"); 129 130 if (pledge("stdio inet mcast recvfd", NULL) == -1) 131 fatal("pledge"); 132 133 event_init(); 134 nbr_init(NBR_HASHSIZE); 135 lsa_cache_init(LSA_HASHSIZE); 136 137 /* setup signal handler */ 138 signal_set(&ev_sigint, SIGINT, ospfe_sig_handler, NULL); 139 signal_set(&ev_sigterm, SIGTERM, ospfe_sig_handler, NULL); 140 signal_add(&ev_sigint, NULL); 141 signal_add(&ev_sigterm, NULL); 142 signal(SIGPIPE, SIG_IGN); 143 signal(SIGHUP, SIG_IGN); 144 145 /* setup pipes */ 146 close(pipe_parent2ospfe[0]); 147 close(pipe_ospfe2rde[1]); 148 close(pipe_parent2rde[0]); 149 close(pipe_parent2rde[1]); 150 151 if ((iev_rde = malloc(sizeof(struct imsgev))) == NULL || 152 (iev_main = malloc(sizeof(struct imsgev))) == NULL) 153 fatal(NULL); 154 imsg_init(&iev_rde->ibuf, pipe_ospfe2rde[0]); 155 iev_rde->handler = ospfe_dispatch_rde; 156 imsg_init(&iev_main->ibuf, pipe_parent2ospfe[1]); 157 iev_main->handler = ospfe_dispatch_main; 158 159 /* setup event handler */ 160 iev_rde->events = EV_READ; 161 event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events, 162 iev_rde->handler, iev_rde); 163 event_add(&iev_rde->ev, NULL); 164 165 iev_main->events = EV_READ; 166 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 167 iev_main->handler, iev_main); 168 event_add(&iev_main->ev, NULL); 169 170 event_set(&oeconf->ev, oeconf->ospf_socket, EV_READ|EV_PERSIST, 171 recv_packet, oeconf); 172 event_add(&oeconf->ev, NULL); 173 174 /* remove unneeded config stuff */ 175 conf_clear_redist_list(&oeconf->redist_list); 176 177 if ((pkt_ptr = calloc(1, READ_BUF_SIZE)) == NULL) 178 fatal("ospfe"); 179 180 /* start interfaces */ 181 LIST_FOREACH(area, &oeconf->area_list, entry) { 182 ospfe_demote_area(area, 0); 183 LIST_FOREACH(iface, &area->iface_list, entry) 184 if_start(xconf, iface); 185 } 186 187 event_dispatch(); 188 189 ospfe_shutdown(); 190 /* NOTREACHED */ 191 return (0); 192 } 193 194 __dead void 195 ospfe_shutdown(void) 196 { 197 struct area *area; 198 struct iface *iface; 199 200 /* close pipes */ 201 msgbuf_write(&iev_rde->ibuf.w); 202 msgbuf_clear(&iev_rde->ibuf.w); 203 close(iev_rde->ibuf.fd); 204 msgbuf_write(&iev_main->ibuf.w); 205 msgbuf_clear(&iev_main->ibuf.w); 206 close(iev_main->ibuf.fd); 207 208 /* stop all interfaces and remove all areas */ 209 while ((area = LIST_FIRST(&oeconf->area_list)) != NULL) { 210 LIST_FOREACH(iface, &area->iface_list, entry) { 211 if (if_fsm(iface, IF_EVT_DOWN)) { 212 log_debug("error stopping interface %s", 213 iface->name); 214 } 215 } 216 LIST_REMOVE(area, entry); 217 area_del(area); 218 } 219 220 close(oeconf->ospf_socket); 221 222 /* clean up */ 223 free(iev_rde); 224 free(iev_main); 225 free(oeconf); 226 free(pkt_ptr); 227 228 log_info("ospf engine exiting"); 229 _exit(0); 230 } 231 232 /* imesg */ 233 int 234 ospfe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen) 235 { 236 return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); 237 } 238 239 int 240 ospfe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid, 241 void *data, u_int16_t datalen) 242 { 243 return (imsg_compose_event(iev_rde, type, peerid, pid, -1, 244 data, datalen)); 245 } 246 247 /* ARGSUSED */ 248 void 249 ospfe_dispatch_main(int fd, short event, void *bula) 250 { 251 static struct area *narea; 252 struct area *area; 253 struct iface *iface, *ifp, *i; 254 struct ifaddrchange *ifc; 255 struct iface_addr *ia, *nia; 256 struct imsg imsg; 257 struct imsgev *iev = bula; 258 struct imsgbuf *ibuf = &iev->ibuf; 259 int n, stub_changed, shut = 0, isvalid, wasvalid; 260 unsigned int ifindex; 261 262 if (event & EV_READ) { 263 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 264 fatal("imsg_read error"); 265 if (n == 0) /* connection closed */ 266 shut = 1; 267 } 268 if (event & EV_WRITE) { 269 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 270 fatal("msgbuf_write"); 271 if (n == 0) /* connection closed */ 272 shut = 1; 273 } 274 275 for (;;) { 276 if ((n = imsg_get(ibuf, &imsg)) == -1) 277 fatal("ospfe_dispatch_main: imsg_get error"); 278 if (n == 0) 279 break; 280 281 switch (imsg.hdr.type) { 282 case IMSG_IFINFO: 283 if (imsg.hdr.len != IMSG_HEADER_SIZE + 284 sizeof(struct iface)) 285 fatalx("IFINFO imsg with wrong len"); 286 ifp = imsg.data; 287 288 LIST_FOREACH(area, &oeconf->area_list, entry) { 289 LIST_FOREACH(i, &area->iface_list, entry) { 290 if (strcmp(i->dependon, 291 ifp->name) == 0) { 292 log_warnx("interface %s" 293 " changed state, %s" 294 " depends on it", 295 ifp->name, i->name); 296 i->depend_ok = 297 ifstate_is_up(ifp); 298 if (ifstate_is_up(i)) 299 orig_rtr_lsa(i->area); 300 } 301 } 302 } 303 304 if (!(ifp->cflags & F_IFACE_CONFIGURED)) 305 break; 306 iface = if_find(ifp->ifindex); 307 if (iface == NULL) 308 fatalx("interface lost in ospfe"); 309 310 wasvalid = (iface->flags & IFF_UP) && 311 LINK_STATE_IS_UP(iface->linkstate); 312 313 if_update(iface, ifp->mtu, ifp->flags, ifp->if_type, 314 ifp->linkstate, ifp->baudrate, ifp->rdomain); 315 316 isvalid = (iface->flags & IFF_UP) && 317 LINK_STATE_IS_UP(iface->linkstate); 318 319 if (wasvalid == isvalid) 320 break; 321 322 if (isvalid) { 323 if_fsm(iface, IF_EVT_UP); 324 log_warnx("interface %s up", iface->name); 325 } else { 326 if_fsm(iface, IF_EVT_DOWN); 327 log_warnx("interface %s down", iface->name); 328 } 329 break; 330 case IMSG_IFADD: 331 if ((iface = malloc(sizeof(struct iface))) == NULL) 332 fatal(NULL); 333 memcpy(iface, imsg.data, sizeof(struct iface)); 334 335 LIST_INIT(&iface->nbr_list); 336 TAILQ_INIT(&iface->ls_ack_list); 337 RB_INIT(&iface->lsa_tree); 338 339 LIST_INSERT_HEAD(&iface->area->iface_list, iface, 340 entry); 341 break; 342 case IMSG_IFDELETE: 343 if (imsg.hdr.len != IMSG_HEADER_SIZE + 344 sizeof(ifindex)) 345 fatalx("IFDELETE imsg with wrong len"); 346 347 memcpy(&ifindex, imsg.data, sizeof(ifindex)); 348 iface = if_find(ifindex); 349 if (iface == NULL) 350 fatalx("interface lost in ospfe"); 351 352 LIST_REMOVE(iface, entry); 353 if_del(iface); 354 break; 355 case IMSG_IFADDRNEW: 356 if (imsg.hdr.len != IMSG_HEADER_SIZE + 357 sizeof(struct ifaddrchange)) 358 fatalx("IFADDRNEW imsg with wrong len"); 359 ifc = imsg.data; 360 361 iface = if_find(ifc->ifindex); 362 if (iface == NULL) 363 fatalx("IFADDRNEW interface lost in ospfe"); 364 365 if ((ia = calloc(1, sizeof(struct iface_addr))) == 366 NULL) 367 fatal("ospfe_dispatch_main IFADDRNEW"); 368 ia->addr = ifc->addr; 369 ia->dstbrd = ifc->dstbrd; 370 ia->prefixlen = ifc->prefixlen; 371 372 TAILQ_INSERT_TAIL(&iface->ifa_list, ia, entry); 373 orig_link_lsa(iface); 374 break; 375 case IMSG_IFADDRDEL: 376 if (imsg.hdr.len != IMSG_HEADER_SIZE + 377 sizeof(struct ifaddrchange)) 378 fatalx("IFADDRDEL imsg with wrong len"); 379 ifc = imsg.data; 380 381 iface = if_find(ifc->ifindex); 382 if (iface == NULL) 383 fatalx("IFADDRDEL interface lost in ospfe"); 384 385 for (ia = TAILQ_FIRST(&iface->ifa_list); ia != NULL; 386 ia = nia) { 387 nia = TAILQ_NEXT(ia, entry); 388 389 if (IN6_ARE_ADDR_EQUAL(&ia->addr, 390 &ifc->addr)) { 391 TAILQ_REMOVE(&iface->ifa_list, ia, 392 entry); 393 free(ia); 394 break; 395 } 396 } 397 orig_link_lsa(iface); 398 break; 399 case IMSG_RECONF_CONF: 400 if ((nconf = malloc(sizeof(struct ospfd_conf))) == 401 NULL) 402 fatal(NULL); 403 memcpy(nconf, imsg.data, sizeof(struct ospfd_conf)); 404 405 LIST_INIT(&nconf->area_list); 406 LIST_INIT(&nconf->cand_list); 407 break; 408 case IMSG_RECONF_AREA: 409 if ((narea = area_new()) == NULL) 410 fatal(NULL); 411 memcpy(narea, imsg.data, sizeof(struct area)); 412 413 LIST_INIT(&narea->iface_list); 414 LIST_INIT(&narea->nbr_list); 415 RB_INIT(&narea->lsa_tree); 416 417 LIST_INSERT_HEAD(&nconf->area_list, narea, entry); 418 break; 419 case IMSG_RECONF_END: 420 if ((oeconf->flags & OSPFD_FLAG_STUB_ROUTER) != 421 (nconf->flags & OSPFD_FLAG_STUB_ROUTER)) 422 stub_changed = 1; 423 else 424 stub_changed = 0; 425 merge_config(oeconf, nconf); 426 nconf = NULL; 427 if (stub_changed) 428 orig_rtr_lsa_all(NULL); 429 break; 430 case IMSG_CTL_KROUTE: 431 case IMSG_CTL_KROUTE_ADDR: 432 case IMSG_CTL_END: 433 control_imsg_relay(&imsg); 434 break; 435 case IMSG_CONTROLFD: 436 if ((fd = imsg.fd) == -1) 437 fatalx("%s: expected to receive imsg control" 438 "fd but didn't receive any", __func__); 439 control_state.fd = fd; 440 /* Listen on control socket. */ 441 TAILQ_INIT(&ctl_conns); 442 control_listen(); 443 if (pledge("stdio inet mcast", NULL) == -1) 444 fatal("pledge"); 445 break; 446 default: 447 log_debug("ospfe_dispatch_main: error handling imsg %d", 448 imsg.hdr.type); 449 break; 450 } 451 imsg_free(&imsg); 452 } 453 if (!shut) 454 imsg_event_add(iev); 455 else { 456 /* this pipe is dead, so remove the event handler */ 457 event_del(&iev->ev); 458 event_loopexit(NULL); 459 } 460 } 461 462 /* ARGSUSED */ 463 void 464 ospfe_dispatch_rde(int fd, short event, void *bula) 465 { 466 struct lsa_hdr lsa_hdr; 467 struct lsa_link lsa_link; 468 struct imsgev *iev = bula; 469 struct imsgbuf *ibuf = &iev->ibuf; 470 struct nbr *nbr; 471 struct lsa_hdr *lhp; 472 struct lsa_ref *ref; 473 struct area *area; 474 struct iface *iface; 475 struct lsa_entry *le; 476 struct imsg imsg; 477 struct abr_rtr ar; 478 int n, noack = 0, shut = 0; 479 u_int16_t l, age; 480 481 if (event & EV_READ) { 482 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 483 fatal("imsg_read error"); 484 if (n == 0) /* connection closed */ 485 shut = 1; 486 } 487 if (event & EV_WRITE) { 488 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 489 fatal("msgbuf_write"); 490 if (n == 0) /* connection closed */ 491 shut = 1; 492 } 493 494 for (;;) { 495 if ((n = imsg_get(ibuf, &imsg)) == -1) 496 fatal("ospfe_dispatch_rde: imsg_get error"); 497 if (n == 0) 498 break; 499 500 switch (imsg.hdr.type) { 501 case IMSG_DD: 502 nbr = nbr_find_peerid(imsg.hdr.peerid); 503 if (nbr == NULL) 504 break; 505 506 /* put these on my ls_req_list for retrieval */ 507 lhp = lsa_hdr_new(); 508 memcpy(lhp, imsg.data, sizeof(*lhp)); 509 ls_req_list_add(nbr, lhp); 510 break; 511 case IMSG_DD_END: 512 nbr = nbr_find_peerid(imsg.hdr.peerid); 513 if (nbr == NULL) 514 break; 515 516 nbr->dd_pending--; 517 if (nbr->dd_pending == 0 && nbr->state & NBR_STA_LOAD) { 518 if (ls_req_list_empty(nbr)) 519 nbr_fsm(nbr, NBR_EVT_LOAD_DONE); 520 else 521 start_ls_req_tx_timer(nbr); 522 } 523 break; 524 case IMSG_DB_SNAPSHOT: 525 nbr = nbr_find_peerid(imsg.hdr.peerid); 526 if (nbr == NULL) 527 break; 528 if (nbr->state != NBR_STA_SNAP) /* discard */ 529 break; 530 531 /* add LSA header to the neighbor db_sum_list */ 532 lhp = lsa_hdr_new(); 533 memcpy(lhp, imsg.data, sizeof(*lhp)); 534 db_sum_list_add(nbr, lhp); 535 break; 536 case IMSG_DB_END: 537 nbr = nbr_find_peerid(imsg.hdr.peerid); 538 if (nbr == NULL) 539 break; 540 541 nbr->dd_snapshot = 0; 542 if (nbr->state != NBR_STA_SNAP) 543 break; 544 545 /* snapshot done, start tx of dd packets */ 546 nbr_fsm(nbr, NBR_EVT_SNAP_DONE); 547 break; 548 case IMSG_LS_FLOOD: 549 nbr = nbr_find_peerid(imsg.hdr.peerid); 550 if (nbr == NULL) 551 break; 552 553 l = imsg.hdr.len - IMSG_HEADER_SIZE; 554 if (l < sizeof(lsa_hdr)) 555 fatalx("ospfe_dispatch_rde: " 556 "bad imsg size"); 557 memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr)); 558 559 ref = lsa_cache_add(imsg.data, l); 560 561 if (lsa_hdr.type == htons(LSA_TYPE_EXTERNAL)) { 562 /* 563 * flood on all areas but stub areas and 564 * virtual links 565 */ 566 LIST_FOREACH(area, &oeconf->area_list, entry) { 567 if (area->stub) 568 continue; 569 LIST_FOREACH(iface, &area->iface_list, 570 entry) { 571 noack += lsa_flood(iface, nbr, 572 &lsa_hdr, imsg.data); 573 } 574 } 575 } else if (lsa_hdr.type == htons(LSA_TYPE_LINK)) { 576 /* 577 * Save link-LSA options of neighbor. 578 * This is needed to originate network-LSA. 579 */ 580 if (l - sizeof(lsa_hdr) < sizeof(lsa_link)) 581 fatalx("ospfe_dispatch_rde: " 582 "bad imsg link size"); 583 memcpy(&lsa_link, (char *)imsg.data + 584 sizeof(lsa_hdr), sizeof(lsa_link)); 585 nbr->link_options = lsa_link.opts & 586 htonl(LSA_24_MASK); 587 588 /* 589 * flood on interface only 590 */ 591 noack += lsa_flood(nbr->iface, nbr, 592 &lsa_hdr, imsg.data); 593 } else { 594 /* 595 * flood on all area interfaces on 596 * area 0.0.0.0 include also virtual links. 597 */ 598 LIST_FOREACH(iface, 599 &nbr->iface->area->iface_list, entry) { 600 noack += lsa_flood(iface, nbr, 601 &lsa_hdr, imsg.data); 602 } 603 /* XXX virtual links */ 604 } 605 606 /* remove from ls_req_list */ 607 le = ls_req_list_get(nbr, &lsa_hdr); 608 if (!(nbr->state & NBR_STA_FULL) && le != NULL) { 609 ls_req_list_free(nbr, le); 610 /* 611 * XXX no need to ack requested lsa 612 * the problem is that the RFC is very 613 * unclear about this. 614 */ 615 noack = 1; 616 } 617 618 if (!noack && nbr->iface != NULL && 619 nbr->iface->self != nbr) { 620 if (!(nbr->iface->state & IF_STA_BACKUP) || 621 nbr->iface->dr == nbr) { 622 /* delayed ack */ 623 lhp = lsa_hdr_new(); 624 memcpy(lhp, &lsa_hdr, sizeof(*lhp)); 625 ls_ack_list_add(nbr->iface, lhp); 626 } 627 } 628 629 lsa_cache_put(ref, nbr); 630 break; 631 case IMSG_LS_UPD: 632 case IMSG_LS_SNAP: 633 /* 634 * IMSG_LS_UPD is used in two cases: 635 * 1. as response to ls requests 636 * 2. as response to ls updates where the DB 637 * is newer then the sent LSA 638 * IMSG_LS_SNAP is used in one case: 639 * in EXSTART when the LSA has age MaxAge 640 */ 641 l = imsg.hdr.len - IMSG_HEADER_SIZE; 642 if (l < sizeof(lsa_hdr)) 643 fatalx("ospfe_dispatch_rde: " 644 "bad imsg size"); 645 646 nbr = nbr_find_peerid(imsg.hdr.peerid); 647 if (nbr == NULL) 648 break; 649 650 if (nbr->iface->self == nbr) 651 break; 652 653 if (imsg.hdr.type == IMSG_LS_SNAP && 654 nbr->state != NBR_STA_SNAP) 655 break; 656 657 memcpy(&age, imsg.data, sizeof(age)); 658 ref = lsa_cache_add(imsg.data, l); 659 if (ntohs(age) >= MAX_AGE) 660 /* add to retransmit list */ 661 ls_retrans_list_add(nbr, imsg.data, 0, 0); 662 else 663 ls_retrans_list_add(nbr, imsg.data, 0, 1); 664 665 lsa_cache_put(ref, nbr); 666 break; 667 case IMSG_LS_ACK: 668 /* 669 * IMSG_LS_ACK is used in two cases: 670 * 1. LSA was a duplicate 671 * 2. LS age is MaxAge and there is no current 672 * instance in the DB plus no neighbor in state 673 * Exchange or Loading 674 */ 675 nbr = nbr_find_peerid(imsg.hdr.peerid); 676 if (nbr == NULL) 677 break; 678 679 if (nbr->iface->self == nbr) 680 break; 681 682 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(lsa_hdr)) 683 fatalx("ospfe_dispatch_rde: bad imsg size"); 684 memcpy(&lsa_hdr, imsg.data, sizeof(lsa_hdr)); 685 686 /* for case one check for implied acks */ 687 if (nbr->iface->state & IF_STA_DROTHER) 688 if (ls_retrans_list_del(nbr->iface->self, 689 &lsa_hdr) == 0) 690 break; 691 if (ls_retrans_list_del(nbr, &lsa_hdr) == 0) 692 break; 693 694 /* send a direct acknowledgement */ 695 send_direct_ack(nbr->iface, nbr->addr, imsg.data, 696 imsg.hdr.len - IMSG_HEADER_SIZE); 697 698 break; 699 case IMSG_LS_BADREQ: 700 nbr = nbr_find_peerid(imsg.hdr.peerid); 701 if (nbr == NULL) 702 break; 703 704 if (nbr->iface->self == nbr) 705 fatalx("ospfe_dispatch_rde: " 706 "dummy neighbor got BADREQ"); 707 708 nbr_fsm(nbr, NBR_EVT_BAD_LS_REQ); 709 break; 710 case IMSG_ABR_UP: 711 memcpy(&ar, imsg.data, sizeof(ar)); 712 713 if ((iface = find_vlink(&ar)) != NULL && 714 iface->state == IF_STA_DOWN) 715 if (if_fsm(iface, IF_EVT_UP)) { 716 log_debug("error starting interface %s", 717 iface->name); 718 } 719 break; 720 case IMSG_ABR_DOWN: 721 memcpy(&ar, imsg.data, sizeof(ar)); 722 723 if ((iface = find_vlink(&ar)) != NULL && 724 iface->state == IF_STA_POINTTOPOINT) 725 if (if_fsm(iface, IF_EVT_DOWN)) { 726 log_debug("error stopping interface %s", 727 iface->name); 728 } 729 break; 730 case IMSG_CTL_AREA: 731 case IMSG_CTL_IFACE: 732 case IMSG_CTL_END: 733 case IMSG_CTL_SHOW_DATABASE: 734 case IMSG_CTL_SHOW_DB_EXT: 735 case IMSG_CTL_SHOW_DB_LINK: 736 case IMSG_CTL_SHOW_DB_NET: 737 case IMSG_CTL_SHOW_DB_RTR: 738 case IMSG_CTL_SHOW_DB_INTRA: 739 case IMSG_CTL_SHOW_DB_SELF: 740 case IMSG_CTL_SHOW_DB_SUM: 741 case IMSG_CTL_SHOW_DB_ASBR: 742 case IMSG_CTL_SHOW_RIB: 743 case IMSG_CTL_SHOW_SUM: 744 case IMSG_CTL_SHOW_SUM_AREA: 745 control_imsg_relay(&imsg); 746 break; 747 default: 748 log_debug("ospfe_dispatch_rde: error handling imsg %d", 749 imsg.hdr.type); 750 break; 751 } 752 imsg_free(&imsg); 753 } 754 if (!shut) 755 imsg_event_add(iev); 756 else { 757 /* this pipe is dead, so remove the event handler */ 758 event_del(&iev->ev); 759 event_loopexit(NULL); 760 } 761 } 762 763 struct iface * 764 find_vlink(struct abr_rtr *ar) 765 { 766 struct area *area; 767 struct iface *iface = NULL; 768 769 LIST_FOREACH(area, &oeconf->area_list, entry) 770 LIST_FOREACH(iface, &area->iface_list, entry) 771 if (iface->abr_id.s_addr == ar->abr_id.s_addr && 772 iface->type == IF_TYPE_VIRTUALLINK && 773 iface->area->id.s_addr == ar->area.s_addr) { 774 iface->dst = ar->dst_ip; 775 iface->addr = ar->addr; 776 iface->metric = ar->metric; 777 778 return (iface); 779 } 780 781 return (iface); 782 } 783 784 void 785 orig_rtr_lsa_all(struct area *area) 786 { 787 struct area *a; 788 789 /* 790 * update all router LSA in all areas except area itself, 791 * as this update is already running. 792 */ 793 LIST_FOREACH(a, &oeconf->area_list, entry) 794 if (a != area) 795 orig_rtr_lsa(a); 796 } 797 798 void 799 orig_rtr_lsa(struct area *area) 800 { 801 struct lsa_hdr lsa_hdr; 802 struct lsa_rtr lsa_rtr; 803 struct lsa_rtr_link rtr_link; 804 struct iface *iface; 805 struct ibuf *buf; 806 struct nbr *nbr, *self = NULL; 807 u_int32_t flags; 808 u_int16_t chksum; 809 u_int8_t border, virtual = 0; 810 811 log_debug("orig_rtr_lsa: area %s", inet_ntoa(area->id)); 812 813 /* XXX IBUF_READ_SIZE */ 814 if ((buf = ibuf_dynamic(sizeof(lsa_hdr), IBUF_READ_SIZE)) == NULL) 815 fatal("orig_rtr_lsa"); 816 817 /* reserve space for LSA header and LSA Router header */ 818 if (ibuf_reserve(buf, sizeof(lsa_hdr)) == NULL) 819 fatal("orig_rtr_lsa: ibuf_reserve failed"); 820 821 if (ibuf_reserve(buf, sizeof(lsa_rtr)) == NULL) 822 fatal("orig_rtr_lsa: ibuf_reserve failed"); 823 824 /* links */ 825 LIST_FOREACH(iface, &area->iface_list, entry) { 826 if (self == NULL && iface->self != NULL) 827 self = iface->self; 828 829 bzero(&rtr_link, sizeof(rtr_link)); 830 831 switch (iface->type) { 832 case IF_TYPE_POINTOPOINT: 833 LIST_FOREACH(nbr, &iface->nbr_list, entry) 834 if (nbr != iface->self && 835 nbr->state & NBR_STA_FULL) 836 break; 837 if (nbr && iface->state & IF_STA_POINTTOPOINT) { 838 log_debug("orig_rtr_lsa: point-to-point, " 839 "interface %s", iface->name); 840 rtr_link.type = LINK_TYPE_POINTTOPOINT; 841 if (iface->dependon[0] != '\0' && 842 iface->depend_ok == 0) 843 rtr_link.metric = MAX_METRIC; 844 else 845 rtr_link.metric = htons(iface->metric); 846 rtr_link.iface_id = htonl(iface->ifindex); 847 rtr_link.nbr_iface_id = htonl(nbr->iface_id); 848 rtr_link.nbr_rtr_id = nbr->id.s_addr; 849 if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 850 fatalx("orig_rtr_lsa: ibuf_add failed"); 851 } 852 continue; 853 case IF_TYPE_BROADCAST: 854 case IF_TYPE_NBMA: 855 if ((iface->state & IF_STA_MULTI)) { 856 if (iface->dr == iface->self) { 857 LIST_FOREACH(nbr, &iface->nbr_list, 858 entry) 859 if (nbr != iface->self && 860 nbr->state & NBR_STA_FULL) 861 break; 862 } else 863 nbr = iface->dr; 864 865 if (nbr && nbr->state & NBR_STA_FULL) { 866 log_debug("orig_rtr_lsa: transit net, " 867 "interface %s", iface->name); 868 869 rtr_link.type = LINK_TYPE_TRANSIT_NET; 870 if (iface->dependon[0] != '\0' && 871 iface->depend_ok == 0) 872 rtr_link.metric = MAX_METRIC; 873 else 874 rtr_link.metric = 875 htons(iface->metric); 876 rtr_link.iface_id = htonl(iface->ifindex); 877 rtr_link.nbr_iface_id = htonl(iface->dr->iface_id); 878 rtr_link.nbr_rtr_id = iface->dr->id.s_addr; 879 if (ibuf_add(buf, &rtr_link, 880 sizeof(rtr_link))) 881 fatalx("orig_rtr_lsa: " 882 "ibuf_add failed"); 883 break; 884 } 885 } 886 break; 887 #if 0 /* TODO virtualllink/pointtomulti */ 888 case IF_TYPE_VIRTUALLINK: 889 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 890 if (nbr != iface->self && 891 nbr->state & NBR_STA_FULL) 892 break; 893 } 894 if (nbr) { 895 rtr_link.id = nbr->id.s_addr; 896 //XXX rtr_link.data = iface->addr.s_addr; 897 rtr_link.type = LINK_TYPE_VIRTUAL; 898 /* RFC 3137: stub router support */ 899 if (oeconf->flags & OSPFD_FLAG_STUB_ROUTER || 900 oe_nofib) 901 rtr_link.metric = 0xffff; 902 else 903 rtr_link.metric = htons(iface->metric); 904 virtual = 1; 905 if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 906 fatalx("orig_rtr_lsa: ibuf_add failed"); 907 908 log_debug("orig_rtr_lsa: virtual link, " 909 "interface %s", iface->name); 910 } 911 continue; 912 case IF_TYPE_POINTOMULTIPOINT: 913 log_debug("orig_rtr_lsa: stub net, " 914 "interface %s", iface->name); 915 //XXX rtr_link.id = iface->addr.s_addr; 916 rtr_link.data = 0xffffffff; 917 rtr_link.type = LINK_TYPE_STUB_NET; 918 rtr_link.metric = htons(iface->metric); 919 if (ibuf_add(buf, &rtr_link, sizeof(rtr_link))) 920 fatalx("orig_rtr_lsa: ibuf_add failed"); 921 922 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 923 if (nbr != iface->self && 924 nbr->state & NBR_STA_FULL) { 925 bzero(&rtr_link, sizeof(rtr_link)); 926 log_debug("orig_rtr_lsa: " 927 "point-to-multipoint, interface %s", 928 iface->name); 929 //XXX rtr_link.id = nbr->addr.s_addr; 930 //XXX rtr_link.data = iface->addr.s_addr; 931 rtr_link.type = LINK_TYPE_POINTTOPOINT; 932 /* RFC 3137: stub router support */ 933 if (oe_nofib || oeconf->flags & 934 OSPFD_FLAG_STUB_ROUTER) 935 rtr_link.metric = MAX_METRIC; 936 else if (iface->dependon[0] != '\0' && 937 iface->dependon_ok == 0) 938 rtr_link.metric = MAX_METRIC; 939 else 940 rtr_link.metric = 941 htons(iface->metric); 942 if (ibuf_add(buf, &rtr_link, 943 sizeof(rtr_link))) 944 fatalx("orig_rtr_lsa: " 945 "ibuf_add failed"); 946 } 947 } 948 continue; 949 #endif /* TODO virtualllink/pointtomulti */ 950 default: 951 fatalx("orig_rtr_lsa: unknown interface type"); 952 } 953 } 954 955 /* LSA router header */ 956 lsa_rtr.opts = 0; 957 flags = 0; 958 959 /* 960 * Set the E bit as soon as an as-ext lsa may be redistributed, only 961 * setting it in case we redistribute something is not worth the fuss. 962 */ 963 if (oeconf->redistribute && !area->stub) 964 flags |= OSPF_RTR_E; 965 966 border = (area_border_router(oeconf) != 0); 967 if (border != oeconf->border) { 968 oeconf->border = border; 969 orig_rtr_lsa_all(area); 970 } 971 972 if (oeconf->border) 973 flags |= OSPF_RTR_B; 974 /* TODO set V flag if a active virtual link ends here and the 975 * area is the transit area for this link. */ 976 if (virtual) 977 flags |= OSPF_RTR_V; 978 979 LSA_24_SETLO(lsa_rtr.opts, area_ospf_options(area)); 980 LSA_24_SETHI(lsa_rtr.opts, flags); 981 lsa_rtr.opts = htonl(lsa_rtr.opts); 982 memcpy(ibuf_seek(buf, sizeof(lsa_hdr), sizeof(lsa_rtr)), 983 &lsa_rtr, sizeof(lsa_rtr)); 984 985 /* LSA header */ 986 lsa_hdr.age = htons(DEFAULT_AGE); 987 lsa_hdr.type = htons(LSA_TYPE_ROUTER); 988 /* XXX needs to be fixed if multiple router-lsa need to be announced */ 989 lsa_hdr.ls_id = 0; 990 lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr; 991 lsa_hdr.seq_num = htonl(INIT_SEQ_NUM); 992 lsa_hdr.len = htons(buf->wpos); 993 lsa_hdr.ls_chksum = 0; /* updated later */ 994 memcpy(ibuf_seek(buf, 0, sizeof(lsa_hdr)), &lsa_hdr, sizeof(lsa_hdr)); 995 996 chksum = htons(iso_cksum(buf->buf, buf->wpos, LS_CKSUM_OFFSET)); 997 memcpy(ibuf_seek(buf, LS_CKSUM_OFFSET, sizeof(chksum)), 998 &chksum, sizeof(chksum)); 999 1000 if (self) 1001 imsg_compose_event(iev_rde, IMSG_LS_UPD, self->peerid, 0, 1002 -1, buf->buf, buf->wpos); 1003 else 1004 log_warnx("orig_rtr_lsa: empty area %s", 1005 inet_ntoa(area->id)); 1006 1007 ibuf_free(buf); 1008 } 1009 1010 void 1011 orig_net_lsa(struct iface *iface) 1012 { 1013 struct lsa_hdr lsa_hdr; 1014 struct nbr *nbr; 1015 struct ibuf *buf; 1016 struct lsa_net lsa_net; 1017 int num_rtr = 0; 1018 u_int16_t chksum; 1019 1020 /* XXX IBUF_READ_SIZE */ 1021 if ((buf = ibuf_dynamic(sizeof(lsa_hdr), IBUF_READ_SIZE)) == NULL) 1022 fatal("orig_net_lsa"); 1023 1024 /* reserve space for LSA header and options field */ 1025 if (ibuf_reserve(buf, sizeof(lsa_hdr) + sizeof(lsa_net)) == NULL) 1026 fatal("orig_net_lsa: ibuf_reserve failed"); 1027 1028 lsa_net.opts = 0; 1029 /* fully adjacent neighbors + self */ 1030 LIST_FOREACH(nbr, &iface->nbr_list, entry) 1031 if (nbr->state & NBR_STA_FULL) { 1032 if (ibuf_add(buf, &nbr->id, sizeof(nbr->id))) 1033 fatal("orig_net_lsa: ibuf_add failed"); 1034 lsa_net.opts |= nbr->link_options; 1035 num_rtr++; 1036 } 1037 1038 if (num_rtr == 1) { 1039 /* non transit net therefore no need to generate a net lsa */ 1040 ibuf_free(buf); 1041 return; 1042 } 1043 1044 /* LSA header */ 1045 if (iface->state & IF_STA_DR) 1046 lsa_hdr.age = htons(DEFAULT_AGE); 1047 else 1048 lsa_hdr.age = htons(MAX_AGE); 1049 1050 lsa_hdr.type = htons(LSA_TYPE_NETWORK); 1051 /* for network LSAs, the link state ID equals the interface ID */ 1052 lsa_hdr.ls_id = htonl(iface->ifindex); 1053 lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr; 1054 lsa_hdr.seq_num = htonl(INIT_SEQ_NUM); 1055 lsa_hdr.len = htons(buf->wpos); 1056 lsa_hdr.ls_chksum = 0; /* updated later */ 1057 memcpy(ibuf_seek(buf, 0, sizeof(lsa_hdr)), &lsa_hdr, sizeof(lsa_hdr)); 1058 1059 lsa_net.opts &= lsa_net.opts & htonl(LSA_24_MASK); 1060 memcpy(ibuf_seek(buf, sizeof(lsa_hdr), sizeof(lsa_net)), &lsa_net, 1061 sizeof(lsa_net)); 1062 1063 chksum = htons(iso_cksum(buf->buf, buf->wpos, LS_CKSUM_OFFSET)); 1064 memcpy(ibuf_seek(buf, LS_CKSUM_OFFSET, sizeof(chksum)), 1065 &chksum, sizeof(chksum)); 1066 1067 imsg_compose_event(iev_rde, IMSG_LS_UPD, iface->self->peerid, 0, 1068 -1, buf->buf, buf->wpos); 1069 1070 ibuf_free(buf); 1071 } 1072 1073 void 1074 orig_link_lsa(struct iface *iface) 1075 { 1076 struct lsa_hdr lsa_hdr; 1077 struct lsa_link lsa_link; 1078 struct lsa_prefix lsa_prefix; 1079 struct ibuf *buf; 1080 struct iface_addr *ia; 1081 struct in6_addr prefix; 1082 unsigned int num_prefix = 0; 1083 u_int16_t chksum; 1084 u_int32_t options; 1085 1086 log_debug("orig_link_lsa: interface %s", iface->name); 1087 1088 switch (iface->type) { 1089 case IF_TYPE_VIRTUALLINK: /* forbidden by rfc5340 */ 1090 return; 1091 case IF_TYPE_BROADCAST: 1092 case IF_TYPE_NBMA: 1093 if ((iface->state & IF_STA_MULTI) == 0) 1094 return; 1095 break; 1096 case IF_TYPE_POINTOPOINT: 1097 case IF_TYPE_POINTOMULTIPOINT: 1098 if ((iface->state & IF_STA_POINTTOPOINT) == 0) 1099 return; 1100 break; 1101 default: 1102 fatalx("orig_link_lsa: unknown interface type"); 1103 } 1104 1105 /* XXX IBUF_READ_SIZE */ 1106 if ((buf = ibuf_dynamic(sizeof(lsa_hdr) + sizeof(lsa_link), 1107 IBUF_READ_SIZE)) == NULL) 1108 fatal("orig_link_lsa"); 1109 1110 /* reserve space for LSA header and LSA link header */ 1111 if (ibuf_reserve(buf, sizeof(lsa_hdr) + sizeof(lsa_link)) == NULL) 1112 fatal("orig_link_lsa: ibuf_reserve failed"); 1113 1114 /* link-local address, and all prefixes configured on interface */ 1115 TAILQ_FOREACH(ia, &iface->ifa_list, entry) { 1116 if (IN6_IS_ADDR_LINKLOCAL(&ia->addr)) { 1117 log_debug("orig_link_lsa: link local address %s", 1118 log_in6addr(&ia->addr)); 1119 lsa_link.lladdr = ia->addr; 1120 continue; 1121 } 1122 1123 lsa_prefix.prefixlen = ia->prefixlen; 1124 lsa_prefix.options = 0; 1125 lsa_prefix.metric = 0; 1126 inet6applymask(&prefix, &ia->addr, ia->prefixlen); 1127 log_debug("orig_link_lsa: prefix %s", log_in6addr(&prefix)); 1128 if (ibuf_add(buf, &lsa_prefix, sizeof(lsa_prefix))) 1129 fatal("orig_link_lsa: ibuf_add failed"); 1130 if (ibuf_add(buf, &prefix.s6_addr[0], 1131 LSA_PREFIXSIZE(ia->prefixlen))) 1132 fatal("orig_link_lsa: ibuf_add failed"); 1133 num_prefix++; 1134 } 1135 1136 /* LSA link header (lladdr has already been filled in above) */ 1137 LSA_24_SETHI(lsa_link.opts, iface->priority); 1138 options = area_ospf_options(iface->area); 1139 LSA_24_SETLO(lsa_link.opts, options); 1140 lsa_link.opts = htonl(lsa_link.opts); 1141 lsa_link.numprefix = htonl(num_prefix); 1142 memcpy(ibuf_seek(buf, sizeof(lsa_hdr), sizeof(lsa_link)), 1143 &lsa_link, sizeof(lsa_link)); 1144 1145 /* LSA header */ 1146 lsa_hdr.age = htons(DEFAULT_AGE); 1147 lsa_hdr.type = htons(LSA_TYPE_LINK); 1148 /* for link LSAs, the link state ID equals the interface ID */ 1149 lsa_hdr.ls_id = htonl(iface->ifindex); 1150 lsa_hdr.adv_rtr = oeconf->rtr_id.s_addr; 1151 lsa_hdr.seq_num = htonl(INIT_SEQ_NUM); 1152 lsa_hdr.len = htons(buf->wpos); 1153 lsa_hdr.ls_chksum = 0; /* updated later */ 1154 memcpy(ibuf_seek(buf, 0, sizeof(lsa_hdr)), &lsa_hdr, sizeof(lsa_hdr)); 1155 1156 chksum = htons(iso_cksum(buf->buf, buf->wpos, LS_CKSUM_OFFSET)); 1157 memcpy(ibuf_seek(buf, LS_CKSUM_OFFSET, sizeof(chksum)), 1158 &chksum, sizeof(chksum)); 1159 1160 imsg_compose_event(iev_rde, IMSG_LS_UPD, iface->self->peerid, 0, 1161 -1, buf->buf, buf->wpos); 1162 1163 ibuf_free(buf); 1164 } 1165 1166 u_int32_t 1167 ospfe_router_id(void) 1168 { 1169 return (oeconf->rtr_id.s_addr); 1170 } 1171 1172 void 1173 ospfe_fib_update(int type) 1174 { 1175 int old = oe_nofib; 1176 1177 if (type == IMSG_CTL_FIB_COUPLE) 1178 oe_nofib = 0; 1179 if (type == IMSG_CTL_FIB_DECOUPLE) 1180 oe_nofib = 1; 1181 if (old != oe_nofib) 1182 orig_rtr_lsa_all(NULL); 1183 } 1184 1185 void 1186 ospfe_iface_ctl(struct ctl_conn *c, unsigned int idx) 1187 { 1188 struct area *area; 1189 struct iface *iface; 1190 struct ctl_iface *ictl; 1191 1192 LIST_FOREACH(area, &oeconf->area_list, entry) 1193 LIST_FOREACH(iface, &area->iface_list, entry) 1194 if (idx == 0 || idx == iface->ifindex) { 1195 ictl = if_to_ctl(iface); 1196 imsg_compose_event(&c->iev, 1197 IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, 1198 ictl, sizeof(struct ctl_iface)); 1199 } 1200 } 1201 1202 void 1203 ospfe_nbr_ctl(struct ctl_conn *c) 1204 { 1205 struct area *area; 1206 struct iface *iface; 1207 struct nbr *nbr; 1208 struct ctl_nbr *nctl; 1209 1210 LIST_FOREACH(area, &oeconf->area_list, entry) 1211 LIST_FOREACH(iface, &area->iface_list, entry) 1212 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 1213 if (iface->self != nbr) { 1214 nctl = nbr_to_ctl(nbr); 1215 imsg_compose_event(&c->iev, 1216 IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl, 1217 sizeof(struct ctl_nbr)); 1218 } 1219 } 1220 1221 imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); 1222 } 1223 1224 void 1225 ospfe_demote_area(struct area *area, int active) 1226 { 1227 struct demote_msg dmsg; 1228 1229 if (ospfd_process != PROC_OSPF_ENGINE || 1230 area->demote_group[0] == '\0') 1231 return; 1232 1233 bzero(&dmsg, sizeof(dmsg)); 1234 strlcpy(dmsg.demote_group, area->demote_group, 1235 sizeof(dmsg.demote_group)); 1236 dmsg.level = area->demote_level; 1237 if (active) 1238 dmsg.level = -dmsg.level; 1239 1240 ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg)); 1241 } 1242 1243 void 1244 ospfe_demote_iface(struct iface *iface, int active) 1245 { 1246 struct demote_msg dmsg; 1247 1248 if (ospfd_process != PROC_OSPF_ENGINE || 1249 iface->demote_group[0] == '\0') 1250 return; 1251 1252 bzero(&dmsg, sizeof(dmsg)); 1253 strlcpy(dmsg.demote_group, iface->demote_group, 1254 sizeof(dmsg.demote_group)); 1255 if (active) 1256 dmsg.level = -1; 1257 else 1258 dmsg.level = 1; 1259 1260 log_warnx("ospfe_demote_iface: group %s level %d", dmsg.demote_group, 1261 dmsg.level); 1262 1263 ospfe_imsg_compose_parent(IMSG_DEMOTE, 0, &dmsg, sizeof(dmsg)); 1264 } 1265