Annotation of embedaddon/bird/proto/ospf/ospf.c, revision 1.1
1.1 ! misho 1: /*
! 2: * BIRD -- OSPF
! 3: *
! 4: * (c) 1999--2004 Ondrej Filip <feela@network.cz>
! 5: * (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
! 6: * (c) 2009--2014 CZ.NIC z.s.p.o.
! 7: *
! 8: * Can be freely distributed and used under the terms of the GNU GPL.
! 9: */
! 10:
! 11: /**
! 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>