]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #5737 from mjstapp/zebra_disable_kern_nhs
authorRuss White <russ@riw.us>
Tue, 4 Feb 2020 13:12:34 +0000 (08:12 -0500)
committerGitHub <noreply@github.com>
Tue, 4 Feb 2020 13:12:34 +0000 (08:12 -0500)
zebra: add config to disable use of kernel nexthops

51 files changed:
bfdd/bfd.h
bfdd/bfd_packet.c
bfdd/bfdd.c
bfdd/config.c
bfdd/control.c
bfdd/log.c [deleted file]
bfdd/subdir.am
bgpd/bgp_debug.c
bgpd/bgp_debug.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_fsm.c
bgpd/bgp_fsm.h
bgpd/bgp_io.c
bgpd/bgp_main.c
bgpd/bgp_network.c
bgpd/bgp_open.c
bgpd/bgp_packet.c
bgpd/bgp_packet.h
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_table.c
bgpd/bgp_table.h
bgpd/bgp_vty.c
bgpd/bgp_vty.h
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
bgpd/bgpd.c
bgpd/bgpd.h
doc/developer/packaging-redhat.rst
doc/user/bgp.rst
doc/user/ospf6d.rst
doc/user/ospfd.rst
doc/user/vtysh.rst
doc/user/zebra.rst
lib/command.h
lib/prefix.c
lib/prefix.h
lib/zclient.c
lib/zclient.h
redhat/frr.spec.in
tests/bgpd/test_mpath.c
tools/generate_support_bundle.py
vtysh/vtysh.c
zebra/debug.c
zebra/rt_netlink.c
zebra/zapi_msg.c
zebra/zebra_nhg.c
zebra/zebra_nhg.h
zebra/zebra_nhg_private.h
zebra/zebra_pbr.c
zebra/zebra_vty.c

index 97702aab547df662300bdbcf3789c4549a92a948..2ae74d7880b1074e104e96ccd483ee0f65e4e1ae 100644 (file)
@@ -427,27 +427,20 @@ void pl_free(struct peer_label *pl);
 
 
 /*
- * log.c
- *
- * Contains code that does the logging procedures. Might implement multiple
- * backends (e.g. zebra log, syslog or other logging lib).
+ * logging - alias to zebra log
  */
-enum blog_level {
-       /* level vs syslog equivalent */
-       BLOG_DEBUG = 0,   /* LOG_DEBUG */
-       BLOG_INFO = 1,    /* LOG_INFO */
-       BLOG_WARNING = 2, /* LOG_WARNING */
-       BLOG_ERROR = 3,   /* LOG_ERR */
-       BLOG_FATAL = 4,   /* LOG_CRIT */
-};
 
-void log_init(int foreground, enum blog_level level,
-             struct frr_daemon_info *fdi);
-void log_info(const char *fmt, ...);
-void log_debug(const char *fmt, ...);
-void log_warning(const char *fmt, ...);
-void log_error(const char *fmt, ...);
-void log_fatal(const char *fmt, ...);
+#define log_debug      zlog_debug
+#define log_info       zlog_info
+#define log_warning    zlog_warn
+#define log_error      zlog_err
+
+#define log_fatal(msg, ...)                                                    \
+       do {                                                                   \
+               zlog_err(msg, ## __VA_ARGS__);                                 \
+               assert(!msg);                                                  \
+               abort();                                                       \
+       } while (0)
 
 
 /*
index 6da5e2cdf9efad3a4fd3030d6c0d903738a56032..1ec761e3b875bcffc24622df121a71de412d4806 100644 (file)
@@ -116,7 +116,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
                return -1;
        }
        if (rv < (ssize_t)datalen)
-               log_debug("packet-send: send partial", strerror(errno));
+               log_debug("packet-send: send partial: %s", strerror(errno));
 
        return 0;
 }
@@ -799,7 +799,7 @@ int bp_udp_send(int sd, uint8_t ttl, uint8_t *data, size_t datalen,
                log_debug("udp-send: loopback failure: (%d) %s", errno, strerror(errno));
                return -1;
        } else if (wlen < (ssize_t)datalen) {
-               log_debug("udp-send: partial send: %ld expected %ld", wlen,
+               log_debug("udp-send: partial send: %zd expected %zu", wlen,
                          datalen);
                return -1;
        }
index 341edbe5cd3e9bebf3e673cb3600135a4fd31443..69f268ab016e811207c82b322145ea1945db5220 100644 (file)
@@ -216,15 +216,12 @@ int main(int argc, char *argv[])
        parse_config(conf);
 #endif
 
-       /* Initialize logging API. */
-       log_init(1, BLOG_DEBUG, &bfdd_di);
+       /* Initialize FRR infrastructure. */
+       master = frr_init();
 
        /* Initialize control socket. */
        control_init(ctl_path);
 
-       /* Initialize FRR infrastructure. */
-       master = frr_init();
-
        /* Initialize BFD data structures. */
        bfd_initialize();
 
index 0c0bac0aaa3150e99522cbf5be19c1ae26bb43d4..dd4a1926942bd66c41d618e825fbd448977d6d29 100644 (file)
@@ -215,7 +215,8 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc)
                        if (strlcpy(bpc->bpc_localif, sval,
                                    sizeof(bpc->bpc_localif))
                            > sizeof(bpc->bpc_localif)) {
-                               log_debug("\tlocal-interface: %s (truncated)");
+                               log_debug("\tlocal-interface: %s (truncated)",
+                                         sval);
                                error++;
                        } else {
                                log_debug("\tlocal-interface: %s", sval);
@@ -235,7 +236,7 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc)
                        bpc->bpc_detectmultiplier =
                                json_object_get_int64(jo_val);
                        bpc->bpc_has_detectmultiplier = true;
-                       log_debug("\tdetect-multiplier: %llu",
+                       log_debug("\tdetect-multiplier: %u",
                                  bpc->bpc_detectmultiplier);
                } else if (strcmp(key, "receive-interval") == 0) {
                        bpc->bpc_recvinterval = json_object_get_int64(jo_val);
index 5c5421c041057bba33cdea79b924b6b525225b93..cf821f45b88f472f81c1711fe4725a74ddc67486 100644 (file)
@@ -471,7 +471,7 @@ static int control_read(struct thread *t)
        bcb->bcb_buf = XMALLOC(MTYPE_BFDD_NOTIFICATION,
                               sizeof(bcm) + bcb->bcb_left + 1);
        if (bcb->bcb_buf == NULL) {
-               log_warning("%s: not enough memory for message size: %u",
+               log_warning("%s: not enough memory for message size: %zu",
                            __func__, bcb->bcb_left);
                control_free(bcs);
                return 0;
diff --git a/bfdd/log.c b/bfdd/log.c
deleted file mode 100644 (file)
index d81d7cd..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*********************************************************************
- * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * log.c: implements an abstraction between loggers interface. Implement all
- * log backends in this file.
- *
- * Authors
- * -------
- * Rafael Zalamena <rzalamena@opensourcerouting.org>
- */
-
-#include <zebra.h>
-
-#include "bfd.h"
-
-#include "lib/log_int.h"
-
-void log_msg(int level, const char *fmt, va_list vl);
-
-
-static int log_fg;
-static int log_level = BLOG_DEBUG;
-
-void log_init(int foreground, enum blog_level level,
-             struct frr_daemon_info *fdi)
-{
-       log_fg = foreground;
-       log_level = level;
-
-       openzlog(fdi->progname, fdi->logname, 0,
-                LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
-}
-
-void log_msg(int level, const char *fmt, va_list vl)
-{
-       if (level < log_level)
-               return;
-
-       switch (level) {
-       case BLOG_DEBUG:
-               vzlog(LOG_DEBUG, fmt, vl);
-               break;
-
-       case BLOG_INFO:
-               vzlog(LOG_INFO, fmt, vl);
-               break;
-
-       case BLOG_WARNING:
-               vzlog(LOG_WARNING, fmt, vl);
-               break;
-
-       case BLOG_ERROR:
-               vzlog(LOG_ERR, fmt, vl);
-               break;
-
-       case BLOG_FATAL:
-               vzlog(LOG_EMERG, fmt, vl);
-               break;
-
-       default:
-               vfprintf(stderr, fmt, vl);
-               break;
-       }
-}
-
-void log_info(const char *fmt, ...)
-{
-       va_list vl;
-
-       va_start(vl, fmt);
-       log_msg(BLOG_INFO, fmt, vl);
-       va_end(vl);
-}
-
-void log_debug(const char *fmt, ...)
-{
-       va_list vl;
-
-       va_start(vl, fmt);
-       log_msg(BLOG_DEBUG, fmt, vl);
-       va_end(vl);
-}
-
-void log_error(const char *fmt, ...)
-{
-       va_list vl;
-
-       va_start(vl, fmt);
-       log_msg(BLOG_ERROR, fmt, vl);
-       va_end(vl);
-}
-
-void log_warning(const char *fmt, ...)
-{
-       va_list vl;
-
-       va_start(vl, fmt);
-       log_msg(BLOG_WARNING, fmt, vl);
-       va_end(vl);
-}
-
-void log_fatal(const char *fmt, ...)
-{
-       va_list vl;
-
-       va_start(vl, fmt);
-       log_msg(BLOG_FATAL, fmt, vl);
-       va_end(vl);
-
-       exit(1);
-}
index 9aa522f3f076b31cfa6ddf7e17bb0d00be909379..254329e221aeec056ce49478b471a4d06ea3d980 100644 (file)
@@ -22,7 +22,6 @@ bfdd_libbfd_a_SOURCES = \
        bfdd/config.c \
        bfdd/control.c \
        bfdd/event.c \
-       bfdd/log.c \
        bfdd/ptm_adapter.c \
        # end
 
index f716c4f308654beb7d7ee8d2275597262b173f17..498a871ce7e9ac6834be0ee562ede3ea20dcf209 100644 (file)
@@ -63,6 +63,7 @@ unsigned long conf_bgp_debug_vpn;
 unsigned long conf_bgp_debug_flowspec;
 unsigned long conf_bgp_debug_labelpool;
 unsigned long conf_bgp_debug_pbr;
+unsigned long conf_bgp_debug_graceful_restart;
 
 unsigned long term_bgp_debug_as4;
 unsigned long term_bgp_debug_neighbor_events;
@@ -80,6 +81,7 @@ unsigned long term_bgp_debug_vpn;
 unsigned long term_bgp_debug_flowspec;
 unsigned long term_bgp_debug_labelpool;
 unsigned long term_bgp_debug_pbr;
+unsigned long term_bgp_debug_graceful_restart;
 
 struct list *bgp_debug_neighbor_events_peers = NULL;
 struct list *bgp_debug_keepalive_peers = NULL;
@@ -1644,6 +1646,23 @@ DEFUN (debug_bgp_zebra,
        return CMD_SUCCESS;
 }
 
+DEFUN (debug_bgp_graceful_restart,
+       debug_bgp_graceful_restart_cmd,
+       "debug bgp graceful-restart",
+       DEBUG_STR
+       BGP_STR
+       GR_DEBUG)
+{
+       if (vty->node == CONFIG_NODE) {
+               DEBUG_ON(graceful_restart, GRACEFUL_RESTART);
+       } else {
+               TERM_DEBUG_ON(graceful_restart, GRACEFUL_RESTART);
+               vty_out(vty, "BGP Graceful Restart debugging is on\n");
+       }
+       return CMD_SUCCESS;
+}
+
+
 DEFUN (debug_bgp_zebra_prefix,
        debug_bgp_zebra_prefix_cmd,
        "debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>",
@@ -1702,6 +1721,23 @@ DEFUN (no_debug_bgp_zebra,
        return CMD_SUCCESS;
 }
 
+DEFUN (no_debug_bgp_graceful_restart,
+       no_debug_bgp_graceful_restart_cmd,
+       "no debug bgp graceful-restart",
+       DEBUG_STR
+       BGP_STR
+       GR_DEBUG
+       NO_STR)
+{
+       if (vty->node == CONFIG_NODE) {
+               DEBUG_OFF(graceful_restart, GRACEFUL_RESTART);
+       } else {
+               TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART);
+               vty_out(vty, "BGP Graceful Restart debugging is off\n");
+       }
+       return CMD_SUCCESS;
+}
+
 DEFUN (no_debug_bgp_zebra_prefix,
        no_debug_bgp_zebra_prefix_cmd,
        "no debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>",
@@ -2039,6 +2075,8 @@ DEFUN (no_debug_bgp,
        TERM_DEBUG_OFF(labelpool, LABELPOOL);
        TERM_DEBUG_OFF(pbr, PBR);
        TERM_DEBUG_OFF(pbr, PBR_ERROR);
+       TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART);
+
        vty_out(vty, "All possible debugging has been turned off\n");
 
        return CMD_SUCCESS;
@@ -2094,7 +2132,11 @@ DEFUN_NOSH (show_debugging_bgp,
 
        if (BGP_DEBUG(zebra, ZEBRA))
                bgp_debug_list_print(vty, "  BGP zebra debugging is on",
-                                    bgp_debug_zebra_prefixes);
+                                       bgp_debug_zebra_prefixes);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               vty_out(vty,
+                       "  BGP graceful-restart debugging is on");
 
        if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS))
                vty_out(vty, "  BGP allow martian next hop debugging is on\n");
@@ -2229,6 +2271,11 @@ static int bgp_config_write_debug(struct vty *vty)
                vty_out(vty, "debug bgp pbr error\n");
                write++;
        }
+
+       if (CONF_BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) {
+               vty_out(vty, "debug bgp graceful-restart\n");
+               write++;
+       }
        return write;
 }
 
@@ -2262,6 +2309,9 @@ void bgp_debug_init(void)
        install_element(ENABLE_NODE, &debug_bgp_bestpath_prefix_cmd);
        install_element(CONFIG_NODE, &debug_bgp_bestpath_prefix_cmd);
 
+       install_element(ENABLE_NODE, &debug_bgp_graceful_restart_cmd);
+       install_element(CONFIG_NODE, &debug_bgp_graceful_restart_cmd);
+
        /* debug bgp updates (in|out) */
        install_element(ENABLE_NODE, &debug_bgp_update_direct_cmd);
        install_element(CONFIG_NODE, &debug_bgp_update_direct_cmd);
@@ -2327,6 +2377,9 @@ void bgp_debug_init(void)
        install_element(ENABLE_NODE, &no_debug_bgp_bestpath_prefix_cmd);
        install_element(CONFIG_NODE, &no_debug_bgp_bestpath_prefix_cmd);
 
+       install_element(ENABLE_NODE, &no_debug_bgp_graceful_restart_cmd);
+       install_element(CONFIG_NODE, &no_debug_bgp_graceful_restart_cmd);
+
        install_element(ENABLE_NODE, &debug_bgp_vpn_cmd);
        install_element(CONFIG_NODE, &debug_bgp_vpn_cmd);
        install_element(ENABLE_NODE, &no_debug_bgp_vpn_cmd);
index e1072c3df25116c2922ef89ab91f7c8de11e1014..1e6482e9693672c80804924350610ca96ab3ce61 100644 (file)
@@ -76,6 +76,7 @@ extern unsigned long conf_bgp_debug_vpn;
 extern unsigned long conf_bgp_debug_flowspec;
 extern unsigned long conf_bgp_debug_labelpool;
 extern unsigned long conf_bgp_debug_pbr;
+extern unsigned long conf_bgp_debug_graceful_restart;
 
 extern unsigned long term_bgp_debug_as4;
 extern unsigned long term_bgp_debug_neighbor_events;
@@ -91,6 +92,7 @@ extern unsigned long term_bgp_debug_vpn;
 extern unsigned long term_bgp_debug_flowspec;
 extern unsigned long term_bgp_debug_labelpool;
 extern unsigned long term_bgp_debug_pbr;
+extern unsigned long term_bgp_debug_graceful_restart;
 
 extern struct list *bgp_debug_neighbor_events_peers;
 extern struct list *bgp_debug_keepalive_peers;
@@ -131,6 +133,8 @@ struct bgp_debug_filter {
 #define BGP_DEBUG_PACKET_SEND         0x01
 #define BGP_DEBUG_PACKET_SEND_DETAIL  0x02
 
+#define BGP_DEBUG_GRACEFUL_RESTART     0x01
+
 #define CONF_DEBUG_ON(a, b)    (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b))
 #define CONF_DEBUG_OFF(a, b)   (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b))
 
index 125ed61e74664f99271ca03cad107a314944cbce..44a884830a7a07d2627d493463168636cabcbf01 100644 (file)
@@ -687,14 +687,22 @@ static void show_esi_routes(struct bgp *bgp,
                        add_prefix_to_json = 1;
                }
 
-               if (json && add_prefix_to_json) {
-                       json_object_string_add(json_prefix, "prefix",
-                                              prefix_str);
-                       json_object_int_add(json_prefix, "prefixLen",
-                                           rn->p.prefixlen);
-                       json_object_object_add(json_prefix, "paths",
-                                              json_paths);
-                       json_object_object_add(json, prefix_str, json_prefix);
+               if (json) {
+                       if (add_prefix_to_json) {
+                               json_object_string_add(json_prefix, "prefix",
+                                                      prefix_str);
+                               json_object_int_add(json_prefix, "prefixLen",
+                                                   rn->p.prefixlen);
+                               json_object_object_add(json_prefix, "paths",
+                                                      json_paths);
+                               json_object_object_add(json, prefix_str,
+                                                      json_prefix);
+                       } else {
+                               json_object_free(json_paths);
+                               json_object_free(json_prefix);
+                               json_paths = NULL;
+                               json_prefix = NULL;
+                       }
                }
        }
 
@@ -786,14 +794,22 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
                        add_prefix_to_json = 1;
                }
 
-               if (json && add_prefix_to_json) {
-                       json_object_string_add(json_prefix, "prefix",
-                                              prefix_str);
-                       json_object_int_add(json_prefix, "prefixLen",
-                                           rn->p.prefixlen);
-                       json_object_object_add(json_prefix, "paths",
-                                              json_paths);
-                       json_object_object_add(json, prefix_str, json_prefix);
+               if (json) {
+                       if (add_prefix_to_json) {
+                               json_object_string_add(json_prefix, "prefix",
+                                                      prefix_str);
+                               json_object_int_add(json_prefix, "prefixLen",
+                                                   rn->p.prefixlen);
+                               json_object_object_add(json_prefix, "paths",
+                                                      json_paths);
+                               json_object_object_add(json, prefix_str,
+                                                      json_prefix);
+                       } else {
+                               json_object_free(json_paths);
+                               json_object_free(json_prefix);
+                               json_paths = NULL;
+                               json_prefix = NULL;
+                       }
                }
        }
 
index 3667dae83d164df70054b335843b00fb08e4416f..da8e6a907bac1338f90ec5d25ce53fcce7cbeb9c 100644 (file)
@@ -35,7 +35,7 @@
 #include "filter.h"
 #include "command.h"
 #include "lib_errors.h"
-
+#include "zclient.h"
 #include "lib/json.h"
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_attr.h"
@@ -58,7 +58,8 @@
 
 DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer))
 DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer))
-
+extern const char *get_afi_safi_str(afi_t afi,
+                       safi_t safi, bool for_json);
 /* Definition of display strings corresponding to FSM events. This should be
  * kept consistent with the events defined in bgpd.h
  */
@@ -250,6 +251,24 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
        peer->remote_id = from_peer->remote_id;
        peer->last_reset = from_peer->last_reset;
 
+       peer->peer_gr_present_state = from_peer->peer_gr_present_state;
+       peer->peer_gr_new_status_flag = from_peer->peer_gr_new_status_flag;
+       bgp_peer_gr_flags_update(peer);
+
+       BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(
+                       peer->bgp,
+                       peer->bgp->peer);
+
+       if (bgp_peer_gr_mode_get(peer) == PEER_DISABLE) {
+
+               UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
+
+               if (CHECK_FLAG(peer->sflags,
+                                       PEER_STATUS_NSF_WAIT)) {
+                       peer_nsf_stop(peer);
+               }
+       }
+
        if (from_peer->hostname != NULL) {
                if (peer->hostname) {
                        XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
@@ -613,6 +632,34 @@ static int bgp_graceful_stale_timer_expire(struct thread *thread)
        return 0;
 }
 
+/* Selection deferral timer processing function */
+static int bgp_graceful_deferral_timer_expire(struct thread *thread)
+{
+       struct afi_safi_info *info;
+       afi_t afi;
+       safi_t safi;
+       struct bgp *bgp;
+
+       info = THREAD_ARG(thread);
+       afi = info->afi;
+       safi = info->safi;
+       bgp = info->bgp;
+
+       if (BGP_DEBUG(update, UPDATE_OUT))
+               zlog_debug(
+                       "afi %d, safi %d : graceful restart deferral timer expired",
+                       afi, safi);
+
+       bgp->gr_info[afi][safi].t_select_deferral = NULL;
+
+       bgp->gr_info[afi][safi].eor_required = 0;
+       bgp->gr_info[afi][safi].eor_received = 0;
+       XFREE(MTYPE_TMP, info);
+
+       /* Best path selection */
+       return bgp_best_path_select_defer(bgp, afi, safi);
+}
+
 static int bgp_update_delay_applicable(struct bgp *bgp)
 {
        /* update_delay_over flag should be reset (set to 0) for any new
@@ -1076,6 +1123,10 @@ int bgp_stop(struct peer *peer)
        safi_t safi;
        char orf_name[BUFSIZ];
        int ret = 0;
+       struct bgp *bgp = peer->bgp;
+       struct graceful_restart_info *gr_info = NULL;
+
+       peer->nsf_af_count = 0;
 
        if (peer_dynamic_neighbor(peer)
            && !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) {
@@ -1098,6 +1149,7 @@ int bgp_stop(struct peer *peer)
                /* bgp log-neighbor-changes of neighbor Down */
                if (bgp_flag_check(peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) {
                        struct vrf *vrf = vrf_lookup_by_id(peer->bgp->vrf_id);
+
                        zlog_info(
                                "%%ADJCHANGE: neighbor %s(%s) in vrf %s Down %s",
                                peer->host,
@@ -1141,6 +1193,38 @@ int bgp_stop(struct peer *peer)
                                        peer->nsf[afi][safi] = 0;
                }
 
+               /* If peer reset before receiving EOR, decrement EOR count and
+                * cancel the selection deferral timer if there are no
+                * pending EOR messages to be received
+                */
+               if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)) {
+                       FOREACH_AFI_SAFI (afi, safi) {
+                               if (!peer->afc_nego[afi][safi]
+                                   || CHECK_FLAG(peer->af_sflags[afi][safi],
+                                                 PEER_STATUS_EOR_RECEIVED))
+                                       continue;
+
+                               gr_info = &bgp->gr_info[afi][safi];
+                               if (!gr_info)
+                                       continue;
+
+                               if (gr_info->eor_required)
+                                       gr_info->eor_required--;
+
+                               if (BGP_DEBUG(update, UPDATE_OUT))
+                                       zlog_debug("peer %s, EOR_required %d",
+                                                  peer->host,
+                                                  gr_info->eor_required);
+
+                               /* There is no pending EOR message */
+                               if (gr_info->eor_required == 0) {
+                                       BGP_TIMER_OFF(
+                                               gr_info->t_select_deferral);
+                                       gr_info->eor_received = 0;
+                               }
+                       }
+               }
+
                /* set last reset time */
                peer->resettime = peer->uptime = bgp_clock();
 
@@ -1249,7 +1333,6 @@ int bgp_stop(struct peer *peer)
        } else {
                bgp_peer_conf_if_to_su_update(peer);
        }
-
        return ret;
 }
 
@@ -1539,6 +1622,10 @@ static int bgp_reconnect(struct peer *peer)
        if (bgp_stop(peer) < 0)
                return -1;
 
+       /* Send graceful restart capabilty */
+       BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(
+                       peer->bgp, peer->bgp->peer);
+
        bgp_start(peer);
        return 0;
 }
@@ -1574,6 +1661,78 @@ static int bgp_fsm_holdtime_expire(struct peer *peer)
        return bgp_stop_with_notify(peer, BGP_NOTIFY_HOLD_ERR, 0);
 }
 
