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