blob: 7327db0c17b8dce6f112c6bf74161d71cc146f1f [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
pauleb821182004-05-01 08:44:08 +0000295 BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
paul718e3742002-12-13 20:15:29 +0000296
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
hassoe0701b72004-05-20 09:19:34 +0000310/* BGP Peer Down Cause */
paulfd79ac92004-10-13 05:06:08 +0000311const char *peer_down_str[] =
hassoe0701b72004-05-20 09:19:34 +0000312{
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
paul718e3742002-12-13 20:15:29 +0000337/* Administrative BGP peer stop event. */
338int
339bgp_stop (struct peer *peer)
340{
paul718e3742002-12-13 20:15:29 +0000341 afi_t afi;
342 safi_t safi;
343 char orf_name[BUFSIZ];
344
345 /* Increment Dropped count. */
346 if (peer->status == Established)
347 {
paul718e3742002-12-13 20:15:29 +0000348 peer->dropped++;
349 bgp_fsm_change_status (peer, Idle);
paul848973c2003-08-13 00:32:49 +0000350
351 /* bgp log-neighbor-changes of neighbor Down */
352 if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
hassoe0701b72004-05-20 09:19:34 +0000353 zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host,
354 peer_down_str [(int) peer->last_reset]);
paul848973c2003-08-13 00:32:49 +0000355
356 /* set last reset time */
357 peer->resettime = time (NULL);
paulc5317402004-05-03 13:25:06 +0000358 /* Reset uptime. */
359 bgp_uptime_reset (peer);
paul848973c2003-08-13 00:32:49 +0000360
paul718e3742002-12-13 20:15:29 +0000361#ifdef HAVE_SNMP
362 bgpTrapBackwardTransition (peer);
363#endif /* HAVE_SNMP */
paul718e3742002-12-13 20:15:29 +0000364
hasso538621f2004-05-21 09:31:30 +0000365 /* Reset uptime. */
366 bgp_uptime_reset (peer);
367
368 /* Need of clear of peer. */
369 bgp_clear_route_all (peer);
hassof4184462005-02-01 20:13:16 +0000370
371 /* Reset peer synctime */
372 peer->synctime = 0;
hasso538621f2004-05-21 09:31:30 +0000373 }
paul718e3742002-12-13 20:15:29 +0000374
375 /* Stop read and write threads when exists. */
376 BGP_READ_OFF (peer->t_read);
377 BGP_WRITE_OFF (peer->t_write);
378
379 /* Stop all timers. */
380 BGP_TIMER_OFF (peer->t_start);
381 BGP_TIMER_OFF (peer->t_connect);
382 BGP_TIMER_OFF (peer->t_holdtime);
383 BGP_TIMER_OFF (peer->t_keepalive);
384 BGP_TIMER_OFF (peer->t_asorig);
385 BGP_TIMER_OFF (peer->t_routeadv);
386
387 /* Delete all existing events of the peer. */
388 BGP_EVENT_DELETE (peer);
389
390 /* Stream reset. */
391 peer->packet_size = 0;
392
393 /* Clear input and output buffer. */
394 if (peer->ibuf)
395 stream_reset (peer->ibuf);
396 if (peer->work)
397 stream_reset (peer->work);
398 stream_fifo_clean (peer->obuf);
399
pauleb821182004-05-01 08:44:08 +0000400 /* Close of file descriptor. */
401 if (peer->fd >= 0)
402 {
403 close (peer->fd);
404 peer->fd = -1;
405 }
paul718e3742002-12-13 20:15:29 +0000406
407 /* Connection information. */
408 if (peer->su_local)
409 {
410 XFREE (MTYPE_SOCKUNION, peer->su_local);
411 peer->su_local = NULL;
412 }
413
414 if (peer->su_remote)
415 {
416 XFREE (MTYPE_SOCKUNION, peer->su_remote);
417 peer->su_remote = NULL;
418 }
pauleb821182004-05-01 08:44:08 +0000419
paul718e3742002-12-13 20:15:29 +0000420 /* Clear remote router-id. */
421 peer->remote_id.s_addr = 0;
422
hasso538621f2004-05-21 09:31:30 +0000423 /* Clear peer capability flag. */
424 peer->cap = 0;
paul718e3742002-12-13 20:15:29 +0000425
426 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
427 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
428 {
hasso538621f2004-05-21 09:31:30 +0000429 /* Reset all negotiated variables */
430 peer->afc_nego[afi][safi] = 0;
431 peer->afc_adv[afi][safi] = 0;
432 peer->afc_recv[afi][safi] = 0;
433
paul718e3742002-12-13 20:15:29 +0000434 /* peer address family capability flags*/
435 peer->af_cap[afi][safi] = 0;
hasso538621f2004-05-21 09:31:30 +0000436
paul718e3742002-12-13 20:15:29 +0000437 /* peer address family status flags*/
438 peer->af_sflags[afi][safi] = 0;
hasso538621f2004-05-21 09:31:30 +0000439
paul718e3742002-12-13 20:15:29 +0000440 /* Received ORF prefix-filter */
441 peer->orf_plist[afi][safi] = NULL;
hasso538621f2004-05-21 09:31:30 +0000442
paul718e3742002-12-13 20:15:29 +0000443 /* ORF received prefix-filter pnt */
444 sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi);
445 prefix_bgp_orf_remove_all (orf_name);
446 }
447
448 /* Reset keepalive and holdtime */
449 if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
450 {
451 peer->v_keepalive = peer->keepalive;
452 peer->v_holdtime = peer->holdtime;
453 }
454 else
455 {
456 peer->v_keepalive = peer->bgp->default_keepalive;
457 peer->v_holdtime = peer->bgp->default_holdtime;
458 }
459
460 peer->update_time = 0;
461
462 /* Until we are sure that there is no problem about prefix count
463 this should be commented out.*/
464#if 0
465 /* Reset prefix count */
466 peer->pcount[AFI_IP][SAFI_UNICAST] = 0;
467 peer->pcount[AFI_IP][SAFI_MULTICAST] = 0;
468 peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0;
469 peer->pcount[AFI_IP6][SAFI_UNICAST] = 0;
470 peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0;
471#endif /* 0 */
472
473 return 0;
474}
475
476/* BGP peer is stoped by the error. */
477int
478bgp_stop_with_error (struct peer *peer)
479{
480 /* Double start timer. */
481 peer->v_start *= 2;
482
483 /* Overflow check. */
484 if (peer->v_start >= (60 * 2))
485 peer->v_start = (60 * 2);
486
487 bgp_stop (peer);
488
489 return 0;
490}
491
492/* TCP connection open. Next we send open message to remote peer. And
493 add read thread for reading open message. */
494int
495bgp_connect_success (struct peer *peer)
496{
hassof4184462005-02-01 20:13:16 +0000497 char buf1[BUFSIZ];
498
pauleb821182004-05-01 08:44:08 +0000499 if (peer->fd < 0)
paul718e3742002-12-13 20:15:29 +0000500 {
501 zlog_err ("bgp_connect_success peer's fd is negative value %d",
pauleb821182004-05-01 08:44:08 +0000502 peer->fd);
paul718e3742002-12-13 20:15:29 +0000503 return -1;
504 }
pauleb821182004-05-01 08:44:08 +0000505 BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
paul718e3742002-12-13 20:15:29 +0000506
hassof4184462005-02-01 20:13:16 +0000507 if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
508 bgp_getsockname (peer);
509
510 if (BGP_DEBUG (normal, NORMAL))
511 {
512 if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
513 zlog_debug ("%s open active, local address %s", peer->host,
514 sockunion2str (peer->su_local, buf1, SU_ADDRSTRLEN));
515 else
516 zlog_debug ("%s passive open", peer->host);
517 }
paul718e3742002-12-13 20:15:29 +0000518
519 if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
520 bgp_open_send (peer);
521
522 return 0;
523}
524
525/* TCP connect fail */
526int
527bgp_connect_fail (struct peer *peer)
528{
529 bgp_stop (peer);
530 return 0;
531}
532
533/* This function is the first starting point of all BGP connection. It
534 try to connect to remote peer with non-blocking IO. */
535int
536bgp_start (struct peer *peer)
537{
538 int status;
539
540 /* If the peer is passive mode, force to move to Active mode. */
541 if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE))
542 {
543 BGP_EVENT_ADD (peer, TCP_connection_open_failed);
544 return 0;
545 }
546
547 status = bgp_connect (peer);
548
549 switch (status)
550 {
551 case connect_error:
552 if (BGP_DEBUG (fsm, FSM))
ajs8c2e2002004-12-08 20:08:54 +0000553 plog_debug (peer->log, "%s [FSM] Connect error", peer->host);
paul718e3742002-12-13 20:15:29 +0000554 BGP_EVENT_ADD (peer, TCP_connection_open_failed);
555 break;
556 case connect_success:
557 if (BGP_DEBUG (fsm, FSM))
ajs8c2e2002004-12-08 20:08:54 +0000558 plog_debug (peer->log, "%s [FSM] Connect immediately success",
pauleb821182004-05-01 08:44:08 +0000559 peer->host);
paul718e3742002-12-13 20:15:29 +0000560 BGP_EVENT_ADD (peer, TCP_connection_open);
561 break;
562 case connect_in_progress:
563 /* To check nonblocking connect, we wait until socket is
564 readable or writable. */
565 if (BGP_DEBUG (fsm, FSM))
ajs8c2e2002004-12-08 20:08:54 +0000566 plog_debug (peer->log, "%s [FSM] Non blocking connect waiting result",
pauleb821182004-05-01 08:44:08 +0000567 peer->host);
568 if (peer->fd < 0)
paul718e3742002-12-13 20:15:29 +0000569 {
570 zlog_err ("bgp_start peer's fd is negative value %d",
pauleb821182004-05-01 08:44:08 +0000571 peer->fd);
paul718e3742002-12-13 20:15:29 +0000572 return -1;
573 }
pauleb821182004-05-01 08:44:08 +0000574 BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
575 BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
paul718e3742002-12-13 20:15:29 +0000576 break;
577 }
578 return 0;
579}
580
581/* Connect retry timer is expired when the peer status is Connect. */
582int
583bgp_reconnect (struct peer *peer)
584{
585 bgp_stop (peer);
586 bgp_start (peer);
587 return 0;
588}
589
590int
591bgp_fsm_open (struct peer *peer)
592{
593 /* Send keepalive and make keepalive timer */
594 bgp_keepalive_send (peer);
595
596 /* Reset holdtimer value. */
597 BGP_TIMER_OFF (peer->t_holdtime);
598
599 return 0;
600}
601
602/* Called after event occured, this function change status and reset
603 read/write and timer thread. */
604void
605bgp_fsm_change_status (struct peer *peer, int status)
606{
607 bgp_dump_state (peer, peer->status, status);
608
609 /* Preserve old status and change into new status. */
610 peer->ostatus = peer->status;
611 peer->status = status;
hassof4184462005-02-01 20:13:16 +0000612
613 if (BGP_DEBUG (normal, NORMAL))
614 zlog_debug ("%s went from %s to %s",
615 peer->host,
616 LOOKUP (bgp_status_msg, peer->ostatus),
617 LOOKUP (bgp_status_msg, peer->status));
paul718e3742002-12-13 20:15:29 +0000618}
619
620/* Keepalive send to peer. */
621int
622bgp_fsm_keepalive_expire (struct peer *peer)
623{
624 bgp_keepalive_send (peer);
625 return 0;
626}
627
628/* Hold timer expire. This is error of BGP connection. So cut the
629 peer and change to Idle status. */
630int
631bgp_fsm_holdtime_expire (struct peer *peer)
632{
633 if (BGP_DEBUG (fsm, FSM))
634 zlog (peer->log, LOG_DEBUG, "%s [FSM] Hold timer expire", peer->host);
635
636 /* Send notify to remote peer. */
637 bgp_notify_send (peer, BGP_NOTIFY_HOLD_ERR, 0);
638
639 /* Sweep if it is temporary peer. */
640 if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
641 {
642 zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host);
643 peer_delete (peer);
644 return -1;
645 }
646
647 return 0;
648}
649
650/* Status goes to Established. Send keepalive packet then make first
651 update information. */
652int
653bgp_establish (struct peer *peer)
654{
655 struct bgp_notify *notify;
656 afi_t afi;
657 safi_t safi;
658
659 /* Reset capability open status flag. */
660 if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
661 SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
662
663 /* Clear last notification data. */
664 notify = &peer->notify;
665 if (notify->data)
666 XFREE (MTYPE_TMP, notify->data);
667 memset (notify, 0, sizeof (struct bgp_notify));
668
669 /* Clear start timer value to default. */
670 peer->v_start = BGP_INIT_START_TIMER;
671
672 /* Increment established count. */
673 peer->established++;
674 bgp_fsm_change_status (peer, Established);
paul848973c2003-08-13 00:32:49 +0000675
676 /* bgp log-neighbor-changes of neighbor Up */
677 if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
678 zlog_info ("%%ADJCHANGE: neighbor %s Up", peer->host);
679
paul718e3742002-12-13 20:15:29 +0000680#ifdef HAVE_SNMP
681 bgpTrapEstablished (peer);
682#endif /* HAVE_SNMP */
683
684 /* Reset uptime, send keepalive, send current table. */
685 bgp_uptime_reset (peer);
686
687 /* Send route-refresh when ORF is enabled */
688 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
689 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
690 if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV))
691 {
692 if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV))
693 bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX,
694 REFRESH_IMMEDIATE, 0);
695 else if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV))
696 bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX_OLD,
697 REFRESH_IMMEDIATE, 0);
698 }
699
700 if (peer->v_keepalive)
701 bgp_keepalive_send (peer);
702
703 /* First update is deferred until ORF or ROUTE-REFRESH is received */
704 for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
705 for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
706 if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV))
707 if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
708 || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))
709 SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH);
710
711 bgp_announce_route_all (peer);
712
713 BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1);
714
715 return 0;
716}
717
718/* Keepalive packet is received. */
719int
720bgp_fsm_keepalive (struct peer *peer)
721{
722 /* peer count update */
723 peer->keepalive_in++;
724
725 BGP_TIMER_OFF (peer->t_holdtime);
726 return 0;
727}
728
729/* Update packet is received. */
730int
731bgp_fsm_update (struct peer *peer)
732{
733 BGP_TIMER_OFF (peer->t_holdtime);
734 return 0;
735}
736
737/* This is empty event. */
738int
739bgp_ignore (struct peer *peer)
740{
741 if (BGP_DEBUG (fsm, FSM))
742 zlog (peer->log, LOG_DEBUG, "%s [FSM] bgp_ignore called", peer->host);
743 return 0;
744}
745
746/* Finite State Machine structure */
747struct {
748 int (*func) ();
749 int next_state;
750} FSM [BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] =
751{
752 {
753 /* Idle state: In Idle state, all events other than BGP_Start is
754 ignored. With BGP_Start event, finite state machine calls
755 bgp_start(). */
756 {bgp_start, Connect}, /* BGP_Start */
757 {bgp_stop, Idle}, /* BGP_Stop */
758 {bgp_stop, Idle}, /* TCP_connection_open */
759 {bgp_stop, Idle}, /* TCP_connection_closed */
760 {bgp_ignore, Idle}, /* TCP_connection_open_failed */
761 {bgp_stop, Idle}, /* TCP_fatal_error */
762 {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
763 {bgp_ignore, Idle}, /* Hold_Timer_expired */
764 {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
765 {bgp_ignore, Idle}, /* Receive_OPEN_message */
766 {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
767 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
768 {bgp_ignore, Idle}, /* Receive_NOTIFICATION_message */
769 },
770 {
771 /* Connect */
772 {bgp_ignore, Connect}, /* BGP_Start */
773 {bgp_stop, Idle}, /* BGP_Stop */
774 {bgp_connect_success, OpenSent}, /* TCP_connection_open */
775 {bgp_stop, Idle}, /* TCP_connection_closed */
776 {bgp_connect_fail, Active}, /* TCP_connection_open_failed */
777 {bgp_connect_fail, Idle}, /* TCP_fatal_error */
778 {bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */
779 {bgp_ignore, Idle}, /* Hold_Timer_expired */
780 {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
781 {bgp_ignore, Idle}, /* Receive_OPEN_message */
782 {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
783 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
784 {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */
785 },
786 {
787 /* Active, */
788 {bgp_ignore, Active}, /* BGP_Start */
789 {bgp_stop, Idle}, /* BGP_Stop */
790 {bgp_connect_success, OpenSent}, /* TCP_connection_open */
791 {bgp_stop, Idle}, /* TCP_connection_closed */
792 {bgp_ignore, Active}, /* TCP_connection_open_failed */
793 {bgp_ignore, Idle}, /* TCP_fatal_error */
794 {bgp_start, Connect}, /* ConnectRetry_timer_expired */
795 {bgp_ignore, Idle}, /* Hold_Timer_expired */
796 {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
797 {bgp_ignore, Idle}, /* Receive_OPEN_message */
798 {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
799 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
800 {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
801 },
802 {
803 /* OpenSent, */
804 {bgp_ignore, OpenSent}, /* BGP_Start */
805 {bgp_stop, Idle}, /* BGP_Stop */
806 {bgp_stop, Idle}, /* TCP_connection_open */
807 {bgp_stop, Active}, /* TCP_connection_closed */
808 {bgp_ignore, Idle}, /* TCP_connection_open_failed */
809 {bgp_stop, Idle}, /* TCP_fatal_error */
810 {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
811 {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
812 {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
813 {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
814 {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
815 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
816 {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
817 },
818 {
819 /* OpenConfirm, */
820 {bgp_ignore, OpenConfirm}, /* BGP_Start */
821 {bgp_stop, Idle}, /* BGP_Stop */
822 {bgp_stop, Idle}, /* TCP_connection_open */
823 {bgp_stop, Idle}, /* TCP_connection_closed */
824 {bgp_stop, Idle}, /* TCP_connection_open_failed */
825 {bgp_stop, Idle}, /* TCP_fatal_error */
826 {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
827 {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
828 {bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */
829 {bgp_ignore, Idle}, /* Receive_OPEN_message */
830 {bgp_establish, Established}, /* Receive_KEEPALIVE_message */
831 {bgp_ignore, Idle}, /* Receive_UPDATE_message */
832 {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
833 },
834 {
835 /* Established, */
836 {bgp_ignore, Established}, /* BGP_Start */
837 {bgp_stop, Idle}, /* BGP_Stop */
838 {bgp_stop, Idle}, /* TCP_connection_open */
839 {bgp_stop, Idle}, /* TCP_connection_closed */
840 {bgp_ignore, Idle}, /* TCP_connection_open_failed */
841 {bgp_stop, Idle}, /* TCP_fatal_error */
842 {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
843 {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
844 {bgp_fsm_keepalive_expire, Established}, /* KeepAlive_timer_expired */
845 {bgp_stop, Idle}, /* Receive_OPEN_message */
846 {bgp_fsm_keepalive, Established}, /* Receive_KEEPALIVE_message */
847 {bgp_fsm_update, Established}, /* Receive_UPDATE_message */
848 {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
849 },
850};
851
paulfd79ac92004-10-13 05:06:08 +0000852static const char *bgp_event_str[] =
paul718e3742002-12-13 20:15:29 +0000853{
854 NULL,
855 "BGP_Start",
856 "BGP_Stop",
857 "TCP_connection_open",
858 "TCP_connection_closed",
859 "TCP_connection_open_failed",
860 "TCP_fatal_error",
861 "ConnectRetry_timer_expired",
862 "Hold_Timer_expired",
863 "KeepAlive_timer_expired",
864 "Receive_OPEN_message",
865 "Receive_KEEPALIVE_message",
866 "Receive_UPDATE_message",
867 "Receive_NOTIFICATION_message"
868};
869
870/* Execute event process. */
871int
872bgp_event (struct thread *thread)
873{
874 int ret;
875 int event;
876 int next;
877 struct peer *peer;
878
879 peer = THREAD_ARG (thread);
880 event = THREAD_VAL (thread);
881
882 /* Logging this event. */
883 next = FSM [peer->status -1][event - 1].next_state;
884
885 if (BGP_DEBUG (fsm, FSM))
ajs8c2e2002004-12-08 20:08:54 +0000886 plog_debug (peer->log, "%s [FSM] %s (%s->%s)", peer->host,
paul718e3742002-12-13 20:15:29 +0000887 bgp_event_str[event],
888 LOOKUP (bgp_status_msg, peer->status),
889 LOOKUP (bgp_status_msg, next));
paul718e3742002-12-13 20:15:29 +0000890
891 /* Call function. */
892 ret = (*(FSM [peer->status - 1][event - 1].func))(peer);
893
894 /* When function do not want proceed next job return -1. */
895 if (ret < 0)
896 return ret;
897
898 /* If status is changed. */
899 if (next != peer->status)
900 bgp_fsm_change_status (peer, next);
901
902 /* Make sure timer is set. */
903 bgp_timer_set (peer);
904
905 return 0;
906}