+/* Start the selection deferral timer thread for the specified AFI, SAFI */
+static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi,
+               struct graceful_restart_info *gr_info)
+{
+       struct afi_safi_info *thread_info;
+
+       /* If the deferral timer is active, then increment eor count */
+       if (gr_info->t_select_deferral) {
+               gr_info->eor_required++;
+               return 0;
+       }
+
+       /* Start the deferral timer when the first peer enabled for the graceful
+        * restart is established
+        */
+       if (gr_info->eor_required == 0) {
+               thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info));
+
+               thread_info->afi = afi;
+               thread_info->safi = safi;
+               thread_info->bgp = bgp;
+
+               thread_add_timer(bm->master, bgp_graceful_deferral_timer_expire,
+                                thread_info, bgp->select_defer_time,
+                                &gr_info->t_select_deferral);
+       }
+       gr_info->eor_required++;
+       /* Send message to RIB indicating route update pending */
+       if (gr_info->af_enabled[afi][safi] == false) {
+               gr_info->af_enabled[afi][safi] = true;
+               /* Send message to RIB */
+               bgp_zebra_update(afi, safi, bgp->vrf_id,
+                                ZEBRA_CLIENT_ROUTE_UPDATE_PENDING);
+       }
+       if (BGP_DEBUG(update, UPDATE_OUT))
+               zlog_debug("Started the deferral timer for %s eor_required %d",
+                               get_afi_safi_str(afi, safi, false),
+                               gr_info->eor_required);
+       return 0;
+}
+
+/* Update the graceful restart information for the specified AFI, SAFI */
+static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi)
+{
+       struct graceful_restart_info *gr_info;
+       struct bgp *bgp = peer->bgp;
+       int ret = 0;
+
+       if ((afi < AFI_IP) || (afi >= AFI_MAX)) {
+               if (BGP_DEBUG(update, UPDATE_OUT))
+                       zlog_debug("%s : invalid afi %d", __func__, afi);
+               return -1;
+       }
+
+       if ((safi < SAFI_UNICAST) || (safi > SAFI_MPLS_VPN)) {
+               if (BGP_DEBUG(update, UPDATE_OUT))
+                       zlog_debug("%s : invalid safi %d", __func__, safi);
+               return -1;
+       }
+
+       /* Restarting router */
+       if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) &&
+           BGP_PEER_RESTARTING_MODE(peer)) {
+               /* Check if the forwarding state is preserved */
+               if (bgp_flag_check(bgp, BGP_FLAG_GR_PRESERVE_FWD)) {
+                       gr_info = &(bgp->gr_info[afi][safi]);
+                       ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info);
+               }
+       }
+       return ret;
+}
+
 /**
  * Transition to Established state.
  *
@@ -1587,6 +1746,7 @@ static int bgp_establish(struct peer *peer)
        int nsf_af_count = 0;
        int ret = 0;
        struct peer *other;
+       int status;
 
        other = peer->doppelganger;
        peer = peer_xfer_conn(peer);
@@ -1626,6 +1786,14 @@ static int bgp_establish(struct peer *peer)
 
        /* graceful restart */
        UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
+       if (bgp_debug_neighbor_events(peer)) {
+               if (BGP_PEER_RESTARTING_MODE(peer))
+                       zlog_debug("peer %s BGP_RESTARTING_MODE",
+                                  peer->host);
+               else if (BGP_PEER_HELPER_MODE(peer))
+                       zlog_debug("peer %s BGP_HELPER_MODE",
+                                  peer->host);
+       }
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
                for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) {
                        if (peer->afc_nego[afi][safi]
@@ -1645,8 +1813,29 @@ static int bgp_establish(struct peer *peer)
                                        bgp_clear_stale_route(peer, afi, safi);
                                peer->nsf[afi][safi] = 0;
                        }
+                       /* Update the graceful restart information */
+                       if (peer->afc_nego[afi][safi]) {
+                               if (!BGP_SELECT_DEFER_DISABLE(peer->bgp)) {
+                                       status = bgp_update_gr_info(peer, afi,
+                                                                   safi);
+                                       if (status < 0)
+                                               zlog_err("Error in updating graceful restart for %s",
+                                                       get_afi_safi_str(afi,
+                                                       safi, false));
+                               } else {
+                                       if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(
+                                               peer) &&
+                                               BGP_PEER_RESTARTING_MODE(peer)
+                                               && bgp_flag_check(peer->bgp,
+                                               BGP_FLAG_GR_PRESERVE_FWD))
+                                               peer->bgp->gr_info[afi][safi]
+                                                       .eor_required++;
+                               }
+                       }
                }
 
+       peer->nsf_af_count = nsf_af_count;
+
        if (nsf_af_count)
                SET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
        else {
@@ -2063,3 +2252,493 @@ int bgp_event_update(struct peer *peer, int event)
 
        return ret;
 }
+/* BGP GR Code */
+
+int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp,
+                       enum global_mode global_new_state,
+                       enum global_mode global_old_state)
+{
+       struct peer *peer = {0};
+       struct listnode *node = {0};
+       struct listnode *nnode = {0};
+       enum peer_mode  peer_old_state = PEER_INVALID;
+
+       for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+
+               if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+                       zlog_debug(
+                       "%s [BGP_GR] Peer: (%s) :",
+                               __func__, peer->host);
+
+               peer_old_state = bgp_peer_gr_mode_get(peer);
+
+               if (peer_old_state == PEER_GLOBAL_INHERIT) {
+
+               /*
+                *Reset only these peers and send a
+                *new open message with the change capabilities.
+                *Considering the mode to be "global_new_state" and
+                *do all operation accordingly
+                */
+
+                       switch (global_new_state) {
+                       case GLOBAL_HELPER:
+                               BGP_PEER_GR_HELPER_ENABLE(peer);
+                               break;
+                       case GLOBAL_GR:
+                               BGP_PEER_GR_ENABLE(peer);
+                               break;
+                       case GLOBAL_DISABLE:
+                               BGP_PEER_GR_DISABLE(peer);
+                               break;
+                       case GLOBAL_INVALID:
+                               zlog_debug(
+                               "%s [BGP_GR] GLOBAL_INVALID",
+                               __func__);
+                               return BGP_ERR_GR_OPERATION_FAILED;
+                       }
+               }
+       }
+
+       bgp->global_gr_present_state = global_new_state;
+
+       return BGP_GR_SUCCESS;
+}
+
+int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd)
+{
+       enum global_mode global_new_state = GLOBAL_INVALID;
+       enum global_mode global_old_state = GLOBAL_INVALID;
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+               "%s [BGP_GR]START: global_gr_cmd :%s:",
+                       __func__, print_global_gr_cmd(global_gr_cmd));
+
+       global_old_state = bgp_global_gr_mode_get(bgp);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+               "[BGP_GR] global_old_gr_state :%s:",
+               print_global_gr_mode(global_old_state));
+
+       if (global_old_state != GLOBAL_INVALID) {
+               global_new_state =
+                       bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd];
+
+               if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+                       zlog_debug(
+                       "[BGP_GR] global_new_gr_state :%s:",
+                       print_global_gr_mode(global_new_state));
+       } else {
+               zlog_err(
+                       "%s [BGP_GR] global_old_state == GLOBAL_INVALID",
+                       __func__);
+               return BGP_ERR_GR_OPERATION_FAILED;
+       }
+
+       if (global_new_state == GLOBAL_INVALID) {
+               zlog_err(
+                       "%s [BGP_GR] global_new_state == GLOBAL_INVALID",
+                               __func__);
+               return BGP_ERR_GR_INVALID_CMD;
+       }
+       if (global_new_state == global_old_state) {
+               /* Trace msg */
+               if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+                       zlog_debug(
+                       "%s [BGP_GR] global_new_state == global_old_state :%s",
+                       __func__, print_global_gr_mode(global_new_state));
+               return BGP_GR_NO_OPERATION;
+       }
+
+       return bgp_gr_lookup_n_update_all_peer(bgp,
+                                       global_new_state,
+                                       global_old_state);
+}
+
+const char *print_peer_gr_mode(enum peer_mode pr_mode)
+{
+       const char *peer_gr_mode = NULL;
+
+       switch (pr_mode) {
+       case PEER_HELPER:
+               peer_gr_mode = "PEER_HELPER";
+               break;
+       case PEER_GR:
+               peer_gr_mode = "PEER_GR";
+               break;
+       case PEER_DISABLE:
+               peer_gr_mode = "PEER_DISABLE";
+               break;
+       case PEER_INVALID:
+               peer_gr_mode = "PEER_INVALID";
+               break;
+       case PEER_GLOBAL_INHERIT:
+               peer_gr_mode = "PEER_GLOBAL_INHERIT";
+               break;
+       }
+
+       return peer_gr_mode;
+}
+
+const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd)
+{
+       const char *peer_gr_cmd = NULL;
+
+       switch (pr_gr_cmd) {
+       case PEER_GR_CMD:
+               peer_gr_cmd = "PEER_GR_CMD";
+               break;
+       case NO_PEER_GR_CMD:
+               peer_gr_cmd = "NO_PEER_GR_CMD";
+               break;
+       case PEER_DISABLE_CMD:
+               peer_gr_cmd = "PEER_GR_CMD";
+               break;
+       case NO_PEER_DISABLE_CMD:
+               peer_gr_cmd = "NO_PEER_GR_CMD";
+               break;
+       case PEER_HELPER_CMD:
+               peer_gr_cmd = "PEER_HELPER_CMD";
+               break;
+       case NO_PEER_HELPER_CMD:
+               peer_gr_cmd = "NO_PEER_HELPER_CMD";
+               break;
+       }
+
+       return peer_gr_cmd;
+}
+
+const char *print_global_gr_mode(enum global_mode gl_mode)
+{
+       const char *global_gr_mode = NULL;
+
+       switch (gl_mode) {
+       case GLOBAL_HELPER:
+               global_gr_mode = "GLOBAL_HELPER";
+               break;
+       case GLOBAL_GR:
+               global_gr_mode = "GLOBAL_GR";
+               break;
+       case GLOBAL_DISABLE:
+               global_gr_mode = "GLOBAL_DISABLE";
+               break;
+       case GLOBAL_INVALID:
+               global_gr_mode = "GLOBAL_INVALID";
+               break;
+       }
+
+       return global_gr_mode;
+}
+
+const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd)
+{
+       const char *global_gr_cmd = NULL;
+
+       switch (gl_gr_cmd) {
+       case GLOBAL_GR_CMD:
+               global_gr_cmd = "GLOBAL_GR_CMD";
+               break;
+       case NO_GLOBAL_GR_CMD:
+               global_gr_cmd = "NO_GLOBAL_GR_CMD";
+               break;
+       case GLOBAL_DISABLE_CMD:
+               global_gr_cmd = "GLOBAL_DISABLE_CMD";
+               break;
+       case NO_GLOBAL_DISABLE_CMD:
+               global_gr_cmd = "NO_GLOBAL_DISABLE_CMD";
+               break;
+       }
+
+       return global_gr_cmd;
+}
+
+enum global_mode bgp_global_gr_mode_get(struct bgp *bgp)
+{
+       return bgp->global_gr_present_state;
+}
+
+enum peer_mode bgp_peer_gr_mode_get(struct peer *peer)
+{
+       return peer->peer_gr_present_state;
+}
+
+int bgp_neighbor_graceful_restart(struct peer *peer,
+                                               int peer_gr_cmd)
+{
+       enum peer_mode  peer_new_state = PEER_INVALID;
+       enum peer_mode  peer_old_state = PEER_INVALID;
+       struct bgp_peer_gr peer_state;
+       int result = BGP_GR_FAILURE;
+
+       /*
+        * fetch peer_old_state from peer structure also
+        * fetch global_old_state from bgp structure,
+        * peer had a back pointer to bgpo struct ;
+        */
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+               "%s [BGP_GR] START:Peer: (%s) : peer_gr_cmd :%s:",
+                 __func__, peer->host, print_peer_gr_cmd(peer_gr_cmd));
+
+       peer_old_state = bgp_peer_gr_mode_get(peer);
+
+       if (peer_old_state == PEER_INVALID) {
+               zlog_debug(
+                       "[BGP_GR] peer_old_state == Invalid state !");
+               return BGP_ERR_GR_OPERATION_FAILED;
+       }
+
+       peer_state = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd];
+       peer_new_state = peer_state.next_state;
+
+       if (peer_new_state == PEER_INVALID) {
+               zlog_debug(
+                       "[BGP_GR] Invalid bgp graceful restart command used !");
+               return BGP_ERR_GR_INVALID_CMD;
+       }
+
+       if (peer_new_state != peer_old_state) {
+               result = peer_state.action_fun(peer,
+                                               peer_old_state,
+                                               peer_new_state);
+       } else {
+               if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+                       zlog_debug(
+                       "[BGP_GR] peer_old_state == peer_new_state !");
+               return BGP_GR_NO_OPERATION;
+       }
+
+       if (result == BGP_GR_SUCCESS) {
+
+               /* Update the mode i.e peer_new_state into the peer structure */
+               peer->peer_gr_present_state = peer_new_state;
+               if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+                       zlog_debug("[BGP_GR] Succesfully change the state of the peer to : %s : !",
+                                       print_peer_gr_mode(peer_new_state));
+
+               return BGP_GR_SUCCESS;
+       }
+
+       return result;
+}
+
+unsigned int bgp_peer_gr_action(struct peer *peer,
+                               int old_peer_state, int new_peer_state)
+{
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "%s [BGP_GR] Move peer from old_peer_state :%s: to new_peer_state :%s: !!!!",
+                       __func__, print_peer_gr_mode(old_peer_state),
+                       print_peer_gr_mode(new_peer_state));
+
+       int bgp_gr_global_mode = GLOBAL_INVALID;
+       unsigned int ret = BGP_GR_FAILURE;
+
+       if (old_peer_state == new_peer_state) {
+       /* Nothing to do over here as the present and old state is the same */
+               return BGP_GR_NO_OPERATION;
+       }
+       if ((old_peer_state == PEER_INVALID) ||
+               (new_peer_state == PEER_INVALID)) {
+       /* something bad happend , print error message */
+               return BGP_ERR_GR_INVALID_CMD;
+       }
+
+       bgp_gr_global_mode = bgp_global_gr_mode_get(peer->bgp);
+
+       if ((old_peer_state == PEER_GLOBAL_INHERIT) &&
+               (new_peer_state != PEER_GLOBAL_INHERIT)) {
+
+               /* fetch the Mode running in the Global state machine
+                *from the bgp structure into a variable called
+                *bgp_gr_global_mode
+                */
+
+               /* Here we are checking if the
+                *1. peer_new_state == global_mode == helper_mode
+                *2. peer_new_state == global_mode == GR_mode
+                *3. peer_new_state == global_mode == disabled_mode
+                */
+
+               BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer);
+
+               if (new_peer_state == bgp_gr_global_mode) {
+               /*This is incremental updates i.e no tear down
+                *of the existing session
+                *as the peer is already working in the same mode.
+                */
+                       ret = BGP_GR_SUCCESS;
+               } else {
+                       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+                               zlog_debug(
+                                       "[BGP_GR] Peer state changed from :%s ",
+                                       print_peer_gr_mode(old_peer_state));
+
+                       bgp_peer_move_to_gr_mode(peer, new_peer_state);
+
+                       ret = BGP_GR_SUCCESS;
+               }
+       }
+       /* In the case below peer is going into Global inherit mode i.e.
+        * the peer would work as the mode configured at the global level
+        */
+       else if ((new_peer_state == PEER_GLOBAL_INHERIT) &&
+               (old_peer_state != PEER_GLOBAL_INHERIT)) {
+               /* Here in this case it would be destructive
+                * in all the cases except one case when,
+                * Global GR is configured Disabled
+                * and present_peer_state is not disable
+                */
+
+               BGP_PEER_GR_GLOBAL_INHERIT_SET(peer);
+
+               if (old_peer_state == bgp_gr_global_mode) {
+
+                       /* This is incremental updates
+                        *i.e no tear down of the existing session
+                        *as the peer is already working in the same mode.
+                        */
+                       ret = BGP_GR_SUCCESS;
+               } else {
+                       /*  Destructive always */
+                       /*  Tear down the old session
+                        *  and send the new capability
+                        *  as per the bgp_gr_global_mode
+                        */
+
+                       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+                               zlog_debug("[BGP_GR] Peer state changed from :%s",
+                                       print_peer_gr_mode(old_peer_state));
+
+                       bgp_peer_move_to_gr_mode(peer, bgp_gr_global_mode);
+
+                       ret = BGP_GR_SUCCESS;
+               }
+       } else {
+               /*
+                *This else case, it include all the cases except -->
+                *(new_peer_state != Peer_Global) &&
+                *( old_peer_state != Peer_Global )
+                */
+               if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+                       zlog_debug("[BGP_GR] Peer state changed from :%s",
+                                       print_peer_gr_mode(old_peer_state));
+
+               bgp_peer_move_to_gr_mode(peer, new_peer_state);
+
+               ret = BGP_GR_SUCCESS;
+       }
+
+       return ret;
+}
+
+inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state)
+
+{
+       int bgp_global_gr_mode = bgp_global_gr_mode_get(peer->bgp);
+
+       switch (new_state) {
+       case PEER_HELPER:
+               BGP_PEER_GR_HELPER_ENABLE(peer);
+               break;
+       case PEER_GR:
+               BGP_PEER_GR_ENABLE(peer);
+               break;
+       case PEER_DISABLE:
+               BGP_PEER_GR_DISABLE(peer);
+               break;
+       case PEER_GLOBAL_INHERIT:
+               BGP_PEER_GR_GLOBAL_INHERIT_SET(peer);
+
+               if (bgp_global_gr_mode == GLOBAL_HELPER) {
+                       BGP_PEER_GR_HELPER_ENABLE(peer);
+               } else if (bgp_global_gr_mode  == GLOBAL_GR) {
+                       BGP_PEER_GR_ENABLE(peer);
+               } else if (bgp_global_gr_mode == GLOBAL_DISABLE) {
+                       BGP_PEER_GR_DISABLE(peer);
+               } else {
+                       zlog_err(
+                       "[BGP_GR] Default switch inherit mode ::: SOMETHING IS WRONG !!!");
+               }
+               break;
+       default:
+               zlog_err("[BGP_GR] Default switch mode ::: SOMETHING IS WRONG !!!");
+               break;
+       }
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug("[BGP_GR] Peer state changed  --to-->  : %d : !",
+                                        new_state);
+}
+
+void bgp_peer_gr_flags_update(struct peer *peer)
+{
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "%s [BGP_GR] called !",
+                               __func__);
+       if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+               PEER_GRACEFUL_RESTART_NEW_STATE_HELPER))
+               SET_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART_HELPER);
+       else
+               UNSET_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART_HELPER);
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_HELPER : %s : !",
+                       peer->host,
+                       (CHECK_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART_HELPER) ?
+                               "Set" : "UnSet"));
+       if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+               PEER_GRACEFUL_RESTART_NEW_STATE_RESTART))
+               SET_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART);
+       else
+               UNSET_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART);
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART : %s : !",
+                       peer->host,
+                       (CHECK_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART) ?
+                               "Set" : "UnSet"));
+       if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+               PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT))
+               SET_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT);
+       else
+               UNSET_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT);
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+               "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT : %s : !",
+                       peer->host,
+                       (CHECK_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT) ?
+                        "Set" : "UnSet"));
+
+       if (!CHECK_FLAG(peer->flags,
+               PEER_FLAG_GRACEFUL_RESTART) &&
+               !CHECK_FLAG(peer->flags,
+                       PEER_FLAG_GRACEFUL_RESTART_HELPER)){
+               zlog_debug(
+                       "[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_MODE!",
+                       peer->host);
+
+               UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
+
+               if (CHECK_FLAG(peer->sflags,
+                               PEER_STATUS_NSF_WAIT)) {
+
+                       peer_nsf_stop(peer);
+                       zlog_debug(
+                               "[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_WAIT!",
+                               peer->host);
+               }
+       }
+}
index 6f955c71beea542eac43142edb34c1d825391bce..b6abaf3e9252f2da57e826ec116af4f2039a0081 100644 (file)
 #define FSM_PEER_TRANSFERRED    2
 #define FSM_PEER_TRANSITIONED   3
 
+#define BGP_PEER_GR_HELPER_ENABLE(peer)        \
+       do {            \
+               UNSET_FLAG( \
+                       peer->peer_gr_new_status_flag,          \
+                       PEER_GRACEFUL_RESTART_NEW_STATE_RESTART);       \
+               SET_FLAG( \
+                       peer->peer_gr_new_status_flag,  \
+                       PEER_GRACEFUL_RESTART_NEW_STATE_HELPER);\
+       } while (0)
+
+#define BGP_PEER_GR_ENABLE(peer)\
+       do {                            \
+               SET_FLAG(   \
+                       peer->peer_gr_new_status_flag,  \
+                       PEER_GRACEFUL_RESTART_NEW_STATE_RESTART); \
+               UNSET_FLAG( \
+                       peer->peer_gr_new_status_flag,  \
+                       PEER_GRACEFUL_RESTART_NEW_STATE_HELPER);\
+       } while (0)
+
+#define BGP_PEER_GR_DISABLE(peer)\
+       do {                            \
+               UNSET_FLAG( \
+                       peer->peer_gr_new_status_flag,  \
+                       PEER_GRACEFUL_RESTART_NEW_STATE_RESTART);\
+               UNSET_FLAG(\
+                       peer->peer_gr_new_status_flag, \
+                       PEER_GRACEFUL_RESTART_NEW_STATE_HELPER);\
+       } while (0)
+
+#define BGP_PEER_GR_GLOBAL_INHERIT_SET(peer) \
+                       SET_FLAG(peer->peer_gr_new_status_flag, \
+                               PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)
+
+#define BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer) \
+                       UNSET_FLAG(peer->peer_gr_new_status_flag, \
+                               PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)
+
+#define BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)                         \
+       (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) &&                 \
+        CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV))
+
+#define BGP_PEER_RESTARTING_MODE(peer)\
+       (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && \
+        CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV) &&     \
+        !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV))
+
+#define BGP_PEER_HELPER_MODE(peer)\
+       (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER) && \
+        CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV) &&           \
+        !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV))
+
 /* Prototypes. */
 extern void bgp_fsm_event_update(struct peer *peer, int valid);
 extern int bgp_event(struct thread *);
@@ -87,6 +139,29 @@ extern void bgp_start_routeadv(struct bgp *);
 extern void bgp_adjust_routeadv(struct peer *);
 
 #include "hook.h"
-DECLARE_HOOK(peer_backward_transition, (struct peer * peer), (peer))
+DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer))
+DECLARE_HOOK(peer_established, (struct peer *peer), (peer))
 
+int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd);
+int bgp_neighbor_graceful_restart(struct peer *peer,
+                       int peer_gr_cmd);
+unsigned int bgp_peer_gr_action(struct peer *peer,
+               int old_peer_state, int new_peer_state);
+void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state);
+unsigned int bgp_peer_gr_helper_enable(struct peer *peer);
+unsigned int bgp_peer_gr_enable(struct peer *peer);
+unsigned int bgp_peer_gr_global_inherit(struct peer *peer);
+unsigned int bgp_peer_gr_disable(struct peer *peer);
+enum peer_mode bgp_peer_gr_mode_get(struct peer *peer);
+enum global_mode bgp_global_gr_mode_get(struct bgp *bgp);
+enum peer_mode bgp_get_peer_gr_mode_from_flags(struct peer *peer);
+unsigned int bgp_peer_gr_global_inherit_unset(struct peer *peer);
+int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp,
+               enum global_mode global_new_state,
+               enum global_mode global_old_state);
+void bgp_peer_gr_flags_update(struct peer *peer);
+const char *print_peer_gr_mode(enum peer_mode pr_mode);
+const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd);
+const char *print_global_gr_mode(enum global_mode gl_mode);
+const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd);
 #endif /* _QUAGGA_BGP_FSM_H */
index fed34e5b65ca375904c19da9068027a75c1552c5..626c36ff052e85c7efbf4f22fc5b15eff486c456 100644 (file)
@@ -462,7 +462,12 @@ static uint16_t bgp_read(struct peer *peer)
                         safe_strerror(errno));
 
                if (peer->status == Established) {
-                       if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) {
+                       if ((CHECK_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART) ||
+                               CHECK_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART_HELPER)) &&
+                               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
@@ -475,10 +480,15 @@ static uint16_t bgp_read(struct peer *peer)
        } else if (nbytes == 0) {
                if (bgp_debug_neighbor_events(peer))
                        zlog_debug("%s [Event] BGP connection closed fd %d",
-                                  peer->host, peer->fd);
+                                       peer->host, peer->fd);
 
                if (peer->status == Established) {
-                       if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) {
+                       if ((CHECK_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART) ||
+                               CHECK_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART_HELPER)) &&
+                               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
index 9cb3957a86c2ff24195554f02121941509afef7d..fab2a584c0a314463c30977d8edf9c1a120d2e15 100644 (file)
@@ -487,6 +487,7 @@ int main(int argc, char **argv)
 
        frr_config_fork();
        /* must be called after fork() */
+       bgp_gr_apply_running_config();
        bgp_pthreads_run();
        frr_run(bm->master);
 
index 4031d2dfde40301a67315ce252f310b7f7d63a08..d7989af553a44b4e0a3923d7dd4159bd04ad097a 100644 (file)
@@ -487,6 +487,22 @@ static int bgp_accept(struct thread *thread)
        hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
 
        peer_xfer_config(peer, peer1);
+       bgp_peer_gr_flags_update(peer);
+
+       BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(
+                       peer->bgp,
+                       peer->bgp->peer);
+
+       if (bgp_peer_gr_mode_get(peer) == PEER_DISABLE) {
+
+               UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
+
+               if (CHECK_FLAG(peer->sflags,
+                               PEER_STATUS_NSF_WAIT)) {
+                       peer_nsf_stop(peer);
+               }
+       }
+
        UNSET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
 
        peer->doppelganger = peer1;
@@ -497,10 +513,9 @@ static int bgp_accept(struct thread *thread)
        BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */
 
        SET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
