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 3623 - OSPFv2 Graceful Restart
96: * - RFC 4576 - OSPFv2 VPN loop prevention
97: * - RFC 5187 - OSPFv3 Graceful Restart
98: * - RFC 5250 - OSPFv2 Opaque LSAs
99: * - RFC 5709 - OSPFv2 HMAC-SHA Cryptographic Authentication
100: * - RFC 5838 - OSPFv3 Support of Address Families
101: * - RFC 6549 - OSPFv2 Multi-Instance Extensions
102: * - RFC 6987 - OSPF Stub Router Advertisement
103: * - RFC 7166 - OSPFv3 Authentication Trailer
104: * - RFC 7770 - OSPF Router Information LSA
105: */
106:
107: #include <stdlib.h>
108: #include "ospf.h"
109:
110: static int ospf_preexport(struct proto *P, rte **new, struct linpool *pool);
111: static void ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool);
112: static void ospf_store_tmp_attrs(struct rte *rt, struct linpool *pool);
113: static void ospf_reload_routes(struct channel *C);
114: static int ospf_rte_better(struct rte *new, struct rte *old);
115: static int ospf_rte_same(struct rte *new, struct rte *old);
116: static void ospf_disp(timer *timer);
117:
118:
119: static void
120: add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
121: {
122: struct ospf_proto *p = oa->po;
123: struct area_net_config *anc;
124: struct area_net *an;
125:
126: fib_init(&oa->net_fib, p->p.pool, ospf_get_af(p),
127: sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
128: fib_init(&oa->enet_fib, p->p.pool, ospf_get_af(p),
129: sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
130:
131: WALK_LIST(anc, ac->net_list)
132: {
133: an = fib_get(&oa->net_fib, &anc->prefix);
134: an->hidden = anc->hidden;
135: }
136:
137: WALK_LIST(anc, ac->enet_list)
138: {
139: an = fib_get(&oa->enet_fib, &anc->prefix);
140: an->hidden = anc->hidden;
141: an->tag = anc->tag;
142: }
143: }
144:
145: static inline uint
146: ospf_opts(struct ospf_proto *p)
147: {
148: if (ospf_is_v2(p))
149: return OPT_O;
150:
151: return ((ospf_is_ip6(p) && !p->af_mc) ? OPT_V6 : 0) |
152: (!p->stub_router ? OPT_R : 0) | (p->af_ext ? OPT_AF : 0);
153: }
154:
155: static void
156: ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
157: {
158: struct ospf_area *oa;
159:
160: OSPF_TRACE(D_EVENTS, "Adding area %R", ac->areaid);
161:
162: oa = mb_allocz(p->p.pool, sizeof(struct ospf_area));
163: add_tail(&p->area_list, NODE oa);
164: p->areano++;
165:
166: oa->ac = ac;
167: oa->areaid = ac->areaid;
168: oa->rt = NULL;
169: oa->po = p;
170: fib_init(&oa->rtr, p->p.pool, NET_IP4, sizeof(ort), OFFSETOF(ort, fn), 0, NULL);
171: add_area_nets(oa, ac);
172:
173: if (oa->areaid == 0)
174: p->backbone = oa;
175:
176: oa->options = ac->type | ospf_opts(p);
177:
178: ospf_notify_rt_lsa(oa);
179: }
180:
181: static void
182: ospf_flush_area(struct ospf_proto *p, u32 areaid)
183: {
184: struct top_hash_entry *en;
185:
186: WALK_SLIST(en, p->lsal)
187: if ((LSA_SCOPE(en->lsa_type) == LSA_SCOPE_AREA) && (en->domain == areaid))
188: ospf_flush_lsa(p, en);
189: }
190:
191: static void
192: ospf_area_remove(struct ospf_area *oa)
193: {
194: struct ospf_proto *p = oa->po;
195: OSPF_TRACE(D_EVENTS, "Removing area %R", oa->areaid);
196:
197: /* We suppose that interfaces are already removed */
198: ospf_flush_area(p, oa->areaid);
199:
200: fib_free(&oa->rtr);
201: fib_free(&oa->net_fib);
202: fib_free(&oa->enet_fib);
203:
204: if (oa->translator_timer)
205: rfree(oa->translator_timer);
206:
207: p->areano--;
208: rem_node(NODE oa);
209: mb_free(oa);
210: }
211:
212: struct ospf_area *
213: ospf_find_area(struct ospf_proto *p, u32 aid)
214: {
215: struct ospf_area *oa;
216: WALK_LIST(oa, p->area_list)
217: if (((struct ospf_area *) oa)->areaid == aid)
218: return oa;
219: return NULL;
220: }
221:
222: static struct ospf_iface *
223: ospf_find_vlink(struct ospf_proto *p, u32 voa, u32 vid)
224: {
225: struct ospf_iface *ifa;
226: WALK_LIST(ifa, p->iface_list)
227: if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa->areaid == voa) && (ifa->vid == vid))
228: return ifa;
229: return NULL;
230: }
231:
232: static void
233: ospf_start_gr_recovery(struct ospf_proto *p)
234: {
235: OSPF_TRACE(D_EVENTS, "Graceful restart started");
236:
237: p->gr_recovery = 1;
238: p->gr_timeout = current_time() + (p->gr_time S);
239: channel_graceful_restart_lock(p->p.main_channel);
240: p->p.main_channel->gr_wait = 1;
241:
242: /* NOTE: We should get end of grace period from non-volatile storage */
243: }
244:
245: void
246: ospf_stop_gr_recovery(struct ospf_proto *p)
247: {
248: p->gr_recovery = 0;
249: p->gr_cleanup = 1;
250: p->gr_timeout = 0;
251:
252: /* Reorigination of router/network LSAs is already scheduled */
253:
254: /* Rest is done in ospf_cleanup_gr_recovery() */
255: }
256:
257: static void
258: ospf_cleanup_gr_recovery(struct ospf_proto *p)
259: {
260: struct top_hash_entry *en;
261:
262: /* Flush dirty LSAa except external ones, these will be handled by feed */
263: WALK_SLIST(en, p->lsal)
264: if (en->gr_dirty)
265: {
266: if ((en->lsa_type == LSA_T_EXT) || (en->lsa_type == LSA_T_NSSA))
267: en->mode = LSA_M_EXPORT;
268: else
269: ospf_flush_lsa(p, en);
270: }
271:
272: /* End graceful restart on channel, will also schedule feed */
273: channel_graceful_restart_unlock(p->p.main_channel);
274:
275: p->gr_cleanup = 0;
276: }
277:
278: static int
279: ospf_start(struct proto *P)
280: {
281: struct ospf_proto *p = (struct ospf_proto *) P;
282: struct ospf_config *c = (struct ospf_config *) (P->cf);
283: struct ospf_area_config *ac;
284:
285: p->router_id = proto_get_router_id(P->cf);
286: p->ospf2 = c->ospf2;
287: p->af_ext = c->af_ext;
288: p->af_mc = c->af_mc;
289: p->rfc1583 = c->rfc1583;
290: p->stub_router = c->stub_router;
291: p->merge_external = c->merge_external;
292: p->instance_id = c->instance_id;
293: p->asbr = c->asbr;
294: p->vpn_pe = c->vpn_pe;
295: p->ecmp = c->ecmp;
296: p->gr_mode = c->gr_mode;
297: p->gr_time = c->gr_time;
298: p->tick = c->tick;
299: p->disp_timer = tm_new_init(P->pool, ospf_disp, p, p->tick S, 0);
300: tm_start(p->disp_timer, 100 MS);
301: p->lsab_size = 256;
302: p->lsab_used = 0;
303: p->lsab = mb_alloc(P->pool, p->lsab_size);
304: p->nhpool = lp_new(P->pool, 12*sizeof(struct nexthop));
305: init_list(&(p->iface_list));
306: init_list(&(p->area_list));
307: fib_init(&p->rtf, P->pool, ospf_get_af(p), sizeof(ort), OFFSETOF(ort, fn), 0, NULL);
308: if (ospf_is_v3(p))
309: idm_init(&p->idm, P->pool, 16);
310: p->areano = 0;
311: p->gr = ospf_top_new(p, P->pool);
312: s_init_list(&(p->lsal));
313:
314: p->flood_event = ev_new_init(P->pool, ospf_flood_event, p);
315:
316: p->log_pkt_tbf = (struct tbf){ .rate = 1, .burst = 5 };
317: p->log_lsa_tbf = (struct tbf){ .rate = 4, .burst = 20 };
318:
319: /* Lock the channel when in GR recovery mode */
320: if (p->p.gr_recovery && (p->gr_mode == OSPF_GR_ABLE))
321: ospf_start_gr_recovery(p);
322:
323: WALK_LIST(ac, c->area_list)
324: ospf_area_add(p, ac);
325:
326: if (c->abr)
327: ospf_open_vlink_sk(p);
328:
329: /* Add all virtual links */
330: struct ospf_iface_patt *ic;
331: WALK_LIST(ic, c->vlink_list)
332: ospf_iface_new_vlink(p, ic);
333:
334: return PS_UP;
335: }
336:
337: static void
338: ospf_dump(struct proto *P)
339: {
340: struct ospf_proto *p = (struct ospf_proto *) P;
341: struct ospf_iface *ifa;
342: struct ospf_neighbor *n;
343:
344: OSPF_TRACE(D_EVENTS, "Area number: %d", p->areano);
345:
346: WALK_LIST(ifa, p->iface_list)
347: {
348: OSPF_TRACE(D_EVENTS, "Interface: %s", ifa->ifname);
349: OSPF_TRACE(D_EVENTS, "state: %u", ifa->state);
350: OSPF_TRACE(D_EVENTS, "DR: %R", ifa->drid);
351: OSPF_TRACE(D_EVENTS, "BDR: %R", ifa->bdrid);
352: WALK_LIST(n, ifa->neigh_list)
353: {
354: OSPF_TRACE(D_EVENTS, " neighbor %R in state %u", n->rid, n->state);
355: }
356: }
357:
358: /*
359: OSPF_TRACE(D_EVENTS, "LSA graph dump start:");
360: ospf_top_dump(p->gr, p);
361: OSPF_TRACE(D_EVENTS, "LSA graph dump finished");
362: */
363: neigh_dump_all();
364: }
365:
366: static struct proto *
367: ospf_init(struct proto_config *CF)
368: {
369: struct ospf_config *cf = (struct ospf_config *) CF;
370: struct proto *P = proto_new(CF);
371:
372: P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
373:
374: P->rt_notify = ospf_rt_notify;
375: P->if_notify = ospf_if_notify;
376: P->ifa_notify = cf->ospf2 ? ospf_ifa_notify2 : ospf_ifa_notify3;
377: P->preexport = ospf_preexport;
378: P->reload_routes = ospf_reload_routes;
379: P->feed_begin = ospf_feed_begin;
380: P->feed_end = ospf_feed_end;
381: P->make_tmp_attrs = ospf_make_tmp_attrs;
382: P->store_tmp_attrs = ospf_store_tmp_attrs;
383: P->rte_better = ospf_rte_better;
384: P->rte_same = ospf_rte_same;
385:
386: return P;
387: }
388:
389: /* If new is better return 1 */
390: static int
391: ospf_rte_better(struct rte *new, struct rte *old)
392: {
393: if (new->u.ospf.metric1 == LSINFINITY)
394: return 0;
395:
396: if(new->attrs->source < old->attrs->source) return 1;
397: if(new->attrs->source > old->attrs->source) return 0;
398:
399: if(new->attrs->source == RTS_OSPF_EXT2)
400: {
401: if(new->u.ospf.metric2 < old->u.ospf.metric2) return 1;
402: if(new->u.ospf.metric2 > old->u.ospf.metric2) return 0;
403: }
404:
405: if (new->u.ospf.metric1 < old->u.ospf.metric1)
406: return 1;
407:
408: return 0; /* Old is shorter or same */
409: }
410:
411: static int
412: ospf_rte_same(struct rte *new, struct rte *old)
413: {
414: /* new->attrs == old->attrs always */
415: return
416: new->u.ospf.metric1 == old->u.ospf.metric1 &&
417: new->u.ospf.metric2 == old->u.ospf.metric2 &&
418: new->u.ospf.tag == old->u.ospf.tag &&
419: new->u.ospf.router_id == old->u.ospf.router_id;
420: }
421:
422:
423: void
424: ospf_schedule_rtcalc(struct ospf_proto *p)
425: {
426: if (p->calcrt)
427: return;
428:
429: OSPF_TRACE(D_EVENTS, "Scheduling routing table calculation");
430: p->calcrt = 1;
431: }
432:
433: static void
434: ospf_reload_routes(struct channel *C)
435: {
436: struct ospf_proto *p = (struct ospf_proto *) C->proto;
437:
438: if (p->calcrt == 2)
439: return;
440:
441: OSPF_TRACE(D_EVENTS, "Scheduling routing table calculation with route reload");
442: p->calcrt = 2;
443: }
444:
445:
446: /**
447: * ospf_disp - invokes routing table calculation, aging and also area_disp()
448: * @timer: timer usually called every @ospf_proto->tick second, @timer->data
449: * point to @ospf_proto
450: */
451: static void
452: ospf_disp(timer * timer)
453: {
454: struct ospf_proto *p = timer->data;
455:
456: /* Check for end of graceful restart */
457: if (p->gr_recovery)
458: ospf_update_gr_recovery(p);
459:
460: /* Originate or flush local topology LSAs */
461: ospf_update_topology(p);
462:
463: /* Process LSA DB */
464: ospf_update_lsadb(p);
465:
466: /* Calculate routing table */
467: if (p->calcrt)
468: ospf_rt_spf(p);
469:
470: /* Cleanup after graceful restart */
471: if (p->gr_cleanup)
472: ospf_cleanup_gr_recovery(p);
473: }
474:
475:
476: /**
477: * ospf_preexport - accept or reject new route from nest's routing table
478: * @P: OSPF protocol instance
479: * @new: the new route
480: * @attrs: list of attributes
481: * @pool: pool for allocation of attributes
482: *
483: * Its quite simple. It does not accept our own routes and leaves the decision on
484: * import to the filters.
485: */
486: static int
487: ospf_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
488: {
489: struct ospf_proto *p = (struct ospf_proto *) P;
490: struct ospf_area *oa = ospf_main_area(p);
491: rte *e = *new;
492:
493: /* Reject our own routes */
494: if (e->attrs->src->proto == P)
495: return -1;
496:
497: /* Do not export routes to stub areas */
498: if (oa_is_stub(oa))
499: return -1;
500:
501: return 0;
502: }
503:
504: static void
505: ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool)
506: {
507: rte_init_tmp_attrs(rt, pool, 4);
508: rte_make_tmp_attr(rt, EA_OSPF_METRIC1, EAF_TYPE_INT, rt->u.ospf.metric1);
509: rte_make_tmp_attr(rt, EA_OSPF_METRIC2, EAF_TYPE_INT, rt->u.ospf.metric2);
510: rte_make_tmp_attr(rt, EA_OSPF_TAG, EAF_TYPE_INT, rt->u.ospf.tag);
511: rte_make_tmp_attr(rt, EA_OSPF_ROUTER_ID, EAF_TYPE_ROUTER_ID, rt->u.ospf.router_id);
512: }
513:
514: static void
515: ospf_store_tmp_attrs(struct rte *rt, struct linpool *pool)
516: {
517: rte_init_tmp_attrs(rt, pool, 4);
518: rt->u.ospf.metric1 = rte_store_tmp_attr(rt, EA_OSPF_METRIC1);
519: rt->u.ospf.metric2 = rte_store_tmp_attr(rt, EA_OSPF_METRIC2);
520: rt->u.ospf.tag = rte_store_tmp_attr(rt, EA_OSPF_TAG);
521: rt->u.ospf.router_id = rte_store_tmp_attr(rt, EA_OSPF_ROUTER_ID);
522: }
523:
524: /**
525: * ospf_shutdown - Finish of OSPF instance
526: * @P: OSPF protocol instance
527: *
528: * RFC does not define any action that should be taken before router
529: * shutdown. To make my neighbors react as fast as possible, I send
530: * them hello packet with empty neighbor list. They should start
531: * their neighbor state machine with event %NEIGHBOR_1WAY.
532: */
533: static int
534: ospf_shutdown(struct proto *P)
535: {
536: struct ospf_proto *p = (struct ospf_proto *) P;
537: struct ospf_iface *ifa;
538:
539: OSPF_TRACE(D_EVENTS, "Shutdown requested");
540:
541: if ((P->down_code == PDC_CMD_GR_DOWN) && (p->gr_mode == OSPF_GR_ABLE))
542: {
543: /* Originate Grace LSAs */
544: WALK_LIST(ifa, p->iface_list)
545: ospf_originate_gr_lsa(p, ifa);
546: }
547: else
548: {
549: /* Send to all my neighbors 1WAY */
550: WALK_LIST(ifa, p->iface_list)
551: ospf_iface_shutdown(ifa);
552: }
553:
554: /* Cleanup locked rta entries */
555: FIB_WALK(&p->rtf, ort, nf)
556: {
557: rta_free(nf->old_rta);
558: }
559: FIB_WALK_END;
560:
561: return PS_DOWN;
562: }
563:
564: static void
565: ospf_get_status(struct proto *P, byte * buf)
566: {
567: struct ospf_proto *p = (struct ospf_proto *) P;
568:
569: if (p->p.proto_state == PS_DOWN)
570: buf[0] = 0;
571: else
572: {
573: struct ospf_iface *ifa;
574: struct ospf_neighbor *n;
575: int adj = 0;
576:
577: WALK_LIST(ifa, p->iface_list)
578: WALK_LIST(n, ifa->neigh_list) if (n->state == NEIGHBOR_FULL)
579: adj = 1;
580:
581: if (adj == 0)
582: strcpy(buf, "Alone");
583: else
584: strcpy(buf, "Running");
585: }
586: }
587:
588: static void
589: ospf_get_route_info(rte * rte, byte * buf)
590: {
591: char *type = "<bug>";
592:
593: switch (rte->attrs->source)
594: {
595: case RTS_OSPF:
596: type = "I";
597: break;
598: case RTS_OSPF_IA:
599: type = "IA";
600: break;
601: case RTS_OSPF_EXT1:
602: type = "E1";
603: break;
604: case RTS_OSPF_EXT2:
605: type = "E2";
606: break;
607: }
608:
609: buf += bsprintf(buf, " %s", type);
610: buf += bsprintf(buf, " (%d/%d", rte->pref, rte->u.ospf.metric1);
611: if (rte->attrs->source == RTS_OSPF_EXT2)
612: buf += bsprintf(buf, "/%d", rte->u.ospf.metric2);
613: buf += bsprintf(buf, ")");
614: if ((rte->attrs->source == RTS_OSPF_EXT1 || rte->attrs->source == RTS_OSPF_EXT2) && rte->u.ospf.tag)
615: {
616: buf += bsprintf(buf, " [%x]", rte->u.ospf.tag);
617: }
618: if (rte->u.ospf.router_id)
619: buf += bsprintf(buf, " [%R]", rte->u.ospf.router_id);
620: }
621:
622: static int
623: ospf_get_attr(eattr * a, byte * buf, int buflen UNUSED)
624: {
625: switch (a->id)
626: {
627: case EA_OSPF_METRIC1:
628: bsprintf(buf, "metric1");
629: return GA_NAME;
630: case EA_OSPF_METRIC2:
631: bsprintf(buf, "metric2");
632: return GA_NAME;
633: case EA_OSPF_TAG:
634: bsprintf(buf, "tag: 0x%08x", a->u.data);
635: return GA_FULL;
636: case EA_OSPF_ROUTER_ID:
637: bsprintf(buf, "router_id");
638: return GA_NAME;
639: default:
640: return GA_UNKNOWN;
641: }
642: }
643:
644: static void
645: ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
646: {
647: struct ospf_proto *p = oa->po;
648: struct ospf_area_config *oac = oa->ac;
649: struct ospf_iface *ifa, *ifx;
650:
651: oa->ac = nac;
652: oa->options = nac->type | ospf_opts(p);
653:
654: if (nac->type != oac->type)
655: {
656: log(L_INFO "%s: Restarting area %R", p->p.name, oa->areaid);
657:
658: /* Remove area interfaces, will be re-added later */
659: WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
660: if (ifa->oa == oa)
661: {
662: ospf_iface_shutdown(ifa);
663: ospf_iface_remove(ifa);
664: }
665:
666: /* Flush area LSAs */
667: ospf_flush_area(p, oa->areaid);
668: }
669:
670: /* Handle net_list */
671: fib_free(&oa->net_fib);
672: fib_free(&oa->enet_fib);
673: add_area_nets(oa, nac);
674:
675: /* No need to handle stubnet_list */
676:
677: oa->marked = 0;
678: ospf_notify_rt_lsa(oa);
679: }
680:
681: /**
682: * ospf_reconfigure - reconfiguration hook
683: * @P: current instance of protocol (with old configuration)
684: * @c: new configuration requested by user
685: *
686: * This hook tries to be a little bit intelligent. Instance of OSPF
687: * will survive change of many constants like hello interval,
688: * password change, addition or deletion of some neighbor on
689: * nonbroadcast network, cost of interface, etc.
690: */
691: static int
692: ospf_reconfigure(struct proto *P, struct proto_config *CF)
693: {
694: struct ospf_proto *p = (struct ospf_proto *) P;
695: struct ospf_config *old = (struct ospf_config *) (P->cf);
696: struct ospf_config *new = (struct ospf_config *) CF;
697: struct ospf_area_config *oac, *nac;
698: struct ospf_area *oa, *oax;
699: struct ospf_iface *ifa, *ifx;
700: struct ospf_iface_patt *ip;
701:
702: if (proto_get_router_id(CF) != p->router_id)
703: return 0;
704:
705: if (p->ospf2 != new->ospf2)
706: return 0;
707:
708: if (p->rfc1583 != new->rfc1583)
709: return 0;
710:
711: if (p->instance_id != new->instance_id)
712: return 0;
713:
714: if (old->abr != new->abr)
715: return 0;
716:
717: if (p->areano == 1)
718: {
719: oac = HEAD(old->area_list);
720: nac = HEAD(new->area_list);
721:
722: if (oac->type != nac->type)
723: return 0;
724: }
725:
726: if (old->vpn_pe != new->vpn_pe)
727: return 0;
728:
729: if ((p->af_ext != new->af_ext) || (p->af_mc != new->af_mc))
730: return 0;
731:
732: if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
733: return 0;
734:
735: p->stub_router = new->stub_router;
736: p->merge_external = new->merge_external;
737: p->asbr = new->asbr;
738: p->ecmp = new->ecmp;
739: p->gr_mode = new->gr_mode;
740: p->gr_time = new->gr_time;
741: p->tick = new->tick;
742: p->disp_timer->recurrent = p->tick S;
743: tm_start(p->disp_timer, 10 MS);
744:
745: /* Mark all areas and ifaces */
746: WALK_LIST(oa, p->area_list)
747: oa->marked = 1;
748:
749: WALK_LIST(ifa, p->iface_list)
750: ifa->marked = 1;
751:
752: /* Add and update areas */
753: WALK_LIST(nac, new->area_list)
754: {
755: oa = ospf_find_area(p, nac->areaid);
756: if (oa)
757: ospf_area_reconfigure(oa, nac);
758: else
759: ospf_area_add(p, nac);
760: }
761:
762: /* Add and update interfaces */
763: ospf_reconfigure_ifaces(p);
764:
765: /* Add and update vlinks */
766: WALK_LIST(ip, new->vlink_list)
767: {
768: ifa = ospf_find_vlink(p, ip->voa, ip->vid);
769: if (ifa)
770: ospf_iface_reconfigure(ifa, ip);
771: else
772: ospf_iface_new_vlink(p, ip);
773: }
774:
775: /* Delete remaining ifaces and areas */
776: WALK_LIST_DELSAFE(ifa, ifx, p->iface_list)
777: if (ifa->marked)
778: {
779: ospf_iface_shutdown(ifa);
780: ospf_iface_remove(ifa);
781: }
782:
783: WALK_LIST_DELSAFE(oa, oax, p->area_list)
784: if (oa->marked)
785: ospf_area_remove(oa);
786:
787: ospf_schedule_rtcalc(p);
788:
789: return 1;
790: }
791:
792:
793: void
794: ospf_sh_neigh(struct proto *P, char *iff)
795: {
796: struct ospf_proto *p = (struct ospf_proto *) P;
797: struct ospf_iface *ifa = NULL;
798: struct ospf_neighbor *n;
799:
800: if (p->p.proto_state != PS_UP)
801: {
802: cli_msg(-1013, "%s: is not up", p->p.name);
803: cli_msg(0, "");
804: return;
805: }
806:
807: cli_msg(-1013, "%s:", p->p.name);
808: cli_msg(-1013, "%-12s\t%3s\t%-15s\t%-5s\t%-10s %s", "Router ID", "Pri",
809: " State", "DTime", "Interface", "Router IP");
810: WALK_LIST(ifa, p->iface_list)
811: if ((iff == NULL) || patmatch(iff, ifa->ifname))
812: WALK_LIST(n, ifa->neigh_list)
813: ospf_sh_neigh_info(n);
814: cli_msg(0, "");
815: }
816:
817: void
818: ospf_sh(struct proto *P)
819: {
820: struct ospf_proto *p = (struct ospf_proto *) P;
821: struct ospf_area *oa;
822: struct ospf_iface *ifa;
823: struct ospf_neighbor *n;
824: int ifano, nno, adjno, firstfib;
825:
826: if (p->p.proto_state != PS_UP)
827: {
828: cli_msg(-1014, "%s: is not up", p->p.name);
829: cli_msg(0, "");
830: return;
831: }
832:
833: cli_msg(-1014, "%s:", p->p.name);
834: cli_msg(-1014, "RFC1583 compatibility: %s", (p->rfc1583 ? "enabled" : "disabled"));
835: cli_msg(-1014, "Stub router: %s", (p->stub_router ? "Yes" : "No"));
836: cli_msg(-1014, "RT scheduler tick: %d", p->tick);
837: cli_msg(-1014, "Number of areas: %u", p->areano);
838: cli_msg(-1014, "Number of LSAs in DB:\t%u", p->gr->hash_entries);
839:
840: WALK_LIST(oa, p->area_list)
841: {
842: cli_msg(-1014, "\tArea: %R (%u) %s", oa->areaid, oa->areaid,
843: oa->areaid == 0 ? "[BACKBONE]" : "");
844: ifano = 0;
845: nno = 0;
846: adjno = 0;
847: WALK_LIST(ifa, p->iface_list)
848: {
849: if (oa == ifa->oa)
850: {
851: ifano++;
852: WALK_LIST(n, ifa->neigh_list)
853: {
854: nno++;
855: if (n->state == NEIGHBOR_FULL)
856: adjno++;
857: }
858: }
859: }
860:
861: cli_msg(-1014, "\t\tStub:\t%s", oa_is_stub(oa) ? "Yes" : "No");
862: cli_msg(-1014, "\t\tNSSA:\t%s", oa_is_nssa(oa) ? "Yes" : "No");
863: cli_msg(-1014, "\t\tTransit:\t%s", oa->trcap ? "Yes" : "No");
864:
865: if (oa_is_nssa(oa))
866: cli_msg(-1014, "\t\tNSSA translation:\t%s%s", oa->translate ? "Yes" : "No",
867: oa->translate == TRANS_WAIT ? " (run down)" : "");
868: cli_msg(-1014, "\t\tNumber of interfaces:\t%u", ifano);
869: cli_msg(-1014, "\t\tNumber of neighbors:\t%u", nno);
870: cli_msg(-1014, "\t\tNumber of adjacent neighbors:\t%u", adjno);
871:
872: firstfib = 1;
873: FIB_WALK(&oa->net_fib, struct area_net, anet)
874: {
875: if(firstfib)
876: {
877: cli_msg(-1014, "\t\tArea networks:");
878: firstfib = 0;
879: }
880: cli_msg(-1014, "\t\t\t%1N\t%s\t%s", anet->fn.addr,
881: anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : "");
882: }
883: FIB_WALK_END;
884:
885: firstfib = 1;
886: FIB_WALK(&oa->enet_fib, struct area_net, anet)
887: {
888: if(firstfib)
889: {
890: cli_msg(-1014, "\t\tArea external networks:");
891: firstfib = 0;
892: }
893: cli_msg(-1014, "\t\t\t%1N\t%s\t%s", anet->fn.addr,
894: anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : "");
895: }
896: FIB_WALK_END;
897:
898: }
899: cli_msg(0, "");
900: }
901:
902: void
903: ospf_sh_iface(struct proto *P, char *iff)
904: {
905: struct ospf_proto *p = (struct ospf_proto *) P;
906: struct ospf_iface *ifa = NULL;
907:
908: if (p->p.proto_state != PS_UP)
909: {
910: cli_msg(-1015, "%s: is not up", p->p.name);
911: cli_msg(0, "");
912: return;
913: }
914:
915: cli_msg(-1015, "%s:", p->p.name);
916: WALK_LIST(ifa, p->iface_list)
917: if ((iff == NULL) || patmatch(iff, ifa->ifname))
918: ospf_iface_info(ifa);
919: cli_msg(0, "");
920: }
921:
922: /* lsa_compare_for_state() - Compare function for 'show ospf state'
923: *
924: * First we want to separate network-LSAs and other LSAs (because network-LSAs
925: * will be presented as network nodes and other LSAs together as router nodes)
926: * Network-LSAs are sorted according to network prefix, other LSAs are sorted
927: * according to originating router id (to get all LSA needed to represent one
928: * router node together). Then, according to LSA type, ID and age.
929: *
930: * For OSPFv3, we have to handle also Prefix-LSAs. We would like to put each
931: * immediately after the referenced LSA. We will make faked LSA based on ref_
932: * values
933: */
934:
935: static struct ospf_lsa_header *
936: fake_lsa_from_prefix_lsa(struct ospf_lsa_header *dst, struct ospf_lsa_header *src,
937: struct ospf_lsa_prefix *px)
938: {
939: dst->age = src->age;
940: dst->type_raw = px->ref_type;
941: dst->id = px->ref_id;
942: dst->rt = px->ref_rt;
943: dst->sn = src->sn;
944:
945: return dst;
946: }
947:
948:
949: static int lsa_compare_ospf3;
950:
951: static int
952: lsa_compare_for_state(const void *p1, const void *p2)
953: {
954: struct top_hash_entry *he1 = * (struct top_hash_entry **) p1;
955: struct top_hash_entry *he2 = * (struct top_hash_entry **) p2;
956: struct ospf_lsa_header *lsa1 = &(he1->lsa);
957: struct ospf_lsa_header *lsa2 = &(he2->lsa);
958: struct ospf_lsa_header lsatmp1, lsatmp2;
959: u16 lsa1_type = he1->lsa_type;
960: u16 lsa2_type = he2->lsa_type;
961:
962: if (he1->domain < he2->domain)
963: return -1;
964: if (he1->domain > he2->domain)
965: return 1;
966:
967:
968: /* px1 or px2 assumes OSPFv3 */
969: int px1 = (lsa1_type == LSA_T_PREFIX);
970: int px2 = (lsa2_type == LSA_T_PREFIX);
971:
972: if (px1)
973: {
974: lsa1 = fake_lsa_from_prefix_lsa(&lsatmp1, lsa1, he1->lsa_body);
975: lsa1_type = lsa1->type_raw; /* FIXME: handle unknown ref_type */
976: }
977:
978: if (px2)
979: {
980: lsa2 = fake_lsa_from_prefix_lsa(&lsatmp2, lsa2, he2->lsa_body);
981: lsa2_type = lsa2->type_raw;
982: }
983:
984:
985: int nt1 = (lsa1_type == LSA_T_NET);
986: int nt2 = (lsa2_type == LSA_T_NET);
987:
988: if (nt1 != nt2)
989: return nt1 - nt2;
990:
991: if (nt1)
992: {
993: /* In OSPFv3, networks are named based on ID of DR */
994: if (lsa_compare_ospf3)
995: {
996: if (lsa1->rt < lsa2->rt)
997: return -1;
998: if (lsa1->rt > lsa2->rt)
999: return 1;
1000: }
1001:
1002: /* For OSPFv2, this is IP of the network,
1003: for OSPFv3, this is interface ID */
1004: if (lsa1->id < lsa2->id)
1005: return -1;
1006: if (lsa1->id > lsa2->id)
1007: return 1;
1008:
1009: if (px1 != px2)
1010: return px1 - px2;
1011:
1012: return lsa1->sn - lsa2->sn;
1013: }
1014: else
1015: {
1016: if (lsa1->rt < lsa2->rt)
1017: return -1;
1018: if (lsa1->rt > lsa2->rt)
1019: return 1;
1020:
1021: if (lsa1_type < lsa2_type)
1022: return -1;
1023: if (lsa1_type > lsa2_type)
1024: return 1;
1025:
1026: if (lsa1->id < lsa2->id)
1027: return -1;
1028: if (lsa1->id > lsa2->id)
1029: return 1;
1030:
1031: if (px1 != px2)
1032: return px1 - px2;
1033:
1034: return lsa1->sn - lsa2->sn;
1035: }
1036: }
1037:
1038: static int
1039: ext_compare_for_state(const void *p1, const void *p2)
1040: {
1041: struct top_hash_entry * he1 = * (struct top_hash_entry **) p1;
1042: struct top_hash_entry * he2 = * (struct top_hash_entry **) p2;
1043: struct ospf_lsa_header *lsa1 = &(he1->lsa);
1044: struct ospf_lsa_header *lsa2 = &(he2->lsa);
1045:
1046: if (lsa1->rt < lsa2->rt)
1047: return -1;
1048: if (lsa1->rt > lsa2->rt)
1049: return 1;
1050:
1051: if (lsa1->id < lsa2->id)
1052: return -1;
1053: if (lsa1->id > lsa2->id)
1054: return 1;
1055:
1056: return lsa1->sn - lsa2->sn;
1057: }
1058:
1059: static inline void
1060: show_lsa_distance(struct top_hash_entry *he)
1061: {
1062: if (he->color == INSPF)
1063: cli_msg(-1016, "\t\tdistance %u", he->dist);
1064: else
1065: cli_msg(-1016, "\t\tunreachable");
1066: }
1067:
1068: static inline void
1069: show_lsa_router(struct ospf_proto *p, struct top_hash_entry *he, int verbose)
1070: {
1071: struct ospf_lsa_rt_walk rtl;
1072:
1073: cli_msg(-1016, "");
1074: cli_msg(-1016, "\trouter %R", he->lsa.rt);
1075: show_lsa_distance(he);
1076:
1077: lsa_walk_rt_init(p, he, &rtl);
1078: while (lsa_walk_rt(&rtl))
1079: if (rtl.type == LSART_VLNK)
1080: cli_msg(-1016, "\t\tvlink %R metric %u", rtl.id, rtl.metric);
1081:
1082: lsa_walk_rt_init(p, he, &rtl);
1083: while (lsa_walk_rt(&rtl))
1084: if (rtl.type == LSART_PTP)
1085: cli_msg(-1016, "\t\trouter %R metric %u", rtl.id, rtl.metric);
1086:
1087: lsa_walk_rt_init(p, he, &rtl);
1088: while (lsa_walk_rt(&rtl))
1089: if (rtl.type == LSART_NET)
1090: {
1091: if (ospf_is_v2(p))
1092: {
1093: /* In OSPFv2, we try to find network-LSA to get prefix/pxlen */
1094: struct top_hash_entry *net_he = ospf_hash_find_net2(p->gr, he->domain, rtl.id);
1095:
1096: if (net_he && (net_he->lsa.age < LSA_MAXAGE))
1097: {
1098: struct ospf_lsa_header *net_lsa = &(net_he->lsa);
1099: struct ospf_lsa_net *net_ln = net_he->lsa_body;
1100:
1101: cli_msg(-1016, "\t\tnetwork %I/%d metric %u",
1102: ipa_from_u32(net_lsa->id & net_ln->optx),
1103: u32_masklen(net_ln->optx), rtl.metric);
1104: }
1105: else
1106: cli_msg(-1016, "\t\tnetwork [%R] metric %u", rtl.id, rtl.metric);
1107: }
1108: else
1109: cli_msg(-1016, "\t\tnetwork [%R-%u] metric %u", rtl.id, rtl.nif, rtl.metric);
1110: }
1111:
1112: if (ospf_is_v2(p) && verbose)
1113: {
1114: lsa_walk_rt_init(p, he, &rtl);
1115: while (lsa_walk_rt(&rtl))
1116: if (rtl.type == LSART_STUB)
1117: cli_msg(-1016, "\t\tstubnet %I/%d metric %u",
1118: ipa_from_u32(rtl.id), u32_masklen(rtl.data), rtl.metric);
1119: }
1120: }
1121:
1122: static inline void
1123: show_lsa_network(struct top_hash_entry *he, int ospf2)
1124: {
1125: struct ospf_lsa_header *lsa = &(he->lsa);
1126: struct ospf_lsa_net *ln = he->lsa_body;
1127: u32 i;
1128:
1129: if (ospf2)
1130: {
1131: cli_msg(-1016, "");
1132: cli_msg(-1016, "\tnetwork %I/%d", ipa_from_u32(lsa->id & ln->optx), u32_masklen(ln->optx));
1133: cli_msg(-1016, "\t\tdr %R", lsa->rt);
1134: }
1135: else
1136: {
1137: cli_msg(-1016, "");
1138: cli_msg(-1016, "\tnetwork [%R-%u]", lsa->rt, lsa->id);
1139: }
1140:
1141: show_lsa_distance(he);
1142:
1143: for (i = 0; i < lsa_net_count(lsa); i++)
1144: cli_msg(-1016, "\t\trouter %R", ln->routers[i]);
1145: }
1146:
1147: static inline void
1148: show_lsa_sum_net(struct top_hash_entry *he, int ospf2, int af)
1149: {
1150: net_addr net;
1151: u8 pxopts;
1152: u32 metric;
1153:
1154: lsa_parse_sum_net(he, ospf2, af, &net, &pxopts, &metric);
1155: cli_msg(-1016, "\t\txnetwork %N metric %u", &net, metric);
1156: }
1157:
1158: static inline void
1159: show_lsa_sum_rt(struct top_hash_entry *he, int ospf2)
1160: {
1161: u32 metric;
1162: u32 dst_rid;
1163: u32 options;
1164:
1165: lsa_parse_sum_rt(he, ospf2, &dst_rid, &metric, &options);
1166: cli_msg(-1016, "\t\txrouter %R metric %u", dst_rid, metric);
1167: }
1168:
1169:
1170: static inline void
1171: show_lsa_external(struct top_hash_entry *he, int ospf2, int af)
1172: {
1173: struct ospf_lsa_ext_local rt;
1174: char str_via[IPA_MAX_TEXT_LENGTH + 8] = "";
1175: char str_tag[16] = "";
1176:
1177: if (he->lsa_type == LSA_T_EXT)
1178: he->domain = 0; /* Unmark the LSA */
1179:
1180: lsa_parse_ext(he, ospf2, af, &rt);
1181:
1182: if (rt.fbit)
1183: bsprintf(str_via, " via %I", rt.fwaddr);
1184:
1185: if (rt.tag)
1186: bsprintf(str_tag, " tag %08x", rt.tag);
1187:
1188: cli_msg(-1016, "\t\t%s %N metric%s %u%s%s",
1189: (he->lsa_type == LSA_T_NSSA) ? "nssa-ext" : "external",
1190: &rt.net, rt.ebit ? "2" : "", rt.metric, str_via, str_tag);
1191: }
1192:
1193: static inline void
1194: show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode, int af)
1195: {
1196: struct ospf_lsa_prefix *px = he->lsa_body;
1197: u32 *buf;
1198: int i;
1199:
1200: /* We check whether given prefix-LSA is related to the current node */
1201: if ((px->ref_type != cnode->lsa.type_raw) || (px->ref_rt != cnode->lsa.rt))
1202: return;
1203:
1204: if ((px->ref_type == LSA_T_RT) && (px->ref_id != 0))
1205: return;
1206:
1207: if ((px->ref_type == LSA_T_NET) && (px->ref_id != cnode->lsa.id))
1208: return;
1209:
1210: buf = px->rest;
1211: for (i = 0; i < px->pxcount; i++)
1212: {
1213: net_addr net;
1214: u8 pxopts;
1215: u16 metric;
1216:
1217: buf = ospf3_get_prefix(buf, af, &net, &pxopts, &metric);
1218:
1219: if (px->ref_type == LSA_T_RT)
1220: cli_msg(-1016, "\t\tstubnet %N metric %u", &net, metric);
1221: else
1222: cli_msg(-1016, "\t\taddress %N", &net);
1223: }
1224: }
1225:
1226: void
1227: ospf_sh_state(struct proto *P, int verbose, int reachable)
1228: {
1229: struct ospf_proto *p = (struct ospf_proto *) P;
1230: int ospf2 = ospf_is_v2(p);
1231: int af = ospf_get_af(p);
1232: uint i, ix, j1, jx;
1233: u32 last_area = 0xFFFFFFFF;
1234:
1235: if (p->p.proto_state != PS_UP)
1236: {
1237: cli_msg(-1016, "%s: is not up", p->p.name);
1238: cli_msg(0, "");
1239: return;
1240: }
1241:
1242: /* We store interesting area-scoped LSAs in array hea and
1243: global-scoped (LSA_T_EXT) LSAs in array hex */
1244:
1245: uint num = p->gr->hash_entries;
1246: struct top_hash_entry *hea[num];
1247: struct top_hash_entry *hex[verbose ? num : 0];
1248: struct top_hash_entry *he;
1249: struct top_hash_entry *cnode = NULL;
1250:
1251: j1 = jx = 0;
1252: WALK_SLIST(he, p->lsal)
1253: {
1254: int accept;
1255:
1256: if (he->lsa.age == LSA_MAXAGE)
1257: continue;
1258:
1259: switch (he->lsa_type)
1260: {
1261: case LSA_T_RT:
1262: case LSA_T_NET:
1263: accept = 1;
1264: break;
1265:
1266: case LSA_T_SUM_NET:
1267: case LSA_T_SUM_RT:
1268: case LSA_T_NSSA:
1269: case LSA_T_PREFIX:
1270: accept = verbose;
1271: break;
1272:
1273: case LSA_T_EXT:
1274: if (verbose)
1275: {
1276: he->domain = 1; /* Abuse domain field to mark the LSA */
1277: hex[jx++] = he;
1278: }
1279: /* fallthrough */
1280: default:
1281: accept = 0;
1282: }
1283:
1284: if (accept)
1285: hea[j1++] = he;
1286: }
1287:
1288: ASSERT(j1 <= num && jx <= num);
1289:
1290: lsa_compare_ospf3 = !ospf2;
1291: qsort(hea, j1, sizeof(struct top_hash_entry *), lsa_compare_for_state);
1292: qsort(hex, jx, sizeof(struct top_hash_entry *), ext_compare_for_state);
1293:
1294: /*
1295: * This code is a bit tricky, we have a primary LSAs (router and
1296: * network) that are presented as a node, and secondary LSAs that
1297: * are presented as a part of a primary node. cnode represents an
1298: * currently opened node (whose header was presented). The LSAs are
1299: * sorted to get secondary LSAs just after related primary LSA (if
1300: * available). We present secondary LSAs only when related primary
1301: * LSA is opened.
1302: *
1303: * AS-external LSAs are stored separately as they might be presented
1304: * several times (for each area when related ASBR is opened). When
1305: * the node is closed, related external routes are presented. We
1306: * also have to take into account that in OSPFv3, there might be
1307: * more router-LSAs and only the first should be considered as a
1308: * primary. This is handled by not closing old router-LSA when next
1309: * one is processed (which is not opened because there is already
1310: * one opened).
1311: */
1312:
1313: ix = 0;
1314: for (i = 0; i < j1; i++)
1315: {
1316: he = hea[i];
1317:
1318: /* If there is no opened node, we open the LSA (if appropriate) or skip to the next one */
1319: if (!cnode)
1320: {
1321: if (((he->lsa_type == LSA_T_RT) || (he->lsa_type == LSA_T_NET))
1322: && ((he->color == INSPF) || !reachable))
1323: {
1324: cnode = he;
1325:
1326: if (he->domain != last_area)
1327: {
1328: cli_msg(-1016, "");
1329: cli_msg(-1016, "area %R", he->domain);
1330: last_area = he->domain;
1331: ix = 0;
1332: }
1333: }
1334: else
1335: continue;
1336: }
1337:
1338: ASSERT(cnode && (he->domain == last_area) && (he->lsa.rt == cnode->lsa.rt));
1339:
1340: switch (he->lsa_type)
1341: {
1342: case LSA_T_RT:
1343: if (he->lsa.id == cnode->lsa.id)
1344: show_lsa_router(p, he, verbose);
1345: break;
1346:
1347: case LSA_T_NET:
1348: show_lsa_network(he, ospf2);
1349: break;
1350:
1351: case LSA_T_SUM_NET:
1352: if (cnode->lsa_type == LSA_T_RT)
1353: show_lsa_sum_net(he, ospf2, af);
1354: break;
1355:
1356: case LSA_T_SUM_RT:
1357: if (cnode->lsa_type == LSA_T_RT)
1358: show_lsa_sum_rt(he, ospf2);
1359: break;
1360:
1361: case LSA_T_EXT:
1362: case LSA_T_NSSA:
1363: show_lsa_external(he, ospf2, af);
1364: break;
1365:
1366: case LSA_T_PREFIX:
1367: show_lsa_prefix(he, cnode, af);
1368: break;
1369: }
1370:
1371: /* In these cases, we close the current node */
1372: if ((i+1 == j1)
1373: || (hea[i+1]->domain != last_area)
1374: || (hea[i+1]->lsa.rt != cnode->lsa.rt)
1375: || (hea[i+1]->lsa_type == LSA_T_NET))
1376: {
1377: while ((ix < jx) && (hex[ix]->lsa.rt < cnode->lsa.rt))
1378: ix++;
1379:
1380: while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt))
1381: show_lsa_external(hex[ix++], ospf2, af);
1382:
1383: cnode = NULL;
1384: }
1385: }
1386:
1387: int hdr = 0;
1388: u32 last_rt = 0xFFFFFFFF;
1389: for (ix = 0; ix < jx; ix++)
1390: {
1391: he = hex[ix];
1392:
1393: /* If it is still marked, we show it now. */
1394: if (he->domain)
1395: {
1396: he->domain = 0;
1397:
1398: if ((he->color != INSPF) && reachable)
1399: continue;
1400:
1401: if (!hdr)
1402: {
1403: cli_msg(-1016, "");
1404: cli_msg(-1016, "other ASBRs");
1405: hdr = 1;
1406: }
1407:
1408: if (he->lsa.rt != last_rt)
1409: {
1410: cli_msg(-1016, "");
1411: cli_msg(-1016, "\trouter %R", he->lsa.rt);
1412: last_rt = he->lsa.rt;
1413: }
1414:
1415: show_lsa_external(he, ospf2, af);
1416: }
1417: }
1418:
1419: cli_msg(0, "");
1420: }
1421:
1422:
1423: static int
1424: lsa_compare_for_lsadb(const void *p1, const void *p2)
1425: {
1426: struct top_hash_entry * he1 = * (struct top_hash_entry **) p1;
1427: struct top_hash_entry * he2 = * (struct top_hash_entry **) p2;
1428: struct ospf_lsa_header *lsa1 = &(he1->lsa);
1429: struct ospf_lsa_header *lsa2 = &(he2->lsa);
1430: int sc1 = LSA_SCOPE(he1->lsa_type);
1431: int sc2 = LSA_SCOPE(he2->lsa_type);
1432:
1433: if (sc1 != sc2)
1434: return sc2 - sc1;
1435:
1436: if (he1->domain != he2->domain)
1437: return he1->domain - he2->domain;
1438:
1439: if (lsa1->rt != lsa2->rt)
1440: return lsa1->rt - lsa2->rt;
1441:
1442: if (lsa1->id != lsa2->id)
1443: return lsa1->id - lsa2->id;
1444:
1445: if (he1->lsa_type != he2->lsa_type)
1446: return he1->lsa_type - he2->lsa_type;
1447:
1448: return lsa1->sn - lsa2->sn;
1449: }
1450:
1451: void
1452: ospf_sh_lsadb(struct lsadb_show_data *ld)
1453: {
1454: struct ospf_proto *p = ld->proto;
1455: uint num = p->gr->hash_entries;
1456: uint i, j;
1457: int last_dscope = -1;
1458: u32 last_domain = 0;
1459: u16 type_mask = ospf_is_v2(p) ? 0x00ff : 0xffff; /* see lsa_etype() */
1460:
1461: if (p->p.proto_state != PS_UP)
1462: {
1463: cli_msg(-1017, "%s: is not up", p->p.name);
1464: cli_msg(0, "");
1465: return;
1466: }
1467:
1468: if (ld->router == SH_ROUTER_SELF)
1469: ld->router = p->router_id;
1470:
1471: struct top_hash_entry *hea[num];
1472: struct top_hash_entry *he;
1473:
1474: j = 0;
1475: WALK_SLIST(he, p->lsal)
1476: if (he->lsa_body)
1477: hea[j++] = he;
1478:
1479: ASSERT(j <= num);
1480:
1481: qsort(hea, j, sizeof(struct top_hash_entry *), lsa_compare_for_lsadb);
1482:
1483: for (i = 0; i < j; i++)
1484: {
1485: struct ospf_lsa_header *lsa = &(hea[i]->lsa);
1486: u16 lsa_type = lsa->type_raw & type_mask;
1487: u16 dscope = LSA_SCOPE(hea[i]->lsa_type);
1488:
1489: /* Hack: 1 is used for LSA_SCOPE_LINK, fixed by & 0xf000 */
1490: if (ld->scope && (dscope != (ld->scope & 0xf000)))
1491: continue;
1492:
1493: if ((ld->scope == LSA_SCOPE_AREA) && (hea[i]->domain != ld->area))
1494: continue;
1495:
1496: /* For user convenience ignore high nibble */
1497: if (ld->type && ((lsa_type & 0x0fff) != (ld->type & 0x0fff)))
1498: continue;
1499:
1500: if (ld->lsid && (lsa->id != ld->lsid))
1501: continue;
1502:
1503: if (ld->router && (lsa->rt != ld->router))
1504: continue;
1505:
1506: if ((dscope != last_dscope) || (hea[i]->domain != last_domain))
1507: {
1508: cli_msg(-1017, "");
1509: switch (dscope)
1510: {
1511: case LSA_SCOPE_AS:
1512: cli_msg(-1017, "Global");
1513: break;
1514:
1515: case LSA_SCOPE_AREA:
1516: cli_msg(-1017, "Area %R", hea[i]->domain);
1517: break;
1518:
1519: case LSA_SCOPE_LINK:
1520: {
1521: struct iface *ifa = if_find_by_index(hea[i]->domain);
1522: cli_msg(-1017, "Link %s", (ifa != NULL) ? ifa->name : "?");
1523: }
1524: break;
1525: }
1526: cli_msg(-1017, "");
1527: cli_msg(-1017," Type LS ID Router Sequence Age Checksum");
1528:
1529: last_dscope = dscope;
1530: last_domain = hea[i]->domain;
1531: }
1532:
1533: cli_msg(-1017," %04x %-15R %-15R %08x %5u %04x",
1534: lsa_type, lsa->id, lsa->rt, lsa->sn, lsa->age, lsa->checksum);
1535: }
1536: cli_msg(0, "");
1537: }
1538:
1539:
1540: struct protocol proto_ospf = {
1541: .name = "OSPF",
1542: .template = "ospf%d",
1543: .class = PROTOCOL_OSPF,
1544: .preference = DEF_PREF_OSPF,
1545: .channel_mask = NB_IP,
1546: .proto_size = sizeof(struct ospf_proto),
1547: .config_size = sizeof(struct ospf_config),
1548: .init = ospf_init,
1549: .dump = ospf_dump,
1550: .start = ospf_start,
1551: .shutdown = ospf_shutdown,
1552: .reconfigure = ospf_reconfigure,
1553: .get_status = ospf_get_status,
1554: .get_attr = ospf_get_attr,
1555: .get_route_info = ospf_get_route_info
1556: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>