Return to ospf.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird / proto / ospf |
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: };