-
        /* Make dummy peer until read Open packet. */
        if (peer1->status == Established
-           && CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) {
+               && CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) {
                /* If we have an existing established connection with graceful
                 * restart
                 * capability announced with one or more address families, then
@@ -508,7 +523,14 @@ static int bgp_accept(struct thread *thread)
                 * existing established connection and move state to connect.
                 */
                peer1->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
-               SET_FLAG(peer1->sflags, PEER_STATUS_NSF_WAIT);
+
+               if (CHECK_FLAG(peer1->flags,
+                       PEER_FLAG_GRACEFUL_RESTART) ||
+                       CHECK_FLAG(peer1->flags,
+                       PEER_FLAG_GRACEFUL_RESTART_HELPER))
+                       SET_FLAG(peer1->sflags,
+                               PEER_STATUS_NSF_WAIT);
+
                bgp_event_update(peer1, TCP_connection_closed);
        }
 
index 23b893c1c87e1e8c2bbc240e5c31895f26159d4e..d0618e90ec83198d026b7e91f1a9701acd1c07ce 100644 (file)
@@ -462,6 +462,8 @@ static int bgp_capability_restart(struct peer *peer,
        restart_flag_time = stream_getw(s);
        if (CHECK_FLAG(restart_flag_time, RESTART_R_BIT))
                SET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV);
+       else
+               UNSET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV);
 
        UNSET_FLAG(restart_flag_time, 0xF000);
        peer->v_gr_restart = restart_flag_time;
@@ -828,6 +830,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
        int ret;
        struct stream *s = BGP_INPUT(peer);
        size_t end = stream_get_getp(s) + length;
+       uint16_t restart_flag_time = 0;
 
        assert(STREAM_READABLE(s) >= length);
 
@@ -1004,6 +1007,12 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
                                        caphdr.length);
                        stream_set_getp(s, start + caphdr.length);
                }
+
+               if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+                       UNSET_FLAG(restart_flag_time, 0xF000);
+                       peer->v_gr_restart = restart_flag_time;
+               }
+
        }
        return 0;
 }
@@ -1299,6 +1308,86 @@ static void bgp_open_capability_orf(struct stream *s, struct peer *peer,
        stream_putc_at(s, capp, cap_len);
 }
 
+static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
+                                unsigned long cp)
+{
+       int len;
+       iana_afi_t pkt_afi;
+       afi_t afi;
+       safi_t safi;
+       iana_safi_t pkt_safi;
+       uint32_t restart_time;
+       unsigned long capp = 0;
+       unsigned long rcapp = 0;
+
+       if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
+           && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER))
+               return;
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug("[BGP_GR] Sending helper Capability for Peer :%s :",
+                          peer->host);
+
+       SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV);
+       stream_putc(s, BGP_OPEN_OPT_CAP);
+       capp = stream_get_endp(s); /* Set Capability Len Pointer */
+       stream_putc(s, 0);       /* Capability Length */
+       stream_putc(s, CAPABILITY_CODE_RESTART);
+       /* Set Restart Capability Len Pointer */
+       rcapp = stream_get_endp(s);
+       stream_putc(s, 0);
+       restart_time = peer->bgp->restart_time;
+       if (peer->bgp->t_startup) {
+               SET_FLAG(restart_time, RESTART_R_BIT);
+               SET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV);
+
+               if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+                       zlog_debug("[BGP_GR] Sending R-Bit for Peer :%s :",
+                                  peer->host);
+       }
+
+       stream_putw(s, restart_time);
+
+       /* Send address-family specific graceful-restart capability
+        * only when GR config is present
+        */
+       if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) {
+               if (bgp_flag_check(peer->bgp, BGP_FLAG_GR_PRESERVE_FWD)
+                   && BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+                       zlog_debug("[BGP_GR] F bit Set");
+
+               FOREACH_AFI_SAFI (afi, safi) {
+                       if (!peer->afc[afi][safi])
+                               continue;
+
+                       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+                               zlog_debug(
+                                       "[BGP_GR] Sending GR Capability for AFI :%d :, SAFI :%d:",
+                                       afi, safi);
+
+                       /* Convert AFI, SAFI to values for
+                        * packet.
+                        */
+                       bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi,
+                                                 &pkt_safi);
+                       stream_putw(s, pkt_afi);
+                       stream_putc(s, pkt_safi);
+                       if (bgp_flag_check(peer->bgp, BGP_FLAG_GR_PRESERVE_FWD))
+                               stream_putc(s, RESTART_F_BIT);
+                       else
+                               stream_putc(s, 0);
+               }
+       }
+
+       /* Total Graceful restart capability Len. */
+       len = stream_get_endp(s) - rcapp - 1;
+       stream_putc_at(s, rcapp, len);
+
+       /* Total Capability Len. */
+       len = stream_get_endp(s) - capp - 1;
+       stream_putc_at(s, capp, len);
+}
+
 /* Fill in capability open option to the packet. */
 void bgp_open_capability(struct stream *s, struct peer *peer)
 {
@@ -1309,7 +1398,6 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
        safi_t safi;
        iana_safi_t pkt_safi;
        as_t local_as;
-       uint32_t restart_time;
        uint8_t afi_safi_count = 0;
        int adv_addpath_tx = 0;
 
@@ -1502,50 +1590,7 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
                                cmd_domainname_get());
        }
 
-       /* Sending base graceful-restart capability irrespective of the config
-        */
-       SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV);
-       stream_putc(s, BGP_OPEN_OPT_CAP);
-       capp = stream_get_endp(s); /* Set Capability Len Pointer */
-       stream_putc(s, 0);       /* Capability Length */
-       stream_putc(s, CAPABILITY_CODE_RESTART);
-       rcapp = stream_get_endp(s); /* Set Restart Capability Len Pointer */
-       stream_putc(s, 0);
-       restart_time = peer->bgp->restart_time;
-       if (peer->bgp->t_startup) {
-               SET_FLAG(restart_time, RESTART_R_BIT);
-               SET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV);
-       }
-       stream_putw(s, restart_time);
-
-       /* Send address-family specific graceful-restart capability only when GR
-          config
-          is present */
-       if (bgp_flag_check(peer->bgp, BGP_FLAG_GRACEFUL_RESTART)) {
-               FOREACH_AFI_SAFI (afi, safi) {
-                       if (peer->afc[afi][safi]) {
-                               /* Convert AFI, SAFI to values for
-                                * packet. */
-                               bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi,
-                                                         &pkt_safi);
-                               stream_putw(s, pkt_afi);
-                               stream_putc(s, pkt_safi);
-                               if (bgp_flag_check(peer->bgp,
-                                                  BGP_FLAG_GR_PRESERVE_FWD))
-                                       stream_putc(s, RESTART_F_BIT);
-                               else
-                                       stream_putc(s, 0);
-                       }
-               }
-       }
-
-       /* Total Graceful restart capability Len. */
-       len = stream_get_endp(s) - rcapp - 1;
-       stream_putc_at(s, rcapp, len);
-
-       /* Total Capability Len. */
-       len = stream_get_endp(s) - capp - 1;
-       stream_putc_at(s, capp, len);
+       bgp_peer_send_gr_capability(s, peer, cp);
 
        /* Total Opt Parm Len. */
        len = stream_get_endp(s) - cp - 1;
index b7e9af002b40294084bd6f56627a928a38034b4e..e77194a6244b70b5909f41efe757c2ee568f4eb9 100644 (file)
@@ -439,28 +439,41 @@ int bgp_generate_updgrp_packets(struct thread *thread)
                         */
                        if (!next_pkt || !next_pkt->buffer) {
                                if (CHECK_FLAG(peer->cap,
-                                              PEER_CAP_RESTART_RCV)) {
+                                               PEER_CAP_RESTART_RCV)) {
                                        if (!(PAF_SUBGRP(paf))->t_coalesce
-                                           && peer->afc_nego[afi][safi]
-                                           && peer->synctime
-                                           && !CHECK_FLAG(
-                                                      peer->af_sflags[afi]
-                                                                     [safi],
-                                                      PEER_STATUS_EOR_SEND)) {
-                                               SET_FLAG(peer->af_sflags[afi]
-                                                                       [safi],
-                                                        PEER_STATUS_EOR_SEND);
-
-                                               if ((s = bgp_update_packet_eor(
-                                                            peer, afi,
-                                                            safi))) {
-                                                       bgp_packet_add(peer, s);
+                                               && peer->afc_nego[afi][safi]
+                                               && peer->synctime
+                                               && !CHECK_FLAG(
+                                               peer->af_sflags[afi][safi],
+                                               PEER_STATUS_EOR_SEND)) {
+                                               /* If EOR is disabled,
+                                                * the message is  not sent
+                                                */
+                                               if (BGP_SEND_EOR(peer->bgp,
+                                                               afi, safi)) {
+                                                       SET_FLAG(
+                                                       peer->af_sflags
+                                                       [afi][safi],
+                                                       PEER_STATUS_EOR_SEND);
+
+                                                       /* Update EOR
+                                                        * send time
+                                                        */
+                                                       peer->eor_stime
+                                                       [afi][safi] =
+                                                       monotime(NULL);
+
+                                                       BGP_UPDATE_EOR_PKT(
+                                                               peer, afi,
+                                                               safi, s);
                                                }
                                        }
                                }
                                continue;
                        }
 
+                       /* Update packet send time */
+                       peer->pkt_stime[afi][safi] = monotime(NULL);
 
                        /* Found a packet template to send, overwrite
                         * packet with appropriate attributes from peer
@@ -723,11 +736,14 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
                                if (first) {
                                        snprintf(c, sizeof(c), " %02x",
                                                 data[i]);
+
                                        strlcat(bgp_notify.data, c,
                                                bgp_notify.length);
+
                                } else {
                                        first = 1;
                                        snprintf(c, sizeof(c), "%02x", data[i]);
+
                                        strlcpy(bgp_notify.data, c,
                                                bgp_notify.length);
                                }
@@ -755,6 +771,11 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
        /* Add packet to peer's output queue */
        stream_fifo_push(peer->obuf, s);
 
+       bgp_peer_gr_flags_update(peer);
+       BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(
+                       peer->bgp,
+                       peer->bgp->peer);
+
        bgp_write_notify(peer);
 }
 
@@ -1404,6 +1425,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
        bgp_size_t attribute_len;
        bgp_size_t update_len;
        bgp_size_t withdraw_len;
+       bool restart = false;
 
        enum NLRI_TYPES {
                NLRI_UPDATE,
@@ -1626,6 +1648,12 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
            || (attr_parse_ret == BGP_ATTR_PARSE_EOR)) {
                afi_t afi = 0;
                safi_t safi;
+               struct graceful_restart_info *gr_info;
+
+               /* Restarting router */
+               if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) &&
+                   BGP_PEER_RESTARTING_MODE(peer))
+                       restart = true;
 
                /* Non-MP IPv4/Unicast is a completely emtpy UPDATE - already
                 * checked
@@ -1652,6 +1680,32 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
                                SET_FLAG(peer->af_sflags[afi][safi],
                                         PEER_STATUS_EOR_RECEIVED);
                                bgp_update_explicit_eors(peer);
+                               /* Update graceful restart information */
+                               gr_info = &(peer->bgp->gr_info[afi][safi]);
+                               if (restart)
+                                       gr_info->eor_received++;
+                               /* If EOR received from all peers and selection
+                                * deferral timer is running, cancel the timer
+                                * and invoke the best path calculation
+                                */
+                               if (gr_info->eor_required ==
+                                               gr_info->eor_received) {
+                                       if (bgp_debug_neighbor_events(
+                                                               peer))
+                                               zlog_debug("%s %d, %s %d",
+                                                       "EOR REQ",
+                                                       gr_info->eor_required,
+                                                       "EOR RCV",
+                                                       gr_info->eor_received);
+                                       BGP_TIMER_OFF(
+                                               gr_info->t_select_deferral);
+                                       gr_info->eor_required = 0;
+                                       gr_info->eor_received = 0;
+                                       /* Best path selection */
+                                       if (bgp_best_path_select_defer(
+                                               peer->bgp, afi, safi) < 0)
+                                               return BGP_Stop;
+                               }
                        }
 
                        /* NSF delete stale route */
@@ -1723,14 +1777,18 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
                                if (first) {
                                        snprintf(c, sizeof(c), " %02x",
                                                stream_getc(peer->curr));
+
                                        strlcat(bgp_notify.data, c,
-                                               bgp_notify.length);
+                                               bgp_notify.length * 3);
+
                                } else {
                                        first = 1;
                                        snprintf(c, sizeof(c), "%02x",
                                                 stream_getc(peer->curr));
+
                                        strlcpy(bgp_notify.data, c,
-                                               bgp_notify.length);
+                                               bgp_notify.length * 3);
+
                                }
                        bgp_notify.raw_data = (uint8_t *)peer->notify.data;
                }
@@ -1756,6 +1814,11 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
            && bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM)
                UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
 
+       bgp_peer_gr_flags_update(peer);
+       BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(
+                       peer->bgp,
+                       peer->bgp->peer);
+
        return Receive_NOTIFICATION_message;
 }
 
@@ -2374,3 +2437,14 @@ int bgp_process_packet(struct thread *thread)
 
        return 0;
 }
+
+/* Send EOR when routes are processed by selection deferral timer */
+void bgp_send_delayed_eor(struct bgp *bgp)
+{
+       struct peer *peer;
+       struct listnode *node, *nnode;
+
+       /* EOR message sent in bgp_write_proceed_actions */
+       for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
+               bgp_write_proceed_actions(peer);
+}
index 49e401790f18c44da490337aa19e385a1560a15e..0242abab26d6e3960affeaa56c1555f357be9877 100644 (file)
@@ -48,6 +48,14 @@ DECLARE_HOOK(bgp_packet_send,
 #define ORF_COMMON_PART_PERMIT     0x00
 #define ORF_COMMON_PART_DENY       0x20
 
+#define BGP_UPDATE_EOR_PKT(_peer, _afi, _safi, _s)       \
+               do { \
+                       _s = bgp_update_packet_eor(_peer, _afi, _safi); \
+                       if (_s) { \
+                               bgp_packet_add(_peer, _s); \
+                       } \
+               } while (0)
+
 /* Packet send and receive function prototypes. */
 extern void bgp_keepalive_send(struct peer *);
 extern void bgp_open_send(struct peer *);
@@ -73,4 +81,5 @@ extern int bgp_packet_set_size(struct stream *s);
 extern int bgp_generate_updgrp_packets(struct thread *);
 extern int bgp_process_packet(struct thread *);
 
+extern void bgp_send_delayed_eor(struct bgp *bgp);
 #endif /* _QUAGGA_BGP_PACKET_H */
index 5f4486b8004252115eed66fa33771999d78f33ca..78f03a707dc6d24579544b112f76231ec2cc05c9 100644 (file)
@@ -40,7 +40,7 @@
 #include "memory.h"
 #include "lib/json.h"
 #include "lib_errors.h"
-
+#include "zclient.h"
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_table.h"
 #include "bgpd/bgp_route.h"
@@ -89,7 +89,8 @@
 /* Extern from bgp_dump.c */
 extern const char *bgp_origin_str[];
 extern const char *bgp_origin_long_str[];
-
+const char *get_afi_safi_str(afi_t afi,
+               safi_t safi, bool for_json);
 /* PMSI strings. */
 #define PMSI_TNLTYPE_STR_NO_INFO "No info"
 #define PMSI_TNLTYPE_STR_DEFAULT PMSI_TNLTYPE_STR_NO_INFO
@@ -295,6 +296,85 @@ struct bgp_path_info *bgp_path_info_unlock(struct bgp_path_info *path)
        return path;
 }
 
+/* This function sets flag BGP_NODE_SELECT_DEFER based on condition */
+static int bgp_node_set_defer_flag(struct bgp_node *rn, bool delete)
+{
+       struct peer *peer;
+       struct bgp_path_info *old_pi, *nextpi;
+       bool set_flag = 0;
+       struct bgp *bgp = NULL;
+       struct bgp_table *table = NULL;
+       afi_t afi = 0;
+       safi_t safi = 0;
+       char buf[PREFIX2STR_BUFFER];
+
+       /* If the flag BGP_NODE_SELECT_DEFER is set and new path is added
+        * then the route selection is deferred
+        */
+       if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER) && (!delete))
+               return 0;
+
+       if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED)) {
+               if (BGP_DEBUG(update, UPDATE_OUT)) {
+                       prefix2str(&rn->p, buf, PREFIX2STR_BUFFER);
+                       zlog_debug("Route %s is in workqueue and being processed, not deferred.",
+                               buf);
+               }
+               return 0;
+       }
+
+       table = bgp_node_table(rn);
+       if (table) {
+               bgp = table->bgp;
+               afi = table->afi;
+               safi = table->safi;
+       }
+
+       for (old_pi = bgp_node_get_bgp_path_info(rn);
+            (old_pi != NULL) && (nextpi = old_pi->next, 1); old_pi = nextpi) {
+               if (CHECK_FLAG(old_pi->flags, BGP_PATH_SELECTED))
+                       continue;
+
+               /* Route selection is deferred if there is a stale path which
+                * which indicates peer is in restart mode
+                */
+               if (CHECK_FLAG(old_pi->flags, BGP_PATH_STALE) &&
+                               (old_pi->sub_type == BGP_ROUTE_NORMAL)) {
+                       set_flag = 1;
+               } else {
+                       /* If the peer is graceful restart capable and peer is
+                        * restarting mode, set the flag BGP_NODE_SELECT_DEFER
+                        */
+                       peer = old_pi->peer;
+                       if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) &&
+                           BGP_PEER_RESTARTING_MODE(peer) &&
+                           (old_pi && old_pi->sub_type == BGP_ROUTE_NORMAL)) {
+                               set_flag = 1;
+                       }
+               }
+               if (set_flag)
+                       break;
+       }
+
+       /* Set the flag BGP_NODE_SELECT_DEFER if route selection deferral timer
+        * is active
+        */
+       if (set_flag && table) {
+               if (bgp && (bgp->gr_info[afi][safi].t_select_deferral)) {
+                       SET_FLAG(rn->flags, BGP_NODE_SELECT_DEFER);
+                       prefix2str(&rn->p, buf, PREFIX2STR_BUFFER);
+                       if (rn->rt_node == NULL)
+                               rn->rt_node = listnode_add(
+                                       bgp->gr_info[afi][safi].route_list, rn);
+                       if (BGP_DEBUG(update, UPDATE_OUT))
+                               zlog_debug("DEFER route %s, rn %p, node %p",
+                                               buf, rn, rn->rt_node);
+                       return 0;
+               }
+       }
+       return -1;
+}
+
 void bgp_path_info_add(struct bgp_node *rn, struct bgp_path_info *pi)
 {
        struct bgp_path_info *top;
@@ -310,6 +390,7 @@ void bgp_path_info_add(struct bgp_node *rn, struct bgp_path_info *pi)
        bgp_path_info_lock(pi);
        bgp_lock_node(rn);
        peer_lock(pi->peer); /* bgp_path_info peer reference */
+       bgp_node_set_defer_flag(rn, false);
 }
 
 /* Do the actual removal of info from RIB, for use by bgp_process
@@ -1973,6 +2054,30 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi,
        return 1;
 }
 
+static int bgp_route_select_timer_expire(struct thread *thread)
+{
+       struct afi_safi_info *info;
+       afi_t afi;
+       safi_t safi;
+       struct bgp *bgp;
+
+       info = THREAD_ARG(thread);
+       afi = info->afi;
+       safi = info->safi;
+       bgp = info->bgp;
+
+       if (BGP_DEBUG(update, UPDATE_OUT))
+               zlog_debug("afi %d, safi %d : route select timer expired",
+                               afi, safi);
+
+       bgp->gr_info[afi][safi].t_route_select = NULL;
+
+       XFREE(MTYPE_TMP, info);
+
+       /* Best path selection */
+       return bgp_best_path_select_defer(bgp, afi, safi);
+}
+
 void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn,
                        struct bgp_maxpaths_cfg *mpath_cfg,
                        struct bgp_path_info_pair *result, afi_t afi,
@@ -2376,6 +2481,15 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
                           afi2str(afi), safi2str(safi));
        }
 
+       /* The best path calculation for the route is deferred if
+        * BGP_NODE_SELECT_DEFER is set
+        */
+       if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) {
+               if (BGP_DEBUG(update, UPDATE_OUT))
+                       zlog_debug("SELECT_DEFER falg set for route %p", rn);
+               return;
+       }
+
        /* Best path selection. */
        bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new,
                           afi, safi);
@@ -2603,6 +2717,65 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
        return;
 }
 
+/* Process the routes with the flag BGP_NODE_SELECT_DEFER set */
+int bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi)
+{
+       struct bgp_node *rn;
+       int cnt = 0;
+       struct afi_safi_info *thread_info;
+       struct listnode *node = NULL, *nnode = NULL;
+
+       if (bgp->gr_info[afi][safi].t_route_select)
+               BGP_TIMER_OFF(bgp->gr_info[afi][safi].t_route_select);
+
+       if (BGP_DEBUG(update, UPDATE_OUT)) {
+               zlog_debug("%s: processing route for %s : cnt %d",
+                          __func__, get_afi_safi_str(afi, safi, false),
+                               listcount(bgp->gr_info[afi][safi].route_list));
+       }
+
+       /* Process the route list */
+       node = listhead(bgp->gr_info[afi][safi].route_list);
+       while (node) {
+               rn = listgetdata(node);
+               nnode = node->next;
+               list_delete_node(bgp->gr_info[afi][safi].route_list, node);
+               rn->rt_node = NULL;
+
+               if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) {
+                       UNSET_FLAG(rn->flags, BGP_NODE_SELECT_DEFER);
+                       bgp_process_main_one(bgp, rn, afi, safi);
+                       cnt++;
+                       if (cnt >= BGP_MAX_BEST_ROUTE_SELECT)
+                               break;
+               }
+               node = nnode;
+       }
+
+       /* Send EOR message when all routes are processed */
+       if (list_isempty(bgp->gr_info[afi][safi].route_list)) {
+               bgp_send_delayed_eor(bgp);
+               /* Send route processing complete message to RIB */
+               bgp_zebra_update(afi, safi, bgp->vrf_id,
+                               ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE);
+               return 0;
+       }
+
+       thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info));
+
+       thread_info->afi = afi;
+       thread_info->safi = safi;
+       thread_info->bgp = bgp;
+
+       /* If there are more routes to be processed, start the
+        * selection timer
+        */
+       thread_add_timer(bm->master, bgp_route_select_timer_expire, thread_info,
+                       BGP_ROUTE_SELECT_DELAY,
+                       &bgp->gr_info[afi][safi].t_route_select);
+       return 0;
+}
+
 static wq_item_status bgp_process_wq(struct work_queue *wq, void *data)
 {
        struct bgp_process_queue *pqnode = data;
@@ -2681,6 +2854,16 @@ void bgp_process(struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
        if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED))
                return;
 
+       /* If the flag BGP_NODE_SELECT_DEFER is set, do not add route to
+        * the workqueue
+        */
+       if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) {
+               if (BGP_DEBUG(update, UPDATE_OUT))
+                       zlog_debug("BGP_NODE_SELECT_DEFER set for route %p",
+                                   rn);
+               return;
+       }
+
        if (wq == NULL)
                return;
 
@@ -2844,13 +3027,41 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi,
 void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi,
                    struct peer *peer, afi_t afi, safi_t safi)
 {
+
+       struct bgp *bgp = NULL;
+       bool delete_route = false;
+
        bgp_aggregate_decrement(peer->bgp, &rn->p, pi, afi, safi);
 
-       if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY))
+       if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
                bgp_path_info_delete(rn, pi); /* keep historical info */
 
-       hook_call(bgp_process, peer->bgp, afi, safi, rn, peer, true);
+               /* If the selected path is removed, reset BGP_NODE_SELECT_DEFER
+                * flag
+                */
+               if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
+                       delete_route = true;
+               else
+                       if (bgp_node_set_defer_flag(rn, true) < 0)
+                               delete_route = true;
+               if (delete_route) {
+                       if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) {
+                               UNSET_FLAG(rn->flags, BGP_NODE_SELECT_DEFER);
+                               bgp = pi->peer->bgp;
+                               if ((rn->rt_node) &&
+                                       (bgp->gr_info[afi][safi]
+                                       .route_list)) {
+                                       list_delete_node(
+                                               bgp->gr_info[afi][safi]
+                                               .route_list,
+                                               rn->rt_node);
+                                       rn->rt_node = NULL;
+                               }
+                       }
+               }
+       }
 
+       hook_call(bgp_process, peer->bgp, afi, safi, rn, peer, true);
        bgp_process(peer->bgp, rn, afi, safi);
 }
 
@@ -3302,6 +3513,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
                                if (CHECK_FLAG(pi->flags, BGP_PATH_STALE)) {
                                        bgp_path_info_unset_flag(
                                                rn, pi, BGP_PATH_STALE);
+                                       bgp_node_set_defer_flag(rn, false);
                                        bgp_process(bgp, rn, afi, safi);
                                }
                        }
@@ -3337,8 +3549,10 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
                }
 
                /* graceful restart STALE flag unset. */
-               if (CHECK_FLAG(pi->flags, BGP_PATH_STALE))
+               if (CHECK_FLAG(pi->flags, BGP_PATH_STALE)) {
                        bgp_path_info_unset_flag(rn, pi, BGP_PATH_STALE);
+                       bgp_node_set_defer_flag(rn, false);
+               }
 
                /* The attribute is changed. */
                bgp_path_info_set_flag(rn, pi, BGP_PATH_ATTR_CHANGED);
