* 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 *);