]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_fsm.c
* bgp_route.c: Clear peer's routing table regardless whether it's
[mirror_frr.git] / bgpd / bgp_fsm.c
CommitLineData
718e3744 1/* 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\f
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
eb821189 295 BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
718e3744 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
e0701b79 310/* BGP Peer Down Cause */
fd79ac91 311const char *peer_down_str[] =
e0701b79 312{
313 "",
314 "Router ID changed",
315 "Remote AS changed",
316 "Local AS change",
317 "Cluster ID changed",
318 "Confederation identifier changed",
319 "Confederation peer changed",
320 "RR client config change",
321 "RS client config change",
322 "Update source change",
323 "Address family activated",
324 "Admin. shutdown",
325 "User reset",
326 "BGP Notification received",
327 "BGP Notification send",
328 "Peer closed the session",
329 "Neighbor deleted",
330 "Peer-group add member",
331 "Peer-group delete member",
332 "Capability changed",
333 "Passive config change",
334 "Multihop config change"
335};
336
718e3744 337/* Administrative BGP peer stop event. */
338int
339bgp_stop (struct peer *peer)
340{
718e3744 341 afi_t afi;
342 safi_t safi;
343 char orf_name[BUFSIZ];
344
345 /* Increment Dropped count. */
346 if (peer->status == Established)
347 {
718e3744 348 peer->dropped++;
349 bgp_fsm_change_status (peer, Idle);
848973c7 350
351 /* bgp log-neighbor-changes of neighbor Down */
352 if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
e0701b79 353 zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host,
354 peer_down_str [(int) peer->last_reset]);
848973c7 355
356 /* set last reset time */
357 peer->resettime = time (NULL);
c5317404 358 /* Reset uptime. */
359 bgp_uptime_reset (peer);
848973c7 360
718e3744 361#ifdef HAVE_SNMP
362 bgpTrapBackwardTransition (peer);
363#endif /* HAVE_SNMP */
718e3744 364
538621f2 365 /* Reset uptime. */
366 bgp_uptime_reset (peer);
367
368 /* Need of clear of peer. */
369 bgp_clear_route_all (peer);
370 }
718e3744 371
372 /* Stop read and write threads when exists. */
373 BGP_READ_OFF (peer->t_read);
374 BGP_WRITE_OFF (peer->t_write);
375
376 /* Stop all timers. */
377 BGP_TIMER_OFF (peer->t_start);
378 BGP_TIMER_OFF (peer->t_connect);
379 BGP_TIMER_OFF (peer->t_holdtime);
380 BGP_TIMER_OFF (peer->t_keepalive);
381 BGP_TIMER_OFF (peer->t_asorig);
382 BGP_TIMER_OFF (peer->t_routeadv);
383
384 /* Delete all existing events of the peer. */
385 BGP_EVENT_DELETE (peer);
386
387 /* Stream reset. */
388 peer->packet_size = 0;
389
390 /* Clear input and output buffer. */
391 if (peer->ibuf)
392 stream_reset (peer->ibuf);
393 if (peer->work)
394 stream_reset (peer->work);
395 stream_fifo_clean (peer->obuf);
396
eb821189 397 /* Close of file descriptor. */
398 if (peer->fd >= 0)
399 {
400 close (peer->fd);
401 peer->fd = -1;
402 }
718e3744 403
404 /* Connection information. */
405 if (peer->su_local)
406 {
407 XFREE (MTYPE_SOCKUNION, peer->su_local);
408 peer->su_local = NULL;
409 }
410
411 if (peer->su_remote)
412 {
413 XFREE (MTYPE_SOCKUNION, peer->su_remote);
414 peer->su_remote = NULL;
415 }
eb821189 416
718e3744 417 /* Clear remote router-id. */
418 peer->remote_id.s_addr = 0;
419
538621f2 420 /* Clear peer capability flag. */
421 peer->cap = 0;
718e3744 422
423 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
424 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
425 {
538621f2 426 /* Reset all negotiated variables */
427 peer->afc_nego[afi][safi] = 0;
428 peer->afc_adv[afi][safi] = 0;
429 peer->afc_recv[afi][safi] = 0;
430
718e3744 431 /* peer address family capability flags*/
432 peer->af_cap[afi][safi] = 0;
538621f2 433
718e3744 434 /* peer address family status flags*/
435 peer->af_sflags[afi][safi] = 0;
538621f2 436
718e3744 437 /* Received ORF prefix-filter */
438 peer->orf_plist[afi][safi] = NULL;
538621f2 439
718e3744 440 /* ORF received prefix-filter pnt */
441 sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi);
442 prefix_bgp_orf_remove_all (orf_name);
443 }
444
445 /* Reset keepalive and holdtime */
446 if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
447 {
448 peer->v_keepalive = peer->keepalive;
449 peer->v_holdtime = peer->holdtime;
450 }
451 else
452 {
453 peer->v_keepalive = peer->bgp->default_keepalive;
454 peer->v_holdtime = peer->bgp->default_holdtime;
455 }
456
457 peer->update_time = 0;
458
459 /* Until we are sure that there is no problem about prefix count
460 this should be commented out.*/
461#if 0
462 /* Reset prefix count */
463 peer->pcount[AFI_IP][SAFI_UNICAST] = 0;
464 peer->pcount[AFI_IP][SAFI_MULTICAST] = 0;
465 peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0;
466 peer->pcount[AFI_IP6][SAFI_UNICAST] = 0;
467 peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0;
468#endif /* 0 */
469
470 return 0;
471}
472
473/* BGP peer is stoped by the error. */
474int
475bgp_stop_with_error (struct peer *peer)
476{
477 /* Double start timer. */
478 peer->v_start *= 2;
479
480 /* Overflow check. */
481 if (peer->v_start >= (60 * 2))
482 peer->v_start = (60 * 2);
483
484 bgp_stop (peer);
485
486 return 0;
487}
488
489/* TCP connection open. Next we send open message to remote peer. And
490 add read thread for reading open message. */
491int
492bgp_connect_success (struct peer *peer)
493{
eb821189 494 if (peer->fd < 0)
718e3744 495 {
496 zlog_err ("bgp_connect_success peer's fd is negative value %d",
eb821189 497 peer->fd);
718e3744 498 return -1;
499 }
eb821189 500 BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
718e3744 501
502 /* bgp_getsockname (peer); */
503
504 if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
505 bgp_open_send (peer);
506
507 return 0;
508}
509
510/* TCP connect fail */
511int
512bgp_connect_fail (struct peer *peer)
513{
514 bgp_stop (peer);
515 return 0;
516}
517
518/* This function is the first starting point of all BGP connection. It
519 try to connect to remote peer with non-blocking IO. */
520int
521bgp_start (struct peer *peer)
522{
523 int status;
524
525 /* If the peer is passive mode, force to move to Active mode. */
526 if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE))
527 {
528 BGP_EVENT_ADD (peer, TCP_connection_open_failed);
529 return 0;
530 }
531
532 status = bgp_connect (peer);
533
534 switch (status)
535 {
536 case connect_error:
537 if (BGP_DEBUG (fsm, FSM))
8c2e200a 538 plog_debug (peer->log, "%s [FSM] Connect error", peer->host);
718e3744 539 BGP_EVENT_ADD (peer, TCP_connection_open_failed);
540 break;
541 case connect_success:
542 if (BGP_DEBUG (fsm, FSM))
8c2e200a 543 plog_debug (peer->log, "%s [FSM] Connect immediately success",
eb821189 544 peer->host);
718e3744 545 BGP_EVENT_ADD (peer, TCP_connection_open);
546 break;
547 case connect_in_progress:
548 /* To check nonblocking connect, we wait until socket is
549 readable or writable. */
550 if (BGP_DEBUG (fsm, FSM))
8c2e200a 551 plog_debug (peer->log, "%s [FSM] Non blocking connect waiting result",
eb821189 552 peer->host);
553 if (peer->fd < 0)
718e3744 554 {
555 zlog_err ("bgp_start peer's fd is negative value %d",
eb821189 556 peer->fd);
718e3744 557 return -1;
558 }
eb821189 559 BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
560 BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
718e3744 561 break;
562 }
563 return 0;
564}
565
566/* Connect retry timer is expired when the peer status is Connect. */
567int
568bgp_reconnect (struct peer *peer)
569{
570 bgp_stop (peer);
571 bgp_start (peer);
572 return 0;
573}
574
575int
576bgp_fsm_open (struct peer *peer)
577{
578 /* Send keepalive and make keepalive timer */
579 bgp_keepalive_send (peer);
580
581 /* Reset holdtimer value. */
582 BGP_TIMER_OFF (peer->t_holdtime);
583
584 return 0;
585}
586
587/* Called after event occured, this function change status and reset
588 read/write and timer thread. */
589void
590bgp_fsm_change_status (struct peer *peer, int status)
591{
592 bgp_dump_state (peer, peer->status, status);
593
594 /* Preserve old status and change into new status. */
595 peer->ostatus = peer->status;
596 peer->status = status;
597}
598
599/* Keepalive send to peer. */
600int
601bgp_fsm_keepalive_expire (struct peer *peer)
602{
603 bgp_keepalive_send (peer);
604 return 0;
605}
606
607/* Hold timer expire. This is error of BGP connection. So cut the
608 peer and change to Idle status. */
609int
610bgp_fsm_holdtime_expire (struct peer *peer)
611{
612 if (BGP_DEBUG (fsm, FSM))
613 zlog (peer->log, LOG_DEBUG, "%s [FSM] Hold timer expire", peer->host);
614
615 /* Send notify to remote peer. */
616 bgp_notify_send (peer, BGP_NOTIFY_HOLD_ERR, 0);
617
618 /* Sweep if it is temporary peer. */
619 if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
620 {
621 zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host);
622 peer_delete (peer);
623 return -1;
624 }
625
626 return 0;
627}
628
629/* Status goes to Established. Send keepalive packet then make first
630 update information. */
631int
632bgp_establish (struct peer *peer)
633{
634 struct bgp_notify *notify;
635 afi_t afi;
636 safi_t safi;
637
638 /* Reset capability open status flag. */
639 if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
640 SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
641
642 /* Clear last notification data. */
643 notify = &peer->notify;
644 if (notify->data)
645 XFREE (MTYPE_TMP, notify->data);
646 memset (notify, 0, sizeof (struct bgp_notify));
647
648 /* Clear start timer value to default. */
649 peer->v_start = BGP_INIT_START_TIMER;
650
651 /* Increment established count. */
652 peer->established++;
653 bgp_fsm_change_status (peer, Established);
848973c7 654
655 /* bgp log-neighbor-changes of neighbor Up */
656 if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
657 zlog_info ("%%ADJCHANGE: neighbor %s Up", peer->host);
658
718e3744 659#ifdef HAVE_SNMP
660 bgpTrapEstablished (peer);
661#endif /* HAVE_SNMP */
662
663 /* Reset uptime, send keepalive, send current table. */
664 bgp_uptime_reset (peer);
665
666 /* Send route-refresh when ORF is enabled */
667 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
668 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
669 if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV))
670 {
671 if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV))
672 bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX,
673 REFRESH_IMMEDIATE, 0);
674 else if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV))
675 bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX_OLD,
676 REFRESH_IMMEDIATE, 0);
677 }
678
679 if (peer->v_keepalive)
680 bgp_keepalive_send (peer);
681
682 /* First update is deferred until ORF or ROUTE-REFRESH is received */
683 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
684 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
685 if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV))
686 if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
687 || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))
688 SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH);
689
690 bgp_announce_route_all (peer);
691
692 BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1);
693
694 return 0;
695}
696
697/* Keepalive packet is received. */
698int
699bgp_fsm_keepalive (struct peer *peer)
700{
701 /* peer count update */
702 peer->keepalive_in++;
703
704 BGP_TIMER_OFF (peer->t_holdtime);
705 return 0;
706}
707
708/* Update packet is received. */
709int
710bgp_fsm_update (struct peer *peer)
711{
712 BGP_TIMER_OFF (peer->t_holdtime);
713 return 0;
714}
715
716/* This is empty event. */
717int
718bgp_ignore (struct peer *peer)
719{
720 if (BGP_DEBUG (fsm, FSM))
721 zlog (peer->log, LOG_DEBUG, "%s [FSM] bgp_ignore called", peer->host);
722 return 0;
723}
724\f
725/* Finite State Machine structure */
726struct {
727 int (*func) ();
728 int next_state;
729} FSM [BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] =
730{
731 {
732 /* Idle state: In Idle state, all events other than BGP_Start is
733 ignored. With BGP_Start event, finite state machine calls
734 bgp_start(). */
735 {bgp_start, Connect}, /* BGP_Start */
736 {bgp_stop, Idle}, /* BGP_Stop */
737 {bgp_stop, Idle}, /* TCP_connection_open */
738 {bgp_stop, Idle}, /* TCP_connection_closed */
739 {bgp_ignore, Idle}, /* TCP_connection_open_failed */
740 {bgp_stop, Idle}, /* TCP_fatal_error */
741 {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
742 {bgp_ignore, Idle}, /* Hold_Timer_expired */
743 {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
744 {bgp_ignore, Idle}, /* Receive_OPEN_message */
745 {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
746 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
747 {bgp_ignore, Idle}, /* Receive_NOTIFICATION_message */
748 },
749 {
750 /* Connect */
751 {bgp_ignore, Connect}, /* BGP_Start */
752 {bgp_stop, Idle}, /* BGP_Stop */
753 {bgp_connect_success, OpenSent}, /* TCP_connection_open */
754 {bgp_stop, Idle}, /* TCP_connection_closed */
755 {bgp_connect_fail, Active}, /* TCP_connection_open_failed */
756 {bgp_connect_fail, Idle}, /* TCP_fatal_error */
757 {bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */
758 {bgp_ignore, Idle}, /* Hold_Timer_expired */
759 {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
760 {bgp_ignore, Idle}, /* Receive_OPEN_message */
761 {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
762 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
763 {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */
764 },
765 {
766 /* Active, */
767 {bgp_ignore, Active}, /* BGP_Start */
768 {bgp_stop, Idle}, /* BGP_Stop */
769 {bgp_connect_success, OpenSent}, /* TCP_connection_open */
770 {bgp_stop, Idle}, /* TCP_connection_closed */
771 {bgp_ignore, Active}, /* TCP_connection_open_failed */
772 {bgp_ignore, Idle}, /* TCP_fatal_error */
773 {bgp_start, Connect}, /* ConnectRetry_timer_expired */
774 {bgp_ignore, Idle}, /* Hold_Timer_expired */
775 {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
776 {bgp_ignore, Idle}, /* Receive_OPEN_message */
777 {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
778 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
779 {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
780 },
781 {
782 /* OpenSent, */
783 {bgp_ignore, OpenSent}, /* BGP_Start */
784 {bgp_stop, Idle}, /* BGP_Stop */
785 {bgp_stop, Idle}, /* TCP_connection_open */
786 {bgp_stop, Active}, /* TCP_connection_closed */
787 {bgp_ignore, Idle}, /* TCP_connection_open_failed */
788 {bgp_stop, Idle}, /* TCP_fatal_error */
789 {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
790 {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
791 {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
792 {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
793 {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
794 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
795 {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
796 },
797 {
798 /* OpenConfirm, */
799 {bgp_ignore, OpenConfirm}, /* BGP_Start */
800 {bgp_stop, Idle}, /* BGP_Stop */
801 {bgp_stop, Idle}, /* TCP_connection_open */
802 {bgp_stop, Idle}, /* TCP_connection_closed */
803 {bgp_stop, Idle}, /* TCP_connection_open_failed */
804 {bgp_stop, Idle}, /* TCP_fatal_error */
805 {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
806 {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
807 {bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */
808 {bgp_ignore, Idle}, /* Receive_OPEN_message */
809 {bgp_establish, Established}, /* Receive_KEEPALIVE_message */
810 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
811 {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
812 },
813 {
814 /* Established, */
815 {bgp_ignore, Established}, /* BGP_Start */
816 {bgp_stop, Idle}, /* BGP_Stop */
817 {bgp_stop, Idle}, /* TCP_connection_open */
818 {bgp_stop, Idle}, /* TCP_connection_closed */
819 {bgp_ignore, Idle}, /* TCP_connection_open_failed */
820 {bgp_stop, Idle}, /* TCP_fatal_error */
821 {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
822 {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
823 {bgp_fsm_keepalive_expire, Established}, /* KeepAlive_timer_expired */
824 {bgp_stop, Idle}, /* Receive_OPEN_message */
825 {bgp_fsm_keepalive, Established}, /* Receive_KEEPALIVE_message */
826 {bgp_fsm_update, Established}, /* Receive_UPDATE_message */
827 {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
828 },
829};
830
fd79ac91 831static const char *bgp_event_str[] =
718e3744 832{
833 NULL,
834 "BGP_Start",
835 "BGP_Stop",
836 "TCP_connection_open",
837 "TCP_connection_closed",
838 "TCP_connection_open_failed",
839 "TCP_fatal_error",
840 "ConnectRetry_timer_expired",
841 "Hold_Timer_expired",
842 "KeepAlive_timer_expired",
843 "Receive_OPEN_message",
844 "Receive_KEEPALIVE_message",
845 "Receive_UPDATE_message",
846 "Receive_NOTIFICATION_message"
847};
848
849/* Execute event process. */
850int
851bgp_event (struct thread *thread)
852{
853 int ret;
854 int event;
855 int next;
856 struct peer *peer;
857
858 peer = THREAD_ARG (thread);
859 event = THREAD_VAL (thread);
860
861 /* Logging this event. */
862 next = FSM [peer->status -1][event - 1].next_state;
863
864 if (BGP_DEBUG (fsm, FSM))
8c2e200a 865 plog_debug (peer->log, "%s [FSM] %s (%s->%s)", peer->host,
718e3744 866 bgp_event_str[event],
867 LOOKUP (bgp_status_msg, peer->status),
868 LOOKUP (bgp_status_msg, next));
869 if (BGP_DEBUG (normal, NORMAL)
870 && strcmp (LOOKUP (bgp_status_msg, peer->status), LOOKUP (bgp_status_msg, next)))
8c2e200a 871 zlog_debug ("%s went from %s to %s",
718e3744 872 peer->host,
873 LOOKUP (bgp_status_msg, peer->status),
874 LOOKUP (bgp_status_msg, next));
875
876 /* Call function. */
877 ret = (*(FSM [peer->status - 1][event - 1].func))(peer);
878
879 /* When function do not want proceed next job return -1. */
880 if (ret < 0)
881 return ret;
882
883 /* If status is changed. */
884 if (next != peer->status)
885 bgp_fsm_change_status (peer, next);
886
887 /* Make sure timer is set. */
888 bgp_timer_set (peer);
889
890 return 0;
891}