index b9f3f3f7620119988f3cc6eebb11673c287ba0c4..e335c39fb12dad47bdb2ca88502abcb86c891e9a 100644 (file)
@@ -635,4 +635,5 @@ extern int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
                             struct bgp_table *table, struct prefix_rd *prd,
                             enum bgp_show_type type, void *output_arg,
                             bool use_json);
+extern int bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi);
 #endif /* _QUAGGA_BGP_ROUTE_H */
index b75246b172c606d9379afa7b1e529d21ac211346..4868686305632caed81dc54b9de0bf979a817ae6 100644 (file)
@@ -127,6 +127,43 @@ struct bgp_table *bgp_table_init(struct bgp *bgp, afi_t afi, safi_t safi)
        return rt;
 }
 
+/* Delete the route node from the selection deferral route list */
+void bgp_delete_listnode(struct bgp_node *node)
+{
+       struct route_node *rn = NULL;
+       struct bgp_table *table = NULL;
+       struct bgp *bgp = NULL;
+       afi_t afi;
+       safi_t safi;
+
+       /* If the route to be deleted is selection pending, update the
+        * route node in gr_info
+        */
+       if (CHECK_FLAG(node->flags, BGP_NODE_SELECT_DEFER)) {
+               table = bgp_node_table(node);
+
+               if (table) {
+                       bgp = table->bgp;
+                       afi = table->afi;
+                       safi = table->safi;
+               } else
+                       return;
+
+               rn = bgp_node_to_rnode(node);
+
+               if (bgp && rn && rn->lock == 1) {
+                       /* Delete the route from the selection pending list */
+                       if ((node->rt_node) &&
+                           (bgp->gr_info[afi][safi].route_list)) {
+                               list_delete_node(
+                                       bgp->gr_info[afi][safi].route_list,
+                                               node->rt_node);
+                               node->rt_node = NULL;
+                       }
+               }
+       }
+}
+
 static struct bgp_node *
 bgp_route_next_until_maxlen(struct bgp_node *node, const struct bgp_node *limit,
                            const uint8_t maxlen)
index b3542e7848a9b11f632d8a90013d5cfecd4e7d54..69cca9eee4eb844885bfde689baf58e1cbb0979c 100644 (file)
@@ -28,6 +28,8 @@
 #include "bgpd.h"
 #include "bgp_advertise.h"
 
+extern void bgp_delete_listnode(struct bgp_node *node);
+
 struct bgp_table {
        /* table belongs to this instance */
        struct bgp *bgp;
@@ -95,7 +97,9 @@ struct bgp_node {
 #define BGP_NODE_USER_CLEAR             (1 << 1)
 #define BGP_NODE_LABEL_CHANGED          (1 << 2)
 #define BGP_NODE_REGISTERED_FOR_LABEL   (1 << 3)
-
+#define BGP_NODE_SELECT_DEFER           (1 << 4)
+       /* list node pointer */
+       struct listnode *rt_node;
        struct bgp_addpath_node_data tx_addpath;
 
        enum bgp_path_selection_reason reason;
@@ -162,6 +166,7 @@ static inline struct bgp_node *bgp_node_parent_nolock(struct bgp_node *node)
  */
 static inline void bgp_unlock_node(struct bgp_node *node)
 {
+       bgp_delete_listnode(node);
        route_unlock_node(bgp_node_to_rnode(node));
 }
 
index 9dc6549d9c40c8df295bd0dccc37f733d5cdbf5e..1cd2f0a3973bfd9b09170166261574b0eb9839df 100644 (file)
@@ -105,9 +105,39 @@ DEFINE_HOOK(bgp_inst_config_write,
                (struct bgp *bgp, struct vty *vty),
                (bgp, vty))
 
+#define GR_NO_OPER "The Graceful Restart No Operation was executed as cmd same as previous one."
+#define GR_INVALID "The Graceful Restart command used is not valid at this moment."
 static struct peer_group *listen_range_exists(struct bgp *bgp,
                                              struct prefix *range, int exact);
 
+/* Show BGP peer's information. */
+enum show_type {
+       show_all,
+       show_peer,
+       show_ipv4_all,
+       show_ipv6_all,
+       show_ipv4_peer,
+       show_ipv6_peer
+};
+
+static struct peer_group *listen_range_exists(
+                                               struct bgp *bgp,
+                                               struct prefix *range,
+                                               int exact);
+
+static void bgp_show_global_graceful_restart_mode_vty(
+                                       struct vty *vty,
+                                       struct bgp *bgp,
+                                       bool use_json,
+                                       json_object *json);
+
+static int bgp_show_neighbor_graceful_restart_afi_all(
+                               struct vty *vty,
+                               enum show_type type,
+                               const char *ip_str,
+                               afi_t afi,
+                               bool use_json);
+
 static enum node_type bgp_node_type(afi_t afi, safi_t safi)
 {
        switch (afi) {
@@ -690,7 +720,16 @@ int bgp_vty_return(struct vty *vty, int ret)
                str = "Operation not allowed on a directly connected neighbor";
                break;
        case BGP_ERR_PEER_SAFI_CONFLICT:
-               str = "Cannot activate peer for both 'ipv4 unicast' and 'ipv4 labeled-unicast'";
+               str = GR_INVALID;
+               break;
+       case BGP_ERR_GR_INVALID_CMD:
+               str = "The Graceful Restart command used is not valid at this moment.";
+               break;
+       case BGP_ERR_GR_OPERATION_FAILED:
+               str = "The Graceful Restart Operation failed due to an err.";
+               break;
+       case BGP_GR_NO_OPERATION:
+               str = GR_NO_OPER;
                break;
        }
        if (str) {
@@ -785,7 +824,8 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
        int ret = 0;
        bool found = false;
        struct peer *peer;
-       struct listnode *node, *nnode;
+
+       VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
 
        /* Clear all neighbors. */
        /*
@@ -795,11 +835,27 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
         */
        if (sort == clear_all) {
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+
+                       bgp_peer_gr_flags_update(peer);
+
+                       if (CHECK_FLAG(peer->flags,
+                                       PEER_FLAG_GRACEFUL_RESTART))
+                               gr_router_detected = true;
+
                        ret = bgp_peer_clear(peer, afi, safi, nnode,
                                                          stype);
 
                        if (ret < 0)
                                bgp_clear_vty_error(vty, peer, afi, safi, ret);
+
+               }
+
+               if (gr_router_detected &&
+                       bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
+                       bgp_zebra_send_capabilities(bgp, false);
+               } else if (!gr_router_detected &&
+                       bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
+                       bgp_zebra_send_capabilities(bgp, true);
                }
 
                /* This is to apply read-only mode on this clear. */
@@ -836,6 +892,9 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                        }
                }
 
+               VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+               VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
                ret = bgp_peer_clear(peer, afi, safi, NULL, stype);
 
                /* if afi/safi not defined for this peer, let caller know */
@@ -881,6 +940,12 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                        if (peer->sort == BGP_PEER_IBGP)
                                continue;
 
+                       bgp_peer_gr_flags_update(peer);
+
+                       if (CHECK_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART))
+                               gr_router_detected = true;
+
                        ret = bgp_peer_clear(peer, afi, safi, nnode, stype);
 
                        if (ret < 0)
@@ -889,6 +954,14 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                                found = true;
                }
 
+               if (gr_router_detected &&
+                       bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
+                       bgp_zebra_send_capabilities(bgp, false);
+               } else if (!gr_router_detected &&
+                       bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
+                       bgp_zebra_send_capabilities(bgp, true);
+               }
+
                if (!found)
                        vty_out(vty,
                                "%%BGP: No external %s peer is configured\n",
@@ -905,6 +978,12 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                        if (peer->as != as)
                                continue;
 
+                       bgp_peer_gr_flags_update(peer);
+
+                       if (CHECK_FLAG(peer->flags,
+                               PEER_FLAG_GRACEFUL_RESTART))
+                               gr_router_detected = true;
+
                        ret = bgp_peer_clear(peer, afi, safi, nnode, stype);
 
                        if (ret < 0)
@@ -913,6 +992,14 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                                found = true;
                }
 
+               if (gr_router_detected &&
+                       bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
+                       bgp_zebra_send_capabilities(bgp, false);
+               } else if (!gr_router_detected &&
+                       bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
+                       bgp_zebra_send_capabilities(bgp, true);
+               }
+
                if (!found)
                        vty_out(vty,
                                "%%BGP: No %s peer is configured with AS %s\n",
@@ -2093,37 +2180,68 @@ DEFUN (no_bgp_deterministic_med,
        return CMD_SUCCESS;
 }
 
-/* "bgp graceful-restart" configuration. */
+/* "bgp graceful-restart mode" configuration. */
 DEFUN (bgp_graceful_restart,
-       bgp_graceful_restart_cmd,
-       "bgp graceful-restart",
-       "BGP specific commands\n"
-       "Graceful restart capability parameters\n")
+       bgp_graceful_restart_cmd,
+       "bgp graceful-restart",
+       "BGP specific commands\n"
+       GR_CMD
+      )
 {
+       int ret = BGP_GR_FAILURE;
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : START ");
+
        VTY_DECLVAR_CONTEXT(bgp, bgp);
-       bgp_flag_set(bgp, BGP_FLAG_GRACEFUL_RESTART);
-       return CMD_SUCCESS;
+
+       ret = bgp_gr_update_all(bgp, GLOBAL_GR_CMD);
+
+       VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+                               bgp->peer, ret);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : END ");
+       vty_out(vty,
+               "Graceful restart configuration changed, reset all peers to take effect\n");
+       return bgp_vty_return(vty, ret);
 }
 
 DEFUN (no_bgp_graceful_restart,
-       no_bgp_graceful_restart_cmd,
-       "no bgp graceful-restart",
-       NO_STR
-       "BGP specific commands\n"
-       "Graceful restart capability parameters\n")
+       no_bgp_graceful_restart_cmd,
+       "no bgp graceful-restart",
+       NO_STR
+       "BGP specific commands\n"
+       NO_GR_CMD
+      )
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
-       bgp_flag_unset(bgp, BGP_FLAG_GRACEFUL_RESTART);
-       return CMD_SUCCESS;
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : START ");
+
+       int ret = BGP_GR_FAILURE;
+
+       ret = bgp_gr_update_all(bgp, NO_GLOBAL_GR_CMD);
+
+       VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+                       bgp->peer, ret);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : END ");
+       vty_out(vty,
+               "Graceful restart configuration changed, reset all peers to take effect\n");
+
+       return bgp_vty_return(vty, ret);
 }
 
 DEFUN (bgp_graceful_restart_stalepath_time,
-       bgp_graceful_restart_stalepath_time_cmd,
-       "bgp graceful-restart stalepath-time (1-4095)",
-       "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_graceful_restart_stalepath_time_cmd,
+       "bgp graceful-restart stalepath-time (1-4095)",
+       "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")
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
        int idx_number = 3;
@@ -2135,12 +2253,12 @@ DEFUN (bgp_graceful_restart_stalepath_time,
 }
 
 DEFUN (bgp_graceful_restart_restart_time,
-       bgp_graceful_restart_restart_time_cmd,
-       "bgp graceful-restart restart-time (1-4095)",
-       "BGP specific commands\n"
-       "Graceful restart capability parameters\n"
-       "Set the time to wait to delete stale routes before a BGP open message is received\n"
-       "Delay value (seconds)\n")
+       bgp_graceful_restart_restart_time_cmd,
+       "bgp graceful-restart restart-time (1-4095)",
+       "BGP specific commands\n"
+       "Graceful restart capability parameters\n"
+       "Set the time to wait to delete stale routes before a BGP open message is received\n"
+       "Delay value (seconds)\n")
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
        int idx_number = 3;
@@ -2151,14 +2269,36 @@ DEFUN (bgp_graceful_restart_restart_time,
        return CMD_SUCCESS;
 }
 
-DEFUN (no_bgp_graceful_restart_stalepath_time,
-       no_bgp_graceful_restart_stalepath_time_cmd,
-       "no bgp graceful-restart stalepath-time [(1-4095)]",
-       NO_STR
+DEFUN (bgp_graceful_restart_select_defer_time,
+       bgp_graceful_restart_select_defer_time_cmd,
+       "bgp graceful-restart select-defer-time (0-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")
+       "Set the time to defer the BGP route selection after restart\n"
+       "Delay value (seconds, 0 - disable)\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       int idx_number = 3;
+       uint32_t defer_time;
+
+       defer_time = strtoul(argv[idx_number]->arg, NULL, 10);
+       bgp->select_defer_time = defer_time;
+       if (defer_time == 0)
+               bgp_flag_set(bgp, BGP_FLAG_SELECT_DEFER_DISABLE);
+       else
+               bgp_flag_unset(bgp, BGP_FLAG_SELECT_DEFER_DISABLE);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_graceful_restart_stalepath_time,
+       no_bgp_graceful_restart_stalepath_time_cmd,
+       "no bgp graceful-restart stalepath-time [(1-4095)]",
+       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")
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
 
@@ -2167,26 +2307,43 @@ DEFUN (no_bgp_graceful_restart_stalepath_time,
 }
 
 DEFUN (no_bgp_graceful_restart_restart_time,
-       no_bgp_graceful_restart_restart_time_cmd,
-       "no bgp graceful-restart restart-time [(1-4095)]",
+       no_bgp_graceful_restart_restart_time_cmd,
+       "no bgp graceful-restart restart-time [(1-4095)]",
+       NO_STR
+       "BGP specific commands\n"
+       "Graceful restart capability parameters\n"
+       "Set the time to wait to delete stale routes before a BGP open message is received\n"
+       "Delay value (seconds)\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+       bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_graceful_restart_select_defer_time,
+       no_bgp_graceful_restart_select_defer_time_cmd,
+       "no bgp graceful-restart select-defer-time [(0-3600)]",
        NO_STR
        "BGP specific commands\n"
        "Graceful restart capability parameters\n"
-       "Set the time to wait to delete stale routes before a BGP open message is received\n"
+       "Set the time to defer the BGP route selection after restart\n"
        "Delay value (seconds)\n")
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
 
-       bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
+       bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME;
+       bgp_flag_unset(bgp, BGP_FLAG_SELECT_DEFER_DISABLE);
+
        return CMD_SUCCESS;
 }
 
 DEFUN (bgp_graceful_restart_preserve_fw,
-       bgp_graceful_restart_preserve_fw_cmd,
-       "bgp graceful-restart preserve-fw-state",
-       "BGP specific commands\n"
-       "Graceful restart capability parameters\n"
-       "Sets F-bit indication that fib is preserved while doing Graceful Restart\n")
+       bgp_graceful_restart_preserve_fw_cmd,
+       "bgp graceful-restart preserve-fw-state",
+       "BGP specific commands\n"
+       "Graceful restart capability parameters\n"
+       "Sets F-bit indication that fib is preserved while doing Graceful Restart\n")
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
        bgp_flag_set(bgp, BGP_FLAG_GR_PRESERVE_FWD);
@@ -2194,15 +2351,366 @@ DEFUN (bgp_graceful_restart_preserve_fw,
 }
 
 DEFUN (no_bgp_graceful_restart_preserve_fw,
-       no_bgp_graceful_restart_preserve_fw_cmd,
-       "no bgp graceful-restart preserve-fw-state",
+       no_bgp_graceful_restart_preserve_fw_cmd,
+       "no bgp graceful-restart preserve-fw-state",
+       NO_STR
+       "BGP specific commands\n"
+       "Graceful restart capability parameters\n"
+       "Unsets F-bit indication that fib is preserved while doing Graceful Restart\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       bgp_flag_unset(bgp, BGP_FLAG_GR_PRESERVE_FWD);
+       return CMD_SUCCESS;
+}
+
+DEFUN (bgp_graceful_restart_disable,
+       bgp_graceful_restart_disable_cmd,
+       "bgp graceful-restart-disable",
+       "BGP specific commands\n"
+       GR_DISABLE)
+{
+       int ret = BGP_GR_FAILURE;
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] bgp_graceful_restart_disable_cmd : START ");
+
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+       ret = bgp_gr_update_all(bgp, GLOBAL_DISABLE_CMD);
+
+       VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+                               bgp->peer, ret);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] bgp_graceful_restart_disable_cmd : END ");
+       vty_out(vty,
+               "Graceful restart configuration changed, reset all peers to take effect\n");
+
+       return bgp_vty_return(vty, ret);
+}
+
+DEFUN (no_bgp_graceful_restart_disable,
+       no_bgp_graceful_restart_disable_cmd,
+       "no bgp graceful-restart-disable",
+       NO_STR
+       "BGP specific commands\n"
+       NO_GR_DISABLE
+      )
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] no_bgp_graceful_restart_disable_cmd : START ");
+
+       int ret = BGP_GR_FAILURE;
+
+       ret = bgp_gr_update_all(bgp, NO_GLOBAL_DISABLE_CMD);
+
+       VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+                               bgp->peer, ret);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] no_bgp_graceful_restart_disable_cmd : END ");
+       vty_out(vty,
+               "Graceful restart configuration changed, reset all peers to take effect\n");
+
+       return bgp_vty_return(vty, ret);
+}
+
+DEFUN (bgp_neighbor_graceful_restart_set,
+       bgp_neighbor_graceful_restart_set_cmd,
+       "neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       GR_NEIGHBOR_CMD
+      )
+{
+       int idx_peer = 1;
+       struct peer *peer;
+       int ret = BGP_GR_FAILURE;
+
+       VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : START ");
+
+       peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       ret = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD);
+
+       VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+       VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : END ");
+       vty_out(vty,
+               "Graceful restart configuration changed, reset this peer to take effect\n");
+
+       return bgp_vty_return(vty, ret);
+}
+
+DEFUN (no_bgp_neighbor_graceful_restart,
+       no_bgp_neighbor_graceful_restart_set_cmd,
+       "no neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       NO_GR_NEIGHBOR_CMD
+      )
+{
+       int idx_peer = 2;
+       int ret = BGP_GR_FAILURE;
+       struct peer *peer;
+
+       VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+       peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : START ");
+
+       ret = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD);
+
+       VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+       VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : END ");
+       vty_out(vty,
+               "Graceful restart configuration changed, reset this peer to take effect\n");
+
+       return bgp_vty_return(vty, ret);
+}
+
+DEFUN (bgp_neighbor_graceful_restart_helper_set,
+       bgp_neighbor_graceful_restart_helper_set_cmd,
+       "neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-helper",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       GR_NEIGHBOR_HELPER_CMD
+      )
+{
+       int idx_peer = 1;
+       struct peer *peer;
+       int ret = BGP_GR_FAILURE;
+
+       VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : START ");
+
+       peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+
+
+       ret = bgp_neighbor_graceful_restart(peer, PEER_HELPER_CMD);
+
+       VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+       VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : END ");
+       vty_out(vty,
+               "Graceful restart configuration changed, reset this peer to take effect\n");
+
+       return bgp_vty_return(vty, ret);
+}
+
+DEFUN (no_bgp_neighbor_graceful_restart_helper,
+       no_bgp_neighbor_graceful_restart_helper_set_cmd,
+       "no neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-helper",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       NO_GR_NEIGHBOR_HELPER_CMD
+      )
+{
+       int idx_peer = 2;
+       int ret = BGP_GR_FAILURE;
+       struct peer *peer;
+
+       VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+       peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : START ");
+
+       ret = bgp_neighbor_graceful_restart(peer,
+                       NO_PEER_HELPER_CMD);
+
+       VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+       VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : END ");
+       vty_out(vty,
+               "Graceful restart configuration changed, reset this peer to take effect\n");
+
+       return bgp_vty_return(vty, ret);
+}
+
+DEFUN (bgp_neighbor_graceful_restart_disable_set,
+       bgp_neighbor_graceful_restart_disable_set_cmd,
+       "neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-disable",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       GR_NEIGHBOR_DISABLE_CMD
+      )
+{
+       int idx_peer = 1;
+       struct peer *peer;
+       int ret = BGP_GR_FAILURE;
+
+       VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] bgp_neighbor_graceful_restart_disable_set_cmd : START ");
+
+       peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       ret = bgp_neighbor_graceful_restart(peer,
+                               PEER_DISABLE_CMD);
+
+       if (peer->bgp->t_startup)
+               bgp_peer_gr_flags_update(peer);
+
+       VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+       VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR]bgp_neighbor_graceful_restart_disable_set_cmd : END ");
+       vty_out(vty,
+               "Graceful restart configuration changed, reset this peer to take effect\n");
+
+       return bgp_vty_return(vty, ret);
+}
+
+DEFUN (no_bgp_neighbor_graceful_restart_disable,
+       no_bgp_neighbor_graceful_restart_disable_set_cmd,
+       "no neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-disable",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       NO_GR_NEIGHBOR_DISABLE_CMD
+      )
+{
+       int idx_peer = 2;
+       int ret = BGP_GR_FAILURE;
+       struct peer *peer;
+
+       VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+       peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : START ");
+
+       ret = bgp_neighbor_graceful_restart(peer, NO_PEER_DISABLE_CMD);
+
+       VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+       VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug(
+                       "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : END ");
+       vty_out(vty,
+               "Graceful restart configuration changed, reset this peer to take effect\n");
+
+       return bgp_vty_return(vty, ret);
+}
+
+DEFUN_HIDDEN (bgp_graceful_restart_disable_eor,
+              bgp_graceful_restart_disable_eor_cmd,
+              "bgp graceful-restart disable-eor",
+              "BGP specific commands\n"
+              "Graceful restart configuration parameters\n"
+              "Disable EOR Check\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       bgp_flag_set(bgp, BGP_FLAG_GR_DISABLE_EOR);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN (no_bgp_graceful_restart_disable_eor,
+              no_bgp_graceful_restart_disable_eor_cmd,
+              "no bgp graceful-restart disable-eor",
+              NO_STR
+              "BGP specific commands\n"
+              "Graceful restart configuration parameters\n"
+              "Disable EOR Check\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       bgp_flag_unset(bgp, BGP_FLAG_GR_DISABLE_EOR);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (bgp_graceful_restart_rib_stale_time,
+       bgp_graceful_restart_rib_stale_time_cmd,
+       "bgp graceful-restart rib-stale-time (1-3600)",
+       "BGP specific commands\n"
+       "Graceful restart configuration parameters\n"
+       "Specify the stale route removal timer in rib\n"
+       "Delay value (seconds)\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       int idx_number = 3;
+       uint32_t stale_time;
+
+       stale_time = strtoul(argv[idx_number]->arg, NULL, 10);
+       bgp->rib_stale_time = stale_time;
+       /* Send the stale timer update message to RIB */
+       if (bgp_zebra_stale_timer_update(bgp))
+               return CMD_WARNING;
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_graceful_restart_rib_stale_time,
+       no_bgp_graceful_restart_rib_stale_time_cmd,
+       "no bgp graceful-restart rib-stale-time [(1-3600)]",
        NO_STR
        "BGP specific commands\n"
-       "Graceful restart capability parameters\n"
-       "Unsets F-bit indication that fib is preserved while doing Graceful Restart\n")
+       "Graceful restart configuration parameters\n"
+       "Specify the stale route removal timer in rib\n"
+       "Delay value (seconds)\n")
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
-       bgp_flag_unset(bgp, BGP_FLAG_GR_PRESERVE_FWD);
+
+       bgp->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME;
+       /* Send the stale timer update message to RIB */
+       if (bgp_zebra_stale_timer_update(bgp))
+               return CMD_WARNING;
+
        return CMD_SUCCESS;
 }
 
@@ -8882,8 +9390,6 @@ const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json)
                return get_afi_safi_vty_str(afi, safi);
 }
 
-/* Show BGP peer's information. */
-enum show_type { show_all, show_peer, show_ipv4_all, show_ipv6_all, show_ipv4_peer, show_ipv6_peer };
 
 static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
                                      afi_t afi, safi_t safi,
@@ -8948,11 +9454,396 @@ static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
        }
 }
 
