Annotation of embedaddon/quagga/bgpd/bgp_fsm.c, revision 1.1
1.1 ! misho 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:
! 5: This file is part of GNU Zebra.
! 6:
! 7: GNU Zebra is free software; you can redistribute it and/or modify it
! 8: under the terms of the GNU General Public License as published by the
! 9: Free Software Foundation; either version 2, or (at your option) any
! 10: later version.
! 11:
! 12: GNU Zebra is distributed in the hope that it will be useful, but
! 13: WITHOUT ANY WARRANTY; without even the implied warranty of
! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 15: General Public License for more details.
! 16:
! 17: You should have received a copy of the GNU General Public License
! 18: along with GNU Zebra; see the file COPYING. If not, write to the Free
! 19: Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
! 20: 02111-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. */
! 53: int bgp_event (struct thread *);
! 54:
! 55: /* BGP thread functions. */
! 56: static int bgp_start_timer (struct thread *);
! 57: static int bgp_connect_timer (struct thread *);
! 58: static int bgp_holdtime_timer (struct thread *);
! 59: static int bgp_keepalive_timer (struct thread *);
! 60:
! 61: /* BGP FSM functions. */
! 62: static int bgp_start (struct peer *);
! 63:
! 64: /* BGP start timer jitter. */
! 65: static int
! 66: bgp_start_jitter (int time)
! 67: {
! 68: return ((rand () % (time + 1)) - (time / 2));
! 69: }
! 70:
! 71: /* Check if suppress start/restart of sessions to peer. */
! 72: #define BGP_PEER_START_SUPPRESSED(P) \
! 73: (CHECK_FLAG ((P)->flags, PEER_FLAG_SHUTDOWN) \
! 74: || CHECK_FLAG ((P)->sflags, PEER_STATUS_PREFIX_OVERFLOW))
! 75:
! 76: /* Hook function called after bgp event is occered. And vty's
! 77: neighbor command invoke this function after making neighbor
! 78: structure. */
! 79: void
! 80: bgp_timer_set (struct peer *peer)
! 81: {
! 82: int jitter = 0;
! 83:
! 84: switch (peer->status)
! 85: {
! 86: case Idle:
! 87: /* First entry point of peer's finite state machine. In Idle
! 88: status start timer is on unless peer is shutdown or peer is
! 89: inactive. All other timer must be turned off */
! 90: if (BGP_PEER_START_SUPPRESSED (peer) || ! peer_active (peer))
! 91: {
! 92: BGP_TIMER_OFF (peer->t_start);
! 93: }
! 94: else
! 95: {
! 96: jitter = bgp_start_jitter (peer->v_start);
! 97: BGP_TIMER_ON (peer->t_start, bgp_start_timer,
! 98: peer->v_start + jitter);
! 99: }
! 100: BGP_TIMER_OFF (peer->t_connect);
! 101: BGP_TIMER_OFF (peer->t_holdtime);
! 102: BGP_TIMER_OFF (peer->t_keepalive);
! 103: BGP_TIMER_OFF (peer->t_asorig);
! 104: BGP_TIMER_OFF (peer->t_routeadv);
! 105: break;
! 106:
! 107: case Connect:
! 108: /* After start timer is expired, the peer moves to Connnect
! 109: status. Make sure start timer is off and connect timer is
! 110: on. */
! 111: BGP_TIMER_OFF (peer->t_start);
! 112: BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect);
! 113: BGP_TIMER_OFF (peer->t_holdtime);
! 114: BGP_TIMER_OFF (peer->t_keepalive);
! 115: BGP_TIMER_OFF (peer->t_asorig);
! 116: BGP_TIMER_OFF (peer->t_routeadv);
! 117: break;
! 118:
! 119: case Active:
! 120: /* Active is waiting connection from remote peer. And if
! 121: connect timer is expired, change status to Connect. */
! 122: BGP_TIMER_OFF (peer->t_start);
! 123: /* If peer is passive mode, do not set connect timer. */
! 124: if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)
! 125: || CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
! 126: {
! 127: BGP_TIMER_OFF (peer->t_connect);
! 128: }
! 129: else
! 130: {
! 131: BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect);
! 132: }
! 133: BGP_TIMER_OFF (peer->t_holdtime);
! 134: BGP_TIMER_OFF (peer->t_keepalive);
! 135: BGP_TIMER_OFF (peer->t_asorig);
! 136: BGP_TIMER_OFF (peer->t_routeadv);
! 137: break;
! 138:
! 139: case OpenSent:
! 140: /* OpenSent status. */
! 141: BGP_TIMER_OFF (peer->t_start);
! 142: BGP_TIMER_OFF (peer->t_connect);
! 143: if (peer->v_holdtime != 0)
! 144: {
! 145: BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer,
! 146: peer->v_holdtime);
! 147: }
! 148: else
! 149: {
! 150: BGP_TIMER_OFF (peer->t_holdtime);
! 151: }
! 152: BGP_TIMER_OFF (peer->t_keepalive);
! 153: BGP_TIMER_OFF (peer->t_asorig);
! 154: BGP_TIMER_OFF (peer->t_routeadv);
! 155: break;
! 156:
! 157: case OpenConfirm:
! 158: /* OpenConfirm status. */
! 159: BGP_TIMER_OFF (peer->t_start);
! 160: BGP_TIMER_OFF (peer->t_connect);
! 161:
! 162: /* If the negotiated Hold Time value is zero, then the Hold Time
! 163: timer and KeepAlive timers are not started. */
! 164: if (peer->v_holdtime == 0)
! 165: {
! 166: BGP_TIMER_OFF (peer->t_holdtime);
! 167: BGP_TIMER_OFF (peer->t_keepalive);
! 168: }
! 169: else
! 170: {
! 171: BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer,
! 172: peer->v_holdtime);
! 173: BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer,
! 174: peer->v_keepalive);
! 175: }
! 176: BGP_TIMER_OFF (peer->t_asorig);
! 177: BGP_TIMER_OFF (peer->t_routeadv);
! 178: break;
! 179:
! 180: case Established:
! 181: /* In Established status start and connect timer is turned
! 182: off. */
! 183: BGP_TIMER_OFF (peer->t_start);
! 184: BGP_TIMER_OFF (peer->t_connect);
! 185:
! 186: /* Same as OpenConfirm, if holdtime is zero then both holdtime
! 187: and keepalive must be turned off. */
! 188: if (peer->v_holdtime == 0)
! 189: {
! 190: BGP_TIMER_OFF (peer->t_holdtime);
! 191: BGP_TIMER_OFF (peer->t_keepalive);
! 192: }
! 193: else
! 194: {
! 195: BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer,
! 196: peer->v_holdtime);
! 197: BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer,
! 198: peer->v_keepalive);
! 199: }
! 200: BGP_TIMER_OFF (peer->t_asorig);
! 201: break;
! 202: case Deleted:
! 203: BGP_TIMER_OFF (peer->t_gr_restart);
! 204: BGP_TIMER_OFF (peer->t_gr_stale);
! 205: BGP_TIMER_OFF (peer->t_pmax_restart);
! 206: case Clearing:
! 207: BGP_TIMER_OFF (peer->t_start);
! 208: BGP_TIMER_OFF (peer->t_connect);
! 209: BGP_TIMER_OFF (peer->t_holdtime);
! 210: BGP_TIMER_OFF (peer->t_keepalive);
! 211: BGP_TIMER_OFF (peer->t_asorig);
! 212: BGP_TIMER_OFF (peer->t_routeadv);
! 213: }
! 214: }
! 215:
! 216: /* BGP start timer. This function set BGP_Start event to thread value
! 217: and process event. */
! 218: static int
! 219: bgp_start_timer (struct thread *thread)
! 220: {
! 221: struct peer *peer;
! 222:
! 223: peer = THREAD_ARG (thread);
! 224: peer->t_start = NULL;
! 225:
! 226: if (BGP_DEBUG (fsm, FSM))
! 227: zlog (peer->log, LOG_DEBUG,
! 228: "%s [FSM] Timer (start timer expire).", peer->host);
! 229:
! 230: THREAD_VAL (thread) = BGP_Start;
! 231: bgp_event (thread); /* bgp_event unlocks peer */
! 232:
! 233: return 0;
! 234: }
! 235:
! 236: /* BGP connect retry timer. */
! 237: static int
! 238: bgp_connect_timer (struct thread *thread)
! 239: {
! 240: struct peer *peer;
! 241:
! 242: peer = THREAD_ARG (thread);
! 243: peer->t_connect = NULL;
! 244:
! 245: if (BGP_DEBUG (fsm, FSM))
! 246: zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (connect timer expire)",
! 247: peer->host);
! 248:
! 249: THREAD_VAL (thread) = ConnectRetry_timer_expired;
! 250: bgp_event (thread); /* bgp_event unlocks peer */
! 251:
! 252: return 0;
! 253: }
! 254:
! 255: /* BGP holdtime timer. */
! 256: static int
! 257: bgp_holdtime_timer (struct thread *thread)
! 258: {
! 259: struct peer *peer;
! 260:
! 261: peer = THREAD_ARG (thread);
! 262: peer->t_holdtime = NULL;
! 263:
! 264: if (BGP_DEBUG (fsm, FSM))
! 265: zlog (peer->log, LOG_DEBUG,
! 266: "%s [FSM] Timer (holdtime timer expire)",
! 267: peer->host);
! 268:
! 269: THREAD_VAL (thread) = Hold_Timer_expired;
! 270: bgp_event (thread); /* bgp_event unlocks peer */
! 271:
! 272: return 0;
! 273: }
! 274:
! 275: /* BGP keepalive fire ! */
! 276: static int
! 277: bgp_keepalive_timer (struct thread *thread)
! 278: {
! 279: struct peer *peer;
! 280:
! 281: peer = THREAD_ARG (thread);
! 282: peer->t_keepalive = NULL;
! 283:
! 284: if (BGP_DEBUG (fsm, FSM))
! 285: zlog (peer->log, LOG_DEBUG,
! 286: "%s [FSM] Timer (keepalive timer expire)",
! 287: peer->host);
! 288:
! 289: THREAD_VAL (thread) = KeepAlive_timer_expired;
! 290: bgp_event (thread); /* bgp_event unlocks peer */
! 291:
! 292: return 0;
! 293: }
! 294:
! 295: static int
! 296: bgp_routeadv_timer (struct thread *thread)
! 297: {
! 298: struct peer *peer;
! 299:
! 300: peer = THREAD_ARG (thread);
! 301: peer->t_routeadv = NULL;
! 302:
! 303: if (BGP_DEBUG (fsm, FSM))
! 304: zlog (peer->log, LOG_DEBUG,
! 305: "%s [FSM] Timer (routeadv timer expire)",
! 306: peer->host);
! 307:
! 308: peer->synctime = bgp_clock ();
! 309:
! 310: BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
! 311:
! 312: BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer,
! 313: peer->v_routeadv);
! 314:
! 315: return 0;
! 316: }
! 317:
! 318: /* BGP Peer Down Cause */
! 319: const char *peer_down_str[] =
! 320: {
! 321: "",
! 322: "Router ID changed",
! 323: "Remote AS changed",
! 324: "Local AS change",
! 325: "Cluster ID changed",
! 326: "Confederation identifier changed",
! 327: "Confederation peer changed",
! 328: "RR client config change",
! 329: "RS client config change",
! 330: "Update source change",
! 331: "Address family activated",
! 332: "Admin. shutdown",
! 333: "User reset",
! 334: "BGP Notification received",
! 335: "BGP Notification send",
! 336: "Peer closed the session",
! 337: "Neighbor deleted",
! 338: "Peer-group add member",
! 339: "Peer-group delete member",
! 340: "Capability changed",
! 341: "Passive config change",
! 342: "Multihop config change",
! 343: "NSF peer closed the session"
! 344: };
! 345:
! 346: static int
! 347: bgp_graceful_restart_timer_expire (struct thread *thread)
! 348: {
! 349: struct peer *peer;
! 350: afi_t afi;
! 351: safi_t safi;
! 352:
! 353: peer = THREAD_ARG (thread);
! 354: peer->t_gr_restart = NULL;
! 355:
! 356: /* NSF delete stale route */
! 357: for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
! 358: for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
! 359: if (peer->nsf[afi][safi])
! 360: bgp_clear_stale_route (peer, afi, safi);
! 361:
! 362: UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
! 363: BGP_TIMER_OFF (peer->t_gr_stale);
! 364:
! 365: if (BGP_DEBUG (events, EVENTS))
! 366: {
! 367: zlog_debug ("%s graceful restart timer expired", peer->host);
! 368: zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
! 369: }
! 370:
! 371: bgp_timer_set (peer);
! 372:
! 373: return 0;
! 374: }
! 375:
! 376: static int
! 377: bgp_graceful_stale_timer_expire (struct thread *thread)
! 378: {
! 379: struct peer *peer;
! 380: afi_t afi;
! 381: safi_t safi;
! 382:
! 383: peer = THREAD_ARG (thread);
! 384: peer->t_gr_stale = NULL;
! 385:
! 386: if (BGP_DEBUG (events, EVENTS))
! 387: zlog_debug ("%s graceful restart stalepath timer expired", peer->host);
! 388:
! 389: /* NSF delete stale route */
! 390: for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
! 391: for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
! 392: if (peer->nsf[afi][safi])
! 393: bgp_clear_stale_route (peer, afi, safi);
! 394:
! 395: return 0;
! 396: }
! 397:
! 398: /* Called after event occured, this function change status and reset
! 399: read/write and timer thread. */
! 400: void
! 401: bgp_fsm_change_status (struct peer *peer, int status)
! 402: {
! 403: bgp_dump_state (peer, peer->status, status);
! 404:
! 405: /* Transition into Clearing or Deleted must /always/ clear all routes..
! 406: * (and must do so before actually changing into Deleted..
! 407: */
! 408: if (status >= Clearing)
! 409: bgp_clear_route_all (peer);
! 410:
! 411: /* Preserve old status and change into new status. */
! 412: peer->ostatus = peer->status;
! 413: peer->status = status;
! 414:
! 415: if (BGP_DEBUG (normal, NORMAL))
! 416: zlog_debug ("%s went from %s to %s",
! 417: peer->host,
! 418: LOOKUP (bgp_status_msg, peer->ostatus),
! 419: LOOKUP (bgp_status_msg, peer->status));
! 420: }
! 421:
! 422: /* Flush the event queue and ensure the peer is shut down */
! 423: static int
! 424: bgp_clearing_completed (struct peer *peer)
! 425: {
! 426: int rc = bgp_stop(peer);
! 427: BGP_EVENT_FLUSH (peer);
! 428:
! 429: return rc;
! 430: }
! 431:
! 432: /* Administrative BGP peer stop event. */
! 433: /* May be called multiple times for the same peer */
! 434: int
! 435: bgp_stop (struct peer *peer)
! 436: {
! 437: afi_t afi;
! 438: safi_t safi;
! 439: char orf_name[BUFSIZ];
! 440:
! 441: /* Can't do this in Clearing; events are used for state transitions */
! 442: if (peer->status != Clearing)
! 443: {
! 444: /* Delete all existing events of the peer */
! 445: BGP_EVENT_FLUSH (peer);
! 446: }
! 447:
! 448: /* Increment Dropped count. */
! 449: if (peer->status == Established)
! 450: {
! 451: peer->dropped++;
! 452:
! 453: /* bgp log-neighbor-changes of neighbor Down */
! 454: if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
! 455: zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host,
! 456: peer_down_str [(int) peer->last_reset]);
! 457:
! 458: /* graceful restart */
! 459: if (peer->t_gr_stale)
! 460: {
! 461: BGP_TIMER_OFF (peer->t_gr_stale);
! 462: if (BGP_DEBUG (events, EVENTS))
! 463: zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
! 464: }
! 465: if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
! 466: {
! 467: if (BGP_DEBUG (events, EVENTS))
! 468: {
! 469: zlog_debug ("%s graceful restart timer started for %d sec",
! 470: peer->host, peer->v_gr_restart);
! 471: zlog_debug ("%s graceful restart stalepath timer started for %d sec",
! 472: peer->host, peer->bgp->stalepath_time);
! 473: }
! 474: BGP_TIMER_ON (peer->t_gr_restart, bgp_graceful_restart_timer_expire,
! 475: peer->v_gr_restart);
! 476: BGP_TIMER_ON (peer->t_gr_stale, bgp_graceful_stale_timer_expire,
! 477: peer->bgp->stalepath_time);
! 478: }
! 479: else
! 480: {
! 481: UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
! 482:
! 483: for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
! 484: for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
! 485: peer->nsf[afi][safi] = 0;
! 486: }
! 487:
! 488: /* set last reset time */
! 489: peer->resettime = peer->uptime = bgp_clock ();
! 490:
! 491: #ifdef HAVE_SNMP
! 492: bgpTrapBackwardTransition (peer);
! 493: #endif /* HAVE_SNMP */
! 494:
! 495: /* Reset peer synctime */
! 496: peer->synctime = 0;
! 497: }
! 498:
! 499: /* Stop read and write threads when exists. */
! 500: BGP_READ_OFF (peer->t_read);
! 501: BGP_WRITE_OFF (peer->t_write);
! 502:
! 503: /* Stop all timers. */
! 504: BGP_TIMER_OFF (peer->t_start);
! 505: BGP_TIMER_OFF (peer->t_connect);
! 506: BGP_TIMER_OFF (peer->t_holdtime);
! 507: BGP_TIMER_OFF (peer->t_keepalive);
! 508: BGP_TIMER_OFF (peer->t_asorig);
! 509: BGP_TIMER_OFF (peer->t_routeadv);
! 510:
! 511: /* Stream reset. */
! 512: peer->packet_size = 0;
! 513:
! 514: /* Clear input and output buffer. */
! 515: if (peer->ibuf)
! 516: stream_reset (peer->ibuf);
! 517: if (peer->work)
! 518: stream_reset (peer->work);
! 519: if (peer->obuf)
! 520: stream_fifo_clean (peer->obuf);
! 521:
! 522: /* Close of file descriptor. */
! 523: if (peer->fd >= 0)
! 524: {
! 525: close (peer->fd);
! 526: peer->fd = -1;
! 527: }
! 528:
! 529: for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
! 530: for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
! 531: {
! 532: /* Reset all negotiated variables */
! 533: peer->afc_nego[afi][safi] = 0;
! 534: peer->afc_adv[afi][safi] = 0;
! 535: peer->afc_recv[afi][safi] = 0;
! 536:
! 537: /* peer address family capability flags*/
! 538: peer->af_cap[afi][safi] = 0;
! 539:
! 540: /* peer address family status flags*/
! 541: peer->af_sflags[afi][safi] = 0;
! 542:
! 543: /* Received ORF prefix-filter */
! 544: peer->orf_plist[afi][safi] = NULL;
! 545:
! 546: /* ORF received prefix-filter pnt */
! 547: sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi);
! 548: prefix_bgp_orf_remove_all (orf_name);
! 549: }
! 550:
! 551: /* Reset keepalive and holdtime */
! 552: if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
! 553: {
! 554: peer->v_keepalive = peer->keepalive;
! 555: peer->v_holdtime = peer->holdtime;
! 556: }
! 557: else
! 558: {
! 559: peer->v_keepalive = peer->bgp->default_keepalive;
! 560: peer->v_holdtime = peer->bgp->default_holdtime;
! 561: }
! 562:
! 563: peer->update_time = 0;
! 564:
! 565: /* Until we are sure that there is no problem about prefix count
! 566: this should be commented out.*/
! 567: #if 0
! 568: /* Reset prefix count */
! 569: peer->pcount[AFI_IP][SAFI_UNICAST] = 0;
! 570: peer->pcount[AFI_IP][SAFI_MULTICAST] = 0;
! 571: peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0;
! 572: peer->pcount[AFI_IP6][SAFI_UNICAST] = 0;
! 573: peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0;
! 574: #endif /* 0 */
! 575:
! 576: return 0;
! 577: }
! 578:
! 579: /* BGP peer is stoped by the error. */
! 580: static int
! 581: bgp_stop_with_error (struct peer *peer)
! 582: {
! 583: /* Double start timer. */
! 584: peer->v_start *= 2;
! 585:
! 586: /* Overflow check. */
! 587: if (peer->v_start >= (60 * 2))
! 588: peer->v_start = (60 * 2);
! 589:
! 590: bgp_stop (peer);
! 591:
! 592: return 0;
! 593: }
! 594:
! 595: /* TCP connection open. Next we send open message to remote peer. And
! 596: add read thread for reading open message. */
! 597: static int
! 598: bgp_connect_success (struct peer *peer)
! 599: {
! 600: char buf1[BUFSIZ];
! 601:
! 602: if (peer->fd < 0)
! 603: {
! 604: zlog_err ("bgp_connect_success peer's fd is negative value %d",
! 605: peer->fd);
! 606: return -1;
! 607: }
! 608: BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
! 609:
! 610: if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
! 611: bgp_getsockname (peer);
! 612:
! 613: if (BGP_DEBUG (normal, NORMAL))
! 614: {
! 615: if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
! 616: zlog_debug ("%s open active, local address %s", peer->host,
! 617: sockunion2str (peer->su_local, buf1, SU_ADDRSTRLEN));
! 618: else
! 619: zlog_debug ("%s passive open", peer->host);
! 620: }
! 621:
! 622: if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
! 623: bgp_open_send (peer);
! 624:
! 625: return 0;
! 626: }
! 627:
! 628: /* TCP connect fail */
! 629: static int
! 630: bgp_connect_fail (struct peer *peer)
! 631: {
! 632: bgp_stop (peer);
! 633: return 0;
! 634: }
! 635:
! 636: /* This function is the first starting point of all BGP connection. It
! 637: try to connect to remote peer with non-blocking IO. */
! 638: int
! 639: bgp_start (struct peer *peer)
! 640: {
! 641: int status;
! 642:
! 643: if (BGP_PEER_START_SUPPRESSED (peer))
! 644: {
! 645: if (BGP_DEBUG (fsm, FSM))
! 646: plog_err (peer->log, "%s [FSM] Trying to start suppressed peer"
! 647: " - this is never supposed to happen!", peer->host);
! 648: return -1;
! 649: }
! 650:
! 651: /* Scrub some information that might be left over from a previous,
! 652: * session
! 653: */
! 654: /* Connection information. */
! 655: if (peer->su_local)
! 656: {
! 657: sockunion_free (peer->su_local);
! 658: peer->su_local = NULL;
! 659: }
! 660:
! 661: if (peer->su_remote)
! 662: {
! 663: sockunion_free (peer->su_remote);
! 664: peer->su_remote = NULL;
! 665: }
! 666:
! 667: /* Clear remote router-id. */
! 668: peer->remote_id.s_addr = 0;
! 669:
! 670: /* Clear peer capability flag. */
! 671: peer->cap = 0;
! 672:
! 673: /* If the peer is passive mode, force to move to Active mode. */
! 674: if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE))
! 675: {
! 676: BGP_EVENT_ADD (peer, TCP_connection_open_failed);
! 677: return 0;
! 678: }
! 679:
! 680: status = bgp_connect (peer);
! 681:
! 682: switch (status)
! 683: {
! 684: case connect_error:
! 685: if (BGP_DEBUG (fsm, FSM))
! 686: plog_debug (peer->log, "%s [FSM] Connect error", peer->host);
! 687: BGP_EVENT_ADD (peer, TCP_connection_open_failed);
! 688: break;
! 689: case connect_success:
! 690: if (BGP_DEBUG (fsm, FSM))
! 691: plog_debug (peer->log, "%s [FSM] Connect immediately success",
! 692: peer->host);
! 693: BGP_EVENT_ADD (peer, TCP_connection_open);
! 694: break;
! 695: case connect_in_progress:
! 696: /* To check nonblocking connect, we wait until socket is
! 697: readable or writable. */
! 698: if (BGP_DEBUG (fsm, FSM))
! 699: plog_debug (peer->log, "%s [FSM] Non blocking connect waiting result",
! 700: peer->host);
! 701: if (peer->fd < 0)
! 702: {
! 703: zlog_err ("bgp_start peer's fd is negative value %d",
! 704: peer->fd);
! 705: return -1;
! 706: }
! 707: BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
! 708: BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
! 709: break;
! 710: }
! 711: return 0;
! 712: }
! 713:
! 714: /* Connect retry timer is expired when the peer status is Connect. */
! 715: static int
! 716: bgp_reconnect (struct peer *peer)
! 717: {
! 718: bgp_stop (peer);
! 719: bgp_start (peer);
! 720: return 0;
! 721: }
! 722:
! 723: static int
! 724: bgp_fsm_open (struct peer *peer)
! 725: {
! 726: /* Send keepalive and make keepalive timer */
! 727: bgp_keepalive_send (peer);
! 728:
! 729: /* Reset holdtimer value. */
! 730: BGP_TIMER_OFF (peer->t_holdtime);
! 731:
! 732: return 0;
! 733: }
! 734:
! 735: /* Keepalive send to peer. */
! 736: static int
! 737: bgp_fsm_keepalive_expire (struct peer *peer)
! 738: {
! 739: bgp_keepalive_send (peer);
! 740: return 0;
! 741: }
! 742:
! 743: /* Hold timer expire. This is error of BGP connection. So cut the
! 744: peer and change to Idle status. */
! 745: static int
! 746: bgp_fsm_holdtime_expire (struct peer *peer)
! 747: {
! 748: if (BGP_DEBUG (fsm, FSM))
! 749: zlog (peer->log, LOG_DEBUG, "%s [FSM] Hold timer expire", peer->host);
! 750:
! 751: /* Send notify to remote peer. */
! 752: bgp_notify_send (peer, BGP_NOTIFY_HOLD_ERR, 0);
! 753:
! 754: /* Sweep if it is temporary peer. */
! 755: if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
! 756: {
! 757: zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host);
! 758: peer_delete (peer);
! 759: return -1;
! 760: }
! 761:
! 762: /* bgp_stop needs to be invoked while in Established state */
! 763: bgp_stop(peer);
! 764:
! 765: return 0;
! 766: }
! 767:
! 768: /* Status goes to Established. Send keepalive packet then make first
! 769: update information. */
! 770: static int
! 771: bgp_establish (struct peer *peer)
! 772: {
! 773: struct bgp_notify *notify;
! 774: afi_t afi;
! 775: safi_t safi;
! 776: int nsf_af_count = 0;
! 777:
! 778: /* Reset capability open status flag. */
! 779: if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
! 780: SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
! 781:
! 782: /* Clear last notification data. */
! 783: notify = &peer->notify;
! 784: if (notify->data)
! 785: XFREE (MTYPE_TMP, notify->data);
! 786: memset (notify, 0, sizeof (struct bgp_notify));
! 787:
! 788: /* Clear start timer value to default. */
! 789: peer->v_start = BGP_INIT_START_TIMER;
! 790:
! 791: /* Increment established count. */
! 792: peer->established++;
! 793: bgp_fsm_change_status (peer, Established);
! 794:
! 795: /* bgp log-neighbor-changes of neighbor Up */
! 796: if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
! 797: zlog_info ("%%ADJCHANGE: neighbor %s Up", peer->host);
! 798:
! 799: /* graceful restart */
! 800: UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
! 801: for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
! 802: for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
! 803: {
! 804: if (peer->afc_nego[afi][safi]
! 805: && CHECK_FLAG (peer->cap, PEER_CAP_RESTART_ADV)
! 806: && CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV))
! 807: {
! 808: if (peer->nsf[afi][safi]
! 809: && ! CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV))
! 810: bgp_clear_stale_route (peer, afi, safi);
! 811:
! 812: peer->nsf[afi][safi] = 1;
! 813: nsf_af_count++;
! 814: }
! 815: else
! 816: {
! 817: if (peer->nsf[afi][safi])
! 818: bgp_clear_stale_route (peer, afi, safi);
! 819: peer->nsf[afi][safi] = 0;
! 820: }
! 821: }
! 822:
! 823: if (nsf_af_count)
! 824: SET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
! 825: else
! 826: {
! 827: UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
! 828: if (peer->t_gr_stale)
! 829: {
! 830: BGP_TIMER_OFF (peer->t_gr_stale);
! 831: if (BGP_DEBUG (events, EVENTS))
! 832: zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
! 833: }
! 834: }
! 835:
! 836: if (peer->t_gr_restart)
! 837: {
! 838: BGP_TIMER_OFF (peer->t_gr_restart);
! 839: if (BGP_DEBUG (events, EVENTS))
! 840: zlog_debug ("%s graceful restart timer stopped", peer->host);
! 841: }
! 842:
! 843: #ifdef HAVE_SNMP
! 844: bgpTrapEstablished (peer);
! 845: #endif /* HAVE_SNMP */
! 846:
! 847: /* Reset uptime, send keepalive, send current table. */
! 848: peer->uptime = bgp_clock ();
! 849:
! 850: /* Send route-refresh when ORF is enabled */
! 851: for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
! 852: for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
! 853: if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV))
! 854: {
! 855: if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV))
! 856: bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX,
! 857: REFRESH_IMMEDIATE, 0);
! 858: else if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV))
! 859: bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX_OLD,
! 860: REFRESH_IMMEDIATE, 0);
! 861: }
! 862:
! 863: if (peer->v_keepalive)
! 864: bgp_keepalive_send (peer);
! 865:
! 866: /* First update is deferred until ORF or ROUTE-REFRESH is received */
! 867: for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
! 868: for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
! 869: if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV))
! 870: if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
! 871: || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))
! 872: SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH);
! 873:
! 874: bgp_announce_route_all (peer);
! 875:
! 876: BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1);
! 877:
! 878: return 0;
! 879: }
! 880:
! 881: /* Keepalive packet is received. */
! 882: static int
! 883: bgp_fsm_keepalive (struct peer *peer)
! 884: {
! 885: /* peer count update */
! 886: peer->keepalive_in++;
! 887:
! 888: BGP_TIMER_OFF (peer->t_holdtime);
! 889: return 0;
! 890: }
! 891:
! 892: /* Update packet is received. */
! 893: static int
! 894: bgp_fsm_update (struct peer *peer)
! 895: {
! 896: BGP_TIMER_OFF (peer->t_holdtime);
! 897: return 0;
! 898: }
! 899:
! 900: /* This is empty event. */
! 901: static int
! 902: bgp_ignore (struct peer *peer)
! 903: {
! 904: if (BGP_DEBUG (fsm, FSM))
! 905: zlog (peer->log, LOG_DEBUG, "%s [FSM] bgp_ignore called", peer->host);
! 906: return 0;
! 907: }
! 908:
! 909: /* Finite State Machine structure */
! 910: static const struct {
! 911: int (*func) (struct peer *);
! 912: int next_state;
! 913: } FSM [BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] =
! 914: {
! 915: {
! 916: /* Idle state: In Idle state, all events other than BGP_Start is
! 917: ignored. With BGP_Start event, finite state machine calls
! 918: bgp_start(). */
! 919: {bgp_start, Connect}, /* BGP_Start */
! 920: {bgp_stop, Idle}, /* BGP_Stop */
! 921: {bgp_stop, Idle}, /* TCP_connection_open */
! 922: {bgp_stop, Idle}, /* TCP_connection_closed */
! 923: {bgp_ignore, Idle}, /* TCP_connection_open_failed */
! 924: {bgp_stop, Idle}, /* TCP_fatal_error */
! 925: {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
! 926: {bgp_ignore, Idle}, /* Hold_Timer_expired */
! 927: {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
! 928: {bgp_ignore, Idle}, /* Receive_OPEN_message */
! 929: {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
! 930: {bgp_ignore, Idle}, /* Receive_UPDATE_message */
! 931: {bgp_ignore, Idle}, /* Receive_NOTIFICATION_message */
! 932: {bgp_ignore, Idle}, /* Clearing_Completed */
! 933: },
! 934: {
! 935: /* Connect */
! 936: {bgp_ignore, Connect}, /* BGP_Start */
! 937: {bgp_stop, Idle}, /* BGP_Stop */
! 938: {bgp_connect_success, OpenSent}, /* TCP_connection_open */
! 939: {bgp_stop, Idle}, /* TCP_connection_closed */
! 940: {bgp_connect_fail, Active}, /* TCP_connection_open_failed */
! 941: {bgp_connect_fail, Idle}, /* TCP_fatal_error */
! 942: {bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */
! 943: {bgp_ignore, Idle}, /* Hold_Timer_expired */
! 944: {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
! 945: {bgp_ignore, Idle}, /* Receive_OPEN_message */
! 946: {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
! 947: {bgp_ignore, Idle}, /* Receive_UPDATE_message */
! 948: {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */
! 949: {bgp_ignore, Idle}, /* Clearing_Completed */
! 950: },
! 951: {
! 952: /* Active, */
! 953: {bgp_ignore, Active}, /* BGP_Start */
! 954: {bgp_stop, Idle}, /* BGP_Stop */
! 955: {bgp_connect_success, OpenSent}, /* TCP_connection_open */
! 956: {bgp_stop, Idle}, /* TCP_connection_closed */
! 957: {bgp_ignore, Active}, /* TCP_connection_open_failed */
! 958: {bgp_ignore, Idle}, /* TCP_fatal_error */
! 959: {bgp_start, Connect}, /* ConnectRetry_timer_expired */
! 960: {bgp_ignore, Idle}, /* Hold_Timer_expired */
! 961: {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
! 962: {bgp_ignore, Idle}, /* Receive_OPEN_message */
! 963: {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
! 964: {bgp_ignore, Idle}, /* Receive_UPDATE_message */
! 965: {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
! 966: {bgp_ignore, Idle}, /* Clearing_Completed */
! 967: },
! 968: {
! 969: /* OpenSent, */
! 970: {bgp_ignore, OpenSent}, /* BGP_Start */
! 971: {bgp_stop, Idle}, /* BGP_Stop */
! 972: {bgp_stop, Active}, /* TCP_connection_open */
! 973: {bgp_stop, Active}, /* TCP_connection_closed */
! 974: {bgp_stop, Active}, /* TCP_connection_open_failed */
! 975: {bgp_stop, Active}, /* TCP_fatal_error */
! 976: {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
! 977: {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
! 978: {bgp_ignore, Idle}, /* KeepAlive_timer_expired */
! 979: {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */
! 980: {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */
! 981: {bgp_ignore, Idle}, /* Receive_UPDATE_message */
! 982: {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
! 983: {bgp_ignore, Idle}, /* Clearing_Completed */
! 984: },
! 985: {
! 986: /* OpenConfirm, */
! 987: {bgp_ignore, OpenConfirm}, /* BGP_Start */
! 988: {bgp_stop, Idle}, /* BGP_Stop */
! 989: {bgp_stop, Idle}, /* TCP_connection_open */
! 990: {bgp_stop, Idle}, /* TCP_connection_closed */
! 991: {bgp_stop, Idle}, /* TCP_connection_open_failed */
! 992: {bgp_stop, Idle}, /* TCP_fatal_error */
! 993: {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */
! 994: {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */
! 995: {bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */
! 996: {bgp_ignore, Idle}, /* Receive_OPEN_message */
! 997: {bgp_establish, Established}, /* Receive_KEEPALIVE_message */
! 998: {bgp_ignore, Idle}, /* Receive_UPDATE_message */
! 999: {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */
! 1000: {bgp_ignore, Idle}, /* Clearing_Completed */
! 1001: },
! 1002: {
! 1003: /* Established, */
! 1004: {bgp_ignore, Established}, /* BGP_Start */
! 1005: {bgp_stop, Clearing}, /* BGP_Stop */
! 1006: {bgp_stop, Clearing}, /* TCP_connection_open */
! 1007: {bgp_stop, Clearing}, /* TCP_connection_closed */
! 1008: {bgp_stop, Clearing}, /* TCP_connection_open_failed */
! 1009: {bgp_stop, Clearing}, /* TCP_fatal_error */
! 1010: {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
! 1011: {bgp_fsm_holdtime_expire, Clearing}, /* Hold_Timer_expired */
! 1012: {bgp_fsm_keepalive_expire, Established}, /* KeepAlive_timer_expired */
! 1013: {bgp_stop, Clearing}, /* Receive_OPEN_message */
! 1014: {bgp_fsm_keepalive, Established}, /* Receive_KEEPALIVE_message */
! 1015: {bgp_fsm_update, Established}, /* Receive_UPDATE_message */
! 1016: {bgp_stop_with_error, Clearing}, /* Receive_NOTIFICATION_message */
! 1017: {bgp_ignore, Idle}, /* Clearing_Completed */
! 1018: },
! 1019: {
! 1020: /* Clearing, */
! 1021: {bgp_ignore, Clearing}, /* BGP_Start */
! 1022: {bgp_stop, Clearing}, /* BGP_Stop */
! 1023: {bgp_stop, Clearing}, /* TCP_connection_open */
! 1024: {bgp_stop, Clearing}, /* TCP_connection_closed */
! 1025: {bgp_stop, Clearing}, /* TCP_connection_open_failed */
! 1026: {bgp_stop, Clearing}, /* TCP_fatal_error */
! 1027: {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */
! 1028: {bgp_stop, Clearing}, /* Hold_Timer_expired */
! 1029: {bgp_stop, Clearing}, /* KeepAlive_timer_expired */
! 1030: {bgp_stop, Clearing}, /* Receive_OPEN_message */
! 1031: {bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */
! 1032: {bgp_stop, Clearing}, /* Receive_UPDATE_message */
! 1033: {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */
! 1034: {bgp_clearing_completed, Idle}, /* Clearing_Completed */
! 1035: },
! 1036: {
! 1037: /* Deleted, */
! 1038: {bgp_ignore, Deleted}, /* BGP_Start */
! 1039: {bgp_ignore, Deleted}, /* BGP_Stop */
! 1040: {bgp_ignore, Deleted}, /* TCP_connection_open */
! 1041: {bgp_ignore, Deleted}, /* TCP_connection_closed */
! 1042: {bgp_ignore, Deleted}, /* TCP_connection_open_failed */
! 1043: {bgp_ignore, Deleted}, /* TCP_fatal_error */
! 1044: {bgp_ignore, Deleted}, /* ConnectRetry_timer_expired */
! 1045: {bgp_ignore, Deleted}, /* Hold_Timer_expired */
! 1046: {bgp_ignore, Deleted}, /* KeepAlive_timer_expired */
! 1047: {bgp_ignore, Deleted}, /* Receive_OPEN_message */
! 1048: {bgp_ignore, Deleted}, /* Receive_KEEPALIVE_message */
! 1049: {bgp_ignore, Deleted}, /* Receive_UPDATE_message */
! 1050: {bgp_ignore, Deleted}, /* Receive_NOTIFICATION_message */
! 1051: {bgp_ignore, Deleted}, /* Clearing_Completed */
! 1052: },
! 1053: };
! 1054:
! 1055: static const char *bgp_event_str[] =
! 1056: {
! 1057: NULL,
! 1058: "BGP_Start",
! 1059: "BGP_Stop",
! 1060: "TCP_connection_open",
! 1061: "TCP_connection_closed",
! 1062: "TCP_connection_open_failed",
! 1063: "TCP_fatal_error",
! 1064: "ConnectRetry_timer_expired",
! 1065: "Hold_Timer_expired",
! 1066: "KeepAlive_timer_expired",
! 1067: "Receive_OPEN_message",
! 1068: "Receive_KEEPALIVE_message",
! 1069: "Receive_UPDATE_message",
! 1070: "Receive_NOTIFICATION_message",
! 1071: "Clearing_Completed",
! 1072: };
! 1073:
! 1074: /* Execute event process. */
! 1075: int
! 1076: bgp_event (struct thread *thread)
! 1077: {
! 1078: int ret = 0;
! 1079: int event;
! 1080: int next;
! 1081: struct peer *peer;
! 1082:
! 1083: peer = THREAD_ARG (thread);
! 1084: event = THREAD_VAL (thread);
! 1085:
! 1086: /* Logging this event. */
! 1087: next = FSM [peer->status -1][event - 1].next_state;
! 1088:
! 1089: if (BGP_DEBUG (fsm, FSM) && peer->status != next)
! 1090: plog_debug (peer->log, "%s [FSM] %s (%s->%s)", peer->host,
! 1091: bgp_event_str[event],
! 1092: LOOKUP (bgp_status_msg, peer->status),
! 1093: LOOKUP (bgp_status_msg, next));
! 1094:
! 1095: /* Call function. */
! 1096: if (FSM [peer->status -1][event - 1].func)
! 1097: ret = (*(FSM [peer->status - 1][event - 1].func))(peer);
! 1098:
! 1099: /* When function do not want proceed next job return -1. */
! 1100: if (ret >= 0)
! 1101: {
! 1102: /* If status is changed. */
! 1103: if (next != peer->status)
! 1104: bgp_fsm_change_status (peer, next);
! 1105:
! 1106: /* Make sure timer is set. */
! 1107: bgp_timer_set (peer);
! 1108: }
! 1109:
! 1110: return ret;
! 1111: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>