1*cb75af8bSclaudio /* $OpenBSD: neighbor.c,v 1.12 2005/03/17 21:17:12 claudio Exp $ */ 2204df0f8Sclaudio 3204df0f8Sclaudio /* 4204df0f8Sclaudio * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5367f601bSnorby * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 6204df0f8Sclaudio * 7204df0f8Sclaudio * Permission to use, copy, modify, and distribute this software for any 8204df0f8Sclaudio * purpose with or without fee is hereby granted, provided that the above 9204df0f8Sclaudio * copyright notice and this permission notice appear in all copies. 10204df0f8Sclaudio * 11204df0f8Sclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12204df0f8Sclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13204df0f8Sclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14204df0f8Sclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15204df0f8Sclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16204df0f8Sclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17204df0f8Sclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18204df0f8Sclaudio */ 19204df0f8Sclaudio 20204df0f8Sclaudio #include <sys/types.h> 21204df0f8Sclaudio #include <sys/ioctl.h> 22204df0f8Sclaudio #include <sys/time.h> 23204df0f8Sclaudio #include <sys/socket.h> 24204df0f8Sclaudio #include <netinet/in.h> 25204df0f8Sclaudio #include <arpa/inet.h> 26204df0f8Sclaudio #include <net/if.h> 27204df0f8Sclaudio 28204df0f8Sclaudio #include <ctype.h> 29204df0f8Sclaudio #include <err.h> 30204df0f8Sclaudio #include <stdio.h> 31204df0f8Sclaudio #include <stdlib.h> 32204df0f8Sclaudio #include <string.h> 33204df0f8Sclaudio #include <event.h> 34204df0f8Sclaudio 35204df0f8Sclaudio #include "ospfd.h" 36204df0f8Sclaudio #include "ospf.h" 37204df0f8Sclaudio #include "ospfe.h" 38204df0f8Sclaudio #include "log.h" 39204df0f8Sclaudio #include "rde.h" 40204df0f8Sclaudio 41204df0f8Sclaudio int nbr_adj_ok(struct nbr *); 42204df0f8Sclaudio 43204df0f8Sclaudio LIST_HEAD(nbr_head, nbr); 44204df0f8Sclaudio 45204df0f8Sclaudio struct nbr_table { 46204df0f8Sclaudio struct nbr_head *hashtbl; 47204df0f8Sclaudio u_int32_t hashmask; 48204df0f8Sclaudio } nbrtable; 49204df0f8Sclaudio 50204df0f8Sclaudio #define NBR_HASH(x) \ 51204df0f8Sclaudio &nbrtable.hashtbl[(x) & nbrtable.hashmask] 52204df0f8Sclaudio 53204df0f8Sclaudio u_int32_t peercnt; 54204df0f8Sclaudio 55204df0f8Sclaudio struct { 56204df0f8Sclaudio int state; 57204df0f8Sclaudio enum nbr_event event; 58204df0f8Sclaudio enum nbr_action action; 59204df0f8Sclaudio int new_state; 60204df0f8Sclaudio } nbr_fsm_tbl[] = { 61204df0f8Sclaudio /* current state event that happened action to take resulting state */ 62204df0f8Sclaudio {NBR_STA_ACTIVE, NBR_EVT_HELLO_RCVD, NBR_ACT_RST_ITIMER, 0}, 63ddc378ebSclaudio {NBR_STA_BIDIR, NBR_EVT_2_WAY_RCVD, NBR_ACT_NOTHING, 0}, 64ddc378ebSclaudio {NBR_STA_INIT, NBR_EVT_1_WAY_RCVD, NBR_ACT_NOTHING, 0}, 65204df0f8Sclaudio {NBR_STA_DOWN, NBR_EVT_HELLO_RCVD, NBR_ACT_STRT_ITIMER, NBR_STA_INIT}, 66204df0f8Sclaudio {NBR_STA_DOWN, NBR_EVT_STRT, NBR_ACT_STRT, NBR_STA_ATTEMPT}, 67204df0f8Sclaudio {NBR_STA_ATTEMPT, NBR_EVT_HELLO_RCVD, NBR_ACT_RST_ITIMER, NBR_STA_INIT}, 68204df0f8Sclaudio {NBR_STA_INIT, NBR_EVT_2_WAY_RCVD, NBR_ACT_EVAL, 0}, 69204df0f8Sclaudio {NBR_STA_XSTRT, NBR_EVT_NEG_DONE, NBR_ACT_SNAP, NBR_STA_SNAP}, 70204df0f8Sclaudio {NBR_STA_SNAP, NBR_EVT_SNAP_DONE, NBR_ACT_SNAP_DONE, NBR_STA_XCHNG}, 71204df0f8Sclaudio {NBR_STA_XCHNG, NBR_EVT_XCHNG_DONE, NBR_ACT_XCHNG_DONE, 0}, 72ddc378ebSclaudio {NBR_STA_LOAD, NBR_EVT_LOAD_DONE, NBR_ACT_NOTHING, NBR_STA_FULL}, 73204df0f8Sclaudio {NBR_STA_2_WAY, NBR_EVT_ADJ_OK, NBR_ACT_EVAL, 0}, 74204df0f8Sclaudio {NBR_STA_ADJFORM, NBR_EVT_ADJ_OK, NBR_ACT_ADJ_OK, 0}, 75204df0f8Sclaudio {NBR_STA_PRELIM, NBR_EVT_ADJ_OK, NBR_ACT_HELLO_CHK, 0}, 763922c68bSclaudio {NBR_STA_ADJFORM, NBR_EVT_ADJTMOUT, NBR_ACT_RESTRT_DD, 0}, 77204df0f8Sclaudio {NBR_STA_FLOOD, NBR_EVT_SEQ_NUM_MIS, NBR_ACT_RESTRT_DD, NBR_STA_XSTRT}, 78204df0f8Sclaudio {NBR_STA_FLOOD, NBR_EVT_BAD_LS_REQ, NBR_ACT_RESTRT_DD, NBR_STA_XSTRT}, 79204df0f8Sclaudio {NBR_STA_ANY, NBR_EVT_KILL_NBR, NBR_ACT_DEL, NBR_STA_DOWN}, 80204df0f8Sclaudio {NBR_STA_ANY, NBR_EVT_LL_DOWN, NBR_ACT_DEL, NBR_STA_DOWN}, 81204df0f8Sclaudio {NBR_STA_ANY, NBR_EVT_ITIMER, NBR_ACT_DEL, NBR_STA_DOWN}, 82204df0f8Sclaudio {NBR_STA_BIDIR, NBR_EVT_1_WAY_RCVD, NBR_ACT_CLR_LST, NBR_STA_INIT}, 83ddc378ebSclaudio {-1, NBR_EVT_NOTHING, NBR_ACT_NOTHING, 0}, 84204df0f8Sclaudio }; 85204df0f8Sclaudio 86204df0f8Sclaudio const char * const nbr_event_names[] = { 87204df0f8Sclaudio "NOTHING", 88204df0f8Sclaudio "HELLO_RECEIVED", 89204df0f8Sclaudio "START", 90204df0f8Sclaudio "2_WAY_RECEIVED", 91204df0f8Sclaudio "NEGOTIATION_DONE", 92204df0f8Sclaudio "SNAPSHOT_DONE", 93204df0f8Sclaudio "EXCHANGE_DONE", 94204df0f8Sclaudio "BAD_LS_REQ", 95204df0f8Sclaudio "LOADING_DONE", 96204df0f8Sclaudio "ADJ_OK", 97204df0f8Sclaudio "SEQ_NUM_MISMATCH", 98204df0f8Sclaudio "1_WAY_RECEIVED", 99204df0f8Sclaudio "KILL_NBR", 100204df0f8Sclaudio "INACTIVITY_TIMER", 101204df0f8Sclaudio "LL_DOWN", 102204df0f8Sclaudio "ADJ_TIMEOUT" 103204df0f8Sclaudio }; 104204df0f8Sclaudio 105204df0f8Sclaudio const char * const nbr_action_names[] = { 106204df0f8Sclaudio "NOTHING", 107204df0f8Sclaudio "START", 108204df0f8Sclaudio "RESET_INACTIVITY_TIMER", 109204df0f8Sclaudio "START_INACTIVITY_TIMER", 110204df0f8Sclaudio "EVAL", 111204df0f8Sclaudio "SNAPSHOT", 112204df0f8Sclaudio "SNAPSHOT_DONE", 113204df0f8Sclaudio "EXCHANGE_DONE", 114204df0f8Sclaudio "ADJ_OK", 115204df0f8Sclaudio "RESET_DD", 116204df0f8Sclaudio "DELETE", 117204df0f8Sclaudio "CLEAR_LISTS" 118204df0f8Sclaudio }; 119204df0f8Sclaudio 120204df0f8Sclaudio int 121204df0f8Sclaudio nbr_fsm(struct nbr *nbr, enum nbr_event event) 122204df0f8Sclaudio { 123204df0f8Sclaudio int old_state; 124204df0f8Sclaudio int new_state = 0; 125204df0f8Sclaudio int i, ret = 0; 126204df0f8Sclaudio 127204df0f8Sclaudio if (nbr == nbr->iface->self) 128204df0f8Sclaudio return (0); 129204df0f8Sclaudio 130204df0f8Sclaudio old_state = nbr->state; 131204df0f8Sclaudio for (i = 0; nbr_fsm_tbl[i].state != -1; i++) 132204df0f8Sclaudio if ((nbr_fsm_tbl[i].state & old_state) && 133204df0f8Sclaudio (nbr_fsm_tbl[i].event == event)) { 134204df0f8Sclaudio new_state = nbr_fsm_tbl[i].new_state; 135204df0f8Sclaudio break; 136204df0f8Sclaudio } 137204df0f8Sclaudio 138204df0f8Sclaudio if (nbr_fsm_tbl[i].state == -1) { 139204df0f8Sclaudio /* XXX event outside of the defined fsm, ignore it. */ 140ddc378ebSclaudio log_warnx("nbr_fsm: neighbor ID %s, " 141204df0f8Sclaudio "event %s not expected in state %s", 142204df0f8Sclaudio inet_ntoa(nbr->id), nbr_event_name(event), 143204df0f8Sclaudio nbr_state_name(old_state)); 144204df0f8Sclaudio return (0); 145204df0f8Sclaudio } 146204df0f8Sclaudio 147204df0f8Sclaudio switch (nbr_fsm_tbl[i].action) { 148204df0f8Sclaudio case NBR_ACT_STRT: 149204df0f8Sclaudio ret = nbr_act_start(nbr); 150204df0f8Sclaudio break; 151204df0f8Sclaudio case NBR_ACT_RST_ITIMER: 152204df0f8Sclaudio ret = nbr_act_reset_itimer(nbr); 153204df0f8Sclaudio break; 154204df0f8Sclaudio case NBR_ACT_STRT_ITIMER: 155204df0f8Sclaudio ret = nbr_act_start_itimer(nbr); 156204df0f8Sclaudio break; 157204df0f8Sclaudio case NBR_ACT_EVAL: 158204df0f8Sclaudio ret = nbr_act_eval(nbr); 159204df0f8Sclaudio break; 160204df0f8Sclaudio case NBR_ACT_SNAP: 161204df0f8Sclaudio ret = nbr_act_snapshot(nbr); 162204df0f8Sclaudio break; 163204df0f8Sclaudio case NBR_ACT_SNAP_DONE: 164204df0f8Sclaudio /* start db exchange */ 165204df0f8Sclaudio start_db_tx_timer(nbr); 166204df0f8Sclaudio break; 167204df0f8Sclaudio case NBR_ACT_XCHNG_DONE: 168204df0f8Sclaudio ret = nbr_act_exchange_done(nbr); 169204df0f8Sclaudio break; 170204df0f8Sclaudio case NBR_ACT_ADJ_OK: 171204df0f8Sclaudio ret = nbr_act_adj_ok(nbr); 172204df0f8Sclaudio break; 173204df0f8Sclaudio case NBR_ACT_RESTRT_DD: 174204df0f8Sclaudio ret = nbr_act_restart_dd(nbr); 175204df0f8Sclaudio break; 176204df0f8Sclaudio case NBR_ACT_DEL: 177204df0f8Sclaudio ret = nbr_act_delete(nbr); 178204df0f8Sclaudio break; 179204df0f8Sclaudio case NBR_ACT_CLR_LST: 180204df0f8Sclaudio ret = nbr_act_clear_lists(nbr); 181204df0f8Sclaudio break; 182204df0f8Sclaudio case NBR_ACT_HELLO_CHK: 183204df0f8Sclaudio ret = nbr_act_hello_check(nbr); 184204df0f8Sclaudio break; 185ddc378ebSclaudio case NBR_ACT_NOTHING: 186204df0f8Sclaudio /* do nothing */ 187204df0f8Sclaudio break; 188204df0f8Sclaudio } 189204df0f8Sclaudio 190204df0f8Sclaudio if (ret) { 191ddc378ebSclaudio log_warnx("nbr_fsm: error changing state for neighbor ID %s, " 192204df0f8Sclaudio "event %s, state %s", inet_ntoa(nbr->id), 193204df0f8Sclaudio nbr_event_name(event), nbr_state_name(old_state)); 194204df0f8Sclaudio return (-1); 195204df0f8Sclaudio } 196204df0f8Sclaudio 197204df0f8Sclaudio if (new_state != 0) 198204df0f8Sclaudio nbr->state = new_state; 199204df0f8Sclaudio 20091cc1f69Sclaudio /* state change inform RDE */ 20191cc1f69Sclaudio if (old_state != nbr->state) 202204df0f8Sclaudio ospfe_imsg_compose_rde(IMSG_NEIGHBOR_CHANGE, 203204df0f8Sclaudio nbr->peerid, 0, &new_state, sizeof(new_state)); 204204df0f8Sclaudio 205204df0f8Sclaudio /* bidirectional communication lost */ 20691cc1f69Sclaudio if (old_state & ~NBR_STA_PRELIM && nbr->state & NBR_STA_PRELIM) 207204df0f8Sclaudio if_fsm(nbr->iface, IF_EVT_NBR_CHNG); 208204df0f8Sclaudio 20991cc1f69Sclaudio /* neighbor changed from/to FULL originate new rtr and net LSA */ 21091cc1f69Sclaudio if (old_state != nbr->state && (old_state & NBR_STA_FULL || 21191cc1f69Sclaudio nbr->state & NBR_STA_FULL)) { 21291cc1f69Sclaudio orig_rtr_lsa(nbr->iface->area); 21391cc1f69Sclaudio if (nbr->iface->state & IF_STA_DR) 21491cc1f69Sclaudio orig_net_lsa(nbr->iface); 21591cc1f69Sclaudio } 21691cc1f69Sclaudio 217204df0f8Sclaudio if (old_state != nbr->state) { 218204df0f8Sclaudio nbr->stats.sta_chng++; 219204df0f8Sclaudio log_debug("nbr_fsm: event %s resulted in action %s and " 220204df0f8Sclaudio "changing state for neighbor ID %s from %s to %s", 221204df0f8Sclaudio nbr_event_name(event), 222204df0f8Sclaudio nbr_action_name(nbr_fsm_tbl[i].action), 223204df0f8Sclaudio inet_ntoa(nbr->id), nbr_state_name(old_state), 224204df0f8Sclaudio nbr_state_name(nbr->state)); 225204df0f8Sclaudio } 226204df0f8Sclaudio 227204df0f8Sclaudio return (ret); 228204df0f8Sclaudio } 229204df0f8Sclaudio 230204df0f8Sclaudio void 231204df0f8Sclaudio nbr_init(u_int32_t hashsize) 232204df0f8Sclaudio { 233204df0f8Sclaudio u_int32_t hs, i; 234204df0f8Sclaudio 235204df0f8Sclaudio for (hs = 1; hs < hashsize; hs <<= 1) 236204df0f8Sclaudio ; 237204df0f8Sclaudio nbrtable.hashtbl = calloc(hs, sizeof(struct nbr_head)); 238204df0f8Sclaudio if (nbrtable.hashtbl == NULL) 239204df0f8Sclaudio fatal("nbr_init"); 240204df0f8Sclaudio 241204df0f8Sclaudio for (i = 0; i < hs; i++) 242204df0f8Sclaudio LIST_INIT(&nbrtable.hashtbl[i]); 243204df0f8Sclaudio 244204df0f8Sclaudio nbrtable.hashmask = hs - 1; 245204df0f8Sclaudio } 246204df0f8Sclaudio 247204df0f8Sclaudio struct nbr * 248204df0f8Sclaudio nbr_new(u_int32_t nbr_id, struct iface *iface, int self) 249204df0f8Sclaudio { 250204df0f8Sclaudio struct nbr_head *head; 251204df0f8Sclaudio struct nbr *nbr = NULL; 252204df0f8Sclaudio struct rde_nbr rn; 253204df0f8Sclaudio 254204df0f8Sclaudio if ((nbr = calloc(1, sizeof(*nbr))) == NULL) 255204df0f8Sclaudio fatal("nbr_new"); 256204df0f8Sclaudio 257204df0f8Sclaudio nbr->state = NBR_STA_DOWN; 258204df0f8Sclaudio nbr->master = true; 259204df0f8Sclaudio nbr->dd_seq_num = arc4random(); /* RFC: some unique value */ 260204df0f8Sclaudio nbr->id.s_addr = nbr_id; 261204df0f8Sclaudio 262204df0f8Sclaudio /* get next unused peerid */ 263204df0f8Sclaudio while (nbr_find_peerid(++peercnt)) 264204df0f8Sclaudio ; 265204df0f8Sclaudio nbr->peerid = peercnt; 266204df0f8Sclaudio head = NBR_HASH(nbr->peerid); 267204df0f8Sclaudio LIST_INSERT_HEAD(head, nbr, hash); 268204df0f8Sclaudio 269204df0f8Sclaudio /* add to peer list */ 270204df0f8Sclaudio nbr->iface = iface; 271204df0f8Sclaudio LIST_INSERT_HEAD(&iface->nbr_list, nbr, entry); 272204df0f8Sclaudio 273204df0f8Sclaudio TAILQ_INIT(&nbr->ls_retrans_list); 274204df0f8Sclaudio TAILQ_INIT(&nbr->db_sum_list); 275204df0f8Sclaudio TAILQ_INIT(&nbr->ls_req_list); 276204df0f8Sclaudio 277204df0f8Sclaudio nbr->ls_req = NULL; 278204df0f8Sclaudio 279204df0f8Sclaudio if (self) { 280204df0f8Sclaudio nbr->state = NBR_STA_FULL; 281204df0f8Sclaudio nbr->addr.s_addr = iface->addr.s_addr; 282204df0f8Sclaudio nbr->priority = iface->priority; 283204df0f8Sclaudio } 284204df0f8Sclaudio 285204df0f8Sclaudio /* set event structures */ 286204df0f8Sclaudio evtimer_set(&nbr->inactivity_timer, nbr_itimer, nbr); 287204df0f8Sclaudio evtimer_set(&nbr->db_tx_timer, db_tx_timer, nbr); 288204df0f8Sclaudio evtimer_set(&nbr->lsreq_tx_timer, ls_req_tx_timer, nbr); 289*cb75af8bSclaudio evtimer_set(&nbr->ls_retrans_timer, ls_retrans_timer, nbr); 290204df0f8Sclaudio evtimer_set(&nbr->adj_timer, nbr_adj_timer, nbr); 291204df0f8Sclaudio 292204df0f8Sclaudio log_debug("nbr_new: neighbor ID %s, peerid %lu", 293204df0f8Sclaudio inet_ntoa(nbr->id), nbr->peerid); 294204df0f8Sclaudio 295204df0f8Sclaudio bzero(&rn, sizeof(rn)); 296204df0f8Sclaudio rn.id.s_addr = nbr->id.s_addr; 297204df0f8Sclaudio rn.area_id.s_addr = nbr->iface->area->id.s_addr; 298204df0f8Sclaudio rn.state = nbr->state; 299204df0f8Sclaudio rn.self = self; 300204df0f8Sclaudio ospfe_imsg_compose_rde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, &rn, 301204df0f8Sclaudio sizeof(rn)); 302204df0f8Sclaudio 303204df0f8Sclaudio return (nbr); 304204df0f8Sclaudio } 305204df0f8Sclaudio 306204df0f8Sclaudio int 307204df0f8Sclaudio nbr_del(struct nbr *nbr) 308204df0f8Sclaudio { 309204df0f8Sclaudio log_debug("nbr_del: neighbor ID %s, peerid %lu", inet_ntoa(nbr->id), 310204df0f8Sclaudio nbr->peerid); 311204df0f8Sclaudio 312204df0f8Sclaudio if (nbr == nbr->iface->self) 313204df0f8Sclaudio return (0); 314204df0f8Sclaudio 315204df0f8Sclaudio ospfe_imsg_compose_rde(IMSG_NEIGHBOR_DOWN, nbr->peerid, 0, NULL, 0); 316204df0f8Sclaudio 317204df0f8Sclaudio /* clear lists */ 318204df0f8Sclaudio ls_retrans_list_clr(nbr); 319204df0f8Sclaudio db_sum_list_clr(nbr); 320204df0f8Sclaudio ls_req_list_clr(nbr); 321204df0f8Sclaudio 322204df0f8Sclaudio LIST_REMOVE(nbr, entry); 323204df0f8Sclaudio LIST_REMOVE(nbr, hash); 324204df0f8Sclaudio 325204df0f8Sclaudio free(nbr); 326204df0f8Sclaudio 327204df0f8Sclaudio return (0); 328204df0f8Sclaudio } 329204df0f8Sclaudio 330204df0f8Sclaudio struct nbr * 331204df0f8Sclaudio nbr_find_peerid(u_int32_t peerid) 332204df0f8Sclaudio { 333204df0f8Sclaudio struct nbr_head *head; 334204df0f8Sclaudio struct nbr *nbr; 335204df0f8Sclaudio 336204df0f8Sclaudio head = NBR_HASH(peerid); 337204df0f8Sclaudio 338204df0f8Sclaudio LIST_FOREACH(nbr, head, hash) { 339204df0f8Sclaudio if (nbr->peerid == peerid) 340204df0f8Sclaudio return (nbr); 341204df0f8Sclaudio } 342204df0f8Sclaudio 343204df0f8Sclaudio return (NULL); 344204df0f8Sclaudio } 345204df0f8Sclaudio 346204df0f8Sclaudio struct nbr * 347204df0f8Sclaudio nbr_find_id(struct iface *iface, u_int32_t rtr_id) 348204df0f8Sclaudio { 349204df0f8Sclaudio struct nbr *nbr = NULL; 350204df0f8Sclaudio 351204df0f8Sclaudio LIST_FOREACH(nbr, &iface->nbr_list, entry) { 352204df0f8Sclaudio if (nbr->id.s_addr == rtr_id) { 353204df0f8Sclaudio return (nbr); 354204df0f8Sclaudio } 355204df0f8Sclaudio } 356204df0f8Sclaudio 357204df0f8Sclaudio return (NULL); 358204df0f8Sclaudio } 359204df0f8Sclaudio 360204df0f8Sclaudio /* timers */ 361204df0f8Sclaudio void 362204df0f8Sclaudio nbr_itimer(int fd, short event, void *arg) 363204df0f8Sclaudio { 364204df0f8Sclaudio struct nbr *nbr = arg; 365204df0f8Sclaudio 366204df0f8Sclaudio log_debug("nbr_itimer: %s", inet_ntoa(nbr->id)); 367204df0f8Sclaudio 36837cea71bSnorby if (nbr->state == NBR_STA_DOWN) { 36937cea71bSnorby nbr_del(nbr); 37037cea71bSnorby } else 371204df0f8Sclaudio nbr_fsm(nbr, NBR_EVT_ITIMER); 372204df0f8Sclaudio } 373204df0f8Sclaudio 374204df0f8Sclaudio int 375204df0f8Sclaudio nbr_start_itimer(struct nbr *nbr) 376204df0f8Sclaudio { 377204df0f8Sclaudio struct timeval tv; 378204df0f8Sclaudio 379204df0f8Sclaudio log_debug("nbr_start_itimer: %s", inet_ntoa(nbr->id)); 380204df0f8Sclaudio 381204df0f8Sclaudio timerclear(&tv); 382204df0f8Sclaudio tv.tv_sec = nbr->iface->dead_interval; 383204df0f8Sclaudio 384204df0f8Sclaudio return (evtimer_add(&nbr->inactivity_timer, &tv)); 385204df0f8Sclaudio } 386204df0f8Sclaudio 387204df0f8Sclaudio int 388204df0f8Sclaudio nbr_stop_itimer(struct nbr *nbr) 389204df0f8Sclaudio { 390204df0f8Sclaudio return (evtimer_del(&nbr->inactivity_timer)); 391204df0f8Sclaudio } 392204df0f8Sclaudio 393204df0f8Sclaudio int 394204df0f8Sclaudio nbr_reset_itimer(struct nbr *nbr) 395204df0f8Sclaudio { 396204df0f8Sclaudio struct timeval tv; 397204df0f8Sclaudio 398204df0f8Sclaudio timerclear(&tv); 399204df0f8Sclaudio tv.tv_sec = nbr->iface->dead_interval; 400204df0f8Sclaudio 401204df0f8Sclaudio return (evtimer_add(&nbr->inactivity_timer, &tv)); 402204df0f8Sclaudio } 403204df0f8Sclaudio 404204df0f8Sclaudio void 405204df0f8Sclaudio nbr_adj_timer(int fd, short event, void *arg) 406204df0f8Sclaudio { 407204df0f8Sclaudio struct nbr *nbr = arg; 408204df0f8Sclaudio 409f71e573aSclaudio if (nbr->state & NBR_STA_ACTIVE && nbr->state != NBR_STA_FULL) { 410204df0f8Sclaudio log_debug("nbr_adj_timer: failed to form adjacency"); 411204df0f8Sclaudio nbr_fsm(nbr, NBR_EVT_ADJTMOUT); 412204df0f8Sclaudio } 413204df0f8Sclaudio } 414204df0f8Sclaudio 415204df0f8Sclaudio int 416204df0f8Sclaudio nbr_start_adj_timer(struct nbr *nbr) 417204df0f8Sclaudio { 418204df0f8Sclaudio struct timeval tv; 419204df0f8Sclaudio 420204df0f8Sclaudio log_debug("nbr_start_adj_timer: %s", inet_ntoa(nbr->id)); 421204df0f8Sclaudio 422204df0f8Sclaudio timerclear(&tv); 423204df0f8Sclaudio tv.tv_sec = DEFAULT_ADJ_TMOUT; 424204df0f8Sclaudio 425204df0f8Sclaudio return (evtimer_add(&nbr->adj_timer, &tv)); 426204df0f8Sclaudio } 427204df0f8Sclaudio 428204df0f8Sclaudio /* actions */ 429204df0f8Sclaudio int 430204df0f8Sclaudio nbr_act_start(struct nbr *nbr) 431204df0f8Sclaudio { 432204df0f8Sclaudio log_debug("nbr_act_start: neighbor ID %s", inet_ntoa(nbr->id)); 433204df0f8Sclaudio 434204df0f8Sclaudio return (-1); 435204df0f8Sclaudio } 436204df0f8Sclaudio 437204df0f8Sclaudio int 438204df0f8Sclaudio nbr_act_reset_itimer(struct nbr *nbr) 439204df0f8Sclaudio { 440204df0f8Sclaudio if (nbr_reset_itimer(nbr)) { 441204df0f8Sclaudio log_warnx("nbr_act_reset_itimer: cannot schedule inactivity " 442204df0f8Sclaudio "timer, neighbor ID %s", inet_ntoa(nbr->id)); 443204df0f8Sclaudio return (-1); 444204df0f8Sclaudio } 445204df0f8Sclaudio 446204df0f8Sclaudio return (0); 447204df0f8Sclaudio } 448204df0f8Sclaudio 449204df0f8Sclaudio int 450204df0f8Sclaudio nbr_act_start_itimer(struct nbr *nbr) 451204df0f8Sclaudio { 452204df0f8Sclaudio if (nbr_start_itimer(nbr)) { 453204df0f8Sclaudio log_warnx("nbr_act_start_itimer: cannot schedule inactivity " 454204df0f8Sclaudio "timer, neighbor ID %s", 455204df0f8Sclaudio inet_ntoa(nbr->id)); 456204df0f8Sclaudio return (-1); 457204df0f8Sclaudio } 458204df0f8Sclaudio 459204df0f8Sclaudio return (0); 460204df0f8Sclaudio } 461204df0f8Sclaudio 462204df0f8Sclaudio int 463204df0f8Sclaudio nbr_adj_ok(struct nbr *nbr) 464204df0f8Sclaudio { 465204df0f8Sclaudio struct iface *iface = nbr->iface; 466204df0f8Sclaudio 467204df0f8Sclaudio switch (iface->type) { 468204df0f8Sclaudio case IF_TYPE_POINTOPOINT: 469204df0f8Sclaudio case IF_TYPE_VIRTUALLINK: 470204df0f8Sclaudio case IF_TYPE_POINTOMULTIPOINT: 471204df0f8Sclaudio break; 472204df0f8Sclaudio case IF_TYPE_BROADCAST: 473204df0f8Sclaudio case IF_TYPE_NBMA: 474204df0f8Sclaudio /* 475204df0f8Sclaudio * if neighbor is dr, bdr or router self is dr or bdr 476204df0f8Sclaudio * start forming adjacancy 477204df0f8Sclaudio */ 478204df0f8Sclaudio if (iface->dr == nbr || iface->bdr == nbr || 479204df0f8Sclaudio iface->state & IF_STA_DRORBDR) 480204df0f8Sclaudio break; 481204df0f8Sclaudio return (0); 482204df0f8Sclaudio default: 483204df0f8Sclaudio fatalx("nbr_act_ok: unknown interface type"); 484204df0f8Sclaudio } 485204df0f8Sclaudio return (1); 486204df0f8Sclaudio } 487204df0f8Sclaudio 488204df0f8Sclaudio int 489204df0f8Sclaudio nbr_act_eval(struct nbr *nbr) 490204df0f8Sclaudio { 491204df0f8Sclaudio log_debug("nbr_act_eval: neighbor ID %s", inet_ntoa(nbr->id)); 492204df0f8Sclaudio 493204df0f8Sclaudio if (!nbr_adj_ok(nbr)) { 494204df0f8Sclaudio nbr->state = NBR_STA_2_WAY; 495204df0f8Sclaudio return (0); 496204df0f8Sclaudio } 497204df0f8Sclaudio 498204df0f8Sclaudio nbr->state = NBR_STA_XSTRT; 499204df0f8Sclaudio nbr->master = true; 500204df0f8Sclaudio nbr->dd_seq_num++; /* as per RFC */ 501299d99d9Sclaudio nbr->dd_pending = 0; 502204df0f8Sclaudio /* initial db negotiation */ 503204df0f8Sclaudio start_db_tx_timer(nbr); 504204df0f8Sclaudio 505204df0f8Sclaudio return (0); 506204df0f8Sclaudio } 507204df0f8Sclaudio 508204df0f8Sclaudio int 509204df0f8Sclaudio nbr_act_snapshot(struct nbr *nbr) 510204df0f8Sclaudio { 511204df0f8Sclaudio log_debug("nbr_act_snapshot: neighbor ID %s", inet_ntoa(nbr->id)); 512204df0f8Sclaudio 513204df0f8Sclaudio stop_db_tx_timer(nbr); 514204df0f8Sclaudio nbr_start_adj_timer(nbr); 515204df0f8Sclaudio 516204df0f8Sclaudio ospfe_imsg_compose_rde(IMSG_DB_SNAPSHOT, nbr->peerid, 0, NULL, 0); 517204df0f8Sclaudio 518204df0f8Sclaudio return (0); 519204df0f8Sclaudio } 520204df0f8Sclaudio 521204df0f8Sclaudio int 522204df0f8Sclaudio nbr_act_exchange_done(struct nbr *nbr) 523204df0f8Sclaudio { 524204df0f8Sclaudio log_debug("nbr_act_exchange_done: neighbor ID %s", inet_ntoa(nbr->id)); 525204df0f8Sclaudio 526204df0f8Sclaudio if (nbr->master) 527204df0f8Sclaudio stop_db_tx_timer(nbr); 528204df0f8Sclaudio 529299d99d9Sclaudio if (ls_req_list_empty(nbr) && nbr->state == NBR_STA_XCHNG && 530299d99d9Sclaudio nbr->dd_pending == 0) { 531204df0f8Sclaudio nbr->state = NBR_STA_FULL; 532204df0f8Sclaudio return (0); 533204df0f8Sclaudio } 534204df0f8Sclaudio 535204df0f8Sclaudio nbr->state = NBR_STA_LOAD; 536299d99d9Sclaudio 537299d99d9Sclaudio if (!ls_req_list_empty(nbr)) 538204df0f8Sclaudio start_ls_req_tx_timer(nbr); 539204df0f8Sclaudio 540204df0f8Sclaudio return (0); 541204df0f8Sclaudio } 542204df0f8Sclaudio 543204df0f8Sclaudio int 544204df0f8Sclaudio nbr_act_adj_ok(struct nbr *nbr) 545204df0f8Sclaudio { 546204df0f8Sclaudio log_debug("nbr_act_adj_ok: neighbor ID %s", inet_ntoa(nbr->id)); 547204df0f8Sclaudio 548204df0f8Sclaudio if (nbr_adj_ok(nbr)) { 549204df0f8Sclaudio if (nbr->state == NBR_STA_2_WAY) 550204df0f8Sclaudio return (nbr_act_eval(nbr)); 551204df0f8Sclaudio } else { 552204df0f8Sclaudio nbr->state = NBR_STA_2_WAY; 553204df0f8Sclaudio return (nbr_act_clear_lists(nbr)); 554204df0f8Sclaudio } 555204df0f8Sclaudio 556204df0f8Sclaudio return (0); 557204df0f8Sclaudio } 558204df0f8Sclaudio 559204df0f8Sclaudio int 560204df0f8Sclaudio nbr_act_restart_dd(struct nbr *nbr) 561204df0f8Sclaudio { 562204df0f8Sclaudio log_debug("nbr_act_restart_dd: neighbor ID %s", inet_ntoa(nbr->id)); 563204df0f8Sclaudio 5643922c68bSclaudio nbr_act_clear_lists(nbr); 5653922c68bSclaudio 5663922c68bSclaudio if (!nbr_adj_ok(nbr)) { 5673922c68bSclaudio nbr->state = NBR_STA_2_WAY; 5683922c68bSclaudio return (0); 5693922c68bSclaudio } 5703922c68bSclaudio 5713922c68bSclaudio nbr->state = NBR_STA_XSTRT; 572204df0f8Sclaudio nbr->master = true; 573204df0f8Sclaudio nbr->dd_seq_num += arc4random() & 0xffff; 574299d99d9Sclaudio nbr->dd_pending = 0; 575204df0f8Sclaudio 5763922c68bSclaudio /* initial db negotiation */ 5773922c68bSclaudio start_db_tx_timer(nbr); 5783922c68bSclaudio 5793922c68bSclaudio return (0); 580204df0f8Sclaudio } 581204df0f8Sclaudio 582204df0f8Sclaudio int 583204df0f8Sclaudio nbr_act_delete(struct nbr *nbr) 584204df0f8Sclaudio { 58537cea71bSnorby struct timeval tv; 58637cea71bSnorby 587204df0f8Sclaudio log_debug("nbr_act_delete: neighbor ID %s", inet_ntoa(nbr->id)); 588204df0f8Sclaudio 589204df0f8Sclaudio /* stop timers */ 590204df0f8Sclaudio if (nbr_stop_itimer(nbr)) { 591204df0f8Sclaudio log_warnx("nbr_act_delete: error removing inactivity timer, " 592204df0f8Sclaudio "neighbor ID %s", inet_ntoa(nbr->id)); 593204df0f8Sclaudio return (-1); 594204df0f8Sclaudio } 595204df0f8Sclaudio 596204df0f8Sclaudio /* clear dr and bdr */ 597204df0f8Sclaudio nbr->dr.s_addr = 0; 598204df0f8Sclaudio nbr->bdr.s_addr = 0; 599204df0f8Sclaudio 60037cea71bSnorby /* schedule kill timer */ 60137cea71bSnorby timerclear(&tv); 60237cea71bSnorby tv.tv_sec = DEFAULT_NBR_TMOUT; 60337cea71bSnorby 60437cea71bSnorby if (evtimer_add(&nbr->inactivity_timer, &tv)) { 60537cea71bSnorby log_warnx("nbr_act_delete: error scheduling neighbor ID %s " 60637cea71bSnorby "for removal", inet_ntoa(nbr->id)); 60737cea71bSnorby } 60837cea71bSnorby 609204df0f8Sclaudio return (nbr_act_clear_lists(nbr)); 610204df0f8Sclaudio } 611204df0f8Sclaudio 612204df0f8Sclaudio int 613204df0f8Sclaudio nbr_act_clear_lists(struct nbr *nbr) 614204df0f8Sclaudio { 615204df0f8Sclaudio log_debug("nbr_act_clear_lists: neighbor ID %s", inet_ntoa(nbr->id)); 616204df0f8Sclaudio 617204df0f8Sclaudio if (stop_db_tx_timer(nbr)) { 618204df0f8Sclaudio log_warnx("nbr_act_delete: error removing db_tx_timer, " 619204df0f8Sclaudio "neighbor ID %s", inet_ntoa(nbr->id)); 620204df0f8Sclaudio return (-1); 621204df0f8Sclaudio } 622204df0f8Sclaudio 623204df0f8Sclaudio if (stop_ls_req_tx_timer(nbr)) { 624204df0f8Sclaudio log_warnx("nbr_act_delete: error removing lsreq_tx_timer, " 625204df0f8Sclaudio "neighbor ID %s", inet_ntoa(nbr->id)); 626204df0f8Sclaudio return (-1); 627204df0f8Sclaudio } 628204df0f8Sclaudio 629204df0f8Sclaudio /* clear lists */ 630204df0f8Sclaudio ls_retrans_list_clr(nbr); 631204df0f8Sclaudio db_sum_list_clr(nbr); 632204df0f8Sclaudio ls_req_list_clr(nbr); 633204df0f8Sclaudio 634204df0f8Sclaudio return (0); 635204df0f8Sclaudio } 636204df0f8Sclaudio 637204df0f8Sclaudio int 638204df0f8Sclaudio nbr_act_hello_check(struct nbr *nbr) 639204df0f8Sclaudio { 640204df0f8Sclaudio log_debug("nbr_act_hello_check: neighbor ID %s", inet_ntoa(nbr->id)); 641204df0f8Sclaudio 642204df0f8Sclaudio return (-1); 643204df0f8Sclaudio } 644204df0f8Sclaudio 645204df0f8Sclaudio struct ctl_nbr * 646204df0f8Sclaudio nbr_to_ctl(struct nbr *nbr) 647204df0f8Sclaudio { 648204df0f8Sclaudio static struct ctl_nbr nctl; 649204df0f8Sclaudio struct timeval tv, now, res; 650204df0f8Sclaudio struct lsa_entry *le; 651204df0f8Sclaudio 652204df0f8Sclaudio memcpy(nctl.name, nbr->iface->name, sizeof(nctl.name)); 653204df0f8Sclaudio memcpy(&nctl.id, &nbr->id, sizeof(nctl.id)); 654d13813cbSclaudio memcpy(&nctl.addr, &nbr->addr, sizeof(nctl.addr)); 655204df0f8Sclaudio memcpy(&nctl.dr, &nbr->dr, sizeof(nctl.dr)); 656204df0f8Sclaudio memcpy(&nctl.bdr, &nbr->bdr, sizeof(nctl.bdr)); 657204df0f8Sclaudio memcpy(&nctl.area, &nbr->iface->area->id, sizeof(nctl.area)); 658204df0f8Sclaudio 659204df0f8Sclaudio /* this list is 99% of the time empty so that's OK for now */ 660204df0f8Sclaudio nctl.db_sum_lst_cnt = 0; 661204df0f8Sclaudio TAILQ_FOREACH(le, &nbr->db_sum_list, entry) 662204df0f8Sclaudio nctl.db_sum_lst_cnt++; 663204df0f8Sclaudio 664204df0f8Sclaudio nctl.ls_req_lst_cnt = nbr->ls_req_cnt; 665204df0f8Sclaudio 666204df0f8Sclaudio /* XXX */ 667204df0f8Sclaudio nctl.ls_retrans_lst_cnt = 0; 668204df0f8Sclaudio TAILQ_FOREACH(le, &nbr->ls_retrans_list, entry) 669204df0f8Sclaudio nctl.ls_retrans_lst_cnt++; 670204df0f8Sclaudio 671204df0f8Sclaudio nctl.nbr_state = nbr->state; 672944ca59cSclaudio 673944ca59cSclaudio /* 674944ca59cSclaudio * We need to trick a bit to show the remote iface state. 675944ca59cSclaudio * The idea is to print DR, BDR or DROther dependent on 676944ca59cSclaudio * the type of the neighbor. 677944ca59cSclaudio */ 678944ca59cSclaudio if (nbr->iface->dr == nbr) 679944ca59cSclaudio nctl.iface_state = IF_STA_DR; 680944ca59cSclaudio else if (nbr->iface->bdr == nbr) 681944ca59cSclaudio nctl.iface_state = IF_STA_BACKUP; 682944ca59cSclaudio else if (nbr->iface->state & IF_STA_MULTI) 683944ca59cSclaudio nctl.iface_state = IF_STA_DROTHER; 684944ca59cSclaudio else 685204df0f8Sclaudio nctl.iface_state = nbr->iface->state; 686204df0f8Sclaudio 687204df0f8Sclaudio nctl.state_chng_cnt = nbr->stats.sta_chng; 688204df0f8Sclaudio 689204df0f8Sclaudio nctl.priority = nbr->priority; 690204df0f8Sclaudio nctl.options = nbr->options; 691204df0f8Sclaudio 692204df0f8Sclaudio gettimeofday(&now, NULL); 693204df0f8Sclaudio if (evtimer_pending(&nbr->inactivity_timer, &tv)) { 694204df0f8Sclaudio timersub(&tv, &now, &res); 695204df0f8Sclaudio nctl.dead_timer = res.tv_sec; 696204df0f8Sclaudio } else 697204df0f8Sclaudio nctl.dead_timer = 0; 698204df0f8Sclaudio 699204df0f8Sclaudio return (&nctl); 700204df0f8Sclaudio } 701204df0f8Sclaudio 702204df0f8Sclaudio /* names */ 703204df0f8Sclaudio const char * 704204df0f8Sclaudio nbr_state_name(int state) 705204df0f8Sclaudio { 706204df0f8Sclaudio switch (state) { 707204df0f8Sclaudio case NBR_STA_DOWN: 708204df0f8Sclaudio return ("DOWN"); 709204df0f8Sclaudio case NBR_STA_ATTEMPT: 710204df0f8Sclaudio return ("ATTEMPT"); 711204df0f8Sclaudio case NBR_STA_INIT: 712204df0f8Sclaudio return ("INIT"); 713204df0f8Sclaudio case NBR_STA_2_WAY: 714204df0f8Sclaudio return ("2-WAY"); 715204df0f8Sclaudio case NBR_STA_XSTRT: 716204df0f8Sclaudio return ("EXSTART"); 717204df0f8Sclaudio case NBR_STA_SNAP: 718204df0f8Sclaudio return ("SNAPSHOT"); 719204df0f8Sclaudio case NBR_STA_XCHNG: 720204df0f8Sclaudio return ("EXCHANGE"); 721204df0f8Sclaudio case NBR_STA_LOAD: 722204df0f8Sclaudio return ("LOADING"); 723204df0f8Sclaudio case NBR_STA_FULL: 724204df0f8Sclaudio return ("FULL"); 725204df0f8Sclaudio default: 726204df0f8Sclaudio return ("UNKNOWN"); 727204df0f8Sclaudio } 728204df0f8Sclaudio } 729204df0f8Sclaudio 730204df0f8Sclaudio const char * 731204df0f8Sclaudio nbr_event_name(int event) 732204df0f8Sclaudio { 733204df0f8Sclaudio return (nbr_event_names[event]); 734204df0f8Sclaudio } 735204df0f8Sclaudio 736204df0f8Sclaudio const char * 737204df0f8Sclaudio nbr_action_name(int action) 738204df0f8Sclaudio { 739204df0f8Sclaudio return (nbr_action_names[action]); 740204df0f8Sclaudio } 741204df0f8Sclaudio 742204df0f8Sclaudio struct lsa_hdr * 743204df0f8Sclaudio lsa_hdr_new(void) 744204df0f8Sclaudio { 745204df0f8Sclaudio struct lsa_hdr *lsa_hdr = NULL; 746204df0f8Sclaudio 747204df0f8Sclaudio if ((lsa_hdr = calloc(1, sizeof(*lsa_hdr))) == NULL) 748204df0f8Sclaudio fatal("lsa_hdr_new"); 749204df0f8Sclaudio 750204df0f8Sclaudio return (lsa_hdr); 751204df0f8Sclaudio } 752