-static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
-                             safi_t safi, bool use_json,
-                             json_object *json_neigh)
+static void bgp_show_neighnor_graceful_restart_rbit(struct vty *vty,
+                                                   struct peer *p,
+                                                   bool use_json,
+                                                   json_object *json)
 {
-       struct bgp_filter *filter;
+       bool rbit_status = 0;
+
+       if (!use_json)
+               vty_out(vty, "\n    R bit          : ");
+
+       if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)
+           && (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV))
+           && (p->status == Established)) {
+
+               if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_BIT_RCV))
+                       rbit_status = 1;
+               else
+                       rbit_status = 0;
+       }
+
+       if (rbit_status) {
+               if (use_json)
+                       json_object_boolean_true_add(json, "rBit");
+               else
+                       vty_out(vty, "True\n");
+       } else {
+               if (use_json)
+                       json_object_boolean_false_add(json, "rBit");
+               else
+                       vty_out(vty, "False\n");
+       }
+}
+
+static void bgp_show_neighbor_graceful_restart_remote_mode(struct vty *vty,
+                                                          struct peer *peer,
+                                                          bool use_json,
+                                                          json_object *json)
+{
+       const char *mode = "NotApplicable";
+
+       if (!use_json)
+               vty_out(vty, "\n    Remote GR Mode : ");
+
+       if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)
+           && (peer->status == Established)) {
+
+               if ((peer->nsf_af_count == 0)
+                   && !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+
+                       mode = "Disable";
+
+               } else if (peer->nsf_af_count == 0
+                          && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+
+                       mode = "Helper";
+
+               } else if (peer->nsf_af_count != 0
+                          && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+
+                       mode = "Restart";
+               }
+       }
+
+       if (use_json) {
+               json_object_string_add(json, "remoteGrMode", mode);
+       } else
+               vty_out(vty, mode, "\n");
+}
+
+static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty,
+                                                         struct peer *p,
+                                                         bool use_json,
+                                                         json_object *json)
+{
+       const char *mode = "Invalid";
+
+       if (!use_json)
+               vty_out(vty, "    Local GR Mode  : ");
+
+       if (bgp_peer_gr_mode_get(p) == PEER_HELPER)
+               mode = "Helper";
+       else if (bgp_peer_gr_mode_get(p) == PEER_GR)
+               mode = "Restart";
+       else if (bgp_peer_gr_mode_get(p) == PEER_DISABLE)
+               mode = "Disable";
+       else if (bgp_peer_gr_mode_get(p) == PEER_GLOBAL_INHERIT) {
+               if (bgp_global_gr_mode_get(p->bgp) == GLOBAL_HELPER)
+                       mode = "Helper*";
+               else if (bgp_global_gr_mode_get(p->bgp) == GLOBAL_GR)
+                       mode = "Restart*";
+               else if (bgp_global_gr_mode_get(p->bgp) == GLOBAL_DISABLE)
+                       mode = "Disable*";
+               else
+                       mode = "Invalid*";
+       }
+
+       if (use_json) {
+               json_object_string_add(json, "localGrMode", mode);
+       } else {
+               vty_out(vty, mode, "\n");
+       }
+}
+
+static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
+       struct vty *vty, struct peer *peer, bool use_json, json_object *json)
+{
+       afi_t afi;
+       safi_t safi;
+       json_object *json_afi_safi = NULL;
+       json_object *json_timer = NULL;
+       json_object *json_endofrib_status = NULL;
+       bool eor_flag = false;
+
+       for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+               for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) {
+                       if (!peer->afc[afi][safi])
+                               continue;
+
+                       if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)
+                           || !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV))
+                               continue;
+
+                       if (use_json) {
+                               json_afi_safi = json_object_new_object();
+                               json_endofrib_status = json_object_new_object();
+                               json_timer = json_object_new_object();
+                       }
+
+                       if (peer->eor_stime[afi][safi]
+                           >= peer->pkt_stime[afi][safi])
+                               eor_flag = true;
+                       else
+                               eor_flag = false;
+
+                       if (!use_json) {
+                               vty_out(vty, "    %s :\n",
+                                       get_afi_safi_str(afi, safi, false));
+
+                               vty_out(vty, "     F bit                 : ");
+                       } else
+                               get_afi_safi_str(afi, safi, true);
+
+                       if (peer->nsf[afi][safi]
+                           && CHECK_FLAG(peer->af_cap[afi][safi],
+                                         PEER_CAP_RESTART_AF_PRESERVE_RCV)) {
+
+                               if (use_json) {
+                                       json_object_boolean_true_add(
+                                               json_afi_safi, "fBit");
+                               } else
+                                       vty_out(vty, "True\n");
+                       } else {
+                               if (use_json)
+                                       json_object_boolean_false_add(
+                                               json_afi_safi, "fBit");
+                               else
+                                       vty_out(vty, "False\n");
+                       }
+
+                       if (!use_json)
+                               vty_out(vty, "     End-of-RIB Received   : ");
+
+                       if (CHECK_FLAG(peer->af_sflags[afi][safi],
+                                      PEER_STATUS_EOR_RECEIVED)) {
+                               if (use_json)
+                                       json_object_boolean_true_add(
+                                               json_endofrib_status,
+                                               "endOfRibRecv");
+                               else
+                                       vty_out(vty, "Yes\n");
+                       } else {
+                               if (use_json)
+                                       json_object_boolean_false_add(
+                                               json_endofrib_status,
+                                               "endOfRibRecv");
+                               else
+                                       vty_out(vty, "No\n");
+                       }
+
+                       if (!use_json)
+                               vty_out(vty, "     End-of-RIB Send       : ");
+
+                       if (CHECK_FLAG(peer->af_sflags[afi][safi],
+                                      PEER_STATUS_EOR_SEND)) {
+                               if (use_json) {
+                                       json_object_boolean_true_add(
+                                               json_endofrib_status,
+                                               "endOfRibSend");
+
+                                       PRINT_EOR_JSON(eor_flag);
+                               } else {
+                                       vty_out(vty, "Yes\n");
+                                       vty_out(vty,
+                                               "     EoRSentAfterUpdate   : ");
+
+                                       PRINT_EOR(eor_flag);
+                               }
+                       } else {
+                               if (use_json) {
+                                       json_object_boolean_false_add(
+                                               json_endofrib_status,
+                                               "endOfRibSend");
+                                       json_object_boolean_false_add(
+                                               json_endofrib_status,
+                                               "endOfRibSentAfterUpdate");
+                               } else {
+                                       vty_out(vty, "No\n");
+                                       vty_out(vty,
+                                               "     EoRSentAfterUpdate   : ");
+                                       vty_out(vty, "No\n");
+                               }
+                       }
+
+                       if (use_json) {
+                               json_object_int_add(json_timer,
+                                                   "stalePathTimer",
+                                                   peer->bgp->stalepath_time);
+
+                               if (peer->t_gr_stale != NULL) {
+                                       json_object_int_add(
+                                               json_timer,
+                                               "stalePathTimerRemaining",
+                                               thread_timer_remain_second(
+                                                       peer->t_gr_stale));
+                               }
+
+                               /* Display Configured Selection
+                                * Deferral only when when
+                                * Gr mode is enabled.
+                                */
+                               if (CHECK_FLAG(peer->flags,
+                                              PEER_FLAG_GRACEFUL_RESTART)) {
+                                       json_object_int_add(
+                                               json_timer,
+                                               "selectionDeferralTimer",
+                                               peer->bgp->stalepath_time);
+                               }
+
+                               if (peer->bgp->gr_info[afi][safi]
+                                           .t_select_deferral
+                                   != NULL) {
+
+                                       json_object_int_add(
+                                               json_timer,
+                                               "selectionDeferralTimerRemaining",
+                                               thread_timer_remain_second(
+                                                       peer->bgp
+                                                               ->gr_info[afi]
+                                                                        [safi]
+                                                               .t_select_deferral));
+                               }
+                       } else {
+                               vty_out(vty, "     Timers:\n");
+
+                               vty_out(vty, "%*s", 6, "");
+                               vty_out(vty,
+                                       "Configured Stale Path Time(sec)%*s: %u\n",
+                                       8, "", peer->bgp->stalepath_time);
+
+                               if (peer->t_gr_stale != NULL) {
+                                       vty_out(vty, "%*s", 6, "");
+                                       vty_out(vty,
+                                               "Stale Path Remaining(sec)%*s: %ld\n",
+                                               14, "",
+                                               thread_timer_remain_second(
+                                                       peer->t_gr_stale));
+                               }
+                               /* Display Configured Selection
+                                * Deferral only when when
+                                * Gr mode is enabled.
+                                */
+                               if (CHECK_FLAG(peer->flags,
+                                              PEER_FLAG_GRACEFUL_RESTART)) {
+                                       vty_out(vty, "%*s", 6, "");
+                                       vty_out(vty,
+                                               "Configured Selection Deferral Time(sec): %u\n",
+                                               peer->bgp->select_defer_time);
+                               }
+
+                               if (peer->bgp->gr_info[afi][safi]
+                                           .t_select_deferral
+                                   != NULL) {
+
+                                       vty_out(vty, "%*s", 6, "");
+                                       vty_out(vty,
+                                               "Selection Deferral Time Remaining(sec) : %ld\n",
+                                               thread_timer_remain_second(
+                                                       peer->bgp
+                                                               ->gr_info[afi]
+                                                                        [safi]
+                                                               .t_select_deferral));
+                               }
+                       }
+                       if (use_json) {
+                               json_object_object_add(json_afi_safi,
+                                                      "endOfRibStatus",
+                                                      json_endofrib_status);
+                               json_object_object_add(json_afi_safi, "timers",
+                                                      json_timer);
+                               json_object_object_add(
+                                       json, get_afi_safi_str(afi, safi, true),
+                                       json_afi_safi);
+                       }
+               }
+       }
+}
+
+static void  bgp_show_neighbor_graceful_restart_time(struct vty *vty,
+                                                       struct peer *p,
+                                                       bool use_json,
+                                                       json_object *json)
+{
+       if (use_json) {
+               json_object *json_timer = NULL;
+
+               json_timer = json_object_new_object();
+
+               json_object_int_add(json_timer, "configuredRestartTimer",
+                                   p->bgp->restart_time);
+
+               json_object_int_add(json_timer, "receivedRestartTimer",
+                                   p->v_gr_restart);
+
+               if (p->t_gr_restart != NULL)
+                       json_object_int_add(
+                               json_timer, "restartTimerRemaining",
+                               thread_timer_remain_second(p->t_gr_restart));
+
+               json_object_object_add(json, "timers", json_timer);
+       } else {
+
+               vty_out(vty, "    Timers :\n");
+               vty_out(vty, "     Configured Restart Time(sec)  : %u\n",
+                       p->bgp->restart_time);
+
+               vty_out(vty, "     Received Restart Time(sec)    : %u\n",
+                       p->v_gr_restart);
+               if (p->t_gr_restart != NULL)
+                       vty_out(vty,
+                               "     Restart Time Remaining(sec)   : %ld\n",
+                               thread_timer_remain_second(p->t_gr_restart));
+       }
+}
+
+static void bgp_show_peer_gr_status(struct vty *vty, struct peer *p,
+                                       bool use_json,
+                                       json_object *json)
+{
+       char buf[SU_ADDRSTRLEN] = {0};
+       char dn_flag[2] = {0};
+       char neighborAddr[INET6_ADDRSTRLEN] = {0};
+
+       if (!p->conf_if && peer_dynamic_neighbor(p))
+               dn_flag[0] = '*';
+
+       if (p->conf_if) {
+               if (use_json)
+                       json_object_string_add(
+                               json, "neighborAddr",
+                               BGP_PEER_SU_UNSPEC(p)
+                                       ? "none"
+                                       : sockunion2str(&p->su, buf,
+                                                       SU_ADDRSTRLEN));
+               else
+                       vty_out(vty, "BGP neighbor on %s: %s\n", p->conf_if,
+                               BGP_PEER_SU_UNSPEC(p)
+                                       ? "none"
+                                       : sockunion2str(&p->su, buf,
+                                                       SU_ADDRSTRLEN));
+       } else {
+               sprintf(neighborAddr, "%s%s", dn_flag, p->host);
+
+               if (use_json)
+                       json_object_string_add(
+                               json, "neighborAddr",
+                               neighborAddr);
+               else
+                       vty_out(vty, "BGP neighbor is %s\n",
+                               neighborAddr);
+       }
+
+       /* more gr info in new format */
+       BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, json);
+}
+
+static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
+                             safi_t safi, bool use_json,
+                             json_object *json_neigh)
+{
+       struct bgp_filter *filter;
        struct peer_af *paf;
        char orf_pfx_name[BUFSIZ];
        int orf_pfx_count;
@@ -9262,7 +10153,9 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
                                        "prefixAllowedRestartIntervalMsecs",
                                        p->pmax_restart[afi][safi] * 60000);
                }
-               json_object_object_add(json_neigh, get_afi_safi_str(afi, safi, true),
+               json_object_object_add(json_neigh,
+                                       get_afi_safi_str(afi,
+                                               safi, true),
                                       json_addr);
 
        } else {
@@ -10701,14 +11594,12 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                        vty_out(vty, "none");
                                                vty_out(vty, "\n");
                                        }
-                               }
+                               } /* Gracefull Restart */
                        }
                }
        }
 
        /* graceful restart information */
-       if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) || p->t_gr_restart
-           || p->t_gr_stale) {
                json_object *json_grace = NULL;
                json_object *json_grace_send = NULL;
                json_object *json_grace_recv = NULL;
@@ -10720,10 +11611,11 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                        json_grace_send = json_object_new_object();
                        json_grace_recv = json_object_new_object();
 
-                       if (p->status == Established) {
+                       if ((p->status == Established) &&
+                                       CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
                                FOREACH_AFI_SAFI (afi, safi) {
                                        if (CHECK_FLAG(p->af_sflags[afi][safi],
-                                                      PEER_STATUS_EOR_SEND)) {
+                                               PEER_STATUS_EOR_SEND)) {
                                                json_object_boolean_true_add(
                                                        json_grace_send,
                                                        get_afi_safi_str(afi,
@@ -10734,8 +11626,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                }
                                FOREACH_AFI_SAFI (afi, safi) {
                                        if (CHECK_FLAG(
-                                                   p->af_sflags[afi][safi],
-                                                   PEER_STATUS_EOR_RECEIVED)) {
+                                               p->af_sflags[afi][safi],
+                                               PEER_STATUS_EOR_RECEIVED)) {
                                                json_object_boolean_true_add(
                                                        json_grace_recv,
                                                        get_afi_safi_str(afi,
@@ -10745,11 +11637,13 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                        }
                                }
                        }
+                       json_object_object_add(json_grace,
+                                               "endOfRibSend",
+                                                       json_grace_send);
+                       json_object_object_add(json_grace,
+                                               "endOfRibRecv",
+                                               json_grace_recv);
 
-                       json_object_object_add(json_grace, "endOfRibSend",
-                                              json_grace_send);
-                       json_object_object_add(json_grace, "endOfRibRecv",
-                                              json_grace_recv);
 
                        if (p->t_gr_restart)
                                json_object_int_add(json_grace,
@@ -10765,12 +11659,16 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                        thread_timer_remain_second(
                                                p->t_gr_stale)
                                                * 1000);
-
+                       /* more gr info in new format */
+                       BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json,
+                                                       json_grace);
                        json_object_object_add(
                                json_neigh, "gracefulRestartInfo", json_grace);
                } else {
-                       vty_out(vty, "  Graceful restart information:\n");
-                       if (p->status == Established) {
+                       vty_out(vty, "  Graceful restart informations:\n");
+                       if ((p->status == Established) &&
+                               CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
+
                                vty_out(vty, "    End-of-RIB send: ");
                                FOREACH_AFI_SAFI (afi, safi) {
                                        if (CHECK_FLAG(p->af_sflags[afi][safi],
@@ -10779,8 +11677,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                        eor_send_af_count ? ", "
                                                                          : "",
                                                        get_afi_safi_str(afi,
-                                                                        safi,
-                                                                        false));
+                                                                       safi,
+                                                                       false));
                                                eor_send_af_count++;
                                        }
                                }
@@ -10814,8 +11712,11 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                        "    The remaining time of stalepath timer is %ld\n",
                                        thread_timer_remain_second(
                                                p->t_gr_stale));
+
+                       /* more gr info in new format */
+                       BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, NULL);
                }
-       }
+
        if (use_json) {
                json_object *json_stat = NULL;
                json_stat = json_object_new_object();
@@ -11229,6 +12130,83 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
        }
 }
 
+static int bgp_show_neighbor_graceful_restart(struct vty *vty,
+                                       struct bgp *bgp,
+                                       enum show_type type,
+                                       union sockunion *su,
+                                       const char *conf_if, afi_t afi,
+                                       bool use_json, json_object *json)
+{
+       struct listnode *node, *nnode;
+       struct peer *peer;
+       int find = 0;
+       safi_t safi = SAFI_UNICAST;
+       json_object *json_neighbor = NULL;
+
+       for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+
+               if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+                       continue;
+
+               if ((peer->afc[afi][safi]) == 0)
+                       continue;
+
+               if (use_json)
+                       json_neighbor = json_object_new_object();
+
+               if (type == show_all) {
+                       bgp_show_peer_gr_status(vty, peer, use_json,
+                                               json_neighbor);
+
+                       if (use_json)
+                               json_object_object_add(json, peer->host,
+                                                      json_neighbor);
+
+               } else if (type == show_peer) {
+                       if (conf_if) {
+                               if ((peer->conf_if
+                                    && !strcmp(peer->conf_if, conf_if))
+                                   || (peer->hostname
+                                       && !strcmp(peer->hostname, conf_if))) {
+                                       find = 1;
+                                       bgp_show_peer_gr_status(vty, peer,
+                                                               use_json,
+                                                               json_neighbor);
+                               }
+                       } else {
+                               if (sockunion_same(&peer->su, su)) {
+                                       find = 1;
+                                       bgp_show_peer_gr_status(vty, peer,
+                                                               use_json,
+                                                               json_neighbor);
+                               }
+                       }
+                       if (use_json && find)
+                               json_object_object_add(json, peer->host,
+                                                      json_neighbor);
+               }
+
+               if (find)
+                       break;
+       }
+
+       if (type == show_peer && !find) {
+               if (use_json)
+                       json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
+               else
+                       vty_out(vty, "%% No such neighbor\n");
+       }
+       if (use_json) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+       } else {
+               vty_out(vty, "\n");
+       }
+
+       return CMD_SUCCESS;
+}
+
 static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
                             enum show_type type, union sockunion *su,
                             const char *conf_if, bool use_json,
@@ -11334,6 +12312,41 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
        return CMD_SUCCESS;
 }
 
+static void  bgp_show_neighbor_graceful_restart_vty(struct vty *vty,
+                                enum show_type type, const char *ip_str,
+                                afi_t afi, bool use_json)
+{
+
+       int ret;
+       struct bgp *bgp;
+       union sockunion su;
+       json_object *json = NULL;
+
+       bgp = bgp_get_default();
+
+       if (!bgp)
+               return;
+
+       if (!use_json)
+               bgp_show_global_graceful_restart_mode_vty(vty, bgp, use_json,
+                                                         NULL);
+
+       json = json_object_new_object();
+       if (ip_str) {
+               ret = str2sockunion(ip_str, &su);
+               if (ret < 0)
+                       bgp_show_neighbor_graceful_restart(vty, bgp, type, NULL,
+                                                          ip_str, afi,
+                                                          use_json, json);
+               else
+                       bgp_show_neighbor_graceful_restart(
+                               vty, bgp, type, &su, NULL, afi, use_json, json);
+       } else
+               bgp_show_neighbor_graceful_restart(vty, bgp, type, NULL, NULL,
+                                                  afi, use_json, json);
+       json_object_free(json);
+}
+
 static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
                                                 enum show_type type,
                                                 const char *ip_str,
@@ -11471,6 +12484,51 @@ static int bgp_show_neighbor_vty(struct vty *vty, const char *name,
        return CMD_SUCCESS;
 }
 
+
+
+/* "show [ip] bgp neighbors graceful-restart" commands.  */
+DEFUN (show_ip_bgp_neighbors_gracrful_restart,
+       show_ip_bgp_neighbors_graceful_restart_cmd,
+       "show bgp [<ipv4|ipv6>] neighbors [<A.B.C.D|X:X::X:X|WORD>] graceful-restart [json]",
+       SHOW_STR
+       BGP_STR
+       IP_STR
+       IPV6_STR
+       NEIGHBOR_STR
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Neighbor on BGP configured interface\n"
+       GR_SHOW
+       JSON_STR)
+{
+       char *sh_arg = NULL;
+       enum show_type sh_type;
+       int idx = 0;
+       afi_t afi = AFI_MAX;
+       bool uj = use_json(argc, argv);
+
+       if      (!argv_find_and_parse_afi(argv, argc, &idx, &afi))
+               afi = AFI_MAX;
+
+       idx++;
+
+       if (argv_find(argv, argc, "A.B.C.D", &idx)
+           || argv_find(argv, argc, "X:X::X:X", &idx)
+           || argv_find(argv, argc, "WORD", &idx)) {
+               sh_type = show_peer;
+               sh_arg = argv[idx]->arg;
+       } else
+               sh_type = show_all;
+
+       if (!argv_find(argv, argc, "graceful-restart", &idx))
+               return CMD_SUCCESS;
+
+
+       return bgp_show_neighbor_graceful_restart_afi_all(vty,
+                                               sh_type, sh_arg,
+                                               afi, uj);
+}
+
 /* "show [ip] bgp neighbors" commands.  */
 DEFUN (show_ip_bgp_neighbors,
        show_ip_bgp_neighbors_cmd,
@@ -11609,7 +12667,68 @@ DEFUN (show_ip_bgp_lcommunity_info,
 
        return CMD_SUCCESS;
 }
+/* Graceful Restart */
+
+static void bgp_show_global_graceful_restart_mode_vty(struct vty *vty,
+                                       struct bgp *bgp,
+                                       bool use_json,
+                                       json_object *json)
+{
+
+
+       vty_out(vty, "\n%s", SHOW_GR_HEADER);
+
+       enum global_mode bgp_global_gr_mode = bgp_global_gr_mode_get(bgp);
+
+       switch (bgp_global_gr_mode) {
+
+       case GLOBAL_HELPER:
+               vty_out(vty, "Global BGP GR Mode :  Helper\n");
+               break;
+
+       case GLOBAL_GR:
+               vty_out(vty, "Global BGP GR Mode :  Restart\n");
+               break;
+
+       case GLOBAL_DISABLE:
+               vty_out(vty, "Global BGP GR Mode :  Disable\n");
+               break;
+
+       case GLOBAL_INVALID:
+               vty_out(vty,
+                       "Global BGP GR Mode  Invalid\n");
+               break;
+       }
+       vty_out(vty, "\n");
+}
+
+static int  bgp_show_neighbor_graceful_restart_afi_all(struct vty *vty,
+                                               enum show_type type,
+                                               const char *ip_str,
+                                               afi_t afi,
+                                               bool use_json)
+{
+       if ((afi == AFI_MAX) && (ip_str == NULL)) {
+               afi = AFI_IP;
+
+               while ((afi != AFI_L2VPN) && (afi < AFI_MAX)) {
 
+                       bgp_show_neighbor_graceful_restart_vty(vty,
+                                                       type, ip_str,
+                                                       afi, use_json);
+                       afi++;
+               }
+       } else if (afi != AFI_MAX) {
+               bgp_show_neighbor_graceful_restart_vty(vty,
+                                                       type, ip_str,
+                                                       afi, use_json);
+       } else {
+               return CMD_ERR_INCOMPLETE;
+       }
+
+       return CMD_SUCCESS;
+}
+/* Graceful Restart */
 
 DEFUN (show_ip_bgp_attr_info,
        show_ip_bgp_attr_info_cmd,
@@ -13437,6 +14556,29 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
        if (peer->as_path_loop_detection)
                vty_out(vty, " neighbor %s sender-as-path-loop-detection\n",
                        addr);
+
+       if (!CHECK_FLAG(peer->peer_gr_new_status_flag,
+                       PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) {
+
+               if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+                              PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) {
+                       vty_out(vty,
+                               " neighbor %s graceful-restart-helper\n", addr);
+               } else if (CHECK_FLAG(
+                                  peer->peer_gr_new_status_flag,
+                                  PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) {
+                       vty_out(vty,
+                               " neighbor %s graceful-restart\n", addr);
+               } else if (
+                       (!(CHECK_FLAG(peer->peer_gr_new_status_flag,
+                                     PEER_GRACEFUL_RESTART_NEW_STATE_HELPER))
+                        && !(CHECK_FLAG(
+                                peer->peer_gr_new_status_flag,
+                                PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)))) {
+                       vty_out(vty, " neighbor %s graceful-restart-disable\n",
+                               addr);
+               }
+       }
 }
 
 /* BGP peer configuration display function. */
@@ -13963,12 +15105,22 @@ int bgp_config_write(struct vty *vty)
                        vty_out(vty,
                                " bgp graceful-restart stalepath-time %u\n",
                                bgp->stalepath_time);
+
                if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME)
                        vty_out(vty, " bgp graceful-restart restart-time %u\n",
                                bgp->restart_time);
-               if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_RESTART))
+
+               if (bgp->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME)
+                       vty_out(vty,
+                               " bgp graceful-restart select-defer-time %u\n",
+                               bgp->select_defer_time);
+
+               if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR)
                        vty_out(vty, " bgp graceful-restart\n");
 
+               if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE)
+                       vty_out(vty, " bgp graceful-restart-disable\n");
+
                /* BGP graceful-shutdown */
                if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
                        vty_out(vty, " bgp graceful-shutdown\n");
@@ -13978,6 +15130,12 @@ int bgp_config_write(struct vty *vty)
                        vty_out(vty,
                                " bgp graceful-restart preserve-fw-state\n");
 
+               /* Stale timer for RIB */
+               if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME)
+                       vty_out(vty,
+                               " bgp graceful-restart rib-stale-time %u\n",
+                               bgp->rib_stale_time);
+
                /* BGP bestpath method. */
                if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_IGNORE))
                        vty_out(vty, " bgp bestpath as-path ignore\n");
@@ -14346,17 +15504,51 @@ void bgp_vty_init(void)
        install_element(BGP_NODE, &bgp_deterministic_med_cmd);
        install_element(BGP_NODE, &no_bgp_deterministic_med_cmd);
 
