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>