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