Annotation of embedaddon/bird2/proto/ospf/neighbor.c, revision 1.1
1.1 ! misho 1: /*
! 2: * BIRD -- OSPF
! 3: *
! 4: * (c) 1999--2004 Ondrej Filip <feela@network.cz>
! 5: * (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
! 6: * (c) 2009--2014 CZ.NIC z.s.p.o.
! 7: *
! 8: * Can be freely distributed and used under the terms of the GNU GPL.
! 9: */
! 10:
! 11: #include "ospf.h"
! 12:
! 13:
! 14: const char *ospf_ns_names[] = {
! 15: "Down", "Attempt", "Init", "2-Way", "ExStart", "Exchange", "Loading", "Full"
! 16: };
! 17:
! 18: const char *ospf_inm_names[] = {
! 19: "HelloReceived", "Start", "2-WayReceived", "NegotiationDone", "ExchangeDone",
! 20: "BadLSReq", "LoadingDone", "AdjOK?", "SeqNumberMismatch", "1-WayReceived",
! 21: "KillNbr", "InactivityTimer", "LLDown"
! 22: };
! 23:
! 24:
! 25: static int can_do_adj(struct ospf_neighbor *n);
! 26: static void inactivity_timer_hook(timer * timer);
! 27: static void dbdes_timer_hook(timer *t);
! 28: static void lsrq_timer_hook(timer *t);
! 29: static void lsrt_timer_hook(timer *t);
! 30: static void ackd_timer_hook(timer *t);
! 31: static void ospf_neigh_stop_graceful_restart_(struct ospf_neighbor *n);
! 32: static void graceful_restart_timeout(timer *t);
! 33:
! 34:
! 35: static void
! 36: init_lists(struct ospf_proto *p, struct ospf_neighbor *n)
! 37: {
! 38: s_init_list(&(n->lsrql));
! 39: n->lsrqi = SHEAD(n->lsrql);
! 40: n->lsrqh = ospf_top_new(p, n->pool);
! 41:
! 42: s_init_list(&(n->lsrtl));
! 43: n->lsrth = ospf_top_new(p, n->pool);
! 44: }
! 45:
! 46: static void
! 47: release_lsrtl(struct ospf_proto *p, struct ospf_neighbor *n)
! 48: {
! 49: struct top_hash_entry *ret, *en;
! 50:
! 51: WALK_SLIST(ret, n->lsrtl)
! 52: {
! 53: en = ospf_hash_find_entry(p->gr, ret);
! 54: if (en)
! 55: en->ret_count--;
! 56: }
! 57: }
! 58:
! 59: /* Resets LSA request and retransmit lists.
! 60: * We do not reset DB summary list iterator here,
! 61: * it is reset during entering EXCHANGE state.
! 62: */
! 63: static void
! 64: reset_lists(struct ospf_proto *p, struct ospf_neighbor *n)
! 65: {
! 66: release_lsrtl(p, n);
! 67: ospf_top_free(n->lsrqh);
! 68: ospf_top_free(n->lsrth);
! 69: ospf_reset_lsack_queue(n);
! 70:
! 71: tm_stop(n->dbdes_timer);
! 72: tm_stop(n->lsrq_timer);
! 73: tm_stop(n->lsrt_timer);
! 74: tm_stop(n->ackd_timer);
! 75:
! 76: init_lists(p, n);
! 77: }
! 78:
! 79: struct ospf_neighbor *
! 80: ospf_neighbor_new(struct ospf_iface *ifa)
! 81: {
! 82: struct ospf_proto *p = ifa->oa->po;
! 83: struct pool *pool = rp_new(p->p.pool, "OSPF Neighbor");
! 84: struct ospf_neighbor *n = mb_allocz(pool, sizeof(struct ospf_neighbor));
! 85:
! 86: n->pool = pool;
! 87: n->ifa = ifa;
! 88: add_tail(&ifa->neigh_list, NODE n);
! 89: n->state = NEIGHBOR_DOWN;
! 90:
! 91: init_lists(p, n);
! 92: s_init(&(n->dbsi), &(p->lsal));
! 93:
! 94: init_list(&n->ackl[ACKL_DIRECT]);
! 95: init_list(&n->ackl[ACKL_DELAY]);
! 96:
! 97: n->inactim = tm_new_init(pool, inactivity_timer_hook, n, 0, 0);
! 98: n->dbdes_timer = tm_new_init(pool, dbdes_timer_hook, n, ifa->rxmtint S, 0);
! 99: n->lsrq_timer = tm_new_init(pool, lsrq_timer_hook, n, ifa->rxmtint S, 0);
! 100: n->lsrt_timer = tm_new_init(pool, lsrt_timer_hook, n, ifa->rxmtint S, 0);
! 101: n->ackd_timer = tm_new_init(pool, ackd_timer_hook, n, ifa->rxmtint S / 2, 0);
! 102:
! 103: return (n);
! 104: }
! 105:
! 106: static void
! 107: ospf_neigh_down(struct ospf_neighbor *n)
! 108: {
! 109: struct ospf_iface *ifa = n->ifa;
! 110: struct ospf_proto *p = ifa->oa->po;
! 111: u32 rid = n->rid;
! 112:
! 113: if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
! 114: {
! 115: struct nbma_node *nn = find_nbma_node(ifa, n->ip);
! 116: if (nn)
! 117: nn->found = 0;
! 118: }
! 119:
! 120: s_get(&(n->dbsi));
! 121: release_lsrtl(p, n);
! 122: rem_node(NODE n);
! 123: rfree(n->pool);
! 124:
! 125: OSPF_TRACE(D_EVENTS, "Neighbor %R on %s removed", rid, ifa->ifname);
! 126: }
! 127:
! 128: /**
! 129: * ospf_neigh_chstate - handles changes related to new or lod state of neighbor
! 130: * @n: OSPF neighbor
! 131: * @state: new state
! 132: *
! 133: * Many actions have to be taken acording to a change of state of a neighbor. It
! 134: * starts rxmt timers, call interface state machine etc.
! 135: */
! 136: static void
! 137: ospf_neigh_chstate(struct ospf_neighbor *n, u8 state)
! 138: {
! 139: struct ospf_iface *ifa = n->ifa;
! 140: struct ospf_proto *p = ifa->oa->po;
! 141: u8 old_state = n->state;
! 142: int old_fadj = ifa->fadj;
! 143:
! 144: if (state == old_state)
! 145: return;
! 146:
! 147: OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed state from %s to %s",
! 148: n->rid, ifa->ifname, ospf_ns_names[old_state], ospf_ns_names[state]);
! 149:
! 150: n->state = state;
! 151:
! 152: /* Increase number of partial adjacencies */
! 153: if ((state == NEIGHBOR_EXCHANGE) || (state == NEIGHBOR_LOADING))
! 154: p->padj++;
! 155:
! 156: /* Decrease number of partial adjacencies */
! 157: if ((old_state == NEIGHBOR_EXCHANGE) || (old_state == NEIGHBOR_LOADING))
! 158: p->padj--;
! 159:
! 160: /* Increase number of full adjacencies */
! 161: if (state == NEIGHBOR_FULL)
! 162: ifa->fadj++;
! 163:
! 164: /* Decrease number of full adjacencies */
! 165: if (old_state == NEIGHBOR_FULL)
! 166: ifa->fadj--;
! 167:
! 168: if ((ifa->fadj != old_fadj) && !n->gr_active)
! 169: {
! 170: /* RFC 2328 12.4 Event 4 - neighbor enters/leaves Full state */
! 171: ospf_notify_rt_lsa(ifa->oa);
! 172: ospf_notify_net_lsa(ifa);
! 173:
! 174: /* RFC 2328 12.4 Event 8 - vlink state change */
! 175: if (ifa->type == OSPF_IT_VLINK)
! 176: ospf_notify_rt_lsa(ifa->voa);
! 177: }
! 178:
! 179: if (state == NEIGHBOR_EXSTART)
! 180: {
! 181: /* First time adjacency attempt */
! 182: if (old_state < NEIGHBOR_EXSTART)
! 183: n->dds = random_u32();
! 184:
! 185: n->dds++;
! 186: n->myimms = DBDES_IMMS;
! 187: n->got_my_rt_lsa = 0;
! 188:
! 189: tm_start(n->dbdes_timer, 0);
! 190: tm_start(n->ackd_timer, ifa->rxmtint S / 2);
! 191: }
! 192:
! 193: if (state > NEIGHBOR_EXSTART)
! 194: n->myimms &= ~DBDES_I;
! 195:
! 196: /* Generate NeighborChange event if needed, see RFC 2328 9.2 */
! 197: if ((state == NEIGHBOR_2WAY) && (old_state < NEIGHBOR_2WAY) && !n->gr_active)
! 198: ospf_iface_sm(ifa, ISM_NEICH);
! 199: if ((state < NEIGHBOR_2WAY) && (old_state >= NEIGHBOR_2WAY) && !n->gr_active)
! 200: ospf_iface_sm(ifa, ISM_NEICH);
! 201: }
! 202:
! 203: /**
! 204: * ospf_neigh_sm - ospf neighbor state machine
! 205: * @n: neighor
! 206: * @event: actual event
! 207: *
! 208: * This part implements the neighbor state machine as described in 10.3 of
! 209: * RFC 2328. The only difference is that state %NEIGHBOR_ATTEMPT is not
! 210: * used. We discover neighbors on nonbroadcast networks in the
! 211: * same way as on broadcast networks. The only difference is in
! 212: * sending hello packets. These are sent to IPs listed in
! 213: * @ospf_iface->nbma_list .
! 214: */
! 215: void
! 216: ospf_neigh_sm(struct ospf_neighbor *n, int event)
! 217: {
! 218: struct ospf_proto *p = n->ifa->oa->po;
! 219:
! 220: DBG("Neighbor state machine for %R on %s, event %s\n",
! 221: n->rid, n->ifa->ifname, ospf_inm_names[event]);
! 222:
! 223: switch (event)
! 224: {
! 225: case INM_START:
! 226: ospf_neigh_chstate(n, NEIGHBOR_ATTEMPT);
! 227: /* NBMA are used different way */
! 228: break;
! 229:
! 230: case INM_HELLOREC:
! 231: if (n->state < NEIGHBOR_INIT)
! 232: ospf_neigh_chstate(n, NEIGHBOR_INIT);
! 233:
! 234: /* Restart inactivity timer */
! 235: tm_start(n->inactim, n->ifa->deadint S);
! 236: break;
! 237:
! 238: case INM_2WAYREC:
! 239: if (n->state < NEIGHBOR_2WAY)
! 240: ospf_neigh_chstate(n, NEIGHBOR_2WAY);
! 241: if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n))
! 242: ospf_neigh_chstate(n, NEIGHBOR_EXSTART);
! 243: break;
! 244:
! 245: case INM_NEGDONE:
! 246: if (n->state == NEIGHBOR_EXSTART)
! 247: {
! 248: ospf_neigh_chstate(n, NEIGHBOR_EXCHANGE);
! 249:
! 250: /* Reset DB summary list iterator */
! 251: s_get(&(n->dbsi));
! 252: s_init(&(n->dbsi), &p->lsal);
! 253:
! 254: /* Add MaxAge LSA entries to retransmission list */
! 255: ospf_add_flushed_to_lsrt(p, n);
! 256: }
! 257: else
! 258: bug("NEGDONE and I'm not in EXSTART?");
! 259: break;
! 260:
! 261: case INM_EXDONE:
! 262: if (!EMPTY_SLIST(n->lsrql))
! 263: ospf_neigh_chstate(n, NEIGHBOR_LOADING);
! 264: else
! 265: ospf_neigh_chstate(n, NEIGHBOR_FULL);
! 266: break;
! 267:
! 268: case INM_LOADDONE:
! 269: ospf_neigh_chstate(n, NEIGHBOR_FULL);
! 270: break;
! 271:
! 272: case INM_ADJOK:
! 273: /* Can In build adjacency? */
! 274: if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n))
! 275: {
! 276: ospf_neigh_chstate(n, NEIGHBOR_EXSTART);
! 277: }
! 278: else if ((n->state >= NEIGHBOR_EXSTART) && !can_do_adj(n))
! 279: {
! 280: reset_lists(p, n);
! 281: ospf_neigh_chstate(n, NEIGHBOR_2WAY);
! 282: }
! 283: break;
! 284:
! 285: case INM_SEQMIS:
! 286: case INM_BADLSREQ:
! 287: if (n->state >= NEIGHBOR_EXCHANGE)
! 288: {
! 289: reset_lists(p, n);
! 290: ospf_neigh_chstate(n, NEIGHBOR_EXSTART);
! 291: }
! 292: break;
! 293:
! 294: case INM_KILLNBR:
! 295: case INM_LLDOWN:
! 296: case INM_INACTTIM:
! 297: if (n->gr_active && (event == INM_INACTTIM))
! 298: {
! 299: /* Just down the neighbor, but do not remove it */
! 300: reset_lists(p, n);
! 301: ospf_neigh_chstate(n, NEIGHBOR_DOWN);
! 302: break;
! 303: }
! 304:
! 305: if (n->gr_active)
! 306: ospf_neigh_stop_graceful_restart_(n);
! 307:
! 308: /* No need for reset_lists() */
! 309: ospf_neigh_chstate(n, NEIGHBOR_DOWN);
! 310: ospf_neigh_down(n);
! 311: break;
! 312:
! 313: case INM_1WAYREC:
! 314: reset_lists(p, n);
! 315: ospf_neigh_chstate(n, NEIGHBOR_INIT);
! 316: break;
! 317:
! 318: default:
! 319: bug("%s: INM - Unknown event?", p->p.name);
! 320: break;
! 321: }
! 322: }
! 323:
! 324: static int
! 325: can_do_adj(struct ospf_neighbor *n)
! 326: {
! 327: struct ospf_iface *ifa = n->ifa;
! 328: struct ospf_proto *p = ifa->oa->po;
! 329: int i = 0;
! 330:
! 331: switch (ifa->type)
! 332: {
! 333: case OSPF_IT_PTP:
! 334: case OSPF_IT_PTMP:
! 335: case OSPF_IT_VLINK:
! 336: i = 1;
! 337: break;
! 338: case OSPF_IT_BCAST:
! 339: case OSPF_IT_NBMA:
! 340: switch (ifa->state)
! 341: {
! 342: case OSPF_IS_DOWN:
! 343: case OSPF_IS_LOOP:
! 344: bug("%s: Iface %s in down state?", p->p.name, ifa->ifname);
! 345: break;
! 346: case OSPF_IS_WAITING:
! 347: DBG("%s: Neighbor? on iface %s\n", p->p.name, ifa->ifname);
! 348: break;
! 349: case OSPF_IS_DROTHER:
! 350: if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid))
! 351: && (n->state >= NEIGHBOR_2WAY))
! 352: i = 1;
! 353: break;
! 354: case OSPF_IS_PTP:
! 355: case OSPF_IS_BACKUP:
! 356: case OSPF_IS_DR:
! 357: if (n->state >= NEIGHBOR_2WAY)
! 358: i = 1;
! 359: break;
! 360: default:
! 361: bug("%s: Iface %s in unknown state?", p->p.name, ifa->ifname);
! 362: break;
! 363: }
! 364: break;
! 365: default:
! 366: bug("%s: Iface %s is unknown type?", p->p.name, ifa->ifname);
! 367: break;
! 368: }
! 369: DBG("%s: Iface %s can_do_adj=%d\n", p->p.name, ifa->ifname, i);
! 370: return i;
! 371: }
! 372:
! 373: static void
! 374: ospf_neigh_start_graceful_restart(struct ospf_neighbor *n, uint gr_time)
! 375: {
! 376: struct ospf_proto *p = n->ifa->oa->po;
! 377:
! 378: OSPF_TRACE(D_EVENTS, "Neighbor %R on %s started graceful restart",
! 379: n->rid, n->ifa->ifname);
! 380:
! 381: n->gr_active = 1;
! 382: p->gr_count++;
! 383:
! 384: n->gr_timer = tm_new_init(n->pool, graceful_restart_timeout, n, 0, 0);
! 385: tm_start(n->gr_timer, gr_time S);
! 386: }
! 387:
! 388: static void
! 389: ospf_neigh_stop_graceful_restart_(struct ospf_neighbor *n)
! 390: {
! 391: struct ospf_proto *p = n->ifa->oa->po;
! 392: struct ospf_iface *ifa = n->ifa;
! 393:
! 394: n->gr_active = 0;
! 395: p->gr_count--;
! 396:
! 397: rfree(n->gr_timer);
! 398: n->gr_timer = NULL;
! 399:
! 400: ospf_notify_rt_lsa(ifa->oa);
! 401: ospf_notify_net_lsa(ifa);
! 402:
! 403: if (ifa->type == OSPF_IT_VLINK)
! 404: ospf_notify_rt_lsa(ifa->voa);
! 405:
! 406: ospf_iface_sm(ifa, ISM_NEICH);
! 407: }
! 408:
! 409: static void
! 410: ospf_neigh_stop_graceful_restart(struct ospf_neighbor *n)
! 411: {
! 412: struct ospf_proto *p = n->ifa->oa->po;
! 413:
! 414: OSPF_TRACE(D_EVENTS, "Neighbor %R on %s finished graceful restart",
! 415: n->rid, n->ifa->ifname);
! 416:
! 417: ospf_neigh_stop_graceful_restart_(n);
! 418: }
! 419:
! 420: void
! 421: ospf_neigh_cancel_graceful_restart(struct ospf_neighbor *n)
! 422: {
! 423: struct ospf_proto *p = n->ifa->oa->po;
! 424:
! 425: OSPF_TRACE(D_EVENTS, "Graceful restart canceled for nbr %R on %s",
! 426: n->rid, n->ifa->ifname);
! 427:
! 428: ospf_neigh_stop_graceful_restart_(n);
! 429:
! 430: if (n->state == NEIGHBOR_DOWN)
! 431: ospf_neigh_down(n);
! 432: }
! 433:
! 434: static void
! 435: graceful_restart_timeout(timer *t)
! 436: {
! 437: struct ospf_neighbor *n = t->data;
! 438: struct ospf_proto *p = n->ifa->oa->po;
! 439:
! 440: OSPF_TRACE(D_EVENTS, "Graceful restart timer expired for nbr %R on %s",
! 441: n->rid, n->ifa->ifname);
! 442:
! 443: ospf_neigh_stop_graceful_restart_(n);
! 444:
! 445: if (n->state == NEIGHBOR_DOWN)
! 446: ospf_neigh_down(n);
! 447: }
! 448:
! 449: static inline int
! 450: changes_in_lsrtl(struct ospf_neighbor *n)
! 451: {
! 452: /* This could be improved, see RFC 3623 3.1 (2) */
! 453:
! 454: struct top_hash_entry *en;
! 455: WALK_SLIST(en, n->lsrtl)
! 456: if (LSA_FUNCTION(en->lsa_type) <= LSA_FUNCTION(LSA_T_NSSA))
! 457: return 1;
! 458:
! 459: return 0;
! 460: }
! 461:
! 462: void
! 463: ospf_neigh_notify_grace_lsa(struct ospf_neighbor *n, struct top_hash_entry *en)
! 464: {
! 465: struct ospf_iface *ifa = n->ifa;
! 466: struct ospf_proto *p = ifa->oa->po;
! 467:
! 468: /* In OSPFv2, neighbors are identified by either IP or Router ID, based on network type */
! 469: uint t = ifa->type;
! 470: if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP)))
! 471: {
! 472: struct ospf_tlv *tlv = lsa_get_tlv(en, LSA_GR_ADDRESS);
! 473: if (!tlv || tlv->length != 4)
! 474: return;
! 475:
! 476: ip_addr addr = ipa_from_u32(tlv->data[0]);
! 477: if (!ipa_equal(n->ip, addr))
! 478: n = find_neigh_by_ip(ifa, addr);
! 479: }
! 480: else
! 481: {
! 482: if (n->rid != en->lsa.rt)
! 483: n = find_neigh(ifa, en->lsa.rt);
! 484: }
! 485:
! 486: if (!n)
! 487: return;
! 488:
! 489: if (en->lsa.age < LSA_MAXAGE)
! 490: {
! 491: u32 period = lsa_get_tlv_u32(en, LSA_GR_PERIOD);
! 492:
! 493: /* Exception for updating grace period */
! 494: if (n->gr_active)
! 495: {
! 496: tm_start(n->gr_timer, (period S) - (en->lsa.age S));
! 497: return;
! 498: }
! 499:
! 500: /* RFC 3623 3.1 (1) - full adjacency */
! 501: if (n->state != NEIGHBOR_FULL)
! 502: return;
! 503:
! 504: /* RFC 3623 3.1 (2) - no changes in LSADB */
! 505: if (changes_in_lsrtl(n))
! 506: return;
! 507:
! 508: /* RFC 3623 3.1 (3) - grace period not expired */
! 509: if (en->lsa.age >= period)
! 510: return;
! 511:
! 512: /* RFC 3623 3.1 (4) - helper mode allowed */
! 513: if (!p->gr_mode)
! 514: return;
! 515:
! 516: /* RFC 3623 3.1 (5) - no local graceful restart */
! 517: if (p->p.gr_recovery)
! 518: return;
! 519:
! 520: ospf_neigh_start_graceful_restart(n, period - en->lsa.age);
! 521: }
! 522: else /* Grace-LSA is flushed */
! 523: {
! 524: if (n->gr_active)
! 525: ospf_neigh_stop_graceful_restart(n);
! 526: }
! 527: }
! 528:
! 529: void
! 530: ospf_neigh_lsadb_changed_(struct ospf_proto *p, struct top_hash_entry *en)
! 531: {
! 532: struct ospf_iface *ifa;
! 533: struct ospf_neighbor *n, *nx;
! 534:
! 535: if (LSA_FUNCTION(en->lsa_type) > LSA_FUNCTION(LSA_T_NSSA))
! 536: return;
! 537:
! 538: /* RFC 3623 3.2 (3) - cancel graceful restart when LSdb changed */
! 539: WALK_LIST(ifa, p->iface_list)
! 540: if (lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
! 541: WALK_LIST_DELSAFE(n, nx, ifa->neigh_list)
! 542: if (n->gr_active)
! 543: ospf_neigh_cancel_graceful_restart(n);
! 544: }
! 545:
! 546:
! 547:
! 548: static inline u32 neigh_get_id(struct ospf_proto *p, struct ospf_neighbor *n)
! 549: { return ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid; }
! 550:
! 551: static struct ospf_neighbor *
! 552: elect_bdr(struct ospf_proto *p, list nl)
! 553: {
! 554: struct ospf_neighbor *neigh, *n1, *n2;
! 555: u32 nid;
! 556:
! 557: n1 = NULL;
! 558: n2 = NULL;
! 559: WALK_LIST(neigh, nl) /* First try those decl. themselves */
! 560: {
! 561: nid = neigh_get_id(p, neigh);
! 562:
! 563: if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
! 564: if (neigh->priority > 0) /* Eligible */
! 565: if (neigh->dr != nid) /* And not decl. itself DR */
! 566: {
! 567: if (neigh->bdr == nid) /* Declaring BDR */
! 568: {
! 569: if (n1 != NULL)
! 570: {
! 571: if (neigh->priority > n1->priority)
! 572: n1 = neigh;
! 573: else if (neigh->priority == n1->priority)
! 574: if (neigh->rid > n1->rid)
! 575: n1 = neigh;
! 576: }
! 577: else
! 578: {
! 579: n1 = neigh;
! 580: }
! 581: }
! 582: else /* And NOT declaring BDR */
! 583: {
! 584: if (n2 != NULL)
! 585: {
! 586: if (neigh->priority > n2->priority)
! 587: n2 = neigh;
! 588: else if (neigh->priority == n2->priority)
! 589: if (neigh->rid > n2->rid)
! 590: n2 = neigh;
! 591: }
! 592: else
! 593: {
! 594: n2 = neigh;
! 595: }
! 596: }
! 597: }
! 598: }
! 599: if (n1 == NULL)
! 600: n1 = n2;
! 601:
! 602: return (n1);
! 603: }
! 604:
! 605: static struct ospf_neighbor *
! 606: elect_dr(struct ospf_proto *p, list nl)
! 607: {
! 608: struct ospf_neighbor *neigh, *n;
! 609: u32 nid;
! 610:
! 611: n = NULL;
! 612: WALK_LIST(neigh, nl) /* And now DR */
! 613: {
! 614: nid = neigh_get_id(p, neigh);
! 615:
! 616: if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
! 617: if (neigh->priority > 0) /* Eligible */
! 618: if (neigh->dr == nid) /* And declaring itself DR */
! 619: {
! 620: if (n != NULL)
! 621: {
! 622: if (neigh->priority > n->priority)
! 623: n = neigh;
! 624: else if (neigh->priority == n->priority)
! 625: if (neigh->rid > n->rid)
! 626: n = neigh;
! 627: }
! 628: else
! 629: {
! 630: n = neigh;
! 631: }
! 632: }
! 633: }
! 634:
! 635: return (n);
! 636: }
! 637:
! 638: /**
! 639: * ospf_dr_election - (Backup) Designed Router election
! 640: * @ifa: actual interface
! 641: *
! 642: * When the wait timer fires, it is time to elect (Backup) Designated Router.
! 643: * Structure describing me is added to this list so every electing router has
! 644: * the same list. Backup Designated Router is elected before Designated
! 645: * Router. This process is described in 9.4 of RFC 2328. The function is
! 646: * supposed to be called only from ospf_iface_sm() as a part of the interface
! 647: * state machine.
! 648: */
! 649: void
! 650: ospf_dr_election(struct ospf_iface *ifa)
! 651: {
! 652: struct ospf_proto *p = ifa->oa->po;
! 653: struct ospf_neighbor *neigh, *ndr, *nbdr, me;
! 654: u32 myid = p->router_id;
! 655:
! 656: DBG("(B)DR election.\n");
! 657:
! 658: me.state = NEIGHBOR_2WAY;
! 659: me.rid = myid;
! 660: me.priority = ifa->priority;
! 661: me.ip = ifa->addr->ip;
! 662:
! 663: me.dr = ospf_is_v2(p) ? ipa_to_u32(ifa->drip) : ifa->drid;
! 664: me.bdr = ospf_is_v2(p) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid;
! 665: me.iface_id = ifa->iface_id;
! 666:
! 667: add_tail(&ifa->neigh_list, NODE & me);
! 668:
! 669: nbdr = elect_bdr(p, ifa->neigh_list);
! 670: ndr = elect_dr(p, ifa->neigh_list);
! 671:
! 672: if (ndr == NULL)
! 673: ndr = nbdr;
! 674:
! 675: /* 9.4. (4) */
! 676: if (((ifa->drid == myid) && (ndr != &me))
! 677: || ((ifa->drid != myid) && (ndr == &me))
! 678: || ((ifa->bdrid == myid) && (nbdr != &me))
! 679: || ((ifa->bdrid != myid) && (nbdr == &me)))
! 680: {
! 681: me.dr = ndr ? neigh_get_id(p, ndr) : 0;
! 682: me.bdr = nbdr ? neigh_get_id(p, nbdr) : 0;
! 683:
! 684: nbdr = elect_bdr(p, ifa->neigh_list);
! 685: ndr = elect_dr(p, ifa->neigh_list);
! 686:
! 687: if (ndr == NULL)
! 688: ndr = nbdr;
! 689: }
! 690:
! 691: rem_node(NODE & me);
! 692:
! 693:
! 694: u32 old_drid = ifa->drid;
! 695: u32 old_bdrid = ifa->bdrid;
! 696: ip_addr none = ospf_is_v2(p) ? IPA_NONE4 : IPA_NONE6;
! 697:
! 698: ifa->drid = ndr ? ndr->rid : 0;
! 699: ifa->drip = ndr ? ndr->ip : none;
! 700: ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
! 701:
! 702: ifa->bdrid = nbdr ? nbdr->rid : 0;
! 703: ifa->bdrip = nbdr ? nbdr->ip : none;
! 704:
! 705: DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid);
! 706:
! 707: /* We are part of the interface state machine */
! 708: if (ifa->drid == myid)
! 709: ospf_iface_chstate(ifa, OSPF_IS_DR);
! 710: else if (ifa->bdrid == myid)
! 711: ospf_iface_chstate(ifa, OSPF_IS_BACKUP);
! 712: else
! 713: ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
! 714:
! 715: /* Review neighbor adjacencies if DR or BDR changed */
! 716: if ((ifa->drid != old_drid) || (ifa->bdrid != old_bdrid))
! 717: WALK_LIST(neigh, ifa->neigh_list)
! 718: if (neigh->state >= NEIGHBOR_2WAY)
! 719: ospf_neigh_sm(neigh, INM_ADJOK);
! 720:
! 721: /* RFC 2328 12.4 Event 3 - DR change */
! 722: if (ifa->drid != old_drid)
! 723: ospf_notify_rt_lsa(ifa->oa);
! 724: }
! 725:
! 726: struct ospf_neighbor *
! 727: find_neigh(struct ospf_iface *ifa, u32 rid)
! 728: {
! 729: struct ospf_neighbor *n;
! 730: WALK_LIST(n, ifa->neigh_list)
! 731: if (n->rid == rid)
! 732: return n;
! 733: return NULL;
! 734: }
! 735:
! 736: struct ospf_neighbor *
! 737: find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip)
! 738: {
! 739: struct ospf_neighbor *n;
! 740: WALK_LIST(n, ifa->neigh_list)
! 741: if (ipa_equal(n->ip, ip))
! 742: return n;
! 743: return NULL;
! 744: }
! 745:
! 746: static void
! 747: inactivity_timer_hook(timer * timer)
! 748: {
! 749: struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
! 750: struct ospf_proto *p = n->ifa->oa->po;
! 751:
! 752: OSPF_TRACE(D_EVENTS, "Inactivity timer expired for nbr %R on %s",
! 753: n->rid, n->ifa->ifname);
! 754: ospf_neigh_sm(n, INM_INACTTIM);
! 755: }
! 756:
! 757: static void
! 758: ospf_neigh_bfd_hook(struct bfd_request *req)
! 759: {
! 760: struct ospf_neighbor *n = req->data;
! 761: struct ospf_proto *p = n->ifa->oa->po;
! 762:
! 763: if (req->down)
! 764: {
! 765: OSPF_TRACE(D_EVENTS, "BFD session down for nbr %R on %s",
! 766: n->rid, n->ifa->ifname);
! 767: ospf_neigh_sm(n, INM_INACTTIM);
! 768: }
! 769: }
! 770:
! 771: void
! 772: ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd)
! 773: {
! 774: struct ospf_proto *p = n->ifa->oa->po;
! 775:
! 776: if (use_bfd && !n->bfd_req)
! 777: n->bfd_req = bfd_request_session(n->pool, n->ip, n->ifa->addr->ip,
! 778: n->ifa->iface, p->p.vrf,
! 779: ospf_neigh_bfd_hook, n);
! 780:
! 781: if (!use_bfd && n->bfd_req)
! 782: {
! 783: rfree(n->bfd_req);
! 784: n->bfd_req = NULL;
! 785: }
! 786: }
! 787:
! 788:
! 789: static void
! 790: dbdes_timer_hook(timer *t)
! 791: {
! 792: struct ospf_neighbor *n = t->data;
! 793: struct ospf_proto *p = n->ifa->oa->po;
! 794:
! 795: // OSPF_TRACE(D_EVENTS, "DBDES timer expired for nbr %R on %s", n->rid, n->ifa->ifname);
! 796:
! 797: if (n->state == NEIGHBOR_EXSTART)
! 798: ospf_send_dbdes(p, n);
! 799:
! 800: if ((n->state == NEIGHBOR_EXCHANGE) && (n->myimms & DBDES_MS))
! 801: ospf_rxmt_dbdes(p, n);
! 802:
! 803: if ((n->state > NEIGHBOR_LOADING) && !(n->myimms & DBDES_MS))
! 804: {
! 805: ospf_reset_ldd(p, n);
! 806: tm_stop(n->dbdes_timer);
! 807: }
! 808: }
! 809:
! 810: static void
! 811: lsrq_timer_hook(timer *t)
! 812: {
! 813: struct ospf_neighbor *n = t->data;
! 814: struct ospf_proto *p = n->ifa->oa->po;
! 815:
! 816: // OSPF_TRACE(D_EVENTS, "LSRQ timer expired for nbr %R on %s", n->rid, n->ifa->ifname);
! 817:
! 818: if ((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrql))
! 819: ospf_send_lsreq(p, n);
! 820: }
! 821:
! 822: static void
! 823: lsrt_timer_hook(timer *t)
! 824: {
! 825: struct ospf_neighbor *n = t->data;
! 826: struct ospf_proto *p = n->ifa->oa->po;
! 827:
! 828: // OSPF_TRACE(D_EVENTS, "LSRT timer expired for nbr %R on %s", n->rid, n->ifa->ifname);
! 829:
! 830: if ((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrtl))
! 831: ospf_rxmt_lsupd(p, n);
! 832: }
! 833:
! 834: static void
! 835: ackd_timer_hook(timer *t)
! 836: {
! 837: struct ospf_neighbor *n = t->data;
! 838: struct ospf_proto *p = n->ifa->oa->po;
! 839:
! 840: ospf_send_lsack(p, n, ACKL_DELAY);
! 841: }
! 842:
! 843:
! 844: void
! 845: ospf_sh_neigh_info(struct ospf_neighbor *n)
! 846: {
! 847: struct ospf_iface *ifa = n->ifa;
! 848: char *pos = "PtP ";
! 849:
! 850: if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
! 851: {
! 852: if (n->rid == ifa->drid)
! 853: pos = "DR ";
! 854: else if (n->rid == ifa->bdrid)
! 855: pos = "BDR ";
! 856: else
! 857: pos = "Other";
! 858: }
! 859:
! 860: cli_msg(-1013, "%-12R\t%3u\t%s/%s\t%6t\t%-10s %I",
! 861: n->rid, n->priority, ospf_ns_names[n->state], pos,
! 862: tm_remains(n->inactim), ifa->ifname, n->ip);
! 863: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>