-       /* "bgp graceful-restart" commands */
-       install_element(BGP_NODE, &bgp_graceful_restart_cmd);
-       install_element(BGP_NODE, &no_bgp_graceful_restart_cmd);
+       /* "bgp graceful-restart" command */
+       install_element(BGP_NODE,
+                       &bgp_graceful_restart_cmd);
+       install_element(BGP_NODE,
+                       &no_bgp_graceful_restart_cmd);
+
+       /* "bgp graceful-restart-disable" command */
+       install_element(BGP_NODE,
+                       &bgp_graceful_restart_disable_cmd);
+       install_element(BGP_NODE,
+                       &no_bgp_graceful_restart_disable_cmd);
+
+       /* "neighbor a:b:c:d graceful-restart" command */
+       install_element(BGP_NODE,
+                       &bgp_neighbor_graceful_restart_set_cmd);
+       install_element(BGP_NODE,
+                       &no_bgp_neighbor_graceful_restart_set_cmd);
+
+       /* "neighbor a:b:c:d graceful-restart-disable" command */
+       install_element(BGP_NODE,
+                       &bgp_neighbor_graceful_restart_disable_set_cmd);
+       install_element(BGP_NODE,
+                       &no_bgp_neighbor_graceful_restart_disable_set_cmd);
+
+       /* "neighbor a:b:c:d graceful-restart-helper" command */
+       install_element(BGP_NODE,
+                       &bgp_neighbor_graceful_restart_helper_set_cmd);
+       install_element(BGP_NODE,
+                       &no_bgp_neighbor_graceful_restart_helper_set_cmd);
+
        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, &bgp_graceful_restart_restart_time_cmd);
        install_element(BGP_NODE, &no_bgp_graceful_restart_restart_time_cmd);
-
+       install_element(BGP_NODE, &bgp_graceful_restart_select_defer_time_cmd);
+       install_element(BGP_NODE,
+                       &no_bgp_graceful_restart_select_defer_time_cmd);
        install_element(BGP_NODE, &bgp_graceful_restart_preserve_fw_cmd);
        install_element(BGP_NODE, &no_bgp_graceful_restart_preserve_fw_cmd);
 
+       install_element(BGP_NODE, &bgp_graceful_restart_disable_eor_cmd);
+       install_element(BGP_NODE, &no_bgp_graceful_restart_disable_eor_cmd);
+       install_element(BGP_NODE, &bgp_graceful_restart_rib_stale_time_cmd);
+       install_element(BGP_NODE, &no_bgp_graceful_restart_rib_stale_time_cmd);
+
        /* "bgp graceful-shutdown" commands */
        install_element(BGP_NODE, &bgp_graceful_shutdown_cmd);
        install_element(BGP_NODE, &no_bgp_graceful_shutdown_cmd);
@@ -15351,6 +16543,9 @@ void bgp_vty_init(void)
        /* "show [ip] bgp neighbors" commands. */
        install_element(VIEW_NODE, &show_ip_bgp_neighbors_cmd);
 
+       install_element(VIEW_NODE,
+                       &show_ip_bgp_neighbors_graceful_restart_cmd);
+
        /* "show [ip] bgp peer-group" commands. */
        install_element(VIEW_NODE, &show_ip_bgp_peer_groups_cmd);
 
index 5f3ce9cd8e54284a68083e53dfbb138a838e9596..2e33ed59b955d2027078be02162ba80054f4bad6 100644 (file)
@@ -22,7 +22,7 @@
 #define _QUAGGA_BGP_VTY_H
 
 #include "bgpd/bgpd.h"
-
+#include "stream.h"
 struct bgp;
 
 #define BGP_INSTANCE_HELP_STR "BGP view\nBGP VRF\nView/VRF name\n"
@@ -46,6 +46,110 @@ struct bgp;
        "Address Family modifier\n"                                            \
        "Address Family modifier\n"
 
+#define SHOW_GR_HEADER \
+       "Codes: GR - Graceful Restart," \
+       " * -  Inheriting Global GR Config,\n" \
+       "       Restart - GR Mode-Restarting," \
+       " Helper - GR Mode-Helper,\n" \
+       "       Disable - GR Mode-Disable.\n\n"
+
+#define BGP_SHOW_PEER_GR_CAPABILITY( \
+                       vty, p, use_json, json) \
+       do {                    \
+               bgp_show_neighbor_graceful_restart_local_mode( \
+                               vty, p, use_json, json);                \
+               bgp_show_neighbor_graceful_restart_remote_mode( \
+                               vty, p, use_json, json); \
+               bgp_show_neighnor_graceful_restart_rbit( \
+                               vty, p, use_json, json);        \
+               bgp_show_neighbor_graceful_restart_time( \
+                               vty, p, use_json, json);        \
+               bgp_show_neighbor_graceful_restart_capability_per_afi_safi(\
+                                               vty, p, use_json, json); \
+       } while (0)
+
+#define VTY_BGP_GR_DEFINE_LOOP_VARIABLE \
+               struct peer *peer_loop = NULL; \
+               struct listnode *node = NULL; \
+               struct listnode *nnode = NULL; \
+               bool gr_router_detected = false
+
+#define VTY_BGP_GR_ROUTER_DETECT( \
+               _bgp, _peer, _peer_list) \
+       do { \
+               if (_peer->bgp->t_startup) \
+                       bgp_peer_gr_flags_update(_peer); \
+               for (ALL_LIST_ELEMENTS(_peer_list, \
+                       node, nnode, peer_loop)) { \
+                       if (CHECK_FLAG(peer_loop->flags,\
+                               PEER_FLAG_GRACEFUL_RESTART)) \
+                               gr_router_detected = true; \
+               } \
+       } while (0)
+
+
+#define VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(_bgp, _ret) \
+       do { \
+               if (gr_router_detected && \
+                       _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \
+                       if (bgp_zebra_send_capabilities(_bgp, false)) \
+                               _ret = BGP_ERR_INVALID_VALUE;\
+               } else if (!gr_router_detected && \
+                       _bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \
+                       if (bgp_zebra_send_capabilities(_bgp, true)) \
+                               _ret = BGP_ERR_INVALID_VALUE;\
+               } \
+       } while (0)
+
+#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA( \
+               _bgp, _peer_list, _ret) \
+       do { \
+               struct peer *peer_loop; \
+               bool gr_router_detected = false; \
+               struct listnode *node = {0}; \
+               struct listnode *nnode = {0}; \
+               for (ALL_LIST_ELEMENTS( \
+                                       _peer_list, node, \
+                                       nnode, peer_loop)) { \
+                       if (peer_loop->bgp->t_startup) \
+                               bgp_peer_gr_flags_update(peer_loop); \
+                       if (CHECK_FLAG( \
+                                               peer_loop->flags, \
+                                               PEER_FLAG_GRACEFUL_RESTART)) \
+                               gr_router_detected = true; \
+               } \
+               if (gr_router_detected && \
+                       _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \
+                       if (bgp_zebra_send_capabilities(_bgp, false)) \
+                               _ret = BGP_ERR_INVALID_VALUE;\
+               } else if (!gr_router_detected && \
+                       _bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \
+                       if (bgp_zebra_send_capabilities(_bgp, true)) \
+                               _ret = BGP_ERR_INVALID_VALUE;\
+               } \
+       } while (0)
+
+
+#define PRINT_EOR(_eor_flag) \
+       do {                    \
+               if (eor_flag)  \
+                       vty_out(vty, "Yes\n");  \
+               else    \
+                       vty_out(vty, "No\n"); \
+       } while (0)
+
+#define PRINT_EOR_JSON(_eor_flag) \
+       do {                    \
+               if (eor_flag) \
+                       json_object_boolean_true_add( \
+                               json_endofrib_status,     \
+                               "endOfRibSentAfterUpdate"); \
+               else                            \
+                       json_object_boolean_false_add( \
+                               json_endofrib_status,      \
+                               "endOfRibSentAfterUpdate"); \
+       } while (0)
+
 extern void bgp_vty_init(void);
 extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
 extern int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
index c99ddaf0a6dcbcb2c0696a4f829de43e95e495a0..03d5cd984fd6c3dddad93ab5cfa37fc5349e6712 100644 (file)
@@ -2437,6 +2437,7 @@ static void bgp_zebra_connected(struct zclient *zclient)
        /* TODO - What if we have peers and networks configured, do we have to
         * kick-start them?
         */
+       BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer);
 }
 
 static int bgp_zebra_process_local_es(ZAPI_CALLBACK_ARGS)
@@ -3016,3 +3017,157 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
                return;
        }
 }
+
+/* Send capabilities to RIB */
+int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable)
+{
+       struct zapi_cap api;
+       int ret = BGP_GR_SUCCESS;
+
+       if (zclient == NULL) {
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("zclient invalid");
+               return BGP_GR_FAILURE;
+       }
+
+       /* Check if the client is connected */
+       if ((zclient->sock < 0) || (zclient->t_connect)) {
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("client not connected");
+               return BGP_GR_FAILURE;
+       }
+
+       /* Check if capability is already sent. If the flag force is set
+        * send the capability since this can be initial bgp configuration
+        */
+       memset(&api, 0, sizeof(struct zapi_cap));
+       if (disable) {
+               api.cap = ZEBRA_CLIENT_GR_DISABLE;
+               api.vrf_id = bgp->vrf_id;
+       } else {
+               api.cap = ZEBRA_CLIENT_GR_CAPABILITIES;
+               api.stale_removal_time = bgp->rib_stale_time;
+               api.vrf_id = bgp->vrf_id;
+       }
+
+       if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES,
+                                     zclient, &api) < 0) {
+               zlog_err("error sending capability");
+               ret = BGP_GR_FAILURE;
+       } else {
+               if (disable)
+                       bgp->present_zebra_gr_state = ZEBRA_GR_DISABLE;
+               else
+                       bgp->present_zebra_gr_state = ZEBRA_GR_ENABLE;
+
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("send capabilty success");
+               ret = BGP_GR_SUCCESS;
+       }
+       return ret;
+}
+
+/* Send route update pesding or completed status to RIB for the
+ * specific AFI, SAFI
+ */
+int bgp_zebra_update(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type)
+{
+       struct zapi_cap api = {0};
+
+       if (zclient == NULL) {
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("zclient == NULL, invalid");
+               return BGP_GR_FAILURE;
+       }
+
+       /* Check if the client is connected */
+       if ((zclient->sock < 0) || (zclient->t_connect)) {
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("client not connected");
+               return BGP_GR_FAILURE;
+       }
+
+       api.afi = afi;
+       api.safi = safi;
+       api.vrf_id = vrf_id;
+       api.cap = type;
+
+       if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES,
+                                     zclient, &api) < 0) {
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("error sending capability");
+               return BGP_GR_FAILURE;
+       }
+       return BGP_GR_SUCCESS;
+}
+
+
+int zclient_capabilities_send(uint32_t cmd, struct zclient *zclient,
+               struct zapi_cap *api)
+{
+       struct stream *s;
+
+       if (zclient == NULL)
+               return -1;
+
+       s = zclient->obuf;
+       stream_reset(s);
+       zclient_create_header(s, cmd, 0);
+       stream_putl(s, api->cap);
+       switch (api->cap) {
+       case ZEBRA_CLIENT_GR_CAPABILITIES:
+       case ZEBRA_CLIENT_RIB_STALE_TIME:
+                       stream_putl(s, api->stale_removal_time);
+                       stream_putl(s, api->vrf_id);
+                       break;
+       case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+       case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+                       stream_putl(s, api->afi);
+                       stream_putl(s, api->safi);
+                       stream_putl(s, api->vrf_id);
+                       break;
+       case ZEBRA_CLIENT_GR_DISABLE:
+                       stream_putl(s, api->vrf_id);
+                       break;
+       default:
+                       break;
+       }
+
+       /* Put length at the first point of the stream */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zclient_send_message(zclient);
+}
+
+/* Send RIB stale timer update */
+int bgp_zebra_stale_timer_update(struct bgp *bgp)
+{
+       struct zapi_cap api;
+
+       if (zclient == NULL) {
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("zclient invalid");
+               return BGP_GR_FAILURE;
+       }
+
+       /* Check if the client is connected */
+       if ((zclient->sock < 0) || (zclient->t_connect)) {
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("client not connected");
+               return BGP_GR_FAILURE;
+       }
+
+       memset(&api, 0, sizeof(struct zapi_cap));
+       api.cap = ZEBRA_CLIENT_RIB_STALE_TIME;
+       api.stale_removal_time = bgp->rib_stale_time;
+       api.vrf_id = bgp->vrf_id;
+       if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES,
+                               zclient, &api) < 0) {
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("error sending capability");
+               return BGP_GR_FAILURE;
+       }
+       if (BGP_DEBUG(zebra, ZEBRA))
+               zlog_debug("send capabilty success");
+       return BGP_GR_SUCCESS;
+}
index 62c311cc1d086c83d0f20cff0167c5cc96f692a6..c0e305286ecfea96e006a485cb06e32d348dc045 100644 (file)
@@ -80,11 +80,11 @@ extern int bgp_zebra_num_connects(void);
 
 extern bool bgp_zebra_nexthop_set(union sockunion *, union sockunion *,
                                  struct bgp_nexthop *, struct peer *);
-
 struct bgp_pbr_action;
 struct bgp_pbr_match;
 struct bgp_pbr_rule;
 struct bgp_pbr_match_entry;
+
 extern void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra,
                                     struct bgp_pbr_rule *pbr,
                                     bool install);
@@ -98,5 +98,8 @@ extern void bgp_send_pbr_iptable(struct bgp_pbr_action *pba,
 
 extern void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
                                afi_t afi, uint32_t table_id, bool announce);
-
+extern int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable);
+extern int bgp_zebra_update(afi_t afi, safi_t safi, vrf_id_t vrf_id,
+                           int type);
+extern int bgp_zebra_stale_timer_update(struct bgp *bgp);
 #endif /* _QUAGGA_BGP_ZEBRA_H */
index 9b0e81491a89bebc63f785bf963c2ebf93b744c8..29ae0c109d88046981a438d990f4b7d3234cc08b 100644 (file)
@@ -1102,6 +1102,119 @@ struct peer *peer_unlock_with_caller(const char *name, struct peer *peer)
 
        return peer;
 }
+/* BGP GR changes */
+
+int bgp_global_gr_init(struct bgp *bgp)
+{
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug("%s called ..", __func__);
+
+       int local_GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE][BGP_GLOBAL_GR_EVENT_CMD] = {
+               /* GLOBAL_HELPER Mode  */
+               {
+               /*Event -> */
+               /*GLOBAL_GR_cmd*/  /*no_Global_GR_cmd*/
+                       GLOBAL_GR,      GLOBAL_INVALID,
+               /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/
+                       GLOBAL_DISABLE, GLOBAL_INVALID
+               },
+               /* GLOBAL_GR Mode */
+               {
+               /*Event -> */
+               /*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/
+                       GLOBAL_INVALID,  GLOBAL_HELPER,
+               /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/
+                       GLOBAL_DISABLE,  GLOBAL_INVALID
+               },
+               /* GLOBAL_DISABLE Mode  */
+               {
+               /*Event -> */
+               /*GLOBAL_GR_cmd */      /*no_Global_GR_cmd*/
+                       GLOBAL_GR,      GLOBAL_INVALID,
+               /*GLOBAL_DISABLE_cmd*//*no_Global_Disable_cmd*/
+                       GLOBAL_INVALID, GLOBAL_HELPER
+               },
+               /* GLOBAL_INVALID Mode  */
+               {
+               /*Event -> */
+               /*GLOBAL_GR_cmd*/       /*no_Global_GR_cmd*/
+                       GLOBAL_INVALID, GLOBAL_INVALID,
+               /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/
+                       GLOBAL_INVALID, GLOBAL_INVALID
+               }
+       };
+       memcpy(bgp->GLOBAL_GR_FSM, local_GLOBAL_GR_FSM,
+                                       sizeof(local_GLOBAL_GR_FSM));
+
+       bgp->global_gr_present_state = GLOBAL_HELPER;
+       bgp->present_zebra_gr_state = ZEBRA_GR_DISABLE;
+
+       return BGP_GR_SUCCESS;
+}
+
+int bgp_peer_gr_init(struct peer *peer)
+{
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug("%s called ..", __func__);
+
+       struct bgp_peer_gr local_Peer_GR_FSM[BGP_PEER_GR_MODE]
+                                       [BGP_PEER_GR_EVENT_CMD] = {
+       {
+       /*      PEER_HELPER Mode        */
+       /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+               { PEER_GR, bgp_peer_gr_action }, {PEER_INVALID, NULL },
+       /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+               {PEER_DISABLE, bgp_peer_gr_action }, {PEER_INVALID, NULL },
+       /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
+               { PEER_INVALID, NULL }, {PEER_GLOBAL_INHERIT,
+                                               bgp_peer_gr_action }
+       },
+       {
+       /*      PEER_GR Mode    */
+       /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+               { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT,
+                                               bgp_peer_gr_action },
+       /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+               {PEER_DISABLE, bgp_peer_gr_action }, { PEER_INVALID, NULL },
+       /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
+               { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL }
+       },
+       {
+       /*      PEER_DISABLE Mode       */
+       /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+               { PEER_GR, bgp_peer_gr_action }, { PEER_INVALID, NULL },
+       /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+               { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT,
+                                               bgp_peer_gr_action },
+       /* Event-> */ /* PEER_HELPER_cmd */  /* NO_PEER_HELPER_CMD */
+               { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL }
+       },
+       {
+       /*      PEER_INVALID Mode       */
+       /* Event-> */ /* PEER_GR_CMD */  /* NO_PEER_GR_CMD */
+               { PEER_INVALID, NULL }, { PEER_INVALID, NULL },
+       /* Event-> */ /* PEER_DISABLE_CMD */  /* NO_PEER_DISABLE_CMD */
+               { PEER_INVALID, NULL }, { PEER_INVALID, NULL },
+       /* Event-> */ /* PEER_HELPER_cmd */  /* NO_PEER_HELPER_CMD */
+               { PEER_INVALID, NULL }, { PEER_INVALID, NULL },
+       },
+       {
+       /*      PEER_GLOBAL_INHERIT Mode        */
+       /* Event-> */ /* PEER_GR_CMD */         /* NO_PEER_GR_CMD */
+               { PEER_GR, bgp_peer_gr_action }, { PEER_INVALID, NULL },
+       /* Event-> */ /* PEER_DISABLE_CMD */     /* NO_PEER_DISABLE_CMD */
+               { PEER_DISABLE, bgp_peer_gr_action}, { PEER_INVALID, NULL },
+       /* Event-> */ /* PEER_HELPER_cmd */     /* NO_PEER_HELPER_CMD */
+               { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL }
+       }
+       };
+       memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM,
+                                       sizeof(local_Peer_GR_FSM));
+       peer->peer_gr_present_state = PEER_GLOBAL_INHERIT;
+       bgp_peer_move_to_gr_mode(peer, PEER_GLOBAL_INHERIT);
+
+       return BGP_GR_SUCCESS;
+}
 
 /* Allocate new peer object, implicitely locked.  */
 struct peer *peer_new(struct bgp *bgp)
@@ -1153,6 +1266,9 @@ struct peer *peer_new(struct bgp *bgp)
 
        SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
 
+       /* Initialize per peer bgp GR FSM */
+       bgp_peer_gr_init(peer);
+
        /* Create buffers.  */
        peer->ibuf = stream_fifo_new();
        peer->obuf = stream_fifo_new();
@@ -1212,6 +1328,9 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
        peer_dst->flags = peer_src->flags;
        peer_dst->cap = peer_src->cap;
 
+       peer_dst->peer_gr_present_state = peer_src->peer_gr_present_state;
+       peer_dst->peer_gr_new_status_flag = peer_src->peer_gr_new_status_flag;
+
        peer_dst->local_as = peer_src->local_as;
        peer_dst->port = peer_src->port;
        (void)peer_sort(peer_dst);
@@ -1534,6 +1653,11 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
        else if (!active && peer_active(peer))
                bgp_timer_set(peer);
 
+       bgp_peer_gr_flags_update(peer);
+       BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(
+               bgp,
+               bgp->peer);
+
        return peer;
 }
 
@@ -2098,7 +2222,7 @@ int peer_afc_set(struct peer *peer, afi_t afi, safi_t safi, int enable)
                return peer_deactivate(peer, afi, safi);
 }
 
-static void peer_nsf_stop(struct peer *peer)
+void peer_nsf_stop(struct peer *peer)
 {
        afi_t afi;
        safi_t safi;
@@ -2902,6 +3026,12 @@ static struct bgp *bgp_create(as_t *as, const char *name,
                                      multipath_num, 0);
                bgp_maximum_paths_set(bgp, afi, safi, BGP_PEER_IBGP,
                                      multipath_num, 0);
+               /* Initialize graceful restart info */
+               bgp->gr_info[afi][safi].eor_required = 0;
+               bgp->gr_info[afi][safi].eor_received = 0;
+               bgp->gr_info[afi][safi].t_select_deferral = NULL;
+               bgp->gr_info[afi][safi].t_route_select = NULL;
+               bgp->gr_info[afi][safi].route_list = list_new();
        }
 
        bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
@@ -2911,6 +3041,8 @@ static struct bgp *bgp_create(as_t *as, const char *name,
        bgp_timers_unset(bgp);
        bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
        bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME;
+       bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME;
+       bgp->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME;
        bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT;
        bgp->dynamic_neighbors_count = 0;
        bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED;
@@ -2941,14 +3073,11 @@ static struct bgp *bgp_create(as_t *as, const char *name,
                bgp->vpn_policy[afi].export_vrf->del =
                        bgp_vrf_string_name_delete;
        }
-       if (name) {
+       if (name)
                bgp->name = XSTRDUP(MTYPE_BGP, name);
-       } else {
-               /* TODO - The startup timer needs to be run for the whole of BGP
-                */
-               thread_add_timer(bm->master, bgp_startup_timer_expire, bgp,
-                                bgp->restart_time, &bgp->t_startup);
-       }
+
+       thread_add_timer(bm->master, bgp_startup_timer_expire, bgp,
+                               bgp->restart_time, &bgp->t_startup);
 
        /* printable name we can use in debug messages */
        if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
@@ -2990,6 +3119,9 @@ static struct bgp *bgp_create(as_t *as, const char *name,
 
        bgp_evpn_init(bgp);
        bgp_pbr_init(bgp);
+
+       /*initilize global GR FSM */
+       bgp_global_gr_init(bgp);
        return bgp;
 }
 
@@ -3233,7 +3365,9 @@ int bgp_delete(struct bgp *bgp)
        struct listnode *node, *next;
        struct vrf *vrf;
        afi_t afi;
+       safi_t safi;
        int i;
+       struct graceful_restart_info *gr_info;
 
        assert(bgp);
 
@@ -3247,6 +3381,18 @@ int bgp_delete(struct bgp *bgp)
        /* Set flag indicating bgp instance delete in progress */
        bgp_flag_set(bgp, BGP_FLAG_DELETE_IN_PROGRESS);
 
+       /* Delete the graceful restart info */
+       FOREACH_AFI_SAFI (afi, safi) {
+               gr_info = &bgp->gr_info[afi][safi];
+               if (!gr_info)
+                       continue;
+
+               BGP_TIMER_OFF(gr_info->t_select_deferral);
+               BGP_TIMER_OFF(gr_info->t_route_select);
+               if (gr_info->route_list)
+                       list_delete(&gr_info->route_list);
+       }
+
        if (BGP_DEBUG(zebra, ZEBRA)) {
                if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
                        zlog_debug("Deleting Default VRF");
@@ -7099,3 +7245,33 @@ struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
        return peer;
 }
 
+void bgp_gr_apply_running_config(void)
+{
+       struct peer *peer = NULL;
+       struct bgp *bgp = NULL;
+       struct listnode *node, *nnode;
+       bool gr_router_detected = false;
+
+       if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+               zlog_debug("[BGP_GR] %s called !",
+                               __func__);
+
+       for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+               for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+                       bgp_peer_gr_flags_update(peer);
+                       if (CHECK_FLAG(peer->flags,
+                                               PEER_FLAG_GRACEFUL_RESTART))
+                               gr_router_detected = true;
+               }
+
+               if (gr_router_detected &&
+                       bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
+                       bgp_zebra_send_capabilities(bgp, true);
+               } else if (!gr_router_detected &&
+                       bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
+                       bgp_zebra_send_capabilities(bgp, false);
+               }
+
+               gr_router_detected = false;
+       }
+}
index 4c4787ed5b9902d0c03ce88733238569c9fecf1b..3f33139ef2389a1d4c7a47582f70c9278e4b3f96 100644 (file)
@@ -65,6 +65,12 @@ enum { AS_UNSPECIFIED = 0,
        AS_EXTERNAL,
 };
 
+/* Zebra Gracaful Restart states */
+enum zebra_gr_mode {
+       ZEBRA_GR_DISABLE = 0,
+       ZEBRA_GR_ENABLE
+};
+
 /* Typedef BGP specific types.  */
 typedef uint32_t as_t;
 typedef uint16_t as16_t; /* we may still encounter 16 Bit asnums */
@@ -232,6 +238,52 @@ enum bgp_instance_type {
        BGP_INSTANCE_TYPE_VIEW
 };
 
