]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #5722 from donaldsharp/kernel_routes
authorRuss White <russ@riw.us>
Thu, 6 Feb 2020 13:04:42 +0000 (08:04 -0500)
committerGitHub <noreply@github.com>
Thu, 6 Feb 2020 13:04:42 +0000 (08:04 -0500)
Kernel routes

159 files changed:
babeld/babeld.c
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_advertise.c
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_clist.c
bgpd/bgp_clist.h
bgpd/bgp_community.c
bgpd/bgp_debug.c
bgpd/bgp_debug.h
bgpd/bgp_dump.c
bgpd/bgp_evpn_vty.c
bgpd/bgp_filter.c
bgpd/bgp_flowspec_util.c
bgpd/bgp_fsm.c
bgpd/bgp_fsm.h
bgpd/bgp_io.c
bgpd/bgp_lcommunity.c
bgpd/bgp_main.c
bgpd/bgp_memory.c
bgpd/bgp_memory.h
bgpd/bgp_mpath.c
bgpd/bgp_network.c
bgpd/bgp_open.c
bgpd/bgp_packet.c
bgpd/bgp_packet.h
bgpd/bgp_pbr.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap.c
bgpd/bgp_snmp.c
bgpd/bgp_table.c
bgpd/bgp_table.h
bgpd/bgp_updgrp.c
bgpd/bgp_updgrp_packet.c
bgpd/bgp_vty.c
bgpd/bgp_vty.h
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/rfapi.c
bgpd/rfapi/rfapi_encap_tlv.c
bgpd/rfapi/rfapi_vty.c
doc/developer/packaging-redhat.rst
doc/developer/zebra.rst
doc/user/bgp.rst
doc/user/ospf6d.rst
doc/user/ospfd.rst
doc/user/pbr.rst
doc/user/vtysh.rst
doc/user/zebra.rst
eigrpd/eigrp_interface.c
eigrpd/eigrp_main.c
eigrpd/eigrp_network.c
eigrpd/eigrp_northbound.c
eigrpd/eigrpd.c
include/linux/seg6.h [new file with mode: 0644]
include/linux/seg6_genl.h [new file with mode: 0644]
include/linux/seg6_hmac.h [new file with mode: 0644]
include/linux/seg6_iptunnel.h [new file with mode: 0644]
include/linux/seg6_local.h [new file with mode: 0644]
include/subdir.am
isisd/isis_bfd.c
isisd/isis_main.c
ldpd/ldp_vty_conf.c
lib/agentx.c
lib/bfd.c
lib/command.c
lib/command.h
lib/distribute.c
lib/filter.c
lib/if.c
lib/if_rmap.c
lib/log.c
lib/netns_linux.c
lib/plist.c
lib/prefix.c
lib/prefix.h
lib/routemap.c
lib/routemap.h
lib/routemap_cli.c [new file with mode: 0644]
lib/routemap_northbound.c [new file with mode: 0644]
lib/srv6.c [new file with mode: 0644]
lib/srv6.h [new file with mode: 0644]
lib/subdir.am
lib/vty.c
lib/zclient.c
lib/zclient.h
nhrpd/nhrp_interface.c
nhrpd/nhrp_route.c
nhrpd/nhrp_shortcut.c
ospf6d/ospf6_main.c
ospf6d/ospf6_message.c
ospfclient/ospf_apiclient.c
ospfd/ospf_abr.c
ospfd/ospf_asbr.c
ospfd/ospf_ase.c
ospfd/ospf_interface.c
ospfd/ospf_ism.c
ospfd/ospf_lsa.c
ospfd/ospf_main.c
ospfd/ospf_packet.c
ospfd/ospf_route.c
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
ospfd/ospfd.c
pimd/mtracebis.c
pimd/pim_bsm.c
pimd/pim_cmd.c
pimd/pim_ifchannel.c
pimd/pim_igmp_mtrace.c
pimd/pim_msdp.c
redhat/frr.spec.in
ripd/rip_interface.c
ripd/rip_main.c
ripd/rip_routemap.c
ripd/ripd.c
ripngd/ripng_interface.c
ripngd/ripng_main.c
ripngd/ripngd.c
scripts/coccinelle/s_addr_0_to_INADDR_ANY.cocci [new file with mode: 0644]
scripts/coccinelle/shorthand_operator.cocci [new file with mode: 0644]
scripts/coccinelle/void_no_return.cocci [new file with mode: 0644]
tests/bgpd/test_mpath.c
tests/lib/test_heavy_wq.c
tools/generate_support_bundle.py
vtysh/extract.pl.in
vtysh/vtysh.c
yang/frr-route-map.yang
yang/subdir.am
zebra/debug.c
zebra/kernel_socket.c
zebra/main.c
zebra/router-id.c
zebra/rt_netlink.c
zebra/subdir.am
zebra/zapi_msg.c
zebra/zebra_dplane.c
zebra/zebra_fpm_netlink.c
zebra/zebra_fpm_protobuf.c
zebra/zebra_gr.c [new file with mode: 0644]
zebra/zebra_mlag.c
zebra/zebra_nhg.c
zebra/zebra_nhg.h
zebra/zebra_nhg_private.h
zebra/zebra_pbr.c
zebra/zebra_rib.c
zebra/zebra_router.h
zebra/zebra_vty.c
zebra/zebra_vxlan.c
zebra/zserv.c
zebra/zserv.h

index 6ad004a4a41a011f738df0b6e70daf2b10999a6d..71bab2fcbfe1c4642069cd4640e9d96bc9a7232f 100644 (file)
@@ -165,7 +165,6 @@ babel_create_routing_process (void)
     return 0;
 fail:
     XFREE(MTYPE_BABEL, babel_routing_process);
-    babel_routing_process = NULL;
     return -1;
 }
 
@@ -324,7 +323,6 @@ babel_clean_routing_process(void)
 
     distribute_list_delete(&babel_routing_process->distribute_ctx);
     XFREE(MTYPE_BABEL, babel_routing_process);
-    babel_routing_process = NULL;
 }
 
 /* Function used with timeout. */
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..ae6f5a3e793165aea49e13a592d8781e4a32c720 100644 (file)
@@ -407,7 +407,6 @@ static void control_reset_buf(struct bfd_control_buffer *bcb)
 {
        /* Get ride of old data. */
        XFREE(MTYPE_BFDD_NOTIFICATION, bcb->bcb_buf);
-       bcb->bcb_buf = NULL;
        bcb->bcb_pos = 0;
        bcb->bcb_left = 0;
 }
@@ -471,7 +470,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 76a65f7f04b50fdaefb131f3d289da87b4acfbf2..8d1c83cf5f4650d9655e486d1fd691e434598ff0 100644 (file)
@@ -256,6 +256,5 @@ void bgp_sync_delete(struct peer *peer)
 
        FOREACH_AFI_SAFI (afi, safi) {
                XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]);
-               peer->sync[afi][safi] = NULL;
        }
 }
index 16de59b72caca0ee2320ff71164d22ba90bb58bb..c0d88fc521a7cb3ffd46dff333efe17d1366a167 100644 (file)
@@ -32,6 +32,7 @@
 #include "table.h"
 #include "filter.h"
 #include "command.h"
+#include "srv6.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_attr.h"
@@ -201,6 +202,8 @@ static struct hash *encap_hash = NULL;
 #if ENABLE_BGP_VNC
 static struct hash *vnc_hash = NULL;
 #endif
+static struct hash *srv6_l3vpn_hash;
+static struct hash *srv6_vpn_hash;
 
 struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
 {
@@ -434,6 +437,158 @@ static void transit_unintern(struct transit **transit)
        }
 }
 
+static void *srv6_l3vpn_hash_alloc(void *p)
+{
+       return p;
+}
+
+static void srv6_l3vpn_free(struct bgp_attr_srv6_l3vpn *l3vpn)
+{
+       XFREE(MTYPE_BGP_SRV6_L3VPN, l3vpn);
+}
+
+static struct bgp_attr_srv6_l3vpn *
+srv6_l3vpn_intern(struct bgp_attr_srv6_l3vpn *l3vpn)
+{
+       struct bgp_attr_srv6_l3vpn *find;
+
+       find = hash_get(srv6_l3vpn_hash, l3vpn, srv6_l3vpn_hash_alloc);
+       if (find != l3vpn)
+               srv6_l3vpn_free(l3vpn);
+       find->refcnt++;
+       return find;
+}
+
+static void srv6_l3vpn_unintern(struct bgp_attr_srv6_l3vpn **l3vpnp)
+{
+       struct bgp_attr_srv6_l3vpn *l3vpn = *l3vpnp;
+
+       if (l3vpn->refcnt)
+               l3vpn->refcnt--;
+
+       if (l3vpn->refcnt == 0) {
+               hash_release(srv6_l3vpn_hash, l3vpn);
+               srv6_l3vpn_free(l3vpn);
+               *l3vpnp = NULL;
+       }
+}
+
+static void *srv6_vpn_hash_alloc(void *p)
+{
+       return p;
+}
+
+static void srv6_vpn_free(struct bgp_attr_srv6_vpn *vpn)
+{
+       XFREE(MTYPE_BGP_SRV6_VPN, vpn);
+}
+
+static struct bgp_attr_srv6_vpn *srv6_vpn_intern(struct bgp_attr_srv6_vpn *vpn)
+{
+       struct bgp_attr_srv6_vpn *find;
+
+       find = hash_get(srv6_vpn_hash, vpn, srv6_vpn_hash_alloc);
+       if (find != vpn)
+               srv6_vpn_free(vpn);
+       find->refcnt++;
+       return find;
+}
+
+static void srv6_vpn_unintern(struct bgp_attr_srv6_vpn **vpnp)
+{
+       struct bgp_attr_srv6_vpn *vpn = *vpnp;
+
+       if (vpn->refcnt)
+               vpn->refcnt--;
+
+       if (vpn->refcnt == 0) {
+               hash_release(srv6_vpn_hash, vpn);
+               srv6_vpn_free(vpn);
+               *vpnp = NULL;
+       }
+}
+
+static uint32_t srv6_l3vpn_hash_key_make(const void *p)
+{
+       const struct bgp_attr_srv6_l3vpn *l3vpn = p;
+       uint32_t key = 0;
+
+       key = jhash(&l3vpn->sid, 16, key);
+       key = jhash_1word(l3vpn->sid_flags, key);
+       key = jhash_1word(l3vpn->endpoint_behavior, key);
+       return key;
+}
+
+static bool srv6_l3vpn_hash_cmp(const void *p1, const void *p2)
+{
+       const struct bgp_attr_srv6_l3vpn *l3vpn1 = p1;
+       const struct bgp_attr_srv6_l3vpn *l3vpn2 = p2;
+
+       return sid_same(&l3vpn1->sid, &l3vpn2->sid)
+              && l3vpn1->sid_flags == l3vpn2->sid_flags
+              && l3vpn1->endpoint_behavior == l3vpn2->endpoint_behavior;
+}
+
+static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn *h1,
+                           const struct bgp_attr_srv6_l3vpn *h2)
+{
+       if (h1 == h2)
+               return true;
+       else if (h1 == NULL || h2 == NULL)
+               return false;
+       else
+               return srv6_l3vpn_hash_cmp((const void *)h1, (const void *)h2);
+}
+
+static unsigned int srv6_vpn_hash_key_make(const void *p)
+{
+       const struct bgp_attr_srv6_vpn *vpn = p;
+       uint32_t key = 0;
+
+       key = jhash(&vpn->sid, 16, key);
+       key = jhash_1word(vpn->sid_flags, key);
+       return key;
+}
+
+static bool srv6_vpn_hash_cmp(const void *p1, const void *p2)
+{
+       const struct bgp_attr_srv6_vpn *vpn1 = p1;
+       const struct bgp_attr_srv6_vpn *vpn2 = p2;
+
+       return sid_same(&vpn1->sid, &vpn2->sid)
+              && vpn1->sid_flags == vpn2->sid_flags;
+}
+
+static bool srv6_vpn_same(const struct bgp_attr_srv6_vpn *h1,
+                         const struct bgp_attr_srv6_vpn *h2)
+{
+       if (h1 == h2)
+               return true;
+       else if (h1 == NULL || h2 == NULL)
+               return false;
+       else
+               return srv6_vpn_hash_cmp((const void *)h1, (const void *)h2);
+}
+
+static void srv6_init(void)
+{
+       srv6_l3vpn_hash =
+               hash_create(srv6_l3vpn_hash_key_make, srv6_l3vpn_hash_cmp,
+                           "BGP Prefix-SID SRv6-L3VPN-Service-TLV");
+       srv6_vpn_hash = hash_create(srv6_vpn_hash_key_make, srv6_vpn_hash_cmp,
+                                   "BGP Prefix-SID SRv6-VPN-Service-TLV");
+}
+
+static void srv6_finish(void)
+{
+       hash_clean(srv6_l3vpn_hash, (void (*)(void *))srv6_l3vpn_free);
+       hash_free(srv6_l3vpn_hash);
+       srv6_l3vpn_hash = NULL;
+       hash_clean(srv6_vpn_hash, (void (*)(void *))srv6_vpn_free);
+       hash_free(srv6_vpn_hash);
+       srv6_vpn_hash = NULL;
+}
+
 static unsigned int transit_hash_key_make(const void *p)
 {
        const struct transit *transit = p;
@@ -557,7 +712,9 @@ bool attrhash_cmp(const void *p1, const void *p2)
                    && overlay_index_same(attr1, attr2)
                    && attr1->nh_ifindex == attr2->nh_ifindex
                    && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex
-                   && attr1->distance == attr2->distance)
+                   && attr1->distance == attr2->distance
+                   && srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn)
+                   && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn))
                        return true;
        }
 
@@ -588,12 +745,22 @@ static void attrhash_finish(void)
 static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty)
 {
        struct attr *attr = bucket->data;
+       char sid_str[BUFSIZ];
 
        vty_out(vty, "attr[%ld] nexthop %s\n", attr->refcnt,
                inet_ntoa(attr->nexthop));
-       vty_out(vty, "\tflags: %" PRIu64 " med: %u local_pref: %u origin: %u weight: %u label: %u\n",
+
+       sid_str[0] = '\0';
+       if (attr->srv6_l3vpn)
+               inet_ntop(AF_INET6, &attr->srv6_l3vpn->sid, sid_str, BUFSIZ);
+       else if (attr->srv6_vpn)
+               inet_ntop(AF_INET6, &attr->srv6_vpn->sid, sid_str, BUFSIZ);
+
+       vty_out(vty,
+               "\tflags: %" PRIu64
+               " med: %u local_pref: %u origin: %u weight: %u label: %u sid: %s\n",
                attr->flag, attr->med, attr->local_pref, attr->origin,
-               attr->weight, attr->label);
+               attr->weight, attr->label, sid_str);
 }
 
 void attr_show_all(struct vty *vty)
@@ -618,6 +785,11 @@ static void *bgp_attr_hash_alloc(void *p)
                val->vnc_subtlvs = NULL;
        }
 #endif
+       if (val->srv6_l3vpn)
+               val->srv6_l3vpn = NULL;
+       if (val->srv6_vpn)
+               val->srv6_vpn = NULL;
+
        attr->refcnt = 0;
        return attr;
 }
@@ -672,6 +844,18 @@ struct attr *bgp_attr_intern(struct attr *attr)
                else
                        attr->encap_subtlvs->refcnt++;
        }
+       if (attr->srv6_l3vpn) {
+               if (!attr->srv6_l3vpn->refcnt)
+                       attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
+               else
+                       attr->srv6_l3vpn->refcnt++;
+       }
+       if (attr->srv6_vpn) {
+               if (!attr->srv6_vpn->refcnt)
+                       attr->srv6_vpn = srv6_vpn_intern(attr->srv6_vpn);
+               else
+                       attr->srv6_vpn->refcnt++;
+       }
 #if ENABLE_BGP_VNC
        if (attr->vnc_subtlvs) {
                if (!attr->vnc_subtlvs->refcnt)
@@ -862,6 +1046,12 @@ void bgp_attr_unintern_sub(struct attr *attr)
        if (attr->vnc_subtlvs)
                encap_unintern(&attr->vnc_subtlvs, VNC_SUBTLV_TYPE);
 #endif
+
+       if (attr->srv6_l3vpn)
+               srv6_l3vpn_unintern(&attr->srv6_l3vpn);
+
+       if (attr->srv6_vpn)
+               srv6_vpn_unintern(&attr->srv6_vpn);
 }
 
 /*
@@ -1742,7 +1932,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
        case BGP_ATTR_NHLEN_IPV4:
                stream_get(&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
                /* Probably needed for RFC 2283 */
-               if (attr->nexthop.s_addr == 0)
+               if (attr->nexthop.s_addr == INADDR_ANY)
                        memcpy(&attr->nexthop.s_addr,
                               &attr->mp_nexthop_global_in, IPV4_MAX_BYTELEN);
                break;
@@ -2147,6 +2337,9 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
        uint32_t srgb_base;
        uint32_t srgb_range;
        int srgb_count;
+       uint8_t sid_type, sid_flags;
+       uint16_t endpoint_behavior;
+       char buf[BUFSIZ];
 
        if (type == BGP_PREFIX_SID_LABEL_INDEX) {
                if (STREAM_READABLE(peer->curr) < length
@@ -2268,13 +2461,81 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
                }
        }
 
-       /*
-        * Placeholder code for Unsupported TLV
-        *  - SRv6 L3 Service TLV (type5)
-        *  - SRv6 L2 Service TLV (type6)
-        */
-       else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE
-           || type == BGP_PREFIX_SID_SRV6_L2_SERVICE) {
+       /* Placeholder code for the VPN-SID Service type */
+       else if (type == BGP_PREFIX_SID_VPN_SID) {
+               if (STREAM_READABLE(peer->curr) < length
+                   || length != BGP_PREFIX_SID_VPN_SID_LENGTH) {
+                       flog_err(EC_BGP_ATTR_LEN,
+                                "Prefix SID VPN SID length is %" PRIu16
+                                " instead of %u",
+                                length, BGP_PREFIX_SID_VPN_SID_LENGTH);
+                       return bgp_attr_malformed(args,
+                                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                                 args->total);
+               }
+
+               /* Parse VPN-SID Sub-TLV */
+               stream_getc(peer->curr);               /* reserved  */
+               sid_type = stream_getc(peer->curr);    /* sid_type  */
+               sid_flags = stream_getc(peer->curr);   /* sid_flags */
+               stream_get(&ipv6_sid, peer->curr,
+                          sizeof(ipv6_sid)); /* sid_value */
+
+               /* Log VPN-SID Sub-TLV */
+               if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
+                       inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
+                       zlog_debug(
+                               "%s: vpn-sid: sid %s, sid-type 0x%02x sid-flags 0x%02x",
+                               __func__, buf, sid_type, sid_flags);
+               }
+
+               /* Configure from Info */
+               attr->srv6_vpn = XMALLOC(MTYPE_BGP_SRV6_VPN,
+                                        sizeof(struct bgp_attr_srv6_vpn));
+               attr->srv6_vpn->refcnt = 0;
+               attr->srv6_vpn->sid_flags = sid_flags;
+               sid_copy(&attr->srv6_vpn->sid, &ipv6_sid);
+       }
+
+       /* Placeholder code for the SRv6 L3 Service type */
+       else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE) {
+               if (STREAM_READABLE(peer->curr) < length
+                   || length != BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH) {
+                       flog_err(EC_BGP_ATTR_LEN,
+                                "Prefix SID SRv6 L3-Service length is %" PRIu16
+                                " instead of %u",
+                                length, BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH);
+                       return bgp_attr_malformed(args,
+                                BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                args->total);
+               }
+
+               /* Parse L3-SERVICE Sub-TLV */
+               stream_getc(peer->curr);               /* reserved  */
+               stream_get(&ipv6_sid, peer->curr,
+                          sizeof(ipv6_sid)); /* sid_value */
+               sid_flags = stream_getc(peer->curr);   /* sid_flags */
+               endpoint_behavior = stream_getw(peer->curr); /* endpoint */
+               stream_getc(peer->curr);               /* reserved  */
+
+               /* Log L3-SERVICE Sub-TLV */
+               if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
+                       inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
+                       zlog_debug(
+                               "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x",
+                               __func__, buf, sid_flags, endpoint_behavior);
+               }
+
+               /* Configure from Info */
+               attr->srv6_l3vpn = XMALLOC(MTYPE_BGP_SRV6_L3VPN,
+                                          sizeof(struct bgp_attr_srv6_l3vpn));
+               attr->srv6_l3vpn->sid_flags = sid_flags;
+               attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior;
+               sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid);
+       }
+
+       /* Placeholder code for Unsupported TLV */
+       else {
 
                if (STREAM_READABLE(peer->curr) < length) {
                        flog_err(
@@ -2966,10 +3227,11 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
 
        /* Nexthop AFI */
        if (afi == AFI_IP
-           && (safi == SAFI_UNICAST ||
-               safi == SAFI_LABELED_UNICAST ||
-               safi == SAFI_MULTICAST))
+           && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST
+               || safi == SAFI_MPLS_VPN || safi == SAFI_MULTICAST))
                nh_afi = peer_cap_enhe(peer, afi, safi) ? AFI_IP6 : AFI_IP;
+       else if (safi == SAFI_FLOWSPEC)
+               nh_afi = afi;
        else
                nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
 
@@ -2996,7 +3258,12 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
                        stream_put(s, &attr->mp_nexthop_global_in, 4);
                        break;
                case SAFI_FLOWSPEC:
-                       stream_putc(s, 0); /* no nexthop for flowspec */
+                       if (attr->mp_nexthop_len == 0)
+                               stream_putc(s, 0); /* no nexthop for flowspec */
+                       else {
+                               stream_putc(s, attr->mp_nexthop_len);
+                               stream_put_ipv4(s, attr->nexthop.s_addr);
+                       }
                default:
                        break;
                }
@@ -3090,13 +3357,9 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
                stream_put_labeled_prefix(s, p, label, addpath_encode,
                                          addpath_tx_id);
        } else if (safi == SAFI_FLOWSPEC) {
-               if (PSIZE (p->prefixlen)+2 < FLOWSPEC_NLRI_SIZELIMIT)
-                       stream_putc(s, PSIZE (p->prefixlen)+2);
-               else
-                       stream_putw(s, (PSIZE (p->prefixlen)+2)|(0xf<<12));
-               stream_putc(s, 2);/* Filter type */
-               stream_putc(s, p->prefixlen);/* Prefix length */
-               stream_put(s, &p->u.prefix, PSIZE (p->prefixlen));
+               stream_putc(s, p->u.prefix_flowspec.prefixlen);
+               stream_put(s, (const void *)p->u.prefix_flowspec.ptr,
+                          p->u.prefix_flowspec.prefixlen);
        } else
                stream_put_prefix_addpath(s, p, addpath_encode, addpath_tx_id);
 }
@@ -3610,6 +3873,36 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
                }
        }
 
+       /* SRv6 Service Information Attribute. */
+       if (afi == AFI_IP && safi == SAFI_MPLS_VPN) {
+               if (attr->srv6_l3vpn) {
+                       stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+                                              | BGP_ATTR_FLAG_TRANS);
+                       stream_putc(s, BGP_ATTR_PREFIX_SID);
+                       stream_putc(s, 24);     /* tlv len */
+                       stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE);
+                       stream_putw(s, 21);     /* sub-tlv len */
+                       stream_putc(s, 0);      /* reserved */
+                       stream_put(s, &attr->srv6_l3vpn->sid,
+                                  sizeof(attr->srv6_l3vpn->sid)); /* sid */
+                       stream_putc(s, 0);      /* sid_flags */
+                       stream_putw(s, 0xffff); /* endpoint */
+                       stream_putc(s, 0);      /* reserved */
+               } else if (attr->srv6_vpn) {
+                       stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
+                                              | BGP_ATTR_FLAG_TRANS);
+                       stream_putc(s, BGP_ATTR_PREFIX_SID);
+                       stream_putc(s, 22);     /* tlv len */
+                       stream_putc(s, BGP_PREFIX_SID_VPN_SID);
+                       stream_putw(s, 0x13);   /* tlv len */
+                       stream_putc(s, 0x00);   /* reserved */
+                       stream_putc(s, 0x01);   /* sid_type */
+                       stream_putc(s, 0x00);   /* sif_flags */
+                       stream_put(s, &attr->srv6_vpn->sid,
+                                  sizeof(attr->srv6_vpn->sid)); /* sid */
+               }
+       }
+
        if (send_as4_path) {
                /* If the peer is NOT As4 capable, AND */
                /* there are ASnums > 65535 in path  THEN
@@ -3738,6 +4031,7 @@ void bgp_attr_init(void)
        cluster_init();
        transit_init();
        encap_init();
+       srv6_init();
 }
 
 void bgp_attr_finish(void)
@@ -3750,6 +4044,7 @@ void bgp_attr_finish(void)
        cluster_finish();
        transit_finish();
        encap_finish();
+       srv6_finish();
 }
 
 /* Make attribute packet. */
index 8bd527c0ff169da64cd75b3139dd271fad8fac06..2e91f56df57aca47f8d47ba51e1219bd166e26b6 100644 (file)
 #define BGP_PREFIX_SID_LABEL_INDEX     1
 #define BGP_PREFIX_SID_IPV6            2
 #define BGP_PREFIX_SID_ORIGINATOR_SRGB 3
+#define BGP_PREFIX_SID_VPN_SID 4
 #define BGP_PREFIX_SID_SRV6_L3_SERVICE 5
 #define BGP_PREFIX_SID_SRV6_L2_SERVICE 6
 
 #define BGP_PREFIX_SID_LABEL_INDEX_LENGTH      7
 #define BGP_PREFIX_SID_IPV6_LENGTH            19
 #define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH  6
+#define BGP_PREFIX_SID_VPN_SID_LENGTH         19
+#define BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH 21
 
 #define BGP_ATTR_NH_AFI(afi, attr) \
        ((afi != AFI_L2VPN) ? afi : \
@@ -111,6 +114,29 @@ enum pta_type {
        PMSI_TNLTYPE_MAX = PMSI_TNLTYPE_MLDP_MP2MP
 };
 
+/*
+ * Prefix-SID type-4
+ * SRv6-VPN-SID-TLV
+ * draft-dawra-idr-srv6-vpn-04
+ */
+struct bgp_attr_srv6_vpn {
+       unsigned long refcnt;
+       uint8_t sid_flags;
+       struct in6_addr sid;
+};
+
+/*
+ * Prefix-SID type-5
+ * SRv6-L3VPN-Service-TLV
+ * draft-dawra-idr-srv6-vpn-05
+ */
+struct bgp_attr_srv6_l3vpn {
+       unsigned long refcnt;
+       uint8_t sid_flags;
+       uint16_t endpoint_behavior;
+       struct in6_addr sid;
+};
+
 /* BGP core attribute structure. */
 struct attr {
        /* AS Path structure */
@@ -198,6 +224,12 @@ struct attr {
        /* MPLS label */
        mpls_label_t label;
 
+       /* SRv6 VPN SID */
+       struct bgp_attr_srv6_vpn *srv6_vpn;
+
+       /* SRv6 L3VPN SID */
+       struct bgp_attr_srv6_l3vpn *srv6_l3vpn;
+
        uint16_t encap_tunneltype;                   /* grr */
        struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */
 
index 29e668d179b34cf01f3445c9004c9d2999fd562f..7ca48a5bea4a798106fceabd462e9f1af22f8d64 100644 (file)
 #include "bgpd/bgp_regex.h"
 #include "bgpd/bgp_clist.h"
 
+/* Calculate new sequential number. */
+static int64_t bgp_clist_new_seq_get(struct community_list *list)
+{
+       int64_t maxseq;
+       int64_t newseq;
+       struct community_entry *entry;
+
+       maxseq = newseq = 0;
+
+       for (entry = list->head; entry; entry = entry->next) {
+               if (maxseq < entry->seq)
+                       maxseq = entry->seq;
+       }
+
+       newseq = ((maxseq / 5) * 5) + 5;
+
+       return (newseq > UINT_MAX) ? UINT_MAX : newseq;
+}
+
+/* Return community-list entry which has same seq number. */
+static struct community_entry *bgp_clist_seq_check(struct community_list *list,
+                                                  int64_t seq)
+{
+       struct community_entry *entry;
+
+       for (entry = list->head; entry; entry = entry->next)
+               if (entry->seq == seq)
+                       return entry;
+       return NULL;
+}
+
 static uint32_t bgp_clist_hash_key_community_list(const void *data)
 {
        struct community_list *cl = (struct community_list *) data;
@@ -285,20 +316,6 @@ static int community_list_empty_p(struct community_list *list)
        return (list->head == NULL && list->tail == NULL) ? 1 : 0;
 }
 
-/* Add community-list entry to the list.  */
-static void community_list_entry_add(struct community_list *list,
-                                    struct community_entry *entry)
-{
-       entry->next = NULL;
-       entry->prev = list->tail;
-
-       if (list->tail)
-               list->tail->next = entry;
-       else
-               list->head = entry;
-       list->tail = entry;
-}
-
 /* Delete community-list entry from the list.  */
 static void community_list_entry_delete(struct community_list_master *cm,
                                        struct community_list *list,
@@ -320,6 +337,57 @@ static void community_list_entry_delete(struct community_list_master *cm,
                community_list_delete(cm, list);
 }
 
+/* Add community-list entry to the list.  */
+static void community_list_entry_add(struct community_list *list,
+                                    struct community_entry *entry,
+                                    struct community_list_handler *ch,
+                                    int master)
+{
+       struct community_list_master *cm = NULL;
+       struct community_entry *replace;
+       struct community_entry *point;
+
+       cm = community_list_master_lookup(ch, master);
+
+       /* Automatic assignment of seq no. */
+       if (entry->seq == COMMUNITY_SEQ_NUMBER_AUTO)
+               entry->seq = bgp_clist_new_seq_get(list);
+
+       if (list->tail && entry->seq > list->tail->seq)
+               point = NULL;
+       else {
+               replace = bgp_clist_seq_check(list, entry->seq);
+               if (replace)
+                       community_list_entry_delete(cm, list, entry);
+
+               /* Check insert point. */
+               for (point = list->head; point; point = point->next)
+                       if (point->seq >= entry->seq)
+                               break;
+       }
+
+       /* In case of this is the first element of the list. */
+       entry->next = point;
+
+       if (point) {
+               if (point->prev)
+                       point->prev->next = entry;
+               else
+                       list->head = entry;
+
+               entry->prev = point->prev;
+               point->prev = entry;
+       } else {
+               if (list->tail)
+                       list->tail->next = entry;
+               else
+                       list->head = entry;
+
+               entry->prev = list->tail;
+               list->tail = entry;
+       }
+}
+
 /* Lookup community-list entry from the list.  */
 static struct community_entry *
 community_list_entry_lookup(struct community_list *list, const void *arg,
@@ -878,12 +946,16 @@ static int community_list_dup_check(struct community_list *list,
 
 /* Set community-list.  */
 int community_list_set(struct community_list_handler *ch, const char *name,
-                      const char *str, int direct, int style)
+                      const char *str, const char *seq, int direct, int style)
 {
        struct community_entry *entry = NULL;
        struct community_list *list;
        struct community *com = NULL;
        regex_t *regex = NULL;
+       int64_t seqnum = COMMUNITY_SEQ_NUMBER_AUTO;
+
+       if (seq)
+               seqnum = (int64_t)atol(seq);
 
        /* Get community list. */
        list = community_list_get(ch, name, COMMUNITY_LIST_MASTER);
@@ -919,6 +991,7 @@ int community_list_set(struct community_list_handler *ch, const char *name,
        entry->any = (str ? 0 : 1);
        entry->u.com = com;
        entry->reg = regex;
+       entry->seq = seqnum;
        entry->config =
                (regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
 
@@ -926,7 +999,8 @@ int community_list_set(struct community_list_handler *ch, const char *name,
        if (community_list_dup_check(list, entry))
                community_entry_free(entry);
        else {
-               community_list_entry_add(list, entry);
+               community_list_entry_add(list, entry, ch,
+                                        COMMUNITY_LIST_MASTER);
                route_map_notify_dependencies(name, RMAP_EVENT_CLIST_ADDED);
        }
 
@@ -935,7 +1009,8 @@ int community_list_set(struct community_list_handler *ch, const char *name,
 
 /* Unset community-list */
 int community_list_unset(struct community_list_handler *ch, const char *name,
-                        const char *str, int direct, int style)
+                        const char *str, const char *seq, int direct,
+                        int style)
 {
        struct community_list_master *cm = NULL;
        struct community_entry *entry = NULL;
@@ -1057,12 +1132,16 @@ static int lcommunity_list_valid(const char *community)
 
 /* Set lcommunity-list.  */
 int lcommunity_list_set(struct community_list_handler *ch, const char *name,
-                       const char *str, int direct, int style)
+                       const char *str, const char *seq, int direct, int style)
 {
        struct community_entry *entry = NULL;
        struct community_list *list;
        struct lcommunity *lcom = NULL;
        regex_t *regex = NULL;
+       int64_t seqnum = COMMUNITY_SEQ_NUMBER_AUTO;
+
+       if (seq)
+               seqnum = (int64_t)atol(seq);
 
        /* Get community list. */
        list = community_list_get(ch, name, LARGE_COMMUNITY_LIST_MASTER);
@@ -1101,6 +1180,7 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
        entry->any = (str ? 0 : 1);
        entry->u.lcom = lcom;
        entry->reg = regex;
+       entry->seq = seqnum;
        entry->config =
                (regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
 
@@ -1108,7 +1188,8 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
        if (community_list_dup_check(list, entry))
                community_entry_free(entry);
        else {
-               community_list_entry_add(list, entry);
+               community_list_entry_add(list, entry, ch,
+                                        LARGE_COMMUNITY_LIST_MASTER);
                route_map_notify_dependencies(name, RMAP_EVENT_LLIST_ADDED);
        }
 
@@ -1118,7 +1199,8 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
 /* Unset community-list.  When str is NULL, delete all of
    community-list entry belongs to the specified name.  */
 int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
-                         const char *str, int direct, int style)
+                         const char *str, const char *seq, int direct,
+                         int style)
 {
        struct community_list_master *cm = NULL;
        struct community_entry *entry = NULL;
@@ -1168,12 +1250,17 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
 
 /* Set extcommunity-list.  */
 int extcommunity_list_set(struct community_list_handler *ch, const char *name,
-                         const char *str, int direct, int style)
+                         const char *str, const char *seq, int direct,
+                         int style)
 {
        struct community_entry *entry = NULL;
        struct community_list *list;
        struct ecommunity *ecom = NULL;
        regex_t *regex = NULL;
+       int64_t seqnum = COMMUNITY_SEQ_NUMBER_AUTO;
+
+       if (seq)
+               seqnum = (int64_t)atol(seq);
 
        if (str == NULL)
                return COMMUNITY_LIST_ERR_MALFORMED_VAL;
@@ -1220,12 +1307,14 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
 
        entry->u.ecom = ecom;
        entry->reg = regex;
+       entry->seq = seqnum;
 
        /* Do not put duplicated community entry.  */
        if (community_list_dup_check(list, entry))
                community_entry_free(entry);
        else {
-               community_list_entry_add(list, entry);
+               community_list_entry_add(list, entry, ch,
+                                        EXTCOMMUNITY_LIST_MASTER);
                route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_ADDED);
        }
 
@@ -1238,7 +1327,8 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
  * specified name.
  */
 int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
-                           const char *str, int direct, int style)
+                           const char *str, const char *seq, int direct,
+                           int style)
 {
        struct community_list_master *cm = NULL;
        struct community_entry *entry = NULL;
index 87b29ac3bebe92a21a12024c7f9c88e8c7f3ddef..c5718aecac58e863d6085bca94e154a62ef05ca2 100644 (file)
@@ -36,6 +36,8 @@
 #define COMMUNITY_LIST_STRING          0
 #define COMMUNITY_LIST_NUMBER          1
 
+#define COMMUNITY_SEQ_NUMBER_AUTO     -1
+
 /* Community-list entry types.  */
 #define COMMUNITY_LIST_STANDARD        0 /* Standard community-list.  */
 #define COMMUNITY_LIST_EXPANDED        1 /* Expanded community-list.  */
@@ -81,6 +83,9 @@ struct community_entry {
        /* Any match.  */
        uint8_t any;
 
+       /* Sequence number. */
+       int64_t seq;
+
        /* Community structure.  */
        union {
                struct community *com;
@@ -135,23 +140,23 @@ extern struct community_list_handler *community_list_init(void);
 extern void community_list_terminate(struct community_list_handler *);
 
 extern int community_list_set(struct community_list_handler *ch,
-                             const char *name, const char *str, int direct,
-                             int style);
+                             const char *name, const char *str,
+                             const char *seq, int direct, int style);
 extern int community_list_unset(struct community_list_handler *ch,
-                               const char *name, const char *str, int direct,
-                               int style);
+                               const char *name, const char *str,
+                               const char *seq, int direct, int style);
 extern int extcommunity_list_set(struct community_list_handler *ch,
-                                const char *name, const char *str, int direct,
-                                int style);
+                                const char *name, const char *str,
+                                const char *seq, int direct, int style);
 extern int extcommunity_list_unset(struct community_list_handler *ch,
                                   const char *name, const char *str,
-                                  int direct, int style);
+                                  const char *seq, int direct, int style);
 extern int lcommunity_list_set(struct community_list_handler *ch,
-                              const char *name, const char *str, int direct,
-                              int style);
+                              const char *name, const char *str,
+                              const char *seq, int direct, int style);
 extern int lcommunity_list_unset(struct community_list_handler *ch,
-                                const char *name, const char *str, int direct,
-                                int style);
+                                const char *name, const char *str,
+                                const char *seq, int direct, int style);
 
 extern struct community_list_master *
 community_list_master_lookup(struct community_list_handler *, int);
index 432c922ea56dd537c8849a06b146a01e1930adc8..496d7ed2b121a9152ed78b8bdc0187efed8c45c9 100644 (file)
@@ -89,7 +89,6 @@ void community_del_val(struct community *com, uint32_t *val)
                                                    com->val, com_length(com));
                        else {
                                XFREE(MTYPE_COMMUNITY_VAL, com->val);
-                               com->val = NULL;
                        }
                        return;
                }
index f716c4f308654beb7d7ee8d2275597262b173f17..f3bd9f59ff5d079a31eaa73468c1bc5baa31e7db 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;
@@ -2096,6 +2134,9 @@ DEFUN_NOSH (show_debugging_bgp,
                bgp_debug_list_print(vty, "  BGP zebra debugging is on",
                                     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 +2270,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 +2308,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 +2376,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 f850cb49cf9979b0cce53a03edb67c7a33e72fef..298f9d0212b353ddb3eab347a52014bc23ce0529 100644 (file)
@@ -667,10 +667,7 @@ static int bgp_dump_set(struct vty *vty, struct bgp_dump *bgp_dump,
 static int bgp_dump_unset(struct bgp_dump *bgp_dump)
 {
        /* Removing file name. */
-       if (bgp_dump->filename) {
-               XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
-               bgp_dump->filename = NULL;
-       }
+       XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->filename);
 
        /* Closing file. */
        if (bgp_dump->fp) {
@@ -687,10 +684,7 @@ static int bgp_dump_unset(struct bgp_dump *bgp_dump)
        bgp_dump->interval = 0;
 
        /* Removing interval string. */
-       if (bgp_dump->interval_str) {
-               XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
-               bgp_dump->interval_str = NULL;
-       }
+       XFREE(MTYPE_BGP_DUMP_STR, bgp_dump->interval_str);
 
        return CMD_SUCCESS;
 }
index 3049a00ce3205822958d66b8738de902c7e547c2..c5f7927c4d5455c4b8cfa2a235dfc45d35d880de 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;
+                       }
                }
        }
 
@@ -763,7 +771,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
                for (; pi; pi = pi->next) {
                        json_object *json_path = NULL;
 
-                       if (vtep_ip.s_addr
+                       if (vtep_ip.s_addr != INADDR_ANY
                            && !IPV4_ADDR_SAME(&(vtep_ip),
                                               &(pi->attr->nexthop)))
                                continue;
@@ -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;
+                       }
                }
        }
 
@@ -2579,18 +2595,29 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
                        add_rd_to_json = 1;
                }
 
-               if (json && add_prefix_to_json) {
-                       json_object_object_add(json_prefix, "paths",
-                                              json_paths);
-                       json_object_object_add(json_rd, prefix_str,
-                                              json_prefix);
+               if (json) {
+                       if (add_prefix_to_json) {
+                               json_object_object_add(json_prefix, "paths",
+                                                      json_paths);
+                               json_object_object_add(json_rd, prefix_str,
+                                                      json_prefix);
+                       } else {
+                               json_object_free(json_paths);
+                               json_object_free(json_prefix);
+                               json_paths = NULL;
+                               json_prefix = NULL;
+                       }
                }
        }
 
-       if (json && add_rd_to_json)
-               json_object_object_add(json, rd_str, json_rd);
-
        if (json) {
+               if (add_rd_to_json)
+                       json_object_object_add(json, rd_str, json_rd);
+               else {
+                       json_object_free(json_rd);
+                       json_rd = NULL;
+               }
+
                json_object_int_add(json, "numPrefix", prefix_cnt);
                json_object_int_add(json, "numPaths", path_cnt);
        } else {
@@ -2732,16 +2759,31 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
                                                              json_path);
                        }
 
-                       if (json && add_prefix_to_json) {
-                               json_object_object_add(json_prefix, "paths",
-                                                      json_paths);
-                               json_object_object_add(json_rd, prefix_str,
-                                                      json_prefix);
+                       if (json) {
+                               if (add_prefix_to_json) {
+                                       json_object_object_add(json_prefix,
+                                                              "paths",
+                                                              json_paths);
+                                       json_object_object_add(json_rd,
+                                                              prefix_str,
+                                                              json_prefix);
+                               } else {
+                                       json_object_free(json_prefix);
+                                       json_object_free(json_paths);
+                                       json_prefix = NULL;
+                                       json_paths = NULL;
+                               }
                        }
                }
 
-               if (json && add_rd_to_json)
-                       json_object_object_add(json, rd_str, json_rd);
+               if (json) {
+                       if (add_rd_to_json)
+                               json_object_object_add(json, rd_str, json_rd);
+                       else {
+                               json_object_free(json_rd);
+                               json_rd = NULL;
+                       }
+               }
        }
 
        if (json) {
index f08f9b2fb759fba023121801b9a4cd5238c6601a..a03551e79ddaafdf04d65a4eb90a5b64865974fa 100644 (file)
@@ -168,10 +168,7 @@ static struct as_list *as_list_new(void)
 
 static void as_list_free(struct as_list *aslist)
 {
-       if (aslist->name) {
-               XFREE(MTYPE_AS_STR, aslist->name);
-               aslist->name = NULL;
-       }
+       XFREE(MTYPE_AS_STR, aslist->name);
        XFREE(MTYPE_AS_LIST, aslist);
 }
 
index b9a0d81cc5a149207136bf8fbcbbaa031ec89400..002aae561a8bc72674494e8337618c4741e8baed 100644 (file)
@@ -455,7 +455,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
                                 * ignore that rule
                                 */
                                if (prefix->family == AF_INET
-                                   && prefix->u.prefix4.s_addr == 0)
+                                   && prefix->u.prefix4.s_addr == INADDR_ANY)
                                        bpem->match_bitmask_iprule |= bitmask;
                                else
                                        bpem->match_bitmask |= bitmask;
index 3667dae83d164df70054b335843b00fb08e4416f..ac8fe5e914774cafb40c497c323e14ae8fa7d1af 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,7 @@
 
 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 +250,22 @@ 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 +629,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 +1120,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 +1146,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 +1190,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 +1330,6 @@ int bgp_stop(struct peer *peer)
        } else {
                bgp_peer_conf_if_to_su_update(peer);
        }
-
        return ret;
 }
 
@@ -1447,7 +1527,7 @@ int bgp_start(struct peer *peer)
        }
 
        /* Clear remote router-id. */
-       peer->remote_id.s_addr = 0;
+       peer->remote_id.s_addr = INADDR_ANY;
 
        /* Clear peer capability flag. */
        peer->cap = 0;
@@ -1539,6 +1619,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 +1658,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 +1743,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 +1783,12 @@ 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 +1808,32 @@ 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 +2250,479 @@ 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..6feabbf570af848b1b88fbf76ad4f13025783a6f 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,28 @@ 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..ab50c545b52e28f4439231a6b907233147d90bb5 100644 (file)
@@ -462,7 +462,10 @@ 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
@@ -478,7 +481,10 @@ static uint16_t bgp_read(struct peer *peer)
                                   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 674686b3c449d7df7da366203fbdaeaccc877622..f889693001a658543ad55dadddd98283c4b4073d 100644 (file)
@@ -527,7 +527,6 @@ void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr)
                                                 lcom->val, lcom_length(lcom));
                        else {
                                XFREE(MTYPE_LCOMMUNITY_VAL, lcom->val);
-                               lcom->val = NULL;
                        }
                        return;
                }
index 9cb3957a86c2ff24195554f02121941509afef7d..74e561c743ea3860dbc54156128f9c1d9b0e9b50 100644 (file)
@@ -272,7 +272,6 @@ static int bgp_vrf_enable(struct vrf *vrf)
        if (bgp && bgp->vrf_id != vrf->vrf_id) {
                if (bgp->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) {
                        XFREE(MTYPE_BGP, bgp->name);
-                       bgp->name = NULL;
                        XFREE(MTYPE_BGP, bgp->name_pretty);
                        bgp->name_pretty = XSTRDUP(MTYPE_BGP, "VRF default");
                        bgp->inst_type = BGP_INSTANCE_TYPE_DEFAULT;
@@ -360,6 +359,8 @@ static void bgp_vrf_terminate(void)
 }
 
 static const struct frr_yang_module_info *const bgpd_yang_modules[] = {
+       &frr_interface_info,
+       &frr_route_map_info,
 };
 
 FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT,
@@ -487,6 +488,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 3e4dfb11add16f35eaf5321cbe0e13fa6b5cf644..41c4108c0abd0b057f4859cbb96d1771e6086066 100644 (file)
@@ -128,3 +128,6 @@ DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE_STR, "BGP flowspec rule str")
 DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_COMPILED, "BGP flowspec compiled")
 DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_NAME, "BGP flowspec name")
 DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_INDEX, "BGP flowspec index")
+
+DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie")
+DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service")
index 03715f5621104c46f881b3b09a629a856e7c083f..5428022551436a397ba3190689bd41aacb123dc2 100644 (file)
@@ -126,4 +126,7 @@ DECLARE_MTYPE(BGP_FLOWSPEC_COMPILED)
 DECLARE_MTYPE(BGP_FLOWSPEC_NAME)
 DECLARE_MTYPE(BGP_FLOWSPEC_INDEX)
 
+DECLARE_MTYPE(BGP_SRV6_L3VPN)
+DECLARE_MTYPE(BGP_SRV6_VPN)
+
 #endif /* _QUAGGA_BGP_MEMORY_H */
index 77448ec15d3477375149fbb5f717497b55f65701..6bc8134f3649d9d6bfa87f2fc5b5b056ec67171f 100644 (file)
@@ -280,7 +280,6 @@ void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath)
                if ((*mpath)->mp_attr)
                        bgp_attr_unintern(&(*mpath)->mp_attr);
                XFREE(MTYPE_BGP_MPATH_INFO, *mpath);
-               *mpath = NULL;
        }
 }
 
@@ -798,7 +797,7 @@ void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
                }
 
                /* Zap multipath attr nexthop so we set nexthop to self */
-               attr.nexthop.s_addr = 0;
+               attr.nexthop.s_addr = INADDR_ANY;
                memset(&attr.mp_nexthop_global, 0, sizeof(struct in6_addr));
 
                /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */
index 4031d2dfde40301a67315ce252f310b7f7d63a08..8b585704d80806fcbcb7021ac24f3f28d23f3753 100644 (file)
@@ -487,6 +487,20 @@ 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,7 +511,6 @@ 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)) {
@@ -508,7 +521,12 @@ 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..473a51c5a0e7cc2984874698ef8e355b9dfcef45 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;
@@ -656,7 +658,7 @@ static int bgp_capability_enhe(struct peer *peer, struct capability_header *hdr)
                nh_afi = afi_iana2int(pkt_nh_afi);
 
                if (afi != AFI_IP || nh_afi != AFI_IP6
-                   || !(safi == SAFI_UNICAST
+                   || !(safi == SAFI_UNICAST || safi == SAFI_MPLS_VPN
                         || safi == SAFI_LABELED_UNICAST)) {
                        flog_warn(
                                EC_BGP_CAPABILITY_INVALID_DATA,
@@ -708,15 +710,8 @@ static int bgp_capability_hostname(struct peer *peer,
        if (len) {
                str[len] = '\0';
 
-               if (peer->hostname != NULL) {
-                       XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
-                       peer->hostname = NULL;
-               }
-
-               if (peer->domainname != NULL) {
-                       XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
-                       peer->domainname = NULL;
-               }
+               XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
+               XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
 
                peer->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, str);
        }
@@ -748,10 +743,7 @@ static int bgp_capability_hostname(struct peer *peer,
        if (len) {
                str[len] = '\0';
 
-               if (peer->domainname != NULL) {
-                       XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
-                       peer->domainname = NULL;
-               }
+               XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
 
                peer->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, str);
        }
@@ -828,6 +820,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 +997,11 @@ 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 +1297,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 +1387,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;
 
@@ -1347,7 +1424,7 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
                        if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)
                            && peer->su.sa.sa_family == AF_INET6
                            && afi == AFI_IP
-                           && (safi == SAFI_UNICAST
+                           && (safi == SAFI_UNICAST || safi == SAFI_MPLS_VPN
                                || safi == SAFI_LABELED_UNICAST)) {
                                /* RFC 5549 Extended Next Hop Encoding
                                 */
@@ -1502,50 +1579,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..afb3a09b6b01eb85c6247cbad0338051d76d215d 100644 (file)
@@ -444,23 +444,37 @@ int bgp_generate_updgrp_packets(struct thread *thread)
                                            && peer->afc_nego[afi][safi]
                                            && peer->synctime
                                            && !CHECK_FLAG(
-                                                      peer->af_sflags[afi]
-                                                                     [safi],
-                                                      PEER_STATUS_EOR_SEND)) {
-                                               SET_FLAG(peer->af_sflags[afi]
+                                                   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);
-
-                                               if ((s = bgp_update_packet_eor(
-                                                            peer, afi,
-                                                            safi))) {
-                                                       bgp_packet_add(peer, s);
+                                                               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 +737,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);
                                }
@@ -736,7 +753,6 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
 
                if (bgp_notify.data) {
                        XFREE(MTYPE_TMP, bgp_notify.data);
-                       bgp_notify.data = NULL;
                        bgp_notify.length = 0;
                }
        }
@@ -755,6 +771,10 @@ 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);
 }
 
@@ -1166,7 +1186,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
        }
 
        /* remote router-id check. */
-       if (remote_id.s_addr == 0 || IPV4_CLASS_DE(ntohl(remote_id.s_addr))
+       if (remote_id.s_addr == INADDR_ANY
+           || IPV4_CLASS_DE(ntohl(remote_id.s_addr))
            || ntohl(peer->local_id.s_addr) == ntohl(remote_id.s_addr)) {
                if (bgp_debug_neighbor_events(peer))
                        zlog_debug("%s bad OPEN, wrong router identifier %s",
@@ -1334,7 +1355,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
            || peer->afc_nego[AFI_IP][SAFI_MULTICAST]
            || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
            || peer->afc_nego[AFI_IP][SAFI_ENCAP]) {
-               if (!peer->nexthop.v4.s_addr) {
+               if (peer->nexthop.v4.s_addr == INADDR_ANY) {
 #if defined(HAVE_CUMULUS)
                        flog_err(
                                EC_BGP_SND_FAIL,
@@ -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,33 @@ 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 */
@@ -1691,7 +1746,6 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
 
        if (peer->notify.data) {
                XFREE(MTYPE_TMP, peer->notify.data);
-               peer->notify.data = NULL;
                peer->notify.length = 0;
        }
 
@@ -1723,14 +1777,17 @@ 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;
                }
@@ -1738,7 +1795,6 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
                bgp_notify_print(peer, &bgp_notify, "received");
                if (bgp_notify.data) {
                        XFREE(MTYPE_TMP, bgp_notify.data);
-                       bgp_notify.data = NULL;
                        bgp_notify.length = 0;
                }
        }
@@ -1756,6 +1812,10 @@ 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 +2434,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..e83f7d950c8f172aa6b38f419bfc1fcc932d290c 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 14f5fefb2020955cf544a93448bd857a8e1e3c62..eea20d721039cb01c46ce7aa77715a38dea2c667 100644 (file)
@@ -754,13 +754,15 @@ int bgp_pbr_build_and_validate_entry(struct prefix *p,
                                 * draft-ietf-idr-flowspec-redirect
                                 */
                                if (api_action_redirect_ip) {
-                                       if (api_action_redirect_ip->u
-                                           .zr.redirect_ip_v4.s_addr)
+                                       if (api_action_redirect_ip->u.zr
+                                                   .redirect_ip_v4.s_addr
+                                           != INADDR_ANY)
                                                continue;
-                                       if (!path->attr->nexthop.s_addr)
+                                       if (path->attr->nexthop.s_addr
+                                           == INADDR_ANY)
                                                continue;
-                                       api_action_redirect_ip->u
-                                               .zr.redirect_ip_v4.s_addr =
+                                       api_action_redirect_ip->u.zr
+                                               .redirect_ip_v4.s_addr =
                                                path->attr->nexthop.s_addr;
                                        api_action_redirect_ip->u.zr.duplicate
                                                = ecom_eval->val[7];
@@ -1260,7 +1262,6 @@ void bgp_pbr_cleanup(struct bgp *bgp)
                return;
        bgp_pbr_reset(bgp, AFI_IP);
        XFREE(MTYPE_PBR, bgp->bgp_pbr_cfg);
-       bgp->bgp_pbr_cfg = NULL;
 }
 
 void bgp_pbr_init(struct bgp *bgp)
index 5f4486b8004252115eed66fa33771999d78f33ca..5e41f82d4a864823300bda93f4cb833a75217910 100644 (file)
 #include "workqueue.h"
 #include "queue.h"
 #include "memory.h"
+#include "srv6.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 +90,7 @@
 /* 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
@@ -233,8 +234,6 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
        if ((*extra)->bgp_fs_pbr)
                list_delete(&((*extra)->bgp_fs_pbr));
        XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra);
-
-       *extra = NULL;
 }
 
 /* Get bgp_path_info extra information for the given bgp_path_info, lazy
@@ -295,6 +294,87 @@ 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
@@ -1454,8 +1535,8 @@ void bgp_attr_add_gshut_community(struct attr *attr)
 static void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr)
 {
        if (family == AF_INET) {
-               attr->nexthop.s_addr = 0;
-               attr->mp_nexthop_global_in.s_addr = 0;
+               attr->nexthop.s_addr = INADDR_ANY;
+               attr->mp_nexthop_global_in.s_addr = INADDR_ANY;
        }
        if (family == AF_INET6)
                memset(&attr->mp_nexthop_global, 0, IPV6_MAX_BYTELEN);
@@ -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,38 @@ 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);
 }
 
@@ -2992,10 +3200,9 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
 
        /* If NEXT_HOP is present, validate it. */
        if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
-               if (attr->nexthop.s_addr == 0
+               if (attr->nexthop.s_addr == INADDR_ANY
                    || IPV4_CLASS_DE(ntohl(attr->nexthop.s_addr))
-                   || bgp_nexthop_self(bgp, afi, type, stype,
-                       attr, rn))
+                   || bgp_nexthop_self(bgp, afi, type, stype, attr, rn))
                        return 1;
        }
 
@@ -3008,11 +3215,11 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
                switch (attr->mp_nexthop_len) {
                case BGP_ATTR_NHLEN_IPV4:
                case BGP_ATTR_NHLEN_VPNV4:
-                       ret = (attr->mp_nexthop_global_in.s_addr == 0
-                              || IPV4_CLASS_DE(ntohl(
-                                         attr->mp_nexthop_global_in.s_addr))
-                              || bgp_nexthop_self(bgp, afi, type, stype,
-                                                  attr, rn));
+                       ret = (attr->mp_nexthop_global_in.s_addr == INADDR_ANY
+                              || IPV4_CLASS_DE(
+                                      ntohl(attr->mp_nexthop_global_in.s_addr))
+                              || bgp_nexthop_self(bgp, afi, type, stype, attr,
+                                                  rn));
                        break;
 
                case BGP_ATTR_NHLEN_IPV6_GLOBAL:
@@ -3302,6 +3509,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 +3545,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);
@@ -3431,6 +3641,22 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
                                bgp_set_valid_label(&extra->label[0]);
                }
 
+               /* Update SRv6 SID */
+               if (attr->srv6_l3vpn) {
+                       extra = bgp_path_info_extra_get(pi);
+                       if (sid_diff(&extra->sid[0], &attr->srv6_l3vpn->sid)) {
+                               sid_copy(&extra->sid[0],
+                                        &attr->srv6_l3vpn->sid);
+                               extra->num_sids = 1;
+                       }
+               } else if (attr->srv6_vpn) {
+                       extra = bgp_path_info_extra_get(pi);
+                       if (sid_diff(&extra->sid[0], &attr->srv6_vpn->sid)) {
+                               sid_copy(&extra->sid[0], &attr->srv6_vpn->sid);
+                               extra->num_sids = 1;
+                       }
+               }
+
 #if ENABLE_BGP_VNC
                if ((afi == AFI_IP || afi == AFI_IP6)
                    && (safi == SAFI_UNICAST)) {
@@ -3610,6 +3836,18 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
                        bgp_set_valid_label(&extra->label[0]);
        }
 
+       /* Update SRv6 SID */
+       if (safi == SAFI_MPLS_VPN) {
+               extra = bgp_path_info_extra_get(new);
+               if (attr->srv6_l3vpn) {
+                       sid_copy(&extra->sid[0], &attr->srv6_l3vpn->sid);
+                       extra->num_sids = 1;
+               } else if (attr->srv6_vpn) {
+                       sid_copy(&extra->sid[0], &attr->srv6_vpn->sid);
+                       extra->num_sids = 1;
+               }
+       }
+
        /* Update Overlay Index */
        if (afi == AFI_L2VPN) {
                overlay_index_update(new->attr,
@@ -5226,7 +5464,6 @@ static int bgp_static_set(struct vty *vty, const char *negate,
                                      bgp_static->rmap.name);
                                route_map_counter_decrement(
                                        bgp_static->rmap.map);
-                               bgp_static->rmap.name = NULL;
                                bgp_static->rmap.map = NULL;
                                bgp_static->valid = 0;
                        }
@@ -5237,7 +5474,7 @@ static int bgp_static_set(struct vty *vty, const char *negate,
                        bgp_static->backdoor = backdoor;
                        bgp_static->valid = 0;
                        bgp_static->igpmetric = 0;
-                       bgp_static->igpnexthop.s_addr = 0;
+                       bgp_static->igpnexthop.s_addr = INADDR_ANY;
                        bgp_static->label_index = label_index;
 
                        if (rmap) {
@@ -5528,7 +5765,7 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty,
                bgp_static->backdoor = 0;
                bgp_static->valid = 0;
                bgp_static->igpmetric = 0;
-               bgp_static->igpnexthop.s_addr = 0;
+               bgp_static->igpnexthop.s_addr = INADDR_ANY;
                bgp_static->label = label;
                bgp_static->prd = prd;
 
@@ -5648,7 +5885,6 @@ static int bgp_table_map_set(struct vty *vty, afi_t afi, safi_t safi,
        } else {
                XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
                route_map_counter_decrement(rmap->map);
-               rmap->name = NULL;
                rmap->map = NULL;
        }
 
@@ -5667,7 +5903,6 @@ static int bgp_table_map_unset(struct vty *vty, afi_t afi, safi_t safi,
        rmap = &bgp->table_map[afi][safi];
        XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
        route_map_counter_decrement(rmap->map);
-       rmap->name = NULL;
        rmap->map = NULL;
 
        if (bgp_fibupd_safi(safi))
@@ -7304,7 +7539,7 @@ void route_vty_out(struct vty *vty, struct prefix *p,
                                                 : inet_ntoa(attr->nexthop),
                                vrf_id_str);
        } else if (safi == SAFI_FLOWSPEC) {
-               if (attr->nexthop.s_addr != 0) {
+               if (attr->nexthop.s_addr != INADDR_ANY) {
                        if (json_paths) {
                                json_nexthop_global = json_object_new_object();
 
@@ -8994,6 +9229,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
                        vty_out(vty, "      Remote label: %d\n", label);
        }
 
+       /* Remote SID */
+       if (path->extra && path->extra->num_sids > 0 && safi != SAFI_EVPN) {
+               inet_ntop(AF_INET6, &path->extra->sid, buf, sizeof(buf));
+               if (json_paths)
+                       json_object_string_add(json_path, "remoteSid", buf);
+               else
+                       vty_out(vty, "      Remote SID: %s\n", buf);
+       }
+
        /* Label Index */
        if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
                if (json_paths)
@@ -10494,6 +10738,7 @@ DEFUN (show_ip_bgp_regexp,
        if (argv_find(argv, argc, "REGEX", &idx))
                regstr = argv[idx]->arg;
 
+       assert(regstr);
        return bgp_show_regexp(vty, bgp, (const char *)regstr, afi, safi,
                                 bgp_show_type_regexp, uj);
 }
@@ -11938,10 +12183,7 @@ static int bgp_distance_set(struct vty *vty, const char *distance_str,
        bdistance->distance = distance;
 
        /* Reset access-list configuration. */
-       if (bdistance->access_list) {
-               XFREE(MTYPE_AS_LIST, bdistance->access_list);
-               bdistance->access_list = NULL;
-       }
+       XFREE(MTYPE_AS_LIST, bdistance->access_list);
        if (access_list_str)
                bdistance->access_list =
                        XSTRDUP(MTYPE_AS_LIST, access_list_str);
index b9f3f3f7620119988f3cc6eebb11673c287ba0c4..8f31cd38dc01e3e7e956d9d6237bc74ca1d568ed 100644 (file)
@@ -78,6 +78,9 @@ enum bgp_show_adj_route_type {
  */
 #define BGP_MAX_LABELS 2
 
+/* Maximum number of sids we can process or send with a prefix. */
+#define BGP_MAX_SIDS 6
+
 /* Error codes for handling NLRI */
 #define BGP_NLRI_PARSE_OK 0
 #define BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW -1
@@ -118,6 +121,10 @@ struct bgp_path_info_extra {
        uint16_t af_flags;
 #define BGP_EVPN_MACIP_TYPE_SVI_IP (1 << 0)
 
+       /* SRv6 SID(s) for SRv6-VPN */
+       struct in6_addr sid[BGP_MAX_SIDS];
+       uint32_t num_sids;
+
 #if ENABLE_BGP_VNC
        union {
 
@@ -635,4 +642,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 ecd770a1d1dc9c90cc40df08145b21ee7440b074..f5de9ac8c67b505b931878cc0b9bf4b3a30f5565 100644 (file)
@@ -1705,7 +1705,7 @@ route_set_ip_nexthop(void *rule, const struct prefix *prefix,
                         */
                        SET_FLAG(path->attr->rmap_change_flags,
                                 BATTR_RMAP_NEXTHOP_PEER_ADDRESS);
-                       path->attr->nexthop.s_addr = 0;
+                       path->attr->nexthop.s_addr = INADDR_ANY;
                }
        } else {
                /* Set next hop value. */
index f31f8cd31bdb5beeb8572c88087f17f1d56b8504..77b547c0aa5f49ad0e1e49f8961fc639fc6b2af5 100644 (file)
@@ -755,7 +755,7 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[],
 
                        oid2in_addr(offset, len, &paddr);
                } else
-                       paddr.s_addr = 0;
+                       paddr.s_addr = INADDR_ANY;
 
                if (!rn)
                        return NULL;
@@ -804,7 +804,7 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[],
                                return min;
                        }
 
-                       paddr.s_addr = 0;
+                       paddr.s_addr = INADDR_ANY;
                } while ((rn = bgp_route_next(rn)) != NULL);
        }
        return NULL;
index b75246b172c606d9379afa7b1e529d21ac211346..04181d38bea113baf2a0e4eb2306c7ed67363786 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 5b3eb2c719b730226f6b59777e8b95bf758f77c9..3dbc67521212299b40baa42a952242bcec60b569 100644 (file)
@@ -111,7 +111,6 @@ static void sync_init(struct update_subgroup *subgrp)
 static void sync_delete(struct update_subgroup *subgrp)
 {
        XFREE(MTYPE_BGP_SYNCHRONISE, subgrp->sync);
-       subgrp->sync = NULL;
        if (subgrp->hash)
                hash_free(subgrp->hash);
        subgrp->hash = NULL;
@@ -220,7 +219,6 @@ static void conf_release(struct peer *src, afi_t afi, safi_t safi)
        XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->usmap.name);
 
        XFREE(MTYPE_BGP_PEER_HOST, src->host);
-       src->host = NULL;
 }
 
 static void peer2_updgrp_copy(struct update_group *updgrp, struct peer_af *paf)
@@ -735,7 +733,6 @@ static void update_group_delete(struct update_group *updgrp)
        conf_release(updgrp->conf, updgrp->afi, updgrp->safi);
 
        XFREE(MTYPE_BGP_PEER_HOST, updgrp->conf->host);
-       updgrp->conf->host = NULL;
 
        XFREE(MTYPE_BGP_PEER_IFNAME, updgrp->conf->ifname);
 
index 39eb065288fc4a3f4a384014a458fb43acc6ae4c..86750c0fcc5673b1d23eaca72265cc167109d43d 100644 (file)
@@ -467,16 +467,16 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
                                        mod_v4nh = &peer->nexthop.v4;
                                        nh_modified = 1;
                                }
-                       } else if (!v4nh.s_addr) {
+                       } else if (v4nh.s_addr == INADDR_ANY) {
                                mod_v4nh = &peer->nexthop.v4;
                                nh_modified = 1;
-                       } else if (
-                               peer->sort == BGP_PEER_EBGP
-                               && (bgp_multiaccess_check_v4(v4nh, peer) == 0)
-                               && !CHECK_FLAG(
+                       } else if (peer->sort == BGP_PEER_EBGP
+                                  && (bgp_multiaccess_check_v4(v4nh, peer)
+                                      == 0)
+                                  && !CHECK_FLAG(
                                           vec->flags,
                                           BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED)
-                               && !peer_af_flag_check(
+                                  && !peer_af_flag_check(
                                           peer, paf->afi, paf->safi,
                                           PEER_FLAG_NEXTHOP_UNCHANGED)) {
                                /* NOTE: not handling case where NH has new AFI
@@ -628,7 +628,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
                        mod_v4nh = &v4nh;
 
                        /* No route-map changes allowed for EVPN nexthops. */
-                       if (!v4nh.s_addr) {
+                       if (v4nh.s_addr == INADDR_ANY) {
                                mod_v4nh = &peer->nexthop.v4;
                                nh_modified = 1;
                        }
index 9dc6549d9c40c8df295bd0dccc37f733d5cdbf5e..f1ec9b49326d044ceb9e73e8c7435130f074c945 100644 (file)
@@ -105,9 +105,36 @@ 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 +717,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 +821,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,6 +832,12 @@ 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);
 
@@ -802,6 +845,14 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                                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. */
                if (stype == BGP_CLEAR_SOFT_NONE)
                        bgp->update_delay_over = 0;
@@ -836,6 +887,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 +935,11 @@ 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 +948,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 +972,11 @@ 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 +985,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 +2173,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 +2246,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 +2262,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 +2300,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 +2344,364 @@ 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 +9381,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,9 +9445,395 @@ 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)
+{
+       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                 : ");
+                       }
+
+                       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));
+               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;
@@ -9262,7 +10145,8 @@ 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 +11585,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,7 +11602,8 @@ 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)) {
@@ -10745,12 +11628,12 @@ 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);
 
+
                        if (p->t_gr_restart)
                                json_object_int_add(json_grace,
                                                    "gracefulRestartTimerMsecs",
@@ -10765,12 +11648,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],
@@ -10778,9 +11665,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                vty_out(vty, "%s%s",
                                                        eor_send_af_count ? ", "
                                                                          : "",
-                                                       get_afi_safi_str(afi,
-                                                                        safi,
-                                                                        false));
+                                                       get_afi_safi_str(
+                                                               afi, safi,
+                                                               false));
                                                eor_send_af_count++;
                                        }
                                }
@@ -10814,8 +11701,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 +12119,82 @@ 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 +12300,42 @@ 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 +12473,50 @@ 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 +12655,65 @@ 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 +14541,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 +15090,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 +15115,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 +15489,45 @@ 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 */
+       /* "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 +16522,8 @@ 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);
 
@@ -15512,21 +16685,29 @@ static void community_list_perror(struct vty *vty, int ret)
 /*community-list standard */
 DEFUN (community_list_standard,
        bgp_community_list_standard_cmd,
-       "bgp community-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
+       "bgp community-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
        BGP_STR
        COMMUNITY_LIST_STR
        "Community list number (standard)\n"
        "Add an standard community-list entry\n"
        "Community list name\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify community to reject\n"
        "Specify community to accept\n"
        COMMUNITY_VAL_STR)
 {
        char *cl_name_or_number = NULL;
+       char *seq = NULL;
        int direct = 0;
        int style = COMMUNITY_LIST_STANDARD;
        int idx = 0;
 
+       argv_find(argv, argc, "(1-4294967295)", &idx);
+       if (idx)
+               seq = argv[idx]->arg;
+
+       idx = 0;
        argv_find(argv, argc, "(1-99)", &idx);
        argv_find(argv, argc, "WORD", &idx);
        cl_name_or_number = argv[idx]->arg;
@@ -15535,8 +16716,8 @@ DEFUN (community_list_standard,
        argv_find(argv, argc, "AA:NN", &idx);
        char *str = argv_concat(argv, argc, idx);
 
-       int ret = community_list_set(bgp_clist, cl_name_or_number, str, direct,
-                                    style);
+       int ret = community_list_set(bgp_clist, cl_name_or_number, str, seq,
+                                    direct, style);
 
        XFREE(MTYPE_TMP, str);
 
@@ -15551,13 +16732,15 @@ DEFUN (community_list_standard,
 
 DEFUN (no_community_list_standard_all,
        no_bgp_community_list_standard_all_cmd,
-       "no bgp community-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
+       "no bgp community-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
        NO_STR
        BGP_STR
        COMMUNITY_LIST_STR
        "Community list number (standard)\n"
        "Add an standard community-list entry\n"
        "Community list name\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify community to reject\n"
        "Specify community to accept\n"
        COMMUNITY_VAL_STR)
@@ -15566,9 +16749,14 @@ DEFUN (no_community_list_standard_all,
        char *str = NULL;
        int direct = 0;
        int style = COMMUNITY_LIST_STANDARD;
-
+       char *seq = NULL;
        int idx = 0;
 
+       argv_find(argv, argc, "(1-4294967295)", &idx);
+       if (idx)
+               seq = argv[idx]->arg;
+
+       idx = 0;
        argv_find(argv, argc, "permit", &idx);
        argv_find(argv, argc, "deny", &idx);
 
@@ -15587,7 +16775,7 @@ DEFUN (no_community_list_standard_all,
        argv_find(argv, argc, "WORD", &idx);
        cl_name_or_number = argv[idx]->arg;
 
-       int ret = community_list_unset(bgp_clist, cl_name_or_number, str,
+       int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq,
                                       direct, style);
 
        XFREE(MTYPE_TMP, str);
@@ -15610,22 +16798,30 @@ ALIAS(no_community_list_standard_all, no_bgp_community_list_standard_all_list_cm
 /*community-list expanded */
 DEFUN (community_list_expanded_all,
        bgp_community_list_expanded_all_cmd,
-       "bgp community-list <(100-500)|expanded WORD> <deny|permit> AA:NN...",
+       "bgp community-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
        BGP_STR
        COMMUNITY_LIST_STR
        "Community list number (expanded)\n"
        "Add an expanded community-list entry\n"
        "Community list name\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify community to reject\n"
        "Specify community to accept\n"
        COMMUNITY_VAL_STR)
 {
        char *cl_name_or_number = NULL;
+       char *seq = NULL;
        int direct = 0;
        int style = COMMUNITY_LIST_EXPANDED;
-
        int idx = 0;
 
+       argv_find(argv, argc, "(1-4294967295)", &idx);
+       if (idx)
+               seq = argv[idx]->arg;
+
+       idx = 0;
+
        argv_find(argv, argc, "(100-500)", &idx);
        argv_find(argv, argc, "WORD", &idx);
        cl_name_or_number = argv[idx]->arg;
@@ -15634,8 +16830,8 @@ DEFUN (community_list_expanded_all,
        argv_find(argv, argc, "AA:NN", &idx);
        char *str = argv_concat(argv, argc, idx);
 
-       int ret = community_list_set(bgp_clist, cl_name_or_number, str, direct,
-                                    style);
+       int ret = community_list_set(bgp_clist, cl_name_or_number, str, seq,
+                                    direct, style);
 
        XFREE(MTYPE_TMP, str);
 
@@ -15650,24 +16846,31 @@ DEFUN (community_list_expanded_all,
 
 DEFUN (no_community_list_expanded_all,
        no_bgp_community_list_expanded_all_cmd,
-       "no bgp community-list <(100-500)|expanded WORD> <deny|permit> AA:NN...",
+       "no bgp community-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
        NO_STR
        BGP_STR
        COMMUNITY_LIST_STR
        "Community list number (expanded)\n"
        "Add an expanded community-list entry\n"
        "Community list name\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify community to reject\n"
        "Specify community to accept\n"
        COMMUNITY_VAL_STR)
 {
        char *cl_name_or_number = NULL;
+       char *seq = NULL;
        char *str = NULL;
        int direct = 0;
        int style = COMMUNITY_LIST_EXPANDED;
-
        int idx = 0;
 
+       argv_find(argv, argc, "(1-4294967295)", &idx);
+       if (idx)
+               seq = argv[idx]->arg;
+
+       idx = 0;
        argv_find(argv, argc, "permit", &idx);
        argv_find(argv, argc, "deny", &idx);
 
@@ -15686,7 +16889,7 @@ DEFUN (no_community_list_expanded_all,
        argv_find(argv, argc, "WORD", &idx);
        cl_name_or_number = argv[idx]->arg;
 
-       int ret = community_list_unset(bgp_clist, cl_name_or_number, str,
+       int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq,
                                       direct, style);
 
        XFREE(MTYPE_TMP, str);
@@ -15813,7 +17016,13 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc,
        char *str;
        int idx = 0;
        char *cl_name;
+       char *seq = NULL;
+
+       argv_find(argv, argc, "(1-4294967295)", &idx);
+       if (idx)
+               seq = argv[idx]->arg;
 
+       idx = 0;
        direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
                                                       : COMMUNITY_DENY;
 
@@ -15837,7 +17046,7 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc,
        else
                str = NULL;
 
-       ret = lcommunity_list_set(bgp_clist, cl_name, str, direct, style);
+       ret = lcommunity_list_set(bgp_clist, cl_name, str, seq, direct, style);
 
        /* Free temporary community list string allocated by
           argv_concat().  */
@@ -15857,7 +17066,13 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc,
        int direct = 0;
        char *str = NULL;
        int idx = 0;
+       char *seq = NULL;
+
+       argv_find(argv, argc, "(1-4294967295)", &idx);
+       if (idx)
+               seq = argv[idx]->arg;
 
+       idx = 0;
        argv_find(argv, argc, "permit", &idx);
        argv_find(argv, argc, "deny", &idx);
 
@@ -15881,7 +17096,7 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc,
        argv_find(argv, argc, "WORD", &idx);
 
        /* Unset community list.  */
-       ret = lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, direct,
+       ret = lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, seq, direct,
                                    style);
 
        /* Free temporary community list string allocated by
@@ -15902,10 +17117,12 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc,
 
 DEFUN (lcommunity_list_standard,
        bgp_lcommunity_list_standard_cmd,
-       "bgp large-community-list (1-99) <deny|permit> AA:BB:CC...",
+       "bgp large-community-list (1-99) [seq (1-4294967295)] <deny|permit> AA:BB:CC...",
        BGP_STR
        LCOMMUNITY_LIST_STR
        "Large Community list number (standard)\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify large community to reject\n"
        "Specify large community to accept\n"
        LCOMMUNITY_VAL_STR)
@@ -15916,10 +17133,12 @@ DEFUN (lcommunity_list_standard,
 
 DEFUN (lcommunity_list_expanded,
        bgp_lcommunity_list_expanded_cmd,
-       "bgp large-community-list (100-500) <deny|permit> LINE...",
+       "bgp large-community-list (100-500) [seq (1-4294967295)] <deny|permit> LINE...",
        BGP_STR
        LCOMMUNITY_LIST_STR
        "Large Community list number (expanded)\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify large community to reject\n"
        "Specify large community to accept\n"
        "An ordered list as a regular-expression\n")
@@ -15930,11 +17149,13 @@ DEFUN (lcommunity_list_expanded,
 
 DEFUN (lcommunity_list_name_standard,
        bgp_lcommunity_list_name_standard_cmd,
-       "bgp large-community-list standard WORD <deny|permit> AA:BB:CC...",
+       "bgp large-community-list standard WORD [seq (1-4294967295)] <deny|permit> AA:BB:CC...",
        BGP_STR
        LCOMMUNITY_LIST_STR
        "Specify standard large-community-list\n"
        "Large Community list name\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify large community to reject\n"
        "Specify large community to accept\n"
        LCOMMUNITY_VAL_STR)
@@ -15945,11 +17166,13 @@ DEFUN (lcommunity_list_name_standard,
 
 DEFUN (lcommunity_list_name_expanded,
        bgp_lcommunity_list_name_expanded_cmd,
-       "bgp large-community-list expanded WORD <deny|permit> LINE...",
+       "bgp large-community-list expanded WORD [seq (1-4294967295)] <deny|permit> LINE...",
        BGP_STR
        LCOMMUNITY_LIST_STR
        "Specify expanded large-community-list\n"
        "Large Community list name\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify large community to reject\n"
        "Specify large community to accept\n"
        "An ordered list as a regular-expression\n")
@@ -15958,8 +17181,8 @@ DEFUN (lcommunity_list_name_expanded,
                                       LARGE_COMMUNITY_LIST_EXPANDED, 1);
 }
 
-DEFUN (no_lcommunity_list_standard_all,
-       no_bgp_lcommunity_list_standard_all_cmd,
+DEFUN (no_lcommunity_list_all,
+       no_bgp_lcommunity_list_all_cmd,
        "no bgp large-community-list <(1-99)|(100-500)|WORD>",
        NO_STR
        BGP_STR
@@ -15972,6 +17195,19 @@ DEFUN (no_lcommunity_list_standard_all,
                                         LARGE_COMMUNITY_LIST_STANDARD);
 }
 
+DEFUN (no_lcommunity_list_name_standard_all,
+       no_bgp_lcommunity_list_name_standard_all_cmd,
+       "no bgp large-community-list standard WORD",
+       NO_STR
+       BGP_STR
+       LCOMMUNITY_LIST_STR
+       "Specify standard large-community-list\n"
+       "Large Community list name\n")
+{
+       return lcommunity_list_unset_vty(vty, argc, argv,
+                                        LARGE_COMMUNITY_LIST_STANDARD);
+}
+
 DEFUN (no_lcommunity_list_name_expanded_all,
        no_bgp_lcommunity_list_name_expanded_all_cmd,
        "no bgp large-community-list expanded WORD",
@@ -15987,11 +17223,13 @@ DEFUN (no_lcommunity_list_name_expanded_all,
 
 DEFUN (no_lcommunity_list_standard,
        no_bgp_lcommunity_list_standard_cmd,
-       "no bgp large-community-list (1-99) <deny|permit> AA:AA:NN...",
+       "no bgp large-community-list (1-99) [seq (1-4294967295)] <deny|permit> AA:AA:NN...",
        NO_STR
        BGP_STR
        LCOMMUNITY_LIST_STR
        "Large Community list number (standard)\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify large community to reject\n"
        "Specify large community to accept\n"
        LCOMMUNITY_VAL_STR)
@@ -16002,11 +17240,13 @@ DEFUN (no_lcommunity_list_standard,
 
 DEFUN (no_lcommunity_list_expanded,
        no_bgp_lcommunity_list_expanded_cmd,
-       "no bgp large-community-list (100-500) <deny|permit> LINE...",
+       "no bgp large-community-list (100-500) [seq (1-4294967295)] <deny|permit> LINE...",
        NO_STR
        BGP_STR
        LCOMMUNITY_LIST_STR
        "Large Community list number (expanded)\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify large community to reject\n"
        "Specify large community to accept\n"
        "An ordered list as a regular-expression\n")
@@ -16017,12 +17257,14 @@ DEFUN (no_lcommunity_list_expanded,
 
 DEFUN (no_lcommunity_list_name_standard,
        no_bgp_lcommunity_list_name_standard_cmd,
-       "no bgp large-community-list standard WORD <deny|permit> AA:AA:NN...",
+       "no bgp large-community-list standard WORD [seq (1-4294967295)] <deny|permit> AA:AA:NN...",
        NO_STR
        BGP_STR
        LCOMMUNITY_LIST_STR
        "Specify standard large-community-list\n"
        "Large Community list name\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify large community to reject\n"
        "Specify large community to accept\n"
        LCOMMUNITY_VAL_STR)
@@ -16033,12 +17275,14 @@ DEFUN (no_lcommunity_list_name_standard,
 
 DEFUN (no_lcommunity_list_name_expanded,
        no_bgp_lcommunity_list_name_expanded_cmd,
-       "no bgp large-community-list expanded WORD <deny|permit> LINE...",
+       "no bgp large-community-list expanded WORD [seq (1-4294967295)] <deny|permit> LINE...",
        NO_STR
        BGP_STR
        LCOMMUNITY_LIST_STR
        "Specify expanded large-community-list\n"
        "Large community list name\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify large community to reject\n"
        "Specify large community to accept\n"
        "An ordered list as a regular-expression\n")
@@ -16133,12 +17377,14 @@ DEFUN (show_lcommunity_list_arg,
 
 DEFUN (extcommunity_list_standard,
        bgp_extcommunity_list_standard_cmd,
-       "bgp extcommunity-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
+       "bgp extcommunity-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
        BGP_STR
        EXTCOMMUNITY_LIST_STR
        "Extended Community list number (standard)\n"
        "Specify standard extcommunity-list\n"
        "Community list name\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify community to reject\n"
        "Specify community to accept\n"
        EXTCOMMUNITY_VAL_STR)
@@ -16146,18 +17392,24 @@ DEFUN (extcommunity_list_standard,
        int style = EXTCOMMUNITY_LIST_STANDARD;
        int direct = 0;
        char *cl_number_or_name = NULL;
+       char *seq = NULL;
 
        int idx = 0;
 
        argv_find(argv, argc, "(1-99)", &idx);
        argv_find(argv, argc, "WORD", &idx);
        cl_number_or_name = argv[idx]->arg;
+
+       argv_find(argv, argc, "(1-4294967295)", &idx);
+       if (idx)
+               seq = argv[idx]->arg;
+
        direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
                                                       : COMMUNITY_DENY;
        argv_find(argv, argc, "AA:NN", &idx);
        char *str = argv_concat(argv, argc, idx);
 
-       int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str,
+       int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str, seq,
                                        direct, style);
 
        XFREE(MTYPE_TMP, str);
@@ -16172,12 +17424,14 @@ DEFUN (extcommunity_list_standard,
 
 DEFUN (extcommunity_list_name_expanded,
        bgp_extcommunity_list_name_expanded_cmd,
-       "bgp extcommunity-list <(100-500)|expanded WORD> <deny|permit> LINE...",
+       "bgp extcommunity-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> LINE...",
        BGP_STR
        EXTCOMMUNITY_LIST_STR
        "Extended Community list number (expanded)\n"
        "Specify expanded extcommunity-list\n"
        "Extended Community list name\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify community to reject\n"
        "Specify community to accept\n"
        "An ordered list as a regular-expression\n")
@@ -16185,17 +17439,23 @@ DEFUN (extcommunity_list_name_expanded,
        int style = EXTCOMMUNITY_LIST_EXPANDED;
        int direct = 0;
        char *cl_number_or_name = NULL;
+       char *seq = NULL;
        int idx = 0;
 
        argv_find(argv, argc, "(100-500)", &idx);
        argv_find(argv, argc, "WORD", &idx);
        cl_number_or_name = argv[idx]->arg;
+
+       argv_find(argv, argc, "(1-4294967295)", &idx);
+       if (idx)
+               seq = argv[idx]->arg;
+
        direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT
                                                       : COMMUNITY_DENY;
        argv_find(argv, argc, "LINE", &idx);
        char *str = argv_concat(argv, argc, idx);
 
-       int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str,
+       int ret = extcommunity_list_set(bgp_clist, cl_number_or_name, str, seq,
                                        direct, style);
 
        XFREE(MTYPE_TMP, str);
@@ -16210,13 +17470,15 @@ DEFUN (extcommunity_list_name_expanded,
 
 DEFUN (no_extcommunity_list_standard_all,
        no_bgp_extcommunity_list_standard_all_cmd,
-       "no bgp extcommunity-list <(1-99)|standard WORD> <deny|permit> AA:NN...",
+       "no bgp extcommunity-list <(1-99)|standard WORD> [seq (1-4294967295)] <deny|permit> AA:NN...",
        NO_STR
        BGP_STR
        EXTCOMMUNITY_LIST_STR
        "Extended Community list number (standard)\n"
        "Specify standard extcommunity-list\n"
        "Community list name\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify community to reject\n"
        "Specify community to accept\n"
        EXTCOMMUNITY_VAL_STR)
@@ -16225,11 +17487,16 @@ DEFUN (no_extcommunity_list_standard_all,
        int direct = 0;
        char *cl_number_or_name = NULL;
        char *str = NULL;
+       char *seq = NULL;
        int idx = 0;
 
+       argv_find(argv, argc, "(1-4294967295)", &idx);
+       if (idx)
+               seq = argv[idx]->arg;
+
+       idx = 0;
        argv_find(argv, argc, "permit", &idx);
        argv_find(argv, argc, "deny", &idx);
-
        if (idx) {
                direct = argv_find(argv, argc, "permit", &idx)
                                 ? COMMUNITY_PERMIT
@@ -16246,7 +17513,7 @@ DEFUN (no_extcommunity_list_standard_all,
        cl_number_or_name = argv[idx]->arg;
 
        int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
-                                         direct, style);
+                                         seq, direct, style);
 
        XFREE(MTYPE_TMP, str);
 
@@ -16268,13 +17535,15 @@ ALIAS(no_extcommunity_list_standard_all,
 
 DEFUN (no_extcommunity_list_expanded_all,
        no_bgp_extcommunity_list_expanded_all_cmd,
-       "no bgp extcommunity-list <(100-500)|expanded WORD> <deny|permit> LINE...",
+       "no bgp extcommunity-list <(100-500)|expanded WORD> [seq (1-4294967295)] <deny|permit> LINE...",
        NO_STR
        BGP_STR
        EXTCOMMUNITY_LIST_STR
        "Extended Community list number (expanded)\n"
        "Specify expanded extcommunity-list\n"
        "Extended Community list name\n"
+       "Sequence number of an entry\n"
+       "Sequence number\n"
        "Specify community to reject\n"
        "Specify community to accept\n"
        "An ordered list as a regular-expression\n")
@@ -16283,8 +17552,14 @@ DEFUN (no_extcommunity_list_expanded_all,
        int direct = 0;
        char *cl_number_or_name = NULL;
        char *str = NULL;
+       char *seq = NULL;
        int idx = 0;
 
+       argv_find(argv, argc, "(1-4294967295)", &idx);
+       if (idx)
+               seq = argv[idx]->arg;
+
+       idx = 0;
        argv_find(argv, argc, "permit", &idx);
        argv_find(argv, argc, "deny", &idx);
 
@@ -16304,7 +17579,7 @@ DEFUN (no_extcommunity_list_expanded_all,
        cl_number_or_name = argv[idx]->arg;
 
        int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str,
-                                         direct, style);
+                                         seq, direct, style);
 
        XFREE(MTYPE_TMP, str);
 
@@ -16415,18 +17690,22 @@ static int community_list_config_write(struct vty *vty)
 
        for (list = cm->num.head; list; list = list->next)
                for (entry = list->head; entry; entry = entry->next) {
-                       vty_out(vty, "bgp community-list %s %s %s\n", list->name,
+                       vty_out(vty,
+                               "bgp community-list %s seq %" PRId64 " %s %s\n",
+                               list->name, entry->seq,
                                community_direct_str(entry->direct),
                                community_list_config_str(entry));
                        write++;
                }
        for (list = cm->str.head; list; list = list->next)
                for (entry = list->head; entry; entry = entry->next) {
-                       vty_out(vty, "bgp community-list %s %s %s %s\n",
+                       vty_out(vty,
+                               "bgp community-list %s %s seq %" PRId64 " %s %s\n",
                                entry->style == COMMUNITY_LIST_STANDARD
                                        ? "standard"
                                        : "expanded",
-                               list->name, community_direct_str(entry->direct),
+                               list->name, entry->seq,
+                               community_direct_str(entry->direct),
                                community_list_config_str(entry));
                        write++;
                }
@@ -16436,18 +17715,23 @@ static int community_list_config_write(struct vty *vty)
 
        for (list = cm->num.head; list; list = list->next)
                for (entry = list->head; entry; entry = entry->next) {
-                       vty_out(vty, "bgp extcommunity-list %s %s %s\n",
-                               list->name, community_direct_str(entry->direct),
+                       vty_out(vty,
+                               "bgp extcommunity-list %s seq %" PRId64 " %s %s\n",
+                               list->name, entry->seq,
+                               community_direct_str(entry->direct),
                                community_list_config_str(entry));
                        write++;
                }
        for (list = cm->str.head; list; list = list->next)
                for (entry = list->head; entry; entry = entry->next) {
-                       vty_out(vty, "bgp extcommunity-list %s %s %s %s\n",
+                       vty_out(vty,
+                               "bgp extcommunity-list %s %s seq %" PRId64
+                               " %s %s\n",
                                entry->style == EXTCOMMUNITY_LIST_STANDARD
                                        ? "standard"
                                        : "expanded",
-                               list->name, community_direct_str(entry->direct),
+                               list->name, entry->seq,
+                               community_direct_str(entry->direct),
                                community_list_config_str(entry));
                        write++;
                }
@@ -16459,18 +17743,24 @@ static int community_list_config_write(struct vty *vty)
 
        for (list = cm->num.head; list; list = list->next)
                for (entry = list->head; entry; entry = entry->next) {
-                       vty_out(vty, "bgp large-community-list %s %s %s\n",
-                               list->name, community_direct_str(entry->direct),
+                       vty_out(vty,
+                               "bgp large-community-list %s seq %" PRId64
+                               " %s %s\n",
+                               list->name, entry->seq,
+                               community_direct_str(entry->direct),
                                community_list_config_str(entry));
                        write++;
                }
        for (list = cm->str.head; list; list = list->next)
                for (entry = list->head; entry; entry = entry->next) {
-                       vty_out(vty, "bgp large-community-list %s %s %s %s\n",
+                       vty_out(vty,
+                               "bgp large-community-list %s %s seq %" PRId64
+                               " %s %s\n",
+
                                entry->style == LARGE_COMMUNITY_LIST_STANDARD
                                        ? "standard"
                                        : "expanded",
-                               list->name, community_direct_str(entry->direct),
+                               list->name, entry->seq, community_direct_str(entry->direct),
                                community_list_config_str(entry));
                        write++;
                }
@@ -16513,7 +17803,9 @@ static void community_list_vty(void)
        install_element(CONFIG_NODE, &bgp_lcommunity_list_expanded_cmd);
        install_element(CONFIG_NODE, &bgp_lcommunity_list_name_standard_cmd);
        install_element(CONFIG_NODE, &bgp_lcommunity_list_name_expanded_cmd);
-       install_element(CONFIG_NODE, &no_bgp_lcommunity_list_standard_all_cmd);
+       install_element(CONFIG_NODE, &no_bgp_lcommunity_list_all_cmd);
+       install_element(CONFIG_NODE,
+                       &no_bgp_lcommunity_list_name_standard_all_cmd);
        install_element(CONFIG_NODE,
                        &no_bgp_lcommunity_list_name_expanded_all_cmd);
        install_element(CONFIG_NODE, &no_bgp_lcommunity_list_standard_cmd);
index 5f3ce9cd8e54284a68083e53dfbb138a838e9596..fa7b96d87bd38d17175dadf469a67dbd1f1a1b14 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,107 @@ 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..076b6aabca12b68282c4699cb0cf0cace2d7e32b 100644 (file)
@@ -819,7 +819,7 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote,
 
                /* IPv4 nexthop. */
                ret = if_get_ipv4_address(ifp, &nexthop->v4);
-               if (!ret && peer->local_id.s_addr)
+               if (!ret && peer->local_id.s_addr != INADDR_ANY)
                        nexthop->v4 = peer->local_id;
 
                /* Global address*/
@@ -1779,7 +1779,6 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type,
        /* Unset route-map. */
        XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name);
        route_map_counter_decrement(red->rmap.map);
-       red->rmap.name = NULL;
        red->rmap.map = NULL;
 
        /* Unset metric. */
@@ -2437,6 +2436,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)
@@ -2548,7 +2548,8 @@ static int bgp_zebra_process_local_vni(ZAPI_CALLBACK_ARGS)
 
        if (cmd == ZEBRA_VNI_ADD)
                return bgp_evpn_local_vni_add(
-                       bgp, vni, vtep_ip.s_addr ? vtep_ip : bgp->router_id,
+                       bgp, vni,
+                       vtep_ip.s_addr != INADDR_ANY ? vtep_ip : bgp->router_id,
                        tenant_vrf_id, mcast_grp);
        else
                return bgp_evpn_local_vni_del(bgp, vni);
@@ -2975,7 +2976,7 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
        SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
 
        /* redirect IP */
-       if (nh->gate.ipv4.s_addr) {
+       if (nh->gate.ipv4.s_addr != INADDR_ANY) {
                char buff[PREFIX_STRLEN];
 
                api_nh->vrf_id = nh->vrf_id;
@@ -3016,3 +3017,120 @@ 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;
+}
+
+
+/* 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..5a02e2fbf9f9b893df68e441158f53da996a8958 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,7 @@ 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..60bcc7b8e3482f4dd56cb4912573875edcc61cf9 100644 (file)
@@ -335,7 +335,8 @@ void bgp_router_id_zebra_bump(vrf_id_t vrf_id, const struct prefix *router_id)
 int bgp_router_id_static_set(struct bgp *bgp, struct in_addr id)
 {
        bgp->router_id_static = id;
-       bgp_router_id_set(bgp, id.s_addr ? &id : &bgp->router_id_zebra,
+       bgp_router_id_set(bgp,
+                         id.s_addr != INADDR_ANY ? &id : &bgp->router_id_zebra,
                          true /* is config */);
        return 0;
 }
@@ -1007,26 +1008,10 @@ static void peer_free(struct peer *peer)
 
        XFREE(MTYPE_PEER_TX_SHUTDOWN_MSG, peer->tx_shutdown_message);
 
-       if (peer->desc) {
-               XFREE(MTYPE_PEER_DESC, peer->desc);
-               peer->desc = NULL;
-       }
-
-       /* Free allocated host character. */
-       if (peer->host) {
-               XFREE(MTYPE_BGP_PEER_HOST, peer->host);
-               peer->host = NULL;
-       }
-
-       if (peer->domainname) {
-               XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
-               peer->domainname = NULL;
-       }
-
-       if (peer->ifname) {
-               XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
-               peer->ifname = NULL;
-       }
+       XFREE(MTYPE_PEER_DESC, peer->desc);
+       XFREE(MTYPE_BGP_PEER_HOST, peer->host);
+       XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
+       XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
 
        /* Update source configuration.  */
        if (peer->update_source) {
@@ -1034,10 +1019,7 @@ static void peer_free(struct peer *peer)
                peer->update_source = NULL;
        }
 
-       if (peer->update_if) {
-               XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
-               peer->update_if = NULL;
-       }
+       XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
 
        XFREE(MTYPE_TMP, peer->notify.data);
        memset(&peer->notify, 0, sizeof(struct bgp_notify));
@@ -1047,10 +1029,7 @@ static void peer_free(struct peer *peer)
 
        bgp_sync_delete(peer);
 
-       if (peer->conf_if) {
-               XFREE(MTYPE_PEER_CONF_IF, peer->conf_if);
-               peer->conf_if = NULL;
-       }
+       XFREE(MTYPE_PEER_CONF_IF, peer->conf_if);
 
        bfd_info_free(&(peer->bfd_info));
 
@@ -1102,6 +1081,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 +1245,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 +1307,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);
@@ -1251,10 +1349,7 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
        if (peer_src->update_source) {
                if (peer_dst->update_source)
                        sockunion_free(peer_dst->update_source);
-               if (peer_dst->update_if) {
-                       XFREE(MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
-                       peer_dst->update_if = NULL;
-               }
+               XFREE(MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
                peer_dst->update_source =
                        sockunion_dup(peer_src->update_source);
        } else if (peer_src->update_if) {
@@ -1534,6 +1629,9 @@ 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 +2196,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;
@@ -2261,57 +2359,24 @@ int peer_delete(struct peer *peer)
                filter = &peer->filter[afi][safi];
 
                for (i = FILTER_IN; i < FILTER_MAX; i++) {
-                       if (filter->dlist[i].name) {
-                               XFREE(MTYPE_BGP_FILTER_NAME,
-                                     filter->dlist[i].name);
-                               filter->dlist[i].name = NULL;
-                       }
-
-                       if (filter->plist[i].name) {
-                               XFREE(MTYPE_BGP_FILTER_NAME,
-                                     filter->plist[i].name);
-                               filter->plist[i].name = NULL;
-                       }
-
-                       if (filter->aslist[i].name) {
-                               XFREE(MTYPE_BGP_FILTER_NAME,
-                                     filter->aslist[i].name);
-                               filter->aslist[i].name = NULL;
-                       }
+                       XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[i].name);
+                       XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[i].name);
+                       XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[i].name);
                }
 
                for (i = RMAP_IN; i < RMAP_MAX; i++) {
-                       if (filter->map[i].name) {
-                               XFREE(MTYPE_BGP_FILTER_NAME,
-                                     filter->map[i].name);
-                               filter->map[i].name = NULL;
-                       }
-               }
-
-               if (filter->usmap.name) {
-                       XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
-                       filter->usmap.name = NULL;
+                       XFREE(MTYPE_BGP_FILTER_NAME, filter->map[i].name);
                }
 
-               if (peer->default_rmap[afi][safi].name) {
-                       XFREE(MTYPE_ROUTE_MAP_NAME,
-                             peer->default_rmap[afi][safi].name);
-                       peer->default_rmap[afi][safi].name = NULL;
-               }
+               XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+               XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name);
        }
 
        FOREACH_AFI_SAFI (afi, safi)
                peer_af_delete(peer, afi, safi);
 
-       if (peer->hostname) {
-               XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
-               peer->hostname = NULL;
-       }
-
-       if (peer->domainname) {
-               XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
-               peer->domainname = NULL;
-       }
+       XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
+       XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
 
        peer_unlock(peer); /* initial reference */
 
@@ -2868,18 +2933,12 @@ static struct bgp *bgp_create(as_t *as, const char *name,
        XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->host);
        bgp->peer_self->host =
                XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement");
-       if (bgp->peer_self->hostname != NULL) {
-               XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->hostname);
-               bgp->peer_self->hostname = NULL;
-       }
+       XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->hostname);
        if (cmd_hostname_get())
                bgp->peer_self->hostname =
                        XSTRDUP(MTYPE_BGP_PEER_HOST, cmd_hostname_get());
 
-       if (bgp->peer_self->domainname != NULL) {
-               XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->domainname);
-               bgp->peer_self->domainname = NULL;
-       }
+       XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->domainname);
        if (cmd_domainname_get())
                bgp->peer_self->domainname =
                        XSTRDUP(MTYPE_BGP_PEER_HOST, cmd_domainname_get());
@@ -2902,6 +2961,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 +2976,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 +3008,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 +3054,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 +3300,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 +3316,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");
@@ -4360,8 +4441,6 @@ int peer_description_unset(struct peer *peer)
 {
        XFREE(MTYPE_PEER_DESC, peer->desc);
 
-       peer->desc = NULL;
-
        return 0;
 }
 
@@ -5111,7 +5190,6 @@ void peer_interface_set(struct peer *peer, const char *str)
 void peer_interface_unset(struct peer *peer)
 {
        XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
-       peer->ifname = NULL;
 }
 
 /* Allow-as in.  */
@@ -7099,3 +7177,31 @@ 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..7d3bd22a68e973ba93e7b59daaf200db3cada1ec 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 */
        /*
@@ -1247,8 +1382,7 @@ DECLARE_QOBJ_TYPE(peer)
        ((peer)->attr = (group)->conf->attr)
 #define PEER_STR_ATTR_INHERIT(peer, group, attr, mt)                           \
        do {                                                                   \
-               if ((peer)->attr)                                              \
-                       XFREE(mt, (peer)->attr);                               \
+               XFREE(mt, (peer)->attr);                                       \
                if ((group)->conf->attr)                                       \
                        (peer)->attr = XSTRDUP(mt, (group)->conf->attr);       \
                else                                                           \
@@ -1456,6 +1590,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 +1657,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 +1914,32 @@ 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};                                   \
+               for (ALL_LIST_ELEMENTS_RO(_peer_list, node, 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 +2129,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 7c4f8eaa012633d364087d4fb9e3d39aff196ee7..4701d2e1fa21fc46612d58cd6c8948e97093c7a5 100644 (file)
@@ -1489,10 +1489,7 @@ void rfapiFreeBgpTeaOptionChain(struct bgp_tea_options *p)
        while (p) {
                next = p->next;
 
-               if (p->value) {
-                       XFREE(MTYPE_BGP_TEA_OPTIONS_VALUE, p->value);
-                       p->value = NULL;
-               }
+               XFREE(MTYPE_BGP_TEA_OPTIONS_VALUE, p->value);
                XFREE(MTYPE_BGP_TEA_OPTIONS, p);
 
                p = next;
index f31342e1925902a4db52f10d85f018b702cefa78..a7bc909c589161dd576560dfdd9d4a9bed530073 100644 (file)
@@ -248,7 +248,6 @@ struct rfapi_un_option *rfapi_encap_tlv_to_un_option(struct attr *attr)
        }
        if (rc) {
                XFREE(MTYPE_RFAPI_UN_OPTION, uo);
-               uo = NULL;
        }
        return uo;
 }
index 5ad822211bbb407618eb32165561c7a565cff7d1..77fcf909c87ad7ecf05ad2a3c4692cfff8f0a45a 100644 (file)
@@ -431,6 +431,14 @@ void rfapi_vty_out_vncinfo(struct vty *vty, struct prefix *p,
                else
                        vty_out(vty, " label=%u",
                                decode_label(&bpi->extra->label[0]));
+
+               if (bpi->extra->num_sids) {
+                       char buf[BUFSIZ];
+
+                       vty_out(vty, " sid=%s",
+                               inet_ntop(AF_INET6, &bpi->extra->sid[0], buf,
+                                         sizeof(buf)));
+               }
        }
 
        if (!rfapiGetVncLifetime(bpi->attr, &lifetime)) {
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 74a8605bf2cd14cf9fb2e783afbda1465310a13b..e3526d184371a47ed91df0538d3f2d1232e3af19 100644 (file)
@@ -169,175 +169,201 @@ Zebra Protocol Commands
 +------------------------------------+-------+
 | ZEBRA_INTERFACE_SET_MASTER         | 6     |
 +------------------------------------+-------+
-| ZEBRA_ROUTE_ADD                    | 7     |
+| ZEBRA_INTERFACE_SET_PROTODOWN      | 7     |
 +------------------------------------+-------+
-| ZEBRA_ROUTE_DELETE                 | 8     |
+| ZEBRA_ROUTE_ADD                    | 8     |
 +------------------------------------+-------+
-| ZEBRA_ROUTE_NOTIFY_OWNER           | 9     |
+| ZEBRA_ROUTE_DELETE                 | 9     |
 +------------------------------------+-------+
-| ZEBRA_REDISTRIBUTE_ADD             | 10    |
+| ZEBRA_ROUTE_NOTIFY_OWNER           | 10    |
 +------------------------------------+-------+
-| ZEBRA_REDISTRIBUTE_DELETE          | 11    |
+| ZEBRA_REDISTRIBUTE_ADD             | 11    |
 +------------------------------------+-------+
-| ZEBRA_REDISTRIBUTE_DEFAULT_ADD     | 12    |
+| ZEBRA_REDISTRIBUTE_DELETE          | 12    |
 +------------------------------------+-------+
-| ZEBRA_REDISTRIBUTE_DEFAULT_DELETE  | 13    |
+| ZEBRA_REDISTRIBUTE_DEFAULT_ADD     | 13    |
 +------------------------------------+-------+
-| ZEBRA_ROUTER_ID_ADD                | 14    |
+| ZEBRA_REDISTRIBUTE_DEFAULT_DELETE  | 14    |
 +------------------------------------+-------+
-| ZEBRA_ROUTER_ID_DELETE             | 15    |
+| ZEBRA_ROUTER_ID_ADD                | 15    |
 +------------------------------------+-------+
-| ZEBRA_ROUTER_ID_UPDATE             | 16    |
+| ZEBRA_ROUTER_ID_DELETE             | 16    |
 +------------------------------------+-------+
-| ZEBRA_HELLO                        | 17    |
+| ZEBRA_ROUTER_ID_UPDATE             | 17    |
 +------------------------------------+-------+
-| ZEBRA_CAPABILITIES                 | 18    |
+| ZEBRA_HELLO                        | 18    |
 +------------------------------------+-------+
-| ZEBRA_NEXTHOP_REGISTER             | 19    |
+| ZEBRA_CAPABILITIES                 | 19    |
 +------------------------------------+-------+
-| ZEBRA_NEXTHOP_UNREGISTER           | 20    |
+| ZEBRA_NEXTHOP_REGISTER             | 20    |
 +------------------------------------+-------+
-| ZEBRA_NEXTHOP_UPDATE               | 21    |
+| ZEBRA_NEXTHOP_UNREGISTER           | 21    |
 +------------------------------------+-------+
-| ZEBRA_INTERFACE_NBR_ADDRESS_ADD    | 22    |
+| ZEBRA_NEXTHOP_UPDATE               | 22    |
 +------------------------------------+-------+
-| ZEBRA_INTERFACE_NBR_ADDRESS_DELETE | 23    |
+| ZEBRA_INTERFACE_NBR_ADDRESS_ADD    | 23    |
 +------------------------------------+-------+
-| ZEBRA_INTERFACE_BFD_DEST_UPDATE    | 24    |
+| ZEBRA_INTERFACE_NBR_ADDRESS_DELETE | 24    |
 +------------------------------------+-------+
-| ZEBRA_IMPORT_ROUTE_REGISTER        | 25    |
+| ZEBRA_INTERFACE_BFD_DEST_UPDATE    | 25    |
 +------------------------------------+-------+
-| ZEBRA_IMPORT_ROUTE_UNREGISTER      | 26    |
+| ZEBRA_IMPORT_ROUTE_REGISTER        | 26    |
 +------------------------------------+-------+
-| ZEBRA_IMPORT_CHECK_UPDATE          | 27    |
+| ZEBRA_IMPORT_ROUTE_UNREGISTER      | 27    |
 +------------------------------------+-------+
-| ZEBRA_BFD_DEST_REGISTER            | 28    |
+| ZEBRA_IMPORT_CHECK_UPDATE          | 28    |
 +------------------------------------+-------+
-| ZEBRA_BFD_DEST_DEREGISTER          | 29    |
+| ZEBRA_BFD_DEST_REGISTER            | 29    |
 +------------------------------------+-------+
-| ZEBRA_BFD_DEST_UPDATE              | 30    |
+| ZEBRA_BFD_DEST_DEREGISTER          | 30    |
 +------------------------------------+-------+
-| ZEBRA_BFD_DEST_REPLAY              | 31    |
+| ZEBRA_BFD_DEST_UPDATE              | 31    |
 +------------------------------------+-------+
-| ZEBRA_REDISTRIBUTE_ROUTE_ADD       | 32    |
+| ZEBRA_BFD_DEST_REPLAY              | 32    |
 +------------------------------------+-------+
-| ZEBRA_REDISTRIBUTE_ROUTE_DEL       | 33    |
+| ZEBRA_REDISTRIBUTE_ROUTE_ADD       | 33    |
 +------------------------------------+-------+
-| ZEBRA_VRF_UNREGISTER               | 34    |
+| ZEBRA_REDISTRIBUTE_ROUTE_DEL       | 34    |
 +------------------------------------+-------+
-| ZEBRA_VRF_ADD                      | 35    |
+| ZEBRA_VRF_UNREGISTER               | 35    |
 +------------------------------------+-------+
-| ZEBRA_VRF_DELETE                   | 36    |
+| ZEBRA_VRF_ADD                      | 36    |
 +------------------------------------+-------+
-| ZEBRA_VRF_LABEL                    | 37    |
+| ZEBRA_VRF_DELETE                   | 37    |
 +------------------------------------+-------+
-| ZEBRA_INTERFACE_VRF_UPDATE         | 38    |
+| ZEBRA_VRF_LABEL                    | 38    |
 +------------------------------------+-------+
-| ZEBRA_BFD_CLIENT_REGISTER          | 39    |
+| ZEBRA_INTERFACE_VRF_UPDATE         | 39    |
 +------------------------------------+-------+
-| ZEBRA_BFD_CLIENT_DEREGISTER        | 40    |
+| ZEBRA_BFD_CLIENT_REGISTER          | 40    |
 +------------------------------------+-------+
-| ZEBRA_INTERFACE_ENABLE_RADV        | 41    |
+| ZEBRA_BFD_CLIENT_DEREGISTER        | 41    |
 +------------------------------------+-------+
-| ZEBRA_INTERFACE_DISABLE_RADV       | 42    |
+| ZEBRA_INTERFACE_ENABLE_RADV        | 42    |
 +------------------------------------+-------+
-| ZEBRA_IPV3_NEXTHOP_LOOKUP_MRIB     | 43    |
+| ZEBRA_INTERFACE_DISABLE_RADV       | 43    |
 +------------------------------------+-------+
-| ZEBRA_INTERFACE_LINK_PARAMS        | 44    |
+| ZEBRA_IPV3_NEXTHOP_LOOKUP_MRIB     | 44    |
 +------------------------------------+-------+
-| ZEBRA_MPLS_LABELS_ADD              | 45    |
+| ZEBRA_INTERFACE_LINK_PARAMS        | 45    |
 +------------------------------------+-------+
-| ZEBRA_MPLS_LABELS_DELETE           | 46    |
+| ZEBRA_MPLS_LABELS_ADD              | 46    |
 +------------------------------------+-------+
-| ZEBRA_IPMR_ROUTE_STATS             | 47    |
+| ZEBRA_MPLS_LABELS_DELETE           | 47    |
 +------------------------------------+-------+
-| ZEBRA_LABEL_MANAGER_CONNECT        | 48    |
+| ZEBRA_MPLS_LABELS_REPLACE          | 48    |
 +------------------------------------+-------+
-| ZEBRA_LABEL_MANAGER_CONNECT_ASYNC  | 49    |
+| ZEBRA_IPMR_ROUTE_STATS             | 49    |
 +------------------------------------+-------+
-| ZEBRA_GET_LABEL_CHUNK              | 50    |
+| ZEBRA_LABEL_MANAGER_CONNECT        | 50    |
 +------------------------------------+-------+
-| ZEBRA_RELEASE_LABEL_CHUNK          | 51    |
+| ZEBRA_LABEL_MANAGER_CONNECT_ASYNC  | 51    |
 +------------------------------------+-------+
-| ZEBRA_FEC_REGISTER                 | 52    |
+| ZEBRA_GET_LABEL_CHUNK              | 52    |
 +------------------------------------+-------+
-| ZEBRA_FEC_UNREGISTER               | 53    |
+| ZEBRA_RELEASE_LABEL_CHUNK          | 53    |
 +------------------------------------+-------+
-| ZEBRA_FEC_UPDATE                   | 54    |
+| ZEBRA_FEC_REGISTER                 | 54    |
 +------------------------------------+-------+
-| ZEBRA_ADVERTISE_DEFAULT_GW         | 55    |
+| ZEBRA_FEC_UNREGISTER               | 55    |
 +------------------------------------+-------+
-| ZEBRA_ADVERTISE_SUBNET             | 56    |
+| ZEBRA_FEC_UPDATE                   | 56    |
 +------------------------------------+-------+
-| ZEBRA_ADVERTISE_ALL_VNI            | 57    |
+| ZEBRA_ADVERTISE_DEFAULT_GW         | 57    |
 +------------------------------------+-------+
-| ZEBRA_LOCAL_ES_ADD                 | 58    |
+| ZEBRA_ADVERTISE_SVI_MACIP          | 58    |
 +------------------------------------+-------+
-| ZEBRA_LOCAL_ES_DEL                 | 59    |
+| ZEBRA_ADVERTISE_SUBNET             | 59    |
 +------------------------------------+-------+
-| ZEBRA_VNI_ADD                      | 60    |
+| ZEBRA_ADVERTISE_ALL_VNI            | 60    |
 +------------------------------------+-------+
-| ZEBRA_VNI_DEL                      | 61    |
+| ZEBRA_LOCAL_ES_ADD                 | 61    |
 +------------------------------------+-------+
-| ZEBRA_L3VNI_ADD                    | 62    |
+| ZEBRA_LOCAL_ES_DEL                 | 62    |
 +------------------------------------+-------+
-| ZEBRA_L3VNI_DEL                    | 63    |
+| ZEBRA_VNI_ADD                      | 63    |
 +------------------------------------+-------+
-| ZEBRA_REMOTE_VTEP_ADD              | 64    |
+| ZEBRA_VNI_DEL                      | 64    |
 +------------------------------------+-------+
-| ZEBRA_REMOTE_VTEP_DEL              | 65    |
+| ZEBRA_L3VNI_ADD                    | 65    |
 +------------------------------------+-------+
-| ZEBRA_MACIP_ADD                    | 66    |
+| ZEBRA_L3VNI_DEL                    | 66    |
 +------------------------------------+-------+
-| ZEBRA_MACIP_DEL                    | 67    |
+| ZEBRA_REMOTE_VTEP_ADD              | 67    |
 +------------------------------------+-------+
-| ZEBRA_IP_PREFIX_ROUTE_ADD          | 68    |
+| ZEBRA_REMOTE_VTEP_DEL              | 68    |
 +------------------------------------+-------+
-| ZEBRA_IP_PREFIX_ROUTE_DEL          | 69    |
+| ZEBRA_MACIP_ADD                    | 69    |
 +------------------------------------+-------+
-| ZEBRA_REMOTE_MACIP_ADD             | 70    |
+| ZEBRA_MACIP_DEL                    | 70    |
 +------------------------------------+-------+
-| ZEBRA_REMOTE_MACIP_DEL             | 71    |
+| ZEBRA_IP_PREFIX_ROUTE_ADD          | 71    |
 +------------------------------------+-------+
-| ZEBRA_PW_ADD                       | 72    |
+| ZEBRA_IP_PREFIX_ROUTE_DEL          | 72    |
 +------------------------------------+-------+
-| ZEBRA_PW_DELETE                    | 73    |
+| ZEBRA_REMOTE_MACIP_ADD             | 73    |
 +------------------------------------+-------+
-| ZEBRA_PW_SET                       | 74    |
+| ZEBRA_REMOTE_MACIP_DEL             | 74    |
 +------------------------------------+-------+
-| ZEBRA_PW_UNSET                     | 75    |
+| ZEBRA_DUPLICATE_ADDR_DETECTION     | 75    |
 +------------------------------------+-------+
-| ZEBRA_PW_STATUS_UPDATE             | 76    |
+| ZEBRA_PW_ADD                       | 76    |
 +------------------------------------+-------+
-| ZEBRA_RULE_ADD                     | 77    |
+| ZEBRA_PW_DELETE                    | 77    |
 +------------------------------------+-------+
-| ZEBRA_RULE_DELETE                  | 78    |
+| ZEBRA_PW_SET                       | 78    |
 +------------------------------------+-------+
-| ZEBRA_RULE_NOTIFY_OWNER            | 79    |
+| ZEBRA_PW_UNSET                     | 79    |
 +------------------------------------+-------+
-| ZEBRA_TABLE_MANAGER_CONNECT        | 80    |
+| ZEBRA_PW_STATUS_UPDATE             | 80    |
 +------------------------------------+-------+
-| ZEBRA_GET_TABLE_CHUNK              | 81    |
+| ZEBRA_RULE_ADD                     | 81    |
 +------------------------------------+-------+
-| ZEBRA_RELEASE_TABLE_CHUNK          | 82    |
+| ZEBRA_RULE_DELETE                  | 82    |
 +------------------------------------+-------+
-| ZEBRA_IPSET_CREATE                 | 83    |
+| ZEBRA_RULE_NOTIFY_OWNER            | 83    |
 +------------------------------------+-------+
-| ZEBRA_IPSET_DESTROY                | 84    |
+| ZEBRA_TABLE_MANAGER_CONNECT        | 84    |
 +------------------------------------+-------+
-| ZEBRA_IPSET_ENTRY_ADD              | 85    |
+| ZEBRA_GET_TABLE_CHUNK              | 85    |
 +------------------------------------+-------+
-| ZEBRA_IPSET_ENTRY_DELETE           | 86    |
+| ZEBRA_RELEASE_TABLE_CHUNK          | 86    |
 +------------------------------------+-------+
-| ZEBRA_IPSET_NOTIFY_OWNER           | 87    |
+| ZEBRA_IPSET_CREATE                 | 87    |
 +------------------------------------+-------+
-| ZEBRA_IPSET_ENTRY_NOTIFY_OWNER     | 88    |
+| ZEBRA_IPSET_DESTROY                | 88    |
 +------------------------------------+-------+
-| ZEBRA_IPTABLE_ADD                  | 89    |
+| ZEBRA_IPSET_ENTRY_ADD              | 89    |
 +------------------------------------+-------+
-| ZEBRA_IPTABLE_DELETE               | 90    |
+| ZEBRA_IPSET_ENTRY_DELETE           | 90    |
 +------------------------------------+-------+
-| ZEBRA_IPTABLE_NOTIFY_OWNER         | 91    |
+| ZEBRA_IPSET_NOTIFY_OWNER           | 91    |
 +------------------------------------+-------+
-| ZEBRA_VXLAN_FLOOD_CONTROL          | 92    |
+| ZEBRA_IPSET_ENTRY_NOTIFY_OWNER     | 92    |
++------------------------------------+-------+
+| ZEBRA_IPTABLE_ADD                  | 93    |
++------------------------------------+-------+
+| ZEBRA_IPTABLE_DELETE               | 94    |
++------------------------------------+-------+
+| ZEBRA_IPTABLE_NOTIFY_OWNER         | 95    |
++------------------------------------+-------+
+| ZEBRA_VXLAN_FLOOD_CONTROL          | 96    |
++------------------------------------+-------+
+| ZEBRA_VXLAN_SG_ADD                 | 97    |
++------------------------------------+-------+
+| ZEBRA_VXLAN_SG_DEL                 | 98    |
++------------------------------------+-------+
+| ZEBRA_VXLAN_SG_REPLAY              | 99    |
++------------------------------------+-------+
+| ZEBRA_MLAG_PROCESS_UP              | 100   |
++------------------------------------+-------+
+| ZEBRA_MLAG_PROCESS_DOWN            | 101   |
++------------------------------------+-------+
+| ZEBRA_MLAG_CLIENT_REGISTER         | 102   |
++------------------------------------+-------+
+| ZEBRA_MLAG_CLIENT_UNREGISTER       | 103   |
++------------------------------------+-------+
+| ZEBRA_MLAG_FORWARD_MSG             | 104   |
++------------------------------------+-------+
+| ZEBRA_CLIENT_CAPABILITIES          | 105   |
 +------------------------------------+-------+
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 68659fbf504cd192275436c7235adffe38826555..b9b28bacedde33023467d3dffdb9ff14d6c69169 100644 (file)
@@ -136,6 +136,11 @@ causes the policy to be installed into the kernel.
    This command is available under interface sub-mode.  This turns
    on the PBR map NAME and allows it to work properly.
 
+.. note::
+   This will not dynamically create PBR maps on sub-interfaces (i.e. vlans)
+   even if one is on the master. Each must have the PBR map explicitly added
+   to the interface.
+
 .. _pbr-details:
 
 PBR Details
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 ece0b4b0c4c4a4aeecadfc2415b6c056acdd01b4..9ef4e8623702ca3e46d92e5862711d51c9aeecef 100644 (file)
@@ -121,7 +121,6 @@ int eigrp_if_delete_hook(struct interface *ifp)
        eigrp_fifo_free(ei->obuf);
 
        XFREE(MTYPE_EIGRP_IF_INFO, ifp->info);
-       ifp->info = NULL;
 
        return 0;
 }
index 0746b04edb79f0585e3766a69b9a632ddaff4b18..922c0fe3e7863b5eff7f305d7242717d61b35628 100644 (file)
@@ -140,6 +140,7 @@ struct quagga_signal_t eigrp_signals[] = {
 static const struct frr_yang_module_info *const eigrpd_yang_modules[] = {
        &frr_eigrpd_info,
        &frr_interface_info,
+       &frr_route_map_info,
 };
 
 FRR_DAEMON_INFO(eigrpd, EIGRP, .vty_port = EIGRP_VTY_PORT,
index 324f309290dbb0bb8d341ae6efab577f6051da2e..39008a01c4a427f6748909b0f869242d62ac3c35 100644 (file)
@@ -230,7 +230,7 @@ int eigrp_network_set(struct eigrp *eigrp, struct prefix *p)
        rn->info = (void *)pref;
 
        /* Schedule Router ID Update. */
-       if (eigrp->router_id.s_addr == 0)
+       if (eigrp->router_id.s_addr == INADDR_ANY)
                eigrp_router_id_update(eigrp);
        /* Run network config now. */
        /* Get target interface. */
index 4ccce2ebb8c3f0ab9ed4705a5ba745500314d166..e03ebb4fcb2814f39bb95be944b14c25f114acca 100644 (file)
@@ -161,7 +161,7 @@ static int eigrpd_instance_router_id_destroy(enum nb_event event,
                break;
        case NB_EV_APPLY:
                eigrp = nb_running_get_entry(dnode, NULL, true);
-               eigrp->router_id_static.s_addr = 0;
+               eigrp->router_id_static.s_addr = INADDR_ANY;
                break;
        }
 
index e93dc0cbfa29a265429de3cf285c98cea4983496..820f015b5711e6889913840a5410680e1d3a321b 100644 (file)
@@ -99,10 +99,10 @@ void eigrp_router_id_update(struct eigrp *eigrp)
 
        router_id_old = eigrp->router_id;
 
-       if (eigrp->router_id_static.s_addr != 0)
+       if (eigrp->router_id_static.s_addr != INADDR_ANY)
                router_id = eigrp->router_id_static;
 
-       else if (eigrp->router_id.s_addr != 0)
+       else if (eigrp->router_id.s_addr != INADDR_ANY)
                router_id = eigrp->router_id;
 
        else
@@ -142,8 +142,8 @@ static struct eigrp *eigrp_new(uint16_t as, vrf_id_t vrf_id)
        eigrp->vrf_id = vrf_id;
        eigrp->vrid = 0;
        eigrp->AS = as;
-       eigrp->router_id.s_addr = 0;
-       eigrp->router_id_static.s_addr = 0;
+       eigrp->router_id.s_addr = INADDR_ANY;
+       eigrp->router_id_static.s_addr = INADDR_ANY;
        eigrp->sequence_number = 1;
 
        /*Configure default K Values for EIGRP Process*/
diff --git a/include/linux/seg6.h b/include/linux/seg6.h
new file mode 100644 (file)
index 0000000..329163e
--- /dev/null
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ *  SR-IPv6 implementation
+ *
+ *  Author:
+ *  David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ *  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.
+ */
+
+#ifndef _LINUX_SEG6_H
+#define _LINUX_SEG6_H
+
+#include <linux/types.h>
+#include <linux/in6.h>         /* For struct in6_addr. */
+
+/*
+ * SRH
+ */
+struct ipv6_sr_hdr {
+       __u8    nexthdr;
+       __u8    hdrlen;
+       __u8    type;
+       __u8    segments_left;
+       __u8    first_segment; /* Represents the last_entry field of SRH */
+       __u8    flags;
+       __u16   tag;
+
+       struct in6_addr segments[0];
+};
+
+#define SR6_FLAG1_PROTECTED    (1 << 6)
+#define SR6_FLAG1_OAM          (1 << 5)
+#define SR6_FLAG1_ALERT                (1 << 4)
+#define SR6_FLAG1_HMAC         (1 << 3)
+
+#define SR6_TLV_INGRESS                1
+#define SR6_TLV_EGRESS         2
+#define SR6_TLV_OPAQUE         3
+#define SR6_TLV_PADDING                4
+#define SR6_TLV_HMAC           5
+
+#define sr_has_hmac(srh) ((srh)->flags & SR6_FLAG1_HMAC)
+
+struct sr6_tlv {
+       __u8 type;
+       __u8 len;
+       __u8 data[0];
+};
+
+#endif
diff --git a/include/linux/seg6_genl.h b/include/linux/seg6_genl.h
new file mode 100644 (file)
index 0000000..0c23052
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_SEG6_GENL_H
+#define _LINUX_SEG6_GENL_H
+
+#define SEG6_GENL_NAME         "SEG6"
+#define SEG6_GENL_VERSION      0x1
+
+enum {
+       SEG6_ATTR_UNSPEC,
+       SEG6_ATTR_DST,
+       SEG6_ATTR_DSTLEN,
+       SEG6_ATTR_HMACKEYID,
+       SEG6_ATTR_SECRET,
+       SEG6_ATTR_SECRETLEN,
+       SEG6_ATTR_ALGID,
+       SEG6_ATTR_HMACINFO,
+       __SEG6_ATTR_MAX,
+};
+
+#define SEG6_ATTR_MAX (__SEG6_ATTR_MAX - 1)
+
+enum {
+       SEG6_CMD_UNSPEC,
+       SEG6_CMD_SETHMAC,
+       SEG6_CMD_DUMPHMAC,
+       SEG6_CMD_SET_TUNSRC,
+       SEG6_CMD_GET_TUNSRC,
+       __SEG6_CMD_MAX,
+};
+
+#define SEG6_CMD_MAX (__SEG6_CMD_MAX - 1)
+
+#endif
diff --git a/include/linux/seg6_hmac.h b/include/linux/seg6_hmac.h
new file mode 100644 (file)
index 0000000..3fb3412
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_SEG6_HMAC_H
+#define _LINUX_SEG6_HMAC_H
+
+#include <linux/types.h>
+#include <linux/seg6.h>
+
+#define SEG6_HMAC_SECRET_LEN   64
+#define SEG6_HMAC_FIELD_LEN    32
+
+struct sr6_tlv_hmac {
+       struct sr6_tlv tlvhdr;
+       __u16 reserved;
+       __be32 hmackeyid;
+       __u8 hmac[SEG6_HMAC_FIELD_LEN];
+};
+
+enum {
+       SEG6_HMAC_ALGO_SHA1 = 1,
+       SEG6_HMAC_ALGO_SHA256 = 2,
+};
+
+#endif
diff --git a/include/linux/seg6_iptunnel.h b/include/linux/seg6_iptunnel.h
new file mode 100644 (file)
index 0000000..3004e98
--- /dev/null
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ *  SR-IPv6 implementation
+ *
+ *  Author:
+ *  David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ *  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.
+ */
+
+#ifndef _LINUX_SEG6_IPTUNNEL_H
+#define _LINUX_SEG6_IPTUNNEL_H
+
+#include <linux/seg6.h>                /* For struct ipv6_sr_hdr. */
+
+enum {
+       SEG6_IPTUNNEL_UNSPEC,
+       SEG6_IPTUNNEL_SRH,
+       __SEG6_IPTUNNEL_MAX,
+};
+#define SEG6_IPTUNNEL_MAX (__SEG6_IPTUNNEL_MAX - 1)
+
+struct seg6_iptunnel_encap {
+       int mode;
+       struct ipv6_sr_hdr srh[0];
+};
+
+#define SEG6_IPTUN_ENCAP_SIZE(x) ((sizeof(*x)) + (((x)->srh->hdrlen + 1) << 3))
+
+enum {
+       SEG6_IPTUN_MODE_INLINE,
+       SEG6_IPTUN_MODE_ENCAP,
+       SEG6_IPTUN_MODE_L2ENCAP,
+};
+
+
+#endif
diff --git a/include/linux/seg6_local.h b/include/linux/seg6_local.h
new file mode 100644 (file)
index 0000000..5312de8
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  SR-IPv6 implementation
+ *
+ *  Author:
+ *  David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ *  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.
+ */
+
+#ifndef _LINUX_SEG6_LOCAL_H
+#define _LINUX_SEG6_LOCAL_H
+
+#include <linux/seg6.h>
+
+enum {
+       SEG6_LOCAL_UNSPEC,
+       SEG6_LOCAL_ACTION,
+       SEG6_LOCAL_SRH,
+       SEG6_LOCAL_TABLE,
+       SEG6_LOCAL_NH4,
+       SEG6_LOCAL_NH6,
+       SEG6_LOCAL_IIF,
+       SEG6_LOCAL_OIF,
+       SEG6_LOCAL_BPF,
+       __SEG6_LOCAL_MAX,
+};
+#define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1)
+
+enum {
+       SEG6_LOCAL_ACTION_UNSPEC        = 0,
+       /* node segment */
+       SEG6_LOCAL_ACTION_END           = 1,
+       /* adjacency segment (IPv6 cross-connect) */
+       SEG6_LOCAL_ACTION_END_X         = 2,
+       /* lookup of next seg NH in table */
+       SEG6_LOCAL_ACTION_END_T         = 3,
+       /* decap and L2 cross-connect */
+       SEG6_LOCAL_ACTION_END_DX2       = 4,
+       /* decap and IPv6 cross-connect */
+       SEG6_LOCAL_ACTION_END_DX6       = 5,
+       /* decap and IPv4 cross-connect */
+       SEG6_LOCAL_ACTION_END_DX4       = 6,
+       /* decap and lookup of DA in v6 table */
+       SEG6_LOCAL_ACTION_END_DT6       = 7,
+       /* decap and lookup of DA in v4 table */
+       SEG6_LOCAL_ACTION_END_DT4       = 8,
+       /* binding segment with insertion */
+       SEG6_LOCAL_ACTION_END_B6        = 9,
+       /* binding segment with encapsulation */
+       SEG6_LOCAL_ACTION_END_B6_ENCAP  = 10,
+       /* binding segment with MPLS encap */
+       SEG6_LOCAL_ACTION_END_BM        = 11,
+       /* lookup last seg in table */
+       SEG6_LOCAL_ACTION_END_S         = 12,
+       /* forward to SR-unaware VNF with static proxy */
+       SEG6_LOCAL_ACTION_END_AS        = 13,
+       /* forward to SR-unaware VNF with masquerading */
+       SEG6_LOCAL_ACTION_END_AM        = 14,
+       /* custom BPF action */
+       SEG6_LOCAL_ACTION_END_BPF       = 15,
+
+       __SEG6_LOCAL_ACTION_MAX,
+};
+
+#define SEG6_LOCAL_ACTION_MAX (__SEG6_LOCAL_ACTION_MAX - 1)
+
+enum {
+       SEG6_LOCAL_BPF_PROG_UNSPEC,
+       SEG6_LOCAL_BPF_PROG,
+       SEG6_LOCAL_BPF_PROG_NAME,
+       __SEG6_LOCAL_BPF_PROG_MAX,
+};
+
+#define SEG6_LOCAL_BPF_PROG_MAX (__SEG6_LOCAL_BPF_PROG_MAX - 1)
+
+#endif
index b1ca1be54fdb55fbcec39f4fb1291e22d7be63e3..86129c4d68a5098734f73bc9955b86418901ed74 100644 (file)
@@ -11,4 +11,9 @@ noinst_HEADERS += \
        include/linux/socket.h \
        include/linux/net_namespace.h \
        include/linux/fib_rules.h \
+       include/linux/seg6.h \
+       include/linux/seg6_genl.h \
+       include/linux/seg6_hmac.h \
+       include/linux/seg6_iptunnel.h \
+       include/linux/seg6_local.h \
        # end
index cf4b841798748959659b4bad758c7663e4d685b9..68be9c1a995660d1222145f96367485a932cd8ec 100644 (file)
@@ -59,7 +59,6 @@ static void bfd_session_free(struct bfd_session **session)
                return;
 
        XFREE(MTYPE_BFD_SESSION, *session);
-       *session = NULL;
 }
 
 static bool bfd_session_same(const struct bfd_session *session, int family,
index 364441f79d92f7de34f434b7c8b5f98a1bce6c25..f7fe089b99a29e3c242929244ddc1c3c4f9c3943 100644 (file)
@@ -39,6 +39,7 @@
 #include "vrf.h"
 #include "qobj.h"
 #include "libfrr.h"
+#include "routemap.h"
 
 #include "isisd/isis_constants.h"
 #include "isisd/isis_common.h"
@@ -166,6 +167,7 @@ static const struct frr_yang_module_info *const isisd_yang_modules[] = {
 #ifndef FABRICD
        &frr_isisd_info,
 #endif /* ifndef FABRICD */
+       &frr_route_map_info,
 };
 
 #ifdef FABRICD
index 4ef57f574a75c21b90f09202653a543041926703..816fcc64b85c8704d97490a5e6bd055a9950255b 100644 (file)
@@ -250,9 +250,8 @@ ldp_config_write(struct vty *vty)
 
        vty_out (vty, "mpls ldp\n");
 
-       if (ldpd_conf->rtr_id.s_addr != 0)
-               vty_out (vty, " router-id %s\n",
-                   inet_ntoa(ldpd_conf->rtr_id));
+       if (ldpd_conf->rtr_id.s_addr != INADDR_ANY)
+               vty_out(vty, " router-id %s\n", inet_ntoa(ldpd_conf->rtr_id));
 
        if (ldpd_conf->lhello_holdtime != LINK_DFLT_HOLDTIME &&
            ldpd_conf->lhello_holdtime != 0)
index 2c6a43d1a7d5b2b8a66c0cd2b5eca6833dd0bd90..b479b5ea4c78720d7c510523770994a110ffd69d 100644 (file)
@@ -55,28 +55,42 @@ static int agentx_timeout(struct thread *t)
 static int agentx_read(struct thread *t)
 {
        fd_set fds;
-       int flags;
+       int flags, new_flags = 0;
        int nonblock = false;
        struct listnode *ln = THREAD_ARG(t);
        list_delete_node(events, ln);
 
        /* fix for non blocking socket */
        flags = fcntl(THREAD_FD(t), F_GETFL, 0);
-       if (-1 == flags)
+       if (-1 == flags) {
+               flog_err(EC_LIB_SYSTEM_CALL, "Failed to get FD settings fcntl: %s(%d)",
+                        strerror(errno), errno);
                return -1;
+       }
 
        if (flags & O_NONBLOCK)
                nonblock = true;
        else
-               fcntl(THREAD_FD(t), F_SETFL, flags | O_NONBLOCK);
+               new_flags = fcntl(THREAD_FD(t), F_SETFL, flags | O_NONBLOCK);
+
+       if (new_flags == -1)
+               flog_err(EC_LIB_SYSTEM_CALL, "Failed to set snmp fd non blocking: %s(%d)",
+                        strerror(errno), errno);
 
        FD_ZERO(&fds);
        FD_SET(THREAD_FD(t), &fds);
        snmp_read(&fds);
 
        /* Reset the flag */
-       if (!nonblock)
-               fcntl(THREAD_FD(t), F_SETFL, flags);
+       if (!nonblock) {
+               new_flags = fcntl(THREAD_FD(t), F_SETFL, flags);
+
+               if (new_flags == -1)
+                       flog_err(
+                               EC_LIB_SYSTEM_CALL,
+                               "Failed to set snmp fd back to original settings: %s(%d)",
+                               strerror(errno), errno);
+       }
 
        netsnmp_check_outstanding_agent_requests();
        agentx_events_update();
index ffb3cbc1f86f044da7a9cf4d0b1d0131561a3b6f..4e192422cdb5ffa49d160db0dc748a7ccefaa31d 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -74,10 +74,7 @@ struct bfd_info *bfd_info_create(void)
  */
 void bfd_info_free(struct bfd_info **bfd_info)
 {
-       if (*bfd_info) {
-               XFREE(MTYPE_BFD_INFO, *bfd_info);
-               *bfd_info = NULL;
-       }
+       XFREE(MTYPE_BFD_INFO, *bfd_info);
 }
 
 /*
index d2145d9f5a03becf2282605bdf3c74b88cac31f9..8811b3a7915484d5d6429a8276f8a68e8e4e35b0 100644 (file)
@@ -2503,8 +2503,6 @@ static void disable_log_file(void)
        zlog_reset_file();
 
        XFREE(MTYPE_HOST, host.logfile);
-
-       host.logfile = NULL;
 }
 
 DEFUN (no_config_log_file,
@@ -2661,8 +2659,7 @@ int cmd_banner_motd_file(const char *file)
 
 void cmd_banner_motd_line(const char *line)
 {
-       if (host.motd)
-               XFREE(MTYPE_HOST, host.motd);
+       XFREE(MTYPE_HOST, host.motd);
        host.motd = XSTRDUP(MTYPE_HOST, line);
 }
 
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 2aa6b927fb01afcc3f1f64f82ca8f2e6afc59857..3ea60c8772df3911dbd2d1a80ece546215182624 100644 (file)
@@ -186,7 +186,6 @@ static int distribute_list_unset(struct distribute_ctx *ctx,
                return 0;
 
        XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
-       dist->list[type] = NULL;
 
        /* Apply this distribute-list to the interface. */
        (ctx->distribute_delete_hook)(ctx, dist);
@@ -232,7 +231,6 @@ static int distribute_list_prefix_unset(struct distribute_ctx *ctx,
                return 0;
 
        XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
-       dist->prefix[type] = NULL;
 
        /* Apply this distribute-list to the interface. */
        (ctx->distribute_delete_hook)(ctx, dist);
index 31e25d600136920c74076d4be64fb0459aae309a..911a8e53d16fc4f65512eee685e154a9969fc54f 100644 (file)
@@ -608,10 +608,7 @@ static int vty_access_list_remark_unset(struct vty *vty, afi_t afi,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       if (access->remark) {
-               XFREE(MTYPE_TMP, access->remark);
-               access->remark = NULL;
-       }
+       XFREE(MTYPE_TMP, access->remark);
 
        if (access->head == NULL && access->tail == NULL)
                access_list_delete(access);
@@ -2554,7 +2551,8 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi)
                                else {
                                        vty_out(vty, " %s",
                                                inet_ntoa(filter->addr));
-                                       if (filter->addr_mask.s_addr != 0)
+                                       if (filter->addr_mask.s_addr
+                                           != INADDR_ANY)
                                                vty_out(vty,
                                                        ", wildcard bits %s",
                                                        inet_ntoa(
@@ -2602,7 +2600,8 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi)
                                else {
                                        vty_out(vty, " %s",
                                                inet_ntoa(filter->addr));
-                                       if (filter->addr_mask.s_addr != 0)
+                                       if (filter->addr_mask.s_addr
+                                           != INADDR_ANY)
                                                vty_out(vty,
                                                        ", wildcard bits %s",
                                                        inet_ntoa(
@@ -2695,7 +2694,7 @@ static void config_write_access_cisco(struct vty *vty, struct filter *mfilter)
                vty_out(vty, " ip");
                if (filter->addr_mask.s_addr == 0xffffffff)
                        vty_out(vty, " any");
-               else if (filter->addr_mask.s_addr == 0)
+               else if (filter->addr_mask.s_addr == INADDR_ANY)
                        vty_out(vty, " host %s", inet_ntoa(filter->addr));
                else {
                        vty_out(vty, " %s", inet_ntoa(filter->addr));
@@ -2704,7 +2703,7 @@ static void config_write_access_cisco(struct vty *vty, struct filter *mfilter)
 
                if (filter->mask_mask.s_addr == 0xffffffff)
                        vty_out(vty, " any");
-               else if (filter->mask_mask.s_addr == 0)
+               else if (filter->mask_mask.s_addr == INADDR_ANY)
                        vty_out(vty, " host %s", inet_ntoa(filter->mask));
                else {
                        vty_out(vty, " %s", inet_ntoa(filter->mask));
@@ -2716,7 +2715,7 @@ static void config_write_access_cisco(struct vty *vty, struct filter *mfilter)
                        vty_out(vty, " any\n");
                else {
                        vty_out(vty, " %s", inet_ntoa(filter->addr));
-                       if (filter->addr_mask.s_addr != 0)
+                       if (filter->addr_mask.s_addr != INADDR_ANY)
                                vty_out(vty, " %s",
                                        inet_ntoa(filter->addr_mask));
                        vty_out(vty, "\n");
index 7332dceb45e89bf7d336a18029ae073349072108..0e9471923f5fc0d368f74b8d08046c5aafdd5910 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -1281,7 +1281,6 @@ void if_link_params_free(struct interface *ifp)
        if (ifp->link_params == NULL)
                return;
        XFREE(MTYPE_IF_LINK_PARAMS, ifp->link_params);
-       ifp->link_params = NULL;
 }
 
 /* ----------- CLI commands ----------- */
index ca6f512ec6d6f2d85f2a4d2ff76bd0231128743a..1973d40be4ec97e223e71f59528b8aa34323a532 100644 (file)
@@ -164,7 +164,6 @@ static int if_rmap_unset(struct if_rmap_ctx *ctx,
                        return 0;
 
                XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]);
-               if_rmap->routemap[IF_RMAP_IN] = NULL;
        }
 
        if (type == IF_RMAP_OUT) {
@@ -174,7 +173,6 @@ static int if_rmap_unset(struct if_rmap_ctx *ctx,
                        return 0;
 
                XFREE(MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]);
-               if_rmap->routemap[IF_RMAP_OUT] = NULL;
        }
 
        if (ctx->if_rmap_delete_hook)
index 798b776d0074f479dda58a1f2a4263d403ea21af..7bf16a82122b701f53c348adf36bf1d2b8150bd7 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -934,7 +934,6 @@ int zlog_reset_file(void)
        zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
 
        XFREE(MTYPE_ZLOG, zl->filename);
-       zl->filename = NULL;
 
        return 1;
 }
@@ -1094,7 +1093,7 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_VXLAN_SG_DEL),
        DESC_ENTRY(ZEBRA_VXLAN_SG_REPLAY),
        DESC_ENTRY(ZEBRA_ERROR),
-};
+       DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES)};
 #undef DESC_ENTRY
 
 static const struct zebra_desc_table unknown = {0, "unknown", '?'};
index d1a31ae35fb5fd8317ca5e1b1f97eed553008093..4d4376250f181ba8029b33faf37318eda4e7f77b 100644 (file)
@@ -371,7 +371,7 @@ int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *))
 
 void ns_disable(struct ns *ns)
 {
-       return ns_disable_internal(ns);
+       ns_disable_internal(ns);
 }
 
 struct ns *ns_lookup(ns_id_t ns_id)
index a0976cd6bdd976ed29da62c8c72a0461795d07c0..f6ceba81e80b370060b534776e769e9a8ff72280 100644 (file)
@@ -496,7 +496,6 @@ static void prefix_list_trie_del(struct prefix_list *plist,
        for (; depth > 0; depth--)
                if (trie_table_empty(*tables[depth])) {
                        XFREE(MTYPE_PREFIX_LIST_TRIE, *tables[depth]);
-                       *tables[depth] = NULL;
                }
 }
 
@@ -1093,10 +1092,7 @@ static int vty_prefix_list_desc_unset(struct vty *vty, afi_t afi,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       if (plist->desc) {
-               XFREE(MTYPE_TMP, plist->desc);
-               plist->desc = NULL;
-       }
+       XFREE(MTYPE_TMP, plist->desc);
 
        if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL)
                prefix_list_delete(plist);
index 219f798dcc947f2e713770070a0812e0d3a33a41..199ff3267bce011aa2cbb96876685846b9f8075a 100644 (file)
@@ -659,7 +659,7 @@ void apply_mask_ipv4(struct prefix_ipv4 *p)
 /* If prefix is 0.0.0.0/0 then return 1 else return 0. */
 int prefix_ipv4_any(const struct prefix_ipv4 *p)
 {
-       return (p->prefix.s_addr == 0 && p->prefixlen == 0);
+       return (p->prefix.s_addr == INADDR_ANY && p->prefixlen == 0);
 }
 
 /* Allocate a new ip version 6 route */
@@ -1081,7 +1081,6 @@ void prefix_free_lists(void *arg)
 void prefix_free(struct prefix **p)
 {
        XFREE(MTYPE_PREFIX, *p);
-       *p = NULL;
 }
 
 /* Utility function to convert ipv4 prefixes to Classful prefixes */
@@ -1113,11 +1112,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
@@ -1145,7 +1144,7 @@ int netmask_str2prefix_str(const char *net_str, const char *mask_str,
        } else {
                destination = ntohl(network.s_addr);
 
-               if (network.s_addr == 0)
+               if (network.s_addr == INADDR_ANY)
                        prefixlen = 0;
                else if (IN_CLASSC(destination))
                        prefixlen = 24;
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 14fec0283cafebcb98f9e6559f3b61a5a0172afd..e46323028ddc3afe72d2047559a581dcd57b9a48 100644 (file)
@@ -50,178 +50,7 @@ static vector route_match_vec;
 /* Vector for route set rules. */
 static vector route_set_vec;
 
-struct route_map_match_set_hooks {
-       /* match interface */
-       int (*match_interface)(struct vty *vty, struct route_map_index *index,
-                              const char *command, const char *arg,
-                              route_map_event_t type);
-
-       /* no match interface */
-       int (*no_match_interface)(struct vty *vty,
-                                 struct route_map_index *index,
-                                 const char *command, const char *arg,
-                                 route_map_event_t type);
-
-       /* match ip address */
-       int (*match_ip_address)(struct vty *vty, struct route_map_index *index,
-                               const char *command, const char *arg,
-                               route_map_event_t type);
-
-       /* no match ip address */
-       int (*no_match_ip_address)(struct vty *vty,
-                                  struct route_map_index *index,
-                                  const char *command, const char *arg,
-                                  route_map_event_t type);
-
-       /* match ip address prefix list */
-       int (*match_ip_address_prefix_list)(struct vty *vty,
-                                           struct route_map_index *index,
-                                           const char *command,
-                                           const char *arg,
-                                           route_map_event_t type);
-
-       /* no match ip address prefix list */
-       int (*no_match_ip_address_prefix_list)(struct vty *vty,
-                                              struct route_map_index *index,
-                                              const char *command,
-                                              const char *arg,
-                                              route_map_event_t type);
-
-       /* match ip next hop */
-       int (*match_ip_next_hop)(struct vty *vty, struct route_map_index *index,
-                                const char *command, const char *arg,
-                                route_map_event_t type);
-
-       /* no match ip next hop */
-       int (*no_match_ip_next_hop)(struct vty *vty,
-                                   struct route_map_index *index,
-                                   const char *command, const char *arg,
-                                   route_map_event_t type);
-
-       /* match ip next hop prefix list */
-       int (*match_ip_next_hop_prefix_list)(struct vty *vty,
-                                            struct route_map_index *index,
-                                            const char *command,
-                                            const char *arg,
-                                            route_map_event_t type);
-
-       /* no match ip next hop prefix list */
-       int (*no_match_ip_next_hop_prefix_list)(struct vty *vty,
-                                               struct route_map_index *index,
-                                               const char *command,
-                                               const char *arg,
-                                               route_map_event_t type);
-
-       /* match ip next-hop type */
-       int (*match_ip_next_hop_type)(struct vty *vty,
-                                            struct route_map_index *index,
-                                            const char *command,
-                                            const char *arg,
-                                            route_map_event_t type);
-
-       /* no match ip next-hop type */
-       int (*no_match_ip_next_hop_type)(struct vty *vty,
-                                               struct route_map_index *index,
-                                               const char *command,
-                                               const char *arg,
-                                               route_map_event_t type);
-
-       /* match ipv6 address */
-       int (*match_ipv6_address)(struct vty *vty,
-                                 struct route_map_index *index,
-                                 const char *command, const char *arg,
-                                 route_map_event_t type);
-
-       /* no match ipv6 address */
-       int (*no_match_ipv6_address)(struct vty *vty,
-                                    struct route_map_index *index,
-                                    const char *command, const char *arg,
-                                    route_map_event_t type);
-
-
-       /* match ipv6 address prefix list */
-       int (*match_ipv6_address_prefix_list)(struct vty *vty,
-                                             struct route_map_index *index,
-                                             const char *command,
-                                             const char *arg,
-                                             route_map_event_t type);
-
-       /* no match ipv6 address prefix list */
-       int (*no_match_ipv6_address_prefix_list)(struct vty *vty,
-                                                struct route_map_index *index,
-                                                const char *command,
-                                                const char *arg,
-                                                route_map_event_t type);
-
-       /* match ipv6 next-hop type */
-       int (*match_ipv6_next_hop_type)(struct vty *vty,
-                                             struct route_map_index *index,
-                                             const char *command,
-                                             const char *arg,
-                                             route_map_event_t type);
-
-       /* no match ipv6 next-hop type */
-       int (*no_match_ipv6_next_hop_type)(struct vty *vty,
-                                          struct route_map_index *index,
-                                          const char *command, const char *arg,
-                                          route_map_event_t type);
-
-       /* match metric */
-       int (*match_metric)(struct vty *vty, struct route_map_index *index,
-                           const char *command, const char *arg,
-                           route_map_event_t type);
-
-       /* no match metric */
-       int (*no_match_metric)(struct vty *vty, struct route_map_index *index,
-                              const char *command, const char *arg,
-                              route_map_event_t type);
-
-       /* match tag */
-       int (*match_tag)(struct vty *vty, struct route_map_index *index,
-                        const char *command, const char *arg,
-                        route_map_event_t type);
-
-       /* no match tag */
-       int (*no_match_tag)(struct vty *vty, struct route_map_index *index,
-                           const char *command, const char *arg,
-                           route_map_event_t type);
-
-       /* set ip nexthop */
-       int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
-                             const char *command, const char *arg);
-
-       /* no set ip nexthop */
-       int (*no_set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
-                                const char *command, const char *arg);
-
-       /* set ipv6 nexthop local */
-       int (*set_ipv6_nexthop_local)(struct vty *vty,
-                                     struct route_map_index *index,
-                                     const char *command, const char *arg);
-
-       /* no set ipv6 nexthop local */
-       int (*no_set_ipv6_nexthop_local)(struct vty *vty,
-                                        struct route_map_index *index,
-                                        const char *command, const char *arg);
-
-       /* set metric */
-       int (*set_metric)(struct vty *vty, struct route_map_index *index,
-                         const char *command, const char *arg);
-
-       /* no set metric */
-       int (*no_set_metric)(struct vty *vty, struct route_map_index *index,
-                            const char *command, const char *arg);
-
-       /* set tag */
-       int (*set_tag)(struct vty *vty, struct route_map_index *index,
-                      const char *command, const char *arg);
-
-       /* no set tag */
-       int (*no_set_tag)(struct vty *vty, struct route_map_index *index,
-                         const char *command, const char *arg);
-};
-
-static struct route_map_match_set_hooks rmap_match_set_hook;
+struct route_map_match_set_hooks rmap_match_set_hook;
 
 /* match interface */
 void route_map_match_interface_hook(int (*func)(
@@ -479,15 +308,21 @@ int generic_match_add(struct vty *vty, struct route_map_index *index,
        ret = route_map_add_match(index, command, arg, type);
        switch (ret) {
        case RMAP_RULE_MISSING:
-               vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
+               if (vty)
+                       vty_out(vty, "%% [%s] Can't find rule.\n",
+                               frr_protonameinst);
+               else
+                       zlog_warn("Can't find rule: %s", command);
                return CMD_WARNING_CONFIG_FAILED;
-               break;
        case RMAP_COMPILE_ERROR:
-               vty_out(vty,
-                       "%% [%s] Argument form is unsupported or malformed.\n",
-                       frr_protonameinst);
+               if (vty)
+                       vty_out(vty,
+                               "%% [%s] Argument form is unsupported or malformed.\n",
+                               frr_protonameinst);
+               else
+                       zlog_warn("Argument form is unsupported or malformed: "
+                                 "%s %s", command, arg);
                return CMD_WARNING_CONFIG_FAILED;
-               break;
        case RMAP_COMPILE_SUCCESS:
                /*
                 * Nothing to do here move along
@@ -524,13 +359,21 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index,
        ret = route_map_delete_match(index, command, dep_name, type);
        switch (ret) {
        case RMAP_RULE_MISSING:
-               vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
+               if (vty)
+                       vty_out(vty, "%% [%s] Can't find rule.\n",
+                               frr_protonameinst);
+               else
+                       zlog_warn("Can't find rule: %s", command);
                retval = CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_ERROR:
-               vty_out(vty,
-                       "%% [%s] Argument form is unsupported or malformed.\n",
-                       frr_protonameinst);
+               if (vty)
+                       vty_out(vty,
+                               "%% [%s] Argument form is unsupported or malformed.\n",
+                               frr_protonameinst);
+               else
+                       zlog_warn("Argument form is unsupported or malformed: "
+                                 "%s %s", command, arg);
                retval = CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
@@ -554,15 +397,20 @@ int generic_set_add(struct vty *vty, struct route_map_index *index,
        ret = route_map_add_set(index, command, arg);
        switch (ret) {
        case RMAP_RULE_MISSING:
-               vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
+               if (vty)
+                       vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
+               else
+                       zlog_warn("Can't find rule: %s", command);
                return CMD_WARNING_CONFIG_FAILED;
-               break;
        case RMAP_COMPILE_ERROR:
-               vty_out(vty,
-                       "%% [%s] Argument form is unsupported or malformed.\n",
-                       frr_protonameinst);
+               if (vty)
+                       vty_out(vty,
+                               "%% [%s] Argument form is unsupported or malformed.\n",
+                               frr_protonameinst);
+               else
+                       zlog_warn("Argument form is unsupported or malformed: "
+                                 "%s %s", command, arg);
                return CMD_WARNING_CONFIG_FAILED;
-               break;
        case RMAP_COMPILE_SUCCESS:
                break;
        }
@@ -578,15 +426,20 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index,
        ret = route_map_delete_set(index, command, arg);
        switch (ret) {
        case RMAP_RULE_MISSING:
-               vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
+               if (vty)
+                       vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst);
+               else
+                       zlog_warn("Can't find rule: %s", command);
                return CMD_WARNING_CONFIG_FAILED;
-               break;
        case RMAP_COMPILE_ERROR:
-               vty_out(vty,
-                       "%% [%s] Argument form is unsupported or malformed.\n",
-                       frr_protonameinst);
+               if (vty)
+                       vty_out(vty,
+                               "%% [%s] Argument form is unsupported or malformed.\n",
+                               frr_protonameinst);
+               else
+                       zlog_warn("Argument form is unsupported or malformed: "
+                                 "%s %s", command, arg);
                return CMD_WARNING_CONFIG_FAILED;
-               break;
        case RMAP_COMPILE_SUCCESS:
                break;
        }
@@ -595,35 +448,9 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index,
 }
 
 
-/* Route map rule. This rule has both `match' rule and `set' rule. */
-struct route_map_rule {
-       /* Rule type. */
-       const struct route_map_rule_cmd *cmd;
-
-       /* For pretty printing. */
-       char *rule_str;
-
-       /* Pre-compiled match rule. */
-       void *value;
-
-       /* Linked list. */
-       struct route_map_rule *next;
-       struct route_map_rule *prev;
-};
-
-/* Making route map list. */
-struct route_map_list {
-       struct route_map *head;
-       struct route_map *tail;
-
-       void (*add_hook)(const char *);
-       void (*delete_hook)(const char *);
-       void (*event_hook)(const char *);
-};
-
 /* Master list of route map. */
-static struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL};
-static struct hash *route_map_master_hash = NULL;
+struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL};
+struct hash *route_map_master_hash = NULL;
 
 static unsigned int route_map_hash_key_make(const void *p)
 {
@@ -691,8 +518,6 @@ static void route_map_rule_delete(struct route_map_rule_list *,
                                  struct route_map_rule *);
 static bool rmap_debug;
 
-static void route_map_index_delete(struct route_map_index *, int);
-
 /* New route map allocation. Please note route map's name must be
    specified. */
 static struct route_map *route_map_new(const char *name)
@@ -784,7 +609,7 @@ static void route_map_free_map(struct route_map *map)
 }
 
 /* Route map delete from list. */
-static void route_map_delete(struct route_map *map)
+void route_map_delete(struct route_map *map)
 {
        struct route_map_index *index;
        char *name;
@@ -883,7 +708,7 @@ static int route_map_clear_updated(struct route_map *map)
 
 /* Lookup route map.  If there isn't route map create one and return
    it. */
-static struct route_map *route_map_get(const char *name)
+struct route_map *route_map_get(const char *name)
 {
        struct route_map *map;
 
@@ -958,14 +783,6 @@ static const char *route_map_result_str(route_map_result_t res)
        return "invalid";
 }
 
-static int route_map_empty(struct route_map *map)
-{
-       if (map->head == NULL && map->tail == NULL)
-               return 1;
-       else
-               return 0;
-}
-
 /* show route-map */
 static void vty_show_route_map_entry(struct vty *vty, struct route_map *map)
 {
@@ -1092,12 +909,13 @@ static struct route_map_index *route_map_index_new(void)
 
        new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index));
        new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
+       TAILQ_INIT(&new->rhclist);
        QOBJ_REG(new, route_map_index);
        return new;
 }
 
 /* Free route map index. */
-static void route_map_index_delete(struct route_map_index *index, int notify)
+void route_map_index_delete(struct route_map_index *index, int notify)
 {
        struct route_map_rule *rule;
 
@@ -1107,6 +925,10 @@ static void route_map_index_delete(struct route_map_index *index, int notify)
                zlog_debug("Deleting route-map %s sequence %d",
                           index->map->name, index->pref);
 
+       /* Free route map northbound hook contexts. */
+       while (!TAILQ_EMPTY(&index->rhclist))
+               routemap_hook_context_free(TAILQ_FIRST(&index->rhclist));
+
        /* Free route match. */
        while ((rule = index->match_list.head) != NULL)
                route_map_rule_delete(&index->match_list, rule);
@@ -1202,7 +1024,7 @@ route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
 }
 
 /* Get route map index. */
-static struct route_map_index *
+struct route_map_index *
 route_map_index_get(struct route_map *map, enum route_map_type type, int pref)
 {
        struct route_map_index *index;
@@ -2063,7 +1885,6 @@ static int route_map_dep_update(struct hash *dephash, const char *dep_name,
                        hash_free(dep->dep_rmap_hash);
                        XFREE(MTYPE_ROUTE_MAP_NAME, dep->dep_name);
                        XFREE(MTYPE_ROUTE_MAP_DEP, dep);
-                       dep = NULL;
                }
                break;
        case RMAP_EVENT_SET_ADDED:
@@ -2209,871 +2030,6 @@ void route_map_notify_dependencies(const char *affected_name,
 
 
 /* VTY related functions. */
-DEFUN (match_interface,
-       match_interface_cmd,
-       "match interface WORD",
-       MATCH_STR
-       "match first hop interface of route\n"
-       "Interface name\n")
-{
-       int idx_word = 2;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.match_interface)
-               return rmap_match_set_hook.match_interface(
-                       vty, index, "interface", argv[idx_word]->arg,
-                       RMAP_EVENT_MATCH_ADDED);
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_match_interface,
-       no_match_interface_cmd,
-       "no match interface [WORD]",
-       NO_STR
-       MATCH_STR
-       "Match first hop interface of route\n"
-       "Interface name\n")
-{
-       char *iface = (argc == 4) ? argv[3]->arg : NULL;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.no_match_interface)
-               return rmap_match_set_hook.no_match_interface(
-                       vty, index, "interface", iface,
-                       RMAP_EVENT_MATCH_DELETED);
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ip_address,
-       match_ip_address_cmd,
-       "match ip address <(1-199)|(1300-2699)|WORD>",
-       MATCH_STR
-       IP_STR
-       "Match address of route\n"
-       "IP access-list number\n"
-       "IP access-list number (expanded range)\n"
-       "IP Access-list name\n")
-{
-       int idx_acl = 3;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.match_ip_address)
-               return rmap_match_set_hook.match_ip_address(
-                       vty, index, "ip address", argv[idx_acl]->arg,
-                       RMAP_EVENT_FILTER_ADDED);
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_ip_address,
-       no_match_ip_address_cmd,
-       "no match ip address [<(1-199)|(1300-2699)|WORD>]",
-       NO_STR
-       MATCH_STR
-       IP_STR
-       "Match address of route\n"
-       "IP access-list number\n"
-       "IP access-list number (expanded range)\n"
-       "IP Access-list name\n")
-{
-       int idx_word = 4;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.no_match_ip_address) {
-               if (argc <= idx_word)
-                       return rmap_match_set_hook.no_match_ip_address(
-                               vty, index, "ip address", NULL,
-                               RMAP_EVENT_FILTER_DELETED);
-               return rmap_match_set_hook.no_match_ip_address(
-                       vty, index, "ip address", argv[idx_word]->arg,
-                       RMAP_EVENT_FILTER_DELETED);
-       }
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ip_address_prefix_list,
-       match_ip_address_prefix_list_cmd,
-       "match ip address prefix-list WORD",
-       MATCH_STR
-       IP_STR
-       "Match address of route\n"
-       "Match entries of prefix-lists\n"
-       "IP prefix-list name\n")
-{
-       int idx_word = 4;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.match_ip_address_prefix_list)
-               return rmap_match_set_hook.match_ip_address_prefix_list(
-                       vty, index, "ip address prefix-list",
-                       argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_ip_address_prefix_list,
-       no_match_ip_address_prefix_list_cmd,
-       "no match ip address prefix-list [WORD]",
-       NO_STR
-       MATCH_STR
-       IP_STR
-       "Match address of route\n"
-       "Match entries of prefix-lists\n"
-       "IP prefix-list name\n")
-{
-       int idx_word = 5;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.no_match_ip_address_prefix_list) {
-               if (argc <= idx_word)
-                       return rmap_match_set_hook
-                               .no_match_ip_address_prefix_list(
-                                       vty, index, "ip address prefix-list",
-                                       NULL, RMAP_EVENT_PLIST_DELETED);
-               return rmap_match_set_hook.no_match_ip_address_prefix_list(
-                       vty, index, "ip address prefix-list",
-                       argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
-       }
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ip_next_hop,
-       match_ip_next_hop_cmd,
-       "match ip next-hop <(1-199)|(1300-2699)|WORD>",
-       MATCH_STR
-       IP_STR
-       "Match next-hop address of route\n"
-       "IP access-list number\n"
-       "IP access-list number (expanded range)\n"
-       "IP Access-list name\n")
-{
-       int idx_acl = 3;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.match_ip_next_hop)
-               return rmap_match_set_hook.match_ip_next_hop(
-                       vty, index, "ip next-hop", argv[idx_acl]->arg,
-                       RMAP_EVENT_FILTER_ADDED);
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_ip_next_hop,
-       no_match_ip_next_hop_cmd,
-       "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
-       NO_STR
-       MATCH_STR
-       IP_STR
-       "Match next-hop address of route\n"
-       "IP access-list number\n"
-       "IP access-list number (expanded range)\n"
-       "IP Access-list name\n")
-{
-       int idx_word = 4;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.no_match_ip_next_hop) {
-               if (argc <= idx_word)
-                       return rmap_match_set_hook.no_match_ip_next_hop(
-                               vty, index, "ip next-hop", NULL,
-                               RMAP_EVENT_FILTER_DELETED);
-               return rmap_match_set_hook.no_match_ip_next_hop(
-                       vty, index, "ip next-hop", argv[idx_word]->arg,
-                       RMAP_EVENT_FILTER_DELETED);
-       }
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ip_next_hop_prefix_list,
-       match_ip_next_hop_prefix_list_cmd,
-       "match ip next-hop prefix-list WORD",
-       MATCH_STR
-       IP_STR
-       "Match next-hop address of route\n"
-       "Match entries of prefix-lists\n"
-       "IP prefix-list name\n")
-{
-       int idx_word = 4;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.match_ip_next_hop_prefix_list)
-               return rmap_match_set_hook.match_ip_next_hop_prefix_list(
-                       vty, index, "ip next-hop prefix-list",
-                       argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_match_ip_next_hop_prefix_list,
-       no_match_ip_next_hop_prefix_list_cmd,
-       "no match ip next-hop prefix-list [WORD]",
-       NO_STR
-       MATCH_STR
-       IP_STR
-       "Match next-hop address of route\n"
-       "Match entries of prefix-lists\n"
-       "IP prefix-list name\n")
-{
-       int idx_word = 5;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.no_match_ip_next_hop) {
-               if (argc <= idx_word)
-                       return rmap_match_set_hook.no_match_ip_next_hop(
-                               vty, index, "ip next-hop prefix-list", NULL,
-                               RMAP_EVENT_PLIST_DELETED);
-               return rmap_match_set_hook.no_match_ip_next_hop(
-                       vty, index, "ip next-hop prefix-list",
-                       argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
-       }
-       return CMD_SUCCESS;
-}
-
-DEFUN(match_ip_next_hop_type, match_ip_next_hop_type_cmd,
-      "match ip next-hop type <blackhole>",
-      MATCH_STR IP_STR
-      "Match next-hop address of route\n"
-      "Match entries by type\n"
-      "Blackhole\n")
-{
-       int idx_word = 4;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.match_ip_next_hop_type)
-               return rmap_match_set_hook.match_ip_next_hop_type(
-                       vty, index, "ip next-hop type", argv[idx_word]->arg,
-                       RMAP_EVENT_MATCH_ADDED);
-       return CMD_SUCCESS;
-}
-
-DEFUN(no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
-      "no match ip next-hop type [<blackhole>]",
-      NO_STR MATCH_STR IP_STR
-      "Match next-hop address of route\n"
-      "Match entries by type\n"
-      "Blackhole\n")
-{
-       int idx_word = 5;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.no_match_ip_next_hop) {
-               if (argc <= idx_word)
-                       return rmap_match_set_hook.no_match_ip_next_hop(
-                               vty, index, "ip next-hop type", NULL,
-                               RMAP_EVENT_MATCH_DELETED);
-               return rmap_match_set_hook.no_match_ip_next_hop(
-                       vty, index, "ip next-hop type", argv[idx_word]->arg,
-                       RMAP_EVENT_MATCH_DELETED);
-       }
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ipv6_address,
-       match_ipv6_address_cmd,
-       "match ipv6 address WORD",
-       MATCH_STR
-       IPV6_STR
-       "Match IPv6 address of route\n"
-       "IPv6 access-list name\n")
-{
-       int idx_word = 3;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.match_ipv6_address)
-               return rmap_match_set_hook.match_ipv6_address(
-                       vty, index, "ipv6 address", argv[idx_word]->arg,
-                       RMAP_EVENT_FILTER_ADDED);
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_match_ipv6_address,
-       no_match_ipv6_address_cmd,
-       "no match ipv6 address WORD",
-       NO_STR
-       MATCH_STR
-       IPV6_STR
-       "Match IPv6 address of route\n"
-       "IPv6 access-list name\n")
-{
-       int idx_word = 4;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.no_match_ipv6_address)
-               return rmap_match_set_hook.no_match_ipv6_address(
-                       vty, index, "ipv6 address", argv[idx_word]->arg,
-                       RMAP_EVENT_FILTER_DELETED);
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (match_ipv6_address_prefix_list,
-       match_ipv6_address_prefix_list_cmd,
-       "match ipv6 address prefix-list WORD",
-       MATCH_STR
-       IPV6_STR
-       "Match address of route\n"
-       "Match entries of prefix-lists\n"
-       "IP prefix-list name\n")
-{
-       int idx_word = 4;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.match_ipv6_address_prefix_list)
-               return rmap_match_set_hook.match_ipv6_address_prefix_list(
-                       vty, index, "ipv6 address prefix-list",
-                       argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED);
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_match_ipv6_address_prefix_list,
-       no_match_ipv6_address_prefix_list_cmd,
-       "no match ipv6 address prefix-list WORD",
-       NO_STR
-       MATCH_STR
-       IPV6_STR
-       "Match address of route\n"
-       "Match entries of prefix-lists\n"
-       "IP prefix-list name\n")
-{
-       int idx_word = 5;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.no_match_ipv6_address_prefix_list)
-               return rmap_match_set_hook.no_match_ipv6_address_prefix_list(
-                       vty, index, "ipv6 address prefix-list",
-                       argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED);
-       return CMD_SUCCESS;
-}
-
-DEFUN(match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
-      "match ipv6 next-hop type <blackhole>",
-      MATCH_STR IPV6_STR
-      "Match next-hop address of route\n"
-      "Match entries by type\n"
-      "Blackhole\n")
-{
-       int idx_word = 4;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.match_ipv6_next_hop_type)
-               return rmap_match_set_hook.match_ipv6_next_hop_type(
-                       vty, index, "ipv6 next-hop type", argv[idx_word]->arg,
-                       RMAP_EVENT_MATCH_ADDED);
-       return CMD_SUCCESS;
-}
-
-DEFUN(no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
-      "no match ipv6 next-hop type [<blackhole>]",
-      NO_STR MATCH_STR IPV6_STR
-      "Match address of route\n"
-      "Match entries by type\n"
-      "Blackhole\n")
-{
-       int idx_word = 5;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.no_match_ipv6_next_hop_type)
-               return rmap_match_set_hook.no_match_ipv6_next_hop_type(
-                       vty, index, "ipv6 next-hop type",
-                       (argc <= idx_word) ? NULL : argv[idx_word]->arg,
-                       RMAP_EVENT_MATCH_DELETED);
-       return CMD_SUCCESS;
-}
-
-DEFUN (match_metric,
-       match_metric_cmd,
-       "match metric (0-4294967295)",
-       MATCH_STR
-       "Match metric of route\n"
-       "Metric value\n")
-{
-       int idx_number = 2;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.match_metric)
-               return rmap_match_set_hook.match_metric(vty, index, "metric",
-                                                       argv[idx_number]->arg,
-                                                       RMAP_EVENT_MATCH_ADDED);
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_metric,
-       no_match_metric_cmd,
-       "no match metric [(0-4294967295)]",
-       NO_STR
-       MATCH_STR
-       "Match metric of route\n"
-       "Metric value\n")
-{
-       int idx_number = 3;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.no_match_metric) {
-               if (argc <= idx_number)
-                       return rmap_match_set_hook.no_match_metric(
-                               vty, index, "metric", NULL,
-                               RMAP_EVENT_MATCH_DELETED);
-               return rmap_match_set_hook.no_match_metric(
-                       vty, index, "metric", argv[idx_number]->arg,
-                       RMAP_EVENT_MATCH_DELETED);
-       }
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (match_tag,
-       match_tag_cmd,
-       "match tag (1-4294967295)",
-       MATCH_STR
-       "Match tag of route\n"
-       "Tag value\n")
-{
-       int idx_number = 2;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.match_tag)
-               return rmap_match_set_hook.match_tag(vty, index, "tag",
-                                                    argv[idx_number]->arg,
-                                                    RMAP_EVENT_MATCH_ADDED);
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (no_match_tag,
-       no_match_tag_cmd,
-       "no match tag [(1-4294967295)]",
-       NO_STR
-       MATCH_STR
-       "Match tag of route\n"
-       "Tag value\n")
-{
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       int idx = 0;
-       char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
-                           ? argv[idx]->arg
-                           : NULL;
-
-       if (rmap_match_set_hook.no_match_tag)
-               return rmap_match_set_hook.no_match_tag(
-                       vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED);
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (set_ip_nexthop,
-       set_ip_nexthop_cmd,
-       "set ip next-hop A.B.C.D",
-       SET_STR
-       IP_STR
-       "Next hop address\n"
-       "IP address of next hop\n")
-{
-       int idx_ipv4 = 3;
-       union sockunion su;
-       int ret;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       ret = str2sockunion(argv[idx_ipv4]->arg, &su);
-       if (ret < 0) {
-               vty_out(vty, "%% Malformed nexthop address\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-       if (su.sin.sin_addr.s_addr == 0
-           || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) {
-               vty_out(vty,
-                       "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       if (rmap_match_set_hook.set_ip_nexthop)
-               return rmap_match_set_hook.set_ip_nexthop(
-                       vty, index, "ip next-hop", argv[idx_ipv4]->arg);
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (no_set_ip_nexthop,
-       no_set_ip_nexthop_cmd,
-       "no set ip next-hop [A.B.C.D]",
-       NO_STR
-       SET_STR
-       IP_STR
-       "Next hop address\n"
-       "IP address of next hop\n")
-{
-       int idx = 0;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-       const char *arg = NULL;
-
-       if (argv_find(argv, argc, "A.B.C.D", &idx))
-               arg = argv[idx]->arg;
-
-       if (rmap_match_set_hook.no_set_ip_nexthop)
-               return rmap_match_set_hook.no_set_ip_nexthop(
-                       vty, index, "ip next-hop", arg);
-
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (set_ipv6_nexthop_local,
-       set_ipv6_nexthop_local_cmd,
-       "set ipv6 next-hop local X:X::X:X",
-       SET_STR
-       IPV6_STR
-       "IPv6 next-hop address\n"
-       "IPv6 local address\n"
-       "IPv6 address of next hop\n")
-{
-       int idx_ipv6 = 4;
-       struct in6_addr addr;
-       int ret;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr);
-       if (!ret) {
-               vty_out(vty, "%% Malformed nexthop address\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-       if (!IN6_IS_ADDR_LINKLOCAL(&addr)) {
-               vty_out(vty, "%% Invalid link-local nexthop address\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       if (rmap_match_set_hook.set_ipv6_nexthop_local)
-               return rmap_match_set_hook.set_ipv6_nexthop_local(
-                       vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg);
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (no_set_ipv6_nexthop_local,
-       no_set_ipv6_nexthop_local_cmd,
-       "no set ipv6 next-hop local [X:X::X:X]",
-       NO_STR
-       SET_STR
-       IPV6_STR
-       "IPv6 next-hop address\n"
-       "IPv6 local address\n"
-       "IPv6 address of next hop\n")
-{
-       int idx_ipv6 = 5;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.no_set_ipv6_nexthop_local) {
-               if (argc <= idx_ipv6)
-                       return rmap_match_set_hook.no_set_ipv6_nexthop_local(
-                               vty, index, "ipv6 next-hop local", NULL);
-               return rmap_match_set_hook.no_set_ipv6_nexthop_local(
-                       vty, index, "ipv6 next-hop local", argv[5]->arg);
-       }
-       return CMD_SUCCESS;
-}
-
-DEFUN (set_metric,
-       set_metric_cmd,
-       "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>",
-       SET_STR
-       "Metric value for destination routing protocol\n"
-       "Metric value\n"
-       "Assign round trip time\n"
-       "Add round trip time\n"
-       "Subtract round trip time\n"
-       "Add metric\n"
-       "Subtract metric\n")
-{
-       int idx_number = 2;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       const char *pass = (argv[idx_number]->type == RANGE_TKN)
-                                  ? argv[idx_number]->arg
-                                  : argv[idx_number]->text;
-
-       if (rmap_match_set_hook.set_metric)
-               return rmap_match_set_hook.set_metric(vty, index, "metric",
-                                                     pass);
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (no_set_metric,
-       no_set_metric_cmd,
-       "no set metric [(0-4294967295)]",
-       NO_STR
-       SET_STR
-       "Metric value for destination routing protocol\n"
-       "Metric value\n")
-{
-       int idx_number = 3;
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       if (rmap_match_set_hook.no_set_metric) {
-               if (argc <= idx_number)
-                       return rmap_match_set_hook.no_set_metric(
-                               vty, index, "metric", NULL);
-               return rmap_match_set_hook.no_set_metric(vty, index, "metric",
-                                                        argv[idx_number]->arg);
-       }
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (set_tag,
-       set_tag_cmd,
-       "set tag (1-4294967295)",
-       SET_STR
-       "Tag value for routing protocol\n"
-       "Tag value\n")
-{
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       int idx_number = 2;
-       if (rmap_match_set_hook.set_tag)
-               return rmap_match_set_hook.set_tag(vty, index, "tag",
-                                                  argv[idx_number]->arg);
-       return CMD_SUCCESS;
-}
-
-
-DEFUN (no_set_tag,
-       no_set_tag_cmd,
-       "no set tag [(1-4294967295)]",
-       NO_STR
-       SET_STR
-       "Tag value for routing protocol\n"
-       "Tag value\n")
-{
-       VTY_DECLVAR_CONTEXT(route_map_index, index);
-
-       int idx_number = 3;
-       if (rmap_match_set_hook.no_set_tag) {
-               if (argc <= idx_number)
-                       return rmap_match_set_hook.no_set_tag(vty, index, "tag",
-                                                             NULL);
-               return rmap_match_set_hook.no_set_tag(vty, index, "tag",
-                                                     argv[idx_number]->arg);
-       }
-       return CMD_SUCCESS;
-}
-
-
-DEFUN_NOSH (route_map,
-       route_map_cmd,
-       "route-map WORD <deny|permit> (1-65535)",
-       "Create route-map or enter route-map command mode\n"
-       "Route map tag\n"
-       "Route map denies set operations\n"
-       "Route map permits set operations\n"
-       "Sequence to insert to/delete from existing route-map entry\n")
-{
-       int idx_word = 1;
-       int idx_permit_deny = 2;
-       int idx_number = 3;
-       struct route_map *map;
-       struct route_map_index *index;
-       char *endptr = NULL;
-       int permit =
-               argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY;
-       unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10);
-       const char *mapname = argv[idx_word]->arg;
-
-       /* Get route map. */
-       map = route_map_get(mapname);
-       index = route_map_index_get(map, permit, pref);
-
-       VTY_PUSH_CONTEXT(RMAP_NODE, index);
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_route_map_all,
-       no_route_map_all_cmd,
-       "no route-map WORD",
-       NO_STR
-       "Create route-map or enter route-map command mode\n"
-       "Route map tag\n")
-{
-       int idx_word = 2;
-       const char *mapname = argv[idx_word]->arg;
-       struct route_map *map;
-
-       map = route_map_lookup_by_name(mapname);
-       if (map == NULL) {
-               vty_out(vty, "%% Could not find route-map %s\n", mapname);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       route_map_delete(map);
-
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_route_map,
-       no_route_map_cmd,
-       "no route-map WORD <deny|permit> (1-65535)",
-       NO_STR
-       "Create route-map or enter route-map command mode\n"
-       "Route map tag\n"
-       "Route map denies set operations\n"
-       "Route map permits set operations\n"
-       "Sequence to insert to/delete from existing route-map entry\n")
-{
-       int idx_word = 2;
-       int idx_permit_deny = 3;
-       int idx_number = 4;
-       struct route_map *map;
-       struct route_map_index *index;
-       char *endptr = NULL;
-       int permit = strmatch(argv[idx_permit_deny]->text, "permit")
-                            ? RMAP_PERMIT
-                            : RMAP_DENY;
-       const char *prefstr = argv[idx_number]->arg;
-       const char *mapname = argv[idx_word]->arg;
-       unsigned long pref = strtoul(prefstr, &endptr, 10);
-
-       /* Existence check. */
-       map = route_map_lookup_by_name(mapname);
-       if (map == NULL) {
-               vty_out(vty, "%% Could not find route-map %s\n", mapname);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       /* Lookup route map index. */
-       index = route_map_index_lookup(map, permit, pref);
-       if (index == NULL) {
-               vty_out(vty, "%% Could not find route-map entry %s %s\n",
-                       mapname, prefstr);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       /* Delete index from route map. */
-       route_map_index_delete(index, 1);
-
-       /* If this route rule is the last one, delete route map itself. */
-       if (route_map_empty(map))
-               route_map_delete(map);
-
-       return CMD_SUCCESS;
-}
-
-DEFUN (rmap_onmatch_next,
-       rmap_onmatch_next_cmd,
-       "on-match next",
-       "Exit policy on matches\n"
-       "Next clause\n")
-{
-       struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
-       if (index) {
-               if (index->type == RMAP_DENY) {
-                       /* Under a deny clause, match means it's finished. No
-                        * need to set next */
-                       vty_out(vty,
-                               "on-match next not supported under route-map deny\n");
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
-               index->exitpolicy = RMAP_NEXT;
-       }
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_rmap_onmatch_next,
-       no_rmap_onmatch_next_cmd,
-       "no on-match next",
-       NO_STR
-       "Exit policy on matches\n"
-       "Next clause\n")
-{
-       struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
-       if (index)
-               index->exitpolicy = RMAP_EXIT;
-
-       return CMD_SUCCESS;
-}
-
-DEFUN (rmap_onmatch_goto,
-       rmap_onmatch_goto_cmd,
-       "on-match goto (1-65535)",
-       "Exit policy on matches\n"
-       "Goto Clause number\n"
-       "Number\n")
-{
-       int idx = 0;
-       char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg
-                                                            : NULL;
-
-       struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-       int d = 0;
-
-       if (index) {
-               if (index->type == RMAP_DENY) {
-                       /* Under a deny clause, match means it's finished. No
-                        * need to go anywhere */
-                       vty_out(vty,
-                               "on-match goto not supported under route-map deny\n");
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
-
-               if (num)
-                       d = strtoul(num, NULL, 10);
-               else
-                       d = index->pref + 1;
-
-               if (d <= index->pref) {
-                       /* Can't allow you to do that, Dave */
-                       vty_out(vty, "can't jump backwards in route-maps\n");
-                       return CMD_WARNING_CONFIG_FAILED;
-               } else {
-                       index->exitpolicy = RMAP_GOTO;
-                       index->nextpref = d;
-               }
-       }
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_rmap_onmatch_goto,
-       no_rmap_onmatch_goto_cmd,
-       "no on-match goto",
-       NO_STR
-       "Exit policy on matches\n"
-       "Goto Clause number\n")
-{
-       struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
-       if (index)
-               index->exitpolicy = RMAP_EXIT;
-
-       return CMD_SUCCESS;
-}
-
-/* Cisco/GNU Zebra compatibility aliases */
-/* ALIAS_FIXME */
-DEFUN (rmap_continue,
-       rmap_continue_cmd,
-       "continue (1-65535)",
-       "Continue on a different entry within the route-map\n"
-       "Route-map entry sequence number\n")
-{
-       return rmap_onmatch_goto(self, vty, argc, argv);
-}
-
-/* ALIAS_FIXME */
-DEFUN (no_rmap_continue,
-       no_rmap_continue_cmd,
-       "no continue [(1-65535)]",
-       NO_STR
-       "Continue on a different entry within the route-map\n"
-       "Route-map entry sequence number\n")
-{
-       return no_rmap_onmatch_goto(self, vty, argc, argv);
-}
-
 static void clear_route_map_helper(struct route_map *map)
 {
        struct route_map_index *index;
@@ -3136,89 +2092,6 @@ DEFUN (rmap_show_unused,
        return vty_show_unused_route_map(vty);
 }
 
-DEFUN (rmap_call,
-       rmap_call_cmd,
-       "call WORD",
-       "Jump to another Route-Map after match+set\n"
-       "Target route-map name\n")
-{
-       int idx_word = 1;
-       struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-       const char *rmap = argv[idx_word]->arg;
-
-       assert(index);
-
-       /* If "call" is invoked with the same route-map name as
-        * the one previously configured then, ignore the duplicate
-        * configuration.
-        */
-       if (index->nextrm && (strcmp(index->nextrm, rmap) == 0))
-               return CMD_SUCCESS;
-
-       if (index->nextrm) {
-               route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
-                                         index->nextrm, index->map->name);
-               XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
-       }
-       index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
-
-       /* Execute event hook. */
-       route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm,
-                                 index->map->name);
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_rmap_call,
-       no_rmap_call_cmd,
-       "no call",
-       NO_STR
-       "Jump to another Route-Map after match+set\n")
-{
-       struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
-       if (index->nextrm) {
-               route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
-                                         index->nextrm, index->map->name);
-               XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm);
-               index->nextrm = NULL;
-       }
-
-       return CMD_SUCCESS;
-}
-
-DEFUN (rmap_description,
-       rmap_description_cmd,
-       "description LINE...",
-       "Route-map comment\n"
-       "Comment describing this route-map rule\n")
-{
-       int idx_line = 1;
-       struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
-       if (index) {
-               if (index->description)
-                       XFREE(MTYPE_TMP, index->description);
-               index->description = argv_concat(argv, argc, idx_line);
-       }
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_rmap_description,
-       no_rmap_description_cmd,
-       "no description",
-       NO_STR
-       "Route-map comment\n")
-{
-       struct route_map_index *index = VTY_GET_CONTEXT(route_map_index);
-
-       if (index) {
-               if (index->description)
-                       XFREE(MTYPE_TMP, index->description);
-               index->description = NULL;
-       }
-       return CMD_SUCCESS;
-}
-
 DEFUN (debug_rmap,
        debug_rmap_cmd,
        "debug route-map",
@@ -3244,59 +2117,6 @@ DEFUN (no_debug_rmap,
 static struct cmd_node rmap_debug_node = {RMAP_DEBUG_NODE, "", 1};
 
 /* Configuration write function. */
-static int route_map_config_write(struct vty *vty)
-{
-       struct route_map *map;
-       struct route_map_index *index;
-       struct route_map_rule *rule;
-       int first = 1;
-       int write = 0;
-       struct listnode *ln;
-       struct list *maplist = list_new();
-
-       for (map = route_map_master.head; map; map = map->next)
-               listnode_add(maplist, map);
-
-       list_sort(maplist, sort_route_map);
-
-       for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
-               for (index = map->head; index; index = index->next) {
-                       if (!first)
-                               vty_out(vty, "!\n");
-                       else
-                               first = 0;
-
-                       vty_out(vty, "route-map %s %s %d\n", map->name,
-                               route_map_type_str(index->type), index->pref);
-
-                       if (index->description)
-                               vty_out(vty, " description %s\n",
-                                       index->description);
-
-                       for (rule = index->match_list.head; rule;
-                            rule = rule->next)
-                               vty_out(vty, " match %s %s\n", rule->cmd->str,
-                                       rule->rule_str ? rule->rule_str : "");
-
-                       for (rule = index->set_list.head; rule;
-                            rule = rule->next)
-                               vty_out(vty, " set %s %s\n", rule->cmd->str,
-                                       rule->rule_str ? rule->rule_str : "");
-                       if (index->nextrm)
-                               vty_out(vty, " call %s\n", index->nextrm);
-                       if (index->exitpolicy == RMAP_GOTO)
-                               vty_out(vty, " on-match goto %d\n",
-                                       index->nextpref);
-                       if (index->exitpolicy == RMAP_NEXT)
-                               vty_out(vty, " on-match next\n");
-
-                       write++;
-               }
-
-       list_delete(&maplist);
-       return write;
-}
-
 static int rmap_config_write_debug(struct vty *vty)
 {
        int write = 0;
@@ -3309,9 +2129,6 @@ static int rmap_config_write_debug(struct vty *vty)
        return write;
 }
 
-/* Route map node structure. */
-static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
-
 /* Common route map rules */
 
 void *route_map_rule_tag_compile(const char *arg)
@@ -3370,14 +2187,6 @@ void route_map_finish(void)
        route_map_master_hash = NULL;
 }
 
-static void rmap_autocomplete(vector comps, struct cmd_token *token)
-{
-       struct route_map *map;
-
-       for (map = route_map_master.head; map; map = map->next)
-               vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
-}
-
 /* Increment the use_count counter while attaching the route map */
 void route_map_counter_increment(struct route_map *map)
 {
@@ -3395,14 +2204,6 @@ void route_map_counter_decrement(struct route_map *map)
        }
 }
 
-static const struct cmd_variable_handler rmap_var_handlers[] = {
-       {/* "route-map WORD" */
-        .varname = "route_map",
-        .completions = rmap_autocomplete},
-       {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
-       {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
-       {.completions = NULL}};
-
 /* Initialization of route map vector. */
 void route_map_init(void)
 {
@@ -3420,43 +2221,17 @@ void route_map_init(void)
                        8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
                        "Route Map Dep Hash");
 
-       cmd_variable_handler_register(rmap_var_handlers);
-
        rmap_debug = false;
 
-       /* Install route map top node. */
-       install_node(&rmap_node, route_map_config_write);
+       route_map_cli_init();
 
+       /* Install route map top node. */
        install_node(&rmap_debug_node, rmap_config_write_debug);
 
        /* Install route map commands. */
-       install_default(RMAP_NODE);
-       install_element(CONFIG_NODE, &route_map_cmd);
-       install_element(CONFIG_NODE, &no_route_map_cmd);
-       install_element(CONFIG_NODE, &no_route_map_all_cmd);
-
        install_element(CONFIG_NODE, &debug_rmap_cmd);
        install_element(CONFIG_NODE, &no_debug_rmap_cmd);
 
-       /* Install the on-match stuff */
-       install_element(RMAP_NODE, &route_map_cmd);
-       install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
-       install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
-       install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
-       install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
-       install_element(RMAP_NODE, &rmap_continue_cmd);
-       install_element(RMAP_NODE, &no_rmap_continue_cmd);
-
-       /* Install the continue stuff (ALIAS of on-match). */
-
-       /* Install the call stuff. */
-       install_element(RMAP_NODE, &rmap_call_cmd);
-       install_element(RMAP_NODE, &no_rmap_call_cmd);
-
-       /* Install description commands. */
-       install_element(RMAP_NODE, &rmap_description_cmd);
-       install_element(RMAP_NODE, &no_rmap_description_cmd);
-
        /* Install show command */
        install_element(ENABLE_NODE, &rmap_clear_counters_cmd);
 
@@ -3465,49 +2240,4 @@ void route_map_init(void)
 
        install_element(ENABLE_NODE, &debug_rmap_cmd);
        install_element(ENABLE_NODE, &no_debug_rmap_cmd);
-
-       install_element(RMAP_NODE, &match_interface_cmd);
-       install_element(RMAP_NODE, &no_match_interface_cmd);
-
-       install_element(RMAP_NODE, &match_ip_address_cmd);
-       install_element(RMAP_NODE, &no_match_ip_address_cmd);
-
-       install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
-       install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
-
-       install_element(RMAP_NODE, &match_ip_next_hop_cmd);
-       install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
-
-       install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
-       install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
-
-       install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
-       install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
-
-       install_element(RMAP_NODE, &match_ipv6_address_cmd);
-       install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
-
-       install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
-       install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
-
-       install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
-       install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
-
-       install_element(RMAP_NODE, &match_metric_cmd);
-       install_element(RMAP_NODE, &no_match_metric_cmd);
-
-       install_element(RMAP_NODE, &match_tag_cmd);
-       install_element(RMAP_NODE, &no_match_tag_cmd);
-
-       install_element(RMAP_NODE, &set_ip_nexthop_cmd);
-       install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
-
-       install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
-       install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
-
-       install_element(RMAP_NODE, &set_metric_cmd);
-       install_element(RMAP_NODE, &no_set_metric_cmd);
-
-       install_element(RMAP_NODE, &set_tag_cmd);
-       install_element(RMAP_NODE, &no_set_tag_cmd);
 }
index 1ffd0525ae66eeec801555e0c7f04cfe19e5a735..05c958967cf37402b174c9c71db4251dcc5f7369 100644 (file)
@@ -140,12 +140,31 @@ enum rmap_compile_rets {
 
 };
 
+/* Route map rule. This rule has both `match' rule and `set' rule. */
+struct route_map_rule {
+       /* Rule type. */
+       const struct route_map_rule_cmd *cmd;
+
+       /* For pretty printing. */
+       char *rule_str;
+
+       /* Pre-compiled match rule. */
+       void *value;
+
+       /* Linked list. */
+       struct route_map_rule *next;
+       struct route_map_rule *prev;
+};
+
 /* Route map rule list. */
 struct route_map_rule_list {
        struct route_map_rule *head;
        struct route_map_rule *tail;
 };
 
+/* Forward struct declaration: the complete can be found later this file. */
+struct routemap_hook_context;
+
 /* Route map index structure. */
 struct route_map_index {
        struct route_map *map;
@@ -178,6 +197,9 @@ struct route_map_index {
        uint64_t applied;
        uint64_t applied_clear;
 
+       /* List of match/sets contexts. */
+       TAILQ_HEAD(, routemap_hook_context) rhclist;
+
        QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(route_map_index)
@@ -435,6 +457,247 @@ extern void route_map_counter_increment(struct route_map *map);
 /* Decrement the route-map used counter */
 extern void route_map_counter_decrement(struct route_map *map);
 
+/* Route map hooks data structure. */
+struct route_map_match_set_hooks {
+       /* match interface */
+       int (*match_interface)(struct vty *vty, struct route_map_index *index,
+                              const char *command, const char *arg,
+                              route_map_event_t type);
+
+       /* no match interface */
+       int (*no_match_interface)(struct vty *vty,
+                                 struct route_map_index *index,
+                                 const char *command, const char *arg,
+                                 route_map_event_t type);
+
+       /* match ip address */
+       int (*match_ip_address)(struct vty *vty, struct route_map_index *index,
+                               const char *command, const char *arg,
+                               route_map_event_t type);
+
+       /* no match ip address */
+       int (*no_match_ip_address)(struct vty *vty,
+                                  struct route_map_index *index,
+                                  const char *command, const char *arg,
+                                  route_map_event_t type);
+
+       /* match ip address prefix list */
+       int (*match_ip_address_prefix_list)(struct vty *vty,
+                                           struct route_map_index *index,
+                                           const char *command,
+                                           const char *arg,
+                                           route_map_event_t type);
+
+       /* no match ip address prefix list */
+       int (*no_match_ip_address_prefix_list)(struct vty *vty,
+                                              struct route_map_index *index,
+                                              const char *command,
+                                              const char *arg,
+                                              route_map_event_t type);
+
+       /* match ip next hop */
+       int (*match_ip_next_hop)(struct vty *vty, struct route_map_index *index,
+                                const char *command, const char *arg,
+                                route_map_event_t type);
+
+       /* no match ip next hop */
+       int (*no_match_ip_next_hop)(struct vty *vty,
+                                   struct route_map_index *index,
+                                   const char *command, const char *arg,
+                                   route_map_event_t type);
+
+       /* match ip next hop prefix list */
+       int (*match_ip_next_hop_prefix_list)(struct vty *vty,
+                                            struct route_map_index *index,
+                                            const char *command,
+                                            const char *arg,
+                                            route_map_event_t type);
+
+       /* no match ip next hop prefix list */
+       int (*no_match_ip_next_hop_prefix_list)(struct vty *vty,
+                                               struct route_map_index *index,
+                                               const char *command,
+                                               const char *arg,
+                                               route_map_event_t type);
+
+       /* match ip next-hop type */
+       int (*match_ip_next_hop_type)(struct vty *vty,
+                                            struct route_map_index *index,
+                                            const char *command,
+                                            const char *arg,
+                                            route_map_event_t type);
+
+       /* no match ip next-hop type */
+       int (*no_match_ip_next_hop_type)(struct vty *vty,
+                                               struct route_map_index *index,
+                                               const char *command,
+                                               const char *arg,
+                                               route_map_event_t type);
+
+       /* match ipv6 address */
+       int (*match_ipv6_address)(struct vty *vty,
+                                 struct route_map_index *index,
+                                 const char *command, const char *arg,
+                                 route_map_event_t type);
+
+       /* no match ipv6 address */
+       int (*no_match_ipv6_address)(struct vty *vty,
+                                    struct route_map_index *index,
+                                    const char *command, const char *arg,
+                                    route_map_event_t type);
+
+
+       /* match ipv6 address prefix list */
+       int (*match_ipv6_address_prefix_list)(struct vty *vty,
+                                             struct route_map_index *index,
+                                             const char *command,
+                                             const char *arg,
+                                             route_map_event_t type);
+
+       /* no match ipv6 address prefix list */
+       int (*no_match_ipv6_address_prefix_list)(struct vty *vty,
+                                                struct route_map_index *index,
+                                                const char *command,
+                                                const char *arg,
+                                                route_map_event_t type);
+
+       /* match ipv6 next-hop type */
+       int (*match_ipv6_next_hop_type)(struct vty *vty,
+                                             struct route_map_index *index,
+                                             const char *command,
+                                             const char *arg,
+                                             route_map_event_t type);
+
+       /* no match ipv6 next-hop type */
+       int (*no_match_ipv6_next_hop_type)(struct vty *vty,
+                                          struct route_map_index *index,
+                                          const char *command, const char *arg,
+                                          route_map_event_t type);
+
+       /* match metric */
+       int (*match_metric)(struct vty *vty, struct route_map_index *index,
+                           const char *command, const char *arg,
+                           route_map_event_t type);
+
+       /* no match metric */
+       int (*no_match_metric)(struct vty *vty, struct route_map_index *index,
+                              const char *command, const char *arg,
+                              route_map_event_t type);
+
+       /* match tag */
+       int (*match_tag)(struct vty *vty, struct route_map_index *index,
+                        const char *command, const char *arg,
+                        route_map_event_t type);
+
+       /* no match tag */
+       int (*no_match_tag)(struct vty *vty, struct route_map_index *index,
+                           const char *command, const char *arg,
+                           route_map_event_t type);
+
+       /* set ip nexthop */
+       int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
+                             const char *command, const char *arg);
+
+       /* no set ip nexthop */
+       int (*no_set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
+                                const char *command, const char *arg);
+
+       /* set ipv6 nexthop local */
+       int (*set_ipv6_nexthop_local)(struct vty *vty,
+                                     struct route_map_index *index,
+                                     const char *command, const char *arg);
+
+       /* no set ipv6 nexthop local */
+       int (*no_set_ipv6_nexthop_local)(struct vty *vty,
+                                        struct route_map_index *index,
+                                        const char *command, const char *arg);
+
+       /* set metric */
+       int (*set_metric)(struct vty *vty, struct route_map_index *index,
+                         const char *command, const char *arg);
+
+       /* no set metric */
+       int (*no_set_metric)(struct vty *vty, struct route_map_index *index,
+                            const char *command, const char *arg);
+
+       /* set tag */
+       int (*set_tag)(struct vty *vty, struct route_map_index *index,
+                      const char *command, const char *arg);
+
+       /* no set tag */
+       int (*no_set_tag)(struct vty *vty, struct route_map_index *index,
+                         const char *command, const char *arg);
+};
+
+extern struct route_map_match_set_hooks rmap_match_set_hook;
+
+/* Making route map list. */
+struct route_map_list {
+       struct route_map *head;
+       struct route_map *tail;
+
+       void (*add_hook)(const char *);
+       void (*delete_hook)(const char *);
+       void (*event_hook)(const char *);
+};
+
+extern struct route_map_list route_map_master;
+
+extern struct route_map *route_map_get(const char *name);
+extern void route_map_delete(struct route_map *map);
+extern struct route_map_index *route_map_index_get(struct route_map *map,
+                                                  enum route_map_type type,
+                                                  int pref);
+extern void route_map_index_delete(struct route_map_index *index, int notify);
+
+/* routemap_northbound.c */
+typedef int (*routemap_match_hook_fun)(struct vty *vty,
+                                      struct route_map_index *rmi,
+                                      const char *command, const char *arg,
+                                      route_map_event_t event);
+
+typedef int (*routemap_set_hook_fun)(struct vty *vty,
+                                    struct route_map_index *rmi,
+                                    const char *command, const char *arg);
+
+struct routemap_hook_context {
+       struct route_map_index *rhc_rmi;
+       const char *rhc_rule;
+       route_map_event_t rhc_event;
+       routemap_set_hook_fun rhc_shook;
+       routemap_match_hook_fun rhc_mhook;
+       TAILQ_ENTRY(routemap_hook_context) rhc_entry;
+};
+
+int lib_route_map_entry_match_destroy(enum nb_event event,
+                                     const struct lyd_node *dnode);
+int lib_route_map_entry_set_destroy(enum nb_event event,
+                                   const struct lyd_node *dnode);
+
+struct routemap_hook_context *
+routemap_hook_context_insert(struct route_map_index *rmi);
+void routemap_hook_context_free(struct routemap_hook_context *rhc);
+
+extern const struct frr_yang_module_info frr_route_map_info;
+
+/* routemap_cli.c */
+extern void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
+                                   bool show_defaults);
+extern void route_map_instance_show_end(struct vty *vty,
+                                       struct lyd_node *dnode);
+extern void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
+                                    bool show_defaults);
+extern void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
+                                 bool show_defaults);
+extern void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode,
+                                      bool show_defaults);
+extern void route_map_call_show(struct vty *vty, struct lyd_node *dnode,
+                               bool show_defaults);
+extern void route_map_description_show(struct vty *vty,
+                                      struct lyd_node *dnode,
+                                      bool show_defaults);
+extern void route_map_cli_init(void);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
new file mode 100644 (file)
index 0000000..7023710
--- /dev/null
@@ -0,0 +1,1129 @@
+/*
+ * Route map northbound CLI implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ *                    Rafael Zalamena
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/command.h"
+#include "lib/northbound_cli.h"
+#include "lib/routemap.h"
+
+#ifndef VTYSH_EXTRACT_PL
+#include "lib/routemap_cli_clippy.c"
+#endif /* VTYSH_EXTRACT_PL */
+
+#define ROUTE_MAP_CMD_STR \
+       "Create route-map or enter route-map command mode\n" \
+       "Route map tag\n"
+#define ROUTE_MAP_OP_CMD_STR \
+       "Route map denies set operations\n" \
+       "Route map permits set operations\n"
+#define ROUTE_MAP_SEQUENCE_CMD_STR \
+       "Sequence to insert to/delete from existing route-map entry\n"
+
+DEFPY_NOSH(
+       route_map, route_map_cmd,
+       "route-map WORD$name <deny|permit>$action (1-65535)$sequence",
+       ROUTE_MAP_CMD_STR
+       ROUTE_MAP_OP_CMD_STR
+       ROUTE_MAP_SEQUENCE_CMD_STR)
+{
+       struct route_map_index *rmi;
+       struct route_map *rm;
+       int action_type;
+       char xpath_action[XPATH_MAXLEN + 64];
+       char xpath_index[XPATH_MAXLEN + 32];
+       char xpath[XPATH_MAXLEN];
+       int rv;
+
+       snprintf(xpath, sizeof(xpath),
+                "/frr-route-map:lib/route-map[name='%s']", name);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+       snprintf(xpath_index, sizeof(xpath_index), "%s/entry[sequence='%lu']",
+                xpath, sequence);
+       nb_cli_enqueue_change(vty, xpath_index, NB_OP_CREATE, NULL);
+
+       snprintf(xpath_action, sizeof(xpath_action), "%s/action", xpath_index);
+       nb_cli_enqueue_change(vty, xpath_action, NB_OP_MODIFY, action);
+
+       rv = nb_cli_apply_changes(vty, NULL);
+       if (rv == CMD_SUCCESS) {
+               VTY_PUSH_XPATH(RMAP_NODE, xpath_index);
+
+               /* Add support for non-migrated route map users. */
+               rm = route_map_get(name);
+               action_type = (action[0] == 'p') ? RMAP_PERMIT : RMAP_DENY;
+               rmi = route_map_index_get(rm, action_type, sequence);
+               VTY_PUSH_CONTEXT(RMAP_NODE, rmi);
+       }
+
+       return rv;
+}
+
+DEFPY(
+       no_route_map_all, no_route_map_all_cmd,
+       "no route-map WORD$name",
+       NO_STR
+       ROUTE_MAP_CMD_STR)
+{
+       char xpath[XPATH_MAXLEN];
+
+       snprintf(xpath, sizeof(xpath),
+                "/frr-route-map:lib/route-map[name='%s']", name);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_route_map, no_route_map_cmd,
+       "no route-map WORD$name <deny|permit>$action (1-65535)$sequence",
+       NO_STR
+       ROUTE_MAP_CMD_STR
+       ROUTE_MAP_OP_CMD_STR
+       ROUTE_MAP_SEQUENCE_CMD_STR)
+{
+       char xpath[XPATH_MAXLEN];
+
+       snprintf(xpath, sizeof(xpath),
+                "/frr-route-map:lib/route-map[name='%s']/entry[sequence='%lu']",
+                name, sequence);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_instance_show(struct vty *vty, struct lyd_node *dnode,
+                            bool show_defaults)
+{
+       const struct route_map_rule *rmr;
+       const struct route_map_index *rmi;
+       const char *name = yang_dnode_get_string(dnode, "../name");
+       const char *action = yang_dnode_get_string(dnode, "./action");
+       const char *sequence = yang_dnode_get_string(dnode, "./sequence");
+
+       vty_out(vty, "route-map %s %s %s\n", name, action, sequence);
+
+       rmi = nb_running_get_entry(dnode, NULL, false);
+       if (rmi == NULL) {
+               /*
+                * We can't have outdated rules if route map hasn't
+                * been created yet.
+                */
+               return;
+       }
+
+#define SKIP_RULE(name) if (strcmp((name), rmr->cmd->str) == 0) continue
+
+       /* Print route map `match` for old CLI users. */
+       for (rmr = rmi->match_list.head; rmr; rmr = rmr->next) {
+               /* Skip all matches implemented by northbound. */
+               SKIP_RULE("interface");
+               SKIP_RULE("ip address");
+               SKIP_RULE("ip address prefix-list");
+               SKIP_RULE("ip next-hop");
+               SKIP_RULE("ip next-hop prefix-list");
+               SKIP_RULE("ip next-hop type");
+               SKIP_RULE("ipv6 address");
+               SKIP_RULE("ipv6 address prefix-list");
+               SKIP_RULE("ipv6 next-hop type");
+               SKIP_RULE("metric");
+               SKIP_RULE("tag");
+
+               vty_out(vty, " match %s %s\n", rmr->cmd->str,
+                       rmr->rule_str ? rmr->rule_str : "");
+       }
+
+       /* Print route map `set` for old CLI users. */
+       for (rmr = rmi->set_list.head; rmr; rmr = rmr->next) {
+               /* Skip all sets implemented by northbound. */
+               SKIP_RULE("metric");
+               SKIP_RULE("tag");
+
+               vty_out(vty, " set %s %s\n", rmr->cmd->str,
+                       rmr->rule_str ? rmr->rule_str : "");
+       }
+
+#undef SKIP_RULE
+}
+
+void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode)
+{
+       vty_out(vty, "!\n");
+}
+
+DEFPY(
+       match_interface, match_interface_cmd,
+       "match interface IFNAME",
+       MATCH_STR
+       "Match first hop interface of route\n"
+       INTERFACE_STR)
+{
+       const char *xpath = "./match-condition[condition='interface']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value), "%s/interface", xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ifname);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_match_interface, no_match_interface_cmd,
+       "no match interface [IFNAME]",
+       NO_STR
+       MATCH_STR
+       "Match first hop interface of route\n"
+       INTERFACE_STR)
+{
+       const char *xpath = "./match-condition[condition='interface']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       match_ip_address, match_ip_address_cmd,
+       "match ip address <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n")
+{
+       const char *xpath = "./match-condition[condition='ipv4-address-list']";
+       char xpath_value[XPATH_MAXLEN + 32];
+       int acln = acll ? acll : aclh;
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       if (name) {
+               snprintf(xpath_value, sizeof(xpath_value), "%s/list-name",
+                        xpath);
+               nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+       } else /* if (acll || aclh) */ {
+               if ((acln >= 1 && acln <= 99)
+                   || (acln >= 1300 && acln <= 1999)) {
+                       snprintf(xpath_value, sizeof(xpath_value),
+                                "%s/access-list-num", xpath);
+               } else {
+                       /*
+                        * if ((acln >= 100 && acln <= 199)
+                        *     || (acln >= 2000 && acln <= 2699))
+                        */
+                       snprintf(xpath_value, sizeof(xpath_value),
+                                "%s/access-list-num-extended", xpath);
+               }
+               nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
+                                     acll_str ? acll_str : aclh_str);
+       }
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_match_ip_address, no_match_ip_address_cmd,
+       "no match ip address [<(1-199)|(1300-2699)|WORD>]",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n")
+{
+       const char *xpath = "./match-condition[condition='ipv4-address-list']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       match_ip_address_prefix_list,
+       match_ip_address_prefix_list_cmd,
+       "match ip address prefix-list WORD$name",
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+       const char *xpath = "./match-condition[condition='ipv4-prefix-list']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd,
+       "no match ip address prefix-list [WORD]",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+       const char *xpath = "./match-condition[condition='ipv4-prefix-list']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       match_ip_next_hop, match_ip_next_hop_cmd,
+       "match ip next-hop <(1-199)$acll|(1300-2699)$aclh|WORD$name>",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n")
+{
+       const char *xpath = "./match-condition[condition='ipv4-next-hop-list']";
+       char xpath_value[XPATH_MAXLEN + 32];
+       int acln = acll ? acll : aclh;
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       if (name) {
+               snprintf(xpath_value, sizeof(xpath_value), "%s/list-name",
+                        xpath);
+               nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+       } else /* if (acll || aclh) */ {
+               if ((acln >= 1 && acln <= 99)
+                   || (acln >= 1300 && acln <= 1999)) {
+                       snprintf(xpath_value, sizeof(xpath_value),
+                                "%s/access-list-num", xpath);
+               } else {
+                       /*
+                        * if ((acln >= 100 && acln <= 199)
+                        *     || (acln >= 2000 && acln <= 2699))
+                        */
+                       snprintf(xpath_value, sizeof(xpath_value),
+                                "%s/access-list-num-extended", xpath);
+               }
+               nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
+                                     acll_str ? acll_str : aclh_str);
+       }
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_match_ip_next_hop, no_match_ip_next_hop_cmd,
+       "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list number\n"
+       "IP access-list number (expanded range)\n"
+       "IP Access-list name\n")
+{
+       const char *xpath = "./match-condition[condition='ipv4-next-hop-list']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       match_ip_next_hop_prefix_list,
+       match_ip_next_hop_prefix_list_cmd,
+       "match ip next-hop prefix-list WORD$name",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+       const char *xpath =
+               "./match-condition[condition='ipv4-next-hop-prefix-list']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_match_ip_next_hop_prefix_list,
+       no_match_ip_next_hop_prefix_list_cmd,
+       "no match ip next-hop prefix-list [WORD]",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+       const char *xpath =
+               "./match-condition[condition='ipv4-next-hop-prefix-list']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       match_ip_next_hop_type, match_ip_next_hop_type_cmd,
+       "match ip next-hop type <blackhole>$type",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries by type\n"
+       "Blackhole\n")
+{
+       const char *xpath = "./match-condition[condition='ipv4-next-hop-type']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-next-hop-type",
+                xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd,
+       "no match ip next-hop type [<blackhole>]",
+       NO_STR MATCH_STR IP_STR
+       "Match next-hop address of route\n"
+       "Match entries by type\n"
+       "Blackhole\n")
+{
+       const char *xpath = "./match-condition[condition='ipv4-next-hop-type']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       match_ipv6_address, match_ipv6_address_cmd,
+       "match ipv6 address WORD$name",
+       MATCH_STR
+       IPV6_STR
+       "Match IPv6 address of route\n"
+       "IPv6 access-list name\n")
+{
+       const char *xpath = "./match-condition[condition='ipv6-address-list']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_match_ipv6_address, no_match_ipv6_address_cmd,
+       "no match ipv6 address [WORD]",
+       NO_STR
+       MATCH_STR
+       IPV6_STR
+       "Match IPv6 address of route\n"
+       "IPv6 access-list name\n")
+{
+       const char *xpath = "./match-condition[condition='ipv6-address-list']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd,
+       "match ipv6 address prefix-list WORD$name",
+       MATCH_STR
+       IPV6_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+       const char *xpath = "./match-condition[condition='ipv6-prefix-list']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_match_ipv6_address_prefix_list,
+       no_match_ipv6_address_prefix_list_cmd,
+       "no match ipv6 address prefix-list [WORD]",
+       NO_STR
+       MATCH_STR
+       IPV6_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+       const char *xpath = "./match-condition[condition='ipv6-prefix-list']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd,
+       "match ipv6 next-hop type <blackhole>$type",
+       MATCH_STR IPV6_STR
+       "Match next-hop address of route\n"
+       "Match entries by type\n"
+       "Blackhole\n")
+{
+       const char *xpath = "./match-condition[condition='ipv6-next-hop-type']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-next-hop-type",
+                xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd,
+       "no match ipv6 next-hop type [<blackhole>]",
+       NO_STR MATCH_STR IPV6_STR
+       "Match address of route\n"
+       "Match entries by type\n"
+       "Blackhole\n")
+{
+       const char *xpath = "./match-condition[condition='ipv6-next-hop-type']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       match_metric, match_metric_cmd,
+       "match metric (0-4294967295)$metric",
+       MATCH_STR
+       "Match metric of route\n"
+       "Metric value\n")
+{
+       const char *xpath = "./match-condition[condition='metric']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value), "%s/metric", xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, metric_str);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_match_metric, no_match_metric_cmd,
+       "no match metric [(0-4294967295)]",
+       NO_STR
+       MATCH_STR
+       "Match metric of route\n"
+       "Metric value\n")
+{
+       const char *xpath = "./match-condition[condition='metric']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       match_tag, match_tag_cmd,
+       "match tag (1-4294967295)$tag",
+       MATCH_STR
+       "Match tag of route\n"
+       "Tag value\n")
+{
+       const char *xpath = "./match-condition[condition='tag']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_match_tag, no_match_tag_cmd,
+       "no match tag [(1-4294967295)]",
+       NO_STR
+       MATCH_STR
+       "Match tag of route\n"
+       "Tag value\n")
+{
+       const char *xpath = "./match-condition[condition='tag']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
+                             bool show_defaults)
+{
+       int condition = yang_dnode_get_enum(dnode, "./condition");
+       struct lyd_node *ln;
+       const char *acl;
+
+       switch (condition) {
+       case 0: /* interface */
+               vty_out(vty, " match interface %s\n",
+                       yang_dnode_get_string(dnode, "./interface"));
+               break;
+       case 1: /* ipv4-address-list */
+       case 3: /* ipv4-next-hop-list */
+               acl = NULL;
+               if ((ln = yang_dnode_get(dnode, "./list-name")) != NULL)
+                       acl = yang_dnode_get_string(ln, NULL);
+               else if ((ln = yang_dnode_get(dnode, "./access-list-num"))
+                        != NULL)
+                       acl = yang_dnode_get_string(ln, NULL);
+               else if ((ln = yang_dnode_get(dnode,
+                                             "./access-list-num-extended"))
+                        != NULL)
+                       acl = yang_dnode_get_string(ln, NULL);
+
+               assert(acl);
+
+               switch (condition) {
+               case 1:
+                       vty_out(vty, " match ip address %s\n", acl);
+                       break;
+               case 3:
+                       vty_out(vty, " match ip next-hop %s\n", acl);
+                       break;
+               }
+               break;
+       case 2: /* ipv4-prefix-list */
+               vty_out(vty, " match ip address prefix-list %s\n",
+                       yang_dnode_get_string(dnode, "./list-name"));
+               break;
+       case 4: /* ipv4-next-hop-prefix-list */
+               vty_out(vty, " match ip next-hop prefix-list %s\n",
+                       yang_dnode_get_string(dnode, "./list-name"));
+               break;
+       case 5: /* ipv4-next-hop-type */
+               vty_out(vty, " match ip next-hop type %s\n",
+                       yang_dnode_get_string(dnode, "./ipv4-next-hop-type"));
+               break;
+       case 6: /* ipv6-address-list */
+               vty_out(vty, " match ipv6 address %s\n",
+                       yang_dnode_get_string(dnode, "./list-name"));
+               break;
+       case 7: /* ipv6-prefix-list */
+               vty_out(vty, " match ipv6 address prefix-list %s\n",
+                       yang_dnode_get_string(dnode, "./list-name"));
+               break;
+       case 8: /* ipv6-next-hop-type */
+               vty_out(vty, " match ipv6 next-hop type %s\n",
+                       yang_dnode_get_string(dnode, "./ipv6-next-hop-type"));
+               break;
+       case 9: /* metric */
+               vty_out(vty, " match metric %s\n",
+                       yang_dnode_get_string(dnode, "./metric"));
+               break;
+       case 10: /* tag */
+               vty_out(vty, " match tag %s\n",
+                       yang_dnode_get_string(dnode, "./tag"));
+               break;
+       case 100:
+               /* NOTHING: custom field, should be handled by daemon. */
+               break;
+       }
+}
+
+DEFPY(
+       set_ip_nexthop, set_ip_nexthop_cmd,
+       "set ip next-hop A.B.C.D$addr",
+       SET_STR
+       IP_STR
+       "Next hop address\n"
+       "IP address of next hop\n")
+{
+       const char *xpath = "./set-action[action='ipv4-next-hop']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-address", xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_set_ip_nexthop, no_set_ip_nexthop_cmd,
+       "no set ip next-hop [A.B.C.D]",
+       NO_STR
+       SET_STR
+       IP_STR
+       "Next hop address\n"
+       "IP address of next hop\n")
+{
+       const char *xpath = "./set-action[action='ipv4-next-hop']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       set_ipv6_nexthop_local, set_ipv6_nexthop_local_cmd,
+       "set ipv6 next-hop local X:X::X:X$addr",
+       SET_STR
+       IPV6_STR
+       "IPv6 next-hop address\n"
+       "IPv6 local address\n"
+       "IPv6 address of next hop\n")
+{
+       const char *xpath = "./set-action[action='ipv6-next-hop']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-address", xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_cmd,
+       "no set ipv6 next-hop local [X:X::X:X]",
+       NO_STR
+       SET_STR
+       IPV6_STR
+       "IPv6 next-hop address\n"
+       "IPv6 local address\n"
+       "IPv6 address of next hop\n")
+{
+       const char *xpath = "./set-action[action='ipv6-next-hop']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       set_metric, set_metric_cmd,
+       "set metric <(0-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|+metric$ametric|-metric$smetric>",
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n"
+       "Assign round trip time\n"
+       "Add round trip time\n"
+       "Subtract round trip time\n"
+       "Add metric\n"
+       "Subtract metric\n")
+{
+       const char *xpath = "./set-action[action='metric']";
+       char xpath_value[XPATH_MAXLEN];
+       char value[64];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       if (rtt) {
+               snprintf(xpath_value, sizeof(xpath_value),
+                        "%s/use-round-trip-time", xpath);
+               snprintf(value, sizeof(value), "true");
+       } else if (artt) {
+               snprintf(xpath_value, sizeof(xpath_value),
+                        "%s/add-round-trip-time", xpath);
+               snprintf(value, sizeof(value), "true");
+       } else if (srtt) {
+               snprintf(xpath_value, sizeof(xpath_value),
+                        "%s/subtract-round-trip-time", xpath);
+               snprintf(value, sizeof(value), "true");
+       } else if (ametric) {
+               snprintf(xpath_value, sizeof(xpath_value), "%s/add-metric",
+                        xpath);
+               snprintf(value, sizeof(value), "true");
+       } else if (smetric) {
+               snprintf(xpath_value, sizeof(xpath_value), "%s/subtract-metric",
+                        xpath);
+               snprintf(value, sizeof(value), "true");
+       } else {
+               snprintf(xpath_value, sizeof(xpath_value), "%s/value", xpath);
+               snprintf(value, sizeof(value), "%lu", metric);
+       }
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_set_metric, no_set_metric_cmd,
+       "no set metric [(0-4294967295)]",
+       NO_STR
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n")
+{
+       const char *xpath = "./set-action[action='metric']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       set_tag, set_tag_cmd,
+       "set tag (1-4294967295)$tag",
+       SET_STR
+       "Tag value for routing protocol\n"
+       "Tag value\n")
+{
+       const char *xpath = "./set-action[action='tag']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_set_tag, no_set_tag_cmd,
+       "no set tag [(1-4294967295)]",
+       NO_STR
+       SET_STR
+       "Tag value for routing protocol\n"
+       "Tag value\n")
+{
+       const char *xpath = "./set-action[action='tag']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
+                          bool show_defaults)
+{
+       int action = yang_dnode_get_enum(dnode, "./action");
+
+       switch (action) {
+       case 0: /* ipv4-next-hop */
+               vty_out(vty, " set ip next-hop %s\n",
+                       yang_dnode_get_string(dnode, "./ipv4-address"));
+               break;
+       case 1: /* ipv6-next-hop */
+               vty_out(vty, " set ipv6 next-hop local %s\n",
+                       yang_dnode_get_string(dnode, "./ipv6-address"));
+               break;
+       case 2: /* metric */
+               if (yang_dnode_get(dnode, "./use-round-trip-time")) {
+                       vty_out(vty, " set metric rtt\n");
+               } else if (yang_dnode_get(dnode, "./add-round-trip-time")) {
+                       vty_out(vty, " set metric +rtt\n");
+               } else if (yang_dnode_get(dnode, "./subtract-round-trip-time")) {
+                       vty_out(vty, " set metric -rtt\n");
+               } else if (yang_dnode_get(dnode, "./add-metric")) {
+                       vty_out(vty, " set metric +metric\n");
+               } else if (yang_dnode_get(dnode, "./subtract-metric")) {
+                       vty_out(vty, " set metric -metric\n");
+               } else {
+                       vty_out(vty, " set metric %s\n",
+                               yang_dnode_get_string(dnode, "./value"));
+               }
+               break;
+       case 3: /* tag */
+               vty_out(vty, " set tag %s\n",
+                       yang_dnode_get_string(dnode, "./tag"));
+               break;
+       case 100:
+               /* NOTHING: custom field, should be handled by daemon. */
+               break;
+       }
+}
+
+DEFPY(
+       rmap_onmatch_next, rmap_onmatch_next_cmd,
+       "on-match next",
+       "Exit policy on matches\n"
+       "Next clause\n")
+{
+       nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "next");
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_rmap_onmatch_next,
+       no_rmap_onmatch_next_cmd,
+       "no on-match next",
+       NO_STR
+       "Exit policy on matches\n"
+       "Next clause\n")
+{
+       nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       rmap_onmatch_goto, rmap_onmatch_goto_cmd,
+       "on-match goto (1-65535)$rm_num",
+       "Exit policy on matches\n"
+       "Goto Clause number\n"
+       "Number\n")
+{
+       nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "goto");
+       nb_cli_enqueue_change(vty, "./goto-value", NB_OP_MODIFY, rm_num_str);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_rmap_onmatch_goto, no_rmap_onmatch_goto_cmd,
+       "no on-match goto",
+       NO_STR
+       "Exit policy on matches\n"
+       "Goto Clause number\n")
+{
+       nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+/* Cisco/GNU Zebra compatibility aliases */
+ALIAS(
+       rmap_onmatch_goto, rmap_continue_cmd,
+       "continue (1-65535)$rm_num",
+       "Continue on a different entry within the route-map\n"
+       "Route-map entry sequence number\n")
+
+ALIAS(
+       no_rmap_onmatch_goto, no_rmap_continue_cmd,
+       "no continue [(1-65535)]",
+       NO_STR
+       "Continue on a different entry within the route-map\n"
+       "Route-map entry sequence number\n")
+
+void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode,
+                               bool show_defaults)
+{
+       int exit_policy = yang_dnode_get_enum(dnode, NULL);
+
+       switch (exit_policy) {
+       case 0: /* permit-or-deny */
+               /* NOTHING: default option. */
+               break;
+       case 1: /* next */
+               vty_out(vty, " on-match next\n");
+               break;
+       case 2: /* goto */
+               vty_out(vty, " on-match goto %s\n",
+                       yang_dnode_get_string(dnode, "../goto-value"));
+               break;
+       }
+}
+
+DEFPY(
+       rmap_call, rmap_call_cmd,
+       "call WORD$name",
+       "Jump to another Route-Map after match+set\n"
+       "Target route-map name\n")
+{
+       nb_cli_enqueue_change(vty, "./call", NB_OP_MODIFY, name);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(
+       no_rmap_call, no_rmap_call_cmd,
+       "no call",
+       NO_STR
+       "Jump to another Route-Map after match+set\n")
+{
+       nb_cli_enqueue_change(vty, "./call", NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_call_show(struct vty *vty, struct lyd_node *dnode,
+                        bool show_defaults)
+{
+       vty_out(vty, " call %s\n", yang_dnode_get_string(dnode, NULL));
+}
+
+DEFPY(
+       rmap_description, rmap_description_cmd,
+       "description LINE...",
+       "Route-map comment\n"
+       "Comment describing this route-map rule\n")
+{
+       char *desc;
+       int rv;
+
+       desc = argv_concat(argv, argc, 1);
+       nb_cli_enqueue_change(vty, "./description", NB_OP_MODIFY, desc);
+       rv = nb_cli_apply_changes(vty, NULL);
+       XFREE(MTYPE_TMP, desc);
+
+       return rv;
+}
+
+DEFUN (no_rmap_description,
+       no_rmap_description_cmd,
+       "no description",
+       NO_STR
+       "Route-map comment\n")
+{
+       nb_cli_enqueue_change(vty, "./description", NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void route_map_description_show(struct vty *vty, struct lyd_node *dnode,
+                               bool show_defaults)
+{
+       vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL));
+}
+
+static int route_map_config_write(struct vty *vty)
+{
+       struct lyd_node *dnode;
+       int written = 0;
+
+       dnode = yang_dnode_get(running_config->dnode,
+                              "/frr-route-map:lib");
+       if (dnode) {
+               nb_cli_show_dnode_cmds(vty, dnode, false);
+               written = 1;
+       }
+
+       return written;
+}
+
+/* Route map node structure. */
+static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1};
+
+static void rmap_autocomplete(vector comps, struct cmd_token *token)
+{
+       struct route_map *map;
+
+       for (map = route_map_master.head; map; map = map->next)
+               vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
+}
+
+static const struct cmd_variable_handler rmap_var_handlers[] = {
+       {.varname = "route_map", .completions = rmap_autocomplete},
+       {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete},
+       {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete},
+       {.completions = NULL}
+};
+
+void route_map_cli_init(void)
+{
+       /* Auto complete handler. */
+       cmd_variable_handler_register(rmap_var_handlers);
+
+       /* CLI commands. */
+       install_node(&rmap_node, route_map_config_write);
+       install_default(RMAP_NODE);
+       install_element(CONFIG_NODE, &route_map_cmd);
+       install_element(CONFIG_NODE, &no_route_map_cmd);
+       install_element(CONFIG_NODE, &no_route_map_all_cmd);
+
+       /* Install the on-match stuff */
+       install_element(RMAP_NODE, &route_map_cmd);
+       install_element(RMAP_NODE, &rmap_onmatch_next_cmd);
+       install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd);
+       install_element(RMAP_NODE, &rmap_onmatch_goto_cmd);
+       install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd);
+       install_element(RMAP_NODE, &rmap_continue_cmd);
+       install_element(RMAP_NODE, &no_rmap_continue_cmd);
+
+       /* Install the call stuff. */
+       install_element(RMAP_NODE, &rmap_call_cmd);
+       install_element(RMAP_NODE, &no_rmap_call_cmd);
+
+       /* Install description commands. */
+       install_element(RMAP_NODE, &rmap_description_cmd);
+       install_element(RMAP_NODE, &no_rmap_description_cmd);
+
+       /* Install 'match' commands. */
+       install_element(RMAP_NODE, &match_interface_cmd);
+       install_element(RMAP_NODE, &no_match_interface_cmd);
+
+       install_element(RMAP_NODE, &match_ip_address_cmd);
+       install_element(RMAP_NODE, &no_match_ip_address_cmd);
+
+       install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd);
+       install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
+
+       install_element(RMAP_NODE, &match_ip_next_hop_cmd);
+       install_element(RMAP_NODE, &no_match_ip_next_hop_cmd);
+
+       install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
+       install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+
+       install_element(RMAP_NODE, &match_ip_next_hop_type_cmd);
+       install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd);
+
+       install_element(RMAP_NODE, &match_ipv6_address_cmd);
+       install_element(RMAP_NODE, &no_match_ipv6_address_cmd);
+
+       install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
+       install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
+
+       install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd);
+       install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd);
+
+       install_element(RMAP_NODE, &match_metric_cmd);
+       install_element(RMAP_NODE, &no_match_metric_cmd);
+
+       install_element(RMAP_NODE, &match_tag_cmd);
+       install_element(RMAP_NODE, &no_match_tag_cmd);
+
+       /* Install 'set' commands. */
+       install_element(RMAP_NODE, &set_ip_nexthop_cmd);
+       install_element(RMAP_NODE, &no_set_ip_nexthop_cmd);
+
+       install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd);
+       install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
+
+       install_element(RMAP_NODE, &set_metric_cmd);
+       install_element(RMAP_NODE, &no_set_metric_cmd);
+
+       install_element(RMAP_NODE, &set_tag_cmd);
+       install_element(RMAP_NODE, &no_set_tag_cmd);
+}
diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c
new file mode 100644 (file)
index 0000000..68b112b
--- /dev/null
@@ -0,0 +1,1446 @@
+/*
+ * Route map northbound implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ *                    Rafael Zalamena
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/command.h"
+#include "lib/log.h"
+#include "lib/northbound.h"
+#include "lib/routemap.h"
+
+/*
+ * Auxiliary functions to avoid code duplication:
+ *
+ * lib_route_map_entry_set_destroy: unset `set` commands.
+ * lib_route_map_entry_match_destroy: unset `match` commands.
+ */
+int lib_route_map_entry_match_destroy(enum nb_event event,
+                                     const struct lyd_node *dnode)
+{
+       struct routemap_hook_context *rhc;
+       int rv;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       rhc = nb_running_get_entry(dnode, NULL, true);
+       if (rhc->rhc_mhook == NULL)
+               return NB_OK;
+
+       rv = rhc->rhc_mhook(NULL, rhc->rhc_rmi, rhc->rhc_rule, NULL,
+                           rhc->rhc_event);
+       if (rv != CMD_SUCCESS)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
+
+int lib_route_map_entry_set_destroy(enum nb_event event,
+                                   const struct lyd_node *dnode)
+{
+       struct routemap_hook_context *rhc;
+       int rv;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       rhc = nb_running_get_entry(dnode, NULL, true);
+       if (rhc->rhc_shook == NULL)
+               return NB_OK;
+
+       rv = rhc->rhc_shook(NULL, rhc->rhc_rmi, rhc->rhc_rule, NULL);
+       if (rv != CMD_SUCCESS)
+               return NB_ERR_INCONSISTENCY;
+
+       return NB_OK;
+}
+
+/*
+ * Auxiliary hook context list manipulation functions.
+ */
+struct routemap_hook_context *
+routemap_hook_context_insert(struct route_map_index *rmi)
+{
+       struct routemap_hook_context *rhc;
+
+       rhc = XCALLOC(MTYPE_TMP, sizeof(*rhc));
+       rhc->rhc_rmi = rmi;
+       TAILQ_INSERT_TAIL(&rmi->rhclist, rhc, rhc_entry);
+
+       return rhc;
+}
+
+void
+routemap_hook_context_free(struct routemap_hook_context *rhc)
+{
+       struct route_map_index *rmi = rhc->rhc_rmi;
+
+       TAILQ_REMOVE(&rmi->rhclist, rhc, rhc_entry);
+       XFREE(MTYPE_TMP, rhc);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map
+ */
+static int lib_route_map_create(enum nb_event event,
+                               const struct lyd_node *dnode,
+                               union nb_resource *resource)
+{
+       struct route_map *rm;
+       const char *rm_name;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               /* NOTHING */
+               break;
+       case NB_EV_APPLY:
+               rm_name = yang_dnode_get_string(dnode, "./name");
+               rm = route_map_get(rm_name);
+               nb_running_set_entry(dnode, rm);
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int lib_route_map_destroy(enum nb_event event,
+                                const struct lyd_node *dnode)
+{
+       struct route_map *rm;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               /* NOTHING */
+               break;
+       case NB_EV_APPLY:
+               rm = nb_running_unset_entry(dnode);
+               route_map_delete(rm);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry
+ */
+static int lib_route_map_entry_create(enum nb_event event,
+                                     const struct lyd_node *dnode,
+                                     union nb_resource *resource)
+{
+       struct route_map_index *rmi;
+       struct route_map *rm;
+       uint16_t sequence;
+       int action;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               /* NOTHING */
+               break;
+       case NB_EV_APPLY:
+               sequence = yang_dnode_get_uint16(dnode, "./sequence");
+               action = yang_dnode_get_enum(dnode, "./action") == 0
+                                ? RMAP_PERMIT
+                                : RMAP_DENY;
+               rm = nb_running_get_entry(dnode, NULL, true);
+               rmi = route_map_index_get(rm, action, sequence);
+               nb_running_set_entry(dnode, rmi);
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int lib_route_map_entry_destroy(enum nb_event event,
+                                      const struct lyd_node *dnode)
+{
+       struct route_map_index *rmi;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               /* NOTHING */
+               break;
+       case NB_EV_APPLY:
+               rmi = nb_running_unset_entry(dnode);
+               route_map_index_delete(rmi, 1);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/description
+ */
+static int lib_route_map_entry_description_modify(enum nb_event event,
+                                                 const struct lyd_node *dnode,
+                                                 union nb_resource *resource)
+{
+       struct route_map_index *rmi;
+       const char *description;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+               /* NOTHING */
+               break;
+       case NB_EV_PREPARE:
+               description = yang_dnode_get_string(dnode, NULL);
+               resource->ptr = XSTRDUP(MTYPE_TMP, description);
+               if (resource->ptr == NULL)
+                       return NB_ERR_RESOURCE;
+               break;
+       case NB_EV_ABORT:
+               XFREE(MTYPE_TMP, resource->ptr);
+               break;
+       case NB_EV_APPLY:
+               rmi = nb_running_get_entry(dnode, NULL, true);
+               if (rmi->description != NULL)
+                       XFREE(MTYPE_TMP, rmi->description);
+               rmi->description = resource->ptr;
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int lib_route_map_entry_description_destroy(enum nb_event event,
+                                                  const struct lyd_node *dnode)
+{
+       struct route_map_index *rmi;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               /* NOTHING */
+               break;
+       case NB_EV_APPLY:
+               rmi = nb_running_get_entry(dnode, NULL, true);
+               if (rmi->description != NULL)
+                       XFREE(MTYPE_TMP, rmi->description);
+               rmi->description = NULL;
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/action
+ */
+static int lib_route_map_entry_action_modify(enum nb_event event,
+                                            const struct lyd_node *dnode,
+                                            union nb_resource *resource)
+{
+       struct route_map_index *rmi;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               /* NOTHING */
+               break;
+       case NB_EV_APPLY:
+               rmi = nb_running_get_entry(dnode, NULL, true);
+               rmi->type = yang_dnode_get_enum(dnode, NULL);
+               /* TODO: notify? */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/call
+ */
+static int lib_route_map_entry_call_modify(enum nb_event event,
+                                          const struct lyd_node *dnode,
+                                          union nb_resource *resource)
+{
+       struct route_map_index *rmi;
+       const char *rm_name, *rmn_name;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+               rm_name = yang_dnode_get_string(dnode, "../../name");
+               rmn_name = yang_dnode_get_string(dnode, NULL);
+               /* Don't allow to jump to the same route map instance. */
+               if (strcmp(rm_name, rmn_name) == 0)
+                       return NB_ERR_VALIDATION;
+
+               /* TODO: detect circular route map sequences. */
+               break;
+       case NB_EV_PREPARE:
+               rmn_name = yang_dnode_get_string(dnode, NULL);
+               resource->ptr = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmn_name);
+               break;
+       case NB_EV_ABORT:
+               XFREE(MTYPE_ROUTE_MAP_NAME, resource->ptr);
+               break;
+       case NB_EV_APPLY:
+               rmi = nb_running_get_entry(dnode, NULL, true);
+               if (rmi->nextrm) {
+                       route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
+                                                 rmi->nextrm, rmi->map->name);
+                       XFREE(MTYPE_ROUTE_MAP_NAME, rmi->nextrm);
+               }
+               rmi->nextrm = resource->ptr;
+               route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, rmi->nextrm,
+                                         rmi->map->name);
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int lib_route_map_entry_call_destroy(enum nb_event event,
+                                           const struct lyd_node *dnode)
+{
+       struct route_map_index *rmi;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               /* NOTHING */
+               break;
+       case NB_EV_APPLY:
+               rmi = nb_running_get_entry(dnode, NULL, true);
+               route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED, rmi->nextrm,
+                                         rmi->map->name);
+               XFREE(MTYPE_ROUTE_MAP_NAME, rmi->nextrm);
+               rmi->nextrm = NULL;
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/exit-policy
+ */
+static int lib_route_map_entry_exit_policy_modify(enum nb_event event,
+                                                 const struct lyd_node *dnode,
+                                                 union nb_resource *resource)
+{
+       struct route_map_index *rmi;
+       int rm_action;
+       int policy;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+               policy = yang_dnode_get_enum(dnode, NULL);
+               switch (policy) {
+               case 0: /* permit-or-deny */
+                       break;
+               case 1: /* next */
+                       /* FALLTHROUGH */
+               case 2: /* goto */
+                       rm_action = yang_dnode_get_enum(dnode, "../action");
+                       if (rm_action == 1 /* deny */) {
+                               /*
+                                * On deny it is not possible to 'goto'
+                                * anywhere.
+                                */
+                               return NB_ERR_VALIDATION;
+                       }
+                       break;
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               rmi = nb_running_get_entry(dnode, NULL, true);
+               policy = yang_dnode_get_enum(dnode, NULL);
+
+               switch (policy) {
+               case 0: /* permit-or-deny */
+                       rmi->exitpolicy = RMAP_EXIT;
+                       break;
+               case 1: /* next */
+                       rmi->exitpolicy = RMAP_NEXT;
+                       break;
+               case 2: /* goto */
+                       rmi->exitpolicy = RMAP_GOTO;
+                       break;
+               }
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/goto-value
+ */
+static int lib_route_map_entry_goto_value_modify(enum nb_event event,
+                                                const struct lyd_node *dnode,
+                                                union nb_resource *resource)
+{
+       struct route_map_index *rmi;
+       uint16_t rmi_index;
+       uint16_t rmi_next;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+               rmi_index = yang_dnode_get_uint16(dnode, "../sequence");
+               rmi_next = yang_dnode_get_uint16(dnode, NULL);
+               if (rmi_next <= rmi_index) {
+                       /* Can't jump backwards on a route map. */
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               /* NOTHING */
+               break;
+       case NB_EV_APPLY:
+               rmi = nb_running_get_entry(dnode, NULL, true);
+               rmi->nextpref = yang_dnode_get_uint16(dnode, NULL);
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int lib_route_map_entry_goto_value_destroy(enum nb_event event,
+                                                 const struct lyd_node *dnode)
+{
+       struct route_map_index *rmi;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               /* NOTHING */
+               break;
+       case NB_EV_APPLY:
+               rmi = nb_running_get_entry(dnode, NULL, true);
+               rmi->nextpref = 0;
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition
+ */
+static int
+lib_route_map_entry_match_condition_create(enum nb_event event,
+                                          const struct lyd_node *dnode,
+                                          union nb_resource *resource)
+{
+       struct routemap_hook_context *rhc;
+       struct route_map_index *rmi;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               /* NOTHING */
+               break;
+       case NB_EV_APPLY:
+               rmi = nb_running_get_entry(dnode, NULL, true);
+               rhc = routemap_hook_context_insert(rmi);
+               nb_running_set_entry(dnode, rhc);
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int
+lib_route_map_entry_match_condition_destroy(enum nb_event event,
+                                           const struct lyd_node *dnode)
+{
+       struct routemap_hook_context *rhc;
+       int rv;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       rv = lib_route_map_entry_match_destroy(event, dnode);
+       rhc = nb_running_unset_entry(dnode);
+       routemap_hook_context_free(rhc);
+
+       return rv;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/interface
+ */
+static int lib_route_map_entry_match_condition_interface_modify(
+       enum nb_event event, const struct lyd_node *dnode,
+       union nb_resource *resource)
+{
+       struct routemap_hook_context *rhc;
+       const char *ifname;
+       int rv;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       /* Check for hook function. */
+       if (rmap_match_set_hook.match_interface == NULL)
+               return NB_OK;
+
+       /* Add configuration. */
+       rhc = nb_running_get_entry(dnode, NULL, true);
+       ifname = yang_dnode_get_string(dnode, NULL);
+
+       /* Set destroy information. */
+       rhc->rhc_mhook = rmap_match_set_hook.no_match_interface;
+       rhc->rhc_rule = "interface";
+       rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+       rv = rmap_match_set_hook.match_interface(NULL, rhc->rhc_rmi,
+                                                "interface", ifname,
+                                                RMAP_EVENT_MATCH_ADDED);
+       if (rv != CMD_SUCCESS) {
+               rhc->rhc_mhook = NULL;
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_interface_destroy(
+       enum nb_event event, const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/access-list-num
+ */
+static int lib_route_map_entry_match_condition_access_list_num_modify(
+       enum nb_event event, const struct lyd_node *dnode,
+       union nb_resource *resource)
+{
+       struct routemap_hook_context *rhc;
+       const char *acl;
+       int condition, rv;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       /* Check for hook function. */
+       rv = CMD_SUCCESS;
+       acl = yang_dnode_get_string(dnode, NULL);
+       rhc = nb_running_get_entry(dnode, NULL, true);
+       condition = yang_dnode_get_enum(dnode, "../condition");
+       switch (condition) {
+       case 1: /* ipv4-address-list */
+               if (rmap_match_set_hook.match_ip_address == NULL)
+                       break;
+               rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address;
+               rhc->rhc_rule = "ip address";
+               rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
+               rv = rmap_match_set_hook.match_ip_address(
+                       NULL, rhc->rhc_rmi, "ip address", acl,
+                       RMAP_EVENT_FILTER_ADDED);
+               break;
+       case 3: /* ipv4-next-hop-list */
+               if (rmap_match_set_hook.match_ip_next_hop == NULL)
+                       break;
+               rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop;
+               rhc->rhc_rule = "ip next-hop";
+               rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
+               rv = rmap_match_set_hook.match_ip_next_hop(
+                       NULL, rhc->rhc_rmi, "ip next-hop", acl,
+                       RMAP_EVENT_FILTER_ADDED);
+               break;
+       }
+       if (rv != CMD_SUCCESS) {
+               rhc->rhc_mhook = NULL;
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_access_list_num_destroy(
+       enum nb_event event, const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/match-condition/access-list-num-extended
+ */
+static int lib_route_map_entry_match_condition_access_list_num_extended_modify(
+       enum nb_event event, const struct lyd_node *dnode,
+       union nb_resource *resource)
+{
+       return lib_route_map_entry_match_condition_access_list_num_modify(
+               event, dnode, resource);
+}
+
+static int lib_route_map_entry_match_condition_access_list_num_extended_destroy(
+       enum nb_event event, const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_match_condition_access_list_num_destroy(
+               event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/list-name
+ */
+static int lib_route_map_entry_match_condition_list_name_modify(
+       enum nb_event event, const struct lyd_node *dnode,
+       union nb_resource *resource)
+{
+       struct routemap_hook_context *rhc;
+       const char *acl;
+       int condition;
+       int rv;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       /* Check for hook installation, otherwise we can just stop. */
+       acl = yang_dnode_get_string(dnode, NULL);
+       rhc = nb_running_get_entry(dnode, NULL, true);
+       condition = yang_dnode_get_enum(dnode, "../condition");
+       switch (condition) {
+       case 1: /* ipv4-address-list */
+               if (rmap_match_set_hook.match_ip_address == NULL)
+                       return NB_OK;
+               rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address;
+               rhc->rhc_rule = "ip address";
+               rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
+               rv = rmap_match_set_hook.match_ip_address(
+                       NULL, rhc->rhc_rmi, "ip address", acl,
+                       RMAP_EVENT_FILTER_ADDED);
+               break;
+       case 2: /* ipv4-prefix-list */
+               if (rmap_match_set_hook.match_ip_address_prefix_list == NULL)
+                       return NB_OK;
+               rhc->rhc_mhook =
+                       rmap_match_set_hook.no_match_ip_address_prefix_list;
+               rhc->rhc_rule = "ip address prefix-list";
+               rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
+               rv = rmap_match_set_hook.match_ip_address_prefix_list(
+                       NULL, rhc->rhc_rmi, "ip address prefix-list", acl,
+                       RMAP_EVENT_PLIST_ADDED);
+               break;
+       case 3: /* ipv4-next-hop-list */
+               if (rmap_match_set_hook.match_ip_next_hop == NULL)
+                       return NB_OK;
+               rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop;
+               rhc->rhc_rule = "ip next-hop";
+               rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
+               rv = rmap_match_set_hook.match_ip_next_hop(
+                       NULL, rhc->rhc_rmi, "ip next-hop", acl,
+                       RMAP_EVENT_FILTER_ADDED);
+               break;
+       case 4: /* ipv4-next-hop-prefix-list */
+               if (rmap_match_set_hook.match_ip_next_hop_prefix_list == NULL)
+                       return NB_OK;
+               rhc->rhc_mhook =
+                       rmap_match_set_hook.no_match_ip_next_hop_prefix_list;
+               rhc->rhc_rule = "ip next-hop prefix-list";
+               rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
+               rv = rmap_match_set_hook.match_ip_next_hop_prefix_list(
+                       NULL, rhc->rhc_rmi, "ip next-hop prefix-list", acl,
+                       RMAP_EVENT_PLIST_ADDED);
+               break;
+       case 6: /* ipv6-address-list */
+               if (rmap_match_set_hook.match_ipv6_address == NULL)
+                       return NB_OK;
+               rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_address;
+               rhc->rhc_rule = "ipv6 address";
+               rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
+               rv = rmap_match_set_hook.match_ipv6_address(
+                       NULL, rhc->rhc_rmi, "ipv6 address", acl,
+                       RMAP_EVENT_FILTER_ADDED);
+               break;
+       case 7: /* ipv6-prefix-list */
+               if (rmap_match_set_hook.match_ipv6_address_prefix_list == NULL)
+                       return NB_OK;
+               rhc->rhc_mhook =
+                       rmap_match_set_hook.no_match_ipv6_address_prefix_list;
+               rhc->rhc_rule = "ipv6 address prefix-list";
+               rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
+               rv = rmap_match_set_hook.match_ipv6_address_prefix_list(
+                       NULL, rhc->rhc_rmi, "ipv6 address prefix-list", acl,
+                       RMAP_EVENT_PLIST_ADDED);
+               break;
+       default:
+               rv = CMD_ERR_NO_MATCH;
+               break;
+       }
+       if (rv != CMD_SUCCESS) {
+               rhc->rhc_mhook = NULL;
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_list_name_destroy(
+       enum nb_event event, const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type
+ */
+static int lib_route_map_entry_match_condition_ipv4_next_hop_type_modify(
+       enum nb_event event, const struct lyd_node *dnode,
+       union nb_resource *resource)
+{
+       struct routemap_hook_context *rhc;
+       const char *type;
+       int rv;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       /* Check for hook function. */
+       if (rmap_match_set_hook.match_ip_next_hop_type == NULL)
+               return NB_OK;
+
+       /* Add configuration. */
+       rhc = nb_running_get_entry(dnode, NULL, true);
+       type = yang_dnode_get_string(dnode, NULL);
+
+       /* Set destroy information. */
+       rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop_type;
+       rhc->rhc_rule = "ip next-hop type";
+       rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+       rv = rmap_match_set_hook.match_ip_next_hop_type(
+               NULL, rhc->rhc_rmi, "ip next-hop type", type,
+               RMAP_EVENT_MATCH_ADDED);
+       if (rv != CMD_SUCCESS) {
+               rhc->rhc_mhook = NULL;
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy(
+       enum nb_event event, const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type
+ */
+static int lib_route_map_entry_match_condition_ipv6_next_hop_type_modify(
+       enum nb_event event, const struct lyd_node *dnode,
+       union nb_resource *resource)
+{
+       struct routemap_hook_context *rhc;
+       const char *type;
+       int rv;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       /* Check for hook function. */
+       if (rmap_match_set_hook.match_ipv6_next_hop_type == NULL)
+               return NB_OK;
+
+       /* Add configuration. */
+       rhc = nb_running_get_entry(dnode, NULL, true);
+       type = yang_dnode_get_string(dnode, NULL);
+
+       /* Set destroy information. */
+       rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_next_hop_type;
+       rhc->rhc_rule = "ipv6 next-hop type";
+       rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+       rv = rmap_match_set_hook.match_ipv6_next_hop_type(
+               NULL, rhc->rhc_rmi, "ipv6 next-hop type", type,
+               RMAP_EVENT_MATCH_ADDED);
+       if (rv != CMD_SUCCESS) {
+               rhc->rhc_mhook = NULL;
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static int lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy(
+       enum nb_event event, const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/metric
+ */
+static int
+lib_route_map_entry_match_condition_metric_modify(enum nb_event event,
+                                                 const struct lyd_node *dnode,
+                                                 union nb_resource *resource)
+{
+       struct routemap_hook_context *rhc;
+       const char *type;
+       int rv;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       /* Check for hook function. */
+       if (rmap_match_set_hook.match_metric == NULL)
+               return NB_OK;
+
+       /* Add configuration. */
+       rhc = nb_running_get_entry(dnode, NULL, true);
+       type = yang_dnode_get_string(dnode, NULL);
+
+       /* Set destroy information. */
+       rhc->rhc_mhook = rmap_match_set_hook.no_match_metric;
+       rhc->rhc_rule = "metric";
+       rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+       rv = rmap_match_set_hook.match_metric(NULL, rhc->rhc_rmi, "metric",
+                                             type, RMAP_EVENT_MATCH_ADDED);
+       if (rv != CMD_SUCCESS) {
+               rhc->rhc_mhook = NULL;
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static int
+lib_route_map_entry_match_condition_metric_destroy(enum nb_event event,
+                                                  const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/tag
+ */
+static int
+lib_route_map_entry_match_condition_tag_modify(enum nb_event event,
+                                              const struct lyd_node *dnode,
+                                              union nb_resource *resource)
+{
+       struct routemap_hook_context *rhc;
+       const char *tag;
+       int rv;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       /* Check for hook function. */
+       if (rmap_match_set_hook.match_tag == NULL)
+               return NB_OK;
+
+       /* Add configuration. */
+       rhc = nb_running_get_entry(dnode, NULL, true);
+       tag = yang_dnode_get_string(dnode, NULL);
+
+       /* Set destroy information. */
+       rhc->rhc_mhook = rmap_match_set_hook.no_match_tag;
+       rhc->rhc_rule = "tag";
+       rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+       rv = rmap_match_set_hook.match_tag(NULL, rhc->rhc_rmi, "tag", tag,
+                                          RMAP_EVENT_MATCH_ADDED);
+       if (rv != CMD_SUCCESS) {
+               rhc->rhc_mhook = NULL;
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static int
+lib_route_map_entry_match_condition_tag_destroy(enum nb_event event,
+                                               const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_match_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action
+ */
+static int lib_route_map_entry_set_action_create(enum nb_event event,
+                                                const struct lyd_node *dnode,
+                                                union nb_resource *resource)
+{
+       return lib_route_map_entry_match_condition_create(event, dnode,
+                                                         resource);
+}
+
+static int lib_route_map_entry_set_action_destroy(enum nb_event event,
+                                                 const struct lyd_node *dnode)
+{
+       struct routemap_hook_context *rhc;
+       int rv;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       rv = lib_route_map_entry_set_destroy(event, dnode);
+       rhc = nb_running_unset_entry(dnode);
+       routemap_hook_context_free(rhc);
+
+       return rv;
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv4-address
+ */
+static int
+lib_route_map_entry_set_action_ipv4_address_modify(enum nb_event event,
+                                                  const struct lyd_node *dnode,
+                                                  union nb_resource *resource)
+{
+       struct routemap_hook_context *rhc;
+       const char *address;
+       struct in_addr ia;
+       int rv;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+               /*
+                * NOTE: validate if 'action' is 'ipv4-next-hop',
+                * currently it is not necessary because this is the
+                * only implemented action.
+                */
+               yang_dnode_get_ipv4(&ia, dnode, NULL);
+               if (ia.s_addr == INADDR_ANY || IPV4_CLASS_DE(ntohl(ia.s_addr)))
+                       return NB_ERR_VALIDATION;
+               /* FALLTHROUGH */
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               break;
+       }
+
+       /* Check for hook function. */
+       if (rmap_match_set_hook.set_ip_nexthop == NULL)
+               return NB_OK;
+
+       /* Add configuration. */
+       rhc = nb_running_get_entry(dnode, NULL, true);
+       address = yang_dnode_get_string(dnode, NULL);
+
+       /* Set destroy information. */
+       rhc->rhc_shook = rmap_match_set_hook.no_set_ip_nexthop;
+       rhc->rhc_rule = "ip next-hop";
+
+       rv = rmap_match_set_hook.set_ip_nexthop(NULL, rhc->rhc_rmi,
+                                               "ip next-hop", address);
+       if (rv != CMD_SUCCESS) {
+               rhc->rhc_shook = NULL;
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static int lib_route_map_entry_set_action_ipv4_address_destroy(
+       enum nb_event event, const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_set_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv6-address
+ */
+static int
+lib_route_map_entry_set_action_ipv6_address_modify(enum nb_event event,
+                                                  const struct lyd_node *dnode,
+                                                  union nb_resource *resource)
+{
+       struct routemap_hook_context *rhc;
+       const char *address;
+       struct in6_addr i6a;
+       int rv;
+
+       switch (event) {
+       case NB_EV_VALIDATE:
+               /*
+                * NOTE: validate if 'action' is 'ipv6-next-hop',
+                * currently it is not necessary because this is the
+                * only implemented action. Other actions might have
+                * different validations.
+                */
+               yang_dnode_get_ipv6(&i6a, dnode, NULL);
+               if (!IN6_IS_ADDR_LINKLOCAL(&i6a))
+                       return NB_ERR_VALIDATION;
+               /* FALLTHROUGH */
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               return NB_OK;
+       case NB_EV_APPLY:
+               break;
+       }
+
+       /* Check for hook function. */
+       if (rmap_match_set_hook.set_ipv6_nexthop_local == NULL)
+               return NB_OK;
+
+       /* Add configuration. */
+       rhc = nb_running_get_entry(dnode, NULL, true);
+       address = yang_dnode_get_string(dnode, NULL);
+
+       /* Set destroy information. */
+       rhc->rhc_shook = rmap_match_set_hook.no_set_ipv6_nexthop_local;
+       rhc->rhc_rule = "ipv6 next-hop local";
+
+       rv = rmap_match_set_hook.set_ipv6_nexthop_local(
+               NULL, rhc->rhc_rmi, "ipv6 next-hop local", address);
+       if (rv != CMD_SUCCESS) {
+               rhc->rhc_shook = NULL;
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static int lib_route_map_entry_set_action_ipv6_address_destroy(
+       enum nb_event event, const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_set_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/value
+ */
+static int set_action_modify(enum nb_event event, const struct lyd_node *dnode,
+                            union nb_resource *resource, const char *value)
+{
+       struct routemap_hook_context *rhc;
+       int rv;
+
+       /*
+        * NOTE: validate if 'action' is 'metric', currently it is not
+        * necessary because this is the only implemented action. Other
+        * actions might have different validations.
+        */
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       /* Check for hook function. */
+       if (rmap_match_set_hook.set_metric == NULL)
+               return NB_OK;
+
+       /* Add configuration. */
+       rhc = nb_running_get_entry(dnode, NULL, true);
+
+       /* Set destroy information. */
+       rhc->rhc_shook = rmap_match_set_hook.no_set_metric;
+       rhc->rhc_rule = "metric";
+
+       rv = rmap_match_set_hook.set_metric(NULL, rhc->rhc_rmi, "metric",
+                                           value);
+       if (rv != CMD_SUCCESS) {
+               rhc->rhc_shook = NULL;
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static int
+lib_route_map_entry_set_action_value_modify(enum nb_event event,
+                                           const struct lyd_node *dnode,
+                                           union nb_resource *resource)
+{
+       const char *metric = yang_dnode_get_string(dnode, NULL);
+
+       return set_action_modify(event, dnode, resource, metric);
+}
+
+static int
+lib_route_map_entry_set_action_value_destroy(enum nb_event event,
+                                            const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_set_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/add-metric
+ */
+static int
+lib_route_map_entry_set_action_add_metric_modify(enum nb_event event,
+                                                const struct lyd_node *dnode,
+                                                union nb_resource *resource)
+{
+       return set_action_modify(event, dnode, resource, "+metric");
+}
+
+static int
+lib_route_map_entry_set_action_add_metric_destroy(enum nb_event event,
+                                                 const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_set_action_value_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-metric
+ */
+static int lib_route_map_entry_set_action_subtract_metric_modify(
+       enum nb_event event, const struct lyd_node *dnode,
+       union nb_resource *resource)
+{
+       return set_action_modify(event, dnode, resource, "-metric");
+}
+
+static int lib_route_map_entry_set_action_subtract_metric_destroy(
+       enum nb_event event, const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_set_action_value_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/use-round-trip-time
+ */
+static int lib_route_map_entry_set_action_use_round_trip_time_modify(
+       enum nb_event event, const struct lyd_node *dnode,
+       union nb_resource *resource)
+{
+       return set_action_modify(event, dnode, resource, "rtt");
+}
+
+static int lib_route_map_entry_set_action_use_round_trip_time_destroy(
+       enum nb_event event, const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_set_action_value_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/add-round-trip-time
+ */
+static int lib_route_map_entry_set_action_add_round_trip_time_modify(
+       enum nb_event event, const struct lyd_node *dnode,
+       union nb_resource *resource)
+{
+       return set_action_modify(event, dnode, resource, "+rtt");
+}
+
+static int lib_route_map_entry_set_action_add_round_trip_time_destroy(
+       enum nb_event event, const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_set_action_value_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time
+ */
+static int lib_route_map_entry_set_action_subtract_round_trip_time_modify(
+       enum nb_event event, const struct lyd_node *dnode,
+       union nb_resource *resource)
+{
+       return set_action_modify(event, dnode, resource, "-rtt");
+}
+
+static int lib_route_map_entry_set_action_subtract_round_trip_time_destroy(
+       enum nb_event event, const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_set_action_value_destroy(event, dnode);
+}
+
+/*
+ * XPath: /frr-route-map:lib/route-map/entry/set-action/tag
+ */
+static int
+lib_route_map_entry_set_action_tag_modify(enum nb_event event,
+                                         const struct lyd_node *dnode,
+                                         union nb_resource *resource)
+{
+       struct routemap_hook_context *rhc;
+       const char *tag;
+       int rv;
+
+       /*
+        * NOTE: validate if 'action' is 'tag', currently it is not
+        * necessary because this is the only implemented action. Other
+        * actions might have different validations.
+        */
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       /* Check for hook function. */
+       if (rmap_match_set_hook.set_tag == NULL)
+               return NB_OK;
+
+       /* Add configuration. */
+       rhc = nb_running_get_entry(dnode, NULL, true);
+       tag = yang_dnode_get_string(dnode, NULL);
+
+       /* Set destroy information. */
+       rhc->rhc_shook = rmap_match_set_hook.no_set_tag;
+       rhc->rhc_rule = "tag";
+
+       rv = rmap_match_set_hook.set_tag(NULL, rhc->rhc_rmi, "tag", tag);
+       if (rv != CMD_SUCCESS) {
+               rhc->rhc_shook = NULL;
+               return NB_ERR_INCONSISTENCY;
+       }
+
+       return NB_OK;
+}
+
+static int
+lib_route_map_entry_set_action_tag_destroy(enum nb_event event,
+                                          const struct lyd_node *dnode)
+{
+       return lib_route_map_entry_set_destroy(event, dnode);
+}
+
+/* clang-format off */
+#if defined(__GNUC__) && ((__GNUC__ - 0) < 5) && !defined(__clang__)
+/*
+ * gcc versions before 5.x miscalculate the size for structs with variable
+ * length arrays (they just count it as size 0)
+ */
+struct frr_yang_module_info_sizen {
+       /* YANG module name. */
+       const char *name;
+
+       /* Northbound callbacks. */
+       const struct {
+               /* Data path of this YANG node. */
+               const char *xpath;
+
+               /* Callbacks implemented for this node. */
+               struct nb_callbacks cbs;
+
+               /* Priority - lower priorities are processed first. */
+               uint32_t priority;
+       } nodes[28];
+};
+
+const struct frr_yang_module_info_sizen frr_route_map_info_sizen asm("frr_route_map_info") = {
+#else
+const struct frr_yang_module_info frr_route_map_info = {
+#endif
+       .name = "frr-route-map",
+       .nodes = {
+               {
+                       .xpath = "/frr-route-map:lib/route-map",
+                       .cbs = {
+                               .create = lib_route_map_create,
+                               .destroy = lib_route_map_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry",
+                       .cbs = {
+                               .create = lib_route_map_entry_create,
+                               .destroy = lib_route_map_entry_destroy,
+                               .cli_show = route_map_instance_show,
+                               .cli_show_end = route_map_instance_show_end,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/description",
+                       .cbs = {
+                               .modify = lib_route_map_entry_description_modify,
+                               .destroy = lib_route_map_entry_description_destroy,
+                               .cli_show = route_map_description_show,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/action",
+                       .cbs = {
+                               .modify = lib_route_map_entry_action_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/call",
+                       .cbs = {
+                               .modify = lib_route_map_entry_call_modify,
+                               .destroy = lib_route_map_entry_call_destroy,
+                               .cli_show = route_map_call_show,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/exit-policy",
+                       .cbs = {
+                               .modify = lib_route_map_entry_exit_policy_modify,
+                               .cli_show = route_map_exit_policy_show,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/goto-value",
+                       .cbs = {
+                               .modify = lib_route_map_entry_goto_value_modify,
+                               .destroy = lib_route_map_entry_goto_value_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/match-condition",
+                       .cbs = {
+                               .create = lib_route_map_entry_match_condition_create,
+                               .destroy = lib_route_map_entry_match_condition_destroy,
+                               .cli_show = route_map_condition_show,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/match-condition/interface",
+                       .cbs = {
+                               .modify = lib_route_map_entry_match_condition_interface_modify,
+                               .destroy = lib_route_map_entry_match_condition_interface_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/match-condition/access-list-num",
+                       .cbs = {
+                               .modify = lib_route_map_entry_match_condition_access_list_num_modify,
+                               .destroy = lib_route_map_entry_match_condition_access_list_num_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/match-condition/access-list-num-extended",
+                       .cbs = {
+                               .modify = lib_route_map_entry_match_condition_access_list_num_extended_modify,
+                               .destroy = lib_route_map_entry_match_condition_access_list_num_extended_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/match-condition/list-name",
+                       .cbs = {
+                               .modify = lib_route_map_entry_match_condition_list_name_modify,
+                               .destroy = lib_route_map_entry_match_condition_list_name_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type",
+                       .cbs = {
+                               .modify = lib_route_map_entry_match_condition_ipv4_next_hop_type_modify,
+                               .destroy = lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type",
+                       .cbs = {
+                               .modify = lib_route_map_entry_match_condition_ipv6_next_hop_type_modify,
+                               .destroy = lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/match-condition/metric",
+                       .cbs = {
+                               .modify = lib_route_map_entry_match_condition_metric_modify,
+                               .destroy = lib_route_map_entry_match_condition_metric_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/match-condition/tag",
+                       .cbs = {
+                               .modify = lib_route_map_entry_match_condition_tag_modify,
+                               .destroy = lib_route_map_entry_match_condition_tag_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action",
+                       .cbs = {
+                               .create = lib_route_map_entry_set_action_create,
+                               .destroy = lib_route_map_entry_set_action_destroy,
+                               .cli_show = route_map_action_show,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action/ipv4-address",
+                       .cbs = {
+                               .modify = lib_route_map_entry_set_action_ipv4_address_modify,
+                               .destroy = lib_route_map_entry_set_action_ipv4_address_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action/ipv6-address",
+                       .cbs = {
+                               .modify = lib_route_map_entry_set_action_ipv6_address_modify,
+                               .destroy = lib_route_map_entry_set_action_ipv6_address_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action/value",
+                       .cbs = {
+                               .modify = lib_route_map_entry_set_action_value_modify,
+                               .destroy = lib_route_map_entry_set_action_value_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action/add-metric",
+                       .cbs = {
+                               .modify = lib_route_map_entry_set_action_add_metric_modify,
+                               .destroy = lib_route_map_entry_set_action_add_metric_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action/subtract-metric",
+                       .cbs = {
+                               .modify = lib_route_map_entry_set_action_subtract_metric_modify,
+                               .destroy = lib_route_map_entry_set_action_subtract_metric_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action/use-round-trip-time",
+                       .cbs = {
+                               .modify = lib_route_map_entry_set_action_use_round_trip_time_modify,
+                               .destroy = lib_route_map_entry_set_action_use_round_trip_time_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action/add-round-trip-time",
+                       .cbs = {
+                               .modify = lib_route_map_entry_set_action_add_round_trip_time_modify,
+                               .destroy = lib_route_map_entry_set_action_add_round_trip_time_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time",
+                       .cbs = {
+                               .modify = lib_route_map_entry_set_action_subtract_round_trip_time_modify,
+                               .destroy = lib_route_map_entry_set_action_subtract_round_trip_time_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action/tag",
+                       .cbs = {
+                               .modify = lib_route_map_entry_set_action_tag_modify,
+                               .destroy = lib_route_map_entry_set_action_tag_destroy,
+                       }
+               },
+               {
+                       .xpath = NULL,
+               },
+       }
+};
diff --git a/lib/srv6.c b/lib/srv6.c
new file mode 100644 (file)
index 0000000..be340f1
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * SRv6 definitions
+ * Copyright (C) 2020  Hiroki Shirokura, LINE Corporation
+ *
+ * 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
+ */
+
+#include "srv6.h"
+#include "log.h"
+
+const char *seg6local_action2str(uint32_t action)
+{
+       switch (action) {
+       case ZEBRA_SEG6_LOCAL_ACTION_END:
+               return "End";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_X:
+               return "End.X";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_T:
+               return "End.T";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DX2:
+               return "End.DX2";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
+               return "End.DX6";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
+               return "End.DX4";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
+               return "End.DT6";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
+               return "End.DT4";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_B6:
+               return "End.B6";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP:
+               return "End.B6.Encap";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_BM:
+               return "End.BM";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_S:
+               return "End.S";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_AS:
+               return "End.AS";
+       case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
+               return "End.AM";
+       case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC:
+               return "unspec";
+       default:
+               return "unknown";
+       }
+}
+
+int snprintf_seg6_segs(char *str,
+               size_t size, const struct seg6_segs *segs)
+{
+       str[0] = '\0';
+       for (size_t i = 0; i < segs->num_segs; i++) {
+               char addr[INET6_ADDRSTRLEN];
+               bool not_last = (i + 1) < segs->num_segs;
+
+               inet_ntop(AF_INET6, &segs->segs[i], addr, sizeof(addr));
+               strlcat(str, addr, size);
+               strlcat(str, not_last ? "," : "", size);
+       }
+       return strlen(str);
+}
+
+const char *seg6local_context2str(char *str, size_t size,
+               struct seg6local_context *ctx, uint32_t action)
+{
+       char b0[128];
+
+       switch (action) {
+
+       case ZEBRA_SEG6_LOCAL_ACTION_END:
+               snprintf(str, size, "USP");
+               return str;
+
+       case ZEBRA_SEG6_LOCAL_ACTION_END_X:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
+               inet_ntop(AF_INET6, &ctx->nh6, b0, 128);
+               snprintf(str, size, "nh6 %s", b0);
+               return str;
+
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
+               inet_ntop(AF_INET, &ctx->nh4, b0, 128);
+               snprintf(str, size, "nh4 %s", b0);
+               return str;
+
+       case ZEBRA_SEG6_LOCAL_ACTION_END_T:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
+               snprintf(str, size, "table %u", ctx->table);
+               return str;
+
+       case ZEBRA_SEG6_LOCAL_ACTION_END_DX2:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_B6:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_BM:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_S:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_AS:
+       case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
+       case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC:
+       default:
+               snprintf(str, size, "unknown(%s)", __func__);
+               return str;
+       }
+}
diff --git a/lib/srv6.h b/lib/srv6.h
new file mode 100644 (file)
index 0000000..24c7ffc
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * SRv6 definitions
+ * Copyright (C) 2020  Hiroki Shirokura, LINE Corporation
+ *
+ * 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
+ */
+
+#ifndef _FRR_SRV6_H
+#define _FRR_SRV6_H
+
+#include <zebra.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#define SRV6_MAX_SIDS 16
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define sid2str(sid, str, size) \
+       inet_ntop(AF_INET6, sid, str, size)
+
+enum seg6_mode_t {
+       INLINE,
+       ENCAP,
+       L2ENCAP,
+};
+
+enum seg6local_action_t {
+       ZEBRA_SEG6_LOCAL_ACTION_UNSPEC       = 0,
+       ZEBRA_SEG6_LOCAL_ACTION_END          = 1,
+       ZEBRA_SEG6_LOCAL_ACTION_END_X        = 2,
+       ZEBRA_SEG6_LOCAL_ACTION_END_T        = 3,
+       ZEBRA_SEG6_LOCAL_ACTION_END_DX2      = 4,
+       ZEBRA_SEG6_LOCAL_ACTION_END_DX6      = 5,
+       ZEBRA_SEG6_LOCAL_ACTION_END_DX4      = 6,
+       ZEBRA_SEG6_LOCAL_ACTION_END_DT6      = 7,
+       ZEBRA_SEG6_LOCAL_ACTION_END_DT4      = 8,
+       ZEBRA_SEG6_LOCAL_ACTION_END_B6       = 9,
+       ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP = 10,
+       ZEBRA_SEG6_LOCAL_ACTION_END_BM       = 11,
+       ZEBRA_SEG6_LOCAL_ACTION_END_S        = 12,
+       ZEBRA_SEG6_LOCAL_ACTION_END_AS       = 13,
+       ZEBRA_SEG6_LOCAL_ACTION_END_AM       = 14,
+       ZEBRA_SEG6_LOCAL_ACTION_END_BPF      = 15,
+};
+
+struct seg6_segs {
+       size_t num_segs;
+       struct in6_addr segs[256];
+};
+
+struct seg6local_context {
+       struct in_addr nh4;
+       struct in6_addr nh6;
+       uint32_t table;
+};
+
+static inline const char *seg6_mode2str(enum seg6_mode_t mode)
+{
+       switch (mode) {
+       case INLINE:
+               return "INLINE";
+       case ENCAP:
+               return "ENCAP";
+       case L2ENCAP:
+               return "L2ENCAP";
+       default:
+               return "unknown";
+       }
+}
+
+static inline bool sid_same(
+               const struct in6_addr *a,
+               const struct in6_addr *b)
+{
+       if (!a && !b)
+               return true;
+       else if (!(a && b))
+               return false;
+       else
+               return memcmp(a, b, sizeof(struct in6_addr)) == 0;
+}
+
+static inline bool sid_diff(
+               const struct in6_addr *a,
+               const struct in6_addr *b)
+{
+       return !sid_same(a, b);
+}
+
+static inline bool sid_zero(
+               const struct in6_addr *a)
+{
+       struct in6_addr zero = {};
+
+       return sid_same(a, &zero);
+}
+
+static inline void *sid_copy(struct in6_addr *dst,
+               const struct in6_addr *src)
+{
+       return memcpy(dst, src, sizeof(struct in6_addr));
+}
+
+const char *
+seg6local_action2str(uint32_t action);
+
+const char *
+seg6local_context2str(char *str, size_t size,
+               struct seg6local_context *ctx, uint32_t action);
+
+int snprintf_seg6_segs(char *str,
+               size_t size, const struct seg6_segs *segs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index cb6fa7a3b81c050098c8adb2d29e0deba7f1b265..4f62eb22641390fbc9a16c184ba41000d02ffbf9 100644 (file)
@@ -51,6 +51,7 @@ lib_libfrr_la_SOURCES = \
        lib/mlag.c \
        lib/module.c \
        lib/mpls.c \
+       lib/srv6.c \
        lib/network.c \
        lib/nexthop.c \
        lib/netns_linux.c \
@@ -70,6 +71,8 @@ lib_libfrr_la_SOURCES = \
        lib/qobj.c \
        lib/ringbuf.c \
        lib/routemap.c \
+       lib/routemap_cli.c \
+       lib/routemap_northbound.c \
        lib/sbuf.c \
        lib/seqlock.c \
        lib/sha256.c \
@@ -103,7 +106,9 @@ lib_libfrr_la_SOURCES = \
        # end
 
 nodist_lib_libfrr_la_SOURCES = \
+       yang/frr-filter.yang.c \
        yang/frr-interface.yang.c \
+       yang/frr-route-map.yang.c \
        yang/frr-route-types.yang.c \
        yang/ietf/ietf-routing-types.yang.c \
        yang/frr-module-translator.yang.c \
@@ -119,6 +124,7 @@ vtysh_scan += \
        $(top_srcdir)/lib/nexthop_group.c \
        $(top_srcdir)/lib/plist.c \
        $(top_srcdir)/lib/routemap.c \
+       $(top_srcdir)/lib/routemap_cli.c \
        $(top_srcdir)/lib/vrf.c \
        $(top_srcdir)/lib/vty.c \
        # end
@@ -138,6 +144,8 @@ lib/nexthop_group_clippy.c: $(CLIPPY_DEPS)
 lib/nexthop_group.lo: lib/nexthop_group_clippy.c
 lib/northbound_cli_clippy.c: $(CLIPPY_DEPS)
 lib/northbound_cli.lo: lib/northbound_cli_clippy.c
+lib/routemap_cli_clippy.c: $(CLIPPY_DEPS)
+lib/routemap_cli.lo: lib/routemap_cli_clippy.c
 lib/vty_clippy.c: $(CLIPPY_DEPS)
 lib/vty.lo: lib/vty_clippy.c
 lib/log_vty_clippy.c: $(CLIPPY_DEPS)
@@ -193,6 +201,7 @@ pkginclude_HEADERS += \
        lib/module.h \
        lib/monotime.h \
        lib/mpls.h \
+       lib/srv6.h \
        lib/network.h \
        lib/nexthop.h \
        lib/nexthop_group.h \
index 40da8abcd74b575a63fe13a2b40fc0b59a9d0dde..cf161338520471264518bd749644c6515da745fb 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -3011,15 +3011,8 @@ void vty_reset(void)
 
        vty_timeout_val = VTY_TIMEOUT_DEFAULT;
 
-       if (vty_accesslist_name) {
-               XFREE(MTYPE_VTY, vty_accesslist_name);
-               vty_accesslist_name = NULL;
-       }
-
-       if (vty_ipv6_accesslist_name) {
-               XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
-               vty_ipv6_accesslist_name = NULL;
-       }
+       XFREE(MTYPE_VTY, vty_accesslist_name);
+       XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
 }
 
 static void vty_save_cwd(void)
index b2c74cd0b90875201a155cd9fa019e9947e1ebc8..d879063460569a5f4f4f46af545e8e7da2790526 100644 (file)
@@ -3299,3 +3299,72 @@ void zclient_interface_set_master(struct zclient *client,
        stream_putw_at(s, 0, stream_get_endp(s));
        zclient_send_message(client);
 }
+
+/*
+ * Send capabilities message to zebra
+ */
+int32_t 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;
+       }
+
+       /* Put length at the first point of the stream */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zclient_send_message(zclient);
+}
+
+/*
+ * Process capabilities message from zebra
+ */
+int32_t 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;
+       }
+stream_failure:
+       return 0;
+}
index d1aa42da6d2ae078a5c16c255c17f017308c2330..9a230d3f3491b286ee03b1582c1f825bb84419f3 100644 (file)
@@ -73,6 +73,18 @@ typedef uint16_t zebra_size_t;
 #define ZEBRA_FEC_REGISTER_LABEL          0x1
 #define ZEBRA_FEC_REGISTER_LABEL_INDEX    0x2
 
+/* Client capabilities */
+enum zserv_client_capabilities {
+       ZEBRA_CLIENT_GR_CAPABILITIES = 1,
+       ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE = 2,
+       ZEBRA_CLIENT_ROUTE_UPDATE_PENDING = 3,
+       ZEBRA_CLIENT_GR_DISABLE = 4,
+       ZEBRA_CLIENT_RIB_STALE_TIME
+};
+
+/* Macro to check if there GR enabled. */
+#define ZEBRA_CLIENT_GR_ENABLED(X) (X == ZEBRA_CLIENT_GR_CAPABILITIES)
+
 extern struct sockaddr_storage zclient_addr;
 extern socklen_t zclient_addr_len;
 
@@ -184,10 +196,11 @@ typedef enum {
        ZEBRA_MLAG_CLIENT_UNREGISTER,
        ZEBRA_MLAG_FORWARD_MSG,
        ZEBRA_ERROR,
+       ZEBRA_CLIENT_CAPABILITIES
 } zebra_message_types_t;
 
 enum zebra_error_types {
-       ZEBRA_UNKNOWN_ERROR,    /* Error of unknown type */
+       ZEBRA_UNKNOWN_ERROR,    /* Error of unknown type */
        ZEBRA_NO_VRF,           /* Vrf in header was not found */
        ZEBRA_INVALID_MSG_TYPE, /* No handler found for msg type */
 };
@@ -222,6 +235,15 @@ struct zclient_capabilities {
        enum mlag_role role;
 };
 
+/* Graceful Restart Capabilities message */
+struct zapi_cap {
+       enum zserv_client_capabilities 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 */
@@ -759,6 +781,11 @@ extern bool zapi_nexthop_update_decode(struct stream *s,
 /* Decode the zebra error message */
 extern bool zapi_error_decode(struct stream *s, enum zebra_error_types *error);
 
+/* Encode and decode restart capabilities */
+extern int32_t zclient_capabilities_send(uint32_t cmd, struct zclient *zclient,
+                                        struct zapi_cap *api);
+extern int32_t zapi_capabilities_decode(struct stream *s, struct zapi_cap *api);
+
 static inline void zapi_route_set_blackhole(struct zapi_route *api,
                                            enum blackhole_type bh_type)
 {
index 9f828a1c7d832a3f58760fc154ee35f57324b3b7..7cf8dfbde42fde3f8b803f7e89f55e6fffc52025 100644 (file)
@@ -135,7 +135,7 @@ static void nhrp_interface_update_nbma(struct interface *ifp)
                                     &nifp->linkidx, &saddr);
                debugf(NHRP_DEBUG_IF, "%s: GRE: %x %x %x", ifp->name,
                       nifp->grekey, nifp->linkidx, saddr.s_addr);
-               if (saddr.s_addr)
+               if (saddr.s_addr != INADDR_ANY)
                        sockunion_set(&nbma, AF_INET, (uint8_t *)&saddr.s_addr,
                                      sizeof(saddr.s_addr));
                else if (!nbmaifp && nifp->linkidx != IFINDEX_INTERNAL)
index cfca86a9bf7897f60e527be99304c931f77deb20..a23ac347454e9b0d7f741aa01aab5e946c760bdf 100644 (file)
@@ -58,7 +58,6 @@ static void nhrp_route_update_put(struct route_node *rn)
        if (!ri->ifp && !ri->nhrp_ifp
            && sockunion_family(&ri->via) == AF_UNSPEC) {
                XFREE(MTYPE_NHRP_ROUTE, rn->info);
-               rn->info = NULL;
                route_unlock_node(rn);
        }
        route_unlock_node(rn);
index 84053b4b5d68ee8c31551297c5a322f50292376f..b3fdecf0ec8c21303c1c459f45837c6e4b95cc59 100644 (file)
@@ -141,7 +141,6 @@ static void nhrp_shortcut_delete(struct nhrp_shortcut *s)
        rn = route_node_lookup(shortcut_rib[afi], s->p);
        if (rn) {
                XFREE(MTYPE_NHRP_SHORTCUT, rn->info);
-               rn->info = NULL;
                route_unlock_node(rn);
                route_unlock_node(rn);
        }
index 0aaefeb3c26a0c4c9d28d899e2651a787782538e..e4bed7a79d0a7251fa427f26b9341bc4ab1116f5 100644 (file)
@@ -167,6 +167,7 @@ struct quagga_signal_t ospf6_signals[] = {
 
 static const struct frr_yang_module_info *const ospf6d_yang_modules[] = {
        &frr_interface_info,
+       &frr_route_map_info,
 };
 
 FRR_DAEMON_INFO(ospf6d, OSPF6, .vty_port = OSPF6_VTY_PORT,
index da42a242522c068a46202e7bf32641e60fe9889e..d75fc39bbbb5970bd70390187f2b212b518517fa 100644 (file)
@@ -1516,15 +1516,8 @@ int ospf6_iobuf_size(unsigned int size)
 
 void ospf6_message_terminate(void)
 {
-       if (recvbuf) {
-               XFREE(MTYPE_OSPF6_MESSAGE, recvbuf);
-               recvbuf = NULL;
-       }
-
-       if (sendbuf) {
-               XFREE(MTYPE_OSPF6_MESSAGE, sendbuf);
-               sendbuf = NULL;
-       }
+       XFREE(MTYPE_OSPF6_MESSAGE, recvbuf);
+       XFREE(MTYPE_OSPF6_MESSAGE, sendbuf);
 
        iobuflen = 0;
 }
index 50485cc7e25c334de1a40787e945d3809c8b13c0..da390e3c704ed806da56afaf989297530e5ade12 100644 (file)
@@ -451,7 +451,7 @@ int ospf_apiclient_lsa_originate(struct ospf_apiclient *oclient,
 
        tmp = SET_OPAQUE_LSID(opaque_type, opaque_id);
        lsah->id.s_addr = htonl(tmp);
-       lsah->adv_router.s_addr = 0;
+       lsah->adv_router.s_addr = INADDR_ANY;
        lsah->ls_seqnum = 0;
        lsah->checksum = 0;
        lsah->length = htons(sizeof(struct lsa_header) + opaquelen);
index c8b8b611efcbd9fdc06ac55af6223e2f50336920..b4690cfa424a39cec334789264922ec668df5691 100644 (file)
@@ -310,7 +310,7 @@ int ospf_area_range_substitute_unset(struct ospf *ospf, struct in_addr area_id,
                        ospf_schedule_abr_task(ospf);
 
        UNSET_FLAG(range->flags, OSPF_AREA_RANGE_SUBSTITUTE);
-       range->subst_addr.s_addr = 0;
+       range->subst_addr.s_addr = INADDR_ANY;
        range->subst_masklen = 0;
 
        return 1;
index a60af36564f6974ff5c9bb756ab398f069f0e439..6d00935347d60eaca8a5770369679795ffeb44b7 100644 (file)
@@ -141,7 +141,6 @@ ospf_external_info_add(struct ospf *ospf, uint8_t type, unsigned short instance,
                                        ospf->vrf_id, inet_ntoa(p.prefix),
                                        p.prefixlen, inetbuf);
                        XFREE(MTYPE_OSPF_EXTERNAL_INFO, rn->info);
-                       rn->info = NULL;
                }
 
        /* Create new External info instance. */
index 44244f651edcb58dac796e7847c2cd77bfab73f3..2c80d485a3fe6f44881907b8822e497ea36f86b8 100644 (file)
@@ -370,7 +370,7 @@ int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa)
               external-LSA.  This indicates the IP address to which
               packets for the destination should be forwarded. */
 
-       if (al->e[0].fwd_addr.s_addr == 0) {
+       if (al->e[0].fwd_addr.s_addr == INADDR_ANY) {
                /* If the forwarding address is set to 0.0.0.0, packets should
                   be sent to the ASBR itself. Among the multiple routing table
                   entries for the ASBR, select the preferred entry as follows.
@@ -470,7 +470,7 @@ int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa)
 
                ospf_route_add(ospf->new_external_route, &p, new, asbr_route);
 
-               if (al->e[0].fwd_addr.s_addr)
+               if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
                        ospf_ase_complete_direct_routes(new, al->e[0].fwd_addr);
                return 0;
        } else {
@@ -512,7 +512,7 @@ int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa)
                                zlog_debug(
                                        "Route[External]: New route is better");
                        ospf_route_subst(rn, new, asbr_route);
-                       if (al->e[0].fwd_addr.s_addr)
+                       if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
                                ospf_ase_complete_direct_routes(
                                        new, al->e[0].fwd_addr);
                        or = new;
@@ -530,7 +530,7 @@ int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa)
                        if (IS_DEBUG_OSPF(lsa, LSA))
                                zlog_debug("Route[External]: Routes are equal");
                        ospf_route_copy_nexthops(or, asbr_route->paths);
-                       if (al->e[0].fwd_addr.s_addr)
+                       if (al->e[0].fwd_addr.s_addr != INADDR_ANY)
                                ospf_ase_complete_direct_routes(
                                        or, al->e[0].fwd_addr);
                }
index 8efb32af37ad61e44b8416f185c7e3edcc53574f..f2efaf322f6bf13770549fec5b895c3bb9fe34af 100644 (file)
@@ -694,7 +694,6 @@ static int ospf_if_delete_hook(struct interface *ifp)
 
        ospf_del_if_params((struct ospf_if_params *)IF_DEF_PARAMS(ifp));
        XFREE(MTYPE_OSPF_IF_INFO, ifp->info);
-       ifp->info = NULL;
 
        return rc;
 }
@@ -863,7 +862,7 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf,
 
        p = prefix_ipv4_new();
        p->family = AF_INET;
-       p->prefix.s_addr = 0;
+       p->prefix.s_addr = INADDR_ANY;
        p->prefixlen = 0;
 
        co->address = (struct prefix *)p;
@@ -886,7 +885,7 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf,
        if (IS_DEBUG_OSPF_EVENT)
                zlog_debug("ospf_vl_new(): set if->name to %s", vi->name);
 
-       area_id.s_addr = 0;
+       area_id.s_addr = INADDR_ANY;
        area = ospf_area_get(ospf, area_id);
        voi->area = area;
 
@@ -908,7 +907,7 @@ static void ospf_vl_if_delete(struct ospf_vl_data *vl_data)
 {
        struct interface *ifp = vl_data->vl_oi->ifp;
 
-       vl_data->vl_oi->address->u.prefix4.s_addr = 0;
+       vl_data->vl_oi->address->u.prefix4.s_addr = INADDR_ANY;
        vl_data->vl_oi->address->prefixlen = 0;
        ospf_if_free(vl_data->vl_oi);
        if_delete(&ifp);
@@ -972,7 +971,7 @@ static void ospf_vl_shutdown(struct ospf_vl_data *vl_data)
        if ((oi = vl_data->vl_oi) == NULL)
                return;
 
-       oi->address->u.prefix4.s_addr = 0;
+       oi->address->u.prefix4.s_addr = INADDR_ANY;
        oi->address->prefixlen = 0;
 
        UNSET_FLAG(oi->ifp->flags, IFF_UP);
index e394b6f472b4f58f2d4439a46c817a269b9245bb..f4e89da45dd5f167cf27067b7e66737768393e9b 100644 (file)
@@ -169,7 +169,7 @@ static void ospf_dr_eligible_routers(struct route_table *nbrs,
        for (rn = route_top(nbrs); rn; rn = route_next(rn))
                if ((nbr = rn->info) != NULL)
                        /* Ignore 0.0.0.0 node*/
-                       if (nbr->router_id.s_addr != 0)
+                       if (nbr->router_id.s_addr != INADDR_ANY)
                                /* Is neighbor eligible? */
                                if (nbr->priority > 0)
                                        /* Is neighbor upper 2-Way? */
@@ -186,7 +186,7 @@ static void ospf_dr_change(struct ospf *ospf, struct route_table *nbrs)
        for (rn = route_top(nbrs); rn; rn = route_next(rn))
                if ((nbr = rn->info) != NULL)
                        /* Ignore 0.0.0.0 node*/
-                       if (nbr->router_id.s_addr != 0)
+                       if (nbr->router_id.s_addr != INADDR_ANY)
                                /* Is neighbor upper 2-Way? */
                                if (nbr->state >= NSM_TwoWay)
                                        /* Ignore myself. */
index 6eec87c93ea87931096cdc5560df1939cd2c2611..35bbe06cd15d8d9518b3485e7127559c67e87cf4 100644 (file)
@@ -820,7 +820,7 @@ static struct ospf_lsa *ospf_router_lsa_originate(struct ospf_area *area)
        }
 
        /* Sanity check. */
-       if (new->data->adv_router.s_addr == 0) {
+       if (new->data->adv_router.s_addr == INADDR_ANY) {
                if (IS_DEBUG_OSPF_EVENT)
                        zlog_debug("LSA[Type1]: AdvRouter is 0, discard");
                ospf_lsa_discard(new);
@@ -1459,7 +1459,7 @@ struct in_addr ospf_get_ip_from_ifp(struct ospf_interface *oi)
 {
        struct in_addr fwd;
 
-       fwd.s_addr = 0;
+       fwd.s_addr = INADDR_ANY;
 
        if (if_is_operative(oi->ifp))
                return oi->address->u.prefix4;
@@ -1931,7 +1931,7 @@ int is_prefix_default(struct prefix_ipv4 *p)
        struct prefix_ipv4 q;
 
        q.family = AF_INET;
-       q.prefix.s_addr = 0;
+       q.prefix.s_addr = INADDR_ANY;
        q.prefixlen = 0;
 
        return prefix_same((struct prefix *)p, (struct prefix *)&q);
@@ -1979,10 +1979,11 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf,
 
           */
 
-       if (ospf->router_id.s_addr == 0) {
+       if (ospf->router_id.s_addr == INADDR_ANY) {
                if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug("LSA[Type5:%pI4]: deferring AS-external-LSA origination, router ID is zero",
-                                  &ei->p.prefix);
+                       zlog_debug(
+                               "LSA[Type5:%pI4]: deferring AS-external-LSA origination, router ID is zero",
+                               &ei->p.prefix);
                return NULL;
        }
 
@@ -2197,7 +2198,7 @@ void ospf_external_lsa_refresh_default(struct ospf *ospf)
 
        p.family = AF_INET;
        p.prefixlen = 0;
-       p.prefix.s_addr = 0;
+       p.prefix.s_addr = INADDR_ANY;
 
        ei = ospf_default_external_info(ospf);
        lsa = ospf_external_info_find_lsa(ospf, &p);
index d02ffe0448df73ad394fd1e04c67218729d2b850..9cde64bc38b50d4f1dbf1b165a94926f46ee499d 100644 (file)
@@ -40,6 +40,7 @@
 #include "zclient.h"
 #include "vrf.h"
 #include "libfrr.h"
+#include "routemap.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_interface.h"
@@ -126,6 +127,7 @@ struct quagga_signal_t ospf_signals[] = {
 
 static const struct frr_yang_module_info *const ospfd_yang_modules[] = {
        &frr_interface_info,
+       &frr_route_map_info,
 };
 
 FRR_DAEMON_INFO(ospfd, OSPF, .vty_port = OSPF_VTY_PORT,
@@ -141,6 +143,7 @@ FRR_DAEMON_INFO(ospfd, OSPF, .vty_port = OSPF_VTY_PORT,
 int main(int argc, char **argv)
 {
        unsigned short instance = 0;
+       bool created = false;
 
 #ifdef SUPPORT_OSPF_API
        /* OSPF apiserver is disabled by default. */
@@ -217,6 +220,17 @@ int main(int argc, char **argv)
        /* OSPF errors init */
        ospf_error_init();
 
+       /*
+        * Need to initialize the default ospf structure, so the interface mode
+        * commands can be duly processed if they are received before 'router
+        * ospf',  when ospfd is restarted
+        */
+       if (instance && !ospf_get_instance(instance, &created)) {
+               flog_err(EC_OSPF_INIT_FAIL, "OSPF instance init failed: %s",
+                        strerror(errno));
+               exit(1);
+       }
+
        frr_config_fork();
        frr_run(master);
 
index 95fb694925a3d1eb090bafb274563541d241257d..1b47fde215894464b9a209bf9c6073b768f26d43 100644 (file)
@@ -1074,7 +1074,8 @@ static void ospf_hello(struct ip *iph, struct ospf_header *ospfh,
        /* If neighbor itself declares DR and no BDR exists,
           cause event BackupSeen */
        if (IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->d_router))
-               if (hello->bd_router.s_addr == 0 && oi->state == ISM_Waiting)
+               if (hello->bd_router.s_addr == INADDR_ANY
+                   && oi->state == ISM_Waiting)
                        OSPF_ISM_EVENT_SCHEDULE(oi, ISM_BackupSeen);
 
        /* neighbor itself declares BDR. */
@@ -3352,7 +3353,7 @@ static int ospf_make_hello(struct ospf_interface *oi, struct stream *s)
        for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
                if ((nbr = rn->info))
                        if (nbr->router_id.s_addr
-                           != 0) /* Ignore 0.0.0.0 node. */
+                           != INADDR_ANY) /* Ignore 0.0.0.0 node. */
                                if (nbr->state
                                    != NSM_Attempt) /* Ignore Down neighbor. */
                                        if (nbr->state
@@ -3364,17 +3365,17 @@ static int ospf_make_hello(struct ospf_interface *oi, struct stream *s)
                                                        /* Check neighbor is
                                                         * sane? */
                                                        if (nbr->d_router.s_addr
-                                                                   != 0
+                                                                   != INADDR_ANY
                                                            && IPV4_ADDR_SAME(
-                                                                      &nbr->d_router,
-                                                                      &oi->address
-                                                                               ->u
-                                                                               .prefix4)
+                                                                   &nbr->d_router,
+                                                                   &oi->address
+                                                                            ->u
+                                                                            .prefix4)
                                                            && IPV4_ADDR_SAME(
-                                                                      &nbr->bd_router,
-                                                                      &oi->address
-                                                                               ->u
-                                                                               .prefix4))
+                                                                   &nbr->bd_router,
+                                                                   &oi->address
+                                                                            ->u
+                                                                            .prefix4))
                                                                flag = 1;
 
                                                        /* Hello packet overflows interface MTU. */
index 6cabc0c985dcd6ce8907f4a00c41fce5030e1ebb..b6e8338ee704101002787c5c913f870076573cc6 100644 (file)
@@ -603,7 +603,7 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link,
                                        IF_NAME(oi));
 
                        path = ospf_path_new();
-                       path->nexthop.s_addr = 0;
+                       path->nexthop.s_addr = INADDR_ANY;
                        path->ifindex = oi->ifp->ifindex;
                        if (CHECK_FLAG(oi->connected->flags,
                                       ZEBRA_IFA_UNNUMBERED))
@@ -962,7 +962,7 @@ int ospf_add_discard_route(struct ospf *ospf, struct route_table *rt,
 
        new_or = ospf_route_new();
        new_or->type = OSPF_DESTINATION_DISCARD;
-       new_or->id.s_addr = 0;
+       new_or->id.s_addr = INADDR_ANY;
        new_or->cost = 0;
        new_or->u.std.area_id = area->area_id;
        new_or->u.std.external_routing = area->external_routing;
index 1542ef88fb9ad3eeedb8e7dadfc1d360af78151a..fb4082e50994f168ff1b98b72b8836479aa9fae6 100644 (file)
@@ -3551,7 +3551,7 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
                }
 
                /* Show DR information. */
-               if (DR(oi).s_addr == 0) {
+               if (DR(oi).s_addr == INADDR_ANY) {
                        if (!use_json)
                                vty_out(vty,
                                        "  No backup designated router on this network\n");
@@ -4199,7 +4199,7 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty,
                                }
 
                                if (nbr->state == NSM_Attempt
-                                   && nbr->router_id.s_addr == 0)
+                                   && nbr->router_id.s_addr == INADDR_ANY)
                                        strlcpy(neigh_str, "neighbor",
                                                sizeof(neigh_str));
                                else
@@ -4258,7 +4258,7 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty,
                                ospf_nbr_state_message(nbr, msgbuf, 16);
 
                                if (nbr->state == NSM_Attempt
-                                   && nbr->router_id.s_addr == 0)
+                                   && nbr->router_id.s_addr == INADDR_ANY)
                                        vty_out(vty, "%-15s %3d %-15s ", "-",
                                                nbr->priority, msgbuf);
                                else
@@ -4908,7 +4908,8 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty,
                        json_neigh_array = NULL;
                }
 
-               if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == 0)
+               if (nbr->state == NSM_Attempt
+                   && nbr->router_id.s_addr == INADDR_ANY)
                        strlcpy(neigh_str, "noNbrId", sizeof(neigh_str));
                else
                        strlcpy(neigh_str, inet_ntoa(nbr->router_id),
@@ -4926,7 +4927,8 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty,
 
        } else {
                /* Show neighbor ID. */
-               if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == 0)
+               if (nbr->state == NSM_Attempt
+                   && nbr->router_id.s_addr == INADDR_ANY)
                        vty_out(vty, " Neighbor %s,", "-");
                else
                        vty_out(vty, " Neighbor %s,",
index 68d9d3bf8319bd1553be65714d5a85f26706f1db..64013435f657ae12817b37065378fcce2fe628dd 100644 (file)
@@ -585,9 +585,9 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype,
        int cur_originate = ospf->default_originate;
        const char *type_str = NULL;
 
-       nexthop.s_addr = 0;
+       nexthop.s_addr = INADDR_ANY;
        p.family = AF_INET;
-       p.prefix.s_addr = 0;
+       p.prefix.s_addr = INADDR_ANY;
        p.prefixlen = 0;
 
        ospf->default_originate = originate;
@@ -854,7 +854,7 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS)
                        /* Nothing has changed, so nothing to do; return */
                        return 0;
                }
-               if (ospf->router_id.s_addr != 0) {
+               if (ospf->router_id.s_addr != INADDR_ANY) {
                        if (ei) {
                                if (is_prefix_default(&p))
                                        ospf_external_lsa_refresh_default(ospf);
index 6a4e63372aedeab31919ccedc4981963b0ac9ab8..2a3f1329a0c158bf11ae9ac74ad0def5fc85776b 100644 (file)
@@ -329,7 +329,7 @@ struct ospf *ospf_lookup_instance(unsigned short instance)
 static int ospf_is_ready(struct ospf *ospf)
 {
        /* OSPF must be on and Router-ID must be configured. */
-       if (!ospf || ospf->router_id.s_addr == 0)
+       if (!ospf || ospf->router_id.s_addr == INADDR_ANY)
                return 0;
 
        return 1;
@@ -379,7 +379,7 @@ struct ospf *ospf_get(unsigned short instance, const char *name, bool *created)
                ospf = ospf_new(instance, name);
                ospf_add(ospf);
 
-               if (ospf->router_id_static.s_addr == 0)
+               if (ospf->router_id_static.s_addr == INADDR_ANY)
                        ospf_router_id_update(ospf);
 
                ospf_opaque_type11_lsa_init(ospf);
@@ -398,7 +398,7 @@ struct ospf *ospf_get_instance(unsigned short instance, bool *created)
                ospf = ospf_new(instance, NULL /* VRF_DEFAULT*/);
                ospf_add(ospf);
 
-               if (ospf->router_id_static.s_addr == 0)
+               if (ospf->router_id_static.s_addr == INADDR_ANY)
                        ospf_router_id_update(ospf);
 
                ospf_opaque_type11_lsa_init(ospf);
@@ -938,7 +938,8 @@ static void add_ospf_interface(struct connected *co, struct ospf_area *area)
         * ospf_router_id_update() will call ospf_if_update
         * whenever r-id is configured instead.
         */
-       if ((area->ospf->router_id.s_addr != 0) && if_is_operative(co->ifp))
+       if ((area->ospf->router_id.s_addr != INADDR_ANY)
+           && if_is_operative(co->ifp))
                ospf_if_up(oi);
 }
 
@@ -1267,7 +1268,7 @@ static void ospf_network_run(struct prefix *p, struct ospf_area *area)
        struct interface *ifp;
 
        /* Schedule Router ID Update. */
-       if (area->ospf->router_id.s_addr == 0)
+       if (area->ospf->router_id.s_addr == INADDR_ANY)
                ospf_router_id_update(area->ospf);
 
        /* Get target interface. */
index dd9576275411c0a88d0dfe8e1210121427314665..2f10abccee5953ecfcd9ce445fa0f59c64f22d4a 100644 (file)
@@ -448,7 +448,7 @@ int main(int argc, char *const argv[])
                exit(EXIT_FAILURE);
        }
 
-       mc_group.s_addr = 0;
+       mc_group.s_addr = INADDR_ANY;
        not_group = false;
 
        if (argc == 3) {
index 4a69e4d1abc43f2d050480582be5f5b97fc4b5a3..e14b7e058d33a10c78ef7795358c818b322973df 100644 (file)
@@ -86,8 +86,7 @@ static void pim_free_bsgrp_node(struct route_table *rt, struct prefix *grp)
 
 static void pim_bsm_node_free(struct bsm_info *bsm)
 {
-       if (bsm->bsm)
-               XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM, bsm->bsm);
+       XFREE(MTYPE_PIM_BSM_PKT_VAR_MEM, bsm->bsm);
        XFREE(MTYPE_PIM_BSM_INFO, bsm);
 }
 
index 01bebebd290215e991f06fe213073e9d55c75c67..6508fb4453f71f4abea06b5173f3aa70385c14ab 100644 (file)
@@ -1741,12 +1741,12 @@ static void pim_show_join(struct pim_instance *pim, struct vty *vty,
                        continue;
 
                RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
-                       if (sg->grp.s_addr != 0
+                       if (sg->grp.s_addr != INADDR_ANY
                            && sg->grp.s_addr != ch->sg.grp.s_addr)
                                continue;
-                       if (sg->src.s_addr != 0
+                       if (sg->src.s_addr != INADDR_ANY
                            && sg->src.s_addr != ch->sg.src.s_addr)
-                       continue;
+                               continue;
                        pim_show_join_helper(vty, pim_ifp, ch, json, now, uj);
                } /* scan interface channels */
        }
@@ -2448,9 +2448,11 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
                char msdp_reg_timer[10];
                char state_str[PIM_REG_STATE_STR_LEN];
 
-               if (sg->grp.s_addr != 0 && sg->grp.s_addr != up->sg.grp.s_addr)
+               if (sg->grp.s_addr != INADDR_ANY
+                   && sg->grp.s_addr != up->sg.grp.s_addr)
                        continue;
-               if (sg->src.s_addr != 0 && sg->src.s_addr != up->sg.src.s_addr)
+               if (sg->src.s_addr != INADDR_ANY
+                   && sg->src.s_addr != up->sg.src.s_addr)
                        continue;
 
                pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
index 3a7eb45f27fb3abdb44c794e913267cf127a5b60..d9c9bb37dd2048171c25b8ce883ca1a7cb6cec2b 100644 (file)
@@ -580,7 +580,7 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
        ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
        ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval(ch);
 
-       ch->ifassert_winner.s_addr = 0;
+       ch->ifassert_winner.s_addr = INADDR_ANY;
 
        /* Assert state */
        ch->t_ifassert_timer = NULL;
index 695d04c7c2ba4cdc0243446fdb21a0e47a57e4fa..309b8c1495b11658c6b4032e4296358959197d4b 100644 (file)
@@ -68,7 +68,7 @@ static bool mtrace_fwd_info_weak(struct pim_instance *pim,
        struct in_addr nh_addr;
        char nexthop_str[INET_ADDRSTRLEN];
 
-       nh_addr.s_addr = 0;
+       nh_addr.s_addr = INADDR_ANY;
 
        memset(&nexthop, 0, sizeof(nexthop));
 
@@ -123,7 +123,7 @@ static bool mtrace_fwd_info(struct pim_instance *pim,
        up = pim_upstream_find(pim, &sg);
 
        if (!up) {
-               sg.src.s_addr = 0;
+               sg.src.s_addr = INADDR_ANY;
                up = pim_upstream_find(pim, &sg);
        }
 
@@ -160,7 +160,7 @@ static bool mtrace_fwd_info(struct pim_instance *pim,
        rspp->rtg_proto = MTRACE_RTG_PROTO_PIM;
 
        /* 6.2.2. 4. Fill in ... S, and Src Mask */
-       if (sg.src.s_addr) {
+       if (sg.src.s_addr != INADDR_ANY) {
                rspp->s = 1;
                rspp->src_mask = MTRACE_SRC_MASK_SOURCE;
        } else {
@@ -181,9 +181,9 @@ static void mtrace_rsp_set_fwd_code(struct igmp_mtrace_rsp *mtrace_rspp,
 static void mtrace_rsp_init(struct igmp_mtrace_rsp *mtrace_rspp)
 {
        mtrace_rspp->arrival = 0;
-       mtrace_rspp->incoming.s_addr = 0;
-       mtrace_rspp->outgoing.s_addr = 0;
-       mtrace_rspp->prev_hop.s_addr = 0;
+       mtrace_rspp->incoming.s_addr = INADDR_ANY;
+       mtrace_rspp->outgoing.s_addr = INADDR_ANY;
+       mtrace_rspp->prev_hop.s_addr = INADDR_ANY;
        mtrace_rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
        mtrace_rspp->out_count = htonl(MTRACE_UNKNOWN_COUNT);
        mtrace_rspp->total = htonl(MTRACE_UNKNOWN_COUNT);
@@ -779,7 +779,7 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr,
 
        /* 6.2.2. 2. Attempt to determine the forwarding information... */
 
-       if (mtracep->grp_addr.s_addr)
+       if (mtracep->grp_addr.s_addr != INADDR_ANY)
                fwd_info = mtrace_fwd_info(pim, mtracep, rspp, &out_ifp);
        else
                fwd_info = mtrace_fwd_info_weak(pim, mtracep, rspp, &out_ifp);
@@ -797,7 +797,7 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr,
 
        reached_source = false;
 
-       if (nh_addr.s_addr == 0) {
+       if (nh_addr.s_addr == INADDR_ANY) {
                /* no pim? i.e. 7.5.3. No Previous Hop */
                if (!out_ifp->info) {
                        if (PIM_DEBUG_MTRACE)
index 58ebc6ce67d716d56f31a9259504894029e56ab7..27af9473bb65cce9f44218d4b08c77da092974f0 100644 (file)
@@ -473,7 +473,7 @@ static void pim_msdp_sa_local_add(struct pim_instance *pim,
                                  struct prefix_sg *sg)
 {
        struct in_addr rp;
-       rp.s_addr = 0;
+       rp.s_addr = INADDR_ANY;
        pim_msdp_sa_ref(pim, NULL /* mp */, sg, rp);
 }
 
@@ -1175,9 +1175,7 @@ static void pim_msdp_peer_free(struct pim_msdp_peer *mp)
                stream_fifo_free(mp->obuf);
        }
 
-       if (mp->mesh_group_name) {
-               XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name);
-       }
+       XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name);
 
        mp->pim = NULL;
        XFREE(MTYPE_PIM_MSDP_PEER, mp);
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 4d4874060675a117a6370ef97f23d747f96e4719..d07cc894a5bb8f86a8199771478556109c6a08e1 100644 (file)
@@ -1210,7 +1210,6 @@ static int rip_interface_delete_hook(struct interface *ifp)
 {
        rip_interface_reset(ifp->info);
        XFREE(MTYPE_RIP_INTERFACE, ifp->info);
-       ifp->info = NULL;
        return 0;
 }
 
index 060bb76585c1aac4434a3ae4937fdd3736377b13..ca41afaea6a8e711542b0a304e741ab1f06a17dd 100644 (file)
@@ -35,6 +35,7 @@
 #include "vrf.h"
 #include "if_rmap.h"
 #include "libfrr.h"
+#include "routemap.h"
 
 #include "ripd/ripd.h"
 #include "ripd/rip_nb.h"
@@ -115,6 +116,7 @@ static struct quagga_signal_t ripd_signals[] = {
 static const struct frr_yang_module_info *const ripd_yang_modules[] = {
        &frr_interface_info,
        &frr_ripd_info,
+       &frr_route_map_info,
 };
 
 FRR_DAEMON_INFO(ripd, RIP, .vty_port = RIP_VTY_PORT,
index 4e848766d6fbfc00ebd5c7c50bce4147e9727a8d..102b64df6b9c326220148a128c73ac3ea02cc6f1 100644 (file)
@@ -158,8 +158,9 @@ route_match_ip_next_hop(void *rule, const struct prefix *prefix,
        if (type == RMAP_RIP) {
                rinfo = object;
                p.family = AF_INET;
-               p.prefix = (rinfo->nh.gate.ipv4.s_addr) ? rinfo->nh.gate.ipv4
-                                                       : rinfo->from;
+               p.prefix = (rinfo->nh.gate.ipv4.s_addr != INADDR_ANY)
+                                  ? rinfo->nh.gate.ipv4
+                                  : rinfo->from;
                p.prefixlen = IPV4_MAX_BITLEN;
 
                alist = access_list_lookup(AFI_IP, (char *)rule);
@@ -207,8 +208,9 @@ route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
        if (type == RMAP_RIP) {
                rinfo = object;
                p.family = AF_INET;
-               p.prefix = (rinfo->nh.gate.ipv4.s_addr) ? rinfo->nh.gate.ipv4
-                                                       : rinfo->from;
+               p.prefix = (rinfo->nh.gate.ipv4.s_addr != INADDR_ANY)
+                                  ? rinfo->nh.gate.ipv4
+                                  : rinfo->from;
                p.prefixlen = IPV4_MAX_BITLEN;
 
                plist = prefix_list_lookup(AFI_IP, (char *)rule);
index ec0770ef3d7d835441ff5da0b81c4edc621b0f9c..5ccefac1788d1a2277a081b5c8a64f5cbf83adc8 100644 (file)
@@ -1223,7 +1223,8 @@ static void rip_response_process(struct rip_packet *packet, int size,
                }
 
                /* RIPv1 does not have nexthop value. */
-               if (packet->version == RIPv1 && rte->nexthop.s_addr != 0) {
+               if (packet->version == RIPv1
+                   && rte->nexthop.s_addr != INADDR_ANY) {
                        zlog_info("RIPv1 packet with nexthop value %s",
                                  inet_ntoa(rte->nexthop));
                        rip_peer_bad_route(rip, from);
@@ -1234,7 +1235,8 @@ static void rip_response_process(struct rip_packet *packet, int size,
                   sub-optimal, but absolutely valid, route may be taken.  If
                   the received Next Hop is not directly reachable, it should be
                   treated as 0.0.0.0. */
-               if (packet->version == RIPv2 && rte->nexthop.s_addr != 0) {
+               if (packet->version == RIPv2
+                   && rte->nexthop.s_addr != INADDR_ANY) {
                        uint32_t addrval;
 
                        /* Multicast address check. */
@@ -1272,7 +1274,8 @@ static void rip_response_process(struct rip_packet *packet, int size,
                                                                "Next hop %s is not directly reachable. Treat it as 0.0.0.0",
                                                                inet_ntoa(
                                                                        rte->nexthop));
-                                               rte->nexthop.s_addr = 0;
+                                               rte->nexthop.s_addr =
+                                                       INADDR_ANY;
                                        }
 
                                        route_unlock_node(rn);
@@ -1282,7 +1285,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
                                                        "Next hop %s is not directly reachable. Treat it as 0.0.0.0",
                                                        inet_ntoa(
                                                                rte->nexthop));
-                                       rte->nexthop.s_addr = 0;
+                                       rte->nexthop.s_addr = INADDR_ANY;
                                }
                        }
                }
@@ -1297,10 +1300,11 @@ static void rip_response_process(struct rip_packet *packet, int size,
                   (/16 for class B's) except when the RIP packet does to inside
                   the classful network in question.  */
 
-               if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
+               if ((packet->version == RIPv1
+                    && rte->prefix.s_addr != INADDR_ANY)
                    || (packet->version == RIPv2
-                       && (rte->prefix.s_addr != 0
-                           && rte->mask.s_addr == 0))) {
+                       && (rte->prefix.s_addr != INADDR_ANY
+                           && rte->mask.s_addr == INADDR_ANY))) {
                        uint32_t destination;
 
                        if (subnetted == -1) {
@@ -1352,7 +1356,8 @@ static void rip_response_process(struct rip_packet *packet, int size,
 
                /* In case of RIPv2, if prefix in RTE is not netmask applied one
                   ignore the entry.  */
-               if ((packet->version == RIPv2) && (rte->mask.s_addr != 0)
+               if ((packet->version == RIPv2)
+                   && (rte->mask.s_addr != INADDR_ANY)
                    && ((rte->prefix.s_addr & rte->mask.s_addr)
                        != rte->prefix.s_addr)) {
                        zlog_warn(
@@ -1363,12 +1368,13 @@ static void rip_response_process(struct rip_packet *packet, int size,
                }
 
                /* Default route's netmask is ignored. */
-               if (packet->version == RIPv2 && (rte->prefix.s_addr == 0)
-                   && (rte->mask.s_addr != 0)) {
+               if (packet->version == RIPv2
+                   && (rte->prefix.s_addr == INADDR_ANY)
+                   && (rte->mask.s_addr != INADDR_ANY)) {
                        if (IS_RIP_DEBUG_EVENT)
                                zlog_debug(
                                        "Default route with non-zero netmask.  Set zero to netmask");
-                       rte->mask.s_addr = 0;
+                       rte->mask.s_addr = INADDR_ANY;
                }
 
                /* Routing table updates. */
@@ -3670,8 +3676,7 @@ static int rip_vrf_enable(struct vrf *vrf)
                                running_config->version++;
                        }
                }
-               if (old_vrf_name)
-                       XFREE(MTYPE_RIP_VRF_NAME, old_vrf_name);
+               XFREE(MTYPE_RIP_VRF_NAME, old_vrf_name);
        }
        if (!rip || rip->enabled)
                return 0;
index 97113a180f22b010fed718d1eaf70852a9e45068..250c7803f7dc4f8b5e26b00467fa77a7784e197b 100644 (file)
@@ -913,7 +913,6 @@ static int ripng_if_new_hook(struct interface *ifp)
 static int ripng_if_delete_hook(struct interface *ifp)
 {
        XFREE(MTYPE_RIPNG_IF, ifp->info);
-       ifp->info = NULL;
        return 0;
 }
 
index 9daeeb9580da39a51a0ca4a5c2a6e045ba4f334c..99adb2cba740de4fdee8d7f55248fa6236b3250a 100644 (file)
@@ -36,6 +36,7 @@
 #include "vrf.h"
 #include "if_rmap.h"
 #include "libfrr.h"
+#include "routemap.h"
 
 #include "ripngd/ripngd.h"
 #include "ripngd/ripng_nb.h"
@@ -115,6 +116,7 @@ struct quagga_signal_t ripng_signals[] = {
 static const struct frr_yang_module_info *const ripngd_yang_modules[] = {
        &frr_interface_info,
        &frr_ripngd_info,
+       &frr_route_map_info,
 };
 
 FRR_DAEMON_INFO(ripngd, RIPNG, .vty_port = RIPNG_VTY_PORT,
index ad2ddd0dba8a2ace03f0ca269d234bd9c388209f..f8d7dc968b8462ec2627e7778ecaa33008690d2c 100644 (file)
@@ -2804,8 +2804,7 @@ static int ripng_vrf_enable(struct vrf *vrf)
                                running_config->version++;
                        }
                }
-               if (old_vrf_name)
-                       XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name);
+               XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name);
        }
 
        if (ripng->enabled)
diff --git a/scripts/coccinelle/s_addr_0_to_INADDR_ANY.cocci b/scripts/coccinelle/s_addr_0_to_INADDR_ANY.cocci
new file mode 100644 (file)
index 0000000..bd7f4af
--- /dev/null
@@ -0,0 +1,14 @@
+@@
+expression e;
+@@
+
+(
+- e.s_addr == 0
++ e.s_addr == INADDR_ANY
+|
+- e.s_addr != 0
++ e.s_addr != INADDR_ANY
+|
+- e.s_addr = 0
++ e.s_addr = INADDR_ANY
+)
diff --git a/scripts/coccinelle/shorthand_operator.cocci b/scripts/coccinelle/shorthand_operator.cocci
new file mode 100644 (file)
index 0000000..f7019d4
--- /dev/null
@@ -0,0 +1,12 @@
+@@
+identifier data;
+constant x;
+@@
+
+(
+- data = data + x
++ data += x
+|
+- data = data - x
++ data -= x
+)
diff --git a/scripts/coccinelle/void_no_return.cocci b/scripts/coccinelle/void_no_return.cocci
new file mode 100644 (file)
index 0000000..7da9e73
--- /dev/null
@@ -0,0 +1,9 @@
+@@
+identifier f;
+expression e;
+@@
+void f(...) {
+  ...
+- return
+  e;
+}
index 21f4b38773c3f4d163c53a448250516f667f8229..3f63c0499ae99e7d95e077fc54ed71f47afa8994 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 442b8c83801f54ad6273fd030ea1a053f2115687..cffd52ee021190fade2442c551938a46522aaf1d 100644 (file)
@@ -81,7 +81,6 @@ static void slow_func_del(struct work_queue *wq, void *data)
        assert(hn && hn->str);
        printf("%s: %s\n", __func__, hn->str);
        XFREE(MTYPE_WQ_NODE_STR, hn->str);
-       hn->str = NULL;
        XFREE(MTYPE_WQ_NODE, hn);
 }
 
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 13413888bf5e6be7b8c2b154895c06b3ee14cee5..b7ac0abe02c0160027d92a6af760952471251497 100755 (executable)
@@ -87,7 +87,7 @@ sub scan_file {
         if ($file =~ /lib\/keychain\.c$/) {
             $protocol = "VTYSH_RIPD|VTYSH_EIGRPD";
         }
-        elsif ($file =~ /lib\/routemap\.c$/) {
+        elsif ($file =~ /lib\/routemap\.c$/ || $file =~ /lib\/routemap_cli\.c$/) {
             $protocol = "VTYSH_RMAP";
         }
         elsif ($file =~ /lib\/vrf\.c$/) {
index b7d35caa3975889b9f912ffab5df3d6ce063ef52..3a46835d1afe1f549054f6eb3cfdf142b767a51a 100644 (file)
@@ -1153,7 +1153,6 @@ static char *command_generator(const char *text, int state)
                return matched[index++];
 
        XFREE(MTYPE_TMP, matched);
-       matched = NULL;
 
        return NULL;
 }
@@ -3058,6 +3057,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 +4041,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 0ce40b474b1fde6d0ec2a6a87760c4f4126a0d29..34a7e28a775b4665d6090f073e73aaa548c0f33e 100644 (file)
@@ -9,6 +9,9 @@ module frr-route-map {
   import frr-filter {
     prefix filter;
   }
+  import frr-interface {
+    prefix frr-interface;
+  }
 
   organization "Free Range Routing";
   contact
@@ -38,367 +41,343 @@ module frr-route-map {
   /*
    * Operational data.
    */
-  container route-map {
-    list instance {
+  container lib {
+    list route-map {
       description "Route map instance";
 
-      key "name sequence";
+      key "name";
 
       leaf name {
         description "Route map instance name";
         type route-map-name;
       }
 
-      leaf sequence {
-        description
-          "Route map instance priority (low number means higher priority)";
-        type route-map-sequence;
-      }
+      list entry {
+        description "Route map entry";
 
-      leaf description {
-        description "Route map description";
-        type string;
-      }
+        key "sequence";
 
-      leaf action {
-        description
-          "Route map actions: permit (executes action), deny (quits evaluation)";
-        mandatory true;
-        type enumeration {
-          enum permit {
-            description
-              "Executes configured action and permits the prefix/route
-               if the conditions matched. An alternative exit action can
-               be configured to continue processing the route map list
-               or jump to process another route map.";
-            value 0;
-          }
-          enum deny {
-            description
-              "If all conditions are met the prefix/route is denied and
-               route map processing stops.";
-            value 1;
-          }
+        leaf sequence {
+          description
+            "Route map instance priority (low number means higher priority)";
+          type route-map-sequence;
         }
-      }
-
-      list match-condition {
-        description "Route map match conditions";
 
-        key "condition";
+        leaf description {
+          description "Route map description";
+          type string;
+        }
 
-        leaf condition {
-          description "Match condition";
+        leaf action {
+          description
+            "Route map actions: permit (executes action), deny (quits evaluation)";
+          mandatory true;
           type enumeration {
-            enum interface {
-              description "Match interface";
+            enum permit {
+              description
+                "Executes configured action and permits the prefix/route
+                 if the conditions matched. An alternative exit action can
+                 be configured to continue processing the route map list
+                 or jump to process another route map.";
               value 0;
             }
-            enum ipv4-address-list {
-              description "Match an IPv4 access-list";
+            enum deny {
+              description
+                "If all conditions are met the prefix/route is denied and
+                 route map processing stops.";
               value 1;
             }
-            enum ipv4-prefix-list {
-              description "Match an IPv4 prefix-list";
-              value 2;
-            }
-            enum ipv4-prefix-length {
-              description "Match an IPv4 prefix length";
-              value 3;
-            }
-            enum ipv4-next-hop-list {
-              description "Match an IPv4 next-hop";
-              value 4;
-            }
-            enum ipv4-next-hop-prefix-list {
-              description "Match an IPv4 next-hop prefix list";
-              value 5;
-            }
-            enum ipv4-next-hop-prefix-length {
-              description "Match an IPv4 next-hop prefix length";
-              value 6;
-            }
-            enum ipv4-next-hop-type {
-              description "Match an IPv4 next-hop type";
-              value 7;
-            }
-            enum ipv6-address-list {
-              description "Match an IPv6 access-list";
-              value 8;
-            }
-            enum ipv6-prefix-list {
-              description "Match an IPv6 prefix-list";
-              value 9;
-            }
-            enum ipv6-prefix-length {
-              description "Match an IPv6 prefix length";
-              value 10;
-            }
-            enum ipv6-next-hop {
-              description "Match an IPv6 next-hop";
-              value 11;
-            }
-            enum ipv6-next-hop-type {
-              description "Match an IPv6 next-hop type";
-              value 12;
-            }
-            enum metric {
-              description "Match a route metric";
-              value 13;
+          }
+        }
+
+        leaf call {
+          description
+            "Call another route map before calling `exit-policy`. If the
+             called route map returns deny then this route map will also
+             return deny";
+          type route-map-name;
+        }
+
+        leaf exit-policy {
+          description "What do to after route map successful match, set and call";
+          type enumeration {
+            enum permit-or-deny {
+              description "End route map evaluation and return";
+              value 0;
             }
-            enum tag {
-              description "Match a route tag";
-              value 14;
+            enum next {
+              description
+                "Proceed evaluating next route map entry per sequence";
+              value 1;
             }
-
-            /*
-             * Protocol YANG models should augment the parent node to
-             * contain the routing protocol specific value. The protocol
-             * must also augment `condition-value` to include its specific
-             * values or expand the `when` statement on the existing cases.
-             */
-            enum routing-protocol-specific {
-              description "Match a routing protocol specific type";
-              value 100;
+            enum goto {
+              description
+                "Go to route map entry with the provided sequence number";
+              value 2;
             }
           }
+          default "permit-or-deny";
         }
 
-        choice condition-value {
+        leaf goto-value {
+          when "../exit-policy = 'goto'";
           description
-            "Value to match (interpretation depends on condition type)";
-          case access-list-num {
-            when "./condition = 'ipv4-address-list' or
-                  ./condition = 'ipv4-next-hop-list'";
-            leaf access-list-num {
-              type filter:access-list-standard;
-            }
-          }
-          case access-list-num-extended {
-            when "./condition = 'ipv4-address-list' or
-                  ./condition = 'ipv4-next-hop-list'";
-            leaf access-list-num-extended {
-              type filter:access-list-extended;
+            "Sequence number to jump (when using `goto` exit policy)";
+          mandatory true;
+          type route-map-sequence;
+        }
+
+        list match-condition {
+          description "Route map match conditions";
+
+          key "condition";
+
+          leaf condition {
+            description "Match condition";
+            type enumeration {
+              enum interface {
+                description "Match interface";
+                value 0;
+              }
+              enum ipv4-address-list {
+                description "Match an IPv4 access-list";
+                value 1;
+              }
+              enum ipv4-prefix-list {
+                description "Match an IPv4 prefix-list";
+                value 2;
+              }
+              enum ipv4-next-hop-list {
+                description "Match an IPv4 next-hop";
+                value 3;
+              }
+              enum ipv4-next-hop-prefix-list {
+                description "Match an IPv4 next-hop prefix list";
+                value 4;
+              }
+              enum ipv4-next-hop-type {
+                description "Match an IPv4 next-hop type";
+                value 5;
+              }
+              enum ipv6-address-list {
+                description "Match an IPv6 access-list";
+                value 6;
+              }
+              enum ipv6-prefix-list {
+                description "Match an IPv6 prefix-list";
+                value 7;
+              }
+              enum ipv6-next-hop-type {
+                description "Match an IPv6 next-hop type";
+                value 8;
+              }
+              enum metric {
+                description "Match a route metric";
+                value 9;
+              }
+              enum tag {
+                description "Match a route tag";
+                value 10;
+              }
+
+              /*
+               * Protocol YANG models should augment the parent node to
+               * contain the routing protocol specific value. The protocol
+               * must also augment `condition-value` to include its specific
+               * values or expand the `when` statement on the existing cases.
+               */
+              enum routing-protocol-specific {
+                description "Match a routing protocol specific type";
+                value 100;
+              }
             }
           }
-          case list-name {
-            when "./condition = 'ipv4-address-list' or
-                  ./condition = 'ipv4-prefix-list' or
-                  ./condition = 'ipv4-next-hop-list' or
-                  ./condition = 'ipv4-next-hop-prefix-list' or
-                  ./condition = 'ipv6-address-list' or
-                  ./condition = 'ipv6-prefix-list'";
-            leaf list-name {
-              type filter:access-list-name;
+
+          choice condition-value {
+            description
+              "Value to match (interpretation depends on condition type)";
+            mandatory true;
+            case interface {
+              when "./condition = 'interface'";
+              leaf interface {
+                type frr-interface:interface-ref;
+              }
             }
-          }
-          case ipv6-address {
-            when "./condition = 'ipv6-next-hop'";
-            leaf ipv6-address {
-              type inet:ipv6-address;
+            case access-list-num {
+              when "./condition = 'ipv4-address-list' or
+                    ./condition = 'ipv4-next-hop-list'";
+              leaf access-list-num {
+                type filter:access-list-standard;
+              }
             }
-          }
-          case ipv4-prefix-length {
-            when "./condition = 'ipv4-prefix-length' or
-                  ./condition = 'ipv4-next-hop-prefix-length'";
-            leaf ipv4-prefix-length {
-              type uint8 {
-                range "0..32";
+            case access-list-num-extended {
+              when "./condition = 'ipv4-address-list' or
+                    ./condition = 'ipv4-next-hop-list'";
+              leaf access-list-num-extended {
+                type filter:access-list-extended;
               }
             }
-          }
-          case ipv6-prefix-length {
-            when "./condition = 'ipv6-prefix-length'";
-            leaf ipv6-prefix-length {
-              type uint8 {
-                range "0..128";
+            case list-name {
+              when "./condition = 'ipv4-address-list' or
+                    ./condition = 'ipv4-prefix-list' or
+                    ./condition = 'ipv4-next-hop-list' or
+                    ./condition = 'ipv4-next-hop-prefix-list' or
+                    ./condition = 'ipv6-address-list' or
+                    ./condition = 'ipv6-prefix-list'";
+              leaf list-name {
+                type filter:access-list-name;
               }
             }
-          }
-          case ipv4-next-hop-type {
-            when "./condition = 'ipv4-next-hop-type'";
-            leaf ipv4-next-hop-type {
-              type enumeration {
-                enum blackhole {
-                  value 0;
+            case ipv4-next-hop-type {
+              when "./condition = 'ipv4-next-hop-type'";
+              leaf ipv4-next-hop-type {
+                type enumeration {
+                  enum blackhole {
+                    value 0;
+                  }
                 }
               }
             }
-          }
-          case ipv6-next-hop-type {
-            when "./condition = 'ipv6-next-hop-type'";
-            leaf ipv6-next-hop-type {
-              type enumeration {
-                enum blackhole {
-                  value 0;
+            case ipv6-next-hop-type {
+              when "./condition = 'ipv6-next-hop-type'";
+              leaf ipv6-next-hop-type {
+                type enumeration {
+                  enum blackhole {
+                    value 0;
+                  }
                 }
               }
             }
-          }
-          case metric {
-            when "./condition = 'metric'";
-            leaf metric {
-              type uint32 {
-                range "1..4294967295";
+            case metric {
+              when "./condition = 'metric'";
+              leaf metric {
+                type uint32 {
+                  range "1..4294967295";
+                }
               }
             }
-          }
-          case tag {
-            when "./condition = 'tag'";
-            leaf tag {
-              type uint32 {
-                range "1..4294967295";
+            case tag {
+              when "./condition = 'tag'";
+              leaf tag {
+                type uint32 {
+                  range "1..4294967295";
+                }
               }
             }
           }
         }
-      }
 
-      list set-action {
-        description "Route map set actions";
+        list set-action {
+          description "Route map set actions";
 
-        key "action";
+          key "action";
 
-        leaf action {
-          description "Action to do when the route map matches";
-          type enumeration {
-            enum ipv4-next-hop {
-              description "Set IPv4 address of the next hop";
-              value 0;
-            }
-            enum ipv6-next-hop {
-              description "Set IPv6 address of the next hop";
-              value 1;
-            }
-            enum metric {
-              description "Set prefix/route metric";
-              value 2;
-            }
-            enum tag {
-              description "Set tag";
-              value 3;
-            }
+          leaf action {
+            description "Action to do when the route map matches";
+            type enumeration {
+              enum ipv4-next-hop {
+                description "Set IPv4 address of the next hop";
+                value 0;
+              }
+              enum ipv6-next-hop {
+                description "Set IPv6 address of the next hop";
+                value 1;
+              }
+              enum metric {
+                description "Set prefix/route metric";
+                value 2;
+              }
+              enum tag {
+                description "Set tag";
+                value 3;
+              }
 
-            /*
-             * Protocol YANG models should augment the parent node to
-             * contain the routing protocol specific value. The protocol
-             * must also augment `action-value` to include its specific
-             * values or expand the `when` statement on the existing cases.
-             */
-            enum routing-protocol-specific {
-              description "Set a routing protocol specific action";
-              value 100;
+              /*
+               * Protocol YANG models should augment the parent node to
+               * contain the routing protocol specific value. The protocol
+               * must also augment `action-value` to include its specific
+               * values or expand the `when` statement on the existing cases.
+               */
+              enum routing-protocol-specific {
+                description "Set a routing protocol specific action";
+                value 100;
+              }
             }
           }
-        }
 
-        choice action-value {
-          description
-            "Value to set (interpretation depends on action-type)";
-          case ipv4-address {
-            when "./action = 'ipv4-next-hop'";
-            leaf ipv4-address {
-              description "IPv4 address";
-              type inet:ipv4-address;
+          choice action-value {
+            description
+              "Value to set (interpretation depends on action-type)";
+            case ipv4-address {
+              when "./action = 'ipv4-next-hop'";
+              leaf ipv4-address {
+                description "IPv4 address";
+                type inet:ipv4-address;
+              }
             }
-          }
-          case ipv6-address {
-            when "./action = 'ipv6-next-hop'";
-            leaf ipv6-address {
-              description "IPv6 address";
-              type inet:ipv6-address;
+            case ipv6-address {
+              when "./action = 'ipv6-next-hop'";
+              leaf ipv6-address {
+                description "IPv6 address";
+                type inet:ipv6-address;
+              }
             }
-          }
-          case metric {
-            when "./action = 'metric'";
-            choice metric-value {
-              description "Metric to set or use";
-              case value {
-                leaf value {
-                  description "Use the following metric value";
-                  type uint32 {
-                    range "0..4294967295";
+            case metric {
+              when "./action = 'metric'";
+              choice metric-value {
+                description "Metric to set or use";
+                case value {
+                  leaf value {
+                    description "Use the following metric value";
+                    type uint32 {
+                      range "0..4294967295";
+                    }
                   }
                 }
-              }
-              case add-metric {
-                leaf add-metric {
-                  description "Add unit to metric";
-                  type boolean;
+                case add-metric {
+                  leaf add-metric {
+                    description "Add unit to metric";
+                    type boolean;
+                  }
                 }
-              }
-              case subtract-metric {
-                leaf subtract-metric {
-                  description "Subtract unit from metric";
-                  type boolean;
+                case subtract-metric {
+                  leaf subtract-metric {
+                    description "Subtract unit from metric";
+                    type boolean;
+                  }
                 }
-              }
-              case use-round-trip-time {
-                leaf use-round-trip-time {
-                  description "Use the round trip time as metric";
-                  type boolean;
+                case use-round-trip-time {
+                  leaf use-round-trip-time {
+                    description "Use the round trip time as metric";
+                    type boolean;
+                  }
                 }
-              }
-              case add-round-trip-time {
-                leaf add-round-trip-time {
-                  description "Add round trip time to metric";
-                  type boolean;
+                case add-round-trip-time {
+                  leaf add-round-trip-time {
+                    description "Add round trip time to metric";
+                    type boolean;
+                  }
                 }
-              }
-              case subtract-round-trip-time {
-                leaf subtract-round-trip-time {
-                  description "Subtract round trip time to metric";
-                  type boolean;
+                case subtract-round-trip-time {
+                  leaf subtract-round-trip-time {
+                    description "Subtract round trip time to metric";
+                    type boolean;
+                  }
                 }
               }
             }
-          }
-          case tag {
-            leaf tag {
-              description "Tag value";
-              type uint32 {
-                range "0..4294967295";
+            case tag {
+              when "./action = 'tag'";
+              leaf tag {
+                description "Tag value";
+                type uint32 {
+                  range "0..4294967295";
+                }
               }
             }
           }
         }
       }
-
-      leaf call {
-        description
-          "Call another route map before calling `exit-policy`. If the
-           called route map returns deny then this route map will also
-           return deny";
-        type string;
-      }
-
-      leaf exit-policy {
-        description "What do to after route map successful match, set and call";
-        type enumeration {
-          enum permit-or-deny {
-            description "End route map evaluation and return";
-            value 0;
-          }
-          enum next {
-            description
-              "Proceed evaluating next route map entry per sequence";
-            value 1;
-          }
-          enum goto {
-            description
-              "Go to route map entry with the provided sequence number";
-            value 2;
-          }
-        }
-        default "permit-or-deny";
-      }
-
-      leaf goto-value {
-        when "../exit-policy = 'goto'";
-        description
-          "Sequence number to jump (when using `goto` exit policy)";
-        type route-map-sequence;
-      }
     }
   }
 }
index cfaf1a6401799c5a017bca510cdafb40698845fe..c1297dafd5603737753d75c6b558982ecb331482 100644 (file)
@@ -19,9 +19,11 @@ EXTRA_DIST += yang/embedmodel.py
 # global symbols :(.  Just put it in the daemon.  Dynamic libraries.so work
 # without problems, as seen in libfrr.
 
+dist_yangmodels_DATA += yang/frr-filter.yang
 dist_yangmodels_DATA += yang/frr-module-translator.yang
 dist_yangmodels_DATA += yang/frr-test-module.yang
 dist_yangmodels_DATA += yang/frr-interface.yang
+dist_yangmodels_DATA += yang/frr-route-map.yang
 dist_yangmodels_DATA += yang/frr-route-types.yang
 dist_yangmodels_DATA += yang/ietf/ietf-routing-types.yang
 
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 c2812aa47b918a9277b88d86b3dc14aca24ac1ab..7cdd6ef84e3d279f513d2b356b2efd722772c58f 100644 (file)
@@ -556,7 +556,7 @@ int ifm_read(struct if_msghdr *ifm)
         * is 12 bytes larger than the 32 bit version.
         */
        if (((struct sockaddr *)cp)->sa_family == AF_UNSPEC)
-               cp = cp + 12;
+               cp += 12;
 #endif
 
        /* Look up for RTA_IFP and skip others. */
index 75f825e5077e7179f22daee23e84b66e30f162a3..5951c7e280758959e62a9400680c3d205430f2a2 100644 (file)
@@ -151,6 +151,10 @@ static void sigint(void)
 
        zebra_dplane_pre_finish();
 
+       /* Clean up GR related info. */
+       zebra_gr_stale_client_cleanup(zrouter.stale_client_list);
+       list_delete_all_node(zrouter.stale_client_list);
+
        for (ALL_LIST_ELEMENTS(zrouter.client_list, ln, nn, client))
                zserv_close_client(client);
 
@@ -233,6 +237,7 @@ struct quagga_signal_t zebra_signals[] = {
 
 static const struct frr_yang_module_info *const zebra_yang_modules[] = {
        &frr_interface_info,
+       &frr_route_map_info,
 };
 
 FRR_DAEMON_INFO(
index b37d4aea70277766a4b2a141136ecf7a2c19b715..710f2f6c2798c24b3b20a7d5f570d720712de85d 100644 (file)
@@ -75,11 +75,11 @@ void router_id_get(struct prefix *p, vrf_id_t vrf_id)
        struct connected *c;
        struct zebra_vrf *zvrf = vrf_info_get(vrf_id);
 
-       p->u.prefix4.s_addr = 0;
+       p->u.prefix4.s_addr = INADDR_ANY;
        p->family = AF_INET;
        p->prefixlen = 32;
 
-       if (zvrf->rid_user_assigned.u.prefix4.s_addr)
+       if (zvrf->rid_user_assigned.u.prefix4.s_addr != INADDR_ANY)
                p->u.prefix4.s_addr = zvrf->rid_user_assigned.u.prefix4.s_addr;
        else if (!list_isempty(zvrf->rid_lo_sorted_list)) {
                node = listtail(zvrf->rid_lo_sorted_list);
@@ -185,7 +185,8 @@ void router_id_write(struct vty *vty)
 
        RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
                if ((zvrf = vrf->info) != NULL)
-                       if (zvrf->rid_user_assigned.u.prefix4.s_addr) {
+                       if (zvrf->rid_user_assigned.u.prefix4.s_addr
+                           != INADDR_ANY) {
                                if (zvrf_id(zvrf) == VRF_DEFAULT)
                                        vty_out(vty, "router-id %s\n",
                                                inet_ntoa(
index dd6e62ee6c8569a215a1f6904f84b42bd5d6baeb..1d63db32e8a5e5f41a60564473cc6e12f56586d7 100644 (file)
 
 static vlanid_t filter_vlan = 0;
 
+/* We capture whether the current kernel supports nexthop ids; by
+ * default, we'll use them if possible. There's also a configuration
+ * available to _disable_ use of kernel nexthops.
+ */
 static bool supports_nh;
 
 struct gw_family_t {
@@ -86,6 +90,12 @@ struct gw_family_t {
 static const char ipv4_ll_buf[16] = "169.254.0.1";
 static struct in_addr ipv4_ll;
 
+/* Helper to control use of kernel-level nexthop ids */
+static bool kernel_nexthops_supported(void)
+{
+       return (supports_nh && zebra_nhg_kernel_nexthops_enabled());
+}
+
 /*
  * The ipv4_ll data structure is used for all 5549
  * additions to the kernel.  Let's figure out the
@@ -1152,10 +1162,12 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
                addattr_l(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4);
                addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex);
 
-               if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
+               if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY
+                   && (cmd == RTM_NEWROUTE))
                        addattr_l(nlmsg, req_size, RTA_PREFSRC,
                                  &nexthop->rmap_src.ipv4, bytelen);
-               else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
+               else if (nexthop->src.ipv4.s_addr != INADDR_ANY
+                        && (cmd == RTM_NEWROUTE))
                        addattr_l(nlmsg, req_size, RTA_PREFSRC,
                                  &nexthop->src.ipv4, bytelen);
 
@@ -1177,10 +1189,10 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
                                bytelen, nexthop);
 
                if (cmd == RTM_NEWROUTE) {
-                       if (nexthop->rmap_src.ipv4.s_addr)
+                       if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
                                addattr_l(nlmsg, req_size, RTA_PREFSRC,
                                          &nexthop->rmap_src.ipv4, bytelen);
-                       else if (nexthop->src.ipv4.s_addr)
+                       else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
                                addattr_l(nlmsg, req_size, RTA_PREFSRC,
                                          &nexthop->src.ipv4, bytelen);
                }
@@ -1226,10 +1238,10 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
 
        if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
                if (cmd == RTM_NEWROUTE) {
-                       if (nexthop->rmap_src.ipv4.s_addr)
+                       if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
                                addattr_l(nlmsg, req_size, RTA_PREFSRC,
                                          &nexthop->rmap_src.ipv4, bytelen);
-                       else if (nexthop->src.ipv4.s_addr)
+                       else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
                                addattr_l(nlmsg, req_size, RTA_PREFSRC,
                                          &nexthop->src.ipv4, bytelen);
                }
@@ -1326,9 +1338,9 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
                rtnh->rtnh_len += sizeof(struct rtattr) + bytelen;
                rtnh->rtnh_ifindex = nexthop->ifindex;
 
-               if (nexthop->rmap_src.ipv4.s_addr)
+               if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
                        *src = &nexthop->rmap_src;
-               else if (nexthop->src.ipv4.s_addr)
+               else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
                        *src = &nexthop->src;
 
                if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1345,9 +1357,9 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
                _netlink_route_rta_add_gateway_info(rtmsg->rtm_family, AF_INET,
                                                    rta, rtnh, NL_PKT_BUF_SIZE,
                                                    bytelen, nexthop);
-               if (nexthop->rmap_src.ipv4.s_addr)
+               if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
                        *src = &nexthop->rmap_src;
-               else if (nexthop->src.ipv4.s_addr)
+               else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
                        *src = &nexthop->src;
 
                if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1386,9 +1398,9 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
 
        /* ifindex */
        if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
-               if (nexthop->rmap_src.ipv4.s_addr)
+               if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
                        *src = &nexthop->rmap_src;
-               else if (nexthop->src.ipv4.s_addr)
+               else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
                        *src = &nexthop->src;
 
                if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1628,7 +1640,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
                          RTA_PAYLOAD(rta));
        }
 
-       if (supports_nh) {
+       if (kernel_nexthops_supported()) {
                /* Kernel supports nexthop objects */
                addattr32(&req.n, sizeof(req), RTA_NH_ID,
                          dplane_ctx_get_nhe_id(ctx));
@@ -1943,7 +1955,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
        size_t req_size = sizeof(req);
 
        /* Nothing to do if the kernel doesn't support nexthop objects */
-       if (!supports_nh)
+       if (!kernel_nexthops_supported())
                return 0;
 
        label_buf[0] = '\0';
@@ -2364,6 +2376,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;
 
@@ -2443,7 +2458,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;
 }
@@ -2501,8 +2516,10 @@ int netlink_nexthop_read(struct zebra_ns *zns)
                 * this kernel must support them.
                 */
                supports_nh = true;
-       else if (IS_ZEBRA_DEBUG_KERNEL)
-               zlog_debug("Nexthop objects not supported on this kernel");
+
+       if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG)
+               zlog_debug("Nexthop objects %ssupported on this kernel",
+                          supports_nh ? "" : "not ");
 
        return ret;
 }
index 77ed5a6caa6f7a56c72a923dcaa829469ef1849b..1d49de54101459aaa0d12b759c04f589dbe0bb9b 100644 (file)
@@ -17,6 +17,7 @@ vtysh_scan += \
        $(top_srcdir)/zebra/zebra_routemap.c \
        $(top_srcdir)/zebra/zebra_vty.c \
        $(top_srcdir)/zebra/zserv.c \
+       $(top_srcdir)/zebra/zebra_gr.c \
        # end
 
 # can be loaded as DSO - always include for vtysh
@@ -101,6 +102,7 @@ zebra_zebra_SOURCES = \
        zebra/table_manager.c \
        zebra/zapi_msg.c \
        zebra/zebra_errors.c \
+       zebra/zebra_gr.c \
        # end
 
 zebra/debug_clippy.c: $(CLIPPY_DEPS)
index c21d00bbe652cd2d44faa0c7e0faffeba2076baa..4d0e34561a5a8854abc889fca35eb41cc3071951 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);
 
@@ -1773,6 +1775,8 @@ static void zread_hello(ZAPI_HANDLER_ARGS)
                client->instance = instance;
        }
 
+       /* Graceful restart processing for client connect */
+       zebra_gr_client_reconnect(client);
        zsend_capabilities(client, zvrf);
        zebra_vrf_update_all(client);
 stream_failure:
@@ -2582,14 +2586,14 @@ static void zserv_error_no_vrf(ZAPI_HANDLER_ARGS)
                zlog_debug("ZAPI message specifies unknown VRF: %d",
                           hdr->vrf_id);
 
-       return zsend_error_msg(client, ZEBRA_NO_VRF, hdr);
+       zsend_error_msg(client, ZEBRA_NO_VRF, hdr);
 }
 
 static void zserv_error_invalid_msg_type(ZAPI_HANDLER_ARGS)
 {
        zlog_info("Zebra received unknown command %d", hdr->command);
 
-       return zsend_error_msg(client, ZEBRA_INVALID_MSG_TYPE, hdr);
+       zsend_error_msg(client, ZEBRA_INVALID_MSG_TYPE, hdr);
 }
 
 void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
@@ -2666,6 +2670,7 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
        [ZEBRA_MLAG_CLIENT_REGISTER] = zebra_mlag_client_register,
        [ZEBRA_MLAG_CLIENT_UNREGISTER] = zebra_mlag_client_unregister,
        [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg,
+       [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities
 };
 
 #if defined(HANDLE_ZAPI_FUZZING)
index bf1ba522a37fb6ead27900b5e5a34ec2f3bc37b7..17b148178f8a0d786a394329fe0058b7ea69abd8 100644 (file)
@@ -549,7 +549,6 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
        }
 
        XFREE(MTYPE_DP_CTX, *pctx);
-       *pctx = NULL;
 }
 
 /*
index 7786dc246c34eac08cef50020ec9b87f2a497d19..d6f55fdeb47c5e952aa6ddfdee19fd555222625a 100644 (file)
@@ -218,7 +218,7 @@ static int netlink_route_info_add_nh(netlink_route_info_t *ri,
        if (nexthop->type == NEXTHOP_TYPE_IPV4
            || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
                nhi.gateway = &nexthop->gate;
-               if (nexthop->src.ipv4.s_addr)
+               if (nexthop->src.ipv4.s_addr != INADDR_ANY)
                        src = &nexthop->src;
        }
 
@@ -228,7 +228,7 @@ static int netlink_route_info_add_nh(netlink_route_info_t *ri,
        }
 
        if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
-               if (nexthop->src.ipv4.s_addr)
+               if (nexthop->src.ipv4.s_addr != INADDR_ANY)
                        src = &nexthop->src;
        }
 
index c09fa1c65d8a755fc620f97f95011de56c27e212..d50981debf58685b38dbfa19f484d973532b1dce 100644 (file)
@@ -86,7 +86,7 @@ static inline int add_nexthop(qpb_allocator_t *allocator, Fpm__AddRoute *msg,
        if (nexthop->type == NEXTHOP_TYPE_IPV4
            || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
                gateway = &nexthop->gate;
-               if (nexthop->src.ipv4.s_addr)
+               if (nexthop->src.ipv4.s_addr != INADDR_ANY)
                        src = &nexthop->src;
        }
 
@@ -96,7 +96,7 @@ static inline int add_nexthop(qpb_allocator_t *allocator, Fpm__AddRoute *msg,
        }
 
        if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
-               if (nexthop->src.ipv4.s_addr)
+               if (nexthop->src.ipv4.s_addr != INADDR_ANY)
                        src = &nexthop->src;
        }
 
diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c
new file mode 100644 (file)
index 0000000..e8c7304
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * Zebra GR related helper functions.
+ *
+ * Portions:
+ *     Copyright (C) 2019 VMware, Inc.
+ *     et al.
+ *
+ * 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
+ */
+
+#include <zebra.h>
+#include <libgen.h>
+
+#include "lib/prefix.h"
+#include "lib/command.h"
+#include "lib/if.h"
+#include "lib/thread.h"
+#include "lib/stream.h"
+#include "lib/memory.h"
+#include "lib/table.h"
+#include "lib/network.h"
+#include "lib/sockunion.h"
+#include "lib/log.h"
+#include "lib/zclient.h"
+#include "lib/privs.h"
+#include "lib/network.h"
+#include "lib/buffer.h"
+#include "lib/nexthop.h"
+#include "lib/vrf.h"
+#include "lib/libfrr.h"
+#include "lib/sockopt.h"
+
+#include "zebra/zebra_router.h"
+#include "zebra/debug.h"
+#include "zebra/zapi_msg.h"
+
+
+/*
+ * Forward declaration.
+ */
+static struct zserv *zebra_gr_find_stale_client(struct zserv *client);
+static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread);
+static int32_t zebra_gr_delete_stale_routes(struct client_gr_info *info);
+static void zebra_gr_process_client_stale_routes(struct zserv *client,
+                                                vrf_id_t vrf_id);
+
+/*
+ * Debug macros.
+ */
+#define LOG_GR(msg, ...)                                                       \
+       do {                                                                   \
+               if (IS_ZEBRA_DEBUG_EVENT)                                      \
+                       zlog_debug(msg, ##__VA_ARGS__);                        \
+       } while (0)
+
+
+/*
+ * Client connection functions
+ */
+
+/*
+ * Function to clean all the stale clients,
+ * function will also clean up all per instance
+ * capabilities that are exchanged.
+ */
+void zebra_gr_stale_client_cleanup(struct list *client_list)
+{
+       struct listnode *node, *nnode;
+       struct zserv *s_client = NULL;
+       struct client_gr_info *info, *ninfo;
+
+       /* Find the stale client */
+       for (ALL_LIST_ELEMENTS(client_list, node, nnode, s_client)) {
+
+               LOG_GR("%s: Stale client %s is being deleted", __func__,
+                      zebra_route_string(s_client->proto));
+
+               TAILQ_FOREACH_SAFE (info, &s_client->gr_info_queue, gr_info,
+                                   ninfo) {
+
+                       /* Cancel the stale timer */
+                       if (info->t_stale_removal != NULL) {
+                               THREAD_OFF(info->t_stale_removal);
+                               info->t_stale_removal = NULL;
+                               /* Process the stale routes */
+                               thread_execute(
+                                   zrouter.master,
+                                   zebra_gr_route_stale_delete_timer_expiry,
+                                   info, 1);
+                       }
+               }
+       }
+}
+
+/*
+ * A helper function to create client info.
+ */
+static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client)
+{
+       struct client_gr_info *info;
+
+       info = XCALLOC(MTYPE_TMP, sizeof(struct client_gr_info));
+
+       TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info);
+       return info;
+}
+
+/*
+ * A helper function to delte and destory client info.
+ */
+static void zebra_gr_client_info_delte(struct zserv *client,
+                                      struct client_gr_info *info)
+{
+       TAILQ_REMOVE(&(client->gr_info_queue), info, gr_info);
+
+       THREAD_OFF(info->t_stale_removal);
+
+       if (info->current_prefix)
+               XFREE(MTYPE_TMP, info->current_prefix);
+
+       LOG_GR("%s: Instance info is being deleted for client %s", __func__,
+              zebra_route_string(client->proto));
+
+       /* Delete all the stale routes. */
+       info->delete = true;
+       zebra_gr_delete_stale_routes(info);
+
+       XFREE(MTYPE_TMP, info);
+}
+
+/*
+ * Function to handle client when it disconnect.
+ */
+int32_t zebra_gr_client_disconnect(struct zserv *client)
+{
+       struct zserv *stale_client;
+       struct timeval tv;
+       struct client_gr_info *info = NULL;
+
+       /* Find the stale client */
+       stale_client = zebra_gr_find_stale_client(client);
+
+       /*
+        * We should never be here.
+        */
+       if (stale_client) {
+               LOG_GR("%s: Stale client %s exist, we should not be here!",
+                      __func__, zebra_route_string(client->proto));
+               assert(0);
+       }
+
+       client->restart_time = monotime(&tv);
+
+       /* For all the GR instance start the starle removal timer. */
+       TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+               if (ZEBRA_CLIENT_GR_ENABLED(info->capabilities)
+                   && (info->t_stale_removal == NULL)) {
+                       thread_add_timer(
+                               zrouter.master,
+                               zebra_gr_route_stale_delete_timer_expiry, info,
+                               info->stale_removal_time,
+                               &info->t_stale_removal);
+                       info->current_afi = AFI_IP;
+                       info->stale_client_ptr = client;
+                       info->stale_client = true;
+                       LOG_GR("%s: Client %s Stale timer update to %d",
+                              __func__, zebra_route_string(client->proto),
+                              info->stale_removal_time);
+               }
+       }
+
+       listnode_add(zrouter.stale_client_list, client);
+
+       return 0;
+}
+
+/*
+ * Function to delete stale client
+ */
+static void zebra_gr_delete_stale_client(struct client_gr_info *info)
+{
+       struct client_gr_info *bgp_info;
+       struct zserv *s_client = NULL;
+
+       s_client = info->stale_client_ptr;
+
+       if (!s_client || !info->stale_client)
+               return;
+
+       /*
+        * If there are bgp instances with the stale delete timer pending
+        * then stale client is not deleted
+        */
+       if ((s_client->gr_instance_count > 0) && info->gr_enable)
+               s_client->gr_instance_count--;
+
+       TAILQ_REMOVE(&(s_client->gr_info_queue), info, gr_info);
+
+       LOG_GR("%s: Client %s gr count %d", __func__,
+              zebra_route_string(s_client->proto),
+              s_client->gr_instance_count);
+
+       TAILQ_FOREACH (bgp_info, &s_client->gr_info_queue, gr_info) {
+               if (bgp_info->t_stale_removal != NULL)
+                       return;
+       }
+
+       LOG_GR("%s: Client %s is being deleted", __func__,
+              zebra_route_string(s_client->proto));
+
+       TAILQ_INIT(&(s_client->gr_info_queue));
+       listnode_delete(zrouter.stale_client_list, s_client);
+       if (info->stale_client)
+               XFREE(MTYPE_TMP, s_client);
+       XFREE(MTYPE_TMP, info);
+}
+
+/*
+ * Function to find stale client.
+ */
+static struct zserv *zebra_gr_find_stale_client(struct zserv *client)
+{
+       struct listnode *node, *nnode;
+       struct zserv *stale_client;
+
+       /* Find the stale client */
+       for (ALL_LIST_ELEMENTS(zrouter.stale_client_list, node, nnode,
+                              stale_client)) {
+               if (client->proto == stale_client->proto
+                   && client->instance == stale_client->instance) {
+                       return stale_client;
+               }
+       }
+
+       return NULL;
+}
+
+/*
+ * Function to handle reconnect of client post restart.
+ */
+void zebra_gr_client_reconnect(struct zserv *client)
+{
+       struct listnode *node, *nnode;
+       struct zserv *old_client = NULL;
+       struct client_gr_info *info = NULL;
+
+       /* Find the stale client */
+       for (ALL_LIST_ELEMENTS(zrouter.stale_client_list, node, nnode,
+                              old_client)) {
+               if (client->proto == old_client->proto
+                   && client->instance == old_client->instance)
+                       break;
+       }
+
+       /* Copy the timers */
+       if (old_client) {
+               client->gr_instance_count = old_client->gr_instance_count;
+               client->restart_time = old_client->restart_time;
+
+               LOG_GR("%s : old client %s, gr_instance_count %d", __func__,
+                      zebra_route_string(old_client->proto),
+                      old_client->gr_instance_count);
+
+               if (TAILQ_FIRST(&old_client->gr_info_queue)) {
+                       TAILQ_CONCAT(&client->gr_info_queue,
+                                    &old_client->gr_info_queue, gr_info);
+                       TAILQ_INIT(&old_client->gr_info_queue);
+               }
+
+               TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+                       info->stale_client_ptr = client;
+                       info->stale_client = false;
+               }
+
+               /* Delete the stale client */
+               listnode_delete(zrouter.stale_client_list, old_client);
+               /* Delete old client */
+               XFREE(MTYPE_TMP, old_client);
+       }
+}
+
+/*
+ * Functions to deal with capabilities
+ */
+
+/*
+ * Update the graceful restart information
+ * for the client instance.
+ * This function handles all the capabilties that are received.
+ */
+static void zebra_client_update_info(struct zserv *client, struct zapi_cap *api)
+{
+       struct client_gr_info *info = NULL;
+
+       /* Find the bgp information for the specified vrf id */
+       TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+               if (info->vrf_id == api->vrf_id)
+                       break;
+       }
+
+
+       /*
+        * If the command is delete, then cancel the stale timer and
+        * delete the bgp info
+        */
+       switch (api->cap) {
+       case ZEBRA_CLIENT_GR_DISABLE:
+               if (!info)
+                       return;
+
+               LOG_GR("%s: Client %s instance GR disabled count %d", __func__,
+                      zebra_route_string(client->proto),
+                      client->gr_instance_count);
+
+               if ((info->gr_enable) && (client->gr_instance_count > 0))
+                       client->gr_instance_count--;
+
+               zebra_gr_client_info_delte(client, info);
+               break;
+       case ZEBRA_CLIENT_GR_CAPABILITIES:
+               /* Allocate bgp info */
+               if (!info)
+                       info = zebra_gr_client_info_create(client);
+
+               /* Udpate other parameters */
+               if (!info->gr_enable) {
+                       client->gr_instance_count++;
+
+                       LOG_GR("%s: Cient %s GR enabled count %d", __func__,
+                              zebra_route_string(client->proto),
+                              client->gr_instance_count);
+
+                       info->capabilities = api->cap;
+                       info->stale_removal_time = api->stale_removal_time;
+                       info->vrf_id = api->vrf_id;
+                       info->gr_enable = true;
+               }
+               break;
+       case ZEBRA_CLIENT_RIB_STALE_TIME:
+               LOG_GR("%s: Client %s stale time update event", __func__,
+                      zebra_route_string(client->proto));
+
+               /* Update the stale removal timer */
+               if (info && info->t_stale_removal == NULL) {
+
+                       LOG_GR("%s: Stale time: %d is now update to: %d",
+                              __func__, info->stale_removal_time,
+                              api->stale_removal_time);
+
+                       info->stale_removal_time = api->stale_removal_time;
+               }
+
+               break;
+       case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+               LOG_GR(
+                  "%s: Client %s route update complete for AFI %d, SAFI %d",
+                  __func__, zebra_route_string(client->proto), api->afi,
+                  api->safi);
+               if (info)
+                       info->route_sync[api->afi][api->safi] = true;
+               break;
+       case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+               LOG_GR("%s: Client %s route update pending for AFI %d, SAFI %d",
+                      __func__, zebra_route_string(client->proto), api->afi,
+                      api->safi);
+               if (info)
+                       info->af_enabled[api->afi][api->safi] = true;
+               break;
+       }
+}
+
+/*
+ * Handler for capabilities that are received from client.
+ */
+static void zebra_client_capabilities_handler(struct zserv *client,
+                                             struct zapi_cap *api)
+{
+       switch (api->cap) {
+       case ZEBRA_CLIENT_GR_CAPABILITIES:
+       case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+       case ZEBRA_CLIENT_GR_DISABLE:
+       case ZEBRA_CLIENT_RIB_STALE_TIME:
+               /*
+                * For all the cases we need to update the client info.
+                */
+               zebra_client_update_info(client, api);
+               break;
+       case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+               /*
+                * After client info has been updated delete all
+                * stale routes
+                */
+               zebra_client_update_info(client, api);
+               zebra_gr_process_client_stale_routes(client, api->vrf_id);
+               break;
+       }
+}
+
+/*
+ * Function to decode and call appropriate functions
+ * to handle client capabilities.
+ */
+void zread_client_capabilities(ZAPI_HANDLER_ARGS)
+{
+       struct zapi_cap api;
+       struct stream *s;
+
+       s = msg;
+
+       if (zapi_capabilities_decode(s, &api)) {
+               LOG_GR("%s: Error in reading capabilities for client %s",
+                      __func__, zebra_route_string(client->proto));
+               return;
+       }
+
+       /* Call the capabilities handler */
+       zebra_client_capabilities_handler(client, &api);
+}
+
+
+/*
+ * Stale route handling
+ */
+
+/*
+ * Delete all the stale routes that have not been refreshed
+ * post restart.
+ */
+static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread)
+{
+       struct client_gr_info *info;
+       int32_t cnt = 0;
+       struct zserv *client;
+
+       info = THREAD_ARG(thread);
+       info->t_stale_removal = NULL;
+       client = (struct zserv *)info->stale_client_ptr;
+
+       /* Set the flag to indicate all stale route deletion */
+       if (thread->u.val == 1)
+               info->delete = true;
+
+       cnt = zebra_gr_delete_stale_routes(info);
+
+       /* Retsart the timer */
+       if (cnt > 0) {
+               LOG_GR("%s: Client %s processed %d routes. Start timer again",
+                      __func__, zebra_route_string(client->proto), cnt);
+
+               thread_add_timer(zrouter.master,
+                                zebra_gr_route_stale_delete_timer_expiry, info,
+                                ZEBRA_DEFAULT_STALE_UPDATE_DELAY,
+                                &info->t_stale_removal);
+       } else {
+               /* No routes to delete for the VRF */
+               LOG_GR("%s: Client %s all starle routes processed", __func__,
+                      zebra_route_string(client->proto));
+
+               if (info->current_prefix != NULL)
+                       XFREE(MTYPE_TMP, info->current_prefix);
+               info->current_prefix = NULL;
+               info->current_afi = 0;
+               zebra_gr_delete_stale_client(info);
+       }
+       return 0;
+}
+
+
+/*
+ * Function to process to check if route entry is stale
+ * or has been updated.
+ */
+static void zebra_gr_process_route_entry(struct zserv *client,
+                                        struct route_node *rn,
+                                        struct route_entry *re)
+{
+       char buf[PREFIX2STR_BUFFER];
+
+       if ((client == NULL) || (rn == NULL) || (re == NULL))
+               return;
+
+       /* If the route is not refreshed after restart, delete the entry */
+       if (re->uptime < client->restart_time) {
+               if (IS_ZEBRA_DEBUG_RIB) {
+                       prefix2str(&rn->p, buf, sizeof(buf));
+                       zlog_debug("%s: Client %s stale route %s is deleted",
+                                  __func__, zebra_route_string(client->proto),
+                                  buf);
+               }
+               rib_delnode(rn, re);
+       }
+}
+
+/*
+ * This function walks through the route table for all vrf and deletes
+ * the stale routes for the restarted client specified by the protocol
+ * type
+ */
+static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info,
+                                          struct zebra_vrf *zvrf)
+{
+       struct route_node *rn, *curr;
+       struct route_entry *re;
+       struct route_entry *next;
+       struct route_table *table;
+       int32_t n = 0;
+       struct prefix *p;
+       afi_t afi, curr_afi;
+       uint8_t proto;
+       uint16_t instance;
+       struct zserv *s_client;
+
+       if ((info == NULL) || (zvrf == NULL))
+               return -1;
+
+       s_client = info->stale_client_ptr;
+       if (s_client == NULL) {
+               LOG_GR("%s: Stale client not present", __func__);
+               return -1;
+       }
+
+       proto = s_client->proto;
+       instance = s_client->instance;
+       curr_afi = info->current_afi;
+
+       LOG_GR("%s: Client %s stale routes are being deleted", __func__,
+              zebra_route_string(proto));
+
+       /* Process routes for all AFI */
+       for (afi = curr_afi; afi < AFI_MAX; afi++) {
+               table = zvrf->table[afi][SAFI_UNICAST];
+               p = info->current_prefix;
+
+               if (table) {
+                       /*
+                        * If the current prefix is NULL then get the first
+                        * route entry in the table
+                        */
+                       if (p == NULL) {
+                               rn = route_top(table);
+                               if (rn == NULL)
+                                       continue;
+                               p = XCALLOC(MTYPE_TMP, sizeof(struct prefix));
+                               if (p == NULL)
+                                       return -1;
+                               curr = rn;
+                               prefix_copy(p, &rn->p);
+                       } else
+                               /* Get the next route entry */
+                               curr = route_table_get_next(table, p);
+
+                       for (rn = curr; rn; rn = srcdest_route_next(rn)) {
+                               RNODE_FOREACH_RE_SAFE (rn, re, next) {
+                                       if (CHECK_FLAG(re->status,
+                                                      ROUTE_ENTRY_REMOVED))
+                                               continue;
+                                       /* If the route refresh is received
+                                        * after restart then do not delete
+                                        * the route
+                                        */
+                                       if (re->type == proto
+                                           && re->instance == instance) {
+                                               zebra_gr_process_route_entry(
+                                                       s_client, rn, re);
+                                               n++;
+                                       }
+
+                                       /* If the max route count is reached
+                                        * then timer thread will be restarted
+                                        * Store the current prefix and afi
+                                        */
+                                       if ((n >= ZEBRA_MAX_STALE_ROUTE_COUNT)
+                                           && (info->delete == false)) {
+                                               prefix_copy(p, &rn->p);
+                                               info->current_afi = afi;
+                                               info->current_prefix = p;
+                                               return n;
+                                       }
+                               }
+                       }
+               }
+               /*
+                * Reset the current prefix to indicate processing completion
+                * of the current AFI
+                */
+               if (info->current_prefix) {
+                       XFREE(MTYPE_TMP, info->current_prefix);
+                       info->current_prefix = NULL;
+               }
+               continue;
+       }
+       return 0;
+}
+
+/*
+ * Delete the stale routes when client is restarted and routes are not
+ * refreshed within the stale timeout
+ */
+static int32_t zebra_gr_delete_stale_routes(struct client_gr_info *info)
+{
+       struct vrf *vrf;
+       struct zebra_vrf *zvrf;
+       uint64_t cnt = 0;
+
+       if (info == NULL)
+               return -1;
+
+       /* Get the current VRF */
+       vrf = vrf_lookup_by_id(info->vrf_id);
+       if (vrf == NULL) {
+               LOG_GR("%s: Invalid VRF %d", __func__, info->vrf_id);
+               return -1;
+       }
+
+       zvrf = vrf->info;
+       if (zvrf == NULL) {
+               LOG_GR("%s: Invalid VRF entry %d", __func__, info->vrf_id);
+               return -1;
+       }
+
+       cnt = zebra_gr_delete_stale_route(info, zvrf);
+       return cnt;
+}
+
+/*
+ * This function checks if route update for all AFI, SAFI is completed
+ * and cancels the stale timer
+ */
+static void zebra_gr_process_client_stale_routes(struct zserv *client,
+                                                vrf_id_t vrf_id)
+{
+       struct client_gr_info *info = NULL;
+       afi_t afi;
+       safi_t safi;
+
+       TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+               if (info->vrf_id == vrf_id)
+                       break;
+       }
+
+       if (info == NULL)
+               return;
+
+       /* Check if route update completed for all AFI, SAFI */
+       for (afi = AFI_IP; afi < AFI_MAX; afi++)
+               for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) {
+                       if (info->af_enabled[afi][safi]) {
+                               if (!info->route_sync[afi][safi]) {
+                                       LOG_GR(
+                                          "%s: Client %s route update not completed for AFI %d, SAFI %d",
+                                          __func__, zebra_route_string(
+                                                           client->proto),
+                                          afi, safi);
+                                       return;
+                               }
+                       }
+               }
+
+       /*
+        * Route update completed for all AFI, SAFI
+        * Cancel the stale timer and process the routes
+        */
+       if (info->t_stale_removal) {
+               LOG_GR("%s: Client %s cancled stale delete timer vrf %d",
+                      __func__, zebra_route_string(client->proto),
+                      info->vrf_id);
+               THREAD_OFF(info->t_stale_removal);
+               thread_execute(zrouter.master,
+                              zebra_gr_route_stale_delete_timer_expiry, info,
+                              0);
+       }
+}
index f6bd5f458647be6a8ba05beff7efc61d0206499d..fc7804a409e22269376c19316a36aa3188406111 100644 (file)
@@ -797,13 +797,11 @@ int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type)
                }
 
                for (i = 0; i < mlag_msg.msg_cnt; i++) {
-                       if (pay_load[i]->vrf_name)
-                               XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
+                       XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
                        if (pay_load[i]->owner_id == MLAG_OWNER_INTERFACE
                            && pay_load[i]->intf_name)
                                XFREE(MTYPE_MLAG_PBUF, pay_load[i]->intf_name);
-                       if (pay_load[i])
-                               XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
+                       XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
                }
                XFREE(MTYPE_MLAG_PBUF, pay_load);
                if (cleanup == true)
@@ -861,13 +859,11 @@ int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type)
                }
 
                for (i = 0; i < mlag_msg.msg_cnt; i++) {
-                       if (pay_load[i]->vrf_name)
-                               XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
+                       XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
                        if (pay_load[i]->owner_id == MLAG_OWNER_INTERFACE
                            && pay_load[i]->intf_name)
                                XFREE(MTYPE_MLAG_PBUF, pay_load[i]->intf_name);
-                       if (pay_load[i])
-                               XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
+                       XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
                }
                XFREE(MTYPE_MLAG_PBUF, pay_load);
                if (cleanup)
@@ -914,8 +910,7 @@ int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type)
                        mlag_lib_msgid_to_str(mlag_msg.msg_type, buf,
                                              sizeof(buf)),
                        len);
-       if (hdr.data.data)
-               XFREE(MTYPE_MLAG_PBUF, hdr.data.data);
+       XFREE(MTYPE_MLAG_PBUF, hdr.data.data);
 
        return len;
 }
index 74303073206b6ac213ddd1dc60156b6bcf00cd75..bb95e72382c1840c4305ae04cf811ac6c91d82c3 100644 (file)
@@ -49,6 +49,9 @@ DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
 /* id counter to keep in sync with kernel */
 uint32_t id_counter;
 
+/*  */
+static bool g_nexthops_enabled = true;
+
 static struct nhg_hash_entry *depends_find(const struct nexthop *nh,
                                           afi_t afi);
 static void depends_add(struct nhg_connected_tree_head *head,
@@ -99,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
@@ -288,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);
        }
 }
 
@@ -481,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,
@@ -504,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):
@@ -531,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)
@@ -591,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;
 }
@@ -681,7 +714,6 @@ static void nhg_ctx_free(struct nhg_ctx **ctx)
 
 done:
        XFREE(MTYPE_NHG_CTX, *ctx);
-       *ctx = NULL;
 }
 
 static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
@@ -1031,11 +1063,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);
 
@@ -1104,8 +1136,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 *
@@ -1146,6 +1184,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,
@@ -1153,7 +1199,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;
 }
@@ -1442,7 +1488,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                 * resolved by a route NH1. The exception is if the route is a
                 * host route.
                 */
-               if (top && rn == top)
+               if (rn == top)
                        if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
                            || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
                                if (IS_ZEBRA_DEBUG_RIB_DETAILED)
@@ -1985,3 +2031,18 @@ void zebra_nhg_sweep_table(struct hash *hash)
 {
        hash_iterate(hash, zebra_nhg_sweep_entry, NULL);
 }
+
+/* Global control to disable use of kernel nexthops, if available. We can't
+ * force the kernel to support nexthop ids, of course, but we can disable
+ * zebra's use of them, for testing e.g. By default, if the kernel supports
+ * nexthop ids, zebra uses them.
+ */
+void zebra_nhg_enable_kernel_nexthops(bool set)
+{
+       g_nexthops_enabled = set;
+}
+
+bool zebra_nhg_kernel_nexthops_enabled(void)
+{
+       return g_nexthops_enabled;
+}
index 522ec1e9ddfb6615cc5b98431a2dfcf559fe3f09..4d001944b7f26c17cefb78699a6f0cb01dbf58de 100644 (file)
@@ -153,6 +153,13 @@ struct nhg_ctx {
        enum nhg_ctx_status status;
 };
 
+/* Global control to disable use of kernel nexthops, if available. We can't
+ * force the kernel to support nexthop ids, of course, but we can disable
+ * zebra's use of them, for testing e.g. By default, if the kernel supports
+ * nexthop ids, zebra uses them.
+ */
+void zebra_nhg_enable_kernel_nexthops(bool set);
+bool zebra_nhg_kernel_nexthops_enabled(void);
 
 /**
  * NHE abstracted tree functions.
@@ -195,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 *
@@ -227,4 +234,5 @@ extern void zebra_nhg_sweep_table(struct hash *hash);
 /* Nexthop resolution processing */
 struct route_entry; /* Forward ref to avoid circular includes */
 extern int nexthop_active_update(struct route_node *rn, struct route_entry *re);
-#endif
+
+#endif /* __ZEBRA_NHG_H__ */
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 0200ef2a5e0b88207b8299400d39123dea2a7603..f3112cc9c039bd564819e75cd8190fe60d529d95 100644 (file)
@@ -3115,8 +3115,6 @@ static struct rib_update_ctx *rib_update_ctx_init(vrf_id_t vrf_id,
 static void rib_update_ctx_fini(struct rib_update_ctx **ctx)
 {
        XFREE(MTYPE_RIB_UPDATE_CTX, *ctx);
-
-       *ctx = NULL;
 }
 
 static int rib_update_handler(struct thread *thread)
index d8ad8a68646d778cfbba94438aa39ebaad3afe07..59bd0e55f0caedb88dac076000cfbc6daec5f04b 100644 (file)
@@ -117,6 +117,9 @@ struct zebra_router {
        /* Lists of clients who have connected to us */
        struct list *client_list;
 
+       /* List of clients in GR */
+       struct list *stale_client_list;
+
        struct zebra_router_table_head tables;
 
        /* L3-VNI hash table (for EVPN). Only in default instance */
index c8b96011dc3b5ed85219b968ea3b9c98202f61b4..86ec2ffef34e9f5571fbe978ea720f9cf54635fb 100644 (file)
@@ -1123,9 +1123,11 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
        vty_out(vty, "     RefCnt: %d\n", nhe->refcnt);
 
        if (nhe_vrf)
-               vty_out(vty, "     VRF: %s\n", nhe_vrf->name);
+               vty_out(vty, "     VRF: %s AFI: %s\n", nhe_vrf->name,
+                       afi2str(nhe->afi));
        else
-               vty_out(vty, "     VRF: UNKNOWN\n");
+               vty_out(vty, "     VRF: UNKNOWN AFI: %s\n",
+                       afi2str(nhe->afi));
 
        if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE))
                vty_out(vty, "     Duplicate - from kernel not hashable\n");
@@ -1276,25 +1278,44 @@ static int show_nexthop_group_id_cmd_helper(struct vty *vty, uint32_t id)
        return CMD_SUCCESS;
 }
 
-static void show_nexthop_group_cmd_helper(struct vty *vty,
-                                         struct zebra_vrf *zvrf, afi_t afi)
+/* Helper function for iteration through the hash of nexthop-groups/nhe-s */
+
+struct nhe_show_context {
+       struct vty *vty;
+       vrf_id_t vrf_id;
+       afi_t afi;
+};
+
+static int nhe_show_walker(struct hash_bucket *bucket, void *arg)
 {
-       struct list *list = hash_to_list(zrouter.nhgs);
-       struct nhg_hash_entry *nhe = NULL;
-       struct listnode *node = NULL;
+       struct nhe_show_context *ctx = arg;
+       struct nhg_hash_entry *nhe;
 
-       for (ALL_LIST_ELEMENTS_RO(list, node, nhe)) {
+       nhe = bucket->data; /* We won't be offered NULL buckets */
 
-               if (afi && nhe->afi != afi)
-                       continue;
+       if (ctx->afi && nhe->afi != ctx->afi)
+               goto done;
 
-               if (nhe->vrf_id != zvrf->vrf->vrf_id)
-                       continue;
+       if (ctx->vrf_id && nhe->vrf_id != ctx->vrf_id)
+               goto done;
 
-               show_nexthop_group_out(vty, nhe);
-       }
+       show_nexthop_group_out(ctx->vty, nhe);
+
+done:
+       return HASHWALK_CONTINUE;
+}
+
+static void show_nexthop_group_cmd_helper(struct vty *vty,
+                                         struct zebra_vrf *zvrf,
+                                         afi_t afi)
+{
+       struct nhe_show_context ctx;
+
+       ctx.vty = vty;
+       ctx.afi = afi;
+       ctx.vrf_id = zvrf->vrf->vrf_id;
 
-       list_delete(&list);
+       hash_walk(zrouter.nhgs_id, nhe_show_walker, &ctx);
 }
 
 static void if_nexthop_group_dump_vty(struct vty *vty, struct interface *ifp)
@@ -1351,18 +1372,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 +1394,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;
 
@@ -1395,7 +1422,8 @@ DEFPY (show_nexthop_group,
                zvrf = zebra_vrf_lookup_by_name(VRF_DEFAULT_NAME);
 
        if (!zvrf) {
-               vty_out(vty, "VRF %s specified does not exist", vrf_name);
+               vty_out(vty, "%% VRF '%s' specified does not exist\n",
+                       vrf_name);
                return CMD_WARNING;
        }
 
@@ -1404,6 +1432,19 @@ DEFPY (show_nexthop_group,
        return CMD_SUCCESS;
 }
 
+DEFPY_HIDDEN(nexthop_group_use_enable,
+            nexthop_group_use_enable_cmd,
+            "[no] zebra nexthop kernel enable",
+            NO_STR
+            ZEBRA_STR
+            "Nexthop configuration \n"
+            "Configure use of kernel nexthops\n"
+            "Enable kernel nexthops\n")
+{
+       zebra_nhg_enable_kernel_nexthops(!no);
+       return CMD_SUCCESS;
+}
+
 DEFUN (no_ip_nht_default_route,
        no_ip_nht_default_route_cmd,
        "no ip nht resolve-via-default",
@@ -3115,6 +3156,10 @@ static int config_write_protocol(struct vty *vty)
        /* Include dataplane info */
        dplane_config_write_helper(vty);
 
+       /* Include nexthop-group config */
+       if (!zebra_nhg_kernel_nexthops_enabled())
+               vty_out(vty, "no zebra nexthop kernel enable\n");
+
        return 1;
 }
 
@@ -3486,6 +3531,7 @@ void zebra_vty_init(void)
        install_element(CONFIG_NODE, &no_zebra_workqueue_timer_cmd);
        install_element(CONFIG_NODE, &zebra_packet_process_cmd);
        install_element(CONFIG_NODE, &no_zebra_packet_process_cmd);
+       install_element(CONFIG_NODE, &nexthop_group_use_enable_cmd);
 
        install_element(VIEW_NODE, &show_nexthop_group_cmd);
        install_element(VIEW_NODE, &show_interface_nexthop_group_cmd);
index ffb2528a245716716984c08d78528142195c6ada..4b56581ca9ba7282f30c0a3893caf071847bccbb 100644 (file)
@@ -3212,7 +3212,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
                        vtep_ip = n->r_vtep_ip;
                        /* Mark appropriately */
                        UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
-                       n->r_vtep_ip.s_addr = 0;
+                       n->r_vtep_ip.s_addr = INADDR_ANY;
                        SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
                        n->ifindex = ifp->ifindex;
                }
@@ -9985,7 +9985,7 @@ static zebra_vxlan_sg_t *zebra_vxlan_sg_add(struct zebra_vrf *zvrf,
         * 2. the XG entry is used by pimd to setup the
         * vxlan-termination-mroute
         */
-       if (sg->src.s_addr) {
+       if (sg->src.s_addr != INADDR_ANY) {
                memset(&sip, 0, sizeof(sip));
                parent = zebra_vxlan_sg_do_ref(zvrf, sip, sg->grp);
                if (!parent)
@@ -10017,7 +10017,7 @@ static void zebra_vxlan_sg_del(zebra_vxlan_sg_t *vxlan_sg)
        /* On SG entry deletion remove the reference to its parent XG
         * entry
         */
-       if (vxlan_sg->sg.src.s_addr) {
+       if (vxlan_sg->sg.src.s_addr != INADDR_ANY) {
                memset(&sip, 0, sizeof(sip));
                zebra_vxlan_sg_do_deref(zvrf, sip, vxlan_sg->sg.grp);
        }
@@ -10076,7 +10076,8 @@ static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
 {
        struct zebra_vrf *zvrf;
 
-       if (!local_vtep_ip.s_addr || !mcast_grp.s_addr)
+       if (local_vtep_ip.s_addr == INADDR_ANY
+           || mcast_grp.s_addr == INADDR_ANY)
                return;
 
        zvrf = vrf_info_lookup(VRF_DEFAULT);
@@ -10091,7 +10092,8 @@ static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
 {
        struct zebra_vrf *zvrf;
 
-       if (!local_vtep_ip.s_addr || !mcast_grp.s_addr)
+       if (local_vtep_ip.s_addr == INADDR_ANY
+           || mcast_grp.s_addr == INADDR_ANY)
                return;
 
        zvrf = vrf_info_lookup(VRF_DEFAULT);
index cca926f3b060f4e0730856f75d4d1f1fc0779ad9..2a5352a1da26e063a00748c07cb77bab5fd24c4b 100644 (file)
@@ -557,6 +557,9 @@ DEFINE_KOOH(zserv_client_close, (struct zserv *client), (client));
  */
 static void zserv_client_free(struct zserv *client)
 {
+       if (client == NULL)
+               return;
+
        hook_call(zserv_client_close, client);
 
        /* Close file descriptor. */
@@ -565,11 +568,14 @@ static void zserv_client_free(struct zserv *client)
 
                close(client->sock);
 
-               nroutes = rib_score_proto(client->proto, client->instance);
-               zlog_notice(
-                       "client %d disconnected. %lu %s routes removed from the rib",
-                       client->sock, nroutes,
-                       zebra_route_string(client->proto));
+               if (!client->gr_instance_count) {
+                       nroutes = rib_score_proto(client->proto,
+                                                 client->instance);
+                       zlog_notice(
+                               "client %d disconnected %lu %s routes removed from the rib",
+                               client->sock, nroutes,
+                               zebra_route_string(client->proto));
+               }
                client->sock = -1;
        }
 
@@ -600,7 +606,25 @@ static void zserv_client_free(struct zserv *client)
        }
        vrf_bitmap_free(client->ridinfo);
 
-       XFREE(MTYPE_TMP, client);
+       /*
+        * If any instance are graceful restart enabled,
+        * client is not deleted
+        */
+       if (!client->gr_instance_count) {
+               if (IS_ZEBRA_DEBUG_EVENT)
+                       zlog_debug("%s: Deleting client %s", __func__,
+                                  zebra_route_string(client->proto));
+               XFREE(MTYPE_TMP, client);
+       } else {
+               /* Handle cases where client has GR instance. */
+               if (IS_ZEBRA_DEBUG_EVENT)
+                       zlog_debug("%s: client %s restart enabled", __func__,
+                                  zebra_route_string(client->proto));
+               if (zebra_gr_client_disconnect(client) < 0)
+                       zlog_err(
+                               "%s: GR enabled but could not handle disconnect event",
+                               __func__);
+       }
 }
 
 void zserv_close_client(struct zserv *client)
@@ -670,6 +694,7 @@ static struct zserv *zserv_client_create(int sock)
        pthread_mutex_init(&client->ibuf_mtx, NULL);
        pthread_mutex_init(&client->obuf_mtx, NULL);
        client->wb = buffer_new(0);
+       TAILQ_INIT(&(client->gr_info_queue));
 
        atomic_store_explicit(&client->connect_time, (uint32_t) monotime(NULL),
                              memory_order_relaxed);
@@ -861,12 +886,14 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen)
        return buf;
 }
 
+/* Display client info details */
 static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
 {
        char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
        char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF];
        time_t connect_time, last_read_time, last_write_time;
        uint32_t last_read_cmd, last_write_cmd;
+       struct client_gr_info *info = NULL;
 
        vty_out(vty, "Client: %s", zebra_route_string(client->proto));
        if (client->instance)
@@ -945,12 +972,100 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
        vty_out(vty, "MAC-IP add notifications: %d\n", client->macipadd_cnt);
        vty_out(vty, "MAC-IP delete notifications: %d\n", client->macipdel_cnt);
 
+       TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+               vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id));
+               vty_out(vty, "Capabilities : ");
+               switch (info->capabilities) {
+               case ZEBRA_CLIENT_GR_CAPABILITIES:
+                       vty_out(vty, "Graceful Restart\n");
+                       break;
+               case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+               case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+               case ZEBRA_CLIENT_GR_DISABLE:
+               case ZEBRA_CLIENT_RIB_STALE_TIME:
+                       vty_out(vty, "None\n");
+                       break;
+               }
+       }
+
 #if defined DEV_BUILD
        vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n",
                client->ibuf_fifo->count, client->ibuf_fifo->max_count,
                client->obuf_fifo->count, client->obuf_fifo->max_count);
 #endif
        vty_out(vty, "\n");
+}
+
+/* Display stale client information */
+static void zebra_show_stale_client_detail(struct vty *vty,
+                                          struct zserv *client)
+{
+       char buf[PREFIX2STR_BUFFER];
+       struct tm *tm;
+       struct timeval tv;
+       time_t uptime;
+       struct client_gr_info *info = NULL;
+       struct zserv *s = NULL;
+
+       if (client->instance)
+               vty_out(vty, " Instance: %d", client->instance);
+
+       TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+               vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id));
+               vty_out(vty, "Capabilities : ");
+               switch (info->capabilities) {
+               case ZEBRA_CLIENT_GR_CAPABILITIES:
+                       vty_out(vty, "Graceful Restart\n");
+                       break;
+               case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+               case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+               case ZEBRA_CLIENT_GR_DISABLE:
+               case ZEBRA_CLIENT_RIB_STALE_TIME:
+                       vty_out(vty, "None\n");
+                       break;
+               }
+
+               if (ZEBRA_CLIENT_GR_ENABLED(info->capabilities)) {
+                       if (info->stale_client_ptr) {
+                               s = (struct zserv *)(info->stale_client_ptr);
+                               uptime = monotime(&tv);
+                               uptime -= s->restart_time;
+                               tm = gmtime(&uptime);
+                               vty_out(vty, "Last restart time : ");
+                               if (uptime < ONE_DAY_SECOND)
+                                       vty_out(vty, "%02d:%02d:%02d",
+                                               tm->tm_hour, tm->tm_min,
+                                               tm->tm_sec);
+                               else if (uptime < ONE_WEEK_SECOND)
+                                       vty_out(vty, "%dd%02dh%02dm",
+                                               tm->tm_yday, tm->tm_hour,
+                                               tm->tm_min);
+                               else
+                                       vty_out(vty, "%02dw%dd%02dh",
+                                               tm->tm_yday / 7,
+                                               tm->tm_yday - ((tm->tm_yday / 7)
+                                                              * 7),
+                                               tm->tm_hour);
+                               vty_out(vty, "  ago\n");
+
+                               vty_out(vty, "Stalepath removal time: %d sec\n",
+                                       info->stale_removal_time);
+                               if (info->t_stale_removal) {
+                                       vty_out(vty,
+                                               "Stale delete timer: %ld sec\n",
+                                               thread_timer_remain_second(
+                                                       info->t_stale_removal));
+                               }
+                       }
+                       vty_out(vty, "Current AFI : %d\n", info->current_afi);
+                       if (info->current_prefix) {
+                               prefix2str(info->current_prefix, buf,
+                                          sizeof(buf));
+                               vty_out(vty, "Current prefix : %s\n", buf);
+                       }
+               }
+       }
+       vty_out(vty, "\n");
        return;
 }
 
@@ -1002,8 +1117,12 @@ DEFUN (show_zebra_client,
        struct listnode *node;
        struct zserv *client;
 
-       for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
+       for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
                zebra_show_client_detail(vty, client);
+               vty_out(vty, "Stale Client Information\n");
+               vty_out(vty, "------------------------\n");
+               zebra_show_stale_client_detail(vty, client);
+       }
 
        return CMD_SUCCESS;
 }
@@ -1047,6 +1166,7 @@ void zserv_init(void)
 {
        /* Client list init. */
        zrouter.client_list = list_new();
+       zrouter.stale_client_list = list_new();
 
        /* Misc init. */
        zsock = -1;
index d8d82a52ec47bab8765843ba94351734211fed23..77ea19202f334ba43e6fa6fcdee7a18768c42932 100644 (file)
@@ -52,6 +52,42 @@ extern "C" {
 
 #define ZEBRA_RMAP_DEFAULT_UPDATE_TIMER 5 /* disabled by default */
 
+
+/* Stale route marker timer */
+#define ZEBRA_DEFAULT_STALE_UPDATE_DELAY 1
+
+/* Count of stale routes processed in timer context */
+#define ZEBRA_MAX_STALE_ROUTE_COUNT 50000
+
+/* Graceful Restart information */
+struct client_gr_info {
+       /* VRF for which GR enabled */
+       vrf_id_t vrf_id;
+
+       /* AFI */
+       afi_t current_afi;
+
+       /* Stale time and GR cap */
+       uint32_t stale_removal_time;
+       enum zserv_client_capabilities capabilities;
+
+       /* GR commands */
+       bool delete;
+       bool gr_enable;
+       bool stale_client;
+
+       /* Route sync and enable flags for AFI/SAFI */
+       bool af_enabled[AFI_MAX][SAFI_MAX];
+       bool route_sync[AFI_MAX][SAFI_MAX];
+
+       /* Book keeping */
+       struct prefix *current_prefix;
+       void *stale_client_ptr;
+       struct thread *t_stale_removal;
+
+       TAILQ_ENTRY(client_gr_info) gr_info;
+};
+
 /* Client structure. */
 struct zserv {
        /* Client pthread */
@@ -170,6 +206,19 @@ struct zserv {
        _Atomic uint32_t last_read_cmd;
        /* command code of last message written */
        _Atomic uint32_t last_write_cmd;
+
+       /*
+        * Number of instances configured with
+        * graceful restart
+        */
+       uint32_t gr_instance_count;
+       time_t restart_time;
+
+       /*
+        * Graceful restart information for
+        * each instance
+        */
+       TAILQ_HEAD(info_list, client_gr_info) gr_info_queue;
 };
 
 #define ZAPI_HANDLER_ARGS                                                      \
@@ -230,7 +279,6 @@ extern int zserv_send_message(struct zserv *client, struct stream *msg);
  */
 extern struct zserv *zserv_find_client(uint8_t proto, unsigned short instance);
 
-
 /*
  * Close a client.
  *
@@ -242,7 +290,6 @@ extern struct zserv *zserv_find_client(uint8_t proto, unsigned short instance);
  */
 extern void zserv_close_client(struct zserv *client);
 
-
 /*
  * Log a ZAPI message hexdump.
  *
@@ -265,6 +312,16 @@ extern void zserv_read_file(char *input);
 /* TODO */
 int zebra_finalize(struct thread *event);
 
+/*
+ * Graceful restart functions.
+ */
+extern int zebra_gr_client_disconnect(struct zserv *client);
+extern void zebra_gr_client_reconnect(struct zserv *client);
+extern void zebra_gr_stale_client_cleanup(struct list *client_list);
+extern void zread_client_capabilities(struct zserv *client, struct zmsghdr *hdr,
+                                     struct stream *msg,
+                                     struct zebra_vrf *zvrf);
+
 #ifdef __cplusplus
 }
 #endif