]>
git.ipfire.org Git - thirdparty/bird.git/blob - proto/ospf/neighbor.c
4 * (c) 1999 - 2000 Ondrej Filip <feela@network.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
11 char *ospf_ns
[]={" down",
20 const char *ospf_inm
[]={ "hello received", "neighbor start", "2-way received",
21 "negotiation done", "exstart done", "bad ls request", "load done",
22 "adjacency ok?", "sequence mismatch", "1-way received", "kill neighbor",
23 "inactivity timer", "line down" };
26 * neigh_chstate - handles changes related to new or lod state of neighbor
30 * Many actions has to be taken acording to state change of neighbor. It
31 * starts rxmt timers, call interface state machine etc.
35 neigh_chstate(struct ospf_neighbor
*n
, u8 state
)
43 struct ospf_iface
*ifa
=n
->ifa
;
44 struct proto_ospf
*po
=ifa
->oa
->po
;
45 struct proto
*p
=&po
->proto
;
49 OSPF_TRACE( D_EVENTS
, "Neighbor %I changes state from \"%s\" to \"%s\".",
50 n
->ip
, ospf_ns
[oldstate
], ospf_ns
[state
]);
52 if((state
==NEIGHBOR_2WAY
) && (oldstate
<NEIGHBOR_2WAY
))
53 ospf_int_sm(ifa
, ISM_NEICH
);
54 if((state
<NEIGHBOR_2WAY
) && (oldstate
>=NEIGHBOR_2WAY
))
55 ospf_int_sm(ifa
, ISM_NEICH
);
57 if(oldstate
==NEIGHBOR_FULL
) /* Decrease number of adjacencies */
60 schedule_rt_lsa(ifa
->oa
);
61 schedule_net_lsa(ifa
);
64 if(state
==NEIGHBOR_FULL
) /* Increase number of adjacencies */
67 schedule_rt_lsa(ifa
->oa
);
68 schedule_net_lsa(ifa
);
70 if(oldstate
>=NEIGHBOR_EXSTART
&& state
<NEIGHBOR_EXSTART
)
73 tm_stop(n
->rxmt_timer
);
75 if(state
==NEIGHBOR_EXSTART
)
77 if(n
->adj
==0) /* First time adjacency */
86 tm_start(n
->rxmt_timer
,1); /* Or some other number ? */
88 if(state
<NEIGHBOR_EXCHANGE
) tm_stop(n
->lsrr_timer
);
92 struct ospf_neighbor
*
95 struct ospf_neighbor
*neigh
,*n1
,*n2
;
99 WALK_LIST (neigh
, nl
) /* First try those decl. themselves */
101 if(neigh
->state
>=NEIGHBOR_2WAY
) /* Higher than 2WAY */
102 if(neigh
->priority
>0) /* Eligible */
103 if(ipa_compare(neigh
->ip
,neigh
->dr
)!=0) /* And not decl. itself DR */
105 if(ipa_compare(neigh
->ip
,neigh
->bdr
)==0) /* Declaring BDR */
109 if(neigh
->priority
>n1
->priority
) n1
=neigh
;
110 else if(neigh
->priority
==n1
->priority
)
111 if(neigh
->rid
>n1
->rid
) n1
=neigh
;
118 else /* And NOT declaring BDR */
122 if(neigh
->priority
>n2
->priority
) n2
=neigh
;
123 else if(neigh
->priority
==n2
->priority
)
124 if(neigh
->rid
>n2
->rid
) n2
=neigh
;
138 struct ospf_neighbor
*
141 struct ospf_neighbor
*neigh
,*n
;
144 WALK_LIST (neigh
, nl
) /* And now DR */
146 if(neigh
->state
>=NEIGHBOR_2WAY
) /* Higher than 2WAY */
147 if(neigh
->priority
>0) /* Eligible */
148 if(ipa_compare(neigh
->ip
,neigh
->dr
)==0) /* And declaring itself DR */
152 if(neigh
->priority
>n
->priority
) n
=neigh
;
153 else if(neigh
->priority
==n
->priority
)
154 if(neigh
->rid
>n
->rid
) n
=neigh
;
167 can_do_adj(struct ospf_neighbor
*n
)
169 struct ospf_iface
*ifa
;
174 p
=(struct proto
*)(ifa
->proto
);
188 bug("%s: Iface %s in down state?", p
->name
, ifa
->iface
->name
);
190 case OSPF_IS_WAITING
:
191 DBG("%s: Neighbor? on iface %s\n",p
->name
, ifa
->iface
->name
);
193 case OSPF_IS_DROTHER
:
194 if(((n
->rid
==ifa
->drid
) || (n
->rid
==ifa
->bdrid
))
195 && (n
->state
>=NEIGHBOR_2WAY
)) i
=1;
200 if(n
->state
>=NEIGHBOR_2WAY
) i
=1;
203 bug("%s: Iface %s in unknown state?",p
->name
, ifa
->iface
->name
);
208 bug("%s: Iface %s is unknown type?",p
->name
, ifa
->iface
->name
);
211 DBG("%s: Iface %s can_do_adj=%d\n",p
->name
, ifa
->iface
->name
,i
);
216 * ospf_neigh_sm - ospf neighbor state machine
218 * @event: actual event
220 * This part implements neighbor state machine as described in 10.3 of
221 * RFC 2328. the only difference is that state %NEIGHBOR_ATTEMPT is not
222 * used. We discover neighbors on nonbroadcast networks using the
223 * same ways as on broadcast networks. The only difference is in
224 * sending hello packets. These are send to IPs listed in
225 * @ospf_iface->nbma_list .
228 ospf_neigh_sm(struct ospf_neighbor
*n
, int event
)
230 struct proto
*p
=(struct proto
*)(n
->ifa
->proto
);
231 struct proto_ospf
*po
=n
->ifa
->proto
;
233 DBG("%s: Neighbor state machine for neighbor %I, event \"%s\".\n",
234 p
->name
, n
->rid
, ospf_inm
[event
]);
239 neigh_chstate(n
,NEIGHBOR_ATTEMPT
);
240 /* NBMA are used different way */
245 case NEIGHBOR_ATTEMPT
:
247 neigh_chstate(n
,NEIGHBOR_INIT
);
254 if(n
->state
<NEIGHBOR_2WAY
) neigh_chstate(n
,NEIGHBOR_2WAY
);
255 if((n
->state
==NEIGHBOR_2WAY
) && can_do_adj(n
))
256 neigh_chstate(n
,NEIGHBOR_EXSTART
);
259 if(n
->state
==NEIGHBOR_EXSTART
)
261 neigh_chstate(n
,NEIGHBOR_EXCHANGE
);
262 s_init_list(&(n
->lsrql
));
263 n
->lsrqh
=ospf_top_new(n
->ifa
->proto
);
264 s_init_list(&(n
->lsrtl
));
265 n
->lsrth
=ospf_top_new(n
->ifa
->proto
);
266 s_init(&(n
->dbsi
), &(n
->ifa
->oa
->lsal
));
267 s_init(&(n
->lsrqi
), &(n
->lsrql
));
268 s_init(&(n
->lsrti
), &(n
->lsrtl
));
269 tm_start(n
->lsrr_timer
,n
->ifa
->rxmtint
);
270 tm_start(n
->ackd_timer
,n
->ifa
->rxmtint
/2);
272 else bug("NEGDONE and I'm not in EXSTART?");
275 neigh_chstate(n
,NEIGHBOR_LOADING
);
278 neigh_chstate(n
,NEIGHBOR_FULL
);
284 /* Can In build adjacency? */
287 neigh_chstate(n
,NEIGHBOR_EXSTART
);
291 if(n
->state
>=NEIGHBOR_EXSTART
)
294 neigh_chstate(n
,NEIGHBOR_2WAY
);
301 OSPF_TRACE(D_EVENTS
, "Bad LS req!");
302 if(n
->state
>=NEIGHBOR_EXCHANGE
)
304 neigh_chstate(n
,NEIGHBOR_EXSTART
);
310 neigh_chstate(n
,NEIGHBOR_DOWN
);
313 neigh_chstate(n
,NEIGHBOR_INIT
);
316 bug("%s: INM - Unknown event?",p
->name
);
322 * bdr_election - (Backup) Designed Router election
323 * @ifa: actual interface
325 * When wait time fires, it time to elect (Backup) Designed Router.
326 * Structure describing me is added to this list so every electing router
327 * has the same list. Backup Designed Router is elected before Designed
328 * Router. This process is described in 9.4 of RFC 2328.
331 bdr_election(struct ospf_iface
*ifa
)
333 struct ospf_neighbor
*neigh
,*ndr
,*nbdr
,me
,*tmp
;
335 ip_addr ndrip
, nbdrip
;
337 struct proto
*p
=&ifa
->proto
->proto
;
339 DBG("(B)DR election.\n");
341 myid
=p
->cf
->global
->router_id
;
343 me
.state
=NEIGHBOR_2WAY
;
345 me
.priority
=ifa
->priority
;
348 me
.ip
=ifa
->iface
->addr
->ip
;
350 add_tail(&ifa
->neigh_list
, NODE
&me
);
352 nbdr
=electbdr(ifa
->neigh_list
);
353 ndr
=electdr(ifa
->neigh_list
);
355 if(ndr
==NULL
) ndr
=nbdr
;
357 if(((ifa
->drid
==myid
) && (ndr
!=&me
))
358 || ((ifa
->drid
!=myid
) && (ndr
==&me
))
359 || ((ifa
->bdrid
==myid
) && (nbdr
!=&me
))
360 || ((ifa
->bdrid
!=myid
) && (nbdr
==&me
)))
362 if(ndr
==NULL
) ifa
->drip
=me
.dr
=ipa_from_u32(0);
363 else ifa
->drip
=me
.dr
=ndr
->ip
;
365 if(nbdr
==NULL
) ifa
->bdrip
=me
.bdr
=ipa_from_u32(0);
366 else ifa
->bdrip
=me
.bdr
=nbdr
->ip
;
368 nbdr
=electbdr(ifa
->neigh_list
);
369 ndr
=electdr(ifa
->neigh_list
);
372 if(ndr
==NULL
) ndrip
=ipa_from_u32(0);
375 if(nbdr
==NULL
) nbdrip
=ipa_from_u32(0);
376 else nbdrip
=nbdr
->ip
;
379 if((ipa_compare(ifa
->drip
,ndrip
)!=0) || (ipa_compare(ifa
->bdrip
,nbdrip
)!=0))
385 ifa
->drip
=ipa_from_u32(0);
396 ifa
->bdrip
=ipa_from_u32(0);
400 ifa
->bdrid
=nbdr
->rid
;
404 DBG("DR=%I, BDR=%I\n", ifa
->drid
, ifa
->bdrid
);
406 if(myid
==ifa
->drid
) iface_chstate(ifa
, OSPF_IS_DR
);
409 if(myid
==ifa
->bdrid
) iface_chstate(ifa
, OSPF_IS_BACKUP
);
410 else iface_chstate(ifa
, OSPF_IS_DROTHER
);
417 WALK_LIST (neigh
, ifa
->neigh_list
)
419 ospf_neigh_sm(neigh
, INM_ADJOK
);
424 struct ospf_neighbor
*
425 find_neigh(struct ospf_iface
*ifa
, u32 rid
)
427 struct ospf_neighbor
*n
;
429 WALK_LIST (n
, ifa
->neigh_list
)
436 /* Find a closest neighbor which is at leas 2-Way */
437 struct ospf_neighbor
*
438 find_neigh_noifa(struct proto_ospf
*po
, u32 rid
)
440 struct ospf_neighbor
*n
=NULL
,*m
;
441 struct ospf_iface
*ifa
;
443 WALK_LIST (ifa
, po
->iface_list
)
444 if((m
=find_neigh(ifa
, rid
))!=NULL
)
446 if(m
->state
>=NEIGHBOR_2WAY
)
450 if(m
->ifa
->cost
< n
->ifa
->cost
) n
=m
;
457 ospf_find_area(struct proto_ospf
*po
, u32 aid
)
459 struct ospf_area
*oa
;
460 WALK_LIST(NODE oa
,po
->area_list
)
461 if(((struct ospf_area
*)oa
)->areaid
==aid
) return oa
;
465 /* Neighbor is inactive for a long time. Remove it. */
467 neighbor_timer_hook(timer
*timer
)
469 struct ospf_neighbor
*n
;
470 struct ospf_iface
*ifa
;
473 n
=(struct ospf_neighbor
*)timer
->data
;
475 p
=(struct proto
*)(ifa
->proto
);
476 OSPF_TRACE(D_EVENTS
,"Inactivity timer fired on interface %s for neighbor %I.",
477 ifa
->iface
->name
, n
->ip
);
478 ospf_neigh_remove(n
);
482 ospf_neigh_remove(struct ospf_neighbor
*n
)
484 struct ospf_iface
*ifa
;
488 p
=(struct proto
*)(ifa
->proto
);
489 neigh_chstate(n
, NEIGHBOR_DOWN
);
492 if(n
->rxmt_timer
!=NULL
)
494 tm_stop(n
->rxmt_timer
);
495 rfree(n
->rxmt_timer
);
497 if(n
->lsrr_timer
!=NULL
)
499 tm_stop(n
->lsrr_timer
);
500 rfree(n
->lsrr_timer
);
502 if(n
->ackd_timer
!=NULL
)
504 tm_stop(n
->ackd_timer
);
505 rfree(n
->ackd_timer
);
513 ospf_top_free(n
->lsrqh
);
517 ospf_top_free(n
->lsrth
);
521 OSPF_TRACE(D_EVENTS
, "Deleting neigbor.");
525 ospf_sh_neigh_info(struct ospf_neighbor
*n
)
527 struct ospf_iface
*ifa
=n
->ifa
;
532 exp
=n
->inactim
->expires
-now
;
537 bsprintf(etime
,"-Inf-");
541 bsprintf(etime
,"%02u:%02u", min
, sec
);
544 if(n
->rid
==ifa
->drid
) pos
="dr ";
545 if(n
->rid
==ifa
->bdrid
) pos
="bdr ";
546 if(n
->ifa
->type
==OSPF_IT_PTP
) pos
="ptp ";
548 cli_msg(-1013,"%-1I\t%3u\t%s/%s\t%-5s\t%-1I\t%-10s",n
->rid
, n
->priority
,
549 ospf_ns
[n
->state
], pos
, etime
, n
->ip
,ifa
->iface
->name
);