+#define BGP_SEND_EOR(bgp, afi, safi)                           \
+       (!bgp_flag_check(bgp, BGP_FLAG_GR_DISABLE_EOR) &&       \
+       ((bgp->gr_info[afi][safi].t_select_deferral == NULL) || \
+        (bgp->gr_info[afi][safi].eor_required ==               \
+         bgp->gr_info[afi][safi].eor_received)))
+
+/* BGP GR Global ds */
+
+#define BGP_GLOBAL_GR_MODE 4
+#define BGP_GLOBAL_GR_EVENT_CMD 4
+
+/* Graceful restart selection deferral timer info */
+struct graceful_restart_info {
+       /* Count of EOR message expected */
+       uint32_t eor_required;
+       /* Count of EOR received */
+       uint32_t eor_received;
+       /* Deferral Timer */
+       struct thread *t_select_deferral;
+       /* Route list */
+       struct list *route_list;
+       /* Best route select */
+       struct thread *t_route_select;
+       /* AFI, SAFI enabled */
+       bool af_enabled[AFI_MAX][SAFI_MAX];
+       /* Route update completed */
+       bool route_sync[AFI_MAX][SAFI_MAX];
+};
+
+enum global_mode {
+       GLOBAL_HELPER = 0, /* This is the default mode */
+       GLOBAL_GR,
+       GLOBAL_DISABLE,
+       GLOBAL_INVALID
+};
+
+enum global_gr_command {
+       GLOBAL_GR_CMD = 0,
+       NO_GLOBAL_GR_CMD,
+       GLOBAL_DISABLE_CMD,
+       NO_GLOBAL_DISABLE_CMD
+};
+
+#define BGP_GR_SUCCESS 0
+#define BGP_GR_FAILURE 1
+
 /* BGP instance structure.  */
 struct bgp {
        /* AS number of this BGP instance.  */
@@ -356,7 +408,10 @@ struct bgp {
 #define BGP_FLAG_IMPORT_CHECK             (1 << 9)
 #define BGP_FLAG_NO_FAST_EXT_FAILOVER     (1 << 10)
 #define BGP_FLAG_LOG_NEIGHBOR_CHANGES     (1 << 11)
+
+/* This flag is set when we have full BGP Graceful-Restart mode enable */
 #define BGP_FLAG_GRACEFUL_RESTART         (1 << 12)
+
 #define BGP_FLAG_ASPATH_CONFED            (1 << 13)
 #define BGP_FLAG_ASPATH_MULTIPATH_RELAX   (1 << 14)
 #define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 15)
@@ -367,6 +422,17 @@ struct bgp {
 #define BGP_FLAG_GR_PRESERVE_FWD          (1 << 20)
 #define BGP_FLAG_GRACEFUL_SHUTDOWN        (1 << 21)
 #define BGP_FLAG_DELETE_IN_PROGRESS       (1 << 22)
+#define BGP_FLAG_SELECT_DEFER_DISABLE     (1 << 23)
+#define BGP_FLAG_GR_DISABLE_EOR           (1 << 24)
+
+       enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE]
+                               [BGP_GLOBAL_GR_EVENT_CMD];
+       enum global_mode global_gr_present_state;
+
+       /* This variable stores the current Graceful Restart state of Zebra
+        * - ZEBRA_GR_ENABLE / ZEBRA_GR_DISABLE
+        */
+       enum zebra_gr_mode present_zebra_gr_state;
 
        /* BGP Per AF flags */
        uint16_t af_flags[AFI_MAX][SAFI_MAX];
@@ -462,7 +528,12 @@ struct bgp {
        /* BGP graceful restart */
        uint32_t restart_time;
        uint32_t stalepath_time;
+       uint32_t select_defer_time;
+       struct graceful_restart_info gr_info[AFI_MAX][SAFI_MAX];
+       uint32_t rib_stale_time;
 
+#define BGP_ROUTE_SELECT_DELAY 1
+#define BGP_MAX_BEST_ROUTE_SELECT 10000
        /* Maximum-paths configuration */
        struct bgp_maxpaths_cfg {
                uint16_t maxpaths_ebgp;
@@ -548,7 +619,6 @@ struct bgp {
 #define BGP_VRF_RD_CFGD                     (1 << 3)
 #define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY    (1 << 4)
 
-
        /* unique ID for auto derivation of RD for this vrf */
        uint16_t vrf_rd_id;
 
@@ -589,6 +659,13 @@ DECLARE_HOOK(bgp_inst_config_write,
                (struct bgp *bgp, struct vty *vty),
                (bgp, vty))
 
+       /* Thread callback information */
+       struct afi_safi_info {
+               afi_t afi;
+               safi_t safi;
+               struct bgp *bgp;
+       };
+
 #define BGP_ROUTE_ADV_HOLD(bgp) (bgp->main_peers_update_hold)
 
 #define IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)                                        \
@@ -596,6 +673,9 @@ DECLARE_HOOK(bgp_inst_config_write,
         || (bgp->inst_type == BGP_INSTANCE_TYPE_VRF                           \
             && bgp->vrf_id != VRF_UNKNOWN))
 
+#define BGP_SELECT_DEFER_DISABLE(bgp)                 \
+       (bgp_flag_check(bgp, BGP_FLAG_SELECT_DEFER_DISABLE))
+
 /* BGP peer-group support. */
 struct peer_group {
        /* Name of the peer-group. */
@@ -726,6 +806,36 @@ struct peer_af {
        safi_t safi;
        int afid;
 };
+/* BGP GR per peer ds */
+
+#define BGP_PEER_GR_MODE 5
+#define BGP_PEER_GR_EVENT_CMD 6
+
+enum peer_mode {
+       PEER_HELPER = 0,
+       PEER_GR,
+       PEER_DISABLE,
+       PEER_INVALID,
+       PEER_GLOBAL_INHERIT /* This is the default mode */
+
+};
+
+enum peer_gr_command {
+       PEER_GR_CMD = 0,
+       NO_PEER_GR_CMD,
+       PEER_DISABLE_CMD,
+       NO_PEER_DISABLE_CMD,
+       PEER_HELPER_CMD,
+       NO_PEER_HELPER_CMD
+};
+
+typedef unsigned int  (*bgp_peer_gr_action_ptr)(struct peer *, int, int);
+
+struct bgp_peer_gr {
+       enum peer_mode next_state;
+       bgp_peer_gr_action_ptr action_fun;
+};
+
 
 /* BGP neighbor structure. */
 struct peer {
@@ -947,11 +1057,36 @@ struct peer {
 #define PEER_FLAG_LOCAL_AS                  (1 << 21) /* local-as */
 #define PEER_FLAG_UPDATE_SOURCE             (1 << 22) /* update-source */
 
+       /* BGP-GR Peer related  flags */
+#define PEER_FLAG_GRACEFUL_RESTART_HELPER   (1 << 23) /* Helper */
+#define PEER_FLAG_GRACEFUL_RESTART          (1 << 24) /* Graceful Restart */
+#define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1 << 25) /* Global-Inherit */
+
+       /*
+        *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
+        *& PEER_FLAG_GRACEFUL_RESTART_HELPER
+        *and PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT
+        */
+
+       struct bgp_peer_gr PEER_GR_FSM[BGP_PEER_GR_MODE][BGP_PEER_GR_EVENT_CMD];
+       enum peer_mode peer_gr_present_state;
+       /* Non stop forwarding afi-safi count for BGP gr feature*/
+       uint8_t nsf_af_count;
+
+       uint8_t peer_gr_new_status_flag;
+#define PEER_GRACEFUL_RESTART_NEW_STATE_HELPER   (1 << 0)
+#define PEER_GRACEFUL_RESTART_NEW_STATE_RESTART  (1 << 1)
+#define PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT  (1 << 2)
+
        /* outgoing message sent in CEASE_ADMIN_SHUTDOWN notify */
        char *tx_shutdown_message;
 
        /* NSF mode (graceful restart) */
        uint8_t nsf[AFI_MAX][SAFI_MAX];
+       /* EOR Send time */
+       time_t eor_stime[AFI_MAX][SAFI_MAX];
+       /* Last update packet sent time */
+       time_t pkt_stime[AFI_MAX][SAFI_MAX];
 
        /* Peer Per AF flags */
        /*
@@ -1456,6 +1591,8 @@ struct bgp_nlri {
 /* BGP graceful restart  */
 #define BGP_DEFAULT_RESTART_TIME               120
 #define BGP_DEFAULT_STALEPATH_TIME             360
+#define BGP_DEFAULT_SELECT_DEFERRAL_TIME       360
+#define BGP_DEFAULT_RIB_STALE_TIME             500
 
 /* BGP uptime string length.  */
 #define BGP_UPTIME_LEN 25
@@ -1521,6 +1658,11 @@ enum bgp_clear_type {
 #define BGP_ERR_INVALID_FOR_DIRECT_PEER         -34
 #define BGP_ERR_PEER_SAFI_CONFLICT              -35
 
+/* BGP GR ERRORS */
+#define BGP_ERR_GR_INVALID_CMD                  -36
+#define BGP_ERR_GR_OPERATION_FAILED             -37
+#define BGP_GR_NO_OPERATION                     -38
+
 /*
  * Enumeration of different policy kinds a peer can be configured with.
  */
@@ -1773,6 +1915,36 @@ extern int peer_af_delete(struct peer *, afi_t, safi_t);
 
 extern void bgp_close(void);
 extern void bgp_free(struct bgp *);
+void bgp_gr_apply_running_config(void);
+
+/* BGP GR */
+int bgp_global_gr_init(struct bgp *bgp);
+int bgp_peer_gr_init(struct peer *peer);
+
+
+#define BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA( \
+               _bgp, _peer_list) \
+do { \
+       struct peer *peer_loop; \
+       bool gr_router_detected = false; \
+       struct listnode *node = {0}; \
+       struct listnode *nnode = {0}; \
+       for (ALL_LIST_ELEMENTS( \
+                               _peer_list, node, \
+                               nnode, peer_loop)) { \
+               if (CHECK_FLAG( \
+                               peer_loop->flags, \
+                               PEER_FLAG_GRACEFUL_RESTART)) \
+                       gr_router_detected = true; \
+       } \
+       if (gr_router_detected && \
+                       _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \
+               bgp_zebra_send_capabilities(_bgp, false); \
+       } else if (!gr_router_detected && \
+                       _bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \
+               bgp_zebra_send_capabilities(_bgp, true); \
+       } \
+} while (0)
 
 static inline struct bgp *bgp_lock(struct bgp *bgp)
 {
@@ -1962,5 +2134,6 @@ extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
 
 /* Hooks */
 DECLARE_HOOK(peer_status_changed, (struct peer * peer), (peer))
+void peer_nsf_stop(struct peer *peer);
 
 #endif /* _QUAGGA_BGPD_H */
index d9c4c5bf0c15245d4082feb0f9b9fe23f25eb9f7..458cfa0ad47d45d3b1ad4c71ac7a2d85be636965 100644 (file)
@@ -22,6 +22,11 @@ Tested on CentOS 6, CentOS 7, CentOS 8 and Fedora 24.
 
       yum install systemd-devel
 
+   For CentOS 7 and CentOS 8, the package will be built using python3
+   and requires additional python3 packages::
+
+       yum install python3-devel python3-sphinx
+
    .. note::
 
      For CentOS 8 you need to install ``platform-python-devel`` package
@@ -29,13 +34,6 @@ Tested on CentOS 6, CentOS 7, CentOS 8 and Fedora 24.
 
        yum install platform-python-devel
 
-   .. warning::
-
-     ``python2-sphinx`` is not shipped for CentOS 8.
-     Development reached the end of life for Python 2.
-     We need to install it using ```pip``::
-
-        pip2 install sphinx
 
    If ``yum`` is not present on your system, use ``dnf`` instead.
 
index d3ac4b22ab0473a349d63983f39f6560f7682ba7..81b4e34647bbbd99fc95b52b7897e47223595abc 100644 (file)
@@ -694,6 +694,181 @@ from eBGP peers, :ref:`bgp-route-selection`.
    MED as an intra-AS metric to steer equal-length AS_PATH routes to, e.g.,
    desired exit points.
 
+
+.. _bgp-graceful-restart:
+
+Graceful Restart
+----------------
+
+BGP graceful restart functionality as defined in
+`RFC-4724 <https://tools.ietf.org/html/rfc4724/>`_ defines the mechanisms that
+allows BGP speaker to continue to forward data packets along known routes
+while the routing protocol information is being restored.
+
+
+Usually, when BGP on a router restarts, all the BGP peers detect that the
+session went down and then came up. This "down/up" transition results in a
+"routing flap" and causes BGP route re-computation, generation of BGP routing
+updates, and unnecessary churn to the forwarding tables.
+
+The following functionality is provided by graceful restart:
+
+1. The feature allows the restarting router to indicate to the helping peer the
+   routes it can preserve in its forwarding plane during control plane restart
+   by sending graceful restart capability in the OPEN message sent during
+   session establishment.
+2. The feature allows helping router to advertise to all other peers the routes
+   received from the restarting router which are preserved in the forwarding
+   plane of the restarting router during control plane restart.
+
+
+::
+
+
+
+ (R1)-----------------------------------------------------------------(R2)
+
+ 1. BGP Graceful Restart Capability exchanged between R1 & R2.
+
+ <--------------------------------------------------------------------->
+
+ 2. Kill BGP Process at R1.
+
+ ---------------------------------------------------------------------->
+
+ 3. R2 Detects the above BGP Restart & verifies BGP Restarting
+   Capability of R1.
+
+ 4. Start BGP Process at R1.
+
+ 5. Re-establish the BGP session between R1 & R2.
+
+ <--------------------------------------------------------------------->
+
+ 6. R2 Send initial route updates, followed by End-Of-Rib.
+
+ <----------------------------------------------------------------------
+
+ 7. R1 was waiting for End-Of-Rib from R2 & which has been received
+   now.
+
+ 8. R1 now runs BGP Best-Path algorithm. Send Initial BGP  Update,
+   followed by End-Of Rib
+
+ <--------------------------------------------------------------------->
+
+
+.. _bgp-end-of-rib-message:
+
+End-of-RIB (EOR) message
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+An UPDATE message with no reachable Network Layer Reachability  Information
+(NLRI) and empty withdrawn NLRI is specified as the End-of-RIB marker that can
+be used by a BGP speaker to indicate to its peer the completion of the initial
+routing update after the session is established.
+
+For the IPv4 unicast address family, the End-of-RIB marker is an UPDATE message
+with the minimum length. For any other address family, it is an UPDATE message
+that contains only the MP_UNREACH_NLRI attribute with no withdrawn routes for
+that <AFI, SAFI>.
+
+Although the End-of-RIB marker is specified for the purpose of BGP graceful
+restart, it is noted that the generation of such a marker upon completion of
+the initial update would be useful for routing convergence in general, and thus
+the practice is recommended.
+
+.. _bgp-route-selection-deferral-timer:
+
+Route Selection Deferral Timer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Specifies the time the restarting router defers the route selection process
+after restart.
+
+Restarting Router : The usage of route election deferral timer is specified
+in https://tools.ietf.org/html/rfc4724#section-4.1
+
+Once the session between the Restarting Speaker and the Receiving Speaker is
+re-established, the Restarting Speaker will receive and process BGP messages
+from its peers.
+
+However, it MUST defer route selection for an address family until it either.
+
+1. Receives the End-of-RIB marker from all its peers (excluding the ones with
+   the "Restart State" bit set in the received capability and excluding the ones
+   that do not advertise the graceful restart capability).
+2. The Selection_Deferral_Timer timeout.
+
+.. index:: bgp graceful-restart select-defer-time (0-3600)
+.. clicmd:: bgp graceful-restart select-defer-time (0-3600)
+
+   This is command, will set deferral time to value specified.
+
+
+.. index:: bgp graceful-restart rib-stale-time (1-3600)
+.. clicmd:: bgp graceful-restart rib-stale-time (1-3600)
+
+   This is command, will set the time for which stale routes are kept in RIB.
+
+.. _bgp-per-peer-graceful-restart:
+
+BGP Per Peer Graceful Restart
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Ability to enable and disable graceful restart, helper and no GR at all mode
+functionality at peer level.
+
+So bgp graceful restart can be enabled at modes  global BGP level or at per
+peer level. There are two FSM, one for BGP GR global mode and other for peer
+per GR.
+
+Default global mode is helper and default peer per mode is inherit from global.
+If per peer mode is configured, the GR mode of this particular peer will
+override the global mode.
+
+.. _bgp-GR-global-mode-cmd:
+
+BGP GR Global Mode Commands
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. index:: bgp graceful-restart
+.. clicmd:: bgp graceful-restart
+
+   This command will enable BGP graceful restart ifunctionality at the global
+   level.
+
+.. index:: bgp graceful-restart disable
+.. clicmd:: bgp graceful-restart disable
+
+   This command will disable both the functionality graceful restart and helper
+   mode.
+
+
+.. _bgp-GR-peer-mode-cmd:
+
+BGP GR Peer Mode Commands
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. index:: neighbor A.B.C.D graceful-restart
+.. clicmd:: neighbor A.B.C.D graceful-restart
+
+   This command will enable BGP graceful restart ifunctionality at the peer
+   level.
+
+.. index:: neighbor A.B.C.D graceful-restart-helper
+.. clicmd:: neighbor A.B.C.D graceful-restart-helper
+
+   This command will enable BGP graceful restart helper only functionality
+   at the peer level.
+
+.. index:: neighbor A.B.C.D graceful-restart-disable
+.. clicmd:: neighbor A.B.C.D graceful-restart-disable
+
+   This command will disable the entire BGP graceful restart functionality
+   at the peer level.
+
+
 .. _bgp-network:
 
 Networks
index 2300cb0e19e81b0b6f5d3d4b43d5bd0c597a0c5b..cd095af8620c4e4758bce6e03088177109412f41 100644 (file)
@@ -128,6 +128,18 @@ OSPF6 interface
 
    Set explicitly network type for specified interface.
 
+OSPF6 route-map
+===============
+
+Usage of *ospfd6*'s route-map support.
+
+.. index:: set metric [+|-](0-4294967295)
+.. clicmd:: set metric [+|-](0-4294967295)
+
+   Set a metric for matched route when sending announcement. Use plus (+) sign
+   to add a metric value to an existing metric. Use minus (-) sign to
+   substract a metric value from an existing metric.
+
 .. _redistribute-routes-to-ospf6:
 
 Redistribute routes to OSPF6
index e6ff59d27c602f47fbab3cd61578150a77913c56..75768269fe32ac5f6fc30255efb98a53e39250bb 100644 (file)
@@ -710,6 +710,18 @@ Interfaces
 
    Enable ospf on an interface and set associated area.
 
+OSPF route-map
+==============
+
+Usage of *ospfd*'s route-map support.
+
+.. index:: set metric [+|-](0-4294967295)
+.. clicmd:: set metric [+|-](0-4294967295)
+
+   Set a metric for matched route when sending announcement. Use plus (+) sign
+   to add a metric value to an existing metric. Use minus (-) sign to
+   substract a metric value from an existing metric.
+
 .. _redistribute-routes-to-ospf:
 
 Redistribution
index 6d569f5fb0a6650a4ee76e157eff39a3c87d9651..dd754a92ee115ac29689685a001e3e9d78d450f4 100644 (file)
@@ -22,6 +22,14 @@ administrator with an external editor.
    have effect for vtysh) need to be manually updated in :file:`vtysh.conf`.
 
 
+.. index:: copy FILENAME running-config
+.. clicmd:: copy FILENAME running-config
+
+   Process and load a configuration file manually; each line in the
+   file is read and processed as if it were being typed (or piped) to
+   vtysh.
+
+
 Pager usage
 ===========
 
index 23a062ab02f00e4211c4d23bb5d16bc59cc4e888..520080e83a993903dcfce10cdb16eaf68f3ecaec 100644 (file)
@@ -911,10 +911,14 @@ zebra Terminal Mode Commands
    Reset statistics related to the zebra code that interacts with the
    optional Forwarding Plane Manager (FPM) component.
 
-.. index:: show nexthop-group [ID] [vrf NAME] [ip|ipv6]
-.. clicmd:: show nexthop-group [ID] [vrf NAME] [ip|ipv6]
-
-   Display nexthop groups created by zebra.
+.. index:: show nexthop-group rib [ID] [vrf NAME] [singleton [ip|ip6]]
+.. clicmd:: show nexthop-group rib [ID] [vrf NAME]
+
+   Display nexthop groups created by zebra.  The [vrf NAME] option
+   is only meaningful if you have started zebra with the --vrfwnetns
+   option as that nexthop groups are per namespace in linux.
+   If you specify singleton you would like to see the singleton
+   nexthop groups that do have an afi.
 
 
 Router-id
index c8dd04604dd4338ef6f9073301ec4c35f6ccfd6f..ea8a76a964f73881650b59a88a59f6976c5bc643 100644 (file)
@@ -418,8 +418,23 @@ struct cmd_node {
 #define DAEMONS_LIST                                                           \
        "<zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|pbrd|fabricd|pimd|staticd|sharpd|vrrpd|ldpd>"
 
+/* Graceful Restart cli help strings */
+#define GR_CMD "Global Graceful Restart command\n"
+#define NO_GR_CMD "Undo Global Graceful Restart command\n"
+#define GR "Global Graceful Restart - GR Mode\n"
+#define GR_DISABLE "Global Graceful Restart - Disable Mode\n"
+#define NO_GR_DISABLE "Undo Global Graceful Restart - Disable Mode\n"
+#define GR_DEBUG "Graceful Restart - Enable Debug Logs\n"
+#define GR_SHOW "Graceful Restart - Show command for Global and all neighbor mode\n"
+#define GR_NEIGHBOR_CMD "Graceful Restart command for a neighbor\n"
+#define NO_GR_NEIGHBOR_CMD "Undo Graceful Restart command for a neighbor\n"
+#define GR_NEIGHBOR_DISABLE_CMD "Graceful Restart Disable command for a neighbor\n"
+#define NO_GR_NEIGHBOR_DISABLE_CMD "Undo Graceful Restart Disable command for a neighbor\n"
+#define GR_NEIGHBOR_HELPER_CMD "Graceful Restart Helper command for a neighbor\n"
+#define NO_GR_NEIGHBOR_HELPER_CMD "Undo Graceful Restart Helper command for a neighbor\n"
+
 /* Prototypes. */
-extern void install_node(struct cmd_node *, int (*)(struct vty *));
+extern void install_node(struct cmd_node *node, int (*)(struct vty *));
 extern void install_default(enum node_type);
 extern void install_element(enum node_type, const struct cmd_element *);
 
index 219f798dcc947f2e713770070a0812e0d3a33a41..806df0b4c697be8583ed4cfd15e48a26141032ae 100644 (file)
@@ -1113,11 +1113,11 @@ in_addr_t ipv4_broadcast_addr(in_addr_t hostaddr, int masklen)
 
        masklen2ip(masklen, &mask);
        return (masklen != IPV4_MAX_PREFIXLEN - 1) ?
-                                                  /* normal case */
-                      (hostaddr | ~mask.s_addr)
-                                                  :
-                                                  /* special case for /31 */
-                      (hostaddr ^ ~mask.s_addr);
+               /* normal case */
+               (hostaddr | ~mask.s_addr)
+                  :
+               /* For prefix 31 return 255.255.255.255 (RFC3021) */
+               htonl(0xFFFFFFFF);
 }
 
 /* Utility function to convert ipv4 netmask to prefixes
index 667627ddfe804aa10e8b577ffdf622ada2942a89..fb80c4ca6cab9430f7bc3ceeb6b00ce49a1a5a91 100644 (file)
@@ -451,8 +451,7 @@ extern uint8_t ip_masklen(struct in_addr);
 extern void masklen2ip(const int, struct in_addr *);
 /* given the address of a host on a network and the network mask length,
  * calculate the broadcast address for that network;
- * special treatment for /31: returns the address of the other host
- * on the network by flipping the host bit */
+ * special treatment for /31 according to RFC3021 section 3.3 */
 extern in_addr_t ipv4_broadcast_addr(in_addr_t hostaddr, int masklen);
 
 extern int netmask_str2prefix_str(const char *, const char *, char *);
index b2c74cd0b90875201a155cd9fa019e9947e1ebc8..7ddf0085dee82257230518cbab5208d1fba7d12e 100644 (file)
@@ -3299,3 +3299,32 @@ void zclient_interface_set_master(struct zclient *client,
        stream_putw_at(s, 0, stream_get_endp(s));
        zclient_send_message(client);
 }
+
+/* Process capabilities message from zebra */
+int zapi_capabilities_decode(struct stream *s, struct zapi_cap *api)
+{
+       memset(api, 0, sizeof(*api));
+
+       STREAM_GETL(s, api->cap);
+       switch (api->cap) {
+       case ZEBRA_CLIENT_GR_CAPABILITIES:
+       case ZEBRA_CLIENT_RIB_STALE_TIME:
+                       STREAM_GETL(s, api->stale_removal_time);
+                       STREAM_GETL(s, api->vrf_id);
+                       break;
+       case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+       case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+                       STREAM_GETL(s, api->afi);
+                       STREAM_GETL(s, api->safi);
+                       STREAM_GETL(s, api->vrf_id);
+                       break;
+       case ZEBRA_CLIENT_GR_DISABLE:
+                       STREAM_GETL(s, api->vrf_id);
+                       break;
+       default:
+                       break;
+       }
+
+stream_failure:
+       return 0;
+}
index d1aa42da6d2ae078a5c16c255c17f017308c2330..bbc70c3835989541d4da368b9ad482ec3c7766a7 100644 (file)
@@ -73,6 +73,14 @@ typedef uint16_t zebra_size_t;
 #define ZEBRA_FEC_REGISTER_LABEL          0x1
 #define ZEBRA_FEC_REGISTER_LABEL_INDEX    0x2
 
+/* Client Graceful Restart */
+#define ZEBRA_CLIENT_GR_CAPABILITIES       0x1
+#define ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE 0x2
+#define ZEBRA_CLIENT_ROUTE_UPDATE_PENDING  0x3
+#define ZEBRA_CLIENT_GR_DISABLE            0x4
+#define ZEBRA_CLIENT_RIB_STALE_TIME        0x5
+#define ZEBRA_CLIENT_GR_ENABLED(X) (X & ZEBRA_CLIENT_GR_CAPABILITIES)
+
 extern struct sockaddr_storage zclient_addr;
 extern socklen_t zclient_addr_len;
 
@@ -184,6 +192,7 @@ typedef enum {
        ZEBRA_MLAG_CLIENT_UNREGISTER,
        ZEBRA_MLAG_FORWARD_MSG,
        ZEBRA_ERROR,
+       ZEBRA_CLIENT_CAPABILITIES
 } zebra_message_types_t;
 
 enum zebra_error_types {
@@ -222,6 +231,15 @@ struct zclient_capabilities {
        enum mlag_role role;
 };
 
+/* Graceful Restart Capabilities message */
+struct zapi_cap {
+       uint32_t  cap;
+       uint32_t  stale_removal_time;
+       afi_t     afi;
+       safi_t    safi;
+       vrf_id_t  vrf_id;
+};
+
 /* Structure for the zebra client. */
 struct zclient {
        /* The thread master we schedule ourselves on */
@@ -776,4 +794,7 @@ extern void zclient_send_mlag_deregister(struct zclient *client);
 extern void zclient_send_mlag_data(struct zclient *client,
                                   struct stream *client_s);
 
+extern int zclient_capabilities_send(uint32_t cmd, struct zclient *zclient,
+               struct zapi_cap *api);
+extern int zapi_capabilities_decode(struct stream *s, struct zapi_cap *api);
 #endif /* _ZEBRA_ZCLIENT_H */
index 670bc6f4c91060b7c6f1bb4dd8d721866be7149d..db465f2b00b61a803de458636d59f81f93924f09 100644 (file)
 %endif
 %endif
 
+# Check for python version - use python2.7 on CentOS 6, otherwise python3
+%if 0%{?rhel} && 0%{?rhel} < 7
+    %global use_python2 1
+%else
+    %global use_python2 0
+%endif
+
 # If init system is systemd, then always enable watchfrr
 %if "%{initsystem}" == "systemd"
     %global with_watchfrr 1
@@ -169,15 +176,18 @@ BuildRequires:  libyang-devel >= 0.16.74
 BuildRequires:  python27-devel
 BuildRequires:  python27-sphinx
 %else
-%if 0%{?rhel} && 0%{?rhel} > 7
-BuildRequires:  python2-devel
-#platform-python-devel is needed for /usr/bin/pathfix.py
-BuildRequires:  platform-python-devel
-%else
+%if %{use_python2}
 BuildRequires:  python-devel >= 2.7
 BuildRequires:  python-sphinx
+%else
+BuildRequires:  python3-devel
+BuildRequires:  python3-sphinx
 %endif
 %endif
+%if 0%{?rhel} > 7
+#platform-python-devel is needed for /usr/bin/pathfix.py
+BuildRequires:  platform-python-devel
+%endif
 Requires:       initscripts
 %if %{with_pam}
 BuildRequires:  pam-devel
@@ -223,12 +233,17 @@ Contributed/3rd party tools which may be of use with frr.
 
 %package pythontools
 Summary: python tools for frr
-%if 0%{?rhel} && 0%{?rhel} > 7
-BuildRequires: python2
-Requires: python2-ipaddress
+%if 0%{?rhel} && 0%{?rhel} < 7
+#python27 is available from ius community repo for RedHat/CentOS 6
+BuildRequires:  python27
+Requires:  python27-ipaddress
+%else
+%if %{use_python2}
+BuildRequires:  python2
+Requires:  python2-ipaddress
 %else
-BuildRequires: python
-Requires: python-ipaddress
+BuildRequires:  python3
+%endif
 %endif
 Group: System Environment/Daemons
 
@@ -369,6 +384,16 @@ developing OSPF-API and frr applications.
 
 make %{?_smp_mflags} MAKEINFO="makeinfo --no-split"
 
+%if %{use_python2}
+# Change frr-reload.py to use python2.7
+sed -e '1c #!/usr/bin/python2.7' -i %{zeb_src}/tools/frr-reload.py
+sed -e '1c #!/usr/bin/python2.7' -i %{zeb_src}/tools/generate_support_bundle.py
+%else
+# Change frr-reload.py to use python3
+sed -e '1c #!/usr/bin/python3' -i %{zeb_src}/tools/frr-reload.py
+sed -e '1c #!/usr/bin/python3' -i %{zeb_src}/tools/generate_support_bundle.py
+%endif
+
 pushd doc
 make info
 popd
@@ -408,10 +433,10 @@ install -m644 %{zeb_rh_src}/frr.pam %{buildroot}%{_sysconfdir}/pam.d/frr
 install -m644 %{zeb_rh_src}/frr.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/frr
 install -d -m750 %{buildroot}%{rundir}
 
-%if 0%{?rhel} && 0%{?rhel} > 7
+%if 0%{?rhel} > 7 || 0%{?fedora} > 29
 # avoid `ERROR: ambiguous python shebang in` errors
-pathfix.py -pni "%{__python2} %{py2_shbang_opts}" %{buildroot}/usr/lib/frr/*.py
-%py_byte_compile %{__python2} %{buildroot}/usr/lib/frr/*.py
+pathfix.py -pni "%{__python3} %{py3_shbang_opts}" %{buildroot}/usr/lib/frr/*.py
+%py_byte_compile %{__python3} %{buildroot}/usr/lib/frr/*.py
 %endif
 
 %pre
@@ -674,11 +699,16 @@ fi
 
 %files pythontools
 %{_sbindir}/generate_support_bundle.py
+%{_sbindir}/frr-reload.py
+%if 0%{?rhel} > 7 || 0%{?fedora} > 29
+%{_sbindir}/__pycache__/*
+%else
 %{_sbindir}/generate_support_bundle.pyc
 %{_sbindir}/generate_support_bundle.pyo
 %{_sbindir}/frr-reload.py
 %{_sbindir}/frr-reload.pyc
 %{_sbindir}/frr-reload.pyo
+%endif
 
 
 %files devel
index 21f4b38773c3f4d163c53a448250516f667f8229..a51ce4c6bc53fdc745e65fee0868785b12c0882b 100644 (file)
@@ -297,7 +297,25 @@ struct bgp_node test_rn;
 static int setup_bgp_path_info_mpath_update(testcase_t *t)
 {
        int i;
+       struct bgp *bgp;
+       struct bgp_table *rt;
+       struct route_node *rt_node;
+       as_t asn = 1;
+
+       t->tmp_data = bgp_create_fake(&asn, NULL);
+       if (!t->tmp_data)
+               return -1;
+
+       bgp = t->tmp_data;
+       rt = bgp->rib[AFI_IP][SAFI_UNICAST];
+
+       if (!rt)
+               return -1;
+
        str2prefix("42.1.1.0/24", &test_rn.p);
+       rt_node = bgp_node_to_rnode(&test_rn);
+       memcpy((struct route_table *)&rt_node->table, &rt->route_table,
+               sizeof(struct route_table));
        setup_bgp_mp_list(t);
        for (i = 0; i < test_mp_list_info_count; i++)
                bgp_path_info_add(&test_rn, &test_mp_list_info[i]);
@@ -352,7 +370,7 @@ static int cleanup_bgp_path_info_mpath_update(testcase_t *t)
        for (i = 0; i < test_mp_list_peer_count; i++)
                sockunion_free(test_mp_list_peer[i].su_remote);
 
-       return 0;
+       return bgp_delete((struct bgp *)t->tmp_data);
 }
 
 testcase_t test_bgp_path_info_mpath_update = {
index c9ca9c3d0df6d58d8a42bfc06cd4d449fb835f41..540b7a1357755d2fe5e95ec264ae3982e5e07f47 100755 (executable)
@@ -30,16 +30,16 @@ def createOutputFile(procName):
   oldFile = LOG_DIR + fileName
   cpFileCmd = "cp " + oldFile + " " + oldFile + ".prev"
   rmFileCmd = "rm -rf " + oldFile
-  print "Making backup of " + oldFile
+  print("Making backup of " + oldFile)
   os.system(cpFileCmd)
-  print "Removing " + oldFile
+  print("Removing " + oldFile)
   os.system(rmFileCmd)
   return fileName
 
 # Open the output file for this process
 def openOutputFile(fileName):
   crt_file_cmd = LOG_DIR + fileName
-  print crt_file_cmd
+  print(crt_file_cmd)
   try:
     outputFile = open(crt_file_cmd, "w")
     return outputFile
@@ -67,14 +67,14 @@ def executeCommand(cmd, outputFile):
       outputFile.write("########################################################\n")
       outputFile.write('\n')
     except:
-      print "Writing to ouptut file Failed"
+      print("Writing to ouptut file Failed")
   except subprocess.CalledProcessError as e:
     dateTime = datetime.datetime.now()
     outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n")
     outputFile.write(e.output)
     outputFile.write("########################################################\n")
     outputFile.write('\n')
-    print "Error:" + e.output
+    print("Error:" + e.output)
 
 
 # Process the support bundle configuration file
@@ -87,26 +87,26 @@ def processConfFile(lines):
     if cmd_line[0] == "PROC_NAME":
       outputFileName = createOutputFile(cmd_line[1])
       if outputFileName:
-        print outputFileName, "created for", cmd_line[1]
+        print(outputFileName, "created for", cmd_line[1])
     elif cmd_line[0] == "CMD_LIST_START":
       outputFile = openOutputFile(outputFileName)
       if outputFile:
-        print outputFileName, "opened"
+        print(outputFileName, "opened")
       else:
-        print outputFileName, "open failed"
-       return FAIL
+        print(outputFileName, "open failed")
+        return FAIL
     elif cmd_line[0] == "CMD_LIST_END":
       if closeOutputFile(outputFile):
-        print outputFileName, "closed"
+        print(outputFileName, "closed")
       else:
-        print outputFileName, "close failed"
+        print(outputFileName, "close failed")
     else:
-      print "Execute:" , cmd_line[0]
+      print("Execute:" , cmd_line[0])
       executeCommand(cmd_line[0], outputFile)
       
 # Main Function
 lines = openConfFile(inputFile)
 if not lines:
-  print "File support_bundle_commands.conf not present in /etc/frr/ directory"
+  print("File support_bundle_commands.conf not present in /etc/frr/ directory")
 else:
   processConfFile(lines)
index b7d35caa3975889b9f912ffab5df3d6ce063ef52..238b1d905bf10ad9eab8060bc8aa40bcf84623eb 100644 (file)
@@ -3058,6 +3058,24 @@ DEFUN (vtysh_copy_running_config,
        return vtysh_write_memory(self, vty, argc, argv);
 }
 
+DEFUN (vtysh_copy_to_running,
+       vtysh_copy_to_running_cmd,
+       "copy FILENAME running-config",
+       "Apply a configuration file\n"
+       "Configuration file to read\n"
+       "Apply to current configuration\n")
+{
+       int ret;
+       const char *fname = argv[1]->arg;
+
+       ret = vtysh_read_config(fname);
+
+       /* Return to enable mode - the 'read_config' api leaves us up a level */
+       vtysh_execute_no_pager("enable");
+
+       return ret;
+}
+
 DEFUN (vtysh_terminal_paginate,
        vtysh_terminal_paginate_cmd,
        "[no] terminal paginate",
@@ -4024,6 +4042,7 @@ void vtysh_init_vty(void)
        install_element(INTERFACE_NODE, &vtysh_link_params_cmd);
        install_element(ENABLE_NODE, &vtysh_show_running_config_cmd);
        install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd);
+       install_element(ENABLE_NODE, &vtysh_copy_to_running_cmd);
 
        install_element(CONFIG_NODE, &vtysh_vrf_cmd);
        install_element(VRF_NODE, &vtysh_vrf_netns_cmd);
index 681dfb87537236643d7f6d2df0df0072b608d9d1..16b1d0057b9eebf4ef0b6663e60a009b4974634d 100644 (file)
@@ -105,9 +105,9 @@ DEFUN_NOSH (show_debugging_zebra,
        if (IS_ZEBRA_DEBUG_MLAG)
                vty_out(vty, "  Zebra mlag debugging is on\n");
        if (IS_ZEBRA_DEBUG_NHG_DETAIL)
-               vty_out(vty, "Zebra detailed nexthop debugging is on\n");
+               vty_out(vty, "  Zebra detailed nexthop debugging is on\n");
        else if (IS_ZEBRA_DEBUG_NHG)
-               vty_out(vty, "Zebra nexthop debugging is on\n");
+               vty_out(vty, "  Zebra nexthop debugging is on\n");
 
        hook_call(zebra_debug_show_debugging, vty);
        return CMD_SUCCESS;
@@ -557,6 +557,14 @@ static int config_write_debug(struct vty *vty)
                write++;
        }
 
+       if (CHECK_FLAG(zebra_debug_nexthop, ZEBRA_DEBUG_NHG_DETAILED)) {
+               vty_out(vty, "debug zebra nexthop detail\n");
+               write++;
+       } else if (CHECK_FLAG(zebra_debug_nexthop, ZEBRA_DEBUG_NHG)) {
+               vty_out(vty, "debug zebra nexthop\n");
+               write++;
+       }
+
        return write;
 }
 
index 32678ed664c92ed5811cdd1affc2674973ac570f..b1c679e06607738aaa8b77e82f190a817544ae78 100644 (file)
@@ -2374,6 +2374,9 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 
        nhm = NLMSG_DATA(h);
 
+       if (ns_id)
+               vrf_id = ns_id;
+
        if (startup && h->nlmsg_type != RTM_NEWNEXTHOP)
                return 0;
 
@@ -2453,7 +2456,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                        return -1;
 
        } else if (h->nlmsg_type == RTM_DELNEXTHOP)
-               zebra_nhg_kernel_del(id);
+               zebra_nhg_kernel_del(id, vrf_id);
 
        return 0;
 }
index c21d00bbe652cd2d44faa0c7e0faffeba2076baa..4fa7a3c164e83285d58da417f1aea45ba73725eb 100644 (file)
@@ -1475,6 +1475,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
                api_nh = &api.nexthops[i];
                ifindex_t ifindex = 0;
 
+               nexthop = NULL;
+
                if (IS_ZEBRA_DEBUG_RECV)
                        zlog_debug("nh type %d", api_nh->type);
 
index ccc898836cc59a7cb238a345bd4c4827dc814572..8026450d6ee676663d1d4e4ecf60a75e347133d4 100644 (file)
@@ -102,31 +102,60 @@ nhg_connected_tree_root(struct nhg_connected_tree_head *head)
        return nhg_connected_tree_first(head);
 }
 
-void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
-                               struct nhg_hash_entry *depend)
+struct nhg_hash_entry *
+nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
+                          struct nhg_hash_entry *depend)
 {
        struct nhg_connected lookup = {};
        struct nhg_connected *remove = NULL;
+       struct nhg_hash_entry *removed_nhe;
 
        lookup.nhe = depend;
 
        /* Lookup to find the element, then remove it */
        remove = nhg_connected_tree_find(head, &lookup);
-       remove = nhg_connected_tree_del(head, remove);
-
        if (remove)
+               /* Re-returning here just in case this API changes..
+                * the _del list api's are a bit undefined at the moment.
+                *
+                * So hopefully returning here will make it fail if the api
+                * changes to something different than currently expected.
+                */
+               remove = nhg_connected_tree_del(head, remove);
+
+       /* If the entry was sucessfully removed, free the 'connected` struct */
+       if (remove) {
+               removed_nhe = remove->nhe;
                nhg_connected_free(remove);
+               return removed_nhe;
+       }
+
+       return NULL;
 }
 
-void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
-                               struct nhg_hash_entry *depend)
+/* Assuming UNIQUE RB tree. If this changes, assumptions here about
+ * insertion need to change.
+ */
+struct nhg_hash_entry *
+nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
+                          struct nhg_hash_entry *depend)
 {
        struct nhg_connected *new = NULL;
 
        new = nhg_connected_new(depend);
 
-       if (new)
-               nhg_connected_tree_add(head, new);
+       /* On success, NULL will be returned from the
+        * RB code.
+        */
+       if (new && (nhg_connected_tree_add(head, new) == NULL))
+               return NULL;
+
+       /* If it wasn't successful, it must be a duplicate. We enforce the
+        * unique property for the `nhg_connected` tree.
+        */
+       nhg_connected_free(new);
+
+       return depend;
 }
 
 static void
@@ -291,15 +320,15 @@ zebra_nhg_connect_depends(struct nhg_hash_entry *nhe,
                struct interface *ifp = NULL;
 
                ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex,
-                                        nhe->vrf_id);
+                                        nhe->nhg->nexthop->vrf_id);
                if (ifp)
                        zebra_nhg_set_if(nhe, ifp);
                else
                        flog_err(
                                EC_ZEBRA_IF_LOOKUP_FAILED,
                                "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
-                               nhe->nhg->nexthop->ifindex, nhe->vrf_id,
-                               nhe->id);
+                               nhe->nhg->nexthop->ifindex,
+                               nhe->nhg->nexthop->vrf_id, nhe->id);
        }
 }
 
