]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #4877 from mjstapp/dplane_neighs
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 4 Sep 2019 14:23:31 +0000 (10:23 -0400)
committerGitHub <noreply@github.com>
Wed, 4 Sep 2019 14:23:31 +0000 (10:23 -0400)
zebra: move evpn neighbors to dataplane

189 files changed:
.clang-format
bfdd/bfd.c
bfdd/bfd_packet.c
bgpd/bgp_advertise.c
bgpd/bgp_advertise.h
bgpd/bgp_bmp.c [new file with mode: 0644]
bgpd/bgp_bmp.h [new file with mode: 0644]
bgpd/bgp_evpn.c
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_fsm.c
bgpd/bgp_io.c
bgpd/bgp_keepalives.c
bgpd/bgp_network.c
bgpd/bgp_open.c
bgpd/bgp_packet.c
bgpd/bgp_route.c
bgpd/bgp_routemap.c
bgpd/bgp_rpki.c
bgpd/bgp_vty.c
bgpd/bgp_vty.h
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/rfapi.c
bgpd/rfapi/vnc_zebra.c
bgpd/subdir.am
configure.ac
debian/frr.install
doc/developer/library.rst
doc/developer/locking.rst [new file with mode: 0644]
doc/developer/subdir.am
doc/developer/workflow.rst
doc/user/bgp.rst
doc/user/bmp.rst [new file with mode: 0644]
doc/user/eigrpd.rst
doc/user/index.rst
doc/user/pbr.rst
doc/user/rpki.rst
doc/user/subdir.am
eigrpd/eigrp_cli.c
eigrpd/eigrp_filter.c
eigrpd/eigrp_filter.h
eigrpd/eigrp_fsm.c
eigrpd/eigrp_hello.c
eigrpd/eigrp_interface.c
eigrpd/eigrp_main.c
eigrpd/eigrp_neighbor.c
eigrpd/eigrp_neighbor.h
eigrpd/eigrp_network.c
eigrpd/eigrp_network.h
eigrpd/eigrp_northbound.c
eigrpd/eigrp_packet.c
eigrpd/eigrp_routemap.c
eigrpd/eigrp_structs.h
eigrpd/eigrp_topology.c
eigrpd/eigrp_topology.h
eigrpd/eigrp_update.c
eigrpd/eigrp_vrf.c [new file with mode: 0644]
eigrpd/eigrp_vrf.h [new file with mode: 0644]
eigrpd/eigrp_vty.c
eigrpd/eigrp_zebra.c
eigrpd/eigrp_zebra.h
eigrpd/eigrpd.c
eigrpd/eigrpd.h
eigrpd/subdir.am
isisd/isis_bfd.c
isisd/isis_bpf.c
isisd/isis_dlpi.c
isisd/isis_memory.c
isisd/isis_memory.h
isisd/isis_northbound.c
isisd/isis_pfpacket.c
isisd/isis_route.c
isisd/isis_route.h
isisd/isis_zebra.c
isisd/isisd.c
isisd/isisd.h
ldpd/socket.c
lib/command.c
lib/command.h
lib/compiler.h
lib/ferr.c
lib/frr_pthread.c
lib/frr_pthread.h
lib/frrcu.c
lib/hash.c
lib/if.c
lib/if.h
lib/log.c
lib/monotime.h
lib/northbound.c
lib/northbound.h
lib/northbound_cli.c
lib/northbound_sysrepo.c
lib/prefix.c
lib/privs.c
lib/privs.h
lib/pullwr.c [new file with mode: 0644]
lib/pullwr.h [new file with mode: 0644]
lib/routemap.c
lib/routemap.h
lib/stream.c
lib/subdir.am
lib/thread.c
lib/vrf.c
lib/vty.c
lib/zclient.c
ospf6d/ospf6_asbr.c
ospf6d/ospf6_network.c
ospfd/ospf_interface.c
ospfd/ospf_interface.h
ospfd/ospf_ism.h
ospfd/ospf_network.c
ospfd/ospf_packet.c
ospfd/ospf_packet.h
ospfd/ospf_vty.c
ospfd/ospfd.c
pbrd/pbr_map.c
pbrd/pbr_map.h
pbrd/pbr_vty.c
pbrd/pbr_zebra.c
pimd/pim_mroute.c
pimd/pim_msdp_socket.c
pimd/pim_sock.c
pimd/pim_vty.c
pimd/pimd.h
python/clidef.py
redhat/frr.spec.in
ripd/ripd.c
ripngd/ripng_interface.c
ripngd/ripngd.c
tests/bgpd/test_peer_attr.c
tests/lib/test_privs.c
tests/topotests/Dockerfile
tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py
tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json [new file with mode: 0755]
tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json [new file with mode: 0755]
tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py [new file with mode: 0755]
tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py [new file with mode: 0755]
tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py
tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py
tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py
tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/adjacencies.py
tests/topotests/bgp_rfapi_basic_sanity/scripts/adjacencies.py
tests/topotests/docker/inner/compile_frr.sh
tests/topotests/example-topojson-test/test_topo_json_single_link_loopback/test_example_topojson.py
tests/topotests/lib/bgp.py
tests/topotests/lib/common_config.py
tests/topotests/lib/topojson.py
tests/topotests/pytest.ini
tools/checkpatch.pl
tools/coccinelle/frr_with_mutex.cocci [new file with mode: 0644]
tools/coccinelle/zprivs.cocci
vrrpd/vrrp.c
vrrpd/vrrp_arp.c
vrrpd/vrrp_ndisc.c
vtysh/vtysh.c
zebra/connected.c
zebra/connected.h
zebra/if_ioctl_solaris.c
zebra/if_netlink.c
zebra/interface.c
zebra/ioctl.c
zebra/ioctl_solaris.c
zebra/ipforward_proc.c
zebra/ipforward_solaris.c
zebra/ipforward_sysctl.c
zebra/irdp_main.c
zebra/kernel_netlink.c
zebra/kernel_socket.c
zebra/rt_netlink.c
zebra/rt_socket.c
zebra/rtadv.c
zebra/zapi_msg.c
zebra/zebra_dplane.c
zebra/zebra_fpm.c
zebra/zebra_mpls_openbsd.c
zebra/zebra_netns_notify.c
zebra/zebra_nhg.c
zebra/zebra_ns.c
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zebra_routemap.c
zebra/zebra_vrf.c
zebra/zebra_vrf.h
zebra/zebra_vty.c
zebra/zserv.c

index 4bd962747fa492853dc386e13b6154d252f6417b..654577d936a8ac5e9e349b48a6f0e96fb35a7249 100644 (file)
@@ -28,6 +28,8 @@ ForEachMacros:
   - frr_each
   - frr_each_safe
   - frr_each_from
+  - frr_with_mutex
+  - frr_with_privs
   - LIST_FOREACH
   - LIST_FOREACH_SAFE
   - SLIST_FOREACH
index 5d143d4e5f60379fd27d8e86a9574e9c206bf772..1f1568f5114399dc439c830781591f4fccfa525e 100644 (file)
@@ -1706,6 +1706,8 @@ static int bfd_vrf_disable(struct vrf *vrf)
        socket_close(&bvrf->bg_mhop);
        socket_close(&bvrf->bg_shop6);
        socket_close(&bvrf->bg_mhop6);
+       socket_close(&bvrf->bg_echo);
+       socket_close(&bvrf->bg_echov6);
 
        /* free context */
        XFREE(MTYPE_BFDD_VRF, bvrf);
index d68a1ad5fd98759b884f4f5fbce3e91744f3bc1b..7fbe6db163ac95ee446efec8af283540caff709e 100644 (file)
@@ -894,7 +894,7 @@ int bp_udp_shop(vrf_id_t vrf_id)
 {
        int sd;
 
-       frr_elevate_privs(&bglobal.bfdd_privs) {
+       frr_with_privs(&bglobal.bfdd_privs) {
                sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
        }
        if (sd == -1)
@@ -909,7 +909,7 @@ int bp_udp_mhop(vrf_id_t vrf_id)
 {
        int sd;
 
-       frr_elevate_privs(&bglobal.bfdd_privs) {
+       frr_with_privs(&bglobal.bfdd_privs) {
                sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
        }
        if (sd == -1)
@@ -934,7 +934,7 @@ int bp_peer_socket(const struct bfd_session *bs)
            && bs->key.vrfname[0])
                device_to_bind = (const char *)bs->key.vrfname;
 
-       frr_elevate_privs(&bglobal.bfdd_privs) {
+       frr_with_privs(&bglobal.bfdd_privs) {
                sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC,
                                bs->vrf->vrf_id, device_to_bind);
        }
@@ -1001,7 +1001,7 @@ int bp_peer_socketv6(const struct bfd_session *bs)
            && bs->key.vrfname[0])
                device_to_bind = (const char *)bs->key.vrfname;
 
-       frr_elevate_privs(&bglobal.bfdd_privs) {
+       frr_with_privs(&bglobal.bfdd_privs) {
                sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC,
                                bs->vrf->vrf_id, device_to_bind);
        }
@@ -1121,7 +1121,7 @@ int bp_udp6_shop(vrf_id_t vrf_id)
 {
        int sd;
 
-       frr_elevate_privs(&bglobal.bfdd_privs) {
+       frr_with_privs(&bglobal.bfdd_privs) {
                sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
        }
        if (sd == -1)
@@ -1137,7 +1137,7 @@ int bp_udp6_mhop(vrf_id_t vrf_id)
 {
        int sd;
 
-       frr_elevate_privs(&bglobal.bfdd_privs) {
+       frr_with_privs(&bglobal.bfdd_privs) {
                sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL);
        }
        if (sd == -1)
@@ -1153,7 +1153,7 @@ int bp_echo_socket(vrf_id_t vrf_id)
 {
        int s;
 
-       frr_elevate_privs(&bglobal.bfdd_privs) {
+       frr_with_privs(&bglobal.bfdd_privs) {
                s = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
        }
        if (s == -1)
@@ -1169,7 +1169,7 @@ int bp_echov6_socket(vrf_id_t vrf_id)
 {
        int s;
 
-       frr_elevate_privs(&bglobal.bfdd_privs) {
+       frr_with_privs(&bglobal.bfdd_privs) {
                s = vrf_socket(AF_INET6, SOCK_DGRAM, 0, vrf_id, NULL);
        }
        if (s == -1)
index 497fb0749e19063c9703bfa11fbf378695dbe182..76a65f7f04b50fdaefb131f3d289da87b4acfbf2 100644 (file)
@@ -194,6 +194,7 @@ void bgp_adj_in_set(struct bgp_node *rn, struct peer *peer, struct attr *attr,
        adj = XCALLOC(MTYPE_BGP_ADJ_IN, sizeof(struct bgp_adj_in));
        adj->peer = peer_lock(peer); /* adj_in peer reference */
        adj->attr = bgp_attr_intern(attr);
+       adj->uptime = bgp_clock();
        adj->addpath_rx_id = addpath_id;
        BGP_ADJ_IN_ADD(rn, adj);
        bgp_lock_node(rn);
index 1b55b6e64b425f0de4c7daecf4b9e04924943726..c983598756e90612f69cb9b463204762a1892b26 100644 (file)
@@ -101,6 +101,9 @@ struct bgp_adj_in {
        /* Received attribute.  */
        struct attr *attr;
 
+       /* timestamp (monotime) */
+       time_t uptime;
+
        /* Addpath identifier */
        uint32_t addpath_rx_id;
 };
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
new file mode 100644 (file)
index 0000000..8fca202
--- /dev/null
@@ -0,0 +1,2240 @@
+/* BMP support.
+ * Copyright (C) 2018 Yasuhiro Ohara
+ * Copyright (C) 2019 David Lamparter for NetDEF, Inc.
+ *
+ * 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 "log.h"
+#include "stream.h"
+#include "sockunion.h"
+#include "command.h"
+#include "prefix.h"
+#include "thread.h"
+#include "linklist.h"
+#include "queue.h"
+#include "pullwr.h"
+#include "memory.h"
+#include "network.h"
+#include "filter.h"
+#include "lib_errors.h"
+#include "stream.h"
+#include "libfrr.h"
+#include "version.h"
+#include "jhash.h"
+#include "termtable.h"
+
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_errors.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_bmp.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_updgrp.h"
+#include "bgpd/bgp_vty.h"
+
+static void bmp_close(struct bmp *bmp);
+static struct bmp_bgp *bmp_bgp_find(struct bgp *bgp);
+static void bmp_targets_put(struct bmp_targets *bt);
+static struct bmp_bgp_peer *bmp_bgp_peer_find(uint64_t peerid);
+static struct bmp_bgp_peer *bmp_bgp_peer_get(struct peer *peer);
+static void bmp_active_disconnected(struct bmp_active *ba);
+static void bmp_active_put(struct bmp_active *ba);
+
+DEFINE_MGROUP(BMP, "BMP (BGP Monitoring Protocol)")
+
+DEFINE_MTYPE_STATIC(BMP, BMP_CONN,     "BMP connection state")
+DEFINE_MTYPE_STATIC(BMP, BMP_TARGETS,  "BMP targets")
+DEFINE_MTYPE_STATIC(BMP, BMP_TARGETSNAME, "BMP targets name")
+DEFINE_MTYPE_STATIC(BMP, BMP_LISTENER, "BMP listener")
+DEFINE_MTYPE_STATIC(BMP, BMP_ACTIVE,   "BMP active connection config")
+DEFINE_MTYPE_STATIC(BMP, BMP_ACLNAME,  "BMP access-list name")
+DEFINE_MTYPE_STATIC(BMP, BMP_QUEUE,    "BMP update queue item")
+DEFINE_MTYPE_STATIC(BMP, BMP,          "BMP instance state")
+DEFINE_MTYPE_STATIC(BMP, BMP_MIRRORQ,  "BMP route mirroring buffer")
+DEFINE_MTYPE_STATIC(BMP, BMP_PEER,     "BMP per BGP peer data")
+DEFINE_MTYPE_STATIC(BMP, BMP_OPEN,     "BMP stored BGP OPEN message")
+
+DEFINE_QOBJ_TYPE(bmp_targets)
+
+static int bmp_bgp_cmp(const struct bmp_bgp *a, const struct bmp_bgp *b)
+{
+       if (a->bgp < b->bgp)
+               return -1;
+       if (a->bgp > b->bgp)
+               return 1;
+       return 0;
+}
+
+static uint32_t bmp_bgp_hash(const struct bmp_bgp *e)
+{
+       return jhash(&e->bgp, sizeof(e->bgp), 0x55aa5a5a);
+}
+
+DECLARE_HASH(bmp_bgph, struct bmp_bgp, bbi, bmp_bgp_cmp, bmp_bgp_hash)
+
+struct bmp_bgph_head bmp_bgph;
+
+static int bmp_bgp_peer_cmp(const struct bmp_bgp_peer *a,
+               const struct bmp_bgp_peer *b)
+{
+       if (a->peerid < b->peerid)
+               return -1;
+       if (a->peerid > b->peerid)
+               return 1;
+       return 0;
+}
+
+static uint32_t bmp_bgp_peer_hash(const struct bmp_bgp_peer *e)
+{
+       return e->peerid;
+}
+
+DECLARE_HASH(bmp_peerh, struct bmp_bgp_peer, bpi,
+               bmp_bgp_peer_cmp, bmp_bgp_peer_hash)
+
+struct bmp_peerh_head bmp_peerh;
+
+DECLARE_LIST(bmp_mirrorq, struct bmp_mirrorq, bmi)
+
+/* listener management */
+
+static int bmp_listener_cmp(const struct bmp_listener *a,
+               const struct bmp_listener *b)
+{
+       int c;
+
+       c = sockunion_cmp(&a->addr, &b->addr);
+       if (c)
+               return c;
+       if (a->port < b->port)
+               return -1;
+       if (a->port > b->port)
+               return 1;
+       return 0;
+}
+
+DECLARE_SORTLIST_UNIQ(bmp_listeners, struct bmp_listener, bli, bmp_listener_cmp)
+
+static int bmp_targets_cmp(const struct bmp_targets *a,
+                          const struct bmp_targets *b)
+{
+       return strcmp(a->name, b->name);
+}
+
+DECLARE_SORTLIST_UNIQ(bmp_targets, struct bmp_targets, bti, bmp_targets_cmp)
+
+DECLARE_LIST(bmp_session, struct bmp, bsi)
+
+DECLARE_DLIST(bmp_qlist, struct bmp_queue_entry, bli)
+
+static int bmp_qhash_cmp(const struct bmp_queue_entry *a,
+               const struct bmp_queue_entry *b)
+{
+       int ret;
+       ret = prefix_cmp(&a->p, &b->p);
+       if (ret)
+               return ret;
+       ret = memcmp(&a->peerid, &b->peerid,
+                       offsetof(struct bmp_queue_entry, refcount) -
+                       offsetof(struct bmp_queue_entry, peerid));
+       return ret;
+}
+
+static uint32_t bmp_qhash_hkey(const struct bmp_queue_entry *e)
+{
+       uint32_t key;
+
+       key = prefix_hash_key((void *)&e->p);
+       key = jhash(&e->peerid,
+                       offsetof(struct bmp_queue_entry, refcount) -
+                       offsetof(struct bmp_queue_entry, peerid),
+                       key);
+       return key;
+}
+
+DECLARE_HASH(bmp_qhash, struct bmp_queue_entry, bhi,
+               bmp_qhash_cmp, bmp_qhash_hkey)
+
+static int bmp_active_cmp(const struct bmp_active *a,
+               const struct bmp_active *b)
+{
+       int c;
+
+       c = strcmp(a->hostname, b->hostname);
+       if (c)
+               return c;
+       if (a->port < b->port)
+               return -1;
+       if (a->port > b->port)
+               return 1;
+       return 0;
+}
+
+DECLARE_SORTLIST_UNIQ(bmp_actives, struct bmp_active, bai, bmp_active_cmp)
+
+static struct bmp *bmp_new(struct bmp_targets *bt, int bmp_sock)
+{
+       struct bmp *new = XCALLOC(MTYPE_BMP_CONN, sizeof(struct bmp));
+       afi_t afi;
+       safi_t safi;
+
+       monotime(&new->t_up);
+       new->targets = bt;
+       new->socket = bmp_sock;
+       new->syncafi = AFI_MAX;
+
+       FOREACH_AFI_SAFI (afi, safi) {
+               new->afistate[afi][safi] = bt->afimon[afi][safi]
+                       ? BMP_AFI_NEEDSYNC : BMP_AFI_INACTIVE;
+       }
+
+       bmp_session_add_tail(&bt->sessions, new);
+       return new;
+}
+
+static void bmp_free(struct bmp *bmp)
+{
+       bmp_session_del(&bmp->targets->sessions, bmp);
+       XFREE(MTYPE_BMP_CONN, bmp);
+}
+
+static void bmp_common_hdr(struct stream *s, uint8_t ver, uint8_t type)
+{
+       stream_putc(s, ver);
+       stream_putl(s, 0); //dummy message length. will be set later.
+       stream_putc(s, type);
+}
+
+static void bmp_per_peer_hdr(struct stream *s, struct peer *peer,
+               uint8_t flags, const struct timeval *tv)
+{
+       char peer_distinguisher[8];
+
+#define BMP_PEER_TYPE_GLOBAL_INSTANCE 0
+#define BMP_PEER_TYPE_RD_INSTANCE     1
+#define BMP_PEER_TYPE_LOCAL_INSTANCE  2
+
+#define BMP_PEER_FLAG_V (1 << 7)
+#define BMP_PEER_FLAG_L (1 << 6)
+#define BMP_PEER_FLAG_A (1 << 5)
+
+       /* Peer Type */
+       stream_putc(s, BMP_PEER_TYPE_GLOBAL_INSTANCE);
+
+       /* Peer Flags */
+       if (peer->su.sa.sa_family == AF_INET6)
+               SET_FLAG(flags, BMP_PEER_FLAG_V);
+       else
+               UNSET_FLAG(flags, BMP_PEER_FLAG_V);
+       stream_putc(s, flags);
+
+       /* Peer Distinguisher */
+       memset (&peer_distinguisher[0], 0, 8);
+       stream_put(s, &peer_distinguisher[0], 8);
+
+       /* Peer Address */
+       if (peer->su.sa.sa_family == AF_INET6)
+               stream_put(s, &peer->su.sin6.sin6_addr, 16);
+       else if (peer->su.sa.sa_family == AF_INET) {
+               stream_putl(s, 0);
+               stream_putl(s, 0);
+               stream_putl(s, 0);
+               stream_put_in_addr(s, &peer->su.sin.sin_addr);
+       } else {
+               stream_putl(s, 0);
+               stream_putl(s, 0);
+               stream_putl(s, 0);
+               stream_putl(s, 0);
+       }
+
+       /* Peer AS */
+       stream_putl(s, peer->as);
+
+       /* Peer BGP ID */
+       stream_put_in_addr(s, &peer->remote_id);
+
+       /* Timestamp */
+       if (tv) {
+               stream_putl(s, tv->tv_sec);
+               stream_putl(s, tv->tv_usec);
+       } else {
+               stream_putl(s, 0);
+               stream_putl(s, 0);
+       }
+}
+
+static void bmp_put_info_tlv(struct stream *s, uint16_t type,
+               const char *string)
+{
+       int len = strlen (string);
+       stream_putw(s, type);
+       stream_putw(s, len);
+       stream_put(s, string, len);
+}
+
+static int bmp_send_initiation(struct bmp *bmp)
+{
+       int len;
+       struct stream *s;
+       s = stream_new(BGP_MAX_PACKET_SIZE);
+       bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_INITIATION);
+
+#define BMP_INFO_TYPE_SYSDESCR 1
+#define BMP_INFO_TYPE_SYSNAME  2
+       bmp_put_info_tlv(s, BMP_INFO_TYPE_SYSDESCR,
+                       FRR_FULL_NAME " " FRR_VER_SHORT);
+       bmp_put_info_tlv(s, BMP_INFO_TYPE_SYSNAME, cmd_hostname_get());
+
+       len = stream_get_endp(s);
+       stream_putl_at(s, BMP_LENGTH_POS, len); //message length is set.
+
+       pullwr_write_stream(bmp->pullwr, s);
+       stream_free(s);
+       return 0;
+}
+
+static void bmp_notify_put(struct stream *s, struct bgp_notify *nfy)
+{
+       size_t len_pos;
+       uint8_t marker[16] = {
+               0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff,
+       };
+
+       stream_put(s, marker, sizeof(marker));
+       len_pos = stream_get_endp(s);
+       stream_putw(s, 0);
+       stream_putc(s, BGP_MSG_NOTIFY);
+       stream_putc(s, nfy->code);
+       stream_putc(s, nfy->subcode);
+       stream_put(s, nfy->data, nfy->length);
+
+       stream_putw_at(s, len_pos, stream_get_endp(s) - len_pos
+                       + sizeof(marker));
+}
+
+static struct stream *bmp_peerstate(struct peer *peer, bool down)
+{
+       struct stream *s;
+       size_t len;
+       struct timeval uptime, uptime_real;
+
+       uptime.tv_sec = peer->uptime;
+       uptime.tv_usec = 0;
+       monotime_to_realtime(&uptime, &uptime_real);
+
+#define BGP_BMP_MAX_PACKET_SIZE        1024
+       s = stream_new(BGP_MAX_PACKET_SIZE);
+
+       if (peer->status == Established && !down) {
+               struct bmp_bgp_peer *bbpeer;
+
+               bmp_common_hdr(s, BMP_VERSION_3,
+                               BMP_TYPE_PEER_UP_NOTIFICATION);
+               bmp_per_peer_hdr(s, peer, 0, &uptime_real);
+
+               /* Local Address (16 bytes) */
+               if (peer->su_local->sa.sa_family == AF_INET6)
+                       stream_put(s, &peer->su_local->sin6.sin6_addr, 16);
+               else if (peer->su_local->sa.sa_family == AF_INET) {
+                       stream_putl(s, 0);
+                       stream_putl(s, 0);
+                       stream_putl(s, 0);
+                       stream_put_in_addr(s, &peer->su_local->sin.sin_addr);
+               }
+
+               /* Local Port, Remote Port */
+               if (peer->su_local->sa.sa_family == AF_INET6)
+                       stream_putw(s, peer->su_local->sin6.sin6_port);
+               else if (peer->su_local->sa.sa_family == AF_INET)
+                       stream_putw(s, peer->su_local->sin.sin_port);
+               if (peer->su_remote->sa.sa_family == AF_INET6)
+                       stream_putw(s, peer->su_remote->sin6.sin6_port);
+               else if (peer->su_remote->sa.sa_family == AF_INET)
+                       stream_putw(s, peer->su_remote->sin.sin_port);
+
+               static const uint8_t dummy_open[] = {
+                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                       0x00, 0x13, 0x01,
+               };
+
+               bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid);
+
+               if (bbpeer && bbpeer->open_tx)
+                       stream_put(s, bbpeer->open_tx, bbpeer->open_tx_len);
+               else {
+                       stream_put(s, dummy_open, sizeof(dummy_open));
+                       zlog_warn("bmp: missing TX OPEN message for peer %s\n",
+                                       peer->host);
+               }
+               if (bbpeer && bbpeer->open_rx)
+                       stream_put(s, bbpeer->open_rx, bbpeer->open_rx_len);
+               else {
+                       stream_put(s, dummy_open, sizeof(dummy_open));
+                       zlog_warn("bmp: missing RX OPEN message for peer %s\n",
+                                       peer->host);
+               }
+
+               if (peer->desc)
+                       bmp_put_info_tlv(s, 0, peer->desc);
+       } else {
+               uint8_t type;
+               size_t type_pos;
+
+               bmp_common_hdr(s, BMP_VERSION_3,
+                               BMP_TYPE_PEER_DOWN_NOTIFICATION);
+               bmp_per_peer_hdr(s, peer, 0, &uptime_real);
+
+               type_pos = stream_get_endp(s);
+               stream_putc(s, 0);      /* placeholder for down reason */
+
+               switch (peer->last_reset) {
+               case PEER_DOWN_NOTIFY_RECEIVED:
+                       type = BMP_PEERDOWN_REMOTE_NOTIFY;
+                       bmp_notify_put(s, &peer->notify);
+                       break;
+               case PEER_DOWN_CLOSE_SESSION:
+                       type = BMP_PEERDOWN_REMOTE_CLOSE;
+                       break;
+               default:
+                       type = BMP_PEERDOWN_LOCAL_NOTIFY;
+                       stream_put(s, peer->last_reset_cause,
+                                       peer->last_reset_cause_size);
+                       break;
+               }
+               stream_putc_at(s, type_pos, type);
+       }
+
+       len = stream_get_endp(s);
+       stream_putl_at(s, BMP_LENGTH_POS, len); //message length is set.
+       return s;
+}
+
+
+static int bmp_send_peerup(struct bmp *bmp)
+{
+       struct peer *peer;
+       struct listnode *node;
+       struct stream *s;
+
+       /* Walk down all peers */
+       for (ALL_LIST_ELEMENTS_RO(bmp->targets->bgp->peer, node, peer)) {
+               s = bmp_peerstate(peer, false);
+               pullwr_write_stream(bmp->pullwr, s);
+               stream_free(s);
+       }
+
+       return 0;
+}
+
+/* XXX: kludge - filling the pullwr's buffer */
+static void bmp_send_all(struct bmp_bgp *bmpbgp, struct stream *s)
+{
+       struct bmp_targets *bt;
+       struct bmp *bmp;
+
+       frr_each(bmp_targets, &bmpbgp->targets, bt)
+               frr_each(bmp_session, &bt->sessions, bmp)
+                       pullwr_write_stream(bmp->pullwr, s);
+       stream_free(s);
+}
+
+/*
+ * Route Mirroring
+ */
+
+#define BMP_MIRROR_TLV_TYPE_BGP_MESSAGE 0
+#define BMP_MIRROR_TLV_TYPE_INFO        1
+
+#define BMP_MIRROR_INFO_CODE_ERRORPDU   0
+#define BMP_MIRROR_INFO_CODE_LOSTMSGS   1
+
+static struct bmp_mirrorq *bmp_pull_mirror(struct bmp *bmp)
+{
+       struct bmp_mirrorq *bmq;
+
+       bmq = bmp->mirrorpos;
+       if (!bmq)
+               return NULL;
+
+       bmp->mirrorpos = bmp_mirrorq_next(&bmp->targets->bmpbgp->mirrorq, bmq);
+
+       bmq->refcount--;
+       if (!bmq->refcount) {
+               bmp->targets->bmpbgp->mirror_qsize -= sizeof(*bmq) + bmq->len;
+               bmp_mirrorq_del(&bmp->targets->bmpbgp->mirrorq, bmq);
+       }
+       return bmq;
+}
+
+static void bmp_mirror_cull(struct bmp_bgp *bmpbgp)
+{
+       while (bmpbgp->mirror_qsize > bmpbgp->mirror_qsizelimit) {
+               struct bmp_mirrorq *bmq, *inner;
+               struct bmp_targets *bt;
+               struct bmp *bmp;
+
+               bmq = bmp_mirrorq_first(&bmpbgp->mirrorq);
+
+               frr_each(bmp_targets, &bmpbgp->targets, bt) {
+                       if (!bt->mirror)
+                               continue;
+                       frr_each(bmp_session, &bt->sessions, bmp) {
+                               if (bmp->mirrorpos != bmq)
+                                       continue;
+
+                               while ((inner = bmp_pull_mirror(bmp))) {
+                                       if (!inner->refcount)
+                                               XFREE(MTYPE_BMP_MIRRORQ,
+                                                               inner);
+                               }
+
+                               zlog_warn("bmp[%s] lost mirror messages due to buffer size limit",
+                                               bmp->remote);
+                               bmp->mirror_lost = true;
+                               pullwr_bump(bmp->pullwr);
+                       }
+               }
+       }
+}
+
+static int bmp_mirror_packet(struct peer *peer, uint8_t type, bgp_size_t size,
+               struct stream *packet)
+{
+       struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
+       struct timeval tv;
+       struct bmp_mirrorq *qitem;
+       struct bmp_targets *bt;
+       struct bmp *bmp;
+
+       gettimeofday(&tv, NULL);
+
+       if (type == BGP_MSG_OPEN) {
+               struct bmp_bgp_peer *bbpeer = bmp_bgp_peer_get(peer);
+
+               XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx);
+
+               bbpeer->open_rx_len = size;
+               bbpeer->open_rx = XMALLOC(MTYPE_BMP_OPEN, size);
+               memcpy(bbpeer->open_rx, packet->data, size);
+       }
+
+       if (!bmpbgp)
+               return 0;
+
+       qitem = XCALLOC(MTYPE_BMP_MIRRORQ, sizeof(*qitem) + size);
+       qitem->peerid = peer->qobj_node.nid;
+       qitem->tv = tv;
+       qitem->len = size;
+       memcpy(qitem->data, packet->data, size);
+
+       frr_each(bmp_targets, &bmpbgp->targets, bt) {
+               if (!bt->mirror)
+                       continue;
+               frr_each(bmp_session, &bt->sessions, bmp) {
+                       qitem->refcount++;
+                       if (!bmp->mirrorpos)
+                               bmp->mirrorpos = qitem;
+                       pullwr_bump(bmp->pullwr);
+               }
+       }
+       if (qitem->refcount == 0)
+               XFREE(MTYPE_BMP_MIRRORQ, qitem);
+       else {
+               bmpbgp->mirror_qsize += sizeof(*qitem) + size;
+               bmp_mirrorq_add_tail(&bmpbgp->mirrorq, qitem);
+
+               bmp_mirror_cull(bmpbgp);
+
+               bmpbgp->mirror_qsizemax = MAX(bmpbgp->mirror_qsizemax,
+                               bmpbgp->mirror_qsize);
+       }
+       return 0;
+}
+
+static void bmp_wrmirror_lost(struct bmp *bmp, struct pullwr *pullwr)
+{
+       struct stream *s;
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+
+       s = stream_new(BGP_MAX_PACKET_SIZE);
+
+       bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING);
+       bmp_per_peer_hdr(s, bmp->targets->bgp->peer_self, 0, &tv);
+
+       stream_putw(s, BMP_MIRROR_TLV_TYPE_INFO);
+       stream_putw(s, 2);
+       stream_putw(s, BMP_MIRROR_INFO_CODE_LOSTMSGS);
+       stream_putl_at(s, BMP_LENGTH_POS, stream_get_endp(s));
+
+       bmp->cnt_mirror_overruns++;
+       pullwr_write_stream(bmp->pullwr, s);
+       stream_free(s);
+}
+
+static bool bmp_wrmirror(struct bmp *bmp, struct pullwr *pullwr)
+{
+       struct bmp_mirrorq *bmq;
+       struct peer *peer;
+       bool written = false;
+
+       if (bmp->mirror_lost) {
+               bmp_wrmirror_lost(bmp, pullwr);
+               bmp->mirror_lost = false;
+               return true;
+       }
+
+       bmq = bmp_pull_mirror(bmp);
+       if (!bmq)
+               return false;
+
+       peer = QOBJ_GET_TYPESAFE(bmq->peerid, peer);
+       if (!peer) {
+               zlog_info("bmp: skipping mirror message for deleted peer");
+               goto out;
+       }
+
+       struct stream *s;
+       s = stream_new(BGP_MAX_PACKET_SIZE);
+
+       bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING);
+       bmp_per_peer_hdr(s, peer, 0, &bmq->tv);
+
+       /* BMP Mirror TLV. */
+       stream_putw(s, BMP_MIRROR_TLV_TYPE_BGP_MESSAGE);
+       stream_putw(s, bmq->len);
+       stream_putl_at(s, BMP_LENGTH_POS, stream_get_endp(s) + bmq->len);
+
+       bmp->cnt_mirror++;
+       pullwr_write_stream(bmp->pullwr, s);
+       pullwr_write(bmp->pullwr, bmq->data, bmq->len);
+
+       stream_free(s);
+       written = true;
+
+out:
+       if (!bmq->refcount)
+               XFREE(MTYPE_BMP_MIRRORQ, bmq);
+       return written;
+}
+
+static int bmp_outgoing_packet(struct peer *peer, uint8_t type, bgp_size_t size,
+               struct stream *packet)
+{
+       if (type == BGP_MSG_OPEN) {
+               struct bmp_bgp_peer *bbpeer = bmp_bgp_peer_get(peer);
+
+               XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx);
+
+               bbpeer->open_tx_len = size;
+               bbpeer->open_tx = XMALLOC(MTYPE_BMP_OPEN, size);
+               memcpy(bbpeer->open_tx, packet->data, size);
+       }
+       return 0;
+}
+
+static int bmp_peer_established(struct peer *peer)
+{
+       struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
+
+       if (!bmpbgp)
+               return 0;
+
+       if (peer->doppelganger && (peer->doppelganger->status != Deleted)) {
+               struct bmp_bgp_peer *bbpeer, *bbdopp;
+
+               bbpeer = bmp_bgp_peer_get(peer);
+               bbdopp = bmp_bgp_peer_find(peer->doppelganger->qobj_node.nid);
+               if (bbdopp) {
+                       XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx);
+                       XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx);
+
+                       bbpeer->open_tx = bbdopp->open_tx;
+                       bbpeer->open_tx_len = bbdopp->open_tx_len;
+                       bbpeer->open_rx = bbdopp->open_rx;
+                       bbpeer->open_rx_len = bbdopp->open_rx_len;
+
+                       bmp_peerh_del(&bmp_peerh, bbdopp);
+                       XFREE(MTYPE_BMP_PEER, bbdopp);
+               }
+       }
+
+       bmp_send_all(bmpbgp, bmp_peerstate(peer, false));
+       return 0;
+}
+
+static int bmp_peer_backward(struct peer *peer)
+{
+       struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
+       struct bmp_bgp_peer *bbpeer;
+
+       if (!bmpbgp)
+               return 0;
+
+       bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid);
+       if (bbpeer) {
+               XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx);
+               bbpeer->open_tx_len = 0;
+               XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx);
+               bbpeer->open_rx_len = 0;
+       }
+
+       bmp_send_all(bmpbgp, bmp_peerstate(peer, true));
+       return 0;
+}
+
+static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags)
+{
+       struct peer *peer;
+       struct listnode *node;
+       struct stream *s, *s2;
+       iana_afi_t pkt_afi;
+       iana_safi_t pkt_safi;
+
+       s = stream_new(BGP_MAX_PACKET_SIZE);
+
+       /* Make BGP update packet. */
+       bgp_packet_set_marker(s, BGP_MSG_UPDATE);
+
+       /* Unfeasible Routes Length */
+       stream_putw(s, 0);
+
+       if (afi == AFI_IP && safi == SAFI_UNICAST) {
+               /* Total Path Attribute Length */
+               stream_putw(s, 0);
+       } else {
+               /* Convert AFI, SAFI to values for packet. */
+               bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
+
+               /* Total Path Attribute Length */
+               stream_putw(s, 6);
+               stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
+               stream_putc(s, BGP_ATTR_MP_UNREACH_NLRI);
+               stream_putc(s, 3);
+               stream_putw(s, pkt_afi);
+               stream_putc(s, pkt_safi);
+       }
+
+       bgp_packet_set_size(s);
+
+       for (ALL_LIST_ELEMENTS_RO(bmp->targets->bgp->peer, node, peer)) {
+               if (!peer->afc_nego[afi][safi])
+                       continue;
+
+               s2 = stream_new(BGP_MAX_PACKET_SIZE);
+
+               bmp_common_hdr(s2, BMP_VERSION_3,
+                               BMP_TYPE_ROUTE_MONITORING);
+               bmp_per_peer_hdr(s2, peer, flags, NULL);
+
+               stream_putl_at(s2, BMP_LENGTH_POS,
+                               stream_get_endp(s) + stream_get_endp(s2));
+
+               bmp->cnt_update++;
+               pullwr_write_stream(bmp->pullwr, s2);
+               pullwr_write_stream(bmp->pullwr, s);
+               stream_free(s2);
+       }
+       stream_free(s);
+}
+
+static struct stream *bmp_update(struct prefix *p, struct peer *peer,
+               struct attr *attr, afi_t afi, safi_t safi)
+{
+       struct bpacket_attr_vec_arr vecarr;
+       struct stream *s;
+       size_t attrlen_pos = 0, mpattrlen_pos = 0;
+       bgp_size_t total_attr_len = 0;
+
+       bpacket_attr_vec_arr_reset(&vecarr);
+
+       s = stream_new(BGP_MAX_PACKET_SIZE);
+       bgp_packet_set_marker(s, BGP_MSG_UPDATE);
+
+       /* 2: withdrawn routes length */
+       stream_putw(s, 0);
+
+       /* 3: total attributes length - attrlen_pos stores the position */
+       attrlen_pos = stream_get_endp(s);
+       stream_putw(s, 0);
+
+       /* 5: Encode all the attributes, except MP_REACH_NLRI attr. */
+       total_attr_len = bgp_packet_attribute(NULL, peer, s, attr,
+                       &vecarr, NULL, afi, safi, peer, NULL, NULL, 0, 0, 0);
+
+       /* space check? */
+
+       /* peer_cap_enhe & add-path removed */
+       if (afi == AFI_IP && safi == SAFI_UNICAST)
+               stream_put_prefix(s, p);
+       else {
+               size_t p1 = stream_get_endp(s);
+
+               /* MPLS removed for now */
+
+               mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi,
+                               &vecarr, attr);
+               bgp_packet_mpattr_prefix(s, afi, safi, p, NULL, NULL, 0,
+                               0, 0, attr);
+               bgp_packet_mpattr_end(s, mpattrlen_pos);
+               total_attr_len += stream_get_endp(s) - p1;
+       }
+
+       /* set the total attribute length correctly */
+       stream_putw_at(s, attrlen_pos, total_attr_len);
+       bgp_packet_set_size(s);
+       return s;
+}
+
+static struct stream *bmp_withdraw(struct prefix *p, afi_t afi, safi_t safi)
+{
+       struct stream *s;
+       size_t attrlen_pos = 0, mp_start, mplen_pos;
+       bgp_size_t total_attr_len = 0;
+       bgp_size_t unfeasible_len;
+
+       s = stream_new(BGP_MAX_PACKET_SIZE);
+
+       bgp_packet_set_marker(s, BGP_MSG_UPDATE);
+       stream_putw(s, 0);
+
+       if (afi == AFI_IP && safi == SAFI_UNICAST) {
+               stream_put_prefix(s, p);
+               unfeasible_len = stream_get_endp(s) - BGP_HEADER_SIZE
+                                - BGP_UNFEASIBLE_LEN;
+               stream_putw_at(s, BGP_HEADER_SIZE, unfeasible_len);
+               stream_putw(s, 0);
+       } else {
+               attrlen_pos = stream_get_endp(s);
+               /* total attr length = 0 for now. reevaluate later */
+               stream_putw(s, 0);
+               mp_start = stream_get_endp(s);
+               mplen_pos = bgp_packet_mpunreach_start(s, afi, safi);
+
+               bgp_packet_mpunreach_prefix(s, p, afi, safi, NULL, NULL, 0,
+                               0, 0, NULL);
+               /* Set the mp_unreach attr's length */
+               bgp_packet_mpunreach_end(s, mplen_pos);
+
+               /* Set total path attribute length. */
+               total_attr_len = stream_get_endp(s) - mp_start;
+               stream_putw_at(s, attrlen_pos, total_attr_len);
+       }
+
+       bgp_packet_set_size(s);
+       return s;
+}
+
+static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
+                       struct prefix *p, struct attr *attr, afi_t afi,
+                       safi_t safi, time_t uptime)
+{
+       struct stream *hdr, *msg;
+       struct timeval tv = { .tv_sec = uptime, .tv_usec = 0 };
+
+       if (attr)
+               msg = bmp_update(p, peer, attr, afi, safi);
+       else
+               msg = bmp_withdraw(p, afi, safi);
+
+       hdr = stream_new(BGP_MAX_PACKET_SIZE);
+       bmp_common_hdr(hdr, BMP_VERSION_3, BMP_TYPE_ROUTE_MONITORING);
+       bmp_per_peer_hdr(hdr, peer, flags, &tv);
+
+       stream_putl_at(hdr, BMP_LENGTH_POS,
+                       stream_get_endp(hdr) + stream_get_endp(msg));
+
+       bmp->cnt_update++;
+       pullwr_write_stream(bmp->pullwr, hdr);
+       pullwr_write_stream(bmp->pullwr, msg);
+       stream_free(hdr);
+       stream_free(msg);
+}
+
+static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr)
+{
+       afi_t afi;
+       safi_t safi;
+
+       if (bmp->syncafi == AFI_MAX) {
+               FOREACH_AFI_SAFI (afi, safi) {
+                       if (bmp->afistate[afi][safi] != BMP_AFI_NEEDSYNC)
+                               continue;
+
+                       bmp->afistate[afi][safi] = BMP_AFI_SYNC;
+
+                       bmp->syncafi = afi;
+                       bmp->syncsafi = safi;
+                       bmp->syncpeerid = 0;
+                       memset(&bmp->syncpos, 0, sizeof(bmp->syncpos));
+                       bmp->syncpos.family = afi2family(afi);
+                       zlog_info("bmp[%s] %s %s sending table",
+                                       bmp->remote,
+                                       afi2str(bmp->syncafi),
+                                       safi2str(bmp->syncsafi));
+                       /* break does not work here, 2 loops... */
+                       goto afibreak;
+               }
+               if (bmp->syncafi == AFI_MAX)
+                       return false;
+       }
+
+afibreak:
+       afi = bmp->syncafi;
+       safi = bmp->syncsafi;
+
+       if (!bmp->targets->afimon[afi][safi]) {
+               /* shouldn't happen */
+               bmp->afistate[afi][safi] = BMP_AFI_INACTIVE;
+               bmp->syncafi = AFI_MAX;
+               bmp->syncsafi = SAFI_MAX;
+               return true;
+       }
+
+       struct bgp_table *table = bmp->targets->bgp->rib[afi][safi];
+       struct bgp_node *bn;
+       struct bgp_path_info *bpi = NULL, *bpiter;
+       struct bgp_adj_in *adjin = NULL, *adjiter;
+
+       bn = bgp_node_lookup(table, &bmp->syncpos);
+       do {
+               if (!bn) {
+                       bn = bgp_table_get_next(table, &bmp->syncpos);
+                       if (!bn) {
+                               zlog_info("bmp[%s] %s %s table completed (EoR)",
+                                               bmp->remote, afi2str(afi),
+                                               safi2str(safi));
+                               bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L);
+                               bmp_eor(bmp, afi, safi, 0);
+
+                               bmp->afistate[afi][safi] = BMP_AFI_LIVE;
+                               bmp->syncafi = AFI_MAX;
+                               bmp->syncsafi = SAFI_MAX;
+                               return true;
+                       }
+                       bmp->syncpeerid = 0;
+                       prefix_copy(&bmp->syncpos, &bn->p);
+               }
+
+               if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) {
+                       for (bpiter = bn->info; bpiter; bpiter = bpiter->next) {
+                               if (!CHECK_FLAG(bpiter->flags, BGP_PATH_VALID))
+                                       continue;
+                               if (bpiter->peer->qobj_node.nid
+                                   <= bmp->syncpeerid)
+                                       continue;
+                               if (bpi && bpiter->peer->qobj_node.nid
+                                               > bpi->peer->qobj_node.nid)
+                                       continue;
+                               bpi = bpiter;
+                       }
+               }
+               if (bmp->targets->afimon[afi][safi] & BMP_MON_PREPOLICY) {
+                       for (adjiter = bn->adj_in; adjiter;
+                            adjiter = adjiter->next) {
+                               if (adjiter->peer->qobj_node.nid
+                                   <= bmp->syncpeerid)
+                                       continue;
+                               if (adjin && adjiter->peer->qobj_node.nid
+                                               > adjin->peer->qobj_node.nid)
+                                       continue;
+                               adjin = adjiter;
+                       }
+               }
+               if (bpi || adjin)
+                       break;
+
+               bn = NULL;
+       } while (1);
+
+       if (adjin && bpi
+           && adjin->peer->qobj_node.nid < bpi->peer->qobj_node.nid) {
+               bpi = NULL;
+               bmp->syncpeerid = adjin->peer->qobj_node.nid;
+       } else if (adjin && bpi
+                  && adjin->peer->qobj_node.nid > bpi->peer->qobj_node.nid) {
+               adjin = NULL;
+               bmp->syncpeerid = bpi->peer->qobj_node.nid;
+       } else if (bpi) {
+               bmp->syncpeerid = bpi->peer->qobj_node.nid;
+       } else if (adjin) {
+               bmp->syncpeerid = adjin->peer->qobj_node.nid;
+       }
+
+       if (bpi)
+               bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, &bn->p, bpi->attr,
+                           afi, safi, bpi->uptime);
+       if (adjin)
+               bmp_monitor(bmp, adjin->peer, 0, &bn->p, adjin->attr,
+                           afi, safi, adjin->uptime);
+
+       return true;
+}
+
+static struct bmp_queue_entry *bmp_pull(struct bmp *bmp)
+{
+       struct bmp_queue_entry *bqe;
+
+       bqe = bmp->queuepos;
+       if (!bqe)
+               return NULL;
+
+       bmp->queuepos = bmp_qlist_next(&bmp->targets->updlist, bqe);
+
+       bqe->refcount--;
+       if (!bqe->refcount) {
+               bmp_qhash_del(&bmp->targets->updhash, bqe);
+               bmp_qlist_del(&bmp->targets->updlist, bqe);
+       }
+       return bqe;
+}
+
+static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
+{
+       struct bmp_queue_entry *bqe;
+       struct peer *peer;
+       struct bgp_node *bn;
+       bool written = false;
+
+       bqe = bmp_pull(bmp);
+       if (!bqe)
+               return false;
+
+       afi_t afi = bqe->afi;
+       safi_t safi = bqe->safi;
+
+       switch (bmp->afistate[afi][safi]) {
+       case BMP_AFI_INACTIVE:
+       case BMP_AFI_NEEDSYNC:
+               goto out;
+       case BMP_AFI_SYNC:
+               if (prefix_cmp(&bqe->p, &bmp->syncpos) <= 0)
+                       /* currently syncing but have already passed this
+                        * prefix => send it. */
+                       break;
+
+               /* currently syncing & haven't reached this prefix yet
+                * => it'll be sent as part of the table sync, no need here */
+               goto out;
+       case BMP_AFI_LIVE:
+               break;
+       }
+
+       peer = QOBJ_GET_TYPESAFE(bqe->peerid, peer);
+       if (!peer) {
+               zlog_info("bmp: skipping queued item for deleted peer");
+               goto out;
+       }
+       if (peer->status != Established)
+               goto out;
+
+       bn = bgp_node_lookup(bmp->targets->bgp->rib[afi][safi], &bqe->p);
+
+       if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) {
+               struct bgp_path_info *bpi;
+
+               for (bpi = bn ? bn->info : NULL; bpi; bpi = bpi->next) {
+                       if (!CHECK_FLAG(bpi->flags, BGP_PATH_VALID))
+                               continue;
+                       if (bpi->peer == peer)
+                               break;
+               }
+
+               bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p,
+                           bpi ? bpi->attr : NULL, afi, safi,
+                           bpi ? bpi->uptime : monotime(NULL));
+               written = true;
+       }
+
+       if (bmp->targets->afimon[afi][safi] & BMP_MON_PREPOLICY) {
+               struct bgp_adj_in *adjin;
+
+               for (adjin = bn ? bn->adj_in : NULL; adjin;
+                    adjin = adjin->next) {
+                       if (adjin->peer == peer)
+                               break;
+               }
+               bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p,
+                           adjin ? adjin->attr : NULL, afi, safi,
+                           adjin ? adjin->uptime : monotime(NULL));
+               written = true;
+       }
+
+out:
+       if (!bqe->refcount)
+               XFREE(MTYPE_BMP_QUEUE, bqe);
+       return written;
+}
+
+static void bmp_wrfill(struct bmp *bmp, struct pullwr *pullwr)
+{
+       switch(bmp->state) {
+       case BMP_PeerUp:
+               bmp_send_peerup(bmp);
+               bmp->state = BMP_Run;
+               break;
+
+       case BMP_Run:
+               if (bmp_wrmirror(bmp, pullwr))
+                       break;
+               if (bmp_wrqueue(bmp, pullwr))
+                       break;
+               if (bmp_wrsync(bmp, pullwr))
+                       break;
+               break;
+       }
+}
+
+static void bmp_wrerr(struct bmp *bmp, struct pullwr *pullwr, bool eof)
+{
+       if (eof)
+               zlog_info("bmp[%s] disconnected", bmp->remote);
+       else
+               flog_warn(EC_LIB_SYSTEM_CALL, "bmp[%s] connection error: %s",
+                               bmp->remote, strerror(errno));
+
+       bmp_close(bmp);
+       bmp_free(bmp);
+}
+
+static void bmp_process_one(struct bmp_targets *bt, struct bgp *bgp,
+               afi_t afi, safi_t safi, struct bgp_node *bn, struct peer *peer)
+{
+       struct bmp *bmp;
+       struct bmp_queue_entry *bqe, bqeref;
+       size_t refcount;
+       char buf[256];
+
+       prefix2str(&bn->p, buf, sizeof(buf));
+
+       refcount = bmp_session_count(&bt->sessions);
+       if (refcount == 0)
+               return;
+
+       memset(&bqeref, 0, sizeof(bqeref));
+       prefix_copy(&bqeref.p, &bn->p);
+       bqeref.peerid = peer->qobj_node.nid;
+       bqeref.afi = afi;
+       bqeref.safi = safi;
+
+       bqe = bmp_qhash_find(&bt->updhash, &bqeref);
+       if (bqe) {
+               if (bqe->refcount >= refcount)
+                       /* nothing to do here */
+                       return;
+
+               bmp_qlist_del(&bt->updlist, bqe);
+       } else {
+               bqe = XMALLOC(MTYPE_BMP_QUEUE, sizeof(*bqe));
+               memcpy(bqe, &bqeref, sizeof(*bqe));
+
+               bmp_qhash_add(&bt->updhash, bqe);
+       }
+
+       bqe->refcount = refcount;
+       bmp_qlist_add_tail(&bt->updlist, bqe);
+
+       frr_each (bmp_session, &bt->sessions, bmp)
+               if (!bmp->queuepos)
+                       bmp->queuepos = bqe;
+}
+
+static int bmp_process(struct bgp *bgp, afi_t afi, safi_t safi,
+                       struct bgp_node *bn, struct peer *peer, bool withdraw)
+{
+       struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
+       struct bmp_targets *bt;
+       struct bmp *bmp;
+
+       if (!bmpbgp)
+               return 0;
+
+       frr_each(bmp_targets, &bmpbgp->targets, bt) {
+               if (!bt->afimon[afi][safi])
+                       continue;
+
+               bmp_process_one(bt, bgp, afi, safi, bn, peer);
+
+               frr_each(bmp_session, &bt->sessions, bmp) {
+                       pullwr_bump(bmp->pullwr);
+               }
+       }
+       return 0;
+}
+
+static void bmp_stat_put_u32(struct stream *s, size_t *cnt, uint16_t type,
+               uint32_t value)
+{
+       stream_putw(s, type);
+       stream_putw(s, 4);
+       stream_putl(s, value);
+       (*cnt)++;
+}
+
+static int bmp_stats(struct thread *thread)
+{
+       struct bmp_targets *bt = THREAD_ARG(thread);
+       struct stream *s;
+       struct peer *peer;
+       struct listnode *node;
+       struct timeval tv;
+
+       if (bt->stat_msec)
+               thread_add_timer_msec(bm->master, bmp_stats, bt, bt->stat_msec,
+                               &bt->t_stats);
+
+       gettimeofday(&tv, NULL);
+
+       /* Walk down all peers */
+       for (ALL_LIST_ELEMENTS_RO(bt->bgp->peer, node, peer)) {
+               size_t count = 0, count_pos, len;
+
+               if (peer->status != Established)
+                       continue;
+
+               s = stream_new(BGP_MAX_PACKET_SIZE);
+               bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_STATISTICS_REPORT);
+               bmp_per_peer_hdr(s, peer, 0, &tv);
+
+               count_pos = stream_get_endp(s);
+               stream_putl(s, 0);
+
+               bmp_stat_put_u32(s, &count, BMP_STATS_PFX_REJECTED,
+                               peer->stat_pfx_filter);
+               bmp_stat_put_u32(s, &count, BMP_STATS_UPD_LOOP_ASPATH,
+                               peer->stat_pfx_aspath_loop);
+               bmp_stat_put_u32(s, &count, BMP_STATS_UPD_LOOP_ORIGINATOR,
+                               peer->stat_pfx_originator_loop);
+               bmp_stat_put_u32(s, &count, BMP_STATS_UPD_LOOP_CLUSTER,
+                               peer->stat_pfx_cluster_loop);
+               bmp_stat_put_u32(s, &count, BMP_STATS_PFX_DUP_WITHDRAW,
+                               peer->stat_pfx_dup_withdraw);
+               bmp_stat_put_u32(s, &count, BMP_STATS_UPD_7606_WITHDRAW,
+                               peer->stat_upd_7606);
+               bmp_stat_put_u32(s, &count, BMP_STATS_FRR_NH_INVALID,
+                               peer->stat_pfx_nh_invalid);
+
+               stream_putl_at(s, count_pos, count);
+
+               len = stream_get_endp(s);
+               stream_putl_at(s, BMP_LENGTH_POS, len);
+
+               bmp_send_all(bt->bmpbgp, s);
+       }
+       return 0;
+}
+
+static struct bmp *bmp_open(struct bmp_targets *bt, int bmp_sock)
+{
+       union sockunion su, *sumem;
+       struct prefix p;
+       int on = 1;
+       struct access_list *acl = NULL;
+       enum filter_type ret;
+       char buf[SU_ADDRSTRLEN];
+       struct bmp *bmp;
+
+       sumem = sockunion_getpeername(bmp_sock);
+       if (!sumem) {
+               close(bmp_sock);
+               return NULL;
+       }
+       memcpy(&su, sumem, sizeof(su));
+       sockunion_free(sumem);
+
+       set_nonblocking(bmp_sock);
+       set_cloexec(bmp_sock);
+       shutdown(bmp_sock, SHUT_RD);
+
+       sockunion2hostprefix(&su, &p);
+
+       acl = NULL;
+       switch (p.family) {
+       case AF_INET:
+               acl = access_list_lookup(AFI_IP, bt->acl_name);
+               break;
+       case AF_INET6:
+               acl = access_list_lookup(AFI_IP6, bt->acl6_name);
+               break;
+       default:
+               break;
+       }
+
+       ret = FILTER_PERMIT;
+       if (acl) {
+               ret = access_list_apply(acl, &p);
+       }
+
+       sockunion2str(&su, buf, SU_ADDRSTRLEN);
+       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ":%u",
+                       su.sa.sa_family == AF_INET
+                               ? ntohs(su.sin.sin_port)
+                               : ntohs(su.sin6.sin6_port));
+
+       if (ret == FILTER_DENY) {
+               bt->cnt_aclrefused++;
+               zlog_info("bmp[%s] connection refused by access-list", buf);
+               close(bmp_sock);
+               return NULL;
+       }
+       bt->cnt_accept++;
+
+       setsockopt(bmp_sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
+       setsockopt(bmp_sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
+
+       zlog_info("bmp[%s] connection established", buf);
+
+       /* Allocate new BMP structure and set up default values. */
+       bmp = bmp_new(bt, bmp_sock);
+       strlcpy(bmp->remote, buf, sizeof(bmp->remote));
+
+       bmp->state = BMP_PeerUp;
+       bmp->pullwr = pullwr_new(bm->master, bmp_sock, bmp, bmp_wrfill,
+                       bmp_wrerr);
+       bmp_send_initiation(bmp);
+
+       return bmp;
+}
+
+/* Accept BMP connection. */
+static int bmp_accept(struct thread *thread)
+{
+       union sockunion su;
+       struct bmp_listener *bl = THREAD_ARG(thread);
+       int bmp_sock;
+
+       /* We continue hearing BMP socket. */
+       thread_add_read(bm->master, bmp_accept, bl, bl->sock, &bl->t_accept);
+
+       memset(&su, 0, sizeof(union sockunion));
+
+       /* We can handle IPv4 or IPv6 socket. */
+       bmp_sock = sockunion_accept(bl->sock, &su);
+       if (bmp_sock < 0) {
+               zlog_info("bmp: accept_sock failed: %s\n",
+                          safe_strerror (errno));
+               return -1;
+       }
+       bmp_open(bl->targets, bmp_sock);
+       return 0;
+}
+
+static void bmp_close(struct bmp *bmp)
+{
+       struct bmp_queue_entry *bqe;
+       struct bmp_mirrorq *bmq;
+
+       if (bmp->active)
+               bmp_active_disconnected(bmp->active);
+
+       while ((bmq = bmp_pull_mirror(bmp)))
+               if (!bmq->refcount)
+                       XFREE(MTYPE_BMP_MIRRORQ, bmq);
+       while ((bqe = bmp_pull(bmp)))
+               if (!bqe->refcount)
+                       XFREE(MTYPE_BMP_QUEUE, bqe);
+
+       THREAD_OFF(bmp->t_read);
+       pullwr_del(bmp->pullwr);
+       close(bmp->socket);
+}
+
+static struct bmp_bgp *bmp_bgp_find(struct bgp *bgp)
+{
+       struct bmp_bgp dummy = { .bgp = bgp };
+       return bmp_bgph_find(&bmp_bgph, &dummy);
+}
+
+static struct bmp_bgp *bmp_bgp_get(struct bgp *bgp)
+{
+       struct bmp_bgp *bmpbgp;
+
+       bmpbgp = bmp_bgp_find(bgp);
+       if (bmpbgp)
+               return bmpbgp;
+
+       bmpbgp = XCALLOC(MTYPE_BMP, sizeof(*bmpbgp));
+       bmpbgp->bgp = bgp;
+       bmpbgp->mirror_qsizelimit = ~0UL;
+       bmp_mirrorq_init(&bmpbgp->mirrorq);
+       bmp_bgph_add(&bmp_bgph, bmpbgp);
+
+       return bmpbgp;
+}
+
+static void bmp_bgp_put(struct bmp_bgp *bmpbgp)
+{
+       struct bmp_targets *bt;
+
+       bmp_bgph_del(&bmp_bgph, bmpbgp);
+
+       frr_each_safe(bmp_targets, &bmpbgp->targets, bt)
+               bmp_targets_put(bt);
+
+       bmp_mirrorq_fini(&bmpbgp->mirrorq);
+       XFREE(MTYPE_BMP, bmpbgp);
+}
+
+static int bmp_bgp_del(struct bgp *bgp)
+{
+       struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp);
+
+       if (bmpbgp)
+               bmp_bgp_put(bmpbgp);
+       return 0;
+}
+
+static struct bmp_bgp_peer *bmp_bgp_peer_find(uint64_t peerid)
+{
+       struct bmp_bgp_peer dummy = { .peerid = peerid };
+       return bmp_peerh_find(&bmp_peerh, &dummy);
+}
+
+static struct bmp_bgp_peer *bmp_bgp_peer_get(struct peer *peer)
+{
+       struct bmp_bgp_peer *bbpeer;
+
+       bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid);
+       if (bbpeer)
+               return bbpeer;
+
+       bbpeer = XCALLOC(MTYPE_BMP_PEER, sizeof(*bbpeer));
+       bbpeer->peerid = peer->qobj_node.nid;
+       bmp_peerh_add(&bmp_peerh, bbpeer);
+
+       return bbpeer;
+}
+
+static struct bmp_targets *bmp_targets_find1(struct bgp *bgp, const char *name)
+{
+       struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp);
+       struct bmp_targets dummy;
+
+       if (!bmpbgp)
+               return NULL;
+       dummy.name = (char *)name;
+       return bmp_targets_find(&bmpbgp->targets, &dummy);
+}
+
+static struct bmp_targets *bmp_targets_get(struct bgp *bgp, const char *name)
+{
+       struct bmp_targets *bt;
+
+       bt = bmp_targets_find1(bgp, name);
+       if (bt)
+               return bt;
+
+       bt = XCALLOC(MTYPE_BMP_TARGETS, sizeof(*bt));
+       bt->name = XSTRDUP(MTYPE_BMP_TARGETSNAME, name);
+       bt->bgp = bgp;
+       bt->bmpbgp = bmp_bgp_get(bgp);
+       bmp_session_init(&bt->sessions);
+       bmp_qhash_init(&bt->updhash);
+       bmp_qlist_init(&bt->updlist);
+       bmp_actives_init(&bt->actives);
+       bmp_listeners_init(&bt->listeners);
+
+       QOBJ_REG(bt, bmp_targets);
+       bmp_targets_add(&bt->bmpbgp->targets, bt);
+       return bt;
+}
+
+static void bmp_targets_put(struct bmp_targets *bt)
+{
+       struct bmp *bmp;
+       struct bmp_active *ba;
+
+       frr_each_safe (bmp_actives, &bt->actives, ba)
+               bmp_active_put(ba);
+
+       frr_each_safe(bmp_session, &bt->sessions, bmp) {
+               bmp_close(bmp);
+               bmp_free(bmp);
+       }
+
+       bmp_targets_del(&bt->bmpbgp->targets, bt);
+       QOBJ_UNREG(bt);
+
+       bmp_listeners_fini(&bt->listeners);
+       bmp_actives_fini(&bt->actives);
+       bmp_qhash_fini(&bt->updhash);
+       bmp_qlist_fini(&bt->updlist);
+
+       XFREE(MTYPE_BMP_ACLNAME, bt->acl_name);
+       XFREE(MTYPE_BMP_ACLNAME, bt->acl6_name);
+       bmp_session_fini(&bt->sessions);
+
+       XFREE(MTYPE_BMP_TARGETSNAME, bt->name);
+       XFREE(MTYPE_BMP_TARGETS, bt);
+}
+
+static struct bmp_listener *bmp_listener_find(struct bmp_targets *bt,
+                                             const union sockunion *su,
+                                             int port)
+{
+       struct bmp_listener dummy;
+       dummy.addr = *su;
+       dummy.port = port;
+       return bmp_listeners_find(&bt->listeners, &dummy);
+}
+
+static struct bmp_listener *bmp_listener_get(struct bmp_targets *bt,
+                                            const union sockunion *su,
+                                            int port)
+{
+       struct bmp_listener *bl = bmp_listener_find(bt, su, port);
+
+       if (bl)
+               return bl;
+
+       bl = XCALLOC(MTYPE_BMP_LISTENER, sizeof(*bl));
+       bl->targets = bt;
+       bl->addr = *su;
+       bl->port = port;
+       bl->sock = -1;
+
+       bmp_listeners_add(&bt->listeners, bl);
+       return bl;
+}
+
+static void bmp_listener_put(struct bmp_listener *bl)
+{
+       bmp_listeners_del(&bl->targets->listeners, bl);
+       XFREE(MTYPE_BMP_LISTENER, bl);
+}
+
+static void bmp_listener_start(struct bmp_listener *bl)
+{
+       int sock, ret;
+
+       sock = socket(bl->addr.sa.sa_family, SOCK_STREAM, 0);
+       if (sock < 0)
+               return;
+
+       sockopt_reuseaddr(sock);
+       sockopt_reuseport(sock);
+       sockopt_v6only(bl->addr.sa.sa_family, sock);
+       set_cloexec(sock);
+
+       ret = sockunion_bind(sock, &bl->addr, bl->port, &bl->addr);
+       if (ret < 0)
+               goto out_sock;
+
+       ret = listen(sock, 3);
+       if (ret < 0)
+               goto out_sock;
+
+       bl->sock = sock;
+       thread_add_read(bm->master, bmp_accept, bl, sock, &bl->t_accept);
+       return;
+out_sock:
+       close(sock);
+}
+
+static void bmp_listener_stop(struct bmp_listener *bl)
+{
+       THREAD_OFF(bl->t_accept);
+
+       if (bl->sock != -1)
+               close(bl->sock);
+       bl->sock = -1;
+}
+
+static struct bmp_active *bmp_active_find(struct bmp_targets *bt,
+                                         const char *hostname, int port)
+{
+       struct bmp_active dummy;
+       dummy.hostname = (char *)hostname;
+       dummy.port = port;
+       return bmp_actives_find(&bt->actives, &dummy);
+}
+
+static struct bmp_active *bmp_active_get(struct bmp_targets *bt,
+                                        const char *hostname, int port)
+{
+       struct bmp_active *ba;
+
+       ba = bmp_active_find(bt, hostname, port);
+       if (ba)
+               return ba;
+
+       ba = XCALLOC(MTYPE_BMP_ACTIVE, sizeof(*ba));
+       ba->targets = bt;
+       ba->hostname = XSTRDUP(MTYPE_TMP, hostname);
+       ba->port = port;
+       ba->minretry = BMP_DFLT_MINRETRY;
+       ba->maxretry = BMP_DFLT_MAXRETRY;
+       ba->socket = -1;
+
+       bmp_actives_add(&bt->actives, ba);
+       return ba;
+}
+
+static void bmp_active_put(struct bmp_active *ba)
+{
+       THREAD_OFF(ba->t_timer);
+       THREAD_OFF(ba->t_read);
+       THREAD_OFF(ba->t_write);
+
+       bmp_actives_del(&ba->targets->actives, ba);
+
+       if (ba->bmp) {
+               ba->bmp->active = NULL;
+               bmp_close(ba->bmp);
+               bmp_free(ba->bmp);
+       }
+       if (ba->socket != -1)
+               close(ba->socket);
+
+       XFREE(MTYPE_TMP, ba->hostname);
+       XFREE(MTYPE_BMP_ACTIVE, ba);
+}
+
+static void bmp_active_setup(struct bmp_active *ba);
+
+static void bmp_active_connect(struct bmp_active *ba)
+{
+       enum connect_result res;
+       char buf[SU_ADDRSTRLEN];
+
+       for (; ba->addrpos < ba->addrtotal; ba->addrpos++) {
+               ba->socket = sockunion_socket(&ba->addrs[ba->addrpos]);
+               if (ba->socket < 0) {
+                       zlog_warn("bmp[%s]: failed to create socket",
+                                 ba->hostname);
+                       continue;
+               }
+               
+               set_nonblocking(ba->socket);
+               res = sockunion_connect(ba->socket, &ba->addrs[ba->addrpos],
+                                     htons(ba->port), 0);
+               switch (res) {
+               case connect_error:
+                       sockunion2str(&ba->addrs[ba->addrpos], buf,
+                                     sizeof(buf));
+                       zlog_warn("bmp[%s]: failed to connect to %s:%d",
+                                 ba->hostname, buf, ba->port);
+                       close(ba->socket);
+                       ba->socket = -1;
+                       continue;
+               case connect_success:
+                       break;
+               case connect_in_progress:
+                       bmp_active_setup(ba);
+                       return;
+               }
+       }
+
+       /* exhausted all addresses */
+       ba->curretry += ba->curretry / 2;
+       bmp_active_setup(ba);
+}
+
+static void bmp_active_resolved(struct resolver_query *resq, int numaddrs,
+                               union sockunion *addr)
+{
+       struct bmp_active *ba = container_of(resq, struct bmp_active, resq);
+       unsigned i;
+
+       if (numaddrs <= 0) {
+               zlog_warn("bmp[%s]: hostname resolution failed", ba->hostname);
+               ba->curretry += ba->curretry / 2;
+               bmp_active_setup(ba);
+               return;
+       }
+       if (numaddrs > (int)array_size(ba->addrs))
+               numaddrs = array_size(ba->addrs);
+
+       ba->addrpos = 0;
+       ba->addrtotal = numaddrs;
+       for (i = 0; i < ba->addrtotal; i++)
+               memcpy(&ba->addrs[i], &addr[i], sizeof(ba->addrs[0]));
+
+       bmp_active_connect(ba);
+}
+
+static int bmp_active_thread(struct thread *t)
+{
+       struct bmp_active *ba = THREAD_ARG(t);
+       socklen_t slen;
+       int status, ret;
+       char buf[SU_ADDRSTRLEN];
+
+       /* all 3 end up here, though only timer or read+write are active
+        * at a time */
+       THREAD_OFF(ba->t_timer);
+       THREAD_OFF(ba->t_read);
+       THREAD_OFF(ba->t_write);
+
+       if (ba->socket == -1) {
+               resolver_resolve(&ba->resq, AF_UNSPEC, ba->hostname,
+                                bmp_active_resolved);
+               return 0;
+       }
+
+       slen = sizeof(status);
+       ret = getsockopt(ba->socket, SOL_SOCKET, SO_ERROR, (void *)&status,
+                        &slen);
+
+       sockunion2str(&ba->addrs[ba->addrpos], buf, sizeof(buf));
+       if (ret < 0 || status != 0) {
+               zlog_warn("bmp[%s]: failed to connect to %s:%d",
+                         ba->hostname, buf, ba->port);
+               goto out_next;
+       }
+
+       zlog_warn("bmp[%s]: outbound connection to %s:%d",
+                 ba->hostname, buf, ba->port);
+
+       ba->bmp = bmp_open(ba->targets, ba->socket);
+       if (!ba->bmp)
+               goto out_next;
+
+       ba->bmp->active = ba;
+       ba->socket = -1;
+       ba->curretry = ba->minretry;
+       return 0;
+
+out_next:
+       close(ba->socket);
+       ba->socket = -1;
+       ba->addrpos++;
+       bmp_active_connect(ba);
+       return 0;
+}
+
+static void bmp_active_disconnected(struct bmp_active *ba)
+{
+       ba->bmp = NULL;
+       bmp_active_setup(ba);
+}
+
+static void bmp_active_setup(struct bmp_active *ba)
+{
+       THREAD_OFF(ba->t_timer);
+       THREAD_OFF(ba->t_read);
+       THREAD_OFF(ba->t_write);
+
+       if (ba->bmp)
+               return;
+       if (ba->resq.callback)
+               return;
+
+       if (ba->curretry > ba->maxretry)
+               ba->curretry = ba->maxretry;
+
+       if (ba->socket == -1)
+               thread_add_timer_msec(bm->master, bmp_active_thread, ba,
+                                     ba->curretry, &ba->t_timer);
+       else {
+               thread_add_read(bm->master, bmp_active_thread, ba, ba->socket,
+                               &ba->t_read);
+               thread_add_write(bm->master, bmp_active_thread, ba, ba->socket,
+                               &ba->t_write);
+       }
+}
+
+static struct cmd_node bmp_node = {BMP_NODE, "%s(config-bgp-bmp)# "};
+
+#define BMP_STR "BGP Monitoring Protocol\n"
+
+#ifndef VTYSH_EXTRACT_PL
+#include "bgp_bmp_clippy.c"
+#endif
+
+DEFPY_NOSH(bmp_targets_main,
+      bmp_targets_cmd,
+      "bmp targets BMPTARGETS",
+      BMP_STR
+      "Create BMP target group\n"
+      "Name of the BMP target group\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       struct bmp_targets *bt;
+
+       bt = bmp_targets_get(bgp, bmptargets);
+
+       VTY_PUSH_CONTEXT_SUB(BMP_NODE, bt);
+       return CMD_SUCCESS;
+}
+
+DEFPY(no_bmp_targets_main,
+      no_bmp_targets_cmd,
+      "no bmp targets BMPTARGETS",
+      NO_STR
+      BMP_STR
+      "Delete BMP target group\n"
+      "Name of the BMP target group\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       struct bmp_targets *bt;
+
+       bt = bmp_targets_find1(bgp, bmptargets);
+       if (!bt) {
+               vty_out(vty, "%% BMP target group not found\n");
+               return CMD_WARNING;
+       }
+       bmp_targets_put(bt);
+       return CMD_SUCCESS;
+}
+
+DEFPY(bmp_listener_main,
+      bmp_listener_cmd,
+      "bmp listener <X:X::X:X|A.B.C.D> port (1-65535)",
+      BMP_STR
+      "Listen for inbound BMP connections\n"
+      "IPv6 address to listen on\n"
+      "IPv4 address to listen on\n"
+      "TCP Port number\n"
+      "TCP Port number\n")
+{
+       VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
+       struct bmp_listener *bl;
+
+       bl = bmp_listener_get(bt, listener, port);
+       if (bl->sock == -1)
+               bmp_listener_start(bl);
+
+       return CMD_SUCCESS;
+}
+
+DEFPY(no_bmp_listener_main,
+      no_bmp_listener_cmd,
+      "no bmp listener <X:X::X:X|A.B.C.D> port (1-65535)",
+      NO_STR
+      BMP_STR
+      "Create BMP listener\n"
+      "IPv6 address to listen on\n"
+      "IPv4 address to listen on\n"
+      "TCP Port number\n"
+      "TCP Port number\n")
+{
+       VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
+       struct bmp_listener *bl;
+
+       bl = bmp_listener_find(bt, listener, port);
+       if (!bl) {
+               vty_out(vty, "%% BMP listener not found\n");
+               return CMD_WARNING;
+       }
+       bmp_listener_stop(bl);
+       bmp_listener_put(bl);
+       return CMD_SUCCESS;
+}
+
+DEFPY(bmp_connect,
+      bmp_connect_cmd,
+      "[no] bmp connect HOSTNAME port (1-65535) "
+               "{min-retry (100-86400000)"
+               "|max-retry (100-86400000)}",
+      NO_STR
+      BMP_STR
+      "Actively establish connection to monitoring station\n"
+      "Monitoring station hostname or address\n"
+      "TCP port\n"
+      "TCP port\n"
+      "Minimum connection retry interval\n"
+      "Minimum connection retry interval (milliseconds)\n"
+      "Maximum connection retry interval\n"
+      "Maximum connection retry interval (milliseconds)\n")
+{
+       VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
+       struct bmp_active *ba;
+
+       if (no) {
+               ba = bmp_active_find(bt, hostname, port);
+               if (!ba) {
+                       vty_out(vty, "%% No such active connection found\n");
+                       return CMD_WARNING;
+               }
+               bmp_active_put(ba);
+               return CMD_SUCCESS;
+       }
+
+       ba = bmp_active_get(bt, hostname, port);
+       if (min_retry_str)
+               ba->minretry = min_retry;
+       if (max_retry_str)
+               ba->maxretry = max_retry;
+       ba->curretry = ba->minretry;
+       bmp_active_setup(ba);
+
+       return CMD_SUCCESS;
+}
+
+DEFPY(bmp_acl,
+      bmp_acl_cmd,
+      "[no] <ip|ipv6>$af access-list WORD",
+      NO_STR
+      IP_STR
+      IPV6_STR
+      "Access list to restrict BMP sessions\n"
+      "Access list name\n")
+{
+       VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
+       char **what;
+
+       if (no)
+               access_list = NULL;
+       if (!strcmp(af, "ipv6"))
+               what = &bt->acl6_name;
+       else
+               what = &bt->acl_name;
+
+       XFREE(MTYPE_BMP_ACLNAME, *what);
+       if (access_list)
+               *what = XSTRDUP(MTYPE_BMP_ACLNAME, access_list);
+
+       return CMD_SUCCESS;
+}
+
+DEFPY(bmp_stats_cfg,
+      bmp_stats_cmd,
+      "[no] bmp stats [interval (100-86400000)]",
+      NO_STR
+      BMP_STR
+      "Send BMP statistics messages\n"
+      "Specify BMP stats interval\n"
+      "Interval (milliseconds) to send BMP Stats in\n")
+{
+       VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
+
+       THREAD_OFF(bt->t_stats);
+       if (no)
+               bt->stat_msec = 0;
+       else if (interval_str)
+               bt->stat_msec = interval;
+       else
+               bt->stat_msec = BMP_STAT_DEFAULT_TIMER;
+
+       if (bt->stat_msec)
+               thread_add_timer_msec(bm->master, bmp_stats, bt, bt->stat_msec,
+                                     &bt->t_stats);
+       return CMD_SUCCESS;
+}
+
+DEFPY(bmp_monitor_cfg,
+      bmp_monitor_cmd,
+      "[no] bmp monitor "BGP_AFI_CMD_STR" <unicast|multicast> <pre-policy|post-policy>$policy",
+      NO_STR
+      BMP_STR
+      "Send BMP route monitoring messages\n"
+      BGP_AFI_HELP_STR
+      "Address family modifier\n"
+      "Address family modifier\n"
+      "Send state before policy and filter processing\n"
+      "Send state with policy and filters applied\n")
+{
+       int index = 0;
+       uint8_t flag, prev;
+       afi_t afi;
+       safi_t safi;
+
+       VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
+       struct bmp *bmp;
+
+       argv_find_and_parse_afi(argv, argc, &index, &afi);
+       argv_find_and_parse_safi(argv, argc, &index, &safi);
+
+       if (policy[1] == 'r')
+               flag = BMP_MON_PREPOLICY;
+       else
+               flag = BMP_MON_POSTPOLICY;
+
+       prev = bt->afimon[afi][safi];
+       if (no)
+               bt->afimon[afi][safi] &= ~flag;
+       else
+               bt->afimon[afi][safi] |= flag;
+
+       if (prev == bt->afimon[afi][safi])
+               return CMD_SUCCESS;
+
+       frr_each (bmp_session, &bt->sessions, bmp) {
+               if (bmp->syncafi == afi && bmp->syncsafi == safi) {
+                       bmp->syncafi = AFI_MAX;
+                       bmp->syncsafi = SAFI_MAX;
+               }
+
+               if (!bt->afimon[afi][safi]) {
+                       bmp->afistate[afi][safi] = BMP_AFI_INACTIVE;
+                       continue;
+               }
+
+               bmp->afistate[afi][safi] = BMP_AFI_NEEDSYNC;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFPY(bmp_mirror_cfg,
+      bmp_mirror_cmd,
+      "[no] bmp mirror",
+      NO_STR
+      BMP_STR
+      "Send BMP route mirroring messages\n")
+{
+       VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
+       struct bmp *bmp;
+
+       if (bt->mirror == !no)
+               return CMD_SUCCESS;
+
+       bt->mirror = !no;
+       if (bt->mirror)
+               return CMD_SUCCESS;
+
+       frr_each (bmp_session, &bt->sessions, bmp) {
+               struct bmp_mirrorq *bmq;
+
+               while ((bmq = bmp_pull_mirror(bmp)))
+                       if (!bmq->refcount)
+                               XFREE(MTYPE_BMP_MIRRORQ, bmq);
+       }
+       return CMD_SUCCESS;
+}
+
+DEFPY(bmp_mirror_limit_cfg,
+      bmp_mirror_limit_cmd,
+      "bmp mirror buffer-limit (0-4294967294)",
+      BMP_STR
+      "Route Mirroring settings\n"
+      "Configure maximum memory used for buffered mirroring messages\n"
+      "Limit in bytes\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       struct bmp_bgp *bmpbgp;
+
+       bmpbgp = bmp_bgp_get(bgp);
+       bmpbgp->mirror_qsizelimit = buffer_limit;
+
+       return CMD_SUCCESS;
+}
+
+DEFPY(no_bmp_mirror_limit_cfg,
+      no_bmp_mirror_limit_cmd,
+      "no bmp mirror buffer-limit [(0-4294967294)]",
+      NO_STR
+      BMP_STR
+      "Route Mirroring settings\n"
+      "Configure maximum memory used for buffered mirroring messages\n"
+      "Limit in bytes\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       struct bmp_bgp *bmpbgp;
+
+       bmpbgp = bmp_bgp_get(bgp);
+       bmpbgp->mirror_qsizelimit = ~0UL;
+
+       return CMD_SUCCESS;
+}
+
+
+DEFPY(show_bmp,
+      show_bmp_cmd,
+      "show bmp",
+      SHOW_STR
+      BMP_STR)
+{
+       struct bmp_bgp *bmpbgp;
+       struct bmp_targets *bt;
+       struct bmp_listener *bl;
+       struct bmp *bmp;
+       struct ttable *tt;
+       char buf[SU_ADDRSTRLEN];
+
+       frr_each(bmp_bgph, &bmp_bgph, bmpbgp) {
+               vty_out(vty, "BMP state for BGP %s:\n\n",
+                               bmpbgp->bgp->name_pretty);
+               vty_out(vty, "  Route Mirroring %9zu bytes (%zu messages) pending\n",
+                               bmpbgp->mirror_qsize,
+                               bmp_mirrorq_count(&bmpbgp->mirrorq));
+               vty_out(vty, "                  %9zu bytes maximum buffer used\n",
+                               bmpbgp->mirror_qsizemax);
+               if (bmpbgp->mirror_qsizelimit != ~0UL)
+                       vty_out(vty, "                  %9zu bytes buffer size limit\n",
+                                       bmpbgp->mirror_qsizelimit);
+               vty_out(vty, "\n");
+
+               frr_each(bmp_targets, &bmpbgp->targets, bt) {
+                       vty_out(vty, "  Targets \"%s\":\n", bt->name);
+                       vty_out(vty, "    Route Mirroring %sabled\n",
+                               bt->mirror ? "en" : "dis");
+
+                       afi_t afi;
+                       safi_t safi;
+
+                       FOREACH_AFI_SAFI (afi, safi) {
+                               const char *str = NULL;
+
+                               switch (bt->afimon[afi][safi]) {
+                               case BMP_MON_PREPOLICY:
+                                       str = "pre-policy";
+                                       break;
+                               case BMP_MON_POSTPOLICY:
+                                       str = "post-policy";
+                                       break;
+                               case BMP_MON_PREPOLICY | BMP_MON_POSTPOLICY:
+                                       str = "pre-policy and post-policy";
+                                       break;
+                               }
+                               if (!str)
+                                       continue;
+                               vty_out(vty, "    Route Monitoring %s %s %s\n",
+                                       afi2str(afi), safi2str(safi), str);
+                       }
+
+                       vty_out(vty, "    Listeners:\n");
+                       frr_each (bmp_listeners, &bt->listeners, bl)
+                               vty_out(vty, "      %s:%d\n",
+                                       sockunion2str(&bl->addr, buf,
+                                                     SU_ADDRSTRLEN), bl->port);
+
+                       vty_out(vty, "\n    %zu connected clients:\n",
+                                       bmp_session_count(&bt->sessions));
+                       tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+                       ttable_add_row(tt, "remote|uptime|MonSent|MirrSent|MirrLost|ByteSent|ByteQ|ByteQKernel");
+                       ttable_rowseps(tt, 0, BOTTOM, true, '-');
+
+                       frr_each (bmp_session, &bt->sessions, bmp) {
+                               uint64_t total;
+                               size_t q, kq;
+
+                               pullwr_stats(bmp->pullwr, &total, &q, &kq);
+
+                               ttable_add_row(tt, "%s|-|%Lu|%Lu|%Lu|%Lu|%zu|%zu",
+                                              bmp->remote,
+                                              bmp->cnt_update,
+                                              bmp->cnt_mirror,
+                                              bmp->cnt_mirror_overruns,
+                                              total, q, kq);
+                       }
+                       char *out = ttable_dump(tt, "\n");
+                       vty_out(vty, "%s", out);
+                       XFREE(MTYPE_TMP, out);
+                       ttable_del(tt);
+                       vty_out(vty, "\n");
+               }
+       }
+
+       return CMD_SUCCESS;
+}
+
+static int bmp_config_write(struct bgp *bgp, struct vty *vty)
+{
+       struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp);
+       struct bmp_targets *bt;
+       struct bmp_listener *bl;
+       struct bmp_active *ba;
+       char buf[SU_ADDRSTRLEN];
+       afi_t afi;
+       safi_t safi;
+
+       if (!bmpbgp)
+               return 0;
+
+       if (bmpbgp->mirror_qsizelimit != ~0UL)
+               vty_out(vty, " !\n bmp mirror buffer-limit %zu\n",
+                       bmpbgp->mirror_qsizelimit);
+
+       frr_each(bmp_targets, &bmpbgp->targets, bt) {
+               vty_out(vty, " !\n bmp targets %s\n", bt->name);
+
+               if (bt->acl6_name)
+                       vty_out(vty, "  ipv6 access-list %s\n", bt->acl6_name);
+               if (bt->acl_name)
+                       vty_out(vty, "  ip access-list %s\n", bt->acl_name);
+
+               if (bt->stat_msec)
+                       vty_out(vty, "  bmp stats interval %d\n",
+                                       bt->stat_msec);
+
+               if (bt->mirror)
+                       vty_out(vty, "  bmp mirror\n");
+
+               FOREACH_AFI_SAFI (afi, safi) {
+                       const char *afi_str = (afi == AFI_IP) ? "ipv4" : "ipv6";
+
+                       if (bt->afimon[afi][safi] & BMP_MON_PREPOLICY)
+                               vty_out(vty, "  bmp monitor %s %s pre-policy\n",
+                                       afi_str, safi2str(safi));
+                       if (bt->afimon[afi][safi] & BMP_MON_POSTPOLICY)
+                               vty_out(vty, "  bmp monitor %s %s post-policy\n",
+                                       afi_str, safi2str(safi));
+               }
+               frr_each (bmp_listeners, &bt->listeners, bl)
+                       vty_out(vty, " \n  bmp listener %s port %d\n",
+                               sockunion2str(&bl->addr, buf, SU_ADDRSTRLEN),
+                               bl->port);
+
+               frr_each (bmp_actives, &bt->actives, ba)
+                       vty_out(vty, "  bmp connect %s port %u min-retry %u max-retry %u\n",
+                               ba->hostname, ba->port, ba->minretry, ba->maxretry);
+       }
+
+       return 0;
+}
+
+static int bgp_bmp_init(struct thread_master *tm)
+{
+       install_node(&bmp_node, NULL);
+       install_default(BMP_NODE);
+       install_element(BGP_NODE, &bmp_targets_cmd);
+       install_element(BGP_NODE, &no_bmp_targets_cmd);
+
+       install_element(BMP_NODE, &bmp_listener_cmd);
+       install_element(BMP_NODE, &no_bmp_listener_cmd);
+       install_element(BMP_NODE, &bmp_connect_cmd);
+       install_element(BMP_NODE, &bmp_acl_cmd);
+       install_element(BMP_NODE, &bmp_stats_cmd);
+       install_element(BMP_NODE, &bmp_monitor_cmd);
+       install_element(BMP_NODE, &bmp_mirror_cmd);
+
+       install_element(BGP_NODE, &bmp_mirror_limit_cmd);
+       install_element(BGP_NODE, &no_bmp_mirror_limit_cmd);
+
+       install_element(VIEW_NODE, &show_bmp_cmd);
+
+       resolver_init(tm);
+       return 0;
+}
+
+static int bgp_bmp_module_init(void)
+{
+       hook_register(bgp_packet_dump, bmp_mirror_packet);
+       hook_register(bgp_packet_send, bmp_outgoing_packet);
+       hook_register(peer_established, bmp_peer_established);
+       hook_register(peer_backward_transition, bmp_peer_backward);
+       hook_register(bgp_process, bmp_process);
+       hook_register(bgp_inst_config_write, bmp_config_write);
+       hook_register(bgp_inst_delete, bmp_bgp_del);
+       hook_register(frr_late_init, bgp_bmp_init);
+       return 0;
+}
+
+FRR_MODULE_SETUP(.name = "bgpd_bmp", .version = FRR_VERSION,
+                .description = "bgpd BMP module",
+                .init = bgp_bmp_module_init)
diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h
new file mode 100644 (file)
index 0000000..9d270e8
--- /dev/null
@@ -0,0 +1,303 @@
+/* BMP support.
+ * Copyright (C) 2018 Yasuhiro Ohara
+ * Copyright (C) 2019 David Lamparter for NetDEF, Inc.
+ *
+ * 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 _BGP_BMP_H_
+#define _BGP_BMP_H_
+
+#include "zebra.h"
+#include "typesafe.h"
+#include "pullwr.h"
+#include "qobj.h"
+#include "resolver.h"
+
+#define BMP_VERSION_3  3
+
+#define BMP_LENGTH_POS  1
+
+/* BMP message types */
+#define BMP_TYPE_ROUTE_MONITORING       0
+#define BMP_TYPE_STATISTICS_REPORT      1
+#define BMP_TYPE_PEER_DOWN_NOTIFICATION 2
+#define BMP_TYPE_PEER_UP_NOTIFICATION   3
+#define BMP_TYPE_INITIATION             4
+#define BMP_TYPE_TERMINATION            5
+#define BMP_TYPE_ROUTE_MIRRORING        6
+
+#define BMP_READ_BUFSIZ        1024
+
+/* bmp->state */
+#define BMP_None        0
+#define BMP_PeerUp      2
+#define BMP_Run         3
+
+/* This one is for BMP Route Monitoring messages, i.e. delivering updates
+ * in somewhat processed (as opposed to fully raw, see mirroring below) form.
+ * RFC explicitly says that we can skip old updates if we haven't sent them out
+ * yet and another newer update for the same prefix arrives.
+ *
+ * So, at most one of these can exist for each (bgp, afi, safi, prefix, peerid)
+ * tuple; if some prefix is "re-added" to the queue, the existing entry is
+ * instead moved to the end of the queue.  This ensures that the queue size is
+ * bounded by the BGP table size.
+ *
+ * bmp_qlist is the queue itself while bmp_qhash is used to efficiently check
+ * whether a tuple is already on the list.  The queue is maintained per
+ * bmp_target.
+ *
+ * refcount = number of "struct bmp *" whose queue position is before this
+ * entry, i.e. number of BMP sessions where we still want to send this out.
+ * Decremented on send so we know when we're done with an entry (i.e. this
+ * always happens from the front of the queue.)
+ */
+
+PREDECL_DLIST(bmp_qlist)
+PREDECL_HASH(bmp_qhash)
+
+struct bmp_queue_entry {
+       struct bmp_qlist_item bli;
+       struct bmp_qhash_item bhi;
+
+       struct prefix p;
+       uint64_t peerid;
+       afi_t afi;
+       safi_t safi;
+
+       size_t refcount;
+};
+
+/* This is for BMP Route Mirroring, which feeds fully raw BGP PDUs out to BMP
+ * receivers.  So, this goes directly off packet RX/TX handling instead of
+ * grabbing bits from tables.
+ *
+ * There is *one* queue for each "struct bgp *" where we throw everything on,
+ * with a size limit.  Refcount works the same as for monitoring above.
+ */
+
+PREDECL_LIST(bmp_mirrorq)
+
+struct bmp_mirrorq {
+       struct bmp_mirrorq_item bmi;
+
+       size_t refcount;
+       uint64_t peerid;
+       struct timeval tv;
+
+       size_t len;
+       uint8_t data[0];
+};
+
+enum {
+       BMP_AFI_INACTIVE = 0,
+       BMP_AFI_NEEDSYNC,
+       BMP_AFI_SYNC,
+       BMP_AFI_LIVE,
+};
+
+PREDECL_LIST(bmp_session)
+
+struct bmp_active;
+struct bmp_targets;
+
+/* an established BMP session to a peer */
+struct bmp {
+       struct bmp_session_item bsi;
+       struct bmp_targets *targets;
+       struct bmp_active *active;
+
+       int socket;
+       char remote[SU_ADDRSTRLEN + 6];
+       struct thread *t_read;
+
+       struct pullwr *pullwr;
+
+       int state;
+
+       /* queue positions must remain synced with refcounts in the items.
+        * Whenever appending a queue item, we need to know the correct number
+        * of "struct bmp *" that want it, and when moving these positions
+        * ahead we need to make sure that refcount is decremented.  Also, on
+        * disconnects we need to walk the queue and drop our reference.
+        */
+       struct bmp_queue_entry *queuepos;
+       struct bmp_mirrorq *mirrorpos;
+       bool mirror_lost;
+
+       /* enum BMP_AFI_* */
+       uint8_t afistate[AFI_MAX][SAFI_MAX];
+
+       /* counters for the various BMP packet types */
+       uint64_t cnt_update, cnt_mirror;
+       /* number of times this peer wasn't fast enough in consuming the
+        * mirror queue
+        */
+       uint64_t cnt_mirror_overruns;
+       struct timeval t_up;
+
+       /* synchronization / startup works by repeatedly finding the next
+        * table entry, the sync* fields note down what we sent last
+        */
+       struct prefix syncpos;
+       uint64_t syncpeerid;
+       afi_t syncafi;
+       safi_t syncsafi;
+};
+
+/* config & state for an active outbound connection.  When the connection
+ * succeeds, "bmp" is set up.
+ */
+
+PREDECL_SORTLIST_UNIQ(bmp_actives)
+
+#define BMP_DFLT_MINRETRY      30000
+#define BMP_DFLT_MAXRETRY      720000
+
+struct bmp_active {
+       struct bmp_actives_item bai;
+       struct bmp_targets *targets;
+       struct bmp *bmp;
+
+       char *hostname;
+       int port;
+       unsigned minretry, maxretry;
+
+       struct resolver_query resq;
+
+       unsigned curretry;
+       unsigned addrpos, addrtotal;
+       union sockunion addrs[8];
+       int socket;
+       struct thread *t_timer, *t_read, *t_write;
+};
+
+/* config & state for passive / listening sockets */
+PREDECL_SORTLIST_UNIQ(bmp_listeners)
+
+struct bmp_listener {
+       struct bmp_listeners_item bli;
+
+       struct bmp_targets *targets;
+
+       union sockunion addr;
+       int port;
+
+       struct thread *t_accept;
+       int sock;
+};
+
+/* bmp_targets - plural since it may contain multiple bmp_listener &
+ * bmp_active items.  If they have the same config, BMP session should be
+ * put in the same targets since that's a bit more effective.
+ */
+PREDECL_SORTLIST_UNIQ(bmp_targets)
+
+struct bmp_targets {
+       struct bmp_targets_item bti;
+
+       struct bmp_bgp *bmpbgp;
+       struct bgp *bgp;
+       char *name;
+
+       struct bmp_listeners_head listeners;
+
+       char *acl_name;
+       char *acl6_name;
+#define BMP_STAT_DEFAULT_TIMER 60000
+       int stat_msec;
+
+       /* only IPv4 & IPv6 / unicast & multicast supported for now */
+#define BMP_MON_PREPOLICY      (1 << 0)
+#define BMP_MON_POSTPOLICY     (1 << 1)
+       uint8_t afimon[AFI_MAX][SAFI_MAX];
+       bool mirror;
+
+       struct bmp_actives_head actives;
+
+       struct thread *t_stats;
+       struct bmp_session_head sessions;
+
+       struct bmp_qhash_head updhash;
+       struct bmp_qlist_head updlist;
+
+       uint64_t cnt_accept, cnt_aclrefused;
+
+       QOBJ_FIELDS
+};
+DECLARE_QOBJ_TYPE(bmp_targets)
+
+/* per struct peer * data.  Lookup by peer->qobj_node.nid, created on demand,
+ * deleted in peer_backward hook. */
+PREDECL_HASH(bmp_peerh)
+
+struct bmp_bgp_peer {
+       struct bmp_peerh_item bpi;
+
+       uint64_t peerid;
+       /* struct peer *peer; */
+
+       uint8_t *open_rx;
+       size_t open_rx_len;
+
+       uint8_t *open_tx;
+       size_t open_tx_len;
+};
+
+/* per struct bgp * data */
+PREDECL_HASH(bmp_bgph)
+
+struct bmp_bgp {
+       struct bmp_bgph_item bbi;
+
+       struct bgp *bgp;
+       struct bmp_targets_head targets;
+
+       struct bmp_mirrorq_head mirrorq;
+       size_t mirror_qsize, mirror_qsizemax;
+
+       size_t mirror_qsizelimit;
+};
+
+enum {
+       BMP_PEERDOWN_LOCAL_NOTIFY       = 1,
+       BMP_PEERDOWN_LOCAL_FSM          = 2,
+       BMP_PEERDOWN_REMOTE_NOTIFY      = 3,
+       BMP_PEERDOWN_REMOTE_CLOSE       = 4,
+       BMP_PEERDOWN_ENDMONITOR         = 5,
+};
+
+enum {
+       BMP_STATS_PFX_REJECTED          = 0,
+       BMP_STATS_PFX_DUP_ADV           = 1,
+       BMP_STATS_PFX_DUP_WITHDRAW      = 2,
+       BMP_STATS_UPD_LOOP_CLUSTER      = 3,
+       BMP_STATS_UPD_LOOP_ASPATH       = 4,
+       BMP_STATS_UPD_LOOP_ORIGINATOR   = 5,
+       BMP_STATS_UPD_LOOP_CONFED       = 6,
+       BMP_STATS_SIZE_ADJ_RIB_IN       = 7,
+       BMP_STATS_SIZE_LOC_RIB          = 8,
+       BMP_STATS_SIZE_ADJ_RIB_IN_SAFI  = 9,
+       BMP_STATS_SIZE_LOC_RIB_IN_SAFI  = 10,
+       BMP_STATS_UPD_7606_WITHDRAW     = 11,
+       BMP_STATS_PFX_7606_WITHDRAW     = 12,
+       BMP_STATS_UPD_DUP               = 13,
+       BMP_STATS_FRR_NH_INVALID        = 65531,
+};
+
+DECLARE_MGROUP(BMP)
+
+#endif /*_BGP_BMP_H_*/
index 3bc3d74de6f2beba78e54e28dc844ad99f025fbc..4d02e39ae22173ce70ef00b64a3cdb8d6ee8efee 100644 (file)
@@ -4459,7 +4459,8 @@ void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
                                          struct ecommunity *ecomadd)
 {
        /* uninstall routes from vrf */
-       uninstall_routes_for_vrf(bgp_vrf);
+       if (is_l3vni_live(bgp_vrf))
+               uninstall_routes_for_vrf(bgp_vrf);
 
        /* Cleanup the RT to VRF mapping */
        bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
@@ -4471,11 +4472,11 @@ void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
        listnode_add_sort(bgp_vrf->vrf_import_rtl, ecomadd);
        SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
 
-       /* map VRF to its RTs */
-       bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
-
-       /* install routes matching the new VRF */
-       install_routes_for_vrf(bgp_vrf);
+       /* map VRF to its RTs and install routes matching the new RTs */
+       if (is_l3vni_live(bgp_vrf)) {
+               bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
+               install_routes_for_vrf(bgp_vrf);
+       }
 }
 
 void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
@@ -4485,7 +4486,8 @@ void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
        struct ecommunity *ecom = NULL;
 
        /* uninstall routes from vrf */
-       uninstall_routes_for_vrf(bgp_vrf);
+       if (is_l3vni_live(bgp_vrf))
+               uninstall_routes_for_vrf(bgp_vrf);
 
        /* Cleanup the RT to VRF mapping */
        bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
@@ -4509,11 +4511,11 @@ void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
                evpn_auto_rt_import_add_for_vrf(bgp_vrf);
        }
 
-       /* map VRFs to its RTs */
-       bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
-
-       /* install routes matching this new RT */
-       install_routes_for_vrf(bgp_vrf);
+       /* map VRFs to its RTs and install routes matching this new RT */
+       if (is_l3vni_live(bgp_vrf)) {
+               bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
+               install_routes_for_vrf(bgp_vrf);
+       }
 }
 
 void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
index a5a091242f1636ca61b95d1ca4be5b1ccc68ac1a..f6bde2e9fa3c837c9b195f68ac272b45475cc566 100644 (file)
@@ -275,6 +275,11 @@ static inline int is_vni_live(struct bgpevpn *vpn)
        return (CHECK_FLAG(vpn->flags, VNI_FLAG_LIVE));
 }
 
+static inline int is_l3vni_live(struct bgp *bgp_vrf)
+{
+       return (bgp_vrf->l3vni && bgp_vrf->l3vni_svi_ifindex);
+}
+
 static inline int is_rd_configured(struct bgpevpn *vpn)
 {
        return (CHECK_FLAG(vpn->flags, VNI_FLAG_RD_CFGD));
index d031d34f1f9975c3c404af640ae0684be3c49b2d..30380f6add7610366796ee21657ef1d2c82e873e 100644 (file)
@@ -3696,7 +3696,7 @@ DEFUN(show_bgp_l2vpn_evpn_es,
  */
 DEFUN(show_bgp_l2vpn_evpn_summary,
       show_bgp_l2vpn_evpn_summary_cmd,
-      "show bgp [vrf VRFNAME] l2vpn evpn summary [json]",
+      "show bgp [vrf VRFNAME] l2vpn evpn summary [failed] [json]",
       SHOW_STR
       BGP_STR
       "bgp vrf\n"
@@ -3704,15 +3704,20 @@ DEFUN(show_bgp_l2vpn_evpn_summary,
       L2VPN_HELP_STR
       EVPN_HELP_STR
       "Summary of BGP neighbor status\n"
+      "Show only sessions not in Established state\n"
       JSON_STR)
 {
        int idx_vrf = 0;
        bool uj = use_json(argc, argv);
        char *vrf = NULL;
+       bool show_failed = false;
 
        if (argv_find(argv, argc, "vrf", &idx_vrf))
                vrf = argv[++idx_vrf]->arg;
-       return bgp_show_summary_vty(vty, vrf, AFI_L2VPN, SAFI_EVPN, uj);
+       if (argv_find(argv, argc, "failed", &idx_vrf))
+               show_failed = true;
+       return bgp_show_summary_vty(vty, vrf, AFI_L2VPN, SAFI_EVPN,
+                                   show_failed, uj);
 }
 
 /*
@@ -3757,9 +3762,9 @@ DEFUN(show_bgp_l2vpn_evpn_route,
                        type = BGP_EVPN_MAC_IP_ROUTE;
                else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
                        type = BGP_EVPN_IMET_ROUTE;
-               else if (strncmp(argv[type_idx + 1]->arg, "es", 2) == 0)
+               else if (strncmp(argv[type_idx + 1]->arg, "e", 1) == 0)
                        type = BGP_EVPN_ES_ROUTE;
-               else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0)
+               else if (strncmp(argv[type_idx + 1]->arg, "p", 1) == 0)
                        type = BGP_EVPN_IP_PREFIX_ROUTE;
                else
                        return CMD_WARNING;
index c9c6fc157e63fdf6f6e353fc2b2e5e83c29c0514..cc7f81d9ff97baf1eba537a02cea4830befebe8e 100644 (file)
@@ -179,9 +179,7 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
         * on various buffers. Those need to be transferred or dropped,
         * otherwise we'll get spurious failures during session establishment.
         */
-       pthread_mutex_lock(&peer->io_mtx);
-       pthread_mutex_lock(&from_peer->io_mtx);
-       {
+       frr_with_mutex(&peer->io_mtx, &from_peer->io_mtx) {
                fd = peer->fd;
                peer->fd = from_peer->fd;
                from_peer->fd = fd;
@@ -222,8 +220,6 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
                ringbuf_copy(peer->ibuf_work, from_peer->ibuf_work,
                             ringbuf_remain(from_peer->ibuf_work));
        }
-       pthread_mutex_unlock(&from_peer->io_mtx);
-       pthread_mutex_unlock(&peer->io_mtx);
 
        peer->as = from_peer->as;
        peer->v_holdtime = from_peer->v_holdtime;
@@ -244,6 +240,7 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
        from_peer->last_event = last_evt;
        from_peer->last_major_event = last_maj_evt;
        peer->remote_id = from_peer->remote_id;
+       peer->last_reset = from_peer->last_reset;
 
        if (from_peer->hostname != NULL) {
                if (peer->hostname) {
@@ -551,7 +548,11 @@ const char *peer_down_str[] = {"",
                               "Intf peering v6only config change",
                               "BFD down received",
                               "Interface down",
-                              "Neighbor address lost"};
+                              "Neighbor address lost",
+                              "Waiting for NHT",
+                              "Waiting for Peer IPv6 LLA",
+                              "Waiting for VRF to be initialized",
+                              "No AFI/SAFI activated for peer"};
 
 static int bgp_graceful_restart_timer_expire(struct thread *thread)
 {
@@ -1162,8 +1163,7 @@ int bgp_stop(struct peer *peer)
        BGP_TIMER_OFF(peer->t_routeadv);
 
        /* Clear input and output buffer.  */
-       pthread_mutex_lock(&peer->io_mtx);
-       {
+       frr_with_mutex(&peer->io_mtx) {
                if (peer->ibuf)
                        stream_fifo_clean(peer->ibuf);
                if (peer->obuf)
@@ -1179,7 +1179,6 @@ int bgp_stop(struct peer *peer)
                        peer->curr = NULL;
                }
        }
-       pthread_mutex_unlock(&peer->io_mtx);
 
        /* Close of file descriptor. */
        if (peer->fd >= 0) {
@@ -1410,6 +1409,7 @@ int bgp_start(struct peer *peer)
                        zlog_debug(
                                "%s [FSM] Unable to get neighbor's IP address, waiting...",
                                peer->host);
+               peer->last_reset = PEER_DOWN_NBR_ADDR;
                return -1;
        }
 
@@ -1455,6 +1455,7 @@ int bgp_start(struct peer *peer)
                                EC_BGP_FSM,
                                "%s [FSM] In a VRF that is not initialised yet",
                                peer->host);
+               peer->last_reset = PEER_DOWN_VRF_UNINIT;
                return -1;
        }
 
@@ -1466,7 +1467,7 @@ int bgp_start(struct peer *peer)
                        if (bgp_debug_neighbor_events(peer))
                                zlog_debug("%s [FSM] Waiting for NHT",
                                           peer->host);
-
+                       peer->last_reset = PEER_DOWN_WAITING_NHT;
                        BGP_EVENT_ADD(peer, TCP_connection_open_failed);
                        return 0;
                }
index f111822e53ca5f46460b0147af65aa415ae848e3..c2d06a4b5a078941cb9261f6ad36d2e88f071877 100644 (file)
@@ -132,12 +132,10 @@ static int bgp_process_writes(struct thread *thread)
 
        struct frr_pthread *fpt = bgp_pth_io;
 
-       pthread_mutex_lock(&peer->io_mtx);
-       {
+       frr_with_mutex(&peer->io_mtx) {
                status = bgp_write(peer);
                reschedule = (stream_fifo_head(peer->obuf) != NULL);
        }
-       pthread_mutex_unlock(&peer->io_mtx);
 
        /* no problem */
        if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) {
@@ -184,11 +182,9 @@ static int bgp_process_reads(struct thread *thread)
 
        struct frr_pthread *fpt = bgp_pth_io;
 
-       pthread_mutex_lock(&peer->io_mtx);
-       {
+       frr_with_mutex(&peer->io_mtx) {
                status = bgp_read(peer);
        }
-       pthread_mutex_unlock(&peer->io_mtx);
 
        /* error checking phase */
        if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) {
@@ -237,11 +233,9 @@ static int bgp_process_reads(struct thread *thread)
                        assert(ringbuf_get(ibw, pktbuf, pktsize) == pktsize);
                        stream_put(pkt, pktbuf, pktsize);
 
-                       pthread_mutex_lock(&peer->io_mtx);
-                       {
+                       frr_with_mutex(&peer->io_mtx) {
                                stream_fifo_push(peer->ibuf, pkt);
                        }
-                       pthread_mutex_unlock(&peer->io_mtx);
 
                        added_pkt = true;
                } else
index bec3bdcb8d0e1320b957e00b8c4f7694a2c71848..6de1c216a65b4bc155061ab3978bd4544dfafcdd 100644 (file)
@@ -245,8 +245,7 @@ void bgp_keepalives_on(struct peer *peer)
         */
        assert(peerhash_mtx);
 
-       pthread_mutex_lock(peerhash_mtx);
-       {
+       frr_with_mutex(peerhash_mtx) {
                holder.peer = peer;
                if (!hash_lookup(peerhash, &holder)) {
                        struct pkat *pkat = pkat_new(peer);
@@ -255,7 +254,6 @@ void bgp_keepalives_on(struct peer *peer)
                }
                SET_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON);
        }
-       pthread_mutex_unlock(peerhash_mtx);
        bgp_keepalives_wake();
 }
 
@@ -275,8 +273,7 @@ void bgp_keepalives_off(struct peer *peer)
         */
        assert(peerhash_mtx);
 
-       pthread_mutex_lock(peerhash_mtx);
-       {
+       frr_with_mutex(peerhash_mtx) {
                holder.peer = peer;
                struct pkat *res = hash_release(peerhash, &holder);
                if (res) {
@@ -285,16 +282,13 @@ void bgp_keepalives_off(struct peer *peer)
                }
                UNSET_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON);
        }
-       pthread_mutex_unlock(peerhash_mtx);
 }
 
 void bgp_keepalives_wake(void)
 {
-       pthread_mutex_lock(peerhash_mtx);
-       {
+       frr_with_mutex(peerhash_mtx) {
                pthread_cond_signal(peerhash_cond);
        }
-       pthread_mutex_unlock(peerhash_mtx);
 }
 
 int bgp_keepalives_stop(struct frr_pthread *fpt, void **result)
index 1dadf00e8f963da7c8d4d881cd1f2f90c20e1d47..887caee95e08aa2f9bb4f2d979c8041fd6af1ee5 100644 (file)
@@ -122,7 +122,7 @@ static int bgp_md5_set_connect(int socket, union sockunion *su,
        int ret = -1;
 
 #if HAVE_DECL_TCP_MD5SIG
-       frr_elevate_privs(&bgpd_privs) {
+       frr_with_privs(&bgpd_privs) {
                ret = bgp_md5_set_socket(socket, su, prefixlen, password);
        }
 #endif /* HAVE_TCP_MD5SIG */
@@ -140,8 +140,7 @@ static int bgp_md5_set_password(struct peer *peer, const char *password)
         * Set or unset the password on the listen socket(s). Outbound
         * connections are taken care of in bgp_connect() below.
         */
-       frr_elevate_privs(&bgpd_privs)
-       {
+       frr_with_privs(&bgpd_privs) {
                for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
                        if (listener->su.sa.sa_family
                            == peer->su.sa.sa_family) {
@@ -167,8 +166,7 @@ int bgp_md5_set_prefix(struct prefix *p, const char *password)
        struct bgp_listener *listener;
 
        /* Set or unset the password on the listen socket(s). */
-       frr_elevate_privs(&bgpd_privs)
-       {
+       frr_with_privs(&bgpd_privs) {
                for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
                        if (listener->su.sa.sa_family == p->family) {
                                prefix2sockunion(p, &su);
@@ -610,7 +608,7 @@ int bgp_connect(struct peer *peer)
                zlog_debug("Peer address not learnt: Returning from connect");
                return 0;
        }
-       frr_elevate_privs(&bgpd_privs) {
+       frr_with_privs(&bgpd_privs) {
        /* Make socket for the peer. */
                peer->fd = vrf_sockunion_socket(&peer->su, peer->bgp->vrf_id,
                                                bgp_get_bound_name(peer));
@@ -630,7 +628,7 @@ int bgp_connect(struct peer *peer)
        sockopt_reuseport(peer->fd);
 
 #ifdef IPTOS_PREC_INTERNETCONTROL
-       frr_elevate_privs(&bgpd_privs) {
+       frr_with_privs(&bgpd_privs) {
                if (sockunion_family(&peer->su) == AF_INET)
                        setsockopt_ipv4_tos(peer->fd,
                                            IPTOS_PREC_INTERNETCONTROL);
@@ -708,7 +706,7 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen,
        sockopt_reuseaddr(sock);
        sockopt_reuseport(sock);
 
-       frr_elevate_privs(&bgpd_privs) {
+       frr_with_privs(&bgpd_privs) {
 
 #ifdef IPTOS_PREC_INTERNETCONTROL
                if (sa->sa_family == AF_INET)
@@ -767,7 +765,7 @@ int bgp_socket(struct bgp *bgp, unsigned short port, const char *address)
        snprintf(port_str, sizeof(port_str), "%d", port);
        port_str[sizeof(port_str) - 1] = '\0';
 
-       frr_elevate_privs(&bgpd_privs) {
+       frr_with_privs(&bgpd_privs) {
                ret = vrf_getaddrinfo(address, port_str, &req, &ainfo_save,
                                      bgp->vrf_id);
        }
@@ -788,7 +786,7 @@ int bgp_socket(struct bgp *bgp, unsigned short port, const char *address)
                if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
                        continue;
 
-               frr_elevate_privs(&bgpd_privs) {
+               frr_with_privs(&bgpd_privs) {
                        sock = vrf_socket(ainfo->ai_family,
                                          ainfo->ai_socktype,
                                          ainfo->ai_protocol, bgp->vrf_id,
index 64529f6ef384efaca43e51766c5bcc55c340767a..7e5e07099d00022bc94c42bff2af6d7a7500b599 100644 (file)
@@ -503,7 +503,7 @@ static int bgp_capability_restart(struct peer *peer,
                        if (bgp_debug_neighbor_events(peer))
                                zlog_debug(
                                        "%s Address family %s is%spreserved",
-                                       peer->host, afi_safi_print(afi, safi),
+                                       peer->host, get_afi_safi_str(afi, safi, false),
                                        CHECK_FLAG(
                                                peer->af_cap[afi][safi],
                                                PEER_CAP_RESTART_AF_PRESERVE_RCV)
index 99522a6522afee71d75022113a35c6d112dfe0c6..c7c1780c21c334a9f4cce3d785ce71bc27b4af04 100644 (file)
@@ -41,6 +41,7 @@
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_table.h"
 #include "bgpd/bgp_dump.h"
+#include "bgpd/bgp_bmp.h"
 #include "bgpd/bgp_attr.h"
 #include "bgpd/bgp_debug.h"
 #include "bgpd/bgp_errors.h"
@@ -123,9 +124,9 @@ int bgp_packet_set_size(struct stream *s)
  */
 static void bgp_packet_add(struct peer *peer, struct stream *s)
 {
-       pthread_mutex_lock(&peer->io_mtx);
-       stream_fifo_push(peer->obuf, s);
-       pthread_mutex_unlock(&peer->io_mtx);
+       frr_with_mutex(&peer->io_mtx) {
+               stream_fifo_push(peer->obuf, s);
+       }
 }
 
 static struct stream *bgp_update_packet_eor(struct peer *peer, afi_t afi,
@@ -140,7 +141,7 @@ static struct stream *bgp_update_packet_eor(struct peer *peer, afi_t afi,
 
        if (bgp_debug_neighbor_events(peer))
                zlog_debug("send End-of-RIB for %s to %s",
-                          afi_safi_print(afi, safi), peer->host);
+                          get_afi_safi_str(afi, safi, false), peer->host);
 
        s = stream_new(BGP_MAX_PACKET_SIZE);
 
@@ -664,7 +665,7 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
        struct stream *s;
 
        /* Lock I/O mutex to prevent other threads from pushing packets */
-       pthread_mutex_lock(&peer->io_mtx);
+       frr_mutex_lock_autounlock(&peer->io_mtx);
        /* ============================================== */
 
        /* Allocate new stream. */
@@ -755,9 +756,6 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
        stream_fifo_push(peer->obuf, s);
 
        bgp_write_notify(peer);
-
-       /* ============================================== */
-       pthread_mutex_unlock(&peer->io_mtx);
 }
 
 /*
@@ -1660,7 +1658,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
                                bgp_clear_stale_route(peer, afi, safi);
 
                        zlog_info("%%NOTIFICATION: rcvd End-of-RIB for %s from %s in vrf %s",
-                                 afi_safi_print(afi, safi), peer->host,
+                                 get_afi_safi_str(afi, safi, false), peer->host,
                                  vrf ? vrf->name : VRF_DEFAULT_NAME);
                }
        }
@@ -2236,11 +2234,9 @@ int bgp_process_packet(struct thread *thread)
                bgp_size_t size;
                char notify_data_length[2];
 
-               pthread_mutex_lock(&peer->io_mtx);
-               {
+               frr_with_mutex(&peer->io_mtx) {
                        peer->curr = stream_fifo_pop(peer->ibuf);
                }
-               pthread_mutex_unlock(&peer->io_mtx);
 
                if (peer->curr == NULL) // no packets to process, hmm...
                        return 0;
@@ -2359,15 +2355,13 @@ int bgp_process_packet(struct thread *thread)
 
        if (fsm_update_result != FSM_PEER_TRANSFERRED
            && fsm_update_result != FSM_PEER_STOPPED) {
-               pthread_mutex_lock(&peer->io_mtx);
-               {
+               frr_with_mutex(&peer->io_mtx) {
                        // more work to do, come back later
                        if (peer->ibuf->count > 0)
                                thread_add_timer_msec(
                                        bm->master, bgp_process_packet, peer, 0,
                                        &peer->t_process_packet);
                }
-               pthread_mutex_unlock(&peer->io_mtx);
        }
 
        return 0;
index 183debddba78f540765311f35115ccad26488e2c..32c9fb16f3b35572e1debd9ed0f88837f63e73ff 100644 (file)
@@ -2750,7 +2750,7 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi,
                zlog_info(
                        "%%MAXPFXEXCEED: No. of %s prefix received from %s %ld exceed, "
                        "limit %ld",
-                       afi_safi_print(afi, safi), peer->host,
+                       get_afi_safi_str(afi, safi, false), peer->host,
                        peer->pcount[afi][safi], peer->pmax[afi][safi]);
                SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT);
 
@@ -2811,7 +2811,7 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi,
 
                zlog_info(
                        "%%MAXPFX: No. of %s prefix received from %s reaches %ld, max %ld",
-                       afi_safi_print(afi, safi), peer->host,
+                       get_afi_safi_str(afi, safi, false), peer->host,
                        peer->pcount[afi][safi], peer->pmax[afi][safi]);
                SET_FLAG(peer->af_sflags[afi][safi],
                         PEER_STATUS_PREFIX_THRESHOLD);
@@ -10696,7 +10696,7 @@ static int bgp_table_stats(struct vty *vty, struct bgp *bgp, afi_t afi,
                return CMD_WARNING;
        }
 
-       vty_out(vty, "BGP %s RIB statistics\n", afi_safi_print(afi, safi));
+       vty_out(vty, "BGP %s RIB statistics\n", get_afi_safi_str(afi, safi, false));
 
        /* labeled-unicast routes live in the unicast table */
        if (safi == SAFI_LABELED_UNICAST)
@@ -10895,7 +10895,7 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi,
        if (use_json) {
                json_object_string_add(json, "prefixCountsFor", peer->host);
                json_object_string_add(json, "multiProtocol",
-                                      afi_safi_print(afi, safi));
+                                      get_afi_safi_str(afi, safi, true));
                json_object_int_add(json, "pfxCounter",
                                    peer->pcount[afi][safi]);
 
@@ -10921,10 +10921,10 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi,
                    && bgp_flag_check(peer->bgp, BGP_FLAG_SHOW_HOSTNAME)) {
                        vty_out(vty, "Prefix counts for %s/%s, %s\n",
                                peer->hostname, peer->host,
-                               afi_safi_print(afi, safi));
+                               get_afi_safi_str(afi, safi, false));
                } else {
                        vty_out(vty, "Prefix counts for %s, %s\n", peer->host,
-                               afi_safi_print(afi, safi));
+                               get_afi_safi_str(afi, safi, false));
                }
 
                vty_out(vty, "PfxCt: %ld\n", peer->pcount[afi][safi]);
@@ -11552,7 +11552,7 @@ DEFUN (show_ip_bgp_neighbor_received_prefix_filter,
        if (count) {
                if (!uj)
                        vty_out(vty, "Address Family: %s\n",
-                               afi_safi_print(afi, safi));
+                               get_afi_safi_str(afi, safi, false));
                prefix_bgp_show_prefix_list(vty, afi, name, uj);
        } else {
                if (uj)
index 7f1a9b71c137f6ba1b63426890785eb448c7bec8..545ca19762997fd1d2e1db2b507090a7f9eee891 100644 (file)
@@ -3057,7 +3057,7 @@ static int bgp_route_match_add(struct vty *vty, const char *command,
 {
        VTY_DECLVAR_CONTEXT(route_map_index, index);
        int retval = CMD_SUCCESS;
-       int ret;
+       enum rmap_compile_rets ret;
 
        ret = route_map_add_match(index, command, arg, type);
        switch (ret) {
@@ -3074,6 +3074,11 @@ static int bgp_route_match_add(struct vty *vty, const char *command,
                        route_map_upd8_dependency(type, arg, index->map->name);
                }
                break;
+       case RMAP_DUPLICATE_RULE:
+               /*
+                * Intentionally doing nothing here.
+                */
+               break;
        }
 
        return retval;
@@ -3084,7 +3089,7 @@ static int bgp_route_match_delete(struct vty *vty, const char *command,
                                  const char *arg, route_map_event_t type)
 {
        VTY_DECLVAR_CONTEXT(route_map_index, index);
-       int ret;
+       enum rmap_compile_rets ret;
        int retval = CMD_SUCCESS;
        char *dep_name = NULL;
        const char *tmpstr;
@@ -3117,6 +3122,11 @@ static int bgp_route_match_delete(struct vty *vty, const char *command,
                if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
                        route_map_upd8_dependency(type, dep_name, rmap_name);
                break;
+       case RMAP_DUPLICATE_RULE:
+               /*
+                * Nothing to do here
+                */
+               break;
        }
 
        XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
@@ -4158,6 +4168,18 @@ DEFUN (no_set_aspath_prepend,
        return ret;
 }
 
+DEFUN (no_set_aspath_prepend_lastas,
+       no_set_aspath_prepend_lastas_cmd,
+       "no set as-path prepend last-as [(1-10)]",
+       NO_STR
+       SET_STR
+       "Transform BGP AS_PATH attribute\n"
+       "Prepend to the as-path\n"
+       "Use the peers AS-number\n"
+       "Number of times to insert\n")
+{
+       return no_set_aspath_prepend(self, vty, argc, argv);
+}
 
 DEFUN (set_aspath_exclude,
        set_aspath_exclude_cmd,
@@ -5123,6 +5145,7 @@ void bgp_route_map_init(void)
        install_element(RMAP_NODE, &set_aspath_prepend_lastas_cmd);
        install_element(RMAP_NODE, &set_aspath_exclude_cmd);
        install_element(RMAP_NODE, &no_set_aspath_prepend_cmd);
+       install_element(RMAP_NODE, &no_set_aspath_prepend_lastas_cmd);
        install_element(RMAP_NODE, &no_set_aspath_exclude_cmd);
        install_element(RMAP_NODE, &no_set_aspath_exclude_all_cmd);
        install_element(RMAP_NODE, &set_origin_cmd);
index 22840d54c6f8c0b908ea633ba0552a3ab532dc43..2cfd65896c9ac1160ca86a00ef0ef67b5276cd49 100644 (file)
 #include "lib/thread.h"
 #ifndef VTYSH_EXTRACT_PL
 #include "rtrlib/rtrlib.h"
-#include "rtrlib/rtr_mgr.h"
-#include "rtrlib/lib/ip.h"
-#include "rtrlib/transport/tcp/tcp_transport.h"
-#if defined(FOUND_SSH)
-#include "rtrlib/transport/ssh/ssh_transport.h"
-#endif
 #endif
 #include "hook.h"
 #include "libfrr.h"
@@ -76,8 +70,6 @@ DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group")
 #define POLLING_PERIOD_DEFAULT 3600
 #define EXPIRE_INTERVAL_DEFAULT 7200
 #define RETRY_INTERVAL_DEFAULT 600
-#define TIMEOUT_DEFAULT 600
-#define INITIAL_SYNCHRONISATION_TIMEOUT_DEFAULT 30
 
 #define RPKI_DEBUG(...)                                                        \
        if (rpki_debug) {                                                      \
@@ -147,8 +139,6 @@ static int rpki_debug;
 static unsigned int polling_period;
 static unsigned int expire_interval;
 static unsigned int retry_interval;
-static unsigned int timeout;
-static unsigned int initial_synchronisation_timeout;
 static int rpki_sync_socket_rtr;
 static int rpki_sync_socket_bgpd;
 
@@ -538,9 +528,6 @@ static int bgp_rpki_init(struct thread_master *master)
        polling_period = POLLING_PERIOD_DEFAULT;
        expire_interval = EXPIRE_INTERVAL_DEFAULT;
        retry_interval = RETRY_INTERVAL_DEFAULT;
-       timeout = TIMEOUT_DEFAULT;
-       initial_synchronisation_timeout =
-               INITIAL_SYNCHRONISATION_TIMEOUT_DEFAULT;
        install_cli_commands();
        rpki_init_sync_socket();
        return 0;
@@ -756,8 +743,6 @@ static int add_cache(struct cache *cache)
        group.sockets_len = 1;
        group.sockets = &cache->rtr_socket;
 
-       listnode_add(cache_list, cache);
-
        if (rtr_is_running) {
                init_tr_socket(cache);
 
@@ -767,6 +752,8 @@ static int add_cache(struct cache *cache)
                }
        }
 
+       listnode_add(cache_list, cache);
+
        return SUCCESS;
 }
 
@@ -793,7 +780,12 @@ static int add_tcp_cache(const char *host, const char *port,
        cache->rtr_socket = rtr_socket;
        cache->preference = preference;
 
-       return add_cache(cache);
+       int ret = add_cache(cache);
+       if (ret != SUCCESS) {
+               free_cache(cache);
+       }
+
+       return ret;
 }
 
 #if defined(FOUND_SSH)
@@ -829,7 +821,12 @@ static int add_ssh_cache(const char *host, const unsigned int port,
        cache->rtr_socket = rtr_socket;
        cache->preference = preference;
 
-       return add_cache(cache);
+       int ret = add_cache(cache);
+       if (ret != SUCCESS) {
+               free_cache(cache);
+       }
+
+       return ret;
 }
 #endif
 
@@ -869,9 +866,6 @@ static int config_write(struct vty *vty)
                vty_out(vty, "!\n");
                vty_out(vty, "rpki\n");
                vty_out(vty, "  rpki polling_period %d\n", polling_period);
-               vty_out(vty, "  rpki timeout %d\n", timeout);
-               vty_out(vty, "  rpki initial-synchronisation-timeout %d\n",
-                       initial_synchronisation_timeout);
                for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
                        switch (cache->type) {
                                struct tr_tcp_config *tcp_config;
@@ -1020,48 +1014,64 @@ DEFUN (no_rpki_retry_interval,
        return CMD_SUCCESS;
 }
 
-DEFPY (rpki_timeout,
+#if (CONFDATE > 20200901)
+CPP_NOTICE("bgpd: time to remove rpki timeout")
+CPP_NOTICE("bgpd: this includes rpki_timeout and rpki_synchronisation_timeout")
+#endif
+
+DEFPY_HIDDEN (rpki_timeout,
        rpki_timeout_cmd,
        "rpki timeout (1-4294967295)$to_arg",
        RPKI_OUTPUT_STRING
        "Set timeout\n"
        "Timeout value\n")
 {
-       timeout = to_arg;
+       vty_out(vty,
+               "This config option is deprecated, and is scheduled for removal.\n");
+       vty_out(vty,
+               "This functionality has also already been removed because it caused bugs and was pointless\n");
        return CMD_SUCCESS;
 }
 
-DEFUN (no_rpki_timeout,
+DEFUN_HIDDEN (no_rpki_timeout,
        no_rpki_timeout_cmd,
        "no rpki timeout",
        NO_STR
        RPKI_OUTPUT_STRING
        "Set timeout back to default\n")
 {
-       timeout = TIMEOUT_DEFAULT;
+       vty_out(vty,
+               "This config option is deprecated, and is scheduled for removal.\n");
+       vty_out(vty,
+               "This functionality has also already been removed because it caused bugs and was pointless\n");
        return CMD_SUCCESS;
 }
 
-DEFPY (rpki_synchronisation_timeout,
+DEFPY_HIDDEN (rpki_synchronisation_timeout,
        rpki_synchronisation_timeout_cmd,
        "rpki initial-synchronisation-timeout (1-4294967295)$ito_arg",
        RPKI_OUTPUT_STRING
        "Set a timeout for the initial synchronisation of prefix validation data\n"
        "Timeout value\n")
 {
-       initial_synchronisation_timeout = ito_arg;
+       vty_out(vty,
+               "This config option is deprecated, and is scheduled for removal.\n");
+       vty_out(vty,
+               "This functionality has also already been removed because it caused bugs and was pointless\n");
        return CMD_SUCCESS;
 }
 
-DEFUN (no_rpki_synchronisation_timeout,
+DEFUN_HIDDEN (no_rpki_synchronisation_timeout,
        no_rpki_synchronisation_timeout_cmd,
        "no rpki initial-synchronisation-timeout",
        NO_STR
        RPKI_OUTPUT_STRING
        "Set the initial synchronisation timeout back to default (30 sec.)\n")
 {
-       initial_synchronisation_timeout =
-               INITIAL_SYNCHRONISATION_TIMEOUT_DEFAULT;
+       vty_out(vty,
+               "This config option is deprecated, and is scheduled for removal.\n");
+       vty_out(vty,
+               "This functionality has also already been removed because it caused bugs and was pointless\n");
        return CMD_SUCCESS;
 }
 
@@ -1083,6 +1093,18 @@ DEFPY (rpki_cache,
        "Preference value\n")
 {
        int return_value;
+       struct listnode *cache_node;
+       struct cache *current_cache;
+
+       for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, current_cache)) {
+               if (current_cache->preference == preference) {
+                       vty_out(vty,
+                               "Cache with preference %ld is already configured\n",
+                               preference);
+                       return CMD_WARNING;
+               }
+       }
+
 
        // use ssh connection
        if (ssh_uname) {
@@ -1128,11 +1150,11 @@ DEFPY (no_rpki_cache,
                return CMD_WARNING;
        }
 
-       if (rtr_is_running) {
+       if (rtr_is_running && listcount(cache_list) == 1) {
+               stop();
+       } else if (rtr_is_running) {
                if (rtr_mgr_remove_group(rtr_config, preference) == RTR_ERROR) {
                        vty_out(vty, "Could not remove cache %ld", preference);
-                       if (listcount(cache_list) == 1)
-                               vty_out(vty, " because it is the last cache");
 
                        vty_out(vty, "\n");
                        return CMD_WARNING;
@@ -1385,7 +1407,7 @@ DEFUN (match_rpki,
        "Prefix not found\n")
 {
        VTY_DECLVAR_CONTEXT(route_map_index, index);
-       int ret;
+       enum rmap_compile_rets ret;
 
        ret = route_map_add_match(index, "rpki", argv[2]->arg,
                                  RMAP_EVENT_MATCH_ADDED);
@@ -1397,6 +1419,12 @@ DEFUN (match_rpki,
                case RMAP_COMPILE_ERROR:
                        vty_out(vty, "%% BGP Argument is malformed.\n");
                        return CMD_WARNING_CONFIG_FAILED;
+               case RMAP_COMPILE_SUCCESS:
+               case RMAP_DUPLICATE_RULE:
+                       /*
+                        * Intentionally doing nothing here
+                        */
+                       break;
                }
        }
        return CMD_SUCCESS;
@@ -1413,7 +1441,7 @@ DEFUN (no_match_rpki,
        "Prefix not found\n")
 {
        VTY_DECLVAR_CONTEXT(route_map_index, index);
-       int ret;
+       enum rmap_compile_rets ret;
 
        ret = route_map_delete_match(index, "rpki", argv[3]->arg);
        if (ret) {
@@ -1424,6 +1452,12 @@ DEFUN (no_match_rpki,
                case RMAP_COMPILE_ERROR:
                        vty_out(vty, "%% BGP Argument is malformed.\n");
                        break;
+               case RMAP_COMPILE_SUCCESS:
+               case RMAP_DUPLICATE_RULE:
+                       /*
+                        * Nothing to do here
+                        */
+                       break;
                }
                return CMD_WARNING_CONFIG_FAILED;
        }
index 4447c2ccf8569b19d0359006021a9837f7fb2593..17bc83ed2ee14650814a2052f2d48fec7e7a5be7 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "command.h"
 #include "lib/json.h"
+#include "lib_errors.h"
 #include "lib/zclient.h"
 #include "prefix.h"
 #include "plist.h"
@@ -130,6 +131,80 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi)
        return BGP_IPV4_NODE;
 }
 
+static const char *get_afi_safi_vty_str(afi_t afi, safi_t safi)
+{
+       if (afi == AFI_IP && safi == SAFI_UNICAST)
+               return "IPv4 Unicast";
+       else if (afi == AFI_IP && safi == SAFI_MULTICAST)
+               return "IPv4 Multicast";
+       else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
+               return "IPv4 Labeled Unicast";
+       else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
+               return "IPv4 VPN";
+       else if (afi == AFI_IP && safi == SAFI_ENCAP)
+               return "IPv4 Encap";
+       else if (afi == AFI_IP && safi == SAFI_FLOWSPEC)
+               return "IPv4 Flowspec";
+       else if (afi == AFI_IP6 && safi == SAFI_UNICAST)
+               return "IPv6 Unicast";
+       else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
+               return "IPv6 Multicast";
+       else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
+               return "IPv6 Labeled Unicast";
+       else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
+               return "IPv6 VPN";
+       else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
+               return "IPv6 Encap";
+       else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC)
+               return "IPv6 Flowspec";
+       else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+               return "L2VPN EVPN";
+       else {
+               flog_err(EC_LIB_DEVELOPMENT, "New afi/safi that needs to be taken care of?");
+               return "Unknown";
+       }
+}
+
+/*
+ * Please note that we have intentionally camelCased
+ * the return strings here.  So if you want
+ * to use this function, please ensure you
+ * are doing this within json output
+ */
+static const char *get_afi_safi_json_str(afi_t afi, safi_t safi)
+{
+       if (afi == AFI_IP && safi == SAFI_UNICAST)
+               return "ipv4Unicast";
+       else if (afi == AFI_IP && safi == SAFI_MULTICAST)
+               return "ipv4Multicast";
+       else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
+               return "ipv4LabeledUnicast";
+       else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
+               return "ipv4Vpn";
+       else if (afi == AFI_IP && safi == SAFI_ENCAP)
+               return "ipv4Encap";
+       else if (afi == AFI_IP && safi == SAFI_FLOWSPEC)
+               return "ipv4Flowspec";
+       else if (afi == AFI_IP6 && safi == SAFI_UNICAST)
+               return "ipv6Unicast";
+       else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
+               return "ipv6Multicast";
+       else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
+               return "ipv6LabeledUnicast";
+       else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
+               return "ipv6Vpn";
+       else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
+               return "ipv6Encap";
+       else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC)
+               return "ipv6Flowspec";
+       else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+               return "l2VpnEvpn";
+       else {
+               flog_err(EC_LIB_DEVELOPMENT, "New afi/safi that needs to be taken care of?");
+               return "Unknown";
+       }
+}
+
 /* Utility function to get address family from current node.  */
 afi_t bgp_node_afi(struct vty *vty)
 {
@@ -584,7 +659,7 @@ static void bgp_clear_vty_error(struct vty *vty, struct peer *peer, afi_t afi,
        case BGP_ERR_AF_UNCONFIGURED:
                vty_out(vty,
                        "%%BGP: Enable %s address family for the neighbor %s\n",
-                       afi_safi_print(afi, safi), peer->host);
+                       get_afi_safi_str(afi, safi, false), peer->host);
                break;
        case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED:
                vty_out(vty,
@@ -738,7 +813,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                if (!found)
                        vty_out(vty,
                                "%%BGP: No %s peer belonging to peer-group %s is configured\n",
-                               afi_safi_print(afi, safi), arg);
+                               get_afi_safi_str(afi, safi, false), arg);
 
                return CMD_SUCCESS;
        }
@@ -760,7 +835,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                if (!found)
                        vty_out(vty,
                                "%%BGP: No external %s peer is configured\n",
-                               afi_safi_print(afi, safi));
+                               get_afi_safi_str(afi, safi, false));
 
                return CMD_SUCCESS;
        }
@@ -784,7 +859,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                if (!found)
                        vty_out(vty,
                                "%%BGP: No %s peer is configured with AS %s\n",
-                               afi_safi_print(afi, safi), arg);
+                               get_afi_safi_str(afi, safi, false), arg);
 
                return CMD_SUCCESS;
        }
@@ -7794,9 +7869,145 @@ static void bgp_show_bestpath_json(struct bgp *bgp, json_object *json)
        json_object_object_add(json, "bestPath", bestpath);
 }
 
+/* Print the error code/subcode for why the peer is down */
+static void bgp_show_peer_reset(struct vty * vty, struct peer *peer,
+                               json_object *json_peer, bool use_json)
+{
+       const char *code_str;
+       const char *subcode_str;
+
+       if (use_json) {
+               if (peer->last_reset == PEER_DOWN_NOTIFY_SEND
+                   || peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) {
+                       char errorcodesubcode_hexstr[5];
+                       char errorcodesubcode_str[256];
+
+                       code_str = bgp_notify_code_str(peer->notify.code);
+                       subcode_str = bgp_notify_subcode_str(
+                                        peer->notify.code,
+                                        peer->notify.subcode);
+
+                       sprintf(errorcodesubcode_hexstr, "%02X%02X",
+                               peer->notify.code, peer->notify.subcode);
+                       json_object_string_add(json_peer,
+                                              "lastErrorCodeSubcode",
+                                              errorcodesubcode_hexstr);
+                       snprintf(errorcodesubcode_str, 255, "%s%s",
+                                code_str, subcode_str);
+                       json_object_string_add(json_peer,
+                                              "lastNotificationReason",
+                                              errorcodesubcode_str);
+                       if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED
+                           && peer->notify.code == BGP_NOTIFY_CEASE
+                           && (peer->notify.subcode
+                               == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN
+                               || peer->notify.subcode
+                               == BGP_NOTIFY_CEASE_ADMIN_RESET)
+                           && peer->notify.length) {
+                               char msgbuf[1024];
+                               const char *msg_str;
+
+                               msg_str = bgp_notify_admin_message(
+                                            msgbuf, sizeof(msgbuf),
+                                            (uint8_t *)peer->notify.data,
+                                            peer->notify.length);
+                               if (msg_str)
+                                       json_object_string_add(
+                                          json_peer,
+                                          "lastShutdownDescription",
+                                          msg_str);
+                       }
+
+               } 
+               json_object_string_add(json_peer, "lastResetDueTo",
+                                      peer_down_str[(int)peer->last_reset]);
+               json_object_int_add(json_peer, "lastResetCode",
+                                   peer->last_reset);
+       } else {
+               if (peer->last_reset == PEER_DOWN_NOTIFY_SEND
+                   || peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) {
+                       code_str = bgp_notify_code_str(peer->notify.code);
+                       subcode_str =
+                               bgp_notify_subcode_str(peer->notify.code,
+                                                      peer->notify.subcode);
+                       vty_out(vty, "  Notification %s (%s%s)\n",
+                               peer->last_reset == PEER_DOWN_NOTIFY_SEND
+                               ? "sent"
+                               : "received",
+                               code_str, subcode_str);
+               } else {
+                       vty_out(vty, "  %s\n",
+                               peer_down_str[(int)peer->last_reset]);
+               }
+       }
+}
+
+static inline bool bgp_has_peer_failed(struct peer *peer, afi_t afi,
+                                      safi_t safi)
+{
+       return ((peer->status != Established) ||
+               !peer->afc_recv[afi][safi]);
+}
+
+static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp,
+                                   struct peer *peer, json_object *json_peer,
+                                   int max_neighbor_width, bool use_json)
+{
+       char timebuf[BGP_UPTIME_LEN], dn_flag[2];
+       int len;
+
+       if (use_json) {
+               if (peer_dynamic_neighbor(peer))
+                       json_object_boolean_true_add(json_peer,
+                                                    "dynamicPeer");
+               if (peer->hostname)
+                       json_object_string_add(json_peer, "hostname",
+                                              peer->hostname);
+
+               if (peer->domainname)
+                       json_object_string_add(json_peer, "domainname",
+                                              peer->domainname);
+               json_object_int_add(json_peer, "connectionsEstablished",
+                                   peer->established);
+               json_object_int_add(json_peer, "connectionsDropped",
+                                   peer->dropped);
+               peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN,
+                           use_json, json_peer);
+               if (peer->status == Established)
+                       json_object_string_add(json_peer, "lastResetDueTo",
+                                              "AFI/SAFI Not Negotiated");
+               else
+                       bgp_show_peer_reset(NULL, peer, json_peer, true);
+       } else {
+               dn_flag[1] = '\0';
+               dn_flag[0] = peer_dynamic_neighbor(peer) ? '*' : '\0';
+               if (peer->hostname
+                   && bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME))
+                       len = vty_out(vty, "%s%s(%s)", dn_flag,
+                                     peer->hostname, peer->host);
+               else
+                       len = vty_out(vty, "%s%s", dn_flag, peer->host);
+
+               /* pad the neighbor column with spaces */
+               if (len < max_neighbor_width)
+                       vty_out(vty, "%*s", max_neighbor_width - len,
+                               " ");
+               vty_out(vty, "%7d %7d %8s", peer->established,
+                       peer->dropped,
+                       peer_uptime(peer->uptime, timebuf,
+                                   BGP_UPTIME_LEN, 0, NULL));
+               if (peer->status == Established)
+                       vty_out(vty, "  AFI/SAFI Not Negotiated\n");
+               else
+                       bgp_show_peer_reset(vty, peer, NULL,
+                                           false);
+       }
+}
+                                
+
 /* Show BGP peer's summary information. */
 static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
-                           bool use_json)
+                           bool show_failed, bool use_json)
 {
        struct peer *peer;
        struct listnode *node, *nnode;
@@ -7804,7 +8015,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
        char timebuf[BGP_UPTIME_LEN], dn_flag[2];
        char neighbor_buf[VTY_BUFSIZ];
        int neighbor_col_default_width = 16;
-       int len;
+       int len, failed_count = 0;
        int max_neighbor_width = 0;
        int pfx_rcd_safi;
        json_object *json = NULL;
@@ -7816,6 +8027,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
         * to
         * display the correct PfxRcd value we must look at SAFI_UNICAST
         */
+
        if (safi == SAFI_LABELED_UNICAST)
                pfx_rcd_safi = SAFI_UNICAST;
        else
@@ -7824,6 +8036,20 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
        if (use_json) {
                json = json_object_new_object();
                json_peers = json_object_new_object();
+               for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+                       if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+                               continue;
+
+                       if (peer->afc[afi][safi]) {
+                               /* See if we have at least a single failed peer */
+                               if (bgp_has_peer_failed(peer, afi, safi))
+                                       failed_count++;
+                               count++;
+                       }
+                       if (peer_dynamic_neighbor(peer))
+                               dn_count++;
+               }
+                               
        } else {
                /* Loop over all neighbors that will be displayed to determine
                 * how many
@@ -7852,6 +8078,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
 
                                if (len > max_neighbor_width)
                                        max_neighbor_width = len;
+                               
+                               /* See if we have at least a single failed peer */
+                               if (bgp_has_peer_failed(peer, afi, safi))
+                                       failed_count++;
+                               count++;
                        }
                }
 
@@ -7862,6 +8093,23 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                        max_neighbor_width = neighbor_col_default_width;
        }
 
+       if (show_failed && !failed_count) {
+               if (use_json) {
+                       json_object_int_add(json, "failedPeersCount", 0);
+                       json_object_int_add(json, "dynamicPeers", dn_count);
+                       json_object_int_add(json, "totalPeers", count);                 
+
+                       vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+                       json_object_free(json);
+               } else {
+                       vty_out(vty, "%% No failed BGP neighbors found\n");
+                       vty_out(vty, "\nTotal number of neighbors %d\n", count);
+               }
+               return CMD_SUCCESS;
+       }
+               
+       count = 0;              /* Reset the value as its used again */
        for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
                if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
                        continue;
@@ -8063,78 +8311,97 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                vty_out(vty, "Neighbor");
                                vty_out(vty, "%*s", max_neighbor_width - 8,
                                        " ");
-                               vty_out(vty,
+                               if (show_failed)
+                                       vty_out(vty, "EstdCnt DropCnt ResetTime Reason\n");
+                               else
+                                       vty_out(vty,
                                        "V         AS MsgRcvd MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd\n");
                        }
                }
 
                count++;
+               /* Works for both failed & successful cases */
+               if (peer_dynamic_neighbor(peer))
+                       dn_count++;
 
                if (use_json) {
-                       json_peer = json_object_new_object();
+                       json_peer = NULL;
+
+                       if (show_failed &&
+                           bgp_has_peer_failed(peer, afi, safi)) {
+                               json_peer = json_object_new_object();
+                               bgp_show_failed_summary(vty, bgp, peer,
+                                                       json_peer, 0, use_json);
+                       } else if (!show_failed) {
+                               json_peer = json_object_new_object();
+                               if (peer_dynamic_neighbor(peer)) {
+                                       json_object_boolean_true_add(json_peer,
+                                                                    "dynamicPeer");
+                               }
 
-                       if (peer_dynamic_neighbor(peer)) {
-                               dn_count++;
-                               json_object_boolean_true_add(json_peer,
-                                                            "dynamicPeer");
+                               if (peer->hostname)
+                                       json_object_string_add(json_peer, "hostname",
+                                                              peer->hostname);
+
+                               if (peer->domainname)
+                                       json_object_string_add(json_peer, "domainname",
+                                                              peer->domainname);
+
+                               json_object_int_add(json_peer, "remoteAs", peer->as);
+                               json_object_int_add(json_peer, "version", 4);
+                               json_object_int_add(json_peer, "msgRcvd",
+                                                   PEER_TOTAL_RX(peer));
+                               json_object_int_add(json_peer, "msgSent",
+                                                   PEER_TOTAL_TX(peer));
+
+                               json_object_int_add(json_peer, "tableVersion",
+                                                   peer->version[afi][safi]);
+                               json_object_int_add(json_peer, "outq",
+                                                   peer->obuf->count);
+                               json_object_int_add(json_peer, "inq", 0);
+                               peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN,
+                                           use_json, json_peer);
+
+                               /*
+                                * Adding "pfxRcd" field to match with the corresponding
+                                * CLI. "prefixReceivedCount" will be deprecated in
+                                * future.
+                                */
+                               json_object_int_add(json_peer, "prefixReceivedCount",
+                                                   peer->pcount[afi][pfx_rcd_safi]);
+                               json_object_int_add(json_peer, "pfxRcd",
+                                                   peer->pcount[afi][pfx_rcd_safi]);
+
+                               paf = peer_af_find(peer, afi, pfx_rcd_safi);
+                               if (paf && PAF_SUBGRP(paf))
+                                       json_object_int_add(json_peer,
+                                                           "pfxSnt",
+                                                           (PAF_SUBGRP(paf))->scount);
+                               if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
+                                       json_object_string_add(json_peer, "state",
+                                                              "Idle (Admin)");
+                               else if (peer->afc_recv[afi][safi])
+                                       json_object_string_add(
+                                                              json_peer, "state",
+                                                              lookup_msg(bgp_status_msg, peer->status,
+                                                                         NULL));
+                               else if (CHECK_FLAG(peer->sflags,
+                                                   PEER_STATUS_PREFIX_OVERFLOW))
+                                       json_object_string_add(json_peer, "state",
+                                                              "Idle (PfxCt)");
+                               else
+                                       json_object_string_add(
+                                                              json_peer, "state",
+                                                              lookup_msg(bgp_status_msg, peer->status,
+                                                                         NULL));
+                               json_object_int_add(json_peer, "connectionsEstablished",
+                                                   peer->established);
+                               json_object_int_add(json_peer, "connectionsDropped",
+                                                   peer->dropped);
                        }
-
-                       if (peer->hostname)
-                               json_object_string_add(json_peer, "hostname",
-                                                      peer->hostname);
-
-                       if (peer->domainname)
-                               json_object_string_add(json_peer, "domainname",
-                                                      peer->domainname);
-
-                       json_object_int_add(json_peer, "remoteAs", peer->as);
-                       json_object_int_add(json_peer, "version", 4);
-                       json_object_int_add(json_peer, "msgRcvd",
-                                           PEER_TOTAL_RX(peer));
-                       json_object_int_add(json_peer, "msgSent",
-                                           PEER_TOTAL_TX(peer));
-
-                       json_object_int_add(json_peer, "tableVersion",
-                                           peer->version[afi][safi]);
-                       json_object_int_add(json_peer, "outq",
-                                           peer->obuf->count);
-                       json_object_int_add(json_peer, "inq", 0);
-                       peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN,
-                                   use_json, json_peer);
-
-                       /*
-                        * Adding "pfxRcd" field to match with the corresponding
-                        * CLI. "prefixReceivedCount" will be deprecated in
-                        * future.
-                        */
-                       json_object_int_add(json_peer, "prefixReceivedCount",
-                                           peer->pcount[afi][pfx_rcd_safi]);
-                       json_object_int_add(json_peer, "pfxRcd",
-                                       peer->pcount[afi][pfx_rcd_safi]);
-
-                       paf = peer_af_find(peer, afi, pfx_rcd_safi);
-                       if (paf && PAF_SUBGRP(paf))
-                               json_object_int_add(json_peer,
-                                               "pfxSnt",
-                                               (PAF_SUBGRP(paf))->scount);
-
-                       if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
-                               json_object_string_add(json_peer, "state",
-                                                      "Idle (Admin)");
-                       else if (peer->afc_recv[afi][safi])
-                               json_object_string_add(
-                                       json_peer, "state",
-                                       lookup_msg(bgp_status_msg, peer->status,
-                                                  NULL));
-                       else if (CHECK_FLAG(peer->sflags,
-                                           PEER_STATUS_PREFIX_OVERFLOW))
-                               json_object_string_add(json_peer, "state",
-                                                      "Idle (PfxCt)");
-                       else
-                               json_object_string_add(
-                                       json_peer, "state",
-                                       lookup_msg(bgp_status_msg, peer->status,
-                                                  NULL));
+                       /* Avoid creating empty peer dicts in JSON */
+                       if (json_peer == NULL)
+                               continue;
 
                        if (peer->conf_if)
                                json_object_string_add(json_peer, "idType",
@@ -8145,65 +8412,72 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                        else if (peer->su.sa.sa_family == AF_INET6)
                                json_object_string_add(json_peer, "idType",
                                                       "ipv6");
-
                        json_object_object_add(json_peers, peer->host,
                                               json_peer);
                } else {
-                       memset(dn_flag, '\0', sizeof(dn_flag));
-                       if (peer_dynamic_neighbor(peer)) {
-                               dn_count++;
-                               dn_flag[0] = '*';
-                       }
-
-                       if (peer->hostname
-                           && bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME))
-                               len = vty_out(vty, "%s%s(%s)", dn_flag,
-                                             peer->hostname, peer->host);
-                       else
-                               len = vty_out(vty, "%s%s", dn_flag, peer->host);
-
-                       /* pad the neighbor column with spaces */
-                       if (len < max_neighbor_width)
-                               vty_out(vty, "%*s", max_neighbor_width - len,
-                                       " ");
-
-                       vty_out(vty, "4 %10u %7u %7u %8" PRIu64 " %4d %4zd %8s",
-                               peer->as, PEER_TOTAL_RX(peer),
-                               PEER_TOTAL_TX(peer), peer->version[afi][safi],
-                               0, peer->obuf->count,
-                               peer_uptime(peer->uptime, timebuf,
-                                           BGP_UPTIME_LEN, 0, NULL));
+                       if (show_failed &&
+                           bgp_has_peer_failed(peer, afi, safi)) {
+                               bgp_show_failed_summary(vty, bgp, peer, NULL,
+                                                       max_neighbor_width,
+                                                       use_json);
+                       } else if (!show_failed) {
+                               memset(dn_flag, '\0', sizeof(dn_flag));
+                               if (peer_dynamic_neighbor(peer)) {
+                                       dn_flag[0] = '*';
+                               }
 
-                       if (peer->status == Established)
-                               if (peer->afc_recv[afi][safi])
-                                       vty_out(vty, " %12ld",
-                                               peer->pcount[afi]
-                                                           [pfx_rcd_safi]);
-                               else
-                                       vty_out(vty, " NoNeg");
-                       else {
-                               if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
-                                       vty_out(vty, " Idle (Admin)");
-                               else if (CHECK_FLAG(
-                                                peer->sflags,
-                                                PEER_STATUS_PREFIX_OVERFLOW))
-                                       vty_out(vty, " Idle (PfxCt)");
+                               if (peer->hostname
+                                   && bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME))
+                                       len = vty_out(vty, "%s%s(%s)", dn_flag,
+                                                     peer->hostname, peer->host);
                                else
-                                       vty_out(vty, " %12s",
-                                               lookup_msg(bgp_status_msg,
-                                                          peer->status, NULL));
+                                       len = vty_out(vty, "%s%s", dn_flag, peer->host);
+
+                               /* pad the neighbor column with spaces */
+                               if (len < max_neighbor_width)
+                                       vty_out(vty, "%*s", max_neighbor_width - len,
+                                               " ");
+
+                               vty_out(vty, "4 %10u %7u %7u %8" PRIu64 " %4d %4zd %8s",
+                                       peer->as, PEER_TOTAL_RX(peer),
+                                       PEER_TOTAL_TX(peer), peer->version[afi][safi],
+                                       0, peer->obuf->count,
+                                       peer_uptime(peer->uptime, timebuf,
+                                                   BGP_UPTIME_LEN, 0, NULL));
+
+                               if (peer->status == Established)
+                                       if (peer->afc_recv[afi][safi])
+                                               vty_out(vty, " %12ld",
+                                                       peer->pcount[afi]
+                                                       [pfx_rcd_safi]);
+                                       else
+                                               vty_out(vty, " NoNeg");
+                               else {
+                                       if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
+                                               vty_out(vty, " Idle (Admin)");
+                                       else if (CHECK_FLAG(
+                                                           peer->sflags,
+                                                           PEER_STATUS_PREFIX_OVERFLOW))
+                                               vty_out(vty, " Idle (PfxCt)");
+                                       else
+                                               vty_out(vty, " %12s",
+                                                       lookup_msg(bgp_status_msg,
+                                                                  peer->status, NULL));
+                               }
+                               vty_out(vty, "\n");
                        }
-                       vty_out(vty, "\n");
+
                }
        }
 
        if (use_json) {
                json_object_object_add(json, "peers", json_peers);
-
+               json_object_int_add(json, "failedPeers", failed_count);
                json_object_int_add(json, "totalPeers", count);
                json_object_int_add(json, "dynamicPeers", dn_count);
 
-               bgp_show_bestpath_json(bgp, json);
+               if (!show_failed)
+                       bgp_show_bestpath_json(bgp, json);
 
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
                                             json, JSON_C_TO_STRING_PRETTY));
@@ -8213,7 +8487,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                        vty_out(vty, "\nTotal number of neighbors %d\n", count);
                else {
                        vty_out(vty, "No %s neighbor is configured\n",
-                               afi_safi_print(afi, safi));
+                               get_afi_safi_str(afi, safi, false));
                }
 
                if (dn_count) {
@@ -8227,7 +8501,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
 }
 
 static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
-                                     int safi, bool use_json)
+                                     int safi, bool show_failed, bool use_json)
 {
        int is_first = 1;
        int afi_wildcard = (afi == AFI_MAX);
@@ -8260,15 +8534,18 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
                                                        is_first = 0;
 
                                                vty_out(vty, "\"%s\":",
-                                                       afi_safi_json(afi,
-                                                                     safi));
+                                                       get_afi_safi_str(afi,
+                                                                        safi,
+                                                                        true));
                                        } else {
                                                vty_out(vty, "\n%s Summary:\n",
-                                                       afi_safi_print(afi,
-                                                                      safi));
+                                                       get_afi_safi_str(afi,
+                                                                        safi,
+                                                                        false));
                                        }
                                }
-                               bgp_show_summary(vty, bgp, afi, safi, use_json);
+                               bgp_show_summary(vty, bgp, afi, safi, show_failed,
+                                                use_json);
                        }
                        safi++;
                        if (!safi_wildcard)
@@ -8290,7 +8567,8 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
 }
 
 static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
-                                              safi_t safi, bool use_json)
+                                              safi_t safi, bool show_failed,
+                                              bool use_json)
 {
        struct listnode *node, *nnode;
        struct bgp *bgp;
@@ -8318,7 +8596,8 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
                                        ? VRF_DEFAULT_NAME
                                        : bgp->name);
                }
-               bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json);
+               bgp_show_summary_afi_safi(vty, bgp, afi, safi, show_failed,
+                                         use_json);
        }
 
        if (use_json)
@@ -8328,13 +8607,14 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
 }
 
 int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
-                        safi_t safi, bool use_json)
+                        safi_t safi, bool show_failed, bool use_json)
 {
        struct bgp *bgp;
 
        if (name) {
                if (strmatch(name, "all")) {
                        bgp_show_all_instances_summary_vty(vty, afi, safi,
+                                                          show_failed,
                                                           use_json);
                        return CMD_SUCCESS;
                } else {
@@ -8350,7 +8630,7 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
                        }
 
                        bgp_show_summary_afi_safi(vty, bgp, afi, safi,
-                                                 use_json);
+                                                 show_failed, use_json);
                        return CMD_SUCCESS;
                }
        }
@@ -8358,7 +8638,8 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
        bgp = bgp_get_default();
 
        if (bgp)
-               bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json);
+               bgp_show_summary_afi_safi(vty, bgp, afi, safi, show_failed,
+                                         use_json);
        else {
                if (use_json)
                        vty_out(vty, "{}\n");
@@ -8373,7 +8654,7 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
 /* `show [ip] bgp summary' commands. */
 DEFUN (show_ip_bgp_summary,
        show_ip_bgp_summary_cmd,
-       "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] summary [json]",
+       "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] summary [failed] [json]",
        SHOW_STR
        IP_STR
        BGP_STR
@@ -8381,11 +8662,13 @@ DEFUN (show_ip_bgp_summary,
        BGP_AFI_HELP_STR
        BGP_SAFI_WITH_LABEL_HELP_STR
        "Summary of BGP neighbor status\n"
+       "Show only sessions not in Established state\n"
        JSON_STR)
 {
        char *vrf = NULL;
        afi_t afi = AFI_MAX;
        safi_t safi = SAFI_MAX;
+       bool show_failed = false;
 
        int idx = 0;
 
@@ -8405,79 +8688,20 @@ DEFUN (show_ip_bgp_summary,
                argv_find_and_parse_safi(argv, argc, &idx, &safi);
        }
 
+       if (argv_find(argv, argc, "failed", &idx))
+               show_failed = true;
+
        bool uj = use_json(argc, argv);
 
-       return bgp_show_summary_vty(vty, vrf, afi, safi, uj);
+       return bgp_show_summary_vty(vty, vrf, afi, safi, show_failed, uj);
 }
 
-const char *afi_safi_print(afi_t afi, safi_t safi)
+const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json)
 {
-       if (afi == AFI_IP && safi == SAFI_UNICAST)
-               return "IPv4 Unicast";
-       else if (afi == AFI_IP && safi == SAFI_MULTICAST)
-               return "IPv4 Multicast";
-       else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
-               return "IPv4 Labeled Unicast";
-       else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
-               return "IPv4 VPN";
-       else if (afi == AFI_IP && safi == SAFI_ENCAP)
-               return "IPv4 Encap";
-       else if (afi == AFI_IP && safi == SAFI_FLOWSPEC)
-               return "IPv4 Flowspec";
-       else if (afi == AFI_IP6 && safi == SAFI_UNICAST)
-               return "IPv6 Unicast";
-       else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
-               return "IPv6 Multicast";
-       else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
-               return "IPv6 Labeled Unicast";
-       else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
-               return "IPv6 VPN";
-       else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
-               return "IPv6 Encap";
-       else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC)
-               return "IPv6 Flowspec";
-       else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
-               return "L2VPN EVPN";
-       else
-               return "Unknown";
-}
-
-/*
- * Please note that we have intentionally camelCased
- * the return strings here.  So if you want
- * to use this function, please ensure you
- * are doing this within json output
- */
-const char *afi_safi_json(afi_t afi, safi_t safi)
-{
-       if (afi == AFI_IP && safi == SAFI_UNICAST)
-               return "ipv4Unicast";
-       else if (afi == AFI_IP && safi == SAFI_MULTICAST)
-               return "ipv4Multicast";
-       else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
-               return "ipv4LabeledUnicast";
-       else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
-               return "ipv4Vpn";
-       else if (afi == AFI_IP && safi == SAFI_ENCAP)
-               return "ipv4Encap";
-       else if (afi == AFI_IP && safi == SAFI_FLOWSPEC)
-               return "ipv4Flowspec";
-       else if (afi == AFI_IP6 && safi == SAFI_UNICAST)
-               return "ipv6Unicast";
-       else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
-               return "ipv6Multicast";
-       else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
-               return "ipv6LabeledUnicast";
-       else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
-               return "ipv6Vpn";
-       else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
-               return "ipv6Encap";
-       else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC)
-               return "ipv6Flowspec";
-       else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
-               return "l2VpnEvpn";
+       if (for_json)
+               return get_afi_safi_json_str(afi, safi);
        else
-               return "Unknown";
+               return get_afi_safi_vty_str(afi, safi);
 }
 
 /* Show BGP peer's information. */
@@ -8855,14 +9079,14 @@ 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, afi_safi_print(afi, safi),
+               json_object_object_add(json_neigh, get_afi_safi_str(afi, safi, true),
                                       json_addr);
 
        } else {
                filter = &p->filter[afi][safi];
 
                vty_out(vty, " For address family: %s\n",
-                       afi_safi_print(afi, safi));
+                       get_afi_safi_str(afi, safi, false));
 
                if (peer_group_active(p))
                        vty_out(vty, "  %s peer-group member\n",
@@ -9150,8 +9374,6 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
        char buf1[PREFIX2STR_BUFFER], buf[SU_ADDRSTRLEN];
        char timebuf[BGP_UPTIME_LEN];
        char dn_flag[2];
-       const char *subcode_str;
-       const char *code_str;
        afi_t afi;
        safi_t safi;
        uint16_t i;
@@ -9569,8 +9791,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                json_object *json_sub = NULL;
                                                json_sub =
                                                        json_object_new_object();
-                                               print_store = afi_safi_print(
-                                                       afi, safi);
+                                               print_store = get_afi_safi_str(
+                                                       afi, safi, true);
 
                                                if (CHECK_FLAG(
                                                            p->af_cap[afi]
@@ -9748,9 +9970,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                                            [AFI_IP]
                                                                            [safi],
                                                                    PEER_CAP_ENHE_AF_RCV)) {
-                                                               print_store = afi_safi_print(
+                                                               print_store = get_afi_safi_str(
                                                                        AFI_IP,
-                                                                       safi);
+                                                                       safi, true);
                                                                json_object_string_add(
                                                                        json_nxt,
                                                                        print_store,
@@ -9850,8 +10072,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
 
                                                json_object_object_add(
                                                        json_multi,
-                                                       afi_safi_print(afi,
-                                                                      safi),
+                                                       get_afi_safi_str(afi,
+                                                                        safi,
+                                                                        true),
                                                        json_exten);
                                        }
                                }
@@ -9957,9 +10180,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                                restart_af_count++;
                                                                json_object_object_add(
                                                                        json_restart,
-                                                                       afi_safi_print(
+                                                                       get_afi_safi_str(
                                                                                afi,
-                                                                               safi),
+                                                                               safi,
+                                                                               true),
                                                                        json_sub);
                                                        }
                                                }
@@ -10018,9 +10242,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                               PEER_CAP_ADDPATH_AF_TX_RCV)) {
                                                        vty_out(vty,
                                                                "      %s: TX ",
-                                                               afi_safi_print(
+                                                               get_afi_safi_str(
                                                                        afi,
-                                                                       safi));
+                                                                       safi,
+                                                                       false));
 
                                                        if (CHECK_FLAG(
                                                                    p->af_cap
@@ -10029,9 +10254,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                                    PEER_CAP_ADDPATH_AF_TX_ADV))
                                                                vty_out(vty,
                                                                        "advertised %s",
-                                                                       afi_safi_print(
+                                                                       get_afi_safi_str(
                                                                                afi,
-                                                                               safi));
+                                                                               safi,
+                                                                               false));
 
                                                        if (CHECK_FLAG(
                                                                    p->af_cap
@@ -10061,9 +10287,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                               PEER_CAP_ADDPATH_AF_RX_RCV)) {
                                                        vty_out(vty,
                                                                "      %s: RX ",
-                                                               afi_safi_print(
+                                                               get_afi_safi_str(
                                                                        afi,
-                                                                       safi));
+                                                                       safi,
+                                                                       false));
 
                                                        if (CHECK_FLAG(
                                                                    p->af_cap
@@ -10072,9 +10299,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                                    PEER_CAP_ADDPATH_AF_RX_ADV))
                                                                vty_out(vty,
                                                                        "advertised %s",
-                                                                       afi_safi_print(
+                                                                       get_afi_safi_str(
                                                                                afi,
-                                                                               safi));
+                                                                               safi,
+                                                                               false));
 
                                                        if (CHECK_FLAG(
                                                                    p->af_cap
@@ -10145,9 +10373,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                                    PEER_CAP_ENHE_AF_RCV))
                                                                vty_out(vty,
                                                                        "           %s\n",
-                                                                       afi_safi_print(
+                                                                       get_afi_safi_str(
                                                                                AFI_IP,
-                                                                               safi));
+                                                                               safi,
+                                                                               false));
                                        }
                                }
 
@@ -10194,8 +10423,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                            || p->afc_recv[afi][safi]) {
                                                vty_out(vty,
                                                        "    Address Family %s:",
-                                                       afi_safi_print(afi,
-                                                                      safi));
+                                                       get_afi_safi_str(
+                                                                  afi,
+                                                                  safi,
+                                                                  false));
                                                if (p->afc_adv[afi][safi])
                                                        vty_out(vty,
                                                                " advertised");
@@ -10280,9 +10511,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                                        restart_af_count
                                                                                ? ", "
                                                                                : "",
-                                                                       afi_safi_print(
+                                                                       get_afi_safi_str(
                                                                                afi,
-                                                                               safi),
+                                                                               safi,
+                                                                               false),
                                                                        CHECK_FLAG(
                                                                                p->af_cap
                                                                                        [afi]
@@ -10321,8 +10553,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                       PEER_STATUS_EOR_SEND)) {
                                                json_object_boolean_true_add(
                                                        json_grace_send,
-                                                       afi_safi_print(afi,
-                                                                      safi));
+                                                       get_afi_safi_str(afi,
+                                                                        safi,
+                                                                        true));
                                                eor_send_af_count++;
                                        }
                                }
@@ -10332,8 +10565,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                    PEER_STATUS_EOR_RECEIVED)) {
                                                json_object_boolean_true_add(
                                                        json_grace_recv,
-                                                       afi_safi_print(afi,
-                                                                      safi));
+                                                       get_afi_safi_str(afi,
+                                                                        safi,
+                                                                        true));
                                                eor_receive_af_count++;
                                        }
                                }
@@ -10371,8 +10605,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                vty_out(vty, "%s%s",
                                                        eor_send_af_count ? ", "
                                                                          : "",
-                                                       afi_safi_print(afi,
-                                                                      safi));
+                                                       get_afi_safi_str(afi,
+                                                                        safi,
+                                                                        false));
                                                eor_send_af_count++;
                                        }
                                }
@@ -10386,8 +10621,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                        eor_receive_af_count
                                                                ? ", "
                                                                : "",
-                                                       afi_safi_print(afi,
-                                                                      safi));
+                                                       get_afi_safi_str(afi,
+                                                                        safi,
+                                                                        false));
                                                eor_receive_af_count++;
                                        }
                                }
@@ -10573,88 +10809,13 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                            (tm->tm_sec * 1000)
                                                    + (tm->tm_min * 60000)
                                                    + (tm->tm_hour * 3600000));
-                       json_object_string_add(
-                               json_neigh, "lastResetDueTo",
-                               peer_down_str[(int)p->last_reset]);
-                       if (p->last_reset == PEER_DOWN_NOTIFY_SEND
-                           || p->last_reset == PEER_DOWN_NOTIFY_RECEIVED) {
-                               char errorcodesubcode_hexstr[5];
-                               char errorcodesubcode_str[256];
-
-                               code_str = bgp_notify_code_str(p->notify.code);
-                               subcode_str = bgp_notify_subcode_str(
-                                       p->notify.code, p->notify.subcode);
-
-                               sprintf(errorcodesubcode_hexstr, "%02X%02X",
-                                       p->notify.code, p->notify.subcode);
-                               json_object_string_add(json_neigh,
-                                                      "lastErrorCodeSubcode",
-                                                      errorcodesubcode_hexstr);
-                               snprintf(errorcodesubcode_str, 255, "%s%s",
-                                        code_str, subcode_str);
-                               json_object_string_add(json_neigh,
-                                                      "lastNotificationReason",
-                                                      errorcodesubcode_str);
-                               if (p->last_reset == PEER_DOWN_NOTIFY_RECEIVED
-                                   && p->notify.code == BGP_NOTIFY_CEASE
-                                   && (p->notify.subcode
-                                               == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN
-                                       || p->notify.subcode
-                                                  == BGP_NOTIFY_CEASE_ADMIN_RESET)
-                                   && p->notify.length) {
-                                       char msgbuf[1024];
-                                       const char *msg_str;
-
-                                       msg_str = bgp_notify_admin_message(
-                                               msgbuf, sizeof(msgbuf),
-                                               (uint8_t *)p->notify.data,
-                                               p->notify.length);
-                                       if (msg_str)
-                                               json_object_string_add(
-                                                       json_neigh,
-                                                       "lastShutdownDescription",
-                                                       msg_str);
-                               }
-                       }
+                       bgp_show_peer_reset(NULL, p, json_neigh, true);
                } else {
                        vty_out(vty, "  Last reset %s, ",
                                peer_uptime(p->resettime, timebuf,
                                            BGP_UPTIME_LEN, 0, NULL));
 
-                       if (p->last_reset == PEER_DOWN_NOTIFY_SEND
-                           || p->last_reset == PEER_DOWN_NOTIFY_RECEIVED) {
-                               code_str = bgp_notify_code_str(p->notify.code);
-                               subcode_str = bgp_notify_subcode_str(
-                                       p->notify.code, p->notify.subcode);
-                               vty_out(vty, "due to NOTIFICATION %s (%s%s)\n",
-                                       p->last_reset == PEER_DOWN_NOTIFY_SEND
-                                               ? "sent"
-                                               : "received",
-                                       code_str, subcode_str);
-                               if (p->last_reset == PEER_DOWN_NOTIFY_RECEIVED
-                                   && p->notify.code == BGP_NOTIFY_CEASE
-                                   && (p->notify.subcode
-                                               == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN
-                                       || p->notify.subcode
-                                                  == BGP_NOTIFY_CEASE_ADMIN_RESET)
-                                   && p->notify.length) {
-                                       char msgbuf[1024];
-                                       const char *msg_str;
-
-                                       msg_str = bgp_notify_admin_message(
-                                               msgbuf, sizeof(msgbuf),
-                                               (uint8_t *)p->notify.data,
-                                               p->notify.length);
-                                       if (msg_str)
-                                               vty_out(vty,
-                                                       "    Message: \"%s\"\n",
-                                                       msg_str);
-                               }
-                       } else {
-                               vty_out(vty, "due to %s\n",
-                                       peer_down_str[(int)p->last_reset]);
-                       }
-
+                       bgp_show_peer_reset(vty, p, NULL, false);
                        if (p->last_reset_cause_size) {
                                msg = p->last_reset_cause;
                                vty_out(vty,
@@ -11319,7 +11480,7 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
                /* Provide context for the block */
                json_object_string_add(json, "vrf", name ? name : "default");
                json_object_string_add(json, "afiSafi",
-                                      afi_safi_print(afi, safi));
+                                      get_afi_safi_str(afi, safi, true));
 
                if (!CHECK_FLAG(bgp->af_flags[afi][safi],
                                BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
@@ -11400,11 +11561,11 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
                                BGP_CONFIG_VRF_TO_VRF_IMPORT))
                        vty_out(vty,
                     "This VRF is not importing %s routes from any other VRF\n",
-                     afi_safi_print(afi, safi));
+                     get_afi_safi_str(afi, safi, false));
                else {
                        vty_out(vty,
                   "This VRF is importing %s routes from the following VRFs:\n",
-                   afi_safi_print(afi, safi));
+                   get_afi_safi_str(afi, safi, false));
 
                        for (ALL_LIST_ELEMENTS_RO(
                                                bgp->vpn_policy[afi].import_vrf,
@@ -11428,11 +11589,11 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
                                BGP_CONFIG_VRF_TO_VRF_EXPORT))
                        vty_out(vty,
                       "This VRF is not exporting %s routes to any other VRF\n",
-                       afi_safi_print(afi, safi));
+                       get_afi_safi_str(afi, safi, false));
                else {
                        vty_out(vty,
                       "This VRF is exporting %s routes to the following VRFs:\n",
-                       afi_safi_print(afi, safi));
+                       get_afi_safi_str(afi, safi, false));
 
                        for (ALL_LIST_ELEMENTS_RO(
                                                bgp->vpn_policy[afi].export_vrf,
@@ -11809,7 +11970,7 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group)
        FOREACH_AFI_SAFI (afi, safi) {
                if (conf->afc[afi][safi]) {
                        af_cfgd = 1;
-                       vty_out(vty, " %s;", afi_safi_print(afi, safi));
+                       vty_out(vty, " %s;", get_afi_safi_str(afi, safi, false));
                }
        }
        if (!af_cfgd)
@@ -14478,12 +14639,13 @@ ALIAS (show_community_list,
 
 DEFUN (show_community_list_arg,
        show_bgp_community_list_arg_cmd,
-       "show bgp community-list <(1-500)|WORD>",
+       "show bgp community-list <(1-500)|WORD> detail",
        SHOW_STR
        BGP_STR
        "List community-list\n"
        "Community-list number\n"
-       "Community-list name\n")
+       "Community-list name\n"
+       "Detailed information on community-list\n")
 {
        int idx_comm_list = 3;
        struct community_list *list;
@@ -14492,8 +14654,8 @@ DEFUN (show_community_list_arg,
        if (argv_find(argv, argc, "ip", &idx)) {
                vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
                vty_out(vty, "if you are using this please migrate to the below command.\n");
-               vty_out(vty, "'show bgp community-list <(1-500)|WORD>'\n");
-               zlog_warn("Deprecated option: 'ip show community-list <(1-500)|WORD>' being used");
+               vty_out(vty, "'show bgp community-list <(1-500)|WORD> detail'\n");
+               zlog_warn("Deprecated option: 'show ip community-list <(1-500)|WORD>' being used");
        }
        list = community_list_lookup(bgp_clist, argv[idx_comm_list]->arg, 0,
                                     COMMUNITY_LIST_MASTER);
@@ -14632,28 +14794,6 @@ CPP_NOTICE("bgpd: remove deprecated 'ip large-community-list <(1-99)|(100-500)|s
 #endif
 DEFUN (lcommunity_list_standard,
        bgp_lcommunity_list_standard_cmd,
-       "bgp large-community-list (1-99) <deny|permit>",
-       BGP_STR
-       LCOMMUNITY_LIST_STR
-       "Large Community list number (standard)\n"
-       "Specify large community to reject\n"
-       "Specify large community to accept\n")
-{
-       return lcommunity_list_set_vty(vty, argc, argv,
-                                      LARGE_COMMUNITY_LIST_STANDARD, 0);
-}
-
-ALIAS (lcommunity_list_standard,
-       ip_lcommunity_list_standard_cmd,
-       "ip large-community-list (1-99) <deny|permit>",
-       IP_STR
-       LCOMMUNITY_LIST_STR
-       "Large Community list number (standard)\n"
-       "Specify large community to reject\n"
-       "Specify large community to accept\n")
-
-DEFUN (lcommunity_list_standard1,
-       bgp_lcommunity_list_standard1_cmd,
        "bgp large-community-list (1-99) <deny|permit> AA:BB:CC...",
        BGP_STR
        LCOMMUNITY_LIST_STR
@@ -14666,8 +14806,8 @@ DEFUN (lcommunity_list_standard1,
                                       LARGE_COMMUNITY_LIST_STANDARD, 0);
 }
 
-ALIAS (lcommunity_list_standard1,
-       ip_lcommunity_list_standard1_cmd,
+ALIAS (lcommunity_list_standard,
+       ip_lcommunity_list_standard_cmd,
        "ip large-community-list (1-99) <deny|permit> AA:BB:CC...",
        IP_STR
        LCOMMUNITY_LIST_STR
@@ -14702,30 +14842,6 @@ ALIAS (lcommunity_list_expanded,
 
 DEFUN (lcommunity_list_name_standard,
        bgp_lcommunity_list_name_standard_cmd,
-       "bgp large-community-list standard WORD <deny|permit>",
-       BGP_STR
-       LCOMMUNITY_LIST_STR
-       "Specify standard large-community-list\n"
-       "Large Community list name\n"
-       "Specify large community to reject\n"
-       "Specify large community to accept\n")
-{
-       return lcommunity_list_set_vty(vty, argc, argv,
-                                      LARGE_COMMUNITY_LIST_STANDARD, 1);
-}
-
-ALIAS (lcommunity_list_name_standard,
-       ip_lcommunity_list_name_standard_cmd,
-       "ip large-community-list standard WORD <deny|permit>",
-       IP_STR
-       LCOMMUNITY_LIST_STR
-       "Specify standard large-community-list\n"
-       "Large Community list name\n"
-       "Specify large community to reject\n"
-       "Specify large community to accept\n")
-
-DEFUN (lcommunity_list_name_standard1,
-       bgp_lcommunity_list_name_standard1_cmd,
        "bgp large-community-list standard WORD <deny|permit> AA:BB:CC...",
        BGP_STR
        LCOMMUNITY_LIST_STR
@@ -14739,8 +14855,8 @@ DEFUN (lcommunity_list_name_standard1,
                                       LARGE_COMMUNITY_LIST_STANDARD, 1);
 }
 
-ALIAS (lcommunity_list_name_standard1,
-       ip_lcommunity_list_name_standard1_cmd,
+ALIAS (lcommunity_list_name_standard,
+       ip_lcommunity_list_name_standard_cmd,
        "ip large-community-list standard WORD <deny|permit> AA:BB:CC...",
        IP_STR
        LCOMMUNITY_LIST_STR
@@ -15003,12 +15119,13 @@ ALIAS (show_lcommunity_list,
 
 DEFUN (show_lcommunity_list_arg,
        show_bgp_lcommunity_list_arg_cmd,
-       "show bgp large-community-list <(1-500)|WORD>",
+       "show bgp large-community-list <(1-500)|WORD> detail",
        SHOW_STR
        BGP_STR
        "List large-community list\n"
-       "large-community-list number\n"
-       "large-community-list name\n")
+       "Large-community-list number\n"
+       "Large-community-list name\n"
+       "Detailed information on large-community-list\n")
 {
        struct community_list *list;
        int idx = 0;
@@ -15016,14 +15133,14 @@ DEFUN (show_lcommunity_list_arg,
        if (argv_find(argv, argc, "ip", &idx)) {
                vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
                vty_out(vty, "if you are using this please migrate to the below command.\n");
-               vty_out(vty, "'show bgp large-community-list <(1-500)|WORD>'\n");
-               zlog_warn("Deprecated option: 'ip show large-community-list <(1-500)|WORD>' being used");
+               vty_out(vty, "'show bgp large-community-list <(1-500)|WORD> detail'\n");
+               zlog_warn("Deprecated option: 'show ip large-community-list <(1-500)|WORD>' being used");
        }
 
        list = community_list_lookup(bgp_clist, argv[3]->arg, 0,
                                     LARGE_COMMUNITY_LIST_MASTER);
        if (!list) {
-               vty_out(vty, "%% Can't find extcommunity-list\n");
+               vty_out(vty, "%% Can't find large-community-list\n");
                return CMD_WARNING;
        }
 
@@ -15404,12 +15521,13 @@ ALIAS (show_extcommunity_list,
 
 DEFUN (show_extcommunity_list_arg,
        show_bgp_extcommunity_list_arg_cmd,
-       "show bgp extcommunity-list <(1-500)|WORD>",
+       "show bgp extcommunity-list <(1-500)|WORD> detail",
        SHOW_STR
        BGP_STR
        "List extended-community list\n"
        "Extcommunity-list number\n"
-       "Extcommunity-list name\n")
+       "Extcommunity-list name\n"
+       "Detailed information on extcommunity-list\n")
 {
        int idx_comm_list = 3;
        struct community_list *list;
@@ -15418,8 +15536,8 @@ DEFUN (show_extcommunity_list_arg,
        if (argv_find(argv, argc, "ip", &idx)) {
                vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
                vty_out(vty, "if you are using this please migrate to the below command.\n");
-               vty_out(vty, "'show bgp extcommunity-list <(1-500)|WORD>'\n");
-               zlog_warn("Deprecated option: 'ip show extcommunity-list <(1-500)|WORD>' being used");
+               vty_out(vty, "'show bgp extcommunity-list <(1-500)|WORD> detail'\n");
+               zlog_warn("Deprecated option: 'show ip extcommunity-list <(1-500)|WORD>' being used");
        }
        list = community_list_lookup(bgp_clist, argv[idx_comm_list]->arg, 0,
                                     EXTCOMMUNITY_LIST_MASTER);
@@ -15566,10 +15684,8 @@ static void community_list_vty(void)
 
        /* Large Community List */
        install_element(CONFIG_NODE, &bgp_lcommunity_list_standard_cmd);
-       install_element(CONFIG_NODE, &bgp_lcommunity_list_standard1_cmd);
        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_standard1_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,
@@ -15581,10 +15697,8 @@ static void community_list_vty(void)
        install_element(VIEW_NODE, &show_bgp_lcommunity_list_cmd);
        install_element(VIEW_NODE, &show_bgp_lcommunity_list_arg_cmd);
        install_element(CONFIG_NODE, &ip_lcommunity_list_standard_cmd);
-       install_element(CONFIG_NODE, &ip_lcommunity_list_standard1_cmd);
        install_element(CONFIG_NODE, &ip_lcommunity_list_expanded_cmd);
        install_element(CONFIG_NODE, &ip_lcommunity_list_name_standard_cmd);
-       install_element(CONFIG_NODE, &ip_lcommunity_list_name_standard1_cmd);
        install_element(CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd);
        install_element(CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd);
        install_element(CONFIG_NODE,
index d9df2b4cfedab1771e36836ea954ebc21a3029e3..27b5ea47b27d461fa617fa17a6460892fdd1aaa7 100644 (file)
@@ -45,8 +45,7 @@ struct bgp;
        "Address Family modifier\n"
 
 extern void bgp_vty_init(void);
-extern const char *afi_safi_print(afi_t afi, safi_t safi);
-extern const char *afi_safi_json(afi_t afi, safi_t safi);
+extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
 extern void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp);
 extern void bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp);
 extern void bgp_config_write_rpkt_quanta(struct vty *vty, struct bgp *bgp);
@@ -72,7 +71,7 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty,
                                               safi_t *safi, struct bgp **bgp,
                                               bool use_json);
 extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
-                               safi_t safi, bool use_json);
+                               safi_t safi, bool show_failed, bool use_json);
 extern void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
                                            afi_t afi);
 #endif /* _QUAGGA_BGP_VTY_H */
index b5f267cc3862221124651cfd7351a0212ff13ab7..5b31fbb3a8c140cb8d77d460fbe74ac3d29d3ace 100644 (file)
@@ -1582,6 +1582,12 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
        }
 
        active = peer_active(peer);
+       if (!active) {
+               if (peer->su.sa.sa_family == AF_UNSPEC)
+                       peer->last_reset = PEER_DOWN_NBR_ADDR;
+               else
+                       peer->last_reset = PEER_DOWN_NOAFI_ACTIVATED;
+       }
 
        /* Last read and reset time set */
        peer->readtime = peer->resettime = bgp_clock();
@@ -2221,10 +2227,12 @@ int peer_delete(struct peer *peer)
        bgp = peer->bgp;
        accept_peer = CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
 
+       bgp_keepalives_off(peer);
        bgp_reads_off(peer);
        bgp_writes_off(peer);
        assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON));
        assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_READS_ON));
+       assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON));
 
        if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT))
                peer_nsf_stop(peer);
index 9e05fd5629d53f2e1ba535f3c0ead97ba4890216..477c0360095767d670286d56aece45ca6d70c887 100644 (file)
@@ -1194,6 +1194,10 @@ struct peer {
 #define PEER_DOWN_BFD_DOWN              24 /* BFD down */
 #define PEER_DOWN_IF_DOWN               25 /* Interface down */
 #define PEER_DOWN_NBR_ADDR_DEL          26 /* Peer address lost */
+#define PEER_DOWN_WAITING_NHT           27 /* Waiting for NHT to resolve */
+#define PEER_DOWN_NBR_ADDR              28 /* Waiting for peer IPv6 IP Addr */
+#define PEER_DOWN_VRF_UNINIT            29 /* Associated VRF is not init yet */
+#define PEER_DOWN_NOAFI_ACTIVATED       30 /* No AFI/SAFI activated for peer */
        size_t last_reset_cause_size;
        uint8_t last_reset_cause[BGP_MAX_PACKET_SIZE];
 
index e7905e56225530f5fe2fe3df84604524a187a65d..9b8f64ee678d4d7c6e786ed7f07f901f3d4ae8df 100644 (file)
@@ -1282,8 +1282,7 @@ static int rfapi_open_inner(struct rfapi_descriptor *rfd, struct bgp *bgp,
         * since this peer is not on the I/O thread, this lock is not strictly
         * necessary, but serves as a reminder to those who may meddle...
         */
-       pthread_mutex_lock(&rfd->peer->io_mtx);
-       {
+       frr_with_mutex(&rfd->peer->io_mtx) {
                // we don't need any I/O related facilities
                if (rfd->peer->ibuf)
                        stream_fifo_free(rfd->peer->ibuf);
@@ -1300,7 +1299,6 @@ static int rfapi_open_inner(struct rfapi_descriptor *rfd, struct bgp *bgp,
                rfd->peer->obuf_work = NULL;
                rfd->peer->ibuf_work = NULL;
        }
-       pthread_mutex_unlock(&rfd->peer->io_mtx);
 
        { /* base code assumes have valid host pointer */
                char buf[BUFSIZ];
index 481500dfb445ec12130259908c14ab1a4276b89a..80a590f56a13173f49ee59de0366f6752666c50a 100644 (file)
@@ -191,8 +191,7 @@ static void vnc_redistribute_add(struct prefix *p, uint32_t metric,
                         * is not strictly necessary, but serves as a reminder
                         * to those who may meddle...
                         */
-                       pthread_mutex_lock(&vncHD1VR.peer->io_mtx);
-                       {
+                       frr_with_mutex(&vncHD1VR.peer->io_mtx) {
                                // we don't need any I/O related facilities
                                if (vncHD1VR.peer->ibuf)
                                        stream_fifo_free(vncHD1VR.peer->ibuf);
@@ -209,7 +208,6 @@ static void vnc_redistribute_add(struct prefix *p, uint32_t metric,
                                vncHD1VR.peer->obuf_work = NULL;
                                vncHD1VR.peer->ibuf_work = NULL;
                        }
-                       pthread_mutex_unlock(&vncHD1VR.peer->io_mtx);
 
                        /* base code assumes have valid host pointer */
                        vncHD1VR.peer->host =
index d281fe4e5930016939fc53b4da0a6091d9bfea99..b338fd4f3dbc6081c02a3d9950180ecb52a58dc3 100644 (file)
@@ -27,6 +27,7 @@ vtysh_scan += \
 
 # can be loaded as DSO - always include for vtysh
 vtysh_scan += $(top_srcdir)/bgpd/bgp_rpki.c
+vtysh_scan += $(top_srcdir)/bgpd/bgp_bmp.c
 
 if ENABLE_BGP_VNC
 vtysh_scan += \
@@ -42,6 +43,9 @@ endif
 if RPKI
 module_LTLIBRARIES += bgpd/bgpd_rpki.la
 endif
+if BGP_BMP
+module_LTLIBRARIES += bgpd/bgpd_bmp.la
+endif
 man8 += $(MANBUILD)/bgpd.8
 endif
 
@@ -129,6 +133,7 @@ noinst_HEADERS += \
        bgpd/bgp_damp.h \
        bgpd/bgp_debug.h \
        bgpd/bgp_dump.h \
+       bgpd/bgp_bmp.h \
        bgpd/bgp_ecommunity.h \
        bgpd/bgp_encap_tlv.h \
        bgpd/bgp_encap_types.h \
@@ -216,6 +221,10 @@ bgpd_bgpd_rpki_la_CFLAGS = $(WERROR) $(RTRLIB_CFLAGS)
 bgpd_bgpd_rpki_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
 bgpd_bgpd_rpki_la_LIBADD = $(RTRLIB_LIBS)
 
+bgpd_bgpd_bmp_la_SOURCES = bgpd/bgp_bmp.c
+bgpd_bgpd_bmp_la_LIBADD = lib/libfrrcares.la
+bgpd_bgpd_bmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+
 bgpd/bgp_evpn_vty_clippy.c: $(CLIPPY_DEPS)
 bgpd/bgp_evpn_vty.$(OBJEXT): bgpd/bgp_evpn_vty_clippy.c
 bgpd/bgp_vty_clippy.c: $(CLIPPY_DEPS)
@@ -229,3 +238,5 @@ bgpd/bgp_routemap.$(OBJEXT): bgpd/bgp_routemap_clippy.c
 bgpd/bgp_rpki_clippy.c: $(CLIPPY_DEPS)
 $(AUTOMAKE_DUMMY)bgpd/bgpd_bgpd_rpki_la-bgp_rpki.lo: bgpd/bgp_rpki_clippy.c
 $(AUTOMAKE_DUMMY)bgpd/bgpd_rpki_la-bgp_rpki.lo: bgpd/bgp_rpki_clippy.c
+bgpd/bgp_bmp_clippy.c: $(CLIPPY_DEPS)
+bgpd/bgp_bmp.lo: bgpd/bgp_bmp_clippy.c
index 134c8692d43b57cf410fcbc21c205b7f364f0ee8..6c1b35b5f2356fe290844c6fdc3f64246b703cdb 100755 (executable)
@@ -479,12 +479,14 @@ AC_ARG_ENABLE([staticd],
   AS_HELP_STRING([--disable-staticd], [do not build staticd]))
 AC_ARG_ENABLE([fabricd],
   AS_HELP_STRING([--disable-fabricd], [do not build fabricd]))
-AC_ARG_ENABLE([bgp-announce],
-  AS_HELP_STRING([--disable-bgp-announce,], [turn off BGP route announcement]))
 AC_ARG_ENABLE([vrrpd],
   AS_HELP_STRING([--disable-vrrpd], [do not build vrrpd]))
+AC_ARG_ENABLE([bgp-announce],
+  AS_HELP_STRING([--disable-bgp-announce,], [turn off BGP route announcement]))
 AC_ARG_ENABLE([bgp-vnc],
   AS_HELP_STRING([--disable-bgp-vnc],[turn off BGP VNC support]))
+AC_ARG_ENABLE([bgp-bmp],
+  AS_HELP_STRING([--disable-bgp-bmp],[turn off BGP BMP support]))
 AC_ARG_ENABLE([snmp],
   AS_HELP_STRING([--enable-snmp], [enable SNMP support for agentx]))
 AC_ARG_ENABLE([config_rollbacks],
@@ -1061,6 +1063,7 @@ case "$host_os" in
     AC_CHECK_LIB([nsl], [main])
     AC_CHECK_LIB([umem], [main])
     SOLARIS="solaris"
+    AC_MSG_WARN([--Solaris support is being considered for deprecation, please let us know if you are still using this--])
     ;;
   linux*)
     AC_MSG_RESULT([Linux])
@@ -1449,6 +1452,16 @@ if test "x$enable_pcreposix" = "xyes"; then
 fi
 AC_SUBST([HAVE_LIBPCREPOSIX])
 
+dnl ------------------
+dnl check C-Ares library
+dnl ------------------
+PKG_CHECK_MODULES([CARES], [libcares], [
+  c_ares_found=true
+],[
+  c_ares_found=false
+])
+AM_CONDITIONAL([CARES], [$c_ares_found])
+
 dnl ##########################################################################
 dnl test "${enable_clippy_only}" != "yes"
 fi
@@ -1518,9 +1531,21 @@ fi
 NHRPD=""
 case "$host_os" in
   linux*)
-    if test "${enable_nhrpd}" != "no"; then
-      NHRPD="nhrpd"
-    fi
+    case "${enable_nhrpd}" in
+      no)
+        ;;
+      yes)
+        if test "$c_ares_found" != "true" ; then
+          AC_MSG_ERROR([nhrpd requires libcares.  Please install c-ares and its -dev headers.])
+        fi
+        NHRPD="nhrpd"
+        ;;
+      *)
+        if test "$c_ares_found" = "true" ; then
+          NHRPD="nhrpd"
+        fi
+        ;;
+    esac
     ;;
   *)
     if test "${enable_nhrpd}" = "yes"; then
@@ -1554,21 +1579,28 @@ if test "${enable_bgp_vnc}" != "no";then
   AC_DEFINE([ENABLE_BGP_VNC], [1], [Enable BGP VNC support])
 fi
 
+bgpd_bmp=false
+case "${enable_bmp}" in
+  no)
+    ;;
+  yes)
+    if test "$c_ares_found" != "true" ; then
+      AC_MSG_ERROR([BMP support requires libcares.  Please install c-ares and its -dev headers.])
+    fi
+    bgpd_bmp=true
+    ;;
+  *)
+    if test "$c_ares_found" = "true" ; then
+      bgpd_bmp=true
+    fi
+    ;;
+esac
+
 dnl ##########################################################################
 dnl LARGE if block
 if test "${enable_clippy_only}" != "yes"; then
 dnl ##########################################################################
 
-dnl ------------------
-dnl check C-Ares library
-dnl ------------------
-if test "${NHRPD}" != ""; then
-  PKG_CHECK_MODULES([CARES], [libcares], ,[
-    AC_MSG_ERROR([trying to build nhrpd, but libcares not found. install c-ares and its -dev headers.])
-  ])
-fi
-AM_CONDITIONAL([CARES], [test "${NHRPD}" != ""])
-
 dnl ------------------
 dnl check Net-SNMP library
 dnl ------------------
@@ -2006,6 +2038,20 @@ if test "${enable_capabilities}" != "no"; then
        -o x"${frr_ac_lcaps}" = x"yes"; then
     AC_DEFINE([HAVE_CAPABILITIES], [1], [capabilities])
   fi
+
+  case "$host_os" in
+  linux*)
+    if test "$frr_ac_lcaps" != "yes"; then
+      AC_MSG_ERROR([libcap and/or its headers were not found.  Running FRR without libcap support built in causes a huge performance penalty.])
+    fi
+    ;;
+  esac
+else
+  case "$host_os" in
+  linux*)
+    AC_MSG_WARN([Running FRR without libcap support built in causes a huge performance penalty.])
+    ;;
+  esac
 fi
 AC_SUBST([LIBCAP])
 
@@ -2192,6 +2238,7 @@ AC_DEFINE_UNQUOTED([WATCHFRR_SH_PATH], ["${CFG_SBIN%/}/watchfrr.sh"], [path to w
 dnl various features
 AM_CONDITIONAL([SUPPORT_REALMS], [test "${enable_realms}" = "yes"])
 AM_CONDITIONAL([ENABLE_BGP_VNC], [test x${enable_bgp_vnc} != xno])
+AM_CONDITIONAL([BGP_BMP], [$bgpd_bmp])
 dnl northbound
 AM_CONDITIONAL([SQLITE3], [$SQLITE3])
 AM_CONDITIONAL([CONFD], [test "x$enable_confd" != "x"])
index fe34b23d025cc6ea24c4a5e5b64e79988c06cfb0..09bddf0fc66672788615c304b80d365b3ff762d1 100644 (file)
@@ -10,6 +10,7 @@ usr/lib/frr/watchfrr
 usr/lib/frr/zebra
 usr/lib/*/frr/modules/zebra_irdp.so
 usr/lib/*/frr/modules/zebra_fpm.so
+usr/lib/*/frr/modules/bgpd_bmp.so
 usr/share/doc/frr/examples
 usr/share/man/
 usr/share/yang/
index 7cd493ccc4435ba52bfe79f8878b88cd3b839558..a904a4e778b9afc42874c04e4580c5c498b1762c 100644 (file)
@@ -11,6 +11,7 @@ Library Facilities (libfrr)
    rcu
    lists
    logging
+   locking
    hooks
    cli
    modules
diff --git a/doc/developer/locking.rst b/doc/developer/locking.rst
new file mode 100644 (file)
index 0000000..aee05aa
--- /dev/null
@@ -0,0 +1,73 @@
+Locking
+=======
+
+FRR ships two small wrappers around ``pthread_mutex_lock()`` /
+``pthread_mutex_unlock``.  Use ``#include "frr_pthread.h"`` to get these
+macros.
+
+.. c:function:: frr_with_mutex(pthread_mutex_t *mutex)
+
+   Begin a C statement block that is executed with the mutex locked.  Any
+   exit from the block (``break``, ``return``, ``goto``, end of block) will
+   cause the mutex to be unlocked::
+
+      int somefunction(int option)
+      {
+          frr_with_mutex(&my_mutex) {
+              /* mutex will be locked */
+
+              if (!option)
+                  /* mutex will be unlocked before return */
+                  return -1;
+
+              if (something(option))
+                  /* mutex will be unlocked before goto */
+                  goto out_err;
+
+              somethingelse();
+
+              /* mutex will be unlocked at end of block */
+          }
+
+          return 0;
+
+      out_err:
+          somecleanup();
+          return -1;
+      }
+
+   This is a macro that internally uses a ``for`` loop.  It is explicitly
+   acceptable to use ``break`` to get out of the block.  Even though a single
+   statement works correctly, FRR coding style requires that this macro always
+   be used with a ``{ ... }`` block.
+
+.. c:function:: frr_mutex_lock_autounlock(pthread_mutex_t *mutex)
+
+   Lock mutex and unlock at the end of the current C statement block::
+
+      int somefunction(int option)
+      {
+          frr_mutex_lock_autounlock(&my_mutex);
+          /* mutex will be locked */
+
+          ...
+          if (error)
+            /* mutex will be unlocked before return */
+            return -1;
+          ...
+
+          /* mutex will be unlocked before return */
+          return 0;
+      }
+
+   This is a macro that internally creates a variable with a destructor.
+   When the variable goes out of scope (i.e. the block ends), the mutex is
+   released.
+
+   .. warning::
+
+      This macro should only used when :c:func:`frr_with_mutex` would
+      result in excessively/weirdly nested code.  This generally is an
+      indicator that the code might be trying to do too many things with
+      the lock held.  Try any possible venues to reduce the amount of
+      code covered by the lock and move to :c:func:`frr_with_mutex`.
index 1fc593e56677023ea5d0fbd9b3d5675ad3410250..557a41c51f6cbfa4a0e89724de5e05f4225dc492 100644 (file)
@@ -31,6 +31,7 @@ dev_RSTFILES = \
        doc/developer/index.rst \
        doc/developer/library.rst \
        doc/developer/lists.rst \
+       doc/developer/locking.rst \
        doc/developer/logging.rst \
        doc/developer/maintainer-release-build.rst \
        doc/developer/memtypes.rst \
index 07c43ac2de7054fae1259fe5634834754450c2a2..3c6887fbac581da6f807148ad20e8804cded0ad2 100644 (file)
@@ -767,6 +767,28 @@ ways that can be unexpected for the original implementor. As such debugs
 ability to turn on/off debugs from the CLI and it is expected that the
 developer will use this convention to allow control of their debugs.
 
+Custom syntax-like block macros
+-------------------------------
+
+FRR uses some macros that behave like the ``for`` or ``if`` C keywords.  These
+macros follow these patterns:
+
+- loop-style macros are named ``frr_each_*`` (and ``frr_each``)
+- single run macros are named ``frr_with_*``
+- to avoid confusion, ``frr_with_*`` macros must always use a ``{ ... }``
+  block even if the block only contains one statement.  The ``frr_each``
+  constructs are assumed to be well-known enough to use normal ``for`` rules.
+- ``break``, ``return`` and ``goto`` all work correctly.  For loop-style
+  macros, ``continue`` works correctly too.
+
+Both the ``each`` and ``with`` keywords are inspired by other (more
+higher-level) programming languages that provide these constructs.
+
+There are also some older iteration macros, e.g. ``ALL_LIST_ELEMENTS`` and
+``FOREACH_AFI_SAFI``.  These macros in some cases do **not** fulfill the above
+pattern (e.g. ``break`` does not work in ``FOREACH_AFI_SAFI`` because it
+expands to 2 nested loops.)
+
 Static Analysis and Sanitizers
 ------------------------------
 Clang/LLVM and GCC come with a variety of tools that can be used to help find
index c329ab6d9fb98d3fbd9875d3856ce9fb5bab4a9f..da339b440961a49f6aad8b282d693a02b7e80711 100644 (file)
@@ -1169,19 +1169,24 @@ AS path access list is user defined AS path.
 Using AS Path in Route Map
 --------------------------
 
-.. index:: match as-path WORD
-.. clicmd:: match as-path WORD
+.. index:: [no] match as-path WORD
+.. clicmd:: [no] match as-path WORD
 
+   For a given as-path, WORD, match it on the BGP as-path given for the prefix
+   and if it matches do normal route-map actions.  The no form of the command
+   removes this match from the route-map.
 
-.. index:: set as-path prepend AS-PATH
-.. clicmd:: set as-path prepend AS-PATH
+.. index:: [no] set as-path prepend AS-PATH
+.. clicmd:: [no] set as-path prepend AS-PATH
 
-   Prepend the given string of AS numbers to the AS_PATH.
+   Prepend the given string of AS numbers to the AS_PATH of the BGP path's NLRI.
+   The no form of this command removes this set operation from the route-map.
 
-.. index:: set as-path prepend last-as NUM
-.. clicmd:: set as-path prepend last-as NUM
+.. index:: [no] set as-path prepend last-as NUM
+.. clicmd:: [no] set as-path prepend last-as NUM
 
    Prepend the existing last AS number (the leftmost ASN) to the AS_PATH.
+   The no form of this command removes this set operation from the route-map.
 
 .. _bgp-communities-attribute:
 
@@ -2246,6 +2251,12 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
    Show a bgp peer summary for the specified address family, and subsequent
    address-family.
 
+.. index:: show bgp [afi] [safi] summary failed [json]
+.. clicmd:: show bgp [afi] [safi] summary failed [json]
+
+   Show a bgp peer summary for peers that are not succesfully exchanging routes
+   for the specified address family, and subsequent address-family.
+
 .. index:: show bgp [afi] [safi] neighbor [PEER]
 .. clicmd:: show bgp [afi] [safi] neighbor [PEER]
 
diff --git a/doc/user/bmp.rst b/doc/user/bmp.rst
new file mode 100644 (file)
index 0000000..061800c
--- /dev/null
@@ -0,0 +1,170 @@
+.. _bmp:
+
+***
+BMP
+***
+
+:abbr:`BMP` (BGP Monitoring Protocol, :rfc:`7854`) is used to send monitoring
+data from BGP routers to network management entities.
+
+Implementation characteristics
+==============================
+
+The `BMP` implementation in FRR has the following properties:
+
+- only the :rfc:`7854` features are currently implemented.  This means protocol
+  version 3 without any extensions.  It is not possible to use an older draft
+  protocol version of BMP.
+
+- the following statistics codes are implemented:
+
+  - 0: count of prefixes rejected
+  - 2: count of duplicate prefix withdrawals
+  - 3: count of **prefixes** with loop in cluster id
+  - 4: count of **prefixes** with loop in AS-path
+  - 5: count of **prefixes** with loop in originator
+  - 11: count of updates subjected to :rfc:`7607` "treat as withdrawal"
+    handling due to errors
+  - 65531: *experimental* count of prefixes rejected due to invalid next-hop
+
+  Note that stat items 3, 4 and 5 are specified to count updates, but FRR
+  implements them as prefix-based counters.
+
+- **route mirroring** is fully implemented, however BGP OPEN messages are not
+  currently included in route mirroring messages.  Their contents can be
+  extracted from the "peer up" notification for sessions that established
+  successfully.  OPEN messages for failed sessions cannot currently be
+  mirrored.
+
+- **route monitoring** is available for IPv4 and IPv6 AFIs, unicast and
+  multicast SAFIs.  Other SAFIs (VPN, Labeled-Unicast, Flowspec, etc.) are not
+  currently supported.
+
+- monitoring peers that have BGP **add-path** enabled on the session will
+  result in somewhat unpredictable behaviour.  Currently, the outcome is:
+
+  - route mirroring functions as intended, messages are copied verbatim
+  - the add-path ID is never included in route monitoring messages
+  - if multiple paths were received from a peer, an unpredictable path is
+    picked and sent on the BMP session.  The selection will differ for
+    pre-policy and post-policy monitoring sessions.
+  - as long as any path is present, something will be advertised on BMP
+    sessions.  Only after the last path is gone a withdrawal will be sent on
+    BMP sessions.
+  - updates to additional paths will trigger BMP route monitoring messages.
+    There is no guarantee on consistency regarding which path is sent in these
+    messages.
+
+- monitoring peers with :rfc:`5549` extended next-hops has not been tested.
+
+Starting BMP
+============
+
+BMP is implemented as a loadable module.  This means that to use BMP, ``bgpd``
+must be started with the ``-M bmp`` option.  It is not possible to enable BMP
+if ``bgpd`` was started without this option.
+
+Configuring BMP
+===============
+
+All of FRR's BMP configuration options are located inside the
+:clicmd:`router bgp ASN` block.  Configure BGP first before proceeding to BMP
+setup.
+
+There is one option that applies to the BGP instance as a whole:
+
+.. index:: bmp mirror buffer-limit(0-4294967294)
+.. clicmd:: [no] bmp mirror buffer-limit(0-4294967294)
+
+   This sets the maximum amount of memory used for buffering BGP messages
+   (updates, keepalives, ...) for sending in BMP Route Mirroring.
+
+   The buffer is for the entire BGP instance; if multiple BMP targets are
+   configured they reference the same buffer and do not consume additional
+   memory.  Queue overhead is included in accounting this memory, so the
+   actual space available for BGP messages is slightly less than the value
+   configured here.
+
+   If the buffer fills up, the oldest messages are removed from the buffer and
+   any BMP sessions where the now-removed messages were still pending have
+   their **entire** queue flushed and a "Mirroring Messages Lost" BMP message
+   is sent.
+
+   BMP Route Monitoring is not affected by this option.
+
+All other configuration is managed per targets:
+
+.. index:: bmp targets NAME
+.. clicmd:: [no] bmp targets NAME
+
+   Create/delete a targets group.  As implied by the plural name, targets may
+   cover multiple outbound active BMP sessions as well as inbound passive
+   listeners.
+
+   If BMP sessions have the same configuration, putting them in the same
+   ``bmp targets`` will reduce overhead.
+
+BMP session configuration
+-------------------------
+
+Inside a ``bmp targets`` block, the following commands control session
+establishment:
+
+.. index:: bmp connect HOSTNAME port (1-65535) {min-retry MSEC|max-retry MSEC}
+.. clicmd:: [no] bmp connect HOSTNAME port (1-65535) {min-retry MSEC|max-retry MSEC}
+
+   Add/remove an active outbound BMP session.  HOSTNAME is resolved via DNS,
+   if multiple addresses are returned they are tried in nondeterministic
+   order.  Only one connection will be established even if multiple addresses
+   are returned.  ``min-retry`` and ``max-retry`` specify (in milliseconds)
+   bounds for exponential backoff.
+
+.. warning::
+
+   ``ip access-list`` and ``ipv6 access-list`` are checked for outbound
+   connections resulting from ``bmp connect`` statements.
+
+.. index:: bmp listener <X:X::X:X|A.B.C.D> port (1-65535)
+.. clicmd:: [no] bmp listener <X:X::X:X|A.B.C.D> port (1-65535)
+
+   Accept incoming BMP sessions on the specified address and port.  You can
+   use ``0.0.0.0`` and ``::`` to listen on all IPv4/IPv6 addresses.
+
+.. clicmd:: [no] ip access-list NAME
+.. clicmd:: [no] ipv6 access-list NAME
+
+   Restrict BMP sessions to the addresses allowed by the respective access
+   lists.  The access lists are checked for both passive and active BMP
+   sessions.  Changes do not affect currently established sessions.
+
+BMP data feed configuration
+---------------------------
+
+The following commands configure what BMP messages are sent on sessions
+associated with a particular ``bmp targets``:
+
+.. index:: bmp stats [interval (100-86400000)]
+.. clicmd:: [no] bmp stats [interval (100-86400000)]
+
+   Send BMP Statistics (counter) messages at the specified interval (in
+   milliseconds.)
+
+.. index:: bmp monitor AFI SAFI <pre-policy|post-policy>
+.. clicmd:: [no] bmp monitor AFI SAFI <pre-policy|post-policy>
+
+   Perform Route Monitoring for the specified AFI and SAFI.  Only IPv4 and
+   IPv6 are currently valid for AFI, and only unicast and multicast are valid
+   for SAFI.  Other AFI/SAFI combinations may be added in the future.
+
+   All BGP neighbors are included in Route Monitoring.  Options to select
+   a subset of BGP sessions may be added in the future.
+
+.. index:: bmp mirror
+.. clicmd:: [no] bmp mirror
+
+   Perform Route Mirroring for all BGP neighbors.  Since this provides a
+   direct feed of BGP messages, there are no AFI/SAFI options to be
+   configured.
+
+   All BGP neighbors are included in Route Mirroring.  Options to select
+   a subset of BGP sessions may be added in the future.
index 330267a8ee83b0cb5fba513dc7e642ce221483a5..915270a5626e87f91b2b820f3e57688674adf24c 100644 (file)
@@ -65,15 +65,16 @@ Certain signals have special meanings to *eigrpd*.
 EIGRP Configuration
 ===================
 
-.. index:: router eigrp (1-65535)
-.. clicmd:: router eigrp (1-65535)
+.. index:: router eigrp (1-65535) [vrf NAME]
+.. clicmd:: router eigrp (1-65535) [vrf NAME]
 
    The `router eigrp` command is necessary to enable EIGRP. To disable EIGRP,
    use the `no router eigrp (1-65535)` command. EIGRP must be enabled before
-   carrying out any of the EIGRP commands.
+   carrying out any of the EIGRP commands.  Specify vrf NAME if you want
+   eigrp to work within the specified vrf.
 
-.. index:: no router eigrp (1-65535)
-.. clicmd:: no router eigrp (1-65535)
+.. index:: no router eigrp (1-65535) [vrf NAME]
+.. clicmd:: no router eigrp (1-65535) [vrf NAME]
 
    Disable EIGRP.
 
@@ -189,8 +190,8 @@ How to Announce EIGRP route
 Show EIGRP Information
 ======================
 
-.. index:: show ip eigrp topology
-.. clicmd:: show ip eigrp topology
+.. index:: show ip eigrp [vrf NAME] topology
+.. clicmd:: show ip eigrp [vrf NAME] topology
 
    Display current EIGRP status.
 
@@ -207,6 +208,17 @@ Show EIGRP Information
       P  10.0.2.0/24, 1 successors, FD is 256256, serno: 0
              via Connected, enp0s3
 
+.. index:: show ip eigrp [vrf NAME] interface
+.. clicmd:: show ip eigrp [vrf NAME] interface
+
+   Display the list of interfaces associated with a particular eigrp
+   instance.
+
+..index:: show ip eigrp [vrf NAME] neighbor
+..clicmd:: show ip eigrp [vrf NAME] neighbor
+
+   Display the list of neighbors that have been established within
+   a particular eigrp instance.
 
 EIGRP Debug Commands
 ====================
index 4e14de673799b37e0577b72eafaa5a420900cfdb..6c3b14e062813a862b5f131317859b4ac98e3b7e 100644 (file)
@@ -57,6 +57,7 @@ Protocols
    static
    vnc
    vrrp
+   bmp
 
 ########
 Appendix
index 6230bf777a46cdcbf8e58eeae6b6823ef149c36a..fab4343f50802d99d38238e4e6a9926ac8b205c8 100644 (file)
@@ -91,6 +91,12 @@ end destination.
    both v4 and v6 prefixes.  This command is used in conjunction of the
    :clicmd:`match src-ip PREFIX` command for matching.
 
+.. clicmd:: match mark (1-4294967295)
+
+   Select the mark to match.  This is a linux only command and if attempted
+   on another platform it will be denied.  This mark translates to the
+   underlying `ip rule .... fwmark XXXX` command.
+
 .. clicmd:: set nexthop-group NAME
 
    Use the nexthop-group NAME as the place to forward packets when the match
index ca6b46d3cff2b40a75092c8ff0f20aae890cafa9..dfac10b4f28a752279d13a9c9a648c9736bdcfa3 100644 (file)
@@ -112,31 +112,6 @@ The following commands are independent of a specific cache server.
 
    The default value is 300 seconds.
 
-.. index:: rpki timeout <1-4,294,967,296>
-.. clicmd:: rpki timeout <1-4,294,967,296>
-
-.. index:: no rpki timeout
-.. clicmd:: no rpki timeout
-
-   Set the number of seconds the router waits for the cache reply. If the cache
-   server is not replying within this time period, the router deletes all
-   received prefix records from the prefix table.
-
-   The default value is 600 seconds.
-
-.. index:: rpki initial-synchronisation-timeout <1-4,294,967,296>
-.. clicmd:: rpki initial-synchronisation-timeout <1-4,294,967,296>
-
-.. index:: no rpki initial-synchronisation-timeout
-.. clicmd:: no rpki initial-synchronisation-timeout
-
-   Set the number of seconds until the first synchronization with the cache
-   server needs to be completed. If the timeout expires, BGP routing is started
-   without RPKI. The router will try to establish the cache server connection in
-   the background.
-
-   The default value is 30 seconds.
-
    The following commands configure one or multiple cache servers.
 
 .. index:: rpki cache (A.B.C.D|WORD) PORT [SSH_USERNAME] [SSH_PRIVKEY_PATH] [SSH_PUBKEY_PATH] [KNOWN_HOSTS_PATH] PREFERENCE
index 1e4d86c722f52854b7087bf7188b971cc82ea8d8..0f0a8a07742cafbe257833ef80420a5301945ca6 100644 (file)
@@ -7,6 +7,7 @@ user_RSTFILES = \
        doc/user/ldpd.rst \
        doc/user/basic.rst \
        doc/user/bgp.rst \
+       doc/user/bmp.rst \
        doc/user/bugs.rst \
        doc/user/conf.py \
        doc/user/eigrpd.rst \
index ba657a7d5deef25a27aeca68387ff552b75396a2..a93d4c8280700fde46719d2df0fe08d7fcc2932b 100644 (file)
 DEFPY_NOSH(
        router_eigrp,
        router_eigrp_cmd,
-       "router eigrp (1-65535)$as",
+       "router eigrp (1-65535)$as [vrf NAME]",
        ROUTER_STR
        EIGRP_STR
-       AS_STR)
+       AS_STR
+       VRF_CMD_HELP_STR)
 {
        char xpath[XPATH_MAXLEN];
        int rv;
 
        snprintf(xpath, sizeof(xpath),
-                "/frr-eigrpd:eigrpd/instance[asn='%s'][vrf='']",
-                as_str);
+                "/frr-eigrpd:eigrpd/instance[asn='%s'][vrf='%s']",
+                as_str, vrf ? vrf : VRF_DEFAULT_NAME);
 
        nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
        rv = nb_cli_apply_changes(vty, NULL);
@@ -60,20 +61,21 @@ DEFPY_NOSH(
        return rv;
 }
 
-DEFPY_NOSH(
+DEFPY(
        no_router_eigrp,
        no_router_eigrp_cmd,
-       "no router eigrp (1-65535)$as",
+       "no router eigrp (1-65535)$as [vrf NAME]",
        NO_STR
        ROUTER_STR
        EIGRP_STR
-       AS_STR)
+       AS_STR
+       VRF_CMD_HELP_STR)
 {
        char xpath[XPATH_MAXLEN];
 
        snprintf(xpath, sizeof(xpath),
-                "/frr-eigrpd:eigrpd/instance[asn='%s'][vrf='']",
-                as_str);
+                "/frr-eigrpd:eigrpd/instance[asn='%s'][vrf='%s']",
+                as_str, vrf ? vrf : VRF_DEFAULT_NAME);
 
        nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
        return nb_cli_apply_changes(vty, NULL);
@@ -83,8 +85,12 @@ void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode,
                           bool show_defaults)
 {
        const char *asn = yang_dnode_get_string(dnode, "./asn");
+       const char *vrf = yang_dnode_get_string(dnode, "./vrf");
 
-       vty_out(vty, "router eigrp %s\n", asn);
+       vty_out(vty, "router eigrp %s", asn);
+       if (strcmp(vrf, VRF_DEFAULT_NAME))
+               vty_out(vty, " vrf %s", vrf);
+       vty_out(vty, "\n");
 }
 
 void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode)
index 93eed9452ccbb6ab4ad9174b45f4f4f2b90a0908..9d5d45ca50f044582119b713ce67d04c5958b1d1 100644 (file)
 void eigrp_distribute_update(struct distribute_ctx *ctx,
                             struct distribute *dist)
 {
+       struct eigrp *e = eigrp_lookup(ctx->vrf->vrf_id);
        struct interface *ifp;
        struct eigrp_interface *ei = NULL;
        struct access_list *alist;
        struct prefix_list *plist;
        // struct route_map *routemap;
-       struct eigrp *e;
 
        /* if no interface address is present, set list to eigrp process struct
         */
-       e = eigrp_lookup();
-       assert(e != NULL);
 
        /* Check if distribute-list was set for process or interface */
        if (!dist->ifname) {
@@ -174,7 +172,7 @@ void eigrp_distribute_update(struct distribute_ctx *ctx,
                return;
        }
 
-       ifp = if_lookup_by_name(dist->ifname, VRF_DEFAULT);
+       ifp = if_lookup_by_name(dist->ifname, e->vrf_id);
        if (ifp == NULL)
                return;
 
@@ -288,7 +286,7 @@ void eigrp_distribute_update_interface(struct interface *ifp)
        struct distribute *dist;
        struct eigrp *eigrp;
 
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_lookup(ifp->vrf_id);
        if (!eigrp)
                return;
        dist = distribute_lookup(eigrp->distribute_ctx, ifp->name);
@@ -302,11 +300,13 @@ void eigrp_distribute_update_interface(struct interface *ifp)
  */
 void eigrp_distribute_update_all(struct prefix_list *notused)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct vrf *vrf;
        struct interface *ifp;
 
-       FOR_ALL_INTERFACES (vrf, ifp)
-               eigrp_distribute_update_interface(ifp);
+       RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+               FOR_ALL_INTERFACES (vrf, ifp)
+                       eigrp_distribute_update_interface(ifp);
+       }
 }
 
 /*
index 34d00ecc133d0dd40f8f63f857269e145b0fa84e..03f45cedbf555671a872c08ea0e1d3b0c9a68c9b 100644 (file)
 
 extern void eigrp_distribute_update(struct distribute_ctx *ctx,
                                    struct distribute *dist);
-extern void eigrp_distribute_update_interface(struct interface *);
-extern void eigrp_distribute_update_all(struct prefix_list *);
-extern void eigrp_distribute_update_all_wrapper(struct access_list *);
-extern int eigrp_distribute_timer_process(struct thread *);
-extern int eigrp_distribute_timer_interface(struct thread *);
+extern void eigrp_distribute_update_interface(struct interface *ifp);
+extern void eigrp_distribute_update_all(struct prefix_list *plist);
+extern void eigrp_distribute_update_all_wrapper(struct access_list *alist);
+extern int eigrp_distribute_timer_process(struct thread *thread);
+extern int eigrp_distribute_timer_interface(struct thread *thread);
 
 #endif /* EIGRPD_EIGRP_FILTER_H_ */
index 4d6d73e20215df475c73c079cafc29bc935d6a91..cc6d47f488e1307c36a6ac5b1cfa1703c0349896 100644 (file)
@@ -445,7 +445,7 @@ int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg)
        prefix->rdistance = prefix->distance = prefix->fdistance = ne->distance;
        prefix->reported_metric = ne->total_metric;
 
-       if (eigrp_nbr_count_get()) {
+       if (eigrp_nbr_count_get(eigrp)) {
                prefix->req_action |= EIGRP_FSM_NEED_QUERY;
                listnode_add(eigrp->topology_changes_internalIPV4, prefix);
        } else {
@@ -471,7 +471,7 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
        prefix->state = EIGRP_FSM_STATE_ACTIVE_3;
        prefix->rdistance = prefix->distance = prefix->fdistance = ne->distance;
        prefix->reported_metric = ne->total_metric;
-       if (eigrp_nbr_count_get()) {
+       if (eigrp_nbr_count_get(eigrp)) {
                prefix->req_action |= EIGRP_FSM_NEED_QUERY;
                listnode_add(eigrp->topology_changes_internalIPV4, prefix);
        } else {
@@ -486,7 +486,7 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
 
 int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
 {
-       struct eigrp *eigrp;
+       struct eigrp *eigrp = msg->eigrp;
        struct eigrp_prefix_entry *prefix = msg->prefix;
        struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
 
@@ -499,13 +499,11 @@ int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
                        if (msg->packet_type == EIGRP_OPC_QUERY)
                                eigrp_send_reply(msg->adv_router, prefix);
                        prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
-                       eigrp = eigrp_lookup();
-                       assert(eigrp);
                        listnode_add(eigrp->topology_changes_internalIPV4,
                                     prefix);
                }
-               eigrp_topology_update_node_flags(prefix);
-               eigrp_update_routing_table(prefix);
+               eigrp_topology_update_node_flags(eigrp, prefix);
+               eigrp_update_routing_table(eigrp, prefix);
        }
 
        if (msg->packet_type == EIGRP_OPC_QUERY)
@@ -536,9 +534,10 @@ int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
        prefix->state = EIGRP_FSM_STATE_PASSIVE;
        prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
        listnode_add(eigrp->topology_changes_internalIPV4, prefix);
-       eigrp_topology_update_node_flags(prefix);
-       eigrp_update_routing_table(prefix);
-       eigrp_update_topology_table_prefix(eigrp->topology_table, prefix);
+       eigrp_topology_update_node_flags(eigrp, prefix);
+       eigrp_update_routing_table(eigrp, prefix);
+       eigrp_update_topology_table_prefix(eigrp, eigrp->topology_table,
+                                          prefix);
 
        return 1;
 }
@@ -588,9 +587,10 @@ int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
        }
        prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
        listnode_add(eigrp->topology_changes_internalIPV4, prefix);
-       eigrp_topology_update_node_flags(prefix);
-       eigrp_update_routing_table(prefix);
-       eigrp_update_topology_table_prefix(eigrp->topology_table, prefix);
+       eigrp_topology_update_node_flags(eigrp, prefix);
+       eigrp_update_routing_table(eigrp, prefix);
+       eigrp_update_topology_table_prefix(eigrp, eigrp->topology_table,
+                                          prefix);
 
        return 1;
 }
@@ -612,7 +612,7 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
        prefix->rdistance = prefix->distance = best_successor->distance;
        prefix->reported_metric = best_successor->total_metric;
 
-       if (eigrp_nbr_count_get()) {
+       if (eigrp_nbr_count_get(eigrp)) {
                prefix->req_action |= EIGRP_FSM_NEED_QUERY;
                listnode_add(eigrp->topology_changes_internalIPV4, prefix);
        } else {
index dacd5caeb51f4a48f752325e91c1949240bca1bc..6f93cd7b3ef3b76e397857eb853110d6fab133c6 100644 (file)
@@ -147,7 +147,7 @@ eigrp_hello_parameter_decode(struct eigrp_neighbor *nbr,
                        zlog_info("Neighbor %s (%s) is pending: new adjacency",
                                  inet_ntoa(nbr->src),
                                  ifindex2ifname(nbr->ei->ifp->ifindex,
-                                                VRF_DEFAULT));
+                                                eigrp->vrf_id));
 
                        /* Expedited hello sent */
                        eigrp_hello_send(nbr->ei, EIGRP_HELLO_NORMAL, NULL);
@@ -167,7 +167,7 @@ eigrp_hello_parameter_decode(struct eigrp_neighbor *nbr,
                                        "Neighbor %s (%s) is down: Interface PEER-TERMINATION received",
                                        inet_ntoa(nbr->src),
                                        ifindex2ifname(nbr->ei->ifp->ifindex,
-                                                      VRF_DEFAULT));
+                                                      eigrp->vrf_id));
                                eigrp_nbr_delete(nbr);
                                return NULL;
                        } else {
@@ -175,7 +175,7 @@ eigrp_hello_parameter_decode(struct eigrp_neighbor *nbr,
                                        "Neighbor %s (%s) going down: Kvalue mismatch",
                                        inet_ntoa(nbr->src),
                                        ifindex2ifname(nbr->ei->ifp->ifindex,
-                                                      VRF_DEFAULT));
+                                                      eigrp->vrf_id));
                                eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
                        }
                }
@@ -245,6 +245,7 @@ static void eigrp_sw_version_decode(struct eigrp_neighbor *nbr,
 static void eigrp_peer_termination_decode(struct eigrp_neighbor *nbr,
                                          struct eigrp_tlv_hdr_type *tlv)
 {
+       struct eigrp *eigrp = nbr->ei->eigrp;
        struct TLV_Peer_Termination_type *param =
                (struct TLV_Peer_Termination_type *)tlv;
 
@@ -254,7 +255,7 @@ static void eigrp_peer_termination_decode(struct eigrp_neighbor *nbr,
        if (my_ip == received_ip) {
                zlog_info("Neighbor %s (%s) is down: Peer Termination received",
                          inet_ntoa(nbr->src),
-                         ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
+                         ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id));
                /* set neighbor to DOWN */
                nbr->state = EIGRP_NEIGHBOR_DOWN;
                /* delete neighbor */
@@ -330,7 +331,7 @@ void eigrp_hello_receive(struct eigrp *eigrp, struct ip *iph,
 
        if (IS_DEBUG_EIGRP_PACKET(eigrph->opcode - 1, RECV))
                zlog_debug("Processing Hello size[%u] int(%s) nbr(%s)", size,
-                          ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT),
+                          ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id),
                           inet_ntoa(nbr->src));
 
        size -= EIGRP_HEADER_LEN;
@@ -484,21 +485,15 @@ static uint16_t eigrp_tidlist_encode(struct stream *s)
  * Part of conditional receive process
  *
  */
-static uint16_t eigrp_sequence_encode(struct stream *s)
+static uint16_t eigrp_sequence_encode(struct eigrp *eigrp, struct stream *s)
 {
        uint16_t length = EIGRP_TLV_SEQ_BASE_LEN;
-       struct eigrp *eigrp;
        struct eigrp_interface *ei;
        struct listnode *node, *node2, *nnode2;
        struct eigrp_neighbor *nbr;
        size_t backup_end, size_end;
        int found;
 
-       eigrp = eigrp_lookup();
-       if (eigrp == NULL) {
-               return 0;
-       }
-
        // add in the parameters TLV
        backup_end = stream_get_endp(s);
        stream_putw(s, EIGRP_TLV_SEQ);
@@ -541,15 +536,10 @@ static uint16_t eigrp_sequence_encode(struct stream *s)
  * Part of conditional receive process
  *
  */
-static uint16_t eigrp_next_sequence_encode(struct stream *s)
+static uint16_t eigrp_next_sequence_encode(struct eigrp *eigrp,
+                                          struct stream *s)
 {
        uint16_t length = EIGRP_NEXT_SEQUENCE_TLV_SIZE;
-       struct eigrp *eigrp;
-
-       eigrp = eigrp_lookup();
-       if (eigrp == NULL) {
-               return 0;
-       }
 
        // add in the parameters TLV
        stream_putw(s, EIGRP_TLV_NEXT_MCAST_SEQ);
@@ -659,8 +649,8 @@ static struct eigrp_packet *eigrp_hello_encode(struct eigrp_interface *ei,
                length += eigrp_sw_version_encode(ep->s);
 
                if (flags & EIGRP_HELLO_ADD_SEQUENCE) {
-                       length += eigrp_sequence_encode(ep->s);
-                       length += eigrp_next_sequence_encode(ep->s);
+                       length += eigrp_sequence_encode(ei->eigrp, ep->s);
+                       length += eigrp_next_sequence_encode(ei->eigrp, ep->s);
                }
 
                // add in the TID list if doing multi-topology
index c52a98ee2544099996970e76c3c40327e8378956..fd1d3f5cb9e0e1fef680c4665363f2afe762a279 100644 (file)
@@ -206,7 +206,7 @@ int eigrp_if_up(struct eigrp_interface *ei)
                eigrp_prefix_entry_add(eigrp->topology_table, pe);
                listnode_add(eigrp->topology_changes_internalIPV4, pe);
 
-               eigrp_nexthop_entry_add(pe, ne);
+               eigrp_nexthop_entry_add(eigrp, pe, ne);
 
                for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei2)) {
                        eigrp_update_send(ei2);
@@ -218,7 +218,7 @@ int eigrp_if_up(struct eigrp_interface *ei)
                struct eigrp_fsm_action_message msg;
 
                ne->prefix = pe;
-               eigrp_nexthop_entry_add(pe, ne);
+               eigrp_nexthop_entry_add(eigrp, pe, ne);
 
                msg.packet_type = EIGRP_OPC_UPDATE;
                msg.eigrp = eigrp;
@@ -329,10 +329,7 @@ void eigrp_if_free(struct eigrp_interface *ei, int source)
 {
        struct prefix dest_addr;
        struct eigrp_prefix_entry *pe;
-       struct eigrp *eigrp = eigrp_lookup();
-
-       if (!eigrp)
-               return;
+       struct eigrp *eigrp = ei->eigrp;
 
        if (source == INTERFACE_DOWN_BY_VTY) {
                THREAD_OFF(ei->t_hello);
@@ -344,7 +341,7 @@ void eigrp_if_free(struct eigrp_interface *ei, int source)
        pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
                                              &dest_addr);
        if (pe)
-               eigrp_prefix_entry_delete(eigrp->topology_table, pe);
+               eigrp_prefix_entry_delete(eigrp, eigrp->topology_table, pe);
 
        eigrp_if_down(ei);
 
index 1781a881735279f99d1dcc5ea1ef0c4a854d4831..299825dd1ba889a8998c303a380847178da4c148 100644 (file)
@@ -65,6 +65,7 @@
 #include "eigrpd/eigrp_snmp.h"
 #include "eigrpd/eigrp_filter.h"
 #include "eigrpd/eigrp_errors.h"
+#include "eigrpd/eigrp_vrf.h"
 //#include "eigrpd/eigrp_routemap.h"
 
 /* eigprd privileges */
@@ -182,6 +183,7 @@ int main(int argc, char **argv, char **envp)
        master = eigrp_om->master;
 
        eigrp_error_init();
+       eigrp_vrf_init();
        vrf_init(NULL, NULL, NULL, NULL, NULL);
 
        /*EIGRPd init*/
index 66dd5f3419b0dc3d8fc1db1066fe4447e4a648ff..2ae3997fae2fde9ffa4fba782d62b807facfac1c 100644 (file)
@@ -194,13 +194,12 @@ void eigrp_nbr_delete(struct eigrp_neighbor *nbr)
 
 int holddown_timer_expired(struct thread *thread)
 {
-       struct eigrp_neighbor *nbr;
-
-       nbr = THREAD_ARG(thread);
+       struct eigrp_neighbor *nbr = THREAD_ARG(thread);
+       struct eigrp *eigrp = nbr->ei->eigrp;
 
        zlog_info("Neighbor %s (%s) is down: holding time expired",
                  inet_ntoa(nbr->src),
-                 ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
+                 ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id));
        nbr->state = EIGRP_NEIGHBOR_DOWN;
        eigrp_nbr_delete(nbr);
 
@@ -297,19 +296,13 @@ void eigrp_nbr_state_update(struct eigrp_neighbor *nbr)
        }
 }
 
-int eigrp_nbr_count_get(void)
+int eigrp_nbr_count_get(struct eigrp *eigrp)
 {
        struct eigrp_interface *iface;
        struct listnode *node, *node2, *nnode2;
        struct eigrp_neighbor *nbr;
-       struct eigrp *eigrp = eigrp_lookup();
        uint32_t counter;
 
-       if (eigrp == NULL) {
-               zlog_debug("EIGRP Routing Process not enabled");
-               return 0;
-       }
-
        counter = 0;
        for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface)) {
                for (ALL_LIST_ELEMENTS(iface->nbrs, node2, nnode2, nbr)) {
@@ -335,20 +328,16 @@ int eigrp_nbr_count_get(void)
  */
 void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty)
 {
-       if (nbr == NULL) {
-               flog_err(EC_EIGRP_CONFIG,
-                        "Nbr Hard restart: Neighbor not specified.");
-               return;
-       }
+       struct eigrp *eigrp = nbr->ei->eigrp;
 
        zlog_debug("Neighbor %s (%s) is down: manually cleared",
                   inet_ntoa(nbr->src),
-                  ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
+                  ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id));
        if (vty != NULL) {
                vty_time_print(vty, 0);
                vty_out(vty, "Neighbor %s (%s) is down: manually cleared\n",
                        inet_ntoa(nbr->src),
-                       ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
+                       ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id));
        }
 
        /* send Hello with Peer Termination TLV */
index 21a8c6a0042ef074bdfa51c30f7eea528d7edf38..1c308fa981d69de5f53471b371063f827ec7dd12 100644 (file)
 #define _ZEBRA_EIGRP_NEIGHBOR_H
 
 /* Prototypes */
-extern struct eigrp_neighbor *eigrp_nbr_get(struct eigrp_interface *,
-                                           struct eigrp_header *, struct ip *);
-extern struct eigrp_neighbor *eigrp_nbr_new(struct eigrp_interface *);
-extern void eigrp_nbr_delete(struct eigrp_neighbor *);
+extern struct eigrp_neighbor *eigrp_nbr_get(struct eigrp_interface *ei,
+                                           struct eigrp_header *,
+                                           struct ip *addr);
+extern struct eigrp_neighbor *eigrp_nbr_new(struct eigrp_interface *ei);
+extern void eigrp_nbr_delete(struct eigrp_neighbor *neigh);
 
-extern int holddown_timer_expired(struct thread *);
+extern int holddown_timer_expired(struct thread *thread);
 
-extern int eigrp_neighborship_check(struct eigrp_neighbor *,
-                                   struct TLV_Parameter_Type *);
-extern void eigrp_nbr_state_update(struct eigrp_neighbor *);
-extern void eigrp_nbr_state_set(struct eigrp_neighbor *, uint8_t state);
-extern uint8_t eigrp_nbr_state_get(struct eigrp_neighbor *);
-extern int eigrp_nbr_count_get(void);
-extern const char *eigrp_nbr_state_str(struct eigrp_neighbor *);
-extern struct eigrp_neighbor *eigrp_nbr_lookup_by_addr(struct eigrp_interface *,
-                                                      struct in_addr *);
-extern struct eigrp_neighbor *eigrp_nbr_lookup_by_addr_process(struct eigrp *,
-                                                              struct in_addr);
+extern int eigrp_neighborship_check(struct eigrp_neighbor *neigh,
+                                   struct TLV_Parameter_Type *tlv);
+extern void eigrp_nbr_state_update(struct eigrp_neighbor *neigh);
+extern void eigrp_nbr_state_set(struct eigrp_neighbor *neigh, uint8_t state);
+extern uint8_t eigrp_nbr_state_get(struct eigrp_neighbor *neigh);
+extern int eigrp_nbr_count_get(struct eigrp *eigrp);
+extern const char *eigrp_nbr_state_str(struct eigrp_neighbor *neigh);
+extern struct eigrp_neighbor *
+eigrp_nbr_lookup_by_addr(struct eigrp_interface *ei, struct in_addr *addr);
+extern struct eigrp_neighbor *
+eigrp_nbr_lookup_by_addr_process(struct eigrp *eigrp, struct in_addr addr);
 extern void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty);
 
 extern int eigrp_nbr_split_horizon_check(struct eigrp_nexthop_entry *ne,
index bbb9487b4d85f15104d0fc445d80110ecd199d80..c7ffbf9f0eb4489fc7f43047c06f2aab26656152 100644 (file)
@@ -53,7 +53,7 @@ static int eigrp_network_match_iface(const struct prefix *connected_prefix,
 static void eigrp_network_run_interface(struct eigrp *, struct prefix *,
                                        struct interface *);
 
-int eigrp_sock_init(void)
+int eigrp_sock_init(struct vrf *vrf)
 {
        int eigrp_sock;
        int ret;
@@ -61,8 +61,10 @@ int eigrp_sock_init(void)
        int hincl = 1;
 #endif
 
-       frr_elevate_privs(&eigrpd_privs) {
-               eigrp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP);
+       frr_with_privs(&eigrpd_privs) {
+               eigrp_sock = vrf_socket(
+                       AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP, vrf->vrf_id,
+                       vrf->vrf_id != VRF_DEFAULT ? vrf->name : NULL);
                if (eigrp_sock < 0) {
                        zlog_err("eigrp_read_sock_init: socket: %s",
                                 safe_strerror(errno));
@@ -209,7 +211,7 @@ int eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p,
 
 int eigrp_network_set(struct eigrp *eigrp, struct prefix *p)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct vrf *vrf = vrf_lookup_by_id(eigrp->vrf_id);
        struct route_node *rn;
        struct interface *ifp;
 
@@ -290,6 +292,9 @@ void eigrp_if_update(struct interface *ifp)
         * we need to check eac one and add the interface as approperate
         */
        for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) {
+               if (ifp->vrf_id != eigrp->vrf_id)
+                       continue;
+
                /* EIGRP must be on and Router-ID must be configured. */
                if (eigrp->router_id.s_addr == 0)
                        continue;
index b3c76bbecc3416537b4adea3b25f3e7bc06768fa..7839fc946b5e6fd398ed34e0d747c2142986a4db 100644 (file)
@@ -30,7 +30,7 @@
 
 /* Prototypes */
 
-extern int eigrp_sock_init(void);
+extern int eigrp_sock_init(struct vrf *vrf);
 extern int eigrp_if_ipmulticast(struct eigrp *, struct prefix *, unsigned int);
 extern int eigrp_network_set(struct eigrp *eigrp, struct prefix *p);
 extern int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p);
index 5f0c91809ed2efe1ffb07dbb821596bae157286f..4ccce2ebb8c3f0ab9ed4705a5ba745500314d166 100644 (file)
@@ -79,13 +79,18 @@ static int eigrpd_instance_create(enum nb_event event,
                                  union nb_resource *resource)
 {
        struct eigrp *eigrp;
+       const char *vrf;
+       vrf_id_t vrfid;
 
        switch (event) {
        case NB_EV_VALIDATE:
                /* NOTHING */
                break;
        case NB_EV_PREPARE:
-               eigrp = eigrp_get(yang_dnode_get_string(dnode, "./asn"));
+               vrf = yang_dnode_get_string(dnode, "./vrf");
+               vrfid = vrf_name_to_id(vrf);
+
+               eigrp = eigrp_get(yang_dnode_get_uint16(dnode, "./asn"), vrfid);
                resource->ptr = eigrp;
                break;
        case NB_EV_ABORT:
@@ -745,14 +750,17 @@ static int eigrpd_instance_redistribute_create(enum nb_event event,
                                               union nb_resource *resource)
 {
        struct eigrp_metrics metrics;
+       const char *vrfname;
        struct eigrp *eigrp;
        uint32_t proto;
+       vrf_id_t vrfid;
 
        switch (event) {
        case NB_EV_VALIDATE:
                proto = yang_dnode_get_enum(dnode, "./protocol");
-               if (vrf_bitmap_check(zclient->redist[AFI_IP][proto],
-                                    VRF_DEFAULT))
+               vrfname = yang_dnode_get_string(dnode, "../vrf");
+               vrfid = vrf_name_to_id(vrfname);
+               if (vrf_bitmap_check(zclient->redist[AFI_IP][proto], vrfid))
                        return NB_ERR_INCONSISTENCY;
                break;
        case NB_EV_PREPARE:
@@ -1181,7 +1189,8 @@ static int lib_interface_eigrp_instance_create(enum nb_event event,
                        break;
                }
 
-               eigrp = eigrp_get(yang_dnode_get_string(dnode, "./asn"));
+               eigrp = eigrp_get(yang_dnode_get_uint16(dnode, "./asn"),
+                                 ifp->vrf_id);
                eif = eigrp_interface_lookup(eigrp, ifp->name);
                if (eif == NULL)
                        return NB_ERR_INCONSISTENCY;
@@ -1192,7 +1201,8 @@ static int lib_interface_eigrp_instance_create(enum nb_event event,
                break;
        case NB_EV_APPLY:
                ifp = nb_running_get_entry(dnode, NULL, true);
-               eigrp = eigrp_get(yang_dnode_get_string(dnode, "./asn"));
+               eigrp = eigrp_get(yang_dnode_get_uint16(dnode, "./asn"),
+                                 ifp->vrf_id);
                eif = eigrp_interface_lookup(eigrp, ifp->name);
                if (eif == NULL)
                        return NB_ERR_INCONSISTENCY;
index 4efb91e4a033e2230592262c8bb92f5fd5be28a2..ba8271d46e17e92ebefbde9e0ff9a6376dab749f 100644 (file)
@@ -77,11 +77,13 @@ const struct message eigrp_packet_type_str[] = {
 static unsigned char zeropad[16] = {0};
 
 /* Forward function reference*/
-static struct stream *eigrp_recv_packet(int, struct interface **,
-                                       struct stream *);
-static int eigrp_verify_header(struct stream *, struct eigrp_interface *,
-                              struct ip *, struct eigrp_header *);
-static int eigrp_check_network_mask(struct eigrp_interface *, struct in_addr);
+static struct stream *eigrp_recv_packet(struct eigrp *eigrp, int fd,
+                                       struct interface **ifp,
+                                       struct stream *s);
+static int eigrp_verify_header(struct stream *s, struct eigrp_interface *ei,
+                              struct ip *addr, struct eigrp_header *header);
+static int eigrp_check_network_mask(struct eigrp_interface *ei,
+                                   struct in_addr mask);
 
 static int eigrp_retrans_count_exceeded(struct eigrp_packet *ep,
                                        struct eigrp_neighbor *nbr)
@@ -495,7 +497,7 @@ int eigrp_read(struct thread *thread)
        thread_add_read(master, eigrp_read, eigrp, eigrp->fd, &eigrp->t_read);
 
        stream_reset(eigrp->ibuf);
-       if (!(ibuf = eigrp_recv_packet(eigrp->fd, &ifp, eigrp->ibuf))) {
+       if (!(ibuf = eigrp_recv_packet(eigrp, eigrp->fd, &ifp, eigrp->ibuf))) {
                /* This raw packet is known to be at least as big as its IP
                 * header. */
                return -1;
@@ -525,7 +527,7 @@ int eigrp_read(struct thread *thread)
                   ifindex
                   retrieval but do not. */
                c = if_lookup_address((void *)&iph->ip_src, AF_INET,
-                                     VRF_DEFAULT);
+                                     eigrp->vrf_id);
 
                if (c == NULL)
                        return 0;
@@ -706,7 +708,8 @@ int eigrp_read(struct thread *thread)
        return 0;
 }
 
-static struct stream *eigrp_recv_packet(int fd, struct interface **ifp,
+static struct stream *eigrp_recv_packet(struct eigrp *eigrp,
+                                       int fd, struct interface **ifp,
                                        struct stream *ibuf)
 {
        int ret;
@@ -774,7 +777,7 @@ static struct stream *eigrp_recv_packet(int fd, struct interface **ifp,
 
        ifindex = getsockopt_ifindex(AF_INET, &msgh);
 
-       *ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
+       *ifp = if_lookup_by_index(ifindex, eigrp->vrf_id);
 
        if (ret != ip_len) {
                zlog_warn(
index bac7494774a7fe441982d43d9e06bdefc9af193c..d78588644f5cceba071b854bde3266d3fcc6b6c1 100644 (file)
@@ -135,7 +135,8 @@ void eigrp_rmap_update(const char *notused)
 static int eigrp_route_match_add(struct vty *vty, struct route_map_index *index,
                                 const char *command, const char *arg)
 {
-       int ret;
+       enum rmap_compile_rets ret;
+
        ret = route_map_add_match(index, command, arg, type);
        switch (ret) {
        case RMAP_RULE_MISSING:
@@ -147,6 +148,10 @@ static int eigrp_route_match_add(struct vty *vty, struct route_map_index *index,
                return CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
+       case RMAP_DUPLICATE_RULE:
+               /*
+                * Intentionally not handling these cases
+                */
                break;
        }
 
@@ -158,7 +163,8 @@ static int eigrp_route_match_delete(struct vty *vty,
                                    struct route_map_index *index,
                                    const char *command, const char *arg)
 {
-       int ret;
+       enum rmap_compile_rets ret;
+
        ret = route_map_delete_match(index, command, arg);
        switch (ret) {
        case RMAP_RULE_MISSING:
@@ -170,6 +176,10 @@ static int eigrp_route_match_delete(struct vty *vty,
                return CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
+       case RMAP_DUPLICATE_RULE:
+               /*
+                * These cases intentionally ignored
+                */
                break;
        }
 
@@ -180,7 +190,7 @@ static int eigrp_route_match_delete(struct vty *vty,
 static int eigrp_route_set_add(struct vty *vty, struct route_map_index *index,
                               const char *command, const char *arg)
 {
-       int ret;
+       enum rmap_compile_rets ret;
 
        ret = route_map_add_set(index, command, arg);
        switch (ret) {
@@ -201,6 +211,10 @@ static int eigrp_route_set_add(struct vty *vty, struct route_map_index *index,
                }
                break;
        case RMAP_COMPILE_SUCCESS:
+       case RMAP_DUPLICATE_RULE:
+               /*
+                * These cases intentionally left blank here
+                */
                break;
        }
 
@@ -212,7 +226,7 @@ static int eigrp_route_set_delete(struct vty *vty,
                                  struct route_map_index *index,
                                  const char *command, const char *arg)
 {
-       int ret;
+       enum rmap_compile_rets ret;
 
        ret = route_map_delete_set(index, command, arg);
        switch (ret) {
@@ -225,6 +239,10 @@ static int eigrp_route_set_delete(struct vty *vty,
                return CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
+       case RMAP_DUPLICATE_RULE:
+               /*
+                * These cases intentionally not handled
+                */
                break;
        }
 
index 1b9186f0114db654bf31f7f81b45b0be63282451..e50858f0715288b4627a25c052841f91ad81a16f 100644 (file)
@@ -69,6 +69,8 @@ struct eigrp_metrics {
 };
 
 struct eigrp {
+       vrf_id_t vrf_id;
+
        uint16_t AS;     /* Autonomous system number */
        uint16_t vrid;       /* Virtual Router ID */
        uint8_t k_values[6]; /*Array for K values configuration*/
@@ -85,7 +87,7 @@ struct eigrp {
        struct list *eiflist;             /* eigrp interfaces */
        uint8_t passive_interface_default; /* passive-interface default */
 
-       unsigned int fd;
+       int fd;
        unsigned int maxsndbuflen;
 
        uint32_t sequence_number; /*Global EIGRP sequence number*/
index e861cdb333b0538d49b707afad1e0eb20fe0bb2b..9cc612eaf1ef210c98b592bd8b159866185ff82a 100644 (file)
@@ -117,9 +117,9 @@ struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void)
 /*
  * Freeing topology table list
  */
-void eigrp_topology_free(struct route_table *table)
+void eigrp_topology_free(struct eigrp *eigrp, struct route_table *table)
 {
-       eigrp_topology_delete_all(table);
+       eigrp_topology_delete_all(eigrp, table);
        route_table_finish(table);
 }
 
@@ -150,7 +150,8 @@ void eigrp_prefix_entry_add(struct route_table *topology,
 /*
  * Adding topology entry to topology node
  */
-void eigrp_nexthop_entry_add(struct eigrp_prefix_entry *node,
+void eigrp_nexthop_entry_add(struct eigrp *eigrp,
+                            struct eigrp_prefix_entry *node,
                             struct eigrp_nexthop_entry *entry)
 {
        struct list *l = list_new();
@@ -161,7 +162,8 @@ void eigrp_nexthop_entry_add(struct eigrp_prefix_entry *node,
                listnode_add_sort(node->entries, entry);
                entry->prefix = node;
 
-               eigrp_zebra_route_add(node->destination, l, node->fdistance);
+               eigrp_zebra_route_add(eigrp, node->destination,
+                                     l, node->fdistance);
        }
 
        list_delete(&l);
@@ -170,10 +172,9 @@ void eigrp_nexthop_entry_add(struct eigrp_prefix_entry *node,
 /*
  * Deleting topology node from topology table
  */
-void eigrp_prefix_entry_delete(struct route_table *table,
+void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table,
                               struct eigrp_prefix_entry *pe)
 {
-       struct eigrp *eigrp = eigrp_lookup();
        struct eigrp_nexthop_entry *ne;
        struct listnode *node, *nnode;
        struct route_node *rn;
@@ -192,10 +193,10 @@ void eigrp_prefix_entry_delete(struct route_table *table,
        listnode_delete(eigrp->topology_changes_internalIPV4, pe);
 
        for (ALL_LIST_ELEMENTS(pe->entries, node, nnode, ne))
-               eigrp_nexthop_entry_delete(pe, ne);
+               eigrp_nexthop_entry_delete(eigrp, pe, ne);
        list_delete(&pe->entries);
        list_delete(&pe->rij);
-       eigrp_zebra_route_delete(pe->destination);
+       eigrp_zebra_route_delete(eigrp, pe->destination);
        prefix_free(pe->destination);
 
        rn->info = NULL;
@@ -207,12 +208,13 @@ void eigrp_prefix_entry_delete(struct route_table *table,
 /*
  * Deleting topology entry from topology node
  */
-void eigrp_nexthop_entry_delete(struct eigrp_prefix_entry *node,
+void eigrp_nexthop_entry_delete(struct eigrp *eigrp,
+                               struct eigrp_prefix_entry *node,
                                struct eigrp_nexthop_entry *entry)
 {
        if (listnode_lookup(node->entries, entry) != NULL) {
                listnode_delete(node->entries, entry);
-               eigrp_zebra_route_delete(node->destination);
+               eigrp_zebra_route_delete(eigrp, node->destination);
                XFREE(MTYPE_EIGRP_NEXTHOP_ENTRY, entry);
        }
 }
@@ -220,7 +222,8 @@ void eigrp_nexthop_entry_delete(struct eigrp_prefix_entry *node,
 /*
  * Deleting all nodes from topology table
  */
-void eigrp_topology_delete_all(struct route_table *topology)
+void eigrp_topology_delete_all(struct eigrp *eigrp,
+                              struct route_table *topology)
 {
        struct route_node *rn;
        struct eigrp_prefix_entry *pe;
@@ -231,7 +234,7 @@ void eigrp_topology_delete_all(struct route_table *topology)
                if (!pe)
                        continue;
 
-               eigrp_prefix_entry_delete(topology, pe);
+               eigrp_prefix_entry_delete(eigrp, topology, pe);
        }
 }
 
@@ -426,17 +429,15 @@ void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
                if (!pe)
                        continue;
 
-               eigrp_topology_update_node_flags(pe);
+               eigrp_topology_update_node_flags(eigrp, pe);
        }
 }
 
-void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest)
+void eigrp_topology_update_node_flags(struct eigrp *eigrp,
+                                     struct eigrp_prefix_entry *dest)
 {
        struct listnode *node;
        struct eigrp_nexthop_entry *entry;
-       struct eigrp *eigrp = eigrp_lookup();
-
-       assert(eigrp);
 
        for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) {
                if (entry->reported_distance < dest->fdistance) {
@@ -464,27 +465,24 @@ void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest)
        }
 }
 
-void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix)
+void eigrp_update_routing_table(struct eigrp *eigrp,
+                               struct eigrp_prefix_entry *prefix)
 {
-       struct eigrp *eigrp = eigrp_lookup();
        struct list *successors;
        struct listnode *node;
        struct eigrp_nexthop_entry *entry;
 
-       if (!eigrp)
-               return;
-
        successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
 
        if (successors) {
-               eigrp_zebra_route_add(prefix->destination, successors,
+               eigrp_zebra_route_add(eigrp, prefix->destination, successors,
                                      prefix->fdistance);
                for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
                        entry->flags |= EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
 
                list_delete(&successors);
        } else {
-               eigrp_zebra_route_delete(prefix->destination);
+               eigrp_zebra_route_delete(eigrp, prefix->destination);
                for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry))
                        entry->flags &= ~EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
        }
@@ -525,7 +523,8 @@ void eigrp_topology_neighbor_down(struct eigrp *eigrp,
        eigrp_update_send_all(eigrp, nbr->ei);
 }
 
-void eigrp_update_topology_table_prefix(struct route_table *table,
+void eigrp_update_topology_table_prefix(struct eigrp *eigrp,
+                                       struct route_table *table,
                                        struct eigrp_prefix_entry *prefix)
 {
        struct listnode *node1, *node2;
@@ -533,11 +532,11 @@ void eigrp_update_topology_table_prefix(struct route_table *table,
        struct eigrp_nexthop_entry *entry;
        for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry)) {
                if (entry->distance == EIGRP_MAX_METRIC) {
-                       eigrp_nexthop_entry_delete(prefix, entry);
+                       eigrp_nexthop_entry_delete(eigrp, prefix, entry);
                }
        }
        if (prefix->distance == EIGRP_MAX_METRIC
            && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED) {
-               eigrp_prefix_entry_delete(table, prefix);
+               eigrp_prefix_entry_delete(eigrp, table, prefix);
        }
 }
index 16bf2261ccb9484e576b6ff5ae51de56f80f1086..718cece40383ad9e814b18106982ea5d26b39b46 100644 (file)
@@ -37,34 +37,41 @@ extern struct route_table *eigrp_topology_new(void);
 extern void eigrp_topology_init(struct route_table *table);
 extern struct eigrp_prefix_entry *eigrp_prefix_entry_new(void);
 extern struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void);
-extern void eigrp_topology_free(struct route_table *table);
+extern void eigrp_topology_free(struct eigrp *eigrp, struct route_table *table);
 extern void eigrp_prefix_entry_add(struct route_table *table,
                                   struct eigrp_prefix_entry *pe);
-extern void eigrp_nexthop_entry_add(struct eigrp_prefix_entry *,
-                                   struct eigrp_nexthop_entry *);
-extern void eigrp_prefix_entry_delete(struct route_table *table,
+extern void eigrp_nexthop_entry_add(struct eigrp *eigrp,
+                                   struct eigrp_prefix_entry *pe,
+                                   struct eigrp_nexthop_entry *ne);
+extern void eigrp_prefix_entry_delete(struct eigrp *eigrp,
+                                     struct route_table *table,
                                      struct eigrp_prefix_entry *pe);
-extern void eigrp_nexthop_entry_delete(struct eigrp_prefix_entry *,
-                                      struct eigrp_nexthop_entry *);
-extern void eigrp_topology_delete_all(struct route_table *table);
+extern void eigrp_nexthop_entry_delete(struct eigrp *eigrp,
+                                      struct eigrp_prefix_entry *pe,
+                                      struct eigrp_nexthop_entry *ne);
+extern void eigrp_topology_delete_all(struct eigrp *eigrp,
+                                     struct route_table *table);
 extern struct eigrp_prefix_entry *
 eigrp_topology_table_lookup_ipv4(struct route_table *table, struct prefix *p);
-extern struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *);
+extern struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *pe);
 extern struct list *
 eigrp_topology_get_successor_max(struct eigrp_prefix_entry *pe,
                                 unsigned int maxpaths);
 extern struct eigrp_nexthop_entry *
-eigrp_prefix_entry_lookup(struct list *, struct eigrp_neighbor *);
-extern struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *,
-                                                  struct eigrp_neighbor *);
-extern void eigrp_topology_update_all_node_flags(struct eigrp *);
-extern void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *);
+eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *neigh);
+extern struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp,
+                                                  struct eigrp_neighbor *n);
+extern void eigrp_topology_update_all_node_flags(struct eigrp *eigrp);
+extern void eigrp_topology_update_node_flags(struct eigrp *eigrp,
+                                            struct eigrp_prefix_entry *pe);
 extern enum metric_change
-eigrp_topology_update_distance(struct eigrp_fsm_action_message *);
-extern void eigrp_update_routing_table(struct eigrp_prefix_entry *);
-extern void eigrp_topology_neighbor_down(struct eigrp *,
-                                        struct eigrp_neighbor *);
-extern void eigrp_update_topology_table_prefix(struct route_table *table,
+eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg);
+extern void eigrp_update_routing_table(struct eigrp *eigrp,
+                                      struct eigrp_prefix_entry *pe);
+extern void eigrp_topology_neighbor_down(struct eigrp *eigrp,
+                                        struct eigrp_neighbor *neigh);
+extern void eigrp_update_topology_table_prefix(struct eigrp *eigrp,
+                                              struct route_table *table,
                                               struct eigrp_prefix_entry *pe);
 
 #endif
index 8db4903077f466ca404ec65874dc1995256829bf..6e2a81e32a07ce94be8a461040cec07a7bf779d2 100644 (file)
@@ -211,7 +211,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
                zlog_debug(
                        "Processing Update size[%u] int(%s) nbr(%s) seq [%u] flags [%0x]",
                        size,
-                       ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT),
+                       ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id),
                        inet_ntoa(nbr->src), nbr->recv_sequence_number, flags);
 
 
@@ -221,7 +221,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
 
                zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
                          inet_ntoa(nbr->src),
-                         ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
+                         ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id));
 
                /* get all prefixes from neighbor from topology table */
                nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
@@ -233,7 +233,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
 
                zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
                          inet_ntoa(nbr->src),
-                         ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
+                         ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id));
 
                /* get all prefixes from neighbor from topology table */
                nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
@@ -282,12 +282,12 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
                        zlog_info("Neighbor %s (%s) is down: peer restarted",
                                  inet_ntoa(nbr->src),
                                  ifindex2ifname(nbr->ei->ifp->ifindex,
-                                                VRF_DEFAULT));
+                                                eigrp->vrf_id));
                        eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING);
                        zlog_info("Neighbor %s (%s) is pending: new adjacency",
                                  inet_ntoa(nbr->src),
                                  ifindex2ifname(nbr->ei->ifp->ifindex,
-                                                VRF_DEFAULT));
+                                                eigrp->vrf_id));
                        eigrp_update_send_init(nbr);
                }
        }
@@ -366,11 +366,11 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
 
                                eigrp_prefix_entry_add(eigrp->topology_table,
                                                       pe);
-                               eigrp_nexthop_entry_add(pe, ne);
+                               eigrp_nexthop_entry_add(eigrp, pe, ne);
                                pe->distance = pe->fdistance = pe->rdistance =
                                        ne->distance;
                                pe->reported_metric = ne->total_metric;
-                               eigrp_topology_update_node_flags(pe);
+                               eigrp_topology_update_node_flags(eigrp, pe);
 
                                pe->req_action |= EIGRP_FSM_NEED_UPDATE;
                                listnode_add(
@@ -965,19 +965,20 @@ void eigrp_update_send_GR(struct eigrp_neighbor *nbr, enum GR_type gr_type,
                zlog_info(
                        "Neighbor %s (%s) is resync: route configuration changed",
                        inet_ntoa(nbr->src),
-                       ifindex2ifname(ei->ifp->ifindex, VRF_DEFAULT));
+                       ifindex2ifname(ei->ifp->ifindex, eigrp->vrf_id));
        } else if (gr_type == EIGRP_GR_MANUAL) {
                /* Graceful restart was called manually */
                zlog_info("Neighbor %s (%s) is resync: manually cleared",
                          inet_ntoa(nbr->src),
-                         ifindex2ifname(ei->ifp->ifindex, VRF_DEFAULT));
+                         ifindex2ifname(ei->ifp->ifindex, eigrp->vrf_id));
 
                if (vty != NULL) {
                        vty_time_print(vty, 0);
                        vty_out(vty,
                                "Neighbor %s (%s) is resync: manually cleared\n",
                                inet_ntoa(nbr->src),
-                               ifindex2ifname(ei->ifp->ifindex, VRF_DEFAULT));
+                               ifindex2ifname(ei->ifp->ifindex,
+                                              eigrp->vrf_id));
                }
        }
 
diff --git a/eigrpd/eigrp_vrf.c b/eigrpd/eigrp_vrf.c
new file mode 100644 (file)
index 0000000..c8c8491
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * eigrp - vrf code
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * 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 "vrf.h"
+
+#include "eigrpd/eigrp_vrf.h"
+
+static int eigrp_vrf_new(struct vrf *vrf)
+{
+       return 0;
+}
+
+static int eigrp_vrf_enable(struct vrf *vrf)
+{
+       return 0;
+}
+
+static int eigrp_vrf_disable(struct vrf *vrf)
+{
+       return 0;
+}
+
+static int eigrp_vrf_delete(struct vrf *vrf)
+{
+       return 0;
+}
+
+void eigrp_vrf_init(void)
+{
+       vrf_init(eigrp_vrf_new, eigrp_vrf_enable,
+                eigrp_vrf_disable, eigrp_vrf_delete, NULL);
+}
diff --git a/eigrpd/eigrp_vrf.h b/eigrpd/eigrp_vrf.h
new file mode 100644 (file)
index 0000000..423a4be
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * eigrp - vrf code
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ *               Donald Sharp
+ *
+ * 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 __EIGRP_VRF_H__
+
+extern void eigrp_vrf_init(void);
+#endif
index 207622e659a6d4ee663cc35f673a358637f8665d..e4a499425b832883c66a3b565f679575a190b44d 100644 (file)
@@ -83,12 +83,31 @@ static void eigrp_vty_display_prefix_entry(struct vty *vty,
        }
 }
 
+static struct eigrp *eigrp_vty_get_eigrp(struct vty *vty, const char *vrf_name)
+{
+       struct vrf *vrf;
+
+       if (vrf_name)
+               vrf = vrf_lookup_by_name(vrf_name);
+       else
+               vrf = vrf_lookup_by_id(VRF_DEFAULT);
+
+       if (!vrf) {
+               vty_out(vty, "VRF %s specified does not exist",
+                       vrf_name ? vrf_name : VRF_DEFAULT_NAME);
+               return NULL;
+       }
+
+       return eigrp_lookup(vrf->vrf_id);
+}
+
 DEFPY (show_ip_eigrp_topology_all,
        show_ip_eigrp_topology_all_cmd,
-       "show ip eigrp topology [all-links$all]",
+       "show ip eigrp [vrf NAME] topology [all-links$all]",
        SHOW_STR
        IP_STR
        "IP-EIGRP show commands\n"
+       VRF_CMD_HELP_STR
        "IP-EIGRP topology\n"
        "Show all links in topology table\n")
 {
@@ -96,7 +115,7 @@ DEFPY (show_ip_eigrp_topology_all,
        struct eigrp_prefix_entry *tn;
        struct route_node *rn;
 
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_vty_get_eigrp(vty, vrf);
        if (eigrp == NULL) {
                vty_out(vty, " EIGRP Routing Process not enabled\n");
                return CMD_SUCCESS;
@@ -119,10 +138,11 @@ DEFPY (show_ip_eigrp_topology_all,
 
 DEFPY (show_ip_eigrp_topology,
        show_ip_eigrp_topology_cmd,
-       "show ip eigrp topology <A.B.C.D$address|A.B.C.D/M$prefix>",
+       "show ip eigrp [vrf NAME] topology <A.B.C.D$address|A.B.C.D/M$prefix>",
        SHOW_STR
        IP_STR
        "IP-EIGRP show commands\n"
+       VRF_CMD_HELP_STR
        "IP-EIGRP topology\n"
        "For a specific address\n"
        "For a specific prefix\n")
@@ -132,7 +152,7 @@ DEFPY (show_ip_eigrp_topology,
        struct route_node *rn;
        struct prefix cmp;
 
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_vty_get_eigrp(vty, vrf);
        if (eigrp == NULL) {
                vty_out(vty, " EIGRP Routing Process not enabled\n");
                return CMD_SUCCESS;
@@ -167,12 +187,13 @@ DEFPY (show_ip_eigrp_topology,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_ip_eigrp_interfaces,
+DEFPY (show_ip_eigrp_interfaces,
        show_ip_eigrp_interfaces_cmd,
-       "show ip eigrp interfaces [IFNAME] [detail]",
+       "show ip eigrp [vrf NAME] interfaces [IFNAME] [detail]$detail",
        SHOW_STR
        IP_STR
        "IP-EIGRP show commands\n"
+       VRF_CMD_HELP_STR
        "IP-EIGRP interfaces\n"
        "Interface name to look at\n"
        "Detailed information\n")
@@ -180,22 +201,13 @@ DEFUN (show_ip_eigrp_interfaces,
        struct eigrp_interface *ei;
        struct eigrp *eigrp;
        struct listnode *node;
-       int idx = 0;
-       bool detail = false;
-       const char *ifname = NULL;
 
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_vty_get_eigrp(vty, vrf);
        if (eigrp == NULL) {
                vty_out(vty, "EIGRP Routing Process not enabled\n");
                return CMD_SUCCESS;
        }
 
-       if (argv_find(argv, argc, "IFNAME", &idx))
-               ifname = argv[idx]->arg;
-
-       if (argv_find(argv, argc, "detail", &idx))
-               detail = true;
-
        if (!ifname)
                show_ip_eigrp_interface_header(vty, eigrp);
 
@@ -210,12 +222,13 @@ DEFUN (show_ip_eigrp_interfaces,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_ip_eigrp_neighbors,
+DEFPY (show_ip_eigrp_neighbors,
        show_ip_eigrp_neighbors_cmd,
-       "show ip eigrp neighbors [IFNAME] [detail]",
+       "show ip eigrp [vrf NAME] neighbors [IFNAME] [detail]$detail",
        SHOW_STR
        IP_STR
        "IP-EIGRP show commands\n"
+       VRF_CMD_HELP_STR
        "IP-EIGRP neighbors\n"
        "Interface to show on\n"
        "Detailed Information\n")
@@ -224,21 +237,13 @@ DEFUN (show_ip_eigrp_neighbors,
        struct eigrp_interface *ei;
        struct listnode *node, *node2, *nnode2;
        struct eigrp_neighbor *nbr;
-       bool detail = false;
-       int idx = 0;
-       const char *ifname = NULL;
 
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_vty_get_eigrp(vty, vrf);
        if (eigrp == NULL) {
                vty_out(vty, " EIGRP Routing Process not enabled\n");
                return CMD_SUCCESS;
        }
 
-       if (argv_find(argv, argc, "IFNAME", &idx))
-               ifname = argv[idx]->arg;
-
-       detail = (argv_find(argv, argc, "detail", &idx));
-
        show_ip_eigrp_neighbor_header(vty, eigrp);
 
        for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) {
@@ -246,7 +251,7 @@ DEFUN (show_ip_eigrp_neighbors,
                        for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr)) {
                                if (detail || (nbr->state == EIGRP_NEIGHBOR_UP))
                                        show_ip_eigrp_neighbor_sub(vty, nbr,
-                                                                  detail);
+                                                                  !!detail);
                        }
                }
        }
@@ -257,12 +262,13 @@ DEFUN (show_ip_eigrp_neighbors,
 /*
  * Execute hard restart for all neighbors
  */
-DEFUN (clear_ip_eigrp_neighbors,
+DEFPY (clear_ip_eigrp_neighbors,
        clear_ip_eigrp_neighbors_cmd,
-       "clear ip eigrp neighbors",
+       "clear ip eigrp [vrf NAME] neighbors",
        CLEAR_STR
        IP_STR
        "Clear IP-EIGRP\n"
+       VRF_CMD_HELP_STR
        "Clear IP-EIGRP neighbors\n")
 {
        struct eigrp *eigrp;
@@ -271,7 +277,7 @@ DEFUN (clear_ip_eigrp_neighbors,
        struct eigrp_neighbor *nbr;
 
        /* Check if eigrp process is enabled */
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_vty_get_eigrp(vty, vrf);
        if (eigrp == NULL) {
                vty_out(vty, " EIGRP Routing Process not enabled\n");
                return CMD_SUCCESS;
@@ -289,13 +295,13 @@ DEFUN (clear_ip_eigrp_neighbors,
                                        "Neighbor %s (%s) is down: manually cleared",
                                        inet_ntoa(nbr->src),
                                        ifindex2ifname(nbr->ei->ifp->ifindex,
-                                                      VRF_DEFAULT));
+                                                      eigrp->vrf_id));
                                vty_time_print(vty, 0);
                                vty_out(vty,
                                        "Neighbor %s (%s) is down: manually cleared\n",
                                        inet_ntoa(nbr->src),
                                        ifindex2ifname(nbr->ei->ifp->ifindex,
-                                                      VRF_DEFAULT));
+                                                      eigrp->vrf_id));
 
                                /* set neighbor to DOWN */
                                nbr->state = EIGRP_NEIGHBOR_DOWN;
@@ -311,12 +317,13 @@ DEFUN (clear_ip_eigrp_neighbors,
 /*
  * Execute hard restart for all neighbors on interface
  */
-DEFUN (clear_ip_eigrp_neighbors_int,
+DEFPY (clear_ip_eigrp_neighbors_int,
        clear_ip_eigrp_neighbors_int_cmd,
-       "clear ip eigrp neighbors IFNAME",
+       "clear ip eigrp [vrf NAME] neighbors IFNAME",
        CLEAR_STR
        IP_STR
        "Clear IP-EIGRP\n"
+       VRF_CMD_HELP_STR
        "Clear IP-EIGRP neighbors\n"
        "Interface's name\n")
 {
@@ -324,20 +331,18 @@ DEFUN (clear_ip_eigrp_neighbors_int,
        struct eigrp_interface *ei;
        struct listnode *node2, *nnode2;
        struct eigrp_neighbor *nbr;
-       int idx = 0;
 
        /* Check if eigrp process is enabled */
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_vty_get_eigrp(vty, vrf);
        if (eigrp == NULL) {
                vty_out(vty, " EIGRP Routing Process not enabled\n");
                return CMD_SUCCESS;
        }
 
        /* lookup interface by specified name */
-       argv_find(argv, argc, "IFNAME", &idx);
-       ei = eigrp_if_lookup_by_name(eigrp, argv[idx]->arg);
+       ei = eigrp_if_lookup_by_name(eigrp, ifname);
        if (ei == NULL) {
-               vty_out(vty, " Interface (%s) doesn't exist\n", argv[idx]->arg);
+               vty_out(vty, " Interface (%s) doesn't exist\n", ifname);
                return CMD_WARNING;
        }
 
@@ -350,13 +355,13 @@ DEFUN (clear_ip_eigrp_neighbors_int,
                        zlog_debug("Neighbor %s (%s) is down: manually cleared",
                                   inet_ntoa(nbr->src),
                                   ifindex2ifname(nbr->ei->ifp->ifindex,
-                                                 VRF_DEFAULT));
+                                                 eigrp->vrf_id));
                        vty_time_print(vty, 0);
                        vty_out(vty,
                                "Neighbor %s (%s) is down: manually cleared\n",
                                inet_ntoa(nbr->src),
                                ifindex2ifname(nbr->ei->ifp->ifindex,
-                                              VRF_DEFAULT));
+                                              eigrp->vrf_id));
 
                        /* set neighbor to DOWN */
                        nbr->state = EIGRP_NEIGHBOR_DOWN;
@@ -371,26 +376,21 @@ DEFUN (clear_ip_eigrp_neighbors_int,
 /*
  * Execute hard restart for neighbor specified by IP
  */
-DEFUN (clear_ip_eigrp_neighbors_IP,
+DEFPY (clear_ip_eigrp_neighbors_IP,
        clear_ip_eigrp_neighbors_IP_cmd,
-       "clear ip eigrp neighbors A.B.C.D",
+       "clear ip eigrp [vrf NAME] neighbors A.B.C.D$nbr_addr",
        CLEAR_STR
        IP_STR
        "Clear IP-EIGRP\n"
+       VRF_CMD_HELP_STR
        "Clear IP-EIGRP neighbors\n"
        "IP-EIGRP neighbor address\n")
 {
        struct eigrp *eigrp;
        struct eigrp_neighbor *nbr;
-       struct in_addr nbr_addr;
-
-       if (!inet_aton(argv[4]->arg, &nbr_addr)) {
-               vty_out(vty, "Unable to parse %s", argv[4]->arg);
-               return CMD_WARNING;
-       }
 
        /* Check if eigrp process is enabled */
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_vty_get_eigrp(vty, vrf);
        if (eigrp == NULL) {
                vty_out(vty, " EIGRP Routing Process not enabled\n");
                return CMD_SUCCESS;
@@ -414,19 +414,20 @@ DEFUN (clear_ip_eigrp_neighbors_IP,
 /*
  * Execute graceful restart for all neighbors
  */
-DEFUN (clear_ip_eigrp_neighbors_soft,
+DEFPY (clear_ip_eigrp_neighbors_soft,
        clear_ip_eigrp_neighbors_soft_cmd,
-       "clear ip eigrp neighbors soft",
+       "clear ip eigrp [vrf NAME] neighbors soft",
        CLEAR_STR
        IP_STR
        "Clear IP-EIGRP\n"
+       VRF_CMD_HELP_STR
        "Clear IP-EIGRP neighbors\n"
        "Resync with peers without adjacency reset\n")
 {
        struct eigrp *eigrp;
 
        /* Check if eigrp process is enabled */
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_vty_get_eigrp(vty, vrf);
        if (eigrp == NULL) {
                vty_out(vty, " EIGRP Routing Process not enabled\n");
                return CMD_SUCCESS;
@@ -441,12 +442,13 @@ DEFUN (clear_ip_eigrp_neighbors_soft,
 /*
  * Execute graceful restart for all neighbors on interface
  */
-DEFUN (clear_ip_eigrp_neighbors_int_soft,
+DEFPY (clear_ip_eigrp_neighbors_int_soft,
        clear_ip_eigrp_neighbors_int_soft_cmd,
-       "clear ip eigrp neighbors IFNAME soft",
+       "clear ip eigrp [vrf NAME] neighbors IFNAME soft",
        CLEAR_STR
        IP_STR
        "Clear IP-EIGRP\n"
+       VRF_CMD_HELP_STR
        "Clear IP-EIGRP neighbors\n"
        "Interface's name\n"
        "Resync with peer without adjacency reset\n")
@@ -455,14 +457,14 @@ DEFUN (clear_ip_eigrp_neighbors_int_soft,
        struct eigrp_interface *ei;
 
        /* Check if eigrp process is enabled */
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_vty_get_eigrp(vty, vrf);
        if (eigrp == NULL) {
                vty_out(vty, " EIGRP Routing Process not enabled\n");
                return CMD_SUCCESS;
        }
 
        /* lookup interface by specified name */
-       ei = eigrp_if_lookup_by_name(eigrp, argv[4]->arg);
+       ei = eigrp_if_lookup_by_name(eigrp, ifname);
        if (ei == NULL) {
                vty_out(vty, " Interface (%s) doesn't exist\n", argv[4]->arg);
                return CMD_WARNING;
@@ -476,27 +478,23 @@ DEFUN (clear_ip_eigrp_neighbors_int_soft,
 /*
  * Execute graceful restart for neighbor specified by IP
  */
-DEFUN (clear_ip_eigrp_neighbors_IP_soft,
+DEFPY (clear_ip_eigrp_neighbors_IP_soft,
        clear_ip_eigrp_neighbors_IP_soft_cmd,
-       "clear ip eigrp neighbors A.B.C.D soft",
+       "clear ip eigrp [vrf NAME] neighbors A.B.C.D$nbr_addr soft",
        CLEAR_STR
        IP_STR
        "Clear IP-EIGRP\n"
+       VRF_CMD_HELP_STR
        "Clear IP-EIGRP neighbors\n"
        "IP-EIGRP neighbor address\n"
        "Resync with peer without adjacency reset\n")
 {
        struct eigrp *eigrp;
        struct eigrp_neighbor *nbr;
-       struct in_addr nbr_addr;
 
-       if (!inet_aton(argv[4]->arg, &nbr_addr)) {
-               vty_out(vty, "Unable to parse: %s", argv[4]->arg);
-               return CMD_WARNING;
-       }
 
        /* Check if eigrp process is enabled */
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_vty_get_eigrp(vty, vrf);
        if (eigrp == NULL) {
                vty_out(vty, " EIGRP Routing Process not enabled\n");
                return CMD_SUCCESS;
index 0a74e86263a320f1b65ec76a23cef07e9e186409..63cbe84ef21ea4558a0880fe476715085d376e55 100644 (file)
@@ -59,7 +59,8 @@ static int eigrp_interface_address_add(ZAPI_CALLBACK_ARGS);
 static int eigrp_interface_address_delete(ZAPI_CALLBACK_ARGS);
 static int eigrp_interface_state_up(ZAPI_CALLBACK_ARGS);
 static int eigrp_interface_state_down(ZAPI_CALLBACK_ARGS);
-static struct interface *zebra_interface_if_lookup(struct stream *);
+static struct interface *zebra_interface_if_lookup(struct stream *,
+                                                  vrf_id_t vrf_id);
 
 static int eigrp_zebra_read_route(ZAPI_CALLBACK_ARGS);
 
@@ -79,7 +80,7 @@ static int eigrp_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
 
        router_id_zebra = router_id.u.prefix4;
 
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_lookup(vrf_id);
 
        if (eigrp != NULL)
                eigrp_router_id_update(eigrp);
@@ -137,7 +138,7 @@ static int eigrp_zebra_read_route(ZAPI_CALLBACK_ARGS)
        if (IPV4_NET127(ntohl(api.prefix.u.prefix4.s_addr)))
                return 0;
 
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_lookup(vrf_id);
        if (eigrp == NULL)
                return 0;
 
@@ -257,7 +258,7 @@ static int eigrp_interface_state_up(ZAPI_CALLBACK_ARGS)
 {
        struct interface *ifp;
 
-       ifp = zebra_interface_if_lookup(zclient->ibuf);
+       ifp = zebra_interface_if_lookup(zclient->ibuf, vrf_id);
 
        if (ifp == NULL)
                return 0;
@@ -328,7 +329,8 @@ static int eigrp_interface_state_down(ZAPI_CALLBACK_ARGS)
        return 0;
 }
 
-static struct interface *zebra_interface_if_lookup(struct stream *s)
+static struct interface *zebra_interface_if_lookup(struct stream *s,
+                                                  vrf_id_t vrf_id)
 {
        char ifname_tmp[INTERFACE_NAMSIZ];
 
@@ -336,11 +338,11 @@ static struct interface *zebra_interface_if_lookup(struct stream *s)
        stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
 
        /* And look it up. */
-       return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
+       return if_lookup_by_name(ifname_tmp, vrf_id);
 }
 
-void eigrp_zebra_route_add(struct prefix *p, struct list *successors,
-                          uint32_t distance)
+void eigrp_zebra_route_add(struct eigrp *eigrp, struct prefix *p,
+                          struct list *successors, uint32_t distance)
 {
        struct zapi_route api;
        struct zapi_nexthop *api_nh;
@@ -352,7 +354,7 @@ void eigrp_zebra_route_add(struct prefix *p, struct list *successors,
                return;
 
        memset(&api, 0, sizeof(api));
-       api.vrf_id = VRF_DEFAULT;
+       api.vrf_id = eigrp->vrf_id;
        api.type = ZEBRA_ROUTE_EIGRP;
        api.safi = SAFI_UNICAST;
        api.metric = distance;
@@ -366,7 +368,7 @@ void eigrp_zebra_route_add(struct prefix *p, struct list *successors,
                if (count >= MULTIPATH_NUM)
                        break;
                api_nh = &api.nexthops[count];
-               api_nh->vrf_id = VRF_DEFAULT;
+               api_nh->vrf_id = eigrp->vrf_id;
                if (te->adv_router->src.s_addr) {
                        api_nh->gate.ipv4 = te->adv_router->src;
                        api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
@@ -388,7 +390,7 @@ void eigrp_zebra_route_add(struct prefix *p, struct list *successors,
        zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
 }
 
-void eigrp_zebra_route_delete(struct prefix *p)
+void eigrp_zebra_route_delete(struct eigrp *eigrp, struct prefix *p)
 {
        struct zapi_route api;
 
@@ -396,7 +398,7 @@ void eigrp_zebra_route_delete(struct prefix *p)
                return;
 
        memset(&api, 0, sizeof(api));
-       api.vrf_id = VRF_DEFAULT;
+       api.vrf_id = eigrp->vrf_id;
        api.type = ZEBRA_ROUTE_EIGRP;
        api.safi = SAFI_UNICAST;
        memcpy(&api.prefix, p, sizeof(*p));
@@ -411,20 +413,20 @@ void eigrp_zebra_route_delete(struct prefix *p)
        return;
 }
 
-int eigrp_is_type_redistributed(int type)
+static int eigrp_is_type_redistributed(int type, vrf_id_t vrf_id)
 {
        return ((DEFAULT_ROUTE_TYPE(type))
                        ? vrf_bitmap_check(zclient->default_information[AFI_IP],
-                                          VRF_DEFAULT)
+                                          vrf_id)
                        : vrf_bitmap_check(zclient->redist[AFI_IP][type],
-                                          VRF_DEFAULT));
+                                          vrf_id));
 }
 
 int eigrp_redistribute_set(struct eigrp *eigrp, int type,
                           struct eigrp_metrics metric)
 {
 
-       if (eigrp_is_type_redistributed(type)) {
+       if (eigrp_is_type_redistributed(type, eigrp->vrf_id)) {
                if (eigrp_metrics_is_same(metric, eigrp->dmetric[type])) {
                        eigrp->dmetric[type] = metric;
                }
@@ -443,7 +445,7 @@ int eigrp_redistribute_set(struct eigrp *eigrp, int type,
        eigrp->dmetric[type] = metric;
 
        zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type, 0,
-                            VRF_DEFAULT);
+                            eigrp->vrf_id);
 
        ++eigrp->redistribute;
 
@@ -453,10 +455,10 @@ int eigrp_redistribute_set(struct eigrp *eigrp, int type,
 int eigrp_redistribute_unset(struct eigrp *eigrp, int type)
 {
 
-       if (eigrp_is_type_redistributed(type)) {
+       if (eigrp_is_type_redistributed(type, eigrp->vrf_id)) {
                memset(&eigrp->dmetric[type], 0, sizeof(struct eigrp_metrics));
                zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, AFI_IP,
-                                    type, 0, VRF_DEFAULT);
+                                    type, 0, eigrp->vrf_id);
                --eigrp->redistribute;
        }
 
index 86b337cfe685f686c91207e8388bf7a9c297c9f3..112f2584ceb6a717b8f1f758ef5a4838aa3b80b5 100644 (file)
 
 extern void eigrp_zebra_init(void);
 
-extern void eigrp_zebra_route_add(struct prefix *, struct list *,
-                                 uint32_t distance);
-extern void eigrp_zebra_route_delete(struct prefix *);
+extern void eigrp_zebra_route_add(struct eigrp *eigrp, struct prefix *p,
+                                 struct list *successors, uint32_t distance);
+extern void eigrp_zebra_route_delete(struct eigrp *eigrp, struct prefix *);
 extern int eigrp_redistribute_set(struct eigrp *, int, struct eigrp_metrics);
 extern int eigrp_redistribute_unset(struct eigrp *, int);
-extern int eigrp_is_type_redistributed(int);
 
 #endif /* _ZEBRA_EIGRP_ZEBRA_H_ */
index 93f8b6f90e8935e26d1eafcea078968c2765c0c4..e93dc0cbfa29a265429de3cf285c98cea4983496 100644 (file)
@@ -64,8 +64,6 @@ static struct eigrp_master eigrp_master;
 
 struct eigrp_master *eigrp_om;
 
-static struct eigrp *eigrp_new(const char *);
-
 extern struct zclient *zclient;
 extern struct in_addr router_id_zebra;
 
@@ -95,7 +93,7 @@ extern struct in_addr router_id_zebra;
  */
 void eigrp_router_id_update(struct eigrp *eigrp)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct vrf *vrf = vrf_lookup_by_id(eigrp->vrf_id);
        struct interface *ifp;
        struct in_addr router_id, router_id_old;
 
@@ -136,14 +134,14 @@ void eigrp_master_init(void)
 }
 
 /* Allocate new eigrp structure. */
-static struct eigrp *eigrp_new(const char *AS)
+static struct eigrp *eigrp_new(uint16_t as, vrf_id_t vrf_id)
 {
        struct eigrp *eigrp = XCALLOC(MTYPE_EIGRP_TOP, sizeof(struct eigrp));
-       int eigrp_socket;
 
        /* init information relevant to peers */
+       eigrp->vrf_id = vrf_id;
        eigrp->vrid = 0;
-       eigrp->AS = atoi(AS);
+       eigrp->AS = as;
        eigrp->router_id.s_addr = 0;
        eigrp->router_id_static.s_addr = 0;
        eigrp->sequence_number = 1;
@@ -161,14 +159,15 @@ static struct eigrp *eigrp_new(const char *AS)
        eigrp->passive_interface_default = EIGRP_IF_ACTIVE;
        eigrp->networks = eigrp_topology_new();
 
-       if ((eigrp_socket = eigrp_sock_init()) < 0) {
+       eigrp->fd = eigrp_sock_init(vrf_lookup_by_id(vrf_id));
+
+       if (eigrp->fd < 0) {
                flog_err_sys(
                        EC_LIB_SOCKET,
                        "eigrp_new: fatal error: eigrp_sock_init was unable to open a socket");
                exit(1);
        }
 
-       eigrp->fd = eigrp_socket;
        eigrp->maxsndbuflen = getsockopt_so_sendbuf(eigrp->fd);
 
        eigrp->ibuf = stream_new(EIGRP_PACKET_MAX_LEN + 1);
@@ -200,16 +199,15 @@ static struct eigrp *eigrp_new(const char *AS)
        eigrp->routemap[EIGRP_FILTER_OUT] = NULL;
 
        /* Distribute list install. */
-       eigrp->distribute_ctx = distribute_list_ctx_create(
-                                          vrf_lookup_by_id(VRF_DEFAULT));
+       eigrp->distribute_ctx =
+               distribute_list_ctx_create(vrf_lookup_by_id(eigrp->vrf_id));
        distribute_list_add_hook(eigrp->distribute_ctx,
                                 eigrp_distribute_update);
        distribute_list_delete_hook(eigrp->distribute_ctx,
                                    eigrp_distribute_update);
 
        /*
-         eigrp->if_rmap_ctx = if_rmap_ctx_create(
-                                      VRF_DEFAULT_NAME);
+         eigrp->if_rmap_ctx = if_rmap_ctx_create(eigrp->vrf_id);
          if_rmap_hook_add (eigrp_if_rmap_update);
          if_rmap_hook_delete (eigrp_if_rmap_update);
        */
@@ -217,13 +215,13 @@ static struct eigrp *eigrp_new(const char *AS)
        return eigrp;
 }
 
-struct eigrp *eigrp_get(const char *AS)
+struct eigrp *eigrp_get(uint16_t as, vrf_id_t vrf_id)
 {
        struct eigrp *eigrp;
 
-       eigrp = eigrp_lookup();
+       eigrp = eigrp_lookup(vrf_id);
        if (eigrp == NULL) {
-               eigrp = eigrp_new(AS);
+               eigrp = eigrp_new(as, vrf_id);
                listnode_add(eigrp_om->eigrp, eigrp);
        }
 
@@ -285,7 +283,7 @@ void eigrp_finish_final(struct eigrp *eigrp)
        list_delete(&eigrp->eiflist);
        list_delete(&eigrp->oi_write_q);
 
-       eigrp_topology_free(eigrp->topology_table);
+       eigrp_topology_free(eigrp, eigrp->topology_table);
 
        eigrp_nbr_delete(eigrp->neighbor_self);
 
@@ -300,10 +298,14 @@ void eigrp_finish_final(struct eigrp *eigrp)
 }
 
 /*Look for existing eigrp process*/
-struct eigrp *eigrp_lookup(void)
+struct eigrp *eigrp_lookup(vrf_id_t vrf_id)
 {
-       if (listcount(eigrp_om->eigrp) == 0)
-               return NULL;
+       struct eigrp *eigrp;
+       struct listnode *node, *nnode;
+
+       for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp))
+               if (eigrp->vrf_id == vrf_id)
+                       return eigrp;
 
-       return listgetdata(listhead(eigrp_om->eigrp));
+       return NULL;
 }
index 3ef3a9c0ccef410431cd354baba15c365544ca45..6b4d45d1fc271e45a15ac83b8c60b5a56582651e 100644 (file)
@@ -48,8 +48,8 @@ extern void eigrp_master_init(void);
 extern void eigrp_terminate(void);
 extern void eigrp_finish_final(struct eigrp *);
 extern void eigrp_finish(struct eigrp *);
-extern struct eigrp *eigrp_get(const char *);
-extern struct eigrp *eigrp_lookup(void);
+extern struct eigrp *eigrp_get(uint16_t as, vrf_id_t vrf_id);
+extern struct eigrp *eigrp_lookup(vrf_id_t vrf_id);
 extern void eigrp_router_id_update(struct eigrp *);
 
 /* eigrp_cli.c */
index cc4676658630f50dad8f9c5d1d3255df32230fdc..5a65c654e93c4e5cbdafc98b74912bb9b1d4d81c 100644 (file)
@@ -35,6 +35,7 @@ eigrpd_libeigrp_a_SOURCES = \
        eigrpd/eigrp_snmp.c \
        eigrpd/eigrp_topology.c \
        eigrpd/eigrp_update.c \
+       eigrpd/eigrp_vrf.c \
        eigrpd/eigrp_vty.c \
        eigrpd/eigrp_zebra.c \
        eigrpd/eigrpd.c \
@@ -66,6 +67,7 @@ noinst_HEADERS += \
        eigrpd/eigrp_packet.h \
        eigrpd/eigrp_snmp.h \
        eigrpd/eigrp_structs.h \
+       eigrpd/eigrp_vrf.h \
        eigrpd/eigrp_vty.h \
        eigrpd/eigrp_zebra.h \
        # end
index fa89c80049bb55524efdc2d111e0f00f0ae9e254..8fc7997d79f085cc46754355ebb7436a8d9bf3d3 100644 (file)
@@ -19,7 +19,9 @@
 #include <zebra.h>
 
 #include "zclient.h"
+#include "nexthop.h"
 #include "bfd.h"
+#include "lib_errors.h"
 
 #include "isisd/isis_bfd.h"
 #include "isisd/isis_zebra.h"
 DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session")
 
 struct bfd_session {
-       struct in_addr dst_ip;
-       struct in_addr src_ip;
+       int family;
+       union g_addr dst_ip;
+       union g_addr src_ip;
        int status;
 };
 
-static struct bfd_session *bfd_session_new(struct in_addr *dst_ip,
-                                          struct in_addr *src_ip)
+static struct bfd_session *bfd_session_new(int family, union g_addr *dst_ip,
+                                          union g_addr *src_ip)
 {
        struct bfd_session *rv;
 
        rv = XCALLOC(MTYPE_BFD_SESSION, sizeof(*rv));
+       rv->family = family;
        rv->dst_ip = *dst_ip;
        rv->src_ip = *src_ip;
        return rv;
@@ -58,15 +62,60 @@ static void bfd_session_free(struct bfd_session **session)
        *session = NULL;
 }
 
+static bool bfd_session_same(const struct bfd_session *session, int family,
+                            const union g_addr *src, const union g_addr *dst)
+{
+       if (session->family != family)
+               return false;
+
+       switch (session->family) {
+       case AF_INET:
+               if (!IPV4_ADDR_SAME(&session->dst_ip.ipv4, &dst->ipv4))
+                       return false;
+               if (!IPV4_ADDR_SAME(&session->src_ip.ipv4, &src->ipv4))
+                       return false;
+               break;
+       case AF_INET6:
+               if (!IPV6_ADDR_SAME(&session->dst_ip.ipv6, &dst->ipv6))
+                       return false;
+               if (!IPV6_ADDR_SAME(&session->src_ip.ipv6, &src->ipv6))
+                       return false;
+               break;
+       default:
+               flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address-family: %u",
+                        __func__, session->family);
+               exit(1);
+       }
+
+       return true;
+}
+
 static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
                          int new_status)
 {
        if (!adj->bfd_session)
                return;
 
-       if (adj->bfd_session->dst_ip.s_addr != dst->u.prefix4.s_addr)
+       if (adj->bfd_session->family != dst->family)
                return;
 
+       switch (adj->bfd_session->family) {
+       case AF_INET:
+               if (!IPV4_ADDR_SAME(&adj->bfd_session->dst_ip.ipv4,
+                                   &dst->u.prefix4))
+                       return;
+               break;
+       case AF_INET6:
+               if (!IPV6_ADDR_SAME(&adj->bfd_session->dst_ip.ipv6,
+                                   &dst->u.prefix6))
+                       return;
+               break;
+       default:
+               flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address-family: %u",
+                        __func__, adj->bfd_session->family);
+               exit(1);
+       }
+
        int old_status = adj->bfd_session->status;
 
        adj->bfd_session->status = new_status;
@@ -76,7 +125,7 @@ static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
        if (isis->debugs & DEBUG_BFD) {
                char dst_str[INET6_ADDRSTRLEN];
 
-               inet_ntop(AF_INET, &adj->bfd_session->dst_ip,
+               inet_ntop(adj->bfd_session->family, &adj->bfd_session->dst_ip,
                          dst_str, sizeof(dst_str));
                zlog_debug("ISIS-BFD: Peer %s on %s changed from %s to %s",
                           dst_str, adj->circuit->interface->name,
@@ -100,14 +149,14 @@ static int isis_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
 
        ifp = bfd_get_peer_info(zclient->ibuf, &dst_ip, NULL, &status,
                                NULL, vrf_id);
-       if (!ifp || dst_ip.family != AF_INET)
+       if (!ifp || (dst_ip.family != AF_INET && dst_ip.family != AF_INET6))
                return 0;
 
        if (isis->debugs & DEBUG_BFD) {
                char dst_buf[INET6_ADDRSTRLEN];
 
-               inet_ntop(AF_INET, &dst_ip.u.prefix4,
-                         dst_buf, sizeof(dst_buf));
+               inet_ntop(dst_ip.family, &dst_ip.u.prefix, dst_buf,
+                         sizeof(dst_buf));
 
                zlog_debug("ISIS-BFD: Received update for %s on %s: Changed state to %s",
                           dst_buf, ifp->name, bfd_get_status_str(status));
@@ -171,7 +220,7 @@ static void isis_bfd_zebra_connected(struct zclient *zclient)
        bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
 }
 
-static void bfd_debug(struct in_addr *dst, struct in_addr *src,
+static void bfd_debug(int family, union g_addr *dst, union g_addr *src,
                      const char *interface, int command)
 {
        if (!(isis->debugs & DEBUG_BFD))
@@ -180,8 +229,8 @@ static void bfd_debug(struct in_addr *dst, struct in_addr *src,
        char dst_str[INET6_ADDRSTRLEN];
        char src_str[INET6_ADDRSTRLEN];
 
-       inet_ntop(AF_INET, dst, dst_str, sizeof(dst_str));
-       inet_ntop(AF_INET, src, src_str, sizeof(src_str));
+       inet_ntop(family, dst, dst_str, sizeof(dst_str));
+       inet_ntop(family, src, src_str, sizeof(src_str));
 
        const char *command_str;
 
@@ -209,10 +258,11 @@ static void bfd_handle_adj_down(struct isis_adjacency *adj)
        if (!adj->bfd_session)
                return;
 
-       bfd_debug(&adj->bfd_session->dst_ip, &adj->bfd_session->src_ip,
-                 adj->circuit->interface->name, ZEBRA_BFD_DEST_DEREGISTER);
+       bfd_debug(adj->bfd_session->family, &adj->bfd_session->dst_ip,
+                 &adj->bfd_session->src_ip, adj->circuit->interface->name,
+                 ZEBRA_BFD_DEST_DEREGISTER);
 
-       bfd_peer_sendmsg(zclient, NULL, AF_INET,
+       bfd_peer_sendmsg(zclient, NULL, adj->bfd_session->family,
                         &adj->bfd_session->dst_ip,
                         &adj->bfd_session->src_ip,
                         adj->circuit->interface->name,
@@ -228,33 +278,50 @@ static void bfd_handle_adj_down(struct isis_adjacency *adj)
 static void bfd_handle_adj_up(struct isis_adjacency *adj, int command)
 {
        struct isis_circuit *circuit = adj->circuit;
+       int family;
+       union g_addr dst_ip;
+       union g_addr src_ip;
+       struct list *local_ips;
+       struct prefix *local_ip;
 
-       if (!circuit->bfd_info
-           || !circuit->ip_router
-           || !adj->ipv4_address_count)
+       if (!circuit->bfd_info)
                goto out;
 
-       struct list *local_ips = fabricd_ip_addrs(adj->circuit);
-
-       if (!local_ips)
+       /*
+        * If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer
+        * creating a BFD session over IPv6.
+        */
+       if (circuit->ipv6_router && adj->ipv6_address_count) {
+               family = AF_INET6;
+               dst_ip.ipv6 = adj->ipv6_addresses[0];
+               local_ips = circuit->ipv6_link;
+               if (!local_ips || list_isempty(local_ips))
+                       goto out;
+               local_ip = listgetdata(listhead(local_ips));
+               src_ip.ipv6 = local_ip->u.prefix6;
+       } else if (circuit->ip_router && adj->ipv4_address_count) {
+               family = AF_INET;
+               dst_ip.ipv4 = adj->ipv4_addresses[0];
+               local_ips = fabricd_ip_addrs(adj->circuit);
+               if (!local_ips || list_isempty(local_ips))
+                       goto out;
+               local_ip = listgetdata(listhead(local_ips));
+               src_ip.ipv4 = local_ip->u.prefix4;
+       } else
                goto out;
 
-       struct in_addr *dst_ip = &adj->ipv4_addresses[0];
-       struct prefix_ipv4 *local_ip = listgetdata(listhead(local_ips));
-       struct in_addr *src_ip = &local_ip->prefix;
-
        if (adj->bfd_session) {
-               if (adj->bfd_session->dst_ip.s_addr != dst_ip->s_addr
-                   || adj->bfd_session->src_ip.s_addr != src_ip->s_addr)
+               if (bfd_session_same(adj->bfd_session, family, &src_ip,
+                                    &dst_ip))
                        bfd_handle_adj_down(adj);
        }
 
        if (!adj->bfd_session)
-               adj->bfd_session = bfd_session_new(dst_ip, src_ip);
+               adj->bfd_session = bfd_session_new(family, &dst_ip, &src_ip);
 
-       bfd_debug(&adj->bfd_session->dst_ip, &adj->bfd_session->src_ip,
-                 circuit->interface->name, command);
-       bfd_peer_sendmsg(zclient, circuit->bfd_info, AF_INET,
+       bfd_debug(adj->bfd_session->family, &adj->bfd_session->dst_ip,
+                 &adj->bfd_session->src_ip, circuit->interface->name, command);
+       bfd_peer_sendmsg(zclient, circuit->bfd_info, adj->bfd_session->family,
                         &adj->bfd_session->dst_ip,
                         &adj->bfd_session->src_ip,
                         circuit->interface->name,
index 4e9aef47adf0f17f87fec51944dd4c498a720bea..d6b85b2fa3ef84a7c919fbaee692ce4e11dd6813 100644 (file)
@@ -187,7 +187,7 @@ int isis_sock_init(struct isis_circuit *circuit)
 {
        int retval = ISIS_OK;
 
-       frr_elevate_privs(&isisd_privs) {
+       frr_with_privs(&isisd_privs) {
 
                retval = open_bpf_dev(circuit);
 
index a96dd93804c047b974e338d7fd2d64a605dc8b02..7d3dfcb01e2f07c9beeaea2993217d2cbf6d8309 100644 (file)
@@ -467,7 +467,7 @@ int isis_sock_init(struct isis_circuit *circuit)
 {
        int retval = ISIS_OK;
 
-       frr_elevate_privs(&isisd_privs) {
+       frr_with_privs(&isisd_privs) {
 
                retval = open_dlpi_dev(circuit);
 
index 7d1ad6b049a5382d4d0f4eac74c46aa915570bc1..27254597676b3091822e16bee8b6966705f089f9 100644 (file)
@@ -39,7 +39,6 @@ DEFINE_MTYPE(ISISD, ISIS_SPFTREE, "ISIS SPFtree")
 DEFINE_MTYPE(ISISD, ISIS_VERTEX, "ISIS vertex")
 DEFINE_MTYPE(ISISD, ISIS_ROUTE_INFO, "ISIS route info")
 DEFINE_MTYPE(ISISD, ISIS_NEXTHOP, "ISIS nexthop")
-DEFINE_MTYPE(ISISD, ISIS_NEXTHOP6, "ISIS nexthop6")
 DEFINE_MTYPE(ISISD, ISIS_DICT, "ISIS dictionary")
 DEFINE_MTYPE(ISISD, ISIS_DICT_NODE, "ISIS dictionary node")
 DEFINE_MTYPE(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route")
index 4078c7a67114ff9f4fc703bbc15a7ae1085bf9e7..e672340e8457c42c3b1504cbadcb0347a9bc5701 100644 (file)
@@ -38,7 +38,6 @@ DECLARE_MTYPE(ISIS_SPFTREE)
 DECLARE_MTYPE(ISIS_VERTEX)
 DECLARE_MTYPE(ISIS_ROUTE_INFO)
 DECLARE_MTYPE(ISIS_NEXTHOP)
-DECLARE_MTYPE(ISIS_NEXTHOP6)
 DECLARE_MTYPE(ISIS_DICT)
 DECLARE_MTYPE(ISIS_DICT_NODE)
 DECLARE_MTYPE(ISIS_EXT_ROUTE)
index 0982a468a62ed5ab98825d49ba46752e9ee2fe42..c1b630eb2db59a6396c360a1442ec0907460dc09 100644 (file)
@@ -1524,29 +1524,64 @@ static int lib_interface_isis_create(enum nb_event event,
        struct interface *ifp;
        struct isis_circuit *circuit;
        const char *area_tag = yang_dnode_get_string(dnode, "./area-tag");
+       uint32_t min_mtu, actual_mtu;
 
-       if (event != NB_EV_APPLY)
-               return NB_OK;
+       switch (event) {
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_VALIDATE:
+               /* check if interface mtu is sufficient. If the area has not
+                * been created yet, assume default MTU for the area
+                */
+               ifp = nb_running_get_entry(dnode, NULL, true);
+               /* zebra might not know yet about the MTU - nothing we can do */
+               if (ifp->mtu == 0)
+                       break;
+               actual_mtu =
+                       if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu;
+               area = isis_area_lookup(area_tag);
+               if (area)
+                       min_mtu = area->lsp_mtu;
+               else
+#ifndef FABRICD
+                       min_mtu = yang_get_default_uint16(
+                               "/frr-isisd:isis/instance/lsp/mtu");
+#else
+                       min_mtu = DEFAULT_LSP_MTU;
+#endif /* ifndef FABRICD */
+               if (actual_mtu < min_mtu) {
+                       flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
+                                 "Interface %s has MTU %" PRIu32
+                                 ", minimum MTU for the area is %" PRIu32 "",
+                                 ifp->name, actual_mtu, min_mtu);
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_APPLY:
+               area = isis_area_lookup(area_tag);
+               /* The area should have already be created. We are
+                * setting the priority of the global isis area creation
+                * slightly lower, so it should be executed first, but I
+                * cannot rely on that so here I have to check.
+                */
+               if (!area) {
+                       flog_err(
+                               EC_LIB_NB_CB_CONFIG_APPLY,
+                               "%s: attempt to create circuit for area %s before the area has been created",
+                               __func__, area_tag);
+                       abort();
+               }
 
-       area = isis_area_lookup(area_tag);
-       /* The area should have already be created. We are
-        * setting the priority of the global isis area creation
-        * slightly lower, so it should be executed first, but I
-        * cannot rely on that so here I have to check.
-        */
-       if (!area) {
-               flog_err(
-                       EC_LIB_NB_CB_CONFIG_APPLY,
-                       "%s: attempt to create circuit for area %s before the area has been created",
-                       __func__, area_tag);
-               abort();
+               ifp = nb_running_get_entry(dnode, NULL, true);
+               circuit = isis_circuit_create(area, ifp);
+               assert(circuit
+                      && (circuit->state == C_STATE_CONF
+                          || circuit->state == C_STATE_UP));
+               nb_running_set_entry(dnode, circuit);
+               break;
        }
 
-       ifp = nb_running_get_entry(dnode, NULL, true);
-       circuit = isis_circuit_create(area, ifp);
-       assert(circuit->state == C_STATE_CONF || circuit->state == C_STATE_UP);
-       nb_running_set_entry(dnode, circuit);
-
        return NB_OK;
 }
 
@@ -1561,21 +1596,8 @@ static int lib_interface_isis_destroy(enum nb_event event,
        circuit = nb_running_unset_entry(dnode);
        if (!circuit)
                return NB_ERR_INCONSISTENCY;
-       /* delete circuit through csm changes */
-       switch (circuit->state) {
-       case C_STATE_UP:
-               isis_csm_state_change(IF_DOWN_FROM_Z, circuit,
-                                     circuit->interface);
-               isis_csm_state_change(ISIS_DISABLE, circuit, circuit->area);
-               break;
-       case C_STATE_CONF:
+       if (circuit->state == C_STATE_UP || circuit->state == C_STATE_CONF)
                isis_csm_state_change(ISIS_DISABLE, circuit, circuit->area);
-               break;
-       case C_STATE_INIT:
-               isis_csm_state_change(IF_DOWN_FROM_Z, circuit,
-                                     circuit->interface);
-               break;
-       }
 
        return NB_OK;
 }
index ea66e6950e68d8c0516297f1bdc1aa8ea6d89164..69ac3fc555b93e4401956a4362cb3ccad046a1cf 100644 (file)
@@ -183,7 +183,7 @@ int isis_sock_init(struct isis_circuit *circuit)
 {
        int retval = ISIS_OK;
 
-       frr_elevate_privs(&isisd_privs) {
+       frr_with_privs(&isisd_privs) {
 
                retval = open_packet_socket(circuit);
 
index 281eaf11bc962c5ff8b72b326cc5ba9e70ec1da3..636a63e29094835461966641a25ec37da2e6dc6a 100644 (file)
@@ -28,6 +28,7 @@
 #include "linklist.h"
 #include "vty.h"
 #include "log.h"
+#include "lib_errors.h"
 #include "memory.h"
 #include "prefix.h"
 #include "hash.h"
 #include "isis_route.h"
 #include "isis_zebra.h"
 
-static struct isis_nexthop *isis_nexthop_create(struct in_addr *ip,
+static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
+                                         union g_addr *ip, ifindex_t ifindex);
+
+static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip,
                                                ifindex_t ifindex)
 {
-       struct listnode *node;
        struct isis_nexthop *nexthop;
 
-       for (ALL_LIST_ELEMENTS_RO(isis->nexthops, node, nexthop)) {
-               if (nexthop->ifindex != ifindex)
-                       continue;
-               if (ip && memcmp(&nexthop->ip, ip, sizeof(struct in_addr)) != 0)
-                       continue;
-
+       nexthop = nexthoplookup(isis->nexthops, family, ip, ifindex);
+       if (nexthop) {
                nexthop->lock++;
                return nexthop;
        }
 
        nexthop = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
 
+       nexthop->family = family;
        nexthop->ifindex = ifindex;
-       memcpy(&nexthop->ip, ip, sizeof(struct in_addr));
+       nexthop->ip = *ip;
        listnode_add(isis->nexthops, nexthop);
        nexthop->lock++;
 
@@ -85,116 +85,79 @@ static void isis_nexthop_delete(struct isis_nexthop *nexthop)
        return;
 }
 
-static int nexthoplookup(struct list *nexthops, struct in_addr *ip,
-                        ifindex_t ifindex)
+static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
+                                         union g_addr *ip, ifindex_t ifindex)
 {
        struct listnode *node;
        struct isis_nexthop *nh;
 
        for (ALL_LIST_ELEMENTS_RO(nexthops, node, nh)) {
-               if (!(memcmp(ip, &nh->ip, sizeof(struct in_addr)))
-                   && ifindex == nh->ifindex)
-                       return 1;
-       }
-
-       return 0;
-}
-
-static struct isis_nexthop6 *isis_nexthop6_new(struct in6_addr *ip6,
-                                              ifindex_t ifindex)
-{
-       struct isis_nexthop6 *nexthop6;
-
-       nexthop6 = XCALLOC(MTYPE_ISIS_NEXTHOP6, sizeof(struct isis_nexthop6));
-
-       nexthop6->ifindex = ifindex;
-       memcpy(&nexthop6->ip6, ip6, sizeof(struct in6_addr));
-       nexthop6->lock++;
-
-       return nexthop6;
-}
-
-static struct isis_nexthop6 *isis_nexthop6_create(struct in6_addr *ip6,
-                                                 ifindex_t ifindex)
-{
-       struct listnode *node;
-       struct isis_nexthop6 *nexthop6;
-
-       for (ALL_LIST_ELEMENTS_RO(isis->nexthops6, node, nexthop6)) {
-               if (nexthop6->ifindex != ifindex)
+               if (nh->family != family)
                        continue;
-               if (ip6
-                   && memcmp(&nexthop6->ip6, ip6, sizeof(struct in6_addr))
-                              != 0)
+               if (nh->ifindex != ifindex)
                        continue;
 
-               nexthop6->lock++;
-               return nexthop6;
-       }
-
-       nexthop6 = isis_nexthop6_new(ip6, ifindex);
-
-       return nexthop6;
-}
-
-static void isis_nexthop6_delete(struct isis_nexthop6 *nexthop6)
-{
-
-       nexthop6->lock--;
-       if (nexthop6->lock == 0) {
-               listnode_delete(isis->nexthops6, nexthop6);
-               XFREE(MTYPE_ISIS_NEXTHOP6, nexthop6);
-       }
-
-       return;
-}
-
-static int nexthop6lookup(struct list *nexthops6, struct in6_addr *ip6,
-                         ifindex_t ifindex)
-{
-       struct listnode *node;
-       struct isis_nexthop6 *nh6;
+               switch (family) {
+               case AF_INET:
+                       if (IPV4_ADDR_CMP(&nh->ip.ipv4, &ip->ipv4))
+                               continue;
+                       break;
+               case AF_INET6:
+                       if (IPV6_ADDR_CMP(&nh->ip.ipv6, &ip->ipv6))
+                               continue;
+                       break;
+               default:
+                       flog_err(EC_LIB_DEVELOPMENT,
+                                "%s: unknown address family [%d]", __func__,
+                                family);
+                       exit(1);
+               }
 
-       for (ALL_LIST_ELEMENTS_RO(nexthops6, node, nh6)) {
-               if (!(memcmp(ip6, &nh6->ip6, sizeof(struct in6_addr)))
-                   && ifindex == nh6->ifindex)
-                       return 1;
+               return nh;
        }
 
-       return 0;
+       return NULL;
 }
 
-static void adjinfo2nexthop(struct list *nexthops, struct isis_adjacency *adj)
+static void adjinfo2nexthop(int family, struct list *nexthops,
+                           struct isis_adjacency *adj)
 {
        struct isis_nexthop *nh;
-
-       for (unsigned int i = 0; i < adj->ipv4_address_count; i++) {
-               struct in_addr *ipv4_addr = &adj->ipv4_addresses[i];
-               if (!nexthoplookup(nexthops, ipv4_addr,
-                                  adj->circuit->interface->ifindex)) {
-                       nh = isis_nexthop_create(
-                               ipv4_addr, adj->circuit->interface->ifindex);
-                       nh->router_address = adj->router_address;
-                       listnode_add(nexthops, nh);
-                       return;
+       union g_addr ip = {};
+
+       switch (family) {
+       case AF_INET:
+               for (unsigned int i = 0; i < adj->ipv4_address_count; i++) {
+                       ip.ipv4 = adj->ipv4_addresses[i];
+
+                       if (!nexthoplookup(nexthops, AF_INET, &ip,
+                                          adj->circuit->interface->ifindex)) {
+                               nh = isis_nexthop_create(
+                                       AF_INET, &ip,
+                                       adj->circuit->interface->ifindex);
+                               listnode_add(nexthops, nh);
+                               break;
+                       }
                }
-       }
-}
-
-static void adjinfo2nexthop6(struct list *nexthops6, struct isis_adjacency *adj)
-{
-       struct isis_nexthop6 *nh6;
-
-       for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
-               struct in6_addr *ipv6_addr = &adj->ipv6_addresses[i];
-               if (!nexthop6lookup(nexthops6, ipv6_addr,
-                                   adj->circuit->interface->ifindex)) {
-                       nh6 = isis_nexthop6_create(
-                               ipv6_addr, adj->circuit->interface->ifindex);
-                       nh6->router_address6 = adj->router_address6;
-                       listnode_add(nexthops6, nh6);
-                       return;
+               break;
+       case AF_INET6:
+               for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
+                       ip.ipv6 = adj->ipv6_addresses[i];
+
+                       if (!nexthoplookup(nexthops, AF_INET6, &ip,
+                                          adj->circuit->interface->ifindex)) {
+                               nh = isis_nexthop_create(
+                                       AF_INET6, &ip,
+                                       adj->circuit->interface->ifindex);
+                               listnode_add(nexthops, nh);
+                               break;
+                       }
                }
+               break;
+       default:
+               flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address family [%d]",
+                        __func__, family);
+               exit(1);
        }
 }
 
@@ -210,35 +173,32 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix,
 
        rinfo = XCALLOC(MTYPE_ISIS_ROUTE_INFO, sizeof(struct isis_route_info));
 
-       if (prefix->family == AF_INET) {
-               rinfo->nexthops = list_new();
-               for (ALL_LIST_ELEMENTS_RO(adjacencies, node, adj)) {
-                       /* check for force resync this route */
-                       if (CHECK_FLAG(adj->circuit->flags,
-                                      ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
-                               SET_FLAG(rinfo->flag,
-                                        ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
-                       /* update neighbor router address */
+       rinfo->nexthops = list_new();
+       for (ALL_LIST_ELEMENTS_RO(adjacencies, node, adj)) {
+               /* check for force resync this route */
+               if (CHECK_FLAG(adj->circuit->flags,
+                              ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
+                       SET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
+
+               /* update neighbor router address */
+               switch (prefix->family) {
+               case AF_INET:
                        if (depth == 2 && prefix->prefixlen == 32)
                                adj->router_address = prefix->u.prefix4;
-                       adjinfo2nexthop(rinfo->nexthops, adj);
-               }
-       }
-       if (prefix->family == AF_INET6) {
-               rinfo->nexthops6 = list_new();
-               for (ALL_LIST_ELEMENTS_RO(adjacencies, node, adj)) {
-                       /* check for force resync this route */
-                       if (CHECK_FLAG(adj->circuit->flags,
-                                      ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
-                               SET_FLAG(rinfo->flag,
-                                        ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
-                       /* update neighbor router address */
+                       break;
+               case AF_INET6:
                        if (depth == 2 && prefix->prefixlen == 128
                            && (!src_p || !src_p->prefixlen)) {
                                adj->router_address6 = prefix->u.prefix6;
                        }
-                       adjinfo2nexthop6(rinfo->nexthops6, adj);
+                       break;
+               default:
+                       flog_err(EC_LIB_DEVELOPMENT,
+                                "%s: unknown address family [%d]", __func__,
+                                prefix->family);
+                       exit(1);
                }
+               adjinfo2nexthop(prefix->family, rinfo->nexthops, adj);
        }
 
        rinfo->cost = cost;
@@ -255,12 +215,6 @@ static void isis_route_info_delete(struct isis_route_info *route_info)
                list_delete(&route_info->nexthops);
        }
 
-       if (route_info->nexthops6) {
-               route_info->nexthops6->del =
-                       (void (*)(void *))isis_nexthop6_delete;
-               list_delete(&route_info->nexthops6);
-       }
-
        XFREE(MTYPE_ISIS_ROUTE_INFO, route_info);
 }
 
@@ -280,7 +234,6 @@ static int isis_route_info_same(struct isis_route_info *new,
 {
        struct listnode *node;
        struct isis_nexthop *nexthop;
-       struct isis_nexthop6 *nexthop6;
 
        if (!CHECK_FLAG(old->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
                return 0;
@@ -291,31 +244,15 @@ static int isis_route_info_same(struct isis_route_info *new,
        if (!isis_route_info_same_attrib(new, old))
                return 0;
 
-       if (family == AF_INET) {
-               for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, nexthop))
-                       if (nexthoplookup(old->nexthops, &nexthop->ip,
-                                         nexthop->ifindex)
-                           == 0)
-                               return 0;
-
-               for (ALL_LIST_ELEMENTS_RO(old->nexthops, node, nexthop))
-                       if (nexthoplookup(new->nexthops, &nexthop->ip,
-                                         nexthop->ifindex)
-                           == 0)
-                               return 0;
-       } else if (family == AF_INET6) {
-               for (ALL_LIST_ELEMENTS_RO(new->nexthops6, node, nexthop6))
-                       if (nexthop6lookup(old->nexthops6, &nexthop6->ip6,
-                                          nexthop6->ifindex)
-                           == 0)
-                               return 0;
-
-               for (ALL_LIST_ELEMENTS_RO(old->nexthops6, node, nexthop6))
-                       if (nexthop6lookup(new->nexthops6, &nexthop6->ip6,
-                                          nexthop6->ifindex)
-                           == 0)
-                               return 0;
-       }
+       for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, nexthop))
+               if (!nexthoplookup(old->nexthops, nexthop->family, &nexthop->ip,
+                                  nexthop->ifindex))
+                       return 0;
+
+       for (ALL_LIST_ELEMENTS_RO(old->nexthops, node, nexthop))
+               if (!nexthoplookup(new->nexthops, nexthop->family, &nexthop->ip,
+                                  nexthop->ifindex))
+                       return 0;
 
        return 1;
 }
index 9d6858586be5d696be2cc4f045fbbfc0b17a52d9..a20a7e038f1c295cfe172e4171b46e7a62a9c5a4 100644 (file)
 #ifndef _ZEBRA_ISIS_ROUTE_H
 #define _ZEBRA_ISIS_ROUTE_H
 
-struct isis_nexthop6 {
-       ifindex_t ifindex;
-       struct in6_addr ip6;
-       struct in6_addr router_address6;
-       unsigned int lock;
-};
+#include "lib/nexthop.h"
 
 struct isis_nexthop {
        ifindex_t ifindex;
-       struct in_addr ip;
-       struct in_addr router_address;
+       int family;
+       union g_addr ip;
        unsigned int lock;
 };
 
@@ -47,7 +42,6 @@ struct isis_route_info {
        uint32_t cost;
        uint32_t depth;
        struct list *nexthops;
-       struct list *nexthops6;
 };
 
 struct isis_route_info *isis_route_create(struct prefix *prefix,
index e2ef934696303d190b128adc513eed05dbb59c55..e8481a558b430514cd1ca9eb293beb7d1308055e 100644 (file)
@@ -27,6 +27,7 @@
 #include "command.h"
 #include "memory.h"
 #include "log.h"
+#include "lib_errors.h"
 #include "if.h"
 #include "network.h"
 #include "prefix.h"
@@ -225,7 +226,6 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
        struct zapi_route api;
        struct zapi_nexthop *api_nh;
        struct isis_nexthop *nexthop;
-       struct isis_nexthop6 *nexthop6;
        struct listnode *node;
        int count = 0;
 
@@ -250,47 +250,41 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
 #endif
 
        /* Nexthops */
-       switch (prefix->family) {
-       case AF_INET:
-               for (ALL_LIST_ELEMENTS_RO(route_info->nexthops, node,
-                                         nexthop)) {
-                       if (count >= MULTIPATH_NUM)
-                               break;
-                       api_nh = &api.nexthops[count];
-                       if (fabricd)
-                               api_nh->onlink = true;
-                       api_nh->vrf_id = VRF_DEFAULT;
+       for (ALL_LIST_ELEMENTS_RO(route_info->nexthops, node, nexthop)) {
+               if (count >= MULTIPATH_NUM)
+                       break;
+               api_nh = &api.nexthops[count];
+               if (fabricd)
+                       api_nh->onlink = true;
+               api_nh->vrf_id = VRF_DEFAULT;
+
+               switch (nexthop->family) {
+               case AF_INET:
                        /* FIXME: can it be ? */
-                       if (nexthop->ip.s_addr != INADDR_ANY) {
+                       if (nexthop->ip.ipv4.s_addr != INADDR_ANY) {
                                api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
-                               api_nh->gate.ipv4 = nexthop->ip;
+                               api_nh->gate.ipv4 = nexthop->ip.ipv4;
                        } else {
                                api_nh->type = NEXTHOP_TYPE_IFINDEX;
                        }
-                       api_nh->ifindex = nexthop->ifindex;
-                       count++;
-               }
-               break;
-       case AF_INET6:
-               for (ALL_LIST_ELEMENTS_RO(route_info->nexthops6, node,
-                                         nexthop6)) {
-                       if (count >= MULTIPATH_NUM)
-                               break;
-                       if (!IN6_IS_ADDR_LINKLOCAL(&nexthop6->ip6)
-                           && !IN6_IS_ADDR_UNSPECIFIED(&nexthop6->ip6)) {
+                       break;
+               case AF_INET6:
+                       if (!IN6_IS_ADDR_LINKLOCAL(&nexthop->ip.ipv6)
+                           && !IN6_IS_ADDR_UNSPECIFIED(&nexthop->ip.ipv6)) {
                                continue;
                        }
-
-                       api_nh = &api.nexthops[count];
-                       if (fabricd)
-                               api_nh->onlink = true;
-                       api_nh->vrf_id = VRF_DEFAULT;
-                       api_nh->gate.ipv6 = nexthop6->ip6;
-                       api_nh->ifindex = nexthop6->ifindex;
+                       api_nh->gate.ipv6 = nexthop->ip.ipv6;
                        api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
-                       count++;
+                       break;
+               default:
+                       flog_err(EC_LIB_DEVELOPMENT,
+                                "%s: unknown address family [%d]", __func__,
+                                nexthop->family);
+                       exit(1);
                }
-               break;
+
+               api_nh->ifindex = nexthop->ifindex;
+               count++;
        }
        if (!count)
                return;
index bee3b6deb56e5dbb401c75c6f3d525fbf5ab6850..67f557ab5052fbac663a90965af071ed81a1981a 100644 (file)
@@ -88,7 +88,6 @@ void isis_new(unsigned long process_id)
        isis->init_circ_list = list_new();
        isis->uptime = time(NULL);
        isis->nexthops = list_new();
-       isis->nexthops6 = list_new();
        dyn_cache_init();
        /*
         * uncomment the next line for full debugs
index f8486ae0d6cd81ae32b90aeec870c933585d91c8..393b1d67c7c7d9bd6e18dbb741cf72cc096b823c 100644 (file)
@@ -69,8 +69,7 @@ struct isis {
        uint32_t router_id;             /* Router ID from zebra */
        struct list *area_list; /* list of IS-IS areas */
        struct list *init_circ_list;
-       struct list *nexthops;            /* IPv4 next hops from this IS */
-       struct list *nexthops6;           /* IPv6 next hops from this IS */
+       struct list *nexthops;            /* IP next hops from this IS */
        uint8_t max_area_addrs;           /* maximumAreaAdresses */
        struct area_addr *man_area_addrs; /* manualAreaAddresses */
        uint32_t debugs;                  /* bitmap for debug */
index b31db2c7bc3feecd63d56aea34e64b46b3d75012..8706d03c6f95dd4999b5662e6a747d9fdf6e903d 100644 (file)
@@ -79,7 +79,7 @@ ldp_create_socket(int af, enum socket_type type)
                sock_set_bindany(fd, 1);
                break;
        }
-       frr_elevate_privs(&ldpd_privs) {
+       frr_with_privs(&ldpd_privs) {
                if (sock_set_reuse(fd, 1) == -1) {
                        close(fd);
                        return (-1);
@@ -254,7 +254,7 @@ int
 sock_set_bindany(int fd, int enable)
 {
 #ifdef HAVE_SO_BINDANY
-       frr_elevate_privs(&ldpd_privs) {
+       frr_with_privs(&ldpd_privs) {
                if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,
                               sizeof(int)) < 0) {
                        log_warn("%s: error setting SO_BINDANY", __func__);
@@ -269,7 +269,7 @@ sock_set_bindany(int fd, int enable)
        }
        return (0);
 #elif defined(IP_BINDANY)
-       frr_elevate_privs(&ldpd_privs) {
+       frr_with_privs(&ldpd_privs) {
                if (setsockopt(fd, IPPROTO_IP, IP_BINDANY, &enable, sizeof(int))
                    < 0) {
                        log_warn("%s: error setting IP_BINDANY", __func__);
@@ -304,7 +304,7 @@ sock_set_md5sig(int fd, int af, union ldpd_addr *addr, const char *password)
 #if HAVE_DECL_TCP_MD5SIG
        addr2sa(af, addr, 0, &su);
 
-       frr_elevate_privs(&ldpe_privs) {
+       frr_with_privs(&ldpe_privs) {
                ret = sockopt_tcp_signature(fd, &su, password);
                save_errno = errno;
        }
index 9dabc2af7eca778487e64903c8e3bdcca7ce8666..de28a726b0c9e8a860b4d54ef5a3f17e74625b7a 100644 (file)
@@ -151,6 +151,7 @@ const char *node_names[] = {
        "bfd peer",              /* BFD_PEER_NODE */
        "openfabric",               // OPENFABRIC_NODE
        "vrrp",                     /* VRRP_NODE */
+       "bmp",                   /* BMP_NODE */
 };
 /* clang-format on */
 
@@ -975,6 +976,7 @@ enum node_type node_parent(enum node_type node)
        case BGP_IPV6M_NODE:
        case BGP_EVPN_NODE:
        case BGP_IPV6L_NODE:
+       case BMP_NODE:
                ret = BGP_NODE;
                break;
        case BGP_EVPN_VNI_NODE:
@@ -1491,6 +1493,7 @@ void cmd_exit(struct vty *vty)
        case BGP_IPV6M_NODE:
        case BGP_EVPN_NODE:
        case BGP_IPV6L_NODE:
+       case BMP_NODE:
                vty->node = BGP_NODE;
                break;
        case BGP_EVPN_VNI_NODE:
@@ -2708,15 +2711,66 @@ DEFUN (no_banner_motd,
 
 DEFUN(find,
       find_cmd,
-      "find COMMAND...",
-      "Find CLI command containing text\n"
-      "Text to search for\n")
+      "find REGEX",
+      "Find CLI command matching a regular expression\n"
+      "Search pattern (POSIX regex)\n")
 {
-       char *text = argv_concat(argv, argc, 1);
+       char *pattern = argv[1]->arg;
        const struct cmd_node *node;
        const struct cmd_element *cli;
        vector clis;
 
+       regex_t exp = {};
+
+       int cr = regcomp(&exp, pattern, REG_NOSUB | REG_EXTENDED);
+
+       if (cr != 0) {
+               switch (cr) {
+               case REG_BADBR:
+                       vty_out(vty, "%% Invalid {...} expression\n");
+                       break;
+               case REG_BADRPT:
+                       vty_out(vty, "%% Bad repetition operator\n");
+                       break;
+               case REG_BADPAT:
+                       vty_out(vty, "%% Regex syntax error\n");
+                       break;
+               case REG_ECOLLATE:
+                       vty_out(vty, "%% Invalid collating element\n");
+                       break;
+               case REG_ECTYPE:
+                       vty_out(vty, "%% Invalid character class name\n");
+                       break;
+               case REG_EESCAPE:
+                       vty_out(vty,
+                               "%% Regex ended with escape character (\\)\n");
+                       break;
+               case REG_ESUBREG:
+                       vty_out(vty,
+                               "%% Invalid number in \\digit construction\n");
+                       break;
+               case REG_EBRACK:
+                       vty_out(vty, "%% Unbalanced square brackets\n");
+                       break;
+               case REG_EPAREN:
+                       vty_out(vty, "%% Unbalanced parentheses\n");
+                       break;
+               case REG_EBRACE:
+                       vty_out(vty, "%% Unbalanced braces\n");
+                       break;
+               case REG_ERANGE:
+                       vty_out(vty,
+                               "%% Invalid endpoint in range expression\n");
+                       break;
+               case REG_ESPACE:
+                       vty_out(vty, "%% Failed to compile (out of memory)\n");
+                       break;
+               }
+
+               goto done;
+       }
+
+
        for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
                node = vector_slot(cmdvec, i);
                if (!node)
@@ -2724,14 +2778,15 @@ DEFUN(find,
                clis = node->cmd_vector;
                for (unsigned int j = 0; j < vector_active(clis); j++) {
                        cli = vector_slot(clis, j);
-                       if (strcasestr(cli->string, text))
+
+                       if (regexec(&exp, cli->string, 0, NULL, 0) == 0)
                                vty_out(vty, "  (%s)  %s\n",
                                        node_names[node->node], cli->string);
                }
        }
 
-       XFREE(MTYPE_TMP, text);
-
+done:
+       regfree(&exp);
        return CMD_SUCCESS;
 }
 
index 8dc35a0fdc26d999cb7f91831296afad4855d3c1..137d3748ae86a49ed23bd3afa6ffacd2a38fb55a 100644 (file)
@@ -159,6 +159,7 @@ enum node_type {
        BFD_PEER_NODE,           /* BFD peer configuration mode. */
        OPENFABRIC_NODE,        /* OpenFabric router configuration node */
        VRRP_NODE,               /* VRRP node */
+       BMP_NODE,               /* BMP config under router bgp */
        NODE_TYPE_MAX, /* maximum */
 };
 
index 6700ca9e8b1080b4a9b66d44eb6f08ed84998b71..e430925e69723a10c3c2e362bfdad38b0cf93d06 100644 (file)
@@ -121,6 +121,49 @@ extern "C" {
 #define macro_inline   static inline __attribute__((unused))
 #define macro_pure     static inline __attribute__((unused, pure))
 
+
+/* variadic macros, use like:
+ * #define V_0()  ...
+ * #define V_1(x) ...
+ * #define V(...) MACRO_VARIANT(V, ##__VA_ARGS__)(__VA_ARGS__)
+ */
+#define _MACRO_VARIANT(A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10, N, ...) N
+
+#define _CONCAT2(a, b) a ## b
+#define _CONCAT(a, b) _CONCAT2(a,b)
+
+#define MACRO_VARIANT(NAME, ...) \
+       _CONCAT(NAME, _MACRO_VARIANT(0, ##__VA_ARGS__, \
+                       _10, _9, _8, _7, _6, _5, _4, _3, _2, _1, _0))
+
+#define NAMECTR(name) _CONCAT(name, __COUNTER__)
+
+/* per-arg repeat macros, use like:
+ * #define PERARG(n) ...n...
+ * #define FOO(...) MACRO_REPEAT(PERARG, ##__VA_ARGS__)
+ */
+
+#define _MACRO_REPEAT_0(NAME)
+#define _MACRO_REPEAT_1(NAME, A1) \
+       NAME(A1)
+#define _MACRO_REPEAT_2(NAME, A1, A2) \
+       NAME(A1) NAME(A2)
+#define _MACRO_REPEAT_3(NAME, A1, A2, A3) \
+       NAME(A1) NAME(A2) NAME(A3)
+#define _MACRO_REPEAT_4(NAME, A1, A2, A3, A4) \
+       NAME(A1) NAME(A2) NAME(A3) NAME(A4)
+#define _MACRO_REPEAT_5(NAME, A1, A2, A3, A4, A5) \
+       NAME(A1) NAME(A2) NAME(A3) NAME(A4) NAME(A5)
+#define _MACRO_REPEAT_6(NAME, A1, A2, A3, A4, A5, A6) \
+       NAME(A1) NAME(A2) NAME(A3) NAME(A4) NAME(A5) NAME(A6)
+#define _MACRO_REPEAT_7(NAME, A1, A2, A3, A4, A5, A6, A7) \
+       NAME(A1) NAME(A2) NAME(A3) NAME(A4) NAME(A5) NAME(A6) NAME(A7)
+#define _MACRO_REPEAT_8(NAME, A1, A2, A3, A4, A5, A6, A7, A8) \
+       NAME(A1) NAME(A2) NAME(A3) NAME(A4) NAME(A5) NAME(A6) NAME(A7) NAME(A8)
+
+#define MACRO_REPEAT(NAME, ...) \
+       MACRO_VARIANT(_MACRO_REPEAT, ##__VA_ARGS__)(NAME, ##__VA_ARGS__)
+
 /*
  * for warnings on macros, put in the macro content like this:
  *   #define MACRO BLA CPP_WARN("MACRO has been deprecated")
index 8afc926c412fa2a3f8dcf72caedd5b236bde7f48..ccf63dea17986260dd56247013abd58b5eafacc4 100644 (file)
@@ -33,6 +33,7 @@
 #include "command.h"
 #include "json.h"
 #include "linklist.h"
+#include "frr_pthread.h"
 
 DEFINE_MTYPE_STATIC(LIB, ERRINFO, "error information")
 
@@ -83,14 +84,12 @@ void log_ref_add(struct log_ref *ref)
 {
        uint32_t i = 0;
 
-       pthread_mutex_lock(&refs_mtx);
-       {
+       frr_with_mutex(&refs_mtx) {
                while (ref[i].code != END_FERR) {
                        hash_get(refs, &ref[i], hash_alloc_intern);
                        i++;
                }
        }
-       pthread_mutex_unlock(&refs_mtx);
 }
 
 struct log_ref *log_ref_get(uint32_t code)
@@ -99,11 +98,9 @@ struct log_ref *log_ref_get(uint32_t code)
        struct log_ref *ref;
 
        holder.code = code;
-       pthread_mutex_lock(&refs_mtx);
-       {
+       frr_with_mutex(&refs_mtx) {
                ref = hash_lookup(refs, &holder);
        }
-       pthread_mutex_unlock(&refs_mtx);
 
        return ref;
 }
@@ -118,11 +115,9 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json)
        if (json)
                top = json_object_new_object();
 
-       pthread_mutex_lock(&refs_mtx);
-       {
+       frr_with_mutex(&refs_mtx) {
                errlist = code ? list_new() : hash_to_list(refs);
        }
-       pthread_mutex_unlock(&refs_mtx);
 
        if (code) {
                ref = log_ref_get(code);
@@ -170,7 +165,7 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json)
 
 DEFUN_NOSH(show_error_code,
           show_error_code_cmd,
-          "show error <(1-4294967296)|all> [json]",
+          "show error <(1-4294967295)|all> [json]",
           SHOW_STR
           "Information on errors\n"
           "Error code to get info about\n"
@@ -189,23 +184,19 @@ DEFUN_NOSH(show_error_code,
 
 void log_ref_init(void)
 {
-       pthread_mutex_lock(&refs_mtx);
-       {
+       frr_with_mutex(&refs_mtx) {
                refs = hash_create(ferr_hash_key, ferr_hash_cmp,
                                   "Error Reference Texts");
        }
-       pthread_mutex_unlock(&refs_mtx);
 }
 
 void log_ref_fini(void)
 {
-       pthread_mutex_lock(&refs_mtx);
-       {
+       frr_with_mutex(&refs_mtx) {
                hash_clean(refs, NULL);
                hash_free(refs);
                refs = NULL;
        }
-       pthread_mutex_unlock(&refs_mtx);
 }
 
 void log_ref_vty_init(void)
index bdb6c2a3973a2101b8c5a637dc097f33d9969bfc..21dfc9256ff9fd7708062b51d4f0c3af829166b1 100644 (file)
@@ -49,21 +49,17 @@ static struct list *frr_pthread_list;
 
 void frr_pthread_init(void)
 {
-       pthread_mutex_lock(&frr_pthread_list_mtx);
-       {
+       frr_with_mutex(&frr_pthread_list_mtx) {
                frr_pthread_list = list_new();
                frr_pthread_list->del = (void (*)(void *))&frr_pthread_destroy;
        }
-       pthread_mutex_unlock(&frr_pthread_list_mtx);
 }
 
 void frr_pthread_finish(void)
 {
-       pthread_mutex_lock(&frr_pthread_list_mtx);
-       {
+       frr_with_mutex(&frr_pthread_list_mtx) {
                list_delete(&frr_pthread_list);
        }
-       pthread_mutex_unlock(&frr_pthread_list_mtx);
 }
 
 struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr,
@@ -94,11 +90,9 @@ struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr,
        pthread_mutex_init(fpt->running_cond_mtx, NULL);
        pthread_cond_init(fpt->running_cond, NULL);
 
-       pthread_mutex_lock(&frr_pthread_list_mtx);
-       {
+       frr_with_mutex(&frr_pthread_list_mtx) {
                listnode_add(frr_pthread_list, fpt);
        }
-       pthread_mutex_unlock(&frr_pthread_list_mtx);
 
        return fpt;
 }
@@ -162,23 +156,19 @@ int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr)
 
 void frr_pthread_wait_running(struct frr_pthread *fpt)
 {
-       pthread_mutex_lock(fpt->running_cond_mtx);
-       {
+       frr_with_mutex(fpt->running_cond_mtx) {
                while (!fpt->running)
                        pthread_cond_wait(fpt->running_cond,
                                          fpt->running_cond_mtx);
        }
-       pthread_mutex_unlock(fpt->running_cond_mtx);
 }
 
 void frr_pthread_notify_running(struct frr_pthread *fpt)
 {
-       pthread_mutex_lock(fpt->running_cond_mtx);
-       {
+       frr_with_mutex(fpt->running_cond_mtx) {
                fpt->running = true;
                pthread_cond_signal(fpt->running_cond);
        }
-       pthread_mutex_unlock(fpt->running_cond_mtx);
 }
 
 int frr_pthread_stop(struct frr_pthread *fpt, void **result)
@@ -190,14 +180,12 @@ int frr_pthread_stop(struct frr_pthread *fpt, void **result)
 
 void frr_pthread_stop_all(void)
 {
-       pthread_mutex_lock(&frr_pthread_list_mtx);
-       {
+       frr_with_mutex(&frr_pthread_list_mtx) {
                struct listnode *n;
                struct frr_pthread *fpt;
                for (ALL_LIST_ELEMENTS_RO(frr_pthread_list, n, fpt))
                        frr_pthread_stop(fpt, NULL);
        }
-       pthread_mutex_unlock(&frr_pthread_list_mtx);
 }
 
 /*
index 6096a50370e20ef55add3d0b390c6d663fd0501c..f70c8a0db40b6fd7fd491c0e451960cca1442c59 100644 (file)
@@ -215,6 +215,54 @@ void frr_pthread_stop_all(void);
 #define pthread_condattr_setclock(A, B)
 #endif
 
+/* mutex auto-lock/unlock */
+
+/* variant 1:
+ * (for short blocks, multiple mutexes supported)
+ * break & return can be used for aborting the block
+ *
+ * frr_with_mutex(&mtx, &mtx2) {
+ *    if (error)
+ *       break;
+ *    ...
+ * }
+ */
+#define _frr_with_mutex(mutex)                                                 \
+       *NAMECTR(_mtx_) __attribute__((                                        \
+               unused, cleanup(_frr_mtx_unlock))) = _frr_mtx_lock(mutex),     \
+       /* end */
+
+#define frr_with_mutex(...)                                                    \
+       for (pthread_mutex_t MACRO_REPEAT(_frr_with_mutex, ##__VA_ARGS__)      \
+            *_once = NULL; _once == NULL; _once = (void *)1)                  \
+       /* end */
+
+/* variant 2:
+ * (more suitable for long blocks, no extra indentation)
+ *
+ * frr_mutex_lock_autounlock(&mtx);
+ * ...
+ */
+#define frr_mutex_lock_autounlock(mutex)                                       \
+       pthread_mutex_t *NAMECTR(_mtx_)                                        \
+               __attribute__((unused, cleanup(_frr_mtx_unlock))) =            \
+                                   _frr_mtx_lock(mutex)                       \
+       /* end */
+
+static inline pthread_mutex_t *_frr_mtx_lock(pthread_mutex_t *mutex)
+{
+       pthread_mutex_lock(mutex);
+       return mutex;
+}
+
+static inline void _frr_mtx_unlock(pthread_mutex_t **mutex)
+{
+       if (!*mutex)
+               return;
+       pthread_mutex_unlock(*mutex);
+       *mutex = NULL;
+}
+
 #ifdef __cplusplus
 }
 #endif
index 7e6475b6487e5992a74b8cba5c83632ee5c2d480..54626f909d2a4ccb372f52d2b4cbdbefa5002ed3 100644 (file)
@@ -55,7 +55,6 @@
 #include "atomlist.h"
 
 DEFINE_MTYPE_STATIC(LIB, RCU_THREAD,    "RCU thread")
-DEFINE_MTYPE_STATIC(LIB, RCU_NEXT,      "RCU sequence barrier")
 
 DECLARE_ATOMLIST(rcu_heads, struct rcu_head, head)
 
@@ -226,7 +225,7 @@ static void rcu_bump(void)
 {
        struct rcu_next *rn;
 
-       rn = XMALLOC(MTYPE_RCU_NEXT, sizeof(*rn));
+       rn = XMALLOC(MTYPE_RCU_THREAD, sizeof(*rn));
 
        /* note: each RCUA_NEXT item corresponds to exactly one seqno bump.
         * This means we don't need to communicate which seqno is which
@@ -269,7 +268,7 @@ static void rcu_bump(void)
         * "last item is being deleted - start over" case, and then we may end
         * up accessing old RCU queue items that are already free'd.
         */
-       rcu_free_internal(MTYPE_RCU_NEXT, rn, head_free);
+       rcu_free_internal(MTYPE_RCU_THREAD, rn, head_free);
 
        /* Only allow the RCU sweeper to run after these 2 items are queued.
         *
index 9d9d39702ec9deacb8d85e45849e9ce60e0ac592..7f8a237047f48d3d990c52efe957edee43fccb51 100644 (file)
@@ -28,6 +28,7 @@
 #include "vty.h"
 #include "command.h"
 #include "libfrr.h"
+#include "frr_pthread.h"
 
 DEFINE_MTYPE_STATIC(LIB, HASH, "Hash")
 DEFINE_MTYPE_STATIC(LIB, HASH_BACKET, "Hash Bucket")
@@ -54,14 +55,12 @@ struct hash *hash_create_size(unsigned int size,
        hash->name = name ? XSTRDUP(MTYPE_HASH, name) : NULL;
        hash->stats.empty = hash->size;
 
-       pthread_mutex_lock(&_hashes_mtx);
-       {
+       frr_with_mutex(&_hashes_mtx) {
                if (!_hashes)
                        _hashes = list_new();
 
                listnode_add(_hashes, hash);
        }
-       pthread_mutex_unlock(&_hashes_mtx);
 
        return hash;
 }
@@ -311,8 +310,7 @@ struct list *hash_to_list(struct hash *hash)
 
 void hash_free(struct hash *hash)
 {
-       pthread_mutex_lock(&_hashes_mtx);
-       {
+       frr_with_mutex(&_hashes_mtx) {
                if (_hashes) {
                        listnode_delete(_hashes, hash);
                        if (_hashes->count == 0) {
@@ -320,7 +318,6 @@ void hash_free(struct hash *hash)
                        }
                }
        }
-       pthread_mutex_unlock(&_hashes_mtx);
 
        XFREE(MTYPE_HASH, hash->name);
 
index 9ee2f02e624785b73f249e967a0abccc72f30195..5f92327562e490a18af3807a675b57acd4986f1b 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -45,6 +45,8 @@ DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected")
 DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label")
 DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters")
 
+static struct interface *if_lookup_by_ifindex(ifindex_t ifindex,
+                                             vrf_id_t vrf_id);
 static int if_cmp_func(const struct interface *, const struct interface *);
 static int if_cmp_index_func(const struct interface *ifp1,
                             const struct interface *ifp2);
@@ -257,8 +259,9 @@ void if_delete(struct interface *ifp)
        XFREE(MTYPE_IF, ifp);
 }
 
-/* Interface existance check by index. */
-struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id)
+/* Used only internally to check within VRF only */
+static struct interface *if_lookup_by_ifindex(ifindex_t ifindex,
+                                             vrf_id_t vrf_id)
 {
        struct vrf *vrf;
        struct interface if_tmp;
@@ -271,6 +274,19 @@ struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id)
        return RB_FIND(if_index_head, &vrf->ifaces_by_index, &if_tmp);
 }
 
+/* Interface existance check by index. */
+struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id)
+{
+       switch (vrf_get_backend()) {
+       case VRF_BACKEND_UNKNOWN:
+       case VRF_BACKEND_NETNS:
+               return(if_lookup_by_ifindex(ifindex, vrf_id));
+       case VRF_BACKEND_VRF_LITE:
+               return(if_lookup_by_index_all_vrf(ifindex));
+       }
+       return NULL;
+}
+
 const char *ifindex2ifname(ifindex_t ifindex, vrf_id_t vrf_id)
 {
        struct interface *ifp;
@@ -329,7 +345,7 @@ struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex)
                return NULL;
 
        RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
-               ifp = if_lookup_by_index(ifindex, vrf->vrf_id);
+               ifp = if_lookup_by_ifindex(ifindex, vrf->vrf_id);
                if (ifp)
                        return ifp;
        }
@@ -337,7 +353,7 @@ struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex)
        return NULL;
 }
 
-/* Lookup interface by IPv4 address. */
+/* Lookup interface by IP address. */
 struct interface *if_lookup_exact_address(void *src, int family,
                                          vrf_id_t vrf_id)
 {
@@ -369,7 +385,7 @@ struct interface *if_lookup_exact_address(void *src, int family,
        return NULL;
 }
 
-/* Lookup interface by IPv4 address. */
+/* Lookup interface by IP address. */
 struct connected *if_lookup_address(void *matchaddr, int family,
                                    vrf_id_t vrf_id)
 {
@@ -489,7 +505,7 @@ struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
        switch (vrf_get_backend()) {
        case VRF_BACKEND_UNKNOWN:
        case VRF_BACKEND_NETNS:
-               ifp = if_lookup_by_index(ifindex, vrf_id);
+               ifp = if_lookup_by_ifindex(ifindex, vrf_id);
                if (ifp)
                        return ifp;
                return if_create_ifindex(ifindex, vrf_id);
index 871e319f29fec3bcf3a7e5fd6823b0909dde2c4e..e3ec278f9fbae0cc99d59aceef25c746f27cabd8 100644 (file)
--- a/lib/if.h
+++ b/lib/if.h
@@ -383,16 +383,12 @@ struct connected {
        /* N.B. the ZEBRA_IFA_PEER flag should be set if and only if
           a peer address has been configured.  If this flag is set,
           the destination field must contain the peer address.
-          Otherwise, if this flag is not set, the destination address
-          will either contain a broadcast address or be NULL.
         */
 
        /* Address of connected network. */
        struct prefix *address;
 
-       /* Peer or Broadcast address, depending on whether ZEBRA_IFA_PEER is
-          set.
-          Note: destination may be NULL if ZEBRA_IFA_PEER is not set. */
+       /* Peer address, if ZEBRA_IFA_PEER is set, otherwise NULL */
        struct prefix *destination;
 
        /* Label for Linux 2.2.X and upper. */
index 51a0ddd6b7c2454e5e2a5f3eec748b4cd602ee1f..f1c0fabfbab944a49eeb692d72dac1d20f239f3d 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -31,6 +31,7 @@
 #include "lib_errors.h"
 #include "lib/hook.h"
 #include "printfrr.h"
+#include "frr_pthread.h"
 
 #ifndef SUNOS_5
 #include <sys/un.h>
@@ -83,89 +84,70 @@ static int zlog_filter_lookup(const char *lookup)
 
 void zlog_filter_clear(void)
 {
-       pthread_mutex_lock(&loglock);
-       zlog_filter_count = 0;
-       pthread_mutex_unlock(&loglock);
+       frr_with_mutex(&loglock) {
+               zlog_filter_count = 0;
+       }
 }
 
 int zlog_filter_add(const char *filter)
 {
-       pthread_mutex_lock(&loglock);
+       frr_with_mutex(&loglock) {
+               if (zlog_filter_count >= ZLOG_FILTERS_MAX)
+                       return 1;
 
-       int ret = 0;
+               if (zlog_filter_lookup(filter) != -1)
+                       /* Filter already present */
+                       return -1;
 
-       if (zlog_filter_count >= ZLOG_FILTERS_MAX) {
-               ret = 1;
-               goto done;
-       }
+               strlcpy(zlog_filters[zlog_filter_count], filter,
+                       sizeof(zlog_filters[0]));
 
-       if (zlog_filter_lookup(filter) != -1) {
-               /* Filter already present */
-               ret = -1;
-               goto done;
-       }
+               if (zlog_filters[zlog_filter_count][0] == '\0')
+                       /* Filter was either empty or didn't get copied
+                        * correctly
+                        */
+                       return -1;
 
-       strlcpy(zlog_filters[zlog_filter_count], filter,
-               sizeof(zlog_filters[0]));
-
-       if (zlog_filters[zlog_filter_count][0] == '\0') {
-               /* Filter was either empty or didn't get copied correctly */
-               ret = -1;
-               goto done;
+               zlog_filter_count++;
        }
-
-       zlog_filter_count++;
-
-done:
-       pthread_mutex_unlock(&loglock);
-       return ret;
+       return 0;
 }
 
 int zlog_filter_del(const char *filter)
 {
-       pthread_mutex_lock(&loglock);
-
-       int found_idx = zlog_filter_lookup(filter);
-       int last_idx = zlog_filter_count - 1;
-       int ret = 0;
+       frr_with_mutex(&loglock) {
+               int found_idx = zlog_filter_lookup(filter);
+               int last_idx = zlog_filter_count - 1;
 
-       if (found_idx == -1) {
-               /* Didn't find the filter to delete */
-               ret = -1;
-               goto done;
-       }
-
-       /* Adjust the filter array */
-       memmove(zlog_filters[found_idx], zlog_filters[found_idx + 1],
-               (last_idx - found_idx) * sizeof(zlog_filters[0]));
+               if (found_idx == -1)
+                       /* Didn't find the filter to delete */
+                       return -1;
 
-       zlog_filter_count--;
+               /* Adjust the filter array */
+               memmove(zlog_filters[found_idx], zlog_filters[found_idx + 1],
+                       (last_idx - found_idx) * sizeof(zlog_filters[0]));
 
-done:
-       pthread_mutex_unlock(&loglock);
-       return ret;
+               zlog_filter_count--;
+       }
+       return 0;
 }
 
 /* Dump all filters to buffer, delimited by new line */
 int zlog_filter_dump(char *buf, size_t max_size)
 {
-       pthread_mutex_lock(&loglock);
-
-       int ret = 0;
        int len = 0;
 
-       for (int i = 0; i < zlog_filter_count; i++) {
-               ret = snprintf(buf + len, max_size - len, " %s\n",
-                              zlog_filters[i]);
-               len += ret;
-               if ((ret < 0) || ((size_t)len >= max_size)) {
-                       len = -1;
-                       goto done;
+       frr_with_mutex(&loglock) {
+               for (int i = 0; i < zlog_filter_count; i++) {
+                       int ret;
+                       ret = snprintf(buf + len, max_size - len, " %s\n",
+                                      zlog_filters[i]);
+                       len += ret;
+                       if ((ret < 0) || ((size_t)len >= max_size))
+                               return -1;
                }
        }
 
-done:
-       pthread_mutex_unlock(&loglock);
        return len;
 }
 
@@ -363,7 +345,7 @@ search:
 /* va_list version of zlog. */
 void vzlog(int priority, const char *format, va_list args)
 {
-       pthread_mutex_lock(&loglock);
+       frr_mutex_lock_autounlock(&loglock);
 
        char proto_str[32] = "";
        int original_errno = errno;
@@ -430,36 +412,31 @@ out:
        if (msg != buf)
                XFREE(MTYPE_TMP, msg);
        errno = original_errno;
-       pthread_mutex_unlock(&loglock);
 }
 
 int vzlog_test(int priority)
 {
-       pthread_mutex_lock(&loglock);
-
-       int ret = 0;
+       frr_mutex_lock_autounlock(&loglock);
 
        struct zlog *zl = zlog_default;
 
        /* When zlog_default is also NULL, use stderr for logging. */
        if (zl == NULL)
-               ret = 1;
+               return 1;
        /* Syslog output */
        else if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG])
-               ret = 1;
+               return 1;
        /* File output. */
        else if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp)
-               ret = 1;
+               return 1;
        /* stdout output. */
        else if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT])
-               ret = 1;
+               return 1;
        /* Terminal monitor. */
        else if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR])
-               ret = 1;
-
-       pthread_mutex_unlock(&loglock);
+               return 1;
 
-       return ret;
+       return 0;
 }
 
 /*
@@ -870,9 +847,9 @@ void openzlog(const char *progname, const char *protoname,
 
        openlog(progname, syslog_flags, zl->facility);
 
-       pthread_mutex_lock(&loglock);
-       zlog_default = zl;
-       pthread_mutex_unlock(&loglock);
+       frr_with_mutex(&loglock) {
+               zlog_default = zl;
+       }
 
 #ifdef HAVE_GLIBC_BACKTRACE
        /* work around backtrace() using lazily resolved dynamically linked
@@ -889,7 +866,8 @@ void openzlog(const char *progname, const char *protoname,
 
 void closezlog(void)
 {
-       pthread_mutex_lock(&loglock);
+       frr_mutex_lock_autounlock(&loglock);
+
        struct zlog *zl = zlog_default;
 
        closelog();
@@ -901,15 +879,14 @@ void closezlog(void)
 
        XFREE(MTYPE_ZLOG, zl);
        zlog_default = NULL;
-       pthread_mutex_unlock(&loglock);
 }
 
 /* Called from command.c. */
 void zlog_set_level(zlog_dest_t dest, int log_level)
 {
-       pthread_mutex_lock(&loglock);
-       zlog_default->maxlvl[dest] = log_level;
-       pthread_mutex_unlock(&loglock);
+       frr_with_mutex(&loglock) {
+               zlog_default->maxlvl[dest] = log_level;
+       }
 }
 
 int zlog_set_file(const char *filename, int log_level)
@@ -929,15 +906,15 @@ int zlog_set_file(const char *filename, int log_level)
        if (fp == NULL) {
                ret = 0;
        } else {
-               pthread_mutex_lock(&loglock);
-               zl = zlog_default;
-
-               /* Set flags. */
-               zl->filename = XSTRDUP(MTYPE_ZLOG, filename);
-               zl->maxlvl[ZLOG_DEST_FILE] = log_level;
-               zl->fp = fp;
-               logfile_fd = fileno(fp);
-               pthread_mutex_unlock(&loglock);
+               frr_with_mutex(&loglock) {
+                       zl = zlog_default;
+
+                       /* Set flags. */
+                       zl->filename = XSTRDUP(MTYPE_ZLOG, filename);
+                       zl->maxlvl[ZLOG_DEST_FILE] = log_level;
+                       zl->fp = fp;
+                       logfile_fd = fileno(fp);
+               }
        }
 
        return ret;
@@ -946,7 +923,7 @@ int zlog_set_file(const char *filename, int log_level)
 /* Reset opend file. */
 int zlog_reset_file(void)
 {
-       pthread_mutex_lock(&loglock);
+       frr_mutex_lock_autounlock(&loglock);
 
        struct zlog *zl = zlog_default;
 
@@ -959,8 +936,6 @@ int zlog_reset_file(void)
        XFREE(MTYPE_ZLOG, zl->filename);
        zl->filename = NULL;
 
-       pthread_mutex_unlock(&loglock);
-
        return 1;
 }
 
index ca27c45dc61437242634b786940095bdc89283a9..e246f177de3ba4d1ed4d6cc12e6a25cd877e2ccf 100644 (file)
@@ -84,6 +84,20 @@ static inline int64_t monotime_until(const struct timeval *ref,
        return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
 }
 
+static inline time_t monotime_to_realtime(const struct timeval *mono,
+                                         struct timeval *realout)
+{
+       struct timeval delta, real;
+
+       monotime_since(mono, &delta);
+       gettimeofday(&real, NULL);
+
+       timersub(&real, &delta, &real);
+       if (realout)
+               *realout = real;
+       return real.tv_sec;
+}
+
 /* Char buffer size for time-to-string api */
 #define MONOTIME_STRLEN 32
 
index 48b450e969c9e0f7537b99e0218ed4c6c88d4ebf..a814f23e14421d0b65a832d7fc4e5b33758c234a 100644 (file)
@@ -26,6 +26,7 @@
 #include "command.h"
 #include "debug.h"
 #include "db.h"
+#include "frr_pthread.h"
 #include "northbound.h"
 #include "northbound_cli.h"
 #include "northbound_db.h"
@@ -723,8 +724,7 @@ int nb_running_lock(enum nb_client client, const void *user)
 {
        int ret = -1;
 
-       pthread_mutex_lock(&running_config_mgmt_lock.mtx);
-       {
+       frr_with_mutex(&running_config_mgmt_lock.mtx) {
                if (!running_config_mgmt_lock.locked) {
                        running_config_mgmt_lock.locked = true;
                        running_config_mgmt_lock.owner_client = client;
@@ -732,7 +732,6 @@ int nb_running_lock(enum nb_client client, const void *user)
                        ret = 0;
                }
        }
-       pthread_mutex_unlock(&running_config_mgmt_lock.mtx);
 
        return ret;
 }
@@ -741,8 +740,7 @@ int nb_running_unlock(enum nb_client client, const void *user)
 {
        int ret = -1;
 
-       pthread_mutex_lock(&running_config_mgmt_lock.mtx);
-       {
+       frr_with_mutex(&running_config_mgmt_lock.mtx) {
                if (running_config_mgmt_lock.locked
                    && running_config_mgmt_lock.owner_client == client
                    && running_config_mgmt_lock.owner_user == user) {
@@ -752,7 +750,6 @@ int nb_running_unlock(enum nb_client client, const void *user)
                        ret = 0;
                }
        }
-       pthread_mutex_unlock(&running_config_mgmt_lock.mtx);
 
        return ret;
 }
@@ -761,14 +758,12 @@ int nb_running_lock_check(enum nb_client client, const void *user)
 {
        int ret = -1;
 
-       pthread_mutex_lock(&running_config_mgmt_lock.mtx);
-       {
+       frr_with_mutex(&running_config_mgmt_lock.mtx) {
                if (!running_config_mgmt_lock.locked
                    || (running_config_mgmt_lock.owner_client == client
                        && running_config_mgmt_lock.owner_user == user))
                        ret = 0;
        }
-       pthread_mutex_unlock(&running_config_mgmt_lock.mtx);
 
        return ret;
 }
index 69d7c8e0ee68e5ce19bb0bb8eab80cc6b3553b2e..ce79d907f9fd9aca81e6eb2bb97b823688f7be12 100644 (file)
@@ -347,15 +347,6 @@ struct nb_callbacks {
         * dnode
         *    libyang data node that should be shown in the form of a CLI
         *    command.
-        *
-        * show_defaults
-        *    Specify whether to display default configuration values or not.
-        *    This parameter can be ignored most of the time since the
-        *    northbound doesn't call this callback for default leaves or
-        *    non-presence containers that contain only default child nodes.
-        *    The exception are commands associated to multiple configuration
-        *    nodes, in which case it might be desirable to hide one or more
-        *    parts of the command when this parameter is set to false.
         */
        void (*cli_show_end)(struct vty *vty, struct lyd_node *dnode);
 };
index c691bb27aaf7f7a7a7db1db5206d3b1fb3b01f7a..884c01a457ec712de33cfe6bb45fbfd73e9e16cc 100644 (file)
@@ -757,7 +757,7 @@ DEFPY (config_load,
        "configuration load\
           <\
            file [<json$json|xml$xml> [translate WORD$translator_family]] FILENAME$filename\
-           |transaction (1-4294967296)$tid\
+           |transaction (1-4294967295)$tid\
          >\
          [replace$replace]",
        "Configuration related settings\n"
@@ -923,12 +923,12 @@ DEFPY (show_config_compare,
           <\
            candidate$c1_candidate\
            |running$c1_running\
-           |transaction (1-4294967296)$c1_tid\
+           |transaction (1-4294967295)$c1_tid\
          >\
           <\
            candidate$c2_candidate\
            |running$c2_running\
-           |transaction (1-4294967296)$c2_tid\
+           |transaction (1-4294967295)$c2_tid\
          >\
          [<json$json|xml$xml> [translate WORD$translator_family]]",
        SHOW_STR
@@ -1029,11 +1029,11 @@ ALIAS (show_config_compare,
        "show configuration compare\
           <\
            running$c1_running\
-           |transaction (1-4294967296)$c1_tid\
+           |transaction (1-4294967295)$c1_tid\
          >\
           <\
            running$c2_running\
-           |transaction (1-4294967296)$c2_tid\
+           |transaction (1-4294967295)$c2_tid\
          >\
         [<json$json|xml$xml> [translate WORD$translator_family]]",
        SHOW_STR
@@ -1192,7 +1192,7 @@ DEFPY (show_config_transaction,
        show_config_transaction_cmd,
        "show configuration transaction\
           [\
-           (1-4294967296)$transaction_id\
+           (1-4294967295)$transaction_id\
            [<json$json|xml$xml> [translate WORD$translator_family]]\
             [<\
              with-defaults$with_defaults\
@@ -1593,7 +1593,7 @@ static int nb_cli_rollback_configuration(struct vty *vty,
 
 DEFPY (rollback_config,
        rollback_config_cmd,
-       "rollback configuration (1-4294967296)$transaction_id",
+       "rollback configuration (1-4294967295)$transaction_id",
        "Rollback to a previous state\n"
        "Running configuration\n"
        "Transaction ID\n")
index 44a55137f82e23e93227c74369b1aaa7a5f52695..77183282bab1ffff83a2f75e099a30817ea17d3e 100644 (file)
@@ -425,7 +425,7 @@ static int frr_sr_state_cb(const char *xpath, sr_val_t **values,
 exit:
        list_delete(&elements);
        *values = NULL;
-       values_cnt = 0;
+       *values_cnt = 0;
 
        return SR_ERR_OK;
 }
index 053e4533e7b152c5a1d8191b8fabea4c49aec1bd..35b679ab90fbef48a76c2c3f74cb96f3be95307f 100644 (file)
@@ -853,7 +853,7 @@ void prefix_ipv4_free(struct prefix_ipv4 *p)
        prefix_free((struct prefix *)p);
 }
 
-/* When string format is invalid return 0. */
+/* If given string is valid return 1 else return 0 */
 int str2prefix_ipv4(const char *str, struct prefix_ipv4 *p)
 {
        int ret;
@@ -881,8 +881,10 @@ int str2prefix_ipv4(const char *str, struct prefix_ipv4 *p)
                cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1);
                memcpy(cp, str, pnt - str);
                *(cp + (pnt - str)) = '\0';
-               ret = inet_aton(cp, &p->prefix);
+               ret = inet_pton(AF_INET, cp, &p->prefix);
                XFREE(MTYPE_TMP, cp);
+               if (ret == 0)
+                       return 0;
 
                /* Get prefix length. */
                plen = (uint8_t)atoi(++pnt);
@@ -1023,7 +1025,7 @@ void prefix_ipv6_free(struct prefix_ipv6 *p)
        prefix_free((struct prefix *)p);
 }
 
-/* If given string is valid return pin6 else return NULL */
+/* If given string is valid return 1 else return 0 */
 int str2prefix_ipv6(const char *str, struct prefix_ipv6 *p)
 {
        char *pnt;
index a3314c6c3ca977a5782d26e6851ec3720336b5f2..09efedf68460ac3ab3ce749d4203242810ef6fbb 100644 (file)
@@ -24,6 +24,7 @@
 #include "log.h"
 #include "privs.h"
 #include "memory.h"
+#include "frr_pthread.h"
 #include "lib_errors.h"
 #include "lib/queue.h"
 
@@ -760,8 +761,7 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
         * Serialize 'raise' operations; particularly important for
         * OSes where privs are process-wide.
         */
-       pthread_mutex_lock(&(privs->mutex));
-       {
+       frr_with_mutex(&(privs->mutex)) {
                /* Locate ref-counting object to use */
                refs = get_privs_refs(privs);
 
@@ -775,7 +775,6 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
                        refs->raised_in_funcname = funcname;
                }
        }
-       pthread_mutex_unlock(&(privs->mutex));
 
        return privs;
 }
@@ -791,8 +790,7 @@ void _zprivs_lower(struct zebra_privs_t **privs)
        /* Serialize 'lower privs' operation - particularly important
         * when OS privs are process-wide.
         */
-       pthread_mutex_lock(&(*privs)->mutex);
-       {
+       frr_with_mutex(&(*privs)->mutex) {
                refs = get_privs_refs(*privs);
 
                if (--(refs->refcount) == 0) {
@@ -806,7 +804,6 @@ void _zprivs_lower(struct zebra_privs_t **privs)
                        refs->raised_in_funcname = NULL;
                }
        }
-       pthread_mutex_unlock(&(*privs)->mutex);
 
        *privs = NULL;
 }
index 2b0b44b3f2f7ca485a3a7e52303592fdc67fac2a..db5707d6750a010b165588b82d66f517fb4b7f28 100644 (file)
@@ -109,16 +109,16 @@ extern void zprivs_get_ids(struct zprivs_ids_t *);
 
 /*
  * Wrapper around zprivs, to be used as:
- *   frr_elevate_privs(&privs) {
+ *   frr_with_privs(&privs) {
  *     ... code ...
  *     if (error)
  *       break;         -- break can be used to get out of the block
  *     ... code ...
  *   }
  *
- * The argument to frr_elevate_privs() can be NULL to leave privileges as-is
+ * The argument to frr_with_privs() can be NULL to leave privileges as-is
  * (mostly useful for conditional privilege-raising, i.e.:)
- *   frr_elevate_privs(cond ? &privs : NULL) {}
+ *   frr_with_privs(cond ? &privs : NULL) {}
  *
  * NB: The code block is always executed, regardless of whether privileges
  * could be raised or not, or whether NULL was given or not.  This is fully
@@ -138,7 +138,7 @@ extern struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
                                           const char *funcname);
 extern void _zprivs_lower(struct zebra_privs_t **privs);
 
-#define frr_elevate_privs(privs)                                               \
+#define frr_with_privs(privs)                                               \
        for (struct zebra_privs_t *_once = NULL,                               \
                                  *_privs __attribute__(                       \
                                          (unused, cleanup(_zprivs_lower))) =  \
diff --git a/lib/pullwr.c b/lib/pullwr.c
new file mode 100644 (file)
index 0000000..0c326f2
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Pull-driven write event handler
+ * Copyright (C) 2019  David Lamparter
+ *
+ * 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 "pullwr.h"
+#include "memory.h"
+#include "monotime.h"
+
+/* defaults */
+#define PULLWR_THRESH  16384   /* size at which we start to call write() */
+#define PULLWR_MAXSPIN 2500    /* max Âµs to spend grabbing more data */
+
+struct pullwr {
+       int fd;
+       struct thread_master *tm;
+       /* writer == NULL <=> we're idle */
+       struct thread *writer;
+
+       void *arg;
+       void (*fill)(void *, struct pullwr *);
+       void (*err)(void *, struct pullwr *, bool);
+
+       /* ring buffer (although it's "un-ringed" on resizing, it WILL wrap
+        * around if data is trickling in while keeping it at a constant size)
+        */
+       size_t bufsz, valid, pos;
+       uint64_t total_written;
+       char *buffer;
+
+       size_t thresh;          /* PULLWR_THRESH */
+       int64_t maxspin;        /* PULLWR_MAXSPIN */
+};
+
+DEFINE_MTYPE_STATIC(LIB, PULLWR_HEAD, "pull-driven write controller")
+DEFINE_MTYPE_STATIC(LIB, PULLWR_BUF,  "pull-driven write buffer")
+
+static int pullwr_run(struct thread *t);
+
+struct pullwr *_pullwr_new(struct thread_master *tm, int fd,
+               void *arg,
+               void (*fill)(void *, struct pullwr *),
+               void (*err)(void *, struct pullwr *, bool))
+{
+       struct pullwr *pullwr;
+
+       pullwr = XCALLOC(MTYPE_PULLWR_HEAD, sizeof(*pullwr));
+       pullwr->fd = fd;
+       pullwr->tm = tm;
+       pullwr->arg = arg;
+       pullwr->fill = fill;
+       pullwr->err = err;
+
+       pullwr->thresh = PULLWR_THRESH;
+       pullwr->maxspin = PULLWR_MAXSPIN;
+
+       return pullwr;
+}
+
+void pullwr_del(struct pullwr *pullwr)
+{
+       THREAD_OFF(pullwr->writer);
+
+       XFREE(MTYPE_PULLWR_BUF, pullwr->buffer);
+       XFREE(MTYPE_PULLWR_HEAD, pullwr);
+}
+
+void pullwr_cfg(struct pullwr *pullwr, int64_t max_spin_usec,
+               size_t write_threshold)
+{
+       pullwr->maxspin = max_spin_usec ?: PULLWR_MAXSPIN;
+       pullwr->thresh = write_threshold ?: PULLWR_THRESH;
+}
+
+void pullwr_bump(struct pullwr *pullwr)
+{
+       if (pullwr->writer)
+               return;
+
+       thread_add_timer(pullwr->tm, pullwr_run, pullwr, 0, &pullwr->writer);
+}
+
+static size_t pullwr_iov(struct pullwr *pullwr, struct iovec *iov)
+{
+       size_t len1;
+
+       if (pullwr->valid == 0)
+               return 0;
+
+       if (pullwr->pos + pullwr->valid <= pullwr->bufsz) {
+               iov[0].iov_base = pullwr->buffer + pullwr->pos;
+               iov[0].iov_len = pullwr->valid;
+               return 1;
+       }
+
+       len1 = pullwr->bufsz - pullwr->pos;
+
+       iov[0].iov_base = pullwr->buffer + pullwr->pos;
+       iov[0].iov_len = len1;
+       iov[1].iov_base = pullwr->buffer;
+       iov[1].iov_len = pullwr->valid - len1;
+       return 2;
+}
+
+static void pullwr_resize(struct pullwr *pullwr, size_t need)
+{
+       struct iovec iov[2];
+       size_t niov, newsize;
+       char *newbuf;
+
+       /* the buffer is maintained at pullwr->thresh * 2 since we'll be
+        * trying to fill it as long as it's anywhere below pullwr->thresh.
+        * That means we frequently end up a little short of it and then write
+        * something that goes over the threshold.  So, just use double.
+        */
+       if (need) {
+               /* resize up */
+               if (pullwr->bufsz - pullwr->valid >= need)
+                       return;
+
+               newsize = MAX((pullwr->valid + need) * 2, pullwr->thresh * 2);
+               newbuf = XMALLOC(MTYPE_PULLWR_BUF, newsize);
+       } else if (!pullwr->valid) {
+               /* resize down, buffer empty */
+               newsize = 0;
+               newbuf = NULL;
+       } else {
+               /* resize down */
+               if (pullwr->bufsz - pullwr->valid < pullwr->thresh)
+                       return;
+               newsize = MAX(pullwr->valid, pullwr->thresh * 2);
+               newbuf = XMALLOC(MTYPE_PULLWR_BUF, newsize);
+       }
+
+       niov = pullwr_iov(pullwr, iov);
+       if (niov >= 1) {
+               memcpy(newbuf, iov[0].iov_base, iov[0].iov_len);
+               if (niov >= 2)
+                       memcpy(newbuf + iov[0].iov_len,
+                               iov[1].iov_base, iov[1].iov_len);
+       }
+
+       XFREE(MTYPE_PULLWR_BUF, pullwr->buffer);
+       pullwr->buffer = newbuf;
+       pullwr->bufsz = newsize;
+       pullwr->pos = 0;
+}
+
+void pullwr_write(struct pullwr *pullwr, const void *data, size_t len)
+{
+       pullwr_resize(pullwr, len);
+
+       if (pullwr->pos + pullwr->valid > pullwr->bufsz) {
+               size_t pos;
+
+               pos = (pullwr->pos + pullwr->valid) % pullwr->bufsz;
+               memcpy(pullwr->buffer + pos, data, len);
+       } else {
+               size_t max1, len1;
+               max1 = pullwr->bufsz - (pullwr->pos + pullwr->valid);
+               max1 = MIN(max1, len);
+
+               memcpy(pullwr->buffer + pullwr->pos + pullwr->valid,
+                               data, max1);
+               len1 = len - max1;
+
+               if (len1)
+                       memcpy(pullwr->buffer, (char *)data + max1, len1);
+
+       }
+       pullwr->valid += len;
+
+       pullwr_bump(pullwr);
+}
+
+static int pullwr_run(struct thread *t)
+{
+       struct pullwr *pullwr = THREAD_ARG(t);
+       struct iovec iov[2];
+       size_t niov, lastvalid;
+       ssize_t nwr;
+       struct timeval t0;
+       bool maxspun = false;
+
+       monotime(&t0);
+
+       do {
+               lastvalid = pullwr->valid - 1;
+               while (pullwr->valid < pullwr->thresh
+                               && pullwr->valid != lastvalid
+                               && !maxspun) {
+                       lastvalid = pullwr->valid;
+                       pullwr->fill(pullwr->arg, pullwr);
+
+                       /* check after doing at least one fill() call so we
+                        * don't spin without making progress on slow boxes
+                        */
+                       if (!maxspun && monotime_since(&t0, NULL)
+                                       >= pullwr->maxspin)
+                               maxspun = true;
+               }
+
+               if (pullwr->valid == 0) {
+                       /* we made a fill() call above that didn't feed any
+                        * data in, and we have nothing more queued, so we go
+                        * into idle, i.e. no calling thread_add_write()
+                        */
+                       pullwr_resize(pullwr, 0);
+                       return 0;
+               }
+
+               niov = pullwr_iov(pullwr, iov);
+               assert(niov);
+
+               nwr = writev(pullwr->fd, iov, niov);
+               if (nwr < 0) {
+                       if (errno == EAGAIN || errno == EWOULDBLOCK)
+                               break;
+                       pullwr->err(pullwr->arg, pullwr, false);
+                       return 0;
+               }
+
+               if (nwr == 0) {
+                       pullwr->err(pullwr->arg, pullwr, true);
+                       return 0;
+               }
+
+               pullwr->total_written += nwr;
+               pullwr->valid -= nwr;
+               pullwr->pos += nwr;
+               pullwr->pos %= pullwr->bufsz;
+       } while (pullwr->valid == 0 && !maxspun);
+       /* pullwr->valid != 0 implies we did an incomplete write, i.e. socket
+        * is full and we go wait until it's available for writing again.
+        */
+
+       thread_add_write(pullwr->tm, pullwr_run, pullwr, pullwr->fd,
+                       &pullwr->writer);
+
+       /* if we hit the time limit, just keep the buffer, we'll probably need
+        * it anyway & another run is already coming up.
+        */
+       if (!maxspun)
+               pullwr_resize(pullwr, 0);
+       return 0;
+}
+
+void pullwr_stats(struct pullwr *pullwr, uint64_t *total_written,
+                 size_t *pending, size_t *kernel_pending)
+{
+       int tmp;
+
+       *total_written = pullwr->total_written;
+       *pending = pullwr->valid;
+
+       if (ioctl(pullwr->fd, TIOCOUTQ, &tmp) != 0)
+               tmp = 0;
+       *kernel_pending = tmp;
+}
diff --git a/lib/pullwr.h b/lib/pullwr.h
new file mode 100644 (file)
index 0000000..601eac1
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Pull-driven write event handler
+ * Copyright (C) 2019  David Lamparter
+ *
+ * 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 _WRITEPOLL_H
+#define _WRITEPOLL_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "thread.h"
+#include "stream.h"
+
+struct pullwr;
+
+/* This is a "pull-driven" write event handler.  Instead of having some buffer
+ * or being driven by the availability of data, it triggers on the space being
+ * available on the socket for data to be written on and then calls fill() to
+ * get data to be sent.
+ *
+ * pullwr_* maintains an "idle" vs. "active" state, going into idle when a
+ * fill() call completes without feeing more data into it.  The overall
+ * semantics are:
+ * - to put data out, call pullwr_write().  This is possible from both inside
+ *   fill() callbacks or anywhere else.  Doing so puts the pullwr into
+ *   active state.
+ * - in active state, the fill() callback will be called and should feed more
+ *   data in.  It should NOT loop to push out more than one "unit" of data;
+ *   the pullwr code handles this by calling fill() until it has enough data.
+ * - if there's nothing more to be sent, fill() returns without doing anything
+ *   and pullwr goes into idle state after flushing all buffered data out.
+ * - when new data becomes available, pullwr_bump() should be called to put
+ *   the pullwr back into active mode so it will collect data from fill(),
+ *   or you can directly call pullwr_write().
+ * - only calling pullwr_write() from within fill() is the cleanest way of
+ *   doing things.
+ *
+ * When the err() callback is called, the pullwr should be considered unusable
+ * and released with pullwr_del().  This can be done from inside the callback,
+ * the pullwr code holds no more references on it when calling err().
+ */
+extern struct pullwr *_pullwr_new(struct thread_master *tm, int fd,
+               void *arg,
+               void (*fill)(void *, struct pullwr *),
+               void (*err)(void *, struct pullwr *, bool eof));
+extern void pullwr_del(struct pullwr *pullwr);
+
+/* type-checking wrapper.  makes sure fill() and err() take a first argument
+ * whose type is identical to the type of arg.
+ * => use "void fill(struct mystruct *arg, ...)" - no "void *arg"
+ */
+#define pullwr_new(tm, fd, arg, fill, err) ({                                  \
+       void (*fill_typechk)(typeof(arg), struct pullwr *) = fill;          \
+       void (*err_typechk)(typeof(arg), struct pullwr *, bool) = err;      \
+       _pullwr_new(tm, fd, arg, (void *)fill_typechk, (void *)err_typechk);   \
+})
+
+/* max_spin_usec is the time after which the pullwr event handler will stop
+ *   trying to get more data from fill() and yield control back to the
+ *   thread_master.  It does reschedule itself to continue later; this is
+ *   only to make sure we don't freeze the entire process if we're piping a
+ *   lot of data to a local endpoint that reads quickly (i.e. no backpressure)
+ *
+ *   default: 2500 (2.5 ms)
+ *
+ * write_threshold is the amount of data buffered from fill() calls at which
+ *   the pullwr code starts calling write().  But this is not a "limit".
+ *   pullwr will keep poking fill() for more data until
+ *   (a) max_spin_usec is reached; fill() will be called again later after
+ *       returning to the thread_master to give other events a chance to run
+ *   (b) fill() returns without pushing any data onto the pullwr with
+ *       pullwr_write(), so fill() will NOT be called again until a call to
+ *       pullwr_bump() or pullwr_write() comes in.
+ *
+ *   default: 16384 (16 kB)
+ *
+ * passing 0 for either value (or not calling it at all) uses the default.
+ */
+extern void pullwr_cfg(struct pullwr *pullwr, int64_t max_spin_usec,
+                      size_t write_threshold);
+
+extern void pullwr_bump(struct pullwr *pullwr);
+extern void pullwr_write(struct pullwr *pullwr,
+               const void *data, size_t len);
+
+static inline void pullwr_write_stream(struct pullwr *pullwr,
+               struct stream *s)
+{
+       pullwr_write(pullwr, s->data, stream_get_endp(s));
+}
+
+extern void pullwr_stats(struct pullwr *pullwr, uint64_t *total_written,
+                        size_t *pending, size_t *kernel_pending);
+
+#endif /* _WRITEPOLL_H */
index eca02e8366779b4ac8fb710de7cda7d20631f574..fc15183bf95c8d029b5438f42c0d06751f4c6304 100644 (file)
@@ -474,7 +474,7 @@ int generic_match_add(struct vty *vty, struct route_map_index *index,
                      const char *command, const char *arg,
                      route_map_event_t type)
 {
-       int ret;
+       enum rmap_compile_rets ret;
 
        ret = route_map_add_match(index, command, arg, type);
        switch (ret) {
@@ -493,6 +493,11 @@ int generic_match_add(struct vty *vty, struct route_map_index *index,
                        frr_protonameinst);
                return CMD_WARNING_CONFIG_FAILED;
                break;
+       case RMAP_DUPLICATE_RULE:
+               /*
+                * Nothing to do here move along
+                */
+               break;
        }
 
        return CMD_SUCCESS;
@@ -502,7 +507,7 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index,
                         const char *command, const char *arg,
                         route_map_event_t type)
 {
-       int ret;
+       enum rmap_compile_rets ret;
        int retval = CMD_SUCCESS;
        char *dep_name = NULL;
        const char *tmpstr;
@@ -537,6 +542,11 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index,
                if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
                        route_map_upd8_dependency(type, dep_name, rmap_name);
                break;
+       case RMAP_DUPLICATE_RULE:
+               /*
+                * Nothing to do here
+                */
+               break;
        }
 
        XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
@@ -548,7 +558,7 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index,
 int generic_set_add(struct vty *vty, struct route_map_index *index,
                    const char *command, const char *arg)
 {
-       int ret;
+       enum rmap_compile_rets ret;
 
        ret = route_map_add_set(index, command, arg);
        switch (ret) {
@@ -563,6 +573,7 @@ int generic_set_add(struct vty *vty, struct route_map_index *index,
                return CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
+       case RMAP_DUPLICATE_RULE:
                break;
        }
 
@@ -572,7 +583,7 @@ int generic_set_add(struct vty *vty, struct route_map_index *index,
 int generic_set_delete(struct vty *vty, struct route_map_index *index,
                       const char *command, const char *arg)
 {
-       int ret;
+       enum rmap_compile_rets ret;
 
        ret = route_map_delete_set(index, command, arg);
        switch (ret) {
@@ -587,6 +598,7 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index,
                return CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
+       case RMAP_DUPLICATE_RULE:
                break;
        }
 
@@ -1388,8 +1400,10 @@ static route_map_event_t get_route_map_delete_event(route_map_event_t type)
 }
 
 /* Add match statement to route map. */
-int route_map_add_match(struct route_map_index *index, const char *match_name,
-                       const char *match_arg, route_map_event_t type)
+enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
+                                          const char *match_name,
+                                          const char *match_arg,
+                                          route_map_event_t type)
 {
        struct route_map_rule *rule;
        struct route_map_rule *next;
@@ -1464,15 +1478,16 @@ int route_map_add_match(struct route_map_index *index, const char *match_name,
 }
 
 /* Delete specified route match rule. */
-int route_map_delete_match(struct route_map_index *index,
-                          const char *match_name, const char *match_arg)
+enum rmap_compile_rets route_map_delete_match(struct route_map_index *index,
+                                             const char *match_name,
+                                             const char *match_arg)
 {
        struct route_map_rule *rule;
        struct route_map_rule_cmd *cmd;
 
        cmd = route_map_lookup_match(match_name);
        if (cmd == NULL)
-               return 1;
+               return RMAP_RULE_MISSING;
 
        for (rule = index->match_list.head; rule; rule = rule->next)
                if (rule->cmd == cmd && (rulecmp(rule->rule_str, match_arg) == 0
@@ -1485,15 +1500,16 @@ int route_map_delete_match(struct route_map_index *index,
                                        index->map->name,
                                        RMAP_EVENT_CALL_ADDED);
                        }
-                       return 0;
+                       return RMAP_COMPILE_SUCCESS;
                }
        /* Can't find matched rule. */
-       return 1;
+       return RMAP_RULE_MISSING;
 }
 
 /* Add route-map set statement to the route map. */
-int route_map_add_set(struct route_map_index *index, const char *set_name,
-                     const char *set_arg)
+enum rmap_compile_rets route_map_add_set(struct route_map_index *index,
+                                        const char *set_name,
+                                        const char *set_arg)
 {
        struct route_map_rule *rule;
        struct route_map_rule *next;
@@ -1543,15 +1559,16 @@ int route_map_add_set(struct route_map_index *index, const char *set_name,
 }
 
 /* Delete route map set rule. */
-int route_map_delete_set(struct route_map_index *index, const char *set_name,
-                        const char *set_arg)
+enum rmap_compile_rets route_map_delete_set(struct route_map_index *index,
+                                           const char *set_name,
+                                           const char *set_arg)
 {
        struct route_map_rule *rule;
        struct route_map_rule_cmd *cmd;
 
        cmd = route_map_lookup_set(set_name);
        if (cmd == NULL)
-               return 1;
+               return RMAP_RULE_MISSING;
 
        for (rule = index->set_list.head; rule; rule = rule->next)
                if ((rule->cmd == cmd) && (rulecmp(rule->rule_str, set_arg) == 0
@@ -1564,10 +1581,10 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name,
                                        index->map->name,
                                        RMAP_EVENT_CALL_ADDED);
                        }
-                       return 0;
+                       return RMAP_COMPILE_SUCCESS;
                }
        /* Can't find matched rule. */
-       return 1;
+       return RMAP_RULE_MISSING;
 }
 
 static enum route_map_cmd_result_t
index f9ad0f64a984fe0e1ba21e5e5904d01ac9a8a9c2..40525987e94662d8ef0b544d1f9fbd96ea111c12 100644 (file)
@@ -126,7 +126,7 @@ struct route_map_rule_cmd {
 };
 
 /* Route map apply error. */
-enum {
+enum rmap_compile_rets {
        RMAP_COMPILE_SUCCESS,
 
        /* Route map rule is missing. */
@@ -220,25 +220,28 @@ extern void route_map_init(void);
 extern void route_map_finish(void);
 
 /* Add match statement to route map. */
-extern int route_map_add_match(struct route_map_index *index,
-                              const char *match_name, const char *match_arg,
-                              route_map_event_t type);
+extern enum rmap_compile_rets route_map_add_match(struct route_map_index *index,
+                                                 const char *match_name,
+                                                 const char *match_arg,
+                                                 route_map_event_t type);
 
 /* Delete specified route match rule. */
-extern int route_map_delete_match(struct route_map_index *index,
-                                 const char *match_name,
-                                 const char *match_arg);
+extern enum rmap_compile_rets
+route_map_delete_match(struct route_map_index *index,
+                      const char *match_name, const char *match_arg);
 
 extern const char *route_map_get_match_arg(struct route_map_index *index,
                                           const char *match_name);
 
 /* Add route-map set statement to the route map. */
-extern int route_map_add_set(struct route_map_index *index,
-                            const char *set_name, const char *set_arg);
+extern enum rmap_compile_rets route_map_add_set(struct route_map_index *index,
+                                               const char *set_name,
+                                               const char *set_arg);
 
 /* Delete route map set rule. */
-extern int route_map_delete_set(struct route_map_index *index,
-                               const char *set_name, const char *set_arg);
+extern enum rmap_compile_rets
+route_map_delete_set(struct route_map_index *index,
+                    const char *set_name, const char *set_arg);
 
 /* Install rule command to the match list. */
 extern void route_map_install_match(struct route_map_rule_cmd *cmd);
index dfd13ca186445a375d85564058831253076efc05..2e1a0193a28bec2accd052f390f9a45521fa51d1 100644 (file)
@@ -28,6 +28,7 @@
 #include "network.h"
 #include "prefix.h"
 #include "log.h"
+#include "frr_pthread.h"
 #include "lib_errors.h"
 
 DEFINE_MTYPE_STATIC(LIB, STREAM, "Stream")
@@ -1136,11 +1137,9 @@ void stream_fifo_push(struct stream_fifo *fifo, struct stream *s)
 
 void stream_fifo_push_safe(struct stream_fifo *fifo, struct stream *s)
 {
-       pthread_mutex_lock(&fifo->mtx);
-       {
+       frr_with_mutex(&fifo->mtx) {
                stream_fifo_push(fifo, s);
        }
-       pthread_mutex_unlock(&fifo->mtx);
 }
 
 /* Delete first stream from fifo. */
@@ -1170,11 +1169,9 @@ struct stream *stream_fifo_pop_safe(struct stream_fifo *fifo)
 {
        struct stream *ret;
 
-       pthread_mutex_lock(&fifo->mtx);
-       {
+       frr_with_mutex(&fifo->mtx) {
                ret = stream_fifo_pop(fifo);
        }
-       pthread_mutex_unlock(&fifo->mtx);
 
        return ret;
 }
@@ -1188,11 +1185,9 @@ struct stream *stream_fifo_head_safe(struct stream_fifo *fifo)
 {
        struct stream *ret;
 
-       pthread_mutex_lock(&fifo->mtx);
-       {
+       frr_with_mutex(&fifo->mtx) {
                ret = stream_fifo_head(fifo);
        }
-       pthread_mutex_unlock(&fifo->mtx);
 
        return ret;
 }
@@ -1212,11 +1207,9 @@ void stream_fifo_clean(struct stream_fifo *fifo)
 
 void stream_fifo_clean_safe(struct stream_fifo *fifo)
 {
-       pthread_mutex_lock(&fifo->mtx);
-       {
+       frr_with_mutex(&fifo->mtx) {
                stream_fifo_clean(fifo);
        }
-       pthread_mutex_unlock(&fifo->mtx);
 }
 
 size_t stream_fifo_count_safe(struct stream_fifo *fifo)
index 2be7537bcc45617178b1c03c93475df6135f746d..e0f1352380925f441a27bb429657e504399fbc8c 100644 (file)
@@ -65,6 +65,7 @@ lib_libfrr_la_SOURCES = \
        lib/prefix.c \
        lib/privs.c \
        lib/ptm_lib.c \
+       lib/pullwr.c \
        lib/qobj.c \
        lib/ringbuf.c \
        lib/routemap.c \
@@ -203,6 +204,7 @@ pkginclude_HEADERS += \
        lib/printfrr.h \
        lib/privs.h \
        lib/ptm_lib.h \
+       lib/pullwr.h \
        lib/pw.h \
        lib/qobj.h \
        lib/queue.h \
index 943b849ebf10d5bd00d207adb5bf1e25a5e7fa0a..90c794e88dc8ac1c828824c3d18d74c2066fe206 100644 (file)
@@ -33,6 +33,7 @@
 #include "network.h"
 #include "jhash.h"
 #include "frratomic.h"
+#include "frr_pthread.h"
 #include "lib_errors.h"
 
 DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread")
@@ -173,8 +174,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter)
        tmp.funcname = "TOTAL";
        tmp.types = filter;
 
-       pthread_mutex_lock(&masters_mtx);
-       {
+       frr_with_mutex(&masters_mtx) {
                for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
                        const char *name = m->name ? m->name : "main";
 
@@ -206,7 +206,6 @@ static void cpu_record_print(struct vty *vty, uint8_t filter)
                        vty_out(vty, "\n");
                }
        }
-       pthread_mutex_unlock(&masters_mtx);
 
        vty_out(vty, "\n");
        vty_out(vty, "Total thread statistics\n");
@@ -240,11 +239,9 @@ static void cpu_record_clear(uint8_t filter)
        struct thread_master *m;
        struct listnode *ln;
 
-       pthread_mutex_lock(&masters_mtx);
-       {
+       frr_with_mutex(&masters_mtx) {
                for (ALL_LIST_ELEMENTS_RO(masters, ln, m)) {
-                       pthread_mutex_lock(&m->mtx);
-                       {
+                       frr_with_mutex(&m->mtx) {
                                void *args[2] = {tmp, m->cpu_record};
                                hash_iterate(
                                        m->cpu_record,
@@ -252,10 +249,8 @@ static void cpu_record_clear(uint8_t filter)
                                                  void *))cpu_record_hash_clear,
                                        args);
                        }
-                       pthread_mutex_unlock(&m->mtx);
                }
        }
-       pthread_mutex_unlock(&masters_mtx);
 }
 
 static uint8_t parse_filter(const char *filterstr)
@@ -370,13 +365,11 @@ DEFUN (show_thread_poll,
        struct listnode *node;
        struct thread_master *m;
 
-       pthread_mutex_lock(&masters_mtx);
-       {
+       frr_with_mutex(&masters_mtx) {
                for (ALL_LIST_ELEMENTS_RO(masters, node, m)) {
                        show_thread_poll_helper(vty, m);
                }
        }
-       pthread_mutex_unlock(&masters_mtx);
 
        return CMD_SUCCESS;
 }
@@ -487,26 +480,22 @@ struct thread_master *thread_master_create(const char *name)
                                   sizeof(struct pollfd) * rv->handler.pfdsize);
 
        /* add to list of threadmasters */
-       pthread_mutex_lock(&masters_mtx);
-       {
+       frr_with_mutex(&masters_mtx) {
                if (!masters)
                        masters = list_new();
 
                listnode_add(masters, rv);
        }
-       pthread_mutex_unlock(&masters_mtx);
 
        return rv;
 }
 
 void thread_master_set_name(struct thread_master *master, const char *name)
 {
-       pthread_mutex_lock(&master->mtx);
-       {
+       frr_with_mutex(&master->mtx) {
                XFREE(MTYPE_THREAD_MASTER, master->name);
                master->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
        }
-       pthread_mutex_unlock(&master->mtx);
 }
 
 #define THREAD_UNUSED_DEPTH 10
@@ -569,13 +558,11 @@ static void thread_array_free(struct thread_master *m,
  */
 void thread_master_free_unused(struct thread_master *m)
 {
-       pthread_mutex_lock(&m->mtx);
-       {
+       frr_with_mutex(&m->mtx) {
                struct thread *t;
                while ((t = thread_list_pop(&m->unuse)))
                        thread_free(m, t);
        }
-       pthread_mutex_unlock(&m->mtx);
 }
 
 /* Stop thread scheduler. */
@@ -583,14 +570,12 @@ void thread_master_free(struct thread_master *m)
 {
        struct thread *t;
 
-       pthread_mutex_lock(&masters_mtx);
-       {
+       frr_with_mutex(&masters_mtx) {
                listnode_delete(masters, m);
                if (masters->count == 0) {
                        list_delete(&masters);
                }
        }
-       pthread_mutex_unlock(&masters_mtx);
 
        thread_array_free(m, m->read);
        thread_array_free(m, m->write);
@@ -621,11 +606,9 @@ unsigned long thread_timer_remain_msec(struct thread *thread)
 {
        int64_t remain;
 
-       pthread_mutex_lock(&thread->mtx);
-       {
+       frr_with_mutex(&thread->mtx) {
                remain = monotime_until(&thread->u.sands, NULL) / 1000LL;
        }
-       pthread_mutex_unlock(&thread->mtx);
 
        return remain < 0 ? 0 : remain;
 }
@@ -642,11 +625,9 @@ unsigned long thread_timer_remain_second(struct thread *thread)
 struct timeval thread_timer_remain(struct thread *thread)
 {
        struct timeval remain;
-       pthread_mutex_lock(&thread->mtx);
-       {
+       frr_with_mutex(&thread->mtx) {
                monotime_until(&thread->u.sands, &remain);
        }
-       pthread_mutex_unlock(&thread->mtx);
        return remain;
 }
 
@@ -770,14 +751,10 @@ struct thread *funcname_thread_add_read_write(int dir, struct thread_master *m,
        struct thread **thread_array;
 
        assert(fd >= 0 && fd < m->fd_limit);
-       pthread_mutex_lock(&m->mtx);
-       {
-               if (t_ptr
-                   && *t_ptr) // thread is already scheduled; don't reschedule
-               {
-                       pthread_mutex_unlock(&m->mtx);
-                       return NULL;
-               }
+       frr_with_mutex(&m->mtx) {
+               if (t_ptr && *t_ptr)
+                       // thread is already scheduled; don't reschedule
+                       break;
 
                /* default to a new pollfd */
                nfds_t queuepos = m->handler.pfdcount;
@@ -817,12 +794,10 @@ struct thread *funcname_thread_add_read_write(int dir, struct thread_master *m,
                        m->handler.pfdcount++;
 
                if (thread) {
-                       pthread_mutex_lock(&thread->mtx);
-                       {
+                       frr_with_mutex(&thread->mtx) {
                                thread->u.fd = fd;
                                thread_array[thread->u.fd] = thread;
                        }
-                       pthread_mutex_unlock(&thread->mtx);
 
                        if (t_ptr) {
                                *t_ptr = thread;
@@ -832,7 +807,6 @@ struct thread *funcname_thread_add_read_write(int dir, struct thread_master *m,
 
                AWAKEN(m);
        }
-       pthread_mutex_unlock(&m->mtx);
 
        return thread;
 }
@@ -850,19 +824,14 @@ funcname_thread_add_timer_timeval(struct thread_master *m,
        assert(type == THREAD_TIMER);
        assert(time_relative);
 
-       pthread_mutex_lock(&m->mtx);
-       {
-               if (t_ptr
-                   && *t_ptr) // thread is already scheduled; don't reschedule
-               {
-                       pthread_mutex_unlock(&m->mtx);
+       frr_with_mutex(&m->mtx) {
+               if (t_ptr && *t_ptr)
+                       // thread is already scheduled; don't reschedule
                        return NULL;
-               }
 
                thread = thread_get(m, type, func, arg, debugargpass);
 
-               pthread_mutex_lock(&thread->mtx);
-               {
+               frr_with_mutex(&thread->mtx) {
                        monotime(&thread->u.sands);
                        timeradd(&thread->u.sands, time_relative,
                                 &thread->u.sands);
@@ -872,11 +841,9 @@ funcname_thread_add_timer_timeval(struct thread_master *m,
                                thread->ref = t_ptr;
                        }
                }
-               pthread_mutex_unlock(&thread->mtx);
 
                AWAKEN(m);
        }
-       pthread_mutex_unlock(&m->mtx);
 
        return thread;
 }
@@ -933,26 +900,20 @@ struct thread *funcname_thread_add_event(struct thread_master *m,
                                         void *arg, int val,
                                         struct thread **t_ptr, debugargdef)
 {
-       struct thread *thread;
+       struct thread *thread = NULL;
 
        assert(m != NULL);
 
-       pthread_mutex_lock(&m->mtx);
-       {
-               if (t_ptr
-                   && *t_ptr) // thread is already scheduled; don't reschedule
-               {
-                       pthread_mutex_unlock(&m->mtx);
-                       return NULL;
-               }
+       frr_with_mutex(&m->mtx) {
+               if (t_ptr && *t_ptr)
+                       // thread is already scheduled; don't reschedule
+                       break;
 
                thread = thread_get(m, THREAD_EVENT, func, arg, debugargpass);
-               pthread_mutex_lock(&thread->mtx);
-               {
+               frr_with_mutex(&thread->mtx) {
                        thread->u.val = val;
                        thread_list_add_tail(&m->event, thread);
                }
-               pthread_mutex_unlock(&thread->mtx);
 
                if (t_ptr) {
                        *t_ptr = thread;
@@ -961,7 +922,6 @@ struct thread *funcname_thread_add_event(struct thread_master *m,
 
                AWAKEN(m);
        }
-       pthread_mutex_unlock(&m->mtx);
 
        return thread;
 }
@@ -1143,15 +1103,13 @@ void thread_cancel_event(struct thread_master *master, void *arg)
 {
        assert(master->owner == pthread_self());
 
-       pthread_mutex_lock(&master->mtx);
-       {
+       frr_with_mutex(&master->mtx) {
                struct cancel_req *cr =
                        XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
                cr->eventobj = arg;
                listnode_add(master->cancel_req, cr);
                do_thread_cancel(master);
        }
-       pthread_mutex_unlock(&master->mtx);
 }
 
 /**
@@ -1167,15 +1125,13 @@ void thread_cancel(struct thread *thread)
 
        assert(master->owner == pthread_self());
 
-       pthread_mutex_lock(&master->mtx);
-       {
+       frr_with_mutex(&master->mtx) {
                struct cancel_req *cr =
                        XCALLOC(MTYPE_TMP, sizeof(struct cancel_req));
                cr->thread = thread;
                listnode_add(master->cancel_req, cr);
                do_thread_cancel(master);
        }
-       pthread_mutex_unlock(&master->mtx);
 }
 
 /**
@@ -1208,8 +1164,7 @@ void thread_cancel_async(struct thread_master *master, struct thread **thread,
        assert(!(thread && eventobj) && (thread || eventobj));
        assert(master->owner != pthread_self());
 
-       pthread_mutex_lock(&master->mtx);
-       {
+       frr_with_mutex(&master->mtx) {
                master->canceled = false;
 
                if (thread) {
@@ -1228,7 +1183,6 @@ void thread_cancel_async(struct thread_master *master, struct thread **thread,
                while (!master->canceled)
                        pthread_cond_wait(&master->cancel_cond, &master->mtx);
        }
-       pthread_mutex_unlock(&master->mtx);
 }
 /* ------------------------------------------------------------------------- */
 
@@ -1527,22 +1481,18 @@ unsigned long thread_consumed_time(RUSAGE_T *now, RUSAGE_T *start,
 int thread_should_yield(struct thread *thread)
 {
        int result;
-       pthread_mutex_lock(&thread->mtx);
-       {
+       frr_with_mutex(&thread->mtx) {
                result = monotime_since(&thread->real, NULL)
                         > (int64_t)thread->yield;
        }
-       pthread_mutex_unlock(&thread->mtx);
        return result;
 }
 
 void thread_set_yield_time(struct thread *thread, unsigned long yield_time)
 {
-       pthread_mutex_lock(&thread->mtx);
-       {
+       frr_with_mutex(&thread->mtx) {
                thread->yield = yield_time;
        }
-       pthread_mutex_unlock(&thread->mtx);
 }
 
 void thread_getrusage(RUSAGE_T *r)
@@ -1637,20 +1587,16 @@ void funcname_thread_execute(struct thread_master *m,
        struct thread *thread;
 
        /* Get or allocate new thread to execute. */
-       pthread_mutex_lock(&m->mtx);
-       {
+       frr_with_mutex(&m->mtx) {
                thread = thread_get(m, THREAD_EVENT, func, arg, debugargpass);
 
                /* Set its event value. */
-               pthread_mutex_lock(&thread->mtx);
-               {
+               frr_with_mutex(&thread->mtx) {
                        thread->add_type = THREAD_EXECUTE;
                        thread->u.val = val;
                        thread->ref = &thread;
                }
-               pthread_mutex_unlock(&thread->mtx);
        }
-       pthread_mutex_unlock(&m->mtx);
 
        /* Execute thread doing all accounting. */
        thread_call(thread);
index 229f19f29ae877a2f2b02ae7c9b65c27e36ae634..575e96bae4540ca5fd024a3ee323185b461ca41f 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -755,7 +755,7 @@ DEFUN_NOSH (vrf_netns,
        if (!pathname)
                return CMD_WARNING_CONFIG_FAILED;
 
-       frr_elevate_privs(vrf_daemon_privs) {
+       frr_with_privs(vrf_daemon_privs) {
                ret = vrf_netns_handler_create(vty, vrf, pathname,
                                               NS_UNKNOWN, NS_UNKNOWN);
        }
index c1535802cff48ef0d4b7029ac55fcaf5de258571..deb9391bd506a0951bf6e8108e1944ff2dcf441e 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -348,6 +348,15 @@ void vty_hello(struct vty *vty)
                        vty_out(vty, "MOTD file not found\n");
        } else if (host.motd)
                vty_out(vty, "%s", host.motd);
+
+#if CONFDATE > 20200901
+       CPP_NOTICE("Please remove solaris code from system as it is deprecated");
+#endif
+#ifdef SUNOS_5
+       zlog_warn("If you are using FRR on Solaris, the FRR developers would love to hear from you\n");
+       zlog_warn("Please send email to dev@lists.frrouting.org about this message\n");
+       zlog_warn("We are considering deprecating Solaris and want to find users of Solaris systems\n");
+#endif
 }
 
 /* Put out prompt and wait input from user. */
index 6937700199d4db8d152258891e983c91ab35681a..2d79d9b3c57226c48f990053103fbb1eef220d06 100644 (file)
@@ -325,8 +325,9 @@ int zclient_read_header(struct stream *s, int sock, uint16_t *size,
        if (*size && stream_read(s, sock, *size) != *size)
                return -1;
 
-stream_failure:
        return 0;
+stream_failure:
+       return -1;
 }
 
 bool zapi_parse_header(struct stream *zmsg, struct zmsghdr *hdr)
@@ -1056,8 +1057,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
        if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID))
                STREAM_GETL(s, api->tableid);
 
-stream_failure:
        return 0;
+stream_failure:
+       return -1;
 }
 
 static void zapi_encode_prefix(struct stream *s, struct prefix *p,
@@ -2254,7 +2256,7 @@ int tm_table_manager_connect(struct zclient *zclient)
 
        return (int)result;
 stream_failure:
-       return 0;
+       return -1;
 }
 
 /**
@@ -2321,8 +2323,9 @@ int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
        if (zclient_debug)
                zlog_debug("Table Chunk assign: %u - %u ", *start, *end);
 
-stream_failure:
        return 0;
+stream_failure:
+       return -1;
 }
 
 /**
index 33b9f71b5fa1e7166a15954dacf618d1dda43cad..4d1c085081760c061829e5588c3b53d95d7d2d5c 100644 (file)
@@ -1581,7 +1581,7 @@ static struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = {
        route_map_rule_tag_free,
 };
 
-static int route_map_command_status(struct vty *vty, int ret)
+static int route_map_command_status(struct vty *vty, enum rmap_compile_rets ret)
 {
        switch (ret) {
        case RMAP_RULE_MISSING:
@@ -1593,6 +1593,7 @@ static int route_map_command_status(struct vty *vty, int ret)
                return CMD_WARNING_CONFIG_FAILED;
                break;
        case RMAP_COMPILE_SUCCESS:
+       case RMAP_DUPLICATE_RULE:
                break;
        }
 
@@ -1610,8 +1611,10 @@ DEFUN (ospf6_routemap_set_metric_type,
 {
        VTY_DECLVAR_CONTEXT(route_map_index, route_map_index);
        int idx_external = 2;
-       int ret = route_map_add_set(route_map_index, "metric-type",
-                                   argv[idx_external]->arg);
+       enum rmap_compile_rets ret = route_map_add_set(route_map_index,
+                                                      "metric-type",
+                                                      argv[idx_external]->arg);
+
        return route_map_command_status(vty, ret);
 }
 
@@ -1627,7 +1630,9 @@ DEFUN (ospf6_routemap_no_set_metric_type,
 {
        VTY_DECLVAR_CONTEXT(route_map_index, route_map_index);
        char *ext = (argc == 4) ? argv[3]->text : NULL;
-       int ret = route_map_delete_set(route_map_index, "metric-type", ext);
+       enum rmap_compile_rets ret = route_map_delete_set(route_map_index,
+                                                         "metric-type", ext);
+
        return route_map_command_status(vty, ret);
 }
 
@@ -1641,8 +1646,10 @@ DEFUN (ospf6_routemap_set_forwarding,
 {
        VTY_DECLVAR_CONTEXT(route_map_index, route_map_index);
        int idx_ipv6 = 2;
-       int ret = route_map_add_set(route_map_index, "forwarding-address",
-                                   argv[idx_ipv6]->arg);
+       enum rmap_compile_rets ret = route_map_add_set(route_map_index,
+                                                      "forwarding-address",
+                                                      argv[idx_ipv6]->arg);
+
        return route_map_command_status(vty, ret);
 }
 
@@ -1657,8 +1664,10 @@ DEFUN (ospf6_routemap_no_set_forwarding,
 {
        VTY_DECLVAR_CONTEXT(route_map_index, route_map_index);
        int idx_ipv6 = 3;
-       int ret = route_map_delete_set(route_map_index, "forwarding-address",
-                                      argv[idx_ipv6]->arg);
+       enum rmap_compile_rets ret = route_map_delete_set(route_map_index,
+                                                         "forwarding-address",
+                                                         argv[idx_ipv6]->arg);
+
        return route_map_command_status(vty, ret);
 }
 
index 625ad884f2f7a8d09bb2422af500f7b2882ceb76..9a18680b8b532c1a2fa16b430c58ab2d9fafeaae 100644 (file)
@@ -85,7 +85,7 @@ void ospf6_serv_close(void)
 /* Make ospf6d's server socket. */
 int ospf6_serv_sock(void)
 {
-       frr_elevate_privs(&ospf6d_privs) {
+       frr_with_privs(&ospf6d_privs) {
 
                ospf6_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP);
                if (ospf6_sock < 0) {
index ce1604a5b1c5a667058f549739f54dd7a39c3c4b..387770870811b45a0867c63bb210648695d80beb 100644 (file)
@@ -225,12 +225,14 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp,
 {
        struct ospf_interface *oi;
 
-       if ((oi = ospf_if_table_lookup(ifp, p)) == NULL) {
-               oi = XCALLOC(MTYPE_OSPF_IF, sizeof(struct ospf_interface));
-               memset(oi, 0, sizeof(struct ospf_interface));
-       } else
+       oi = ospf_if_table_lookup(ifp, p);
+       if (oi)
                return oi;
 
+       oi = XCALLOC(MTYPE_OSPF_IF, sizeof(struct ospf_interface));
+
+       oi->obuf = ospf_fifo_new();
+
        /* Set zebra interface pointer. */
        oi->ifp = ifp;
        oi->address = p;
@@ -264,8 +266,6 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp,
 
        oi->ospf = ospf;
 
-       ospf_if_stream_set(oi);
-
        QOBJ_REG(oi, ospf_interface);
 
        if (IS_DEBUG_OSPF_EVENT)
@@ -325,8 +325,7 @@ void ospf_if_free(struct ospf_interface *oi)
 {
        ospf_if_down(oi);
 
-       if (oi->obuf)
-               ospf_fifo_free(oi->obuf);
+       ospf_fifo_free(oi->obuf);
 
        assert(oi->state == ISM_Down);
 
@@ -490,29 +489,20 @@ static void ospf_if_reset_stats(struct ospf_interface *oi)
        oi->ls_ack_in = oi->ls_ack_out = 0;
 }
 
-void ospf_if_stream_set(struct ospf_interface *oi)
-{
-       /* set output fifo queue. */
-       if (oi->obuf == NULL)
-               oi->obuf = ospf_fifo_new();
-}
-
 void ospf_if_stream_unset(struct ospf_interface *oi)
 {
        struct ospf *ospf = oi->ospf;
 
-       if (oi->obuf) {
-               /* flush the interface packet queue */
-               ospf_fifo_flush(oi->obuf);
-               /*reset protocol stats */
-               ospf_if_reset_stats(oi);
-
-               if (oi->on_write_q) {
-                       listnode_delete(ospf->oi_write_q, oi);
-                       if (list_isempty(ospf->oi_write_q))
-                               OSPF_TIMER_OFF(ospf->t_write);
-                       oi->on_write_q = 0;
-               }
+       /* flush the interface packet queue */
+       ospf_fifo_flush(oi->obuf);
+       /*reset protocol stats */
+       ospf_if_reset_stats(oi);
+
+       if (oi->on_write_q) {
+               listnode_delete(ospf->oi_write_q, oi);
+               if (list_isempty(ospf->oi_write_q))
+                       OSPF_TIMER_OFF(ospf->t_write);
+               oi->on_write_q = 0;
        }
 }
 
@@ -903,8 +893,6 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf,
 
        ospf_area_add_if(voi->area, voi);
 
-       ospf_if_stream_set(voi);
-
        if (IS_DEBUG_OSPF_EVENT)
                zlog_debug("ospf_vl_new(): Stop");
        return voi;
index b88d405875a5f4fee04695f828c0241562b41f0b..0c903954d321b2aab78d3bd63085e7d933e967de 100644 (file)
@@ -285,7 +285,6 @@ extern void ospf_if_update_params(struct interface *, struct in_addr);
 
 extern int ospf_if_new_hook(struct interface *);
 extern void ospf_if_init(void);
-extern void ospf_if_stream_set(struct ospf_interface *);
 extern void ospf_if_stream_unset(struct ospf_interface *);
 extern void ospf_if_reset_variables(struct ospf_interface *);
 extern int ospf_if_is_enable(struct ospf_interface *);
index 5ae99ab32070b2d87b0c944b6d62fb4aafb0f828..8d21403695faf7a8657ca5bcd4f84bdbe7aa3328 100644 (file)
@@ -53,8 +53,9 @@
                        listnode_add((O)->oi_write_q, oi);                     \
                        oi->on_write_q = 1;                                    \
                }                                                              \
-               thread_add_write(master, ospf_write, (O), (O)->fd,             \
-                                &(O)->t_write);                               \
+               if (!list_isempty((O)->oi_write_q))                            \
+                       thread_add_write(master, ospf_write, (O), (O)->fd,     \
+                                        &(O)->t_write);                       \
        } while (0)
 
 /* Macro for OSPF ISM timer turn on. */
index 1415a6e8b748f54ed779c399b958f9f2a6c78b1f..b8e2dac70e83f30a7a09680f3dff6bfe77814658 100644 (file)
@@ -190,7 +190,7 @@ int ospf_sock_init(struct ospf *ospf)
                /* silently return since VRF is not ready */
                return -1;
        }
-       frr_elevate_privs(&ospfd_privs) {
+       frr_with_privs(&ospfd_privs) {
                ospf_sock = vrf_socket(AF_INET, SOCK_RAW, IPPROTO_OSPFIGP,
                                       ospf->vrf_id, ospf->name);
                if (ospf_sock < 0) {
index 62b0444796534962578ae22bbc3a1834c3222c5d..5a29c1fb07abb2c511875e581d74ffe015308a17 100644 (file)
@@ -132,7 +132,7 @@ static int ospf_auth_type(struct ospf_interface *oi)
        return auth_type;
 }
 
-struct ospf_packet *ospf_packet_new(size_t size)
+static struct ospf_packet *ospf_packet_new(size_t size)
 {
        struct ospf_packet *new;
 
@@ -231,22 +231,8 @@ void ospf_fifo_free(struct ospf_fifo *fifo)
        XFREE(MTYPE_OSPF_FIFO, fifo);
 }
 
-void ospf_packet_add(struct ospf_interface *oi, struct ospf_packet *op)
+static void ospf_packet_add(struct ospf_interface *oi, struct ospf_packet *op)
 {
-       if (!oi->obuf) {
-               flog_err(
-                       EC_OSPF_PKT_PROCESS,
-                       "ospf_packet_add(interface %s in state %d [%s], packet type %s, "
-                       "destination %s) called with NULL obuf, ignoring "
-                       "(please report this bug)!\n",
-                       IF_NAME(oi), oi->state,
-                       lookup_msg(ospf_ism_state_msg, oi->state, NULL),
-                       lookup_msg(ospf_packet_type_str,
-                                  stream_getc_from(op->s, 1), NULL),
-                       inet_ntoa(op->dst));
-               return;
-       }
-
        /* Add packet to end of queue. */
        ospf_fifo_push(oi->obuf, op);
 
@@ -257,20 +243,6 @@ void ospf_packet_add(struct ospf_interface *oi, struct ospf_packet *op)
 static void ospf_packet_add_top(struct ospf_interface *oi,
                                struct ospf_packet *op)
 {
-       if (!oi->obuf) {
-               flog_err(
-                       EC_OSPF_PKT_PROCESS,
-                       "ospf_packet_add(interface %s in state %d [%s], packet type %s, "
-                       "destination %s) called with NULL obuf, ignoring "
-                       "(please report this bug)!\n",
-                       IF_NAME(oi), oi->state,
-                       lookup_msg(ospf_ism_state_msg, oi->state, NULL),
-                       lookup_msg(ospf_packet_type_str,
-                                  stream_getc_from(op->s, 1), NULL),
-                       inet_ntoa(op->dst));
-               return;
-       }
-
        /* Add packet to head of queue. */
        ospf_fifo_push_head(oi->obuf, op);
 
@@ -278,7 +250,7 @@ static void ospf_packet_add_top(struct ospf_interface *oi,
        /* ospf_fifo_debug (oi->obuf); */
 }
 
-void ospf_packet_delete(struct ospf_interface *oi)
+static void ospf_packet_delete(struct ospf_interface *oi)
 {
        struct ospf_packet *op;
 
@@ -288,7 +260,7 @@ void ospf_packet_delete(struct ospf_interface *oi)
                ospf_packet_free(op);
 }
 
-struct ospf_packet *ospf_packet_dup(struct ospf_packet *op)
+static struct ospf_packet *ospf_packet_dup(struct ospf_packet *op)
 {
        struct ospf_packet *new;
 
@@ -698,12 +670,9 @@ static int ospf_write(struct thread *thread)
                return -1;
        }
 
-       ospf->t_write = NULL;
-
        node = listhead(ospf->oi_write_q);
        assert(node);
        oi = listgetdata(node);
-       assert(oi);
 
 #ifdef WANT_OSPF_WRITE_FRAGMENT
        /* seed ipid static with low order bits of time */
@@ -906,9 +875,7 @@ static int ospf_write(struct thread *thread)
                /* Setup to service from the head of the queue again */
                if (!list_isempty(ospf->oi_write_q)) {
                        node = listhead(ospf->oi_write_q);
-                       assert(node);
                        oi = listgetdata(node);
-                       assert(oi);
                }
        }
 
@@ -4062,6 +4029,23 @@ static void ospf_ls_upd_queue_send(struct ospf_interface *oi,
                        oi->on_write_q = 1;
                }
                ospf_write(&os_packet_thd);
+               /*
+                * We are fake calling ospf_write with a fake
+                * thread.  Imagine that we have oi_a already
+                * enqueued and we have turned on the write
+                * thread(t_write).
+                * Now this function calls this for oi_b
+                * so the on_write_q has oi_a and oi_b on
+                * it, ospf_write runs and clears the packets
+                * for both oi_a and oi_b.  Removing them from
+                * the on_write_q.  After this thread of execution
+                * finishes we will execute the t_write thread
+                * with nothing in the on_write_q causing an
+                * assert.  So just make sure that the t_write
+                * is actually turned off.
+                */
+               if (list_isempty(oi->ospf->oi_write_q))
+                       OSPF_TIMER_OFF(oi->ospf->t_write);
        } else {
                /* Hook thread to write packet. */
                OSPF_ISM_WRITE_ON(oi->ospf);
index a508727968a37366798233fef64055697286cf88..5a3e029f2ea9e7f161a7fce9fbb67158918ed63f 100644 (file)
@@ -131,8 +131,6 @@ struct ospf_ls_update {
 #define IS_SET_DD_ALL(X)        ((X) & OSPF_DD_FLAG_ALL)
 
 /* Prototypes. */
-extern void ospf_output_forward(struct stream *, int);
-extern struct ospf_packet *ospf_packet_new(size_t);
 extern void ospf_packet_free(struct ospf_packet *);
 extern struct ospf_fifo *ospf_fifo_new(void);
 extern void ospf_fifo_push(struct ospf_fifo *, struct ospf_packet *);
@@ -140,10 +138,6 @@ extern struct ospf_packet *ospf_fifo_pop(struct ospf_fifo *);
 extern struct ospf_packet *ospf_fifo_head(struct ospf_fifo *);
 extern void ospf_fifo_flush(struct ospf_fifo *);
 extern void ospf_fifo_free(struct ospf_fifo *);
-extern void ospf_packet_add(struct ospf_interface *, struct ospf_packet *);
-extern void ospf_packet_delete(struct ospf_interface *);
-extern struct stream *ospf_stream_dup(struct stream *);
-extern struct ospf_packet *ospf_packet_dup(struct ospf_packet *);
 
 extern int ospf_read(struct thread *);
 extern void ospf_hello_send(struct ospf_interface *);
index 2564c6f3301397ebabf383102b71cd7612d933f8..8fa91f500c315fc42a7627371eb3016d8cff548d 100644 (file)
@@ -3442,6 +3442,9 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
                        else
                                vty_out(vty, "  This interface is UNNUMBERED,");
                } else {
+                       struct in_addr dest;
+                       const char *dstr;
+
                        /* Show OSPF interface information. */
                        if (use_json) {
                                json_object_string_add(
@@ -3455,46 +3458,40 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
                                        inet_ntoa(oi->address->u.prefix4),
                                        oi->address->prefixlen);
 
-                       if (oi->connected->destination
-                           || oi->type == OSPF_IFTYPE_VIRTUALLINK) {
-                               struct in_addr *dest;
-                               const char *dstr;
-
-                               if (CONNECTED_PEER(oi->connected)
-                                   || oi->type == OSPF_IFTYPE_VIRTUALLINK)
-                                       dstr = "Peer";
-                               else
-                                       dstr = "Broadcast";
+                       /* For Vlinks, showing the peer address is
+                        * probably more informative than the local
+                        * interface that is being used */
+                       if (oi->type == OSPF_IFTYPE_VIRTUALLINK) {
+                               dstr = "Peer";
+                               dest = oi->vl_data->peer_addr;
+                       } else if (CONNECTED_PEER(oi->connected)
+                                        && oi->connected->destination) {
+                               dstr = "Peer";
+                               dest = oi->connected->destination->u.prefix4;
+                       } else {
+                               dstr = "Broadcast";
+                               dest.s_addr = ipv4_broadcast_addr(
+                                               oi->connected->address->u.prefix4.s_addr,
+                                               oi->connected->address->prefixlen);
+                       }
 
-                               /* For Vlinks, showing the peer address is
-                  * probably more
-                  *  *  *  *                * informative than the local
-                  * interface that is being used
-                  *   *   *   *                               */
+                       if (use_json) {
+                               json_object_string_add(
+                                       json_interface_sub,
+                                       "ospfIfType", dstr);
                                if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
-                                       dest = &oi->vl_data->peer_addr;
+                                       json_object_string_add(
+                                               json_interface_sub,
+                                               "vlinkPeer",
+                                               inet_ntoa(dest));
                                else
-                                       dest = &oi->connected->destination->u
-                                                       .prefix4;
-
-                               if (use_json) {
                                        json_object_string_add(
                                                json_interface_sub,
-                                               "ospfIfType", dstr);
-                                       if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
-                                               json_object_string_add(
-                                                       json_interface_sub,
-                                                       "vlinkPeer",
-                                                       inet_ntoa(*dest));
-                                       else
-                                               json_object_string_add(
-                                                       json_interface_sub,
-                                                       "localIfUsed",
-                                                       inet_ntoa(*dest));
-                               } else
-                                       vty_out(vty, " %s %s,", dstr,
-                                               inet_ntoa(*dest));
-                       }
+                                               "localIfUsed",
+                                               inet_ntoa(dest));
+                       } else
+                               vty_out(vty, " %s %s,", dstr,
+                                       inet_ntoa(dest));
                }
                if (use_json) {
                        json_object_string_add(json_interface_sub, "area",
index b91a55f6351049ea467be0e0231758358e1dc0e1..e48a5b4d369bce43d37c8c91756ed6e3420ce655 100644 (file)
@@ -2097,7 +2097,7 @@ static int ospf_vrf_enable(struct vrf *vrf)
                                old_vrf_id);
 
                if (old_vrf_id != ospf->vrf_id) {
-                       frr_elevate_privs(&ospfd_privs) {
+                       frr_with_privs(&ospfd_privs) {
                                /* stop zebra redist to us for old vrf */
                                zclient_send_dereg_requests(zclient,
                                                            old_vrf_id);
index 5e67990d5ef72bd0345ce497867f5c6ea54128f1..1a8461c6c13be85a8774957e0bdc767aaa7040aa 100644 (file)
@@ -316,7 +316,7 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
                pbrms->ruleno = pbr_nht_get_next_rule(seqno);
                pbrms->parent = pbrm;
                pbrms->reason =
-                       PBR_MAP_INVALID_SRCDST |
+                       PBR_MAP_INVALID_EMPTY |
                        PBR_MAP_INVALID_NO_NEXTHOPS;
 
                QOBJ_REG(pbrms, pbr_map_sequence);
@@ -350,10 +350,10 @@ pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms)
        }
 }
 
-static void pbr_map_sequence_check_src_dst_valid(struct pbr_map_sequence *pbrms)
+static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence *pbrms)
 {
-       if (!pbrms->src && !pbrms->dst)
-               pbrms->reason |= PBR_MAP_INVALID_SRCDST;
+       if (!pbrms->src && !pbrms->dst && !pbrms->mark)
+               pbrms->reason |= PBR_MAP_INVALID_EMPTY;
 }
 
 /*
@@ -364,7 +364,7 @@ static void pbr_map_sequence_check_valid(struct pbr_map_sequence *pbrms)
 {
        pbr_map_sequence_check_nexthops_valid(pbrms);
 
-       pbr_map_sequence_check_src_dst_valid(pbrms);
+       pbr_map_sequence_check_not_empty(pbrms);
 }
 
 static bool pbr_map_check_valid_internal(struct pbr_map *pbrm)
index 945f76bb2bbf88ec9c081cc7357802d6346cd88c..112acfe44e9fc4471ee4e9f55649221fee6ecb1d 100644 (file)
@@ -87,6 +87,7 @@ struct pbr_map_sequence {
         */
        struct prefix *src;
        struct prefix *dst;
+       uint32_t mark;
 
        /*
         * Family of the src/dst.  Needed when deleting since we clear them
@@ -126,7 +127,7 @@ struct pbr_map_sequence {
 #define PBR_MAP_INVALID_NEXTHOP        (1 << 1)
 #define PBR_MAP_INVALID_NO_NEXTHOPS    (1 << 2)
 #define PBR_MAP_INVALID_BOTH_NHANDGRP  (1 << 3)
-#define PBR_MAP_INVALID_SRCDST         (1 << 4)
+#define PBR_MAP_INVALID_EMPTY          (1 << 4)
        uint64_t reason;
 
        QOBJ_FIELDS
index 95f38563b1de07140ed30c223329d2c6b8fe6af8..5e7addc9d2b0e10bde2cb014a677d3ecafd22d4c 100644 (file)
@@ -172,6 +172,33 @@ DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
        return CMD_SUCCESS;
 }
 
+DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
+       "[no] match mark (1-4294967295)$mark",
+       NO_STR
+       "Match the rest of the command\n"
+       "Choose the mark value to use\n"
+       "mark\n")
+{
+       struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+
+#ifndef GNU_LINUX
+       vty_out(vty, "pbr marks are not supported on this platform");
+       return CMD_WARNING_CONFIG_FAILED;
+#endif
+
+       if (!no) {
+               if (pbrms->mark == (uint32_t) mark)
+                       return CMD_SUCCESS;
+               pbrms->mark = (uint32_t) mark;
+       } else {
+               pbrms->mark = 0;
+       }
+
+       pbr_map_check(pbrms);
+
+       return CMD_SUCCESS;
+ }
+
 DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
        "[no] set nexthop-group NHGNAME$name",
        NO_STR
@@ -453,6 +480,8 @@ DEFPY (show_pbr_map,
                                vty_out(vty, "\tDST Match: %s\n",
                                        prefix2str(pbrms->dst, buf,
                                                   sizeof(buf)));
+                       if (pbrms->mark)
+                               vty_out(vty, "\tMARK Match: %u\n", pbrms->mark);
 
                        if (pbrms->nhgrp_name) {
                                vty_out(vty,
@@ -632,6 +661,9 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
                vty_out(vty, " match dst-ip %s\n",
                        prefix2str(pbrms->dst, buff, sizeof(buff)));
 
+       if (pbrms->mark)
+               vty_out(vty, " match mark %u\n", pbrms->mark);
+
        if (pbrms->nhgrp_name)
                vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
 
@@ -704,6 +736,7 @@ void pbr_vty_init(void)
        install_element(INTERFACE_NODE, &pbr_policy_cmd);
        install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
        install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
+       install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
        install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
        install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
        install_element(VIEW_NODE, &show_pbr_cmd);
index 466a9a13ae1ae6451148b5d8282fd0b0f20a128d..d74d0fcd23d35e5acf4eb69e105a5e65164015f2 100644 (file)
@@ -526,7 +526,7 @@ static void pbr_encode_pbr_map_sequence(struct stream *s,
        stream_putw(s, 0);  /* src port */
        pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family);
        stream_putw(s, 0);  /* dst port */
-       stream_putl(s, 0);  /* fwmark */
+       stream_putl(s, pbrms->mark);
        if (pbrms->nhgrp_name)
                stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name));
        else if (pbrms->nhg)
index 1c66007fbb467de0823d5ad6364cb8dd4780d57a..f7f4b54aead1ff25f8cf70d83f7446ad5af54f27 100644 (file)
@@ -57,7 +57,7 @@ static int pim_mroute_set(struct pim_instance *pim, int enable)
         * We need to create the VRF table for the pim mroute_socket
         */
        if (pim->vrf_id != VRF_DEFAULT) {
-               frr_elevate_privs(&pimd_privs) {
+               frr_with_privs(&pimd_privs) {
 
                        data = pim->vrf->data.l.table_id;
                        err = setsockopt(pim->mroute_socket, IPPROTO_IP,
@@ -75,7 +75,7 @@ static int pim_mroute_set(struct pim_instance *pim, int enable)
                }
        }
 
-       frr_elevate_privs(&pimd_privs) {
+       frr_with_privs(&pimd_privs) {
                opt = enable ? MRT_INIT : MRT_DONE;
                /*
                 * *BSD *cares* about what value we pass down
@@ -735,7 +735,7 @@ int pim_mroute_socket_enable(struct pim_instance *pim)
 {
        int fd;
 
-       frr_elevate_privs(&pimd_privs) {
+       frr_with_privs(&pimd_privs) {
 
                fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
 
index b1f7cfd2c66b57b05e170b2f06735138308c2e40..22eb8bc7b40061ab0d8d15d4b01d44b215421be1 100644 (file)
@@ -175,7 +175,7 @@ int pim_msdp_sock_listen(struct pim_instance *pim)
                }
        }
 
-       frr_elevate_privs(&pimd_privs) {
+       frr_with_privs(&pimd_privs) {
                /* bind to well known TCP port */
                rc = bind(sock, (struct sockaddr *)&sin, socklen);
        }
index c4538a4ac52e83d4ccbae8d25b88320c981899f4..82255cd3b077f6bc679b172f52bdb6dd04831a33 100644 (file)
@@ -46,7 +46,7 @@ int pim_socket_raw(int protocol)
 {
        int fd;
 
-       frr_elevate_privs(&pimd_privs) {
+       frr_with_privs(&pimd_privs) {
 
                fd = socket(AF_INET, SOCK_RAW, protocol);
 
@@ -65,7 +65,7 @@ void pim_socket_ip_hdr(int fd)
 {
        const int on = 1;
 
-       frr_elevate_privs(&pimd_privs) {
+       frr_with_privs(&pimd_privs) {
 
                if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)))
                        zlog_err("%s: Could not turn on IP_HDRINCL option: %s",
@@ -83,7 +83,7 @@ int pim_socket_bind(int fd, struct interface *ifp)
        int ret = 0;
 #ifdef SO_BINDTODEVICE
 
-       frr_elevate_privs(&pimd_privs) {
+       frr_with_privs(&pimd_privs) {
 
                ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifp->name,
                                 strlen(ifp->name));
index d1935195df4855a037c5f162f3562aa5f7847247..1c4ecf299f60c3726d3ab4c9fe139532bd402648 100644 (file)
@@ -81,7 +81,7 @@ int pim_debug_config_write(struct vty *vty)
                ++writes;
        }
 
-       if (PIM_DEBUG_MROUTE_DETAIL) {
+       if (PIM_DEBUG_MROUTE_DETAIL_ONLY) {
                vty_out(vty, "debug mroute detail\n");
                ++writes;
        }
@@ -107,7 +107,7 @@ int pim_debug_config_write(struct vty *vty)
                vty_out(vty, "debug pim trace\n");
                ++writes;
        }
-       if (PIM_DEBUG_PIM_TRACE_DETAIL) {
+       if (PIM_DEBUG_PIM_TRACE_DETAIL_ONLY) {
                vty_out(vty, "debug pim trace detail\n");
                ++writes;
        }
index 175936e0a756ec733cf96d1f6c0d904d0a9bd5c6..3b83d3b6c7df16b43f550ac81258f6a7fe94390a 100644 (file)
@@ -163,6 +163,8 @@ extern uint8_t qpim_ecmp_rebalance_enable;
 #define PIM_DEBUG_PIM_TRACE (router->debugs & PIM_MASK_PIM_TRACE)
 #define PIM_DEBUG_PIM_TRACE_DETAIL                                             \
        (router->debugs & (PIM_MASK_PIM_TRACE_DETAIL | PIM_MASK_PIM_TRACE))
+#define PIM_DEBUG_PIM_TRACE_DETAIL_ONLY                                        \
+       (router->debugs & PIM_MASK_PIM_TRACE_DETAIL)
 #define PIM_DEBUG_IGMP_EVENTS (router->debugs & PIM_MASK_IGMP_EVENTS)
 #define PIM_DEBUG_IGMP_PACKETS (router->debugs & PIM_MASK_IGMP_PACKETS)
 #define PIM_DEBUG_IGMP_TRACE (router->debugs & PIM_MASK_IGMP_TRACE)
@@ -173,6 +175,7 @@ extern uint8_t qpim_ecmp_rebalance_enable;
 #define PIM_DEBUG_MROUTE (router->debugs & PIM_MASK_MROUTE)
 #define PIM_DEBUG_MROUTE_DETAIL                                                \
        (router->debugs & (PIM_MASK_MROUTE_DETAIL | PIM_MASK_MROUTE))
+#define PIM_DEBUG_MROUTE_DETAIL_ONLY (router->debugs & PIM_MASK_MROUTE_DETAIL)
 #define PIM_DEBUG_PIM_HELLO (router->debugs & PIM_MASK_PIM_HELLO)
 #define PIM_DEBUG_PIM_J_P (router->debugs & PIM_MASK_PIM_J_P)
 #define PIM_DEBUG_PIM_REG (router->debugs & PIM_MASK_PIM_REG)
index bc2f5caebfa1861793ef644cd501194fcd6b43c9..baa6ed52b25aac22d118e314bb928bfb56ce2439 100644 (file)
@@ -351,6 +351,7 @@ if __name__ == '__main__':
     macros = Macros()
     macros.load('lib/route_types.h')
     macros.load(os.path.join(basepath, 'lib/command.h'))
+    macros.load(os.path.join(basepath, 'bgpd/bgp_vty.h'))
     # sigh :(
     macros['PROTO_REDIST_STR'] = 'FRR_REDIST_STR_ISISD'
 
index 014cae02ee8840633a7ccb80a5a76b1084546158..fa0a6d8a0a33f1f03b04877ff9bc6002551143fe 100644 (file)
@@ -634,6 +634,7 @@ fi
     %{_libdir}/frr/modules/bgpd_rpki.so
 %endif
 %{_libdir}/frr/modules/zebra_irdp.so
+%{_libdir}/frr/modules/bgpd_bmp.so
 %{_bindir}/*
 %config(noreplace) %{configdir}/[!v]*.conf*
 %config(noreplace) %attr(750,%{frr_user},%{frr_user}) %{configdir}/daemons
index 561fbcb52d1b33b3bdc8cd4950b4a18d54fee0b5..ad373aebdfbbf3cfc9af9edb1de934d2705cfdde 100644 (file)
@@ -1395,7 +1395,7 @@ int rip_create_socket(struct vrf *vrf)
        /* Make datagram socket. */
        if (vrf->vrf_id != VRF_DEFAULT)
                vrf_dev = vrf->name;
-       frr_elevate_privs(&ripd_privs) {
+       frr_with_privs(&ripd_privs) {
                sock = vrf_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, vrf->vrf_id,
                                  vrf_dev);
                if (sock < 0) {
@@ -1415,7 +1415,7 @@ int rip_create_socket(struct vrf *vrf)
 #endif
        setsockopt_so_recvbuf(sock, RIP_UDP_RCV_BUF);
 
-       frr_elevate_privs(&ripd_privs) {
+       frr_with_privs(&ripd_privs) {
                if ((ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)))
                    < 0) {
                        zlog_err("%s: Can't bind socket %d to %s port %d: %s",
index 49ed13a2c29b416d67275f3f86704f8b6473baa5..9ed9dc28feb22c9de5ae9bda91f6685fe1fe8226 100644 (file)
@@ -75,7 +75,7 @@ static int ripng_multicast_join(struct interface *ifp, int sock)
                 * While this is bogus, privs are available and easy to use
                 * for this call as a workaround.
                 */
-               frr_elevate_privs(&ripngd_privs) {
+               frr_with_privs(&ripngd_privs) {
 
                        ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
                                         (char *)&mreq, sizeof(mreq));
index 3314892e74afded39219148b8c4c4cf1823152e5..49f7dda646a9cac67282986bfab019e1fd7b0451 100644 (file)
@@ -120,8 +120,7 @@ int ripng_make_socket(struct vrf *vrf)
        /* Make datagram socket. */
        if (vrf->vrf_id != VRF_DEFAULT)
                vrf_dev = vrf->name;
-       frr_elevate_privs(&ripngd_privs)
-       {
+       frr_with_privs(&ripngd_privs) {
                sock = vrf_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP,
                                  vrf->vrf_id, vrf_dev);
                if (sock < 0) {
@@ -160,7 +159,7 @@ int ripng_make_socket(struct vrf *vrf)
 #endif /* SIN6_LEN */
        ripaddr.sin6_port = htons(RIPNG_PORT_DEFAULT);
 
-       frr_elevate_privs(&ripngd_privs) {
+       frr_with_privs(&ripngd_privs) {
                ret = bind(sock, (struct sockaddr *)&ripaddr, sizeof(ripaddr));
                if (ret < 0) {
                        zlog_err("Can't bind ripng socket: %s.",
index 78016dc9cefe544dfde53ab6bdb3ac386e95e640..8e1b62ac15e513a9d5fc52df07e3715a0445bb6a 100644 (file)
@@ -1170,7 +1170,7 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa)
        /* Test Preparation: Switch and activate address-family. */
        if (!is_attr_type_global(pa->type)) {
                test_log(test, "prepare: switch address-family to [%s]",
-                        afi_safi_print(pa->afi, pa->safi));
+                        get_afi_safi_str(pa->afi, pa->safi, false));
                test_execute(test, "address-family %s %s",
                             str_from_afi(pa->afi), str_from_safi(pa->safi));
                test_execute(test, "neighbor %s activate", g->name);
@@ -1237,7 +1237,7 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa)
        /* Test Preparation: Switch and activate address-family. */
        if (!is_attr_type_global(pa->type)) {
                test_log(test, "prepare: switch address-family to [%s]",
-                        afi_safi_print(pa->afi, pa->safi));
+                        get_afi_safi_str(pa->afi, pa->safi, false));
                test_execute(test, "address-family %s %s",
                             str_from_afi(pa->afi), str_from_safi(pa->safi));
                test_execute(test, "neighbor %s activate", g->name);
@@ -1285,7 +1285,7 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa)
        /* Test Preparation: Switch and activate address-family. */
        if (!is_attr_type_global(pa->type)) {
                test_log(test, "prepare: switch address-family to [%s]",
-                        afi_safi_print(pa->afi, pa->safi));
+                        get_afi_safi_str(pa->afi, pa->safi, false));
                test_execute(test, "address-family %s %s",
                             str_from_afi(pa->afi), str_from_safi(pa->safi));
                test_execute(test, "neighbor %s activate", g->name);
index fc3d908661f34b6af16e3017a3d20f4f8c90aac0..de638bc67a3e0df1792587ee5e3987c13ecf90f1 100644 (file)
@@ -113,7 +113,7 @@ int main(int argc, char **argv)
        ((test_privs.current_state() == ZPRIVS_RAISED) ? "Raised" : "Lowered")
 
        printf("%s\n", PRIV_STATE());
-       frr_elevate_privs(&test_privs) {
+       frr_with_privs(&test_privs) {
                printf("%s\n", PRIV_STATE());
        }
 
@@ -125,7 +125,7 @@ int main(int argc, char **argv)
 
        /* but these should continue to work... */
        printf("%s\n", PRIV_STATE());
-       frr_elevate_privs(&test_privs) {
+       frr_with_privs(&test_privs) {
                printf("%s\n", PRIV_STATE());
        }
 
index ea6fa4b9e0f617a4b2b830465012bbd2e767922b..46026887821ea0e0b0570f18bb293e1c982da178 100644 (file)
@@ -40,12 +40,12 @@ RUN export DEBIAN_FRONTEND=noninteractive \
         pytest
 
 RUN cd /tmp \
-    && wget -q https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang-dev_0.16.46_amd64.deb \
+    && wget -q https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-10/Debian-AMD64-Packages/libyang-dev_0.16.105-1_amd64.deb \
          -O libyang-dev.deb \
-    && wget -q https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang_0.16.46_amd64.deb \
+    && wget -q https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-10/Debian-AMD64-Packages/libyang0.16_0.16.105-1_amd64.deb \
          -O libyang.deb \
-    && echo "039252cc66eb254a97e160b1c325af669470cde8a02d73ec9f7b920ed3c7997c  libyang.deb" | sha256sum -c - \
-    && echo "e7e2d5bfc7b33b3218df8bef404432970f9b4ad10d6dbbdcb0e0be2babbb68e9  libyang-dev.deb" | sha256sum -c - \
+    && echo "34bef017e527a590020185f05dc39203bdf1c86223e0d990839623ec629d8598  libyang.deb" | sha256sum -c - \
+    && echo "fe9cc6e3b173ca56ef49428c281e96bf76c0f910aa75cf85098076411484e8f4  libyang-dev.deb" | sha256sum -c - \
     && dpkg -i libyang*.deb \
     && rm libyang*.deb
 
index 095ebe33445e72adb693ec482b0f9ee6f34bb609..e99111d90b1a0ccb7f0ee78ab16612a9bd204532 100755 (executable)
@@ -375,7 +375,7 @@ def test_static_routes(request):
     # Verifying RIB routes
     dut = 'r3'
     protocol = 'bgp'
-    next_hop = '10.0.0.2'
+    next_hop = ['10.0.0.2', '10.0.0.5']
     result = verify_rib(tgen, 'ipv4', dut, input_dict, next_hop=next_hop,
                         protocol=protocol)
     assert result is True, "Testcase {} :Failed \n Error: {}". \
diff --git a/tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json b/tests/topotests/bgp-ecmp-topo2/ebgp_ecmp_topo2.json
new file mode 100755 (executable)
index 0000000..50797f1
--- /dev/null
@@ -0,0 +1,664 @@
+{
+    "address_types": [
+        "ipv4",
+        "ipv6"
+    ],
+    "ipv4base": "10.0.0.0",
+    "ipv4mask": 24,
+    "ipv6base": "fd00::",
+    "ipv6mask": 64,
+    "link_ip_start": {
+        "ipv4": "10.0.0.0",
+        "v4mask": 24,
+        "ipv6": "fd00::",
+        "v6mask": 64
+    },
+    "lo_prefix": {
+        "ipv4": "1.0.",
+        "v4mask": 32,
+        "ipv6": "2001:DB8:F::",
+        "v6mask": 128
+    },
+    "routers": {
+        "r1": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r1-link1": {}
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r1-link1": {}
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link8": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link9": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link10": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link11": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link12": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link13": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link14": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link15": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link16": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link17": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link18": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link19": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link20": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link21": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link22": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link23": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link24": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link25": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link26": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link27": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link28": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link29": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link30": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link31": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link32": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "200",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r1": {
+                                    "dest_link": {
+                                        "r2-link1": {}
+                                    }
+                                },
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link1": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link2": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link3": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link4": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link5": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link6": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link7": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link8": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link9": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link10": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link11": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link12": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link13": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link14": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link15": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link16": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link17": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link18": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link19": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link20": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link21": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link22": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link23": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link24": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link25": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link26": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link27": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link28": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link29": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link30": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link31": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link32": {
+                                            "next_hop_self": true
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r1": {
+                                    "dest_link": {
+                                        "r2-link1": {}
+                                    }
+                                },
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link1": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link2": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link3": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link4": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link5": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link6": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link7": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link8": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link9": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link10": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link11": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link12": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link13": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link14": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link15": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link16": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link17": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link18": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link19": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link20": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link21": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link22": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link23": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link24": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link25": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link26": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link27": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link28": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link29": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link30": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link31": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link32": {
+                                            "next_hop_self": true
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link8": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link9": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link10": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link11": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link12": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link13": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link14": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link15": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link16": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link17": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link18": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link19": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link20": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link21": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link22": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link23": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link24": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link25": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link26": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link27": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link28": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link29": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link30": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link31": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link32": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "300",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ebgp": 32
+                            },
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link1": {},
+                                        "r3-link2": {},
+                                        "r3-link3": {},
+                                        "r3-link4": {},
+                                        "r3-link5": {},
+                                        "r3-link6": {},
+                                        "r3-link7": {},
+                                        "r3-link8": {},
+                                        "r3-link9": {},
+                                        "r3-link10": {},
+                                        "r3-link11": {},
+                                        "r3-link12": {},
+                                        "r3-link13": {},
+                                        "r3-link14": {},
+                                        "r3-link15": {},
+                                        "r3-link16": {},
+                                        "r3-link17": {},
+                                        "r3-link18": {},
+                                        "r3-link19": {},
+                                        "r3-link20": {},
+                                        "r3-link21": {},
+                                        "r3-link22": {},
+                                        "r3-link23": {},
+                                        "r3-link24": {},
+                                        "r3-link25": {},
+                                        "r3-link26": {},
+                                        "r3-link27": {},
+                                        "r3-link28": {},
+                                        "r3-link29": {},
+                                        "r3-link30": {},
+                                        "r3-link31": {},
+                                        "r3-link32": {}
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ebgp": 32
+                            },
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link1": {},
+                                        "r3-link2": {},
+                                        "r3-link3": {},
+                                        "r3-link4": {},
+                                        "r3-link5": {},
+                                        "r3-link6": {},
+                                        "r3-link7": {},
+                                        "r3-link8": {},
+                                        "r3-link9": {},
+                                        "r3-link10": {},
+                                        "r3-link11": {},
+                                        "r3-link12": {},
+                                        "r3-link13": {},
+                                        "r3-link14": {},
+                                        "r3-link15": {},
+                                        "r3-link16": {},
+                                        "r3-link17": {},
+                                        "r3-link18": {},
+                                        "r3-link19": {},
+                                        "r3-link20": {},
+                                        "r3-link21": {},
+                                        "r3-link22": {},
+                                        "r3-link23": {},
+                                        "r3-link24": {},
+                                        "r3-link25": {},
+                                        "r3-link26": {},
+                                        "r3-link27": {},
+                                        "r3-link28": {},
+                                        "r3-link29": {},
+                                        "r3-link30": {},
+                                        "r3-link31": {},
+                                        "r3-link32": {}
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json b/tests/topotests/bgp-ecmp-topo2/ibgp_ecmp_topo2.json
new file mode 100755 (executable)
index 0000000..9010b8c
--- /dev/null
@@ -0,0 +1,674 @@
+{
+    "address_types": [
+        "ipv4",
+        "ipv6"
+    ],
+    "ipv4base": "10.0.0.0",
+    "ipv4mask": 24,
+    "ipv6base": "fd00::",
+    "ipv6mask": 64,
+    "link_ip_start": {
+        "ipv4": "10.0.0.0",
+        "v4mask": 24,
+        "ipv6": "fd00::",
+        "v6mask": 64
+    },
+    "lo_prefix": {
+        "ipv4": "1.0.",
+        "v4mask": 32,
+        "ipv6": "2001:DB8:F::",
+        "v6mask": 128
+    },
+    "routers": {
+        "r1": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r1-link1": {}
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r1-link1": {}
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link8": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link9": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link10": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link11": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link12": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link13": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link14": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link15": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link16": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link17": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link18": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link19": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link20": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link21": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link22": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link23": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link24": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link25": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link26": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link27": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link28": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link29": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link30": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link31": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link32": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r1": {
+                                    "dest_link": {
+                                        "r2-link1": {}
+                                    }
+                                },
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link1": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link2": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link3": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link4": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link5": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link6": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link7": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link8": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link9": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link10": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link11": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link12": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link13": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link14": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link15": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link16": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link17": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link18": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link19": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link20": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link21": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link22": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link23": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link24": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link25": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link26": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link27": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link28": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link29": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link30": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link31": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link32": {
+                                            "next_hop_self": true
+                                        }
+                                    }
+                                }
+                            },
+                            "redistribute": [
+                                {
+                                    "redist_type": "static"
+                                }
+                            ]
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r1": {
+                                    "dest_link": {
+                                        "r2-link1": {}
+                                    }
+                                },
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link1": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link2": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link3": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link4": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link5": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link6": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link7": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link8": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link9": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link10": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link11": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link12": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link13": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link14": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link15": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link16": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link17": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link18": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link19": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link20": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link21": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link22": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link23": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link24": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link25": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link26": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link27": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link28": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link29": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link30": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link31": {
+                                            "next_hop_self": true
+                                        },
+                                        "r2-link32": {
+                                            "next_hop_self": true
+                                        }
+                                    }
+                                }
+                            },
+                            "redistribute": [
+                                {
+                                    "redist_type": "static"
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link8": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link9": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link10": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link11": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link12": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link13": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link14": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link15": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link16": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link17": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link18": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link19": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link20": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link21": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link22": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link23": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link24": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link25": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link26": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link27": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link28": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link29": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link30": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link31": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link32": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ibgp": 32
+                            },
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link1": {},
+                                        "r3-link2": {},
+                                        "r3-link3": {},
+                                        "r3-link4": {},
+                                        "r3-link5": {},
+                                        "r3-link6": {},
+                                        "r3-link7": {},
+                                        "r3-link8": {},
+                                        "r3-link9": {},
+                                        "r3-link10": {},
+                                        "r3-link11": {},
+                                        "r3-link12": {},
+                                        "r3-link13": {},
+                                        "r3-link14": {},
+                                        "r3-link15": {},
+                                        "r3-link16": {},
+                                        "r3-link17": {},
+                                        "r3-link18": {},
+                                        "r3-link19": {},
+                                        "r3-link20": {},
+                                        "r3-link21": {},
+                                        "r3-link22": {},
+                                        "r3-link23": {},
+                                        "r3-link24": {},
+                                        "r3-link25": {},
+                                        "r3-link26": {},
+                                        "r3-link27": {},
+                                        "r3-link28": {},
+                                        "r3-link29": {},
+                                        "r3-link30": {},
+                                        "r3-link31": {},
+                                        "r3-link32": {}
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ibgp": 32
+                            },
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link1": {},
+                                        "r3-link2": {},
+                                        "r3-link3": {},
+                                        "r3-link4": {},
+                                        "r3-link5": {},
+                                        "r3-link6": {},
+                                        "r3-link7": {},
+                                        "r3-link8": {},
+                                        "r3-link9": {},
+                                        "r3-link10": {},
+                                        "r3-link11": {},
+                                        "r3-link12": {},
+                                        "r3-link13": {},
+                                        "r3-link14": {},
+                                        "r3-link15": {},
+                                        "r3-link16": {},
+                                        "r3-link17": {},
+                                        "r3-link18": {},
+                                        "r3-link19": {},
+                                        "r3-link20": {},
+                                        "r3-link21": {},
+                                        "r3-link22": {},
+                                        "r3-link23": {},
+                                        "r3-link24": {},
+                                        "r3-link25": {},
+                                        "r3-link26": {},
+                                        "r3-link27": {},
+                                        "r3-link28": {},
+                                        "r3-link29": {},
+                                        "r3-link30": {},
+                                        "r3-link31": {},
+                                        "r3-link32": {}
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
new file mode 100755 (executable)
index 0000000..4b9f419
--- /dev/null
@@ -0,0 +1,817 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2019 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+
+"""
+Following tests are covered to test ecmp functionality on EBGP.
+1. Verify routes installed as per maximum-paths configuration (8/16/32)
+2. Disable/Shut selected paths nexthops and verify other next are installed in
+   the RIB of DUT. Enable interfaces and verify RIB count.
+3. Verify BGP table and RIB in DUT after clear BGP routes and neighbors.
+4. Verify routes are cleared from BGP and RIB table of DUT when
+   redistribute static configuration is removed.
+5. Shut BGP neigbors one by one and verify BGP and routing table updated
+   accordingly in DUT
+6. Delete static routes and verify routers are cleared from BGP table and RIB
+   of DUT.
+7. Verify routes are cleared from BGP and RIB table of DUT when advertise
+   network configuration is removed.
+"""
+import os
+import sys
+import time
+import json
+import pytest
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+sys.path.append(os.path.join(CWD, '../../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from mininet.topo import Topo
+
+from lib.common_config import (
+    start_topology, write_test_header,
+    write_test_footer,
+    verify_rib, create_static_routes, check_address_types,
+    interface_status, reset_config_on_routers
+)
+from lib.topolog import logger
+from lib.bgp import (
+    verify_bgp_convergence, create_router_bgp,
+    clear_bgp_and_verify)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology and configuration creation
+jsonFile = "{}/ebgp_ecmp_topo2.json".format(CWD)
+
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+NEXT_HOPS = {"ipv4": [], "ipv6": []}
+INTF_LIST_R3 = []
+INTF_LIST_R2 = []
+NETWORK = {"ipv4": "11.0.20.1/32", "ipv6": "1::/64"}
+NEXT_HOP_IP = {"ipv4": "10.0.0.1", "ipv6": "fd00::1"}
+BGP_CONVERGENCE = False
+
+
+class CreateTopo(Topo):
+    """
+    Test topology builder.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+    Sets up the pytest environment.
+
+    * `mod`: module name
+    """
+    global NEXT_HOPS, INTF_LIST_R3, INTF_LIST_R2, TEST_STATIC
+    global ADDR_TYPES
+
+    testsuite_run_time = time.asctime(time.localtime(time.time()))
+    logger.info("Testsuite start time: {}".format(testsuite_run_time))
+    logger.info("=" * 40)
+
+    logger.info("Running setup_module to create topology")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # tgen.mininet_cli()
+    # Api call verify whether BGP is converged
+    ADDR_TYPES = check_address_types()
+
+    BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+    assert BGP_CONVERGENCE is True, ("setup_module :Failed \n Error:"
+                                     " {}".format(BGP_CONVERGENCE))
+
+    link_data = [val for links, val in
+                 topo["routers"]["r2"]["links"].iteritems()
+                 if "r3" in links]
+    for adt in ADDR_TYPES:
+        NEXT_HOPS[adt] = [val[adt].split("/")[0] for val in link_data]
+        if adt == "ipv4":
+            NEXT_HOPS[adt] = sorted(
+                NEXT_HOPS[adt], key=lambda x: int(x.split(".")[2]))
+        elif adt == "ipv6":
+            NEXT_HOPS[adt] = sorted(
+                NEXT_HOPS[adt], key=lambda x: int(x.split(':')[-3], 16))
+
+    INTF_LIST_R2 = [val["interface"].split("/")[0] for val in link_data]
+    INTF_LIST_R2 = sorted(INTF_LIST_R2, key=lambda x: int(x.split("eth")[1]))
+
+    link_data = [val for links, val in
+                 topo["routers"]["r3"]["links"].iteritems()
+                 if "r2" in links]
+    INTF_LIST_R3 = [val["interface"].split("/")[0] for val in link_data]
+    INTF_LIST_R3 = sorted(INTF_LIST_R3, key=lambda x: int(x.split("eth")[1]))
+
+    # STATIC_ROUTE = True
+    logger.info("Running setup_module() done")
+
+
+def teardown_module():
+    """
+    Teardown the pytest environment.
+
+    * `mod`: module name
+    """
+
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+
+def static_or_nw(tgen, topo, tc_name, test_type, dut):
+
+    if test_type == "redist_static":
+        input_dict_static = {
+            dut: {
+                "static_routes": [
+                    {
+                        "network": NETWORK["ipv4"],
+                        "next_hop": NEXT_HOP_IP["ipv4"]
+                    },
+                    {
+                        "network": NETWORK["ipv6"],
+                        "next_hop": NEXT_HOP_IP["ipv6"]
+                    }
+                ]
+            }
+        }
+        logger.info("Configuring static route on router %s", dut)
+        result = create_static_routes(tgen, input_dict_static)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+        input_dict_2 = {
+            dut: {
+                "bgp": {
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "redistribute": [{
+                                    "redist_type": "static"
+                                }]
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "redistribute": [{
+                                    "redist_type": "static"
+                                }]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        logger.info("Configuring redistribute static route on router %s", dut)
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    elif test_type == "advertise_nw":
+        input_dict_nw = {
+            dut: {
+                "bgp": {
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "advertise_networks": [
+                                    {"network": NETWORK["ipv4"]}
+                                ]
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "advertise_networks": [
+                                    {"network": NETWORK["ipv6"]}
+                                ]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        logger.info("Advertising networks %s %s from router %s",
+                    NETWORK["ipv4"], NETWORK["ipv6"], dut)
+        result = create_router_bgp(tgen, topo, input_dict_nw)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+
+@pytest.mark.parametrize("ecmp_num", ["8", "16", "32"])
+@pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"])
+def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
+    """
+    Verify routes installed as per maximum-paths
+    configuration (8/16/32).
+    """
+
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    reset_config_on_routers(tgen)
+
+    static_or_nw(tgen, topo, tc_name, test_type, "r2")
+
+    input_dict = {
+        "r3": {
+            "bgp": {
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ebgp": ecmp_num,
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ebgp": ecmp_num,
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    logger.info("Configuring bgp maximum-paths %s on router r3", ecmp_num)
+    result = create_router_bgp(tgen, topo, input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    # Verifying RIB routes
+    dut = "r3"
+    protocol = "bgp"
+
+    for addr_type in ADDR_TYPES:
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_1,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_ecmp_after_clear_bgp(request):
+    """ Verify BGP table and RIB in DUT after clear BGP routes and neighbors"""
+
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    reset_config_on_routers(tgen)
+
+    # Verifying RIB routes
+    dut = "r3"
+    protocol = "bgp"
+
+    static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
+    for addr_type in ADDR_TYPES:
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_1,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    # Clear bgp
+    result = clear_bgp_and_verify(tgen, topo, dut)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_1,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_ecmp_remove_redistribute_static(request):
+    """ Verify routes are cleared from BGP and RIB table of DUT when
+        redistribute static configuration is removed."""
+
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    reset_config_on_routers(tgen)
+    static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
+    for addr_type in ADDR_TYPES:
+
+        # Verifying RIB routes
+        dut = "r3"
+        protocol = "bgp"
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_1,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    input_dict_2 = {
+        "r2": {
+            "bgp": {
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "redistribute": [{
+                                "redist_type": "static",
+                                "delete": True
+
+                            }]
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "redistribute": [{
+                                "redist_type": "static",
+                                "delete": True
+
+                            }]
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    logger.info("Remove redistribute static")
+    result = create_router_bgp(tgen, topo, input_dict_2)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+
+        # Verifying RIB routes
+        dut = "r3"
+        protocol = "bgp"
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3 are deleted", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_1,
+                            next_hop=[], protocol=protocol, expected=False)
+        assert result is not True, "Testcase {} : Failed \n Routes still" \
+                                   " present in RIB".format(tc_name)
+
+    logger.info("Enable redistribute static")
+    input_dict_2 = {
+        "r2": {
+            "bgp": {
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "redistribute": [{
+                                "redist_type": "static"
+                            }]
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "redistribute": [{
+                                "redist_type": "static"
+                            }]
+                        }
+                    }
+                }
+            }
+        }
+    }
+    result = create_router_bgp(tgen, topo, input_dict_2)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        # Verifying RIB routes
+        dut = "r3"
+        protocol = "bgp"
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_1,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_ecmp_shut_bgp_neighbor(request):
+    """
+    Disable/Shut selected paths nexthops and verify other next are installed in
+    the RIB of DUT. Enable interfaces and verify RIB count.
+
+    Shut BGP neigbors one by one and verify BGP and routing table updated
+    accordingly in DUT
+    """
+
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    logger.info(INTF_LIST_R2)
+    # Verifying RIB routes
+    dut = "r3"
+    protocol = "bgp"
+
+    reset_config_on_routers(tgen)
+    static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
+
+    for addr_type in ADDR_TYPES:
+        input_dict = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    for intf_num in range(len(INTF_LIST_R2)+1, 16):
+        intf_val = INTF_LIST_R2[intf_num:intf_num+16]
+
+        input_dict_1 = {
+            "r2": {
+                "interface_list": [intf_val],
+                "status": "down"
+            }
+        }
+        logger.info("Shutting down neighbor interface {} on r2".
+                    format(intf_val))
+        result = interface_status(tgen, topo, input_dict_1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+        for addr_type in ADDR_TYPES:
+            if intf_num + 16 < 32:
+                check_hops = NEXT_HOPS[addr_type]
+            else:
+                check_hops = []
+
+            input_dict = {
+                "r3": {
+                    "static_routes": [
+                        {
+                            "network": NETWORK[addr_type]
+                        }
+                    ]
+                }
+            }
+            logger.info("Verifying %s routes on r3", addr_type)
+            result = verify_rib(tgen, addr_type, dut, input_dict,
+                                next_hop=check_hops,
+                                protocol=protocol)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result)
+
+    input_dict_1 = {
+        "r2": {
+            "interface_list": INTF_LIST_R2,
+            "status": "up"
+        }
+    }
+
+    logger.info("Enabling all neighbor interface {} on r2")
+    result = interface_status(tgen, topo, input_dict_1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
+    for addr_type in ADDR_TYPES:
+        input_dict = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_ecmp_remove_static_route(request):
+    """
+    Delete static routes and verify routers are cleared from BGP table,
+    and RIB of DUT.
+    """
+
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Verifying RIB routes
+    dut = "r3"
+    protocol = "bgp"
+
+    reset_config_on_routers(tgen)
+
+    static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
+    for addr_type in ADDR_TYPES:
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_1,
+            next_hop=NEXT_HOPS[addr_type], protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "delete": True
+                    }
+                ]
+            }
+        }
+
+        logger.info("Remove static routes")
+        result = create_static_routes(tgen, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+        logger.info("Verifying %s routes on r3 are removed", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_2,
+                            next_hop=[], protocol=protocol, expected=False)
+        assert result is not True, "Testcase {} : Failed \n Routes still" \
+                                   " present in RIB".format(tc_name)
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Enable static route")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_4,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+
+def test_ecmp_remove_nw_advertise(request):
+    """
+    Verify routes are cleared from BGP and RIB table of DUT,
+    when advertise network configuration is removed
+    """
+
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Verifying RIB routes
+    dut = "r3"
+    protocol = "bgp"
+
+    reset_config_on_routers(tgen)
+    static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
+    for addr_type in ADDR_TYPES:
+        input_dict = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    input_dict_3 = {
+        "r2": {
+            "bgp": {
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "advertise_networks": [{
+                                    "network": NETWORK["ipv4"],
+                                    "delete": True
+                                }]
+                            }
+                        },
+                    "ipv6": {
+                        "unicast": {
+                            "advertise_networks": [{
+                                    "network": NETWORK["ipv6"],
+                                    "delete": True
+                                }]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+    logger.info("Withdraw advertised networks")
+    result = create_router_bgp(tgen, topo, input_dict_3)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        input_dict = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict,
+                            next_hop=[], protocol=protocol, expected=False)
+        assert result is not True, "Testcase {} : Failed \n Routes still" \
+                                   " present in RIB".format(tc_name)
+
+    static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
+    for addr_type in ADDR_TYPES:
+        input_dict = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
new file mode 100755 (executable)
index 0000000..a9f18ed
--- /dev/null
@@ -0,0 +1,813 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2019 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+
+"""
+Following tests are covered to test ecmp functionality on EBGP.
+1. Verify routes installed as per maximum-paths configuration (8/16/32)
+2. Disable/Shut selected paths nexthops and verify other next are installed in
+   the RIB of DUT. Enable interfaces and verify RIB count.
+3. Verify BGP table and RIB in DUT after clear BGP routes and neighbors.
+4. Verify routes are cleared from BGP and RIB table of DUT when
+   redistribute static configuration is removed.
+5. Shut BGP neigbors one by one and verify BGP and routing table updated
+   accordingly in DUT
+6. Delete static routes and verify routers are cleared from BGP table and RIB
+   of DUT.
+7. Verify routes are cleared from BGP and RIB table of DUT when advertise
+   network configuration is removed.
+"""
+import os
+import sys
+import time
+import json
+import pytest
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+sys.path.append(os.path.join(CWD, '../../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from mininet.topo import Topo
+
+from lib.common_config import (
+    start_topology, write_test_header,
+    write_test_footer,
+    verify_rib, create_static_routes, check_address_types,
+    interface_status, reset_config_on_routers
+)
+from lib.topolog import logger
+from lib.bgp import (
+    verify_bgp_convergence, create_router_bgp,
+    clear_bgp_and_verify)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology and configuration creation
+jsonFile = "{}/ibgp_ecmp_topo2.json".format(CWD)
+
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+NEXT_HOPS = {"ipv4": [], "ipv6": []}
+INTF_LIST_R3 = []
+INTF_LIST_R2 = []
+NETWORK = {"ipv4": "11.0.20.1/32", "ipv6": "1::/64"}
+NEXT_HOP_IP = {"ipv4": "10.0.0.1", "ipv6": "fd00::1"}
+BGP_CONVERGENCE = False
+
+
+class CreateTopo(Topo):
+    """
+    Test topology builder.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+    Sets up the pytest environment.
+
+    * `mod`: module name
+    """
+    global NEXT_HOPS, INTF_LIST_R3, INTF_LIST_R2, TEST_STATIC
+    global ADDR_TYPES
+
+    testsuite_run_time = time.asctime(time.localtime(time.time()))
+    logger.info("Testsuite start time: {}".format(testsuite_run_time))
+    logger.info("=" * 40)
+
+    logger.info("Running setup_module to create topology")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # tgen.mininet_cli()
+    # Api call verify whether BGP is converged
+    ADDR_TYPES = check_address_types()
+
+    for addr_type in ADDR_TYPES:
+        BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+        assert BGP_CONVERGENCE is True, ("setup_module :Failed \n Error:"
+                                         " {}".format(BGP_CONVERGENCE))
+
+    link_data = [val for links, val in
+                 topo["routers"]["r2"]["links"].iteritems()
+                 if "r3" in links]
+    for adt in ADDR_TYPES:
+        NEXT_HOPS[adt] = [val[adt].split("/")[0] for val in link_data]
+        if adt == "ipv4":
+            NEXT_HOPS[adt] = sorted(
+                NEXT_HOPS[adt], key=lambda x: int(x.split(".")[2]))
+        elif adt == "ipv6":
+            NEXT_HOPS[adt] = sorted(
+                NEXT_HOPS[adt], key=lambda x: int(x.split(':')[-3], 16))
+
+    INTF_LIST_R2 = [val["interface"].split("/")[0] for val in link_data]
+    INTF_LIST_R2 = sorted(INTF_LIST_R2, key=lambda x: int(x.split("eth")[1]))
+
+    link_data = [val for links, val in
+                 topo["routers"]["r3"]["links"].iteritems()
+                 if "r2" in links]
+    INTF_LIST_R3 = [val["interface"].split("/")[0] for val in link_data]
+    INTF_LIST_R3 = sorted(INTF_LIST_R3, key=lambda x: int(x.split("eth")[1]))
+
+    # STATIC_ROUTE = True
+    logger.info("Running setup_module() done")
+
+
+def teardown_module():
+    """
+    Teardown the pytest environment.
+
+    * `mod`: module name
+    """
+
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+
+def static_or_nw(tgen, topo, tc_name, test_type, dut):
+
+    if test_type == "redist_static":
+        input_dict_static = {
+            dut: {
+                "static_routes": [
+                    {
+                        "network": NETWORK["ipv4"],
+                        "next_hop": NEXT_HOP_IP["ipv4"]
+                    },
+                    {
+                        "network": NETWORK["ipv6"],
+                        "next_hop": NEXT_HOP_IP["ipv6"]
+                    }
+                ]
+            }
+        }
+        logger.info("Configuring static route on router %s", dut)
+        result = create_static_routes(tgen, input_dict_static)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+        input_dict_2 = {
+            dut: {
+                "bgp": {
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "redistribute": [{
+                                    "redist_type": "static"
+                                }]
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "redistribute": [{
+                                    "redist_type": "static"
+                                }]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        logger.info("Configuring redistribute static route on router %s", dut)
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    elif test_type == "advertise_nw":
+        input_dict_nw = {
+            dut: {
+                "bgp": {
+                    "address_family": {
+                        "ipv4": {
+                            "unicast": {
+                                "advertise_networks": [
+                                    {"network": NETWORK["ipv4"]}
+                                ]
+                            }
+                        },
+                        "ipv6": {
+                            "unicast": {
+                                "advertise_networks": [
+                                    {"network": NETWORK["ipv6"]}
+                                ]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        logger.info("Advertising networks %s %s from router %s",
+                    NETWORK["ipv4"], NETWORK["ipv6"], dut)
+        result = create_router_bgp(tgen, topo, input_dict_nw)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+
+@pytest.mark.parametrize("ecmp_num", ["8", "16", "32"])
+@pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"])
+def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
+    """
+    Verify routes installed as per maximum-paths
+    configuration (8/16/32).
+    """
+
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    reset_config_on_routers(tgen)
+
+    static_or_nw(tgen, topo, tc_name, test_type, "r2")
+
+    input_dict = {
+        "r3": {
+            "bgp": {
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ibgp": ecmp_num,
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "maximum_paths": {
+                                "ibgp": ecmp_num,
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    logger.info("Configuring bgp maximum-paths %s on router r3", ecmp_num)
+    result = create_router_bgp(tgen, topo, input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    # Verifying RIB routes
+    dut = "r3"
+    protocol = "bgp"
+
+    for addr_type in ADDR_TYPES:
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_1,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_ecmp_after_clear_bgp(request):
+    """ Verify BGP table and RIB in DUT after clear BGP routes and neighbors"""
+
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    reset_config_on_routers(tgen)
+
+    # Verifying RIB routes
+    dut = "r3"
+    protocol = "bgp"
+
+    static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
+    for addr_type in ADDR_TYPES:
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_1,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    # Clear bgp
+    result = clear_bgp_and_verify(tgen, topo, dut)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_1,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_ecmp_remove_redistribute_static(request):
+    """ Verify routes are cleared from BGP and RIB table of DUT when
+        redistribute static configuration is removed."""
+
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    reset_config_on_routers(tgen)
+    static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
+    for addr_type in ADDR_TYPES:
+
+        # Verifying RIB routes
+        dut = "r3"
+        protocol = "bgp"
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_1,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    input_dict_2 = {
+        "r2": {
+            "bgp": {
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "redistribute": [{
+                                "redist_type": "static",
+                                "delete": True
+
+                            }]
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "redistribute": [{
+                                "redist_type": "static",
+                                "delete": True
+
+                            }]
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    logger.info("Remove redistribute static")
+    result = create_router_bgp(tgen, topo, input_dict_2)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+
+        # Verifying RIB routes
+        dut = "r3"
+        protocol = "bgp"
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3 are deleted", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_1,
+                            next_hop=[], protocol=protocol, expected=False)
+        assert result is not True, "Testcase {} : Failed \n Routes still" \
+                                   " present in RIB".format(tc_name)
+
+    logger.info("Enable redistribute static")
+    input_dict_2 = {
+        "r2": {
+            "bgp": {
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "redistribute": [{
+                                "redist_type": "static"
+                            }]
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "redistribute": [{
+                                "redist_type": "static"
+                            }]
+                        }
+                    }
+                }
+            }
+        }
+    }
+    result = create_router_bgp(tgen, topo, input_dict_2)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        # Verifying RIB routes
+        dut = "r3"
+        protocol = "bgp"
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_1,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_ecmp_shut_bgp_neighbor(request):
+    """ Shut BGP neigbors one by one and verify BGP and routing table updated
+        accordingly in DUT """
+
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    logger.info(INTF_LIST_R2)
+    # Verifying RIB routes
+    dut = "r3"
+    protocol = "bgp"
+
+    reset_config_on_routers(tgen)
+    static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
+
+    for addr_type in ADDR_TYPES:
+        input_dict = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    for intf_num in range(len(INTF_LIST_R2)+1, 16):
+        intf_val = INTF_LIST_R2[intf_num:intf_num+16]
+
+        input_dict_1 = {
+            "r2": {
+                "interface_list": [intf_val],
+                "status": "down"
+            }
+        }
+        logger.info("Shutting down neighbor interface {} on r2".
+                    format(intf_val))
+        result = interface_status(tgen, topo, input_dict_1)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+        for addr_type in ADDR_TYPES:
+            if intf_num + 16 < 32:
+                check_hops = NEXT_HOPS[addr_type]
+            else:
+                check_hops = []
+
+            input_dict = {
+                "r3": {
+                    "static_routes": [
+                        {
+                            "network": NETWORK[addr_type]
+                        }
+                    ]
+                }
+            }
+            logger.info("Verifying %s routes on r3", addr_type)
+            result = verify_rib(tgen, addr_type, dut, input_dict,
+                                next_hop=check_hops,
+                                protocol=protocol)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result)
+
+    input_dict_1 = {
+        "r2": {
+            "interface_list": INTF_LIST_R2,
+            "status": "up"
+        }
+    }
+
+    logger.info("Enabling all neighbor interface {} on r2")
+    result = interface_status(tgen, topo, input_dict_1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
+    for addr_type in ADDR_TYPES:
+        input_dict = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_ecmp_remove_static_route(request):
+    """
+    Delete static routes and verify routers are cleared from BGP table,
+    and RIB of DUT.
+    """
+
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Verifying RIB routes
+    dut = "r3"
+    protocol = "bgp"
+
+    reset_config_on_routers(tgen)
+
+    static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
+    for addr_type in ADDR_TYPES:
+        input_dict_1 = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_1,
+            next_hop=NEXT_HOPS[addr_type], protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP[addr_type],
+                        "delete": True
+                    }
+                ]
+            }
+        }
+
+        logger.info("Remove static routes")
+        result = create_static_routes(tgen, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+        logger.info("Verifying %s routes on r3 are removed", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_2,
+                            next_hop=[], protocol=protocol, expected=False)
+        assert result is not True, "Testcase {} : Failed \n Routes still" \
+                                   " present in RIB".format(tc_name)
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Enable static route")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict_4,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    write_test_footer(tc_name)
+
+
+def test_ecmp_remove_nw_advertise(request):
+    """
+    Verify routes are cleared from BGP and RIB table of DUT,
+    when advertise network configuration is removed
+    """
+
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    # Verifying RIB routes
+    dut = "r3"
+    protocol = "bgp"
+
+    reset_config_on_routers(tgen)
+    static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
+    for addr_type in ADDR_TYPES:
+        input_dict = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+    input_dict_3 = {
+        "r2": {
+            "bgp": {
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "advertise_networks": [{
+                                    "network": NETWORK["ipv4"],
+                                    "delete": True
+                                }]
+                            }
+                        },
+                    "ipv6": {
+                        "unicast": {
+                            "advertise_networks": [{
+                                    "network": NETWORK["ipv6"],
+                                    "delete": True
+                                }]
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+    logger.info("Withdraw advertised networks")
+    result = create_router_bgp(tgen, topo, input_dict_3)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(
+        tc_name, result)
+
+    for addr_type in ADDR_TYPES:
+        input_dict = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict,
+                            next_hop=[], protocol=protocol, expected=False)
+        assert result is not True, "Testcase {} : Failed \n Routes still" \
+                                   " present in RIB".format(tc_name)
+
+    static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
+    for addr_type in ADDR_TYPES:
+        input_dict = {
+            "r3": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type]
+                    }
+                ]
+            }
+        }
+        logger.info("Verifying %s routes on r3", addr_type)
+        result = verify_rib(tgen, addr_type, dut, input_dict,
+                            next_hop=NEXT_HOPS[addr_type],
+                            protocol=protocol)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result)
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index 2b9c411ff27417252e84f796763c5c96e8aceda6..9f92b4b290807f1fa3a5d1ae88540760fa91dace 100755 (executable)
@@ -219,7 +219,8 @@ def test_next_hop_attribute(request):
     dut = "r1"
     protocol = "bgp"
     result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
-    assert result is not True
+    assert result is not True, "Testcase {} : Failed \n Error: Routes still" \
+                               " present in RIB".format(tc_name)
 
     # Configure next-hop-self to bgp neighbor
     input_dict_1 = {
@@ -484,7 +485,7 @@ def test_localpref_attribute(request):
                             "neighbor": {
                                 "r1": {
                                     "dest_link": {
-                                        "r3": {
+                                        "r2": {
                                             "route_maps": [
                                                 {"name": "RMAP_LOCAL_PREF",
                                                  "direction": "in"}
@@ -499,6 +500,7 @@ def test_localpref_attribute(request):
             }
         }
     }
+
     result = create_router_bgp(tgen, topo, input_dict_4)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(
         tc_name, result)
index d3892e9d07d4d4aa576f984ef1de053e3ebeb462..b8975997ead0da22e35c29999c57dd852d2978b8 100755 (executable)
@@ -386,8 +386,8 @@ def test_ip_prefix_lists_out_permit(request):
         tc_name, result)
 
     result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
-    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
-        tc_name, result)
+    assert result is not True, "Testcase {} : Failed \n Error: Routes still" \
+                               " present in RIB".format(tc_name)
     write_test_footer(tc_name)
 
 
@@ -497,8 +497,8 @@ def test_ip_prefix_lists_in_deny_and_permit_any(request):
     dut = "r3"
     protocol = "bgp"
     result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
-    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
-        tc_name, result)
+    assert result is not True, "Testcase {} : Failed \n Error: Routes still" \
+                               " present in RIB".format(tc_name)
 
     write_test_footer(tc_name)
 
@@ -542,7 +542,6 @@ def test_delete_prefix_lists(request):
     result = verify_prefix_lists(tgen, input_dict_2)
     assert result is not True, "Testcase {} : Failed \n Error: {}".format(
         tc_name, result)
-    logger.info(result)
 
     # Delete prefix list
     input_dict_2 = {
@@ -714,9 +713,8 @@ def test_ip_prefix_lists_out_deny_and_permit_any(request):
     dut = "r4"
     protocol = "bgp"
     result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
-    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
-        tc_name, result)
-
+    assert result is not True, "Testcase {} : Failed \n Error: Routes still" \
+                               " present in RIB".format(tc_name)
     write_test_footer(tc_name)
 
 
@@ -859,8 +857,8 @@ def test_modify_prefix_lists_in_permit_to_deny(request):
     dut = "r3"
     protocol = "bgp"
     result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
-    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
-        tc_name, result)
+    assert result is not True, "Testcase {} : Failed \n Error: Routes still" \
+                               " present in RIB".format(tc_name)
 
     write_test_footer(tc_name)
 
@@ -972,8 +970,8 @@ def test_modify_prefix_lists_in_deny_to_permit(request):
     dut = "r3"
     protocol = "bgp"
     result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
-    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
-        tc_name, result)
+    assert result is not True, "Testcase {} : Failed \n Error: Routes still" \
+                               " present in RIB".format(tc_name)
 
     # Modify  ip prefix list
     input_dict_1 = {
@@ -1152,8 +1150,8 @@ def test_modify_prefix_lists_out_permit_to_deny(request):
     dut = "r4"
     protocol = "bgp"
     result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
-    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
-        tc_name, result)
+    assert result is not True, "Testcase {} : Failed \n Error: Routes still" \
+                               " present in RIB".format(tc_name)
 
     write_test_footer(tc_name)
 
@@ -1265,8 +1263,8 @@ def test_modify_prefix_lists_out_deny_to_permit(request):
     dut = "r4"
     protocol = "bgp"
     result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False)
-    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
-        tc_name, result)
+    assert result is not True, "Testcase {} : Failed \n Error: Routes still" \
+                               " present in RIB".format(tc_name)
 
     # Modify ip prefix list
     input_dict_1 = {
@@ -1439,8 +1437,8 @@ def test_ip_prefix_lists_implicit_deny(request):
     dut = "r4"
     protocol = "bgp"
     result = verify_rib(tgen, "ipv4", dut, input_dict_1, protocol=protocol, expected=False)
-    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
-        tc_name, result)
+    assert result is not True, "Testcase {} : Failed \n Error: Routes still" \
+                               " present in RIB".format(tc_name)
 
     write_test_footer(tc_name)
 
index de6c35ba8fab09f20087b3a639a1032209c70f7b..ed350ebfeb157e7e6b3006cf423a83f35e800390 100644 (file)
@@ -88,7 +88,7 @@ def test_bgp_maximum_prefix_invalid():
         while True:
             output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
             if output['192.168.255.1']['bgpState'] == 'Established':
-                if output['192.168.255.1']['addressFamilyInfo']['IPv4 Unicast']['acceptedPrefixCounter'] == 2:
+                if output['192.168.255.1']['addressFamilyInfo']['ipv4Unicast']['acceptedPrefixCounter'] == 2:
                     return True
 
     def _bgp_comm_list_delete(router):
index 7b3a883afa5504f762084300fc845908dacb2f9c..1317a510d13a03ab91e040b132a5bc025f4a88cc 100644 (file)
@@ -2,16 +2,16 @@ from lutil import luCommand
 luCommand('ce1','ping 192.168.1.1 -c 1',' 0. packet loss','pass','CE->PE ping')
 luCommand('ce2','ping 192.168.1.1 -c 1',' 0. packet loss','pass','CE->PE ping')
 luCommand('ce3','ping 192.168.1.1 -c 1',' 0. packet loss','pass','CE->PE ping')
-luCommand('ce1','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up',90)
-luCommand('ce2','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up')
-luCommand('ce3','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up')
+luCommand('ce1','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up',180)
+luCommand('ce2','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up',180)
+luCommand('ce3','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up',180)
 luCommand('r1','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
 luCommand('r3','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
 luCommand('r4','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
-luCommand('r2','vtysh -c "show bgp summary"',' 00:0.* 00:0.* 00:0','wait','Core adjacencies up')
-luCommand('r1','vtysh -c "show bgp summary"',' 00:0','pass','Core adjacencies up')
-luCommand('r3','vtysh -c "show bgp summary"',' 00:0','pass','Core adjacencies up')
-luCommand('r4','vtysh -c "show bgp summary"',' 00:0','pass','Core adjacencies up')
+luCommand('r2','vtysh -c "show bgp summary"',' 00:0.* 00:0.* 00:0','wait','Core adjacencies up',180)
+luCommand('r1','vtysh -c "show bgp summary"',' 00:0','wait','Core adjacencies up',180)
+luCommand('r3','vtysh -c "show bgp summary"',' 00:0','wait','Core adjacencies up',180)
+luCommand('r4','vtysh -c "show bgp summary"',' 00:0','wait','Core adjacencies up',180)
 luCommand('r1','vtysh -c "show bgp vrf all summary"',' 00:0.* 00:0','pass','All adjacencies up')
 luCommand('r3','vtysh -c "show bgp vrf all summary"',' 00:0.* 00:0','pass','All adjacencies up')
 luCommand('r4','vtysh -c "show bgp vrf all summary"',' 00:0.* 00:0','pass','All adjacencies up')
index 5674120b9c750c7213e8fd4348d7d626d2a7f7a1..c2b0cf9e7a2068287035ec6ae764b4258828b17d 100644 (file)
@@ -6,10 +6,10 @@ luCommand('ce4','vtysh -c "show bgp vrf all summary"',' 00:0','wait','Adjacencie
 luCommand('r1','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
 luCommand('r3','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
 luCommand('r4','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
-luCommand('r2','vtysh -c "show bgp summary"',' 00:0.* 00:0.* 00:0','wait','Core adjacencies up',300)
-luCommand('r1','vtysh -c "show bgp summary"',' 00:0','pass','Core adjacencies up')
-luCommand('r3','vtysh -c "show bgp summary"',' 00:0','pass','Core adjacencies up')
-luCommand('r4','vtysh -c "show bgp summary"',' 00:0','pass','Core adjacencies up')
+luCommand('r2','vtysh -c "show bgp summary"',' 00:0.* 00:0.* 00:0','wait','Core adjacencies up',180)
+luCommand('r1','vtysh -c "show bgp summary"',' 00:0','wait','Core adjacencies up', 180)
+luCommand('r3','vtysh -c "show bgp summary"',' 00:0','wait','Core adjacencies up', 180)
+luCommand('r4','vtysh -c "show bgp summary"',' 00:0','wait','Core adjacencies up', 180)
 luCommand('r1','vtysh -c "show bgp vrf all summary"',' 00:0.* 00:0','pass','All adjacencies up')
 luCommand('r3','vtysh -c "show bgp vrf all summary"',' 00:0.* 00:0','pass','All adjacencies up')
 luCommand('r4','vtysh -c "show bgp vrf all summary"',' 00:0.* 00:0.* 00:0','pass','All adjacencies up')
index 1f53791f6a4402894491c8ff66de21095292d01d..6fbe4ff1c0da59510c62edcc703ee6004ff502e8 100644 (file)
@@ -1,10 +1,10 @@
 luCommand('r1','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
 luCommand('r3','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
 luCommand('r4','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60)
-luCommand('r2','vtysh -c "show bgp summary"',' 00:0.* 00:0.* 00:0','wait','Core adjacencies up',30)
-luCommand('r1','vtysh -c "show bgp vrf all summary"',' 00:0','pass','All adjacencies up')
-luCommand('r3','vtysh -c "show bgp vrf all summary"',' 00:0','pass','All adjacencies up')
-luCommand('r4','vtysh -c "show bgp vrf all summary"',' 00:0','pass','All adjacencies up')
+luCommand('r2','vtysh -c "show bgp summary"',' 00:0.* 00:0.* 00:0','wait','Core adjacencies up',180)
+luCommand('r1','vtysh -c "show bgp vrf all summary"',' 00:0','wait','All adjacencies up',180)
+luCommand('r3','vtysh -c "show bgp vrf all summary"',' 00:0','wait','All adjacencies up',180)
+luCommand('r4','vtysh -c "show bgp vrf all summary"',' 00:0','wait','All adjacencies up',180)
 luCommand('r1','ping 3.3.3.3 -c 1',' 0. packet loss','wait','PE->PE3 (loopback) ping')
 luCommand('r1','ping 4.4.4.4 -c 1',' 0. packet loss','wait','PE->PE4 (loopback) ping')
 #luCommand('r4','ping 3.3.3.3 -c 1',' 0. packet loss','wait','PE->PE3 (loopback) ping')
index 2d72082c1ecd44a0d4b47052baa2815cb815ab7c..dee0ec81181fe8a4ec1d2154a47f34f1e44e033d 100755 (executable)
@@ -84,6 +84,7 @@ if [ ! -e Makefile ]; then
                --enable-static-bin \
                --enable-static \
                --enable-shared \
+               --enable-dev-build \
                --with-moduledir=/usr/lib/frr/modules \
                --prefix=/usr \
                --localstatedir=/var/run/frr \
index b794b96a631e26b9402f8969047642148c24cdf5..cd069aaec5e1df5aa13b5443ab66c249bab58461 100755 (executable)
@@ -178,7 +178,7 @@ def test_static_routes(request):
     # Static routes are created as part of initial configuration,
     # verifying RIB
     dut = 'r3'
-    next_hop = '10.0.0.1'
+    next_hop = ['10.0.0.1', '10.0.0.5']
     input_dict = {
         "r1": {
             "static_routes": [
index 2613f45f1ccf48cf923c970b61e52315fdd15770..c47dddb8d4d9a8286756e5f7e07b0786dff54fb8 100644 (file)
@@ -32,7 +32,8 @@ from lib.common_config import (create_common_configuration,
                                load_config_to_router,
                                check_address_types,
                                generate_ips,
-                               find_interface_with_greater_ip)
+                               find_interface_with_greater_ip,
+                               run_frr_cmd, retry)
 
 BGP_CONVERGENCE_TIMEOUT = 10
 
@@ -116,8 +117,8 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False):
             logger.debug("Router %s: 'bgp' not present in input_dict", router)
             continue
 
-        result = __create_bgp_global(tgen, input_dict, router, build)
-        if result is True:
+        data_all_bgp = __create_bgp_global(tgen, input_dict, router, build)
+        if data_all_bgp:
             bgp_data = input_dict[router]["bgp"]
 
             bgp_addr_data = bgp_data.setdefault("address_family", {})
@@ -134,8 +135,18 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False):
                     or ipv6_data.setdefault("unicast", {}) else False
 
                 if neigh_unicast:
-                    result = __create_bgp_unicast_neighbor(
-                        tgen, topo, input_dict, router, build)
+                    data_all_bgp = __create_bgp_unicast_neighbor(
+                        tgen, topo, input_dict, router,
+                        config_data=data_all_bgp)
+
+        try:
+            result = create_common_configuration(tgen, router, data_all_bgp,
+                                                 "bgp", build)
+        except InvalidCLIError:
+            # Traceback
+            errormsg = traceback.format_exc()
+            logger.error(errormsg)
+            return errormsg
 
     logger.debug("Exiting lib API: create_router_bgp()")
     return result
@@ -157,77 +168,66 @@ def __create_bgp_global(tgen, input_dict, router, build=False):
     True or False
     """
 
-    result = False
     logger.debug("Entering lib API: __create_bgp_global()")
-    try:
-
-        bgp_data = input_dict[router]["bgp"]
-        del_bgp_action = bgp_data.setdefault("delete", False)
-        if del_bgp_action:
-            config_data = ["no router bgp"]
-            result = create_common_configuration(tgen, router, config_data,
-                                                 "bgp", build=build)
-            return result
 
-        config_data = []
+    bgp_data = input_dict[router]["bgp"]
+    del_bgp_action = bgp_data.setdefault("delete", False)
+    if del_bgp_action:
+        config_data = ["no router bgp"]
 
-        if "local_as" not in bgp_data and build:
-            logger.error("Router %s: 'local_as' not present in input_dict"
-                         "for BGP", router)
-            return False
+        return config_data
 
-        local_as = bgp_data.setdefault("local_as", "")
-        cmd = "router bgp {}".format(local_as)
-        vrf_id = bgp_data.setdefault("vrf", None)
-        if vrf_id:
-            cmd = "{} vrf {}".format(cmd, vrf_id)
-
-        config_data.append(cmd)
+    config_data = []
 
-        router_id = bgp_data.setdefault("router_id", None)
-        del_router_id = bgp_data.setdefault("del_router_id", False)
-        if del_router_id:
-            config_data.append("no bgp router-id")
-        if router_id:
-            config_data.append("bgp router-id {}".format(
-                router_id))
+    if "local_as" not in bgp_data and build:
+        logger.error("Router %s: 'local_as' not present in input_dict"
+                     "for BGP", router)
+        return False
 
-        aggregate_address = bgp_data.setdefault("aggregate_address",
-                                                {})
-        if aggregate_address:
-            network = aggregate_address.setdefault("network", None)
-            if not network:
-                logger.error("Router %s: 'network' not present in "
-                             "input_dict for BGP", router)
-            else:
-                cmd = "aggregate-address {}".format(network)
+    local_as = bgp_data.setdefault("local_as", "")
+    cmd = "router bgp {}".format(local_as)
+    vrf_id = bgp_data.setdefault("vrf", None)
+    if vrf_id:
+        cmd = "{} vrf {}".format(cmd, vrf_id)
+
+    config_data.append(cmd)
+
+    router_id = bgp_data.setdefault("router_id", None)
+    del_router_id = bgp_data.setdefault("del_router_id", False)
+    if del_router_id:
+        config_data.append("no bgp router-id")
+    if router_id:
+        config_data.append("bgp router-id {}".format(
+            router_id))
+
+    aggregate_address = bgp_data.setdefault("aggregate_address",
+                                            {})
+    if aggregate_address:
+        network = aggregate_address.setdefault("network", None)
+        if not network:
+            logger.error("Router %s: 'network' not present in "
+                         "input_dict for BGP", router)
+        else:
+            cmd = "aggregate-address {}".format(network)
 
-                as_set = aggregate_address.setdefault("as_set", False)
-                summary = aggregate_address.setdefault("summary", False)
-                del_action = aggregate_address.setdefault("delete", False)
-                if as_set:
-                    cmd = "{} {}".format(cmd, "as-set")
-                if summary:
-                    cmd = "{} {}".format(cmd, "summary")
+            as_set = aggregate_address.setdefault("as_set", False)
+            summary = aggregate_address.setdefault("summary", False)
+            del_action = aggregate_address.setdefault("delete", False)
+            if as_set:
+                cmd = "{} {}".format(cmd, "as-set")
+            if summary:
+                cmd = "{} {}".format(cmd, "summary")
 
-                if del_action:
-                    cmd = "no {}".format(cmd)
+            if del_action:
+                cmd = "no {}".format(cmd)
 
-                config_data.append(cmd)
+            config_data.append(cmd)
 
-        result = create_common_configuration(tgen, router, config_data,
-                                             "bgp", build=build)
-    except InvalidCLIError:
-        # Traceback
-        errormsg = traceback.format_exc()
-        logger.error(errormsg)
-        return errormsg
-
-    logger.debug("Exiting lib API: create_bgp_global()")
-    return result
+    return config_data
 
 
-def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router, build=False):
+def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router,
+                                  config_data=None):
     """
     Helper API to create configuration for address-family unicast
 
@@ -240,124 +240,118 @@ def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router, build=False):
     * `build` : Only for initial setup phase this is set as True.
     """
 
-    result = False
     logger.debug("Entering lib API: __create_bgp_unicast_neighbor()")
-    try:
-        config_data = ["router bgp"]
-        bgp_data = input_dict[router]["bgp"]["address_family"]
 
-        for addr_type, addr_dict in bgp_data.iteritems():
-            if not addr_dict:
-                continue
+    add_neigh = True
+    if "router bgp "in config_data:
+        add_neigh = False
+    bgp_data = input_dict[router]["bgp"]["address_family"]
 
-            if not check_address_types(addr_type):
-                continue
+    for addr_type, addr_dict in bgp_data.iteritems():
+        if not addr_dict:
+            continue
 
+        if not check_address_types(addr_type):
+            continue
+
+        addr_data = addr_dict["unicast"]
+        if addr_data:
             config_data.append("address-family {} unicast".format(
                 addr_type
             ))
-            addr_data = addr_dict["unicast"]
-            advertise_network = addr_data.setdefault("advertise_networks",
-                                                     [])
-            for advertise_network_dict in advertise_network:
-                network = advertise_network_dict["network"]
-                if type(network) is not list:
-                    network = [network]
-
-                if "no_of_network" in advertise_network_dict:
-                    no_of_network = advertise_network_dict["no_of_network"]
-                else:
-                    no_of_network = 1
-
-                del_action = advertise_network_dict.setdefault("delete",
-                                                               False)
+        advertise_network = addr_data.setdefault("advertise_networks",
+                                                 [])
+        for advertise_network_dict in advertise_network:
+            network = advertise_network_dict["network"]
+            if type(network) is not list:
+                network = [network]
+
+            if "no_of_network" in advertise_network_dict:
+                no_of_network = advertise_network_dict["no_of_network"]
+            else:
+                no_of_network = 1
 
-                # Generating IPs for verification
-                prefix = str(
-                    ipaddr.IPNetwork(unicode(network[0])).prefixlen)
-                network_list = generate_ips(network, no_of_network)
-                for ip in network_list:
-                    ip = str(ipaddr.IPNetwork(unicode(ip)).network)
+            del_action = advertise_network_dict.setdefault("delete",
+                                                           False)
 
-                    cmd = "network {}/{}\n".format(ip, prefix)
-                    if del_action:
-                        cmd = "no {}".format(cmd)
+            # Generating IPs for verification
+            prefix = str(
+                ipaddr.IPNetwork(unicode(network[0])).prefixlen)
+            network_list = generate_ips(network, no_of_network)
+            for ip in network_list:
+                ip = str(ipaddr.IPNetwork(unicode(ip)).network)
 
-                    config_data.append(cmd)
+                cmd = "network {}/{}".format(ip, prefix)
+                if del_action:
+                    cmd = "no {}".format(cmd)
 
-            max_paths = addr_data.setdefault("maximum_paths", {})
-            if max_paths:
-                ibgp = max_paths.setdefault("ibgp", None)
-                ebgp = max_paths.setdefault("ebgp", None)
-                if ibgp:
-                    config_data.append("maximum-paths ibgp {}".format(
-                        ibgp
-                    ))
-                if ebgp:
-                    config_data.append("maximum-paths {}".format(
-                        ebgp
-                    ))
-
-            aggregate_address = addr_data.setdefault("aggregate_address",
-                                                     {})
-            if aggregate_address:
-                ip = aggregate_address("network", None)
-                attribute = aggregate_address("attribute", None)
-                if ip:
-                    cmd = "aggregate-address {}".format(ip)
-                    if attribute:
-                        cmd = "{} {}".format(cmd, attribute)
+                config_data.append(cmd)
 
-                    config_data.append(cmd)
+        max_paths = addr_data.setdefault("maximum_paths", {})
+        if max_paths:
+            ibgp = max_paths.setdefault("ibgp", None)
+            ebgp = max_paths.setdefault("ebgp", None)
+            if ibgp:
+                config_data.append("maximum-paths ibgp {}".format(
+                    ibgp
+                ))
+            if ebgp:
+                config_data.append("maximum-paths {}".format(
+                    ebgp
+                ))
+
+        aggregate_address = addr_data.setdefault("aggregate_address",
+                                                 {})
+        if aggregate_address:
+            ip = aggregate_address("network", None)
+            attribute = aggregate_address("attribute", None)
+            if ip:
+                cmd = "aggregate-address {}".format(ip)
+                if attribute:
+                    cmd = "{} {}".format(cmd, attribute)
 
-            redistribute_data = addr_data.setdefault("redistribute", {})
-            if redistribute_data:
-                for redistribute in redistribute_data:
-                    if "redist_type" not in redistribute:
-                        logger.error("Router %s: 'redist_type' not present in "
-                                     "input_dict", router)
-                    else:
-                        cmd = "redistribute {}".format(
-                            redistribute["redist_type"])
-                        redist_attr = redistribute.setdefault("attribute",
-                                                              None)
-                        if redist_attr:
-                            cmd = "{} {}".format(cmd, redist_attr)
-                        del_action = redistribute.setdefault("delete", False)
-                        if del_action:
-                            cmd = "no {}".format(cmd)
-                        config_data.append(cmd)
+                config_data.append(cmd)
 
-            if "neighbor" in addr_data:
-                neigh_data = __create_bgp_neighbor(topo, input_dict,
-                                                   router, addr_type)
-                config_data.extend(neigh_data)
+        redistribute_data = addr_data.setdefault("redistribute", {})
+        if redistribute_data:
+            for redistribute in redistribute_data:
+                if "redist_type" not in redistribute:
+                    logger.error("Router %s: 'redist_type' not present in "
+                                 "input_dict", router)
+                else:
+                    cmd = "redistribute {}".format(
+                        redistribute["redist_type"])
+                    redist_attr = redistribute.setdefault("attribute",
+                                                          None)
+                    if redist_attr:
+                        cmd = "{} {}".format(cmd, redist_attr)
+                    del_action = redistribute.setdefault("delete", False)
+                    if del_action:
+                        cmd = "no {}".format(cmd)
+                    config_data.append(cmd)
 
-        for addr_type, addr_dict in bgp_data.iteritems():
-            if not addr_dict or not check_address_types(addr_type):
-                continue
+        if "neighbor" in addr_data:
+            neigh_data = __create_bgp_neighbor(topo, input_dict,
+                                               router, addr_type, add_neigh)
+            config_data.extend(neigh_data)
 
-            addr_data = addr_dict["unicast"]
-            if "neighbor" in addr_data:
-                neigh_addr_data = __create_bgp_unicast_address_family(
-                    topo, input_dict, router, addr_type)
+    for addr_type, addr_dict in bgp_data.iteritems():
+        if not addr_dict or not check_address_types(addr_type):
+            continue
 
-                config_data.extend(neigh_addr_data)
+        addr_data = addr_dict["unicast"]
+        if "neighbor" in addr_data:
+            neigh_addr_data = __create_bgp_unicast_address_family(
+                topo, input_dict, router, addr_type, add_neigh)
 
-        result = create_common_configuration(tgen, router, config_data,
-                                             None, build=build)
+            config_data.extend(neigh_addr_data)
 
-    except InvalidCLIError:
-        # Traceback
-        errormsg = traceback.format_exc()
-        logger.error(errormsg)
-        return errormsg
 
     logger.debug("Exiting lib API: __create_bgp_unicast_neighbor()")
-    return result
+    return config_data
 
 
-def __create_bgp_neighbor(topo, input_dict, router, addr_type):
+def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
     """
     Helper API to create neighbor specific configuration
 
@@ -391,7 +385,8 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type):
 
             neigh_cxt = "neighbor {}".format(ip_addr)
 
-            config_data.append("{} remote-as {}".format(neigh_cxt, remote_as))
+            if add_neigh:
+                config_data.append("{} remote-as {}".format(neigh_cxt, remote_as))
             if addr_type == "ipv6":
                 config_data.append("address-family ipv6 unicast")
                 config_data.append("{} activate".format(neigh_cxt))
@@ -429,7 +424,8 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type):
     return config_data
 
 
-def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type):
+def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type,
+                                        add_neigh=True):
     """
     API prints bgp global config to bgp_json file.
 
@@ -531,6 +527,7 @@ def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type):
 #############################################
 # Verification APIs
 #############################################
+@retry(attempts=3, wait=2, return_is_str=True)
 def verify_router_id(tgen, topo, input_dict):
     """
     Running command "show ip bgp json" for DUT and reading router-id
@@ -565,7 +562,7 @@ def verify_router_id(tgen, topo, input_dict):
     errormsg(str) or True
     """
 
-    logger.info("Entering lib API: verify_router_id()")
+    logger.debug("Entering lib API: verify_router_id()")
     for router in input_dict.keys():
         if router not in tgen.routers():
             continue
@@ -576,9 +573,9 @@ def verify_router_id(tgen, topo, input_dict):
             "del_router_id", False)
 
         logger.info("Checking router %s router-id", router)
-        show_bgp_json = rnode.vtysh_cmd("show ip bgp json",
+        show_bgp_json = run_frr_cmd(rnode, "show bgp summary json",
                                         isjson=True)
-        router_id_out = show_bgp_json["routerId"]
+        router_id_out = show_bgp_json["ipv4Unicast"]["routerId"]
         router_id_out = ipaddr.IPv4Address(unicode(router_id_out))
 
         # Once router-id is deleted, highest interface ip should become
@@ -598,100 +595,84 @@ def verify_router_id(tgen, topo, input_dict):
                                                  router_id_out)
             return errormsg
 
-    logger.info("Exiting lib API: verify_router_id()")
+    logger.debug("Exiting lib API: verify_router_id()")
     return True
 
 
+@retry(attempts=20, wait=2, return_is_str=True)
 def verify_bgp_convergence(tgen, topo):
     """
     API will verify if BGP is converged with in the given time frame.
     Running "show bgp summary json" command and verify bgp neighbor
     state is established,
-
     Parameters
     ----------
     * `tgen`: topogen object
     * `topo`: input json file data
     * `addr_type`: ip_type, ipv4/ipv6
-
     Usage
     -----
     # To veriry is BGP is converged for all the routers used in
     topology
     results = verify_bgp_convergence(tgen, topo, "ipv4")
-
     Returns
     -------
     errormsg(str) or True
     """
 
-    logger.info("Entering lib API: verify_bgp_confergence()")
+    logger.debug("Entering lib API: verify_bgp_convergence()")
     for router, rnode in tgen.routers().iteritems():
-        logger.info("Verifying BGP Convergence on router %s:", router)
-
-        for retry in range(1, 11):
-            show_bgp_json = rnode.vtysh_cmd("show bgp summary json",
-                                            isjson=True)
-            # Verifying output dictionary show_bgp_json is empty or not
-            if not bool(show_bgp_json):
-                errormsg = "BGP is not running"
-                return errormsg
+        logger.info("Verifying BGP Convergence on router %s", router)
+        show_bgp_json = run_frr_cmd(rnode, "show bgp summary json",
+                                    isjson=True)
+        # Verifying output dictionary show_bgp_json is empty or not
+        if not bool(show_bgp_json):
+            errormsg = "BGP is not running"
+            return errormsg
 
-            # To find neighbor ip type
+        # To find neighbor ip type
+        bgp_addr_type = topo["routers"][router]["bgp"]["address_family"]
+        for addr_type in bgp_addr_type.keys():
+            if not check_address_types(addr_type):
+                continue
             total_peer = 0
 
-            bgp_addr_type = topo["routers"][router]["bgp"]["address_family"]
-            for addr_type in bgp_addr_type.keys():
-                if not check_address_types(addr_type):
-                    continue
-
-                bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
-
-                for bgp_neighbor in bgp_neighbors:
-                    total_peer += len(bgp_neighbors[bgp_neighbor]["dest_link"])
-
-            for addr_type in bgp_addr_type.keys():
-                bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
-
-                no_of_peer = 0
-                for bgp_neighbor, peer_data in bgp_neighbors.iteritems():
-                    for dest_link in peer_data["dest_link"].keys():
-                        data = topo["routers"][bgp_neighbor]["links"]
-                        if dest_link in data:
-                            neighbor_ip = \
-                                data[dest_link][addr_type].split("/")[0]
-                            if addr_type == "ipv4":
-                                ipv4_data = show_bgp_json["ipv4Unicast"][
-                                    "peers"]
-                                nh_state = ipv4_data[neighbor_ip]["state"]
-                            else:
-                                ipv6_data = show_bgp_json["ipv6Unicast"][
-                                    "peers"]
-                                nh_state = ipv6_data[neighbor_ip]["state"]
-
-                            if nh_state == "Established":
-                                no_of_peer += 1
-            if no_of_peer == total_peer:
-                logger.info("BGP is Converged for router %s", router)
-                break
-            else:
-                logger.warning("BGP is not yet Converged for router %s",
-                               router)
-                sleeptime = 2 * retry
-                if sleeptime <= BGP_CONVERGENCE_TIMEOUT:
-                    # Waiting for BGP to converge
-                    logger.info("Waiting for %s sec for BGP to converge on"
-                                " router %s...", sleeptime, router)
-                    sleep(sleeptime)
-                else:
-                    show_bgp_summary = rnode.vtysh_cmd("show bgp summary")
-                    errormsg = "TIMEOUT!! BGP is not converged in {} " \
-                               "seconds  for router {} \n {}".format(
-                                   BGP_CONVERGENCE_TIMEOUT, router,
-                                   show_bgp_summary)
-                    return errormsg
+            bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+
+            for bgp_neighbor in bgp_neighbors:
+                total_peer += len(bgp_neighbors[bgp_neighbor]["dest_link"])
+
+        for addr_type in bgp_addr_type.keys():
+            if not check_address_types(addr_type):
+                continue
+            bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+
+            no_of_peer = 0
+            for bgp_neighbor, peer_data in bgp_neighbors.iteritems():
+                for dest_link in peer_data["dest_link"].keys():
+                    data = topo["routers"][bgp_neighbor]["links"]
+                    if dest_link in data:
+                        neighbor_ip = \
+                            data[dest_link][addr_type].split("/")[0]
+                        if addr_type == "ipv4":
+                            ipv4_data = show_bgp_json["ipv4Unicast"][
+                                "peers"]
+                            nh_state = ipv4_data[neighbor_ip]["state"]
+                        else:
+                            ipv6_data = show_bgp_json["ipv6Unicast"][
+                                "peers"]
+                            nh_state = ipv6_data[neighbor_ip]["state"]
+
+                        if nh_state == "Established":
+                            no_of_peer += 1
+        if no_of_peer == total_peer:
+            logger.info("BGP is Converged for router %s", router)
+        else:
+            errormsg = "BGP is not converged for router {}".format(
+                router)
+            return errormsg
 
-    logger.info("Exiting API: verify_bgp_confergence()")
+    logger.debug("Exiting API: verify_bgp_convergence()")
     return True
 
 
@@ -723,7 +704,7 @@ def modify_as_number(tgen, topo, input_dict):
     errormsg(str) or True
     """
 
-    logger.info("Entering lib API: modify_as_number()")
+    logger.debug("Entering lib API: modify_as_number()")
     try:
 
         new_topo = deepcopy(topo["routers"])
@@ -757,11 +738,12 @@ def modify_as_number(tgen, topo, input_dict):
         logger.error(errormsg)
         return errormsg
 
-    logger.info("Exiting lib API: modify_as_number()")
+    logger.debug("Exiting lib API: modify_as_number()")
 
     return True
 
 
+@retry(attempts=3, wait=2, return_is_str=True)
 def verify_as_numbers(tgen, topo, input_dict):
     """
     This API is to verify AS numbers for given DUT by running
@@ -791,7 +773,7 @@ def verify_as_numbers(tgen, topo, input_dict):
     errormsg(str) or True
     """
 
-    logger.info("Entering lib API: verify_as_numbers()")
+    logger.debug("Entering lib API: verify_as_numbers()")
     for router in input_dict.keys():
         if router not in tgen.routers():
             continue
@@ -800,7 +782,7 @@ def verify_as_numbers(tgen, topo, input_dict):
 
         logger.info("Verifying AS numbers for  dut %s:", router)
 
-        show_ip_bgp_neighbor_json = rnode.vtysh_cmd(
+        show_ip_bgp_neighbor_json = run_frr_cmd(rnode,
             "show ip bgp neighbor json", isjson=True)
         local_as = input_dict[router]["bgp"]["local_as"]
         bgp_addr_type = topo["routers"][router]["bgp"]["address_family"]
@@ -846,7 +828,7 @@ def verify_as_numbers(tgen, topo, input_dict):
                                     "neighbor %s, found expected: %s",
                                     router, bgp_neighbor, remote_as)
 
-    logger.info("Exiting lib API: verify_AS_numbers()")
+    logger.debug("Exiting lib API: verify_AS_numbers()")
     return True
 
 
@@ -873,7 +855,7 @@ def clear_bgp_and_verify(tgen, topo, router):
     errormsg(str) or True
     """
 
-    logger.info("Entering lib API: clear_bgp_and_verify()")
+    logger.debug("Entering lib API: clear_bgp_and_verify()")
 
     if router not in tgen.routers():
         return False
@@ -883,20 +865,14 @@ def clear_bgp_and_verify(tgen, topo, router):
     peer_uptime_before_clear_bgp = {}
     # Verifying BGP convergence before bgp clear command
     for retry in range(1, 11):
-        sleeptime = 2 * retry
-        if sleeptime <= BGP_CONVERGENCE_TIMEOUT:
-            # Waiting for BGP to converge
-            logger.info("Waiting for %s sec for BGP to converge on router"
-                        " %s...", sleeptime, router)
-            sleep(sleeptime)
-        else:
-            errormsg = "TIMEOUT!! BGP is not converged in {} seconds for" \
-                       " router {}".format(BGP_CONVERGENCE_TIMEOUT, router)
-            return errormsg
+        sleeptime = 3
+        # Waiting for BGP to converge
+        logger.info("Waiting for %s sec for BGP to converge on router"
+                    " %s...", sleeptime, router)
+        sleep(sleeptime)
 
-        show_bgp_json = rnode.vtysh_cmd("show bgp summary json",
+        show_bgp_json = run_frr_cmd(rnode, "show bgp summary json",
                                         isjson=True)
-        logger.info(show_bgp_json)
         # Verifying output dictionary show_bgp_json is empty or not
         if not bool(show_bgp_json):
             errormsg = "BGP is not running"
@@ -950,33 +926,33 @@ def clear_bgp_and_verify(tgen, topo, router):
                         " clear", router)
             break
         else:
-            logger.warning("BGP is not yet Converged for router %s "
-                           "before bgp clear", router)
+            logger.info("BGP is not yet Converged for router %s "
+                        "before bgp clear", router)
+    else:
+        errormsg = "TIMEOUT!! BGP is not converged in 30 seconds for" \
+                   " router {}".format(router)
+        return errormsg
 
     logger.info(peer_uptime_before_clear_bgp)
     # Clearing BGP
     logger.info("Clearing BGP neighborship for router %s..", router)
     for addr_type in bgp_addr_type.keys():
         if addr_type == "ipv4":
-            rnode.vtysh_cmd("clear ip bgp *")
+            run_frr_cmd(rnode, "clear ip bgp *")
         elif addr_type == "ipv6":
-            rnode.vtysh_cmd("clear bgp ipv6 *")
+            run_frr_cmd(rnode, "clear bgp ipv6 *")
 
     peer_uptime_after_clear_bgp = {}
     # Verifying BGP convergence after bgp clear command
-    for retry in range(1, 11):
-        sleeptime = 2 * retry
-        if sleeptime <= BGP_CONVERGENCE_TIMEOUT:
-            # Waiting for BGP to converge
-            logger.info("Waiting for %s sec for BGP to converge on router"
-                        " %s...", sleeptime, router)
-            sleep(sleeptime)
-        else:
-            errormsg = "TIMEOUT!! BGP is not converged in {} seconds for" \
-                       " router {}".format(BGP_CONVERGENCE_TIMEOUT, router)
-            return errormsg
+    for retry in range(11):
+        sleeptime = 3
+        # Waiting for BGP to converge
+        logger.info("Waiting for %s sec for BGP to converge on router"
+                    " %s...", sleeptime, router)
+        sleep(sleeptime)
+
 
-        show_bgp_json = rnode.vtysh_cmd("show bgp summary json",
+        show_bgp_json = run_frr_cmd(rnode, "show bgp summary json",
                                         isjson=True)
         # Verifying output dictionary show_bgp_json is empty or not
         if not bool(show_bgp_json):
@@ -1028,9 +1004,12 @@ def clear_bgp_and_verify(tgen, topo, router):
                         router)
             break
         else:
-            logger.warning("BGP is not yet Converged for router %s after"
-                           " bgp clear", router)
-
+            logger.info("BGP is not yet Converged for router %s after"
+                        " bgp clear", router)
+    else:
+        errormsg = "TIMEOUT!! BGP is not converged in 30 seconds for" \
+                   " router {}".format(router)
+        return errormsg
     logger.info(peer_uptime_after_clear_bgp)
     # Comparing peerUptimeEstablishedEpoch dictionaries
     if peer_uptime_before_clear_bgp != peer_uptime_after_clear_bgp:
@@ -1041,7 +1020,7 @@ def clear_bgp_and_verify(tgen, topo, router):
                    " {}".format(router)
         return errormsg
 
-    logger.info("Exiting lib API: clear_bgp_and_verify()")
+    logger.debug("Exiting lib API: clear_bgp_and_verify()")
     return True
 
 
@@ -1077,7 +1056,7 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict):
     errormsg(str) or True
     """
 
-    logger.info("Entering lib API: verify_bgp_timers_and_functionality()")
+    logger.debug("Entering lib API: verify_bgp_timers_and_functionality()")
     sleep(5)
     router_list = tgen.routers()
     for router in input_dict.keys():
@@ -1090,7 +1069,7 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict):
                     router)
 
         show_ip_bgp_neighbor_json = \
-            rnode.vtysh_cmd("show ip bgp neighbor json", isjson=True)
+            run_frr_cmd(rnode, "show ip bgp neighbor json", isjson=True)
 
         bgp_addr_type = input_dict[router]["bgp"]["address_family"]
 
@@ -1178,7 +1157,7 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict):
                     sleep(keepalivetimer)
                     sleep(2)
                     show_bgp_json = \
-                        rnode.vtysh_cmd("show bgp summary json",
+                        run_frr_cmd(rnode, "show bgp summary json",
                                         isjson=True)
 
                     if addr_type == "ipv4":
@@ -1192,17 +1171,13 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict):
                             (holddowntimer - keepalivetimer):
                         if nh_state != "Established":
                             errormsg = "BGP neighborship has not  gone " \
-                                       "down in {} sec for neighbor {}\n" \
-                                       "show_bgp_json: \n {} ".format(
-                                timer, bgp_neighbor,
-                                show_bgp_json)
+                                       "down in {} sec for neighbor {}" \
+                                .format(timer, bgp_neighbor)
                             return errormsg
                         else:
                             logger.info("BGP neighborship is intact in %s"
-                                        " sec for neighbor %s \n "
-                                        "show_bgp_json : \n %s",
-                                        timer, bgp_neighbor,
-                                        show_bgp_json)
+                                        " sec for neighbor %s",
+                                        timer, bgp_neighbor)
 
                 ####################
                 # Shutting down peer interface and verifying that BGP
@@ -1229,7 +1204,7 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict):
                     sleep(keepalivetimer)
                     sleep(2)
                     show_bgp_json = \
-                        rnode.vtysh_cmd("show bgp summary json",
+                        run_frr_cmd(rnode, "show bgp summary json",
                                         isjson=True)
 
                     if addr_type == "ipv4":
@@ -1242,22 +1217,19 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict):
                     if timer == holddowntimer:
                         if nh_state == "Established":
                             errormsg = "BGP neighborship has not gone " \
-                                       "down in {} sec for neighbor {}\n" \
-                                       "show_bgp_json: \n {} ".format(
-                                timer, bgp_neighbor,
-                                show_bgp_json)
+                                       "down in {} sec for neighbor {}" \
+                                .format(timer, bgp_neighbor)
                             return errormsg
                         else:
                             logger.info("BGP neighborship has gone down in"
-                                        " %s sec for neighbor %s \n"
-                                        "show_bgp_json : \n %s",
-                                        timer, bgp_neighbor,
-                                        show_bgp_json)
+                                        " %s sec for neighbor %s",
+                                        timer, bgp_neighbor)
 
-    logger.info("Exiting lib API: verify_bgp_timers_and_functionality()")
+    logger.debug("Exiting lib API: verify_bgp_timers_and_functionality()")
     return True
 
 
+@retry(attempts=3, wait=2, return_is_str=True)
 def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict,
                                           attribute):
     """
@@ -1319,7 +1291,7 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict,
 
     sleep(2)
     logger.info("Verifying router %s RIB for best path:", router)
-    sh_ip_bgp_json = rnode.vtysh_cmd(command, isjson=True)
+    sh_ip_bgp_json = run_frr_cmd(rnode, command, isjson=True)
 
     for route_val in input_dict.values():
         net_data = route_val["bgp"]["address_family"]["ipv4"]["unicast"]
@@ -1380,7 +1352,7 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict,
             else:
                 command = "show ipv6 route json"
 
-            rib_routes_json = rnode.vtysh_cmd(command, isjson=True)
+            rib_routes_json = run_frr_cmd(rnode, command, isjson=True)
 
             # Verifying output dictionary rib_routes_json is not empty
             if not bool(rib_routes_json):
@@ -1417,6 +1389,7 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict,
     return True
 
 
+@retry(attempts=3, wait=2, return_is_str=True)
 def verify_best_path_as_per_admin_distance(tgen, addr_type, router, input_dict,
                                            attribute):
     """
@@ -1451,7 +1424,7 @@ def verify_best_path_as_per_admin_distance(tgen, addr_type, router, input_dict,
     errormsg(str) or True
     """
 
-    logger.info("Entering lib API: verify_best_path_as_per_admin_distance()")
+    logger.debug("Entering lib API: verify_best_path_as_per_admin_distance()")
     router_list = tgen.routers()
     if router not in router_list:
         return False
@@ -1490,7 +1463,7 @@ def verify_best_path_as_per_admin_distance(tgen, addr_type, router, input_dict,
             compare = "LOWEST"
 
         # Show ip route
-        rib_routes_json = rnode.vtysh_cmd(command, isjson=True)
+        rib_routes_json = run_frr_cmd(rnode, command, isjson=True)
 
         # Verifying output dictionary rib_routes_json is not empty
         if not bool(rib_routes_json):
index 75880cfd285171191593036d06879fb7e5033ce5..f2d33f94ae574b25923540acbb6cd5bb62be82e2 100644 (file)
@@ -23,24 +23,32 @@ from datetime import datetime
 from time import sleep
 from subprocess import call
 from subprocess import STDOUT as SUB_STDOUT
+from subprocess import PIPE as SUB_PIPE
+from subprocess import Popen
+from functools import wraps
+from re import search as re_search
+
 import StringIO
 import os
 import ConfigParser
 import traceback
 import socket
 import ipaddr
+import re
 
 from lib import topotest
 
 from functools import partial
 from lib.topolog import logger, logger_config
 from lib.topogen import TopoRouter
+from lib.topotest import interface_set_status
 
 
 FRRCFG_FILE = "frr_json.conf"
 FRRCFG_BKUP_FILE = "frr_json_initial.conf"
 
 ERROR_LIST = ["Malformed", "Failure", "Unknown"]
+ROUTER_LIST = []
 
 ####
 CD = os.path.dirname(os.path.realpath(__file__))
@@ -142,6 +150,35 @@ class InvalidCLIError(Exception):
     pass
 
 
+def run_frr_cmd(rnode, cmd, isjson=False):
+    """
+    Execute frr show commands in priviledged mode
+
+    * `rnode`: router node on which commands needs to executed
+    * `cmd`: Command to be executed on frr
+    * `isjson`: If command is to get json data or not
+
+    :return str:
+    """
+
+    if cmd:
+        ret_data = rnode.vtysh_cmd(cmd, isjson=isjson)
+
+        if True:
+            if isjson:
+                logger.debug(ret_data)
+                print_data = rnode.vtysh_cmd(cmd.rstrip("json"), isjson=False)
+            else:
+                print_data = ret_data
+
+            logger.info('Output for command [ %s] on router %s:\n%s',
+                        cmd.rstrip("json"), rnode.name, print_data)
+        return ret_data
+
+    else:
+        raise InvalidCLIError('No actual cmd passed')
+
+
 def create_common_configuration(tgen, router, data, config_type=None,
                                 build=False):
     """
@@ -186,6 +223,7 @@ def create_common_configuration(tgen, router, data, config_type=None,
             frr_cfg_fd.write(config_map[config_type])
         for line in data:
             frr_cfg_fd.write("{} \n".format(str(line)))
+        frr_cfg_fd.write("\n")
 
     except IOError as err:
         logger.error("Unable to open FRR Config File. error(%s): %s" %
@@ -215,10 +253,13 @@ def reset_config_on_routers(tgen, routerName=None):
     logger.debug("Entering API: reset_config_on_routers")
 
     router_list = tgen.routers()
-    for rname, router in router_list.iteritems():
+    for rname in ROUTER_LIST:
         if routerName and routerName != rname:
             continue
 
+        router = router_list[rname]
+        logger.info("Configuring router %s to initial test configuration",
+                    rname)
         cfg = router.run("vtysh -c 'show running'")
         fname = "{}/{}/frr.sav".format(TMPDIR, rname)
         dname = "{}/{}/delta.conf".format(TMPDIR, rname)
@@ -235,16 +276,35 @@ def reset_config_on_routers(tgen, routerName=None):
 
         f.close()
 
-        command = "/usr/lib/frr/frr-reload.py  --input {}/{}/frr.sav" \
-                  " --test {}/{}/frr_json_initial.conf > {}". \
-            format(TMPDIR, rname, TMPDIR, rname, dname)
-        result = call(command, shell=True, stderr=SUB_STDOUT)
+        run_cfg_file = "{}/{}/frr.sav".format(TMPDIR, rname)
+        init_cfg_file = "{}/{}/frr_json_initial.conf".format(TMPDIR, rname)
+        command = "/usr/lib/frr/frr-reload.py  --input {} --test {} > {}". \
+            format(run_cfg_file, init_cfg_file, dname)
+        result = call(command, shell=True, stderr=SUB_STDOUT,
+                      stdout=SUB_PIPE)
 
         # Assert if command fail
         if result > 0:
-            errormsg = ("Command:{} is failed due to non-zero exit"
-                        " code".format(command))
-            return errormsg
+            logger.error("Delta file creation failed. Command executed %s",
+                         command)
+            with open(run_cfg_file, 'r') as fd:
+                logger.info('Running configuration saved in %s is:\n%s',
+                             run_cfg_file, fd.read())
+            with open(init_cfg_file, 'r') as fd:
+                logger.info('Test configuration saved in %s is:\n%s',
+                             init_cfg_file, fd.read())
+
+            err_cmd = ['/usr/bin/vtysh', '-m', '-f', run_cfg_file]
+            result = Popen(err_cmd, stdout=SUB_PIPE, stderr=SUB_PIPE)
+            output = result.communicate()
+            for out_data in output:
+                temp_data = out_data.decode('utf-8').lower()
+                for out_err in ERROR_LIST:
+                    if out_err.lower() in temp_data:
+                        logger.error("Found errors while validating data in"
+                                     " %s", run_cfg_file)
+                        raise InvalidCLIError(out_data)
+            raise InvalidCLIError("Unknown error in %s", output)
 
         f = open(dname, "r")
         delta = StringIO.StringIO()
@@ -264,7 +324,7 @@ def reset_config_on_routers(tgen, routerName=None):
         delta.write("end\n")
         output = router.vtysh_multicmd(delta.getvalue(),
                                        pretty_output=False)
-        logger.info("New configuration for router {}:".format(rname))
+
         delta.close()
         delta = StringIO.StringIO()
         cfg = router.run("vtysh -c 'show running'")
@@ -276,6 +336,8 @@ def reset_config_on_routers(tgen, routerName=None):
         # Router current configuration to log file or console if
         # "show_router_config" is defined in "pytest.ini"
         if show_router_config:
+            logger.info("Configuration on router {} after config reset:".
+                        format(rname))
             logger.info(delta.getvalue())
         delta.close()
 
@@ -297,34 +359,39 @@ def load_config_to_router(tgen, routerName, save_bkup=False):
     logger.debug("Entering API: load_config_to_router")
 
     router_list = tgen.routers()
-    for rname, router in router_list.iteritems():
-        if rname == routerName:
-            try:
-                frr_cfg_file = "{}/{}/{}".format(TMPDIR, rname, FRRCFG_FILE)
-                frr_cfg_bkup = "{}/{}/{}".format(TMPDIR, rname,
-                                                 FRRCFG_BKUP_FILE)
-                with open(frr_cfg_file, "r") as cfg:
-                    data = cfg.read()
-                    if save_bkup:
-                        with open(frr_cfg_bkup, "w") as bkup:
-                            bkup.write(data)
-
-                    output = router.vtysh_multicmd(data, pretty_output=False)
-                    for out_err in ERROR_LIST:
-                        if out_err.lower() in output.lower():
-                            raise InvalidCLIError("%s" % output)
-            except IOError as err:
-                errormsg = ("Unable to open config File. error(%s):"
-                            "  %s", (err.errno, err.strerror))
-                return errormsg
+    for rname in ROUTER_LIST:
+        if routerName and routerName != rname:
+            continue
 
-            logger.info("New configuration for router {}:".format(rname))
-            new_config = router.run("vtysh -c 'show running'")
+        router = router_list[rname]
+        try:
+            frr_cfg_file = "{}/{}/{}".format(TMPDIR, rname, FRRCFG_FILE)
+            frr_cfg_bkup = "{}/{}/{}".format(TMPDIR, rname,
+                                             FRRCFG_BKUP_FILE)
+            with open(frr_cfg_file, "r+") as cfg:
+                data = cfg.read()
+                logger.info("Applying following configuration on router"
+                            " {}:\n{}".format(rname, data))
+                if save_bkup:
+                    with open(frr_cfg_bkup, "w") as bkup:
+                        bkup.write(data)
+
+                output = router.vtysh_multicmd(data, pretty_output=False)
+                for out_err in ERROR_LIST:
+                    if out_err.lower() in output.lower():
+                        raise InvalidCLIError("%s" % output)
+
+                cfg.truncate(0)
+        except IOError as err:
+            errormsg = ("Unable to open config File. error(%s):"
+                        "  %s", (err.errno, err.strerror))
+            return errormsg
 
-            # Router current configuration to log file or console if
-            # "show_router_config" is defined in "pytest.ini"
-            if show_router_config:
-                logger.info(new_config)
+        # Router current configuration to log file or console if
+        # "show_router_config" is defined in "pytest.ini"
+        if show_router_config:
+            new_config = router.run("vtysh -c 'show running'")
+            logger.info(new_config)
 
     logger.debug("Exting API: load_config_to_router")
     return True
@@ -337,21 +404,25 @@ def start_topology(tgen):
     * `tgen`  : topogen object
     """
 
-    global TMPDIR
+    global TMPDIR, ROUTER_LIST
     # Starting topology
     tgen.start_topology()
 
     # Starting deamons
+
     router_list = tgen.routers()
+    ROUTER_LIST = sorted(router_list.keys(),
+                         key=lambda x: int(re_search('\d+', x).group(0)))
     TMPDIR = os.path.join(LOGDIR, tgen.modname)
 
-    for rname, router in router_list.iteritems():
+    router_list = tgen.routers()
+    for rname in ROUTER_LIST:
+        router = router_list[rname]
         try:
             os.chdir(TMPDIR)
 
-            # Creating rouer named dir and empty zebra.conf bgpd.conf files
+            # Creating router named dir and empty zebra.conf bgpd.conf files
             # inside the current directory
-
             if os.path.isdir('{}'.format(rname)):
                 os.system("rm -rf {}".format(rname))
                 os.mkdir('{}'.format(rname))
@@ -371,13 +442,11 @@ def start_topology(tgen):
         router.load_config(
             TopoRouter.RD_ZEBRA,
             '{}/{}/zebra.conf'.format(TMPDIR, rname)
-            # os.path.join(tmpdir, '{}/zebra.conf'.format(rname))
         )
         # Loading empty bgpd.conf file to router, to start the bgp deamon
         router.load_config(
             TopoRouter.RD_BGP,
             '{}/{}/bgpd.conf'.format(TMPDIR, rname)
-            # os.path.join(tmpdir, '{}/bgpd.conf'.format(rname))
         )
 
         # Starting routers
@@ -446,27 +515,31 @@ def validate_ip_address(ip_address):
                                          " address" % ip_address)
 
 
-def check_address_types(addr_type):
+def check_address_types(addr_type=None):
     """
     Checks environment variable set and compares with the current address type
     """
-    global ADDRESS_TYPES
-    if ADDRESS_TYPES is None:
-        ADDRESS_TYPES = "dual"
-
-    if ADDRESS_TYPES == "dual":
-        ADDRESS_TYPES = ["ipv4", "ipv6"]
-    elif ADDRESS_TYPES == "ipv4":
-        ADDRESS_TYPES = ["ipv4"]
-    elif ADDRESS_TYPES == "ipv6":
-        ADDRESS_TYPES = ["ipv6"]
-
-    if addr_type not in ADDRESS_TYPES:
+
+    addr_types_env = os.environ.get("ADDRESS_TYPES")
+    if not addr_types_env:
+        addr_types_env = "dual"
+
+    if addr_types_env == "dual":
+        addr_types = ["ipv4", "ipv6"]
+    elif addr_types_env == "ipv4":
+        addr_types = ["ipv4"]
+    elif addr_types_env == "ipv6":
+        addr_types = ["ipv6"]
+
+    if addr_type is None:
+        return addr_types
+
+    if addr_type not in addr_types:
         logger.error("{} not in supported/configured address types {}".
-                     format(addr_type, ADDRESS_TYPES))
+                     format(addr_type, addr_types))
         return False
 
-    return ADDRESS_TYPES
+    return True
 
 
 def generate_ips(network, no_of_ips):
@@ -548,7 +621,7 @@ def write_test_header(tc_name):
     """ Display message at beginning of test case"""
     count = 20
     logger.info("*"*(len(tc_name)+count))
-    logger.info("START -> Testcase : %s", tc_name)
+    logger.info("START -> Testcase : %s" % tc_name)
     logger.info("*"*(len(tc_name)+count))
 
 
@@ -556,10 +629,169 @@ def write_test_footer(tc_name):
     """ Display message at end of test case"""
     count = 21
     logger.info("="*(len(tc_name)+count))
-    logger.info("PASSED -> Testcase : %s", tc_name)
+    logger.info("Testcase : %s -> PASSED", tc_name)
     logger.info("="*(len(tc_name)+count))
 
 
+def interface_status(tgen, topo, input_dict):
+    """
+    Delete ip route maps from device
+
+    * `tgen`  : Topogen object
+    * `topo`  : json file data
+    * `input_dict` :  for which router, route map has to be deleted
+
+    Usage
+    -----
+    input_dict = {
+        "r3": {
+            "interface_list": ['eth1-r1-r2', 'eth2-r1-r3'],
+            "status": "down"
+        }
+    }
+    Returns
+    -------
+    errormsg(str) or True
+    """
+    logger.debug("Entering lib API: interface_status()")
+
+    try:
+        global frr_cfg
+        for router in input_dict.keys():
+
+            interface_list = input_dict[router]['interface_list']
+            status = input_dict[router].setdefault('status', 'up')
+            for intf in interface_list:
+                rnode = tgen.routers()[router]
+                interface_set_status(rnode, intf, status)
+
+            # Load config to router
+            load_config_to_router(tgen, router)
+
+    except Exception as e:
+        # handle any exception
+        logger.error("Error %s occured. Arguments %s.", e.message, e.args)
+
+        # Traceback
+        errormsg = traceback.format_exc()
+        logger.error(errormsg)
+        return errormsg
+
+    logger.debug("Exiting lib API: interface_status()")
+    return True
+
+
+def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0):
+    """
+    Retries function execution, if return is an errormsg or exception
+
+    * `attempts`: Number of attempts to make
+    * `wait`: Number of seconds to wait between each attempt
+    * `return_is_str`: Return val is an errormsg in case of failure
+    * `initial_wait`: Sleeps for this much seconds before executing function
+
+    """
+
+    def _retry(func):
+
+        @wraps(func)
+        def func_retry(*args, **kwargs):
+            _wait = kwargs.pop('wait', wait)
+            _attempts = kwargs.pop('attempts', attempts)
+            _attempts = int(_attempts)
+            if _attempts < 0:
+                raise ValueError("attempts must be 0 or greater")
+
+            if initial_wait > 0:
+                logger.info("Waiting for [%s]s as initial delay", initial_wait)
+                sleep(initial_wait)
+
+            _return_is_str = kwargs.pop('return_is_str', return_is_str)
+            for i in range(1, _attempts + 1):
+                try:
+                    _expected = kwargs.setdefault('expected', True)
+                    kwargs.pop('expected')
+                    ret = func(*args, **kwargs)
+                    logger.debug("Function returned %s" % ret)
+                    if return_is_str and isinstance(ret, bool):
+                        return ret
+                    elif return_is_str and _expected is False:
+                        return ret
+
+                    if _attempts == i:
+                        return ret
+                except Exception as err:
+                    if _attempts == i:
+                        logger.info("Max number of attempts (%r) reached",
+                                    _attempts)
+                        raise
+                    else:
+                        logger.info("Function returned %s", err)
+                if i < _attempts:
+                    logger.info("Retry [#%r] after sleeping for %ss"
+                                % (i, _wait))
+                    sleep(_wait)
+        func_retry._original = func
+        return func_retry
+    return _retry
+
+
+def disable_v6_link_local(tgen, router, intf_name=None):
+    """
+    Disables ipv6 link local addresses for a particular interface or
+    all interfaces
+
+    * `tgen`: tgen onject
+    * `router` : router for which hightest interface should be
+                 calculated
+    * `intf_name` : Interface name for which v6 link local needs to
+                    be disabled
+    """
+
+    router_list = tgen.routers()
+    for rname, rnode in router_list.iteritems():
+        if rname != router:
+            continue
+
+        linklocal = []
+
+        ifaces = router_list[router].run('ip -6 address')
+
+        # Fix newlines (make them all the same)
+        ifaces = ('\n'.join(ifaces.splitlines()) + '\n').splitlines()
+
+        interface = None
+        ll_per_if_count = 0
+        for line in ifaces:
+            # Interface name
+            m = re.search('[0-9]+: ([^:]+)[@if0-9:]+ <', line)
+            if m:
+                interface = m.group(1).split("@")[0]
+                ll_per_if_count = 0
+
+            # Interface ip
+            m = re.search('inet6 (fe80::[0-9a-f]+:[0-9a-f]+:[0-9a-f]+'
+                          ':[0-9a-f]+[/0-9]*) scope link', line)
+            if m:
+                local = m.group(1)
+                ll_per_if_count += 1
+                if ll_per_if_count > 1:
+                    linklocal += [["%s-%s" % (interface, ll_per_if_count), local]]
+                else:
+                    linklocal += [[interface, local]]
+
+        if len(linklocal[0]) > 1:
+            link_local_dict = {item[0]: item[1] for item in linklocal}
+
+            for lname, laddr in link_local_dict.items():
+
+                if intf_name is not None and lname != intf_name:
+                    continue
+
+                cmd = "ip addr del {} dev {}".format(laddr, lname)
+                router_list[router].run(cmd)
+
+
 #############################################
 # These APIs,  will used by testcase
 #############################################
@@ -589,19 +821,22 @@ def create_interfaces_cfg(tgen, topo, build=False):
                     interface_name = destRouterLink
                 else:
                     interface_name = data["interface"]
-                interface_data.append("interface {}\n".format(
+                    if "ipv6" in data:
+                        disable_v6_link_local(tgen, c_router, interface_name)
+                interface_data.append("interface {}".format(
                     str(interface_name)
                 ))
                 if "ipv4" in data:
                     intf_addr = c_data["links"][destRouterLink]["ipv4"]
-                    interface_data.append("ip address {}\n".format(
+                    interface_data.append("ip address {}".format(
                         intf_addr
                     ))
                 if "ipv6" in data:
                     intf_addr = c_data["links"][destRouterLink]["ipv6"]
-                    interface_data.append("ipv6 address {}\n".format(
+                    interface_data.append("ipv6 address {}".format(
                         intf_addr
                     ))
+
             result = create_common_configuration(tgen, c_router,
                                                  interface_data,
                                                  "interface_config",
@@ -662,7 +897,7 @@ def create_static_routes(tgen, input_dict, build=False):
         for router in input_dict.keys():
             if "static_routes" not in input_dict[router]:
                 errormsg = "static_routes not present in input_dict"
-                logger.info(errormsg)
+                logger.debug(errormsg)
                 continue
 
             static_routes_list = []
@@ -768,7 +1003,7 @@ def create_prefix_lists(tgen, input_dict, build=False):
         for router in input_dict.keys():
             if "prefix_lists" not in input_dict[router]:
                 errormsg = "prefix_lists not present in input_dict"
-                logger.info(errormsg)
+                logger.debug(errormsg)
                 continue
 
             config_data = []
@@ -922,7 +1157,7 @@ def create_route_maps(tgen, input_dict, build=False):
         for router in input_dict.keys():
             if "route_maps" not in input_dict[router]:
                 errormsg = "route_maps not present in input_dict"
-                logger.info(errormsg)
+                logger.debug(errormsg)
                 continue
             rmap_data = []
             for rmap_name, rmap_value in \
@@ -1014,7 +1249,7 @@ def create_route_maps(tgen, input_dict, build=False):
 
                         # Weight
                         if weight:
-                            rmap_data.append("set weight {} \n".format(
+                            rmap_data.append("set weight {}".format(
                                 weight))
 
                     # Adding MATCH and SET sequence to RMAP if defined
@@ -1092,7 +1327,8 @@ def create_route_maps(tgen, input_dict, build=False):
 #############################################
 # Verification APIs
 #############################################
-def _verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
+@retry(attempts=10, return_is_str=True, initial_wait=2)
+def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
     """
     Data will be read from input_dict or input JSON file, API will generate
     same prefixes, which were redistributed by either create_static_routes() or
@@ -1140,7 +1376,7 @@ def _verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
     errormsg(str) or True
     """
 
-    logger.info("Entering lib API: verify_rib()")
+    logger.debug("Entering lib API: verify_rib()")
 
     router_list = tgen.routers()
     for routerInput in input_dict.keys():
@@ -1160,9 +1396,8 @@ def _verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
                 else:
                     command = "show ipv6 route json"
 
-            sleep(10)
             logger.info("Checking router %s RIB:", router)
-            rib_routes_json = rnode.vtysh_cmd(command, isjson=True)
+            rib_routes_json = run_frr_cmd(rnode, command, isjson=True)
 
             # Verifying output dictionary rib_routes_json is not empty
             if bool(rib_routes_json) is False:
@@ -1181,7 +1416,7 @@ def _verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
                     if "no_of_ip" in static_route:
                         no_of_ip = static_route["no_of_ip"]
                     else:
-                        no_of_ip = 0
+                        no_of_ip = 1
 
                     # Generating IPs for verification
                     ip_list = generate_ips(network, no_of_ip)
@@ -1199,9 +1434,9 @@ def _verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
                                 found_hops = [rib_r["ip"] for rib_r in
                                               rib_routes_json[st_rt][0][
                                                   "nexthops"]]
-                                for nh in next_hop:
+                                for nh in found_hops:
                                     nh_found = False
-                                    if nh and nh in found_hops:
+                                    if nh and nh in next_hop:
                                         nh_found = True
                                     else:
                                         errormsg = ("Nexthop {} is Missing for {}"
@@ -1257,30 +1492,10 @@ def _verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
                 logger.info("Verified routes in router %s RIB, found routes"
                             " are: %s", dut, found_routes)
 
-    logger.info("Exiting lib API: verify_rib()")
+    logger.debug("Exiting lib API: verify_rib()")
     return True
 
 
-def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None, expected=True):
-    """
-    Wrapper function for `_verify_rib` that tries multiple time to get results.
-
-    When the expected result is `False` we actually should expect for an string instead.
-    """
-
-    # Use currying to hide the parameters and create a test function.
-    test_func = partial(_verify_rib, tgen, addr_type, dut, input_dict, next_hop, protocol)
-
-    # Call the test function and expect it to return True, otherwise try it again.
-    if expected is True:
-        _, result = topotest.run_and_expect(test_func, True, count=20, wait=6)
-    else:
-        _, result = topotest.run_and_expect_type(test_func, str, count=20, wait=6)
-
-    # Return as normal.
-    return result
-
-
 def verify_admin_distance_for_static_routes(tgen, input_dict):
     """
     API to verify admin distance for static routes as defined in input_dict/
@@ -1311,7 +1526,7 @@ def verify_admin_distance_for_static_routes(tgen, input_dict):
     errormsg(str) or True
     """
 
-    logger.info("Entering lib API: verify_admin_distance_for_static_routes()")
+    logger.debug("Entering lib API: verify_admin_distance_for_static_routes()")
 
     for router in input_dict.keys():
         if router not in tgen.routers():
@@ -1326,7 +1541,7 @@ def verify_admin_distance_for_static_routes(tgen, input_dict):
                 command = "show ip route json"
             else:
                 command = "show ipv6 route json"
-            show_ip_route_json = rnode.vtysh_cmd(command, isjson=True)
+            show_ip_route_json = run_frr_cmd(rnode, command, isjson=True)
 
             logger.info("Verifying admin distance for static route %s"
                         " under dut %s:", static_route, router)
@@ -1356,7 +1571,7 @@ def verify_admin_distance_for_static_routes(tgen, input_dict):
                             format(network, router))
                 return errormsg
 
-    logger.info("Exiting lib API: verify_admin_distance_for_static_routes()")
+    logger.debug("Exiting lib API: verify_admin_distance_for_static_routes()")
     return True
 
 
@@ -1384,7 +1599,7 @@ def verify_prefix_lists(tgen, input_dict):
     errormsg(str) or True
     """
 
-    logger.info("Entering lib API: verify_prefix_lists()")
+    logger.debug("Entering lib API: verify_prefix_lists()")
 
     for router in input_dict.keys():
         if router not in tgen.routers():
@@ -1393,7 +1608,7 @@ def verify_prefix_lists(tgen, input_dict):
         rnode = tgen.routers()[router]
 
         # Show ip prefix list
-        show_prefix_list = rnode.vtysh_cmd("show ip prefix-list")
+        show_prefix_list = run_frr_cmd(rnode, "show ip prefix-list")
 
         # Verify Prefix list is deleted
         prefix_lists_addr = input_dict[router]["prefix_lists"]
@@ -1403,12 +1618,12 @@ def verify_prefix_lists(tgen, input_dict):
 
             for prefix_list in prefix_lists_addr[addr_type].keys():
                 if prefix_list in show_prefix_list:
-                    errormsg = ("Prefix list {} is not deleted from router"
+                    errormsg = ("Prefix list {} is/are present in the router"
                                 " {}".format(prefix_list, router))
                     return errormsg
 
-                logger.info("Prefix list %s is/are deleted successfully"
+                logger.info("Prefix list %s is/are not present in the router"
                             " from router %s", prefix_list, router)
 
-    logger.info("Exiting lib API: verify_prefix_lissts()")
+    logger.debug("Exiting lib API: verify_prefix_lissts()")
     return True
index 4130451d2e4a95ba07423d4858bc59ec7b548911..7a00fe4c50f27c3d8b1480b61a9ebd558f5bd086 100644 (file)
@@ -20,6 +20,7 @@
 
 from collections import OrderedDict
 from json import dumps as json_dumps
+from re import search as re_search
 import ipaddr
 import pytest
 
@@ -38,6 +39,9 @@ from lib.common_config import (
 
 from lib.bgp import create_router_bgp
 
+ROUTER_LIST = []
+
+
 def build_topo_from_json(tgen, topo):
     """
     Reads configuration from JSON file. Adds routers, creates interface
@@ -48,13 +52,15 @@ def build_topo_from_json(tgen, topo):
     * `topo`: json file data
     """
 
-    listRouters = []
-    for routerN in sorted(topo['routers'].iteritems()):
-        logger.info('Topo: Add router {}'.format(routerN[0]))
-        tgen.add_router(routerN[0])
-        listRouters.append(routerN[0])
+    ROUTER_LIST = sorted(topo['routers'].keys(),
+        key=lambda x: int(re_search('\d+', x).group(0)))
+
+    listRouters = ROUTER_LIST[:]
+    for routerN in ROUTER_LIST:
+        logger.info('Topo: Add router {}'.format(routerN))
+        tgen.add_router(routerN)
+        listRouters.append(routerN)
 
-    listRouters.sort()
     if 'ipv4base' in topo:
         ipv4Next = ipaddr.IPv4Address(topo['link_ip_start']['ipv4'])
         ipv4Step = 2 ** (32 - topo['link_ip_start']['v4mask'])
@@ -78,7 +84,7 @@ def build_topo_from_json(tgen, topo):
                 elif 'link' in x:
                     return int(x.split('-link')[1])
                 else:
-                    return int(x.split('r')[1])
+                    return int(re_search('\d+', x).group(0))
             for destRouterLink, data in sorted(topo['routers'][curRouter]['links']. \
                                                iteritems(),
                                                key=lambda x: link_sort(x[0])):
@@ -179,12 +185,13 @@ def build_config_from_json(tgen, topo, save_bkup=True):
 
     data = topo["routers"]
     for func_type in func_dict.keys():
-        logger.info('Building configuration for {}'.format(func_type))
+        logger.info('Checking for {} configuration in input data'.format(
+            func_type))
 
         func_dict.get(func_type)(tgen, data, build=True)
 
     for router in sorted(topo['routers'].keys()):
-        logger.info('Configuring router {}...'.format(router))
+        logger.debug('Configuring router {}...'.format(router))
 
         result = load_config_to_router(tgen, router, save_bkup)
         if not result:
index 7ea38491d82892cb7c0e3db3c0c4b227f1dbd61d..ade5bfd5010d661252620b87db3bfe32ee14064f 100644 (file)
@@ -1,6 +1,6 @@
 # Skip pytests example directory
 [pytest]
-norecursedirs = .git example-test lib docker
+norecursedirs = .git example-test example-topojson-test lib docker
 
 [topogen]
 # Default configuration values
@@ -15,7 +15,7 @@ norecursedirs = .git example-test lib docker
 
 # Display router current configuration during test execution,
 # by default configuration will not be shown
-show_router_config = True
+show_router_config = True
 
 # Default daemons binaries path.
 #frrdir = /usr/lib/frr
index 1b48d10a09a0cab9b810a5c2017f9ef26730d28f..c0624d933e467c40071baae398b903de5411de76 100755 (executable)
@@ -3351,7 +3351,7 @@ sub process {
 
 # if/while/etc brace do not go on next line, unless defining a do while loop,
 # or if that brace on the next line is for something else
-               if ($line =~ /(.*)\b((?:if|while|for|switch|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) {
+               if ($line =~ /(.*)\b((?:if|while|for|switch|(?:[a-z_]+|)frr_(each|with)[a-z_]+)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) {
                        my $pre_ctx = "$1$2";
 
                        my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0);
@@ -3397,7 +3397,7 @@ sub process {
                }
 
 # Check relative indent for conditionals and blocks.
-               if ($line =~ /\b(?:(?:if|while|for|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|(?:do|else)\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+               if ($line =~ /\b(?:(?:if|while|for|(?:[a-z_]+|)frr_(each|with)[a-z_]+)\s*\(|(?:do|else)\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
                        ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
                                ctx_statement_block($linenr, $realcnt, 0)
                                        if (!defined $stat);
@@ -5177,6 +5177,31 @@ sub process {
                        }
                }
 
+               if (!defined $suppress_ifbraces{$linenr - 1} &&
+                                       $line =~ /\b(frr_with_)/) {
+                       my ($level, $endln, @chunks) =
+                               ctx_statement_full($linenr, $realcnt, $-[0]);
+
+                       # Check the condition.
+                       my ($cond, $block) = @{$chunks[0]};
+                       #print "CHECKING<$linenr> cond<$cond> block<$block>\n";
+                       if (defined $cond) {
+                               substr($block, 0, length($cond), '');
+                       }
+
+                       if ($level == 0 && $block !~ /^\s*\{/) {
+                               my $herectx = $here . "\n";
+                               my $cnt = statement_rawlines($block);
+
+                               for (my $n = 0; $n < $cnt; $n++) {
+                                       $herectx .= raw_line($linenr, $n) . "\n";
+                               }
+
+                               WARN("BRACES",
+                                    "braces {} are mandatory for frr_with_* blocks\n" . $herectx);
+                       }
+               }
+
 # check for single line unbalanced braces
                if ($sline =~ /^.\s*\}\s*else\s*$/ ||
                    $sline =~ /^.\s*else\s*\{\s*$/) {
diff --git a/tools/coccinelle/frr_with_mutex.cocci b/tools/coccinelle/frr_with_mutex.cocci
new file mode 100644 (file)
index 0000000..ec8b739
--- /dev/null
@@ -0,0 +1,23 @@
+@@
+expression E;
+iterator name frr_with_mutex;
+@@
+
+- pthread_mutex_lock(E);
++ frr_with_mutex(E) {
+- {
+    ...
+- }
+- pthread_mutex_unlock(E);
++ }
+
+
+@@
+expression E;
+@@
+
+- pthread_mutex_lock(E);
++ frr_with_mutex(E) {
+  ...
+- pthread_mutex_unlock(E);
++ }
index 76d13c3f0d49f06b7e4928d8ef090b14d408f6d9..11628a7eae754c90c64be5cb9ddabd29b93dd1b2 100644 (file)
@@ -2,12 +2,12 @@
 identifier change;
 identifier end;
 expression E, f, g;
-iterator name frr_elevate_privs;
+iterator name frr_with_privs;
 @@
 
 - if (E.change(ZPRIVS_RAISE))
 -   f;
-+ frr_elevate_privs(&E) {
++ frr_with_privs(&E) {
   <+...
 -   goto end;
 +   break;
@@ -20,7 +20,7 @@ iterator name frr_elevate_privs;
 @@
 identifier change, errno, safe_strerror, exit;
 expression E, f1, f2, f3, ret, fn;
-iterator name frr_elevate_privs;
+iterator name frr_with_privs;
 @@
 
   if (E.change(ZPRIVS_RAISE))
@@ -44,7 +44,7 @@ iterator name frr_elevate_privs;
 @@
 identifier change;
 expression E, f1, f2, f3, ret;
-iterator name frr_elevate_privs;
+iterator name frr_with_privs;
 @@
 
   if (E.change(ZPRIVS_RAISE))
@@ -64,12 +64,12 @@ iterator name frr_elevate_privs;
 @@
 identifier change;
 expression E, f, g;
-iterator name frr_elevate_privs;
+iterator name frr_with_privs;
 @@
 
 - if (E.change(ZPRIVS_RAISE))
 -   f;
-+ frr_elevate_privs(&E) {
++ frr_with_privs(&E) {
   ...
 - if (E.change(ZPRIVS_LOWER))
 -   g;
index 951ad3f58fbeda76411315a5dd15b7174326bb06..b4049b55eb9c5f98be71ca6bdcc94fd61dfbf970 100644 (file)
@@ -1065,8 +1065,7 @@ static int vrrp_socket(struct vrrp_router *r)
        int ret;
        bool failed = false;
 
-       frr_elevate_privs(&vrrp_privs)
-       {
+       frr_with_privs(&vrrp_privs) {
                r->sock_rx = socket(r->family, SOCK_RAW, IPPROTO_VRRP);
                r->sock_tx = socket(r->family, SOCK_RAW, IPPROTO_VRRP);
        }
@@ -1102,8 +1101,7 @@ static int vrrp_socket(struct vrrp_router *r)
                setsockopt_ipv4_multicast_loop(r->sock_tx, 0);
 
                /* Bind Rx socket to exact interface */
-               frr_elevate_privs(&vrrp_privs)
-               {
+               frr_with_privs(&vrrp_privs) {
                        ret = setsockopt(r->sock_rx, SOL_SOCKET,
                                         SO_BINDTODEVICE, r->vr->ifp->name,
                                         strlen(r->vr->ifp->name));
@@ -1213,8 +1211,7 @@ static int vrrp_socket(struct vrrp_router *r)
                setsockopt_ipv6_multicast_loop(r->sock_tx, 0);
 
                /* Bind Rx socket to exact interface */
-               frr_elevate_privs(&vrrp_privs)
-               {
+               frr_with_privs(&vrrp_privs) {
                        ret = setsockopt(r->sock_rx, SOL_SOCKET,
                                         SO_BINDTODEVICE, r->vr->ifp->name,
                                         strlen(r->vr->ifp->name));
index 78e153a082245d0b6a83f5dfbd94c0b5115fb36f..750050e8c33bd414921112101c121045d7711732 100644 (file)
@@ -188,7 +188,7 @@ void vrrp_garp_init(void)
        /* Create the socket descriptor */
        /* FIXME: why ETH_P_RARP? */
        errno = 0;
-       frr_elevate_privs(&vrrp_privs) {
+       frr_with_privs(&vrrp_privs) {
                garp_fd = socket(PF_PACKET, SOCK_RAW | SOCK_CLOEXEC,
                                 htons(ETH_P_RARP));
        }
index 348958509a97e187471080230314d63797c08961..dc546b09a2cc4077420fff363dfbeee9ca32d85a 100644 (file)
@@ -214,8 +214,7 @@ int vrrp_ndisc_una_send_all(struct vrrp_router *r)
 
 void vrrp_ndisc_init(void)
 {
-       frr_elevate_privs(&vrrp_privs)
-       {
+       frr_with_privs(&vrrp_privs) {
                ndisc_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IPV6));
        }
 
index fba754f6265ef0b7aa9ccb051fcb51e3045bfbfc..a762e9555caf871aa03dda75c757c9b2d7a28c2e 100644 (file)
@@ -164,9 +164,10 @@ static int vtysh_reconnect(struct vtysh_client *vclient);
 static void vclient_close(struct vtysh_client *vclient)
 {
        if (vclient->fd >= 0) {
-               vty_out(vty,
-                       "Warning: closing connection to %s because of an I/O error!\n",
-                       vclient->name);
+               if (vty->of)
+                       vty_out(vty,
+                               "Warning: closing connection to %s because of an I/O error!\n",
+                               vclient->name);
                close(vclient->fd);
                /* indicate as candidate for reconnect */
                vclient->fd = VTYSH_WAS_ACTIVE;
@@ -237,8 +238,11 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
                        continue;
 
                if (nread <= 0) {
-                       vty_out(vty, "vtysh: error reading from %s: %s (%d)",
-                               vclient->name, safe_strerror(errno), errno);
+                       if (vty->of)
+                               vty_out(vty,
+                                       "vtysh: error reading from %s: %s (%d)",
+                                       vclient->name, safe_strerror(errno),
+                                       errno);
                        goto out_err;
                }
 
@@ -383,7 +387,7 @@ static int vtysh_client_run_all(struct vtysh_client *head_client,
                        rc_all = rc;
                }
        }
-       if (wrong_instance && !correct_instance) {
+       if (wrong_instance && !correct_instance && vty->of) {
                vty_out(vty,
                        "%% [%s]: command ignored as it targets an instance that is not running\n",
                        head_client->name);
@@ -1256,6 +1260,8 @@ static struct cmd_node bgp_vrf_policy_node = {BGP_VRF_POLICY_NODE,
 static struct cmd_node bgp_vnc_l2_group_node = {
        BGP_VNC_L2_GROUP_NODE, "%s(config-router-vnc-l2-group)# "};
 
+static struct cmd_node bmp_node = {BMP_NODE, "%s(config-bgp-bmp)# "};
+
 static struct cmd_node ospf_node = {OSPF_NODE, "%s(config-router)# "};
 
 static struct cmd_node eigrp_node = {EIGRP_NODE, "%s(config-router)# "};
@@ -1331,7 +1337,7 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_end_all, vtysh_end_all_cmd, "end",
 }
 
 DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd,
-       "router bgp [(1-4294967295) [<view|vrf> WORD]]",
+       "router bgp [(1-4294967295)$instasn [<view|vrf> WORD]]",
        ROUTER_STR BGP_STR AS_STR
        "BGP view\nBGP VRF\n"
        "View/VRF name\n")
@@ -1474,6 +1480,18 @@ DEFUNSH(VTYSH_BGPD,
        return CMD_SUCCESS;
 }
 
+DEFUNSH(VTYSH_BGPD,
+       bmp_targets,
+       bmp_targets_cmd,
+       "bmp targets BMPTARGETS",
+       "BGP Monitoring Protocol\n"
+       "Create BMP target group\n"
+       "Name of the BMP target group\n")
+{
+       vty->node = BMP_NODE;
+       return CMD_SUCCESS;
+}
+
 DEFUNSH(VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd,
        "address-family <l2vpn evpn>",
        "Enter Address Family command mode\n"
@@ -1581,10 +1599,11 @@ DEFUNSH(VTYSH_OSPFD, router_ospf, router_ospf_cmd,
        return CMD_SUCCESS;
 }
 
-DEFUNSH(VTYSH_EIGRPD, router_eigrp, router_eigrp_cmd, "router eigrp (1-65535)",
+DEFUNSH(VTYSH_EIGRPD, router_eigrp, router_eigrp_cmd, "router eigrp (1-65535) [vrf NAME]",
        "Enable a routing process\n"
        "Start EIGRP configuration\n"
-       "AS number to use\n")
+       "AS number to use\n"
+       VRF_CMD_HELP_STR)
 {
        vty->node = EIGRP_NODE;
        return CMD_SUCCESS;
@@ -1838,6 +1857,7 @@ static int vtysh_exit(struct vty *vty)
        case BGP_VNC_DEFAULTS_NODE:
        case BGP_VNC_NVE_GROUP_NODE:
        case BGP_VNC_L2_GROUP_NODE:
+       case BMP_NODE:
                vty->node = BGP_NODE;
                break;
        case BGP_EVPN_VNI_NODE:
@@ -1928,6 +1948,19 @@ DEFUNSH(VTYSH_BGPD, rpki_quit, rpki_quit_cmd, "quit",
        return rpki_exit(self, vty, argc, argv);
 }
 
+DEFUNSH(VTYSH_BGPD, bmp_exit, bmp_exit_cmd, "exit",
+       "Exit current mode and down to previous mode\n")
+{
+       vtysh_exit(vty);
+       return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_BGPD, bmp_quit, bmp_quit_cmd, "quit",
+       "Exit current mode and down to previous mode\n")
+{
+       return bmp_exit(self, vty, argc, argv);
+}
+
 DEFUNSH(VTYSH_VRF, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf",
        "Exit from VRF configuration mode\n")
 {
@@ -3255,15 +3288,66 @@ DEFUN (no_vtysh_output_file,
 
 DEFUN(find,
       find_cmd,
-      "find COMMAND...",
-      "Find CLI command containing text\n"
-      "Text to search for\n")
+      "find REGEX",
+      "Find CLI command matching a regular expression\n"
+      "Search pattern (POSIX regex)\n")
 {
-       char *text = argv_concat(argv, argc, 1);
+       char *pattern = argv[1]->arg;
        const struct cmd_node *node;
        const struct cmd_element *cli;
        vector clis;
 
+       regex_t exp = {};
+
+       int cr = regcomp(&exp, pattern, REG_NOSUB | REG_EXTENDED);
+
+       if (cr != 0) {
+               switch (cr) {
+               case REG_BADBR:
+                       vty_out(vty, "%% Invalid \\{...\\} expression\n");
+                       break;
+               case REG_BADRPT:
+                       vty_out(vty, "%% Bad repetition operator\n");
+                       break;
+               case REG_BADPAT:
+                       vty_out(vty, "%% Regex syntax error\n");
+                       break;
+               case REG_ECOLLATE:
+                       vty_out(vty, "%% Invalid collating element\n");
+                       break;
+               case REG_ECTYPE:
+                       vty_out(vty, "%% Invalid character class name\n");
+                       break;
+               case REG_EESCAPE:
+                       vty_out(vty,
+                               "%% Regex ended with escape character (\\)\n");
+                       break;
+               case REG_ESUBREG:
+                       vty_out(vty,
+                               "%% Invalid number in \\digit construction\n");
+                       break;
+               case REG_EBRACK:
+                       vty_out(vty, "%% Unbalanced square brackets\n");
+                       break;
+               case REG_EPAREN:
+                       vty_out(vty, "%% Unbalanced parentheses\n");
+                       break;
+               case REG_EBRACE:
+                       vty_out(vty, "%% Unbalanced braces\n");
+                       break;
+               case REG_ERANGE:
+                       vty_out(vty,
+                               "%% Invalid endpoint in range expression\n");
+                       break;
+               case REG_ESPACE:
+                       vty_out(vty, "%% Failed to compile (out of memory)\n");
+                       break;
+               }
+
+               goto done;
+       }
+
+
        for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
                node = vector_slot(cmdvec, i);
                if (!node)
@@ -3271,14 +3355,15 @@ DEFUN(find,
                clis = node->cmd_vector;
                for (unsigned int j = 0; j < vector_active(clis); j++) {
                        cli = vector_slot(clis, j);
-                       if (strcasestr(cli->string, text))
+
+                       if (regexec(&exp, cli->string, 0, NULL, 0) == 0)
                                vty_out(vty, "  (%s)  %s\n",
                                        node_names[node->node], cli->string);
                }
        }
 
-       XFREE(MTYPE_TMP, text);
-
+done:
+       regfree(&exp);
        return CMD_SUCCESS;
 }
 
@@ -3616,6 +3701,7 @@ void vtysh_init_vty(void)
        install_node(&openfabric_node, NULL);
        install_node(&vty_node, NULL);
        install_node(&rpki_node, NULL);
+       install_node(&bmp_node, NULL);
 #if HAVE_BFDD > 0
        install_node(&bfd_node, NULL);
        install_node(&bfd_peer_node, NULL);
@@ -3849,6 +3935,11 @@ void vtysh_init_vty(void)
        install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd);
        install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd);
 
+       install_element(BGP_NODE, &bmp_targets_cmd);
+       install_element(BMP_NODE, &bmp_exit_cmd);
+       install_element(BMP_NODE, &bmp_quit_cmd);
+       install_element(BMP_NODE, &vtysh_end_all_cmd);
+
        install_element(CONFIG_NODE, &rpki_cmd);
        install_element(RPKI_NODE, &rpki_exit_cmd);
        install_element(RPKI_NODE, &rpki_quit_cmd);
index 4101a4bf2430647313e7d1cee6ef9a0e42315057..6b92945c6314123c1e472292104614f4425e83bc 100644 (file)
@@ -120,10 +120,6 @@ struct connected *connected_check_ptp(struct interface *ifp,
        struct connected *ifc;
        struct listnode *node;
 
-       /* ignore broadcast addresses */
-       if (p->prefixlen != IPV4_MAX_PREFIXLEN)
-               d = NULL;
-
        for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
                if (!prefix_same(ifc->address, p))
                        continue;
@@ -143,6 +139,12 @@ static int connected_same(struct connected *ifc1, struct connected *ifc2)
        if (ifc1->ifp != ifc2->ifp)
                return 0;
 
+       if (ifc1->flags != ifc2->flags)
+               return 0;
+
+       if (ifc1->conf != ifc2->conf)
+               return 0;
+
        if (ifc1->destination)
                if (!ifc2->destination)
                        return 0;
@@ -154,12 +156,6 @@ static int connected_same(struct connected *ifc1, struct connected *ifc2)
                if (!prefix_same(ifc1->destination, ifc2->destination))
                        return 0;
 
-       if (ifc1->flags != ifc2->flags)
-               return 0;
-
-       if (ifc1->conf != ifc2->conf)
-               return 0;
-
        return 1;
 }
 
@@ -239,7 +235,7 @@ void connected_up(struct interface *ifp, struct connected *ifc)
                        return;
                break;
        case AFI_IP6:
-#ifndef LINUX
+#ifndef GNU_LINUX
                /* XXX: It is already done by rib_bogus_ipv6 within rib_add */
                if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6))
                        return;
@@ -276,7 +272,7 @@ void connected_up(struct interface *ifp, struct connected *ifc)
 
 /* Add connected IPv4 route to the interface. */
 void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr,
-                       uint16_t prefixlen, struct in_addr *broad,
+                       uint16_t prefixlen, struct in_addr *dest,
                        const char *label, uint32_t metric)
 {
        struct prefix_ipv4 *p;
@@ -302,59 +298,39 @@ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr,
                                                         : prefixlen;
        ifc->address = (struct prefix *)p;
 
-       /* If there is broadcast or peer address. */
-       if (broad) {
-               p = prefix_ipv4_new();
-               p->family = AF_INET;
-               p->prefix = *broad;
-               p->prefixlen = prefixlen;
-               ifc->destination = (struct prefix *)p;
-
+       /* If there is a peer address. */
+       if (CONNECTED_PEER(ifc)) {
                /* validate the destination address */
-               if (CONNECTED_PEER(ifc)) {
-                       if (IPV4_ADDR_SAME(addr, broad))
+               if (dest) {
+                       p = prefix_ipv4_new();
+                       p->family = AF_INET;
+                       p->prefix = *dest;
+                       p->prefixlen = prefixlen;
+                       ifc->destination = (struct prefix *)p;
+
+                       if (IPV4_ADDR_SAME(addr, dest))
                                flog_warn(
                                        EC_ZEBRA_IFACE_SAME_LOCAL_AS_PEER,
                                        "warning: interface %s has same local and peer "
                                        "address %s, routing protocols may malfunction",
                                        ifp->name, inet_ntoa(*addr));
                } else {
-                       if (broad->s_addr
-                           != ipv4_broadcast_addr(addr->s_addr, prefixlen)) {
-                               char buf[2][INET_ADDRSTRLEN];
-                               struct in_addr bcalc;
-                               bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,
-                                                                  prefixlen);
-                               flog_warn(
-                                       EC_ZEBRA_BCAST_ADDR_MISMATCH,
-                                       "warning: interface %s broadcast addr %s/%d != "
-                                       "calculated %s, routing protocols may malfunction",
-                                       ifp->name,
-                                       inet_ntop(AF_INET, broad, buf[0],
-                                                 sizeof(buf[0])),
-                                       prefixlen,
-                                       inet_ntop(AF_INET, &bcalc, buf[1],
-                                                 sizeof(buf[1])));
-                       }
-               }
-
-       } else {
-               if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) {
                        zlog_debug(
                                "warning: %s called for interface %s "
                                "with peer flag set, but no peer address supplied",
                                __func__, ifp->name);
                        UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
                }
-
-               /* no broadcast or destination address was supplied */
-               if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
-                       zlog_debug(
-                               "warning: PtP interface %s with addr %s/%d needs a "
-                               "peer address",
-                               ifp->name, inet_ntoa(*addr), prefixlen);
        }
 
+       /* no destination address was supplied */
+       if (!dest && (prefixlen == IPV4_MAX_PREFIXLEN)
+               && if_is_pointopoint(ifp))
+               zlog_debug(
+                       "warning: PtP interface %s with addr %s/%d needs a "
+                       "peer address",
+                       ifp->name, inet_ntoa(*addr), prefixlen);
+
        /* Label of this address. */
        if (label)
                ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label);
@@ -464,7 +440,7 @@ static void connected_delete_helper(struct connected *ifc, struct prefix *p)
 /* Delete connected IPv4 route to the interface. */
 void connected_delete_ipv4(struct interface *ifp, int flags,
                           struct in_addr *addr, uint16_t prefixlen,
-                          struct in_addr *broad)
+                          struct in_addr *dest)
 {
        struct prefix p, d;
        struct connected *ifc;
@@ -475,10 +451,10 @@ void connected_delete_ipv4(struct interface *ifp, int flags,
        p.prefixlen = CHECK_FLAG(flags, ZEBRA_IFA_PEER) ? IPV4_MAX_PREFIXLEN
                                                        : prefixlen;
 
-       if (broad) {
+       if (dest) {
                memset(&d, 0, sizeof(struct prefix));
                d.family = AF_INET;
-               d.u.prefix4 = *broad;
+               d.u.prefix4 = *dest;
                d.prefixlen = prefixlen;
                ifc = connected_check_ptp(ifp, &p, &d);
        } else
@@ -489,7 +465,7 @@ void connected_delete_ipv4(struct interface *ifp, int flags,
 
 /* Add connected IPv6 route to the interface. */
 void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
-                       struct in6_addr *broad, uint16_t prefixlen,
+                       struct in6_addr *dest, uint16_t prefixlen,
                        const char *label, uint32_t metric)
 {
        struct prefix_ipv6 *p;
@@ -514,10 +490,10 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
        p->prefixlen = prefixlen;
        ifc->address = (struct prefix *)p;
 
-       if (broad) {
+       if (dest) {
                p = prefix_ipv6_new();
                p->family = AF_INET6;
-               IPV6_ADDR_COPY(&p->prefix, broad);
+               IPV6_ADDR_COPY(&p->prefix, dest);
                p->prefixlen = prefixlen;
                ifc->destination = (struct prefix *)p;
        } else {
@@ -547,7 +523,7 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
 }
 
 void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address,
-                          struct in6_addr *broad, uint16_t prefixlen)
+                          struct in6_addr *dest, uint16_t prefixlen)
 {
        struct prefix p, d;
        struct connected *ifc;
@@ -557,10 +533,10 @@ void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address,
        memcpy(&p.u.prefix6, address, sizeof(struct in6_addr));
        p.prefixlen = prefixlen;
 
-       if (broad) {
+       if (dest) {
                memset(&d, 0, sizeof(struct prefix));
                d.family = AF_INET6;
-               IPV6_ADDR_COPY(&d.u.prefix6, broad);
+               IPV6_ADDR_COPY(&d.u.prefix6, dest);
                d.prefixlen = prefixlen;
                ifc = connected_check_ptp(ifp, &p, &d);
        } else
index 7672bec0063fdaa2b266b1439f4fa35f72c4585a..14f6cb2db013d5ee3245aca7d7e3e15d0e7ea1c0 100644 (file)
@@ -40,12 +40,12 @@ extern struct connected *connected_check_ptp(struct interface *ifp,
 
 extern void connected_add_ipv4(struct interface *ifp, int flags,
                               struct in_addr *addr, uint16_t prefixlen,
-                              struct in_addr *broad, const char *label,
+                              struct in_addr *dest, const char *label,
                               uint32_t metric);
 
 extern void connected_delete_ipv4(struct interface *ifp, int flags,
                                  struct in_addr *addr, uint16_t prefixlen,
-                                 struct in_addr *broad);
+                                 struct in_addr *dest);
 
 extern void connected_delete_ipv4_unnumbered(struct connected *ifc);
 
@@ -53,12 +53,12 @@ extern void connected_up(struct interface *ifp, struct connected *ifc);
 extern void connected_down(struct interface *ifp, struct connected *ifc);
 
 extern void connected_add_ipv6(struct interface *ifp, int flags,
-                              struct in6_addr *address, struct in6_addr *broad,
+                              struct in6_addr *address, struct in6_addr *dest,
                               uint16_t prefixlen, const char *label,
                               uint32_t metric);
 extern void connected_delete_ipv6(struct interface *ifp,
                                  struct in6_addr *address,
-                                 struct in6_addr *broad, uint16_t prefixlen);
+                                 struct in6_addr *dest, uint16_t prefixlen);
 
 extern int connected_is_unnumbered(struct interface *);
 
index 8b539a90499532be23337701a1d198098a7160c2..2a2504ebf8adec7b49a23a15bd6623ee7e08e8d9 100644 (file)
@@ -60,7 +60,7 @@ static int interface_list_ioctl(int af)
        size_t needed, lastneeded = 0;
        char *buf = NULL;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                sock = socket(af, SOCK_DGRAM, 0);
        }
 
@@ -72,7 +72,7 @@ static int interface_list_ioctl(int af)
        }
 
 calculate_lifc_len:
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                lifn.lifn_family = af;
                lifn.lifn_flags = LIFC_NOXMIT;
                /* we want NOXMIT interfaces too */
@@ -107,7 +107,7 @@ calculate_lifc_len:
        lifconf.lifc_len = needed;
        lifconf.lifc_buf = buf;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                ret = ioctl(sock, SIOCGLIFCONF, &lifconf);
        }
 
index 2c536c5d1f92523e1dbac44344068c90904f5494..c71b95f753ad894648408b6962691642db21d69b 100644 (file)
@@ -385,7 +385,7 @@ static int get_iflink_speed(struct interface *interface)
        ifdata.ifr_data = (caddr_t)&ecmd;
 
        /* use ioctl to get IP address of an interface */
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                sd = vrf_socket(PF_INET, SOCK_DGRAM, IPPROTO_IP,
                                interface->vrf_id,
                                NULL);
@@ -888,11 +888,13 @@ static int netlink_address_ctx(const struct zebra_dplane_ctx *ctx)
                        p = dplane_ctx_get_intf_dest(ctx);
                        addattr_l(&req.n, sizeof(req), IFA_ADDRESS,
                                  &p->u.prefix, bytelen);
-               } else if (cmd == RTM_NEWADDR &&
-                          dplane_ctx_intf_has_dest(ctx)) {
-                       p = dplane_ctx_get_intf_dest(ctx);
+               } else if (cmd == RTM_NEWADDR) {
+                       struct in_addr broad = {
+                               .s_addr = ipv4_broadcast_addr(p->u.prefix4.s_addr,
+                                                       p->prefixlen)
+                       };
                        addattr_l(&req.n, sizeof(req), IFA_BROADCAST,
-                                 &p->u.prefix, bytelen);
+                                 &broad, bytelen);
                }
        }
 
@@ -1065,7 +1067,7 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                else
                        connected_delete_ipv4(
                                ifp, flags, (struct in_addr *)addr,
-                               ifa->ifa_prefixlen, (struct in_addr *)broad);
+                               ifa->ifa_prefixlen, NULL);
        }
        if (ifa->ifa_family == AF_INET6) {
                if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) {
@@ -1091,8 +1093,7 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                                                   metric);
                } else
                        connected_delete_ipv6(ifp, (struct in6_addr *)addr,
-                                             (struct in6_addr *)broad,
-                                             ifa->ifa_prefixlen);
+                                             NULL, ifa->ifa_prefixlen);
        }
 
        return 0;
index a2f80aff4e691101334561639e6b84b0ccc96359..6486c01430c39bc02c1c8e8538053903c4064558 100644 (file)
@@ -1081,12 +1081,10 @@ static void connected_dump_vty(struct vty *vty, struct connected *connected)
        vty_out(vty, "/%d", p->prefixlen);
 
        /* If there is destination address, print it. */
-       if (connected->destination) {
-               vty_out(vty,
-                       (CONNECTED_PEER(connected) ? " peer " : " broadcast "));
+       if (CONNECTED_PEER(connected) && connected->destination) {
+               vty_out(vty, " peer ");
                prefix_vty_out(vty, connected->destination);
-               if (CONNECTED_PEER(connected))
-                       vty_out(vty, "/%d", connected->destination->prefixlen);
+               vty_out(vty, "/%d", connected->destination->prefixlen);
        }
 
        if (CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY))
@@ -2684,12 +2682,6 @@ static int ip_address_install(struct vty *vty, struct interface *ifp,
                        p = prefix_ipv4_new();
                        *p = pp;
                        ifc->destination = (struct prefix *)p;
-               } else if (p->prefixlen <= IPV4_MAX_PREFIXLEN - 2) {
-                       p = prefix_ipv4_new();
-                       *p = lp;
-                       p->prefix.s_addr = ipv4_broadcast_addr(p->prefix.s_addr,
-                                                              p->prefixlen);
-                       ifc->destination = (struct prefix *)p;
                }
 
                /* Label. */
index 8202e076afb49cf387408d95d38b12f077b3036b..b461a0888184fdb148648ca351513f7dc18dfd7e 100644 (file)
@@ -57,7 +57,7 @@ int if_ioctl(unsigned long request, caddr_t buffer)
        int ret;
        int err = 0;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                sock = socket(AF_INET, SOCK_DGRAM, 0);
                if (sock < 0) {
                        zlog_err("Cannot create UDP socket: %s",
@@ -83,7 +83,7 @@ int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id)
        int ret;
        int err = 0;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                sock = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
                if (sock < 0) {
                        zlog_err("Cannot create UDP socket: %s",
@@ -110,7 +110,7 @@ static int if_ioctl_ipv6(unsigned long request, caddr_t buffer)
        int ret;
        int err = 0;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                sock = socket(AF_INET6, SOCK_DGRAM, 0);
                if (sock < 0) {
                        zlog_err("Cannot create IPv6 datagram socket: %s",
index 1f96fa23ea3af4b2c1368c1171ecaa3b33f94395..2c71d949f75fec74615f637dd3548fccd689878e 100644 (file)
@@ -66,7 +66,7 @@ int if_ioctl(unsigned long request, caddr_t buffer)
        int ret;
        int err;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
 
                sock = socket(AF_INET, SOCK_DGRAM, 0);
                if (sock < 0) {
@@ -96,7 +96,7 @@ int if_ioctl_ipv6(unsigned long request, caddr_t buffer)
        int ret;
        int err;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
 
                sock = socket(AF_INET6, SOCK_DGRAM, 0);
                if (sock < 0) {
index 8f44c377b33ecf873be3453ea95e808816f0f499..709d2176aa01529a6efa2e16df360178d5428639 100644 (file)
@@ -76,7 +76,7 @@ int ipforward_on(void)
 {
        FILE *fp;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
 
                fp = fopen(proc_ipv4_forwarding, "w");
 
@@ -97,7 +97,7 @@ int ipforward_off(void)
 {
        FILE *fp;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
 
                fp = fopen(proc_ipv4_forwarding, "w");
 
@@ -143,7 +143,7 @@ int ipforward_ipv6_on(void)
 {
        FILE *fp;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
 
                fp = fopen(proc_ipv6_forwarding, "w");
 
@@ -165,7 +165,7 @@ int ipforward_ipv6_off(void)
 {
        FILE *fp;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
 
                fp = fopen(proc_ipv6_forwarding, "w");
 
index 1bb743059c7b3e3060110849010ec982e73b47f5..1a45328248be9ac8f393504eaca233a0a1d73cd8 100644 (file)
@@ -83,7 +83,7 @@ static int solaris_nd(const int cmd, const char *parameter, const int value)
        strioctl.ic_len = ND_BUFFER_SIZE;
        strioctl.ic_dp = nd_buf;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                if ((fd = open(device, O_RDWR)) < 0) {
                        flog_err_sys(EC_LIB_SYSTEM_CALL,
                                     "failed to open device %s - %s", device,
index cc9421c2754db5f51eb3861dc5b81f0ee76f9f20..ac8f5370759bbfc5b81c85ca15303c68b2e2e7a6 100644 (file)
@@ -56,7 +56,7 @@ int ipforward_on(void)
        int ipforwarding = 1;
 
        len = sizeof ipforwarding;
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                if (sysctl(mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) {
                        flog_err_sys(EC_LIB_SYSTEM_CALL,
                                     "Can't set ipforwarding on");
@@ -72,7 +72,7 @@ int ipforward_off(void)
        int ipforwarding = 0;
 
        len = sizeof ipforwarding;
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                if (sysctl(mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) {
                        flog_err_sys(EC_LIB_SYSTEM_CALL,
                                     "Can't set ipforwarding on");
@@ -97,7 +97,7 @@ int ipforward_ipv6(void)
        int ip6forwarding = 0;
 
        len = sizeof ip6forwarding;
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                if (sysctl(mib_ipv6, MIB_SIZ, &ip6forwarding, &len, 0, 0) < 0) {
                        flog_err_sys(EC_LIB_SYSTEM_CALL,
                                     "can't get ip6forwarding value");
@@ -113,7 +113,7 @@ int ipforward_ipv6_on(void)
        int ip6forwarding = 1;
 
        len = sizeof ip6forwarding;
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                if (sysctl(mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len)
                    < 0) {
                        flog_err_sys(EC_LIB_SYSTEM_CALL,
@@ -130,7 +130,7 @@ int ipforward_ipv6_off(void)
        int ip6forwarding = 0;
 
        len = sizeof ip6forwarding;
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                if (sysctl(mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len)
                    < 0) {
                        flog_err_sys(EC_LIB_SYSTEM_CALL,
index 38d241eaa5b45c5624109281b878878096bc07a3..0de618625d770e67bb41edc402b7856c55b44183 100644 (file)
@@ -82,7 +82,7 @@ int irdp_sock_init(void)
        int save_errno;
        int sock;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
 
                sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
                save_errno = errno;
index 2c306434a36dca516e0736137c81ced52a7ada85..f52b4746ae7f0472dc9da9f0f7eb523a6781288f 100644 (file)
@@ -183,7 +183,7 @@ static int netlink_recvbuf(struct nlsock *nl, uint32_t newsize)
        }
 
        /* Try force option (linux >= 2.6.14) and fall back to normal set */
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE,
                                 &nl_rcvbufsize,
                                 sizeof(nl_rcvbufsize));
@@ -220,7 +220,7 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups,
        int sock;
        int namelen;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                sock = ns_socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, ns_id);
                if (sock < 0) {
                        zlog_err("Can't open %s socket: %s", nl->name,
@@ -352,7 +352,7 @@ static void netlink_write_incoming(const char *buf, const unsigned int size,
        FILE *f;
 
        snprintf(fname, MAXPATHLEN, "%s/%s_%u", frr_vtydir, "netlink", counter);
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                f = fopen(fname, "w");
        }
        if (f) {
@@ -373,7 +373,7 @@ static long netlink_read_file(char *buf, const char *fname)
        FILE *f;
        long file_bytes = -1;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                f = fopen(fname, "r");
        }
        if (f) {
@@ -989,7 +989,7 @@ int netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
                        n->nlmsg_flags);
 
        /* Send message to netlink interface. */
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                status = sendmsg(nl->sock, &msg, 0);
                save_errno = errno;
        }
@@ -1056,7 +1056,7 @@ int netlink_request(struct nlsock *nl, struct nlmsghdr *n)
        snl.nl_family = AF_NETLINK;
 
        /* Raise capabilities and send message, then lower capabilities. */
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                ret = sendto(nl->sock, (void *)n, n->nlmsg_len, 0,
                             (struct sockaddr *)&snl, sizeof snl);
        }
index 156ce50725ec758d6e99f5594006a9f38912bf1c..60fbbcc0598f4eb8e0fefd1be2cee804f0286a1b 100644 (file)
@@ -1426,7 +1426,7 @@ static int kernel_read(struct thread *thread)
 /* Make routing socket. */
 static void routing_socket(struct zebra_ns *zns)
 {
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                routing_sock = ns_socket(AF_ROUTE, SOCK_RAW, 0, zns->ns_id);
 
                dplane_routing_sock =
index f819699160421778510210175a3638ca0f6ce328..98d1dbbbca47343ea4d8ee2d282dafc0243762c9 100644 (file)
@@ -1054,33 +1054,28 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
        label_buf[0] = '\0';
 
        assert(nexthop);
-       for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
-               char label_buf1[20];
+       char label_buf1[20];
 
-               nh_label = nh->nh_label;
-               if (!nh_label || !nh_label->num_labels)
-                       continue;
+       nh_label = nexthop->nh_label;
 
-               for (int i = 0; i < nh_label->num_labels; i++) {
-                       if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
-                               continue;
+       for (int i = 0; nh_label && i < nh_label->num_labels; i++) {
+               if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
+                       continue;
 
-                       if (IS_ZEBRA_DEBUG_KERNEL) {
-                               if (!num_labels)
-                                       sprintf(label_buf, "label %u",
-                                               nh_label->label[i]);
-                               else {
-                                       sprintf(label_buf1, "/%u",
-                                               nh_label->label[i]);
-                                       strlcat(label_buf, label_buf1,
-                                               sizeof(label_buf));
-                               }
+               if (IS_ZEBRA_DEBUG_KERNEL) {
+                       if (!num_labels)
+                               sprintf(label_buf, "label %u",
+                                       nh_label->label[i]);
+                       else {
+                               sprintf(label_buf1, "/%u", nh_label->label[i]);
+                               strlcat(label_buf, label_buf1,
+                                       sizeof(label_buf));
                        }
-
-                       out_lse[num_labels] =
-                               mpls_lse_encode(nh_label->label[i], 0, 0, 0);
-                       num_labels++;
                }
+
+               out_lse[num_labels] =
+                       mpls_lse_encode(nh_label->label[i], 0, 0, 0);
+               num_labels++;
        }
 
        if (num_labels) {
@@ -1245,33 +1240,28 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
        label_buf[0] = '\0';
 
        assert(nexthop);
-       for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
-               char label_buf1[20];
+       char label_buf1[20];
 
-               nh_label = nh->nh_label;
-               if (!nh_label || !nh_label->num_labels)
-                       continue;
+       nh_label = nexthop->nh_label;
 
-               for (int i = 0; i < nh_label->num_labels; i++) {
-                       if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
-                               continue;
+       for (int i = 0; nh_label && i < nh_label->num_labels; i++) {
+               if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
+                       continue;
 
-                       if (IS_ZEBRA_DEBUG_KERNEL) {
-                               if (!num_labels)
-                                       sprintf(label_buf, "label %u",
-                                               nh_label->label[i]);
-                               else {
-                                       sprintf(label_buf1, "/%u",
-                                               nh_label->label[i]);
-                                       strlcat(label_buf, label_buf1,
-                                               sizeof(label_buf));
-                               }
+               if (IS_ZEBRA_DEBUG_KERNEL) {
+                       if (!num_labels)
+                               sprintf(label_buf, "label %u",
+                                       nh_label->label[i]);
+                       else {
+                               sprintf(label_buf1, "/%u", nh_label->label[i]);
+                               strlcat(label_buf, label_buf1,
+                                       sizeof(label_buf));
                        }
-
-                       out_lse[num_labels] =
-                               mpls_lse_encode(nh_label->label[i], 0, 0, 0);
-                       num_labels++;
                }
+
+               out_lse[num_labels] =
+                       mpls_lse_encode(nh_label->label[i], 0, 0, 0);
+               num_labels++;
        }
 
        if (num_labels) {
index 62675f8daf66a47c3f97d5c8bb4e4c778c58b412..f8ce71713a798f200ee6f68e7a6986844fe2d2df 100644 (file)
@@ -314,7 +314,7 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
        type = dplane_ctx_get_type(ctx);
        old_type = dplane_ctx_get_old_type(ctx);
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
 
                if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
                        if (!RSYSTEM_ROUTE(type))
index 5841c44b0334fa152735397c2b956cf933478802..b084fb99ca1152b888912c5dd436bf80d8bfc36b 100644 (file)
@@ -760,7 +760,7 @@ static int rtadv_make_socket(ns_id_t ns_id)
        int ret = 0;
        struct icmp6_filter filter;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
 
                sock = ns_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, ns_id);
 
index b6a8ee950c3d94905e86a91fa7ae2a2ab1eef497..fa6a2f62ec00318cbe329ff207214e44b0d5daee 100644 (file)
@@ -2507,7 +2507,7 @@ static void zserv_write_incoming(struct stream *orig, uint16_t command)
 
        snprintf(fname, MAXPATHLEN, "%s/%u", frr_vtydir, command);
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                fd = open(fname, O_CREAT | O_WRONLY | O_EXCL, 0644);
        }
        stream_flush(copy, fd);
index 09daf0c5721d1ea94b749bfc718b42b04a4597bb..569ccfb0b1de0e65a5f61dacd2e79c51a568040a 100644 (file)
@@ -134,7 +134,7 @@ struct dplane_intf_info {
 #define DPLANE_INTF_CONNECTED   (1 << 0) /* Connected peer, p2p */
 #define DPLANE_INTF_SECONDARY   (1 << 1)
 #define DPLANE_INTF_BROADCAST   (1 << 2)
-#define DPLANE_INTF_HAS_DEST    (1 << 3)
+#define DPLANE_INTF_HAS_DEST    DPLANE_INTF_CONNECTED
 #define DPLANE_INTF_HAS_LABEL   (1 << 4)
 
        /* Interface address/prefix */
@@ -2082,9 +2082,6 @@ static enum zebra_dplane_result intf_addr_update_internal(
                ctx->u.intf.dest_prefix = *(ifc->destination);
                ctx->u.intf.flags |=
                        (DPLANE_INTF_CONNECTED | DPLANE_INTF_HAS_DEST);
-       } else if (ifc->destination) {
-               ctx->u.intf.dest_prefix = *(ifc->destination);
-               ctx->u.intf.flags |= DPLANE_INTF_HAS_DEST;
        }
 
        if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
index eaf43095bc8ec27d48a918d517332fedf6c7d7d0..4144c0afe06e6211baf57911fcce4985b9df9007 100644 (file)
@@ -1927,6 +1927,9 @@ static inline void zfpm_init_message_format(const char *format)
                                "FPM protobuf message format is not available");
                        return;
                }
+               flog_warn(EC_ZEBRA_PROTOBUF_NOT_AVAILABLE,
+                         "FPM protobuf message format is deprecated and scheduled to be removed. "
+                         "Please convert to using netlink format or contact dev@lists.frrouting.org with your use case.");
                zfpm_g->message_format = ZFPM_MSG_FORMAT_PROTOBUF;
                return;
        }
index 9f3ea70c77aa5b4035889584e9872df4cc3edc65..fcd476dc2c35a26e75be8b32842ee5f253515e75 100644 (file)
@@ -119,7 +119,7 @@ static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label,
                        hdr.rtm_mpls = MPLS_OP_SWAP;
        }
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                ret = writev(kr_state.fd, iov, iovcnt);
        }
 
@@ -226,7 +226,7 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label,
                        hdr.rtm_mpls = MPLS_OP_SWAP;
        }
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                ret = writev(kr_state.fd, iov, iovcnt);
        }
 
index 476638591bec231726b9be673e84d302718b8f5a..d42cf3d60a22f3527aa3e11fe3334036af4d2961 100644 (file)
@@ -77,7 +77,7 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
        if (netnspath == NULL)
                return;
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                ns_id = zebra_ns_id_get(netnspath);
        }
        if (ns_id == NS_UNKNOWN)
@@ -97,7 +97,7 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
                ns_map_nsid_with_external(ns_id, false);
                return;
        }
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                ret = vrf_netns_handler_create(NULL, vrf, netnspath,
                                               ns_id_external, ns_id);
        }
@@ -202,14 +202,14 @@ static int zebra_ns_ready_read(struct thread *t)
        netnspath = zns_info->netnspath;
        if (--zns_info->retries == 0)
                stop_retry = 1;
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                err = ns_switch_to_netns(netnspath);
        }
        if (err < 0)
                return zebra_ns_continue_read(zns_info, stop_retry);
 
        /* go back to default ns */
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                err = ns_switchback_to_initial();
        }
        if (err < 0)
index f4b86f3cfe96dd064ddce855f05e3f91a46406ef..ee2956d3ea78b1895cb44ae0805773e1dd1df509 100644 (file)
@@ -25,6 +25,7 @@
 #include "lib/nexthop.h"
 #include "lib/nexthop_group_private.h"
 #include "lib/routemap.h"
+#include "lib/mpls.h"
 
 #include "zebra/connected.h"
 #include "zebra/debug.h"
@@ -38,6 +39,10 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
                                 struct nexthop *nexthop)
 {
        struct nexthop *resolved_hop;
+       uint8_t num_labels = 0;
+       mpls_label_t labels[MPLS_MAX_LABELS];
+       enum lsp_types_t label_type = ZEBRA_LSP_NONE;
+       int i = 0;
 
        resolved_hop = nexthop_new();
        SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -94,11 +99,24 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
        if (newhop->flags & NEXTHOP_FLAG_ONLINK)
                resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
 
-       /* Copy labels of the resolved route */
-       if (newhop->nh_label)
-               nexthop_add_labels(resolved_hop, newhop->nh_label_type,
-                                  newhop->nh_label->num_labels,
-                                  &newhop->nh_label->label[0]);
+       /* Copy labels of the resolved route and the parent resolving to it */
+       if (newhop->nh_label) {
+               for (i = 0; i < newhop->nh_label->num_labels; i++)
+                       labels[num_labels++] = newhop->nh_label->label[i];
+               label_type = newhop->nh_label_type;
+       }
+
+       if (nexthop->nh_label) {
+               for (i = 0; i < nexthop->nh_label->num_labels; i++)
+                       labels[num_labels++] = nexthop->nh_label->label[i];
+
+               /* If the parent has labels, use its type */
+               label_type = nexthop->nh_label_type;
+       }
+
+       if (num_labels)
+               nexthop_add_labels(resolved_hop, label_type, num_labels,
+                                  labels);
 
        resolved_hop->rparent = nexthop;
        _nexthop_add(&nexthop->resolved, resolved_hop);
@@ -120,6 +138,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
        struct nexthop *newhop;
        struct interface *ifp;
        rib_dest_t *dest;
+       struct zebra_vrf *zvrf;
 
        if ((nexthop->type == NEXTHOP_TYPE_IPV4)
            || nexthop->type == NEXTHOP_TYPE_IPV6)
@@ -194,7 +213,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
        }
        /* Lookup table.  */
        table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
-       if (!table) {
+       /* get zvrf */
+       zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
+       if (!table || !zvrf) {
                if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                        zlog_debug("\t%s: Table not found",
                                   __PRETTY_FUNCTION__);
@@ -224,7 +245,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                /* However, do not resolve over default route unless explicitly
                 * allowed. */
                if (is_default_prefix(&rn->p)
-                   && !rnh_resolve_via_default(p.family)) {
+                   && !rnh_resolve_via_default(zvrf, p.family)) {
                        if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                                zlog_debug(
                                        "\t:%s: Resolved against default route",
index 94918365a330e4e50c20344b0b79e2e5d1304d96..37f53bf91187fddf220624d9480b3cd0c64de4a4 100644 (file)
@@ -180,7 +180,7 @@ int zebra_ns_init(const char *optional_default_name)
 
        dzns = zebra_ns_alloc();
 
-       frr_elevate_privs(&zserv_privs) {
+       frr_with_privs(&zserv_privs) {
                ns_id = zebra_ns_id_get_default();
        }
        ns_id_external = ns_map_nsid_with_external(ns_id, true);
index b54b47bad458287b0d819ad831ce297427b4cf36..b85784f5933504f8bb913810645893c2a818845d 100644 (file)
@@ -37,6 +37,7 @@
 #include "vrf.h"
 #include "workqueue.h"
 #include "nexthop_group_private.h"
+#include "frr_pthread.h"
 
 #include "zebra/zebra_router.h"
 #include "zebra/connected.h"
@@ -3204,12 +3205,10 @@ static int rib_process_dplane_results(struct thread *thread)
                TAILQ_INIT(&ctxlist);
 
                /* Take lock controlling queue of results */
-               pthread_mutex_lock(&dplane_mutex);
-               {
+               frr_with_mutex(&dplane_mutex) {
                        /* Dequeue list of context structs */
                        dplane_ctx_list_append(&ctxlist, &rib_dplane_q);
                }
-               pthread_mutex_unlock(&dplane_mutex);
 
                /* Dequeue context block */
                ctx = dplane_ctx_dequeue(&ctxlist);
@@ -3307,12 +3306,10 @@ static int rib_process_dplane_results(struct thread *thread)
 static int rib_dplane_results(struct dplane_ctx_q *ctxlist)
 {
        /* Take lock controlling queue of results */
-       pthread_mutex_lock(&dplane_mutex);
-       {
+       frr_with_mutex(&dplane_mutex) {
                /* Enqueue context blocks */
                dplane_ctx_list_append(&rib_dplane_q, ctxlist);
        }
-       pthread_mutex_unlock(&dplane_mutex);
 
        /* Ensure event is signalled to zebra main pthread */
        thread_add_event(zrouter.master, rib_process_dplane_results, NULL, 0,
index da2fe4a30cd2dbfcbd7664ae39e3770a95a20aa9..666ebb70e82f0bded0413e34417f0052c696e509 100644 (file)
@@ -62,9 +62,6 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
 static void print_rnh(struct route_node *rn, struct vty *vty);
 static int zebra_client_cleanup_rnh(struct zserv *client);
 
-int zebra_rnh_ip_default_route = 0;
-int zebra_rnh_ipv6_default_route = 0;
-
 void zebra_rnh_init(void)
 {
        hook_register(zserv_client_close, zebra_client_cleanup_rnh);
@@ -656,7 +653,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
                 * match route to be exact if so specified
                 */
                if (is_default_prefix(&rn->p)
-                   && !rnh_resolve_via_default(rn->p.family)) {
+                   && !rnh_resolve_via_default(zvrf, rn->p.family)) {
                        if (IS_ZEBRA_DEBUG_NHT_DETAILED)
                                zlog_debug(
                                        "\tNot allowed to resolve through default prefix");
@@ -1213,3 +1210,12 @@ static int zebra_client_cleanup_rnh(struct zserv *client)
 
        return 0;
 }
+
+int rnh_resolve_via_default(struct zebra_vrf *zvrf, int family)
+{
+       if (((family == AF_INET) && zvrf->zebra_rnh_ip_default_route)
+           || ((family == AF_INET6) && zvrf->zebra_rnh_ipv6_default_route))
+               return 1;
+       else
+               return 0;
+}
index c7d2c0d2984a6fa7f26f812810ce0ec7ba5d6e8b..6e2dab8d9ff232da4f22295e10add575838430c2 100644 (file)
 extern "C" {
 #endif
 
-extern int zebra_rnh_ip_default_route;
-extern int zebra_rnh_ipv6_default_route;
-
 extern void zebra_rnh_init(void);
 
-static inline int rnh_resolve_via_default(int family)
-{
-       if (((family == AF_INET) && zebra_rnh_ip_default_route)
-           || ((family == AF_INET6) && zebra_rnh_ipv6_default_route))
-               return 1;
-       else
-               return 0;
-}
-
 static inline const char *rnh_type2str(rnh_type_t type)
 {
        switch (type) {
@@ -72,6 +60,8 @@ extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty,
                                  rnh_type_t type, struct prefix *p);
 extern char *rnh_str(struct rnh *rnh, char *buf, int size);
 
+extern int rnh_resolve_via_default(struct zebra_vrf *zvrf, int family);
+
 #ifdef __cplusplus
 }
 #endif
index cee2c8980fc477107c006f91864c63c5b7161d5b..88d2091394c99dcf74ee0e5a8e7b6c33cdc0b7e9 100644 (file)
@@ -64,7 +64,7 @@ static int zebra_route_match_add(struct vty *vty, const char *command,
                                 const char *arg, route_map_event_t type)
 {
        VTY_DECLVAR_CONTEXT(route_map_index, index);
-       int ret;
+       enum rmap_compile_rets ret;
        int retval = CMD_SUCCESS;
 
        ret = route_map_add_match(index, command, arg, type);
@@ -82,6 +82,11 @@ static int zebra_route_match_add(struct vty *vty, const char *command,
                        route_map_upd8_dependency(type, arg, index->map->name);
                }
                break;
+       case RMAP_DUPLICATE_RULE:
+               /*
+                * Nothing to do here
+                */
+               break;
        }
 
        return retval;
@@ -92,7 +97,7 @@ static int zebra_route_match_delete(struct vty *vty, const char *command,
                                    const char *arg, route_map_event_t type)
 {
        VTY_DECLVAR_CONTEXT(route_map_index, index);
-       int ret;
+       enum rmap_compile_rets ret;
        int retval = CMD_SUCCESS;
        char *dep_name = NULL;
        const char *tmpstr;
@@ -125,6 +130,11 @@ static int zebra_route_match_delete(struct vty *vty, const char *command,
                if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
                        route_map_upd8_dependency(type, dep_name, rmap_name);
                break;
+       case RMAP_DUPLICATE_RULE:
+               /*
+                * Nothing to do here
+                */
+               break;
        }
 
        XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
index fcc94a7be906827bbd0392f5077c6c66c90a58a0..72d0b6866db800c0dc8f61e10e73cfce7ac3ad53 100644 (file)
@@ -488,6 +488,11 @@ static int vrf_config_write(struct vty *vty)
                if (zvrf_id(zvrf) == VRF_DEFAULT) {
                        if (zvrf->l3vni)
                                vty_out(vty, "vni %u\n", zvrf->l3vni);
+                       if (zvrf->zebra_rnh_ip_default_route)
+                               vty_out(vty, "ip nht resolve-via-default\n");
+
+                       if (zvrf->zebra_rnh_ipv6_default_route)
+                               vty_out(vty, "ipv6 nht resolve-via-default\n");
                } else {
                        vty_frame(vty, "vrf %s\n", zvrf_name(zvrf));
                        if (zvrf->l3vni)
@@ -497,8 +502,14 @@ static int vrf_config_write(struct vty *vty)
                                                ? " prefix-routes-only"
                                                : "");
                        zebra_ns_config_write(vty, (struct ns *)vrf->ns_ctxt);
+                       if (zvrf->zebra_rnh_ip_default_route)
+                               vty_out(vty, " ip nht resolve-via-default\n");
+
+                       if (zvrf->zebra_rnh_ipv6_default_route)
+                               vty_out(vty, " ipv6 nht resolve-via-default\n");
                }
 
+
                zebra_routemap_config_write_protocol(vty, zvrf);
 
                if (zvrf_id(zvrf) != VRF_DEFAULT)
index f92e1a010b01f8c53183503d4d0ba441f808c9e9..6c80f9bcb449ac502da809a91cda1bc7326c3601 100644 (file)
@@ -174,6 +174,9 @@ struct zebra_vrf {
 #if defined(HAVE_RTADV)
        struct rtadv rtadv;
 #endif /* HAVE_RTADV */
+
+       int zebra_rnh_ip_default_route;
+       int zebra_rnh_ipv6_default_route;
 };
 #define PROTO_RM_NAME(zvrf, afi, rtype) zvrf->proto_rm[afi][rtype].name
 #define NHT_RM_NAME(zvrf, afi, rtype) zvrf->nht_rm[afi][rtype].name
index 5c0dc2738019f3a2754cb58455dd4bcf07714680..38de01e228926561e58469c4b7d89f78085fc401 100644 (file)
@@ -455,6 +455,10 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                                    re->status);
                json_object_int_add(json_route, "internalFlags",
                                    re->flags);
+               json_object_int_add(json_route, "internalNextHopNum",
+                                   re->nexthop_num);
+               json_object_int_add(json_route, "internalNextHopActiveNum",
+                                   re->nexthop_active_num);
                if (uptime < ONE_DAY_SECOND)
                        sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
                                tm->tm_sec);
@@ -1086,10 +1090,10 @@ DEFUN (ip_nht_default_route,
        if (!zvrf)
                return CMD_WARNING;
 
-       if (zebra_rnh_ip_default_route)
+       if (zvrf->zebra_rnh_ip_default_route)
                return CMD_SUCCESS;
 
-       zebra_rnh_ip_default_route = 1;
+       zvrf->zebra_rnh_ip_default_route = 1;
 
        zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL);
        return CMD_SUCCESS;
@@ -1108,10 +1112,10 @@ DEFUN (no_ip_nht_default_route,
        if (!zvrf)
                return CMD_WARNING;
 
-       if (!zebra_rnh_ip_default_route)
+       if (!zvrf->zebra_rnh_ip_default_route)
                return CMD_SUCCESS;
 
-       zebra_rnh_ip_default_route = 0;
+       zvrf->zebra_rnh_ip_default_route = 0;
        zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL);
        return CMD_SUCCESS;
 }
@@ -1128,10 +1132,10 @@ DEFUN (ipv6_nht_default_route,
        if (!zvrf)
                return CMD_WARNING;
 
-       if (zebra_rnh_ipv6_default_route)
+       if (zvrf->zebra_rnh_ipv6_default_route)
                return CMD_SUCCESS;
 
-       zebra_rnh_ipv6_default_route = 1;
+       zvrf->zebra_rnh_ipv6_default_route = 1;
        zebra_evaluate_rnh(zvrf, AFI_IP6, 1, RNH_NEXTHOP_TYPE, NULL);
        return CMD_SUCCESS;
 }
@@ -1150,10 +1154,10 @@ DEFUN (no_ipv6_nht_default_route,
        if (!zvrf)
                return CMD_WARNING;
 
-       if (!zebra_rnh_ipv6_default_route)
+       if (!zvrf->zebra_rnh_ipv6_default_route)
                return CMD_SUCCESS;
 
-       zebra_rnh_ipv6_default_route = 0;
+       zvrf->zebra_rnh_ipv6_default_route = 0;
        zebra_evaluate_rnh(zvrf, AFI_IP6, 1, RNH_NEXTHOP_TYPE, NULL);
        return CMD_SUCCESS;
 }
@@ -2625,12 +2629,6 @@ static int config_write_protocol(struct vty *vty)
        if (allow_delete)
                vty_out(vty, "allow-external-route-update\n");
 
-       if (zebra_rnh_ip_default_route)
-               vty_out(vty, "ip nht resolve-via-default\n");
-
-       if (zebra_rnh_ipv6_default_route)
-               vty_out(vty, "ipv6 nht resolve-via-default\n");
-
        if (zrouter.ribq->spec.hold != ZEBRA_RIB_PROCESS_HOLD_TIME)
                vty_out(vty, "zebra work-queue %u\n", zrouter.ribq->spec.hold);
 
index 70b4594813ecfd7b6ccefc480f4eeae4a3aa3b8b..c008441d6abad57c7d782e1438c2ca5149cac1d9 100644 (file)
@@ -231,13 +231,11 @@ static int zserv_write(struct thread *thread)
 
        cache = stream_fifo_new();
 
-       pthread_mutex_lock(&client->obuf_mtx);
-       {
+       frr_with_mutex(&client->obuf_mtx) {
                while (stream_fifo_head(client->obuf_fifo))
                        stream_fifo_push(cache,
                                         stream_fifo_pop(client->obuf_fifo));
        }
-       pthread_mutex_unlock(&client->obuf_mtx);
 
        if (cache->tail) {
                msg = cache->tail;
@@ -427,13 +425,11 @@ static int zserv_read(struct thread *thread)
                                      memory_order_relaxed);
 
                /* publish read packets on client's input queue */
-               pthread_mutex_lock(&client->ibuf_mtx);
-               {
+               frr_with_mutex(&client->ibuf_mtx) {
                        while (cache->head)
                                stream_fifo_push(client->ibuf_fifo,
                                                 stream_fifo_pop(cache));
                }
-               pthread_mutex_unlock(&client->ibuf_mtx);
 
                /* Schedule job to process those packets */
                zserv_event(client, ZSERV_PROCESS_MESSAGES);
@@ -499,8 +495,7 @@ static int zserv_process_messages(struct thread *thread)
        uint32_t p2p = zrouter.packets_to_process;
        bool need_resched = false;
 
-       pthread_mutex_lock(&client->ibuf_mtx);
-       {
+       frr_with_mutex(&client->ibuf_mtx) {
                uint32_t i;
                for (i = 0; i < p2p && stream_fifo_head(client->ibuf_fifo);
                     ++i) {
@@ -516,7 +511,6 @@ static int zserv_process_messages(struct thread *thread)
                if (stream_fifo_head(client->ibuf_fifo))
                        need_resched = true;
        }
-       pthread_mutex_unlock(&client->ibuf_mtx);
 
        while (stream_fifo_head(cache)) {
                msg = stream_fifo_pop(cache);
@@ -535,11 +529,9 @@ static int zserv_process_messages(struct thread *thread)
 
 int zserv_send_message(struct zserv *client, struct stream *msg)
 {
-       pthread_mutex_lock(&client->obuf_mtx);
-       {
+       frr_with_mutex(&client->obuf_mtx) {
                stream_fifo_push(client->obuf_fifo, msg);
        }
-       pthread_mutex_unlock(&client->obuf_mtx);
 
        zserv_client_event(client, ZSERV_CLIENT_WRITE);
 
@@ -790,7 +782,7 @@ void zserv_start(char *path)
        setsockopt_so_recvbuf(zsock, 1048576);
        setsockopt_so_sendbuf(zsock, 1048576);
 
-       frr_elevate_privs((sa.ss_family != AF_UNIX) ? &zserv_privs : NULL) {
+       frr_with_privs((sa.ss_family != AF_UNIX) ? &zserv_privs : NULL) {
                ret = bind(zsock, (struct sockaddr *)&sa, sa_len);
        }
        if (ret < 0) {