blob: 3d8e957675d92c835bf51513b7abb8ead47364ff [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP-4 Finite State Machine
2 From RFC1771 [A Border Gateway Protocol 4 (BGP-4)]
3 Copyright (C) 1996, 97, 98 Kunihiro Ishiguro
4
5This file is part of GNU Zebra.
6
7GNU Zebra is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by the
9Free Software Foundation; either version 2, or (at your option) any
10later version.
11
12GNU Zebra is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Zebra; see the file COPYING. If not, write to the Free
19Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
2002111-1307, USA. */
21
22#include <zebra.h>
23
24#include "linklist.h"
25#include "prefix.h"
26#include "vty.h"
27#include "sockunion.h"
28#include "thread.h"
29#include "log.h"
30#include "stream.h"
31#include "memory.h"
32#include "plist.h"
33
34#include "bgpd/bgpd.h"
35#include "bgpd/bgp_attr.h"
36#include "bgpd/bgp_debug.h"
37#include "bgpd/bgp_fsm.h"
38#include "bgpd/bgp_packet.h"
39#include "bgpd/bgp_network.h"
40#include "bgpd/bgp_route.h"
41#include "bgpd/bgp_dump.h"
42#include "bgpd/bgp_open.h"
43#ifdef HAVE_SNMP
44#include "bgpd/bgp_snmp.h"
45#endif /* HAVE_SNMP */
46
47/* BGP FSM (finite state machine) has three types of functions. Type
48 one is thread functions. Type two is event functions. Type three
49 is FSM functions. Timer functions are set by bgp_timer_set
50 function. */
51
52/* BGP event function. */
53int bgp_event (struct thread *);
54
55/* BGP thread functions. */
56static int bgp_start_timer (struct thread *);
57static int bgp_connect_timer (struct thread *);
58static int bgp_holdtime_timer (struct thread *);
59static int bgp_keepalive_timer (struct thread *);
60
61/* BGP FSM functions. */
62static int bgp_start (struct peer *);
63
64/* BGP start timer jitter. */
65int
66bgp_start_jitter (int time)
67{
68 return ((rand () % (time + 1)) - (time / 2));
69}
70
71/* Hook function called after bgp event is occered. And vty's
72 neighbor command invoke this function after making neighbor
73 structure. */
74void
75bgp_timer_set (struct peer *peer)
76{
77 int jitter = 0;
78
79 switch (peer->status)
80 {
81 case Idle:
82 /* First entry point of peer's finite state machine. In Idle
83 status start timer is on unless peer is shutdown or peer is
84 inactive. All other timer must be turned off */
85 if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)
86 || CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)
87 || ! peer_active (peer))
88 {
89 BGP_TIMER_OFF (peer->t_start);
90 }
91 else
92 {
93 jitter = bgp_start_jitter (peer->v_start);
94 BGP_TIMER_ON (peer->t_start, bgp_start_timer,
95 peer->v_start + jitter);
96 }
97 BGP_TIMER_OFF (peer->t_connect);
98 BGP_TIMER_OFF (peer->t_holdtime);
99 BGP_TIMER_OFF (peer->t_keepalive);
100 BGP_TIMER_OFF (peer->t_asorig);
101 BGP_TIMER_OFF (peer->t_routeadv);
102 break;
103
104 case Connect:
105 /* After start timer is expired, the peer moves to Connnect
106 status. Make sure start timer is off and connect timer is
107 on. */
108 BGP_TIMER_OFF (peer->t_start);
109 BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect);
110 BGP_TIMER_OFF (peer->t_holdtime);
111 BGP_TIMER_OFF (peer->t_keepalive);
112 BGP_TIMER_OFF (peer->t_asorig);
113 BGP_TIMER_OFF (peer->t_routeadv);
114 break;
115
116 case Active:
117 /* Active is waiting connection from remote peer. And if
118 connect timer is expired, change status to Connect. */
119 BGP_TIMER_OFF (peer->t_start);
120 /* If peer is passive mode, do not set connect timer. */
121 if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE))
122 {
123 BGP_TIMER_OFF (peer->t_connect);
124 }
125 else
126 {
127 BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect);
128 }
129 BGP_TIMER_OFF (peer->t_holdtime);
130 BGP_TIMER_OFF (peer->t_keepalive);
131 BGP_TIMER_OFF (peer->t_asorig);
132 BGP_TIMER_OFF (peer->t_routeadv);
133 break;
134
135 case OpenSent:
136 /* OpenSent status. */
137 BGP_TIMER_OFF (peer->t_start);
138 BGP_TIMER_OFF (peer->t_connect);
139 if (peer->v_holdtime != 0)
140 {
141 BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer,
142 peer->v_holdtime);
143 }
144 else
145 {
146 BGP_TIMER_OFF (peer->t_holdtime);
147 }
148 BGP_TIMER_OFF (peer->t_keepalive);
149 BGP_TIMER_OFF (peer->t_asorig);
150 BGP_TIMER_OFF (peer->t_routeadv);
151 break;
152
153 case OpenConfirm:
154 /* OpenConfirm status. */
155 BGP_TIMER_OFF (peer->t_start);
156 BGP_TIMER_OFF (peer->t_connect);
157
158 /* If the negotiated Hold Time value is zero, then the Hold Time
159 timer and KeepAlive timers are not started. */
160 if (peer->v_holdtime == 0)
161 {
162 BGP_TIMER_OFF (peer->t_holdtime);
163 BGP_TIMER_OFF (peer->t_keepalive);
164 }
165 else
166 {
167 BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer,
168 peer->v_holdtime);
169 BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer,
170 peer->v_keepalive);
171 }
172 BGP_TIMER_OFF (peer->t_asorig);
173 BGP_TIMER_OFF (peer->t_routeadv);
174 break;
175
176 case Established:
177 /* In Established status start and connect timer is turned
178 off. */
179 BGP_TIMER_OFF (peer->t_start);
180 BGP_TIMER_OFF (peer->t_connect);
181
182 /* Same as OpenConfirm, if holdtime is zero then both holdtime
183 and keepalive must be turned off. */
184 if (peer->v_holdtime == 0)
185 {
186 BGP_TIMER_OFF (peer->t_holdtime);
187 BGP_TIMER_OFF (peer->t_keepalive);
188 }
189 else
190 {
191 BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer,
192 peer->v_holdtime);
193 BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer,
194 peer->v_keepalive);
195 }
196 BGP_TIMER_OFF (peer->t_asorig);
197 break;
198 }
199}
200
201/* BGP start timer. This function set BGP_Start event to thread value
202 and process event. */
203static int
204bgp_start_timer (struct thread *thread)
205{
206 struct peer *peer;
207
208 peer = THREAD_ARG (thread);
209 peer->t_start = NULL;
210
211 if (BGP_DEBUG (fsm, FSM))
212 zlog (peer->log, LOG_DEBUG,
213 "%s [FSM] Timer (start timer expire).", peer->host);
214
215 THREAD_VAL (thread) = BGP_Start;
216 bgp_event (thread);
217
218 return 0;
219}
220
221/* BGP connect retry timer. */
222static int
223bgp_connect_timer (struct thread *thread)
224{
225 struct peer *peer;
226
227 peer = THREAD_ARG (thread);
228 peer->t_connect = NULL;
229
230 if (BGP_DEBUG (fsm, FSM))
231 zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (connect timer expire)",
232 peer->host);
233
234 THREAD_VAL (thread) = ConnectRetry_timer_expired;
235 bgp_event (thread);
236
237 return 0;
238}
239
240/* BGP holdtime timer. */
241static int
242bgp_holdtime_timer (struct thread *thread)
243{
244 struct peer *peer;
245
246 peer = THREAD_ARG (thread);
247 peer->t_holdtime = NULL;
248
249 if (BGP_DEBUG (fsm, FSM))
250 zlog (peer->log, LOG_DEBUG,
251 "%s [FSM] Timer (holdtime timer expire)",
252 peer->host);
253
254 THREAD_VAL (thread) = Hold_Timer_expired;
255 bgp_event (thread);
256
257 return 0;
258}
259
260/* BGP keepalive fire ! */
261static int
262bgp_keepalive_timer (struct thread *thread)
263{
264 struct peer *peer;
265
266 peer = THREAD_ARG (thread);
267 peer->t_keepalive = NULL;
268
269 if (BGP_DEBUG (fsm, FSM))
270 zlog (peer->log, LOG_DEBUG,
271 "%s [FSM] Timer (keepalive timer expire)",
272 peer->host);
273
274 THREAD_VAL (thread) = KeepAlive_timer_expired;
275 bgp_event (thread);
276
277 return 0;
278}
279
280int
281bgp_routeadv_timer (struct thread *thread)
282{
283 struct peer *peer;
284
285 peer = THREAD_ARG (thread);
286 peer->t_routeadv = NULL;
287
288 if (BGP_DEBUG (fsm, FSM))
289 zlog (peer->log, LOG_DEBUG,
290 "%s [FSM] Timer (routeadv timer expire)",
291 peer->host);
292
293 peer->synctime = time (NULL);
294
295 BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
296
297 BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer,
298 peer->v_routeadv);
299
300 return 0;
301}
302
303/* Reset bgp update timer */
304static void
305bgp_uptime_reset (struct peer *peer)
306{
307 peer->uptime = time (NULL);
308}
309
310/* Administrative BGP peer stop event. */
311int
312bgp_stop (struct peer *peer)
313{
314 int established = 0;
315 afi_t afi;
316 safi_t safi;
317 char orf_name[BUFSIZ];
318
319 /* Increment Dropped count. */
320 if (peer->status == Established)
321 {
322 established = 1;
323 peer->dropped++;
324 bgp_fsm_change_status (peer, Idle);
paul848973c2003-08-13 00:32:49 +0000325
326 /* bgp log-neighbor-changes of neighbor Down */
327 if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
328 zlog_info ("%%ADJCHANGE: neighbor %s Down", peer->host);
329
330 /* set last reset time */
331 peer->resettime = time (NULL);
332
paul718e3742002-12-13 20:15:29 +0000333#ifdef HAVE_SNMP
334 bgpTrapBackwardTransition (peer);
335#endif /* HAVE_SNMP */
336 }
337
338 /* Reset uptime. */
339 bgp_uptime_reset (peer);
340
341 /* Need of clear of peer. */
342 if (established)
343 bgp_clear_route_all (peer);
344
345 /* Stop read and write threads when exists. */
346 BGP_READ_OFF (peer->t_read);
347 BGP_WRITE_OFF (peer->t_write);
348
349 /* Stop all timers. */
350 BGP_TIMER_OFF (peer->t_start);
351 BGP_TIMER_OFF (peer->t_connect);
352 BGP_TIMER_OFF (peer->t_holdtime);
353 BGP_TIMER_OFF (peer->t_keepalive);
354 BGP_TIMER_OFF (peer->t_asorig);
355 BGP_TIMER_OFF (peer->t_routeadv);
356
357 /* Delete all existing events of the peer. */
358 BGP_EVENT_DELETE (peer);
359
360 /* Stream reset. */
361 peer->packet_size = 0;
362
363 /* Clear input and output buffer. */
364 if (peer->ibuf)
365 stream_reset (peer->ibuf);
366 if (peer->work)
367 stream_reset (peer->work);
368 stream_fifo_clean (peer->obuf);
369
370 /* Close of file descriptor. */
371 if (peer->fd >= 0)
372 {
373 close (peer->fd);
374 peer->fd = -1;
375 }
376
377 /* Connection information. */
378 if (peer->su_local)
379 {
380 XFREE (MTYPE_SOCKUNION, peer->su_local);
381 peer->su_local = NULL;
382 }
383
384 if (peer->su_remote)
385 {
386 XFREE (MTYPE_SOCKUNION, peer->su_remote);
387 peer->su_remote = NULL;
388 }
389
390 /* Clear remote router-id. */
391 peer->remote_id.s_addr = 0;
392
393 /* Reset all negotiated variables */
394 peer->afc_nego[AFI_IP][SAFI_UNICAST] = 0;
395 peer->afc_nego[AFI_IP][SAFI_MULTICAST] = 0;
396 peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] = 0;
397 peer->afc_nego[AFI_IP6][SAFI_UNICAST] = 0;
398 peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = 0;
399 peer->afc_adv[AFI_IP][SAFI_UNICAST] = 0;
400 peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 0;
401 peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 0;
402 peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 0;
403 peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 0;
404 peer->afc_recv[AFI_IP][SAFI_UNICAST] = 0;
405 peer->afc_recv[AFI_IP][SAFI_MULTICAST] = 0;
406 peer->afc_recv[AFI_IP][SAFI_MPLS_VPN] = 0;
407 peer->afc_recv[AFI_IP6][SAFI_UNICAST] = 0;
408 peer->afc_recv[AFI_IP6][SAFI_MULTICAST] = 0;
409
410 /* Reset route refresh flag. */
411 UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV);
412 UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
413 UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
414 UNSET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV);
415 UNSET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
416
417 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
418 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
419 {
420 /* peer address family capability flags*/
421 peer->af_cap[afi][safi] = 0;
422 /* peer address family status flags*/
423 peer->af_sflags[afi][safi] = 0;
424 /* Received ORF prefix-filter */
425 peer->orf_plist[afi][safi] = NULL;
426 /* ORF received prefix-filter pnt */
427 sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi);
428 prefix_bgp_orf_remove_all (orf_name);
429 }
430
431 /* Reset keepalive and holdtime */
432 if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
433 {
434 peer->v_keepalive = peer->keepalive;
435 peer->v_holdtime = peer->holdtime;
436 }
437 else
438 {
439 peer->v_keepalive = peer->bgp->default_keepalive;
440 peer->v_holdtime = peer->bgp->default_holdtime;
441 }
442
443 peer->update_time = 0;
444
445 /* Until we are sure that there is no problem about prefix count
446 this should be commented out.*/
447#if 0
448 /* Reset prefix count */
449 peer->pcount[AFI_IP][SAFI_UNICAST] = 0;
450 peer->pcount[AFI_IP][SAFI_MULTICAST] = 0;
451 peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0;
452 peer->pcount[AFI_IP6][SAFI_UNICAST] = 0;
453 peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0;
454#endif /* 0 */
455
456 return 0;
457}
458
459/* BGP peer is stoped by the error. */
460int
461bgp_stop_with_error (struct peer *peer)
462{
463 /* Double start timer. */
464 peer->v_start *= 2;
465
466 /* Overflow check. */
467 if (peer->v_start >= (60 * 2))
468 peer->v_start = (60 * 2);
469
470 bgp_stop (peer);
471
472 return 0;
473}
474
475/* TCP connection open. Next we send open message to remote peer. And
476 add read thread for reading open message. */
477int
478bgp_connect_success (struct peer *peer)
479{
480 if (peer->fd < 0)
481 {
482 zlog_err ("bgp_connect_success peer's fd is negative value %d",
483 peer->fd);
484 return -1;
485 }
486 BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
487
488 /* bgp_getsockname (peer); */
489
490 if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
491 bgp_open_send (peer);
492
493 return 0;
494}
495
496/* TCP connect fail */
497int
498bgp_connect_fail (struct peer *peer)
499{
500 bgp_stop (peer);
501 return 0;
502}
503
504/* This function is the first starting point of all BGP connection. It
505 try to connect to remote peer with non-blocking IO. */
506int
507bgp_start (struct peer *peer)
508{
509 int status;
510
511 /* If the peer is passive mode, force to move to Active mode. */
512 if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE))
513 {
514 BGP_EVENT_ADD (peer, TCP_connection_open_failed);
515 return 0;
516 }
517
518 status = bgp_connect (peer);
519
520 switch (status)
521 {
522 case connect_error:
523 if (BGP_DEBUG (fsm, FSM))
524 plog_info (peer->log, "%s [FSM] Connect error", peer->host);
525 BGP_EVENT_ADD (peer, TCP_connection_open_failed);
526 break;
527 case connect_success:
528 if (BGP_DEBUG (fsm, FSM))
529 plog_info (peer->log, "%s [FSM] Connect immediately success",
530 peer->host);
531 BGP_EVENT_ADD (peer, TCP_connection_open);
532 break;
533 case connect_in_progress:
534 /* To check nonblocking connect, we wait until socket is
535 readable or writable. */
536 if (BGP_DEBUG (fsm, FSM))
537 plog_info (peer->log, "%s [FSM] Non blocking connect waiting result",
538 peer->host);
539 if (peer->fd < 0)
540 {
541 zlog_err ("bgp_start peer's fd is negative value %d",
542 peer->fd);
543 return -1;
544 }
545 BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
546 BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
547 break;
548 }
549 return 0;
550}
551
552/* Connect retry timer is expired when the peer status is Connect. */
553int
554bgp_reconnect (struct peer *peer)
555{
556 bgp_stop (peer);
557 bgp_start (peer);
558 return 0;
559}
560
561int
562bgp_fsm_open (struct peer *peer)
563{
564 /* Send keepalive and make keepalive timer */
565 bgp_keepalive_send (peer);
566
567 /* Reset holdtimer value. */
568 BGP_TIMER_OFF (peer->t_holdtime);
569
570 return 0;
571}
572
573/* Called after event occured, this function change status and reset
574 read/write and timer thread. */
575void
576bgp_fsm_change_status (struct peer *peer, int status)
577{
578 bgp_dump_state (peer, peer->status, status);
579
580 /* Preserve old status and change into new status. */
581 peer->ostatus = peer->status;
582 peer->status = status;
583}
584
585/* Keepalive send to peer. */
586int
587bgp_fsm_keepalive_expire (struct peer *peer)
588{
589 bgp_keepalive_send (peer);
590 return 0;
591}
592
593/* Hold timer expire. This is error of BGP connection. So cut the
594 peer and change to Idle status. */
595int
596bgp_fsm_holdtime_expire (struct peer *peer)
597{
598 if (BGP_DEBUG (fsm, FSM))
599 zlog (peer->log, LOG_DEBUG, "%s [FSM] Hold timer expire", peer->host);
600
601 /* Send notify to remote peer. */
602 bgp_notify_send (peer, BGP_NOTIFY_HOLD_ERR, 0);
603
604 /* Sweep if it is temporary peer. */
605 if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
606 {
607 zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host);
608 peer_delete (peer);
609 return -1;
610 }
611
612 return 0;
613}
614
615/* Status goes to Established. Send keepalive packet then make first
616 update information. */
617int
618bgp_establish (struct peer *peer)
619{
620 struct bgp_notify *notify;
621 afi_t afi;
622 safi_t safi;
623
624 /* Reset capability open status flag. */
625 if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
626 SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
627
628 /* Clear last notification data. */
629 notify = &peer->notify;
630 if (notify->data)
631 XFREE (MTYPE_TMP, notify->data);
632 memset (notify, 0, sizeof (struct bgp_notify));
633
634 /* Clear start timer value to default. */
635 peer->v_start = BGP_INIT_START_TIMER;
636
637 /* Increment established count. */
638 peer->established++;
639 bgp_fsm_change_status (peer, Established);
paul848973c2003-08-13 00:32:49 +0000640
641 /* bgp log-neighbor-changes of neighbor Up */
642 if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
643 zlog_info ("%%ADJCHANGE: neighbor %s Up", peer->host);
644
paul718e3742002-12-13 20:15:29 +0000645#ifdef HAVE_SNMP
646 bgpTrapEstablished (peer);
647#endif /* HAVE_SNMP */
648
649 /* Reset uptime, send keepalive, send current table. */
650 bgp_uptime_reset (peer);
651
652 /* Send route-refresh when ORF is enabled */
653 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
654 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
655 if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV))
656 {
657 if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV))
658 bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX,
659 REFRESH_IMMEDIATE, 0);
660 else if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV))
661 bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX_OLD,
662 REFRESH_IMMEDIATE, 0);
663 }
664
665 if (peer->v_keepalive)
666 bgp_keepalive_send (peer);
667
668 /* First update is deferred until ORF or ROUTE-REFRESH is received */
669 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
670 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
671 if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV))
672 if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
673 || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))
674 SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH);
675
676 bgp_announce_route_all (peer);
677
678 BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1);
679
680 return 0;
681}
682
683/* Keepalive packet is received. */
684int
685bgp_fsm_keepalive (struct peer *peer)
686{
687 /* peer count update */
688 peer->keepalive_in++;
689
690 BGP_TIMER_OFF (peer->t_holdtime);
691 return 0;
692}
693
694/* Update packet is received. */
695int
696bgp_fsm_update (struct peer *peer)
697{
698 BGP_TIMER_OFF (peer->t_holdtime);
699 return 0;
700}
701
702/* This is empty event. */
703int
704bgp_ignore (struct peer *peer)
705{
706 if (BGP_DEBUG (fsm, FSM))
707 zlog (peer->log, LOG_DEBUG, "%s [FSM] bgp_ignore called", peer->host);
708 return 0;
709}
710
711/* Finite State Machine structure */
712struct {
713 int (*func) ();
714 int next_state;
715} FSM [BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] =
716{
717 {
718 /* Idle state: In Idle state, all events other than BGP_Start is
719 ignored. With BGP_Start event, finite state machine calls
720 bgp_start(). */
721 {bgp_start, Connect}, /* BGP_Start */
722 {bgp_stop, Idle}, /* BGP_Stop */
723 {bgp_stop, Idle}, /* TCP_connection_open */
724 {bgp_stop, Idle}, /* TCP_connection_closed */
725 {bgp_ignore, Idle}, /* TCP_connection_open_failed */
726 {bgp_stop, Idle}, /* TCP_fatal_error */
727 {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
728 {bgp_ignore, Idle}, /* Hold_Timer_expired */
729 {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
730 {bgp_ignore, Idle}, /* Receive_OPEN_message */
731 {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
732 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
733 {bgp_ignore, Idle}, /* Receive_NOTIFICATION_message */
734 },
735 {
736 /* Connect */
737 {bgp_ignore, Connect}, /* BGP_Start */
738 {bgp_stop, Idle}, /* BGP_Stop */
739 {bgp_connect_success, OpenSent}, /* TCP_connection_open */
740 {bgp_stop, Idle}, /* TCP_connection_closed */
741 {bgp_connect_fail, Active}, /* TCP_connection_open_failed */
742 {bgp_connect_fail, Idle}, /* TCP_fatal_error */
743 {bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */
744 {bgp_ignore, Idle}, /* Hold_Timer_expired */
745 {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
746 {bgp_ignore, Idle}, /* Receive_OPEN_message */
747 {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
748 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
749 {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */
750 },
751 {
752 /* Active, */
753 {bgp_ignore, Active}, /* BGP_Start */
754 {bgp_stop, Idle}, /* BGP_Stop */
755 {bgp_connect_success, OpenSent}, /* TCP_connection_open */
756 {bgp_stop, Idle}, /* TCP_connection_closed */
757 {bgp_ignore, Active}, /* TCP_connection_open_failed */
758 {bgp_ignore, Idle}, /* TCP_fatal_error */
759 {bgp_start, Connect}, /* ConnectRetry_timer_expired */
760 {bgp_ignore, Idle}, /* Hold_Timer_expired */
761 {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
762 {bgp_ignore, Idle}, /* Receive_OPEN_message */
763 {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
764 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
765 {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
766 },
767 {
768 /* OpenSent, */
769 {bgp_ignore, OpenSent}, /* BGP_Start */
770 {bgp_stop, Idle}, /* BGP_Stop */
771 {bgp_stop, Idle}, /* TCP_connection_open */
772 {bgp_stop, Active}, /* TCP_connection_closed */
773 {bgp_ignore, Idle}, /* TCP_connection_open_failed */
774 {bgp_stop, Idle}, /* TCP_fatal_error */
775 {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
776 {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
777 {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
778 {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
779 {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
780 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
781 {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
782 },
783 {
784 /* OpenConfirm, */
785 {bgp_ignore, OpenConfirm}, /* BGP_Start */
786 {bgp_stop, Idle}, /* BGP_Stop */
787 {bgp_stop, Idle}, /* TCP_connection_open */
788 {bgp_stop, Idle}, /* TCP_connection_closed */
789 {bgp_stop, Idle}, /* TCP_connection_open_failed */
790 {bgp_stop, Idle}, /* TCP_fatal_error */
791 {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
792 {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
793 {bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */
794 {bgp_ignore, Idle}, /* Receive_OPEN_message */
795 {bgp_establish, Established}, /* Receive_KEEPALIVE_message */
796 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
797 {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
798 },
799 {
800 /* Established, */
801 {bgp_ignore, Established}, /* BGP_Start */
802 {bgp_stop, Idle}, /* BGP_Stop */
803 {bgp_stop, Idle}, /* TCP_connection_open */
804 {bgp_stop, Idle}, /* TCP_connection_closed */
805 {bgp_ignore, Idle}, /* TCP_connection_open_failed */
806 {bgp_stop, Idle}, /* TCP_fatal_error */
807 {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
808 {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
809 {bgp_fsm_keepalive_expire, Established}, /* KeepAlive_timer_expired */
810 {bgp_stop, Idle}, /* Receive_OPEN_message */
811 {bgp_fsm_keepalive, Established}, /* Receive_KEEPALIVE_message */
812 {bgp_fsm_update, Established}, /* Receive_UPDATE_message */
813 {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
814 },
815};
816
817static char *bgp_event_str[] =
818{
819 NULL,
820 "BGP_Start",
821 "BGP_Stop",
822 "TCP_connection_open",
823 "TCP_connection_closed",
824 "TCP_connection_open_failed",
825 "TCP_fatal_error",
826 "ConnectRetry_timer_expired",
827 "Hold_Timer_expired",
828 "KeepAlive_timer_expired",
829 "Receive_OPEN_message",
830 "Receive_KEEPALIVE_message",
831 "Receive_UPDATE_message",
832 "Receive_NOTIFICATION_message"
833};
834
835/* Execute event process. */
836int
837bgp_event (struct thread *thread)
838{
839 int ret;
840 int event;
841 int next;
842 struct peer *peer;
843
844 peer = THREAD_ARG (thread);
845 event = THREAD_VAL (thread);
846
847 /* Logging this event. */
848 next = FSM [peer->status -1][event - 1].next_state;
849
850 if (BGP_DEBUG (fsm, FSM))
851 plog_info (peer->log, "%s [FSM] %s (%s->%s)", peer->host,
852 bgp_event_str[event],
853 LOOKUP (bgp_status_msg, peer->status),
854 LOOKUP (bgp_status_msg, next));
855 if (BGP_DEBUG (normal, NORMAL)
856 && strcmp (LOOKUP (bgp_status_msg, peer->status), LOOKUP (bgp_status_msg, next)))
857 zlog_info ("%s went from %s to %s",
858 peer->host,
859 LOOKUP (bgp_status_msg, peer->status),
860 LOOKUP (bgp_status_msg, next));
861
862 /* Call function. */
863 ret = (*(FSM [peer->status - 1][event - 1].func))(peer);
864
865 /* When function do not want proceed next job return -1. */
866 if (ret < 0)
867 return ret;
868
869 /* If status is changed. */
870 if (next != peer->status)
871 bgp_fsm_change_status (peer, next);
872
873 /* Make sure timer is set. */
874 bgp_timer_set (peer);
875
876 return 0;
877}