iof-bird-daemon / proto / ospf / ospf.c @ 725270cb
History | View | Annotate | Download (21 KB)
1 | c1f8dc91 | Ondrej Filip | /*
|
---|---|---|---|
2 | * BIRD -- OSPF
|
||
3 | *
|
||
4 | 7ab3ff6a | Ondrej Filip | * (c) 1999 - 2000 Ondrej Filip <feela@network.cz>
|
5 | c1f8dc91 | Ondrej Filip | *
|
6 | * Can be freely distributed and used under the terms of the GNU GPL.
|
||
7 | */
|
||
8 | |||
9 | 89755a86 | Ondrej Filip | /**
|
10 | * DOC: Open Shortest Path First (OSPF)
|
||
11 | *
|
||
12 | 725270cb | Martin Mares | * The OSPF protocol is quite complicated and its complex implemenation is
|
13 | * split to many files. In |ospf.c|, you can find mostly interface
|
||
14 | * for communication with the core (e.g., reconfiguration hooks, shutdown
|
||
15 | * and initialisation and so on). In |packet.c|, you can find various
|
||
16 | * functions for sending and receiving of generic OSPF packets. There are
|
||
17 | * also routines for autentication and checksumming. File |iface.c| contains
|
||
18 | * the interface state machine, allocation and deallocation of OSPF's
|
||
19 | * interface data structures. Source |neighbor.c| includes the neighbor state
|
||
20 | * machine and functions for election of Designed Router and Backup
|
||
21 | * Designed router. In |hello.c|, there are routines for sending
|
||
22 | * and receiving of hello packets as well as functions for maintaining
|
||
23 | * wait times and the inactivity timer. Files |lsreq.c|, |lsack.c|, |dbdes.c|
|
||
24 | * contain functions for sending and receiving of link-state requests,
|
||
25 | * link-state acknoledges and database descriptions respectively.
|
||
26 | * In |lsupd.c|, there are functions for sending and receiving
|
||
27 | * of link-state updates and also the flooding algorithm. Source |topology.c| is
|
||
28 | * a place where routines for searching LSA's in the link-state database,
|
||
29 | * adding and deleting them reside, there also are functions for originating
|
||
30 | * of various types of LSA's (router LSA, net LSA, external LSA). File |rt.c|
|
||
31 | * contains routines for calculating the routing table. |lsalib.c| is a set
|
||
32 | * of various functions for working with the LSA's (endianity conversions,
|
||
33 | * calculation of checksum etc.).
|
||
34 | 89755a86 | Ondrej Filip | *
|
35 | 725270cb | Martin Mares | * One instance of the protocol is able to hold LSA databases for
|
36 | * multiple OSPF areas, to exchange routing information between
|
||
37 | * multiple neighbors and to calculate the routing tables. The core
|
||
38 | * structure is &proto_ospf to which multiple &ospf_area and
|
||
39 | * &ospf_iface structures are connected. To &ospf_area is also connected
|
||
40 | * &top_hash_graph which is a dynamic hashing structure that
|
||
41 | * describes the link-state database. It allows fast search, addition
|
||
42 | * and deletion. Each LSA is kept in two pieces: header and body. Both of them are
|
||
43 | * kept in endianity of the CPU.
|
||
44 | 37c3e558 | Ondrej Filip | *
|
45 | 725270cb | Martin Mares | * Every area has its own area_disp() which is
|
46 | * responsible for late originating of router LSA, calculating
|
||
47 | * of the routing table and it also ages and flushes the LSA's. This
|
||
48 | 89755a86 | Ondrej Filip | * function is called in regular intervals.
|
49 | 725270cb | Martin Mares | * To every &ospf_iface, we connect one or more
|
50 | * &ospf_neighbor's -- a structure containing many timers and queues
|
||
51 | * for building adjacency and for exchange of routing messages.
|
||
52 | 89755a86 | Ondrej Filip | *
|
53 | 725270cb | Martin Mares | * BIRD's OSPF implementation respects RFC2328 in every detail, but
|
54 | * some of internal algorithms do differ. The RFC recommends to make a snapshot
|
||
55 | * of the link-state database when a new adjacency is forming and send
|
||
56 | * the database description packets based on information of this
|
||
57 | * snapshot. The database can be quite large in some networks, so
|
||
58 | * we rather walk through a &slist structure which allows us to
|
||
59 | * continue even if the actual LSA we were worked with is deleted. New
|
||
60 | * LSA's are added at the tail of this &slist.
|
||
61 | 89755a86 | Ondrej Filip | *
|
62 | 725270cb | Martin Mares | * We also don't keep a separate OSPF routing table, because the core
|
63 | * helps us by being able to recognize when a route is updated
|
||
64 | * to an identical one and it suppresses the update automatically.
|
||
65 | * Due to this, we can flush all the routes we've recalculated and
|
||
66 | * also those we're deleted to the core's routing table and the
|
||
67 | * core will take care of the rest. This simplifies the process
|
||
68 | * and conserves memory.
|
||
69 | 89755a86 | Ondrej Filip | */
|
70 | |||
71 | c1f8dc91 | Ondrej Filip | #include "ospf.h" |
72 | |||
73 | static int |
||
74 | ospf_start(struct proto *p)
|
||
75 | { |
||
76 | 163b2073 | Ondrej Filip | struct proto_ospf *po=(struct proto_ospf *)p; |
77 | 51cff78b | Ondrej Filip | struct ospf_config *c=(struct ospf_config *)(p->cf); |
78 | struct ospf_area_config *ac;
|
||
79 | struct ospf_area *oa;
|
||
80 | f14032ef | Ondrej Filip | |
81 | aa1e082c | Ondrej Filip | fib_init(&po->efib,p->pool,sizeof(struct extfib),16,init_efib); |
82 | 5970fcda | Ondrej Filip | init_list(&(po->iface_list)); |
83 | init_list(&(po->area_list)); |
||
84 | po->areano=0;
|
||
85 | 51cff78b | Ondrej Filip | if(EMPTY_LIST(c->area_list))
|
86 | { |
||
87 | log("%s: Cannot start, no OSPF areas configured", p->name);
|
||
88 | return PS_DOWN;
|
||
89 | } |
||
90 | 5b1a92e6 | Ondrej Filip | |
91 | 51cff78b | Ondrej Filip | WALK_LIST(ac,c->area_list) |
92 | { |
||
93 | oa=mb_allocz(po->proto.pool, sizeof(struct ospf_area)); |
||
94 | add_tail(&po->area_list,NODE oa); |
||
95 | po->areano++; |
||
96 | oa->stub=ac->stub; |
||
97 | oa->tick=ac->tick; |
||
98 | oa->areaid=ac->areaid; |
||
99 | oa->gr=ospf_top_new(po); |
||
100 | s_init_list(&(oa->lsal)); |
||
101 | oa->rt=NULL;
|
||
102 | oa->po=po; |
||
103 | oa->disp_timer=tm_new(po->proto.pool); |
||
104 | oa->disp_timer->data=oa; |
||
105 | oa->disp_timer->randomize=0;
|
||
106 | oa->disp_timer->hook=area_disp; |
||
107 | oa->disp_timer->recurrent=oa->tick; |
||
108 | tm_start(oa->disp_timer,oa->tick); |
||
109 | oa->calcrt=0;
|
||
110 | oa->origrt=0;
|
||
111 | fib_init(&oa->infib,po->proto.pool,sizeof(struct infib),16,init_infib); |
||
112 | } |
||
113 | c1f8dc91 | Ondrej Filip | return PS_UP;
|
114 | } |
||
115 | |||
116 | static void |
||
117 | ospf_dump(struct proto *p)
|
||
118 | { |
||
119 | char areastr[20]; |
||
120 | b332fcdf | Ondrej Filip | struct ospf_iface *ifa;
|
121 | struct ospf_neighbor *n;
|
||
122 | c1f8dc91 | Ondrej Filip | struct ospf_config *c = (void *) p->cf; |
123 | 163b2073 | Ondrej Filip | struct proto_ospf *po=(struct proto_ospf *)p; |
124 | 15087574 | Ondrej Filip | struct ospf_area *oa;
|
125 | c1f8dc91 | Ondrej Filip | |
126 | ee4880c8 | Ondrej Filip | OSPF_TRACE(D_EVENTS, "Area number: %d", po->areano);
|
127 | b332fcdf | Ondrej Filip | |
128 | 163b2073 | Ondrej Filip | WALK_LIST(ifa, po->iface_list) |
129 | b332fcdf | Ondrej Filip | { |
130 | f14032ef | Ondrej Filip | OSPF_TRACE(D_EVENTS, "Interface: %s", ifa->iface->name);
|
131 | OSPF_TRACE(D_EVENTS, "state: %u", ifa->state);
|
||
132 | OSPF_TRACE(D_EVENTS, "DR: %I", ifa->drid);
|
||
133 | OSPF_TRACE(D_EVENTS, "BDR: %I", ifa->bdrid);
|
||
134 | b332fcdf | Ondrej Filip | WALK_LIST(n, ifa->neigh_list) |
135 | { |
||
136 | ee4880c8 | Ondrej Filip | OSPF_TRACE(D_EVENTS, " neighbor %I in state %u", n->rid, n->state);
|
137 | b332fcdf | Ondrej Filip | } |
138 | } |
||
139 | 163b2073 | Ondrej Filip | |
140 | 8496b2e4 | Ondrej Filip | WALK_LIST(NODE oa,po->area_list) |
141 | 15087574 | Ondrej Filip | { |
142 | f14032ef | Ondrej Filip | OSPF_TRACE(D_EVENTS, "LSA graph dump for area \"%I\" start:", oa->areaid);
|
143 | 992705f6 | Ondrej Filip | ospf_top_dump(oa->gr,p); |
144 | f14032ef | Ondrej Filip | OSPF_TRACE(D_EVENTS, "LSA graph dump for area \"%I\" finished", oa->areaid);
|
145 | 15087574 | Ondrej Filip | } |
146 | c6c56264 | Ondrej Filip | neigh_dump_all(); |
147 | c1f8dc91 | Ondrej Filip | } |
148 | |||
149 | static struct proto * |
||
150 | ospf_init(struct proto_config *c)
|
||
151 | { |
||
152 | 4c630a6d | Ondrej Filip | struct proto *p = proto_new(c, sizeof(struct proto_ospf)); |
153 | 163b2073 | Ondrej Filip | struct proto_ospf *po=(struct proto_ospf *)p; |
154 | 3fa5722d | Ondrej Filip | struct ospf_config *oc=(struct ospf_config *)c; |
155 | b36a0a79 | Ondrej Filip | struct ospf_area_config *ac;
|
156 | 89d6782d | Ondrej Filip | struct ospf_iface_patt *patt;
|
157 | c1f8dc91 | Ondrej Filip | |
158 | 2d5b9992 | Ondrej Filip | p->import_control = ospf_import_control; |
159 | 5919c66e | Martin Mares | p->make_tmp_attrs = ospf_make_tmp_attrs; |
160 | p->store_tmp_attrs = ospf_store_tmp_attrs; |
||
161 | e8085aba | Ondrej Filip | p->rt_notify = ospf_rt_notify; |
162 | 04c3a83c | Ondrej Filip | p->if_notify = ospf_if_notify; |
163 | 5919c66e | Martin Mares | p->rte_better = ospf_rte_better; |
164 | p->rte_same = ospf_rte_same; |
||
165 | 163b2073 | Ondrej Filip | |
166 | 3fa5722d | Ondrej Filip | po->rfc1583=oc->rfc1583; |
167 | c1f8dc91 | Ondrej Filip | return p;
|
168 | } |
||
169 | |||
170 | bbd76b42 | Ondrej Filip | /* If new is better return 1 */
|
171 | static int |
||
172 | ospf_rte_better(struct rte *new, struct rte *old) |
||
173 | { |
||
174 | struct proto *p = new->attrs->proto;
|
||
175 | |||
176 | if(new->u.ospf.metric1=LSINFINITY) return 0; |
||
177 | |||
178 | if(((new->attrs->source==RTS_OSPF) || (new->attrs->source==RTS_OSPF_IA))
|
||
179 | && (old->attrs->source==RTS_OSPF_EXT)) return 1; |
||
180 | |||
181 | if(((old->attrs->source==RTS_OSPF) || (old->attrs->source==RTS_OSPF_IA))
|
||
182 | && (new->attrs->source==RTS_OSPF_EXT)) return 0; |
||
183 | |||
184 | if(new->u.ospf.metric2!=0) |
||
185 | { |
||
186 | if(old->u.ospf.metric2==0) return 0; |
||
187 | if(new->u.ospf.metric2<old->u.ospf.metric2) return 1; |
||
188 | return 0; |
||
189 | } |
||
190 | else
|
||
191 | { |
||
192 | if(old->u.ospf.metric2!=0) return 1; |
||
193 | if(new->u.ospf.metric1<old->u.ospf.metric1) return 1; |
||
194 | return 0; |
||
195 | } |
||
196 | } |
||
197 | |||
198 | 00c1f79a | Ondrej Filip | static int |
199 | ospf_rte_same(struct rte *new, struct rte *old) |
||
200 | { |
||
201 | 5919c66e | Martin Mares | /* new->attrs == old->attrs always */
|
202 | return
|
||
203 | new->u.ospf.metric1 == old->u.ospf.metric1 && |
||
204 | new->u.ospf.metric2 == old->u.ospf.metric2 && |
||
205 | new->u.ospf.tag == old->u.ospf.tag; |
||
206 | } |
||
207 | 00c1f79a | Ondrej Filip | |
208 | 5919c66e | Martin Mares | static ea_list *
|
209 | ospf_build_attrs(ea_list *next, struct linpool *pool, u32 m1, u32 m2, u32 tag)
|
||
210 | { |
||
211 | struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 3*sizeof(eattr)); |
||
212 | |||
213 | l->next = next; |
||
214 | l->flags = EALF_SORTED; |
||
215 | l->count = 3;
|
||
216 | l->attrs[0].id = EA_OSPF_METRIC1;
|
||
217 | l->attrs[0].flags = 0; |
||
218 | l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
|
||
219 | l->attrs[0].u.data = m1;
|
||
220 | l->attrs[1].id = EA_OSPF_METRIC2;
|
||
221 | l->attrs[1].flags = 0; |
||
222 | l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
|
||
223 | l->attrs[1].u.data = m2;
|
||
224 | l->attrs[2].id = EA_OSPF_TAG;
|
||
225 | l->attrs[2].flags = 0; |
||
226 | l->attrs[2].type = EAF_TYPE_INT | EAF_TEMP;
|
||
227 | l->attrs[2].u.data = tag;
|
||
228 | return l;
|
||
229 | 00c1f79a | Ondrej Filip | } |
230 | |||
231 | 70a38319 | Ondrej Filip | void
|
232 | schedule_rt_lsa(struct ospf_area *oa)
|
||
233 | { |
||
234 | struct proto_ospf *po=oa->po;
|
||
235 | struct proto *p=&po->proto;
|
||
236 | |||
237 | f14032ef | Ondrej Filip | OSPF_TRACE(D_EVENTS, "Scheduling RT lsa origination for area %I.",
|
238 | 70a38319 | Ondrej Filip | oa->areaid); |
239 | oa->origrt=1;
|
||
240 | } |
||
241 | |||
242 | void
|
||
243 | schedule_rtcalc(struct ospf_area *oa)
|
||
244 | { |
||
245 | struct proto_ospf *po=oa->po;
|
||
246 | struct proto *p=&po->proto;
|
||
247 | |||
248 | f14032ef | Ondrej Filip | OSPF_TRACE(D_EVENTS, "Scheduling RT calculation for area %I.",
|
249 | 70a38319 | Ondrej Filip | oa->areaid); |
250 | oa->calcrt=1;
|
||
251 | } |
||
252 | |||
253 | 6f58dc64 | Ondrej Filip | /**
|
254 | * area_disp - invokes link-state database aging, originating of
|
||
255 | * router LSA and routing table calculation
|
||
256 | * @timer - it's called every @ospf_area->tick seconds
|
||
257 | *
|
||
258 | * It ivokes aging and when @ospf_area->origrt is set to 1, start
|
||
259 | * function for origination of router LSA. It also start routing
|
||
260 | * table calculation when @ospf_area->calcrt is set.
|
||
261 | */
|
||
262 | 70a38319 | Ondrej Filip | void
|
263 | area_disp(timer *timer) |
||
264 | { |
||
265 | struct ospf_area *oa=timer->data;
|
||
266 | struct top_hash_entry *en,*nxt;
|
||
267 | |||
268 | /* First of all try to age LSA DB */
|
||
269 | d1660fd3 | Ondrej Filip | ospf_age(oa); |
270 | 70a38319 | Ondrej Filip | |
271 | /* Now try to originage rt_lsa */
|
||
272 | if(oa->origrt) originate_rt_lsa(oa);
|
||
273 | oa->origrt=0;
|
||
274 | |||
275 | if(oa->calcrt) ospf_rt_spfa(oa);
|
||
276 | oa->calcrt=0;
|
||
277 | } |
||
278 | |||
279 | 6f58dc64 | Ondrej Filip | /**
|
280 | * ospf_import_control - accept or reject new route from nest's routing table
|
||
281 | * @p: current instance of protocol
|
||
282 | * @attrs: list of arttributes
|
||
283 | * @pool: pool for alloction of attributes
|
||
284 | *
|
||
285 | * Its quite simple. It does not accept our own routes and decision of
|
||
286 | * import leaves to the filters.
|
||
287 | */
|
||
288 | |||
289 | 2d5b9992 | Ondrej Filip | int
|
290 | ospf_import_control(struct proto *p, rte **new, ea_list **attrs, struct linpool *pool) |
||
291 | { |
||
292 | rte *e=*new; |
||
293 | struct proto_ospf *po=(struct proto_ospf *)p; |
||
294 | |||
295 | 5919c66e | Martin Mares | if(p==e->attrs->proto) return -1; /* Reject our own routes */ |
296 | 8441f179 | Martin Mares | *attrs = ospf_build_attrs(*attrs, pool, LSINFINITY, 10000, 0); |
297 | 5919c66e | Martin Mares | return 0; /* Leave decision to the filters */ |
298 | } |
||
299 | 2d5b9992 | Ondrej Filip | |
300 | 5919c66e | Martin Mares | struct ea_list *
|
301 | ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool) |
||
302 | { |
||
303 | return ospf_build_attrs(NULL, pool, rt->u.ospf.metric1, rt->u.ospf.metric2, rt->u.ospf.tag); |
||
304 | } |
||
305 | |||
306 | void
|
||
307 | ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs) |
||
308 | { |
||
309 | 8441f179 | Martin Mares | rt->u.ospf.metric1 = ea_get_int(attrs, EA_OSPF_METRIC1, LSINFINITY); |
310 | rt->u.ospf.metric2 = ea_get_int(attrs, EA_OSPF_METRIC2, 10000);
|
||
311 | 5919c66e | Martin Mares | rt->u.ospf.tag = ea_get_int(attrs, EA_OSPF_TAG, 0);
|
312 | 2d5b9992 | Ondrej Filip | } |
313 | |||
314 | 6f58dc64 | Ondrej Filip | /**
|
315 | * ospf_shutdown - Finnish of OSPF instance
|
||
316 | * @p: current instance of protocol
|
||
317 | *
|
||
318 | * RFC does not define any action that should be taken befor router
|
||
319 | * shutdown. To make my neighbors react as fast as possible, I send
|
||
320 | * them hello packet with empty neighbor list. They should start
|
||
321 | * theirs neighbor state machine with event %NEIGHBOR_1WAY.
|
||
322 | */
|
||
323 | |||
324 | 4bd28fb6 | Ondrej Filip | static int |
325 | ospf_shutdown(struct proto *p)
|
||
326 | { |
||
327 | struct proto_ospf *po=(struct proto_ospf *)p; |
||
328 | struct ospf_iface *ifa;
|
||
329 | struct ospf_neighbor *n;
|
||
330 | struct ospf_area *oa;
|
||
331 | ee4880c8 | Ondrej Filip | OSPF_TRACE(D_EVENTS, "Shutdown requested");
|
332 | 4bd28fb6 | Ondrej Filip | |
333 | /* And send to all my neighbors 1WAY */
|
||
334 | WALK_LIST(ifa, po->iface_list) |
||
335 | { |
||
336 | 1b128de3 | Ondrej Filip | init_list(&ifa->neigh_list); |
337 | 4bd28fb6 | Ondrej Filip | hello_timer_hook(ifa->hello_timer); |
338 | } |
||
339 | |||
340 | return PS_DOWN;
|
||
341 | } |
||
342 | |||
343 | e8085aba | Ondrej Filip | void
|
344 | ospf_rt_notify(struct proto *p, net *n, rte *new, rte *old, ea_list *attrs)
|
||
345 | { |
||
346 | struct proto_ospf *po=(struct proto_ospf *)p; |
||
347 | |||
348 | ee4880c8 | Ondrej Filip | OSPF_TRACE(D_EVENTS, "Got route %I/%d %s", p->name, n->n.prefix,
|
349 | e8085aba | Ondrej Filip | n->n.pxlen, new ? "up" : "down"); |
350 | |||
351 | if(new) /* Got some new route */ |
||
352 | { |
||
353 | 5919c66e | Martin Mares | originate_ext_lsa(n, new, po, attrs); |
354 | e8085aba | Ondrej Filip | } |
355 | else
|
||
356 | { |
||
357 | 4bd28fb6 | Ondrej Filip | u32 rtid=po->proto.cf->global->router_id; |
358 | struct ospf_area *oa;
|
||
359 | struct top_hash_entry *en;
|
||
360 | 273fd2c1 | Ondrej Filip | u32 pr=ipa_to_u32(n->n.prefix); |
361 | struct ospf_lsa_ext *ext;
|
||
362 | int i;
|
||
363 | 4bd28fb6 | Ondrej Filip | |
364 | /* Flush old external LSA */
|
||
365 | WALK_LIST(oa, po->area_list) |
||
366 | { |
||
367 | 273fd2c1 | Ondrej Filip | for(i=0;i<MAXNETS;i++,pr++) |
368 | { |
||
369 | if(en=ospf_hash_find(oa->gr, pr, rtid, LSA_T_EXT))
|
||
370 | { |
||
371 | ext=en->lsa_body; |
||
372 | if(ipa_compare(ext->netmask, ipa_mkmask(n->n.pxlen))==0) |
||
373 | { |
||
374 | net_flush_lsa(en,po,oa); |
||
375 | break;
|
||
376 | } |
||
377 | } |
||
378 | } |
||
379 | 4bd28fb6 | Ondrej Filip | } |
380 | e8085aba | Ondrej Filip | } |
381 | } |
||
382 | |||
383 | 4414d9a5 | Ondrej Filip | static void |
384 | ospf_get_status(struct proto *p, byte *buf)
|
||
385 | { |
||
386 | struct proto_ospf *po=(struct proto_ospf *)p; |
||
387 | |||
388 | if (p->proto_state == PS_DOWN) buf[0] = 0; |
||
389 | else
|
||
390 | { |
||
391 | struct ospf_iface *ifa;
|
||
392 | struct ospf_neighbor *n;
|
||
393 | int adj=0; |
||
394 | |||
395 | WALK_LIST(ifa,po->iface_list) |
||
396 | WALK_LIST(n,ifa->neigh_list) |
||
397 | if(n->state==NEIGHBOR_FULL) adj=1; |
||
398 | |||
399 | if(adj==0) strcpy(buf, "Alone"); |
||
400 | else strcpy(buf, "Running"); |
||
401 | } |
||
402 | } |
||
403 | |||
404 | f7c0525e | Ondrej Filip | static void |
405 | ospf_get_route_info(rte *rte, byte *buf, ea_list *attrs) |
||
406 | { |
||
407 | char met=' '; |
||
408 | 05dbc97b | Ondrej Filip | char type=' '; |
409 | f7c0525e | Ondrej Filip | |
410 | 05dbc97b | Ondrej Filip | if(rte->attrs->source==RTS_OSPF_EXT)
|
411 | { |
||
412 | met='1';
|
||
413 | type='E';
|
||
414 | a7a3a0a3 | Ondrej Filip | |
415 | 05dbc97b | Ondrej Filip | } |
416 | a7a3a0a3 | Ondrej Filip | if(rte->u.ospf.metric2!=LSINFINITY) met='2'; |
417 | 05dbc97b | Ondrej Filip | if(rte->attrs->source==RTS_OSPF_IA) type='A'; |
418 | if(rte->attrs->source==RTS_OSPF) type='I'; |
||
419 | 73232f6b | Ondrej Filip | buf += bsprintf(buf, " %c", type);
|
420 | if(met!=' ') buf += bsprintf(buf, "%c", met); |
||
421 | buf += bsprintf(buf, " (%d/%d)", rte->pref,
|
||
422 | a7a3a0a3 | Ondrej Filip | (rte->u.ospf.metric2==LSINFINITY) ? rte->u.ospf.metric1 : |
423 | rte->u.ospf.metric2); |
||
424 | 23df5e4c | Martin Mares | if(rte->attrs->source==RTS_OSPF_EXT && rte->u.ospf.tag)
|
425 | a7a3a0a3 | Ondrej Filip | { |
426 | 23df5e4c | Martin Mares | buf += bsprintf(buf, " [%x]", rte->u.ospf.tag);
|
427 | a7a3a0a3 | Ondrej Filip | } |
428 | f7c0525e | Ondrej Filip | } |
429 | |||
430 | 5919c66e | Martin Mares | static int |
431 | ospf_get_attr(eattr *a, byte *buf) |
||
432 | { |
||
433 | switch (a->id)
|
||
434 | { |
||
435 | case EA_OSPF_METRIC1: bsprintf(buf, "metric1"); return GA_NAME; |
||
436 | case EA_OSPF_METRIC2: bsprintf(buf, "metric2"); return GA_NAME; |
||
437 | case EA_OSPF_TAG: bsprintf(buf, "tag: %08x", a->u.data); return GA_FULL; |
||
438 | default: return GA_UNKNOWN; |
||
439 | } |
||
440 | } |
||
441 | 6f58dc64 | Ondrej Filip | |
442 | edc34dc9 | Ondrej Filip | static int |
443 | ospf_patt_compare(struct ospf_iface_patt *a, struct ospf_iface_patt *b) |
||
444 | { |
||
445 | fa6c2405 | Ondrej Filip | return ((a->type==b->type)&&(a->priority==b->priority));
|
446 | edc34dc9 | Ondrej Filip | } |
447 | 5919c66e | Martin Mares | |
448 | 6f58dc64 | Ondrej Filip | /**
|
449 | * ospf_reconfigure - reconfiguration hook
|
||
450 | * @p: current instance of protocol (with old configuration)
|
||
451 | * @c: new configuration requested by user
|
||
452 | *
|
||
453 | * This hook tries to be a little bit inteligent. Instance of OSPF
|
||
454 | * will survive change of many constants like hello interval,
|
||
455 | * password change, addition of deletion of some neighbor on
|
||
456 | * nonbroadcast network, cost of interface, etc.
|
||
457 | */
|
||
458 | 80787d41 | Ondrej Filip | static int |
459 | ospf_reconfigure(struct proto *p, struct proto_config *c) |
||
460 | { |
||
461 | edc34dc9 | Ondrej Filip | struct ospf_config *old=(struct ospf_config *)(p->cf); |
462 | struct ospf_config *new=(struct ospf_config *)c; |
||
463 | struct ospf_area_config *ac1,*ac2;
|
||
464 | struct proto_ospf *po=( struct proto_ospf *)p; |
||
465 | struct ospf_iface_patt *ip1,*ip2;
|
||
466 | struct ospf_iface *ifa;
|
||
467 | struct nbma_node *nb1,*nb2,*nbnx;
|
||
468 | struct ospf_area *oa;
|
||
469 | int found;
|
||
470 | |||
471 | 6f58dc64 | Ondrej Filip | po->rfc1583=new->rfc1583; |
472 | WALK_LIST(oa, po->area_list) /* Routing table must be recalculated */
|
||
473 | { |
||
474 | schedule_rtcalc(oa); |
||
475 | } |
||
476 | edc34dc9 | Ondrej Filip | |
477 | ac1=HEAD(old->area_list); |
||
478 | ac2=HEAD(new->area_list); |
||
479 | |||
480 | /* I should get it in same order */
|
||
481 | |||
482 | while(((NODE (ac1))->next!=NULL) && ((NODE (ac2))->next!=NULL)) |
||
483 | { |
||
484 | if(ac1->areaid!=ac2->areaid) return 0; |
||
485 | if(ac1->stub!=ac2->stub) return 0; |
||
486 | if(ac1->tick!=ac2->tick)
|
||
487 | { |
||
488 | WALK_LIST(oa,po->area_list) |
||
489 | { |
||
490 | if(oa->areaid==ac2->areaid)
|
||
491 | { |
||
492 | oa->tick=ac2->tick; |
||
493 | tm_start(oa->disp_timer,oa->tick); |
||
494 | OSPF_TRACE(D_EVENTS, |
||
495 | "Changing tick interval on area %I from %d to %d",
|
||
496 | oa->areaid, ac1->tick, ac2->tick); |
||
497 | break;
|
||
498 | } |
||
499 | } |
||
500 | } |
||
501 | |||
502 | if(!iface_patts_equal(&ac1->patt_list, &ac2->patt_list,
|
||
503 | (void *) ospf_patt_compare))
|
||
504 | return 0; |
||
505 | |||
506 | WALK_LIST(ifa, po->iface_list) |
||
507 | { |
||
508 | if(ip1=(struct ospf_iface_patt *) |
||
509 | iface_patt_match(&ac1->patt_list, ifa->iface)) |
||
510 | { |
||
511 | /* Now reconfigure interface */
|
||
512 | if(!(ip2=(struct ospf_iface_patt *) |
||
513 | iface_patt_match(&ac2->patt_list, ifa->iface))) return 0; |
||
514 | |||
515 | /* HELLO TIMER */
|
||
516 | if(ip1->helloint!=ip2->helloint)
|
||
517 | { |
||
518 | ifa->helloint=ip2->helloint; |
||
519 | ifa->hello_timer->recurrent=ifa->helloint; |
||
520 | tm_start(ifa->hello_timer,ifa->helloint); |
||
521 | OSPF_TRACE(D_EVENTS, |
||
522 | "Changing hello interval on interface %s from %d to %d",
|
||
523 | ifa->iface->name,ip1->helloint,ip2->helloint); |
||
524 | } |
||
525 | |||
526 | fa6c2405 | Ondrej Filip | /* COST */
|
527 | if(ip1->cost!=ip2->cost)
|
||
528 | { |
||
529 | ifa->cost=ip2->cost; |
||
530 | OSPF_TRACE(D_EVENTS, |
||
531 | "Changing cost interface %s from %d to %d",
|
||
532 | ifa->iface->name,ip1->cost,ip2->cost); |
||
533 | schedule_rt_lsa(ifa->oa); |
||
534 | } |
||
535 | |||
536 | edc34dc9 | Ondrej Filip | /* AUTHETICATION */
|
537 | if(ip1->autype!=ip2->autype)
|
||
538 | { |
||
539 | ifa->autype=ip2->autype; |
||
540 | OSPF_TRACE(D_EVENTS, |
||
541 | "Changing autentication type on interface %s",
|
||
542 | ifa->iface->name); |
||
543 | } |
||
544 | if(strncmp(ip1->password,ip2->password,8)!=0) |
||
545 | { |
||
546 | memcpy(ifa->aukey,ip2->password,8);
|
||
547 | OSPF_TRACE(D_EVENTS, |
||
548 | "Changing password on interface %s",
|
||
549 | ifa->iface->name); |
||
550 | } |
||
551 | |||
552 | /* RXMT */
|
||
553 | if(ip1->rxmtint!=ip2->rxmtint)
|
||
554 | { |
||
555 | ifa->rxmtint=ip2->rxmtint; |
||
556 | OSPF_TRACE(D_EVENTS, |
||
557 | "Changing retransmit interval on interface %s from %d to %d",
|
||
558 | ifa->iface->name,ip1->rxmtint,ip2->rxmtint); |
||
559 | } |
||
560 | |||
561 | /* WAIT */
|
||
562 | if(ip1->waitint!=ip2->waitint)
|
||
563 | { |
||
564 | ifa->waitint=ip2->waitint; |
||
565 | if(ifa->wait_timer->expires!=0) |
||
566 | tm_start(ifa->wait_timer,ifa->waitint); |
||
567 | OSPF_TRACE(D_EVENTS, |
||
568 | "Changing wait interval on interface %s from %d to %d",
|
||
569 | ifa->iface->name,ip1->waitint,ip2->waitint); |
||
570 | } |
||
571 | |||
572 | /* INFTRANS */
|
||
573 | if(ip1->inftransdelay!=ip2->inftransdelay)
|
||
574 | { |
||
575 | ifa->inftransdelay=ip2->inftransdelay; |
||
576 | OSPF_TRACE(D_EVENTS, |
||
577 | "Changing transmit delay on interface %s from %d to %d",
|
||
578 | ifa->iface->name,ip1->inftransdelay,ip2->inftransdelay); |
||
579 | } |
||
580 | |||
581 | /* DEAD COUNT */
|
||
582 | if(ip1->deadc!=ip2->deadc)
|
||
583 | { |
||
584 | ifa->deadc=ip2->deadc; |
||
585 | OSPF_TRACE(D_EVENTS, |
||
586 | "Changing dead count on interface %s from %d to %d",
|
||
587 | ifa->iface->name,ip1->deadc,ip2->deadc); |
||
588 | } |
||
589 | |||
590 | /* NBMA LIST */
|
||
591 | /* First remove old */
|
||
592 | WALK_LIST_DELSAFE(nb1, nbnx, ifa->nbma_list) |
||
593 | { |
||
594 | found=0;
|
||
595 | WALK_LIST(nb2, ip2->nbma_list) |
||
596 | if(ipa_compare(nb1->ip,nb2->ip)==0) |
||
597 | { |
||
598 | found=1;
|
||
599 | break;
|
||
600 | } |
||
601 | |||
602 | if(!found)
|
||
603 | { |
||
604 | OSPF_TRACE(D_EVENTS, |
||
605 | "Removing NBMA neighbor %I on interface %s",
|
||
606 | nb1->ip,ifa->iface->name); |
||
607 | rem_node(NODE nb1); |
||
608 | mb_free(nb1); |
||
609 | } |
||
610 | } |
||
611 | /* And then add new */
|
||
612 | WALK_LIST(nb2, ip2->nbma_list) |
||
613 | { |
||
614 | found=0;
|
||
615 | WALK_LIST(nb1, ifa->nbma_list) |
||
616 | if(ipa_compare(nb1->ip,nb2->ip)==0) |
||
617 | { |
||
618 | found=1;
|
||
619 | break;
|
||
620 | } |
||
621 | if(!found)
|
||
622 | { |
||
623 | nb1=mb_alloc(p->pool,sizeof(struct nbma_node)); |
||
624 | nb1->ip=nb2->ip; |
||
625 | add_tail(&ifa->nbma_list, NODE nb1); |
||
626 | OSPF_TRACE(D_EVENTS, |
||
627 | "Adding NBMA neighbor %I on interface %s",
|
||
628 | nb1->ip,ifa->iface->name); |
||
629 | } |
||
630 | } |
||
631 | } |
||
632 | } |
||
633 | |||
634 | NODE ac1=(NODE (ac1))->next; |
||
635 | NODE ac2=(NODE (ac2))->next; |
||
636 | } |
||
637 | |||
638 | if(((NODE (ac1))->next)!=((NODE (ac2))->next))
|
||
639 | return 0; /* One is not null */ |
||
640 | |||
641 | return 1; /* Everythink OK :-) */ |
||
642 | 80787d41 | Ondrej Filip | } |
643 | a783e259 | Ondrej Filip | |
644 | void
|
||
645 | c4f0f014 | Ondrej Filip | ospf_sh_neigh(struct proto *p, char *iff) |
646 | a783e259 | Ondrej Filip | { |
647 | c4f0f014 | Ondrej Filip | struct ospf_iface *ifa=NULL,*f; |
648 | a783e259 | Ondrej Filip | struct ospf_neighbor *n;
|
649 | struct proto_ospf *po=(struct proto_ospf *)p; |
||
650 | 3488634c | Ondrej Filip | |
651 | if(p->proto_state != PS_UP)
|
||
652 | { |
||
653 | cli_msg(-1013,"%s: is not up", p->name); |
||
654 | cli_msg(0,""); |
||
655 | return;
|
||
656 | } |
||
657 | c4f0f014 | Ondrej Filip | |
658 | if(iff!=NULL) |
||
659 | { |
||
660 | WALK_LIST(f, po->iface_list) |
||
661 | { |
||
662 | a489f0ce | Ondrej Filip | if(strcmp(iff,f->iface->name)==0) |
663 | { |
||
664 | ifa=f; |
||
665 | break;
|
||
666 | } |
||
667 | c4f0f014 | Ondrej Filip | } |
668 | if(ifa==NULL) |
||
669 | { |
||
670 | cli_msg(0,""); |
||
671 | return;
|
||
672 | } |
||
673 | a489f0ce | Ondrej Filip | cli_msg(-1013,"%s:", p->name); |
674 | cli_msg(-1013,"%-12s\t%3s\t%-15s\t%-5s\t%-12s\t%-10s","Router ID","Pri", |
||
675 | " State", "DTime", "Router IP", "Interface"); |
||
676 | WALK_LIST(n, ifa->neigh_list) ospf_sh_neigh_info(n); |
||
677 | cli_msg(0,""); |
||
678 | ece612e1 | Ondrej Filip | return;
|
679 | a489f0ce | Ondrej Filip | } |
680 | |||
681 | 4ab4e977 | Ondrej Filip | cli_msg(-1013,"%s:", p->name); |
682 | a783e259 | Ondrej Filip | cli_msg(-1013,"%-12s\t%3s\t%-15s\t%-5s\t%-12s\t%-10s","Router ID","Pri", |
683 | " State", "DTime", "Router IP", "Interface"); |
||
684 | a489f0ce | Ondrej Filip | WALK_LIST(ifa,po->iface_list) |
685 | WALK_LIST(n, ifa->neigh_list) |
||
686 | ospf_sh_neigh_info(n); |
||
687 | a783e259 | Ondrej Filip | cli_msg(0,""); |
688 | } |
||
689 | 4ab4e977 | Ondrej Filip | |
690 | void
|
||
691 | ospf_sh(struct proto *p)
|
||
692 | { |
||
693 | struct ospf_area *oa;
|
||
694 | struct proto_ospf *po=(struct proto_ospf *)p; |
||
695 | struct ospf_iface *ifa;
|
||
696 | struct ospf_neighbor *n;
|
||
697 | int ifano;
|
||
698 | int nno;
|
||
699 | int adjno;
|
||
700 | |||
701 | 3488634c | Ondrej Filip | if(p->proto_state != PS_UP)
|
702 | { |
||
703 | cli_msg(-1014,"%s: is not up", p->name); |
||
704 | cli_msg(0,""); |
||
705 | return;
|
||
706 | } |
||
707 | |||
708 | 4ab4e977 | Ondrej Filip | cli_msg(-1014,"%s:", p->name); |
709 | cli_msg(-1014,"Number of areas: %u", po->areano); |
||
710 | |||
711 | WALK_LIST(oa,po->area_list) |
||
712 | { |
||
713 | cli_msg(-1014,"\tArea: %I (%u) %s", oa->areaid, oa->areaid, |
||
714 | oa->areaid==0 ? "[BACKBONE]" : ""); |
||
715 | ifano=0;
|
||
716 | nno=0;
|
||
717 | adjno=0;
|
||
718 | WALK_LIST(ifa, po->iface_list) |
||
719 | { |
||
720 | if(oa==ifa->oa) ifano++;
|
||
721 | WALK_LIST(n, ifa->neigh_list) |
||
722 | { |
||
723 | nno++; |
||
724 | if(n->state==NEIGHBOR_FULL) adjno++;
|
||
725 | } |
||
726 | } |
||
727 | 3b580a23 | Ondrej Filip | cli_msg(-1014,"\t\tStub:\t%s", oa->stub ? "Yes" : "No"); |
728 | cli_msg(-1014,"\t\tRT scheduler tick:\t%u", oa->tick); |
||
729 | cli_msg(-1014,"\t\tNumber of interfaces:\t%u", ifano); |
||
730 | cli_msg(-1014,"\t\tNumber of LSAs in DB:\t%u", oa->gr->hash_entries); |
||
731 | cli_msg(-1014,"\t\tNumber of neighbors:\t%u", nno); |
||
732 | cli_msg(-1014,"\t\tNumber of adjacent neighbors:\t%u", adjno); |
||
733 | 4ab4e977 | Ondrej Filip | } |
734 | cli_msg(0,""); |
||
735 | } |
||
736 | |||
737 | c4f0f014 | Ondrej Filip | void
|
738 | ospf_sh_iface(struct proto *p, char *iff) |
||
739 | { |
||
740 | struct ospf_area *oa;
|
||
741 | struct proto_ospf *po=(struct proto_ospf *)p; |
||
742 | struct ospf_iface *ifa=NULL,*f; |
||
743 | struct ospf_neighbor *n;
|
||
744 | int ifano;
|
||
745 | int nno;
|
||
746 | int adjno;
|
||
747 | |||
748 | 3488634c | Ondrej Filip | if(p->proto_state != PS_UP)
|
749 | { |
||
750 | cli_msg(-1015,"%s: is not up", p->name); |
||
751 | cli_msg(0,""); |
||
752 | return;
|
||
753 | } |
||
754 | |||
755 | c4f0f014 | Ondrej Filip | if(iff!=NULL) |
756 | { |
||
757 | WALK_LIST(f, po->iface_list) |
||
758 | { |
||
759 | a489f0ce | Ondrej Filip | if(strcmp(iff,f->iface->name)==0) |
760 | { |
||
761 | ifa=f; |
||
762 | break;
|
||
763 | } |
||
764 | c4f0f014 | Ondrej Filip | } |
765 | a489f0ce | Ondrej Filip | |
766 | c4f0f014 | Ondrej Filip | if(ifa==NULL) |
767 | { |
||
768 | cli_msg(0,""); |
||
769 | return;
|
||
770 | } |
||
771 | cli_msg(-1015,"%s:", p->name); |
||
772 | ospf_iface_info(ifa); |
||
773 | cli_msg(0,""); |
||
774 | return;
|
||
775 | } |
||
776 | cli_msg(-1015,"%s:", p->name); |
||
777 | WALK_LIST(ifa, po->iface_list) ospf_iface_info(ifa); |
||
778 | cli_msg(0,""); |
||
779 | } |
||
780 | |||
781 | 80787d41 | Ondrej Filip | struct protocol proto_ospf = {
|
782 | name: "OSPF", |
||
783 | template: "ospf%d",
|
||
784 | attr_class: EAP_OSPF, |
||
785 | init: ospf_init, |
||
786 | dump: ospf_dump, |
||
787 | start: ospf_start, |
||
788 | shutdown: ospf_shutdown, |
||
789 | get_route_info: ospf_get_route_info, |
||
790 | get_attr: ospf_get_attr, |
||
791 | get_status: ospf_get_status, |
||
792 | reconfigure: ospf_reconfigure |
||
793 | }; |