Annotation of embedaddon/bird/proto/ospf/ospf.c, revision 1.1.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: /**
                     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:     default:
                   1207:       accept = 0;
                   1208:     }
                   1209: 
                   1210:     if (accept)
                   1211:       hea[j1++] = he;
                   1212:   }
                   1213: 
                   1214:   ASSERT(j1 <= num && jx <= num);
                   1215: 
                   1216:   lsa_compare_ospf3 = !ospf2;
                   1217:   qsort(hea, j1, sizeof(struct top_hash_entry *), lsa_compare_for_state);
                   1218:   qsort(hex, jx, sizeof(struct top_hash_entry *), ext_compare_for_state);
                   1219: 
                   1220:   /*
                   1221:    * This code is a bit tricky, we have a primary LSAs (router and
                   1222:    * network) that are presented as a node, and secondary LSAs that
                   1223:    * are presented as a part of a primary node. cnode represents an
                   1224:    * currently opened node (whose header was presented). The LSAs are
                   1225:    * sorted to get secondary LSAs just after related primary LSA (if
                   1226:    * available). We present secondary LSAs only when related primary
                   1227:    * LSA is opened.
                   1228:    *
                   1229:    * AS-external LSAs are stored separately as they might be presented
                   1230:    * several times (for each area when related ASBR is opened). When
                   1231:    * the node is closed, related external routes are presented. We
                   1232:    * also have to take into account that in OSPFv3, there might be
                   1233:    * more router-LSAs and only the first should be considered as a
                   1234:    * primary. This is handled by not closing old router-LSA when next
                   1235:    * one is processed (which is not opened because there is already
                   1236:    * one opened).
                   1237:    */
                   1238: 
                   1239:   ix = 0;
                   1240:   for (i = 0; i < j1; i++)
                   1241:   {
                   1242:     he = hea[i];
                   1243: 
                   1244:     /* If there is no opened node, we open the LSA (if appropriate) or skip to the next one */
                   1245:     if (!cnode)
                   1246:     {
                   1247:       if (((he->lsa_type == LSA_T_RT) || (he->lsa_type == LSA_T_NET))
                   1248:          && ((he->color == INSPF) || !reachable))
                   1249:       {
                   1250:        cnode = he;
                   1251: 
                   1252:        if (he->domain != last_area)
                   1253:        {
                   1254:          cli_msg(-1016, "");
                   1255:          cli_msg(-1016, "area %R", he->domain);
                   1256:          last_area = he->domain;
                   1257:          ix = 0;
                   1258:        }
                   1259:       }
                   1260:       else
                   1261:        continue;
                   1262:     }
                   1263: 
                   1264:     ASSERT(cnode && (he->domain == last_area) && (he->lsa.rt == cnode->lsa.rt));
                   1265: 
                   1266:     switch (he->lsa_type)
                   1267:     {
                   1268:     case LSA_T_RT:
                   1269:       if (he->lsa.id == cnode->lsa.id)
                   1270:        show_lsa_router(p, he, verbose);
                   1271:       break;
                   1272: 
                   1273:     case LSA_T_NET:
                   1274:       show_lsa_network(he, ospf2);
                   1275:       break;
                   1276: 
                   1277:     case LSA_T_SUM_NET:
                   1278:       if (cnode->lsa_type == LSA_T_RT)
                   1279:        show_lsa_sum_net(he, ospf2);
                   1280:       break;
                   1281: 
                   1282:     case LSA_T_SUM_RT:
                   1283:       if (cnode->lsa_type == LSA_T_RT)
                   1284:        show_lsa_sum_rt(he, ospf2);
                   1285:       break;
                   1286: 
                   1287:     case LSA_T_EXT:
                   1288:     case LSA_T_NSSA:
                   1289:       show_lsa_external(he, ospf2);
                   1290:       break;
                   1291: 
                   1292:     case LSA_T_PREFIX:
                   1293:       show_lsa_prefix(he, cnode);
                   1294:       break;
                   1295:     }
                   1296: 
                   1297:     /* In these cases, we close the current node */
                   1298:     if ((i+1 == j1)
                   1299:        || (hea[i+1]->domain != last_area)
                   1300:        || (hea[i+1]->lsa.rt != cnode->lsa.rt)
                   1301:        || (hea[i+1]->lsa_type == LSA_T_NET))
                   1302:     {
                   1303:       while ((ix < jx) && (hex[ix]->lsa.rt < cnode->lsa.rt))
                   1304:        ix++;
                   1305: 
                   1306:       while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt))
                   1307:        show_lsa_external(hex[ix++], ospf2);
                   1308: 
                   1309:       cnode = NULL;
                   1310:     }
                   1311:   }
                   1312: 
                   1313:   int hdr = 0;
                   1314:   u32 last_rt = 0xFFFFFFFF;
                   1315:   for (ix = 0; ix < jx; ix++)
                   1316:   {
                   1317:     he = hex[ix];
                   1318: 
                   1319:     /* If it is still marked, we show it now. */
                   1320:     if (he->domain)
                   1321:     {
                   1322:       he->domain = 0;
                   1323: 
                   1324:       if ((he->color != INSPF) && reachable)
                   1325:        continue;
                   1326: 
                   1327:       if (!hdr)
                   1328:       {
                   1329:        cli_msg(-1016, "");
                   1330:        cli_msg(-1016, "other ASBRs");
                   1331:        hdr = 1;
                   1332:       }
                   1333: 
                   1334:       if (he->lsa.rt != last_rt)
                   1335:       {
                   1336:        cli_msg(-1016, "");
                   1337:        cli_msg(-1016, "\trouter %R", he->lsa.rt);
                   1338:        last_rt = he->lsa.rt;
                   1339:       }
                   1340: 
                   1341:       show_lsa_external(he, ospf2);
                   1342:     }
                   1343:   }
                   1344: 
                   1345:   cli_msg(0, "");
                   1346: }
                   1347: 
                   1348: 
                   1349: static int
                   1350: lsa_compare_for_lsadb(const void *p1, const void *p2)
                   1351: {
                   1352:   struct top_hash_entry * he1 = * (struct top_hash_entry **) p1;
                   1353:   struct top_hash_entry * he2 = * (struct top_hash_entry **) p2;
                   1354:   struct ospf_lsa_header *lsa1 = &(he1->lsa);
                   1355:   struct ospf_lsa_header *lsa2 = &(he2->lsa);
                   1356:   int sc1 = LSA_SCOPE(he1->lsa_type);
                   1357:   int sc2 = LSA_SCOPE(he2->lsa_type);
                   1358: 
                   1359:   if (sc1 != sc2)
                   1360:     return sc2 - sc1;
                   1361: 
                   1362:   if (he1->domain != he2->domain)
                   1363:     return he1->domain - he2->domain;
                   1364: 
                   1365:   if (lsa1->rt != lsa2->rt)
                   1366:     return lsa1->rt - lsa2->rt;
                   1367: 
                   1368:   if (lsa1->id != lsa2->id)
                   1369:     return lsa1->id - lsa2->id;
                   1370: 
                   1371:   if (he1->lsa_type != he2->lsa_type)
                   1372:     return he1->lsa_type - he2->lsa_type;
                   1373: 
                   1374:   return lsa1->sn - lsa2->sn;
                   1375: }
                   1376: 
                   1377: void
                   1378: ospf_sh_lsadb(struct lsadb_show_data *ld)
                   1379: {
                   1380:   struct ospf_proto *p = (struct ospf_proto *) proto_get_named(ld->name, &proto_ospf);
                   1381:   uint num = p->gr->hash_entries;
                   1382:   uint i, j;
                   1383:   int last_dscope = -1;
                   1384:   u32 last_domain = 0;
                   1385:   u16 type_mask = ospf_is_v2(p) ?  0x00ff : 0xffff;    /* see lsa_etype() */
                   1386: 
                   1387:   if (p->p.proto_state != PS_UP)
                   1388:   {
                   1389:     cli_msg(-1017, "%s: is not up", p->p.name);
                   1390:     cli_msg(0, "");
                   1391:     return;
                   1392:   }
                   1393: 
                   1394:   if (ld->router == SH_ROUTER_SELF)
                   1395:     ld->router = p->router_id;
                   1396: 
                   1397:   struct top_hash_entry *hea[num];
                   1398:   struct top_hash_entry *he;
                   1399: 
                   1400:   j = 0;
                   1401:   WALK_SLIST(he, p->lsal)
                   1402:     if (he->lsa_body)
                   1403:       hea[j++] = he;
                   1404: 
                   1405:   ASSERT(j <= num);
                   1406: 
                   1407:   qsort(hea, j, sizeof(struct top_hash_entry *), lsa_compare_for_lsadb);
                   1408: 
                   1409:   for (i = 0; i < j; i++)
                   1410:   {
                   1411:     struct ospf_lsa_header *lsa = &(hea[i]->lsa);
                   1412:     u16 lsa_type = lsa->type_raw & type_mask;
                   1413:     u16 dscope = LSA_SCOPE(hea[i]->lsa_type);
                   1414: 
                   1415:     /* Hack: 1 is used for LSA_SCOPE_LINK, fixed by & 0xf000 */
                   1416:     if (ld->scope && (dscope != (ld->scope & 0xf000)))
                   1417:       continue;
                   1418: 
                   1419:     if ((ld->scope == LSA_SCOPE_AREA) && (hea[i]->domain != ld->area))
                   1420:       continue;
                   1421: 
                   1422:     /* For user convenience ignore high nibble */
                   1423:     if (ld->type && ((lsa_type & 0x0fff) != (ld->type & 0x0fff)))
                   1424:       continue;
                   1425: 
                   1426:     if (ld->lsid && (lsa->id != ld->lsid))
                   1427:       continue;
                   1428: 
                   1429:     if (ld->router && (lsa->rt != ld->router))
                   1430:       continue;
                   1431: 
                   1432:     if ((dscope != last_dscope) || (hea[i]->domain != last_domain))
                   1433:     {
                   1434:       cli_msg(-1017, "");
                   1435:       switch (dscope)
                   1436:       {
                   1437:       case LSA_SCOPE_AS:
                   1438:        cli_msg(-1017, "Global");
                   1439:        break;
                   1440: 
                   1441:       case LSA_SCOPE_AREA:
                   1442:        cli_msg(-1017, "Area %R", hea[i]->domain);
                   1443:        break;
                   1444: 
                   1445:       case LSA_SCOPE_LINK:
                   1446:        {
                   1447:          struct iface *ifa = if_find_by_index(hea[i]->domain);
                   1448:          cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?");
                   1449:        }
                   1450:        break;
                   1451:       }
                   1452:       cli_msg(-1017, "");
                   1453:       cli_msg(-1017," Type   LS ID           Router          Sequence   Age  Checksum");
                   1454: 
                   1455:       last_dscope = dscope;
                   1456:       last_domain = hea[i]->domain;
                   1457:     }
                   1458: 
                   1459:     cli_msg(-1017," %04x  %-15R %-15R  %08x %5u    %04x",
                   1460:            lsa_type, lsa->id, lsa->rt, lsa->sn, lsa->age, lsa->checksum);
                   1461:   }
                   1462:   cli_msg(0, "");
                   1463: }
                   1464: 
                   1465: 
                   1466: struct protocol proto_ospf = {
                   1467:   .name =              "OSPF",
                   1468:   .template =          "ospf%d",
                   1469:   .attr_class =                EAP_OSPF,
                   1470:   .preference =                DEF_PREF_OSPF,
                   1471:   .config_size =       sizeof(struct ospf_config),
                   1472:   .init =              ospf_init,
                   1473:   .dump =              ospf_dump,
                   1474:   .start =             ospf_start,
                   1475:   .shutdown =          ospf_shutdown,
                   1476:   .reconfigure =       ospf_reconfigure,
                   1477:   .get_status =                ospf_get_status,
                   1478:   .get_attr =          ospf_get_attr,
                   1479:   .get_route_info =    ospf_get_route_info
                   1480: };

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