@@ -484,7 +513,9 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
        resolved_ng.nexthop = nh;
 
        depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
-       depends_add(nhg_depends, depend);
+
+       if (depend)
+               depends_add(nhg_depends, depend);
 }
 
 static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
@@ -507,10 +538,10 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
        lookup.type = type ? type : ZEBRA_ROUTE_NHG;
        lookup.nhg = nhg;
 
+       lookup.vrf_id = vrf_id;
        if (lookup.nhg->nexthop->next) {
                /* Groups can have all vrfs and AF's in them */
                lookup.afi = AFI_UNSPEC;
-               lookup.vrf_id = VRF_DEFAULT;
        } else {
                switch (lookup.nhg->nexthop->type) {
                case (NEXTHOP_TYPE_IFINDEX):
@@ -534,8 +565,6 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
                        lookup.afi = AFI_IP6;
                        break;
                }
-
-               lookup.vrf_id = vrf_id;
        }
 
        if (id)
@@ -594,10 +623,11 @@ zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type)
 {
        struct nhg_hash_entry *nhe = NULL;
        struct nexthop_group nhg = {};
+       vrf_id_t vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nh->vrf_id;
 
        nexthop_group_add_sorted(&nhg, nh);
 
-       zebra_nhg_find(&nhe, id, &nhg, NULL, nh->vrf_id, afi, type);
+       zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type);
 
        return nhe;
 }
@@ -1034,11 +1064,11 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
 }
 
 /* Kernel-side, received delete message */
-int zebra_nhg_kernel_del(uint32_t id)
+int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id)
 {
        struct nhg_ctx *ctx = NULL;
 
-       ctx = nhg_ctx_init(id, NULL, NULL, 0, 0, 0, 0);
+       ctx = nhg_ctx_init(id, NULL, NULL, vrf_id, 0, 0, 0);
 
        nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
 
@@ -1107,8 +1137,14 @@ done:
 static void depends_add(struct nhg_connected_tree_head *head,
                        struct nhg_hash_entry *depend)
 {
-       nhg_connected_tree_add_nhe(head, depend);
-       zebra_nhg_increment_ref(depend);
+       /* If NULL is returned, it was successfully added and
+        * needs to have its refcnt incremented.
+        *
+        * Else the NHE is already present in the tree and doesn't
+        * need to increment the refcnt.
+        */
+       if (nhg_connected_tree_add_nhe(head, depend) == NULL)
+               zebra_nhg_increment_ref(depend);
 }
 
 static struct nhg_hash_entry *
@@ -1149,6 +1185,14 @@ struct nhg_hash_entry *
 zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
 {
        struct nhg_hash_entry *nhe = NULL;
+       vrf_id_t vrf_id;
+
+       /*
+        * CLANG SA is complaining that nexthop may be NULL
+        * Make it happy but this is ridonc
+        */
+       assert(nhg->nexthop);
+       vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nhg->nexthop->vrf_id;
 
        if (!(nhg && nhg->nexthop)) {
                flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
@@ -1156,7 +1200,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
                return NULL;
        }
 
-       zebra_nhg_find(&nhe, id, nhg, NULL, nhg->nexthop->vrf_id, rt_afi, 0);
+       zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, 0);
 
        return nhe;
 }
index f1d88092c6e2b95f5cadd2a86209e6a4111e39de..4d001944b7f26c17cefb78699a6f0cb01dbf58de 100644 (file)
@@ -202,7 +202,7 @@ extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
                                 vrf_id_t vrf_id, afi_t afi, int type,
                                 int startup);
 /* Del via kernel */
-extern int zebra_nhg_kernel_del(uint32_t id);
+extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id);
 
 /* Find via route creation */
 extern struct nhg_hash_entry *
index 79107b047c95c1485d81f596d1d847f0e5e72614..92f438fcec75c217b43f70fa0f73b72cf940d8c9 100644 (file)
@@ -52,9 +52,22 @@ extern bool
 nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head);
 extern struct nhg_connected *
 nhg_connected_tree_root(struct nhg_connected_tree_head *head);
-extern void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
-                                      struct nhg_hash_entry *nhe);
-extern void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
-                                      struct nhg_hash_entry *nhe);
+
+/* I realize _add/_del returns are backwords.
+ *
+ * Currently the list APIs are not standardized for what happens in
+ * the _del() function when the item isn't present.
+ *
+ * We are choosing to return NULL if not found in the _del case for now.
+ */
+
+/* Delete NHE from the tree. On success, return the NHE, otherwise NULL. */
+extern struct nhg_hash_entry *
+nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
+                          struct nhg_hash_entry *nhe);
+/* ADD NHE to the tree. On success, return NULL, otherwise return the NHE. */
+extern struct nhg_hash_entry *
+nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
+                          struct nhg_hash_entry *nhe);
 
 #endif /* __ZEBRA_NHG_PRIVATE_H__ */
index fe7a93a50c4de617850f0e54f38f0bae80079500..ff3907451b4808c6d274af1736d1a3ed06efaa21 100644 (file)
@@ -483,8 +483,10 @@ static void zebra_pbr_cleanup_ipset(struct hash_bucket *b, void *data)
        int *sock = data;
 
        if (ipset->sock == *sock) {
-               hook_call(zebra_pbr_ipset_update, 0, ipset);
-               hash_release(zrouter.ipset_hash, ipset);
+               if (hash_release(zrouter.ipset_hash, ipset))
+                       zebra_pbr_ipset_free(ipset);
+               else
+                       hook_call(zebra_pbr_ipset_update, 0, ipset);
        }
 }
 
@@ -494,8 +496,10 @@ static void zebra_pbr_cleanup_ipset_entry(struct hash_bucket *b, void *data)
        int *sock = data;
 
        if (ipset->sock == *sock) {
-               hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
-               hash_release(zrouter.ipset_entry_hash, ipset);
+               if (hash_release(zrouter.ipset_entry_hash, ipset))
+                       zebra_pbr_ipset_entry_free(ipset);
+               else
+                       hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
        }
 }
 
@@ -505,8 +509,10 @@ static void zebra_pbr_cleanup_iptable(struct hash_bucket *b, void *data)
        int *sock = data;
 
        if (iptable->sock == *sock) {
-               hook_call(zebra_pbr_iptable_update, 0, iptable);
-               hash_release(zrouter.iptable_hash, iptable);
+               if (hash_release(zrouter.iptable_hash, iptable))
+                       zebra_pbr_iptable_free(iptable);
+               else
+                       hook_call(zebra_pbr_iptable_update, 0, iptable);
        }
 }
 
index 7b377a81c1e4f7b5ccd1ec06b111f315e62e13b3..866b38b47e4817638afc1fc30f311f5b4e40bc1b 100644 (file)
@@ -1351,18 +1351,19 @@ DEFPY (show_interface_nexthop_group,
 
 DEFPY (show_nexthop_group,
        show_nexthop_group_cmd,
-       "show nexthop-group rib <(0-4294967295)$id|[<ip$v4|ipv6$v6>] [vrf <NAME$vrf_name|all$vrf_all>]>",
+       "show nexthop-group rib <(0-4294967295)$id|[singleton <ip$v4|ipv6$v6>] [vrf <NAME$vrf_name|all$vrf_all>]>",
        SHOW_STR
        "Show Nexthop Groups\n"
        "RIB information\n"
        "Nexthop Group ID\n"
+       "Show Singleton Nexthop-Groups\n"
        IP_STR
        IP6_STR
        VRF_FULL_CMD_HELP_STR)
 {
 
        struct zebra_vrf *zvrf = NULL;
-       afi_t afi = 0;
+       afi_t afi = AFI_UNSPEC;
 
        if (id)
                return show_nexthop_group_id_cmd_helper(vty, id);
@@ -1372,6 +1373,11 @@ DEFPY (show_nexthop_group,
        else if (v6)
                afi = AFI_IP6;
 
+       if (vrf_is_backend_netns() && (vrf_name || vrf_all)) {
+               vty_out(vty, "VRF subcommand does not make any sense in l3mdev based vrf's");
+               return CMD_WARNING;
+       }
+
        if (vrf_all) {
                struct vrf *vrf;