File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / proto / ospf / ospf.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 19:50:23 2021 UTC (3 years, 4 months ago) by misho
Branches: bird, MAIN
CVS tags: v1_6_8p3, HEAD
bird 1.6.8

    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: /**
   12:  * DOC: Open Shortest Path First (OSPF)
   13:  *
   14:  * The OSPF protocol is quite complicated and its complex implemenation is split
   15:  * to many files. In |ospf.c|, you will find mainly the interface for
   16:  * communication with the core (e.g., reconfiguration hooks, shutdown and
   17:  * initialisation and so on). File |iface.c| contains the interface state
   18:  * machine and functions for allocation and deallocation of OSPF's interface
   19:  * data structures. Source |neighbor.c| includes the neighbor state machine and
   20:  * functions for election of Designated Router and Backup Designated router. In
   21:  * |packet.c|, you will find various functions for sending and receiving generic
   22:  * OSPF packets. There are also routines for authentication and checksumming.
   23:  * In |hello.c|, there are routines for sending and receiving of hello packets
   24:  * as well as functions for maintaining wait times and the inactivity timer.
   25:  * Files |lsreq.c|, |lsack.c|, |dbdes.c| contain functions for sending and
   26:  * receiving of link-state requests, link-state acknowledgements and database
   27:  * descriptions respectively.  In |lsupd.c|, there are functions for sending and
   28:  * receiving of link-state updates and also the flooding algorithm. Source
   29:  * |topology.c| is a place where routines for searching LSAs in the link-state
   30:  * database, adding and deleting them reside, there also are functions for
   31:  * originating of various types of LSAs (router LSA, net LSA, external LSA).
   32:  * File |rt.c| contains routines for calculating the routing table. |lsalib.c|
   33:  * is a set of various functions for working with the LSAs (endianity
   34:  * conversions, calculation of checksum etc.).
   35:  *
   36:  * One instance of the protocol is able to hold LSA databases for multiple OSPF
   37:  * areas, to exchange routing information between multiple neighbors and to
   38:  * calculate the routing tables. The core structure is &ospf_proto to which
   39:  * multiple &ospf_area and &ospf_iface structures are connected. &ospf_proto is
   40:  * also connected to &top_hash_graph which is a dynamic hashing structure that
   41:  * describes the link-state database. It allows fast search, addition and
   42:  * deletion. Each LSA is kept in two pieces: header and body. Both of them are
   43:  * kept in the endianity of the CPU.
   44:  *
   45:  * In OSPFv2 specification, it is implied that there is one IP prefix for each
   46:  * physical network/interface (unless it is an ptp link). But in modern systems,
   47:  * there might be more independent IP prefixes associated with an interface.  To
   48:  * handle this situation, we have one &ospf_iface for each active IP prefix
   49:  * (instead for each active iface); This behaves like virtual interface for the
   50:  * purpose of OSPF.  If we receive packet, we associate it with a proper virtual
   51:  * interface mainly according to its source address.
   52:  *
   53:  * OSPF keeps one socket per &ospf_iface. This allows us (compared to one socket
   54:  * approach) to evade problems with a limit of multicast groups per socket and
   55:  * with sending multicast packets to appropriate interface in a portable way.
   56:  * The socket is associated with underlying physical iface and should not
   57:  * receive packets received on other ifaces (unfortunately, this is not true on
   58:  * BSD). Generally, one packet can be received by more sockets (for example, if
   59:  * there are more &ospf_iface on one physical iface), therefore we explicitly
   60:  * filter received packets according to src/dst IP address and received iface.
   61:  *
   62:  * Vlinks are implemented using particularly degenerate form of &ospf_iface,
   63:  * which has several exceptions: it does not have its iface or socket (it copies
   64:  * these from 'parent' &ospf_iface) and it is present in iface list even when
   65:  * down (it is not freed in ospf_iface_down()).
   66:  *
   67:  * The heart beat of ospf is ospf_disp(). It is called at regular intervals
   68:  * (&ospf_proto->tick). It is responsible for aging and flushing of LSAs in the
   69:  * database, updating topology information in LSAs and for routing table
   70:  * calculation.
   71:  *
   72:  * To every &ospf_iface, we connect one or more &ospf_neighbor's -- a structure
   73:  * containing many timers and queues for building adjacency and for exchange of
   74:  * routing messages.
   75:  *
   76:  * BIRD's OSPF implementation respects RFC2328 in every detail, but some of
   77:  * internal algorithms do differ. The RFC recommends making a snapshot of the
   78:  * link-state database when a new adjacency is forming and sending the database
   79:  * description packets based on the information in this snapshot. The database
   80:  * can be quite large in some networks, so rather we walk through a &slist
   81:  * structure which allows us to continue even if the actual LSA we were working
   82:  * with is deleted. New LSAs are added at the tail of this &slist.
   83:  *
   84:  * We also do not keep a separate OSPF routing table, because the core helps us
   85:  * by being able to recognize when a route is updated to an identical one and it
   86:  * suppresses the update automatically. Due to this, we can flush all the routes
   87:  * we have recalculated and also those we have deleted to the core's routing
   88:  * table and the core will take care of the rest. This simplifies the process
   89:  * and conserves memory.
   90:  *
   91:  * Supported standards:
   92:  * - RFC 2328 - main OSPFv2 standard
   93:  * - RFC 5340 - main OSPFv3 standard
   94:  * - RFC 3101 - OSPFv2 NSSA areas
   95:  * - RFC 6549 - OSPFv2 multi-instance extensions
   96:  * - RFC 6987 - OSPF stub router advertisement
   97:  */
   98: 
   99: #include <stdlib.h>
  100: #include "ospf.h"
  101: 
  102: static int ospf_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool);
  103: static struct ea_list *ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool);
  104: static void ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs);
  105: static int ospf_reload_routes(struct proto *P);
  106: static int ospf_rte_better(struct rte *new, struct rte *old);
  107: static int ospf_rte_same(struct rte *new, struct rte *old);
  108: static void ospf_disp(timer *timer);
  109: 
  110: static void
  111: ospf_area_initfib(struct fib_node *fn)
  112: {
  113:   struct area_net *an = (struct area_net *) fn;
  114:   an->hidden = 0;
  115:   an->active = 0;
  116: }
  117: 
  118: static void
  119: add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
  120: {
  121:   struct ospf_proto *p = oa->po;
  122:   struct area_net_config *anc;
  123:   struct area_net *an;
  124: 
  125:   fib_init(&oa->net_fib, p->p.pool, sizeof(struct area_net), 0, ospf_area_initfib);
  126:   fib_init(&oa->enet_fib, p->p.pool, sizeof(struct area_net), 0, ospf_area_initfib);
  127: 
  128:   WALK_LIST(anc, ac->net_list)
  129:   {
  130:     an = (struct area_net *) fib_get(&oa->net_fib, &anc->px.addr, anc->px.len);
  131:     an->hidden = anc->hidden;
  132:   }
  133: 
  134:   WALK_LIST(anc, ac->enet_list)
  135:   {
  136:     an = (struct area_net *) fib_get(&oa->enet_fib, &anc->px.addr, anc->px.len);
  137:     an->hidden = anc->hidden;
  138:     an->tag = anc->tag;
  139:   }
  140: }
  141: 
  142: static void
  143: ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
  144: {
  145:   struct ospf_area *oa;
  146: 
  147:   OSPF_TRACE(D_EVENTS, "Adding area %R", ac->areaid);
  148: 
  149:   oa = mb_allocz(p->p.pool, sizeof(struct ospf_area));
  150:   add_tail(&p->area_list, NODE oa);
  151:   p->areano++;
  152: 
  153:   oa->ac = ac;
  154:   oa->areaid = ac->areaid;
  155:   oa->rt = NULL;
  156:   oa->po = p;
  157:   fib_init(&oa->rtr, p->p.pool, sizeof(ort), 0, ospf_rt_initort);
  158:   add_area_nets(oa, ac);
  159: 
  160:   if (oa->areaid == 0)
  161:     p->backbone = oa;
  162: 
  163:   if (ospf_is_v2(p))
  164:     oa->options = ac->type;
  165:   else
  166:     oa->options = ac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
  167: 
  168:   ospf_notify_rt_lsa(oa);
  169: }
  170: 
  171: static void
  172: ospf_flush_area(struct ospf_proto *p, u32 areaid)
  173: {
  174:   struct top_hash_entry *en;
  175: 
  176:   WALK_SLIST(en, p->lsal)
  177:     if ((LSA_SCOPE(en->lsa_type) == LSA_SCOPE_AREA) && (en->domain == areaid))
  178:       ospf_flush_lsa(p, en);
  179: }
  180: 
  181: static void
  182: ospf_area_remove(struct ospf_area *oa)
  183: {
  184:   struct ospf_proto *p = oa->po;
  185:   OSPF_TRACE(D_EVENTS, "Removing area %R", oa->areaid);
  186: 
  187:   /* We suppose that interfaces are already removed */
  188:   ospf_flush_area(p, oa->areaid);
  189: 
  190:   fib_free(&oa->rtr);
  191:   fib_free(&oa->net_fib);
  192:   fib_free(&oa->enet_fib);
  193: 
  194:   if (oa->translator_timer)
  195:     rfree(oa->translator_timer);
  196: 
  197:   p->areano--;
  198:   rem_node(NODE oa);
  199:   mb_free(oa);
  200: }
  201: 
  202: 
  203: struct ospf_area *
  204: ospf_find_area(struct ospf_proto *p, u32 aid)
  205: {
  206:   struct ospf_area *oa;
  207:   WALK_LIST(oa, p->area_list)
  208:     if (((struct ospf_area *) oa)->areaid == aid)
  209:       return oa;
  210:   return NULL;
  211: }
  212: 
  213: static struct ospf_iface *
  214: ospf_find_vlink(struct ospf_proto *p, u32 voa, u32 vid)
  215: {
  216:   struct ospf_iface *ifa;
  217:   WALK_LIST(ifa, p->iface_list)
  218:     if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa->areaid == voa) && (ifa->vid == vid))
  219:       return ifa;
  220:   return NULL;
  221: }
  222: 
  223: static int
  224: ospf_start(struct proto *P)
  225: {
  226:   struct ospf_proto *p = (struct ospf_proto *) P;
  227:   struct ospf_config *c = (struct ospf_config *) (P->cf);
  228:   struct ospf_area_config *ac;
  229: 
  230:   p->router_id = proto_get_router_id(P->cf);
  231:   p->ospf2 = c->ospf2;
  232:   p->rfc1583 = c->rfc1583;
  233:   p->stub_router = c->stub_router;
  234:   p->merge_external = c->merge_external;
  235:   p->asbr = c->asbr;
  236:   p->ecmp = c->ecmp;
  237:   p->tick = c->tick;
  238:   p->disp_timer = tm_new_set(P->pool, ospf_disp, p, 0, p->tick);
  239:   tm_start(p->disp_timer, 1);
  240:   p->lsab_size = 256;
  241:   p->lsab_used = 0;
  242:   p->lsab = mb_alloc(P->pool, p->lsab_size);
  243:   p->nhpool = lp_new(P->pool, 12*sizeof(struct mpnh));
  244:   init_list(&(p->iface_list));
  245:   init_list(&(p->area_list));
  246:   fib_init(&p->rtf, P->pool, sizeof(ort), 0, ospf_rt_initort);
  247:   p->areano = 0;
  248:   p->gr = ospf_top_new(p, P->pool);
  249:   s_init_list(&(p->lsal));
  250: 
  251:   p->flood_event = ev_new(P->pool);
  252:   p->flood_event->hook = ospf_flood_event;
  253:   p->flood_event->data = p;
  254: 
  255:   p->log_pkt_tbf = (struct tbf){ .rate = 1, .burst = 5 };
  256:   p->log_lsa_tbf = (struct tbf){ .rate = 4, .burst = 20 };
  257: 
  258:   WALK_LIST(ac, c->area_list)
  259:     ospf_area_add(p, ac);
  260: 
  261:   if (c->abr)
  262:     ospf_open_vlink_sk(p);
  263: 
  264:   /* Add all virtual links */
  265:   struct ospf_iface_patt *ic;
  266:   WALK_LIST(ic, c->vlink_list)
  267:     ospf_iface_new_vlink(p, ic);
  268: 
  269:   return PS_UP;
  270: }
  271: 
  272: static void
  273: ospf_dump(struct proto *P)
  274: {
  275:   struct ospf_proto *p = (struct ospf_proto *) P;
  276:   struct ospf_iface *ifa;
  277:   struct ospf_neighbor *n;
  278: 
  279:   OSPF_TRACE(D_EVENTS, "Area number: %d", p->areano);
  280: 
  281:   WALK_LIST(ifa, p->iface_list)
  282:   {
  283:     OSPF_TRACE(D_EVENTS, "Interface: %s", ifa->ifname);
  284:     OSPF_TRACE(D_EVENTS, "state: %u", ifa->state);
  285:     OSPF_TRACE(D_EVENTS, "DR:  %R", ifa->drid);
  286:     OSPF_TRACE(D_EVENTS, "BDR: %R", ifa->bdrid);
  287:     WALK_LIST(n, ifa->neigh_list)
  288:     {
  289:       OSPF_TRACE(D_EVENTS, "  neighbor %R in state %u", n->rid, n->state);
  290:     }
  291:   }
  292: 
  293:   /*
  294:   OSPF_TRACE(D_EVENTS, "LSA graph dump start:");
  295:   ospf_top_dump(p->gr, p);
  296:   OSPF_TRACE(D_EVENTS, "LSA graph dump finished");
  297:   */
  298:   neigh_dump_all();
  299: }
  300: 
  301: static struct proto *
  302: ospf_init(struct proto_config *c)
  303: {
  304:   struct ospf_config *oc = (struct ospf_config *) c;
  305:   struct proto *P = proto_new(c, sizeof(struct ospf_proto));
  306: 
  307:   P->accept_ra_types = RA_OPTIMAL;
  308:   P->rt_notify = ospf_rt_notify;
  309:   P->if_notify = ospf_if_notify;
  310:   P->ifa_notify = oc->ospf2 ? ospf_ifa_notify2 : ospf_ifa_notify3;
  311:   P->import_control = ospf_import_control;
  312:   P->reload_routes = ospf_reload_routes;
  313:   P->make_tmp_attrs = ospf_make_tmp_attrs;
  314:   P->store_tmp_attrs = ospf_store_tmp_attrs;
  315:   P->rte_better = ospf_rte_better;
  316:   P->rte_same = ospf_rte_same;
  317: 
  318:   return P;
  319: }
  320: 
  321: /* If new is better return 1 */
  322: static int
  323: ospf_rte_better(struct rte *new, struct rte *old)
  324: {
  325:   if (new->u.ospf.metric1 == LSINFINITY)
  326:     return 0;
  327: 
  328:   if(new->attrs->source < old->attrs->source) return 1;
  329:   if(new->attrs->source > old->attrs->source) return 0;
  330: 
  331:   if(new->attrs->source == RTS_OSPF_EXT2)
  332:   {
  333:     if(new->u.ospf.metric2 < old->u.ospf.metric2) return 1;
  334:     if(new->u.ospf.metric2 > old->u.ospf.metric2) return 0;
  335:   }
  336: 
  337:   if (new->u.ospf.metric1 < old->u.ospf.metric1)
  338:     return 1;
  339: 
  340:   return 0;			/* Old is shorter or same */
  341: }
  342: 
  343: static int
  344: ospf_rte_same(struct rte *new, struct rte *old)
  345: {
  346:   /* new->attrs == old->attrs always */
  347:   return
  348:     new->u.ospf.metric1 == old->u.ospf.metric1 &&
  349:     new->u.ospf.metric2 == old->u.ospf.metric2 &&
  350:     new->u.ospf.tag == old->u.ospf.tag &&
  351:     new->u.ospf.router_id == old->u.ospf.router_id;
  352: }
  353: 
  354: static ea_list *
  355: ospf_build_attrs(ea_list * next, struct linpool *pool, u32 m1, u32 m2,
  356: 		 u32 tag, u32 rid)
  357: {
  358:   struct ea_list *l =
  359:     lp_alloc(pool, sizeof(struct ea_list) + 4 * sizeof(eattr));
  360: 
  361:   l->next = next;
  362:   l->flags = EALF_SORTED;
  363:   l->count = 4;
  364:   l->attrs[0].id = EA_OSPF_METRIC1;
  365:   l->attrs[0].flags = 0;
  366:   l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
  367:   l->attrs[0].u.data = m1;
  368:   l->attrs[1].id = EA_OSPF_METRIC2;
  369:   l->attrs[1].flags = 0;
  370:   l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
  371:   l->attrs[1].u.data = m2;
  372:   l->attrs[2].id = EA_OSPF_TAG;
  373:   l->attrs[2].flags = 0;
  374:   l->attrs[2].type = EAF_TYPE_INT | EAF_TEMP;
  375:   l->attrs[2].u.data = tag;
  376:   l->attrs[3].id = EA_OSPF_ROUTER_ID;
  377:   l->attrs[3].flags = 0;
  378:   l->attrs[3].type = EAF_TYPE_ROUTER_ID | EAF_TEMP;
  379:   l->attrs[3].u.data = rid;
  380:   return l;
  381: }
  382: 
  383: 
  384: void
  385: ospf_schedule_rtcalc(struct ospf_proto *p)
  386: {
  387:   if (p->calcrt)
  388:     return;
  389: 
  390:   OSPF_TRACE(D_EVENTS, "Scheduling routing table calculation");
  391:   p->calcrt = 1;
  392: }
  393: 
  394: static int
  395: ospf_reload_routes(struct proto *P)
  396: {
  397:   struct ospf_proto *p = (struct ospf_proto *) P;
  398: 
  399:   if (p->calcrt != 2)
  400:     OSPF_TRACE(D_EVENTS, "Scheduling routing table calculation with route reload");
  401: 
  402:   p->calcrt = 2;
  403: 
  404:   return 1;
  405: }
  406: 
  407: 
  408: /**
  409:  * ospf_disp - invokes routing table calculation, aging and also area_disp()
  410:  * @timer: timer usually called every @ospf_proto->tick second, @timer->data
  411:  * point to @ospf_proto
  412:  */
  413: static void
  414: ospf_disp(timer * timer)
  415: {
  416:   struct ospf_proto *p = timer->data;
  417: 
  418:   /* Originate or flush local topology LSAs */
  419:   ospf_update_topology(p);
  420: 
  421:   /* Process LSA DB */
  422:   ospf_update_lsadb(p);
  423: 
  424:   /* Calculate routing table */
  425:   if (p->calcrt)
  426:     ospf_rt_spf(p);
  427: }
  428: 
  429: 
  430: /**
  431:  * ospf_import_control - accept or reject new route from nest's routing table
  432:  * @P: OSPF protocol instance
  433:  * @new: the new route
  434:  * @attrs: list of attributes
  435:  * @pool: pool for allocation of attributes
  436:  *
  437:  * Its quite simple. It does not accept our own routes and leaves the decision on
  438:  * import to the filters.
  439:  */
  440: static int
  441: ospf_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
  442: {
  443:   struct ospf_proto *p = (struct ospf_proto *) P;
  444:   struct ospf_area *oa = ospf_main_area(p);
  445:   rte *e = *new;
  446: 
  447:   if (e->attrs->src->proto == P)
  448:     return -1;			/* Reject our own routes */
  449: 
  450:   if (oa_is_stub(oa))
  451:     return -1;			/* Do not export routes to stub areas */
  452: 
  453:   ea_list *ea = e->attrs->eattrs;
  454:   u32 m0 = ea_get_int(ea, EA_GEN_IGP_METRIC, LSINFINITY);
  455:   u32 m1 = MIN(m0, LSINFINITY);
  456:   u32 m2 = 10000;
  457:   u32 tag = 0;
  458: 
  459:   /* Hack for setting attributes directly in static protocol */
  460:   if (e->attrs->source == RTS_STATIC)
  461:   {
  462:     m1 = ea_get_int(ea, EA_OSPF_METRIC1, m1);
  463:     m2 = ea_get_int(ea, EA_OSPF_METRIC2, 10000);
  464:     tag = ea_get_int(ea, EA_OSPF_TAG, 0);
  465:   }
  466: 
  467:   *attrs = ospf_build_attrs(*attrs, pool, m1, m2, tag, 0);
  468:   return 0;			/* Leave decision to the filters */
  469: }
  470: 
  471: static struct ea_list *
  472: ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool)
  473: {
  474:   return ospf_build_attrs(NULL, pool, rt->u.ospf.metric1, rt->u.ospf.metric2,
  475: 			  rt->u.ospf.tag, rt->u.ospf.router_id);
  476: }
  477: 
  478: static void
  479: ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
  480: {
  481:   rt->u.ospf.metric1 = ea_get_int(attrs, EA_OSPF_METRIC1, LSINFINITY);
  482:   rt->u.ospf.metric2 = ea_get_int(attrs, EA_OSPF_METRIC2, 10000);
  483:   rt->u.ospf.tag = ea_get_int(attrs, EA_OSPF_TAG, 0);
  484:   rt->u.ospf.router_id = ea_get_int(attrs, EA_OSPF_ROUTER_ID, 0);
  485: }
  486: 
  487: /**
  488:  * ospf_shutdown - Finish of OSPF instance
  489:  * @P: OSPF protocol instance
  490:  *
  491:  * RFC does not define any action that should be taken before router
  492:  * shutdown. To make my neighbors react as fast as possible, I send
  493:  * them hello packet with empty neighbor list. They should start
  494:  * their neighbor state machine with event %NEIGHBOR_1WAY.
  495:  */
  496: static int
  497: ospf_shutdown(struct proto *P)
  498: {
  499:   struct ospf_proto *p = (struct ospf_proto *) P;
  500:   struct ospf_iface *ifa;
  501: 
  502:   OSPF_TRACE(D_EVENTS, "Shutdown requested");
  503: 
  504:   /* And send to all my neighbors 1WAY */
  505:   WALK_LIST(ifa, p->iface_list)
  506:     ospf_iface_shutdown(ifa);
  507: 
  508:   /* Cleanup locked rta entries */
  509:   FIB_WALK(&p->rtf, nftmp)
  510:   {
  511:     rta_free(((ort *) nftmp)->old_rta);
  512:   }
  513:   FIB_WALK_END;
  514: 
  515:   return PS_DOWN;
  516: }
  517: 
  518: static void
  519: ospf_get_status(struct proto *P, byte * buf)
  520: {
  521:   struct ospf_proto *p = (struct ospf_proto *) P;
  522: 
  523:   if (p->p.proto_state == PS_DOWN)
  524:     buf[0] = 0;
  525:   else
  526:   {
  527:     struct ospf_iface *ifa;
  528:     struct ospf_neighbor *n;
  529:     int adj = 0;
  530: 
  531:     WALK_LIST(ifa, p->iface_list)
  532:       WALK_LIST(n, ifa->neigh_list) if (n->state == NEIGHBOR_FULL)
  533:       adj = 1;
  534: 
  535:     if (adj == 0)
  536:       strcpy(buf, "Alone");
  537:     else
  538:       strcpy(buf, "Running");
  539:   }
  540: }
  541: 
  542: static void
  543: ospf_get_route_info(rte * rte, byte * buf, ea_list * attrs UNUSED)
  544: {
  545:   char *type = "<bug>";
  546: 
  547:   switch (rte->attrs->source)
  548:   {
  549:   case RTS_OSPF:
  550:     type = "I";
  551:     break;
  552:   case RTS_OSPF_IA:
  553:     type = "IA";
  554:     break;
  555:   case RTS_OSPF_EXT1:
  556:     type = "E1";
  557:     break;
  558:   case RTS_OSPF_EXT2:
  559:     type = "E2";
  560:     break;
  561:   }
  562: 
  563:   buf += bsprintf(buf, " %s", type);
  564:   buf += bsprintf(buf, " (%d/%d", rte->pref, rte->u.ospf.metric1);
  565:   if (rte->attrs->source == RTS_OSPF_EXT2)
  566:     buf += bsprintf(buf, "/%d", rte->u.ospf.metric2);
  567:   buf += bsprintf(buf, ")");
  568:   if ((rte->attrs->source == RTS_OSPF_EXT1 || rte->attrs->source == RTS_OSPF_EXT2) && rte->u.ospf.tag)
  569:   {
  570:     buf += bsprintf(buf, " [%x]", rte->u.ospf.tag);
  571:   }
  572:   if (rte->u.ospf.router_id)
  573:     buf += bsprintf(buf, " [%R]", rte->u.ospf.router_id);
  574: }
  575: 
  576: static int
  577: ospf_get_attr(eattr * a, byte * buf, int buflen UNUSED)
  578: {
  579:   switch (a->id)
  580:   {
  581:   case EA_OSPF_METRIC1:
  582:     bsprintf(buf, "metric1");
  583:     return GA_NAME;
  584:   case EA_OSPF_METRIC2:
  585:     bsprintf(buf, "metric2");
  586:     return GA_NAME;
  587:   case EA_OSPF_TAG:
  588:     bsprintf(buf, "tag: 0x%08x", a->u.data);
  589:     return GA_FULL;
  590:   case EA_OSPF_ROUTER_ID:
  591:     bsprintf(buf, "router_id");
  592:     return GA_NAME;
  593:   default:
  594:     return GA_UNKNOWN;
  595:   }
  596: }
  597: 
  598: static void
  599: ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
  600: {
  601:   struct ospf_proto *p = oa->po;
  602:   struct ospf_area_config *oac = oa->ac;
  603:   struct ospf_iface *ifa;
  604: 
  605:   oa->ac = nac;
  606: 
  607:   if (ospf_is_v2(p))
  608:     oa->options = nac->type;
  609:   else
  610:     oa->options = nac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
  611: 
  612:   if (nac->type != oac->type)
  613:   {
  614:     /* Force restart of area interfaces */
  615:     WALK_LIST(ifa, p->iface_list)
  616:       if (ifa->oa == oa)
  617: 	ifa->marked = 2;
  618:   }
  619: 
  620:   /* Handle net_list */
  621:   fib_free(&oa->net_fib);
  622:   fib_free(&oa->enet_fib);
  623:   add_area_nets(oa, nac);
  624: 
  625:   /* No need to handle stubnet_list */
  626: 
  627:   oa->marked = 0;
  628:   ospf_notify_rt_lsa(oa);
  629: }
  630: 
  631: /**
  632:  * ospf_reconfigure - reconfiguration hook
  633:  * @P: current instance of protocol (with old configuration)
  634:  * @c: new configuration requested by user
  635:  *
  636:  * This hook tries to be a little bit intelligent. Instance of OSPF
  637:  * will survive change of many constants like hello interval,
  638:  * password change, addition or deletion of some neighbor on
  639:  * nonbroadcast network, cost of interface, etc.
  640:  */
  641: static int
  642: ospf_reconfigure(struct proto *P, struct proto_config *c)
  643: {
  644:   struct ospf_proto *p = (struct ospf_proto *) P;
  645:   struct ospf_config *old = (struct ospf_config *) (P->cf);
  646:   struct ospf_config *new = (struct ospf_config *) c;
  647:   struct ospf_area_config *nac;
  648:   struct ospf_area *oa, *oax;
  649:   struct ospf_iface *ifa, *ifx;
  650:   struct ospf_iface_patt *ip;
  651: 
  652:   if (proto_get_router_id(c) != p->router_id)
  653:     return 0;
  654: 
  655:   if (p->rfc1583 != new->rfc1583)
  656:     return 0;
  657: 
  658:   if (old->abr != new->abr)
  659:     return 0;
  660: 
  661:   p->stub_router = new->stub_router;
  662:   p->merge_external = new->merge_external;
  663:   p->asbr = new->asbr;
  664:   p->ecmp = new->ecmp;
  665:   p->tick = new->tick;
  666:   p->disp_timer->recurrent = p->tick;
  667:   tm_start(p->disp_timer, 1);
  668: 
  669:   /* Mark all areas and ifaces */
  670:   WALK_LIST(oa, p->area_list)
  671:     oa->marked = 1;
  672: 
  673:   WALK_LIST(ifa, p->iface_list)
  674:     ifa->marked = 1;
  675: 
  676:   /* Add and update areas */
  677:   WALK_LIST(nac, new->area_list)
  678:   {
  679:     oa = ospf_find_area(p, nac->areaid);
  680:     if (oa)
  681:       ospf_area_reconfigure(oa, nac);
  682:     else
  683:       ospf_area_add(p, nac);
  684:   }
  685: 
  686:   /* Add and update interfaces */
  687:   ospf_reconfigure_ifaces(p);
  688: 
  689:   /* Add and update vlinks */
  690:   WALK_LIST(ip, new->vlink_list)
  691:   {
  692:     ifa = ospf_find_vlink(p, ip->voa, ip->vid);
  693:     if (ifa)
  694:       ospf_iface_reconfigure(ifa, ip);
  695:     else
  696:       ospf_iface_new_vlink(p, ip);
  697:   }
  698: 
  699:   /* Delete remaining ifaces and areas */
  700:   WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
  701:     if (ifa->marked)
  702:     {
  703:       ospf_iface_shutdown(ifa);
  704:       ospf_iface_remove(ifa);
  705:     }
  706: 
  707:   WALK_LIST_DELSAFE(oa, oax, p->area_list)
  708:     if (oa->marked)
  709:       ospf_area_remove(oa);
  710: 
  711:   ospf_schedule_rtcalc(p);
  712: 
  713:   return 1;
  714: }
  715: 
  716: 
  717: void
  718: ospf_sh_neigh(struct proto *P, char *iff)
  719: {
  720:   struct ospf_proto *p = (struct ospf_proto *) P;
  721:   struct ospf_iface *ifa = NULL;
  722:   struct ospf_neighbor *n;
  723: 
  724:   if (p->p.proto_state != PS_UP)
  725:   {
  726:     cli_msg(-1013, "%s: is not up", p->p.name);
  727:     cli_msg(0, "");
  728:     return;
  729:   }
  730: 
  731:   cli_msg(-1013, "%s:", p->p.name);
  732:   cli_msg(-1013, "%-12s\t%3s\t%-15s\t%-5s\t%-10s %-12s", "Router ID", "Pri",
  733: 	  "     State", "DTime", "Interface", "Router IP");
  734:   WALK_LIST(ifa, p->iface_list)
  735:     if ((iff == NULL) || patmatch(iff, ifa->ifname))
  736:       WALK_LIST(n, ifa->neigh_list)
  737: 	ospf_sh_neigh_info(n);
  738:   cli_msg(0, "");
  739: }
  740: 
  741: void
  742: ospf_sh(struct proto *P)
  743: {
  744:   struct ospf_proto *p = (struct ospf_proto *) P;
  745:   struct ospf_area *oa;
  746:   struct ospf_iface *ifa;
  747:   struct ospf_neighbor *n;
  748:   int ifano, nno, adjno, firstfib;
  749:   struct area_net *anet;
  750: 
  751:   if (p->p.proto_state != PS_UP)
  752:   {
  753:     cli_msg(-1014, "%s: is not up", p->p.name);
  754:     cli_msg(0, "");
  755:     return;
  756:   }
  757: 
  758:   cli_msg(-1014, "%s:", p->p.name);
  759:   cli_msg(-1014, "RFC1583 compatibility: %s", (p->rfc1583 ? "enabled" : "disabled"));
  760:   cli_msg(-1014, "Stub router: %s", (p->stub_router ? "Yes" : "No"));
  761:   cli_msg(-1014, "RT scheduler tick: %d", p->tick);
  762:   cli_msg(-1014, "Number of areas: %u", p->areano);
  763:   cli_msg(-1014, "Number of LSAs in DB:\t%u", p->gr->hash_entries);
  764: 
  765:   WALK_LIST(oa, p->area_list)
  766:   {
  767:     cli_msg(-1014, "\tArea: %R (%u) %s", oa->areaid, oa->areaid,
  768: 	    oa->areaid == 0 ? "[BACKBONE]" : "");
  769:     ifano = 0;
  770:     nno = 0;
  771:     adjno = 0;
  772:     WALK_LIST(ifa, p->iface_list)
  773:     {
  774:       if (oa == ifa->oa)
  775:       {
  776: 	ifano++;
  777: 	WALK_LIST(n, ifa->neigh_list)
  778: 	{
  779: 	  nno++;
  780: 	  if (n->state == NEIGHBOR_FULL)
  781: 	    adjno++;
  782: 	}
  783:       }
  784:     }
  785: 
  786:     cli_msg(-1014, "\t\tStub:\t%s", oa_is_stub(oa) ? "Yes" : "No");
  787:     cli_msg(-1014, "\t\tNSSA:\t%s", oa_is_nssa(oa) ? "Yes" : "No");
  788:     cli_msg(-1014, "\t\tTransit:\t%s", oa->trcap ? "Yes" : "No");
  789: 
  790:     if (oa_is_nssa(oa))
  791:       cli_msg(-1014, "\t\tNSSA translation:\t%s%s", oa->translate ? "Yes" : "No",
  792: 	      oa->translate == TRANS_WAIT ? " (run down)" : "");
  793:     cli_msg(-1014, "\t\tNumber of interfaces:\t%u", ifano);
  794:     cli_msg(-1014, "\t\tNumber of neighbors:\t%u", nno);
  795:     cli_msg(-1014, "\t\tNumber of adjacent neighbors:\t%u", adjno);
  796: 
  797:     firstfib = 1;
  798:     FIB_WALK(&oa->net_fib, nftmp)
  799:     {
  800:       anet = (struct area_net *) nftmp;
  801:       if(firstfib)
  802:       {
  803: 	cli_msg(-1014, "\t\tArea networks:");
  804: 	firstfib = 0;
  805:       }
  806:       cli_msg(-1014, "\t\t\t%1I/%u\t%s\t%s", anet->fn.prefix, anet->fn.pxlen,
  807: 		anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : "");
  808:     }
  809:     FIB_WALK_END;
  810: 
  811:     firstfib = 1;
  812:     FIB_WALK(&oa->enet_fib, nftmp)
  813:     {
  814:       anet = (struct area_net *) nftmp;
  815:       if(firstfib)
  816:       {
  817: 	cli_msg(-1014, "\t\tArea external networks:");
  818: 	firstfib = 0;
  819:       }
  820:       cli_msg(-1014, "\t\t\t%1I/%u\t%s\t%s", anet->fn.prefix, anet->fn.pxlen,
  821: 		anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : "");
  822:     }
  823:     FIB_WALK_END;
  824: 
  825:   }
  826:   cli_msg(0, "");
  827: }
  828: 
  829: void
  830: ospf_sh_iface(struct proto *P, char *iff)
  831: {
  832:   struct ospf_proto *p = (struct ospf_proto *) P;
  833:   struct ospf_iface *ifa = NULL;
  834: 
  835:   if (p->p.proto_state != PS_UP)
  836:   {
  837:     cli_msg(-1015, "%s: is not up", p->p.name);
  838:     cli_msg(0, "");
  839:     return;
  840:   }
  841: 
  842:   cli_msg(-1015, "%s:", p->p.name);
  843:   WALK_LIST(ifa, p->iface_list)
  844:     if ((iff == NULL) || patmatch(iff, ifa->ifname))
  845:       ospf_iface_info(ifa);
  846:   cli_msg(0, "");
  847: }
  848: 
  849: /* lsa_compare_for_state() - Compare function for 'show ospf state'
  850:  *
  851:  * First we want to separate network-LSAs and other LSAs (because network-LSAs
  852:  * will be presented as network nodes and other LSAs together as router nodes)
  853:  * Network-LSAs are sorted according to network prefix, other LSAs are sorted
  854:  * according to originating router id (to get all LSA needed to represent one
  855:  * router node together). Then, according to LSA type, ID and age.
  856:  *
  857:  * For OSPFv3, we have to handle also Prefix-LSAs. We would like to put each
  858:  * immediately after the referenced LSA. We will make faked LSA based on ref_
  859:  * values
  860:  */
  861: 
  862: static struct ospf_lsa_header *
  863: fake_lsa_from_prefix_lsa(struct ospf_lsa_header *dst, struct ospf_lsa_header *src,
  864: 			 struct ospf_lsa_prefix *px)
  865: {
  866:   dst->age = src->age;
  867:   dst->type_raw = px->ref_type;
  868:   dst->id = px->ref_id;
  869:   dst->rt = px->ref_rt;
  870:   dst->sn = src->sn;
  871: 
  872:   return dst;
  873: }
  874: 
  875: 
  876: static int lsa_compare_ospf3;
  877: 
  878: static int
  879: lsa_compare_for_state(const void *p1, const void *p2)
  880: {
  881:   struct top_hash_entry *he1 = * (struct top_hash_entry **) p1;
  882:   struct top_hash_entry *he2 = * (struct top_hash_entry **) p2;
  883:   struct ospf_lsa_header *lsa1 = &(he1->lsa);
  884:   struct ospf_lsa_header *lsa2 = &(he2->lsa);
  885:   struct ospf_lsa_header lsatmp1, lsatmp2;
  886:   u16 lsa1_type = he1->lsa_type;
  887:   u16 lsa2_type = he2->lsa_type;
  888: 
  889:   if (he1->domain < he2->domain)
  890:     return -1;
  891:   if (he1->domain > he2->domain)
  892:     return 1;
  893: 
  894: 
  895:   /* px1 or px2 assumes OSPFv3 */
  896:   int px1 = (lsa1_type == LSA_T_PREFIX);
  897:   int px2 = (lsa2_type == LSA_T_PREFIX);
  898: 
  899:   if (px1)
  900:   {
  901:     lsa1 = fake_lsa_from_prefix_lsa(&lsatmp1, lsa1, he1->lsa_body);
  902:     lsa1_type = lsa1->type_raw;	/* FIXME: handle unknown ref_type */
  903:   }
  904: 
  905:   if (px2)
  906:   {
  907:     lsa2 = fake_lsa_from_prefix_lsa(&lsatmp2, lsa2, he2->lsa_body);
  908:     lsa2_type = lsa2->type_raw;
  909:   }
  910: 
  911: 
  912:   int nt1 = (lsa1_type == LSA_T_NET);
  913:   int nt2 = (lsa2_type == LSA_T_NET);
  914: 
  915:   if (nt1 != nt2)
  916:     return nt1 - nt2;
  917: 
  918:   if (nt1)
  919:   {
  920:     /* In OSPFv3, networks are named based on ID of DR */
  921:     if (lsa_compare_ospf3)
  922:     {
  923:       if (lsa1->rt < lsa2->rt)
  924: 	return -1;
  925:       if (lsa1->rt > lsa2->rt)
  926: 	return 1;
  927:     }
  928: 
  929:     /* For OSPFv2, this is IP of the network,
  930:        for OSPFv3, this is interface ID */
  931:     if (lsa1->id < lsa2->id)
  932:       return -1;
  933:     if (lsa1->id > lsa2->id)
  934:       return 1;
  935: 
  936:     if (px1 != px2)
  937:       return px1 - px2;
  938: 
  939:     return lsa1->sn - lsa2->sn;
  940:   }
  941:   else
  942:   {
  943:     if (lsa1->rt < lsa2->rt)
  944:       return -1;
  945:     if (lsa1->rt > lsa2->rt)
  946:       return 1;
  947: 
  948:     if (lsa1_type < lsa2_type)
  949:       return -1;
  950:     if (lsa1_type > lsa2_type)
  951:       return 1;
  952: 
  953:     if (lsa1->id < lsa2->id)
  954:       return -1;
  955:     if (lsa1->id > lsa2->id)
  956:       return 1;
  957: 
  958:     if (px1 != px2)
  959:       return px1 - px2;
  960: 
  961:     return lsa1->sn - lsa2->sn;
  962:   }
  963: }
  964: 
  965: static int
  966: ext_compare_for_state(const void *p1, const void *p2)
  967: {
  968:   struct top_hash_entry * he1 = * (struct top_hash_entry **) p1;
  969:   struct top_hash_entry * he2 = * (struct top_hash_entry **) p2;
  970:   struct ospf_lsa_header *lsa1 = &(he1->lsa);
  971:   struct ospf_lsa_header *lsa2 = &(he2->lsa);
  972: 
  973:   if (lsa1->rt < lsa2->rt)
  974:     return -1;
  975:   if (lsa1->rt > lsa2->rt)
  976:     return 1;
  977: 
  978:   if (lsa1->id < lsa2->id)
  979:     return -1;
  980:   if (lsa1->id > lsa2->id)
  981:     return 1;
  982: 
  983:   return lsa1->sn - lsa2->sn;
  984: }
  985: 
  986: static inline void
  987: show_lsa_distance(struct top_hash_entry *he)
  988: {
  989:   if (he->color == INSPF)
  990:     cli_msg(-1016, "\t\tdistance %u", he->dist);
  991:   else
  992:     cli_msg(-1016, "\t\tunreachable");
  993: }
  994: 
  995: static inline void
  996: show_lsa_router(struct ospf_proto *p, struct top_hash_entry *he, int verbose)
  997: {
  998:   struct ospf_lsa_rt_walk rtl;
  999: 
 1000:   cli_msg(-1016, "");
 1001:   cli_msg(-1016, "\trouter %R", he->lsa.rt);
 1002:   show_lsa_distance(he);
 1003: 
 1004:   lsa_walk_rt_init(p, he, &rtl);
 1005:   while (lsa_walk_rt(&rtl))
 1006:     if (rtl.type == LSART_VLNK)
 1007:       cli_msg(-1016, "\t\tvlink %R metric %u", rtl.id, rtl.metric);
 1008: 
 1009:   lsa_walk_rt_init(p, he, &rtl);
 1010:   while (lsa_walk_rt(&rtl))
 1011:     if (rtl.type == LSART_PTP)
 1012:       cli_msg(-1016, "\t\trouter %R metric %u", rtl.id, rtl.metric);
 1013: 
 1014:   lsa_walk_rt_init(p, he, &rtl);
 1015:   while (lsa_walk_rt(&rtl))
 1016:     if (rtl.type == LSART_NET)
 1017:     {
 1018:       if (ospf_is_v2(p))
 1019:       {
 1020: 	/* In OSPFv2, we try to find network-LSA to get prefix/pxlen */
 1021: 	struct top_hash_entry *net_he = ospf_hash_find_net2(p->gr, he->domain, rtl.id);
 1022: 
 1023: 	if (net_he && (net_he->lsa.age < LSA_MAXAGE))
 1024: 	{
 1025: 	  struct ospf_lsa_header *net_lsa = &(net_he->lsa);
 1026: 	  struct ospf_lsa_net *net_ln = net_he->lsa_body;
 1027: 
 1028: 	  cli_msg(-1016, "\t\tnetwork %I/%d metric %u",
 1029: 		  ipa_from_u32(net_lsa->id & net_ln->optx),
 1030: 		  u32_masklen(net_ln->optx), rtl.metric);
 1031: 	}
 1032: 	else
 1033: 	  cli_msg(-1016, "\t\tnetwork [%R] metric %u", rtl.id, rtl.metric);
 1034:       }
 1035:       else
 1036: 	cli_msg(-1016, "\t\tnetwork [%R-%u] metric %u", rtl.id, rtl.nif, rtl.metric);
 1037:     }
 1038: 
 1039:   if (ospf_is_v2(p) && verbose)
 1040:   {
 1041:     lsa_walk_rt_init(p, he, &rtl);
 1042:     while (lsa_walk_rt(&rtl))
 1043:       if (rtl.type == LSART_STUB)
 1044: 	cli_msg(-1016, "\t\tstubnet %I/%d metric %u",
 1045: 		ipa_from_u32(rtl.id), u32_masklen(rtl.data), rtl.metric);
 1046:   }
 1047: }
 1048: 
 1049: static inline void
 1050: show_lsa_network(struct top_hash_entry *he, int ospf2)
 1051: {
 1052:   struct ospf_lsa_header *lsa = &(he->lsa);
 1053:   struct ospf_lsa_net *ln = he->lsa_body;
 1054:   u32 i;
 1055: 
 1056:   if (ospf2)
 1057:   {
 1058:     cli_msg(-1016, "");
 1059:     cli_msg(-1016, "\tnetwork %I/%d", ipa_from_u32(lsa->id & ln->optx), u32_masklen(ln->optx));
 1060:     cli_msg(-1016, "\t\tdr %R", lsa->rt);
 1061:   }
 1062:   else
 1063:   {
 1064:     cli_msg(-1016, "");
 1065:     cli_msg(-1016, "\tnetwork [%R-%u]", lsa->rt, lsa->id);
 1066:   }
 1067: 
 1068:   show_lsa_distance(he);
 1069: 
 1070:   for (i = 0; i < lsa_net_count(lsa); i++)
 1071:     cli_msg(-1016, "\t\trouter %R", ln->routers[i]);
 1072: }
 1073: 
 1074: static inline void
 1075: show_lsa_sum_net(struct top_hash_entry *he, int ospf2)
 1076: {
 1077:   ip_addr ip;
 1078:   int pxlen;
 1079:   u8 pxopts;
 1080:   u32 metric;
 1081: 
 1082:   lsa_parse_sum_net(he, ospf2, &ip, &pxlen, &pxopts, &metric);
 1083:   cli_msg(-1016, "\t\txnetwork %I/%d metric %u", ip, pxlen, metric);
 1084: }
 1085: 
 1086: static inline void
 1087: show_lsa_sum_rt(struct top_hash_entry *he, int ospf2)
 1088: {
 1089:   u32 metric;
 1090:   u32 dst_rid;
 1091:   u32 options;
 1092: 
 1093:   lsa_parse_sum_rt(he, ospf2, &dst_rid, &metric, &options);
 1094:   cli_msg(-1016, "\t\txrouter %R metric %u", dst_rid, metric);
 1095: }
 1096: 
 1097: 
 1098: static inline void
 1099: show_lsa_external(struct top_hash_entry *he, int ospf2)
 1100: {
 1101:   struct ospf_lsa_ext_local rt;
 1102:   char str_via[STD_ADDRESS_P_LENGTH + 8] = "";
 1103:   char str_tag[16] = "";
 1104: 
 1105:   if (he->lsa_type == LSA_T_EXT)
 1106:     he->domain = 0; /* Unmark the LSA */
 1107: 
 1108:   lsa_parse_ext(he, ospf2, &rt);
 1109: 
 1110:   if (rt.fbit)
 1111:     bsprintf(str_via, " via %I", rt.fwaddr);
 1112: 
 1113:   if (rt.tag)
 1114:     bsprintf(str_tag, " tag %08x", rt.tag);
 1115: 
 1116:   cli_msg(-1016, "\t\t%s %I/%d metric%s %u%s%s",
 1117: 	  (he->lsa_type == LSA_T_NSSA) ? "nssa-ext" : "external",
 1118: 	  rt.ip, rt.pxlen, rt.ebit ? "2" : "", rt.metric, str_via, str_tag);
 1119: }
 1120: 
 1121: static inline void
 1122: show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode)
 1123: {
 1124:   struct ospf_lsa_prefix *px = he->lsa_body;
 1125:   ip_addr pxa;
 1126:   int pxlen;
 1127:   u8 pxopts;
 1128:   u16 metric;
 1129:   u32 *buf;
 1130:   int i;
 1131: 
 1132:   /* We check whether given prefix-LSA is related to the current node */
 1133:   if ((px->ref_type != cnode->lsa.type_raw) || (px->ref_rt != cnode->lsa.rt))
 1134:     return;
 1135: 
 1136:   if ((px->ref_type == LSA_T_RT) && (px->ref_id != 0))
 1137:     return;
 1138: 
 1139:   if ((px->ref_type == LSA_T_NET) && (px->ref_id != cnode->lsa.id))
 1140:     return;
 1141: 
 1142:   buf = px->rest;
 1143:   for (i = 0; i < px->pxcount; i++)
 1144:     {
 1145:       buf = lsa_get_ipv6_prefix(buf, &pxa, &pxlen, &pxopts, &metric);
 1146: 
 1147:       if (px->ref_type == LSA_T_RT)
 1148: 	cli_msg(-1016, "\t\tstubnet %I/%d metric %u", pxa, pxlen, metric);
 1149:       else
 1150: 	cli_msg(-1016, "\t\taddress %I/%d", pxa, pxlen);
 1151:     }
 1152: }
 1153: 
 1154: void
 1155: ospf_sh_state(struct proto *P, int verbose, int reachable)
 1156: {
 1157:   struct ospf_proto *p = (struct ospf_proto *) P;
 1158:   int ospf2 = ospf_is_v2(p);
 1159:   uint i, ix, j1, jx;
 1160:   u32 last_area = 0xFFFFFFFF;
 1161: 
 1162:   if (p->p.proto_state != PS_UP)
 1163:   {
 1164:     cli_msg(-1016, "%s: is not up", p->p.name);
 1165:     cli_msg(0, "");
 1166:     return;
 1167:   }
 1168: 
 1169:   /* We store interesting area-scoped LSAs in array hea and
 1170:      global-scoped (LSA_T_EXT) LSAs in array hex */
 1171: 
 1172:   int num = p->gr->hash_entries;
 1173:   struct top_hash_entry *hea[num];
 1174:   struct top_hash_entry *hex[verbose ? num : 0];
 1175:   struct top_hash_entry *he;
 1176:   struct top_hash_entry *cnode = NULL;
 1177: 
 1178:   j1 = jx = 0;
 1179:   WALK_SLIST(he, p->lsal)
 1180:   {
 1181:     int accept;
 1182: 
 1183:     if (he->lsa.age == LSA_MAXAGE)
 1184:       continue;
 1185: 
 1186:     switch (he->lsa_type)
 1187:     {
 1188:     case LSA_T_RT:
 1189:     case LSA_T_NET:
 1190:       accept = 1;
 1191:       break;
 1192: 
 1193:     case LSA_T_SUM_NET:
 1194:     case LSA_T_SUM_RT:
 1195:     case LSA_T_NSSA:
 1196:     case LSA_T_PREFIX:
 1197:       accept = verbose;
 1198:       break;
 1199: 
 1200:     case LSA_T_EXT:
 1201:       if (verbose)
 1202:       {
 1203: 	he->domain = 1; /* Abuse domain field to mark the LSA */
 1204: 	hex[jx++] = he;
 1205:       }
 1206:       /* fallthrough */
 1207:     default:
 1208:       accept = 0;
 1209:     }
 1210: 
 1211:     if (accept)
 1212:       hea[j1++] = he;
 1213:   }
 1214: 
 1215:   ASSERT(j1 <= num && jx <= num);
 1216: 
 1217:   lsa_compare_ospf3 = !ospf2;
 1218:   qsort(hea, j1, sizeof(struct top_hash_entry *), lsa_compare_for_state);
 1219:   qsort(hex, jx, sizeof(struct top_hash_entry *), ext_compare_for_state);
 1220: 
 1221:   /*
 1222:    * This code is a bit tricky, we have a primary LSAs (router and
 1223:    * network) that are presented as a node, and secondary LSAs that
 1224:    * are presented as a part of a primary node. cnode represents an
 1225:    * currently opened node (whose header was presented). The LSAs are
 1226:    * sorted to get secondary LSAs just after related primary LSA (if
 1227:    * available). We present secondary LSAs only when related primary
 1228:    * LSA is opened.
 1229:    *
 1230:    * AS-external LSAs are stored separately as they might be presented
 1231:    * several times (for each area when related ASBR is opened). When
 1232:    * the node is closed, related external routes are presented. We
 1233:    * also have to take into account that in OSPFv3, there might be
 1234:    * more router-LSAs and only the first should be considered as a
 1235:    * primary. This is handled by not closing old router-LSA when next
 1236:    * one is processed (which is not opened because there is already
 1237:    * one opened).
 1238:    */
 1239: 
 1240:   ix = 0;
 1241:   for (i = 0; i < j1; i++)
 1242:   {
 1243:     he = hea[i];
 1244: 
 1245:     /* If there is no opened node, we open the LSA (if appropriate) or skip to the next one */
 1246:     if (!cnode)
 1247:     {
 1248:       if (((he->lsa_type == LSA_T_RT) || (he->lsa_type == LSA_T_NET))
 1249: 	  && ((he->color == INSPF) || !reachable))
 1250:       {
 1251: 	cnode = he;
 1252: 
 1253: 	if (he->domain != last_area)
 1254: 	{
 1255: 	  cli_msg(-1016, "");
 1256: 	  cli_msg(-1016, "area %R", he->domain);
 1257: 	  last_area = he->domain;
 1258: 	  ix = 0;
 1259: 	}
 1260:       }
 1261:       else
 1262: 	continue;
 1263:     }
 1264: 
 1265:     ASSERT(cnode && (he->domain == last_area) && (he->lsa.rt == cnode->lsa.rt));
 1266: 
 1267:     switch (he->lsa_type)
 1268:     {
 1269:     case LSA_T_RT:
 1270:       if (he->lsa.id == cnode->lsa.id)
 1271: 	show_lsa_router(p, he, verbose);
 1272:       break;
 1273: 
 1274:     case LSA_T_NET:
 1275:       show_lsa_network(he, ospf2);
 1276:       break;
 1277: 
 1278:     case LSA_T_SUM_NET:
 1279:       if (cnode->lsa_type == LSA_T_RT)
 1280: 	show_lsa_sum_net(he, ospf2);
 1281:       break;
 1282: 
 1283:     case LSA_T_SUM_RT:
 1284:       if (cnode->lsa_type == LSA_T_RT)
 1285: 	show_lsa_sum_rt(he, ospf2);
 1286:       break;
 1287: 
 1288:     case LSA_T_EXT:
 1289:     case LSA_T_NSSA:
 1290:       show_lsa_external(he, ospf2);
 1291:       break;
 1292: 
 1293:     case LSA_T_PREFIX:
 1294:       show_lsa_prefix(he, cnode);
 1295:       break;
 1296:     }
 1297: 
 1298:     /* In these cases, we close the current node */
 1299:     if ((i+1 == j1)
 1300: 	|| (hea[i+1]->domain != last_area)
 1301: 	|| (hea[i+1]->lsa.rt != cnode->lsa.rt)
 1302: 	|| (hea[i+1]->lsa_type == LSA_T_NET))
 1303:     {
 1304:       while ((ix < jx) && (hex[ix]->lsa.rt < cnode->lsa.rt))
 1305: 	ix++;
 1306: 
 1307:       while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt))
 1308: 	show_lsa_external(hex[ix++], ospf2);
 1309: 
 1310:       cnode = NULL;
 1311:     }
 1312:   }
 1313: 
 1314:   int hdr = 0;
 1315:   u32 last_rt = 0xFFFFFFFF;
 1316:   for (ix = 0; ix < jx; ix++)
 1317:   {
 1318:     he = hex[ix];
 1319: 
 1320:     /* If it is still marked, we show it now. */
 1321:     if (he->domain)
 1322:     {
 1323:       he->domain = 0;
 1324: 
 1325:       if ((he->color != INSPF) && reachable)
 1326: 	continue;
 1327: 
 1328:       if (!hdr)
 1329:       {
 1330: 	cli_msg(-1016, "");
 1331: 	cli_msg(-1016, "other ASBRs");
 1332: 	hdr = 1;
 1333:       }
 1334: 
 1335:       if (he->lsa.rt != last_rt)
 1336:       {
 1337: 	cli_msg(-1016, "");
 1338: 	cli_msg(-1016, "\trouter %R", he->lsa.rt);
 1339: 	last_rt = he->lsa.rt;
 1340:       }
 1341: 
 1342:       show_lsa_external(he, ospf2);
 1343:     }
 1344:   }
 1345: 
 1346:   cli_msg(0, "");
 1347: }
 1348: 
 1349: 
 1350: static int
 1351: lsa_compare_for_lsadb(const void *p1, const void *p2)
 1352: {
 1353:   struct top_hash_entry * he1 = * (struct top_hash_entry **) p1;
 1354:   struct top_hash_entry * he2 = * (struct top_hash_entry **) p2;
 1355:   struct ospf_lsa_header *lsa1 = &(he1->lsa);
 1356:   struct ospf_lsa_header *lsa2 = &(he2->lsa);
 1357:   int sc1 = LSA_SCOPE(he1->lsa_type);
 1358:   int sc2 = LSA_SCOPE(he2->lsa_type);
 1359: 
 1360:   if (sc1 != sc2)
 1361:     return sc2 - sc1;
 1362: 
 1363:   if (he1->domain != he2->domain)
 1364:     return he1->domain - he2->domain;
 1365: 
 1366:   if (lsa1->rt != lsa2->rt)
 1367:     return lsa1->rt - lsa2->rt;
 1368: 
 1369:   if (lsa1->id != lsa2->id)
 1370:     return lsa1->id - lsa2->id;
 1371: 
 1372:   if (he1->lsa_type != he2->lsa_type)
 1373:     return he1->lsa_type - he2->lsa_type;
 1374: 
 1375:   return lsa1->sn - lsa2->sn;
 1376: }
 1377: 
 1378: void
 1379: ospf_sh_lsadb(struct lsadb_show_data *ld)
 1380: {
 1381:   struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->name, &proto_ospf);
 1382:   uint num = p->gr->hash_entries;
 1383:   uint i, j;
 1384:   int last_dscope = -1;
 1385:   u32 last_domain = 0;
 1386:   u16 type_mask = ospf_is_v2(p) ?  0x00ff : 0xffff;	/* see lsa_etype() */
 1387: 
 1388:   if (p->p.proto_state != PS_UP)
 1389:   {
 1390:     cli_msg(-1017, "%s: is not up", p->p.name);
 1391:     cli_msg(0, "");
 1392:     return;
 1393:   }
 1394: 
 1395:   if (ld->router == SH_ROUTER_SELF)
 1396:     ld->router = p->router_id;
 1397: 
 1398:   struct top_hash_entry *hea[num];
 1399:   struct top_hash_entry *he;
 1400: 
 1401:   j = 0;
 1402:   WALK_SLIST(he, p->lsal)
 1403:     if (he->lsa_body)
 1404:       hea[j++] = he;
 1405: 
 1406:   ASSERT(j <= num);
 1407: 
 1408:   qsort(hea, j, sizeof(struct top_hash_entry *), lsa_compare_for_lsadb);
 1409: 
 1410:   for (i = 0; i < j; i++)
 1411:   {
 1412:     struct ospf_lsa_header *lsa = &(hea[i]->lsa);
 1413:     u16 lsa_type = lsa->type_raw & type_mask;
 1414:     u16 dscope = LSA_SCOPE(hea[i]->lsa_type);
 1415: 
 1416:     /* Hack: 1 is used for LSA_SCOPE_LINK, fixed by & 0xf000 */
 1417:     if (ld->scope && (dscope != (ld->scope & 0xf000)))
 1418:       continue;
 1419: 
 1420:     if ((ld->scope == LSA_SCOPE_AREA) && (hea[i]->domain != ld->area))
 1421:       continue;
 1422: 
 1423:     /* For user convenience ignore high nibble */
 1424:     if (ld->type && ((lsa_type & 0x0fff) != (ld->type & 0x0fff)))
 1425:       continue;
 1426: 
 1427:     if (ld->lsid && (lsa->id != ld->lsid))
 1428:       continue;
 1429: 
 1430:     if (ld->router && (lsa->rt != ld->router))
 1431:       continue;
 1432: 
 1433:     if ((dscope != last_dscope) || (hea[i]->domain != last_domain))
 1434:     {
 1435:       cli_msg(-1017, "");
 1436:       switch (dscope)
 1437:       {
 1438:       case LSA_SCOPE_AS:
 1439: 	cli_msg(-1017, "Global");
 1440: 	break;
 1441: 
 1442:       case LSA_SCOPE_AREA:
 1443: 	cli_msg(-1017, "Area %R", hea[i]->domain);
 1444: 	break;
 1445: 
 1446:       case LSA_SCOPE_LINK:
 1447: 	{
 1448: 	  struct iface *ifa = if_find_by_index(hea[i]->domain);
 1449: 	  cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?");
 1450: 	}
 1451: 	break;
 1452:       }
 1453:       cli_msg(-1017, "");
 1454:       cli_msg(-1017," Type   LS ID           Router          Sequence   Age  Checksum");
 1455: 
 1456:       last_dscope = dscope;
 1457:       last_domain = hea[i]->domain;
 1458:     }
 1459: 
 1460:     cli_msg(-1017," %04x  %-15R %-15R  %08x %5u    %04x",
 1461: 	    lsa_type, lsa->id, lsa->rt, lsa->sn, lsa->age, lsa->checksum);
 1462:   }
 1463:   cli_msg(0, "");
 1464: }
 1465: 
 1466: 
 1467: struct protocol proto_ospf = {
 1468:   .name =		"OSPF",
 1469:   .template =		"ospf%d",
 1470:   .attr_class =		EAP_OSPF,
 1471:   .preference =		DEF_PREF_OSPF,
 1472:   .config_size =	sizeof(struct ospf_config),
 1473:   .init =		ospf_init,
 1474:   .dump =		ospf_dump,
 1475:   .start =		ospf_start,
 1476:   .shutdown =		ospf_shutdown,
 1477:   .reconfigure =	ospf_reconfigure,
 1478:   .get_status =		ospf_get_status,
 1479:   .get_attr =		ospf_get_attr,
 1480:   .get_route_info =	ospf_get_route_info
 1481: };

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>