* bgp_fsm.c, bgp_open.c, bgp_packet.c, bgp_route.[ch], bgp_vty.c,
bgpd.[ch]: Add BGP_INFO_STALE flag and end-of-rib support. "bgp
graceful-restart" commands added. Show numbers of individual
messages in "show ip bgp neighbor" command. Final pieces of graceful
restart.
[merge from GNU Zebra]
diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog
index 67da8ff..c867b9f 100644
--- a/bgpd/ChangeLog
+++ b/bgpd/ChangeLog
@@ -1,3 +1,11 @@
+2005-02-02 Akihiro Mizutani <mizutani@net-chef.net
+
+ * bgp_fsm.c, bgp_open.c, bgp_packet.c, bgp_route.[ch], bgp_vty.c,
+ bgpd.[ch]: Add BGP_INFO_STALE flag and end-of-rib support. "bgp
+ graceful-restart" commands added. Show numbers of individual
+ messages in "show ip bgp neighbor" command. Final pieces of graceful
+ restart.
+
2005-02-01 Akihiro Mizutani <mizutani@net-chef.net>
* bgp_open.c, bgp_packet.c, bgp_vty.c, bgpd.[ch]: Remove "no neighbor
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 7327db0..c8ca417 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -118,7 +118,8 @@
connect timer is expired, change status to Connect. */
BGP_TIMER_OFF (peer->t_start);
/* If peer is passive mode, do not set connect timer. */
- if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE))
+ if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)
+ || CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
{
BGP_TIMER_OFF (peer->t_connect);
}
@@ -331,9 +332,62 @@
"Peer-group delete member",
"Capability changed",
"Passive config change",
- "Multihop config change"
+ "Multihop config change",
+ "NSF peer closed the session"
};
+int
+bgp_graceful_restart_timer_expire (struct thread *thread)
+{
+ struct peer *peer;
+ afi_t afi;
+ safi_t safi;
+
+ peer = THREAD_ARG (thread);
+ peer->t_gr_restart = NULL;
+
+ /* NSF delete stale route */
+ for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
+ if (peer->nsf[afi][safi])
+ bgp_clear_stale_route (peer, afi, safi);
+
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
+ BGP_TIMER_OFF (peer->t_gr_stale);
+
+ if (BGP_DEBUG (events, EVENTS))
+ {
+ zlog_debug ("%s graceful restart timer expired", peer->host);
+ zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
+ }
+
+ bgp_timer_set (peer);
+
+ return 0;
+}
+
+int
+bgp_graceful_stale_timer_expire (struct thread *thread)
+{
+ struct peer *peer;
+ afi_t afi;
+ safi_t safi;
+
+ peer = THREAD_ARG (thread);
+ peer->t_gr_stale = NULL;
+
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart stalepath timer expired", peer->host);
+
+ /* NSF delete stale route */
+ for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
+ if (peer->nsf[afi][safi])
+ bgp_clear_stale_route (peer, afi, safi);
+
+ return 0;
+}
+
/* Administrative BGP peer stop event. */
int
bgp_stop (struct peer *peer)
@@ -353,6 +407,36 @@
zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host,
peer_down_str [(int) peer->last_reset]);
+ /* graceful restart */
+ if (peer->t_gr_stale)
+ {
+ BGP_TIMER_OFF (peer->t_gr_stale);
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
+ }
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
+ {
+ if (BGP_DEBUG (events, EVENTS))
+ {
+ zlog_debug ("%s graceful restart timer started for %d sec",
+ peer->host, peer->v_gr_restart);
+ zlog_debug ("%s graceful restart stalepath timer started for %d sec",
+ peer->host, peer->bgp->stalepath_time);
+ }
+ BGP_TIMER_ON (peer->t_gr_restart, bgp_graceful_restart_timer_expire,
+ peer->v_gr_restart);
+ BGP_TIMER_ON (peer->t_gr_stale, bgp_graceful_stale_timer_expire,
+ peer->bgp->stalepath_time);
+ }
+ else
+ {
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
+
+ for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
+ peer->nsf[afi][safi] = 0;
+ }
+
/* set last reset time */
peer->resettime = time (NULL);
/* Reset uptime. */
@@ -655,6 +739,7 @@
struct bgp_notify *notify;
afi_t afi;
safi_t safi;
+ int nsf_af_count = 0;
/* Reset capability open status flag. */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN))
@@ -677,6 +762,50 @@
if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
zlog_info ("%%ADJCHANGE: neighbor %s Up", peer->host);
+ /* graceful restart */
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
+ for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
+ {
+ if (peer->afc_nego[afi][safi]
+ && CHECK_FLAG (peer->cap, PEER_CAP_RESTART_ADV)
+ && CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV))
+ {
+ if (peer->nsf[afi][safi]
+ && ! CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV))
+ bgp_clear_stale_route (peer, afi, safi);
+
+ peer->nsf[afi][safi] = 1;
+ nsf_af_count++;
+ }
+ else
+ {
+ if (peer->nsf[afi][safi])
+ bgp_clear_stale_route (peer, afi, safi);
+ peer->nsf[afi][safi] = 0;
+ }
+ }
+
+ if (nsf_af_count)
+ SET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
+ else
+ {
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
+ if (peer->t_gr_stale)
+ {
+ BGP_TIMER_OFF (peer->t_gr_stale);
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
+ }
+ }
+
+ if (peer->t_gr_restart)
+ {
+ BGP_TIMER_OFF (peer->t_gr_restart);
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart timer stopped", peer->host);
+ }
+
#ifdef HAVE_SNMP
bgpTrapEstablished (peer);
#endif /* HAVE_SNMP */
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 8321bcf..7250383 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -401,7 +401,6 @@
struct graceful_restart_af graf;
u_int16_t restart_flag_time;
int restart_bit = 0;
- int forwarding_bit = 0;
u_char *restart_pnt;
u_char *restart_end;
@@ -418,15 +417,15 @@
restart_flag_time = ntohs(cap.mpc.afi);
if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
restart_bit = 1;
- UNSET_FLAG (restart_flag_time, 0xF000);
- peer->restart_time_rcv = restart_flag_time;
+ UNSET_FLAG (restart_flag_time, 0xF000);
+ peer->v_gr_restart = restart_flag_time;
if (BGP_DEBUG (normal, NORMAL))
{
zlog_debug ("%s OPEN has Graceful Restart capability", peer->host);
zlog_debug ("%s Peer has%srestarted. Restart Time : %d",
peer->host, restart_bit ? " " : " not ",
- peer->restart_time_rcv);
+ peer->v_gr_restart);
}
restart_pnt = pnt + 4;
@@ -440,7 +439,7 @@
safi = graf.safi;
if (CHECK_FLAG (graf.flag, RESTART_F_BIT))
- forwarding_bit = 1;
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
if (strcmp (afi_safi_print (afi, safi), "Unknown") == 0)
{
@@ -458,12 +457,13 @@
{
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s Address family %s is%spreserved", peer->host,
- afi_safi_print (afi, safi), forwarding_bit ? " " : " not ");
+ afi_safi_print (afi, safi),
+ CHECK_FLAG (peer->af_cap[afi][safi],
+ PEER_CAP_RESTART_AF_PRESERVE_RCV)
+ ? " " : " not ");
- if (forwarding_bit)
SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
}
- forwarding_bit = 0;
restart_pnt += 4;
}
}
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 854b32c..201ffbb 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -46,6 +46,7 @@
#include "bgpd/bgp_network.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_advertise.h"
+#include "bgpd/bgp_vty.h"
int stream_put_prefix (struct stream *, struct prefix *);
@@ -243,7 +244,50 @@
return packet;
}
return NULL;
+}
+struct stream *
+bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct stream *s;
+ struct stream *packet;
+
+#ifdef DISABLE_BGP_ANNOUNCE
+ return;
+#endif /* DISABLE_BGP_ANNOUNCE */
+
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("send End-of-RIB for %s to %s", afi_safi_print (afi, safi), peer->host);
+
+ s = stream_new (BGP_MAX_PACKET_SIZE);
+
+ /* Make BGP update packet. */
+ bgp_packet_set_marker (s, BGP_MSG_UPDATE);
+
+ /* Unfeasible Routes Length */
+ stream_putw (s, 0);
+
+ if (afi == AFI_IP && safi == SAFI_UNICAST)
+ {
+ /* Total Path Attribute Length */
+ stream_putw (s, 0);
+ }
+ else
+ {
+ /* Total Path Attribute Length */
+ stream_putw (s, 6);
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+ stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
+ stream_putc (s, 3);
+ stream_putw (s, afi);
+ stream_putc (s, safi);
+ }
+
+ bgp_packet_set_size (s);
+ packet = bgp_packet_dup (s);
+ bgp_packet_add (peer, packet);
+ stream_free (s);
+ return packet;
}
/* Make BGP withdraw packet. */
@@ -504,11 +548,34 @@
if (adv)
{
if (adv->binfo && adv->binfo->uptime < peer->synctime)
- s = bgp_update_packet (peer, afi, safi);
+ {
+ if (CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_RCV)
+ && CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_ADV)
+ && ! CHECK_FLAG (adv->binfo->flags, BGP_INFO_STALE)
+ && safi != SAFI_MPLS_VPN)
+ {
+ if (CHECK_FLAG (adv->binfo->peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_RECEIVED))
+ s = bgp_update_packet (peer, afi, safi);
+ }
+ else
+ s = bgp_update_packet (peer, afi, safi);
+ }
if (s)
return s;
}
+
+ if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV))
+ {
+ if (peer->afc_nego[afi][safi] && peer->synctime
+ && ! CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND)
+ && safi != SAFI_MPLS_VPN)
+ {
+ SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND);
+ return bgp_update_packet_eor (peer, afi, safi);
+ }
+ }
}
return NULL;
@@ -1192,13 +1259,24 @@
/* Hack part. */
if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
{
- if (ret == 0 && realpeer->status != Active
- && realpeer->status != OpenSent
- && realpeer->status != OpenConfirm)
+ if (realpeer->status == Established
+ && CHECK_FLAG (realpeer->sflags, PEER_STATUS_NSF_MODE))
+ {
+ realpeer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
+ SET_FLAG (realpeer->sflags, PEER_STATUS_NSF_WAIT);
+ }
+ else if (ret == 0 && realpeer->status != Active
+ && realpeer->status != OpenSent
+ && realpeer->status != OpenConfirm)
+
{
if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s [Event] peer's status is %s close connection",
- realpeer->host, LOOKUP (bgp_status_msg, peer->status));
+ zlog_debug ("%s peer status is %s close connection",
+ realpeer->host, LOOKUP (bgp_status_msg,
+ realpeer->status));
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONNECT_REJECT);
+
return -1;
}
@@ -1524,8 +1602,14 @@
if (! attribute_len && ! withdraw_len)
{
/* End-of-RIB received */
+ SET_FLAG (peer->af_sflags[AFI_IP][SAFI_UNICAST],
+ PEER_STATUS_EOR_RECEIVED);
- if (BGP_DEBUG (update, UPDATE_IN))
+ /* NSF delete stale route */
+ if (peer->nsf[AFI_IP][SAFI_UNICAST])
+ bgp_clear_stale_route (peer, AFI_IP, SAFI_UNICAST);
+
+ if (BGP_DEBUG (normal, NORMAL))
zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Unicast from %s",
peer->host);
}
@@ -1542,14 +1626,20 @@
&& mp_withdraw.safi == SAFI_MULTICAST)
bgp_nlri_parse (peer, NULL, &mp_withdraw);
- if (attribute_len == 6 && ! withdraw_len
+ if (! withdraw_len
&& mp_withdraw.afi == AFI_IP
&& mp_withdraw.safi == SAFI_MULTICAST
&& mp_withdraw.length == 0)
{
/* End-of-RIB received */
+ SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST],
+ PEER_STATUS_EOR_RECEIVED);
- if (BGP_DEBUG (update, UPDATE_IN))
+ /* NSF delete stale route */
+ if (peer->nsf[AFI_IP][SAFI_MULTICAST])
+ bgp_clear_stale_route (peer, AFI_IP, SAFI_MULTICAST);
+
+ if (BGP_DEBUG (normal, NORMAL))
zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Multicast from %s",
peer->host);
}
@@ -1566,14 +1656,19 @@
&& mp_withdraw.safi == SAFI_UNICAST)
bgp_nlri_parse (peer, NULL, &mp_withdraw);
- if (attribute_len == 6 && ! withdraw_len
+ if (! withdraw_len
&& mp_withdraw.afi == AFI_IP6
&& mp_withdraw.safi == SAFI_UNICAST
&& mp_withdraw.length == 0)
{
/* End-of-RIB received */
+ SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED);
- if (BGP_DEBUG (update, UPDATE_IN))
+ /* NSF delete stale route */
+ if (peer->nsf[AFI_IP6][SAFI_UNICAST])
+ bgp_clear_stale_route (peer, AFI_IP6, SAFI_UNICAST);
+
+ if (BGP_DEBUG (normal, NORMAL))
zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Unicast from %s",
peer->host);
}
@@ -1590,13 +1685,17 @@
&& mp_withdraw.safi == SAFI_MULTICAST)
bgp_nlri_parse (peer, NULL, &mp_withdraw);
- if (attribute_len == 6 && ! withdraw_len
+ if (! withdraw_len
&& mp_withdraw.afi == AFI_IP6
&& mp_withdraw.safi == SAFI_MULTICAST
&& mp_withdraw.length == 0)
{
/* End-of-RIB received */
+ /* NSF delete stale route */
+ if (peer->nsf[AFI_IP6][SAFI_MULTICAST])
+ bgp_clear_stale_route (peer, AFI_IP6, SAFI_MULTICAST);
+
if (BGP_DEBUG (update, UPDATE_IN))
zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Multicast from %s",
peer->host);
@@ -1614,7 +1713,7 @@
&& mp_withdraw.safi == BGP_SAFI_VPNV4)
bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw);
- if (attribute_len == 6 && ! withdraw_len
+ if (! withdraw_len
&& mp_withdraw.afi == AFI_IP
&& mp_withdraw.safi == BGP_SAFI_VPNV4
&& mp_withdraw.length == 0)
@@ -2080,6 +2179,18 @@
plog_err (peer->log, "%s [Error] bgp_read_packet error: %s",
peer->host, safe_strerror (errno));
+
+ if (peer->status == Established)
+ {
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE))
+ {
+ peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
+ SET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
+ }
+ else
+ peer->last_reset = PEER_DOWN_CLOSE_SESSION;
+ }
+
BGP_EVENT_ADD (peer, TCP_fatal_error);
return -1;
}
@@ -2092,7 +2203,15 @@
peer->host, peer->fd);
if (peer->status == Established)
- peer->last_reset = PEER_DOWN_CLOSE_SESSION;
+ {
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE))
+ {
+ peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
+ SET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
+ }
+ else
+ peer->last_reset = PEER_DOWN_CLOSE_SESSION;
+ }
BGP_EVENT_ADD (peer, TCP_connection_closed);
return -1;
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 2e7f7b3..2453cff 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1393,7 +1393,8 @@
if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY) &&
rn->table->type == BGP_TABLE_MAIN)
{
- peer->pcount[afi][safi]--;
+ if (! CHECK_FLAG (ri->flags, BGP_INFO_STALE))
+ peer->pcount[afi][safi]--;
bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi);
}
@@ -1780,6 +1781,13 @@
peer->host,
inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
p->prefixlen);
+
+ /* graceful restart STALE flag unset. */
+ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
+ {
+ UNSET_FLAG (ri->flags, BGP_INFO_STALE);
+ peer->pcount[afi][safi]++;
+ }
}
bgp_unlock_node (rn);
@@ -1794,6 +1802,13 @@
inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
p->prefixlen);
+ /* graceful restart STALE flag unset. */
+ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
+ {
+ UNSET_FLAG (ri->flags, BGP_INFO_STALE);
+ peer->pcount[afi][safi]++;
+ }
+
/* The attribute is changed. */
SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
@@ -2255,7 +2270,18 @@
for (ri = rn->info; ri; ri = ri->next)
if (ri->peer == peer)
{
- bgp_rib_remove (rn, ri, peer, afi, safi);
+ /* graceful restart STALE flag set. */
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)
+ && peer->nsf[afi][safi]
+ && ! CHECK_FLAG (ri->flags, BGP_INFO_STALE)
+ && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)
+ && ! CHECK_FLAG (ri->flags, BGP_INFO_DAMPED))
+ {
+ SET_FLAG (ri->flags, BGP_INFO_STALE);
+ peer->pcount[afi][safi]--;
+ }
+ else
+ bgp_rib_remove (rn, ri, peer, afi, safi);
break;
}
for (ain = rn->adj_in; ain; ain = ain->next)
@@ -2327,6 +2353,27 @@
break;
}
}
+
+void
+bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct bgp_node *rn;
+ struct bgp_info *ri;
+ struct bgp_table *table;
+
+ table = peer->bgp->rib[afi][safi];
+
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ {
+ for (ri = rn->info; ri; ri = ri->next)
+ if (ri->peer == peer)
+ {
+ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
+ bgp_rib_remove (rn, ri, peer, afi, safi);
+ break;
+ }
+ }
+}
/* Delete all kernel routes. */
void
@@ -4725,7 +4772,9 @@
struct attr *attr;
/* Route status display. */
- if (binfo->suppress)
+ if (CHECK_FLAG (binfo->flags, BGP_INFO_STALE))
+ vty_out (vty, "S");
+ else if (binfo->suppress)
vty_out (vty, "s");
else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
vty_out (vty, "*");
@@ -5106,26 +5155,19 @@
aspath_print_vty (vty, attr->aspath);
}
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)
- || CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)
- || CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)
- || CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)
- || CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
- {
- vty_out (vty, ",");
-
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))
- vty_out (vty, " (aggregated by %d %s)", attr->aggregator_as,
- inet_ntoa (attr->aggregator_addr));
- if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
- vty_out (vty, " (Received from a RR-client)");
- if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
- vty_out (vty, " (Received from a RS-client)");
- if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
- vty_out (vty, " (history entry)");
- else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
- vty_out (vty, " (suppressed due to dampening)");
- }
+ if (CHECK_FLAG (binfo->flags, BGP_INFO_STALE))
+ vty_out (vty, ", (stale)");
+ if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)))
+ vty_out (vty, ", (aggregated by %d %s)", attr->aggregator_as,
+ inet_ntoa (attr->aggregator_addr));
+ if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
+ vty_out (vty, ", (Received from a RR-client)");
+ if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
+ vty_out (vty, ", (Received from a RS-client)");
+ if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
+ vty_out (vty, ", (history entry)");
+ else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
+ vty_out (vty, ", (suppressed due to dampening)");
vty_out (vty, "%s", VTY_NEWLINE);
/* Line2 display Next-hop, Neighbor, Router-id */
@@ -5251,6 +5293,8 @@
vty_out (vty, "%s", VTY_NEWLINE);
}
+#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal,%s r RIB-failure, S Stale%s"
+#define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s"
#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s"
#define BGP_SHOW_DAMP_HEADER " Network From Reuse Path%s"
#define BGP_SHOW_FLAP_HEADER " Network From Flaps Duration Reuse Path%s"
@@ -5449,9 +5493,9 @@
if (header)
{
- vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (*router_id), VTY_NEWLINE);
- vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE);
- vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (*router_id), VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
if (type == bgp_show_type_dampend_paths
|| type == bgp_show_type_damp_neighbor)
vty_out (vty, BGP_SHOW_DAMP_HEADER, VTY_NEWLINE);
@@ -8114,8 +8158,8 @@
PEER_STATUS_DEFAULT_ORIGINATE))
{
vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
- vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE);
- vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
vty_out (vty, "Originating default network 0.0.0.0%s%s",
VTY_NEWLINE, VTY_NEWLINE);
@@ -8131,8 +8175,8 @@
if (header1)
{
vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
- vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE);
- vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
header1 = 0;
}
if (header2)
@@ -8155,8 +8199,8 @@
if (header1)
{
vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE);
- vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE);
- vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
header1 = 0;
}
if (header2)
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index e324ef0..46ae54d 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -36,7 +36,7 @@
#define BGP_ROUTE_REDISTRIBUTE 3
/* BGP information status. */
- u_char flags;
+ u_int16_t flags;
#define BGP_INFO_IGP_CHANGED (1 << 0)
#define BGP_INFO_DAMPED (1 << 1)
#define BGP_INFO_HISTORY (1 << 2)
@@ -45,6 +45,7 @@
#define BGP_INFO_ATTR_CHANGED (1 << 5)
#define BGP_INFO_DMED_CHECK (1 << 6)
#define BGP_INFO_DMED_SELECTED (1 << 7)
+#define BGP_INFO_STALE (1 << 8)
/* Peer structure. */
struct peer *peer;
@@ -134,6 +135,7 @@
void bgp_clear_route (struct peer *, afi_t, safi_t);
void bgp_clear_route_all (struct peer *);
void bgp_clear_adj_in (struct peer *, afi_t, safi_t);
+void bgp_clear_stale_route (struct peer *, afi_t, safi_t);
int bgp_nlri_sanity_check (struct peer *, int, u_char *, bgp_size_t);
int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index be57c12..8ee47c7 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -806,6 +806,53 @@
return CMD_SUCCESS;
}
+DEFUN (bgp_graceful_restart_stalepath_time,
+ bgp_graceful_restart_stalepath_time_cmd,
+ "bgp graceful-restart stalepath-time <1-3600>",
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Set the max time to hold onto restarting peer's stale paths\n"
+ "Delay value (seconds)\n")
+{
+ struct bgp *bgp;
+ u_int32_t stalepath;
+
+ bgp = vty->index;
+ if (! bgp)
+ return CMD_WARNING;
+
+ VTY_GET_INTEGER_RANGE ("stalepath-time", stalepath, argv[0], 1, 3600);
+ bgp->stalepath_time = stalepath;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_graceful_restart_stalepath_time,
+ no_bgp_graceful_restart_stalepath_time_cmd,
+ "no bgp graceful-restart stalepath-time",
+ NO_STR
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Set the max time to hold onto restarting peer's stale paths\n")
+{
+ struct bgp *bgp;
+
+ bgp = vty->index;
+ if (! bgp)
+ return CMD_WARNING;
+
+ bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME;
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_bgp_graceful_restart_stalepath_time,
+ no_bgp_graceful_restart_stalepath_time_val_cmd,
+ "no bgp graceful-restart stalepath-time <1-3600>",
+ NO_STR
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Set the max time to hold onto restarting peer's stale paths\n"
+ "Delay value (seconds)\n")
+
/* "bgp fast-external-failover" configuration. */
DEFUN (bgp_fast_external_failover,
bgp_fast_external_failover_cmd,
@@ -6950,6 +6997,13 @@
if (p->status == Established)
vty_out (vty, ", up for %8s",
peer_uptime (p->uptime, timebuf, BGP_UPTIME_LEN));
+ else if (p->status == Active)
+ {
+ if (CHECK_FLAG (p->flags, PEER_FLAG_PASSIVE))
+ vty_out (vty, " (passive)");
+ else if (CHECK_FLAG (p->sflags, PEER_STATUS_NSF_WAIT))
+ vty_out (vty, " (NSF passive)");
+ }
vty_out (vty, "%s", VTY_NEWLINE);
/* read timer */
@@ -6964,7 +7018,7 @@
vty_out (vty, ", keepalive interval is %d seconds%s",
p->keepalive, VTY_NEWLINE);
}
-
+
/* Capability. */
if (p->status == Established)
{
@@ -7046,17 +7100,19 @@
int restart_af_count = 0;
vty_out (vty, " Remote Restart timer is %d seconds%s",
- p->restart_time_rcv, VTY_NEWLINE);
- vty_out (vty, " Address families preserved by peer:%s ", VTY_NEWLINE);
+ p->v_gr_restart, VTY_NEWLINE);
+ vty_out (vty, " Address families by peer:%s ", VTY_NEWLINE);
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV))
{
- vty_out (vty, "%s%s", restart_af_count ? ", " : "",
- afi_safi_print (afi, safi));
+ vty_out (vty, "%s%s(%s)", restart_af_count ? ", " : "",
+ afi_safi_print (afi, safi),
+ CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV) ?
+ "preserved" : "not preserved");
restart_af_count++;
- }
+ }
if (! restart_af_count)
vty_out (vty, "none");
vty_out (vty, "%s", VTY_NEWLINE);
@@ -7065,15 +7121,67 @@
}
}
+ /* graceful restart information */
+ if (CHECK_FLAG (p->cap, PEER_CAP_RESTART_RCV)
+ || p->t_gr_restart
+ || p->t_gr_stale)
+ {
+ int eor_send_af_count = 0;
+ int eor_receive_af_count = 0;
+
+ vty_out (vty, " Graceful restart informations:%s", VTY_NEWLINE);
+ if (p->status == Established)
+ {
+ vty_out (vty, " End-of-RIB send: ");
+ for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
+ if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_EOR_SEND))
+ {
+ vty_out (vty, "%s%s", eor_send_af_count ? ", " : "",
+ afi_safi_print (afi, safi));
+ eor_send_af_count++;
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_out (vty, " End-of-RIB received: ");
+ for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
+ if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED))
+ {
+ vty_out (vty, "%s%s", eor_receive_af_count ? ", " : "",
+ afi_safi_print (afi, safi));
+ eor_receive_af_count++;
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+
+ if (p->t_gr_restart)
+ {
+ vty_out (vty, " The remaining time of restart timer is %ld%s",
+ thread_timer_remain_second (p->t_gr_restart), VTY_NEWLINE);
+ }
+ if (p->t_gr_stale)
+ {
+ vty_out (vty, " The remaining time of stalepath timer is %ld%s",
+ thread_timer_remain_second (p->t_gr_stale), VTY_NEWLINE);
+ }
+ }
+
/* Packet counts. */
- vty_out(vty, " Received %d messages, %d notifications, %d in queue%s",
- p->open_in + p->update_in + p->keepalive_in + p->refresh_in
- + p->dynamic_cap_in, p->notify_in, 0, VTY_NEWLINE);
- vty_out(vty, " Sent %d messages, %d notifications, %ld in queue%s",
- p->open_out + p->update_out + p->keepalive_out + p->refresh_out
- + p->dynamic_cap_out, p->notify_out, p->obuf->count, VTY_NEWLINE);
- vty_out(vty, " Route refresh request: received %d, sent %d%s",
- p->refresh_in, p->refresh_out, VTY_NEWLINE);
+ vty_out (vty, " Message statistics:%s", VTY_NEWLINE);
+ vty_out (vty, " Inq depth is 0%s", VTY_NEWLINE);
+ vty_out (vty, " Outq depth is %ld%s", p->obuf->count, VTY_NEWLINE);
+ vty_out (vty, " Sent Rcvd%s", VTY_NEWLINE);
+ vty_out (vty, " Opens: %10d %10d%s", p->open_out, p->open_in, VTY_NEWLINE);
+ vty_out (vty, " Notifications: %10d %10d%s", p->notify_out, p->notify_in, VTY_NEWLINE);
+ vty_out (vty, " Updates: %10d %10d%s", p->update_out, p->update_in, VTY_NEWLINE);
+ vty_out (vty, " Keepalives: %10d %10d%s", p->keepalive_out, p->keepalive_in, VTY_NEWLINE);
+ vty_out (vty, " Route Refresh: %10d %10d%s", p->refresh_out, p->refresh_in, VTY_NEWLINE);
+ vty_out (vty, " Capability: %10d %10d%s", p->dynamic_cap_out, p->dynamic_cap_in, VTY_NEWLINE);
+ vty_out (vty, " Total: %10d %10d%s", p->open_out + p->notify_out +
+ p->update_out + p->keepalive_out + p->refresh_out + p->dynamic_cap_out,
+ p->open_in + p->notify_in + p->update_in + p->keepalive_in + p->refresh_in +
+ p->dynamic_cap_in, VTY_NEWLINE);
/* advertisement-interval */
vty_out (vty, " Minimum time between advertisement runs is %d seconds%s",
@@ -7136,11 +7244,9 @@
/* Local address. */
if (p->su_local)
{
- vty_out (vty, "Local host: %s, Local port: %d%s%s",
+ vty_out (vty, "Local host: %s, Local port: %d%s",
sockunion2str (p->su_local, buf1, SU_ADDRSTRLEN),
ntohs (p->su_local->sin.sin_port),
- CHECK_FLAG (p->flags, PEER_FLAG_PASSIVE) ?
- ", passive-mode" : "",
VTY_NEWLINE);
}
@@ -8480,11 +8586,12 @@
install_element (BGP_NODE, &bgp_deterministic_med_cmd);
install_element (BGP_NODE, &no_bgp_deterministic_med_cmd);
-#if 0
/* "bgp graceful-restart" commands */
install_element (BGP_NODE, &bgp_graceful_restart_cmd);
install_element (BGP_NODE, &no_bgp_graceful_restart_cmd);
-#endif /* 0 */
+ install_element (BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd);
+ install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd);
+ install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_val_cmd);
/* "bgp fast-external-failover" commands */
install_element (BGP_NODE, &bgp_fast_external_failover_cmd);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 1a50476..279c546 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1040,6 +1040,34 @@
return 0;
}
+void
+peer_nsf_stop (struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
+ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
+
+ for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
+ peer->nsf[afi][safi] = 0;
+
+ if (peer->t_gr_restart)
+ {
+ BGP_TIMER_OFF (peer->t_gr_restart);
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart timer stopped", peer->host);
+ }
+ if (peer->t_gr_stale)
+ {
+ BGP_TIMER_OFF (peer->t_gr_stale);
+ if (BGP_DEBUG (events, EVENTS))
+ zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
+ }
+ bgp_clear_route_all (peer);
+}
+
/* Delete peer from confguration. */
int
peer_delete (struct peer *peer)
@@ -1052,6 +1080,9 @@
bgp = peer->bgp;
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
+ peer_nsf_stop (peer);
+
/* If this peer belongs to peer group. Clearn up the
relationship. */
if (peer->group)
@@ -1075,6 +1106,8 @@
BGP_TIMER_OFF (peer->t_asorig);
BGP_TIMER_OFF (peer->t_routeadv);
BGP_TIMER_OFF (peer->t_pmax_restart);
+ BGP_TIMER_OFF (peer->t_gr_restart);
+ BGP_TIMER_OFF (peer->t_gr_stale);
/* Delete from all peer list. */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
@@ -2148,6 +2181,9 @@
{
if (CHECK_FLAG (peer->flags, flag))
{
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
+ peer_nsf_stop (peer);
+
UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
if (peer->t_pmax_restart)
{
@@ -2157,6 +2193,9 @@
peer->host);
}
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
+ peer_nsf_stop (peer);
+
if (peer->status == Established)
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
@@ -4703,6 +4742,9 @@
vty_out (vty, " bgp deterministic-med%s", VTY_NEWLINE);
/* BGP graceful-restart. */
+ if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME)
+ vty_out (vty, " bgp graceful-restart stalepath-time %d%s",
+ bgp->stalepath_time, VTY_NEWLINE);
if (bgp_flag_check (bgp, BGP_FLAG_GRACEFUL_RESTART))
vty_out (vty, " bgp graceful-restart%s", VTY_NEWLINE);
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index e14a8ad..f8a3627 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -142,8 +142,8 @@
u_int32_t default_keepalive;
/* BGP graceful restart */
- u_int16_t restart_time;
- u_int16_t stalepath_time;
+ u_int32_t restart_time;
+ u_int32_t stalepath_time;
};
/* BGP peer-group support. */
@@ -318,10 +318,8 @@
#define PEER_CAP_ORF_PREFIX_RM_RCV (1 << 3) /* receive-mode received */
#define PEER_CAP_ORF_PREFIX_SM_OLD_RCV (1 << 4) /* send-mode received */
#define PEER_CAP_ORF_PREFIX_RM_OLD_RCV (1 << 5) /* receive-mode received */
-#define PEER_CAP_RESTART_AF_RCV (1 << 6) /* graceful restart received */
-
- /* Gracefull Restart */
- u_int16_t restart_time_rcv;
+#define PEER_CAP_RESTART_AF_RCV (1 << 6) /* graceful restart afi/safi received */
+#define PEER_CAP_RESTART_AF_PRESERVE_RCV (1 << 7) /* graceful restart afi/safi F-bit received */
/* Global configuration flags. */
u_int32_t flags;
@@ -334,6 +332,9 @@
#define PEER_FLAG_ENFORCE_MULTIHOP (1 << 6) /* enforce-multihop */
#define PEER_FLAG_LOCAL_AS_NO_PREPEND (1 << 7) /* local-as no-prepend */
+ /* NSF mode (graceful restart) */
+ u_char nsf[AFI_MAX][SAFI_MAX];
+
/* Per AF configuration flags. */
u_int32_t af_flags[AFI_MAX][SAFI_MAX];
#define PEER_FLAG_SEND_COMMUNITY (1 << 0) /* send-community */
@@ -368,6 +369,8 @@
#define PEER_STATUS_CAPABILITY_OPEN (1 << 2) /* capability open send */
#define PEER_STATUS_HAVE_ACCEPT (1 << 3) /* accept peer's parent */
#define PEER_STATUS_GROUP (1 << 4) /* peer-group conf */
+#define PEER_STATUS_NSF_MODE (1 << 5) /* NSF aware peer */
+#define PEER_STATUS_NSF_WAIT (1 << 6) /* wait comeback peer */
/* Peer status af flags (reset in bgp_stop) */
u_int16_t af_sflags[AFI_MAX][SAFI_MAX];
@@ -376,6 +379,8 @@
#define PEER_STATUS_DEFAULT_ORIGINATE (1 << 2) /* default-originate peer */
#define PEER_STATUS_PREFIX_THRESHOLD (1 << 3) /* exceed prefix-threshold */
#define PEER_STATUS_PREFIX_LIMIT (1 << 4) /* exceed prefix-limit */
+#define PEER_STATUS_EOR_SEND (1 << 5) /* end-of-rib send to peer */
+#define PEER_STATUS_EOR_RECEIVED (1 << 6) /* end-of-rib received from peer */
/* Default attribute value for the peer. */
@@ -398,6 +403,7 @@
u_int32_t v_asorig;
u_int32_t v_routeadv;
u_int32_t v_pmax_restart;
+ u_int32_t v_gr_restart;
/* Threads. */
struct thread *t_read;
@@ -409,6 +415,8 @@
struct thread *t_asorig;
struct thread *t_routeadv;
struct thread *t_pmax_restart;
+ struct thread *t_gr_restart;
+ struct thread *t_gr_stale;
/* Statistics field */
u_int32_t open_in; /* Open message input count */
@@ -486,6 +494,7 @@
#define PEER_DOWN_CAPABILITY_CHANGE 19 /* neighbor capability command */
#define PEER_DOWN_PASSIVE_CHANGE 20 /* neighbor passive command */
#define PEER_DOWN_MULTIHOP_CHANGE 21 /* neighbor multihop command */
+#define PEER_DOWN_NSF_CLOSE_SESSION 22 /* NSF tcp session close */
/* The kind of route-map Flags.*/
u_char rmap_type;
@@ -893,3 +902,5 @@
int peer_clear (struct peer *);
int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type);
+
+void peer_nsf_stop (struct peer *);