]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge branch 'master' into evpn-session-vrf
authorTuetuopay <tuetuopay@me.com>
Thu, 28 Mar 2019 17:41:38 +0000 (18:41 +0100)
committerGitHub <noreply@github.com>
Thu, 28 Mar 2019 17:41:38 +0000 (18:41 +0100)
242 files changed:
.dockerignore
Makefile.am
alpine/APKBUILD.in
alpine/docker-start [deleted file]
bfdd/bfd.c
bfdd/bfd.h
bfdd/bfd_packet.c
bfdd/bfdd_vty.c
bfdd/config.c
bfdd/ptm_adapter.c
bgpd/bgp_addpath.c
bgpd/bgp_attr.c
bgpd/bgp_evpn.c
bgpd/bgp_evpn.h
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_fsm.c
bgpd/bgp_main.c
bgpd/bgp_mplsvpn.c
bgpd/bgp_mplsvpn.h
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap.c
bgpd/bgp_rpki.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
bgpd/bgpd.c
bgpd/bgpd.h
configure.ac
doc/developer/building-frr-for-centos6.rst
doc/developer/building-frr-for-centos7.rst
doc/developer/building-frr-for-fedora.rst [new file with mode: 0644]
doc/developer/building-frr-for-fedora24.rst [deleted file]
doc/developer/building-frr-for-freebsd10.rst
doc/developer/building-frr-for-freebsd11.rst
doc/developer/building-frr-for-freebsd9.rst
doc/developer/building-frr-for-openwrt.rst
doc/developer/building-frr-for-ubuntu1404.rst
doc/developer/building-frr-for-ubuntu1604.rst
doc/developer/building-frr-for-ubuntu1804.rst
doc/developer/building-libyang.rst
doc/developer/building.rst
doc/developer/conf.py
doc/developer/hooks.rst
doc/developer/include-compile.rst [new file with mode: 0644]
doc/developer/logging.rst
doc/developer/memtypes.rst
doc/developer/ospf-api.rst
doc/developer/ospf-sr.rst
doc/developer/packaging-debian.rst
doc/developer/packaging-redhat.rst [new file with mode: 0644]
doc/developer/packaging.rst
doc/developer/subdir.am
doc/developer/topotests-snippets.rst
doc/developer/topotests.rst
doc/developer/vtysh.rst
doc/developer/workflow.rst
doc/manpages/conf.py
doc/manpages/defines.rst
doc/user/basic.rst
doc/user/bgp.rst
doc/user/flowspec.rst
doc/user/installation.rst
doc/user/ospfd.rst
doc/user/pbr.rst
doc/user/pim.rst
doc/user/sharp.rst
doc/user/zebra.rst
docker/alpine/Dockerfile
docker/alpine/alpine-build.sh [deleted file]
docker/alpine/build.sh
docker/alpine/builder [deleted file]
docker/alpine/docker-start [new file with mode: 0755]
eigrpd/eigrp_fsm.c
isisd/isis_pdu.c
isisd/isis_zebra.c
lib/if.c
lib/log.c
lib/nexthop_group.c
lib/nexthop_group.h
lib/northbound.c
lib/privs.c
lib/vrf.c
lib/vrf.h
lib/zclient.c
ospf6d/ospf6_area.c
ospf6d/ospf6_asbr.c
ospf6d/ospf6_spf.c
ospf6d/ospf6_zebra.c
ospfd/ospf_api.c
ospfd/ospf_apiserver.c
ospfd/ospf_packet.c
ospfd/ospf_ri.c
ospfd/ospf_snmp.c
ospfd/ospf_spf.c
ospfd/ospf_sr.c
ospfd/ospf_vty.c
pbrd/pbr_nht.c
pbrd/pbr_nht.h
pbrd/pbr_vty.c
pbrd/pbr_zebra.c
pimd/pim_cmd.c
pimd/pim_igmp_mtrace.c
pimd/pim_join.c
pimd/pim_jp_agg.c
pimd/pim_mroute.c
pimd/pim_nht.c
pimd/pim_nht.h
pimd/pim_oil.c
pimd/pim_oil.h
pimd/pim_register.c
pimd/pim_rp.c
pimd/pim_rp.h
pimd/pim_rpf.c
pimd/pim_rpf.h
pimd/pim_upstream.c
pimd/pim_upstream.h
pimd/pim_zebra.c
pimd/pimd.c
redhat/README.rpm_build.md [deleted file]
redhat/daemons [deleted file]
redhat/frr.init [deleted file]
redhat/frr.service [deleted file]
redhat/frr.spec.in
ripd/rip_cli.c
ripngd/ripng_interface.c
ripngd/ripng_zebra.c
sharpd/sharp_globals.h
sharpd/sharp_vty.c
sharpd/sharp_zebra.c
sharpd/sharp_zebra.h
tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref
tests/topotests/bfd-topo2/__init__.py [new file with mode: 0644]
tests/topotests/bfd-topo2/r1/bfdd.conf [new file with mode: 0644]
tests/topotests/bfd-topo2/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bfd-topo2/r1/ipv4_routes.json [new file with mode: 0644]
tests/topotests/bfd-topo2/r1/ipv6_routes.json [new file with mode: 0644]
tests/topotests/bfd-topo2/r1/peers.json [new file with mode: 0644]
tests/topotests/bfd-topo2/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-topo2/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bfd-topo2/r2/ipv4_routes.json [new file with mode: 0644]
tests/topotests/bfd-topo2/r2/ipv6_routes.json [new file with mode: 0644]
tests/topotests/bfd-topo2/r2/ospf6d.conf [new file with mode: 0644]
tests/topotests/bfd-topo2/r2/ospfd.conf [new file with mode: 0644]
tests/topotests/bfd-topo2/r2/peers.json [new file with mode: 0644]
tests/topotests/bfd-topo2/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-topo2/r3/ipv4_routes.json [new file with mode: 0644]
tests/topotests/bfd-topo2/r3/ipv6_routes.json [new file with mode: 0644]
tests/topotests/bfd-topo2/r3/ospfd.conf [new file with mode: 0644]
tests/topotests/bfd-topo2/r3/peers.json [new file with mode: 0644]
tests/topotests/bfd-topo2/r3/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-topo2/r4/bfdd.conf [new file with mode: 0644]
tests/topotests/bfd-topo2/r4/ipv4_routes.json [new file with mode: 0644]
tests/topotests/bfd-topo2/r4/ipv6_routes.json [new file with mode: 0644]
tests/topotests/bfd-topo2/r4/ospf6d.conf [new file with mode: 0644]
tests/topotests/bfd-topo2/r4/peers.json [new file with mode: 0644]
tests/topotests/bfd-topo2/r4/zebra.conf [new file with mode: 0644]
tests/topotests/bfd-topo2/test_bfd_topo2.dot [new file with mode: 0644]
tests/topotests/bfd-topo2/test_bfd_topo2.jpg [new file with mode: 0644]
tests/topotests/bfd-topo2/test_bfd_topo2.py [new file with mode: 0644]
tests/topotests/docker/build.sh
tests/topotests/docker/frr-topotests.sh
tests/topotests/ldp-vpls-topo1/r1/zebra.conf
tests/topotests/ldp-vpls-topo1/r2/zebra.conf
tests/topotests/ldp-vpls-topo1/r3/zebra.conf
tests/topotests/lib/topogen.py
tests/topotests/lib/topotest.py
tests/topotests/pim-basic/mcast-rx.py [new file with mode: 0755]
tests/topotests/pim-basic/mcast-tx.py [new file with mode: 0755]
tests/topotests/pim-basic/r1/pimd.conf [new file with mode: 0644]
tests/topotests/pim-basic/r1/zebra.conf [new file with mode: 0644]
tests/topotests/pim-basic/r2/pimd.conf [new file with mode: 0644]
tests/topotests/pim-basic/r2/zebra.conf [new file with mode: 0644]
tests/topotests/pim-basic/test_pim.py [new file with mode: 0644]
tools/etc/frr/daemons
tools/etc/frr/support_bundle_commands.conf [new file with mode: 0644]
tools/frr.in
tools/frrcommon.sh.in
tools/generate_support_bundle.py [new file with mode: 0644]
zebra/connected.c
zebra/connected.h
zebra/debug.c
zebra/debug.h
zebra/if_netlink.h
zebra/interface.h
zebra/ioctl.h
zebra/ioctl_solaris.h
zebra/ipforward.h
zebra/irdp.h
zebra/irdp_main.c
zebra/irdp_packet.c
zebra/kernel_netlink.c
zebra/kernel_netlink.h
zebra/kernel_socket.c
zebra/kernel_socket.h
zebra/label_manager.h
zebra/main.c
zebra/redistribute.h
zebra/rib.h
zebra/router-id.h
zebra/rt.h
zebra/rt_netlink.c
zebra/rt_netlink.h
zebra/rt_socket.c
zebra/rtadv.h
zebra/rule_netlink.h
zebra/table_manager.h
zebra/zapi_msg.c
zebra/zapi_msg.h
zebra/zebra_dplane.c
zebra/zebra_dplane.h
zebra/zebra_errors.h
zebra/zebra_fpm_private.h
zebra/zebra_l2.h
zebra/zebra_memory.h
zebra/zebra_mlag.h
zebra/zebra_mpls.h
zebra/zebra_mpls_openbsd.c
zebra/zebra_mroute.h
zebra/zebra_netns_id.h
zebra/zebra_netns_notify.h
zebra/zebra_ns.h
zebra/zebra_pbr.h
zebra/zebra_ptm.c
zebra/zebra_ptm.h
zebra/zebra_ptm_redistribute.h
zebra/zebra_pw.h
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zebra_routemap.h
zebra/zebra_router.c
zebra/zebra_router.h
zebra/zebra_vrf.c
zebra/zebra_vrf.h
zebra/zebra_vty.c
zebra/zebra_vxlan.c
zebra/zebra_vxlan.h
zebra/zebra_vxlan_private.h
zebra/zserv.c
zebra/zserv.h

index f2fc34583d3e482edd93929b2d7864e41fec56cd..d613e18dfc0ae1e810854a5396fccab3b5c08aa0 100644 (file)
@@ -5,3 +5,4 @@
 **/*.lo
 **/*.so
 **/.libs
+docker/alpine/pkgs
index 6e3c2a418169a502119ef95d7b94e9a70cfe5c17..2618029a4bfdc6d674785ea24cfd2d92bc03fffc 100644 (file)
@@ -175,13 +175,9 @@ EXTRA_DIST += \
        python/clidef.py \
        python/clippy/__init__.py \
        \
-       redhat/frr.init \
-       redhat/frr.service \
-       redhat/daemons \
        redhat/frr.logrotate \
        redhat/frr.pam \
        redhat/frr.spec \
-       redhat/README.rpm_build.md \
        \
        snapcraft/snapcraft.yaml \
        snapcraft/README.snap_build.md \
index 969b85f5240d52c6e14146a346dbed8ed7f6e184..0f56a427dd772990795911734ef1d891c6e13ea5 100644 (file)
@@ -9,13 +9,13 @@ license="GPL-2.0"
 depends="json-c c-ares ipsec-tools iproute2 python py-ipaddr bash"
 makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
     acct autoconf automake bash
-    binutils binutils-libs bison bsd-compat-headers build-base
+    binutils bison bsd-compat-headers build-base
     c-ares c-ares-dev ca-certificates cryptsetup-libs curl
     device-mapper-libs expat fakeroot flex fortify-headers gdbm
     git gmp isl json-c-dev kmod lddtree libacl libatomic libattr
     libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc
     libgomp libisoburn libisofs libltdl libressl libssh2
-    libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1
+    libstdc++ libtool libuuid libyang-dev linux-headers lzip lzo m4 make mkinitfs mpc1
     mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base
     patch pax-utils pcre perl pkgconf python2 python2-dev readline
     readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs
@@ -23,7 +23,7 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
 checkdepends="pytest py-setuptools"
 install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
 subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
-source="$pkgname-$pkgver.tar.gz docker-start daemons"
+source="$pkgname-$pkgver.tar.gz"
 
 builddir="$srcdir"/$pkgname-$pkgver
 
@@ -60,8 +60,7 @@ package() {
        cd "$builddir"
        make DESTDIR="$pkgdir" install
 
-       install -Dm755 "$srcdir"/docker-start "$pkgdir"$_sbindir
-       install -Dm644 "$srcdir"/daemons "$pkgdir"$_sysconfdir
+       install -Dm644 "$builddir"/tools/etc/frr/daemons "$pkgdir"$_sysconfdir
        install -d "$pkgdir"/etc/init.d
        ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr
 }
diff --git a/alpine/docker-start b/alpine/docker-start
deleted file mode 100755 (executable)
index 43854ab..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-
-set -e
-
-##
-# For volume mounts...
-##
-chown -R frr:frr /etc/frr
-/etc/init.d/frr start
-exec sleep 10000d
index be6f2caa44862aa0d365518d158e85125d0ca5bb..3575ba7a008c9d5cb0af319f771bcf0d96e8cb15 100644 (file)
@@ -36,7 +36,9 @@ DEFINE_QOBJ_TYPE(bfd_session);
 /*
  * Prototypes
  */
-static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc);
+void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
+                struct sockaddr_any *local, bool mhop, const char *ifname,
+                const char *vrfname);
 
 static uint32_t ptm_bfd_gen_ID(void);
 static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd);
@@ -52,66 +54,47 @@ static void bs_down_handler(struct bfd_session *bs, int nstate);
 static void bs_init_handler(struct bfd_session *bs, int nstate);
 static void bs_up_handler(struct bfd_session *bs, int nstate);
 
+/* Zeroed array with the size of an IPv6 address. */
+struct in6_addr zero_addr;
 
 /*
  * Functions
  */
-static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc)
+void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
+                struct sockaddr_any *local, bool mhop, const char *ifname,
+                const char *vrfname)
 {
-       struct bfd_session_observer *bso;
-       struct bfd_session *bs = NULL;
-       bool is_shop, is_ipv4;
-
-       TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
-               bs = bso->bso_bs;
-
-               is_shop = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
-               is_ipv4 = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6);
-               /* Quick checks first. */
-               if (is_shop != (!bpc->bpc_mhop))
-                       continue;
-               if (is_ipv4 != bpc->bpc_ipv4)
-                       continue;
-
-               /*
-                * Slow lookup without hash because we don't have all
-                * information yet.
-                */
-               if (is_shop) {
-                       if (strcmp(bs->ifname, bpc->bpc_localif))
-                               continue;
-                       if (memcmp(&bs->shop.peer, &bpc->bpc_peer,
-                                  sizeof(bs->shop.peer)))
-                               continue;
-
-                       break;
-               }
-
-               if (strcmp(bs->vrfname, bpc->bpc_vrfname))
-                       continue;
-               if (memcmp(&bs->mhop.peer, &bpc->bpc_peer,
-                          sizeof(bs->mhop.peer)))
-                       continue;
-               if (memcmp(&bs->mhop.local, &bpc->bpc_local,
-                          sizeof(bs->mhop.local)))
-                       continue;
+       memset(key, 0, sizeof(*key));
 
+       switch (peer->sa_sin.sin_family) {
+       case AF_INET:
+               key->family = AF_INET;
+               memcpy(&key->peer, &peer->sa_sin.sin_addr,
+                      sizeof(peer->sa_sin.sin_addr));
+               memcpy(&key->local, &local->sa_sin.sin_addr,
+                      sizeof(local->sa_sin.sin_addr));
+               break;
+       case AF_INET6:
+               key->family = AF_INET6;
+               memcpy(&key->peer, &peer->sa_sin6.sin6_addr,
+                      sizeof(peer->sa_sin6.sin6_addr));
+               memcpy(&key->local, &local->sa_sin6.sin6_addr,
+                      sizeof(local->sa_sin6.sin6_addr));
                break;
        }
-       if (bso == NULL)
-               bs = NULL;
 
-       return bs;
+       key->mhop = mhop;
+       if (ifname && ifname[0])
+               strlcpy(key->ifname, ifname, sizeof(key->ifname));
+       if (vrfname && vrfname[0])
+               strlcpy(key->vrfname, vrfname, sizeof(key->vrfname));
 }
 
 struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
 {
        struct bfd_session *bs;
        struct peer_label *pl;
-       struct interface *ifp;
-       struct vrf *vrf;
-       struct bfd_mhop_key mhop;
-       struct bfd_shop_key shop;
+       struct bfd_key key;
 
        /* Try to find label first. */
        if (bpc->bpc_has_label) {
@@ -123,38 +106,10 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
        }
 
        /* Otherwise fallback to peer/local hash lookup. */
-       if (bpc->bpc_mhop) {
-               memset(&mhop, 0, sizeof(mhop));
-               mhop.peer = bpc->bpc_peer;
-               mhop.local = bpc->bpc_local;
-               if (bpc->bpc_has_vrfname) {
-                       vrf = vrf_lookup_by_name(bpc->bpc_vrfname);
-                       if (vrf == NULL)
-                               return NULL;
-
-                       mhop.vrfid = vrf->vrf_id;
-               }
+       gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop,
+                   bpc->bpc_localif, bpc->bpc_vrfname);
 
-               bs = bfd_mhop_lookup(mhop);
-       } else {
-               memset(&shop, 0, sizeof(shop));
-               shop.peer = bpc->bpc_peer;
-               if (bpc->bpc_has_localif) {
-                       ifp = if_lookup_by_name_all_vrf(bpc->bpc_localif);
-                       if (ifp == NULL)
-                               return NULL;
-
-                       shop.ifindex = ifp->ifindex;
-               }
-
-               bs = bfd_shop_lookup(shop);
-       }
-
-       if (bs != NULL)
-               return bs;
-
-       /* Search for entries that are incomplete. */
-       return bs_peer_waiting_find(bpc);
+       return bfd_key_lookup(key);
 }
 
 /*
@@ -165,7 +120,6 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
  */
 int bfd_session_enable(struct bfd_session *bs)
 {
-       struct sockaddr_in6 *sin6;
        struct interface *ifp = NULL;
        struct vrf *vrf = NULL;
        int psock;
@@ -174,8 +128,8 @@ int bfd_session_enable(struct bfd_session *bs)
         * If the interface or VRF doesn't exist, then we must register
         * the session but delay its start.
         */
-       if (bs->ifname[0] != 0) {
-               ifp = if_lookup_by_name_all_vrf(bs->ifname);
+       if (bs->key.ifname[0]) {
+               ifp = if_lookup_by_name_all_vrf(bs->key.ifname);
                if (ifp == NULL) {
                        log_error(
                                "session-enable: specified interface doesn't exists.");
@@ -184,15 +138,17 @@ int bfd_session_enable(struct bfd_session *bs)
 
                vrf = vrf_lookup_by_id(ifp->vrf_id);
                if (vrf == NULL) {
-                       log_error("session-enable: specified VRF doesn't exists.");
+                       log_error(
+                               "session-enable: specified VRF doesn't exists.");
                        return 0;
                }
        }
 
-       if (bs->vrfname[0] != 0) {
-               vrf = vrf_lookup_by_name(bs->vrfname);
+       if (bs->key.vrfname[0]) {
+               vrf = vrf_lookup_by_name(bs->key.vrfname);
                if (vrf == NULL) {
-                       log_error("session-enable: specified VRF doesn't exists.");
+                       log_error(
+                               "session-enable: specified VRF doesn't exists.");
                        return 0;
                }
        }
@@ -202,26 +158,15 @@ int bfd_session_enable(struct bfd_session *bs)
        if (bs->vrf == NULL)
                bs->vrf = vrf_lookup_by_id(VRF_DEFAULT);
 
-       if (bs->ifname[0] != 0 &&
-           BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
+       if (bs->key.ifname[0]
+           && BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
                bs->ifp = ifp;
 
-       /* Set the IPv6 scope id for link-local addresses. */
-       if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
-               sin6 = &bs->mhop.peer.sa_sin6;
-               if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
-                       sin6->sin6_scope_id = bs->ifp != NULL
-                                                     ? bs->ifp->ifindex
-                                                     : IFINDEX_INTERNAL;
-
-               sin6 = &bs->mhop.local.sa_sin6;
-               if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
-                       sin6->sin6_scope_id = bs->ifp != NULL
-                                                     ? bs->ifp->ifindex
-                                                     : IFINDEX_INTERNAL;
-
-               bs->local_ip.sa_sin6 = *sin6;
-               bs->local_address.sa_sin6 = *sin6;
+       /* Sanity check: don't leak open sockets. */
+       if (bs->sock != -1) {
+               zlog_debug("session-enable: previous socket open");
+               close(bs->sock);
+               bs->sock = -1;
        }
 
        /*
@@ -232,11 +177,11 @@ int bfd_session_enable(struct bfd_session *bs)
        if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) {
                psock = bp_peer_socket(bs);
                if (psock == -1)
-                       return -1;
+                       return 0;
        } else {
                psock = bp_peer_socketv6(bs);
                if (psock == -1)
-                       return -1;
+                       return 0;
        }
 
        /*
@@ -247,25 +192,6 @@ int bfd_session_enable(struct bfd_session *bs)
        bfd_recvtimer_update(bs);
        ptm_bfd_start_xmt_timer(bs, false);
 
-       /* Registrate session into data structures. */
-       bs->discrs.my_discr = ptm_bfd_gen_ID();
-       bfd_id_insert(bs);
-       if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
-               if (vrf != NULL)
-                       bs->mhop.vrfid = vrf->vrf_id;
-               else
-                       bs->mhop.vrfid = VRF_DEFAULT;
-
-               bfd_mhop_insert(bs);
-       } else {
-               if (ifp != NULL)
-                       bs->shop.ifindex = ifp->ifindex;
-               else
-                       bs->shop.ifindex = IFINDEX_INTERNAL;
-
-               bfd_shop_insert(bs);
-       }
-
        return 0;
 }
 
@@ -288,13 +214,6 @@ void bfd_session_disable(struct bfd_session *bs)
        bfd_echo_recvtimer_delete(bs);
        bfd_xmttimer_delete(bs);
        bfd_echo_xmttimer_delete(bs);
-
-       /* Unregister session from hashes to avoid unwanted activation. */
-       bfd_id_delete(bs->discrs.my_discr);
-       if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
-               bfd_mhop_delete(bs->mhop);
-       else
-               bfd_shop_delete(bs->shop);
 }
 
 static uint32_t ptm_bfd_gen_ID(void)
@@ -438,21 +357,20 @@ static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
        if (bs == NULL)
                return NULL;
 
-       /* Remove unused fields. */
-       switch (sa->sa_sin.sin_family) {
+       switch (bs->key.family) {
        case AF_INET:
-               sa->sa_sin.sin_port = 0;
-               if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin)) == 0)
-                       return bs;
+               if (memcmp(&sa->sa_sin.sin_addr, &bs->key.peer,
+                          sizeof(sa->sa_sin.sin_addr)))
+                       return NULL;
                break;
        case AF_INET6:
-               sa->sa_sin6.sin6_port = 0;
-               if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin6)) == 0)
-                       return bs;
+               if (memcmp(&sa->sa_sin6.sin6_addr, &bs->key.peer,
+                          sizeof(sa->sa_sin6.sin6_addr)))
+                       return NULL;
                break;
        }
 
-       return NULL;
+       return bs;
 }
 
 struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
@@ -461,32 +379,30 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
                                      ifindex_t ifindex, vrf_id_t vrfid,
                                      bool is_mhop)
 {
-       struct bfd_session *l_bfd = NULL;
-       struct bfd_mhop_key mhop;
-       struct bfd_shop_key shop;
+       struct interface *ifp;
+       struct vrf *vrf;
+       struct bfd_key key;
 
        /* Find our session using the ID signaled by the remote end. */
        if (cp->discrs.remote_discr)
                return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr));
 
        /* Search for session without using discriminator. */
-       if (is_mhop) {
-               memset(&mhop, 0, sizeof(mhop));
-               mhop.peer = *peer;
-               mhop.local = *local;
-               mhop.vrfid = vrfid;
-
-               l_bfd = bfd_mhop_lookup(mhop);
-       } else {
-               memset(&shop, 0, sizeof(shop));
-               shop.peer = *peer;
-               shop.ifindex = ifindex;
+       ifp = if_lookup_by_index(ifindex, vrfid);
+       if (vrfid == VRF_DEFAULT) {
+               /*
+                * Don't use the default vrf, otherwise we won't find
+                * sessions that doesn't specify it.
+                */
+               vrf = NULL;
+       } else
+               vrf = vrf_lookup_by_id(vrfid);
 
-               l_bfd = bfd_shop_lookup(shop);
-       }
+       gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL,
+                   vrf ? vrf->name : NULL);
 
        /* XXX maybe remoteDiscr should be checked for remoteHeard cases. */
-       return l_bfd;
+       return bfd_key_lookup(key);
 }
 
 int bfd_xmt_cb(struct thread *t)
@@ -701,6 +617,9 @@ static void bfd_session_free(struct bfd_session *bs)
 
        bfd_session_disable(bs);
 
+       bfd_key_delete(bs->key);
+       bfd_id_delete(bs->discrs.my_discr);
+
        /* Remove observer if any. */
        TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
                if (bso->bso_bs != bs)
@@ -743,29 +662,47 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
         * start. See `bfd_session_enable` for more information.
         */
        if (bpc->bpc_has_localif)
-               strlcpy(bfd->ifname, bpc->bpc_localif, sizeof(bfd->ifname));
+               strlcpy(bfd->key.ifname, bpc->bpc_localif,
+                       sizeof(bfd->key.ifname));
 
        if (bpc->bpc_has_vrfname)
-               strlcpy(bfd->vrfname, bpc->bpc_vrfname, sizeof(bfd->vrfname));
-
-       /* Add observer if we have moving parts. */
-       if (bfd->ifname[0] || bfd->vrfname[0])
-               bs_observer_add(bfd);
+               strlcpy(bfd->key.vrfname, bpc->bpc_vrfname,
+                       sizeof(bfd->key.vrfname));
 
        /* Copy remaining data. */
        if (bpc->bpc_ipv4 == false)
                BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
 
-       if (bpc->bpc_mhop) {
-               BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH);
-               bfd->mhop.peer = bpc->bpc_peer;
-               bfd->mhop.local = bpc->bpc_local;
-       } else {
-               bfd->shop.peer = bpc->bpc_peer;
+       bfd->key.family = (bpc->bpc_ipv4) ? AF_INET : AF_INET6;
+       switch (bfd->key.family) {
+       case AF_INET:
+               memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin.sin_addr,
+                      sizeof(bpc->bpc_peer.sa_sin.sin_addr));
+               memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin.sin_addr,
+                      sizeof(bpc->bpc_local.sa_sin.sin_addr));
+               break;
+
+       case AF_INET6:
+               memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin6.sin6_addr,
+                      sizeof(bpc->bpc_peer.sa_sin6.sin6_addr));
+               memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin6.sin6_addr,
+                      sizeof(bpc->bpc_local.sa_sin6.sin6_addr));
+               break;
+
+       default:
+               assert(1);
+               break;
        }
 
-       bfd->local_ip = bpc->bpc_local;
-       bfd->local_address = bpc->bpc_local;
+       if (bpc->bpc_mhop)
+               BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH);
+
+       bfd->key.mhop = bpc->bpc_mhop;
+
+       /* Registrate session into data structures. */
+       bfd_key_insert(bfd);
+       bfd->discrs.my_discr = ptm_bfd_gen_ID();
+       bfd_id_insert(bfd);
 
        /* Try to enable session and schedule for packet receive/send. */
        if (bfd_session_enable(bfd) == -1) {
@@ -774,6 +711,10 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
                return NULL;
        }
 
+       /* Add observer if we have moving parts. */
+       if (bfd->key.ifname[0] || bfd->key.vrfname[0] || bfd->sock == -1)
+               bs_observer_add(bfd);
+
        /* Apply other configurations. */
        _bfd_session_update(bfd, bpc);
 
@@ -1219,35 +1160,26 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen)
        snprintf(buf, buflen, "%u second(s)", second);
 }
 
-const char *bs_to_string(struct bfd_session *bs)
+const char *bs_to_string(const struct bfd_session *bs)
 {
        static char buf[256];
+       char addr_buf[INET6_ADDRSTRLEN];
        int pos;
        bool is_mhop = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
 
        pos = snprintf(buf, sizeof(buf), "mhop:%s", is_mhop ? "yes" : "no");
-       if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
-               pos += snprintf(buf + pos, sizeof(buf) - pos,
-                               " peer:%s local:%s", satostr(&bs->mhop.peer),
-                               satostr(&bs->mhop.local));
-
-               if (bs->mhop.vrfid != VRF_DEFAULT)
-                       snprintf(buf + pos, sizeof(buf) - pos, " vrf:%u",
-                                bs->mhop.vrfid);
-       } else {
-               pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s",
-                               satostr(&bs->shop.peer));
-
-               if (bs->local_address.sa_sin.sin_family)
-                       pos += snprintf(buf + pos, sizeof(buf) - pos,
-                                       " local:%s",
-                                       satostr(&bs->local_address));
-
-               if (bs->shop.ifindex)
-                       snprintf(buf + pos, sizeof(buf) - pos, " ifindex:%u",
-                                bs->shop.ifindex);
-       }
-
+       pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s",
+                       inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
+                                 sizeof(addr_buf)));
+       pos += snprintf(buf + pos, sizeof(buf) - pos, " local:%s",
+                       inet_ntop(bs->key.family, &bs->key.local, addr_buf,
+                                 sizeof(addr_buf)));
+       if (bs->key.vrfname[0])
+               pos += snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s",
+                               bs->key.vrfname);
+       if (bs->key.ifname[0])
+               pos += snprintf(buf + pos, sizeof(buf) - pos, " ifname:%s",
+                               bs->key.ifname);
        return buf;
 }
 
@@ -1255,16 +1187,25 @@ int bs_observer_add(struct bfd_session *bs)
 {
        struct bfd_session_observer *bso;
 
-       bso = XMALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso));
+       bso = XCALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso));
+       bso->bso_isaddress = false;
        bso->bso_bs = bs;
        bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
        if (bso->bso_isinterface)
-               strlcpy(bso->bso_entryname, bs->ifname,
+               strlcpy(bso->bso_entryname, bs->key.ifname,
                        sizeof(bso->bso_entryname));
        else
-               strlcpy(bso->bso_entryname, bs->vrfname,
+               strlcpy(bso->bso_entryname, bs->key.vrfname,
                        sizeof(bso->bso_entryname));
 
+       /* Handle socket binding failures caused by missing local addresses. */
+       if (bs->sock == -1) {
+               bso->bso_isaddress = true;
+               bso->bso_addr.family = bs->key.family;
+               memcpy(&bso->bso_addr.u.prefix, &bs->key.local,
+                      sizeof(bs->key.local));
+       }
+
        TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry);
 
        return 0;
@@ -1276,21 +1217,59 @@ void bs_observer_del(struct bfd_session_observer *bso)
        XFREE(MTYPE_BFDD_SESSION_OBSERVER, bso);
 }
 
+void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
+{
+       memset(bpc, 0, sizeof(*bpc));
+
+       bpc->bpc_ipv4 = (bs->key.family == AF_INET);
+       bpc->bpc_mhop = bs->key.mhop;
+
+       switch (bs->key.family) {
+       case AF_INET:
+               bpc->bpc_peer.sa_sin.sin_family = AF_INET;
+               memcpy(&bpc->bpc_peer.sa_sin.sin_addr, &bs->key.peer,
+                      sizeof(bpc->bpc_peer.sa_sin.sin_addr));
+
+               if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) {
+                       bpc->bpc_local.sa_sin.sin_family = AF_INET6;
+                       memcpy(&bpc->bpc_local.sa_sin.sin_addr, &bs->key.local,
+                              sizeof(bpc->bpc_local.sa_sin.sin_addr));
+               }
+               break;
+
+       case AF_INET6:
+               bpc->bpc_peer.sa_sin.sin_family = AF_INET6;
+               memcpy(&bpc->bpc_peer.sa_sin6.sin6_addr, &bs->key.peer,
+                      sizeof(bpc->bpc_peer.sa_sin6.sin6_addr));
+
+               bpc->bpc_local.sa_sin6.sin6_family = AF_INET6;
+               memcpy(&bpc->bpc_local.sa_sin6.sin6_addr, &bs->key.local,
+                      sizeof(bpc->bpc_local.sa_sin6.sin6_addr));
+               break;
+       }
+
+       if (bs->key.ifname[0]) {
+               bpc->bpc_has_localif = true;
+               strlcpy(bpc->bpc_localif, bs->key.ifname,
+                       sizeof(bpc->bpc_localif));
+       }
+
+       if (bs->key.vrfname[0]) {
+               bpc->bpc_has_vrfname = true;
+               strlcpy(bpc->bpc_vrfname, bs->key.vrfname,
+                       sizeof(bpc->bpc_vrfname));
+       }
+}
+
 
 /*
  * BFD hash data structures to find sessions.
  */
 static struct hash *bfd_id_hash;
-static struct hash *bfd_shop_hash;
-static struct hash *bfd_mhop_hash;
+static struct hash *bfd_key_hash;
 
 static unsigned int bfd_id_hash_do(void *p);
-static unsigned int bfd_shop_hash_do(void *p);
-static unsigned int bfd_mhop_hash_do(void *p);
-
-static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop);
-static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop);
-static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop);
+static unsigned int bfd_key_hash_do(void *p);
 
 static void _bfd_free(struct hash_bucket *hb,
                      void *arg __attribute__((__unused__)));
@@ -1311,73 +1290,20 @@ static bool bfd_id_hash_cmp(const void *n1, const void *n2)
 }
 
 /* BFD hash for single hop. */
-static unsigned int bfd_shop_hash_do(void *p)
-{
-       struct bfd_session *bs = p;
-
-       return jhash(&bs->shop, sizeof(bs->shop), 0);
-}
-
-static bool bfd_shop_hash_cmp(const void *n1, const void *n2)
-{
-       const struct bfd_session *bs1 = n1, *bs2 = n2;
-
-       return memcmp(&bs1->shop, &bs2->shop, sizeof(bs1->shop)) == 0;
-}
-
-/* BFD hash for multi hop. */
-static unsigned int bfd_mhop_hash_do(void *p)
+static unsigned int bfd_key_hash_do(void *p)
 {
        struct bfd_session *bs = p;
 
-       return jhash(&bs->mhop, sizeof(bs->mhop), 0);
+       return jhash(&bs->key, sizeof(bs->key), 0);
 }
 
-static bool bfd_mhop_hash_cmp(const void *n1, const void *n2)
+static bool bfd_key_hash_cmp(const void *n1, const void *n2)
 {
        const struct bfd_session *bs1 = n1, *bs2 = n2;
 
-       return memcmp(&bs1->mhop, &bs2->mhop, sizeof(bs1->mhop)) == 0;
-}
-
-/* Helper functions */
-static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop)
-{
-       bs->shop = *shop;
-
-       /* Remove unused fields. */
-       switch (bs->shop.peer.sa_sin.sin_family) {
-       case AF_INET:
-               bs->shop.peer.sa_sin.sin_port = 0;
-               break;
-       case AF_INET6:
-               bs->shop.peer.sa_sin6.sin6_port = 0;
-               break;
-       }
-}
-
-static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop)
-{
-       _shop_key(bs, shop);
-       bs->shop.ifindex = IFINDEX_INTERNAL;
+       return memcmp(&bs1->key, &bs2->key, sizeof(bs1->key)) == 0;
 }
 
-static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop)
-{
-       bs->mhop = *mhop;
-
-       /* Remove unused fields. */
-       switch (bs->mhop.peer.sa_sin.sin_family) {
-       case AF_INET:
-               bs->mhop.peer.sa_sin.sin_port = 0;
-               bs->mhop.local.sa_sin.sin_port = 0;
-               break;
-       case AF_INET6:
-               bs->mhop.peer.sa_sin6.sin6_port = 0;
-               bs->mhop.local.sa_sin6.sin6_port = 0;
-               break;
-       }
-}
 
 /*
  * Hash public interface / exported functions.
@@ -1393,32 +1319,33 @@ struct bfd_session *bfd_id_lookup(uint32_t id)
        return hash_lookup(bfd_id_hash, &bs);
 }
 
-struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop)
+struct bfd_session *bfd_key_lookup(struct bfd_key key)
 {
        struct bfd_session bs, *bsp;
 
-       _shop_key(&bs, &shop);
+       bs.key = key;
+       bsp = hash_lookup(bfd_key_hash, &bs);
 
-       bsp = hash_lookup(bfd_shop_hash, &bs);
-       if (bsp == NULL && bs.shop.ifindex != 0) {
-               /*
-                * Since the local interface spec is optional, try
-                * searching the key without it as well.
-                */
-               _shop_key2(&bs, &shop);
-               bsp = hash_lookup(bfd_shop_hash, &bs);
+       /* Handle cases where local-address is optional. */
+       if (bsp == NULL && bs.key.family == AF_INET) {
+               memset(&bs.key.local, 0, sizeof(bs.key.local));
+               bsp = hash_lookup(bfd_key_hash, &bs);
        }
 
-       return bsp;
-}
-
-struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop)
-{
-       struct bfd_session bs;
+       /* Handle cases where ifname is optional. */
+       bs.key = key;
+       if (bsp == NULL && bs.key.ifname[0]) {
+               memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
+               bsp = hash_lookup(bfd_key_hash, &bs);
 
-       _mhop_key(&bs, &mhop);
+               /* Handle cases where local-address and ifname are optional. */
+               if (bsp == NULL && bs.key.family == AF_INET) {
+                       memset(&bs.key.local, 0, sizeof(bs.key.local));
+                       bsp = hash_lookup(bfd_key_hash, &bs);
+               }
+       }
 
-       return hash_lookup(bfd_mhop_hash, &bs);
+       return bsp;
 }
 
 /*
@@ -1440,31 +1367,18 @@ struct bfd_session *bfd_id_delete(uint32_t id)
        return hash_release(bfd_id_hash, &bs);
 }
 
-struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop)
+struct bfd_session *bfd_key_delete(struct bfd_key key)
 {
        struct bfd_session bs, *bsp;
 
-       _shop_key(&bs, &shop);
-       bsp = hash_release(bfd_shop_hash, &bs);
-       if (bsp == NULL && shop.ifindex != 0) {
-               /*
-                * Since the local interface spec is optional, try
-                * searching the key without it as well.
-                */
-               _shop_key2(&bs, &shop);
-               bsp = hash_release(bfd_shop_hash, &bs);
+       bs.key = key;
+       bsp = hash_lookup(bfd_key_hash, &bs);
+       if (bsp == NULL && key.ifname[0]) {
+               memset(bs.key.ifname, 0, sizeof(bs.key.ifname));
+               bsp = hash_lookup(bfd_key_hash, &bs);
        }
 
-       return bsp;
-}
-
-struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop)
-{
-       struct bfd_session bs;
-
-       _mhop_key(&bs, &mhop);
-
-       return hash_release(bfd_mhop_hash, &bs);
+       return hash_release(bfd_key_hash, bsp);
 }
 
 /* Iteration functions. */
@@ -1473,14 +1387,9 @@ void bfd_id_iterate(hash_iter_func hif, void *arg)
        hash_iterate(bfd_id_hash, hif, arg);
 }
 
-void bfd_shop_iterate(hash_iter_func hif, void *arg)
-{
-       hash_iterate(bfd_shop_hash, hif, arg);
-}
-
-void bfd_mhop_iterate(hash_iter_func hif, void *arg)
+void bfd_key_iterate(hash_iter_func hif, void *arg)
 {
-       hash_iterate(bfd_mhop_hash, hif, arg);
+       hash_iterate(bfd_key_hash, hif, arg);
 }
 
 /*
@@ -1494,24 +1403,17 @@ bool bfd_id_insert(struct bfd_session *bs)
        return (hash_get(bfd_id_hash, bs, hash_alloc_intern) == bs);
 }
 
-bool bfd_shop_insert(struct bfd_session *bs)
-{
-       return (hash_get(bfd_shop_hash, bs, hash_alloc_intern) == bs);
-}
-
-bool bfd_mhop_insert(struct bfd_session *bs)
+bool bfd_key_insert(struct bfd_session *bs)
 {
-       return (hash_get(bfd_mhop_hash, bs, hash_alloc_intern) == bs);
+       return (hash_get(bfd_key_hash, bs, hash_alloc_intern) == bs);
 }
 
 void bfd_initialize(void)
 {
        bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp,
-                                 "BFD discriminator hash");
-       bfd_shop_hash = hash_create(bfd_shop_hash_do, bfd_shop_hash_cmp,
-                                   "BFD single hop hash");
-       bfd_mhop_hash = hash_create(bfd_mhop_hash_do, bfd_mhop_hash_cmp,
-                                   "BFD multihop hop hash");
+                                 "BFD session discriminator hash");
+       bfd_key_hash = hash_create(bfd_key_hash_do, bfd_key_hash_cmp,
+                                  "BFD session hash");
 }
 
 static void _bfd_free(struct hash_bucket *hb,
@@ -1532,11 +1434,9 @@ void bfd_shutdown(void)
         * assert() here to make sure it really happened.
         */
        bfd_id_iterate(_bfd_free, NULL);
-       assert(bfd_shop_hash->count == 0);
-       assert(bfd_mhop_hash->count == 0);
+       assert(bfd_key_hash->count == 0);
 
        /* Now free the hashes themselves. */
        hash_free(bfd_id_hash);
-       hash_free(bfd_shop_hash);
-       hash_free(bfd_mhop_hash);
+       hash_free(bfd_key_hash);
 }
index 7451ca82a387e4753591c3ec070c039fa696088c..a69ff9a1a7b9a33b7756d6ef6305a125904220d2 100644 (file)
@@ -173,15 +173,13 @@ enum bfd_session_flags {
 #define BFD_CHECK_FLAG(field, flag) (field & flag)
 
 /* BFD session hash keys */
-struct bfd_shop_key {
-       struct sockaddr_any peer;
-       ifindex_t ifindex;
-};
-
-struct bfd_mhop_key {
-       struct sockaddr_any peer;
-       struct sockaddr_any local;
-       vrf_id_t vrfid;
+struct bfd_key {
+       uint16_t family;
+       uint8_t mhop;
+       struct in6_addr peer;
+       struct in6_addr local;
+       char ifname[MAXNAMELEN];
+       char vrfname[MAXNAMELEN];
 };
 
 struct bfd_session_stats {
@@ -227,19 +225,14 @@ struct bfd_session {
        uint8_t polling;
 
        /* This and the localDiscr are the keys to state info */
+       struct bfd_key key;
        struct peer_label *pl;
-       union {
-               struct bfd_shop_key shop;
-               struct bfd_mhop_key mhop;
-       };
-       int sock;
 
        struct sockaddr_any local_address;
-       struct sockaddr_any local_ip;
        struct interface *ifp;
        struct vrf *vrf;
-       char ifname[MAXNAMELEN];
-       char vrfname[MAXNAMELEN];
+
+       int sock;
 
        /* BFD session flags */
        enum bfd_session_flags flags;
@@ -281,7 +274,11 @@ struct bfd_state_str_list {
 struct bfd_session_observer {
        struct bfd_session *bso_bs;
        bool bso_isinterface;
-       char bso_entryname[MAXNAMELEN];
+       bool bso_isaddress;
+       union {
+               char bso_entryname[MAXNAMELEN];
+               struct prefix bso_addr;
+       };
 
        TAILQ_ENTRY(bfd_session_observer) bso_entry;
 };
@@ -531,38 +528,28 @@ const char *satostr(struct sockaddr_any *sa);
 const char *diag2str(uint8_t diag);
 int strtosa(const char *addr, struct sockaddr_any *sa);
 void integer2timestr(uint64_t time, char *buf, size_t buflen);
-const char *bs_to_string(struct bfd_session *bs);
+const char *bs_to_string(const struct bfd_session *bs);
 
 int bs_observer_add(struct bfd_session *bs);
 void bs_observer_del(struct bfd_session_observer *bso);
 
+void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
+
 /* BFD hash data structures interface */
 void bfd_initialize(void);
 void bfd_shutdown(void);
 struct bfd_session *bfd_id_lookup(uint32_t id);
-struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop);
-struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop);
-struct bfd_vrf *bfd_vrf_lookup(int vrf_id);
-struct bfd_iface *bfd_iface_lookup(const char *ifname);
+struct bfd_session *bfd_key_lookup(struct bfd_key key);
 
 struct bfd_session *bfd_id_delete(uint32_t id);
-struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop);
-struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop);
-struct bfd_vrf *bfd_vrf_delete(int vrf_id);
-struct bfd_iface *bfd_iface_delete(const char *ifname);
+struct bfd_session *bfd_key_delete(struct bfd_key key);
 
 bool bfd_id_insert(struct bfd_session *bs);
-bool bfd_shop_insert(struct bfd_session *bs);
-bool bfd_mhop_insert(struct bfd_session *bs);
-bool bfd_vrf_insert(struct bfd_vrf *vrf);
-bool bfd_iface_insert(struct bfd_iface *iface);
+bool bfd_key_insert(struct bfd_session *bs);
 
 typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg);
 void bfd_id_iterate(hash_iter_func hif, void *arg);
-void bfd_shop_iterate(hash_iter_func hif, void *arg);
-void bfd_mhop_iterate(hash_iter_func hif, void *arg);
-void bfd_vrf_iterate(hash_iter_func hif, void *arg);
-void bfd_iface_iterate(hash_iter_func hif, void *arg);
+void bfd_key_iterate(hash_iter_func hif, void *arg);
 
 /* Export callback functions for `event.c`. */
 extern struct thread_master *master;
@@ -572,6 +559,8 @@ int bfd_echo_recvtimer_cb(struct thread *t);
 int bfd_xmt_cb(struct thread *t);
 int bfd_echo_xmt_cb(struct thread *t);
 
+extern struct in6_addr zero_addr;
+
 
 /*
  * bfdd_vty.c
index 8601bd2e4090ef32f79375b3e39b510364da8d53..93677ec85aceeb7709385a07c652682b843d73aa 100644 (file)
@@ -79,7 +79,10 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
        if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
                memset(&sin6, 0, sizeof(sin6));
                sin6.sin6_family = AF_INET6;
-               sin6.sin6_addr = bs->shop.peer.sa_sin6.sin6_addr;
+               memcpy(&sin6.sin6_addr, &bs->key.peer, sizeof(sin6.sin6_addr));
+               if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
+                       sin6.sin6_scope_id = bs->ifp->ifindex;
+
                sin6.sin6_port =
                        (port) ? *port
                               : (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
@@ -92,7 +95,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
        } else {
                memset(&sin, 0, sizeof(sin));
                sin.sin_family = AF_INET;
-               sin.sin_addr = bs->shop.peer.sa_sin.sin_addr;
+               memcpy(&sin.sin_addr, &bs->key.peer, sizeof(sin.sin_addr));
                sin.sin_port =
                        (port) ? *port
                               : (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
@@ -120,7 +123,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data,
 
 void ptm_bfd_echo_snd(struct bfd_session *bfd)
 {
-       struct sockaddr_any *sa;
+       struct sockaddr *sa;
        socklen_t salen;
        int sd;
        struct bfd_echo_pkt bep;
@@ -135,31 +138,36 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
        bep.len = BFD_ECHO_PKT_LEN;
        bep.my_discr = htonl(bfd->discrs.my_discr);
 
-       sa = BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MH) ? &bfd->mhop.peer
-                                                         : &bfd->shop.peer;
        if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
                sd = bglobal.bg_echov6;
-               sin6 = sa->sa_sin6;
+               memset(&sin6, 0, sizeof(sin6));
+               sin6.sin6_family = AF_INET6;
+               memcpy(&sin6.sin6_addr, &bfd->key.peer, sizeof(sin6.sin6_addr));
+               if (bfd->ifp && IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
+                       sin6.sin6_scope_id = bfd->ifp->ifindex;
+
                sin6.sin6_port = htons(BFD_DEF_ECHO_PORT);
 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
                sin6.sin6_len = sizeof(sin6);
 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
 
-               sa = (struct sockaddr_any *)&sin6;
+               sa = (struct sockaddr *)&sin6;
                salen = sizeof(sin6);
        } else {
                sd = bglobal.bg_echo;
-               sin = sa->sa_sin;
+               memset(&sin6, 0, sizeof(sin6));
+               sin.sin_family = AF_INET;
+               memcpy(&sin.sin_addr, &bfd->key.peer, sizeof(sin.sin_addr));
                sin.sin_port = htons(BFD_DEF_ECHO_PORT);
 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
                sin.sin_len = sizeof(sin);
 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
 
-               sa = (struct sockaddr_any *)&sin;
+               sa = (struct sockaddr *)&sin;
                salen = sizeof(sin);
        }
-       if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep),
-                       (struct sockaddr *)sa, salen)
+       if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep), sa,
+                       salen)
            == -1)
                return;
 
@@ -602,8 +610,8 @@ int bfd_recv_cb(struct thread *t)
                                 bfd->mh_ttl, BFD_TTL_VAL);
                        return 0;
                }
-       } else if (bfd->local_ip.sa_sin.sin_family == AF_UNSPEC) {
-               bfd->local_ip = local;
+       } else if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) {
+               bfd->local_address = local;
        }
 
        /*
@@ -917,25 +925,26 @@ int bp_peer_socket(const struct bfd_session *bs)
                return -1;
        }
 
-       if (bs->shop.ifindex != IFINDEX_INTERNAL) {
-               if (bp_bind_dev(sd, bs->ifp->name) != 0) {
+       if (bs->key.ifname[0]) {
+               if (bp_bind_dev(sd, bs->key.ifname) != 0) {
                        close(sd);
                        return -1;
                }
-       } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
-                  bs->mhop.vrfid != VRF_DEFAULT) {
-               if (bp_bind_dev(sd, bs->vrf->name) != 0) {
+       } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
+                  && bs->key.vrfname[0]) {
+               if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
                        close(sd);
                        return -1;
                }
        }
 
        /* Find an available source port in the proper range */
-       sin = bs->local_ip.sa_sin;
+       memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
        sin.sin_len = sizeof(sin);
 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+       memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr));
        if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
                sin.sin_addr.s_addr = INADDR_ANY;
 
@@ -987,20 +996,23 @@ int bp_peer_socketv6(const struct bfd_session *bs)
        }
 
        /* Find an available source port in the proper range */
-       sin6 = bs->local_ip.sa_sin6;
+       memset(&sin6, 0, sizeof(sin6));
        sin6.sin6_family = AF_INET6;
 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
        sin6.sin6_len = sizeof(sin6);
 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+       memcpy(&sin6.sin6_addr, &bs->key.local, sizeof(sin6.sin6_addr));
+       if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
+               sin6.sin6_scope_id = bs->ifp->ifindex;
 
-       if (bs->shop.ifindex != IFINDEX_INTERNAL) {
-               if (bp_bind_dev(sd, bs->ifp->name) != 0) {
+       if (bs->key.ifname[0]) {
+               if (bp_bind_dev(sd, bs->key.ifname) != 0) {
                        close(sd);
                        return -1;
                }
-       } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) &&
-                  bs->mhop.vrfid != VRF_DEFAULT) {
-               if (bp_bind_dev(sd, bs->vrf->name) != 0) {
+       } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)
+                  && bs->key.vrfname[0]) {
+               if (bp_bind_dev(sd, bs->key.vrfname) != 0) {
                        close(sd);
                        return -1;
                }
index c77cd08be8033d514ffdcc43fbd52c173c8a0f36..c13949207642fe1e81673269291b48a957afda2f 100644 (file)
@@ -79,7 +79,6 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv,
                    const char *local_str, const char *ifname,
                    const char *vrfname);
 
-
 /*
  * Commands definition.
  */
@@ -369,22 +368,25 @@ DEFPY(bfd_no_peer, bfd_no_peer_cmd,
  */
 static void _display_peer_header(struct vty *vty, struct bfd_session *bs)
 {
-       if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
-               vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
+       char addr_buf[INET6_ADDRSTRLEN];
+
+       vty_out(vty, "\tpeer %s",
+               inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
+                         sizeof(addr_buf)));
+
+       if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
                vty_out(vty, " multihop");
-               vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
-               if (bs->vrfname[0])
-                       vty_out(vty, " vrf %s", bs->vrfname);
-               vty_out(vty, "\n");
-       } else {
-               vty_out(vty, "\tpeer %s", satostr(&bs->shop.peer));
-               if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
-                       vty_out(vty, " local-address %s",
-                               satostr(&bs->local_address));
-               if (bs->ifname[0])
-                       vty_out(vty, " interface %s", bs->ifname);
-               vty_out(vty, "\n");
-       }
+
+       if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
+               vty_out(vty, " local-address %s",
+                       inet_ntop(bs->key.family, &bs->key.local, addr_buf,
+                                 sizeof(addr_buf)));
+
+       if (bs->key.vrfname[0])
+               vty_out(vty, " vrf %s", bs->key.vrfname);
+       if (bs->key.ifname[0])
+               vty_out(vty, " interface %s", bs->key.ifname);
+       vty_out(vty, "\n");
 
        if (bs->pl)
                vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
@@ -453,22 +455,25 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs)
 static struct json_object *_peer_json_header(struct bfd_session *bs)
 {
        struct json_object *jo = json_object_new_object();
+       char addr_buf[INET6_ADDRSTRLEN];
 
-       if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
+       if (bs->key.mhop)
                json_object_boolean_true_add(jo, "multihop");
-               json_object_string_add(jo, "peer", satostr(&bs->mhop.peer));
-               json_object_string_add(jo, "local", satostr(&bs->mhop.local));
-               if (bs->vrfname[0])
-                       json_object_string_add(jo, "vrf", bs->vrfname);
-       } else {
+       else
                json_object_boolean_false_add(jo, "multihop");
-               json_object_string_add(jo, "peer", satostr(&bs->shop.peer));
-               if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
-                       json_object_string_add(jo, "local",
-                                              satostr(&bs->local_address));
-               if (bs->ifname[0])
-                       json_object_string_add(jo, "interface", bs->ifname);
-       }
+
+       json_object_string_add(jo, "peer",
+                              inet_ntop(bs->key.family, &bs->key.peer,
+                                        addr_buf, sizeof(addr_buf)));
+       if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
+               json_object_string_add(jo, "local",
+                                      inet_ntop(bs->key.family, &bs->key.local,
+                                                addr_buf, sizeof(addr_buf)));
+
+       if (bs->key.vrfname[0])
+               json_object_string_add(jo, "vrf", bs->key.vrfname);
+       if (bs->key.ifname[0])
+               json_object_string_add(jo, "interface", bs->key.ifname);
 
        if (bs->pl)
                json_object_string_add(jo, "label", bs->pl->pl_label);
@@ -916,25 +921,29 @@ static int bfdd_write_config(struct vty *vty)
 
 static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs)
 {
-       if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
-               vty_out(vty, " peer %s", satostr(&bs->mhop.peer));
+       char addr_buf[INET6_ADDRSTRLEN];
+
+       vty_out(vty, " peer %s",
+               inet_ntop(bs->key.family, &bs->key.peer, addr_buf,
+                         sizeof(addr_buf)));
+
+       if (bs->key.mhop)
                vty_out(vty, " multihop");
-               vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
-               if (bs->vrfname[0])
-                       vty_out(vty, " vrf %s", bs->vrfname);
-               vty_out(vty, "\n");
-       } else {
-               vty_out(vty, " peer %s", satostr(&bs->shop.peer));
-               if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
-                       vty_out(vty, " local-address %s",
-                               satostr(&bs->local_address));
-               if (bs->ifname[0])
-                       vty_out(vty, " interface %s", bs->ifname);
-               vty_out(vty, "\n");
-       }
+
+       if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
+               vty_out(vty, " local-address %s",
+                       inet_ntop(bs->key.family, &bs->key.local, addr_buf,
+                                 sizeof(addr_buf)));
+
+       if (bs->key.vrfname[0])
+               vty_out(vty, " vrf %s", bs->key.vrfname);
+       if (bs->key.ifname[0])
+               vty_out(vty, " interface %s", bs->key.ifname);
+       vty_out(vty, "\n");
 
        if (bs->sock == -1)
-               vty_out(vty, "  ! vrf or interface doesn't exist\n");
+               vty_out(vty,
+                       "  ! vrf, interface or local-address doesn't exist\n");
 
        if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
                vty_out(vty, "  detect-multiplier %d\n", bs->detect_mult);
@@ -980,16 +989,7 @@ static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg)
 
 static int bfdd_peer_write_config(struct vty *vty)
 {
-       struct bfd_session_observer *bso;
-
        bfd_id_iterate(_bfdd_peer_write_config_iter, vty);
-       TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
-               /* Only print disabled sessions here. */
-               if (bso->bso_bs->sock != -1)
-                       continue;
-
-               _bfdd_peer_write_config(vty, bso->bso_bs);
-       }
 
        return 1;
 }
index 17e155e41df37208c6b8a846e3fddc7f8e0469f6..cd57ea9fe38b03ecd01aeb7dfe1cf4744b7299d9 100644 (file)
@@ -309,24 +309,7 @@ static int parse_peer_label_config(struct json_object *jo,
        log_debug("\tpeer-label: %s", sval);
 
        /* Translate the label into BFD address keys. */
-       bpc->bpc_ipv4 = !BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_IPV6);
-       bpc->bpc_mhop = BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_MH);
-       if (bpc->bpc_mhop) {
-               bpc->bpc_peer = pl->pl_bs->mhop.peer;
-               bpc->bpc_local = pl->pl_bs->mhop.local;
-               if (pl->pl_bs->mhop.vrfid != VRF_DEFAULT) {
-                       bpc->bpc_has_vrfname = true;
-                       strlcpy(bpc->bpc_vrfname, pl->pl_bs->vrf->name,
-                               sizeof(bpc->bpc_vrfname));
-               }
-       } else {
-               bpc->bpc_peer = pl->pl_bs->shop.peer;
-               if (pl->pl_bs->ifname[0]) {
-                       bpc->bpc_has_localif = true;
-                       strlcpy(bpc->bpc_localif, pl->pl_bs->ifname,
-                               sizeof(bpc->bpc_localif));
-               }
-       }
+       bs_to_bpc(pl->pl_bs, bpc);
 
        return 0;
 }
@@ -519,6 +502,8 @@ int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr,
 
 static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
 {
+       char addr_buf[INET6_ADDRSTRLEN];
+
        /* Add peer 'key' information. */
        if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6))
                json_object_boolean_true_add(jo, "ipv6");
@@ -528,21 +513,26 @@ static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
        if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
                json_object_boolean_true_add(jo, "multihop");
                json_object_string_add(jo, "peer-address",
-                                      satostr(&bs->mhop.peer));
+                                      inet_ntop(bs->key.family, &bs->key.peer,
+                                                addr_buf, sizeof(addr_buf)));
                json_object_string_add(jo, "local-address",
-                                      satostr(&bs->mhop.local));
-               if (bs->vrfname[0])
-                       json_object_string_add(jo, "vrf-name", bs->vrfname);
+                                      inet_ntop(bs->key.family, &bs->key.local,
+                                                addr_buf, sizeof(addr_buf)));
+               if (bs->key.vrfname[0])
+                       json_object_string_add(jo, "vrf-name", bs->key.vrfname);
        } else {
                json_object_boolean_false_add(jo, "multihop");
                json_object_string_add(jo, "peer-address",
-                                      satostr(&bs->shop.peer));
-               if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
-                       json_object_string_add(jo, "local-address",
-                                              satostr(&bs->local_address));
-               if (bs->ifname[0])
+                                      inet_ntop(bs->key.family, &bs->key.peer,
+                                                addr_buf, sizeof(addr_buf)));
+               if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local)))
+                       json_object_string_add(
+                               jo, "local-address",
+                               inet_ntop(bs->key.family, &bs->key.local,
+                                         addr_buf, sizeof(addr_buf)));
+               if (bs->key.ifname[0])
                        json_object_string_add(jo, "local-interface",
-                                              bs->ifname);
+                                              bs->key.ifname);
        }
 
        if (bs->pl)
index 5610c352fb3f1fdebedd7768d9f382eabd5dcfb8..b44d13f132a34b67df5216cccc19b8d3e587a4ab 100644 (file)
@@ -55,7 +55,7 @@ static struct zclient *zclient;
 /*
  * Prototypes
  */
-static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa);
+static int _ptm_msg_address(struct stream *msg, int family, const void *addr);
 
 static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
 static int _ptm_msg_read(struct stream *msg, int command,
@@ -127,24 +127,24 @@ static void debug_printbpc(const char *func, unsigned int line,
 #define DEBUG_PRINTBPC(bpc)
 #endif /* BFD_DEBUG */
 
-static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa)
+static int _ptm_msg_address(struct stream *msg, int family, const void *addr)
 {
-       switch (sa->sa_sin.sin_family) {
+       stream_putc(msg, family);
+
+       switch (family) {
        case AF_INET:
-               stream_putc(msg, sa->sa_sin.sin_family);
-               stream_put_in_addr(msg, &sa->sa_sin.sin_addr);
+               stream_put(msg, addr, sizeof(struct in_addr));
                stream_putc(msg, 32);
                break;
 
        case AF_INET6:
-               stream_putc(msg, sa->sa_sin6.sin6_family);
-               stream_put(msg, &sa->sa_sin6.sin6_addr,
-                          sizeof(sa->sa_sin6.sin6_addr));
+               stream_put(msg, addr, sizeof(struct in6_addr));
                stream_putc(msg, 128);
                break;
 
        default:
-               return -1;
+               assert(0);
+               break;
        }
 
        return 0;
@@ -153,7 +153,6 @@ static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa)
 int ptm_bfd_notify(struct bfd_session *bs)
 {
        struct stream *msg;
-       struct sockaddr_any sac;
 
        bs->stats.znotification++;
 
@@ -195,10 +194,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
                stream_putl(msg, IFINDEX_INTERNAL);
 
        /* BFD destination prefix information. */
-       if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
-               _ptm_msg_address(msg, &bs->mhop.peer);
-       else
-               _ptm_msg_address(msg, &bs->shop.peer);
+       _ptm_msg_address(msg, bs->key.family, &bs->key.peer);
 
        /* BFD status */
        switch (bs->ses_state) {
@@ -218,34 +214,7 @@ int ptm_bfd_notify(struct bfd_session *bs)
        }
 
        /* BFD source prefix information. */
-       if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
-               _ptm_msg_address(msg, &bs->mhop.local);
-       } else {
-               if (bs->local_address.sa_sin.sin_family)
-                       _ptm_msg_address(msg, &bs->local_address);
-               else if (bs->local_address.sa_sin.sin_family)
-                       _ptm_msg_address(msg, &bs->local_ip);
-               else {
-                       sac = bs->shop.peer;
-                       switch (sac.sa_sin.sin_family) {
-                       case AF_INET:
-                               memset(&sac.sa_sin.sin_addr, 0,
-                                      sizeof(sac.sa_sin.sin_family));
-                               break;
-                       case AF_INET6:
-                               memset(&sac.sa_sin6.sin6_addr, 0,
-                                      sizeof(sac.sa_sin6.sin6_family));
-                               break;
-
-                       default:
-                               assert(false);
-                               break;
-                       }
-
-                       /* No local address found yet, so send zeroes. */
-                       _ptm_msg_address(msg, &sac);
-               }
-       }
+       _ptm_msg_address(msg, bs->key.family, &bs->key.local);
 
        /* Write packet size. */
        stream_putw_at(msg, 0, stream_get_endp(msg));
@@ -290,7 +259,6 @@ stream_failure:
 static int _ptm_msg_read(struct stream *msg, int command,
                         struct bfd_peer_cfg *bpc, struct ptm_client **pc)
 {
-       struct interface *ifp;
        uint32_t pid;
        uint8_t ttl __attribute__((unused));
        size_t ifnamelen;
@@ -385,31 +353,6 @@ static int _ptm_msg_read(struct stream *msg, int command,
                if (bpc->bpc_has_localif) {
                        STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
                        bpc->bpc_localif[ifnamelen] = 0;
-
-                       /*
-                        * IPv6 link-local addresses must use scope id,
-                        * otherwise the session lookup will always fail
-                        * and we'll have multiple sessions showing up.
-                        *
-                        * This problem only happens with single hop
-                        * since it is not possible to have link-local
-                        * address for multi hop sessions.
-                        */
-                       if (bpc->bpc_ipv4 == false
-                           && IN6_IS_ADDR_LINKLOCAL(
-                                      &bpc->bpc_peer.sa_sin6.sin6_addr)) {
-                               ifp = if_lookup_by_name_all_vrf(
-                                       bpc->bpc_localif);
-                               if (ifp == NULL) {
-                                       log_error(
-                                               "ptm-read: interface %s doesn't exists",
-                                               bpc->bpc_localif);
-                                       return -1;
-                               }
-
-                               bpc->bpc_peer.sa_sin6.sin6_scope_id =
-                                       ifp->ifindex;
-                       }
                }
        }
 
@@ -608,7 +551,7 @@ static void bfdd_sessions_enable_interface(struct interface *ifp)
 
                /* Interface name mismatch. */
                bs = bso->bso_bs;
-               if (strcmp(ifp->name, bs->ifname))
+               if (strcmp(ifp->name, bs->key.ifname))
                        continue;
                /* Skip enabled sessions. */
                if (bs->sock != -1)
@@ -630,7 +573,7 @@ static void bfdd_sessions_disable_interface(struct interface *ifp)
 
                /* Interface name mismatch. */
                bs = bso->bso_bs;
-               if (strcmp(ifp->name, bs->ifname))
+               if (strcmp(ifp->name, bs->key.ifname))
                        continue;
                /* Skip disabled sessions. */
                if (bs->sock == -1)
@@ -691,6 +634,48 @@ static int bfdd_interface_vrf_update(int command __attribute__((__unused__)),
        return 0;
 }
 
+static void bfdd_sessions_enable_address(struct connected *ifc)
+{
+       struct bfd_session_observer *bso;
+       struct bfd_session *bs;
+       struct prefix prefix;
+
+       TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
+               if (bso->bso_isaddress == false)
+                       continue;
+
+               /* Skip enabled sessions. */
+               bs = bso->bso_bs;
+               if (bs->sock != -1)
+                       continue;
+
+               /* Check address. */
+               prefix = bso->bso_addr;
+               prefix.prefixlen = ifc->address->prefixlen;
+               if (prefix_cmp(&prefix, ifc->address))
+                       continue;
+
+               /* Try to enable it. */
+               bfd_session_enable(bs);
+       }
+}
+
+static int bfdd_interface_address_update(int cmd, struct zclient *zc,
+                                        zebra_size_t len
+                                        __attribute__((__unused__)),
+                                        vrf_id_t vrfid)
+{
+       struct connected *ifc;
+
+       ifc = zebra_interface_address_read(cmd, zc->ibuf, vrfid);
+       if (ifc == NULL)
+               return 0;
+
+       bfdd_sessions_enable_address(ifc);
+
+       return 0;
+}
+
 void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
 {
        zclient = zclient_new(master, &zclient_options_default);
@@ -713,6 +698,10 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
 
        /* Learn about interface VRF. */
        zclient->interface_vrf_update = bfdd_interface_vrf_update;
+
+       /* Learn about new addresses being registered. */
+       zclient->interface_address_add = bfdd_interface_address_update;
+       zclient->interface_address_delete = bfdd_interface_address_update;
 }
 
 void bfdd_zclient_stop(void)
index c7fd1ba0e23e51d7d5707003ba6291102cb3646c..63373cb9a73f5d1e5014711a83daaf86254dee3d 100644 (file)
@@ -384,7 +384,7 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
                }
        }
 
-       zlog_info("Resetting peer %s%s due to change in addpath config\n",
+       zlog_info("Resetting peer %s%s due to change in addpath config",
                  CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) ? "group " : "",
                  peer->host);
 
index 226bf99d2c13eaa2dc5f38d8d2eb6d40f3fb183f..bea46f3e454a4c6b8774c72867071862234bd31e 100644 (file)
@@ -1715,7 +1715,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
                stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
                if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
                        if (!peer->nexthop.ifp) {
-                               zlog_warn("%s: interface not set appropriately to handle some attributes",
+                               zlog_warn("%s: Received a V6/VPNV6 Global attribute but address is a V6 LL and we have no peer interface information, withdrawing",
                                          peer->host);
                                return BGP_ATTR_PARSE_WITHDRAW;
                        }
@@ -1732,7 +1732,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
                stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
                if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
                        if (!peer->nexthop.ifp) {
-                               zlog_warn("%s: interface not set appropriately to handle some attributes",
+                               zlog_warn("%s: Received V6/VPNV6 Global and LL attribute but global address is a V6 LL and we have no peer interface information, withdrawing",
                                          peer->host);
                                return BGP_ATTR_PARSE_WITHDRAW;
                        }
@@ -1762,7 +1762,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
                        attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
                }
                if (!peer->nexthop.ifp) {
-                       zlog_warn("%s: Interface not set appropriately to handle this some attributes",
+                       zlog_warn("%s: Received a V6 LL nexthop and we have no peer interface information, withdrawing",
                                  peer->host);
                        return BGP_ATTR_PARSE_WITHDRAW;
                }
index ca13ee951e550054c28a3d44d77ef1253feeb0ac..732cc6d2bb4c044c1d1ee8c4e789b1145bd3e231 100644 (file)
@@ -48,6 +48,7 @@
 #include "bgpd/bgp_zebra.h"
 #include "bgpd/bgp_nexthop.h"
 #include "bgpd/bgp_addpath.h"
+#include "bgpd/bgp_mac.h"
 
 /*
  * Definitions and external declarations.
@@ -2503,6 +2504,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
        /* Perform route selection and update zebra, if required. */
        bgp_process(bgp_vrf, rn, afi, safi);
 
+       /* Process for route leaking. */
+       vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi);
+
        return ret;
 }
 
@@ -2668,6 +2672,9 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
        if (!pi)
                return 0;
 
+       /* Process for route leaking. */
+       vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi);
+
        bgp_aggregate_decrement(bgp_vrf, &rn->p, pi, afi, safi);
 
        /* Mark entry for deletion */
@@ -2940,6 +2947,41 @@ static int install_uninstall_routes_for_es(struct bgp *bgp,
        return 0;
 }
 
+/* This API will scan evpn routes for checking attribute's rmac
+ * macthes with bgp instance router mac. It avoid installing
+ * route into bgp vrf table and remote rmac in bridge table.
+ */
+static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf,
+                                         struct prefix_evpn *evp,
+                                         struct bgp_path_info *pi)
+{
+       /* evpn route could have learnt prior to L3vni has come up,
+        * perform rmac check before installing route and
+        * remote router mac.
+        * The route will be removed from global bgp table once
+        * SVI comes up with MAC and stored in hash, triggers
+        * bgp_mac_rescan_all_evpn_tables.
+        */
+       if (pi->attr &&
+           memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) {
+               if (bgp_debug_update(pi->peer, NULL, NULL, 1)) {
+                       char buf1[PREFIX_STRLEN];
+                       char attr_str[BUFSIZ] = {0};
+
+                       bgp_dump_attr(pi->attr, attr_str, BUFSIZ);
+
+                       zlog_debug("%s: bgp %u prefix %s with attr %s - DENIED due to self mac",
+                               __func__, bgp_vrf->vrf_id,
+                               prefix2str(evp, buf1, sizeof(buf1)),
+                               attr_str);
+               }
+
+               return 1;
+       }
+
+       return 0;
+}
+
 /*
  * Install or uninstall mac-ip routes are appropriate for this
  * particular VRF.
@@ -2996,6 +3038,10 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
                                        continue;
 
                                if (is_route_matching_for_vrf(bgp_vrf, pi)) {
+                                       if (bgp_evpn_route_rmac_self_check(
+                                                               bgp_vrf, evp, pi))
+                                               continue;
+
                                        if (install)
                                                ret = install_evpn_route_entry_in_vrf(
                                                        bgp_vrf, evp, pi);
@@ -4223,11 +4269,13 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi)
 
        table = bgp_vrf->rib[afi][safi];
        for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
-               /* Only care about "selected" routes - non-imported. */
+               /* Only care about "selected" routes. Also ensure that
+                * these are routes that are injectable into EVPN.
+                */
                /* TODO: Support for AddPath for EVPN. */
                for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
                        if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
-                           && (!pi->extra || !pi->extra->parent)) {
+                           && is_route_injectable_into_evpn(pi)) {
                                bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p,
                                                              afi, safi);
                                break;
@@ -4294,12 +4342,13 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
        table = bgp_vrf->rib[afi][safi];
        for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
                /* Need to identify the "selected" route entry to use its
-                * attribute. Also, we only consider "non-imported" routes.
+                * attribute. Also, ensure that the route is injectable
+                * into EVPN.
                 * TODO: Support for AddPath for EVPN.
                 */
                for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
                        if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
-                           && (!pi->extra || !pi->extra->parent)) {
+                           && is_route_injectable_into_evpn(pi)) {
 
                                /* apply the route-map */
                                if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
@@ -5033,6 +5082,9 @@ void bgp_evpn_derive_auto_rt_export(struct bgp *bgp, struct bgpevpn *vpn)
  */
 void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp)
 {
+       if (is_vrf_rd_configured(bgp))
+               return;
+
        form_auto_rd(bgp->router_id, bgp->vrf_rd_id, &bgp->vrf_prd);
 }
 
index 7f88c1ebf0950267a9cf4ae913d1ed70877c57ea..f5802fa894002162a8d6efde0c21fe6d6bb6ca52 100644 (file)
@@ -89,8 +89,13 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
            !ri->extra->parent)
                return 0;
 
-       /* See if the parent is of family L2VPN/EVPN */
-       parent_ri = (struct bgp_path_info *)ri->extra->parent;
+       /* Determine parent recursively */
+       for (parent_ri = ri->extra->parent;
+            parent_ri->extra && parent_ri->extra->parent;
+            parent_ri = parent_ri->extra->parent)
+               ;
+
+       /* See if of family L2VPN/EVPN */
        rn = parent_ri->net;
        if (!rn)
                return 0;
@@ -102,6 +107,38 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri)
        return 0;
 }
 
+/* Flag if the route path's family is EVPN. */
+static inline bool is_pi_family_evpn(struct bgp_path_info *pi)
+{
+       return is_pi_family_matching(pi, AFI_L2VPN, SAFI_EVPN);
+}
+
+/* Flag if the route is injectable into EVPN. This would be either a
+ * non-imported route or a non-EVPN imported route.
+ */
+static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
+{
+       struct bgp_path_info *parent_pi;
+       struct bgp_table *table;
+       struct bgp_node *rn;
+
+       if (pi->sub_type != BGP_ROUTE_IMPORTED ||
+           !pi->extra ||
+           !pi->extra->parent)
+               return true;
+
+       parent_pi = (struct bgp_path_info *)pi->extra->parent;
+       rn = parent_pi->net;
+       if (!rn)
+               return true;
+       table = bgp_node_table(rn);
+       if (table &&
+           table->afi == AFI_L2VPN &&
+           table->safi == SAFI_EVPN)
+               return false;
+       return true;
+}
+
 extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
                                           struct prefix *p,
                                           struct attr *src_attr, afi_t afi,
index c7f2671b78377ca2e9c4446044f4a9976f52cbd0..785139865e40f0813310a37028c9278aa99f46d9 100644 (file)
@@ -30,8 +30,9 @@
 
 #define RT_ADDRSTRLEN 28
 
-/* EVPN prefix lengths. This reprsent the sizeof struct prefix_evpn  */
-#define EVPN_ROUTE_PREFIXLEN     224
+/* EVPN prefix lengths. This represents the sizeof struct evpn_addr
+ * in bits  */
+#define EVPN_ROUTE_PREFIXLEN (sizeof(struct evpn_addr) * 8)
 
 /* EVPN route types. */
 typedef enum {
index f020483ebbcf052d74c073bae3c916ffdc815492..0454fc2212674acc844c5d6e246a0b6c173df163 100644 (file)
@@ -3369,7 +3369,8 @@ DEFUN (bgp_evpn_advertise_type5,
        }
 
        /* advertise type-5 routes */
-       bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
+       if (advertise_type5_routes(bgp_vrf, afi))
+               bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
        return CMD_SUCCESS;
 }
 
@@ -5222,7 +5223,7 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
                vty_out(vty, "  default-originate ipv6\n");
 
        if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
-               vty_out(vty, "   rd %s\n",
+               vty_out(vty, "  rd %s\n",
                        prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1)));
 
        /* import route-target */
index b70c8bbd631cb88b2cf55b12838185ade095d858..447d8da613722bd17eb00d61694b61707f6c7fb3 100644 (file)
@@ -310,7 +310,8 @@ void bgp_timer_set(struct peer *peer)
                   status start timer is on unless peer is shutdown or peer is
                   inactive.  All other timer must be turned off */
                if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer)
-                   || peer->bgp->vrf_id == VRF_UNKNOWN) {
+                   || (peer->bgp->inst_type != BGP_INSTANCE_TYPE_VIEW &&
+                       peer->bgp->vrf_id == VRF_UNKNOWN)) {
                        BGP_TIMER_OFF(peer->t_start);
                } else {
                        BGP_TIMER_ON(peer->t_start, bgp_start_timer,
@@ -1422,7 +1423,8 @@ int bgp_start(struct peer *peer)
                return 0;
        }
 
-       if (peer->bgp->vrf_id == VRF_UNKNOWN) {
+       if (peer->bgp->inst_type != BGP_INSTANCE_TYPE_VIEW &&
+           peer->bgp->vrf_id == VRF_UNKNOWN) {
                if (bgp_debug_neighbor_events(peer))
                        flog_err(
                                EC_BGP_FSM,
index 697889cc6b03b354b4a86d39f5651feb4a169c7b..e42bc441154b935dd426b5e507c6e8c52995ce43 100644 (file)
@@ -284,9 +284,9 @@ static int bgp_vrf_enable(struct vrf *vrf)
                bgp_vrf_link(bgp, vrf);
 
                bgp_handle_socket(bgp, vrf, old_vrf_id, true);
-               /* Update any redistribute vrf bitmaps if the vrf_id changed */
+               /* Update any redistribution if vrf_id changed */
                if (old_vrf_id != bgp->vrf_id)
-                       bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id);
+                       bgp_redistribute_redo(bgp);
                bgp_instance_up(bgp);
                vpn_leak_zebra_vrf_label_update(bgp, AFI_IP);
                vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6);
@@ -333,9 +333,9 @@ static int bgp_vrf_disable(struct vrf *vrf)
                /* We have instance configured, unlink from VRF and make it
                 * "down". */
                bgp_vrf_unlink(bgp, vrf);
-               /* Update any redistribute vrf bitmaps if the vrf_id changed */
+               /* Delete any redistribute vrf bitmaps if the vrf_id changed */
                if (old_vrf_id != bgp->vrf_id)
-                       bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id);
+                       bgp_unset_redist_vrf_bitmaps(bgp, old_vrf_id);
                bgp_instance_down(bgp);
        }
 
index 765170d1a5f2e222a19541c85593bbfad1734756..d211f1afffdee108a9e944f777cbed5ff04030a5 100644 (file)
@@ -46,6 +46,7 @@
 #include "bgpd/bgp_zebra.h"
 #include "bgpd/bgp_nexthop.h"
 #include "bgpd/bgp_nht.h"
+#include "bgpd/bgp_evpn.h"
 
 #if ENABLE_BGP_VNC
 #include "bgpd/rfapi/rfapi_backend.h"
@@ -552,8 +553,12 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
                if (bpi->extra && bpi->extra->bgp_orig)
                        bgp_nexthop = bpi->extra->bgp_orig;
 
-               /* No nexthop tracking for redistributed routes */
-               if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
+               /*
+                * No nexthop tracking for redistributed routes or for
+                * EVPN-imported routes that get leaked.
+                */
+               if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
+                   is_pi_family_evpn(bpi_ultimate))
                        nh_valid = 1;
                else
                        /*
@@ -614,8 +619,11 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
         * No nexthop tracking for redistributed routes because
         * their originating protocols will do the tracking and
         * withdraw those routes if the nexthops become unreachable
+        * This also holds good for EVPN-imported routes that get
+        * leaked.
         */
-       if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)
+       if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE ||
+           is_pi_family_evpn(bpi_ultimate))
                nh_valid = 1;
        else
                /*
@@ -683,11 +691,10 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,            /* to */
                return;
        }
 
-       /* loop check - should not be an imported route. */
-       if (path_vrf->extra && path_vrf->extra->bgp_orig)
+       /* Is this route exportable into the VPN table? */
+       if (!is_route_injectable_into_vpn(path_vrf))
                return;
 
-
        if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
                if (debug)
                        zlog_debug("%s: %s skipping: %s", __func__,
@@ -894,15 +901,6 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn,               /* to */
                        path_vrf->type, path_vrf->sub_type);
        }
 
-       if (path_vrf->sub_type != BGP_ROUTE_NORMAL
-           && path_vrf->sub_type != BGP_ROUTE_STATIC
-           && path_vrf->sub_type != BGP_ROUTE_REDISTRIBUTE) {
-
-               if (debug)
-                       zlog_debug("%s: wrong sub_type %d", __func__,
-                                  path_vrf->sub_type);
-               return;
-       }
        if (!bgp_vpn)
                return;
 
@@ -912,6 +910,10 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn,               /* to */
                return;
        }
 
+       /* Is this route exportable into the VPN table? */
+       if (!is_route_injectable_into_vpn(path_vrf))
+               return;
+
        if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) {
                if (debug)
                        zlog_debug("%s: skipping: %s", __func__, debugmsg);
@@ -995,7 +997,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */
                                    == bgp_vrf) {
                                        /* delete route */
                                        if (debug)
-                                               zlog_debug("%s: deleting it\n",
+                                               zlog_debug("%s: deleting it",
                                                           __func__);
                                        bgp_aggregate_decrement(bgp_vpn, &bn->p,
                                                                bpi, afi, safi);
@@ -1352,7 +1354,10 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */
 
                for (bpi = bgp_node_get_bgp_path_info(bn); bpi;
                     bpi = bpi->next) {
-                       if (bpi->extra && bpi->extra->bgp_orig != bgp_vrf) {
+                       if (bpi->extra
+                           && bpi->extra->bgp_orig != bgp_vrf
+                           && bpi->extra->parent
+                           && is_pi_family_vpn(bpi->extra->parent)) {
 
                                /* delete route */
                                bgp_aggregate_decrement(bgp_vrf, &bn->p, bpi,
index 5b989e1853fd81fe1475d35914c40b3e87defd62..2ef9570aac1f128f217dca30f8c8969e1c8fab3e 100644 (file)
@@ -226,6 +226,39 @@ static inline void vpn_leak_postchange(vpn_policy_direction_t direction,
        }
 }
 
+/* Flag if the route is injectable into VPN. This would be either a
+ * non-imported route or a non-VPN imported route.
+ */
+static inline bool is_route_injectable_into_vpn(struct bgp_path_info *pi)
+{
+       struct bgp_path_info *parent_pi;
+       struct bgp_table *table;
+       struct bgp_node *rn;
+
+       if (pi->sub_type != BGP_ROUTE_IMPORTED ||
+           !pi->extra ||
+           !pi->extra->parent)
+               return true;
+
+       parent_pi = (struct bgp_path_info *)pi->extra->parent;
+       rn = parent_pi->net;
+       if (!rn)
+               return true;
+       table = bgp_node_table(rn);
+       if (table &&
+           (table->afi == AFI_IP || table->afi == AFI_IP6) &&
+           table->safi == SAFI_MPLS_VPN)
+               return false;
+       return true;
+}
+
+/* Flag if the route path's family is VPN. */
+static inline bool is_pi_family_vpn(struct bgp_path_info *pi)
+{
+       return (is_pi_family_matching(pi, AFI_IP, SAFI_MPLS_VPN) ||
+               is_pi_family_matching(pi, AFI_IP6, SAFI_MPLS_VPN));
+}
+
 extern void vpn_policy_routemap_event(const char *rmap_name);
 
 extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey);
index 90a8f8cec56c2a9345baa3bee0ef96c1f8121f70..eca632dd448cf1601fb46375646f9682b686326b 100644 (file)
@@ -2476,8 +2476,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
 
        /* advertise/withdraw type-5 routes */
        if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
-               if (advertise_type5_routes(bgp, afi) && new_select &&
-                   (!new_select->extra || !new_select->extra->parent)) {
+               if (advertise_type5_routes(bgp, afi) &&
+                   new_select &&
+                   is_route_injectable_into_evpn(new_select)) {
 
                        /* apply the route-map */
                        if (bgp->adv_cmd_rmap[afi][safi].map) {
@@ -2500,8 +2501,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
                                                               afi, safi);
 
                        }
-               } else if (advertise_type5_routes(bgp, afi) && old_select &&
-                        (!old_select->extra || !old_select->extra->parent))
+               } else if (advertise_type5_routes(bgp, afi) &&
+                          old_select &&
+                          is_route_injectable_into_evpn(old_select))
                        bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
        }
 
index 04a3c85f2c3ca6f7d5d787f879c4170090d17e9c..fc5bf0c7558a03ff1c74af0712d63aca3df4039c 100644 (file)
@@ -409,6 +409,24 @@ static inline int bgp_fibupd_safi(safi_t safi)
        return 0;
 }
 
+/* Flag if the route path's family matches params. */
+static inline bool is_pi_family_matching(struct bgp_path_info *pi,
+                                        afi_t afi, safi_t safi)
+{
+       struct bgp_table *table;
+       struct bgp_node *rn;
+
+       rn = pi->net;
+       if (!rn)
+               return false;
+       table = bgp_node_table(rn);
+       if (table &&
+           table->afi == afi &&
+           table->safi == safi)
+               return true;
+       return false;
+}
+
 /* Prototypes. */
 extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi,
                           struct peer *peer, afi_t afi, safi_t safi);
index 135c9753f73967cdd6d9820d770a05ec4c5b945a..c276f5ef7b87ba4dbbd31f26f712f7193d3fda3b 100644 (file)
@@ -3368,7 +3368,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
                                "Processing route_map %s update on advertise type5 route command",
                                rmap_name);
 
-               if (route_update) {
+               if (route_update && advertise_type5_routes(bgp, afi)) {
                        bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
                        bgp_evpn_advertise_type5_routes(bgp, afi, safi);
                }
index a38d78916c1837a7f69fbb40c73afdb670dc4336..b16b9f7b1ed7dcc89d2fe59b0c590f3fcb206de0 100644 (file)
@@ -125,7 +125,7 @@ static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket);
 static struct cache *find_cache(const uint8_t preference);
 static int add_tcp_cache(const char *host, const char *port,
                         const uint8_t preference);
-static void print_record(const struct pfx_record *record, void *data);
+static void print_record(const struct pfx_record *record, struct vty *vty);
 static int is_synchronized(void);
 static int is_running(void);
 static void route_match_free(void *rule);
@@ -271,17 +271,23 @@ static struct cache *find_cache(const uint8_t preference)
        return NULL;
 }
 
-static void print_record(const struct pfx_record *record, void *data)
+static void print_record(const struct pfx_record *record, struct vty *vty)
 {
        char ip[INET6_ADDRSTRLEN];
+
+       lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
+       vty_out(vty, "%-40s   %3u - %3u   %10u\n", ip, record->min_len,
+               record->max_len, record->asn);
+}
+
+static void print_record_cb(const struct pfx_record *record, void *data)
+{
        struct rpki_for_each_record_arg *arg = data;
        struct vty *vty = arg->vty;
 
        (*arg->prefix_amount)++;
 
-       lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip));
-       vty_out(vty, "%-40s   %3u - %3u   %10u\n", ip, record->min_len,
-               record->max_len, record->asn);
+       print_record(record, vty);
 }
 
 static struct rtr_mgr_group *get_groups(void)
@@ -663,10 +669,10 @@ static void print_prefix_table(struct vty *vty)
        vty_out(vty, "%-40s %s  %s\n", "Prefix", "Prefix Length", "Origin-AS");
 
        arg.prefix_amount = &number_of_ipv4_prefixes;
-       pfx_table_for_each_ipv4_record(pfx_table, print_record, &arg);
+       pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg);
 
        arg.prefix_amount = &number_of_ipv6_prefixes;
-       pfx_table_for_each_ipv6_record(pfx_table, print_record, &arg);
+       pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg);
 
        vty_out(vty, "Number of IPv4 Prefixes: %u\n", number_of_ipv4_prefixes);
        vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes);
@@ -1179,6 +1185,58 @@ DEFUN (show_rpki_prefix_table,
        return CMD_SUCCESS;
 }
 
+DEFPY (show_rpki_prefix,
+       show_rpki_prefix_cmd,
+       "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [(1-4294967295)$asn]",
+       SHOW_STR
+       RPKI_OUTPUT_STRING
+       "Lookup IP prefix and optionally ASN in prefix table\n"
+       "IPv4 prefix\n"
+       "IPv6 prefix\n"
+       "AS Number\n")
+{
+
+       if (!is_synchronized()) {
+               vty_out(vty, "No Conection to RPKI cache server.\n");
+               return CMD_WARNING;
+       }
+
+       struct lrtr_ip_addr addr;
+       char addr_str[INET6_ADDRSTRLEN];
+       size_t addr_len = strchr(prefix_str, '/') - prefix_str;
+
+       memset(addr_str, 0, sizeof(addr_str));
+       memcpy(addr_str, prefix_str, addr_len);
+
+       if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) {
+               vty_out(vty, "Invalid IP prefix\n");
+               return CMD_WARNING;
+       }
+
+       struct pfx_record *matches = NULL;
+       unsigned int match_count = 0;
+       enum pfxv_state result;
+
+       if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count,
+                                asn, &addr, prefix->prefixlen, &result)
+           != PFX_SUCCESS) {
+               vty_out(vty, "Prefix lookup failed");
+               return CMD_WARNING;
+       }
+
+       vty_out(vty, "%-40s %s  %s\n", "Prefix", "Prefix Length", "Origin-AS");
+       for (size_t i = 0; i < match_count; ++i) {
+               const struct pfx_record *record = &matches[i];
+
+               if (record->max_len >= prefix->prefixlen
+                   && ((asn != 0 && asn == record->asn) || asn == 0)) {
+                       print_record(&matches[i], vty);
+               }
+       }
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (show_rpki_cache_server,
        show_rpki_cache_server_cmd,
        "show rpki cache-server",
@@ -1450,6 +1508,7 @@ static void install_cli_commands(void)
        install_element(ENABLE_NODE, &show_rpki_prefix_table_cmd);
        install_element(ENABLE_NODE, &show_rpki_cache_connection_cmd);
        install_element(ENABLE_NODE, &show_rpki_cache_server_cmd);
+       install_element(ENABLE_NODE, &show_rpki_prefix_cmd);
 
        /* Install debug commands */
        install_element(CONFIG_NODE, &debug_rpki_cmd);
index d426e65c530ab2881138c0124c019c72dac0d2dd..5350ebeec7c7a13cf2dcd3b2f28d07da509486c9 100644 (file)
@@ -2055,29 +2055,6 @@ DEFUN (no_bgp_graceful_restart_preserve_fw,
        return CMD_SUCCESS;
 }
 
-static void bgp_redistribute_redo(struct bgp *bgp)
-{
-       afi_t afi;
-       int i;
-       struct list *red_list;
-       struct listnode *node;
-       struct bgp_redist *red;
-
-       for (afi = AFI_IP; afi < AFI_MAX; afi++) {
-               for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
-
-                       red_list = bgp->redist[afi][i];
-                       if (!red_list)
-                               continue;
-
-                       for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
-                               bgp_redistribute_resend(bgp, afi, i,
-                                                       red->instance);
-                       }
-               }
-       }
-}
-
 /* "bgp graceful-shutdown" configuration */
 DEFUN (bgp_graceful_shutdown,
        bgp_graceful_shutdown_cmd,
@@ -2841,18 +2818,23 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
                as = strtoul(as_str, NULL, 10);
        }
 
-       /* If peer is peer group, call proper function.  */
+       /* If peer is peer group or interface peer, call proper function. */
        ret = str2sockunion(peer_str, &su);
        if (ret < 0) {
-               /* Check for peer by interface */
+               struct peer *peer;
+
+               /* Check if existing interface peer */
+               peer = peer_lookup_by_conf_if(bgp, peer_str);
+
                ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, afi,
                                     safi);
-               if (ret < 0) {
+
+               /* if not interface peer, check peer-group settings */
+               if (ret < 0 && !peer) {
                        ret = peer_group_remote_as(bgp, peer_str, &as, as_type);
                        if (ret < 0) {
                                vty_out(vty,
-                                       "%% Create the peer-group or interface first or specify \"interface\" keyword\n");
-                               vty_out(vty, "%% if using an unnumbered interface neighbor\n");
+                                       "%% Create the peer-group or interface first\n");
                                return CMD_WARNING_CONFIG_FAILED;
                        }
                        return CMD_SUCCESS;
@@ -3251,7 +3233,7 @@ DEFUN (no_neighbor_interface_peer_group_remote_as,
        /* look up for neighbor by interface name config. */
        peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg);
        if (peer) {
-               peer_as_change(peer, 0, AS_SPECIFIED);
+               peer_as_change(peer, 0, AS_UNSPECIFIED);
                return CMD_SUCCESS;
        }
 
@@ -8031,7 +8013,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                        json, "ribMemory",
                                        ents * sizeof(struct bgp_node));
 
-                               ents = listcount(bgp->peer);
+                               ents = bgp->af_peer_count[afi][safi];
                                json_object_int_add(json, "peerCount", ents);
                                json_object_int_add(json, "peerMemory",
                                                    ents * sizeof(struct peer));
@@ -8071,7 +8053,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                                                   bgp_node)));
 
                                /* Peer related usage */
-                               ents = listcount(bgp->peer);
+                               ents = bgp->af_peer_count[afi][safi];
                                vty_out(vty, "Peers %ld, using %s of memory\n",
                                        ents,
                                        mtype_memstr(
@@ -8522,7 +8504,7 @@ const char *afi_safi_json(afi_t afi, safi_t safi)
 }
 
 /* Show BGP peer's information. */
-enum show_type { show_all, show_peer };
+enum show_type { show_all, show_peer, show_ipv4_all, show_ipv6_all, show_ipv4_peer, show_ipv6_peer };
 
 static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
                                      afi_t afi, safi_t safi,
@@ -10945,6 +10927,14 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
        struct peer *peer;
        int find = 0;
        bool nbr_output = false;
+       afi_t afi = AFI_MAX;
+       safi_t safi = SAFI_MAX;
+
+       if (type == show_ipv4_peer || type == show_ipv4_all) {
+               afi = AFI_IP;
+       } else if (type == show_ipv6_peer || type == show_ipv6_all) {
+               afi = AFI_IP6;
+       }
 
        for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
                if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
@@ -10973,17 +10963,54 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
                                }
                        }
                        break;
+               case show_ipv4_peer:
+               case show_ipv6_peer:
+                       FOREACH_SAFI (safi) {
+                               if (peer->afc[afi][safi]) {
+                                       if (conf_if) {
+                                               if ((peer->conf_if
+                                                    && !strcmp(peer->conf_if, conf_if))
+                                                   || (peer->hostname
+                                                       && !strcmp(peer->hostname, conf_if))) {
+                                                       find = 1;
+                                                       bgp_show_peer(vty, peer, use_json,
+                                                                     json);
+                                                       break;
+                                               }
+                                       } else {
+                                               if (sockunion_same(&peer->su, su)) {
+                                                       find = 1;
+                                                       bgp_show_peer(vty, peer, use_json,
+                                                                     json);
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       break;
+               case show_ipv4_all:
+               case show_ipv6_all:
+                       FOREACH_SAFI (safi) {
+                               if (peer->afc[afi][safi]) {
+                                       bgp_show_peer(vty, peer, use_json, json);
+                                       nbr_output = true;
+                                       break;
+                               }
+                       }
+                       break;
                }
        }
 
-       if (type == show_peer && !find) {
+       if ((type == show_peer || type == show_ipv4_peer ||
+            type == show_ipv6_peer) && !find) {
                if (use_json)
                        json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
                else
                        vty_out(vty, "%% No such neighbor in this view/vrf\n");
        }
 
-       if (type != show_peer && !nbr_output && !use_json)
+       if (type != show_peer && type != show_ipv4_peer &&
+           type != show_ipv6_peer && !nbr_output && !use_json)
                vty_out(vty, "%% No BGP neighbors found\n");
 
        if (use_json) {
@@ -11049,7 +11076,8 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
                                        : bgp->name);
                }
 
-               if (type == show_peer) {
+               if (type == show_peer || type == show_ipv4_peer ||
+                   type == show_ipv6_peer) {
                        ret = str2sockunion(ip_str, &su);
                        if (ret < 0)
                                bgp_show_neighbor(vty, bgp, type, NULL, ip_str,
@@ -11058,7 +11086,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
                                bgp_show_neighbor(vty, bgp, type, &su, NULL,
                                                  use_json, json);
                } else {
-                       bgp_show_neighbor(vty, bgp, show_all, NULL, NULL,
+                       bgp_show_neighbor(vty, bgp, type, NULL, NULL,
                                          use_json, json);
                }
                json_object_free(json);
@@ -11151,6 +11179,7 @@ DEFUN (show_ip_bgp_neighbors,
        char *vrf = NULL;
        char *sh_arg = NULL;
        enum show_type sh_type;
+       afi_t afi = AFI_MAX;
 
        bool uj = use_json(argc, argv);
 
@@ -11166,13 +11195,29 @@ DEFUN (show_ip_bgp_neighbors,
                vrf = argv[idx + 1]->arg;
 
        idx++;
+
+       if (argv_find(argv, argc, "ipv4", &idx)) {
+               sh_type = show_ipv4_all;
+               afi = AFI_IP;
+       } else if (argv_find(argv, argc, "ipv6", &idx)) {
+               sh_type = show_ipv6_all;
+               afi = AFI_IP6;
+       } else {
+               sh_type = show_all;
+       }
+
        if (argv_find(argv, argc, "A.B.C.D", &idx)
            || argv_find(argv, argc, "X:X::X:X", &idx)
            || argv_find(argv, argc, "WORD", &idx)) {
                sh_type = show_peer;
                sh_arg = argv[idx]->arg;
-       } else
-               sh_type = show_all;
+       }
+
+       if (sh_type == show_peer && afi == AFI_IP) {
+               sh_type = show_ipv4_peer;
+       } else if (sh_type == show_peer && afi == AFI_IP6) {
+               sh_type = show_ipv6_peer;
+       }
 
        return bgp_show_neighbor_vty(vty, vrf, sh_type, sh_arg, uj);
 }
@@ -11267,8 +11312,9 @@ DEFUN (show_ip_bgp_attr_info,
        return CMD_SUCCESS;
 }
 
-static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
-                                  safi_t safi, bool use_json)
+static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
+                                  afi_t afi, safi_t safi,
+                                  bool use_json, json_object *json)
 {
        struct bgp *bgp;
        struct listnode *node;
@@ -11277,13 +11323,10 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
        char *ecom_str;
        vpn_policy_direction_t dir;
 
-       if (use_json) {
-               json_object *json = NULL;
+       if (json) {
                json_object *json_import_vrfs = NULL;
                json_object *json_export_vrfs = NULL;
 
-               json = json_object_new_object();
-
                bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
 
                if (!bgp) {
@@ -11354,11 +11397,12 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
                        XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
                }
 
-               vty_out(vty, "%s\n",
-                       json_object_to_json_string_ext(json,
+               if (use_json) {
+                       vty_out(vty, "%s\n",
+                               json_object_to_json_string_ext(json,
                                                      JSON_C_TO_STRING_PRETTY));
-               json_object_free(json);
-
+                       json_object_free(json);
+               }
        } else {
                bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
 
@@ -11422,6 +11466,54 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi,
        return CMD_SUCCESS;
 }
 
+static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi,
+                                               safi_t safi, bool use_json)
+{
+       struct listnode *node, *nnode;
+       struct bgp *bgp;
+       char *vrf_name = NULL;
+       json_object *json = NULL;
+       json_object *json_vrf = NULL;
+       json_object *json_vrfs = NULL;
+
+       if (use_json) {
+               json = json_object_new_object();
+               json_vrfs = json_object_new_object();
+       }
+
+       for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+
+               if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT)
+                       vrf_name = bgp->name;
+
+               if (use_json) {
+                       json_vrf = json_object_new_object();
+               } else {
+                       vty_out(vty, "\nInstance %s:\n",
+                               (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+                               ? VRF_DEFAULT_NAME : bgp->name);
+               }
+               bgp_show_route_leak_vty(vty, vrf_name, afi, safi, 0, json_vrf);
+               if (use_json) {
+                       if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+                               json_object_object_add(json_vrfs,
+                                               VRF_DEFAULT_NAME, json_vrf);
+                       else
+                               json_object_object_add(json_vrfs, vrf_name,
+                                                      json_vrf);
+               }
+       }
+
+       if (use_json) {
+               json_object_object_add(json, "vrfs", json_vrfs);
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(json,
+                                               JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+
+       return CMD_SUCCESS;
+}
+
 /* "show [ip] bgp route-leak" command.  */
 DEFUN (show_ip_bgp_route_leak,
        show_ip_bgp_route_leak_cmd,
@@ -11441,6 +11533,7 @@ DEFUN (show_ip_bgp_route_leak,
 
        bool uj = use_json(argc, argv);
        int idx = 0;
+       json_object *json = NULL;
 
        /* show [ip] bgp */
        if (argv_find(argv, argc, "ip", &idx)) {
@@ -11470,7 +11563,13 @@ DEFUN (show_ip_bgp_route_leak,
                return CMD_WARNING;
        }
 
-       return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj);
+       if (vrf && strmatch(vrf, "all"))
+               return bgp_show_all_instance_route_leak_vty(vty, afi, safi, uj);
+
+       if (uj)
+               json = json_object_new_object();
+
+       return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj, json);
 }
 
 static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi,
index 0c77f63335026ea45ca56edb723962cdb20cd4fa..66fcbb3f3afa9ed82a79b676985b45bcbb6d116e 100644 (file)
@@ -1819,23 +1819,42 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type,
        return CMD_SUCCESS;
 }
 
-/* Update redistribute vrf bitmap during triggers like
-   restart networking or delete/add VRFs */
-void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id)
+void bgp_redistribute_redo(struct bgp *bgp)
+{
+       afi_t afi;
+       int i;
+       struct list *red_list;
+       struct listnode *node;
+       struct bgp_redist *red;
+
+       for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+               for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+
+                       red_list = bgp->redist[afi][i];
+                       if (!red_list)
+                               continue;
+
+                       for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
+                               bgp_redistribute_resend(bgp, afi, i,
+                                                       red->instance);
+                       }
+               }
+       }
+}
+
+/* Unset redistribute vrf bitmap during triggers like
+   restart networking or delete VRFs */
+void bgp_unset_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id)
 {
        int i;
        afi_t afi;
 
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
                for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
-                       if ((old_vrf_id == VRF_UNKNOWN)
-                           || vrf_bitmap_check(zclient->redist[afi][i],
-                                               old_vrf_id)) {
+                       if (vrf_bitmap_check(zclient->redist[afi][i],
+                                            old_vrf_id))
                                vrf_bitmap_unset(zclient->redist[afi][i],
                                                 old_vrf_id);
-                               vrf_bitmap_set(zclient->redist[afi][i],
-                                              bgp->vrf_id);
-                       }
        return;
 }
 
index fc19c5e17f5c6bd3ab1ecd79418b051cc42b18f6..b912870b80dbf94e0e5f58dd0f3d87c672b70c81 100644 (file)
@@ -49,6 +49,7 @@ extern void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer);
 extern void bgp_zebra_instance_register(struct bgp *);
 extern void bgp_zebra_instance_deregister(struct bgp *);
 
+extern void bgp_redistribute_redo(struct bgp *bgp);
 extern struct bgp_redist *bgp_redist_lookup(struct bgp *, afi_t, uint8_t,
                                            unsigned short);
 extern struct bgp_redist *bgp_redist_add(struct bgp *, afi_t, uint8_t,
index 8fcf417b3a2e11577be2e44d8557b688a768aa9f..17928d6850e02cb39c143f41be5710d5ab7da48b 100644 (file)
@@ -707,6 +707,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
 {
        struct peer_af *af;
        int afid;
+       struct bgp *bgp;
 
        if (!peer)
                return NULL;
@@ -715,6 +716,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
        if (afid >= BGP_AF_MAX)
                return NULL;
 
+       bgp = peer->bgp;
        assert(peer->peer_af_array[afid] == NULL);
 
        /* Allocate new peer af */
@@ -725,6 +727,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
        af->safi = safi;
        af->afid = afid;
        af->peer = peer;
+       bgp->af_peer_count[afi][safi]++;
 
        return af;
 }
@@ -747,6 +750,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
 {
        struct peer_af *af;
        int afid;
+       struct bgp *bgp;
 
        if (!peer)
                return -1;
@@ -759,6 +763,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
        if (!af)
                return -1;
 
+       bgp = peer->bgp;
        bgp_stop_announce_route_timer(af);
 
        if (PAF_SUBGRP(af)) {
@@ -768,8 +773,12 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
                                   af->subgroup->id, peer->host);
        }
 
+
        update_subgroup_remove_peer(af->subgroup, af);
 
+       if (bgp->af_peer_count[afi][safi])
+               bgp->af_peer_count[afi][safi]--;
+
        peer->peer_af_array[afid] = NULL;
        XFREE(MTYPE_BGP_PEER_AF, af);
        return 0;
@@ -2714,7 +2723,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
                        peer->sort = group->conf->sort;
                }
 
-               if (!group->conf->as) {
+               if (!group->conf->as && peer_sort(peer)) {
                        if (peer_sort(group->conf) != BGP_PEER_INTERNAL
                            && peer_sort(group->conf) != peer_sort(peer)) {
                                if (as)
index f9c269e3e6e8b4974f530de893c4227f7dde3e8f..b0f65675342d3d82896ea87f1bded9833e443592 100644 (file)
@@ -99,6 +99,9 @@ enum bgp_af_index {
        for (afi = AFI_IP; afi < AFI_MAX; afi++)                               \
                for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
 
+#define FOREACH_SAFI(safi)                                            \
+       for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+
 extern struct frr_pthread *bgp_pth_io;
 extern struct frr_pthread *bgp_pth_ka;
 
@@ -377,6 +380,9 @@ struct bgp {
 #define BGP_CONFIG_VRF_TO_VRF_IMPORT                   (1 << 7)
 #define BGP_CONFIG_VRF_TO_VRF_EXPORT                   (1 << 8)
 
+       /* BGP per AF peer count */
+       uint32_t af_peer_count[AFI_MAX][SAFI_MAX];
+
        /* Route table for next-hop lookup cache. */
        struct bgp_table *nexthop_cache_table[AFI_MAX];
 
@@ -1906,7 +1912,7 @@ static inline void bgp_vrf_unlink(struct bgp *bgp, struct vrf *vrf)
        bgp->vrf_id = VRF_UNKNOWN;
 }
 
-extern void bgp_update_redist_vrf_bitmaps(struct bgp *, vrf_id_t);
+extern void bgp_unset_redist_vrf_bitmaps(struct bgp *, vrf_id_t);
 
 /* For benefit of rfapi */
 extern struct peer *peer_new(struct bgp *bgp);
index fcfc4bd2fbd37ad6aa002890b24fd0b68a8a0c0a..9ae196fcb19e5fa5f2ae5ac3032f088edcec19fc 100755 (executable)
@@ -765,7 +765,7 @@ AC_DEFINE_UNQUOTED([CONFIGFILE_MASK], [${enable_configfile_mask}], [Mask for con
 enable_logfile_mask=${enable_logfile_mask:-0600}
 AC_DEFINE_UNQUOTED([LOGFILE_MASK], [${enable_logfile_mask}], [Mask for log files])
 
-MPATH_NUM=1
+MPATH_NUM=16
 
 case "${enable_multipath}" in
   0)
index c57573cb9fe2ea7357ae5dbc1b933b7879f8d7a0..732959212eb486068aa03c89007b130caddc0514 100644 (file)
@@ -1,9 +1,10 @@
+.. _building-centos6:
+
 CentOS 6
 ========================================
 
-(As an alternative to this installation, you may prefer to create a FRR
-rpm package yourself and install that package instead. See instructions
-in redhat/README.rpm\_build.md on how to build a rpm package)
+This document describes installation from source. If you want to build an RPM,
+see :ref:`packaging-redhat`.
 
 Instructions are tested with ``CentOS 6.8`` on ``x86_64`` platform
 
@@ -24,7 +25,7 @@ CentOS 6 restrictions:
    PIMd is needed
 -  MPLS is not supported on ``CentOS 6``. MPLS requires Linux Kernel 4.5
    or higher (LDP can be built, but may have limited use without MPLS)
--  Zebra is unable to detect what bridge/vrf an interface is associcated
+-  Zebra is unable to detect what bridge/vrf an interface is associated
    with (IFLA\_INFO\_SLAVE\_KIND does not exist in the kernel headers,
    you can use a newer kernel + headers to get this functionality)
 -  frr\_reload.py will not work, as this requires Python 2.7, and CentOS
@@ -235,7 +236,7 @@ settings)::
    # Controls source route verification
    net.ipv4.conf.default.rp_filter = 0
 
-Load the modifed sysctl's on the system:
+Load the modified sysctl's on the system:
 
 .. code-block:: shell
 
index 8f82cd6c9ab6ab6b8acf6271065ea894fe1d6d66..89445408bd97382764894b6626dd5b7c9ac26bec 100644 (file)
@@ -1,9 +1,8 @@
 CentOS 7
 ========================================
 
-(As an alternative to this installation, you may prefer to create a FRR
-rpm package yourself and install that package instead. See instructions
-in redhat/README.rpm\_build.md on how to build a rpm package)
+This document describes installation from source. If you want to build an RPM,
+see :ref:`packaging-redhat`.
 
 CentOS 7 restrictions:
 ----------------------
@@ -127,7 +126,7 @@ following content:
     net.ipv4.conf.all.forwarding=1
     net.ipv6.conf.all.forwarding=1
 
-Load the modifed sysctl's on the system:
+Load the modified sysctl's on the system:
 
 ::
 
diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst
new file mode 100644 (file)
index 0000000..6900aed
--- /dev/null
@@ -0,0 +1,122 @@
+Fedora 24+
+==========
+
+This document describes installation from source. If you want to build an RPM,
+see :ref:`packaging-redhat`.
+
+These instructions have been tested on Fedora 24+.
+
+Installing Dependencies
+-----------------------
+
+.. code-block:: console
+
+   sudo dnf install git autoconf automake libtool make gawk \
+     readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \
+     pam-devel pytest bison flex c-ares-devel python3-devel python2-sphinx \
+     perl-core patch
+
+.. include:: building-libyang.rst
+
+Building & Installing FRR
+-------------------------
+
+Add FRR user and groups
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+   sudo groupadd -g 92 frr
+   sudo groupadd -r -g 85 frrvty
+   sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \
+     -c "FRR FRRouting suite" -d /var/run/frr frr
+
+Compile
+^^^^^^^
+
+.. include:: include-compile.rst
+
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+   sudo install -m 775 -o frr -g frr -d /var/log/frr
+   sudo install -m 775 -o frr -g frrvty -d /etc/frr
+   sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
+
+Tweak sysctls
+^^^^^^^^^^^^^
+
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
+
+Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the following
+content:
+
+::
+
+   #
+   # Enable packet forwarding
+   #
+   net.ipv4.conf.all.forwarding=1
+   net.ipv6.conf.all.forwarding=1
+   #
+   # Enable MPLS Label processing on all interfaces
+   #
+   #net.mpls.conf.eth0.input=1
+   #net.mpls.conf.eth1.input=1
+   #net.mpls.conf.eth2.input=1
+   #net.mpls.platform_labels=100000
+
+.. note::
+
+   MPLS must be invidividually enabled on each interface that requires it. See
+   the example in the config block above.
+
+Load the modifed sysctls on the system:
+
+.. code-block:: console
+
+   sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
+
+Create a new file ``/etc/modules-load.d/mpls.conf`` with the following content:
+
+::
+
+   # Load MPLS Kernel Modules
+   mpls-router
+   mpls-iptunnel
+
+And load the kernel modules on the running system:
+
+.. code-block:: console
+
+   sudo modprobe mpls-router mpls-iptunnel
+
+Install service files
+^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: console
+
+   sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
+   sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
+   sudo systemctl enable frr
+
+Enable daemons
+^^^^^^^^^^^^^^
+
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``watchfrr_enable=...`` and ``zebra=...`` etc.  Enable the daemons
+as required by changing the value to ``yes``.
+
+Start FRR
+^^^^^^^^^
+
+.. code-block:: frr
+
+   sudo systemctl start frr
diff --git a/doc/developer/building-frr-for-fedora24.rst b/doc/developer/building-frr-for-fedora24.rst
deleted file mode 100644 (file)
index 2edf9b3..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-Fedora 24
-=========================================
-
-(As an alternative to this installation, you may prefer to create a FRR
-rpm package yourself and install that package instead. See instructions
-in redhat/README.rpm\_build.md on how to build a rpm package)
-
-Install required packages
--------------------------
-
-Add packages:
-
-::
-
-    sudo dnf install git autoconf automake libtool make gawk \
-      readline-devel texinfo net-snmp-devel groff pkgconfig \
-      json-c-devel pam-devel pytest bison flex c-ares-devel \
-      python3-devel python3-sphinx
-
-.. include:: building-libyang.rst
-
-Get FRR, compile it and install it (from Git)
----------------------------------------------
-
-**This assumes you want to build and install FRR from source and not
-using any packages**
-
-Add frr groups and user
-^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
-    sudo groupadd -g 92 frr
-    sudo groupadd -r -g 85 frrvty
-    sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \
-      -c "FRR FRRouting suite" -d /var/run/frr frr
-
-Download Source, configure and compile it
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-(You may prefer different options on configure statement. These are just
-an example.)
-
-::
-
-    git clone https://github.com/frrouting/frr.git frr
-    cd frr
-    ./bootstrap.sh
-    ./configure \
-        --bindir=/usr/bin \
-        --sbindir=/usr/lib/frr \
-        --sysconfdir=/etc/frr \
-        --libdir=/usr/lib/frr \
-        --libexecdir=/usr/lib/frr \
-        --localstatedir=/var/run/frr \
-        --with-moduledir=/usr/lib/frr/modules \
-        --enable-snmp=agentx \
-        --enable-multipath=64 \
-        --enable-user=frr \
-        --enable-group=frr \
-        --enable-vty-group=frrvty \
-        --disable-exampledir \
-        --enable-fpm \
-        --with-pkg-git-version \
-        --with-pkg-extra-version=-MyOwnFRRVersion
-    make
-    make check
-    sudo make install
-
-Create empty FRR configuration files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
-    sudo mkdir /var/log/frr
-    sudo mkdir /etc/frr
-    sudo touch /etc/frr/zebra.conf
-    sudo touch /etc/frr/bgpd.conf
-    sudo touch /etc/frr/ospfd.conf
-    sudo touch /etc/frr/ospf6d.conf
-    sudo touch /etc/frr/isisd.conf
-    sudo touch /etc/frr/ripd.conf
-    sudo touch /etc/frr/ripngd.conf
-    sudo touch /etc/frr/pimd.conf
-    sudo touch /etc/frr/ldpd.conf
-    sudo touch /etc/frr/nhrpd.conf
-    sudo touch /etc/frr/eigrpd.conf
-    sudo touch /etc/frr/babeld.conf
-    sudo chown -R frr:frr /etc/frr/
-    sudo touch /etc/frr/vtysh.conf
-    sudo chown frr:frrvty /etc/frr/vtysh.conf
-    sudo chmod 640 /etc/frr/*.conf
-
-Install daemon config file
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
-    sudo install -p -m 644 redhat/daemons /etc/frr/
-    sudo chown frr:frr /etc/frr/daemons
-
-Edit /etc/frr/daemons as needed to select the required daemons
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc.
-Enable the daemons as required by changing the value to ``yes``
-
-Enable IP & IPv6 forwarding (and MPLS)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the
-following content: (Please make sure to list all interfaces with
-required MPLS similar to ``net.mpls.conf.eth0.input=1``)
-
-::
-
-    # Sysctl for routing
-    #
-    # Routing: We need to forward packets
-    net.ipv4.conf.all.forwarding=1
-    net.ipv6.conf.all.forwarding=1
-    #
-    # Enable MPLS Label processing on all interfaces
-    net.mpls.conf.eth0.input=1
-    net.mpls.conf.eth1.input=1
-    net.mpls.conf.eth2.input=1
-    net.mpls.platform_labels=100000
-
-Load the modifed sysctl's on the system:
-
-::
-
-    sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
-
-Create a new file ``/etc/modules-load.d/mpls.conf`` with the following
-content:
-
-::
-
-    # Load MPLS Kernel Modules
-    mpls-router
-    mpls-iptunnel
-
-And load the kernel modules on the running system:
-
-::
-
-    sudo modprobe mpls-router mpls-iptunnel
-
-Install frr Service and redhat init files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
-    sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
-    sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
-
-Enable required frr at startup
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
-    sudo systemctl enable frr
-
-Reboot or start FRR manually
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-::
-
-    sudo systemctl start frr
index a6539309a238b04145bad584c5afb5f5e11393e2..5d0a7f6cbb057b69c1b15da29aecd7c45e9f6087 100644 (file)
@@ -11,7 +11,7 @@ FreeBSD 10 restrictions:
 Install required packages
 -------------------------
 
-Add packages: (Allow the install of the package managment tool if this
+Add packages: (Allow the install of the package management tool if this
 is first package install and asked)
 
 ::
index 16d06e0a6647af5680183dc58b4cf443e9e0d4f6..c85255e6eeef5b11a07e8b0fb90f43781bb3fa74 100644 (file)
@@ -11,7 +11,7 @@ FreeBSD 11 restrictions:
 Install required packages
 -------------------------
 
-Add packages: (Allow the install of the package managment tool if this
+Add packages: (Allow the install of the package management tool if this
 is first package install and asked)
 
 .. code-block:: shell
index 36492fb88657fe5549118cd9c3ea0a32711f332d..4009f1b8d3f44a2a0ba3355c3891654b1f1db710 100644 (file)
@@ -11,7 +11,7 @@ FreeBSD 9 restrictions:
 Install required packages
 -------------------------
 
-Add packages: (Allow the install of the package managment tool if this
+Add packages: (Allow the install of the package management tool if this
 is first package install and asked)
 
 ::
index b9be1b52260e485aa0d0398fd10edbfd2208fff8..8f72ab5d9dcf43d7ea2cef1f3237427248d73e45 100644 (file)
@@ -63,10 +63,10 @@ Usage
 -----
 
 Edit ``/usr/sbin/frr.init`` and add/remove the daemons name in section
-``DAEMONS=`` or don't install unneded packages For example: zebra bgpd ldpd
+``DAEMONS=`` or don't install unneeded packages For example: zebra bgpd ldpd
 isisd nhrpd ospfd ospf6d pimd ripd ripngd
 
-Enable the serivce
+Enable the service
 ^^^^^^^^^^^^^^^^^^
 
 -  ``service frr enable``
index b1eaf57e8d52de355bbf62d9ba424679bcee4a37..0942f1973737881ddcab20f86e231e3ae0a1970a 100644 (file)
@@ -1,35 +1,30 @@
-Ubuntu 14.04LTS
-===============================================
+Ubuntu 14.04 LTS
+================
 
--  MPLS is not supported on ``Ubuntu 14.04`` with default kernel. MPLS
-   requires Linux Kernel 4.5 or higher (LDP can be built, but may have
-   limited use without MPLS) For an updated Ubuntu Kernel, see
-   http://kernel.ubuntu.com/~kernel-ppa/mainline/
-
-Install required packages
--------------------------
+This document describes installation from source. If you want to build a
+``deb``, see :ref:`packaging-debian`.
 
-Add packages:
+Installing Dependencies
+-----------------------
 
-::
+.. code-block:: console
 
+   apt-get update
    apt-get install \
       git autoconf automake libtool make gawk libreadline-dev texinfo \
-      dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
-      libc-ares-dev python3-dev python3-sphinx install-info build-essential
+      pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
+      libc-ares-dev python3-dev python3-sphinx install-info build-essential \
+      libsnmp-dev perl
 
 .. include:: building-libyang.rst
 
-Get FRR, compile it and install it (from Git)
----------------------------------------------
-
-**This assumes you want to build and install FRR from source and not
-using any packages**
+Building & Installing FRR
+-------------------------
 
-Add frr groups and user
+Add FRR user and groups
 ^^^^^^^^^^^^^^^^^^^^^^^
 
-::
+.. code-block:: console
 
     sudo groupadd -r -g 92 frr
     sudo groupadd -r -g 85 frrvty
@@ -37,102 +32,104 @@ Add frr groups and user
        --gecos "FRR suite" --shell /sbin/nologin frr
     sudo usermod -a -G frrvty frr
 
-Download Source, configure and compile it
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Compile
+^^^^^^^
 
-(You may prefer different options on configure statement. These are just
-an example.)
+.. include:: include-compile.rst
 
-::
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-    git clone https://github.com/frrouting/frr.git frr
-    cd frr
-    ./bootstrap.sh
-    ./configure \
-        --prefix=/usr \
-        --enable-exampledir=/usr/share/doc/frr/examples/ \
-        --localstatedir=/var/run/frr \
-        --sbindir=/usr/lib/frr \
-        --sysconfdir=/etc/frr \
-        --enable-multipath=64 \
-        --enable-user=frr \
-        --enable-group=frr \
-        --enable-vty-group=frrvty \
-        --enable-configfile-mask=0640 \
-        --enable-logfile-mask=0640 \
-        --enable-fpm \
-        --with-pkg-git-version \
-        --with-pkg-extra-version=-MyOwnFRRVersion
-    make
-    make check
-    sudo make install
-
-Create empty FRR configuration files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. code-block:: console
+
+   sudo install -m 775 -o frr -g frr -d /var/log/frr
+   sudo install -m 775 -o frr -g frrvty -d /etc/frr
+   sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
+
+Tweak sysctls
+^^^^^^^^^^^^^
+
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
+
+Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
+other settings):
 
 ::
 
-    sudo install -m 755 -o frr -g frr -d /var/log/frr
-    sudo install -m 775 -o frr -g frrvty -d /etc/frr
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
-    sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
-
-Enable IP & IPv6 forwarding
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
-other settings)
+   # Uncomment the next line to enable packet forwarding for IPv4
+   net.ipv4.ip_forward=1
+
+   # Uncomment the next line to enable packet forwarding for IPv6
+   #  Enabling this option disables Stateless Address Autoconfiguration
+   #  based on Router Advertisements for this host
+   net.ipv6.conf.all.forwarding=1
+
+Reboot or use ``sysctl -p`` to apply the same config to the running system.
+
+Add MPLS kernel modules
+"""""""""""""""""""""""
+
+.. warning::
+
+   MPLS is not supported on Ubuntu 14.04 with the default kernel. MPLS requires
+   kernel 4.5 or higher. LDPD can be built, but may have limited use without
+   MPLS. For an updated Ubuntu Kernel, see
+   http://kernel.ubuntu.com/~kernel-ppa/mainline/
+
+Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default.  To
+enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
 
 ::
 
-    # Uncomment the next line to enable packet forwarding for IPv4
-    net.ipv4.ip_forward=1
+   # Load MPLS Kernel Modules
+   mpls_router
+   mpls_iptunnel
+
+
+And load the kernel modules on the running system:
+
+.. code-block:: console
+
+   sudo modprobe mpls-router mpls-iptunnel
+
+Enable MPLS Forwarding
+""""""""""""""""""""""
 
-    # Uncomment the next line to enable packet forwarding for IPv6
-    #  Enabling this option disables Stateless Address Autoconfiguration
-    #  based on Router Advertisements for this host
-    net.ipv6.conf.all.forwarding=1
+Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
+equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
 
-**Reboot** or use ``sysctl -p`` to apply the same config to the running
-system
+::
+
+   # Enable MPLS Label processing on all interfaces
+   net.mpls.conf.eth0.input=1
+   net.mpls.conf.eth1.input=1
+   net.mpls.conf.eth2.input=1
+   net.mpls.platform_labels=100000
 
 Install the init.d service
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-::
+.. code-block:: console
 
-    sudo install -m 755 tools/frr /etc/init.d/frr
-    sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
-    sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+   sudo install -m 755 tools/frr /etc/init.d/frr
 
 Enable daemons
 ^^^^^^^^^^^^^^
 
-| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
-  those daemons you want to start by systemd.
-| For example.
-
-::
-
-    zebra=yes
-    bgpd=yes
-    ospfd=yes
-    ospf6d=yes
-    ripd=yes
-    ripngd=yes
-    isisd=yes
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``watchfrr_enable=...`` and ``zebra=...`` etc.  Enable the daemons
+as required by changing the value to ``yes``.
 
 Start the init.d service
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
--  /etc/init.d/frr start
--  use ``/etc/init.d/frr status`` to check its status.
+.. code-block:: console
+
+  /etc/init.d/frr start
+
+Use ``/etc/init.d/frr status`` to check its status.
index 0762e07eb9e0e2b2782c63297cc1707527143070..63cb9aa13a4809b0b324333b4bef487d30d91900 100644 (file)
-Ubuntu 16.04LTS
-===============================================
+Ubuntu 16.04 LTS
+================
 
--  MPLS is not supported on ``Ubuntu 16.04`` with default kernel. MPLS
-   requires Linux Kernel 4.5 or higher (LDP can be built, but may have
-   limited use without MPLS) For an updated Ubuntu Kernel, see
-   http://kernel.ubuntu.com/~kernel-ppa/mainline/
-
-Install required packages
--------------------------
+This document describes installation from source. If you want to build a
+``deb``, see :ref:`packaging-debian`.
 
-Add packages:
+Installing Dependencies
+-----------------------
 
-::
+.. code-block:: console
 
+   apt-get update
    apt-get install \
-      git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \
+      git autoconf automake libtool make gawk libreadline-dev texinfo \
       pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
-      libc-ares-dev python3-dev libsystemd-dev python-ipaddress \
-      python3-sphinx install-info build-essential libsystemd-dev
+      libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
+      install-info build-essential libsystemd-dev libsnmp-dev perl
 
 .. include:: building-libyang.rst
 
-Get FRR, compile it and install it (from Git)
----------------------------------------------
-
-**This assumes you want to build and install FRR from source and not
-using any packages**
+Building & Installing FRR
+-------------------------
 
-Add frr groups and user
+Add FRR user and groups
 ^^^^^^^^^^^^^^^^^^^^^^^
 
-::
+.. code-block:: console
 
-    sudo groupadd -r -g 92 frr
-    sudo groupadd -r -g 85 frrvty
-    sudo adduser --system --ingroup frr --home /var/run/frr/ \
-       --gecos "FRR suite" --shell /sbin/nologin frr
-    sudo usermod -a -G frrvty frr
+   sudo groupadd -r -g 92 frr
+   sudo groupadd -r -g 85 frrvty
+   sudo adduser --system --ingroup frr --home /var/run/frr/ \
+      --gecos "FRR suite" --shell /sbin/nologin frr
+   sudo usermod -a -G frrvty frr
 
-Download Source, configure and compile it
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Compile
+^^^^^^^
 
-(You may prefer different options on configure statement. These are just
-an example.)
+.. include:: include-compile.rst
 
-::
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-    git clone https://github.com/frrouting/frr.git frr
-    cd frr
-    ./bootstrap.sh
-    ./configure \
-        --prefix=/usr \
-        --enable-exampledir=/usr/share/doc/frr/examples/ \
-        --localstatedir=/var/run/frr \
-        --sbindir=/usr/lib/frr \
-        --sysconfdir=/etc/frr \
-        --enable-multipath=64 \
-        --enable-user=frr \
-        --enable-group=frr \
-        --enable-vty-group=frrvty \
-        --enable-configfile-mask=0640 \
-        --enable-logfile-mask=0640 \
-        --enable-fpm \
-        --enable-systemd=yes \
-        --with-pkg-git-version \
-        --with-pkg-extra-version=-MyOwnFRRVersion
-    make
-    make check
-    sudo make install
-
-Create empty FRR configuration files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. code-block:: console
 
-::
+   sudo install -m 775 -o frr -g frr -d /var/log/frr
+   sudo install -m 775 -o frr -g frrvty -d /etc/frr
+   sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
 
-    sudo install -m 755 -o frr -g frr -d /var/log/frr
-    sudo install -m 775 -o frr -g frrvty -d /etc/frr
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
-    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
-    sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
-
-Enable IPv4 & IPv6 forwarding
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the
-other settings)
+Tweak sysctls
+^^^^^^^^^^^^^
+
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
+
+Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
+other settings):
 
 ::
 
-    # Uncomment the next line to enable packet forwarding for IPv4
-    net.ipv4.ip_forward=1
+   # Uncomment the next line to enable packet forwarding for IPv4
+   net.ipv4.ip_forward=1
+
+   # Uncomment the next line to enable packet forwarding for IPv6
+   #  Enabling this option disables Stateless Address Autoconfiguration
+   #  based on Router Advertisements for this host
+   net.ipv6.conf.all.forwarding=1
 
-    # Uncomment the next line to enable packet forwarding for IPv6
-    #  Enabling this option disables Stateless Address Autoconfiguration
-    #  based on Router Advertisements for this host
-    net.ipv6.conf.all.forwarding=1
+Reboot or use ``sysctl -p`` to apply the same config to the running system.
 
-Enable MPLS Forwarding (with Linux Kernel >= 4.5)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Add MPLS kernel modules
+"""""""""""""""""""""""
+
+.. warning::
+
+   MPLS is not supported on Ubuntu 16.04 with the default kernel. MPLS requires
+   kernel 4.5 or higher. LDPD can be built, but may have limited use without
+   MPLS. For an updated Ubuntu Kernel, see
+   http://kernel.ubuntu.com/~kernel-ppa/mainline/
 
-Edit ``/etc/sysctl.conf`` and the following lines. Make sure to add a
-line equal to ``net.mpls.conf.eth0.input`` or each interface used with
-MPLS
+Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default.  To
+enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
 
 ::
 
-    # Enable MPLS Label processing on all interfaces
-    net.mpls.conf.eth0.input=1
-    net.mpls.conf.eth1.input=1
-    net.mpls.conf.eth2.input=1
-    net.mpls.platform_labels=100000
+   # Load MPLS Kernel Modules
+   mpls_router
+   mpls_iptunnel
 
-Add MPLS kernel modules
-^^^^^^^^^^^^^^^^^^^^^^^
 
-Add the following lines to ``/etc/modules-load.d/modules.conf``:
+And load the kernel modules on the running system:
 
-::
+.. code-block:: console
 
-    # Load MPLS Kernel Modules
-    mpls-router
-    mpls-iptunnel
+   sudo modprobe mpls-router mpls-iptunnel
 
-**Reboot** or use ``sysctl -p`` to apply the same config to the running
-system
+Enable MPLS Forwarding
+""""""""""""""""""""""
 
-Install the systemd service (if rebooted from last step, change directory back to frr directory)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
+equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
 
 ::
 
-    sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
-    sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
-    sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
-    sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+   # Enable MPLS Label processing on all interfaces
+   net.mpls.conf.eth0.input=1
+   net.mpls.conf.eth1.input=1
+   net.mpls.conf.eth2.input=1
+   net.mpls.platform_labels=100000
 
-Enable daemons
-^^^^^^^^^^^^^^
+Install service files
+^^^^^^^^^^^^^^^^^^^^^
 
-| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for
-  those daemons you want to start by systemd.
-| For example.
+.. code-block:: console
 
-::
+   sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
+   sudo systemctl enable frr
 
-    zebra=yes
-    bgpd=yes
-    ospfd=yes
-    ospf6d=yes
-    ripd=yes
-    ripngd=yes
-    isisd=yes
+Enable daemons
+^^^^^^^^^^^^^^
 
-Enable the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^^
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``watchfrr_enable=...`` and ``zebra=...`` etc.  Enable the daemons
+as required by changing the value to ``yes``.
 
--  systemctl enable frr
+Start FRR
+^^^^^^^^^
 
-Start the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^
+.. code-block:: console
 
--  systemctl start frr
--  use ``systemctl status frr`` to check its status.
+   systemctl start frr
index 089d5a216a5d02986c2f4a9c5c3e59093640ef2d..6f7f0acd11237b45b83571a295b08b62ef784909 100644 (file)
@@ -1,55 +1,44 @@
 Ubuntu 18.04 LTS
 ================
 
-Install dependencies
---------------------
+This document describes installation from source. If you want to build a
+``deb``, see :ref:`packaging-debian`.
 
-Required packages
-^^^^^^^^^^^^^^^^^
+Installing Dependencies
+-----------------------
 
-::
+.. code-block:: console
 
+   sudo apt update
    sudo apt-get install \
       git autoconf automake libtool make gawk libreadline-dev texinfo \
       pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \
-      libc-ares-dev python3-dev libsystemd-dev python-ipaddress \
-      python3-sphinx install-info build-essential libsystemd-dev
+      libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \
+      install-info build-essential libsystemd-dev libsnmp-dev perl
 
 .. include:: building-libyang.rst
 
-Optional packages
-^^^^^^^^^^^^^^^^^
-
-Dependencies for additional functionality can be installed as-desired.
-
 Protobuf
-~~~~~~~~
+^^^^^^^^
 
-::
+.. code-block:: console
 
-   sudo apt-get install \
-       protobuf-c-compiler \
-       libprotobuf-c-dev
+   sudo apt-get install protobuf-c-compiler libprotobuf-c-dev
 
 ZeroMQ
-~~~~~~
-
-::
+^^^^^^
 
-   sudo apt-get install \
-       libzmq5 \
-       libzmq3-dev
+.. code-block:: console
 
-Get FRR, compile it and install it (from Git)
----------------------------------------------
+   sudo apt-get install libzmq5 libzmq3-dev
 
-**This assumes you want to build and install FRR from source and not
-using any packages**
+Building & Installing FRR
+-------------------------
 
-Add frr groups and user
+Add FRR user and groups
 ^^^^^^^^^^^^^^^^^^^^^^^
 
-::
+.. code-block:: console
 
    sudo groupadd -r -g 92 frr
    sudo groupadd -r -g 85 frrvty
@@ -57,104 +46,29 @@ Add frr groups and user
       --gecos "FRR suite" --shell /sbin/nologin frr
    sudo usermod -a -G frrvty frr
 
-Download source
-^^^^^^^^^^^^^^^
-
-::
-
-   git clone https://github.com/frrouting/frr.git frr
-
-Configure
-^^^^^^^^^
-Options below are provided as an example.
-
-.. seealso:: *Installation* section of user guide
-
-.. code-block:: shell
-
-   cd frr
-   ./bootstrap.sh
-   ./configure \
-       --prefix=/usr \
-       --enable-exampledir=/usr/share/doc/frr/examples/ \
-       --localstatedir=/var/run/frr \
-       --sbindir=/usr/lib/frr \
-       --sysconfdir=/etc/frr \
-       --enable-multipath=64 \
-       --enable-user=frr \
-       --enable-group=frr \
-       --enable-vty-group=frrvty \
-       --enable-configfile-mask=0640 \
-       --enable-logfile-mask=0640 \
-       --enable-fpm \
-       --enable-systemd=yes \
-       --with-pkg-git-version \
-       --with-pkg-extra-version=-MyOwnFRRVersion
-
-If optional packages were installed, the associated feature may now be
-enabled.
-
-.. option:: --enable-protobuf
-
-Enable support for protobuf transport
-
-.. option:: --enable-zeromq
-
-Enable support for ZeroMQ transport
-
 Compile
 ^^^^^^^
 
-::
-
-   make
-   make check
-   sudo make install
-
-Create empty FRR configuration files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. include:: include-compile.rst
 
-Although not strictly necessary, it's good practice to create empty
-configuration files _before_ starting FRR. This assures that the permissions
-are correct. If the files are not already present, FRR will create them.
+Install FRR configuration files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-It's also important to consider _which_ files to create. FRR supports writing
-configuration to a monolithic file, :file:`/etc/frr/frr.conf`.
+.. code-block:: console
 
-.. seealso:: *VTYSH* section of user guide
-
-The presence of :file:`/etc/frr/frr.conf` on startup implicitly configures FRR
-to ignore daemon-specific configuration files.
-
-Daemon-specific configuration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-::
-
-   sudo install -m 755 -o frr -g frr -d /var/log/frr
+   sudo install -m 775 -o frr -g frr -d /var/log/frr
    sudo install -m 775 -o frr -g frrvty -d /etc/frr
-   sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
-   sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
-   sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf
-   sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf
-   sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf
-   sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf
-   sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf
-   sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
-   sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
-   sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
-
-Monolithic configuration
-~~~~~~~~~~~~~~~~~~~~~~~~
+   sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf
+   sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons
 
-::
+Tweak sysctls
+^^^^^^^^^^^^^
 
-   sudo install -m 755 -o frr -g frr -d /var/log/frr
-   sudo install -m 775 -o frr -g frrvty -d /etc/frr
-   sudo install -m 640 -o frr -g frr /dev/null /etc/frr/frr.conf
-
-Enable IPv4 & IPv6 forwarding
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and
+MPLS (if supported by your platform). If your platform does not support MPLS,
+skip the MPLS related configuration in this section.
 
 Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the
 other settings):
@@ -169,8 +83,10 @@ other settings):
    #  based on Router Advertisements for this host
    net.ipv6.conf.all.forwarding=1
 
+Reboot or use ``sysctl -p`` to apply the same config to the running system.
+
 Add MPLS kernel modules
-^^^^^^^^^^^^^^^^^^^^^^^
+"""""""""""""""""""""""
 
 Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default.  To
 enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
@@ -181,10 +97,15 @@ enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`:
    mpls_router
    mpls_iptunnel
 
-Reboot or use ``sysctl -p`` to apply the same config to the running system.
+
+And load the kernel modules on the running system:
+
+.. code-block:: console
+
+   sudo modprobe mpls-router mpls-iptunnel
 
 Enable MPLS Forwarding
-^^^^^^^^^^^^^^^^^^^^^^
+""""""""""""""""""""""
 
 Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line
 equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
@@ -197,48 +118,24 @@ equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS.
    net.mpls.conf.eth2.input=1
    net.mpls.platform_labels=100000
 
-Install the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Install service files
+^^^^^^^^^^^^^^^^^^^^^
 
-::
+.. code-block:: console
 
    sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
-   sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons
-   sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf
-   sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf
+   sudo systemctl enable frr
 
 Enable daemons
 ^^^^^^^^^^^^^^
 
-Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for those
-daemons you want to start by systemd.  For example:
-
-::
-
-   zebra=yes
-   bgpd=yes
-   ospfd=yes
-   ospf6d=yes
-   ripd=yes
-   ripngd=yes
-   isisd=yes
-
-Enable the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^^
+Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the
+section with ``watchfrr_enable=...`` and ``zebra=...`` etc.  Enable the daemons
+as required by changing the value to ``yes``.
 
-Enabling the systemd service causes FRR to be started upon boot. To enable it,
-use the following command:
-
-.. code-block:: shell
-
-   systemctl enable frr
-
-Start the systemd service
-^^^^^^^^^^^^^^^^^^^^^^^^^
+Start FRR
+^^^^^^^^^
 
 .. code-block:: shell
 
    systemctl start frr
-
-After starting the service, you can use ``systemctl status frr`` to check its
-status.
index c45c294b75295db8640da9422235c04e2a093fc7..41fe09e322fef4445a432106dc750c8de0ac3877 100644 (file)
@@ -1,57 +1,55 @@
-The libyang library can be installed from third-party packages available `here
-<https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
+FRR depends on the relatively new ``libyang`` library to provide YANG/NETCONF
+support. Unfortunately, most distributions do not yet offer a ``libyang``
+package from their repositories. Therefore we offer two options to install this
+library.
 
-Note: the libyang dev/devel packages need to be installed in addition
-to the libyang core package in order to build FRR successfully.
+**Option 1: Binary Install**
+
+The FRR project builds binary ``libyang`` packages, which we offer for download
+`here <https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
 
 .. warning::
-   libyang ABI version 0.16.74 or newer will be required to build FRR in the
-   near future since it significantly eases build and installation
-   considerations.  "0.16-r3" is equal to 0.16.105 and will work, "0.16-r2"
-   is equal to 0.16.52 and will stop working.  The CI artifacts will be
-   updated shortly.
 
-For example, for CentOS 7.x:
+   ``libyang`` version 0.16.74 or newer is required to build FRR.
+
+.. note::
 
-.. code-block:: shell
+   The ``libyang`` development packages need to be installed in addition to the
+   libyang core package in order to build FRR successfully. Make sure to
+   download and install those from the link above alongside the binary
+   packages.
 
-   wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/CentOS-7-x86_64-Packages/libyang-0.16.46-0.x86_64.rpm
-   wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/CentOS-7-x86_64-Packages/libyang-devel-0.16.46-0.x86_64.rpm
-   sudo rpm -i libyang-0.16.46-0.x86_64.rpm libyang-devel-0.16.46-0.x86_64.rpm
+   Depending on your platform, you may also need to install the PCRE
+   development package. Typically this is ``libpcre-dev`` or ``pcre-devel``.
 
-or Ubuntu 18.04:
+.. note::
 
-.. code-block:: shell
+   For Debian-based systems, the official ``libyang`` package requires recent
+   versions of ``swig`` (3.0.12) and ``debhelper`` (11) which are only
+   available in Debian buster (10).  However, ``libyang`` packages built on
+   Debian buster can be installed on both Debian jessie (8) and Debian stretch
+   (9), as well as various Ubuntu systems.  The ``python3-yang`` package will
+   not work, but the other packages (``libyang-dev`` is the one needed for FRR)
+   will.
 
-   wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang-dev_0.16.46_amd64.deb
-   wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang_0.16.46_amd64.deb
-   sudo apt install libpcre3-dev
-   sudo dpkg -i libyang-dev_0.16.46_amd64.deb libyang_0.16.46_amd64.deb
+**Option 2: Source Install**
 
 .. note::
-   For Debian-based systems, the official libyang package requires recent
-   versions of swig (3.0.12) and debhelper (11) which are only available in
-   Debian buster (10).  However, libyang packages built on Debian buster can
-   be installed on both Debian jessie (8) and Debian stretch (9), as well as
-   various Ubuntu systems.  The python3-yang package will not work, but the
-   other packages (libyang-dev is the one needed for FRR) will.
 
-Alternatively, libyang can be built and installed manually by following
-the steps below:
+   Ensure that the `libyang build requirements
+   <https://github.com/CESNET/libyang/blob/master/README.md#build-requirements>`_
+   are met before continuing. Usually this entails installing ``cmake`` and
+   ``libpcre-dev`` or ``pcre-devel``.
 
-.. code-block:: shell
+.. code-block:: console
 
-   git clone https://github.com/opensourcerouting/libyang
+   git clone https://github.com/CESNET/libyang.git
    cd libyang
-   git checkout -b tmp origin/tmp
    mkdir build; cd build
-   cmake -DENABLE_LYD_PRIV=ON ..
+   cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
    make
    sudo make install
 
 When building libyang on CentOS 6, it's also necessary to pass the
 ``-DENABLE_CACHE=OFF`` parameter to cmake.
 
-Note: please check the `libyang build requirements
-<https://github.com/CESNET/libyang/blob/master/README.md#build-requirements>`_
-first.
index 96559b0abe396709dd4db989adc3265f912a267a..c13fb10ffc290da4e88d4b4a2615f3b056431a61 100644 (file)
@@ -12,7 +12,7 @@ Building FRR
    building-frr-for-centos7
    building-frr-for-debian8
    building-frr-for-debian9
-   building-frr-for-fedora24
+   building-frr-for-fedora
    building-frr-for-freebsd10
    building-frr-for-freebsd11
    building-frr-for-freebsd9
index af8673e5fabf09e27ca8835c00919be65b8be5d9..9acfab739a943f376ccc58fb23dcb843c402781b 100644 (file)
@@ -131,7 +131,7 @@ language = None
 
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
-exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst']
+exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst', 'include-compile.rst']
 
 # The reST default role (used for this markup: `text`) to use for all
 # documents.
index 4140a0d171e4f940b6b55a5cacef66f593fe8db6..10fe6b9c43605b656e94978a6df37455128eec61 100644 (file)
@@ -6,7 +6,7 @@ Hooks
 Libfrr provides type-safe subscribable hook points where other pieces of
 code can add one or more callback functions.  "type-safe" in this case
 applies to the function pointers used for subscriptions.  The
-implementations checks (at compile-time) wheter a callback to be added has
+implementations checks (at compile-time) whether a callback to be added has
 the appropriate function signature (parameters) for the hook.
 
 Example:
diff --git a/doc/developer/include-compile.rst b/doc/developer/include-compile.rst
new file mode 100644 (file)
index 0000000..0ff0ae3
--- /dev/null
@@ -0,0 +1,37 @@
+Clone the FRR git repo and use the included ``configure`` script to configure
+FRR's build time options to your liking. The full option listing can be
+obtained by running ``./configure -h``. The options shown below are examples.
+
+.. note::
+
+   If your platform uses ``systemd``, please make sure to add
+   ``--enable-systemd=yes`` to your configure options.
+
+.. code-block:: console
+
+   git clone https://github.com/frrouting/frr.git frr
+   cd frr
+   ./bootstrap.sh
+   ./configure \
+       --prefix=/usr \
+       --includedir=\${prefix}/include \
+       --enable-exampledir=\${prefix}/share/doc/frr/examples \
+       --bindir=\${prefix}/bin \
+       --sbindir=\${prefix}/lib/frr \
+       --libdir=\${prefix}/lib/frr \
+       --libexecdir=\${prefix}/lib/frr \
+       --localstatedir=/var/run/frr \
+       --sysconfdir=/etc/frr \
+       --with-moduledir=\${prefix}/lib/frr/modules \
+       --with-libyang-pluginsdir=\${prefix}/lib/frr/libyang_plugins \
+       --enable-configfile-mask=0640 \
+       --enable-logfile-mask=0640 \
+       --enable-snmp=agentx \
+       --enable-multipath=64 \
+       --enable-user=frr \
+       --enable-group=frr \
+       --enable-vty-group=frrvty \
+       --with-pkg-git-version \
+       --with-pkg-extra-version=-MyOwnFRRVersion
+   make
+   sudo make install
index 4338d900e65b74835313b9a9ca430e8f65f8b9d8..1dc188515827e4b9cd5a774b20ff230fd47b2844 100644 (file)
@@ -18,7 +18,7 @@ maybe by a syslog collector from all routers.)  Therefore, anything that
 needs to get the user in the loop—and only these things—are warnings or
 errors.
 
-Note that this doesn't neccessarily mean the user needs to fix something in
+Note that this doesn't necessarily mean the user needs to fix something in
 the FRR instance.  It also includes when we detect something else needs
 fixing, for example another router, the system we're running on, or the
 configuration.  The common point is that the user should probably do
index 43cbe002cffd670719a31ce0d751a6073591c322..153131bab927d2144a8a7c5989930f1232cac04e 100644 (file)
@@ -3,7 +3,7 @@
 Memtypes
 ========
 
-FRR includes wrappers arround ``malloc()`` and ``free()`` that count the number
+FRR includes wrappers around ``malloc()`` and ``free()`` that count the number
 of objects currently allocated, for each of a defined ``MTYPE``.
 
 To this extent, there are *memory groups* and *memory types*.  Each memory
index 90fc52efd0e7187d29c5f281483e7559efc0a64f..f4f38a63e904fcbd50d9119e2f46d495e7ef1120 100644 (file)
@@ -284,7 +284,7 @@ Each message begins with the following header:
 The message type field can take one of the following values:
 
 +-------------------------------+---------+
-| Messages to OSPF deamon       | Value   |
+| Messages to OSPF daemon       | Value   |
 +===============================+=========+
 | MSG\_REGISTER\_OPAQUETYPE     | 1       |
 +-------------------------------+---------+
@@ -300,7 +300,7 @@ The message type field can take one of the following values:
 +-------------------------------+---------+
 
 +-----------------------------+---------+
-| Messages from OSPF deamon   | Value   |
+| Messages from OSPF daemon   | Value   |
 +=============================+=========+
 | MSG\_REPLY                  | 10      |
 +-----------------------------+---------+
index 4a673b155b1670f0c88f77aaa05cb39c4e7832b2..23bc803d76368f32d17ee0958e0e99e9e16915fb 100644 (file)
@@ -31,7 +31,7 @@ Implementation details
 Concepts
 ^^^^^^^^
 
-Segment Routing used 3 differents OPAQUE LSA in OSPF to carry the various
+Segment Routing used 3 different OPAQUE LSA in OSPF to carry the various
 information:
 
 * **Router Information:** flood the Segment Routing capabilities of the node.
@@ -40,7 +40,7 @@ information:
 * **Extended Link:** flood the Adjaceny and Lan Adjacency Segment Identifier
 * **Extended Prefix:** flood the Prefix Segment Identifier
 
-The implementation follow previous TE and Router Information codes. It used the
+The implementation follows previous TE and Router Information codes. It used the
 OPAQUE LSA functions defined in ospf_opaque.[c,h] as well as the OSPF API. This
 latter is mandatory for the implementation as it provides the Callback to
 Segment Routing functions (see below) when an Extended Link / Prefix or Router
@@ -71,7 +71,7 @@ The figure below shows the relation between the various files:
   (4.0.0.0), Extended Prefix (7.0.0.X) and Link (8.0.0.X) by ospf_ri.c,
   respectively ospf_ext.c.
 * ospf_ri.c send back to ospf_sr.c received Router Information LSA and update
-  Self Router Information LSA with paramters provided by ospf_sr.c i.e. SRGB
+  Self Router Information LSA with parameters provided by ospf_sr.c i.e. SRGB
   and MSD. It use ospf_opaque.c functions to send/received these Opaque LSAs.
 * ospf_ext.c send back to ospf_sr.c received Extended Prefix and Link Opaque
   LSA and send self Extended Prefix and Link Opaque LSA through ospf_opaque.c
@@ -129,8 +129,8 @@ Opaque LSA it is the `ospf_opaque_lsa_install_hook()`.  For deletion, it is
 Note that incoming LSA which is already present in the LSDB will be inserted
 after the old instance of this LSA remove from the LSDB. Thus, after the first
 time, each incoming LSA will trigger a `delete` following by an `install`. This
-is not very helpfull to handle real LSA deletion. In fact, LSA deletion is done
-by Flushing LSA i.e. flood LSA after seting its age to MAX_AGE. Then, a garbage
+is not very helpful to handle real LSA deletion. In fact, LSA deletion is done
+by Flushing LSA i.e. flood LSA after setting its age to MAX_AGE. Then, a garbage
 function has the role to remove all LSA with `age == MAX_AGE` in the LSDB. So,
 to handle LSA Flush, the best is to look to the LSA age to determine if it is
 an installation or a future deletion i.e. the flushed LSA is first store in the
@@ -144,7 +144,7 @@ introduced. When this command is activated, function
 `ospf_router_info_update_sr()` is called to indicate to Router Information
 process that Segment Routing TLVs must be flood. Same function is called to
 modify the Segment Routing Global Block (SRGB) and Maximum Stack Depth (MSD)
-TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possiblity
+TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possibility
 to modify this TLV is offer by the code.
 
 When Opaque LSA Tyep 4 i.e. Router Information are stored in LSDB, function
@@ -159,8 +159,8 @@ Extended Link Prefix LSAs
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Like for Router Information, Segment Routing is activate at the Extended
-Link/Prefix level with new `segment-routing on` command. This trigger
-automtically the flooding of Extended Link LSA for all ospf interface where
+Link/Prefix level with new `segment-routing on` command. This triggers
+automatically the flooding of Extended Link LSA for all ospf interfaces where
 adjacency is full. For Extended Prefix LSA, the new CLI command
 `segment-routing prefix ...` will trigger the flooding of Prefix SID
 TLV/SubTLVs.
@@ -255,7 +255,7 @@ The first segment-routing statement enable it. The Second one set the SRGB,
 third line the MSD and finally, set the Prefix SID index for a given prefix.
 Note that only prefix of Loopback interface could be configured with a Prefix
 SID. It is possible to add `no-php-flag` at the end of the prefix command to
-disbale Penultimate Hop Popping. This advertises peers that they MUST NOT pop
+disable Penultimate Hop Popping. This advertises to peers that they MUST NOT pop
 the MPLS label prior to sending the packet.
 
 Known limitations
index c660f986804fc69761bc7c633a4f468988679d2c..b57286d5a1ecd57c36ef5d468866dadc736eedaa 100644 (file)
@@ -1,3 +1,5 @@
+.. _packaging-debian:
+
 Packaging Debian
 ================
 
diff --git a/doc/developer/packaging-redhat.rst b/doc/developer/packaging-redhat.rst
new file mode 100644 (file)
index 0000000..f6b9931
--- /dev/null
@@ -0,0 +1,85 @@
+.. _packaging-redhat:
+
+Packaging Red Hat
+=================
+
+Tested on CentOS 6, CentOS 7 and Fedora 24.
+
+1. On CentOS 6, refer to :ref:`building-centos6` for details on installing
+   sufficiently up-to-date package versions to enable building FRR.
+
+   Newer automake/autoconf/bison is only needed to build the RPM and is **not**
+   needed to install the binary RPM package.
+
+2. Install the build dependencies for your platform. Refer to the
+   platform-specific build documentation on how to do this.
+
+3. Install the following additional packages::
+
+      yum install rpm-build net-snmp-devel pam-devel libcap-devel
+
+   If your platform uses systemd::
+
+      yum install systemd-devel
+
+   If ``yum`` is not present on your system, use ``dnf`` instead.
+
+3. Checkout FRR::
+
+      git clone https://github.com/frrouting/frr.git frr
+
+4. Run Bootstrap and make distribution tar.gz::
+
+      cd frr
+      ./bootstrap.sh
+      ./configure --with-pkg-extra-version=-MyRPMVersion SPHINXBUILD=sphinx-build2.7
+      make dist
+
+   .. note::
+
+      The only ``configure`` option respected when building RPMs is
+      ``--with-pkg-extra-version``.
+
+5. Create RPM directory structure and populate with sources::
+
+     mkdir rpmbuild
+     mkdir rpmbuild/SOURCES
+     mkdir rpmbuild/SPECS
+     cp redhat/*.spec rpmbuild/SPECS/
+     cp frr*.tar.gz rpmbuild/SOURCES/
+
+6. Edit :file:`rpm/SPECS/frr.spec` with configuration as needed.
+
+   Look at the beginning of the file and adjust the following parameters to
+   enable or disable features as required::
+
+      ############### FRRouting (FRR) configure options #################
+      # with-feature options
+      %{!?with_pam:           %global  with_pam           0 }
+      %{!?with_ospfclient:    %global  with_ospfclient    1 }
+      %{!?with_ospfapi:       %global  with_ospfapi       1 }
+      %{!?with_irdp:          %global  with_irdp          1 }
+      %{!?with_rtadv:         %global  with_rtadv         1 }
+      %{!?with_ldpd:          %global  with_ldpd          1 }
+      %{!?with_nhrpd:         %global  with_nhrpd         1 }
+      %{!?with_eigrp:         %global  with_eigrpd        1 }
+      %{!?with_shared:        %global  with_shared        1 }
+      %{!?with_multipath:     %global  with_multipath     256 }
+      %{!?frr_user:           %global  frr_user           frr }
+      %{!?vty_group:          %global  vty_group          frrvty }
+      %{!?with_fpm:           %global  with_fpm           0 }
+      %{!?with_watchfrr:      %global  with_watchfrr      1 }
+      %{!?with_bgp_vnc:       %global  with_bgp_vnc       0 }
+      %{!?with_pimd:          %global  with_pimd          1 }
+      %{!?with_rpki:          %global  with_rpki          0 }
+
+7. Build the RPM::
+
+      rpmbuild --define "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/frr.spec
+
+   If building with RPKI, then download and install the additional RPKI
+   packages from
+   https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact
+
+If all works correctly, then you should end up with the RPMs under
+:file:`rpmbuild/RPMS` and the source RPM under :file:`rpmbuild/SRPMS`.
index 27e6e155fb1c25f36e9829d663f1b50be30a1bcd..b174a9660c2d206373e40c9dd8bc49f07daeb52c 100644 (file)
@@ -7,3 +7,4 @@ Packaging
 
    maintainer-release-build
    packaging-debian
+   packaging-redhat
index d7699136745fb14f6dedbd96b06edf8acf74b64e..7ae48881abb87a338bf0d43ea8c2e13502bd1346 100644 (file)
@@ -5,13 +5,12 @@
 dev_RSTFILES = \
        doc/developer/bgp-typecodes.rst \
        doc/developer/bgpd.rst \
-       doc/developer/building-frr-for-openwrt.rst \
        doc/developer/building-frr-for-alpine.rst \
        doc/developer/building-frr-for-centos6.rst \
        doc/developer/building-frr-for-centos7.rst \
        doc/developer/building-frr-for-debian8.rst \
        doc/developer/building-frr-for-debian9.rst \
-       doc/developer/building-frr-for-fedora24.rst \
+       doc/developer/building-frr-for-fedora.rst \
        doc/developer/building-frr-for-freebsd10.rst \
        doc/developer/building-frr-for-freebsd11.rst \
        doc/developer/building-frr-for-freebsd9.rst \
@@ -19,6 +18,7 @@ dev_RSTFILES = \
        doc/developer/building-frr-for-netbsd7.rst \
        doc/developer/building-frr-for-omnios.rst \
        doc/developer/building-frr-for-openbsd6.rst \
+       doc/developer/building-frr-for-openwrt.rst \
        doc/developer/building-frr-for-ubuntu1404.rst \
        doc/developer/building-frr-for-ubuntu1604.rst \
        doc/developer/building-frr-for-ubuntu1804.rst \
@@ -27,6 +27,7 @@ dev_RSTFILES = \
        doc/developer/cli.rst \
        doc/developer/conf.py \
        doc/developer/hooks.rst \
+       doc/developer/include-compile.rst \
        doc/developer/index.rst \
        doc/developer/library.rst \
        doc/developer/logging.rst \
@@ -37,8 +38,9 @@ dev_RSTFILES = \
        doc/developer/ospf-api.rst \
        doc/developer/ospf-sr.rst \
        doc/developer/ospf.rst \
-       doc/developer/packaging.rst \
        doc/developer/packaging-debian.rst \
+       doc/developer/packaging-redhat.rst
+       doc/developer/packaging.rst \
        doc/developer/testing.rst \
        doc/developer/topotests-snippets.rst \
        doc/developer/topotests.rst \
index 649229b43341b6557a42064c41c5004e102fb210..fb3c928a77d57dae678b952a6d210fdbfcd651e6 100644 (file)
@@ -48,17 +48,17 @@ A sample of this snippet in a test can be found `here
 Interacting with equipment
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-You might want to interact with the topology equipments during the tests and
+You might want to interact with the topology equipment during the tests and
 there are different ways to do so.
 
 Notes:
 
-1. When using the Topogen API, all the equipments code derive from ``Topogear``
+1. When using the Topogen API, all the equipment code derives from ``Topogear``
    (`lib/topogen.py <lib/topogen.py>`__). If you feel brave you can look by
-   yourself how the abstractions that will be mentioned here works.
+   yourself how the abstractions that will be mentioned here work.
 
 2. When not using the ``Topogen`` API there is only one way to interact with
-   the equipments, which is by calling the ``mininet`` API functions directly
+   the equipment, which is by calling the ``mininet`` API functions directly
    to spawn commands.
 
 Interacting with the Linux sandbox
@@ -149,7 +149,7 @@ Translating vtysh JSON output into Python structures:
 
 .. note::
 
-   ``vtysh_(multi)cmd`` is only available for router type of equipments.
+   ``vtysh_(multi)cmd`` is only available for router types of equipment.
 
 Invoking mininet CLI
 ^^^^^^^^^^^^^^^^^^^^
@@ -195,7 +195,7 @@ Loading JSON from a file:
 Comparing JSON output
 ^^^^^^^^^^^^^^^^^^^^^
 
-After obtaining JSON output formated with Python data structures, you may use
+After obtaining JSON output formatted with Python data structures, you may use
 it to assert a minimalist schema:
 
 .. code:: py
index aa06c8dffd7defd9b373557c29f9097fc9a39b44..605b9c9a0cfeb588742850be73e8e94de4d13228 100644 (file)
@@ -151,7 +151,7 @@ Collect Memory Leak Information
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 FRR processes have the capabilities to report remaining memory allocations upon
-exit. To enable the reporting of the memory, define an enviroment variable
+exit. To enable the reporting of the memory, define an environment variable
 ``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.::
 
    export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
@@ -410,7 +410,7 @@ Defining the Topology
 The first step to write a new test is to define the topology. This step can be
 done in many ways, but the recommended is to use Graphviz to generate a drawing
 of the topology. It allows us to see the topology graphically and to see the
-names of equipments, links and addresses.
+names of equipment, links and addresses.
 
 Here is an example of Graphviz dot file that generates the template topology
 :file:`tests/topotests/example-test/test_template.dot` (the inlined code might
index 4a52eb0544ac8c713f3d8ce0ac466c9e3d5cbecf..160676a7b1f7eb7c909f282940316fae11945c58 100644 (file)
@@ -43,7 +43,7 @@ simplifying the output. This is discussed in :ref:`vtysh-configuration`.
 Command Extraction
 ------------------
 
-When VTYSH is built, a Perl script named :file:`extract.pl` searches the FRR
+When VTYSH is built, a Perl script named :file:`extract.pl` searches the FRR
 codebase looking for ``DEFUN``'s. It extracts these ``DEFUN``'s, transforms
 them into ``DEFSH``'s and appends them to ``vtysh_cmd.c``. Each ``DEFSH``
 contains the name of the command plus ``_vtysh``, as well as a flag that
@@ -167,7 +167,7 @@ Protocol
 VTYSH communicates with FRR daemons by way of domain socket. Each daemon
 creates its own socket, typically in :file:`/var/run/frr/<daemon>.vty`. The
 protocol is very simple. In the VTYSH to daemon direction, messages are simply
-NULL-terminated strings, whose content are CLI commands. Here is a typical
+NUL-terminated strings, whose content are CLI commands. Here is a typical
 message from VTYSH to a daemon:
 
 ::
@@ -178,7 +178,7 @@ message from VTYSH to a daemon:
    00000010: 6c0a 00                                  l..
 
 
-The response format has some more data in it. First is a NULL-terminated string
+The response format has some more data in it. First is a NUL-terminated string
 containing the plaintext response, which is just the output of the command that
 was sent in the request. This is displayed to the user. The plaintext response
 is followed by 3 null marker bytes, followed by a 1-byte status code that
index 1bb0886fd58d94d085468ba8f9a175fd5dc0e61f..b3b3a47cb03c6bbf64abc2df8742344930f1d7ed 100644 (file)
@@ -99,9 +99,14 @@ Bugfix releases are made as needed at 1 month intervals until the next
 ``MAJOR.MINOR`` release branch is pulled. Depending on the severity of the bugs,
 bugfix releases may occur sooner.
 
-Bugfixes are applied to the two most recent releases. Security fixes are
-backported to all releases less than or equal to at least one year old. Security
-fixes may also be backported to older releases depending on severity.
+Bugfixes are applied to the two most recent releases. However, backporting of bug
+fixes to older than the two most recent releases will not be prevented, if acked
+under the classical development workflow applying for a pull request.
+
+Security fixes are backported to all releases less than or equal to at least one
+year old. Security fixes may also be backported to older releases depending on
+severity.
+
 
 Long term support branches ( LTS )
 -----------------------------------------
@@ -128,7 +133,7 @@ branch is required. The work can be shared by multiple people. In all cases, the
 must be at least one person that is in charge of the maintenance branch. The person
 on people responsible for a maintenance branch must be a FRR maintainer. Note that
 they may choose to abandon support for the maintenance branch at any time. If
-noone takes over the responsibility of the LTS branch, then the support will be
+no one takes over the responsibility of the LTS branch, then the support will be
 discontinued.
 
 The LTS branch duties are the following ones:
@@ -371,7 +376,7 @@ system in which submissions from an individual representing one company should
 be merged by someone unaffiliated with that company.
 
 Guidelines for code review
-""""""""""""""""""""""""""
+--------------------------
 
 - As a rule of thumb, the depth of the review should be proportional to the
   scope and / or impact of the patch.
index f57bc1d27868eecc379211746d44bad55e19ef32..46240de1c0a1244679408c63de9ed88e3d7bdf5e 100644 (file)
@@ -129,7 +129,7 @@ language = None
 
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
-exclude_patterns = ['_build', 'common-options.rst', 'epilogue.rst', 'defines.rst']
+exclude_patterns = ['_build', 'common-options.rst', 'epilogue.rst', 'defines.rst', 'bfd-options.rst']
 
 # The reST default role (used for this markup: `text`) to use for all
 # documents.
index e1f7ec4ce83dd42592fd60da149ce4e677441cdb..cdf5e1967e47f340933b58572b8bbfb19ad20172 100644 (file)
@@ -1,3 +1,3 @@
 .. |synopsis-options| replace:: [-d|-t|-dt] [-C] [-f config-file] [-i pid-file] [-z zclient-path] [-u user] [-g group] [-A vty-addr] [-P vty-port] [-M module[:options]] [-N pathspace] [--vty_socket vty-path] [--moduledir module-path]
 .. |synopsis-options-hv| replace:: [-h] [-v]
-.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), mtracebis(8)
+.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), fabricd(8), mtracebis(8)
index 8201fdf1b91b076d71e88a4afe7c95652dd69b62..8fbea29ee7ec42aef3cc83d2101d35baa2877422 100644 (file)
@@ -390,7 +390,7 @@ Terminal Mode Commands
 .. index:: find COMMAND...
 .. clicmd:: find COMMAND...
 
-   This commmand performs a simple substring search across all defined commands
+   This command performs a simple substring search across all defined commands
    in all modes. As an example, suppose you're in enable mode and can't
    remember where the command to turn OSPF segment routing on is:
 
index 5b453e75c3b9ef0f1b20fc753e3349e06635502a..be331ffb99577f7c680bbf97fccbff729c9e7b83 100644 (file)
@@ -511,8 +511,8 @@ cause may lead to routing instability or oscillation across multiple speakers
 in iBGP topologies. This can occur with full-mesh iBGP, but is particularly
 problematic in non-full-mesh iBGP topologies that further reduce the routing
 information known to each speaker. This has primarily been documented with iBGP
-route-reflection topologies. However, any route-hiding technologies potentially
-could also exacerbate oscillation with MED.
+:ref:`route-reflection <bgp-route-reflector>` topologies. However, any
+route-hiding technologies potentially could also exacerbate oscillation with MED.
 
 This second issue occurs where speakers each have only a subset of routes, and
 there are cycles in the preferences between different combinations of routes -
@@ -1145,7 +1145,7 @@ is 4 octet long. The following format is used to define the community value.
    ``graceful-shutdown`` represents well-known communities value
    ``GRACEFUL_SHUTDOWN`` ``0xFFFF0000`` ``65535:0``. :rfc:`8326` implements
    the purpose Graceful BGP Session Shutdown to reduce the amount of
-   lost traffic when taking BGP sessions down for maintainance. The use
+   lost traffic when taking BGP sessions down for maintenance. The use
    of the community needs to be supported from your peers side to
    actually have any effect.
 
@@ -1176,20 +1176,20 @@ is 4 octet long. The following format is used to define the community value.
 ``llgr-stale``
    ``llgr-stale`` represents well-known communities value ``LLGR_STALE``
    ``0xFFFF0006`` ``65535:6``.
-   Assigned and intented only for use with routers supporting the
+   Assigned and intended only for use with routers supporting the
    Long-lived Graceful Restart Capability  as described in
    [Draft-IETF-uttaro-idr-bgp-persistence]_.
-   Routers recieving routes with this community may (depending on
+   Routers receiving routes with this community may (depending on
    implementation) choose allow to reject or modify routes on the
    presence or absence of this community.
 
 ``no-llgr``
    ``no-llgr`` represents well-known communities value ``NO_LLGR``
    ``0xFFFF0007`` ``65535:7``.
-   Assigned and intented only for use with routers supporting the
+   Assigned and intended only for use with routers supporting the
    Long-lived Graceful Restart Capability  as described in
    [Draft-IETF-uttaro-idr-bgp-persistence]_.
-   Routers recieving routes with this community may (depending on
+   Routers receiving routes with this community may (depending on
    implementation) choose allow to reject or modify routes on the
    presence or absence of this community.
 
@@ -1251,7 +1251,7 @@ UPDATE messages.
 There are two types of community list:
 
 standard
-   This type accepts an explicit value for the atttribute.
+   This type accepts an explicit value for the attribute.
 
 expanded
    This type accepts a regular expression. Because the regex must be
@@ -2240,10 +2240,15 @@ Displaying Routes by AS Path
 Route Reflector
 ===============
 
-.. note:: This documentation is woefully incomplete.
+BGP routers connected inside the same AS through BGP belong to an internal
+BGP session, or IBGP. In order to prevent routing table loops, IBGP does not
+advertise IBGP-learned routes to other routers in the same session. As such,
+IBGP requires a full mesh of all peers. For large networks, this quickly becomes
+unscalable. Introducing route reflectors removes the need for the full-mesh.
 
-.. index:: bgp cluster-id A.B.C.D
-.. clicmd:: bgp cluster-id A.B.C.D
+When route reflectors are configured, these will reflect the routes announced
+by the peers configured as clients. A route reflector client is configured
+with:
 
 .. index:: neighbor PEER route-reflector-client
 .. clicmd:: neighbor PEER route-reflector-client
@@ -2251,6 +2256,13 @@ Route Reflector
 .. index:: no neighbor PEER route-reflector-client
 .. clicmd:: no neighbor PEER route-reflector-client
 
+To avoid single points of failure, multiple route reflectors can be configured.
+
+A cluster is a collection of route reflectors and their clients, and is used
+by route reflectors to avoid looping.
+
+.. index:: bgp cluster-id A.B.C.D
+.. clicmd:: bgp cluster-id A.B.C.D
 
 .. _routing-policy:
 
@@ -2469,7 +2481,7 @@ certainly contains silly mistakes, if not serious flaws.
    route-map rm-no-export permit 20
    !
    route-map rm-blackhole permit 10
-    description blackhole, up-pref and ensure it cant escape this AS
+    description blackhole, up-pref and ensure it cannot escape this AS
     set ip next-hop 127.0.0.1
     set local-preference 10
     set community additive no-export
index f6af88cac8124d8c0f2bb6a4548e0cf8fc34bf5d..b274afe8a25fdac34b27f6f2650593329fe7e8fb 100644 (file)
@@ -167,7 +167,7 @@ set.  That VRF will then be selected. The below full configuration example
 depicts how Route Targets are configured and how VRFs and cross VRF
 configuration is done.  Note that the VRF are mapped on Linux Network
 Namespaces. For data traffic to cross VRF boundaries, virtual ethernet
-interfaces are created with private IP adressing scheme.
+interfaces are created with private IP addressing scheme.
 
 .. code-block:: frr
 
@@ -322,7 +322,7 @@ There are some other known issues:
 - The validation procedure depicted in :rfc:`5575` is not available.
 
   This validation procedure has not been implemented, as this feature was not
-  used in the existing setups you shared wih us.
+  used in the existing setups you shared with us.
 
 - The filtering action shaper value, if positive, is not used to apply shaping.
 
index 4e1582ccd8f8a2a57b924b6e89d1f61fd24c05b8..964297292f2ca6c418254eb5ebacb3c18d878069 100644 (file)
@@ -272,10 +272,11 @@ options from the list below.
 .. option:: --enable-multipath=X
 
    Compile FRR with up to X way ECMP supported.  This number can be from 0-999.
-   For backwards compatability with older configure options when setting X = 0,
+   For backwards compatibility with older configure options when setting X = 0,
    we will build FRR with 64 way ECMP.  This is needed because there are
    hardcoded arrays that FRR builds towards, so we need to know how big to
-   make these arrays at build time.
+   make these arrays at build time.  Additionally if this parameter is
+   not passed in FRR will default to 16 ECMP.
 
 .. option:: --enable-shell-access
 
index b6a7cd5de03e172e7e62b077bbda273570644b48..ad0a8639a34a5ff09dc9bb72171aea936731a7b7 100644 (file)
@@ -218,7 +218,7 @@ To start OSPF process you have to specify the OSPF router.
    SPF-triggering event occurs within the hold-time of the previous SPF
    calculation.
 
-   This command supercedes the *timers spf* command in previous FRR
+   This command supersedes the *timers spf* command in previous FRR
    releases.
 
 .. index:: max-metric router-lsa [on-startup|on-shutdown] (5-86400)
index 638767c55777b4a54ee7497c1a24b6875650ec82..6230bf777a46cdcbf8e58eeae6b6823ef149c36a 100644 (file)
@@ -88,7 +88,7 @@ end destination.
 
    When a incoming packet matches the destination prefix specified, take the
    packet and forward according to the nexthops specified.  This command accepts
-   both v4 and v6 prefixes.  This command is used in conjuction of the
+   both v4 and v6 prefixes.  This command is used in conjunction of the
    :clicmd:`match src-ip PREFIX` command for matching.
 
 .. clicmd:: set nexthop-group NAME
index feb77db1e154615802f19cbd70bd6a2e4c4b69ea..f4611c520b16c0e33404647713687df1d2091215 100644 (file)
@@ -210,8 +210,8 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
 
    Set the IGMP version used on this interface. The default value is 3.
 
-.. index:: ip multicat boundary oil WORD
-.. clicmd:: ip multicat boundary oil WORD
+.. index:: ip multicast boundary oil WORD
+.. clicmd:: ip multicast boundary oil WORD
 
    Set a pim multicast boundary, based upon the WORD prefix-list. If a pim join
    or IGMP report is received on this interface and the Group is denied by the
index ca8f1f512fec16c08c614f2a6e3792e6fe3eb8d0..4568c2a9010c3cb34b6b8a40555c24ed350abce9 100644 (file)
@@ -29,7 +29,7 @@ documented elsewhere.
 Using SHARP
 ===========
 
-All sharp commands are under the enable node and preceeded by the ``sharp``
+All sharp commands are under the enable node and preceded by the ``sharp``
 keyword. At present, no sharp commands will be preserved in the config.
 
 .. index:: sharp install
index 9dfe1ea39c905d8755b5181b613b6c7b9607c194..a7bf0c74da0cd6c4e91c045619c5349bc51936de 100644 (file)
@@ -380,7 +380,7 @@ At startup, FRR detects the presence of that file. It detects that the file
 statistics information matches the same file statistics information as
 `/proc/self/ns/net` ( through stat() function). As statistics information
 matches, then `vrf0` stands for the new default namespace name.
-Consequently, the VRF naming `Default` will be overriden by the new discovered
+Consequently, the VRF naming `Default` will be overridden by the new discovered
 namespace name `vrf0`.
 
 For those who don't use VRF backend with *Linux network namespace*, it is
@@ -422,7 +422,7 @@ in routing entry, and can be configured like a route:
 .. index:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
 .. clicmd:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL
 
-   NETWORK ans MASK stand for the IP prefix entry to be added as static
+   NETWORK and MASK stand for the IP prefix entry to be added as static
    route entry.
    GATEWAY is the gateway IP address to reach, in order to reach the prefix.
    INTERFACE is the interface behind which the prefix is located.
index dd29358b07368e78ab625d79291fc8e979a60e3d..815983a3940a195b03a04aadc1e7ef61795c8aac 100644 (file)
@@ -1,35 +1,58 @@
-FROM alpine:3.7 as source-builder
-ARG commit
-RUN apk add --no-cache abuild acct alpine-sdk attr autoconf automake bash \
-    binutils binutils-libs bison bsd-compat-headers build-base \
-    c-ares c-ares-dev ca-certificates cryptsetup-libs curl \
-    device-mapper-libs expat fakeroot flex fortify-headers g++ gcc gdbm \
-    git gmp isl json-c json-c-dev kmod lddtree libacl libatomic libattr \
-    libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc \
-    libgomp libisoburn libisofs libltdl libressl libssh2 \
-    libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1 \
-    mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base \
-    patch pax-utils pcre perl pkgconf python2 python2-dev readline \
-    readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs \
-    groff gzip bc py-sphinx
-ADD . /src
-RUN (cd /src && \
-       ./bootstrap.sh && \
-       ./configure \
+# This stage builds a dist tarball from the source
+FROM alpine:edge as source-builder
+
+RUN mkdir -p /src/alpine
+COPY alpine/APKBUILD.in /src/alpine
+RUN source /src/alpine/APKBUILD.in \
+       && echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
+       && apk add \
+               --no-cache \
+               --update-cache \
+               $makedepends \
+               gzip
+
+COPY . /src
+ARG PKGVER
+RUN cd /src \
+       && ./bootstrap.sh \
+       && ./configure \
                --enable-numeric-version \
-               --with-pkg-extra-version=_git$commit && \
-       make dist)
-FROM alpine:3.7 as alpine-builder
-RUN apk add --no-cache abuild alpine-sdk && mkdir -p /pkgs/apk
-ADD docker/alpine/alpine-build.sh /usr/bin/
-ADD docker/alpine/builder /etc/sudoers.d
-COPY --from=source-builder /src/*.tar.gz /src/alpine/* /src/tools/etc/frr/daemons* /dist/
+               --with-pkg-extra-version="_git$PKGVER" \
+       && make dist
+
+# This stage builds an apk from the dist tarball
+FROM alpine:edge as alpine-builder
+# Don't use nocache here so that abuild can use the cache
+RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
+       && apk add \
+               --update-cache \
+               abuild \
+               alpine-conf \
+               alpine-sdk \
+       && setup-apkcache /var/cache/apk \
+       && mkdir -p /pkgs/apk \
+       && echo 'builder ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
+
+COPY --from=source-builder /src/frr-*.tar.gz /src/alpine/* /dist/
 RUN adduser -D -G abuild builder && chown -R builder /dist /pkgs
 USER builder
-RUN /usr/bin/alpine-build.sh
-FROM alpine:3.7
+RUN cd /dist \
+       && abuild-keygen -a -n \
+       && abuild checksum \
+       && abuild -r -P /pkgs/apk
+
+# This stage installs frr from the apk
+FROM alpine:edge
 RUN mkdir -p /pkgs/apk
 COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/
-RUN apk add --no-cache tini
-RUN apk add --no-cache --allow-untrusted /pkgs/apk/x86_64/*.apk
+RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \
+       && apk add \
+               --no-cache \
+               --update-cache \
+               tini \
+       && apk add \
+               --no-cache \
+               --allow-untrusted /pkgs/apk/*/*.apk \
+       && rm -rf /pkgs
+COPY docker/alpine/docker-start /usr/lib/frr/docker-start
 ENTRYPOINT [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ]
diff --git a/docker/alpine/alpine-build.sh b/docker/alpine/alpine-build.sh
deleted file mode 100755 (executable)
index d4c0311..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-set -e
-
-cd /dist
-
-sudo apk --update add alpine-conf
-sudo setup-apkcache /var/cache/apk
-abuild-keygen -a -n
-abuild checksum
-abuild -r -P /pkgs/apk
index 40ed1194fe6cb23514352d146a30ec2f689b6f0c..22a36877c039d1f0f4301d86a05704b1845b0690 100755 (executable)
@@ -1,17 +1,30 @@
 #!/bin/sh
 
 set -e
-set -v
 set -x
 
 ##
-# commit must be converted to decimal
+# Package version needs to be decimal
 ##
-c=`git rev-parse --short=10 HEAD`
-commit=`printf '%u\n' 0x$c`
-docker build -f docker/alpine/Dockerfile \
-       --build-arg commit=$commit -t frr:alpine-$c .
-id=`docker create frr:alpine-$c`
-docker cp ${id}:/pkgs/ docker
-docker rm $id
-docker rmi frr:alpine-$c
+GITREV="$(git rev-parse --short=10 HEAD)"
+PKGVER="$(printf '%u\n' 0x$GITREV)"
+
+docker build \
+       --pull \
+       --file=docker/alpine/Dockerfile \
+       --build-arg="PKGVER=$PKGVER" \
+       --tag="frr:alpine-builder-$GITREV" \
+       --target=alpine-builder \
+       .
+
+CONTAINER_ID="$(docker create "frr:alpine-builder-$GITREV")"
+docker cp "${CONTAINER_ID}:/pkgs/" docker/alpine
+docker rm "${CONTAINER_ID}"
+
+docker build \
+       --file=docker/alpine/Dockerfile \
+       --build-arg="PKGVER=$PKGVER" \
+       --tag="frr:alpine-$GITREV" \
+       .
+
+docker rmi "frr:alpine-builder-$GITREV"
diff --git a/docker/alpine/builder b/docker/alpine/builder
deleted file mode 100644 (file)
index a950b8a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-builder ALL=(ALL) NOPASSWD:ALL
diff --git a/docker/alpine/docker-start b/docker/alpine/docker-start
new file mode 100755 (executable)
index 0000000..52cfb66
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+set -e
+
+##
+# For volume mounts...
+##
+chown -R frr:frr /etc/frr
+/usr/lib/frr/frrinit.sh start
+
+# Sleep forever
+exec tail -f /dev/null
index 22f5a5ddb1cb22f0ba525d933673d015ab4394a1..4d6d73e20215df475c73c079cafc29bc935d6a91 100644 (file)
@@ -314,7 +314,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
                        if (prefix->rij->count)
                                return EIGRP_FSM_KEEP_STATE;
 
-                       zlog_info("All reply received\n");
+                       zlog_info("All reply received");
                        if (head->reported_distance < prefix->fdistance) {
                                return EIGRP_FSM_EVENT_LR_FCS;
                        }
@@ -344,7 +344,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
                        } else if (prefix->rij->count) {
                                return EIGRP_FSM_KEEP_STATE;
                        } else {
-                               zlog_info("All reply received\n");
+                               zlog_info("All reply received");
                                return EIGRP_FSM_EVENT_LR;
                        }
                } else if (msg->packet_type == EIGRP_OPC_UPDATE
@@ -366,7 +366,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
                        if (prefix->rij->count) {
                                return EIGRP_FSM_KEEP_STATE;
                        } else {
-                               zlog_info("All reply received\n");
+                               zlog_info("All reply received");
                                if (head->reported_distance
                                    < prefix->fdistance) {
                                        return EIGRP_FSM_EVENT_LR_FCS;
@@ -390,7 +390,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
                        } else if (prefix->rij->count) {
                                return EIGRP_FSM_KEEP_STATE;
                        } else {
-                               zlog_info("All reply received\n");
+                               zlog_info("All reply received");
                                return EIGRP_FSM_EVENT_LR;
                        }
                } else if (msg->packet_type == EIGRP_OPC_UPDATE
index 107de47f3db70803615754966c8d9e28c942dc91..8e9302963dabdd6dd7c0d11d0c21adf893342474 100644 (file)
@@ -131,7 +131,7 @@ static int process_p2p_hello(struct iih_info *iih)
        if (tw_adj) {
                if (tw_adj->state > ISIS_THREEWAY_DOWN) {
                        if (isis->debugs & DEBUG_ADJ_PACKETS) {
-                               zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d\n",
+                               zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d",
                                           iih->circuit->area->area_tag,
                                           iih->circuit->interface->name,
                                           tw_adj->state);
@@ -144,7 +144,7 @@ static int process_p2p_hello(struct iih_info *iih)
                        || tw_adj->neighbor_circuit_id != (uint32_t) iih->circuit->idx)) {
 
                        if (isis->debugs & DEBUG_ADJ_PACKETS) {
-                               zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.\n",
+                               zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.",
                                           iih->circuit->area->area_tag,
                                           iih->circuit->interface->name);
                        }
@@ -1523,7 +1523,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
        }
 
        if (fabricd_initial_sync_is_complete(circuit->area) && resync_needed)
-               zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!\n");
+               zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!");
 
        retval = ISIS_OK;
 out:
index dfe74e325ed0f2831b0e5c303c3d2ae63ac5b2b3..79d79f8911647653be9c590c00fe21dc7235f15b 100644 (file)
@@ -362,6 +362,10 @@ static int isis_zebra_read(int command, struct zclient *zclient,
        if (zapi_route_decode(zclient->ibuf, &api) < 0)
                return -1;
 
+       if (api.prefix.family == AF_INET6
+           && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
+               return 0;
+
        /*
         * Avoid advertising a false default reachability. (A default
         * route installed by IS-IS gets redistributed from zebra back
index abcc6c5d3cf4ee7d76087de595b5d0e5f99aca89..5b1473af40907408fb9ed1d29afce6fe66838313 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -396,6 +396,7 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id)
        struct interface *ifp;
 
        switch (vrf_get_backend()) {
+       case VRF_BACKEND_UNKNOWN:
        case VRF_BACKEND_NETNS:
                ifp = if_lookup_by_name(name, vrf_id);
                if (ifp)
@@ -1279,6 +1280,11 @@ static int lib_interface_create(enum nb_event event,
                                  vrf->name);
                        return NB_ERR_VALIDATION;
                }
+
+               /* if VRF is netns or not yet known - init for instance
+                * then assumption is that passed config is exact
+                * then the user intent was not to use an other iface
+                */
                if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) {
                        ifp = if_lookup_by_name_all_vrf(ifname);
                        if (ifp && ifp->vrf_id != vrf->vrf_id) {
index e98040eb0634e5c3e68413d1dc222219abef7201..cf623a4c19bbdfbfb946df5efd8356dfadb3d6db 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -991,6 +991,7 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_ROUTER_ID_DELETE),
        DESC_ENTRY(ZEBRA_ROUTER_ID_UPDATE),
        DESC_ENTRY(ZEBRA_HELLO),
+       DESC_ENTRY(ZEBRA_CAPABILITIES),
        DESC_ENTRY(ZEBRA_NEXTHOP_REGISTER),
        DESC_ENTRY(ZEBRA_NEXTHOP_UNREGISTER),
        DESC_ENTRY(ZEBRA_NEXTHOP_UPDATE),
@@ -1012,6 +1013,7 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_VRF_LABEL),
        DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE),
        DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER),
+       DESC_ENTRY(ZEBRA_BFD_CLIENT_DEREGISTER),
        DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV),
        DESC_ENTRY(ZEBRA_INTERFACE_DISABLE_RADV),
        DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB),
@@ -1023,6 +1025,9 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC),
        DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK),
        DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK),
+       DESC_ENTRY(ZEBRA_FEC_REGISTER),
+       DESC_ENTRY(ZEBRA_FEC_UNREGISTER),
+       DESC_ENTRY(ZEBRA_FEC_UPDATE),
        DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
        DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
        DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP),
@@ -1057,6 +1062,11 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_IPSET_DESTROY),
        DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD),
        DESC_ENTRY(ZEBRA_IPSET_ENTRY_DELETE),
+       DESC_ENTRY(ZEBRA_IPSET_NOTIFY_OWNER),
+       DESC_ENTRY(ZEBRA_IPSET_ENTRY_NOTIFY_OWNER),
+       DESC_ENTRY(ZEBRA_IPTABLE_ADD),
+       DESC_ENTRY(ZEBRA_IPTABLE_DELETE),
+       DESC_ENTRY(ZEBRA_IPTABLE_NOTIFY_OWNER),
        DESC_ENTRY(ZEBRA_VXLAN_FLOOD_CONTROL),
 };
 #undef DESC_ENTRY
index f940418d8325b89dd1a1de747ce0da64ec891399..27ab04279c1cc3617dca745fd3b19c2f54def98c 100644 (file)
@@ -188,11 +188,25 @@ static int nhgc_cmp_helper(const char *a, const char *b)
        return strcmp(a, b);
 }
 
+static int nhgc_addr_cmp_helper(const union sockunion *a, const union sockunion *b)
+{
+       if (!a && !b)
+               return 0;
+
+       if (a && !b)
+               return -1;
+
+       if (!a && b)
+               return 1;
+
+       return sockunion_cmp(a, b);
+}
+
 static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
 {
        int ret;
 
-       ret = sockunion_cmp(&nh1->addr, &nh2->addr);
+       ret = nhgc_addr_cmp_helper(nh1->addr, nh2->addr);
        if (ret)
                return ret;
 
@@ -209,6 +223,9 @@ static void nhgl_delete(struct nexthop_hold *nh)
 
        XFREE(MTYPE_TMP, nh->nhvrf_name);
 
+       if (nh->addr)
+               sockunion_free(nh->addr);
+
        XFREE(MTYPE_TMP, nh);
 }
 
@@ -292,8 +309,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
                nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name);
        if (intf)
                nh->intf = XSTRDUP(MTYPE_TMP, intf);
-
-       nh->addr = *addr;
+       if (addr)
+               nh->addr = sockunion_dup(addr);
 
        listnode_add_sort(nhgc->nhg_list, nh);
 }
@@ -308,7 +325,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
 
        for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
                if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&
-                   sockunion_cmp(addr, &nh->addr) == 0 &&
+                   nhgc_addr_cmp_helper(addr, nh->addr) == 0 &&
                    nhgc_cmp_helper(intf, nh->intf) == 0)
                        break;
        }
@@ -320,13 +337,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
                return;
 
        list_delete_node(nhgc->nhg_list, node);
-
-       if (nh->nhvrf_name)
-               XFREE(MTYPE_TMP, nh->nhvrf_name);
-       if (nh->intf)
-               XFREE(MTYPE_TMP, nh->intf);
-
-       XFREE(MTYPE_TMP, nh);
+       nhgl_delete(nh);
 }
 
 static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
@@ -347,36 +358,45 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
 
        nhop->vrf_id = vrf->vrf_id;
 
-       if (addr->sa.sa_family == AF_INET) {
-               nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
-               if (intf) {
-                       nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
-                       nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
-                       if (nhop->ifindex == IFINDEX_INTERNAL)
-                               return false;
-               } else
-                       nhop->type = NEXTHOP_TYPE_IPV4;
-       } else {
-               memcpy(&nhop->gate.ipv6, &addr->sin6.sin6_addr, 16);
-               if (intf) {
-                       nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
-                       nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
-                       if (nhop->ifindex == IFINDEX_INTERNAL)
-                               return false;
-               } else
-                       nhop->type = NEXTHOP_TYPE_IPV6;
+       if (intf) {
+               nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
+               if (nhop->ifindex == IFINDEX_INTERNAL)
+                       return false;
        }
 
+       if (addr) {
+               if (addr->sa.sa_family == AF_INET) {
+                       nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
+                       if (intf)
+                               nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+                       else
+                               nhop->type = NEXTHOP_TYPE_IPV4;
+               } else {
+                       nhop->gate.ipv6 = addr->sin6.sin6_addr;
+                       if (intf)
+                               nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+                       else
+                               nhop->type = NEXTHOP_TYPE_IPV6;
+               }
+       } else
+               nhop->type = NEXTHOP_TYPE_IFINDEX;
+
        return true;
 }
 
 DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
-      "[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
+      "[no] nexthop\
+        <\
+         <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
+         |INTERFACE$intf\
+       >\
+       [nexthop-vrf NAME$name]",
       NO_STR
       "Specify one of the nexthops in this ECMP group\n"
       "v4 Address\n"
       "v6 Address\n"
       "Interface to use\n"
+      "Interface to use\n"
       "If the nexthop is in a different vrf tell us\n"
       "The nexthop-vrf Name\n")
 {
@@ -385,13 +405,6 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
        struct nexthop *nh;
        bool legal;
 
-       /*
-        * This is impossible to happen as that the cli parser refuses
-        * to let you get here without an addr, but the SA system
-        * does not understand this intricacy
-        */
-       assert(addr);
-
        legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name);
 
        if (nhop.type == NEXTHOP_TYPE_IPV6
@@ -480,9 +493,10 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
 {
        char buf[100];
 
-       vty_out(vty, "nexthop ");
+       vty_out(vty, "nexthop");
 
-       vty_out(vty, "%s", sockunion2str(&nh->addr, buf, sizeof(buf)));
+       if (nh->addr)
+               vty_out(vty, " %s", sockunion2str(nh->addr, buf, sizeof(buf)));
 
        if (nh->intf)
                vty_out(vty, " %s", nh->intf);
@@ -504,7 +518,7 @@ static int nexthop_group_write(struct vty *vty)
                vty_out(vty, "nexthop-group %s\n", nhgc->name);
 
                for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
-                       vty_out(vty, "  ");
+                       vty_out(vty, " ");
                        nexthop_group_write_nexthop_internal(vty, nh);
                }
 
@@ -526,7 +540,7 @@ void nexthop_group_enable_vrf(struct vrf *vrf)
                        struct nexthop nhop;
                        struct nexthop *nh;
 
-                       if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
+                       if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
                                                         nhh->intf,
                                                         nhh->nhvrf_name))
                                continue;
@@ -562,7 +576,7 @@ void nexthop_group_disable_vrf(struct vrf *vrf)
                        struct nexthop nhop;
                        struct nexthop *nh;
 
-                       if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr,
+                       if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
                                                         nhh->intf,
                                                         nhh->nhvrf_name))
                                continue;
@@ -600,7 +614,7 @@ void nexthop_group_interface_state_change(struct interface *ifp,
                                struct nexthop nhop;
 
                                if (!nexthop_group_parse_nexthop(
-                                           &nhop, &nhh->addr, nhh->intf,
+                                           &nhop, nhh->addr, nhh->intf,
                                            nhh->nhvrf_name))
                                        continue;
 
index b14cbb5b5c7314ebd0a7d7d2428bc085765fc24b..c6e290eeeade11e184b676cc8ac6cd94234b7596 100644 (file)
@@ -68,7 +68,7 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
 
 struct nexthop_hold {
        char *nhvrf_name;
-       union sockunion addr;
+       union sockunion *addr;
        char *intf;
 };
 
index 15139aa8d04049f6272b5bdd4a4be25dc03eda85..edf7e0eca6893add20ad0dbbd5927b23d78500ee 100644 (file)
@@ -348,39 +348,58 @@ static void nb_config_diff_del_changes(struct nb_config_cbs *changes)
  * configurations. Given a new subtree, calculate all new YANG data nodes,
  * excluding default leafs and leaf-lists. This is a recursive function.
  */
-static void nb_config_diff_new_subtree(const struct lyd_node *dnode,
-                                      struct nb_config_cbs *changes)
+static void nb_config_diff_created(const struct lyd_node *dnode,
+                                  struct nb_config_cbs *changes)
 {
+       enum nb_operation operation;
        struct lyd_node *child;
 
-       LY_TREE_FOR (dnode->child, child) {
-               enum nb_operation operation;
+       switch (dnode->schema->nodetype) {
+       case LYS_LEAF:
+       case LYS_LEAFLIST:
+               if (lyd_wd_default((struct lyd_node_leaf_list *)dnode))
+                       break;
 
-               switch (child->schema->nodetype) {
-               case LYS_LEAF:
-               case LYS_LEAFLIST:
-                       if (lyd_wd_default((struct lyd_node_leaf_list *)child))
-                               break;
+               if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
+                       operation = NB_OP_CREATE;
+               else if (nb_operation_is_valid(NB_OP_MODIFY, dnode->schema))
+                       operation = NB_OP_MODIFY;
+               else
+                       return;
 
-                       if (nb_operation_is_valid(NB_OP_CREATE, child->schema))
-                               operation = NB_OP_CREATE;
-                       else if (nb_operation_is_valid(NB_OP_MODIFY,
-                                                      child->schema))
-                               operation = NB_OP_MODIFY;
-                       else
-                               continue;
+               nb_config_diff_add_change(changes, operation, dnode);
+               break;
+       case LYS_CONTAINER:
+       case LYS_LIST:
+               if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
+                       nb_config_diff_add_change(changes, NB_OP_CREATE, dnode);
 
-                       nb_config_diff_add_change(changes, operation, child);
-                       break;
-               case LYS_CONTAINER:
-               case LYS_LIST:
-                       if (nb_operation_is_valid(NB_OP_CREATE, child->schema))
-                               nb_config_diff_add_change(changes, NB_OP_CREATE,
-                                                         child);
-                       nb_config_diff_new_subtree(child, changes);
-                       break;
-               default:
-                       break;
+               /* Process child nodes recursively. */
+               LY_TREE_FOR (dnode->child, child) {
+                       nb_config_diff_created(child, changes);
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void nb_config_diff_deleted(const struct lyd_node *dnode,
+                                  struct nb_config_cbs *changes)
+{
+       if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema))
+               nb_config_diff_add_change(changes, NB_OP_DESTROY, dnode);
+       else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) {
+               struct lyd_node *child;
+
+               /*
+                * Non-presence containers need special handling since they
+                * don't have "destroy" callbacks. In this case, what we need to
+                * do is to call the "destroy" callbacks of their child nodes
+                * when applicable (i.e. optional nodes).
+                */
+               LY_TREE_FOR (dnode->child, child) {
+                       nb_config_diff_deleted(child, changes);
                }
        }
 }
@@ -399,42 +418,27 @@ static void nb_config_diff(const struct nb_config *config1,
        for (int i = 0; diff->type[i] != LYD_DIFF_END; i++) {
                LYD_DIFFTYPE type;
                struct lyd_node *dnode;
-               enum nb_operation operation;
 
                type = diff->type[i];
 
                switch (type) {
                case LYD_DIFF_CREATED:
                        dnode = diff->second[i];
-
-                       if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema))
-                               operation = NB_OP_CREATE;
-                       else if (nb_operation_is_valid(NB_OP_MODIFY,
-                                                      dnode->schema))
-                               operation = NB_OP_MODIFY;
-                       else
-                               continue;
+                       nb_config_diff_created(dnode, changes);
                        break;
                case LYD_DIFF_DELETED:
                        dnode = diff->first[i];
-                       operation = NB_OP_DESTROY;
+                       nb_config_diff_deleted(dnode, changes);
                        break;
                case LYD_DIFF_CHANGED:
                        dnode = diff->second[i];
-                       operation = NB_OP_MODIFY;
+                       nb_config_diff_add_change(changes, NB_OP_MODIFY, dnode);
                        break;
                case LYD_DIFF_MOVEDAFTER1:
                case LYD_DIFF_MOVEDAFTER2:
                default:
                        continue;
                }
-
-               nb_config_diff_add_change(changes, operation, dnode);
-
-               if (type == LYD_DIFF_CREATED
-                   && CHECK_FLAG(dnode->schema->nodetype,
-                                 LYS_CONTAINER | LYS_LIST))
-                       nb_config_diff_new_subtree(dnode, changes);
        }
 
        lyd_free_diff(diff);
index 3ce8e0d57a4b7239a5dc4b64636ca5a36ab28cc5..59f24afe4a5aecc4a84f47b18a778401ed8d4dd1 100644 (file)
@@ -708,19 +708,19 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
 
        /* If we're already elevated, just return */
        pthread_mutex_lock(&(privs->mutex));
-       if (++privs->refcount > 1) {
-               pthread_mutex_unlock(&(privs->mutex));
-               return privs;
+       {
+               if (++(privs->refcount) == 1) {
+                       errno = 0;
+                       if (privs->change(ZPRIVS_RAISE)) {
+                               zlog_err("%s: Failed to raise privileges (%s)",
+                                        funcname, safe_strerror(errno));
+                       }
+                       errno = save_errno;
+                       privs->raised_in_funcname = funcname;
+               }
        }
        pthread_mutex_unlock(&(privs->mutex));
 
-       errno = 0;
-       if (privs->change(ZPRIVS_RAISE)) {
-               zlog_err("%s: Failed to raise privileges (%s)",
-                        funcname, safe_strerror(errno));
-       }
-       errno = save_errno;
-       privs->raised_in_funcname = funcname;
        return privs;
 }
 
@@ -733,19 +733,20 @@ void _zprivs_lower(struct zebra_privs_t **privs)
 
        /* Don't lower privs if there's another caller */
        pthread_mutex_lock(&(*privs)->mutex);
-       if (--((*privs)->refcount) > 0) {
-               pthread_mutex_unlock(&(*privs)->mutex);
-               return;
+       {
+               if (--((*privs)->refcount) == 0) {
+                       errno = 0;
+                       if ((*privs)->change(ZPRIVS_LOWER)) {
+                               zlog_err("%s: Failed to lower privileges (%s)",
+                                        (*privs)->raised_in_funcname,
+                                        safe_strerror(errno));
+                       }
+                       errno = save_errno;
+                       (*privs)->raised_in_funcname = NULL;
+               }
        }
        pthread_mutex_unlock(&(*privs)->mutex);
 
-       errno = 0;
-       if ((*privs)->change(ZPRIVS_LOWER)) {
-               zlog_err("%s: Failed to lower privileges (%s)",
-                        (*privs)->raised_in_funcname, safe_strerror(errno));
-       }
-       errno = save_errno;
-       (*privs)->raised_in_funcname = NULL;
        *privs = NULL;
 }
 
index df93bc33b948e0c6c04e2d96967852f7b0ebda38..dd87ed63e810b7cf5a7107ac2330f42f2445ad4b 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -56,6 +56,7 @@ struct vrf_id_head vrfs_by_id = RB_INITIALIZER(&vrfs_by_id);
 struct vrf_name_head vrfs_by_name = RB_INITIALIZER(&vrfs_by_name);
 
 static int vrf_backend;
+static int vrf_backend_configured;
 static struct zebra_privs_t *vrf_daemon_privs;
 static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL;
 
@@ -613,12 +614,15 @@ int vrf_is_backend_netns(void)
 
 int vrf_get_backend(void)
 {
+       if (!vrf_backend_configured)
+               return VRF_BACKEND_UNKNOWN;
        return vrf_backend;
 }
 
 void vrf_configure_backend(int vrf_backend_netns)
 {
        vrf_backend = vrf_backend_netns;
+       vrf_backend_configured = 1;
 }
 
 int vrf_handler_create(struct vty *vty, const char *vrfname,
@@ -662,7 +666,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
                                "VRF %u is already configured with VRF %s\n",
                                vrf->vrf_id, vrf->name);
                else
-                       zlog_info("VRF %u is already configured with VRF %s\n",
+                       zlog_info("VRF %u is already configured with VRF %s",
                                  vrf->vrf_id, vrf->name);
                return CMD_WARNING_CONFIG_FAILED;
        }
index b947ab1d52ca1640146baeff242c6f05c93fb28a..d8fedf91116b8b5b6a67bb12e050e53aabd5e3ea 100644 (file)
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -101,8 +101,9 @@ RB_PROTOTYPE(vrf_name_head, vrf, name_entry, vrf_name_compare)
 DECLARE_QOBJ_TYPE(vrf)
 
 /* Allow VRF with netns as backend */
-#define VRF_BACKEND_VRF_LITE 0
-#define VRF_BACKEND_NETNS    1
+#define VRF_BACKEND_VRF_LITE   0
+#define VRF_BACKEND_NETNS      1
+#define VRF_BACKEND_UNKNOWN    2
 
 extern struct vrf_id_head vrfs_by_id;
 extern struct vrf_name_head vrfs_by_name;
index 9db1dd74f2d91421a679ffbbfa8778ee13b84fcf..7b94f1d907a3e80d61c7cef3a6991b95fff688ae 100644 (file)
@@ -629,7 +629,7 @@ void zclient_init(struct zclient *zclient, int redist_default,
        }
 
        if (zclient_debug)
-               zlog_debug("zclient_start is called");
+               zlog_debug("scheduling zclient connection");
 
        zclient_event(ZCLIENT_SCHEDULE, zclient);
 }
@@ -2504,8 +2504,9 @@ static int zclient_read(struct thread *thread)
        length -= ZEBRA_HEADER_SIZE;
 
        if (zclient_debug)
-               zlog_debug("zclient 0x%p command 0x%x VRF %u\n",
-                          (void *)zclient, command, vrf_id);
+               zlog_debug("zclient 0x%p command %s VRF %u",
+                          (void *)zclient, zserv_command_string(command),
+                          vrf_id);
 
        switch (command) {
        case ZEBRA_CAPABILITIES:
@@ -2574,14 +2575,14 @@ static int zclient_read(struct thread *thread)
                break;
        case ZEBRA_NEXTHOP_UPDATE:
                if (zclient_debug)
-                       zlog_debug("zclient rcvd nexthop update\n");
+                       zlog_debug("zclient rcvd nexthop update");
                if (zclient->nexthop_update)
                        (*zclient->nexthop_update)(command, zclient, length,
                                                   vrf_id);
                break;
        case ZEBRA_IMPORT_CHECK_UPDATE:
                if (zclient_debug)
-                       zlog_debug("zclient rcvd import check update\n");
+                       zlog_debug("zclient rcvd import check update");
                if (zclient->import_check_update)
                        (*zclient->import_check_update)(command, zclient,
                                                        length, vrf_id);
@@ -2608,7 +2609,7 @@ static int zclient_read(struct thread *thread)
                break;
        case ZEBRA_FEC_UPDATE:
                if (zclient_debug)
-                       zlog_debug("zclient rcvd fec update\n");
+                       zlog_debug("zclient rcvd fec update");
                if (zclient->fec_update)
                        (*zclient->fec_update)(command, zclient, length);
                break;
index 76722aad1028550c37df5510352adfaa11cfb892..484e5adae674a3ab044629e0b346d0dad7640fa5 100644 (file)
@@ -138,11 +138,11 @@ static void ospf6_area_stub_update(struct ospf6_area *area)
 
        if (IS_AREA_STUB(area)) {
                if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
-                       zlog_debug("Stubbing out area for if %s\n", area->name);
+                       zlog_debug("Stubbing out area for if %s", area->name);
                OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
        } else if (IS_AREA_ENABLED(area)) {
                if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
-                       zlog_debug("Normal area for if %s\n", area->name);
+                       zlog_debug("Normal area for if %s", area->name);
                OSPF6_OPT_SET(area->options, OSPF6_OPT_E);
                ospf6_asbr_send_externals_to_area(area);
        }
@@ -450,7 +450,7 @@ DEFUN (area_range,
 
        range->path.u.cost_config = cost;
 
-       zlog_debug("%s: for prefix %s, flag = %x\n", __func__,
+       zlog_debug("%s: for prefix %s, flag = %x", __func__,
                   argv[idx_ipv6_prefixlen]->arg, range->flag);
        if (range->rnode == NULL) {
                ospf6_route_add(range, oa->range_table);
index 3153c29aa18ae66998f3b68435536a78f8b0b68a..2795bb9abdfb46c99ad369bb6d162bd359e8cea9 100644 (file)
@@ -1006,7 +1006,7 @@ void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa)
 
        for (ALL_LSDB(oa->ospf6->lsdb, lsa)) {
                if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
-                       zlog_debug("%s: Flooding AS-External LSA %s\n",
+                       zlog_debug("%s: Flooding AS-External LSA %s",
                                   __func__, lsa->name);
                        ospf6_flood_area(NULL, lsa, oa);
                }
index d4f6f6f4aebb287b1fde2cf6b8839ed3a835d048..f08426fb47994173b10b32250230d44c6330ba2e 100644 (file)
@@ -475,7 +475,7 @@ void ospf6_spf_calculation(uint32_t router_id,
        lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
        if (lsa == NULL) {
                if (IS_OSPF6_DEBUG_SPF(PROCESS))
-                       zlog_debug("%s: No router LSA for area %s\n", __func__,
+                       zlog_debug("%s: No router LSA for area %s", __func__,
                                   oa->name);
                return;
        }
index 54f1735e7acc6652ba747695a0e96af0a8b8aab4..abdc82a73841983085325bf3f5456aca87e4c217 100644 (file)
@@ -226,6 +226,9 @@ static int ospf6_zebra_read_route(int command, struct zclient *zclient,
        if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
                return 0;
 
+       if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
+               return 0;
+
        ifindex = api.nexthops[0].ifindex;
        nexthop = &api.nexthops[0].gate.ipv6;
 
index a3b337a0c0b782dbd7caabb95af8ada37ee43d1a..f06e45392eb09968afe4692c93f29daf7c1fd23e 100644 (file)
@@ -74,12 +74,12 @@ void api_opaque_lsa_print(struct lsa_header *data)
        olsa = (struct opaque_lsa *)data;
 
        opaquelen = ntohs(data->length) - OSPF_LSA_HEADER_SIZE;
-       zlog_debug("apiserver_lsa_print: opaquelen=%d\n", opaquelen);
+       zlog_debug("apiserver_lsa_print: opaquelen=%d", opaquelen);
 
        for (i = 0; i < opaquelen; i++) {
                zlog_debug("0x%x ", olsa->mydata[i]);
        }
-       zlog_debug("\n");
+       zlog_debug(" ");
 }
 
 /* -----------------------------------------------------------
@@ -242,7 +242,7 @@ const char *ospf_api_errname(int errcode)
 void msg_print(struct msg *msg)
 {
        if (!msg) {
-               zlog_debug("msg_print msg=NULL!\n");
+               zlog_debug("msg_print msg=NULL!");
                return;
        }
 
index d0ee8187229535f9c1f060b6028fdc388da94e33..d6f1fba28b18c9c6505175a7ddf02224ab436ba9 100644 (file)
@@ -2024,7 +2024,7 @@ int ospf_apiserver_del_if(struct interface *ifp)
 
        /* zlog_warn for debugging */
        zlog_warn("ospf_apiserver_del_if");
-       zlog_warn("ifp name=%s status=%d index=%d\n", ifp->name, ifp->status,
+       zlog_warn("ifp name=%s status=%d index=%d", ifp->name, ifp->status,
                  ifp->ifindex);
 
        oi = ospf_apiserver_if_lookup_by_ifp(ifp);
@@ -2110,7 +2110,6 @@ void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa)
                for (i = 0; i < opaquelen; i++) {
                        zlog_debug("0x%x ", olsa->data[i]);
                }
-               zlog_debug("\n");
        }
        return;
 }
index b3c91b9006e98c210421329e02341355196cbd36..43c5e338b0893b3b3cb8c0386cdf1ced1b748743 100644 (file)
@@ -3447,7 +3447,14 @@ static int ospf_make_ls_req_func(struct stream *s, uint16_t *length,
 
        oi = nbr->oi;
 
-       /* LS Request packet overflows interface MTU. */
+       /* LS Request packet overflows interface MTU
+        * delta is just number of bytes required for 1 LS Req
+        * ospf_packet_max will return the number of bytes can
+        * be accomodated without ospf header. So length+delta
+        * can be compared to ospf_packet_max
+        * to check if it can fit another lsreq in the same packet.
+        */
+
        if (*length + delta > ospf_packet_max(oi))
                return 0;
 
@@ -3466,7 +3473,7 @@ static int ospf_make_ls_req(struct ospf_neighbor *nbr, struct stream *s)
 {
        struct ospf_lsa *lsa;
        uint16_t length = OSPF_LS_REQ_MIN_SIZE;
-       unsigned long delta = stream_get_endp(s) + 12;
+       unsigned long delta = 12;
        struct route_table *table;
        struct route_node *rn;
        int i;
@@ -3530,8 +3537,9 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update,
 
                assert(lsa->data);
 
-               /* Will it fit? */
-               if (length + delta + ntohs(lsa->data->length) > size_noauth)
+               /* Will it fit? Minimum it has to fit atleast one */
+               if ((length + delta + ntohs(lsa->data->length) > size_noauth) &&
+                               (count > 0))
                        break;
 
                /* Keep pointer to LS age. */
@@ -3568,13 +3576,21 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack,
 {
        struct listnode *node, *nnode;
        uint16_t length = OSPF_LS_ACK_MIN_SIZE;
-       unsigned long delta = stream_get_endp(s) + 24;
+       unsigned long delta = OSPF_LSA_HEADER_SIZE;
        struct ospf_lsa *lsa;
 
        for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) {
                assert(lsa);
 
-               if (length + delta > ospf_packet_max(oi))
+               /* LS Ack packet overflows interface MTU
+                * delta is just number of bytes required for
+                * 1 LS Ack(1 LS Hdr) ospf_packet_max will return
+                * the number of bytes can be accomodated without
+                * ospf header. So length+delta can be compared
+                * against ospf_packet_max to check if it can fit
+                * another ls header in the same packet.
+                */
+               if ((length + delta) > ospf_packet_max(oi))
                        break;
 
                stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE);
index 4a0d4add150859818160fb5b4677d9c3fcae09e7..5f01edfbdfa75889d454c91d767b62e7a812133a 100644 (file)
@@ -1372,14 +1372,14 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
        }
 
        else {
-               zlog_debug("  Segment Routing Algorithm TLV:\n");
+               zlog_debug("  Segment Routing Algorithm TLV:");
                for (i = 0; i < ntohs(algo->header.length); i++)
                        switch (algo->value[i]) {
                        case 0:
-                               zlog_debug("    Algorithm %d: SPF\n", i);
+                               zlog_debug("    Algorithm %d: SPF", i);
                                break;
                        case 1:
-                               zlog_debug("    Algorithm %d: Strict SPF\n", i);
+                               zlog_debug("    Algorithm %d: Strict SPF", i);
                                break;
                        default:
                                zlog_debug(
index f068efc8dbf0c6d005016df97960c935a0335490..c26545344a9f5818213fb16d2eab3f90e0eb52f7 100644 (file)
@@ -901,7 +901,7 @@ static struct ospf_lsa *lsdb_lookup_next(struct ospf_area *area, uint8_t *type,
        /* Sanity check, if LSA type unknwon
           merley skip any LSA */
        if ((i < OSPF_MIN_LSA) || (i >= OSPF_MAX_LSA)) {
-               zlog_debug("Strange request with LSA type %d\n", i);
+               zlog_debug("Strange request with LSA type %d", i);
                return NULL;
        }
 
index 9c223facd354b4326175c11d5ece75814c4eab7e..74dba273e619815fb89c9931ec250f0639ff6f74 100644 (file)
@@ -1140,13 +1140,13 @@ ospf_rtrs_print (struct route_table *rtrs)
               if (path->nexthop.s_addr == 0)
                 {
                   if (IS_DEBUG_OSPF_EVENT)
-                    zlog_debug ("   directly attached to %s\r\n",
+                    zlog_debug ("   directly attached to %s\r",
                                ifindex2ifname (path->ifindex), VRF_DEFAULT);
                 }
               else
                 {
                   if (IS_DEBUG_OSPF_EVENT)
-                    zlog_debug ("   via %s, %s\r\n",
+                    zlog_debug ("   via %s, %s\r",
                                inet_ntoa (path->nexthop),
                                ifindex2ifname (path->ifindex), VRF_DEFAULT);
                 }
index f0ddf7cc0a3e57ae47fc8e66cb0f3c62b82f1b43..a49352086828ef72692f70d72de54638459c265d 100644 (file)
@@ -1600,7 +1600,7 @@ static int ospf_sr_update_schedule(struct thread *t)
        monotime(&stop_time);
 
        if (IS_DEBUG_OSPF_SR)
-               zlog_debug("SR (%s): SPF Processing Time(usecs): %lld\n",
+               zlog_debug("SR (%s): SPF Processing Time(usecs): %lld",
                           __func__,
                           (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
                                   + (stop_time.tv_usec - start_time.tv_usec));
index bb22f211a7c07ca55567b2636b07d2976e803de9..b5d8739fcb1ecc7d5e2fb6ef48a336baf8900939 100644 (file)
@@ -3029,13 +3029,13 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf,
                        if (ospf->stub_router_startup_time
                            != OSPF_STUB_ROUTER_UNCONFIGURED)
                                json_object_int_add(
-                                       json_vrf, "postStartEnabledMsecs",
-                                       ospf->stub_router_startup_time / 1000);
+                                       json_vrf, "postStartEnabledSecs",
+                                       ospf->stub_router_startup_time);
                        if (ospf->stub_router_shutdown_time
                            != OSPF_STUB_ROUTER_UNCONFIGURED)
                                json_object_int_add(
-                                       json_vrf, "preShutdownEnabledMsecs",
-                                       ospf->stub_router_shutdown_time / 1000);
+                                       json_vrf, "preShutdownEnabledSecs",
+                                       ospf->stub_router_shutdown_time);
                } else {
                        vty_out(vty,
                                " Stub router advertisement is configured\n");
@@ -3511,8 +3511,8 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
                        json_object_int_add(json_interface_sub, "cost",
                                            oi->output_cost);
                        json_object_int_add(
-                               json_interface_sub, "transmitDelayMsecs",
-                               1000 / OSPF_IF_PARAM(oi, transmit_delay));
+                               json_interface_sub, "transmitDelaySecs",
+                               OSPF_IF_PARAM(oi, transmit_delay));
                        json_object_string_add(json_interface_sub, "state",
                                               lookup_msg(ospf_ism_state_msg,
                                                          oi->state, NULL));
@@ -3616,20 +3616,20 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
                        if (OSPF_IF_PARAM(oi, fast_hello) == 0)
                                json_object_int_add(
                                        json_interface_sub, "timerMsecs",
-                                       1000 / OSPF_IF_PARAM(oi, v_hello));
+                                       OSPF_IF_PARAM(oi, v_hello) * 1000);
                        else
                                json_object_int_add(
                                        json_interface_sub, "timerMsecs",
                                        1000 / OSPF_IF_PARAM(oi, fast_hello));
                        json_object_int_add(json_interface_sub,
-                                           "timerDeadMsecs",
-                                           1000 / OSPF_IF_PARAM(oi, v_wait));
+                                           "timerDeadSecs",
+                                           OSPF_IF_PARAM(oi, v_wait));
                        json_object_int_add(json_interface_sub,
-                                           "timerWaitMsecs",
-                                           1000 / OSPF_IF_PARAM(oi, v_wait));
+                                           "timerWaitSecs",
+                                           OSPF_IF_PARAM(oi, v_wait));
                        json_object_int_add(
-                               json_interface_sub, "timerRetransmit",
-                               1000 / OSPF_IF_PARAM(oi, retransmit_interval));
+                               json_interface_sub, "timerRetransmitSecs",
+                               OSPF_IF_PARAM(oi, retransmit_interval));
                } else {
                        vty_out(vty, "  Timer intervals configured,");
                        vty_out(vty, " Hello ");
index 6a025fd72482a3cf9544ab259f2f48c0e82b959d..7504752725df4d601454ab2b617dc80d296d6819 100644 (file)
@@ -50,7 +50,7 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
 static void
 pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
                                struct nexthop_group nhg,
-                               enum nexthop_types_t nh_afi);
+                               enum nexthop_types_t nh_type);
 
 /*
  * Nexthop refcount.
@@ -157,7 +157,7 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2)
 
        switch (pbrnc1->nexthop->type) {
        case NEXTHOP_TYPE_IFINDEX:
-               return true;
+               return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex;
        case NEXTHOP_TYPE_IPV4_IFINDEX:
        case NEXTHOP_TYPE_IPV4:
                return pbrnc1->nexthop->gate.ipv4.s_addr
@@ -264,6 +264,14 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
 
        pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
        pbr_map_check_nh_group_change(nhgc->name);
+
+       if (nhop->type == NEXTHOP_TYPE_IFINDEX) {
+               struct interface *ifp;
+
+               ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
+               if (ifp)
+                       pbr_nht_nexthop_interface_update(ifp);
+       }
 }
 
 void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
@@ -274,7 +282,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
        struct pbr_nexthop_group_cache *pnhgc;
        struct pbr_nexthop_cache pnhc_find = {};
        struct pbr_nexthop_cache *pnhc;
-       enum nexthop_types_t nh_afi = nhop->type;
+       enum nexthop_types_t nh_type = nhop->type;
 
        /* find pnhgc by name */
        strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name));
@@ -296,7 +304,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
        if (pnhgc->nhh->count)
                pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
        else
-               pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_afi);
+               pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_type);
 
        pbr_map_check_nh_group_change(nhgc->name);
 }
@@ -372,39 +380,53 @@ void pbr_nht_route_removed_for_table(uint32_t table_id)
  *    - AFI_MAX on error
  */
 static afi_t pbr_nht_which_afi(struct nexthop_group nhg,
-                              enum nexthop_types_t nh_afi)
+                              enum nexthop_types_t nh_type)
 {
        struct nexthop *nexthop;
        afi_t install_afi = AFI_MAX;
        bool v6, v4, bh;
 
+       if (nh_type) {
+               switch (nh_type) {
+               case NEXTHOP_TYPE_IPV4:
+               case NEXTHOP_TYPE_IPV4_IFINDEX:
+                       return AFI_IP;
+               case NEXTHOP_TYPE_IPV6:
+               case NEXTHOP_TYPE_IPV6_IFINDEX:
+                       return AFI_IP6;
+               case NEXTHOP_TYPE_IFINDEX:
+               case NEXTHOP_TYPE_BLACKHOLE:
+                       return AFI_MAX;
+               }
+       }
+
        v6 = v4 = bh = false;
 
-       if (!nh_afi) {
-               for (ALL_NEXTHOPS(nhg, nexthop)) {
-                       nh_afi = nexthop->type;
+       for (ALL_NEXTHOPS(nhg, nexthop)) {
+               nh_type = nexthop->type;
+
+               switch (nh_type) {
+               case NEXTHOP_TYPE_IFINDEX:
+                       break;
+               case NEXTHOP_TYPE_IPV4:
+               case NEXTHOP_TYPE_IPV4_IFINDEX:
+                       v6 = true;
+                       install_afi = AFI_IP;
+                       break;
+               case NEXTHOP_TYPE_IPV6:
+               case NEXTHOP_TYPE_IPV6_IFINDEX:
+                       v4 = true;
+                       install_afi = AFI_IP6;
+                       break;
+               case NEXTHOP_TYPE_BLACKHOLE:
+                       bh = true;
                        break;
                }
        }
 
-       switch (nh_afi) {
-       case NEXTHOP_TYPE_IFINDEX:
-               break;
-       case NEXTHOP_TYPE_IPV4:
-       case NEXTHOP_TYPE_IPV4_IFINDEX:
-               v6 = true;
-               install_afi = AFI_IP;
-               break;
-       case NEXTHOP_TYPE_IPV6:
-       case NEXTHOP_TYPE_IPV6_IFINDEX:
-               v4 = true;
-               install_afi = AFI_IP6;
-               break;
-       case NEXTHOP_TYPE_BLACKHOLE:
-               bh = true;
+       /* Interface and/or blackhole nexthops only. */
+       if (!v4 && !v6)
                install_afi = AFI_MAX;
-               break;
-       }
 
        if (!bh && v6 && v4)
                DEBUGD(&pbr_dbg_nht,
@@ -423,9 +445,9 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
                                          struct nexthop_group nhg)
 {
        afi_t install_afi;
-       enum nexthop_types_t nh_afi = 0;
+       enum nexthop_types_t nh_type = 0;
 
-       install_afi = pbr_nht_which_afi(nhg, nh_afi);
+       install_afi = pbr_nht_which_afi(nhg, nh_type);
 
        route_add(pnhgc, nhg, install_afi);
 }
@@ -433,11 +455,11 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
 static void
 pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
                                struct nexthop_group nhg,
-                               enum nexthop_types_t nh_afi)
+                               enum nexthop_types_t nh_type)
 {
        afi_t install_afi;
 
-       install_afi = pbr_nht_which_afi(nhg, nh_afi);
+       install_afi = pbr_nht_which_afi(nhg, nh_type);
 
        pnhgc->installed = false;
        pnhgc->valid = false;
@@ -526,7 +548,7 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
        struct listnode *node;
        struct pbr_map_interface *pmi;
        struct nexthop *nh;
-       enum nexthop_types_t nh_afi = 0;
+       enum nexthop_types_t nh_type = 0;
 
        if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) {
                for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
@@ -542,13 +564,13 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
        pnhgc = hash_lookup(pbr_nhg_hash, &find);
 
        nh = pbrms->nhg->nexthop;
-       nh_afi = nh->type;
+       nh_type = nh->type;
        lup.nexthop = nh;
        pnhc = hash_lookup(pnhgc->nhh, &lup);
        pnhc->parent = NULL;
        hash_release(pnhgc->nhh, pnhc);
        pbr_nh_delete(&pnhc);
-       pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_afi);
+       pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_type);
 
        hash_release(pbr_nhg_hash, pnhgc);
 
@@ -653,6 +675,7 @@ bool pbr_nht_nexthop_group_valid(const char *name)
 
 struct pbr_nht_individual {
        struct zapi_route *nhr;
+       struct interface *ifp;
 
        uint32_t valid;
 };
@@ -716,6 +739,56 @@ void pbr_nht_nexthop_update(struct zapi_route *nhr)
        hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr);
 }
 
+static void
+pbr_nht_individual_nexthop_interface_update_lookup(struct hash_backet *b,
+                                                  void *data)
+{
+       struct pbr_nexthop_cache *pnhc = b->data;
+       struct pbr_nht_individual *pnhi = data;
+       bool old_valid;
+
+       old_valid = pnhc->valid;
+
+       if (pnhc->nexthop->type == NEXTHOP_TYPE_IFINDEX
+           && pnhc->nexthop->ifindex == pnhi->ifp->ifindex)
+               pnhc->valid = !!if_is_up(pnhi->ifp);
+
+       DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name,
+              old_valid, pnhc->valid);
+
+       if (pnhc->valid)
+               pnhi->valid += 1;
+}
+
+static void pbr_nht_nexthop_interface_update_lookup(struct hash_backet *b,
+                                                   void *data)
+{
+       struct pbr_nexthop_group_cache *pnhgc = b->data;
+       struct pbr_nht_individual pnhi;
+       bool old_valid;
+
+       old_valid = pnhgc->valid;
+
+       pnhi.ifp = data;
+       pnhi.valid = 0;
+       hash_iterate(pnhgc->nhh,
+                    pbr_nht_individual_nexthop_interface_update_lookup, &pnhi);
+
+       /*
+        * If any of the specified nexthops are valid we are valid
+        */
+       pnhgc->valid = !!pnhi.valid;
+
+       if (old_valid != pnhgc->valid)
+               pbr_map_check_nh_group_change(pnhgc->name);
+}
+
+void pbr_nht_nexthop_interface_update(struct interface *ifp)
+{
+       hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_update_lookup,
+                    ifp);
+}
+
 static uint32_t pbr_nhg_hash_key(void *arg)
 {
        struct pbr_nexthop_group_cache *nhgc =
index d37803fbe32e52fffeb5c0b605715064413254b4..4ef41cede7dd76a2fca02758e336787271cae2ce 100644 (file)
@@ -117,5 +117,10 @@ extern void pbr_nht_show_nexthop_group(struct vty *vty, const char *name);
  */
 extern void pbr_nht_nexthop_update(struct zapi_route *nhr);
 
+/*
+ * When we get a callback from zebra about an interface status update.
+ */
+extern void pbr_nht_nexthop_interface_update(struct interface *ifp);
+
 extern void pbr_nht_init(void);
 #endif
index f8232c9581fdfbce715364f92a7c9638a7390004..067d5c01fdfac621cebd1a0bf8fdc70dc88d8888 100644 (file)
@@ -221,13 +221,19 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
 }
 
 DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
-      "[no] set nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
+      "[no] set nexthop\
+        <\
+         <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
+         |INTERFACE$intf\
+       >\
+        [nexthop-vrf NAME$name]",
       NO_STR
       "Set for the PBR-MAP\n"
       "Specify one of the nexthops in this map\n"
       "v4 Address\n"
       "v6 Address\n"
       "Interface to use\n"
+      "Interface to use\n"
       "If the nexthop is in a different vrf tell us\n"
       "The nexthop-vrf Name\n")
 {
@@ -255,44 +261,38 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
        memset(&nhop, 0, sizeof(nhop));
        nhop.vrf_id = vrf->vrf_id;
 
-       /*
-        * Make SA happy.  CLIPPY is not going to give us a NULL
-        * addr.
-        */
-       assert(addr);
-       if (addr->sa.sa_family == AF_INET) {
-               nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
-               if (intf) {
-                       nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
-                       nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
-                       if (nhop.ifindex == IFINDEX_INTERNAL) {
-                               vty_out(vty,
-                                       "Specified Intf %s does not exist in vrf: %s\n",
-                                       intf, vrf->name);
-                               return CMD_WARNING_CONFIG_FAILED;
-                       }
-               } else
-                       nhop.type = NEXTHOP_TYPE_IPV4;
-       } else {
-               memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
-               if (intf) {
-                       nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
-                       nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
-                       if (nhop.ifindex == IFINDEX_INTERNAL) {
-                               vty_out(vty,
-                                       "Specified Intf %s does not exist in vrf: %s\n",
-                                       intf, vrf->name);
-                               return CMD_WARNING_CONFIG_FAILED;
-                       }
+       if (intf) {
+               nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
+               if (nhop.ifindex == IFINDEX_INTERNAL) {
+                       vty_out(vty,
+                               "Specified Intf %s does not exist in vrf: %s\n",
+                               intf, vrf->name);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+       }
+
+       if (addr) {
+               if (addr->sa.sa_family == AF_INET) {
+                       nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
+                       if (intf)
+                               nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
+                       else
+                               nhop.type = NEXTHOP_TYPE_IPV4;
                } else {
-                       if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
-                               vty_out(vty,
-                                       "Specified a v6 LL with no interface, rejecting\n");
-                               return CMD_WARNING_CONFIG_FAILED;
+                       nhop.gate.ipv6 = addr->sin6.sin6_addr;
+                       if (intf)
+                               nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
+                       else {
+                               if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
+                                       vty_out(vty,
+                                               "Specified a v6 LL with no interface, rejecting\n");
+                                       return CMD_WARNING_CONFIG_FAILED;
+                               }
+                               nhop.type = NEXTHOP_TYPE_IPV6;
                        }
-                       nhop.type = NEXTHOP_TYPE_IPV6;
                }
-       }
+       } else
+               nhop.type = NEXTHOP_TYPE_IFINDEX;
 
        if (pbrms->nhg)
                nh = nexthop_exists(pbrms->nhg, &nhop);
@@ -335,6 +335,14 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
                pbr_map_check(pbrms);
        }
 
+       if (nhop.type == NEXTHOP_TYPE_IFINDEX) {
+               struct interface *ifp;
+
+               ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id);
+               if (ifp)
+                       pbr_nht_nexthop_interface_update(ifp);
+       }
+
        return CMD_SUCCESS;
 }
 
@@ -616,18 +624,18 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
        vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno);
 
        if (pbrms->src)
-               vty_out(vty, "  match src-ip %s\n",
+               vty_out(vty, " match src-ip %s\n",
                        prefix2str(pbrms->src, buff, sizeof(buff)));
 
        if (pbrms->dst)
-               vty_out(vty, "  match dst-ip %s\n",
+               vty_out(vty, " match dst-ip %s\n",
                        prefix2str(pbrms->dst, buff, sizeof(buff)));
 
        if (pbrms->nhgrp_name)
-               vty_out(vty, "  set nexthop-group %s\n", pbrms->nhgrp_name);
+               vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
 
        if (pbrms->nhg) {
-               vty_out(vty, "  set ");
+               vty_out(vty, " set ");
                nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
        }
 
index 558e635748067a4450f8410b8b512f5908f72c69..44c8daa97b90c214759dfaa701ac0dd3f60e0bf2 100644 (file)
@@ -75,6 +75,8 @@ static int interface_add(int command, struct zclient *zclient,
        if (!ifp->info)
                pbr_if_new(ifp);
 
+       pbr_nht_nexthop_interface_update(ifp);
+
        return 0;
 }
 
@@ -144,6 +146,8 @@ static int interface_state_up(int command, struct zclient *zclient,
        DEBUGD(&pbr_dbg_zebra,
               "%s: %s is up", __PRETTY_FUNCTION__, ifp->name);
 
+       pbr_nht_nexthop_interface_update(ifp);
+
        return 0;
 }
 
@@ -157,6 +161,8 @@ static int interface_state_down(int command, struct zclient *zclient,
        DEBUGD(&pbr_dbg_zebra,
               "%s: %s is down", __PRETTY_FUNCTION__, ifp->name);
 
+       pbr_nht_nexthop_interface_update(ifp);
+
        return 0;
 }
 
index 91aba949eaa5757468376f877d5fa33ec174ed41..f058b7adbfb26ffbe7c62fcbe94b7b188fb24fc9 100644 (file)
@@ -1191,7 +1191,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
                        vty_out(vty, "Designated Router\n");
                        vty_out(vty, "-----------------\n");
                        vty_out(vty, "Address   : %s\n", dr_str);
-                       vty_out(vty, "Priority  : %d(%d)\n",
+                       vty_out(vty, "Priority  : %u(%d)\n",
                                pim_ifp->pim_dr_priority,
                                pim_ifp->pim_dr_num_nondrpri_neighbors);
                        vty_out(vty, "Uptime    : %s\n", dr_uptime);
@@ -2370,9 +2370,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
                                         up->t_join_timer);
 
                /*
-                * If we have a J/P timer for the neighbor display that
+                * If the upstream is not dummy and it has a J/P timer for the
+                * neighbor display that
                 */
-               if (!up->t_join_timer) {
+               if (!up->t_join_timer && up->rpf.source_nexthop.interface) {
                        struct pim_neighbor *nbr;
 
                        nbr = pim_neighbor_find(
@@ -2412,8 +2413,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
                        json_row = json_object_new_object();
                        json_object_pim_upstream_add(json_row, up);
                        json_object_string_add(
-                               json_row, "inboundInterface",
-                               up->rpf.source_nexthop.interface->name);
+                           json_row, "inboundInterface",
+                           up->rpf.source_nexthop.interface
+                               ? up->rpf.source_nexthop.interface->name
+                               : "Unknown");
 
                        /*
                         * The RPF address we use is slightly different
@@ -2463,8 +2466,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
                } else {
                        vty_out(vty,
                                "%-10s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n",
-                               up->rpf.source_nexthop.interface->name, src_str,
-                               grp_str, state_str, uptime, join_timer,
+                               up->rpf.source_nexthop.interface
+                                   ? up->rpf.source_nexthop.interface->name
+                                   : "Unknown",
+                               src_str, grp_str, state_str, uptime, join_timer,
                                rs_timer, ka_timer, up->ref_count);
                }
        }
@@ -6351,8 +6356,8 @@ DEFUN (interface_ip_pim_drprio,
        pim_ifp->pim_dr_priority = strtol(argv[idx_number]->arg, NULL, 10);
 
        if (old_dr_prio != pim_ifp->pim_dr_priority) {
-               if (pim_if_dr_election(ifp))
-                       pim_hello_restart_now(ifp);
+               pim_if_dr_election(ifp);
+               pim_hello_restart_now(ifp);
        }
 
        return CMD_SUCCESS;
@@ -6377,8 +6382,8 @@ DEFUN (interface_no_ip_pim_drprio,
 
        if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) {
                pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY;
-               if (pim_if_dr_election(ifp))
-                       pim_hello_restart_now(ifp);
+               pim_if_dr_election(ifp);
+               pim_hello_restart_now(ifp);
        }
 
        return CMD_SUCCESS;
index 1fb624a6a0bde85f6542697ed8312eef70020c1f..f51e0c0d2f1a1e2be1a3c6df3032a89a17ee7766 100644 (file)
@@ -133,6 +133,13 @@ static bool mtrace_fwd_info(struct pim_instance *pim,
        if (!up)
                return false;
 
+       if (!up->rpf.source_nexthop.interface) {
+               if (PIM_DEBUG_TRACE)
+                       zlog_debug("%s: up %s RPF is not present",
+                       __PRETTY_FUNCTION__, up->sg_str);
+               return false;
+       }
+
        ifp_in = up->rpf.source_nexthop.interface;
        nh_addr = up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4;
        total = htonl(MTRACE_UNKNOWN_COUNT);
index ae5032be73f7d41088a7e19f54babc2f8351d8ef..cbacaf3ea872733b4c749c3875e2230cf6c68bb2 100644 (file)
@@ -439,9 +439,6 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
        size_t packet_size = 0;
        size_t group_size = 0;
 
-       on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface,
-                rpf->rpf_addr.u.prefix4);
-
        if (rpf->source_nexthop.interface)
                pim_ifp = rpf->source_nexthop.interface->info;
        else {
@@ -450,6 +447,9 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
                return -1;
        }
 
+       on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface,
+               rpf->rpf_addr.u.prefix4);
+
        if (!pim_ifp) {
                zlog_warn("%s: multicast not enabled on interface %s",
                          __PRETTY_FUNCTION__,
index 7726ffda576da4c1e982ffec1c0fe035f82fe2cd..06a9e6d0d646888b2d0bbca6b31b3b95cb6404b2 100644 (file)
@@ -213,8 +213,18 @@ void pim_jp_agg_upstream_verification(struct pim_upstream *up, bool ignore)
 {
 #ifdef PIM_JP_AGG_DEBUG
        struct interface *ifp;
-       struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info;
-       struct pim_instance *pim = pim_ifp->pim;
+       struct pim_interface *pim_ifp;
+       struct pim_instance *pim;
+
+       if (!up->rpf.source_nexthop.interface) {
+               if (PIM_DEBUG_TRACE)
+                       zlog_debug("%s: up %s RPF is not present",
+                               __PRETTY_FUNCTION__, up->sg_str);
+               return;
+       }
+
+       pim_ifp = up->rpf.source_nexthop.interface->info;
+       pim = pim_ifp->pim;
 
        FOR_ALL_INTERFACES (pim->vrf, ifp) {
                pim_ifp = ifp->info;
index dd9e21cae8782a030f8e498376b4f918d91e8278..67b1a95f74789c8dac64d6f193c6e69a627e6279 100644 (file)
@@ -234,7 +234,8 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
        up->channel_oil->cc.pktcnt++;
        PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
        // resolve mfcc_parent prior to mroute_add in channel_add_oif
-       if (up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
+       if (up->rpf.source_nexthop.interface &&
+           up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
                int vif_index = 0;
                vif_index = pim_if_find_vifindex_by_ifindex(
                        pim_ifp->pim,
@@ -301,6 +302,13 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
                return 0;
        }
 
+       if (!up->rpf.source_nexthop.interface) {
+               if (PIM_DEBUG_TRACE)
+                       zlog_debug("%s: up %s RPF is not present",
+                               __PRETTY_FUNCTION__, up->sg_str);
+               return 0;
+       }
+
        pim_ifp = up->rpf.source_nexthop.interface->info;
 
        rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
index b6cd1a7d11493f49a5076149b43125c7de8b7d09..9b5379384c9905a6baa96dff4e51c32c33aa2641 100644 (file)
@@ -39,6 +39,7 @@
 #include "pim_jp_agg.h"
 #include "pim_zebra.h"
 #include "pim_zlookup.h"
+#include "pim_rp.h"
 
 /**
  * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
@@ -170,6 +171,8 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
        struct pim_nexthop_cache *pnc = NULL;
        struct pim_nexthop_cache lookup;
        struct zclient *zclient = NULL;
+       struct listnode *upnode = NULL;
+       struct pim_upstream *upstream = NULL;
 
        zclient = pim_zebra_zclient_get();
 
@@ -177,8 +180,30 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
        lookup.rpf.rpf_addr = *addr;
        pnc = hash_lookup(pim->rpf_hash, &lookup);
        if (pnc) {
-               if (rp)
+               if (rp) {
+                       /* Release the (*, G)upstream from pnc->upstream_hash,
+                        * whose Group belongs to the RP getting deleted
+                        */
+                       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
+                               upstream)) {
+                               struct prefix grp;
+                               struct rp_info *trp_info;
+
+                               if (upstream->sg.src.s_addr != INADDR_ANY)
+                                       continue;
+
+                               grp.family = AF_INET;
+                               grp.prefixlen = IPV4_MAX_BITLEN;
+                               grp.u.prefix4 = upstream->sg.grp;
+
+                               trp_info = pim_rp_find_match_group(pim, &grp);
+                               if (trp_info == rp)
+                                       hash_release(pnc->upstream_hash,
+                                                    upstream);
+                       }
                        listnode_delete(pnc->rp_list, rp);
+               }
+
                if (up)
                        hash_release(pnc->upstream_hash, up);
 
@@ -207,6 +232,17 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
        }
 }
 
+void pim_rp_nexthop_del(struct rp_info *rp_info)
+{
+       rp_info->rp.source_nexthop.interface = NULL;
+       rp_info->rp.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
+               PIM_NET_INADDR_ANY;
+       rp_info->rp.source_nexthop.mrib_metric_preference =
+               router->infinite_assert_metric.metric_preference;
+       rp_info->rp.source_nexthop.mrib_route_metric =
+               router->infinite_assert_metric.route_metric;
+}
+
 /* Update RP nexthop info based on Nexthop update received from Zebra.*/
 static void pim_update_rp_nh(struct pim_instance *pim,
                             struct pim_nexthop_cache *pnc)
@@ -220,9 +256,11 @@ static void pim_update_rp_nh(struct pim_instance *pim,
                        continue;
 
                // Compute PIM RPF using cached nexthop
-               pim_ecmp_nexthop_search(pim, pnc, &rp_info->rp.source_nexthop,
-                                       &rp_info->rp.rpf_addr, &rp_info->group,
-                                       1);
+               if (!pim_ecmp_nexthop_search(pim, pnc,
+                   &rp_info->rp.source_nexthop,
+                   &rp_info->rp.rpf_addr, &rp_info->group,
+                   1))
+                       pim_rp_nexthop_del(rp_info);
        }
 }
 
@@ -278,12 +316,12 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg)
        old.source_nexthop.interface = up->rpf.source_nexthop.interface;
        rpf_result = pim_rpf_update(pim, up, &old, 0);
        if (rpf_result == PIM_RPF_FAILURE) {
-               pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__);
+               pim_upstream_rpf_clear(pim, up);
                return HASHWALK_CONTINUE;
        }
 
        /* update kernel multicast forwarding cache (MFC) */
-       if (up->channel_oil) {
+       if (up->rpf.source_nexthop.interface) {
                ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex;
 
                vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
@@ -306,9 +344,10 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg)
 
        if (PIM_DEBUG_PIM_NHT) {
                zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s",
-                          __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
-                          old.source_nexthop.interface->name,
-                          up->rpf.source_nexthop.interface->name);
+                       __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
+                       old.source_nexthop.interface
+                       ? old.source_nexthop.interface->name : "Unknwon",
+                       up->rpf.source_nexthop.interface->name);
        }
 
        return HASHWALK_CONTINUE;
index 796fbf9731943f2ca58278527ba516341455d630..6eff7bbc891a33caf75528c2c434400fc72910cb 100644 (file)
@@ -68,4 +68,5 @@ void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
 void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p);
 int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
                                     struct prefix *src, struct prefix *grp);
+void pim_rp_nexthop_del(struct rp_info *rp_info);
 #endif
index 2e12d728cfd4d68927ffc2420d0e0d296ec0d7ef..55d26113f7c51981729486117c00599589a6fb3d 100644 (file)
@@ -168,13 +168,15 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
                return c_oil;
        }
 
-       ifp = pim_if_find_by_vif_index(pim, input_vif_index);
-       if (!ifp) {
-               /* warning only */
-               zlog_warn(
-                       "%s: (S,G)=%s could not find input interface for input_vif_index=%d",
-                       __PRETTY_FUNCTION__, pim_str_sg_dump(sg),
-                       input_vif_index);
+       if (input_vif_index != MAXVIFS) {
+               ifp = pim_if_find_by_vif_index(pim, input_vif_index);
+               if (!ifp) {
+                       /* warning only */
+                       zlog_warn(
+                               "%s: (S,G)=%s could not find input interface for input_vif_index=%d",
+                               __PRETTY_FUNCTION__, pim_str_sg_dump(sg),
+                               input_vif_index);
+               }
        }
 
        c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
@@ -447,25 +449,31 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
        channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] =
                PIM_MROUTE_MIN_TTL;
 
-       if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
-               if (PIM_DEBUG_MROUTE) {
-                       char group_str[INET_ADDRSTRLEN];
-                       char source_str[INET_ADDRSTRLEN];
-                       pim_inet4_dump("<group?>",
-                                      channel_oil->oil.mfcc_mcastgrp,
-                                      group_str, sizeof(group_str));
-                       pim_inet4_dump("<source?>",
-                                      channel_oil->oil.mfcc_origin, source_str,
-                                      sizeof(source_str));
-                       zlog_debug(
-                               "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
-                               __FILE__, __PRETTY_FUNCTION__, oif->name,
-                               pim_ifp->mroute_vif_index, source_str,
-                               group_str);
-               }
+       /* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not
+        * valid to get installed in kernel.
+        */
+       if (channel_oil->oil.mfcc_parent != MAXVIFS) {
+               if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
+                       if (PIM_DEBUG_MROUTE) {
+                               char group_str[INET_ADDRSTRLEN];
+                               char source_str[INET_ADDRSTRLEN];
+                               pim_inet4_dump("<group?>",
+                                     channel_oil->oil.mfcc_mcastgrp,
+                                     group_str, sizeof(group_str));
+                               pim_inet4_dump("<source?>",
+                                     channel_oil->oil.mfcc_origin, source_str,
+                                     sizeof(source_str));
+                               zlog_debug(
+                                   "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
+                                   __FILE__, __PRETTY_FUNCTION__, oif->name,
+                                   pim_ifp->mroute_vif_index, source_str,
+                                   group_str);
+                       }
 
-               channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
-               return -5;
+                       channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]
+                               = old_ttl;
+                       return -5;
+               }
        }
 
        channel_oil->oif_creation[pim_ifp->mroute_vif_index] =
index 94d3840e98db72aafa561e706620cac66f0ed399..5dd4e8b326a38e963a545507b49a38629257b3f8 100644 (file)
@@ -64,6 +64,25 @@ struct channel_counts {
 
   Each channel_oil.oil is used to control an (S,G) entry in the Kernel
   Multicast Forwarding Cache.
+
+  There is a case when we create a channel_oil but don't install in the kernel
+
+  Case where (S, G) entry not installed in the kernel:
+    FRR receives IGMP/PIM (*, G) join and RP is not configured or
+    not-reachable, then create a channel_oil for the group G with the incoming
+    interface(channel_oil.oil.mfcc_parent) as invalid i.e "MAXVIF" and populate
+    the outgoing interface where join is received. Keep this entry in the stack,
+    but don't install in the kernel(channel_oil.installed = 0).
+
+  Case where (S, G) entry installed in the kernel:
+    When RP is configured and is reachable for the group G, and receiving a
+    join if channel_oil is already present then populate the incoming interface
+    and install the entry in the kernel, if channel_oil not present, then create
+    a new_channel oil(channel_oil.installed = 1).
+
+  is_valid: indicate if this entry is valid to get installed in kernel.
+  installed: indicate if this entry is installed in the kernel.
+
 */
 
 struct channel_oil {
index 4b402de6348e10f651b396ac3b2dd7fd9b2d3f5c..a4965b8ffe43733081adacf7908d731ec36cf2a3 100644 (file)
@@ -97,7 +97,7 @@ void pim_register_stop_send(struct interface *ifp, struct prefix_sg *sg,
        pinfo = (struct pim_interface *)ifp->info;
        if (!pinfo) {
                if (PIM_DEBUG_PIM_TRACE)
-                       zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__);
+                       zlog_debug("%s: No pinfo!", __PRETTY_FUNCTION__);
                return;
        }
        if (pim_msg_send(pinfo->pim_sock_fd, src, originator, buffer,
index 308d5a5e06c6791895787fd27440810ac6f8cea3..7094b93a45d5fe62f3bfe54339e3f6af01569968 100644 (file)
@@ -45,7 +45,9 @@
 #include "pim_iface.h"
 #include "pim_msdp.h"
 #include "pim_nht.h"
-
+#include "pim_mroute.h"
+#include "pim_oil.h"
+#include "pim_zebra.h"
 
 /* Cleanup pim->rpf_hash each node data */
 void pim_rp_list_hash_clean(void *data)
@@ -200,7 +202,7 @@ static struct rp_info *pim_rp_find_exact(struct pim_instance *pim,
 /*
  * Given a group, return the rp_info for that group
  */
-static struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
+struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
                                               const struct prefix *group)
 {
        struct listnode *node;
@@ -333,6 +335,77 @@ static void pim_rp_check_interfaces(struct pim_instance *pim,
        }
 }
 
+void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up)
+{
+       struct pim_rpf old_rpf;
+       enum pim_rpf_result rpf_result;
+       struct in_addr old_upstream_addr;
+       struct in_addr new_upstream_addr;
+       struct prefix nht_p;
+
+       old_upstream_addr = up->upstream_addr;
+       pim_rp_set_upstream_addr(pim, &new_upstream_addr, up->sg.src,
+                                up->sg.grp);
+
+       if (PIM_DEBUG_TRACE)
+               zlog_debug("%s: pim upstream update for  old upstream %s",
+                          __PRETTY_FUNCTION__,
+                          inet_ntoa(old_upstream_addr));
+
+       if (old_upstream_addr.s_addr == new_upstream_addr.s_addr)
+               return;
+
+       /* Lets consider a case, where a PIM upstream has a better RP as a
+        * result of a new RP configuration with more precise group range.
+        * This upstream has to be added to the upstream hash of new RP's
+        * NHT(pnc) and has to be removed from old RP's NHT upstream hash
+        */
+       if (old_upstream_addr.s_addr != INADDR_ANY) {
+               /* Deregister addr with Zebra NHT */
+               nht_p.family = AF_INET;
+               nht_p.prefixlen = IPV4_MAX_BITLEN;
+               nht_p.u.prefix4 = old_upstream_addr;
+               if (PIM_DEBUG_TRACE) {
+                       char buf[PREFIX2STR_BUFFER];
+
+                       prefix2str(&nht_p, buf, sizeof(buf));
+                       zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
+                                  __PRETTY_FUNCTION__, up->sg_str, buf);
+               }
+               pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
+       }
+
+       /* Update the upstream address */
+       up->upstream_addr = new_upstream_addr;
+
+       old_rpf.source_nexthop.interface = up->rpf.source_nexthop.interface;
+
+       rpf_result = pim_rpf_update(pim, up, &old_rpf, 1);
+       if (rpf_result == PIM_RPF_FAILURE)
+               pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__);
+
+       /* update kernel multicast forwarding cache (MFC) */
+       if (up->rpf.source_nexthop.interface && up->channel_oil) {
+               ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex;
+               int vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
+               /* Pass Current selected NH vif index to mroute download */
+               if (vif_index)
+                       pim_scan_individual_oil(up->channel_oil, vif_index);
+               else {
+                       if (PIM_DEBUG_PIM_NHT)
+                               zlog_debug(
+                                 "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
+                                 __PRETTY_FUNCTION__, up->sg_str,
+                                 up->rpf.source_nexthop.interface->name);
+               }
+       }
+
+       if (rpf_result == PIM_RPF_CHANGED)
+               pim_zebra_upstream_rpf_changed(pim, up, &old_rpf);
+
+       pim_zebra_update_all_interfaces(pim);
+}
+
 int pim_rp_new(struct pim_instance *pim, const char *rp,
               const char *group_range, const char *plist)
 {
@@ -347,6 +420,8 @@ int pim_rp_new(struct pim_instance *pim, const char *rp,
        struct prefix temp;
        struct pim_nexthop_cache pnc;
        struct route_node *rn;
+       struct pim_upstream *up;
+       struct listnode *upnode;
 
        rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
 
@@ -468,6 +543,27 @@ int pim_rp_new(struct pim_instance *pim, const char *rp,
                                        "%s: NHT Register rp_all addr %s grp %s ",
                                        __PRETTY_FUNCTION__, buf, buf1);
                        }
+
+                       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
+                                                 up)) {
+                               /* Find (*, G) upstream whose RP is not
+                                * configured yet
+                                */
+                               if ((up->upstream_addr.s_addr == INADDR_ANY)
+                                   && (up->sg.src.s_addr == INADDR_ANY)) {
+                                       struct prefix grp;
+                                       struct rp_info *trp_info;
+
+                                       grp.family = AF_INET;
+                                       grp.prefixlen = IPV4_MAX_BITLEN;
+                                       grp.u.prefix4 = up->sg.grp;
+                                       trp_info = pim_rp_find_match_group(pim,
+                                                                         &grp);
+                                       if (trp_info == rp_all)
+                                               pim_upstream_update(pim, up);
+                               }
+                       }
+
                        memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
                        if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all,
                                                      &pnc)) {
@@ -535,6 +631,21 @@ int pim_rp_new(struct pim_instance *pim, const char *rp,
                           rn->lock);
        }
 
+       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+               if (up->sg.src.s_addr == INADDR_ANY) {
+                       struct prefix grp;
+                       struct rp_info *trp_info;
+
+                       grp.family = AF_INET;
+                       grp.prefixlen = IPV4_MAX_BITLEN;
+                       grp.u.prefix4 = up->sg.grp;
+                       trp_info = pim_rp_find_match_group(pim, &grp);
+
+                       if (trp_info == rp_info)
+                               pim_upstream_update(pim, up);
+               }
+       }
+
        /* Register addr with Zebra NHT */
        nht_p.family = AF_INET;
        nht_p.prefixlen = IPV4_MAX_BITLEN;
@@ -577,6 +688,9 @@ int pim_rp_del(struct pim_instance *pim, const char *rp,
        struct prefix nht_p;
        struct route_node *rn;
        bool was_plist = false;
+       struct rp_info *trp_info;
+       struct pim_upstream *up;
+       struct listnode *upnode;
 
        if (group_range == NULL)
                result = str2prefix("224.0.0.0/4", &group);
@@ -621,6 +735,23 @@ int pim_rp_del(struct pim_instance *pim, const char *rp,
        rp_all = pim_rp_find_match_group(pim, &g_all);
 
        if (rp_all == rp_info) {
+               for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+                       /* Find the upstream (*, G) whose upstream address is
+                        * same as the deleted RP
+                        */
+                       if ((up->upstream_addr.s_addr == rp_addr.s_addr) &&
+                           (up->sg.src.s_addr == INADDR_ANY)) {
+                               struct prefix grp;
+                               grp.family = AF_INET;
+                               grp.prefixlen = IPV4_MAX_BITLEN;
+                               grp.u.prefix4 = up->sg.grp;
+                               trp_info = pim_rp_find_match_group(pim, &grp);
+                               if (trp_info == rp_all) {
+                                       pim_upstream_rpf_clear(pim, up);
+                                       up->upstream_addr.s_addr = INADDR_ANY;
+                               }
+                       }
+               }
                rp_all->rp.rpf_addr.family = AF_INET;
                rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
                rp_all->i_am_rp = 0;
@@ -655,6 +786,34 @@ int pim_rp_del(struct pim_instance *pim, const char *rp,
 
        pim_rp_refresh_group_to_rp_mapping(pim);
 
+       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+               /* Find the upstream (*, G) whose upstream address is same as
+                * the deleted RP
+                */
+               if ((up->upstream_addr.s_addr == rp_addr.s_addr) &&
+                   (up->sg.src.s_addr == INADDR_ANY)) {
+                       struct prefix grp;
+
+                       grp.family = AF_INET;
+                       grp.prefixlen = IPV4_MAX_BITLEN;
+                       grp.u.prefix4 = up->sg.grp;
+
+                       trp_info = pim_rp_find_match_group(pim, &grp);
+
+                       /* RP not found for the group grp */
+                       if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) {
+                               pim_upstream_rpf_clear(pim, up);
+                               pim_rp_set_upstream_addr(pim,
+                                       &up->upstream_addr,
+                                       up->sg.src, up->sg.grp);
+                       }
+
+                       /* RP found for the group grp */
+                       else
+                               pim_upstream_update(pim, up);
+               }
+       }
+
        XFREE(MTYPE_PIM_RP, rp_info);
        return PIM_SUCCESS;
 }
@@ -681,6 +840,7 @@ void pim_rp_setup(struct pim_instance *pim)
                else {
                        if (PIM_DEBUG_PIM_NHT_RP) {
                                char buf[PREFIX2STR_BUFFER];
+
                                prefix2str(&nht_p, buf, sizeof(buf));
                                zlog_debug(
                                        "%s: NHT Local Nexthop not found for RP %s ",
@@ -869,7 +1029,7 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group)
  * the rp configured and the source address
  *
  * If we have don't have a RP configured and the source address is *
- * then return failure.
+ * then set the upstream addr as INADDR_ANY and return failure.
  *
  */
 int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up,
@@ -890,6 +1050,7 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up,
                if (PIM_DEBUG_PIM_NHT_RP)
                        zlog_debug("%s: Received a (*,G) with no RP configured",
                                   __PRETTY_FUNCTION__);
+               up->s_addr = INADDR_ANY;
                return 0;
        }
 
index 672a69631907c0d12ae4375e2b4d36eca7d8deb7..7769864c08b35d8da940fcca257db1cf15e8f735 100644 (file)
@@ -71,4 +71,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty,
                             bool uj);
 void pim_resolve_rp_nh(struct pim_instance *pim);
 int pim_rp_list_cmp(void *v1, void *v2);
+struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
+                                       const struct prefix *group);
+void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up);
 #endif
index 814d2e076bb0f581d5d20770432aed962166b024..ee145a5b51a56501da7508fa300f0d10d0825d16 100644 (file)
@@ -205,6 +205,12 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
        struct prefix src, grp;
        bool neigh_needed = true;
 
+       if (up->upstream_addr.s_addr == INADDR_ANY) {
+               zlog_debug("%s: RP is not configured yet for %s",
+                       __PRETTY_FUNCTION__, up->sg_str);
+               return PIM_RPF_OK;
+       }
+
        saved.source_nexthop = rpf->source_nexthop;
        saved.rpf_addr = rpf->rpf_addr;
 
@@ -307,6 +313,33 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
        return PIM_RPF_OK;
 }
 
+/*
+ * In the case of RP deletion and RP unreachablity,
+ * uninstall the mroute in the kernel and clear the
+ * rpf information in the pim upstream and pim channel
+ * oil data structure.
+ */
+void pim_upstream_rpf_clear(struct pim_instance *pim,
+                           struct pim_upstream *up)
+{
+       if (up->rpf.source_nexthop.interface) {
+               if (up->channel_oil) {
+                       up->channel_oil->oil.mfcc_parent = MAXVIFS;
+                       pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__);
+
+               }
+               pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
+               up->rpf.source_nexthop.interface = NULL;
+               up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
+                       PIM_NET_INADDR_ANY;
+               up->rpf.source_nexthop.mrib_metric_preference =
+                       router->infinite_assert_metric.metric_preference;
+               up->rpf.source_nexthop.mrib_route_metric =
+                       router->infinite_assert_metric.route_metric;
+               up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
+       }
+}
+
 /*
   RFC 4601: 4.1.6.  State Summarization Macros
 
index b9fe162f21c66714fca28cea618ff40d195c4ba4..a4793df667f379ce10aba5c21a4052c481d958b6 100644 (file)
@@ -64,7 +64,8 @@ int pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
 enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
                                   struct pim_upstream *up, struct pim_rpf *old,
                                   uint8_t is_new);
-
+void pim_upstream_rpf_clear(struct pim_instance *pim,
+                           struct pim_upstream *up);
 int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf);
 int pim_rpf_addr_is_inaddr_any(struct pim_rpf *rpf);
 
index c6ab8f5a2af117a1f65fc012921f0b20cb041e4b..cb89e30a5024c6778d4a83edd2d96fc7028e5fcc 100644 (file)
@@ -219,17 +219,25 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
                pim_msdp_up_del(pim, &up->sg);
        }
 
-       /* Deregister addr with Zebra NHT */
-       nht_p.family = AF_INET;
-       nht_p.prefixlen = IPV4_MAX_BITLEN;
-       nht_p.u.prefix4 = up->upstream_addr;
-       if (PIM_DEBUG_TRACE) {
-               char buf[PREFIX2STR_BUFFER];
-               prefix2str(&nht_p, buf, sizeof(buf));
-               zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
-                          __PRETTY_FUNCTION__, up->sg_str, buf);
+       /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT
+        * and assign up->upstream_addr as INADDR_ANY.
+        * So before de-registering the upstream address, check if is not equal
+        * to INADDR_ANY. This is done in order to avoid de-registering for
+        * 255.255.255.255 which is maintained for some reason..
+        */
+       if (up->upstream_addr.s_addr != INADDR_ANY) {
+               /* Deregister addr with Zebra NHT */
+               nht_p.family = AF_INET;
+               nht_p.prefixlen = IPV4_MAX_BITLEN;
+               nht_p.u.prefix4 = up->upstream_addr;
+               if (PIM_DEBUG_TRACE) {
+                       char buf[PREFIX2STR_BUFFER];
+                       prefix2str(&nht_p, buf, sizeof(buf));
+                       zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
+                                  __PRETTY_FUNCTION__, up->sg_str, buf);
+               }
+               pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
        }
-       pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
 
        XFREE(MTYPE_PIM_UPSTREAM, up);
 
@@ -238,6 +246,13 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
 
 void pim_upstream_send_join(struct pim_upstream *up)
 {
+       if (!up->rpf.source_nexthop.interface) {
+               if (PIM_DEBUG_TRACE)
+                       zlog_debug("%s: up %s RPF is not present",
+                               __PRETTY_FUNCTION__, up->sg_str);
+               return;
+       }
+
        if (PIM_DEBUG_TRACE) {
                char rpf_str[PREFIX_STRLEN];
                pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str,
@@ -263,6 +278,13 @@ static int on_join_timer(struct thread *t)
 
        up = THREAD_ARG(t);
 
+       if (!up->rpf.source_nexthop.interface) {
+               if (PIM_DEBUG_TRACE)
+                       zlog_debug("%s: up %s RPF is not present",
+                       __PRETTY_FUNCTION__, up->sg_str);
+               return 0;
+       }
+
        /*
         * In the case of a HFR we will not ahve anyone to send this to.
         */
@@ -284,12 +306,13 @@ static int on_join_timer(struct thread *t)
 
 static void join_timer_stop(struct pim_upstream *up)
 {
-       struct pim_neighbor *nbr;
+       struct pim_neighbor *nbr = NULL;
 
        THREAD_OFF(up->t_join_timer);
 
-       nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
-                               up->rpf.rpf_addr.u.prefix4);
+       if (up->rpf.source_nexthop.interface)
+               nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
+                                       up->rpf.rpf_addr.u.prefix4);
 
        if (nbr)
                pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
@@ -356,6 +379,13 @@ void pim_upstream_join_suppress(struct pim_upstream *up,
        long t_joinsuppress_msec;
        long join_timer_remain_msec;
 
+       if (!up->rpf.source_nexthop.interface) {
+               if (PIM_DEBUG_TRACE)
+                       zlog_debug("%s: up %s RPF is not present",
+                               __PRETTY_FUNCTION__, up->sg_str);
+               return;
+       }
+
        t_joinsuppress_msec =
                MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
                    1000 * holdtime);
@@ -389,6 +419,13 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
        long join_timer_remain_msec;
        int t_override_msec;
 
+       if (!up->rpf.source_nexthop.interface) {
+               if (PIM_DEBUG_TRACE)
+                       zlog_debug("%s: up %s RPF is not present",
+                               __PRETTY_FUNCTION__, up->sg_str);
+               return;
+       }
+
        join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
        t_override_msec =
                pim_if_t_override_msec(up->rpf.source_nexthop.interface);
@@ -511,6 +548,20 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
 {
        enum pim_upstream_state old_state = up->join_state;
 
+       if (up->upstream_addr.s_addr == INADDR_ANY) {
+               if (PIM_DEBUG_PIM_EVENTS)
+                       zlog_debug("%s: RPF not configured for %s",
+                               __PRETTY_FUNCTION__, up->sg_str);
+               return;
+       }
+
+       if (!up->rpf.source_nexthop.interface)  {
+               if (PIM_DEBUG_PIM_EVENTS)
+                       zlog_debug("%s: RP not reachable for %s",
+                               __PRETTY_FUNCTION__, up->sg_str);
+               return;
+       }
+
        if (PIM_DEBUG_PIM_EVENTS) {
                zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
                           __PRETTY_FUNCTION__, up->sg_str,
@@ -558,11 +609,14 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
                    && !I_am_RP(pim, up->sg.grp)) {
                        if (PIM_DEBUG_PIM_TRACE_DETAIL)
                                zlog_debug(
-                                       "%s: *,G IIF %s S,G IIF %s ",
-                                       __PRETTY_FUNCTION__,
-                                       up->parent->rpf.source_nexthop
-                                               .interface->name,
-                                       up->rpf.source_nexthop.interface->name);
+                                 "%s: *,G IIF %s S,G IIF %s ",
+                                 __PRETTY_FUNCTION__,
+                                 up->parent->rpf.source_nexthop.interface ?
+                                 up->parent->rpf.source_nexthop.interface->name
+                                 : "Unknown",
+                                 up->rpf.source_nexthop.interface ?
+                                 up->rpf.source_nexthop.interface->name :
+                                 "Unknown");
                        pim_jp_agg_single_upstream_send(&up->parent->rpf,
                                                        up->parent,
                                                        1 /* (W,G) Join */);
@@ -611,15 +665,14 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
                ch->upstream = up;
 
        up = hash_get(pim->upstream_hash, up, hash_alloc_intern);
+       /* Set up->upstream_addr as INADDR_ANY, if RP is not
+        * configured and retain the upstream data structure
+        */
        if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
                                      sg->grp)) {
                if (PIM_DEBUG_TRACE)
                        zlog_debug("%s: Received a (*,G) with no RP configured",
                                   __PRETTY_FUNCTION__);
-
-               hash_release(pim->upstream_hash, up);
-               XFREE(MTYPE_PIM_UPSTREAM, up);
-               return NULL;
        }
 
        up->parent = pim_upstream_find_parent(pim, up);
@@ -659,45 +712,34 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
        if (up->sg.src.s_addr != INADDR_ANY)
                wheel_add_item(pim->upstream_sg_wheel, up);
 
-       rpf_result = pim_rpf_update(pim, up, NULL, 1);
-       if (rpf_result == PIM_RPF_FAILURE) {
-               struct prefix nht_p;
-
-               if (PIM_DEBUG_TRACE)
-                       zlog_debug(
-                               "%s: Attempting to create upstream(%s), Unable to RPF for source",
-                               __PRETTY_FUNCTION__, up->sg_str);
-
-               nht_p.family = AF_INET;
-               nht_p.prefixlen = IPV4_MAX_BITLEN;
-               nht_p.u.prefix4 = up->upstream_addr;
-               pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
+       if (up->upstream_addr.s_addr == INADDR_ANY)
+               /* Create a dummmy channel oil with incoming ineterface MAXVIFS,
+                * since RP is not configured
+                */
+               up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS);
 
-               if (up->parent) {
-                       listnode_delete(up->parent->sources, up);
-                       up->parent = NULL;
+       else {
+               rpf_result = pim_rpf_update(pim, up, NULL, 1);
+               if (rpf_result == PIM_RPF_FAILURE) {
+                       if (PIM_DEBUG_TRACE)
+                               zlog_debug(
+                                       "%s: Attempting to create upstream(%s), Unable to RPF for source",
+                                       __PRETTY_FUNCTION__, up->sg_str);
+                       /* Create a dummmy channel oil with incoming ineterface
+                        * MAXVIFS, since RP is not reachable
+                        */
+                       up->channel_oil = pim_channel_oil_add(
+                               pim, &up->sg, MAXVIFS);
                }
 
-               if (up->sg.src.s_addr != INADDR_ANY)
-                       wheel_remove_item(pim->upstream_sg_wheel, up);
-
-               pim_upstream_remove_children(pim, up);
-               if (up->sources)
-                       list_delete(&up->sources);
-
-               list_delete(&up->ifchannels);
-
-               hash_release(pim->upstream_hash, up);
-               XFREE(MTYPE_PIM_UPSTREAM, up);
-               return NULL;
+               if (up->rpf.source_nexthop.interface) {
+                       pim_ifp = up->rpf.source_nexthop.interface->info;
+                       if (pim_ifp)
+                               up->channel_oil = pim_channel_oil_add(pim,
+                                       &up->sg, pim_ifp->mroute_vif_index);
+               }
        }
 
-       if (up->rpf.source_nexthop.interface) {
-               pim_ifp = up->rpf.source_nexthop.interface->info;
-               if (pim_ifp)
-                       up->channel_oil = pim_channel_oil_add(
-                               pim, &up->sg, pim_ifp->mroute_vif_index);
-       }
        listnode_add_sort(pim->upstream_list, up);
 
        if (PIM_DEBUG_TRACE) {
@@ -783,7 +825,7 @@ struct pim_upstream *pim_upstream_add(struct pim_instance *pim,
                        zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
                   __PRETTY_FUNCTION__, name,
                   up->sg_str, buf, up->rpf.source_nexthop.interface ?
-                   up->rpf.source_nexthop.interface->name : "NIL" ,
+                   up->rpf.source_nexthop.interface->name : "Unknown" ,
                   found, up->ref_count);
                } else
                        zlog_debug("%s(%s): (%s) failure to create",
@@ -896,7 +938,7 @@ void pim_upstream_update_join_desired(struct pim_instance *pim,
                PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
 
        /* switched from false to true */
-       if (is_join_desired && !was_join_desired) {
+       if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) {
                pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
                return;
        }
@@ -973,7 +1015,9 @@ void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
                                (old_rpf_ifp == ch->interface) &&
                                /* RPF_interface(S) stopped being I */
                                (ch->upstream->rpf.source_nexthop
-                                        .interface != ch->interface)) {
+                                       .interface) &&
+                               (ch->upstream->rpf.source_nexthop
+                                       .interface != ch->interface)) {
                                assert_action_a5(ch);
                        }
                } /* PIM_IFASSERT_I_AM_LOSER */
@@ -1339,6 +1383,13 @@ static int pim_upstream_register_stop_timer(struct thread *t)
        case PIM_REG_JOIN:
                break;
        case PIM_REG_PRUNE:
+               if (!up->rpf.source_nexthop.interface) {
+                       if (PIM_DEBUG_TRACE)
+                               zlog_debug("%s: up %s RPF is not present",
+                                       __PRETTY_FUNCTION__, up->sg_str);
+                       return 0;
+               }
+
                pim_ifp = up->rpf.source_nexthop.interface->info;
                if (!pim_ifp) {
                        if (PIM_DEBUG_TRACE)
@@ -1515,11 +1566,19 @@ void pim_upstream_find_new_rpf(struct pim_instance *pim)
         * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
         */
        for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
+               if (up->upstream_addr.s_addr == INADDR_ANY) {
+                       if (PIM_DEBUG_TRACE)
+                               zlog_debug(
+                                   "%s: RP not configured for Upstream %s",
+                                   __PRETTY_FUNCTION__, up->sg_str);
+                       continue;
+               }
+
                if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
                        if (PIM_DEBUG_TRACE)
                                zlog_debug(
-                                       "Upstream %s without a path to send join, checking",
-                                       up->sg_str);
+                                       "%s: Upstream %s without a path to send join, checking",
+                                       __PRETTY_FUNCTION__, up->sg_str);
                        pim_rpf_update(pim, up, NULL, 1);
                }
        }
@@ -1586,7 +1645,8 @@ static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
 
        /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
         * so we will skip that here */
-       if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
+       if (up->rpf.source_nexthop.interface &&
+               pim_if_connected_to_source(up->rpf.source_nexthop.interface,
                                       up->sg.src)) {
                return true;
        }
@@ -1679,7 +1739,8 @@ static void pim_upstream_sg_running(void *arg)
        } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
                pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
 
-       if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) {
+       if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) &&
+           (up->rpf.source_nexthop.interface)) {
                pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
        }
        return;
index f44b95c81105095774f6c080330e846ca6dc70a7..70e70140d19b0c2838c7af9465b275efafee1784 100644 (file)
@@ -88,10 +88,30 @@ enum pim_upstream_sptbit {
 
 /*
   Upstream (S,G) channel in Joined state
-
   (S,G) in the "Not Joined" state is not represented
-
   See RFC 4601: 4.5.7.  Sending (S,G) Join/Prune Message
+
+  upstream_addr : Who we are talking to.
+  For (*, G), upstream_addr is RP address or INADDR_ANY(if RP not configured)
+  For (S, G), upstream_addr is source address
+
+  rpf: contains the nexthop information to whom we are talking to.
+
+  join_state: JOINED/NOTJOINED
+
+  In the case when FRR receives IGMP/PIM (*, G) join for group G and RP is not
+  configured, then create a pim_upstream with the below information.
+  pim_upstream->upstream address: INADDR_ANY
+  pim_upstream->rpf: Unknown
+  pim_upstream->state: NOTJOINED
+
+  When a new RP gets configured for G, find the corresponding pim upstream (*,G)
+  entries and update the upstream address as new RP address if it the better one
+  for the group G.
+
+  When RP becomes reachable, populate the nexthop information in
+  pim_upstream->rpf and update the state to JOINED.
+
 */
 struct pim_upstream {
        struct pim_upstream *parent;
index 11ca6e8a108010bba7a44ff19fca425c5b6af770..78cccd5877732e0594fc75aa69f706626d8fbca0 100644 (file)
@@ -472,55 +472,72 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim,
                                    struct pim_upstream *up,
                                    struct pim_rpf *old)
 {
-       struct pim_neighbor *nbr;
+       if (old->source_nexthop.interface) {
+               struct pim_neighbor *nbr;
 
-       nbr = pim_neighbor_find(old->source_nexthop.interface,
-                               old->rpf_addr.u.prefix4);
-       if (nbr)
-               pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
+               nbr = pim_neighbor_find(old->source_nexthop.interface,
+                                       old->rpf_addr.u.prefix4);
+               if (nbr)
+                       pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
 
-       /*
-        * We have detected a case where we might need
-        * to rescan the inherited o_list so do it.
-        */
-       if (up->channel_oil->oil_inherited_rescan) {
-               pim_upstream_inherited_olist_decide(pim, up);
-               up->channel_oil->oil_inherited_rescan = 0;
-       }
-
-       if (up->join_state == PIM_UPSTREAM_JOINED) {
                /*
-                * If we come up real fast we can be here
-                * where the mroute has not been installed
-                * so install it.
+                * We have detected a case where we might need
+                * to rescan the inherited o_list so do it.
                 */
-               if (!up->channel_oil->installed)
-                       pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
+               if (up->channel_oil->oil_inherited_rescan) {
+                       pim_upstream_inherited_olist_decide(pim, up);
+                       up->channel_oil->oil_inherited_rescan = 0;
+               }
+
+               if (up->join_state == PIM_UPSTREAM_JOINED) {
+                       /*
+                        * If we come up real fast we can be here
+                        * where the mroute has not been installed
+                        * so install it.
+                        */
+                       if (!up->channel_oil->installed)
+                               pim_mroute_add(up->channel_oil,
+                                       __PRETTY_FUNCTION__);
+
+                       /*
+                        * RFC 4601: 4.5.7.  Sending (S,G)
+                        * Join/Prune Messages
+                        *
+                        * Transitions from Joined State
+                        *
+                        * RPF'(S,G) changes not due to an Assert
+                        *
+                        * The upstream (S,G) state machine remains
+                        * in Joined state. Send Join(S,G) to the new
+                        * upstream neighbor, which is the new value
+                        * of RPF'(S,G).  Send Prune(S,G) to the old
+                        * upstream neighbor, which is the old value
+                        * of RPF'(S,G).  Set the Join Timer (JT) to
+                        * expire after t_periodic seconds.
+                        */
+                       pim_jp_agg_switch_interface(old, &up->rpf, up);
+
+                       pim_upstream_join_timer_restart(up, old);
+               } /* up->join_state == PIM_UPSTREAM_JOINED */
+       }
 
+       else {
                /*
-                * RFC 4601: 4.5.7.  Sending (S,G)
-                * Join/Prune Messages
-                *
-                * Transitions from Joined State
-                *
-                * RPF'(S,G) changes not due to an Assert
-                *
-                * The upstream (S,G) state machine remains
-                * in Joined state. Send Join(S,G) to the new
-                * upstream neighbor, which is the new value
-                * of RPF'(S,G).  Send Prune(S,G) to the old
-                * upstream neighbor, which is the old value
-                * of RPF'(S,G).  Set the Join Timer (JT) to
-                * expire after t_periodic seconds.
+                * We have detected a case where we might need
+                * to rescan the inherited o_list so do it.
                 */
-               pim_jp_agg_switch_interface(old, &up->rpf, up);
+               if (up->channel_oil->oil_inherited_rescan) {
+                       pim_upstream_inherited_olist_decide(pim, up);
+                       up->channel_oil->oil_inherited_rescan = 0;
+               }
 
-               pim_upstream_join_timer_restart(up, old);
-       } /* up->join_state == PIM_UPSTREAM_JOINED */
+               if (!up->channel_oil->installed)
+                       pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
+       }
 
-       /* FIXME can join_desired actually be changed by
-          pim_rpf_update()
-          returning PIM_RPF_CHANGED ? */
+       /* FIXME can join_desired actually be changed by pim_rpf_update()
+        * returning PIM_RPF_CHANGED ?
+        */
        pim_upstream_update_join_desired(pim, up);
 }
 
@@ -535,6 +552,14 @@ static void scan_upstream_rpf_cache(struct pim_instance *pim)
                struct pim_rpf old;
                struct prefix nht_p;
 
+               if (up->upstream_addr.s_addr == INADDR_ANY) {
+                       if (PIM_DEBUG_TRACE)
+                               zlog_debug(
+                                   "%s: RP not configured for Upstream %s",
+                                   __PRETTY_FUNCTION__, up->sg_str);
+                       continue;
+               }
+
                nht_p.family = AF_INET;
                nht_p.prefixlen = IPV4_MAX_BITLEN;
                nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
@@ -561,10 +586,9 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
        int input_iface_vif_index;
        int old_vif_index;
 
-       if (!pim_rp_set_upstream_addr(c_oil->pim, &vif_source,
+       pim_rp_set_upstream_addr(c_oil->pim, &vif_source,
                                      c_oil->oil.mfcc_origin,
-                                     c_oil->oil.mfcc_mcastgrp))
-               return;
+                                     c_oil->oil.mfcc_mcastgrp);
 
        if (in_vif_index)
                input_iface_vif_index = in_vif_index;
@@ -950,112 +974,141 @@ void igmp_source_forward_start(struct pim_instance *pim,
                struct pim_upstream *up = NULL;
 
                if (!pim_rp_set_upstream_addr(pim, &vif_source,
-                                             source->source_addr, sg.grp))
-                       return;
-
-               /* Register addr with Zebra NHT */
-               nht_p.family = AF_INET;
-               nht_p.prefixlen = IPV4_MAX_BITLEN;
-               nht_p.u.prefix4 = vif_source;
-               memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache));
+                                             source->source_addr, sg.grp)) {
+                       /*Create a dummy channel oil */
+                       source->source_channel_oil =
+                           pim_channel_oil_add(pim, &sg, MAXVIFS);
 
-               src.family = AF_INET;
-               src.prefixlen = IPV4_MAX_BITLEN;
-               src.u.prefix4 = vif_source; // RP or Src address
-               grp.family = AF_INET;
-               grp.prefixlen = IPV4_MAX_BITLEN;
-               grp.u.prefix4 = sg.grp;
+                       if (!source->source_channel_oil) {
+                               if (PIM_DEBUG_IGMP_TRACE) {
+                                       zlog_debug(
+                                       "%s %s: could not create OIL for channel (S,G)=%s",
+                                       __FILE__, __PRETTY_FUNCTION__,
+                                       pim_str_sg_dump(&sg));
+                               }
+                               return;
+                       }
+               }
 
-               if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
+               else {
+                       /* Register addr with Zebra NHT */
+                       nht_p.family = AF_INET;
+                       nht_p.prefixlen = IPV4_MAX_BITLEN;
+                       nht_p.u.prefix4 = vif_source;
+                       memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache));
+
+                       src.family = AF_INET;
+                       src.prefixlen = IPV4_MAX_BITLEN;
+                       src.u.prefix4 = vif_source; // RP or Src address
+                       grp.family = AF_INET;
+                       grp.prefixlen = IPV4_MAX_BITLEN;
+                       grp.u.prefix4 = sg.grp;
+
+                       if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
                                              &out_pnc)) {
-                       if (out_pnc.nexthop_num) {
-                               up = pim_upstream_find(pim, &sg);
-                               memset(&nexthop, 0, sizeof(nexthop));
-                               if (up)
-                                       memcpy(&nexthop,
-                                              &up->rpf.source_nexthop,
-                                              sizeof(struct pim_nexthop));
-                               pim_ecmp_nexthop_search(pim, &out_pnc, &nexthop,
-                                                       &src, &grp, 0);
-                               if (nexthop.interface)
-                                       input_iface_vif_index =
+                               if (out_pnc.nexthop_num) {
+                                       up = pim_upstream_find(pim, &sg);
+                                       memset(&nexthop, 0, sizeof(nexthop));
+                                       if (up)
+                                               memcpy(&nexthop,
+                                                   &up->rpf.source_nexthop,
+                                                   sizeof(struct pim_nexthop));
+                                       pim_ecmp_nexthop_search(pim, &out_pnc,
+                                                               &nexthop,
+                                                               &src, &grp, 0);
+                                       if (nexthop.interface)
+                                               input_iface_vif_index =
                                                pim_if_find_vifindex_by_ifindex(
-                                                       pim,
-                                                       nexthop.interface->ifindex);
-                       } else {
-                               if (PIM_DEBUG_ZEBRA) {
-                                       char buf1[INET_ADDRSTRLEN];
-                                       char buf2[INET_ADDRSTRLEN];
-                                       pim_inet4_dump("<source?>",
+                                                   pim,
+                                                   nexthop.interface->ifindex);
+                               } else {
+                                       if (PIM_DEBUG_ZEBRA) {
+                                               char buf1[INET_ADDRSTRLEN];
+                                               char buf2[INET_ADDRSTRLEN];
+
+                                               pim_inet4_dump("<source?>",
                                                       nht_p.u.prefix4, buf1,
                                                       sizeof(buf1));
-                                       pim_inet4_dump("<source?>",
+                                               pim_inet4_dump("<source?>",
                                                       grp.u.prefix4, buf2,
                                                       sizeof(buf2));
-                                       zlog_debug(
+                                               zlog_debug(
                                                "%s: NHT Nexthop not found for addr %s grp %s",
                                                __PRETTY_FUNCTION__, buf1,
                                                buf2);
+                                       }
                                }
-                       }
-               } else
-                       input_iface_vif_index =
-                               pim_ecmp_fib_lookup_if_vif_index(pim, &src,
+                       } else
+                               input_iface_vif_index =
+                                   pim_ecmp_fib_lookup_if_vif_index(pim, &src,
                                                                 &grp);
 
-               if (PIM_DEBUG_ZEBRA) {
-                       char buf2[INET_ADDRSTRLEN];
-                       pim_inet4_dump("<source?>", vif_source, buf2,
-                                      sizeof(buf2));
-                       zlog_debug("%s: NHT %s vif_source %s vif_index:%d ",
-                                  __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
-                                  buf2, input_iface_vif_index);
-               }
-
-               if (input_iface_vif_index < 1) {
-                       if (PIM_DEBUG_IGMP_TRACE) {
-                               char source_str[INET_ADDRSTRLEN];
-                               pim_inet4_dump("<source?>", source->source_addr,
-                                              source_str, sizeof(source_str));
-                               zlog_debug(
-                                       "%s %s: could not find input interface for source %s",
-                                       __FILE__, __PRETTY_FUNCTION__,
-                                       source_str);
-                       }
-                       return;
-               }
+                       if (PIM_DEBUG_ZEBRA) {
+                               char buf2[INET_ADDRSTRLEN];
 
-               /*
-                 Protect IGMP against adding looped MFC entries created by both
-                 source and receiver attached to the same interface. See TODO
-                 T22.
-               */
-               if (input_iface_vif_index == pim_oif->mroute_vif_index) {
-                       /* ignore request for looped MFC entry */
-                       if (PIM_DEBUG_IGMP_TRACE) {
-                               zlog_debug(
-                                       "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
+                               pim_inet4_dump("<source?>", vif_source, buf2,
+                                              sizeof(buf2));
+                               zlog_debug("%s: NHT %s vif_source %s vif_index:%d ",
                                        __PRETTY_FUNCTION__,
                                        pim_str_sg_dump(&sg),
-                                       source->source_group->group_igmp_sock
-                                               ->fd,
-                                       source->source_group->group_igmp_sock
-                                               ->interface->name,
-                                       input_iface_vif_index);
+                                       buf2, input_iface_vif_index);
                        }
-                       return;
-               }
 
-               source->source_channel_oil =
-                       pim_channel_oil_add(pim, &sg, input_iface_vif_index);
-               if (!source->source_channel_oil) {
-                       if (PIM_DEBUG_IGMP_TRACE) {
-                               zlog_debug(
-                                       "%s %s: could not create OIL for channel (S,G)=%s",
-                                       __FILE__, __PRETTY_FUNCTION__,
-                                       pim_str_sg_dump(&sg));
+                       if (input_iface_vif_index < 1) {
+                               if (PIM_DEBUG_IGMP_TRACE) {
+                                       char source_str[INET_ADDRSTRLEN];
+                                       pim_inet4_dump("<source?>",
+                                               source->source_addr,
+                                               source_str, sizeof(source_str));
+                                       zlog_debug(
+                                           "%s %s: could not find input interface for source %s",
+                                           __FILE__, __PRETTY_FUNCTION__,
+                                           source_str);
+                               }
+                               source->source_channel_oil =
+                                   pim_channel_oil_add(pim, &sg, MAXVIFS);
+                       }
+
+                       else {
+                               /*
+                                * Protect IGMP against adding looped MFC
+                                * entries created by both source and receiver
+                                * attached to the same interface. See TODO
+                                * T22.
+                                */
+                               if (input_iface_vif_index ==
+                                   pim_oif->mroute_vif_index) {
+                                       /* ignore request for looped MFC entry
+                                        */
+                                       if (PIM_DEBUG_IGMP_TRACE) {
+                                               zlog_debug(
+                                                   "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
+                                                   __PRETTY_FUNCTION__,
+                                                   pim_str_sg_dump(&sg),
+                                                   source->source_group
+                                                   ->group_igmp_sock->fd,
+                                                   source->source_group
+                                                   ->group_igmp_sock
+                                                   ->interface->name,
+                                                   input_iface_vif_index);
+                                       }
+                                       return;
+                               }
+
+                               source->source_channel_oil =
+                                   pim_channel_oil_add(pim, &sg,
+                                       input_iface_vif_index);
+                               if (!source->source_channel_oil) {
+                                       if (PIM_DEBUG_IGMP_TRACE) {
+                                               zlog_debug(
+                                                   "%s %s: could not create OIL for channel (S,G)=%s",
+                                                   __FILE__,
+                                                   __PRETTY_FUNCTION__,
+                                                   pim_str_sg_dump(&sg));
+                                       }
+                                       return;
+                               }
                        }
-                       return;
                }
        }
 
@@ -1188,15 +1241,13 @@ void pim_forward_start(struct pim_ifchannel *ch)
                               sizeof(upstream_str));
                zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)", __PRETTY_FUNCTION__,
                           source_str, group_str, ch->interface->name,
-                          upstream_str);
+                          inet_ntoa(up->upstream_addr));
        }
 
        /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS,
           as part of mroute_del called by pim_forward_stop.
        */
-       if (!up->channel_oil
-           || (up->channel_oil
-               && up->channel_oil->oil.mfcc_parent >= MAXVIFS)) {
+       if ((up->upstream_addr.s_addr != INADDR_ANY) && (!up->channel_oil)) {
                struct prefix nht_p, src, grp;
                struct pim_nexthop_cache out_pnc;
 
@@ -1267,17 +1318,33 @@ void pim_forward_start(struct pim_ifchannel *ch)
                                        __FILE__, __PRETTY_FUNCTION__,
                                        source_str);
                        }
-                       return;
+                       up->channel_oil = pim_channel_oil_add(pim, &up->sg,
+                                                               MAXVIFS);
                }
+
+               else {
+                       up->channel_oil = pim_channel_oil_add(pim, &up->sg,
+                                                       input_iface_vif_index);
+                       if (!up->channel_oil) {
+                               if (PIM_DEBUG_PIM_TRACE)
+                                       zlog_debug(
+                                           "%s %s: could not create OIL for channel (S,G)=%s",
+                                           __FILE__, __PRETTY_FUNCTION__,
+                                           up->sg_str);
+                               return;
+                       }
+               }
+
                if (PIM_DEBUG_TRACE) {
                        struct interface *in_intf = pim_if_find_by_vif_index(
                                pim, input_iface_vif_index);
                        zlog_debug(
                                "%s: Update channel_oil IIF %s VIFI %d entry %s ",
                                __PRETTY_FUNCTION__,
-                               in_intf ? in_intf->name : "NIL",
+                               in_intf ? in_intf->name : "Unknown",
                                input_iface_vif_index, up->sg_str);
                }
+
                up->channel_oil = pim_channel_oil_add(pim, &up->sg,
                                                      input_iface_vif_index);
                if (!up->channel_oil) {
index 656b000579f380d73d633b27e9c7f79e2b2e49aa..889a83a136bdaec25bc9bf9214c2e3f34b368f18 100644 (file)
@@ -127,8 +127,6 @@ void pim_terminate(void)
 {
        struct zclient *zclient;
 
-       pim_free();
-
        /* reverse prefix_list_init */
        prefix_list_add_hook(NULL);
        prefix_list_delete_hook(NULL);
@@ -142,6 +140,8 @@ void pim_terminate(void)
                zclient_free(zclient);
        }
 
+       pim_free();
        pim_router_terminate();
+
        frr_fini();
 }
diff --git a/redhat/README.rpm_build.md b/redhat/README.rpm_build.md
deleted file mode 100644 (file)
index a3f0957..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-Building your own FRRouting RPM
-======================================
-(Tested on CentOS 6, CentOS 7 and Fedora 24.)
-
-1. On CentOS 6 (which doesn't provide a bison/automake/autoconf of a recent enough version):
-    - Check out ../doc/developer/building-frr-for-centos6.rst for details on installing
-    a bison/automake/autoconf to support frr building.
-
-    Newer automake/autoconf/bison is only needed to build the rpm and is
-    **not** needed to install the binary rpm package
-
-2. Install the build packages as documented in doc/developer/building-frr-for-xxxxx.rst and the following additional packages:
-
-        yum install rpm-build net-snmp-devel pam-devel libcap-devel
-
-    Additionally, on systems with systemd (CentOS 7, Fedora)
-
-        yum install systemd-devel
-
-    (use `dnf install` on new Fedora instead of `yum install`)
-
-3. Checkout FRR under a **unpriviledged** user account
-
-        git clone https://github.com/frrouting/frr.git frr
-
-4. Run Bootstrap and make distribution tar.gz
-
-        cd frr
-        ./bootstrap.sh
-        ./configure --with-pkg-extra-version=-MyRPMVersion \
-            SPHINXBUILD=sphinx-build2.7
-        make dist
-            
-    Note: configure parameters are not important for the RPM building - except the `with-pkg-extra-version` if you want to give the RPM a specific name to
-    mark your own unoffical build
-
-5. Create RPM directory structure and populate with sources
-
-        mkdir rpmbuild
-        mkdir rpmbuild/SOURCES
-        mkdir rpmbuild/SPECS
-        cp redhat/*.spec rpmbuild/SPECS/
-        cp frr*.tar.gz rpmbuild/SOURCES/
-
-6. Edit rpm/SPECS/frr.spec with configuration as needed
-    Look at the beginning of the file and adjust the following parameters to enable or disable features as required:
-    
-        ############### FRRouting (FRR) configure options #################
-        # with-feature options
-        %{!?with_pam:           %global  with_pam           0 }
-        %{!?with_ospfclient:    %global  with_ospfclient    1 }
-        %{!?with_ospfapi:       %global  with_ospfapi       1 }
-        %{!?with_irdp:          %global  with_irdp          1 }
-        %{!?with_rtadv:         %global  with_rtadv         1 }
-        %{!?with_ldpd:          %global  with_ldpd          1 }
-        %{!?with_nhrpd:         %global  with_nhrpd         1 }
-        %{!?with_eigrp:         %global  with_eigrpd        1 }
-        %{!?with_shared:        %global  with_shared        1 }
-        %{!?with_multipath:     %global  with_multipath     256 }
-        %{!?frr_user:           %global  frr_user           frr }
-        %{!?vty_group:          %global  vty_group          frrvty }
-        %{!?with_fpm:           %global  with_fpm           0 }
-        %{!?with_watchfrr:      %global  with_watchfrr      1 }
-        %{!?with_bgp_vnc:       %global  with_bgp_vnc       0 }
-        %{!?with_pimd:          %global  with_pimd          1 }
-        %{!?with_rpki:          %global  with_rpki          0 }
-
-7. Build the RPM
-
-        rpmbuild --define "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/frr.spec
-
-   If building with RPKI, then download and install the additional RPKI
-   packages from
-        https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact
-
-DONE.
-
-If all works correctly, then you should end up with the RPMs under 
-`rpmbuild/RPMS` and the Source RPM under `rpmbuild/SRPMS`
-
-
-Enabling daemons after installation of the package:
----------------------------------------------------
-
-### init.d based systems (ie CentOS 6):
-
-1. Edit /etc/frr/daemons and enable required routing daemons (Zebra is probably needed for most deployments, so make sure to enable it.)
-
-2. Enable the daemons as needed to run after boot (Zebra is mandatory)
-    
-        chkconfig frr on
-
-3. Check your firewall / IPtables to make sure the routing protocols are
-allowed.
-        
-5. Start the FRR daemons (or reboot)
-
-        service frr start
-            
-Configuration is stored in `/etc/frr/*.conf` files and daemon selection is stored in `/etc/frr/daemons`.
-
-
-### systemd based systems (ie CentOS 7, Fedora 24)
-
-1. Edit /etc/frr/daemons and enable required routing daemons (Zebra is probably needed for most deployments, so make sure to enable it.)
-2. Enable the frr daemons to run after boot.
-    
-        systemctl enable frr
-
-2. Check your firewall / IPtables to make sure the routing protocols are
-allowed.
-        
-3. Start the daemons (or reboot)
-
-        systemctl start frr
-            
-Configuration is stored in `/etc/frr/*.conf` files and daemon selection is stored in `/etc/frr/daemons`.
-
diff --git a/redhat/daemons b/redhat/daemons
deleted file mode 100644 (file)
index 7f3ff36..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-# This file tells the frr package which daemons to start.
-#
-# Entries are in the format: <daemon>=(yes|no|priority)
-#   0, "no"  = disabled
-#   1, "yes" = highest priority
-#   2 .. 10  = lower priorities
-#
-# For daemons which support multiple instances, a 2nd line listing
-# the instances can be added. Eg for ospfd:
-#   ospfd=yes
-#   ospfd_instances="1,2"
-#
-# Priorities were suggested by Dancer <dancer@zeor.simegen.com>.
-# They're used to start the FRR daemons in more than one step
-# (for example start one or two at network initialization and the
-# rest later). The number of FRR daemons being small, priorities
-# must be between 1 and 9, inclusive (or the initscript has to be
-# changed). /etc/init.d/frr then can be started as
-#
-#   /etc/init.d/frr <start|stop|restart|<priority>>
-#
-# where priority 0 is the same as 'stop', priority 10 or 'start'
-# means 'start all'
-#
-# Sample configurations for these daemons can be found in
-# /usr/share/doc/frr/examples/.
-#
-# ATTENTION:
-#
-# When activation a daemon at the first time, a config file, even if it is
-# empty, has to be present *and* be owned by the user and group "frr", else
-# the daemon will not be started by /etc/init.d/frr. The permissions should
-# be u=rw,g=r,o=.
-# When using "vtysh" such a config file is also needed. It should be owned by
-# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
-#
-watchfrr_enable=yes
-watchfrr_options="-r '/usr/lib/frr/frr restart %s' -s '/usr/lib/frr/frr start %s' -k '/usr/lib/frr/frr stop %s'"
-#
-zebra=no
-bgpd=no
-ospfd=no
-ospf6d=no
-ripd=no
-ripngd=no
-isisd=no
-ldpd=no
-pimd=no
-nhrpd=no
-eigrpd=no
-babeld=no
-sharpd=no
-pbrd=no
-staticd=no
-bfdd=no
-fabricd=no
-
-#
-# Command line options for the daemons
-#
-zebra_options=("-A 127.0.0.1")
-bgpd_options=("-A 127.0.0.1")
-ospfd_options=("-A 127.0.0.1")
-ospf6d_options=("-A ::1")
-ripd_options=("-A 127.0.0.1")
-ripngd_options=("-A ::1")
-isisd_options=("-A 127.0.0.1")
-ldpd_options=("-A 127.0.0.1")
-pimd_options=("-A 127.0.0.1")
-nhrpd_options=("-A 127.0.0.1")
-eigrpd_options=("-A 127.0.0.1")
-babeld_options=("-A 127.0.0.1")
-sharpd_options=("-A 127.0.0.1")
-pbrd_options=("-A 127.0.0.1")
-staticd_options=("-A 127.0.0.1")
-bfdd_options=("-A 127.0.0.1")
-fabricd_options=("-A 127.0.0.1")
-
-#
-# If the vtysh_enable is yes, then the unified config is read
-# and applied if it exists.  If no unified frr.conf exists
-# then the per-daemon <daemon>.conf files are used)
-# If vtysh_enable is no or non-existant, the frr.conf is ignored.
-# it is highly suggested to have this set to yes
-vtysh_enable=yes
-
diff --git a/redhat/frr.init b/redhat/frr.init
deleted file mode 100755 (executable)
index b59656a..0000000
+++ /dev/null
@@ -1,577 +0,0 @@
-#!/bin/bash
-#
-#   /etc/rc.d/init.d/frr
-#
-#   Start/Stop the FRR Routing daemons
-#   <any general comments about this init script>
-#
-# chkconfig: 2345 15 85
-#
-# description: FRRouting (FRR) is a routing suite for IP routing protocols
-#              like BGP, OSPF, RIP and others. This script contols the main
-#              daemon "frr" as well as the individual protocol daemons.
-#
-### BEGIN INIT INFO
-# Provides: frr
-# Required-Start: $local_fs $network $syslog
-# Required-Stop: $local_fs $syslog
-# Should-Start: $syslog
-# Should-Stop: $network $syslog
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Start/Stop the FRR Routing daemons
-# Description: FRRouting (FRR) is a routing suite for IP routing protocols
-#              like BGP, OSPF, RIP and others. This script contols the main
-#              daemon "frr" as well as the individual protocol daemons.
-### END INIT INFO
-
-PATH=/bin:/usr/bin:/sbin:/usr/sbin
-D_PATH=/usr/lib/frr
-C_PATH=/etc/frr
-V_PATH=/var/run/frr
-
-# Local Daemon selection may be done by using /etc/frr/daemons.
-# See /usr/share/doc/frr/README.Debian.gz for further information.
-# Keep zebra first and do not list watchfrr!
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd pimd pbrd ldpd nhrpd eigrpd babeld staticd sharpd bfdd fabricd"
-MAX_INSTANCES=5
-RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py
-
-. /etc/init.d/functions
-
-# Print the name of the pidfile.
-pidfile()
-{
-    echo "$V_PATH/$1.pid"
-}
-
-# Print the name of the vtysh.
-vtyfile()
-{
-    echo "$V_PATH/$1.vty"
-}
-
-# Check if daemon is started by using the pidfile.
-started()
-{
-    [ ! -e `pidfile $1` ] && return 3
-    if [ -n "$2" ] && [ "$2" == "log" ]; then
-        status -p `pidfile $1` $1 && return 0 || return $?
-    else
-        kill -0 `cat \`pidfile $1\`` 2> /dev/null || return 1
-        return 0
-    fi
-}
-
-# Loads the config via vtysh -b if configured to do so.
-vtysh_b ()
-{
-        # Rember, that all variables have been incremented by 1 in convert_daemon_prios()
-        if [ "$vtysh_enable" = 2 -a -f $C_PATH/frr.conf ]; then
-                /usr/bin/vtysh -b -n
-        fi
-}
-
-# Check if the daemon is activated and if its executable and config files
-# are in place.
-# params:       daemon name
-# returns:      0=ok, 1=error
-check_daemon()
-{
-    # If the integrated config file is used the others are not checked.
-    if [ -r "$C_PATH/frr.conf" ]; then
-        return 0
-    fi
-
-    # vtysh_enable has no config file nor binary so skip check.
-    # (Not sure why vtysh_enable is in this list but does not hurt)
-    if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then
-        # check for daemon binary
-        if [ ! -x "$D_PATH/$1" ]; then return 1; fi
-
-        # check for config file
-        if [ -n "$2" ]; then
-            if [ ! -r "$C_PATH/$1-$2.conf" ]; then
-                touch "$C_PATH/$1-$2.conf"
-                chown frr:frr "$C_PATH/$1-$2.conf"
-            fi
-        elif [ ! -r "$C_PATH/$1.conf" ]; then
-            touch "$C_PATH/$1.conf"
-            chown frr:frr "$C_PATH/$1.conf"
-        fi
-    fi
-    return 0
-}
-
-# Starts the server if it's not already running according to the pid file.
-# The Frr daemons creates the pidfile when starting.
-start()
-{
-    local dmn inst
-    dmn="$1"
-    inst="$2"
-
-    ulimit -n $MAX_FDS > /dev/null 2> /dev/null
-    if [ "$dmn" = "watchfrr" ]; then
-
-        # We may need to restart watchfrr if new daemons are added and/or
-        # removed
-        if started "$dmn" ; then
-            stop watchfrr
-        else
-            # Echo only once. watchfrr is printed in the stop above
-            echo -n " $dmn"
-        fi
-
-        if [ -e /var/run/frr/watchfrr.started ] ; then
-            rm /var/run/frr/watchfrr.started
-        fi
-        # redhat /etc/init.d/functions daemon() re-expands args :(
-        # eval "set - $watchfrr_options"
-        daemon --pidfile=`pidfile $dmn` "$D_PATH/$dmn" -d "$watchfrr_options"
-        RETVAL=$?
-        [ $RETVAL -ne 0 ] && break
-        for i in `seq 1 10`;
-        do
-            if [ -e /var/run/frr/watchfrr.started ] ; then
-                RETVAL=0
-                break
-            else
-                sleep 1
-            fi
-        done
-        RETVAL=1
-    elif [ -n "$inst" ]; then
-        echo -n " $dmn-$inst"
-        if ! check_daemon $dmn $inst ; then
-            echo -n " (binary does not exist)"
-            return;
-        fi
-        daemon --pidfile=`pidfile $dmn-$inst` "$D_PATH/$dmn" -d `eval echo "$""$dmn""_options"` -n "$inst"
-        RETVAL=$?
-    else
-        echo -n " $dmn "
-        if ! check_daemon $dmn; then
-            echo " (binary does not exist)"
-            return;
-        fi
-        daemon --pidfile=`pidfile $dmn` "$D_PATH/$dmn" -d `eval echo "$""$dmn""_options"`
-        RETVAL=$?
-    fi
-    echo
-    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$dmn
-    return $RETVAL
-}
-
-# Stop the daemon given in the parameter, printing its name to the terminal.
-stop()
-{
-    local inst
-
-    if [ -n "$2" ]; then
-       inst="$1-$2"
-    else
-       inst="$1"
-    fi
-
-    if ! started "$inst" ; then
-        # echo -n " ($inst)"
-        return 0
-    else
-        echo -n " $inst"
-        PIDFILE=`pidfile $inst`
-        PID=`cat $PIDFILE 2>/dev/null`
-        killproc -p "$PIDFILE" "$D_PATH/$1"
-        RETVAL=$?
-        [ $RETVAL -eq 0 ] && rm -f $lockfile
-        rm -f `pidfile $inst`
-        rm -f `vtyfile $inst`
-        echo
-        return $RETVAL
-    fi
-}
-
-# Converts values from /etc/frr/daemons to all-numeric values.
-convert_daemon_prios()
-{
-    for name in $DAEMONS zebra vtysh_enable watchfrr_enable; do
-        # First, assign the value set by the user to $value
-        eval value=\${${name}:0:3}
-
-        # Daemon not activated or entry missing?
-        if [ "$value" = "no" -o "$value" = "" ]; then value=0; fi
-
-        # These strings parsed for backwards compatibility.
-        if [ "$value" = "yes"  -o  "$value" = "true" ]; then
-            value=1;
-        fi
-
-        # Zebra is threatened special. It must be between 0=off and the first
-        # user assigned value "1" so we increase all other enabled daemons' values.
-        if [ "$name" != "zebra" -a "$value" -gt 0 ]; then value=`expr "$value" + 1`; fi
-
-        # If e.g. name is zebra then we set "zebra=yes".
-        eval $name=$value
-    done
-}
-
-# Starts watchfrr for all wanted daemons.
-start_watchfrr()
-{
-    local daemon_name
-    local daemon_prio
-    local found_one
-    local daemon_inst
-
-    # Start the monitor daemon only if desired.
-    if [ 0 -eq "$watchfrr_enable" ]; then
-        return
-    fi
-
-    # Check variable type
-    if declare -p watchfrr_options | grep -q '^declare \-a'; then
-        # old array support
-        watchfrr_options="${watchfrr_options[@]}"
-    fi
-
-    # Which daemons have been started?
-    found_one=0
-    for daemon_name in $DAEMONS; do
-        eval daemon_prio=\$$daemon_name
-        if [ "$daemon_prio" -gt 0 ]; then
-            eval "daemon_inst=\${${daemon_name}_instances//,/ }"
-            if [ -n "$daemon_inst" ]; then
-                for inst in ${daemon_inst}; do
-                    eval "inst_disable=\${${daemon_name}_${inst}}"
-                    if [ -z ${inst_disable} ] || [ ${inst_disable} != 0 ]; then
-                        if check_daemon $daemon_name $inst; then
-                            watchfrr_options="$watchfrr_options ${daemon_name}-${inst}"
-                        fi
-                    fi
-                done
-            else
-                if check_daemon $daemon_name; then
-                    watchfrr_options="$watchfrr_options $daemon_name"
-                fi
-            fi
-            found_one=1
-        fi
-    done
-
-    # Start if at least one daemon is activated.
-    if [ $found_one -eq 1 ]; then
-        echo "Starting FRRouting monitor daemon:"
-        start watchfrr
-    fi
-}
-
-# Stopps watchfrr.
-stop_watchfrr()
-{
-    echo "Stopping FRRouting monitor daemon:"
-    stop watchfrr
-}
-
-# Stops all daemons that have a lower level of priority than the given.
-# (technically if daemon_prio >= wanted_prio)
-stop_prio()
-{
-    local wanted_prio
-    local daemon_prio
-    local daemon_list
-    local daemon_inst
-    local inst
-
-    if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then
-        daemon=${BASH_REMATCH[1]}
-        inst=${BASH_REMATCH[2]}
-    else
-        daemon="$2"
-    fi
-
-    wanted_prio=$1
-    daemon_list=${daemon:-$DAEMONS}
-
-    echo "Stopping FRRouting daemons (prio:$wanted_prio):"
-
-    for prio_i in `seq 10 -1 $wanted_prio`; do
-        for daemon_name in $daemon_list; do
-            eval daemon_prio=\${${daemon_name}:0:3}
-            daemon_inst=""
-            if [ $daemon_prio -eq $prio_i ]; then
-                eval "daemon_inst=\${${daemon_name}_instances//,/ }"
-                if [ -n "$daemon_inst" ]; then
-                    for i in ${daemon_inst}; do
-                        if [ -n "$inst" ] && [ "$i" == "$inst" ]; then
-                            stop "$daemon_name" "$inst"
-                        elif [ x"$inst"  == x ]; then
-                            stop "$daemon_name" "$i"
-                        fi
-                    done
-                else
-                    stop "$daemon_name"
-                fi
-            fi
-        done
-    done
-
-    if [ -z "$inst" ]; then
-    # Now stop other daemons that're prowling, coz the daemons file changed
-        echo "Stopping other FRRouting daemons"
-        if [ -n "$daemon" ]; then
-            eval "file_list_suffix="$V_PATH"/"$daemon*""
-        else
-            eval "file_list_suffix="$V_PATH/*""
-        fi
-        for pidfile in $file_list_suffix.pid; do
-            if [ -f "$pidfile" ]; then
-                filename=${pidfile##*/}
-                daemon=${filename%.*}
-                echo -n " $daemon"
-                killproc -p "$pidfile" "$daemon"
-                RETVAL=$?
-                [ $RETVAL -eq 0 ] && rm -f $lockfile
-                rm -f "$pidfile"
-                echo
-            fi
-        done
-        echo -n "Removing remaining .vty files"
-        for vtyfile in $file_list_suffix.vty; do
-            rm -rf "$vtyfile"
-        done
-        echo
-    fi
-}
-
-# Starts all daemons that have a higher level of priority than the given.
-# (technically if daemon_prio <= wanted_prio)
-start_prio()
-{
-    local wanted_prio
-    local daemon_prio
-    local daemon_list
-    local daemon_name
-    local daemon_inst
-    local inst
-
-    if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then
-        daemon=${BASH_REMATCH[1]}
-        inst=${BASH_REMATCH[2]}
-    else
-        daemon="$2"
-    fi
-
-    wanted_prio=$1
-    daemon_list=${daemon:-$DAEMONS}
-
-    echo "Starting FRRouting daemons (prio:$wanted_prio):"
-
-    for prio_i in `seq 1 $wanted_prio`; do
-        for daemon_name in $daemon_list; do
-            eval daemon_prio=\$${daemon_name}
-            daemon_inst=""
-            if [ $daemon_prio -eq $prio_i ]; then
-                eval "daemon_inst=\${${daemon_name}_instances//,/ }"
-                if [ -n "$daemon_inst" ]; then
-                    if [ `echo "$daemon_inst" | wc -w` -gt ${MAX_INSTANCES} ]; then
-                        echo "Max instances supported is ${MAX_INSTANCES}. Aborting"
-                        exit 1
-                    fi
-                    # Check if we're starting again by switching from single instance
-                    # to MI version
-                    if started "$daemon_name"; then
-                        PIDFILE=`pidfile $daemon_name`
-                        killproc -p "$PIDFILE" "$daemon_name"
-                        rm -f `pidfile $1`
-                        rm -f `vtyfile $1`
-                    fi
-
-                    for i in ${daemon_inst}; do
-                        if [ -n "$inst" ] && [ "$i" == "$inst" ]; then
-                            start "$daemon_name" "$inst"
-                        elif [ x"$inst" == x ]; then
-                            start "$daemon_name" "$i"
-                        fi
-                    done
-                else
-                    # Check if we're starting again by switching from
-                    # single instance to MI version
-                    eval "file_list_suffix="$V_PATH"/"$daemon_name-*""
-                    for pidfile in $file_list_suffix.pid; do
-                        if [ -f "$pidfile" ]; then
-                            killproc -p "$pidfile" "$daemon_name"
-                            rm -rf "$pidfile"
-                        fi
-                    done
-                    for vtyfile in $file_list_suffix.vty; do
-                        rm -rf "$vtyfile"
-                    done
-
-                    start "$daemon_name"
-                fi
-            fi
-        done
-    done
-}
-
-check_status()
-{
-    local daemon_name
-    local daemon_prio
-    local daemon_inst
-    local failed_status=0
-
-    if [ -n "$1" ] && [[ "$1" =~ (.*)-(.*) ]]; then
-        daemon=${BASH_REMATCH[1]}
-        inst=${BASH_REMATCH[2]}
-    else
-        daemon="$1"
-    fi
-
-    daemon_list=${daemon:-$DAEMONS}
-
-    # Which daemons have been started?
-    for daemon_name in $daemon_list; do
-        eval daemon_prio=\$$daemon_name
-        if [ "$daemon_prio" -gt 0 ]; then
-            eval "daemon_inst=\${${daemon_name}_instances//,/ }"
-            if [ -n "$daemon_inst" ]; then
-                for i in ${daemon_inst}; do
-                    if [ -n "$inst" -a "$inst" = "$i" ]; then
-                        started "$1" "log" || failed_status=$?
-                    elif [ -z "$inst" ]; then
-                        started "$daemon_name-$i" "log" || failed_status=$?
-                    fi
-                done
-            else
-                started "$daemon_name" "log" || failed_status=$?
-            fi
-        fi
-    done
-
-    # All daemons that need to have been started are up and running
-    return $failed_status
-}
-
-#########################################################
-#               Main program                            #
-#########################################################
-
-# Config broken but script must exit silently.
-[ ! -r "$C_PATH/daemons" ] && exit 0
-
-# Load configuration
-. "$C_PATH/daemons"
-
-# Read configuration variable file if it is present
-[ -r /etc/sysconfig/frr ] && . /etc/sysconfig/frr
-
-MAX_INSTANCES=${MAX_INSTANCES:=5}
-
-# Set priority of un-startable daemons to 'no' and substitute 'yes' to '0'
-convert_daemon_prios
-
-if [ ! -d $V_PATH ]; then
-    echo "Creating $V_PATH"
-    mkdir -p $V_PATH
-    chown frr:frr $V_PATH
-    chmod 755 /$V_PATH
-fi
-
-if [ -n "$3" ] && [ "$3" != "all" ]; then
-    dmn="$2"-"$3"
-elif [ -n "$2" ] && [ "$2" != "all" ]; then
-    dmn="$2"
-fi
-
-case "$1" in
-    start)
-        # Try to load this necessary (at least for 2.6) module.
-        if [ -d /lib/modules/`uname -r` ] ; then
-            echo "Loading capability module if not yet done."
-            LC_ALL=C modprobe -a capability 2>&1 | egrep -v "(not found|Can't locate)"
-        fi
-
-        # Start all daemons
-        cd $C_PATH/
-        if [ "$2" != "watchfrr" ]; then
-          start_prio 10 $dmn
-        fi
-        start_watchfrr
-        vtysh_b
-        ;;
-
-    1|2|3|4|5|6|7|8|9|10)
-        # Stop/start daemons for the appropriate priority level
-        stop_prio $1
-        start_prio $1
-        vtysh_b
-        ;;
-
-    stop|0)
-        # Stop all daemons at level '0' or 'stop'
-        stop_watchfrr
-        if [ "$dmn" != "watchfrr" ]; then
-            [ -n "${dmn}" ] && eval "${dmn/-/_}=0"
-            stop_prio 0 $dmn
-        fi
-
-        if [ -z "$dmn" -o "$dmn" = "zebra" ]; then
-            echo "Removing all routes made by zebra."
-            ip route flush proto zebra
-            # At least in CentOS/RHEL 6, iproute2 doesn't know
-            # about the new protocol names, so we have to flush them
-            # by number (it also doesn't support rt_protos.d
-            ip route flush proto 186
-            ip route flush proto 187
-            ip route flush proto 188
-            ip route flush proto 189
-            ip route flush proto 190
-            ip route flush proto 191
-            ip route flush proto 192
-            ip route flush proto 193
-            ip route flush proto 194
-        else
-            [ -n "$dmn" ] && eval "${dmn/-/_}=0"
-            start_watchfrr
-        fi
-        ;;
-
-    reload)
-        # Just apply the commands that have changed, no restart necessary
-        if [ ! -x "$RELOAD_SCRIPT" ]; then
-            echo "frr-reload - reload not supported. Use restart or install frr-pythontools package"
-            exit 1
-        fi
-        NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}"
-        if [ ! -r $NEW_CONFIG_FILE ]; then
-            echo "Unable to read configuration file $NEW_CONFIG_FILE. Only supporting integrated config"
-            exit 1
-        fi
-        echo "Applying only incremental changes to running configuration from frr.conf"
-        "$RELOAD_SCRIPT" --reload /etc/frr/frr.conf
-        exit $?
-        ;;
-
-    status)
-        check_status $dmn
-        exit $?
-        ;;
-
-    restart|force-reload)
-        $0 stop $dmn
-        sleep 1
-        $0 start $dmn
-        ;;
-
-    *)
-        echo "Usage: /etc/init.d/frr {start|stop|status|reload|restart|force-reload|<priority>} [daemon]"
-        echo "       E.g. '/etc/init.d/frr 5' would start all daemons with a prio 1-5."
-        echo "       reload applies only modifications from the running config to all daemons."
-        echo "       reload neither restarts starts any daemon nor starts any new ones."
-        echo "       Read /usr/share/doc/frr/README.Debian for details."
-        exit 1
-        ;;
-esac
-
-exit 0
diff --git a/redhat/frr.service b/redhat/frr.service
deleted file mode 100644 (file)
index 01934a9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-[Unit]
-Description=FRRouting (FRR)
-Wants=network.target
-After=network-pre.target systemd-sysctl.service
-Before=network.target
-OnFailure=heartbeat-failed@%n.service
-
-[Service]
-Nice=-5
-Type=forking
-NotifyAccess=all
-StartLimitInterval=3m
-StartLimitBurst=3
-TimeoutSec=2m
-WatchdogSec=60s
-RestartSec=5
-Restart=on-abnormal
-LimitNOFILE=1024
-ExecStart=/usr/lib/frr/frr start
-ExecStop=/usr/lib/frr/frr stop
-ExecReload=/usr/lib/frr/frr reload
-
-[Install]
-WantedBy=multi-user.target
index 78b1f7c87c2bfc3979969fb54f184a714d818474..36f92598651c6ff50add9c19190365c91850df9b 100644 (file)
@@ -376,15 +376,13 @@ rm -vf %{buildroot}%{_libdir}/frr/libyang_plugins/*.la
 # install /etc sources
 %if "%{initsystem}" == "systemd"
 mkdir -p %{buildroot}%{_unitdir}
-install -m644 %{zeb_rh_src}/frr.service %{buildroot}%{_unitdir}/frr.service
-install %{zeb_rh_src}/frr.init %{buildroot}%{_sbindir}/frr
+install -m644 %{zeb_src}/tools/frr.service %{buildroot}%{_unitdir}/frr.service
 %else
 mkdir -p %{buildroot}%{_initddir}
-install %{zeb_rh_src}/frr.init %{buildroot}%{_sbindir}/frr
-ln -s %{_sbindir}/frr %{buildroot}%{_initddir}/frr
+ln -s %{_sbindir}/frrinit.sh %{buildroot}%{_initddir}/frr
 %endif
 
-install %{zeb_rh_src}/daemons %{buildroot}%{_sysconfdir}/frr
+install %{zeb_src}/tools/etc/frr/daemons %{buildroot}%{_sysconfdir}/frr
 # add rpki module to daemon
 %if %{with_rpki}
     sed -i -e 's/^\(bgpd_options=\)\(.*\)\(".*\)/\1\2 -M rpki\3/' %{buildroot}%{_sysconfdir}/frr/daemons
@@ -474,7 +472,7 @@ zebra_spec_add_service fabricd      2618/tcp "Fabricd vty"
 
 # Fix bad path in previous config files
 #  Config files won't get replaced by default, so we do this ugly hack to fix it
-%__sed -i 's|/etc/init.d/|%{_sbindir}/|g' %{configdir}/daemons 2> /dev/null || true
+%__sed -i 's|watchfrr_options=|#watchfrr_options=|g' %{configdir}/daemons 2> /dev/null || true
 
 # With systemd, watchfrr is mandatory. Fix config to make sure it's enabled if
 # we install or upgrade to a frr built with systemd
@@ -632,7 +630,6 @@ fi
 %else
     %{_initddir}/frr
 %endif
-%{_sbindir}/frr
 %config(noreplace) %{_sysconfdir}/pam.d/frr
 %config(noreplace) %{_sysconfdir}/logrotate.d/frr
 %{_sbindir}/frr-reload
index 6fbcdc059be0f87e900f9b344585d6834c4027f4..62aaad5d97030eb23d8e6c22077515f57aa19ba8 100644 (file)
@@ -378,10 +378,19 @@ DEFPY (rip_passive_interface,
        "Suppress routing updates on an interface\n"
        "Interface name\n")
 {
-       nb_cli_enqueue_change(vty, "./passive-interface",
-                             no ? NB_OP_DESTROY : NB_OP_CREATE, ifname);
-       nb_cli_enqueue_change(vty, "./non-passive-interface",
-                             no ? NB_OP_CREATE : NB_OP_DESTROY, ifname);
+       bool passive_default =
+               yang_dnode_get_bool(vty->candidate_config->dnode, "%s%s",
+                                   VTY_CURR_XPATH, "/passive-default");
+
+       if (passive_default) {
+               nb_cli_enqueue_change(vty, "./non-passive-interface",
+                                     no ? NB_OP_CREATE : NB_OP_DESTROY,
+                                     ifname);
+       } else {
+               nb_cli_enqueue_change(vty, "./passive-interface",
+                                     no ? NB_OP_DESTROY : NB_OP_CREATE,
+                                     ifname);
+       }
 
        return nb_cli_apply_changes(vty, NULL);
 }
index e5dc6e6af69ccefb906185ca3804b0d623c13a90..ea32b622a6ac530720b4b31ebb18bc0175f44931 100644 (file)
@@ -90,7 +90,7 @@ static int ripng_multicast_join(struct interface *ifp)
                         * group on
                         * an interface that has just gone down.
                         */
-                       zlog_warn("ripng join on %s EADDRINUSE (ignoring)\n",
+                       zlog_warn("ripng join on %s EADDRINUSE (ignoring)",
                                  ifp->name);
                        return 0; /* not an error */
                }
@@ -124,7 +124,7 @@ static int ripng_multicast_leave(struct interface *ifp)
                ret = setsockopt(ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
                                 (char *)&mreq, sizeof(mreq));
                if (ret < 0)
-                       zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s\n",
+                       zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s",
                                  safe_strerror(errno));
 
                if (IS_RIPNG_DEBUG_EVENT)
index 28a57f25d007bbbcf6814d82e733df6d92b50f98..c68c066f0cbee94da2864475911740ab460a1d3b 100644 (file)
@@ -126,6 +126,9 @@ static int ripng_zebra_read_route(int command, struct zclient *zclient,
        if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
                return 0;
 
+       if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
+               return 0;
+
        nexthop = api.nexthops[0].gate.ipv6;
        ifindex = api.nexthops[0].ifindex;
 
index 065fb092d4e8f6dcc2e2c9d5fd7f2d45377ab521..4e5c933667acd367b501f029fe1aae0457b4c100 100644 (file)
@@ -38,6 +38,7 @@ struct sharp_routes {
        int32_t repeat;
 
        uint8_t inst;
+       vrf_id_t vrf_id;
 
        struct timeval t_start;
        struct timeval t_end;
index 9018cfb359986db22f9dadcbb05afcff15f1c249..fbcbbe3fdca7119f940b168a69e12b4c4cc4111f 100644 (file)
 #endif
 
 DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
-      "sharp watch <nexthop$n|import$import> X:X::X:X$nhop [connected$connected]",
+      "sharp watch [vrf NAME$name] <nexthop$n|import$import> X:X::X:X$nhop [connected$connected]",
       "Sharp routing Protocol\n"
       "Watch for changes\n"
+      "The vrf we would like to watch if non-default\n"
+      "The NAME of the vrf\n"
       "Watch for nexthop changes\n"
       "Watch for import check changes\n"
       "The v6 nexthop to signal for watching\n"
       "Should the route be connected\n")
 {
+       struct vrf *vrf;
        struct prefix p;
        bool type_import;
 
+       if (!name)
+               name = VRF_DEFAULT_NAME;
+       vrf = vrf_lookup_by_name(name);
+       if (!vrf) {
+               vty_out(vty, "The vrf NAME specified: %s does not exist\n",
+                       name);
+               return CMD_WARNING;
+       }
 
        if (n)
                type_import = false;
@@ -63,23 +74,36 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
        p.family = AF_INET6;
 
        sharp_nh_tracker_get(&p);
-       sharp_zebra_nexthop_watch(&p, type_import, true, !!connected);
+       sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import,
+                                 true, !!connected);
 
        return CMD_SUCCESS;
 }
 
 DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
-      "sharp watch <nexthop$n|import$import> A.B.C.D$nhop [connected$connected]",
+      "sharp watch [vrf NAME$name] <nexthop$n|import$import> A.B.C.D$nhop [connected$connected]",
       "Sharp routing Protocol\n"
       "Watch for changes\n"
+      "The vrf we would like to watch if non-default\n"
+      "The NAME of the vrf\n"
       "Watch for nexthop changes\n"
       "Watch for import check changes\n"
       "The v4 nexthop to signal for watching\n"
       "Should the route be connected\n")
 {
+       struct vrf *vrf;
        struct prefix p;
        bool type_import;
 
+       if (!name)
+               name = VRF_DEFAULT_NAME;
+       vrf = vrf_lookup_by_name(name);
+       if (!vrf) {
+               vty_out(vty, "The vrf NAME specified: %s does not exist\n",
+                       name);
+               return CMD_WARNING;
+       }
+
        memset(&p, 0, sizeof(p));
 
        if (n)
@@ -92,7 +116,8 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
        p.family = AF_INET;
 
        sharp_nh_tracker_get(&p);
-       sharp_zebra_nexthop_watch(&p, type_import, true, !!connected);
+       sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import,
+                                 true, !!connected);
 
        return CMD_SUCCESS;
 }
@@ -132,10 +157,12 @@ DEFPY (install_routes_data_dump,
 
 DEFPY (install_routes,
        install_routes_cmd,
-       "sharp install routes <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]",
+       "sharp install routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]",
        "Sharp routing Protocol\n"
        "install some routes\n"
        "Routes to install\n"
+       "The vrf we would like to install into if non-default\n"
+       "The NAME of the vrf\n"
        "v4 Address to start /32 generation at\n"
        "v6 Address to start /32 generation at\n"
        "Nexthop to use(Can be an IPv4 or IPv6 address)\n"
@@ -149,6 +176,7 @@ DEFPY (install_routes,
        "Should we repeat this command\n"
        "How many times to repeat this command\n")
 {
+       struct vrf *vrf;
        struct prefix prefix;
        uint32_t rts;
 
@@ -176,6 +204,16 @@ DEFPY (install_routes,
        }
        sg.r.orig_prefix = prefix;
 
+       if (!name)
+               name = VRF_DEFAULT_NAME;
+
+       vrf = vrf_lookup_by_name(name);
+       if (!vrf) {
+               vty_out(vty, "The vrf NAME specified: %s does not exist\n",
+                       name);
+               return CMD_WARNING;
+       }
+
        if (nexthop_group) {
                struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group);
                if (!nhgc) {
@@ -195,12 +233,15 @@ DEFPY (install_routes,
                        sg.r.nhop.type = NEXTHOP_TYPE_IPV6;
                }
 
+               sg.r.nhop.vrf_id = vrf->vrf_id;
                sg.r.nhop_group.nexthop = &sg.r.nhop;
        }
 
        sg.r.inst = instance;
+       sg.r.vrf_id = vrf->vrf_id;
        rts = routes;
-       sharp_install_routes_helper(&prefix, sg.r.inst, &sg.r.nhop_group, rts);
+       sharp_install_routes_helper(&prefix, sg.r.vrf_id,
+                                   sg.r.inst, &sg.r.nhop_group, rts);
 
        return CMD_SUCCESS;
 }
@@ -237,16 +278,19 @@ DEFPY(vrf_label, vrf_label_cmd,
 
 DEFPY (remove_routes,
        remove_routes_cmd,
-       "sharp remove routes <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
+       "sharp remove routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> (1-1000000)$routes [instance (0-255)$instance]",
        "Sharp Routing Protocol\n"
        "Remove some routes\n"
        "Routes to remove\n"
+       "The vrf we would like to remove from if non-default\n"
+       "The NAME of the vrf\n"
        "v4 Starting spot\n"
        "v6 Starting spot\n"
        "Routes to uninstall\n"
        "instance to use\n"
        "Value of instance\n")
 {
+       struct vrf *vrf;
        struct prefix prefix;
 
        sg.r.total_routes = routes;
@@ -265,9 +309,18 @@ DEFPY (remove_routes,
                prefix.u.prefix6 = start6;
        }
 
+       vrf = vrf_lookup_by_name(name ? name : VRF_DEFAULT_NAME);
+       if (!vrf) {
+               vty_out(vty, "The vrf NAME specified: %s does not exist\n",
+                       name ? name : VRF_DEFAULT_NAME);
+               return CMD_WARNING;
+       }
+
        sg.r.inst = instance;
+       sg.r.vrf_id = vrf->vrf_id;
        rts = routes;
-       sharp_remove_routes_helper(&prefix, sg.r.inst, rts);
+       sharp_remove_routes_helper(&prefix, sg.r.vrf_id,
+                                  sg.r.inst, rts);
 
        return CMD_SUCCESS;
 }
index 4682dbc73a4fd3e4e73602d880b9ef7765eb92b2..f1e83628c2ee5876eccb17fc1804f6ab281108d7 100644 (file)
@@ -131,8 +131,8 @@ static int interface_state_down(int command, struct zclient *zclient,
        return 0;
 }
 
-void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
-                                struct nexthop_group *nhg,
+void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
+                                uint8_t instance, struct nexthop_group *nhg,
                                 uint32_t routes)
 {
        uint32_t temp, i;
@@ -148,7 +148,7 @@ void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
 
        monotime(&sg.r.t_start);
        for (i = 0; i < routes; i++) {
-               route_add(p, (uint8_t)instance, nhg);
+               route_add(p, vrf_id, (uint8_t)instance, nhg);
                if (v4)
                        p->u.prefix4.s_addr = htonl(++temp);
                else
@@ -156,8 +156,8 @@ void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
        }
 }
 
-void sharp_remove_routes_helper(struct prefix *p, uint8_t instance,
-                               uint32_t routes)
+void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id,
+                               uint8_t instance, uint32_t routes)
 {
        uint32_t temp, i;
        bool v4 = false;
@@ -172,7 +172,7 @@ void sharp_remove_routes_helper(struct prefix *p, uint8_t instance,
 
        monotime(&sg.r.t_start);
        for (i = 0; i < routes; i++) {
-               route_delete(p, (uint8_t)instance);
+               route_delete(p, vrf_id, (uint8_t)instance);
                if (v4)
                        p->u.prefix4.s_addr = htonl(++temp);
                else
@@ -190,12 +190,14 @@ static void handle_repeated(bool installed)
 
        if (installed) {
                sg.r.removed_routes = 0;
-               sharp_remove_routes_helper(&p, sg.r.inst, sg.r.total_routes);
+               sharp_remove_routes_helper(&p, sg.r.vrf_id,
+                                          sg.r.inst, sg.r.total_routes);
        }
 
        if (installed) {
                sg.r.installed_routes = 0;
-               sharp_install_routes_helper(&p, sg.r.inst, &sg.r.nhop_group,
+               sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst,
+                                           &sg.r.nhop_group,
                                            sg.r.total_routes);
        }
 }
@@ -255,7 +257,8 @@ void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label)
        zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP);
 }
 
-void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg)
+void route_add(struct prefix *p, vrf_id_t vrf_id,
+              uint8_t instance, struct nexthop_group *nhg)
 {
        struct zapi_route api;
        struct zapi_nexthop *api_nh;
@@ -263,7 +266,7 @@ void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg)
        int i = 0;
 
        memset(&api, 0, sizeof(api));
-       api.vrf_id = VRF_DEFAULT;
+       api.vrf_id = vrf_id;
        api.type = ZEBRA_ROUTE_SHARP;
        api.instance = instance;
        api.safi = SAFI_UNICAST;
@@ -274,7 +277,7 @@ void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg)
 
        for (ALL_NEXTHOPS_PTR(nhg, nh)) {
                api_nh = &api.nexthops[i];
-               api_nh->vrf_id = VRF_DEFAULT;
+               api_nh->vrf_id = nh->vrf_id;
                api_nh->type = nh->type;
                switch (nh->type) {
                case NEXTHOP_TYPE_IPV4:
@@ -305,12 +308,12 @@ void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg)
        zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
 }
 
-void route_delete(struct prefix *p, uint8_t instance)
+void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance)
 {
        struct zapi_route api;
 
        memset(&api, 0, sizeof(api));
-       api.vrf_id = VRF_DEFAULT;
+       api.vrf_id = vrf_id;
        api.type = ZEBRA_ROUTE_SHARP;
        api.safi = SAFI_UNICAST;
        api.instance = instance;
@@ -320,7 +323,7 @@ void route_delete(struct prefix *p, uint8_t instance)
        return;
 }
 
-void sharp_zebra_nexthop_watch(struct prefix *p, bool import,
+void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import,
                               bool watch, bool connected)
 {
        int command;
@@ -337,7 +340,7 @@ void sharp_zebra_nexthop_watch(struct prefix *p, bool import,
                        command = ZEBRA_IMPORT_ROUTE_UNREGISTER;
        }
 
-       if (zclient_send_rnh(zclient, command, p, connected, VRF_DEFAULT) < 0)
+       if (zclient_send_rnh(zclient, command, p, connected, vrf_id) < 0)
                zlog_warn("%s: Failure to send nexthop to zebra",
                          __PRETTY_FUNCTION__);
 }
index b219022f028cd481d6afb296806589705da5d685..57ffcc7690dabb7ecd0121d16c61b234911b4f83 100644 (file)
 extern void sharp_zebra_init(void);
 
 extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label);
-extern void route_add(struct prefix *p, uint8_t instance,
+extern void route_add(struct prefix *p, vrf_id_t, uint8_t instance,
                      struct nexthop_group *nhg);
-extern void route_delete(struct prefix *p, uint8_t instance);
-extern void sharp_zebra_nexthop_watch(struct prefix *p, bool import,
-                                     bool watch, bool connected);
+extern void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance);
+extern void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id,
+                                     bool import, bool watch, bool connected);
 
-extern void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
-                                        struct nexthop_group *nhg,
-                                        uint32_t routes);
-extern void sharp_remove_routes_helper(struct prefix *p, uint8_t instance,
-                                      uint32_t routes);
+extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
+                                       uint8_t instance,
+                                       struct nexthop_group *nhg,
+                                       uint32_t routes);
+extern void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id,
+                                      uint8_t instance, uint32_t routes);
 #endif
index 6777cd9fc3031ea4bfda92082df65db83beda5b6..85388c738d549f908f3849a9386267fdd7ef196d 100644 (file)
@@ -1,7 +1,7 @@
 BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0
 BGP table version 1
 RIB entries 1, using XXXX bytes of memory
-Peers 4, using XXXX KiB of memory
+Peers 2, using XXXX KiB of memory
 
 Neighbor         V         AS MsgRcvd MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd
 fc00:0:0:8::1000 4        100       0       0        0    0    0    never       Active
diff --git a/tests/topotests/bfd-topo2/__init__.py b/tests/topotests/bfd-topo2/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bfd-topo2/r1/bfdd.conf b/tests/topotests/bfd-topo2/r1/bfdd.conf
new file mode 100644 (file)
index 0000000..5c2571b
--- /dev/null
@@ -0,0 +1,5 @@
+bfd
+ peer 2001:db8:4::1 multihop local-address 2001:db8:1::1
+  no shutdown
+ !
+!
diff --git a/tests/topotests/bfd-topo2/r1/bgpd.conf b/tests/topotests/bfd-topo2/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..1623b45
--- /dev/null
@@ -0,0 +1,13 @@
+router bgp 101
+ bgp router-id 10.254.254.1
+ neighbor r2g peer-group
+ neighbor r2g remote-as external
+ neighbor r2g bfd
+ neighbor r1-eth0 interface peer-group r2g
+ address-family ipv4 unicast
+  redistribute connected
+ exit-address-family
+ address-family ipv6 unicast
+  neighbor r2g activate
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-topo2/r1/ipv4_routes.json b/tests/topotests/bfd-topo2/r1/ipv4_routes.json
new file mode 100644 (file)
index 0000000..8a2ec25
--- /dev/null
@@ -0,0 +1,68 @@
+{
+    "10.0.3.0/24": [
+        {
+            "distance": 20,
+            "protocol": "bgp",
+            "internalFlags": 8,
+            "metric": 0,
+            "selected": true,
+            "installed": true,
+            "prefix": "10.0.3.0/24",
+            "internalStatus": 34,
+            "nexthops": [
+                {
+                    "interfaceName": "r1-eth0",
+                    "interfaceIndex": 2,
+                    "fib": true,
+                    "flags": 3,
+                    "active": true,
+                    "afi": "ipv6"
+                }
+            ]
+        }
+    ],
+    "10.254.254.2/32": [
+        {
+            "distance": 20,
+            "protocol": "bgp",
+            "internalFlags": 8,
+            "metric": 0,
+            "selected": true,
+            "installed": true,
+            "prefix": "10.254.254.2/32",
+            "internalStatus": 34,
+            "nexthops": [
+                {
+                    "interfaceName": "r1-eth0",
+                    "interfaceIndex": 2,
+                    "fib": true,
+                    "flags": 3,
+                    "active": true,
+                    "afi": "ipv6"
+                }
+            ]
+        }
+    ],
+    "10.254.254.1/32": [
+        {
+            "distance": 0,
+            "protocol": "connected",
+            "internalFlags": 8,
+            "metric": 0,
+            "selected": true,
+            "installed": true,
+            "prefix": "10.254.254.1/32",
+            "internalStatus": 32,
+            "nexthops": [
+                {
+                    "directlyConnected": true,
+                    "interfaceName": "lo",
+                    "interfaceIndex": 1,
+                    "fib": true,
+                    "flags": 3,
+                    "active": true
+                }
+            ]
+        }
+    ]
+}
diff --git a/tests/topotests/bfd-topo2/r1/ipv6_routes.json b/tests/topotests/bfd-topo2/r1/ipv6_routes.json
new file mode 100644 (file)
index 0000000..618853b
--- /dev/null
@@ -0,0 +1,63 @@
+{
+  "2001:db8:4::/64": [
+    {
+      "distance": 20,
+      "protocol": "bgp",
+      "internalFlags": 8,
+      "metric": 0,
+      "selected": true,
+      "installed": true,
+      "prefix": "2001:db8:4::/64",
+      "internalStatus": 34,
+      "nexthops": [
+        {
+          "interfaceName": "r1-eth0",
+          "interfaceIndex": 2,
+          "fib": true,
+          "flags": 3,
+          "active": true,
+          "afi": "ipv6"
+        }
+      ]
+    }
+  ],
+  "2001:db8:1::/64": [
+    {
+      "distance": 20,
+      "protocol": "bgp",
+      "internalFlags": 0,
+      "metric": 0,
+      "internalStatus": 2,
+      "prefix": "2001:db8:1::/64",
+      "nexthops": [
+        {
+          "interfaceName": "r1-eth0",
+          "interfaceIndex": 2,
+          "flags": 1,
+          "active": true,
+          "afi": "ipv6"
+        }
+      ]
+    },
+    {
+      "distance": 0,
+      "protocol": "connected",
+      "internalFlags": 8,
+      "metric": 0,
+      "selected": true,
+      "installed": true,
+      "prefix": "2001:db8:1::/64",
+      "internalStatus": 32,
+      "nexthops": [
+        {
+          "directlyConnected": true,
+          "interfaceName": "r1-eth0",
+          "interfaceIndex": 2,
+          "fib": true,
+          "flags": 3,
+          "active": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-topo2/r1/peers.json b/tests/topotests/bfd-topo2/r1/peers.json
new file mode 100644 (file)
index 0000000..b14351c
--- /dev/null
@@ -0,0 +1,29 @@
+[
+    {
+        "multihop":true,
+        "peer":"2001:db8:4::1",
+        "local":"2001:db8:1::1",
+        "status":"up",
+        "diagnostic":"ok",
+        "remote-diagnostic":"ok",
+        "receive-interval":300,
+        "transmit-interval":300,
+        "echo-interval":0,
+        "remote-receive-interval":300,
+        "remote-transmit-interval":300,
+        "remote-echo-interval":50
+    },
+    {
+        "multihop":false,
+        "interface":"r1-eth0",
+        "status":"up",
+        "diagnostic":"ok",
+        "remote-diagnostic":"ok",
+        "receive-interval":300,
+        "transmit-interval":300,
+        "echo-interval":0,
+        "remote-receive-interval":300,
+        "remote-transmit-interval":300,
+        "remote-echo-interval":50
+    }
+]
diff --git a/tests/topotests/bfd-topo2/r1/zebra.conf b/tests/topotests/bfd-topo2/r1/zebra.conf
new file mode 100644 (file)
index 0000000..7fe5eb2
--- /dev/null
@@ -0,0 +1,6 @@
+interface lo
+ ip address 10.254.254.1/32
+!
+interface r1-eth0
+ ipv6 address 2001:db8:1::1/64
+!
diff --git a/tests/topotests/bfd-topo2/r2/bgpd.conf b/tests/topotests/bfd-topo2/r2/bgpd.conf
new file mode 100644 (file)
index 0000000..bf42d21
--- /dev/null
@@ -0,0 +1,16 @@
+router bgp 102
+ bgp router-id 10.254.254.2
+ neighbor r2g peer-group
+ neighbor r2g remote-as external
+ neighbor r2g bfd
+ neighbor r2-eth0 interface peer-group r2g
+ !
+ address-family ipv4 unicast
+  redistribute connected
+ exit-address-family
+ !
+ address-family ipv6 unicast
+  redistribute connected
+  neighbor r2g activate
+ exit-address-family
+!
diff --git a/tests/topotests/bfd-topo2/r2/ipv4_routes.json b/tests/topotests/bfd-topo2/r2/ipv4_routes.json
new file mode 100644 (file)
index 0000000..b9d8afb
--- /dev/null
@@ -0,0 +1,108 @@
+{
+  "10.0.3.0/24": [
+    {
+      "distance": 110,
+      "protocol": "ospf",
+      "internalFlags": 0,
+      "metric": 10,
+      "internalStatus": 2,
+      "prefix": "10.0.3.0/24",
+      "nexthops": [
+        {
+          "active": true,
+          "directlyConnected": true,
+          "flags": 1,
+          "interfaceIndex": 3,
+          "interfaceName": "r2-eth1"
+        }
+      ]
+    },
+    {
+      "distance": 0,
+      "protocol": "connected",
+      "internalFlags": 8,
+      "metric": 0,
+      "selected": true,
+      "installed": true,
+      "prefix": "10.0.3.0/24",
+      "internalStatus": 32,
+      "nexthops": [
+        {
+          "directlyConnected": true,
+          "interfaceName": "r2-eth1",
+          "interfaceIndex": 3,
+          "fib": true,
+          "flags": 3,
+          "active": true
+        }
+      ]
+    }
+  ],
+  "10.254.254.3/32": [
+    {
+      "distance": 110,
+      "protocol": "ospf",
+      "internalFlags": 8,
+      "metric": 20,
+      "selected": true,
+      "installed": true,
+      "prefix": "10.254.254.3/32",
+      "internalStatus": 34,
+      "nexthops": [
+        {
+          "interfaceName": "r2-eth1",
+          "ip": "10.0.3.1",
+          "interfaceIndex": 3,
+          "fib": true,
+          "flags": 3,
+          "active": true,
+          "afi": "ipv4"
+        }
+      ]
+    }
+  ],
+  "10.254.254.2/32": [
+    {
+      "distance": 0,
+      "protocol": "connected",
+      "internalFlags": 8,
+      "metric": 0,
+      "selected": true,
+      "installed": true,
+      "prefix": "10.254.254.2/32",
+      "internalStatus": 32,
+      "nexthops": [
+        {
+          "directlyConnected": true,
+          "interfaceName": "lo",
+          "interfaceIndex": 1,
+          "fib": true,
+          "flags": 3,
+          "active": true
+        }
+      ]
+    }
+  ],
+  "10.254.254.1/32": [
+    {
+      "distance": 20,
+      "protocol": "bgp",
+      "internalFlags": 8,
+      "metric": 0,
+      "selected": true,
+      "installed": true,
+      "prefix": "10.254.254.1/32",
+      "internalStatus": 34,
+      "nexthops": [
+        {
+          "interfaceName": "r2-eth0",
+          "interfaceIndex": 2,
+          "fib": true,
+          "flags": 3,
+          "active": true,
+          "afi": "ipv6"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-topo2/r2/ipv6_routes.json b/tests/topotests/bfd-topo2/r2/ipv6_routes.json
new file mode 100644 (file)
index 0000000..004e758
--- /dev/null
@@ -0,0 +1,63 @@
+{
+  "2001:db8:4::/64": [
+    {
+      "distance": 110,
+      "protocol": "ospf6",
+      "internalFlags": 0,
+      "metric": 10,
+      "internalStatus": 2,
+      "prefix": "2001:db8:4::/64",
+      "nexthops": [
+        {
+          "active": true,
+          "directlyConnected": true,
+          "flags": 1,
+          "interfaceIndex": 4,
+          "interfaceName": "r2-eth2"
+        }
+      ]
+    },
+    {
+      "distance": 0,
+      "protocol": "connected",
+      "internalFlags": 8,
+      "metric": 0,
+      "selected": true,
+      "installed": true,
+      "prefix": "2001:db8:4::/64",
+      "internalStatus": 32,
+      "nexthops": [
+        {
+          "directlyConnected": true,
+          "interfaceName": "r2-eth2",
+          "interfaceIndex": 4,
+          "fib": true,
+          "flags": 3,
+          "active": true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1::/64": [
+    {
+      "distance": 0,
+      "protocol": "connected",
+      "internalFlags": 8,
+      "metric": 0,
+      "selected": true,
+      "installed": true,
+      "prefix": "2001:db8:1::/64",
+      "internalStatus": 32,
+      "nexthops": [
+        {
+          "directlyConnected": true,
+          "interfaceName": "r2-eth0",
+          "interfaceIndex": 2,
+          "fib": true,
+          "flags": 3,
+          "active": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-topo2/r2/ospf6d.conf b/tests/topotests/bfd-topo2/r2/ospf6d.conf
new file mode 100644 (file)
index 0000000..f1cdb50
--- /dev/null
@@ -0,0 +1,9 @@
+interface r2-eth2
+ ipv6 ospf6 bfd
+!
+router ospf6
+ ospf6 router-id 10.254.254.2
+ redistribute connected
+ redistribute bgp
+ interface r2-eth2 area 0.0.0.1
+!
diff --git a/tests/topotests/bfd-topo2/r2/ospfd.conf b/tests/topotests/bfd-topo2/r2/ospfd.conf
new file mode 100644 (file)
index 0000000..8e0c459
--- /dev/null
@@ -0,0 +1,9 @@
+interface r2-eth1
+ ip ospf area 0.0.0.1
+ ip ospf bfd
+!
+router ospf
+ ospf router-id 10.254.254.2
+ redistribute connected
+ redistribute bgp
+!
diff --git a/tests/topotests/bfd-topo2/r2/peers.json b/tests/topotests/bfd-topo2/r2/peers.json
new file mode 100644 (file)
index 0000000..29075fc
--- /dev/null
@@ -0,0 +1,42 @@
+[
+  {
+    "status": "up",
+    "transmit-interval": 300,
+    "remote-receive-interval": 300,
+    "echo-interval": 0,
+    "diagnostic": "ok",
+    "multihop": false,
+    "interface": "r2-eth0",
+    "remote-transmit-interval": 300,
+    "receive-interval": 300,
+    "remote-echo-interval": 50,
+    "remote-diagnostic": "ok"
+  },
+  {
+    "status": "up",
+    "transmit-interval": 300,
+    "remote-receive-interval": 300,
+    "echo-interval": 0,
+    "diagnostic": "ok",
+    "multihop": false,
+    "interface": "r2-eth2",
+    "remote-transmit-interval": 300,
+    "receive-interval": 300,
+    "remote-echo-interval": 50,
+    "remote-diagnostic": "ok"
+  },
+  {
+    "status": "up",
+    "transmit-interval": 300,
+    "remote-receive-interval": 300,
+    "echo-interval": 0,
+    "diagnostic": "ok",
+    "multihop": false,
+    "interface": "r2-eth1",
+    "remote-transmit-interval": 300,
+    "receive-interval": 300,
+    "remote-echo-interval": 50,
+    "remote-diagnostic": "ok",
+    "peer": "10.0.3.1"
+  }
+]
diff --git a/tests/topotests/bfd-topo2/r2/zebra.conf b/tests/topotests/bfd-topo2/r2/zebra.conf
new file mode 100644 (file)
index 0000000..cccbf65
--- /dev/null
@@ -0,0 +1,15 @@
+ip forwarding
+ipv6 forwarding
+!
+interface lo
+ ip address 10.254.254.2/32
+!
+interface r2-eth0
+ ipv6 address 2001:db8:1::2/64
+!
+interface r2-eth1
+ ip address 10.0.3.2/24
+!
+interface r2-eth2
+ ipv6 address 2001:db8:4::2/64
+!
diff --git a/tests/topotests/bfd-topo2/r3/ipv4_routes.json b/tests/topotests/bfd-topo2/r3/ipv4_routes.json
new file mode 100644 (file)
index 0000000..14dfc69
--- /dev/null
@@ -0,0 +1,109 @@
+{
+  "10.0.3.0/24": [
+    {
+      "distance": 110,
+      "protocol": "ospf",
+      "internalFlags": 0,
+      "metric": 10,
+      "internalStatus": 0,
+      "prefix": "10.0.3.0/24",
+      "nexthops": [
+        {
+          "active": true,
+          "directlyConnected": true,
+          "flags": 1,
+          "interfaceIndex": 2,
+          "interfaceName": "r3-eth0"
+        }
+      ]
+    },
+    {
+      "distance": 0,
+      "protocol": "connected",
+      "internalFlags": 8,
+      "metric": 0,
+      "selected": true,
+      "installed": true,
+      "prefix": "10.0.3.0/24",
+      "internalStatus": 32,
+      "nexthops": [
+        {
+          "directlyConnected": true,
+          "interfaceName": "r3-eth0",
+          "interfaceIndex": 2,
+          "fib": true,
+          "flags": 3,
+          "active": true
+        }
+      ]
+    }
+  ],
+  "10.254.254.3/32": [
+    {
+      "distance": 0,
+      "protocol": "connected",
+      "internalFlags": 8,
+      "metric": 0,
+      "selected": true,
+      "installed": true,
+      "prefix": "10.254.254.3/32",
+      "internalStatus": 32,
+      "nexthops": [
+        {
+          "directlyConnected": true,
+          "interfaceName": "lo",
+          "interfaceIndex": 1,
+          "fib": true,
+          "flags": 3,
+          "active": true
+        }
+      ]
+    }
+  ],
+  "10.254.254.2/32": [
+    {
+      "distance": 110,
+      "protocol": "ospf",
+      "internalFlags": 8,
+      "metric": 20,
+      "selected": true,
+      "installed": true,
+      "prefix": "10.254.254.2/32",
+      "internalStatus": 34,
+      "nexthops": [
+        {
+          "interfaceName": "r3-eth0",
+          "ip": "10.0.3.2",
+          "interfaceIndex": 2,
+          "fib": true,
+          "flags": 3,
+          "active": true,
+          "afi": "ipv4"
+        }
+      ]
+    }
+  ],
+  "10.254.254.1/32": [
+    {
+      "distance": 110,
+      "protocol": "ospf",
+      "internalFlags": 8,
+      "metric": 20,
+      "selected": true,
+      "installed": true,
+      "prefix": "10.254.254.1/32",
+      "internalStatus": 34,
+      "nexthops": [
+        {
+          "interfaceName": "r3-eth0",
+          "ip": "10.0.3.2",
+          "interfaceIndex": 2,
+          "fib": true,
+          "flags": 3,
+          "active": true,
+          "afi": "ipv4"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-topo2/r3/ipv6_routes.json b/tests/topotests/bfd-topo2/r3/ipv6_routes.json
new file mode 100644 (file)
index 0000000..2c63c08
--- /dev/null
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/bfd-topo2/r3/ospfd.conf b/tests/topotests/bfd-topo2/r3/ospfd.conf
new file mode 100644 (file)
index 0000000..cf2a1bd
--- /dev/null
@@ -0,0 +1,8 @@
+interface r3-eth0
+ ip ospf area 0.0.0.1
+ ip ospf bfd
+!
+router ospf
+ ospf router-id 10.254.254.3
+ redistribute connected
+!
diff --git a/tests/topotests/bfd-topo2/r3/peers.json b/tests/topotests/bfd-topo2/r3/peers.json
new file mode 100644 (file)
index 0000000..6698bff
--- /dev/null
@@ -0,0 +1,16 @@
+[
+  {
+    "status": "up",
+    "transmit-interval": 300,
+    "remote-receive-interval": 300,
+    "echo-interval": 0,
+    "diagnostic": "ok",
+    "multihop": false,
+    "interface": "r3-eth0",
+    "remote-transmit-interval": 300,
+    "receive-interval": 300,
+    "remote-echo-interval": 50,
+    "remote-diagnostic": "ok",
+    "peer": "10.0.3.2"
+  }
+]
diff --git a/tests/topotests/bfd-topo2/r3/zebra.conf b/tests/topotests/bfd-topo2/r3/zebra.conf
new file mode 100644 (file)
index 0000000..96fd08c
--- /dev/null
@@ -0,0 +1,6 @@
+interface lo
+ ip address 10.254.254.3/32
+!
+interface r3-eth0
+ ip address 10.0.3.1/24
+!
diff --git a/tests/topotests/bfd-topo2/r4/bfdd.conf b/tests/topotests/bfd-topo2/r4/bfdd.conf
new file mode 100644 (file)
index 0000000..fdb4412
--- /dev/null
@@ -0,0 +1,5 @@
+bfd
+ peer 2001:db8:1::1 multihop local-address 2001:db8:4::1
+  no shutdown
+ !
+!
diff --git a/tests/topotests/bfd-topo2/r4/ipv4_routes.json b/tests/topotests/bfd-topo2/r4/ipv4_routes.json
new file mode 100644 (file)
index 0000000..ae1e97b
--- /dev/null
@@ -0,0 +1,24 @@
+{
+  "10.254.254.4/32": [
+    {
+      "distance": 0,
+      "protocol": "connected",
+      "internalFlags": 8,
+      "metric": 0,
+      "selected": true,
+      "installed": true,
+      "prefix": "10.254.254.4/32",
+      "internalStatus": 32,
+      "nexthops": [
+        {
+          "directlyConnected": true,
+          "interfaceName": "lo",
+          "interfaceIndex": 1,
+          "fib": true,
+          "flags": 3,
+          "active": true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-topo2/r4/ipv6_routes.json b/tests/topotests/bfd-topo2/r4/ipv6_routes.json
new file mode 100644 (file)
index 0000000..33608b4
--- /dev/null
@@ -0,0 +1,63 @@
+{
+  "2001:db8:4::/64": [
+    {
+      "distance": 110,
+      "protocol": "ospf6",
+      "internalFlags": 0,
+      "metric": 10,
+      "internalStatus": 2,
+      "prefix": "2001:db8:4::/64",
+      "nexthops": [
+        {
+          "active": true,
+          "directlyConnected": true,
+          "flags": 1,
+          "interfaceIndex": 2,
+          "interfaceName": "r4-eth0"
+        }
+      ]
+    },
+    {
+      "distance": 0,
+      "protocol": "connected",
+      "internalFlags": 8,
+      "metric": 0,
+      "selected": true,
+      "installed": true,
+      "prefix": "2001:db8:4::/64",
+      "internalStatus": 32,
+      "nexthops": [
+        {
+          "directlyConnected": true,
+          "interfaceName": "r4-eth0",
+          "interfaceIndex": 2,
+          "fib": true,
+          "flags": 3,
+          "active": true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1::/64": [
+    {
+      "distance": 110,
+      "protocol": "ospf6",
+      "internalFlags": 8,
+      "metric": 10,
+      "selected": true,
+      "installed": true,
+      "prefix": "2001:db8:1::/64",
+      "internalStatus": 34,
+      "nexthops": [
+        {
+          "interfaceName": "r4-eth0",
+          "interfaceIndex": 2,
+          "fib": true,
+          "flags": 3,
+          "active": true,
+          "afi": "ipv6"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bfd-topo2/r4/ospf6d.conf b/tests/topotests/bfd-topo2/r4/ospf6d.conf
new file mode 100644 (file)
index 0000000..756597d
--- /dev/null
@@ -0,0 +1,8 @@
+interface r4-eth0
+ ipv6 ospf6 bfd
+!
+router ospf6
+ ospf6 router-id 10.254.254.4
+ redistribute connected
+ interface r4-eth0 area 0.0.0.1
+!
diff --git a/tests/topotests/bfd-topo2/r4/peers.json b/tests/topotests/bfd-topo2/r4/peers.json
new file mode 100644 (file)
index 0000000..83101eb
--- /dev/null
@@ -0,0 +1,29 @@
+[
+    {
+        "multihop":true,
+        "peer":"2001:db8:1::1",
+        "local":"2001:db8:4::1",
+        "status":"up",
+        "diagnostic":"ok",
+        "remote-diagnostic":"ok",
+        "receive-interval":300,
+        "transmit-interval":300,
+        "echo-interval":0,
+        "remote-receive-interval":300,
+        "remote-transmit-interval":300,
+        "remote-echo-interval":50
+    },
+    {
+        "multihop":false,
+        "interface":"r4-eth0",
+        "status":"up",
+        "diagnostic":"ok",
+        "remote-diagnostic":"ok",
+        "receive-interval":300,
+        "transmit-interval":300,
+        "echo-interval":0,
+        "remote-receive-interval":300,
+        "remote-transmit-interval":300,
+        "remote-echo-interval":50
+    }
+]
diff --git a/tests/topotests/bfd-topo2/r4/zebra.conf b/tests/topotests/bfd-topo2/r4/zebra.conf
new file mode 100644 (file)
index 0000000..e4f8fd8
--- /dev/null
@@ -0,0 +1,6 @@
+interface lo
+ ip address 10.254.254.4/32
+!
+interface r4-eth0
+ ipv6 address 2001:db8:4::1/64
+!
diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.dot b/tests/topotests/bfd-topo2/test_bfd_topo2.dot
new file mode 100644 (file)
index 0000000..6b68fb3
--- /dev/null
@@ -0,0 +1,73 @@
+## Color coding:
+#########################
+##  Main FRR: #f08080  red
+##  Switches: #d0e0d0  gray
+##  RIP:      #19e3d9  Cyan
+##  RIPng:    #fcb314  dark yellow
+##  OSPFv2:   #32b835  Green
+##  OSPFv3:   #19e3d9  Cyan
+##  ISIS IPv4 #fcb314  dark yellow
+##  ISIS IPv6 #9a81ec  purple
+##  BGP IPv4  #eee3d3  beige
+##  BGP IPv6  #fdff00  yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+  label="bfd-topo2";
+
+  # Routers
+  r1 [
+    shape=doubleoctagon,
+    label="r1",
+    fillcolor="#f08080",
+    style=filled,
+  ];
+  r2 [
+    shape=doubleoctagon
+    label="r2",
+    fillcolor="#f08080",
+    style=filled,
+  ];
+  r3 [
+    shape=doubleoctagon
+    label="r3",
+    fillcolor="#f08080",
+    style=filled,
+  ];
+  r4 [
+    shape=doubleoctagon
+    label="r4",
+    fillcolor="#f08080",
+    style=filled,
+  ];
+
+  # Switches
+  sw1 [
+    shape=oval,
+    label="sw1\n2001:db8:1::/64",
+    fillcolor="#d0e0d0",
+    style=filled,
+  ];
+  sw2 [
+    shape=oval,
+    label="sw2\n10.0.3.0/24",
+    fillcolor="#d0e0d0",
+    style=filled,
+  ];
+  sw3 [
+    shape=oval,
+    label="sw3\n2001:db8:4::/64",
+    fillcolor="#d0e0d0",
+    style=filled,
+  ];
+
+  # Connections
+  r1 -- sw1 [label="eth0"];
+  r2 -- sw1 [label="eth0"];
+
+  r2 -- sw2 [label="eth1"];
+  r3 -- sw2 [label="eth0"];
+
+  r2 -- sw3 [label="eth2"];
+  r4 -- sw3 [label="eth0"];
+}
diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.jpg b/tests/topotests/bfd-topo2/test_bfd_topo2.jpg
new file mode 100644 (file)
index 0000000..35fe562
Binary files /dev/null and b/tests/topotests/bfd-topo2/test_bfd_topo2.jpg differ
diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.py b/tests/topotests/bfd-topo2/test_bfd_topo2.py
new file mode 100644 (file)
index 0000000..773db12
--- /dev/null
@@ -0,0 +1,191 @@
+#!/usr/bin/env python
+
+#
+# test_bfd_topo2.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# 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 NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF 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.
+#
+
+"""
+test_bfd_topo2.py: Test the FRR/Quagga BFD daemon with multihop and BGP
+unnumbered.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+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, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+
+class BFDTopo(Topo):
+    "Test topology builder"
+    def build(self, *_args, **_opts):
+        "Build function"
+        tgen = get_topogen(self)
+
+        # Create 4 routers.
+        for routern in range(1, 5):
+            tgen.add_router('r{}'.format(routern))
+
+        switch = tgen.add_switch('s1')
+        switch.add_link(tgen.gears['r1'])
+        switch.add_link(tgen.gears['r2'])
+
+        switch = tgen.add_switch('s2')
+        switch.add_link(tgen.gears['r2'])
+        switch.add_link(tgen.gears['r3'])
+
+        switch = tgen.add_switch('s3')
+        switch.add_link(tgen.gears['r2'])
+        switch.add_link(tgen.gears['r4'])
+
+
+def setup_module(mod):
+    "Sets up the pytest environment"
+    tgen = Topogen(BFDTopo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+    for rname, router in router_list.iteritems():
+        router.load_config(
+            TopoRouter.RD_ZEBRA,
+            os.path.join(CWD, '{}/zebra.conf'.format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_BFD,
+            os.path.join(CWD, '{}/bfdd.conf'.format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_BGP,
+            os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_OSPF,
+            os.path.join(CWD, '{}/ospfd.conf'.format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_OSPF6,
+            os.path.join(CWD, '{}/ospf6d.conf'.format(rname))
+        )
+
+    # Initialize all routers.
+    tgen.start_router()
+
+    # Verify that we are using the proper version and that the BFD
+    # daemon exists.
+    for router in router_list.values():
+        # Check for Version
+        if router.has_version('<', '5.1'):
+            tgen.set_error('Unsupported FRR version')
+            break
+
+
+def teardown_module(_mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+    tgen.stop_topology()
+
+
+def test_protocols_convergence():
+    """
+    Assert that all protocols have converged before checking for the BFD
+    statuses as they depend on it.
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # Check IPv4 routing tables.
+    logger.info("Checking IPv4 routes for convergence")
+    for router in tgen.routers().values():
+        json_file = '{}/{}/ipv4_routes.json'.format(CWD, router.name)
+        if not os.path.isfile(json_file):
+            logger.info('skipping file {}'.format(json_file))
+            continue
+
+        expected = json.loads(open(json_file).read())
+        test_func = partial(topotest.router_json_cmp,
+                            router, 'show ip route json', expected)
+        _, result = topotest.run_and_expect(test_func, None, count=160,
+                                            wait=0.5)
+        assertmsg = '"{}" JSON output mismatches'.format(router.name)
+        assert result is None, assertmsg
+
+    # Check IPv6 routing tables.
+    logger.info("Checking IPv6 routes for convergence")
+    for router in tgen.routers().values():
+        json_file = '{}/{}/ipv6_routes.json'.format(CWD, router.name)
+        if not os.path.isfile(json_file):
+            logger.info('skipping file {}'.format(json_file))
+            continue
+
+        expected = json.loads(open(json_file).read())
+        test_func = partial(topotest.router_json_cmp,
+                            router, 'show ipv6 route json', expected)
+        _, result = topotest.run_and_expect(test_func, None, count=160,
+                                            wait=0.5)
+        assertmsg = '"{}" JSON output mismatches'.format(router.name)
+        assert result is None, assertmsg
+
+
+def test_bfd_connection():
+    "Assert that the BFD peers can find themselves."
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info('waiting for bfd peers to go up')
+
+    for router in tgen.routers().values():
+        json_file = '{}/{}/peers.json'.format(CWD, router.name)
+        expected = json.loads(open(json_file).read())
+
+        test_func = partial(topotest.router_json_cmp,
+                            router, 'show bfd peers json', expected)
+        _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5)
+        assertmsg = '"{}" JSON output mismatches'.format(router.name)
+        assert result is None, assertmsg
+
+
+def test_memory_leak():
+    "Run the memory leak test and report results."
+    tgen = get_topogen()
+    if not tgen.is_memleak_enabled():
+        pytest.skip('Memory leak test/report is disabled')
+
+    tgen.report_memory_leaks()
+
+
+if __name__ == '__main__':
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index 344fb2ffcba97958d52e8e152a8fad1752ec72f9..70ce2efe851667d176a382b91b0ec985a7e5d859 100755 (executable)
@@ -26,5 +26,5 @@ cd "$(dirname "$0")"/..
 
 exec docker build --pull \
                  --compress \
-                 -t frrouting/frr:topotests-latest \
+                 -t frrouting/topotests:latest \
                  .
index 6d8bea00022d93ad9b39083cdce5fa32368102be..ef916abcf3c7daefb480e33b7580c4fd6584e148 100755 (executable)
@@ -136,7 +136,7 @@ if [ -z "$TOPOTEST_BUILDCACHE" ]; then
 fi
 
 if [ "${TOPOTEST_PULL:-1}" = "1" ]; then
-       docker pull frrouting/frr:topotests-latest
+       docker pull frrouting/topotests:latest
 fi
 
 set -- --rm -i \
@@ -149,7 +149,7 @@ set -- --rm -i \
        -e "TOPOTEST_SANITIZER=$TOPOTEST_SANITIZER" \
        --privileged \
        $TOPOTEST_OPTIONS \
-       frrouting/frr:topotests-latest "$@"
+       frrouting/topotests:latest "$@"
 
 if [ -t 0 ]; then
        set -- -t "$@"
index d0ec9f5d75988210e2780389116b85f2686ed91c..edfa1780a946e42a38d7ef91d8cd30cab5457e8e 100644 (file)
@@ -2,10 +2,12 @@ log file zebra.log
 !
 hostname r1
 !
-debug zebra rib
+debug zebra kernel
+debug zebra rib detailed
+debug zebra dplane detailed
 debug zebra nht
 debug zebra pseudowires
-debug zebra packet
+debug zebra mpls
 !
 interface lo
  ip address 1.1.1.1/32
index 8bd800714c2a6af8e2f3f464e588bc44b881c05d..6b95efdce8c2e88eea4476a7fa6b4f4b6fbc5d60 100644 (file)
@@ -2,10 +2,11 @@ log file zebra.log
 !
 hostname r2
 !
-debug zebra rib
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
 debug zebra nht
 debug zebra pseudowires
-debug zebra packet
 !
 interface lo
  ip address 2.2.2.2/32
index 2ff61365b5e20084ebac6a1202d3e9d33542539e..85ec68ff32bbdbbda52f033e6aeb632f27aad24f 100644 (file)
@@ -2,10 +2,11 @@ log file zebra.log
 !
 hostname r3
 !
-debug zebra rib
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
 debug zebra nht
 debug zebra pseudowires
-debug zebra packet
 !
 interface lo
  ip address 3.3.3.3/32
index 8688a13aef16b8f0dfcd0508aa9b22f252a1f692..d989240a162ba91349620d5247cc36f4a90b9d6a 100644 (file)
@@ -586,9 +586,9 @@ class TopoRouter(TopoGear):
         os.system('chmod -R go+rw /tmp/topotests')
 
         # Open router log file
-        logfile = '{0}/{1}.log'.format(dir, name)
-
+        logfile = '{0}/{1}.log'.format(self.logdir, name)
         self.logger = logger_config.get_logger(name=name, target=logfile)
+
         self.tgen.topo.addNode(self.name, cls=self.cls, **params)
 
     def __str__(self):
index 84358b94bc2b29171f167308746b1a150f612966..e0da20e07f506d95d37479b422f7b497f3665c4c 100644 (file)
@@ -63,23 +63,6 @@ class json_cmp_result(object):
     def __str__(self):
         return '\n'.join(self.errors)
 
-def get_test_logdir(node=None, init=False):
-    """
-    Return the current test log directory based on PYTEST_CURRENT_TEST
-    environment variable.
-    Optional paramters:
-    node:  when set, adds the node specific log directory to the init dir
-    init:  when set, initializes the log directory and fixes path permissions
-    """
-    cur_test = os.environ['PYTEST_CURRENT_TEST']
-
-    ret = '/tmp/topotests/' + cur_test[0:cur_test.find(".py")].replace('/','.')
-    if node != None:
-        dir = ret + "/" + node
-    if init:
-        os.system('mkdir -p ' + dir)
-        os.system('chmod -R go+rw /tmp/topotests')
-    return ret
 
 def json_diff(d1, d2):
     """
@@ -612,7 +595,21 @@ class Router(Node):
 
     def __init__(self, name, **params):
         super(Router, self).__init__(name, **params)
-        self.logdir = params.get('logdir', get_test_logdir(name, True))
+        self.logdir = params.get('logdir')
+
+        # If this topology is using old API and doesn't have logdir
+        # specified, then attempt to generate an unique logdir.
+        if self.logdir is None:
+            cur_test = os.environ['PYTEST_CURRENT_TEST']
+            self.logdir = ('/tmp/topotests/' +
+                           cur_test[0:cur_test.find(".py")].replace('/', '.'))
+
+        # If the logdir is not created, then create it and set the
+        # appropriated permissions.
+        if not os.path.isdir(self.logdir):
+            os.system('mkdir -p ' + self.logdir + '/' + name)
+            os.system('chmod -R go+rw /tmp/topotests')
+
         self.daemondir = None
         self.hasmpls = False
         self.routertype = 'frr'
diff --git a/tests/topotests/pim-basic/mcast-rx.py b/tests/topotests/pim-basic/mcast-rx.py
new file mode 100755 (executable)
index 0000000..9e3484e
--- /dev/null
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+#
+# mcast-rx.py
+#
+# Copyright (c) 2018 Cumulus Networks, Inc.
+#
+# 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 Cumulus Networks DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF 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.
+#
+"""
+Subscribe to a multicast group so that the kernel sends an IGMP JOIN
+for the multicast group we subscribed to.
+"""
+
+import argparse
+import logging
+import re
+import os
+import socket
+import subprocess
+import struct
+import sys
+import time
+
+
+def ifname_to_ifindex(ifname):
+    output = subprocess.check_output("ip link show %s" % ifname, shell=True)
+    first_line = output.split('\n')[0]
+    re_index = re.search('^(\d+):', first_line)
+
+    if re_index:
+        return int(re_index.group(1))
+
+    log.error("Could not parse the ifindex for %s out of\n%s" % (ifname, first_line))
+    return None
+
+
+# Thou shalt be root
+if os.geteuid() != 0:
+    sys.stderr.write('ERROR: You must have root privileges\n')
+    sys.exit(1)
+
+
+logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)5s: %(message)s')
+
+# Color the errors and warnings in red
+logging.addLevelName(logging.ERROR, "\033[91m  %s\033[0m" % logging.getLevelName(logging.ERROR))
+logging.addLevelName(logging.WARNING, "\033[91m%s\033[0m" % logging.getLevelName(logging.WARNING))
+log = logging.getLogger(__name__)
+
+parser = argparse.ArgumentParser(description='Multicast RX utility',
+                                 version='1.0.0')
+parser.add_argument('group', help='Multicast IP')
+parser.add_argument('ifname', help='Interface name')
+parser.add_argument('--port', help='UDP port', default=1000)
+parser.add_argument('--sleep', help='Time to sleep before we stop waiting',
+                    default = 5)
+args = parser.parse_args()
+
+# Create the datagram socket
+sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+sock.bind((args.group, args.port))
+
+newpid = os.fork()
+
+if newpid == 0:
+    ifindex = ifname_to_ifindex(args.ifname)
+    mreq = struct.pack("=4sLL", socket.inet_aton(args.group), socket.INADDR_ANY, ifindex)
+    sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
+    time.sleep(float(args.sleep))
+    sock.close()
diff --git a/tests/topotests/pim-basic/mcast-tx.py b/tests/topotests/pim-basic/mcast-tx.py
new file mode 100755 (executable)
index 0000000..c469e47
--- /dev/null
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+#
+# mcast-tx.py
+#
+# Copyright (c) 2018 Cumulus Networks, Inc.
+#
+# 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 Cumulus Networks DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF 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.
+#
+
+import argparse
+import logging
+import socket
+import struct
+import time
+
+
+logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)5s: %(message)s')
+
+# Color the errors and warnings in red
+logging.addLevelName(logging.ERROR, "\033[91m  %s\033[0m" % logging.getLevelName(logging.ERROR))
+logging.addLevelName(logging.WARNING, "\033[91m%s\033[0m" % logging.getLevelName(logging.WARNING))
+log = logging.getLogger(__name__)
+
+parser = argparse.ArgumentParser(description='Multicast packet generator', version='1.0.0')
+parser.add_argument('group', help='Multicast IP')
+parser.add_argument('ifname', help='Interface name')
+parser.add_argument('--port', type=int, help='UDP port number', default=1000)
+parser.add_argument('--ttl', type=int, help='time-to-live', default=20)
+parser.add_argument('--count', type=int, help='Packets to send', default=1)
+parser.add_argument('--interval', type=int, help='ms between packets', default=100)
+args = parser.parse_args()
+
+# Create the datagram socket
+sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+# IN.SO_BINDTODEVICE is not defined in some releases of python but it is 25
+# https://github.com/sivel/bonding/issues/10
+#
+# Bind our socket to ifname
+sock.setsockopt(socket.SOL_SOCKET,
+                25,
+                struct.pack("%ds" % len(args.ifname), args.ifname))
+
+# We need to make sure our sendto() finishes before we close the socket
+sock.setblocking(1)
+
+# Set the time-to-live
+sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, struct.pack('b', args.ttl))
+
+ms = args.interval / 1000.0
+
+# Send data to the multicast group
+for x in xrange(args.count):
+    log.info('TX multicast UDP packet to %s:%d on %s' % (args.group, args.port, args.ifname))
+    sent = sock.sendto('foobar %d' % x, (args.group, args.port))
+
+    if args.count > 1 and ms:
+        time.sleep(ms)
+
+sock.close()
diff --git a/tests/topotests/pim-basic/r1/pimd.conf b/tests/topotests/pim-basic/r1/pimd.conf
new file mode 100644 (file)
index 0000000..5740c66
--- /dev/null
@@ -0,0 +1,10 @@
+hostname r1
+!
+interface r1-eth0
+  ip igmp
+  ip pim sm
+!
+interface lo
+  ip pim sm
+!
+ip pim rp 10.254.0.1
diff --git a/tests/topotests/pim-basic/r1/zebra.conf b/tests/topotests/pim-basic/r1/zebra.conf
new file mode 100644 (file)
index 0000000..2bf7129
--- /dev/null
@@ -0,0 +1,8 @@
+hostname r1
+!
+interface r1-eth0
+ ip address 10.0.20.1/24
+!
+interface lo
+ ip address 10.254.0.1/32
+!
diff --git a/tests/topotests/pim-basic/r2/pimd.conf b/tests/topotests/pim-basic/r2/pimd.conf
new file mode 100644 (file)
index 0000000..932cff6
--- /dev/null
@@ -0,0 +1 @@
+hostname r2
diff --git a/tests/topotests/pim-basic/r2/zebra.conf b/tests/topotests/pim-basic/r2/zebra.conf
new file mode 100644 (file)
index 0000000..cb30858
--- /dev/null
@@ -0,0 +1,8 @@
+hostname r2
+!
+interface r2-eth0
+ ip address 10.0.20.2/24
+!
+interface lo
+ ip address 10.254.0.2/32
+!
diff --git a/tests/topotests/pim-basic/test_pim.py b/tests/topotests/pim-basic/test_pim.py
new file mode 100644 (file)
index 0000000..6d54b8f
--- /dev/null
@@ -0,0 +1,158 @@
+#!/usr/bin/env python
+
+#
+# test_pim.py
+#
+# Copyright (c) 2018 Cumulus Networks, Inc.
+#                    Donald Sharp
+#
+# 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 Cumulus Networks DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF 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.
+#
+
+"""
+test_pim.py: Test pim
+"""
+
+import os
+import sys
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+from mininet.topo import Topo
+
+class PIMTopo(Topo):
+    def build(self, *_args, **_opts):
+        "Build function"
+        tgen = get_topogen(self)
+
+        for routern in range(1, 3):
+            tgen.add_router('r{}'.format(routern))
+
+        # r1 <- sw1 -> r2
+        sw = tgen.add_switch('sw1')
+        sw.add_link(tgen.gears['r1'])
+        sw.add_link(tgen.gears['r2'])
+
+
+def setup_module(mod):
+    "Sets up the pytest environment"
+    tgen = Topogen(PIMTopo, mod.__name__)
+    tgen.start_topology()
+
+    # For all registered routers, load the zebra configuration file
+    for rname, router in tgen.routers().iteritems():
+        router.load_config(
+            TopoRouter.RD_ZEBRA,
+            os.path.join(CWD, '{}/zebra.conf'.format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_PIM,
+            os.path.join(CWD, '{}/pimd.conf'.format(rname))
+        )
+
+    # After loading the configurations, this function loads configured daemons.
+    tgen.start_router()
+
+
+def teardown_module(mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+
+    # This function tears down the whole topology.
+    tgen.stop_topology()
+
+
+def test_pim_send_mcast_stream():
+    "Establish a Multicast stream from r2 -> r1 and then ensure S,G is created as appropriate"
+    logger.info("Establish a Mcast stream from r2->r1 and then ensure S,G created")
+
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    r2 = tgen.gears['r2']
+    r1 = tgen.gears['r1']
+
+    # Let's establish a S,G stream from r2 -> r1
+    CWD = os.path.dirname(os.path.realpath(__file__))
+    r2.run("{}/mcast-tx.py --ttl 5 --count 5 --interval 10 229.1.1.1 r2-eth0 > /tmp/bar".format(CWD))
+
+    # Let's see that it shows up and we have established some basic state
+    out = r1.vtysh_cmd("show ip pim upstream json", isjson=True)
+    expected = {
+        '229.1.1.1': {
+            '10.0.20.2': {
+                'firstHopRouter': 1,
+                'joinState': 'NotJoined',
+                'regState': 'RegPrune',
+                'inboundInterface': 'r1-eth0',
+            }
+        }
+    }
+
+    assert topotest.json_cmp(out, expected) is None, 'failed to converge pim'
+
+
+def test_pim_igmp_report():
+    "Send a igmp report from r2->r1 and ensure that the *,G state is created on r1"
+    logger.info("Send a igmp report from r2-r1 and ensure *,G created")
+
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    r2 = tgen.gears['r2']
+    r1 = tgen.gears['r1']
+
+    # Let's send a igmp report from r2->r1
+    CWD = os.path.dirname(os.path.realpath(__file__))
+    r2.run("{}/mcast-rx.py 229.1.1.2 r2-eth0 &".format(CWD))
+
+    out = r1.vtysh_cmd("show ip pim upstream json", isjson=True)
+    expected = {
+        '229.1.1.2': {
+            '*': {
+                'sourceIgmp': 1,
+                'joinState': 'Joined',
+                'regState': 'RegNoInfo',
+                'sptBit': 0,
+            }
+        }
+    }
+
+    assert topotest.json_cmp(out, expected) is None, 'failed to converge pim'
+
+
+def test_memory_leak():
+    "Run the memory leak test and report results."
+    tgen = get_topogen()
+    if not tgen.is_memleak_enabled():
+        pytest.skip('Memory leak test/report is disabled')
+
+    tgen.report_memory_leaks()
+
+
+if __name__ == '__main__':
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index 0fca541137d51d0ccc9d5c0a00626103342650ae..2abff422c99b887c0738b8416a4111c5f03c6736 100644 (file)
@@ -5,7 +5,7 @@
 #
 # ATTENTION:
 #
-# When activation a daemon at the first time, a config file, even if it is
+# When activating a daemon for the first time, a config file, even if it is
 # empty, has to be present *and* be owned by the user and group "frr", else
 # the daemon will not be started by /etc/init.d/frr. The permissions should
 # be u=rw,g=r,o=.
diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf
new file mode 100644 (file)
index 0000000..d52824f
--- /dev/null
@@ -0,0 +1,83 @@
+# FRR Support Bundle Command List
+# Do Not modify the lines that start with
+# PROC_NAME, CMD_LIST_START and CMD_LIST_END
+# Add the new command for each process between
+# CMD_LIST_START and CMD_LIST_END lines
+
+# BGP Support Bundle Command List
+PROC_NAME:bgp
+CMD_LIST_START
+show bgp summary
+show ip bgp
+show ip bgp neighbors
+show ip bgp summary
+show ip bgp statistics
+
+show ip bgp update-groups advertise-queue
+show ip bgp update-groups advertised-routes
+show ip bgp update-groups packet-queue
+show ip bgp update-groups statistics
+show ip bgp peer-group
+show ip bgp memory
+
+show bgp ipv6
+show bgp ipv6 neighbors
+show bgp ipv6 summary
+show bgp ipv6 update-groups advertise-queue
+show bgp ipv6 update-groups advertised-routes
+show bgp ipv6 update-groups packet-queue
+show bgp ipv6 update-groups statistics
+show ip bgp statistics
+
+show bgp evpn route
+CMD_LIST_END
+
+# Zebra Support Bundle Command List
+PROC_NAME:zebra
+CMD_LIST_START
+show zebra
+show zebra client summary
+show ip route
+
+show route-map
+show memory
+show interface
+show vrf
+show error all
+show work-queues
+show running-config
+show thread cpu
+show thread poll
+show daemons
+show version
+CMD_LIST_END
+
+# OSPF Support Bundle Command List
+# PROC_NAME:ospf
+# CMD_LIST_START
+# CMD_LIST_END
+
+# RIP Support Bundle Command List
+# PROC_NAME:rip
+# CMD_LIST_START
+# CMD_LIST_END
+
+# ISIS Support Bundle Command List
+# PROC_NAME:isis
+# CMD_LIST_START
+# CMD_LIST_END
+
+# BFD Support Bundle Command List
+# PROC_NAME:bfd
+# CMD_LIST_START
+# CMD_LIST_END
+
+# STATIC Support Bundle Command List
+# PROC_NAME:static
+# CMD_LIST_START
+# CMD_LIST_END
+
+# PIM Support Bundle Command List
+# PROC_NAME:pim
+# CMD_LIST_START
+# CMD_LIST_END
index a443191fd04122893ee200870f22b4f16440220b..2e3a094589cb4eb738f8bf1c24a75be31f47647c 100755 (executable)
@@ -504,7 +504,9 @@ check_status()
 
 # Load configuration
 . "$C_PATH/daemons"
-. "$C_PATH/daemons.conf"
+if [ -e "$C_PATH/daemons.conf" ]; then
+       . "$C_PATH/daemons.conf"
+fi
 
 # Read configuration variable file if it is present
 [ -r /etc/default/frr ] && . /etc/default/frr
index 76a0d617ba199616d2e158f158fb7e0b56fd0e49..897e6d65587d0b1e8f51e0c532606026109da4e3 100644 (file)
@@ -291,7 +291,7 @@ load_old_config "$C_PATH/daemons.conf"
 load_old_config "/etc/default/frr"
 load_old_config "/etc/sysconfig/frr"
 
-if declare -p watchfrr_options | grep -q '^declare \-a'; then
+if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare \-a'; then
        log_warning_msg "watchfrr_options contains a bash array value." \
                "The configured value is intentionally ignored since it is likely wrong." \
                "Please remove or fix the setting."
diff --git a/tools/generate_support_bundle.py b/tools/generate_support_bundle.py
new file mode 100644 (file)
index 0000000..118ca11
--- /dev/null
@@ -0,0 +1,110 @@
+########################################################
+### Python Script to generate the FRR support bundle ###
+########################################################
+import os
+import subprocess
+import datetime
+
+TOOLS_DIR="tools/"
+ETC_DIR="/etc/frr/"
+LOG_DIR="/var/log/frr/"
+SUCCESS = 1
+FAIL = 0
+
+inputFile = ETC_DIR + "support_bundle_commands.conf"
+
+# Open support bundle configuration file
+def openConfFile(i_file):
+  try:
+    with open(i_file) as supportBundleConfFile:
+      lines = filter(None, (line.rstrip() for line in supportBundleConfFile))
+    return lines
+  except IOError:
+    return ([])
+
+# Create the output file name
+def createOutputFile(procName):
+  fileName = procName + "_support_bundle.log"
+  oldFile = LOG_DIR + fileName
+  cpFileCmd = "cp " + oldFile + " " + oldFile + ".prev"
+  rmFileCmd = "rm -rf " + oldFile
+  print "Making backup of " + oldFile
+  os.system(cpFileCmd)
+  print "Removing " + oldFile
+  os.system(rmFileCmd)
+  return fileName
+
+# Open the output file for this process
+def openOutputFile(fileName):
+  crt_file_cmd = LOG_DIR + fileName
+  print crt_file_cmd
+  try:
+    outputFile = open(crt_file_cmd, "w")
+    return outputFile
+  except IOError:
+    return ()
+
+# Close the output file for this process
+def closeOutputFile(file):
+  try:
+    file.close()
+    return SUCCESS
+  except IOError:
+    return FAIL
+
+# Execute the command over vtysh and store in the
+# output file
+def executeCommand(cmd, outputFile):
+  cmd_exec_str = "vtysh -c \"" + cmd + "\" "
+  try:
+    cmd_output = subprocess.check_output(cmd_exec_str, shell=True)
+    try:
+      dateTime = datetime.datetime.now()
+      outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n")
+      outputFile.write(cmd_output)
+      outputFile.write("########################################################\n")
+      outputFile.write('\n')
+    except:
+      print "Writing to ouptut file Failed"
+  except subprocess.CalledProcessError as e:
+    dateTime = datetime.datetime.now()
+    outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n")
+    outputFile.write(e.output)
+    outputFile.write("########################################################\n")
+    outputFile.write('\n')
+    print "Error:" + e.output
+
+
+# Process the support bundle configuration file
+# and call appropriate functions
+def processConfFile(lines):
+  for line in lines:
+    if line[0][0] == '#':
+      continue
+    cmd_line = line.split(':')
+    if cmd_line[0] == "PROC_NAME":
+      outputFileName = createOutputFile(cmd_line[1])
+      if outputFileName:
+        print outputFileName, "created for", cmd_line[1]
+    elif cmd_line[0] == "CMD_LIST_START":
+      outputFile = openOutputFile(outputFileName)
+      if outputFile:
+        print outputFileName, "opened"
+      else:
+        print outputFileName, "open failed"
+       return FAIL
+    elif cmd_line[0] == "CMD_LIST_END":
+      if closeOutputFile(outputFile):
+        print outputFileName, "closed"
+      else:
+        print outputFileName, "close failed"
+    else:
+      print "Execute:" , cmd_line[0]
+      executeCommand(cmd_line[0], outputFile)
+      
+# Main Function
+lines = openConfFile(inputFile)
+if not lines:
+  print "File support_bundle_commands.conf not present in /etc/frr/ directory"
+else:
+  processConfFile(lines)
index c449855f6dfb40901485e334a6b60a2544887ea9..7114a3286be1b3e36b7dca5584f1147f5b1d14d3 100644 (file)
@@ -272,7 +272,7 @@ void connected_up(struct interface *ifp, struct connected *ifc)
                                ifp->vrf_id, ifp->name,
                                prefix2str(&p, buf, sizeof(buf)));
                }
-               mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id));
+               mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), &p);
        }
 }
 
@@ -437,7 +437,7 @@ void connected_down(struct interface *ifp, struct connected *ifc)
                                ifp->vrf_id, ifp->name,
                                prefix2str(&p, buf, sizeof(buf)));
                }
-               mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id));
+               mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), &p);
        }
 }
 
@@ -471,7 +471,7 @@ static void connected_delete_helper(struct connected *ifc, struct prefix *p)
                                ifp->vrf_id, ifp->name,
                                prefix2str(p, buf, sizeof(buf)));
                }
-               mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id));
+               mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), p);
        }
 }
 
@@ -594,5 +594,5 @@ int connected_is_unnumbered(struct interface *ifp)
                        return CHECK_FLAG(connected->flags,
                                          ZEBRA_IFA_UNNUMBERED);
        }
-       return 0;
+       return 1;
 }
index faba30b0d5c653a30a9e4208070cf9115295f905..7672bec0063fdaa2b266b1439f4fa35f72c4585a 100644 (file)
 #include "lib/if.h"
 #include "lib/prefix.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern struct connected *connected_check(struct interface *ifp,
                                         union prefixconstptr p);
 extern struct connected *connected_check_ptp(struct interface *ifp,
@@ -58,4 +62,7 @@ extern void connected_delete_ipv6(struct interface *ifp,
 
 extern int connected_is_unnumbered(struct interface *);
 
+#ifdef __cplusplus
+}
+#endif
 #endif /*_ZEBRA_CONNECTED_H */
index 87999a1bbce03e66976b66e967959e8ee7d42d11..8e5fb0ea103b8e4474a242753204b8665b6e2406 100644 (file)
@@ -87,7 +87,9 @@ DEFUN_NOSH (show_debugging_zebra,
 
        if (IS_ZEBRA_DEBUG_FPM)
                vty_out(vty, "  Zebra FPM debugging is on\n");
-       if (IS_ZEBRA_DEBUG_NHT)
+       if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+               vty_out(vty, "  Zebra detailed next-hop tracking debugging is on\n");
+       else if (IS_ZEBRA_DEBUG_NHT)
                vty_out(vty, "  Zebra next-hop tracking debugging is on\n");
        if (IS_ZEBRA_DEBUG_MPLS)
                vty_out(vty, "  Zebra MPLS debugging is on\n");
@@ -119,12 +121,19 @@ DEFUN (debug_zebra_events,
 
 DEFUN (debug_zebra_nht,
        debug_zebra_nht_cmd,
-       "debug zebra nht",
+       "debug zebra nht [detailed]",
        DEBUG_STR
        "Zebra configuration\n"
-       "Debug option set for zebra next hop tracking\n")
+       "Debug option set for zebra next hop tracking\n"
+       "Debug option set for detailed info\n")
 {
+       int idx = 0;
+
        zebra_debug_nht = ZEBRA_DEBUG_NHT;
+
+       if (argv_find(argv, argc, "detailed", &idx))
+               zebra_debug_nht |= ZEBRA_DEBUG_NHT_DETAILED;
+
        return CMD_SUCCESS;
 }
 
@@ -320,11 +329,12 @@ DEFUN (no_debug_zebra_events,
 
 DEFUN (no_debug_zebra_nht,
        no_debug_zebra_nht_cmd,
-       "no debug zebra nht",
+       "no debug zebra nht [detailed]",
        NO_STR
        DEBUG_STR
        "Zebra configuration\n"
-       "Debug option set for zebra next hop tracking\n")
+       "Debug option set for zebra next hop tracking\n"
+       "Debug option set for detailed info\n")
 {
        zebra_debug_nht = 0;
        return CMD_SUCCESS;
@@ -490,10 +500,15 @@ static int config_write_debug(struct vty *vty)
                vty_out(vty, "debug zebra fpm\n");
                write++;
        }
-       if (IS_ZEBRA_DEBUG_NHT) {
+
+       if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+               vty_out(vty, "debug zebra nht detailed\n");
+               write++;
+       } else if (IS_ZEBRA_DEBUG_NHT) {
                vty_out(vty, "debug zebra nht\n");
                write++;
        }
+
        if (IS_ZEBRA_DEBUG_MPLS) {
                vty_out(vty, "debug zebra mpls\n");
                write++;
@@ -530,6 +545,7 @@ void zebra_debug_init(void)
        zebra_debug_pw = 0;
        zebra_debug_dplane = 0;
        zebra_debug_mlag = 0;
+       zebra_debug_nht = 0;
 
        install_node(&debug_node, config_write_debug);
 
index c79cd96c214d53e99c17f1e99c686df2a9da09f8..176226f7ae402b5ff0d10645ddc1a6d5b1dd8688 100644 (file)
 
 #include "lib/vty.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Debug flags. */
 #define ZEBRA_DEBUG_EVENT   0x01
 
@@ -40,7 +44,9 @@
 #define ZEBRA_DEBUG_RIB_DETAILED   0x02
 
 #define ZEBRA_DEBUG_FPM     0x01
-#define ZEBRA_DEBUG_NHT     0x01
+
+#define ZEBRA_DEBUG_NHT 0x01
+#define ZEBRA_DEBUG_NHT_DETAILED 0x02
 
 #define ZEBRA_DEBUG_MPLS    0x01
 
 #define IS_ZEBRA_DEBUG_RIB_DETAILED  (zebra_debug_rib & ZEBRA_DEBUG_RIB_DETAILED)
 
 #define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM)
+
 #define IS_ZEBRA_DEBUG_NHT  (zebra_debug_nht & ZEBRA_DEBUG_NHT)
+#define IS_ZEBRA_DEBUG_NHT_DETAILED (zebra_debug_nht & ZEBRA_DEBUG_NHT_DETAILED)
+
 #define IS_ZEBRA_DEBUG_MPLS  (zebra_debug_mpls & ZEBRA_DEBUG_MPLS)
 #define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN)
 #define IS_ZEBRA_DEBUG_PW  (zebra_debug_pw & ZEBRA_DEBUG_PW)
@@ -99,4 +108,8 @@ extern void zebra_debug_init(void);
 
 DECLARE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty));
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_DEBUG_H */
index 65a266a519f503b92970c2fca934f09123233ed2..710fd525587549dcc5e866ea1017a587492803e0 100644 (file)
 
 #ifdef HAVE_NETLINK
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id,
                                  int startup);
 extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
 extern int interface_lookup_netlink(struct zebra_ns *zns);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* HAVE_NETLINK */
 
 #endif /* _ZEBRA_IF_NETLINK_H */
index 1dbcf33fad84eadf3e7d2b478ea4ace70a738d8e..ce404e82537269a49ced567519399c8de4c5b4fa 100644 (file)
 
 #include "zebra/zebra_l2.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* For interface multicast configuration. */
 #define IF_ZEBRA_MULTICAST_UNSPEC 0
 #define IF_ZEBRA_MULTICAST_ON     1
@@ -432,4 +436,8 @@ extern int interface_list_proc(void);
 extern int ifaddr_proc_ipv6(void);
 #endif /* HAVE_PROC_NET_IF_INET6 */
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_INTERFACE_H */
index 2a8ea779092839c5b5308a8316e3c0b7967b683e..67ffd45a0818adec7e5dceaa9916e2b92bc55c70 100644 (file)
 #ifndef _ZEBRA_IOCTL_H
 #define _ZEBRA_IOCTL_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Prototypes. */
 extern void ifreq_set_name(struct ifreq *, struct interface *);
 extern int if_ioctl(unsigned long, caddr_t);
@@ -53,4 +57,8 @@ extern struct connected *if_lookup_linklocal(struct interface *);
 
 #endif /* SOLARIS_IPV6 */
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_IOCTL_H */
index 3507e563cdcf2388c624de25ef04c4147fbb2260..363f38289656fba1b285efb9aeefb8a30de22945 100644 (file)
 #ifndef _ZEBRA_IF_IOCTL_SOLARIS_H
 #define _ZEBRA_IF_IOCTL_SOLARIS_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 void lifreq_set_name(struct lifreq *, const char *);
 int if_get_flags_direct(const char *, uint64_t *, unsigned int af);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_IF_IOCTL_SOLARIS_H */
index fe9f2db9119ea690eb1bf987740f9957eb40267f..9884678c7a687b4198fa77b6af3d7e25aea08732 100644 (file)
 #ifndef _ZEBRA_IPFORWARD_H
 #define _ZEBRA_IPFORWARD_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern int ipforward(void);
 extern int ipforward_on(void);
 extern int ipforward_off(void);
@@ -29,4 +33,8 @@ extern int ipforward_ipv6(void);
 extern int ipforward_ipv6_on(void);
 extern int ipforward_ipv6_off(void);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_IPFORWARD_H */
index 4800e75be378213f162e24f64eabf7e1231ed468..3f4fa93460ac5f9ba743450d868f0748927a7501 100644 (file)
 
 #include "lib/vty.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define TRUE 1
 #define FALSE 0
 
@@ -150,5 +154,8 @@ extern int irdp_read_raw(struct thread *r);
 extern void send_packet(struct interface *ifp, struct stream *s, uint32_t dst,
                        struct prefix *p, uint32_t ttl);
 
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* _IRDP_H */
index a9734056bc09e320387ef932b2d89b9c47498ef1..38d241eaa5b45c5624109281b878878096bc07a3 100644 (file)
@@ -241,7 +241,7 @@ int irdp_send_thread(struct thread *t_advert)
                timer = MAX_INITIAL_ADVERT_INTERVAL;
 
        if (irdp->flags & IF_DEBUG_MISC)
-               zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name,
+               zlog_debug("IRDP: New timer for %s set to %u", ifp->name,
                           timer);
 
        irdp->t_advertise = NULL;
index 774d84d66d87bd1274029bb5755e5c32bdab8033..2804787620ab6ff8d9be38264fa1ae6969ea25e6 100644 (file)
@@ -166,7 +166,7 @@ static void parse_irdp_packet(char *p, int len, struct interface *ifp)
        case ICMP_ROUTERSOLICIT:
 
                if (irdp->flags & IF_DEBUG_MESSAGES)
-                       zlog_debug("IRDP: RX Solicit on %s from %s\n",
+                       zlog_debug("IRDP: RX Solicit on %s from %s",
                                   ifp->name, inet_ntoa(src));
 
                process_solicit(ifp);
@@ -253,7 +253,7 @@ int irdp_read_raw(struct thread *r)
        if (!(irdp->flags & IF_ACTIVE)) {
 
                if (irdp->flags & IF_DEBUG_MISC)
-                       zlog_debug("IRDP: RX ICMP for disabled interface %s\n",
+                       zlog_debug("IRDP: RX ICMP for disabled interface %s",
                                   ifp->name);
                return 0;
        }
index 2f850c6338d51a9fdf7916a6bf264896d171ee6a..fe37a333581ed12244f62acce217dba9adddbe7c 100644 (file)
@@ -606,53 +606,59 @@ const char *nl_rttype_to_str(uint8_t rttype)
        return lookup_msg(rttype_str, rttype, "");
 }
 
-#define NL_OK(nla, len)                                                        \
+#define NLA_OK(nla, len)                                                       \
        ((len) >= (int)sizeof(struct nlattr)                                   \
         && (nla)->nla_len >= sizeof(struct nlattr)                            \
         && (nla)->nla_len <= (len))
-#define NL_NEXT(nla, attrlen)                                                  \
-       ((attrlen) -= RTA_ALIGN((nla)->nla_len),                               \
-        (struct nlattr *)(((char *)(nla)) + RTA_ALIGN((nla)->nla_len)))
-#define NL_RTA(r)                                                              \
-       ((struct nlattr *)(((char *)(r))                                       \
-                          + NLMSG_ALIGN(sizeof(struct nlmsgerr))))
+#define NLA_NEXT(nla, attrlen)                                                 \
+       ((attrlen) -= NLA_ALIGN((nla)->nla_len),                               \
+        (struct nlattr *)(((char *)(nla)) + NLA_ALIGN((nla)->nla_len)))
+#define NLA_LENGTH(len) (NLA_ALIGN(sizeof(struct nlattr)) + (len))
+#define NLA_DATA(nla) ((struct nlattr *)(((char *)(nla)) + NLA_LENGTH(0)))
+
+#define ERR_NLA(err, inner_len)                                                \
+       ((struct nlattr *)(((char *)(err))                                     \
+                          + NLMSG_ALIGN(sizeof(struct nlmsgerr))              \
+                          + NLMSG_ALIGN((inner_len))))
 
 static void netlink_parse_nlattr(struct nlattr **tb, int max,
                                 struct nlattr *nla, int len)
 {
-       while (NL_OK(nla, len)) {
+       while (NLA_OK(nla, len)) {
                if (nla->nla_type <= max)
                        tb[nla->nla_type] = nla;
-               nla = NL_NEXT(nla, len);
+               nla = NLA_NEXT(nla, len);
        }
 }
 
 static void netlink_parse_extended_ack(struct nlmsghdr *h)
 {
-       struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
-       const struct nlmsgerr *err =
-               (const struct nlmsgerr *)((uint8_t *)h
-                                         + NLMSG_ALIGN(
-                                                   sizeof(struct nlmsghdr)));
+       struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
+       const struct nlmsgerr *err = (const struct nlmsgerr *)NLMSG_DATA(h);
        const struct nlmsghdr *err_nlh = NULL;
-       uint32_t hlen = sizeof(*err);
+       /* Length not including nlmsghdr */
+       uint32_t len = 0;
+       /* Inner error netlink message length */
+       uint32_t inner_len = 0;
        const char *msg = NULL;
        uint32_t off = 0;
 
        if (!(h->nlmsg_flags & NLM_F_CAPPED))
-               hlen += h->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+               inner_len = (uint32_t)NLMSG_PAYLOAD(&err->msg, 0);
+
+       len = (uint32_t)(NLMSG_PAYLOAD(h, sizeof(struct nlmsgerr)) - inner_len);
 
-       memset(tb, 0, sizeof(tb));
-       netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, NL_RTA(h), hlen);
+       netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, ERR_NLA(err, inner_len),
+                            len);
 
        if (tb[NLMSGERR_ATTR_MSG])
-               msg = (const char *)RTA_DATA(tb[NLMSGERR_ATTR_MSG]);
+               msg = (const char *)NLA_DATA(tb[NLMSGERR_ATTR_MSG]);
 
        if (tb[NLMSGERR_ATTR_OFFS]) {
-               off = *(uint32_t *)RTA_DATA(tb[NLMSGERR_ATTR_OFFS]);
+               off = *(uint32_t *)NLA_DATA(tb[NLMSGERR_ATTR_OFFS]);
 
                if (off > h->nlmsg_len) {
-                       zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS\n");
+                       zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS");
                } else if (!(h->nlmsg_flags & NLM_F_CAPPED)) {
                        /*
                         * Header of failed message
index 9918729eb66adc959082f81b574a4c363dfb7451..076ca5c5c7579253eb07859d42ee15046cc99568 100644 (file)
 #ifndef _ZEBRA_KERNEL_NETLINK_H
 #define _ZEBRA_KERNEL_NETLINK_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifdef HAVE_NETLINK
 
 #define NL_RCV_PKT_BUF_SIZE     32768
@@ -68,4 +72,8 @@ extern int netlink_request(struct nlsock *nl, struct nlmsghdr *n);
 
 #endif /* HAVE_NETLINK */
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_KERNEL_NETLINK_H */
index 792756efebdbaf161b5ea7a21e7d2ea8012fff51..ad461919038b162f1d76099e7b66bb8513bd3ea7 100644 (file)
@@ -622,7 +622,7 @@ int ifm_read(struct if_msghdr *ifm)
                 * RTA_IFP) is required.
                 */
                if (!ifnlen) {
-                       zlog_debug("Interface index %d (new) missing ifname\n",
+                       zlog_debug("Interface index %d (new) missing ifname",
                                   ifm->ifm_index);
                        return -1;
                }
index 096a21f78238cb8181fe6097f6ccab40639167f8..15079d796d624d16c484608d600bb562eb2e11e7 100644 (file)
 #ifndef __ZEBRA_KERNEL_SOCKET_H
 #define __ZEBRA_KERNEL_SOCKET_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Error codes of zebra. */
 #define ZEBRA_ERR_NOERROR                0
 #define ZEBRA_ERR_RTEXIST               -1
@@ -38,4 +42,8 @@ extern int rtm_write(int, union sockunion *, union sockunion *,
                     enum blackhole_type, int);
 extern const struct message rtm_type_str[];
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __ZEBRA_KERNEL_SOCKET_H */
index 3e3def5f98bbf47eaf7a18e11cc6da2a4786c65d..3ea89fbfc3ec928c25119909bf70cc8370a57aee 100644 (file)
 
 #include "zebra/zserv.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define NO_PROTO 0
 
 /*
@@ -74,4 +78,8 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
 int release_daemon_label_chunks(struct zserv *client);
 void label_manager_close(void);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _LABEL_MANAGER_H */
index c605050c57fe37ae2e70665573bfebc0cd974c49..184e798bd070f1484804082a8df794dc14d46774 100644 (file)
@@ -153,7 +153,9 @@ static void sigint(void)
        for (ALL_LIST_ELEMENTS(zrouter.client_list, ln, nn, client))
                zserv_close_client(client);
 
+       zserv_close();
        list_delete_all_node(zrouter.client_list);
+
        zebra_ptm_finish();
 
        if (retain_mode)
index f0dc79574cc1518600a9a0cdf99ec3804e3ec385..74a593b2409a3aa4b4945b2170d87f09903147e1 100644 (file)
 #include "zebra/zserv.h"
 #include "zebra/rib.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* ZAPI command handlers */
 extern void zebra_redistribute_add(ZAPI_HANDLER_ARGS);
 extern void zebra_redistribute_delete(ZAPI_HANDLER_ARGS);
@@ -73,4 +77,9 @@ extern int is_zebra_import_table_enabled(afi_t, uint32_t table_id);
 extern int zebra_import_table_config(struct vty *);
 
 extern void zebra_import_table_rm_update(const char *rmap);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_REDISTRIBUTE_H */
index a478fffddb3dacb9bc43c0fbca053005f498e041..e26831e1a6427b7d4e2dda7f625aff06aa735d37 100644 (file)
 #include "mpls.h"
 #include "srcdest_table.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define DISTANCE_INFINITY  255
 #define ZEBRA_KERNEL_TABLE_MAX 252 /* support for no more than this rt tables */
 
@@ -140,6 +144,15 @@ typedef struct rib_dest_t_ {
         */
        uint32_t flags;
 
+       /*
+        * The list of nht prefixes that have ended up
+        * depending on this route node.
+        * After route processing is returned from
+        * the data plane we will run evaluate_rnh
+        * on these prefixes.
+        */
+       struct list *nht;
+
        /*
         * Linkage to put dest on the FPM processing queue.
         */
@@ -168,6 +181,8 @@ typedef struct rib_dest_t_ {
  */
 #define RIB_DEST_UPDATE_FPM    (1 << (ZEBRA_MAX_QINDEX + 2))
 
+#define RIB_DEST_UPDATE_LSPS   (1 << (ZEBRA_MAX_QINDEX + 3))
+
 /*
  * Macro to iterate over each route for a destination (prefix).
  */
@@ -355,6 +370,8 @@ extern struct route_table *rib_tables_iter_next(rib_tables_iter_t *iter);
 
 extern uint8_t route_distance(int type);
 
+extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq);
+
 /*
  * Inline functions.
  */
@@ -426,6 +443,11 @@ static inline struct zebra_vrf *rib_dest_vrf(rib_dest_t *dest)
        return rib_table_info(rib_dest_table(dest))->zvrf;
 }
 
+/*
+ * Create the rib_dest_t and attach it to the specified node
+ */
+extern rib_dest_t *zebra_rib_create_dest(struct route_node *rn);
+
 /*
  * rib_tables_iter_init
  */
@@ -464,4 +486,9 @@ extern void zebra_vty_init(void);
 extern pid_t pid;
 
 extern bool v6_rr_semantics;
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /*_ZEBRA_RIB_H */
index 6b15159fdba2ee0306df35fc369d7919467bb4d6..f7d16853f18e90ffe7103a4a85ca07882f05f3ed 100644 (file)
 #include "zclient.h"
 #include "if.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern void router_id_add_address(struct connected *);
 extern void router_id_del_address(struct connected *);
 extern void router_id_init(struct zebra_vrf *);
@@ -37,4 +41,8 @@ extern void router_id_cmd_init(void);
 extern void router_id_write(struct vty *);
 extern void router_id_get(struct prefix *, vrf_id_t);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index 4080b0ccb287e0fbec1439d1b10841f0c803558e..2c77af2aad9f12a9962956f83ad4bf13f4ff1309 100644 (file)
 #include "zebra/zebra_mpls.h"
 #include "zebra/zebra_dplane.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RSYSTEM_ROUTE(type)                                            \
+       ((type) == ZEBRA_ROUTE_KERNEL || (type) == ZEBRA_ROUTE_CONNECT)
+
 /*
  * Update or delete a route, LSP, or pseudowire from the kernel,
  * using info from a dataplane context.
@@ -91,4 +98,8 @@ extern void neigh_read_specific_ip(struct ipaddr *ip,
                                   struct interface *vlan_if);
 extern void route_read(struct zebra_ns *zns);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_RT_H */
index 18cf389d5e0001b83f2ade927c5d7dd29e3b4f63..289ed5a15b147acda0cfe996c384ba967cbeff29 100644 (file)
@@ -835,7 +835,7 @@ int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 
        if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) {
                /* If this is not route add/delete message print warning. */
-               zlog_debug("Kernel message: %s NS %u\n",
+               zlog_debug("Kernel message: %s NS %u",
                           nl_msg_type_to_str(h->nlmsg_type), ns_id);
                return 0;
        }
@@ -927,7 +927,7 @@ static void _netlink_route_nl_add_gateway_info(uint8_t route_family,
                                               uint8_t gw_family,
                                               struct nlmsghdr *nlmsg,
                                               size_t req_size, int bytelen,
-                                              struct nexthop *nexthop)
+                                              const struct nexthop *nexthop)
 {
        if (route_family == AF_MPLS) {
                struct gw_family_t gw_fam;
@@ -954,7 +954,7 @@ static void _netlink_route_rta_add_gateway_info(uint8_t route_family,
                                                struct rtattr *rta,
                                                struct rtnexthop *rtnh,
                                                size_t req_size, int bytelen,
-                                               struct nexthop *nexthop)
+                                               const struct nexthop *nexthop)
 {
        if (route_family == AF_MPLS) {
                struct gw_family_t gw_fam;
@@ -990,7 +990,7 @@ static void _netlink_route_rta_add_gateway_info(uint8_t route_family,
  * @param req_size: The size allocated for the message.
  */
 static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
-                                           struct nexthop *nexthop,
+                                           const struct nexthop *nexthop,
                                            struct nlmsghdr *nlmsg,
                                            struct rtmsg *rtmsg,
                                            size_t req_size, int cmd)
@@ -1009,7 +1009,7 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
        label_buf[0] = '\0';
 
        assert(nexthop);
-       for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
+       for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
                char label_buf1[20];
 
                nh_label = nh->nh_label;
@@ -1175,11 +1175,11 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
  *             the prefsrc should be stored.
  */
 static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
-                                          struct nexthop *nexthop,
+                                          const struct nexthop *nexthop,
                                           struct rtattr *rta,
                                           struct rtnexthop *rtnh,
                                           struct rtmsg *rtmsg,
-                                          union g_addr **src)
+                                          const union g_addr **src)
 {
        struct mpls_label_stack *nh_label;
        mpls_lse_t out_lse[MPLS_MAX_LABELS];
@@ -1200,7 +1200,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
        label_buf[0] = '\0';
 
        assert(nexthop);
-       for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
+       for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
                char label_buf1[20];
 
                nh_label = nh->nh_label;
@@ -1342,7 +1342,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
 }
 
 static inline void _netlink_mpls_build_singlepath(const char *routedesc,
-                                                 zebra_nhlfe_t *nhlfe,
+                                                 const zebra_nhlfe_t *nhlfe,
                                                  struct nlmsghdr *nlmsg,
                                                  struct rtmsg *rtmsg,
                                                  size_t req_size, int cmd)
@@ -1358,9 +1358,9 @@ static inline void _netlink_mpls_build_singlepath(const char *routedesc,
 
 
 static inline void
-_netlink_mpls_build_multipath(const char *routedesc, zebra_nhlfe_t *nhlfe,
+_netlink_mpls_build_multipath(const char *routedesc, const zebra_nhlfe_t *nhlfe,
                              struct rtattr *rta, struct rtnexthop *rtnh,
-                             struct rtmsg *rtmsg, union g_addr **src)
+                             struct rtmsg *rtmsg, const union g_addr **src)
 {
        int bytelen;
        uint8_t family;
@@ -1438,7 +1438,6 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
 static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
 {
        int bytelen;
-       struct sockaddr_nl snl;
        struct nexthop *nexthop = NULL;
        unsigned int nexthop_num;
        int family;
@@ -1656,7 +1655,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
                char buf[NL_PKT_BUF_SIZE];
                struct rtattr *rta = (void *)buf;
                struct rtnexthop *rtnh;
-               union g_addr *src1 = NULL;
+               const union g_addr *src1 = NULL;
 
                rta->rta_type = RTA_MULTIPATH;
                rta->rta_len = RTA_LENGTH(0);
@@ -1747,11 +1746,6 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx)
        }
 
 skip:
-
-       /* Destination netlink address. */
-       memset(&snl, 0, sizeof(snl));
-       snl.nl_family = AF_NETLINK;
-
        /* Talk to netlink socket. */
        return netlink_talk_info(netlink_talk_filter, &req.n,
                                 dplane_ctx_get_ns(ctx), 0);
@@ -1842,7 +1836,9 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
                         * of the route delete.  If that happens yeah we're
                         * screwed.
                         */
-                       (void)netlink_route_multipath(RTM_DELROUTE, ctx);
+                       if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
+                               (void)netlink_route_multipath(RTM_DELROUTE,
+                                                             ctx);
                        cmd = RTM_NEWROUTE;
                }
 
@@ -1850,7 +1846,10 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
                return ZEBRA_DPLANE_REQUEST_FAILURE;
        }
 
-       ret = netlink_route_multipath(cmd, ctx);
+       if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)))
+               ret = netlink_route_multipath(cmd, ctx);
+       else
+               ret = 0;
        if ((cmd == RTM_NEWROUTE) && (ret == 0)) {
                /* Update installed nexthops to signal which have been
                 * installed.
@@ -1971,23 +1970,38 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        /* The interface should exist. */
        ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
                                        ndm->ndm_ifindex);
-       if (!ifp || !ifp->info)
+       if (!ifp || !ifp->info) {
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("\t%s without associated interface: %u",
+                                  __PRETTY_FUNCTION__, ndm->ndm_ifindex);
                return 0;
+       }
 
        /* The interface should be something we're interested in. */
-       if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
+       if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) {
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("\t%s Not interested in %s, not a slave",
+                                  __PRETTY_FUNCTION__, ifp->name);
                return 0;
+       }
 
        /* Drop "permanent" entries. */
-       if (ndm->ndm_state & NUD_PERMANENT)
+       if (ndm->ndm_state & NUD_PERMANENT) {
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("\t%s Entry is PERMANENT, dropping",
+                                  __PRETTY_FUNCTION__);
                return 0;
+       }
 
        zif = (struct zebra_if *)ifp->info;
        if ((br_if = zif->brslave_info.br_if) == NULL) {
-               zlog_debug("%s family %s IF %s(%u) brIF %u - no bridge master",
-                          nl_msg_type_to_str(h->nlmsg_type),
-                          nl_family_to_str(ndm->ndm_family), ifp->name,
-                          ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex);
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug(
+                               "%s family %s IF %s(%u) brIF %u - no bridge master",
+                               nl_msg_type_to_str(h->nlmsg_type),
+                               nl_family_to_str(ndm->ndm_family), ifp->name,
+                               ndm->ndm_ifindex,
+                               zif->brslave_info.bridge_ifindex);
                return 0;
        }
 
@@ -1996,20 +2010,24 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
 
        if (!tb[NDA_LLADDR]) {
-               zlog_debug("%s family %s IF %s(%u) brIF %u - no LLADDR",
-                          nl_msg_type_to_str(h->nlmsg_type),
-                          nl_family_to_str(ndm->ndm_family), ifp->name,
-                          ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex);
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("%s family %s IF %s(%u) brIF %u - no LLADDR",
+                                  nl_msg_type_to_str(h->nlmsg_type),
+                                  nl_family_to_str(ndm->ndm_family), ifp->name,
+                                  ndm->ndm_ifindex,
+                                  zif->brslave_info.bridge_ifindex);
                return 0;
        }
 
        if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {
-               zlog_debug(
-                       "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %lu",
-                       nl_msg_type_to_str(h->nlmsg_type),
-                       nl_family_to_str(ndm->ndm_family), ifp->name,
-                       ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex,
-                       (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR]));
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug(
+                               "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %lu",
+                               nl_msg_type_to_str(h->nlmsg_type),
+                               nl_family_to_str(ndm->ndm_family), ifp->name,
+                               ndm->ndm_ifindex,
+                               zif->brslave_info.bridge_ifindex,
+                               (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR]));
                return 0;
        }
 
@@ -2042,8 +2060,12 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
                           prefix_mac2str(&mac, buf, sizeof(buf)),
                           dst_present ? dst_buf : "");
 
-       if (filter_vlan && vid != filter_vlan)
+       if (filter_vlan && vid != filter_vlan) {
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("\tFiltered due to filter vlan: %d",
+                                  filter_vlan);
                return 0;
+       }
 
        /* If add or update, do accordingly if learnt on a "local" interface; if
         * the notification is over VxLAN, this has to be related to
@@ -2051,10 +2073,6 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
         * so perform an implicit delete of any local entry (if it exists).
         */
        if (h->nlmsg_type == RTM_NEWNEIGH) {
-               /* Drop "permanent" entries. */
-               if (ndm->ndm_state & NUD_PERMANENT)
-                       return 0;
-
                if (IS_ZEBRA_IF_VXLAN(ifp))
                        return zebra_vxlan_check_del_local_mac(ifp, br_if, &mac,
                                                               vid);
@@ -2071,8 +2089,11 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
         * Ignore the notification from VxLan driver as it is also generated
         * when mac moves from remote to local.
         */
-       if (dst_present)
+       if (dst_present) {
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("\tNo Destination Present");
                return 0;
+       }
 
        if (IS_ZEBRA_IF_VXLAN(ifp))
                return zebra_vxlan_check_readd_remote_mac(ifp, br_if, &mac,
@@ -2385,6 +2406,9 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        /* if kernel deletes our rfc5549 neighbor entry, re-install it */
        if (h->nlmsg_type == RTM_DELNEIGH && (ndm->ndm_state & NUD_PERMANENT)) {
                netlink_handle_5549(ndm, zif, ifp, &ip);
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug(
+                               "\tNeighbor Entry Received is a 5549 entry, finished");
                return 0;
        }
 
@@ -2410,20 +2434,27 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
                        return 0;
        } else if (IS_ZEBRA_IF_BRIDGE(ifp))
                link_if = ifp;
-       else
+       else {
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug(
+                               "\tNeighbor Entry received is not on a VLAN or a BRIDGE, ignoring");
                return 0;
+       }
 
        memset(&mac, 0, sizeof(struct ethaddr));
        if (h->nlmsg_type == RTM_NEWNEIGH) {
                if (tb[NDA_LLADDR]) {
                        if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {
-                               zlog_debug(
-                                       "%s family %s IF %s(%u) - LLADDR is not MAC, len %lu",
-                                       nl_msg_type_to_str(h->nlmsg_type),
-                                       nl_family_to_str(ndm->ndm_family),
-                                       ifp->name, ndm->ndm_ifindex,
-                                       (unsigned long)RTA_PAYLOAD(
-                                               tb[NDA_LLADDR]));
+                               if (IS_ZEBRA_DEBUG_KERNEL)
+                                       zlog_debug(
+                                               "%s family %s IF %s(%u) - LLADDR is not MAC, len %lu",
+                                               nl_msg_type_to_str(
+                                                       h->nlmsg_type),
+                                               nl_family_to_str(
+                                                       ndm->ndm_family),
+                                               ifp->name, ndm->ndm_ifindex,
+                                               (unsigned long)RTA_PAYLOAD(
+                                                       tb[NDA_LLADDR]));
                                return 0;
                        }
 
@@ -2750,7 +2781,7 @@ int kernel_upd_neigh(struct interface *ifp, struct ipaddr *ip,
 int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
 {
        mpls_lse_t lse;
-       zebra_nhlfe_t *nhlfe;
+       const zebra_nhlfe_t *nhlfe;
        struct nexthop *nexthop = NULL;
        unsigned int nexthop_num;
        const char *routedesc;
@@ -2853,7 +2884,7 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
                char buf[NL_PKT_BUF_SIZE];
                struct rtattr *rta = (void *)buf;
                struct rtnexthop *rtnh;
-               union g_addr *src1 = NULL;
+               const union g_addr *src1 = NULL;
 
                rta->rta_type = RTA_MULTIPATH;
                rta->rta_len = RTA_LENGTH(0);
index 473ad98a3fbc2b7392ae85ccfff26fca5e45c871..29e0152bb2c9d73c4b33549e6c2d73f439ecaada 100644 (file)
 #include "zebra/zebra_mpls.h"
 #include "zebra/zebra_dplane.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define NL_DEFAULT_ROUTE_METRIC 20
 
 /*
@@ -79,6 +83,10 @@ extern int netlink_macfdb_read_specific_mac(struct zebra_ns *zns,
 extern int netlink_neigh_read_specific_ip(struct ipaddr *ip,
                                          struct interface *vlan_if);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* HAVE_NETLINK */
 
 #endif /* _ZEBRA_RT_NETLINK_H */
index f25259f300cef721a1edf47fb91a57d07d212a93..8d8bdd0a6df839c09c31d89ff4b561ec722e1681 100644 (file)
@@ -304,33 +304,41 @@ static int kernel_rtm(int cmd, const struct prefix *p,
 enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
 {
        enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS;
+       uint32_t type, old_type;
 
        if (dplane_ctx_get_src(ctx) != NULL) {
                zlog_err("route add: IPv6 sourcedest routes unsupported!");
                return ZEBRA_DPLANE_REQUEST_FAILURE;
        }
 
+       type = dplane_ctx_get_type(ctx);
+       old_type = dplane_ctx_get_old_type(ctx);
+
        frr_elevate_privs(&zserv_privs) {
 
-               if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE)
-                       kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
-                                  dplane_ctx_get_ng(ctx),
-                                  dplane_ctx_get_metric(ctx));
-               else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL)
-                       kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
-                                  dplane_ctx_get_ng(ctx),
-                                  dplane_ctx_get_metric(ctx));
-               else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) {
+               if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
+                       if (!RSYSTEM_ROUTE(type))
+                               kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
+                                          dplane_ctx_get_ng(ctx),
+                                          dplane_ctx_get_metric(ctx));
+               } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) {
+                       if (!RSYSTEM_ROUTE(type))
+                               kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
+                                          dplane_ctx_get_ng(ctx),
+                                          dplane_ctx_get_metric(ctx));
+               } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) {
                        /* Must do delete and add separately -
                         * no update available
                         */
-                       kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
-                                  dplane_ctx_get_old_ng(ctx),
-                                  dplane_ctx_get_old_metric(ctx));
-
-                       kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
-                                  dplane_ctx_get_ng(ctx),
-                                  dplane_ctx_get_metric(ctx));
+                       if (!RSYSTEM_ROUTE(old_type))
+                               kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
+                                          dplane_ctx_get_old_ng(ctx),
+                                          dplane_ctx_get_old_metric(ctx));
+
+                       if (!RSYSTEM_ROUTE(type))
+                               kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
+                                          dplane_ctx_get_ng(ctx),
+                                          dplane_ctx_get_metric(ctx));
                } else {
                        zlog_err("Invalid routing socket update op %s (%u)",
                                 dplane_op2str(dplane_ctx_get_op(ctx)),
@@ -339,6 +347,20 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
                }
        } /* Elevated privs */
 
+       if (RSYSTEM_ROUTE(type)
+           && dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE) {
+               struct nexthop *nexthop;
+
+               for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
+                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+                               continue;
+
+                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
+                               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+                       }
+               }
+       }
+
        return res;
 }
 
index f7c27ebcb3a0c9c5de776e3ba49823ea1e396db0..53c497fc09c49b4823c96e12d515c0c07e0fae6d 100644 (file)
 #include "vty.h"
 #include "zebra/interface.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* NB: RTADV is defined in zebra/interface.h above */
 #if defined(HAVE_RTADV)
 
@@ -137,5 +141,8 @@ extern void rtadv_cmd_init(void);
 extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS);
 extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS);
 
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* _ZEBRA_RTADV_H */
index 4547a1bb3b1480fe6d0d3d434f0457cda53e510f..8c4741dc06115b2313afb48b7e1ee2c9be880f4c 100644 (file)
 
 #ifdef HAVE_NETLINK
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*
  * Handle netlink notification informing a rule add or delete.
  */
@@ -36,6 +40,10 @@ extern int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
  */
 extern int netlink_rules_read(struct zebra_ns *zns);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* HAVE_NETLINK */
 
 #endif /* _ZEBRA_RULE_NETLINK_H */
index 5196162c4c549e2c6cfc9fd93a5a75f6863317f9..4f78f5097e635c7c775b24cdd1988e73cedca857 100644 (file)
 
 #include "zebra/zserv.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*
  * Table chunk struct
  * Client daemon which the chunk belongs to can be identified by either
@@ -63,4 +67,8 @@ int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
 int release_daemon_table_chunks(struct zserv *client);
 void table_manager_disable(ns_id_t ns_id);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _TABLE_MANAGER_H */
index 9f2bbcf426c68a1ba59e3663e0be5710d4a0b182..2eeb1f278809cb279fe9061d052f015b149cd3f8 100644 (file)
@@ -1036,6 +1036,8 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
        uint8_t flags = 0;
        uint16_t type = cmd2type[hdr->command];
        bool exist;
+       bool flag_changed = false;
+       uint8_t orig_flags;
 
        if (IS_ZEBRA_DEBUG_NHT)
                zlog_debug(
@@ -1084,6 +1086,7 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
                if (!rnh)
                        return;
 
+               orig_flags = rnh->flags;
                if (type == RNH_NEXTHOP_TYPE) {
                        if (flags
                            && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
@@ -1101,9 +1104,12 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
                                UNSET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH);
                }
 
+               if (orig_flags != rnh->flags)
+                       flag_changed = true;
+
                zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf));
                /* Anything not AF_INET/INET6 has been filtered out above */
-               if (!exist)
+               if (!exist || flag_changed)
                        zebra_evaluate_rnh(zvrf, family2afi(p.family), 1, type,
                                           &p);
        }
@@ -1456,8 +1462,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
                                       &(api_nh->gate.ipv4),
                                       sizeof(struct in_addr));
                                zebra_vxlan_evpn_vrf_route_add(
-                                       vrf_id, &api_nh->rmac, &vtep_ip,
-                                       &api.prefix);
+                                       api_nh->vrf_id, &api_nh->rmac,
+                                       &vtep_ip, &api.prefix);
                        }
                        break;
                case NEXTHOP_TYPE_IPV6:
@@ -1479,8 +1485,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
                                memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6),
                                       sizeof(struct in6_addr));
                                zebra_vxlan_evpn_vrf_route_add(
-                                       vrf_id, &api_nh->rmac, &vtep_ip,
-                                       &api.prefix);
+                                       api_nh->vrf_id, &api_nh->rmac,
+                                       &vtep_ip, &api.prefix);
                        }
                        break;
                case NEXTHOP_TYPE_BLACKHOLE:
index b770b8e8810c1fab0028c4080ac60deb7c07ead4..d30fa2d0ef1586a725da5309b3241748e42a6467 100644 (file)
 #include "zebra/zebra_pbr.h"
 #include "zebra/zebra_errors.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*
  * This is called to process inbound ZAPI messages.
  *
@@ -86,3 +90,7 @@ extern void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
                                   const unsigned int nexthop_num);
 
 extern void zsend_capabilities_all_clients(void);
+
+#ifdef __cplusplus
+}
+#endif
index 894914e57645defcf1100ea9fe12277348f74a1d..df26a8534cc95f6a67567806f043f170a07f7568 100644 (file)
@@ -111,10 +111,13 @@ struct dplane_pw_info {
        int af;
        int status;
        uint32_t flags;
-       union g_addr nexthop;
+       union g_addr dest;
        mpls_label_t local_label;
        mpls_label_t remote_label;
 
+       /* Nexthops */
+       struct nexthop_group nhg;
+
        union pw_protocol_fields fields;
 };
 
@@ -386,6 +389,15 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
 
        case DPLANE_OP_PW_INSTALL:
        case DPLANE_OP_PW_UNINSTALL:
+               /* Free allocated nexthops */
+               if ((*pctx)->u.pw.nhg.nexthop) {
+                       /* This deals with recursive nexthops too */
+                       nexthops_free((*pctx)->u.pw.nhg.nexthop);
+
+                       (*pctx)->u.pw.nhg.nexthop = NULL;
+               }
+               break;
+
        case DPLANE_OP_NONE:
                break;
        }
@@ -744,14 +756,15 @@ uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx)
        return ctx->u.lsp.flags;
 }
 
-zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx)
+const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
 
        return ctx->u.lsp.nhlfe_list;
 }
 
-zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx)
+const zebra_nhlfe_t *
+dplane_ctx_get_best_nhlfe(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
 
@@ -814,12 +827,12 @@ int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx)
        return ctx->u.pw.status;
 }
 
-const union g_addr *dplane_ctx_get_pw_nexthop(
+const union g_addr *dplane_ctx_get_pw_dest(
        const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
 
-       return &(ctx->u.pw.nexthop);
+       return &(ctx->u.pw.dest);
 }
 
 const union pw_protocol_fields *dplane_ctx_get_pw_proto(
@@ -830,6 +843,14 @@ const union pw_protocol_fields *dplane_ctx_get_pw_proto(
        return &(ctx->u.pw.fields);
 }
 
+const struct nexthop_group *
+dplane_ctx_get_pw_nhg(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return &(ctx->u.pw.nhg);
+}
+
 /*
  * End of dplane context accessors
  */
@@ -1039,6 +1060,12 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
                              enum dplane_op_e op,
                              struct zebra_pw *pw)
 {
+       struct prefix p;
+       afi_t afi;
+       struct route_table *table;
+       struct route_node *rn;
+       struct route_entry *re;
+
        if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
                zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u",
                           dplane_op2str(op), pw->ifname, pw->local_label,
@@ -1056,6 +1083,7 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
 
        /* This name appears to be c-string, so we use string copy. */
        strlcpy(ctx->u.pw.ifname, pw->ifname, sizeof(ctx->u.pw.ifname));
+
        ctx->zd_vrf_id = pw->vrf_id;
        ctx->u.pw.ifindex = pw->ifindex;
        ctx->u.pw.type = pw->type;
@@ -1064,10 +1092,37 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
        ctx->u.pw.remote_label = pw->remote_label;
        ctx->u.pw.flags = pw->flags;
 
-       ctx->u.pw.nexthop = pw->nexthop;
+       ctx->u.pw.dest = pw->nexthop;
 
        ctx->u.pw.fields = pw->data;
 
+       /* Capture nexthop info for the pw destination. We need to look
+        * up and use zebra datastructs, but we're running in the zebra
+        * pthread here so that should be ok.
+        */
+       memcpy(&p.u, &pw->nexthop, sizeof(pw->nexthop));
+       p.family = pw->af;
+       p.prefixlen = ((pw->af == AF_INET) ?
+                      IPV4_MAX_PREFIXLEN : IPV6_MAX_PREFIXLEN);
+
+       afi = (pw->af == AF_INET) ? AFI_IP : AFI_IP6;
+       table = zebra_vrf_table(afi, SAFI_UNICAST, pw->vrf_id);
+       if (table) {
+               rn = route_node_match(table, &p);
+               if (rn) {
+                       RNODE_FOREACH_RE(rn, re) {
+                               if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
+                                       break;
+                       }
+
+                       if (re)
+                               copy_nexthops(&(ctx->u.pw.nhg.nexthop),
+                                             re->ng.nexthop, NULL);
+
+                       route_unlock_node(rn);
+               }
+       }
+
        return AOK;
 }
 
index 81226961e85d97c6e95157576f409b222c6994df..1246fcc8ec1d9d25920b4d0d5afd197b0f008463 100644 (file)
 #include "zebra/zserv.h"
 #include "zebra/zebra_mpls.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Key netlink info from zebra ns */
 struct zebra_dplane_info {
        ns_id_t ns_id;
@@ -203,8 +207,9 @@ const struct nexthop_group *dplane_ctx_get_old_ng(
 mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx);
 uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx);
 uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx);
-zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx);
-zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx);
+const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const struct zebra_dplane_ctx *ctx);
+const zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(
+       const struct zebra_dplane_ctx *ctx);
 uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx);
 
 /* Accessors for pseudowire information */
@@ -215,10 +220,12 @@ int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx);
 int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx);
 uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx);
 int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx);
-const union g_addr *dplane_ctx_get_pw_nexthop(
+const union g_addr *dplane_ctx_get_pw_dest(
        const struct zebra_dplane_ctx *ctx);
 const union pw_protocol_fields *dplane_ctx_get_pw_proto(
        const struct zebra_dplane_ctx *ctx);
+const struct nexthop_group *dplane_ctx_get_pw_nhg(
+       const struct zebra_dplane_ctx *ctx);
 
 /* Namespace info - esp. for netlink communication */
 const struct zebra_dplane_info *dplane_ctx_get_ns(
@@ -391,4 +398,8 @@ void zebra_dplane_pre_finish(void);
 void zebra_dplane_finish(void);
 void zebra_dplane_shutdown(void);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_DPLANE_H */
index 0af5f8a5514ac57a7662590c50d40a82d2dc1f9e..2b7831a408277720de3eb416098569bd61eb1d4b 100644 (file)
 
 #include "lib/ferr.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 enum zebra_log_refs {
        EC_ZEBRA_LM_RESPONSE = ZEBRA_FERR_START,
        EC_ZEBRA_LM_NO_SUCH_CLIENT,
@@ -126,4 +130,8 @@ enum zebra_log_refs {
 
 void zebra_error_init(void);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __EC_ZEBRAORS_H__ */
index 969ab6cfee3b01f65812b893348c8442e00b5482..943aad98642c754537e5c2db2530d993fc6769ba 100644 (file)
 
 #include "zebra/debug.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
 
 #define zfpm_debug(...)                                                        \
@@ -61,4 +65,9 @@ extern int zfpm_protobuf_encode_route(rib_dest_t *dest, struct route_entry *re,
                                      uint8_t *in_buf, size_t in_buf_len);
 
 extern struct route_entry *zfpm_route_for_update(rib_dest_t *dest);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_FPM_PRIVATE_H */
index 68c9d4a7a1a72bbf072da5a105aabd4a04eb2179..2e3e5b4a855b82a9903052b5760e5f14b3e268b9 100644 (file)
 #include "vlan.h"
 #include "vxlan.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* zebra L2 interface information - bridge slave (linkage to bridge) */
 struct zebra_l2info_brslave {
        ifindex_t bridge_ifindex; /* Bridge Master */
@@ -96,4 +100,9 @@ extern void zebra_l2if_update_bridge_slave(struct interface *ifp,
 
 extern void zebra_l2if_update_bond_slave(struct interface *ifp,
                                         ifindex_t bond_ifindex);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_L2_H */
index de55478de2fc841d59b810063e0a83d8f31de1d4..667c73b2270fd348ef6bf8886dc31085c3e0c05c 100644 (file)
 
 #include "memory.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 DECLARE_MGROUP(ZEBRA)
 DECLARE_MTYPE(RTADV_PREFIX)
 DECLARE_MTYPE(ZEBRA_NS)
@@ -37,4 +41,8 @@ DECLARE_MTYPE(RNH)
 DECLARE_MTYPE(DP_CTX)
 DECLARE_MTYPE(DP_PROV)
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _QUAGGA_ZEBRA_MEMORY_H */
index c5c147c833e3d592be179ec4148d3ef70e651d63..90a5a41fa4f2b2a3346d2ea00c8538534b170553 100644 (file)
 
 #include "mlag.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 void zebra_mlag_init(void);
 void zebra_mlag_terminate(void);
 
 enum mlag_role zebra_mlag_get_role(void);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index 39f084ad2f7bbee121a52f265faca0d19efb208c..3a131e1aaf1224ca637ef7573e1f4370c69ebbfd 100644 (file)
@@ -34,6 +34,9 @@
 #include "zebra/zserv.h"
 #include "zebra/zebra_vrf.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 /* Definitions and macros. */
 
@@ -507,31 +510,48 @@ static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type)
        return "Unknown";
 }
 
-static inline void mpls_mark_lsps_for_processing(struct zebra_vrf *zvrf)
+static inline void mpls_mark_lsps_for_processing(struct zebra_vrf *zvrf,
+                                                struct prefix *p)
 {
+       struct route_table *table;
+       struct route_node *rn;
+       rib_dest_t *dest;
+
        if (!zvrf)
                return;
 
-       zvrf->mpls_flags |= MPLS_FLAG_SCHEDULE_LSPS;
+       table = zvrf->table[family2afi(p->family)][SAFI_UNICAST];
+       if (!table)
+               return;
+
+       rn = route_node_match(table, p);
+       if (!rn)
+               return;
+
+
+       dest = rib_dest_from_rnode(rn);
+       SET_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS);
 }
 
-static inline void mpls_unmark_lsps_for_processing(struct zebra_vrf *zvrf)
+static inline void mpls_unmark_lsps_for_processing(struct route_node *rn)
 {
-       if (!zvrf)
-               return;
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
 
-       zvrf->mpls_flags &= ~MPLS_FLAG_SCHEDULE_LSPS;
+       UNSET_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS);
 }
 
-static inline int mpls_should_lsps_be_processed(struct zebra_vrf *zvrf)
+static inline int mpls_should_lsps_be_processed(struct route_node *rn)
 {
-       if (!zvrf)
-               return 0;
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
 
-       return ((zvrf->mpls_flags & MPLS_FLAG_SCHEDULE_LSPS) ? 1 : 0);
+       return !!CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS);
 }
 
 /* Global variables. */
 extern int mpls_enabled;
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /*_ZEBRA_MPLS_H */
index ade36cbce4e1c60fb00db1023df26267ad378e1c..977a8eaf3c7711d7a3c9b464f1d70c909d33cbc7 100644 (file)
@@ -43,7 +43,7 @@ struct {
 } kr_state;
 
 static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label,
-                               zebra_nhlfe_t *nhlfe)
+                               const zebra_nhlfe_t *nhlfe)
 {
        struct iovec iov[5];
        struct rt_msghdr hdr;
@@ -135,7 +135,7 @@ static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label,
 #endif
 
 static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label,
-                               zebra_nhlfe_t *nhlfe)
+                               const zebra_nhlfe_t *nhlfe)
 {
        struct iovec iov[5];
        struct rt_msghdr hdr;
@@ -238,7 +238,7 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label,
 
 static int kernel_lsp_cmd(struct zebra_dplane_ctx *ctx)
 {
-       zebra_nhlfe_t *nhlfe;
+       const zebra_nhlfe_t *nhlfe;
        struct nexthop *nexthop = NULL;
        unsigned int nexthop_num = 0;
        int action;
@@ -342,7 +342,7 @@ static enum zebra_dplane_result kmpw_install(struct zebra_dplane_ctx *ctx)
 
        /* pseudowire nexthop */
        memset(&ss, 0, sizeof(ss));
-       gaddr = dplane_ctx_get_pw_nexthop(ctx);
+       gaddr = dplane_ctx_get_pw_dest(ctx);
        switch (dplane_ctx_get_pw_af(ctx)) {
        case AF_INET:
                sa_in->sin_family = AF_INET;
index 33851536005faa3dc64b013ae5dc48840c8b985d..3c12b82da3ed2380bd279304522430d043513127 100644 (file)
 
 #include "zebra/zserv.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct mcast_route_data {
        struct prefix_sg sg;
        unsigned int ifindex;
@@ -32,4 +36,8 @@ struct mcast_route_data {
 
 void zebra_ipmr_route_stats(ZAPI_HANDLER_ARGS);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index d6530e6694877d7bdbf6c0fceadafeff0f58bf67..7a5f6851f481f94cc11eeaeca0c26a1a781b5215 100644 (file)
 #include "zebra.h"
 #include "ns.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern ns_id_t zebra_ns_id_get(const char *netnspath);
 extern ns_id_t zebra_ns_id_get_default(void);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __ZEBRA_NS_ID_H__ */
index 0ced749ae821b63aede0e3ee47309971743f85bd..18939283a70783dc47f1cdb6ac0356a52dcc4f30 100644 (file)
 #ifndef _NETNS_NOTIFY_H
 #define _NETNS_NOTIFY_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern void zebra_ns_notify_init(void);
 extern void zebra_ns_notify_parse(void);
 extern void zebra_ns_notify_close(void);
 
 extern struct zebra_privs_t zserv_privs;
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* NETNS_NOTIFY_H */
index 01af64c17bba2e7ca349adf921d3ccf41232e64c..dc79a83db0d878216b57ac9cde2231871acaccdb 100644 (file)
 #include "zebra/rib.h"
 #include "zebra/zebra_vrf.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifdef HAVE_NETLINK
 /* Socket interface to kernel */
 struct nlsock {
@@ -68,4 +72,8 @@ int zebra_ns_final_shutdown(struct ns *ns);
 
 int zebra_ns_config_write(struct vty *vty, struct ns *ns);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index 5b6c23896c13f5ce5028df14ad1467725dbb6523..0d55491107604c39635939a8475b7affe9b43eaa 100644 (file)
 #include "rt.h"
 #include "pbr.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct zebra_pbr_rule {
        int sock;
 
@@ -252,4 +256,8 @@ DECLARE_HOOK(zebra_pbr_ipset_entry_update,
 DECLARE_HOOK(zebra_pbr_ipset_update,
             (int cmd, struct zebra_pbr_ipset *ipset), (cmd, ipset));
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_PBR_H */
index cc5e38e690df9bf3389790eed6e898cf14440bed..bb352dc2ffd698fb3176500324cbf928b4c7979c 100644 (file)
@@ -328,7 +328,7 @@ DEFUN (zebra_ptm_enable_if,
        if (!old_ptm_enable && ptm_cb.ptm_enable) {
                if (!if_is_operative(ifp) && send_linkdown) {
                        if (IS_ZEBRA_DEBUG_EVENT)
-                               zlog_debug("%s: Bringing down interface %s\n",
+                               zlog_debug("%s: Bringing down interface %s",
                                           __func__, ifp->name);
                        if_down(ifp);
                }
@@ -354,7 +354,7 @@ DEFUN (no_zebra_ptm_enable_if,
                ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF;
                if (if_is_no_ptm_operative(ifp) && send_linkup) {
                        if (IS_ZEBRA_DEBUG_EVENT)
-                               zlog_debug("%s: Bringing up interface %s\n",
+                               zlog_debug("%s: Bringing up interface %s",
                                           __func__, ifp->name);
                        if_up(ifp);
                }
index d0cdaf0bce8781f7409d297a0c041ad43d42a973..e578a02a94a4581330147b1244f20fdb5760b831 100644 (file)
@@ -31,6 +31,10 @@ extern const char ZEBRA_PTM_SOCK_NAME[];
 #include "zebra/zserv.h"
 #include "zebra/interface.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Zebra ptm context block */
 struct zebra_ptm_cb {
        int ptm_sock; /* ptm file descriptor. */
@@ -87,4 +91,9 @@ void zebra_ptm_if_init(struct zebra_if *zebra_ifp);
 void zebra_ptm_if_set_ptm_state(struct interface *ifp,
                                struct zebra_if *zebra_ifp);
 void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index c1b12bd0d18eac9310f4b359245a3114912bf202..4daf405825372f82f6a572c25742a56a1ce61e2b 100644 (file)
 
 #ifndef _ZEBRA_PTM_REDISTRIBUTE_H
 #define _ZEBRA_PTM_REDISTRIBUTE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern void zebra_interface_bfd_update(struct interface *, struct prefix *,
                                       struct prefix *, int, vrf_id_t);
 extern void zebra_bfd_peer_replay_req(void);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_PTM_REDISTRIBUTE_H */
index 9692fb4d40dd8fb6ff746dfe59bebabee17ee634..bbb37767251486b0f5b7df2f0a5350e45d9b4d75 100644 (file)
 
 #include "zebra/zebra_vrf.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define PW_INSTALL_RETRY_INTERVAL      30
 
 struct zebra_pw {
@@ -74,4 +78,8 @@ void zebra_pw_init(struct zebra_vrf *);
 void zebra_pw_exit(struct zebra_vrf *);
 void zebra_pw_vty_init(void);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* ZEBRA_PW_H_ */
index 2014aa3bed13fffccd723e3927bddf68feb35097..557e6876e2ced199605eb30f0921423437bc1f40 100644 (file)
@@ -1175,10 +1175,7 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re)
                if (zebra_rib_labeled_unicast(re))
                        zebra_mpls_lsp_uninstall(info->zvrf, rn, re);
 
-               if (!RIB_SYSTEM_ROUTE(re))
-                       rib_uninstall_kernel(rn, re);
-               else
-                       UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+               rib_uninstall_kernel(rn, re);
 
                dest->selected_fib = NULL;
 
@@ -1207,6 +1204,16 @@ static int rib_can_delete_dest(rib_dest_t *dest)
                return 0;
        }
 
+       /*
+        * Unresolved rnh's are stored on the default route's list
+        *
+        * dest->rnode can also be the source prefix node in an
+        * ipv6 sourcedest table.  Fortunately the prefix of a
+        * source prefix node can never be the default prefix.
+        */
+       if (is_default_prefix(&dest->rnode->p))
+               return 0;
+
        /*
         * Don't delete the dest if we have to update the FPM about this
         * prefix.
@@ -1218,6 +1225,88 @@ static int rib_can_delete_dest(rib_dest_t *dest)
        return 1;
 }
 
+void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq)
+{
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
+       struct listnode *node, *nnode;
+       struct rnh *rnh;
+
+       /*
+        * We are storing the rnh's associated withb
+        * the tracked nexthop as a list of the rn's.
+        * Unresolved rnh's are placed at the top
+        * of the tree list.( 0.0.0.0/0 for v4 and 0::0/0 for v6 )
+        * As such for each rn we need to walk up the tree
+        * and see if any rnh's need to see if they
+        * would match a more specific route
+        */
+       while (rn) {
+               if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+                       char buf[PREFIX_STRLEN];
+
+                       zlog_debug("%s: %s Being examined for Nexthop Tracking",
+                                  __PRETTY_FUNCTION__,
+                                  srcdest_rnode2str(rn, buf, sizeof(buf)));
+               }
+               if (!dest) {
+                       rn = rn->parent;
+                       if (rn)
+                               dest = rib_dest_from_rnode(rn);
+                       continue;
+               }
+               /*
+                * If we have any rnh's stored in the nht list
+                * then we know that this route node was used for
+                * nht resolution and as such we need to call the
+                * nexthop tracking evaluation code
+                */
+               for (ALL_LIST_ELEMENTS(dest->nht, node, nnode, rnh)) {
+                       struct zebra_vrf *zvrf =
+                               zebra_vrf_lookup_by_id(rnh->vrf_id);
+                       struct prefix *p = &rnh->node->p;
+
+                       if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+                               char buf1[PREFIX_STRLEN];
+                               char buf2[PREFIX_STRLEN];
+
+                               zlog_debug("%u:%s has Nexthop(%s) depending on it, evaluating %u:%u",
+                                          zvrf->vrf->vrf_id,
+                                          srcdest_rnode2str(rn, buf1,
+                                                     sizeof(buf1)),
+                                          prefix2str(p, buf2, sizeof(buf2)),
+                                          seq, rnh->seqno);
+                       }
+
+                       /*
+                        * If we have evaluated this node on this pass
+                        * already, due to following the tree up
+                        * then we know that we can move onto the next
+                        * rnh to process.
+                        *
+                        * Additionally we call zebra_evaluate_rnh
+                        * when we gc the dest.  In this case we know
+                        * that there must be no other re's where
+                        * we were originally as such we know that
+                        * that sequence number is ok to respect.
+                        */
+                       if (rnh->seqno == seq) {
+                               if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+                                       zlog_debug(
+                                               "\tNode processed and moved already");
+                               continue;
+                       }
+
+                       rnh->seqno = seq;
+                       zebra_evaluate_rnh(zvrf, family2afi(p->family), 0,
+                                          rnh->type, p);
+               }
+
+               rn = rn->parent;
+               if (rn)
+                       dest = rib_dest_from_rnode(rn);
+       }
+}
+
 /*
  * rib_gc_dest
  *
@@ -1244,7 +1333,10 @@ int rib_gc_dest(struct route_node *rn)
                rnode_debug(rn, zvrf_id(zvrf), "removing dest from table");
        }
 
+       zebra_rib_evaluate_rn_nexthops(rn, zebra_router_get_next_sequence());
+
        dest->rnode = NULL;
+       list_delete(&dest->nht);
        XFREE(MTYPE_RIB_DEST, dest);
        rn->info = NULL;
 
@@ -1258,8 +1350,6 @@ int rib_gc_dest(struct route_node *rn)
 static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                                struct route_entry *new)
 {
-       rib_dest_t *dest = rib_dest_from_rnode(rn);
-
        hook_call(rib_update, rn, "new route selected");
 
        /* Update real nexthop. This may actually determine if nexthop is active
@@ -1281,10 +1371,7 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
        if (zebra_rib_labeled_unicast(new))
                zebra_mpls_lsp_install(zvrf, rn, new);
 
-       if (!RIB_SYSTEM_ROUTE(new))
-               rib_install_kernel(rn, new, NULL);
-       else
-               dest->selected_fib = new;
+       rib_install_kernel(rn, new, NULL);
 
        UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED);
 }
@@ -1292,7 +1379,6 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
 static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                                struct route_entry *old)
 {
-       rib_dest_t *dest = rib_dest_from_rnode(rn);
        hook_call(rib_update, rn, "removing existing route");
 
        /* Uninstall from kernel. */
@@ -1308,20 +1394,7 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
        if (zebra_rib_labeled_unicast(old))
                zebra_mpls_lsp_uninstall(zvrf, rn, old);
 
-       if (!RIB_SYSTEM_ROUTE(old))
-               rib_uninstall_kernel(rn, old);
-       else {
-               UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED);
-               /*
-                * We are setting this to NULL here
-                * because that is what we traditionally
-                * have been doing.  I am not positive
-                * that this is the right thing to do
-                * but let's leave the code alone
-                * for the RIB_SYSTEM_ROUTE case
-                */
-               dest->selected_fib = NULL;
-       }
+       rib_uninstall_kernel(rn, old);
 
        /* Update nexthop for route, reset changed flag. */
        /* Note: this code also handles the Linux case when an interface goes
@@ -1340,9 +1413,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
                                   struct route_entry *old,
                                   struct route_entry *new)
 {
-       struct nexthop *nexthop = NULL;
        int nh_active = 0;
-       rib_dest_t *dest = rib_dest_from_rnode(rn);
 
        /*
         * We have to install or update if a new route has been selected or
@@ -1384,48 +1455,15 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
                        if (zebra_rib_labeled_unicast(old))
                                zebra_mpls_lsp_uninstall(zvrf, rn, old);
 
-                       /* Non-system route should be installed. */
-                       if (!RIB_SYSTEM_ROUTE(new)) {
-                               /* If labeled-unicast route, install transit
-                                * LSP. */
-                               if (zebra_rib_labeled_unicast(new))
-                                       zebra_mpls_lsp_install(zvrf, rn, new);
+                       /*
+                        * Non-system route should be installed.
+                        * If labeled-unicast route, install transit
+                        * LSP.
+                        */
+                       if (zebra_rib_labeled_unicast(new))
+                               zebra_mpls_lsp_install(zvrf, rn, new);
 
-                               rib_install_kernel(rn, new, old);
-                       } else {
-                               UNSET_FLAG(new->status, ROUTE_ENTRY_INSTALLED);
-                               /*
-                                * We do not need to install the
-                                * selected route because it
-                                * is already isntalled by
-                                * the system( ie not us )
-                                * so just mark it as winning
-                                * we do need to ensure that
-                                * if we uninstall a route
-                                * from ourselves we don't
-                                * over write this pointer
-                                */
-                               dest->selected_fib = NULL;
-                       }
-                       /* If install succeeded or system route, cleanup flags
-                        * for prior route. */
-                       if (new != old) {
-                               if (RIB_SYSTEM_ROUTE(new)) {
-                                       if (!RIB_SYSTEM_ROUTE(old))
-                                               rib_uninstall_kernel(rn, old);
-                                       else
-                                               UNSET_FLAG(
-                                                       old->status,
-                                                       ROUTE_ENTRY_INSTALLED);
-                               } else {
-                                       UNSET_FLAG(old->status,
-                                                  ROUTE_ENTRY_INSTALLED);
-                                       for (nexthop = old->ng.nexthop; nexthop;
-                                            nexthop = nexthop->next)
-                                               UNSET_FLAG(nexthop->flags,
-                                                          NEXTHOP_FLAG_FIB);
-                               }
-                       }
+                       rib_install_kernel(rn, new, old);
                }
 
                /*
@@ -1455,25 +1493,18 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
                        if (zebra_rib_labeled_unicast(old))
                                zebra_mpls_lsp_uninstall(zvrf, rn, old);
 
-                       if (!RIB_SYSTEM_ROUTE(old))
-                               rib_uninstall_kernel(rn, old);
-                       else {
-                               UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED);
-                               dest->selected_fib = NULL;
-                       }
+                       rib_uninstall_kernel(rn, old);
                }
        } else {
                /*
                 * Same route selected; check if in the FIB and if not,
-                * re-install. This
-                * is housekeeping code to deal with race conditions in kernel
-                * with linux
-                * netlink reporting interface up before IPv4 or IPv6 protocol
-                * is ready
+                * re-install. This is housekeeping code to deal with
+                * race conditions in kernel with linux netlink reporting
+                * interface up before IPv4 or IPv6 protocol is ready
                 * to add routes.
                 */
-               if (!RIB_SYSTEM_ROUTE(new)
-                   && !CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED))
+               if (!CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED) ||
+                   RIB_SYSTEM_ROUTE(new))
                        rib_install_kernel(rn, new, NULL);
        }
 
@@ -1725,18 +1756,9 @@ static void rib_process(struct route_node *rn)
                        UNSET_FLAG(new_selected->status, ROUTE_ENTRY_CHANGED);
                }
 
-               if (new_selected) {
+               if (new_selected)
                        SET_FLAG(new_selected->flags, ZEBRA_FLAG_SELECTED);
 
-                       /* Special case: new route is system route, so
-                        * dataplane update will not be done - ensure we
-                        * redistribute the route.
-                        */
-                       if (RIB_SYSTEM_ROUTE(new_selected))
-                               redistribute_update(p, src_p, new_selected,
-                                                   old_selected);
-               }
-
                if (old_selected) {
                        if (!new_selected)
                                redistribute_delete(p, src_p, old_selected);
@@ -1763,6 +1785,24 @@ static void rib_process(struct route_node *rn)
        rib_gc_dest(rn);
 }
 
+static void zebra_rib_evaluate_mpls(struct route_node *rn)
+{
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
+       struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
+
+       if (!dest)
+               return;
+
+       if (CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS)) {
+               if (IS_ZEBRA_DEBUG_MPLS)
+                       zlog_debug(
+                               "%u: Scheduling all LSPs upon RIB completion",
+                               zvrf_id(zvrf));
+               zebra_mpls_lsp_schedule(zvrf);
+               mpls_unmark_lsps_for_processing(rn);
+       }
+}
+
 /*
  * Utility to match route with dplane context data
  */
@@ -1821,6 +1861,30 @@ done:
        return (result);
 }
 
+static void zebra_rib_fixup_system(struct route_node *rn)
+{
+       struct route_entry *re;
+
+       RNODE_FOREACH_RE(rn, re) {
+               struct nexthop *nhop;
+
+               if (!RIB_SYSTEM_ROUTE(re))
+                       continue;
+
+               if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
+                       continue;
+
+               SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+
+               for (ALL_NEXTHOPS(re->ng, nhop)) {
+                       if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE))
+                               continue;
+
+                       SET_FLAG(nhop->flags, NEXTHOP_FLAG_FIB);
+               }
+       }
+}
+
 /*
  * Route-update results processing after async dataplane update.
  */
@@ -1836,6 +1900,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
        enum dplane_op_e op;
        enum zebra_dplane_result status;
        const struct prefix *dest_pfx, *src_pfx;
+       uint32_t seq;
 
        /* Locate rn and re(s) from ctx */
 
@@ -1912,11 +1977,13 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                        break;
        }
 
+       seq = dplane_ctx_get_seq(ctx);
+
        /*
         * Check sequence number(s) to detect stale results before continuing
         */
        if (re) {
-               if (re->dplane_sequence != dplane_ctx_get_seq(ctx)) {
+               if (re->dplane_sequence != seq) {
                        if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
                                zlog_debug("%u:%s Stale dplane result for re %p",
                                           dplane_ctx_get_vrf(ctx),
@@ -1932,7 +1999,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                                           dplane_ctx_get_vrf(ctx),
                                           dest_str, old_re);
                } else
-                       UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+                       UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED);
        }
 
        switch (op) {
@@ -1987,6 +2054,17 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                                                   NEXTHOP_FLAG_FIB);
                        }
 
+                       /*
+                        * System routes are weird in that they
+                        * allow multiple to be installed that match
+                        * to the same prefix, so after we get the
+                        * result we need to clean them up so that
+                        * we can actually use them.
+                        */
+                       if ((re && RIB_SYSTEM_ROUTE(re)) ||
+                           (old_re && RIB_SYSTEM_ROUTE(old_re)))
+                               zebra_rib_fixup_system(rn);
+
                        if (zvrf) {
                                zvrf->installs++;
                                /* Set flag for nexthop tracking processing */
@@ -2010,9 +2088,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                        zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED);
 
                } else {
-                       if (re)
+                       if (re) {
                                SET_FLAG(re->status, ROUTE_ENTRY_FAILED);
-                       if (old_re)
+                               UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+                       } if (old_re)
                                SET_FLAG(old_re->status, ROUTE_ENTRY_FAILED);
                        if (re)
                                zsend_route_notify_owner(re, dest_pfx,
@@ -2052,10 +2131,24 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                                  prefix2str(dest_pfx,
                                             dest_str, sizeof(dest_str)));
                }
+
+               /*
+                * System routes are weird in that they
+                * allow multiple to be installed that match
+                * to the same prefix, so after we get the
+                * result we need to clean them up so that
+                * we can actually use them.
+                */
+               if ((re && RIB_SYSTEM_ROUTE(re)) ||
+                   (old_re && RIB_SYSTEM_ROUTE(old_re)))
+                       zebra_rib_fixup_system(rn);
                break;
        default:
                break;
        }
+
+       zebra_rib_evaluate_rn_nexthops(rn, seq);
+       zebra_rib_evaluate_mpls(rn);
 done:
 
        if (rn)
@@ -2110,47 +2203,12 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex)
        return 1;
 }
 
+
 /*
  * Perform next-hop tracking processing after RIB updates.
  */
 static void do_nht_processing(void)
 {
-       struct vrf *vrf;
-       struct zebra_vrf *zvrf;
-
-       /* Evaluate nexthops for those VRFs which underwent route processing.
-        * This
-        * should limit the evaluation to the necessary VRFs in most common
-        * situations.
-        */
-       RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
-               zvrf = vrf->info;
-               if (zvrf == NULL || !(zvrf->flags & ZEBRA_VRF_RIB_SCHEDULED))
-                       continue;
-
-               if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHT)
-                       zlog_debug("NHT processing check for zvrf %s",
-                                  zvrf_name(zvrf));
-
-               zvrf->flags &= ~ZEBRA_VRF_RIB_SCHEDULED;
-               zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL);
-               zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_IMPORT_CHECK_TYPE,
-                                  NULL);
-               zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL);
-               zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_IMPORT_CHECK_TYPE,
-                                  NULL);
-       }
-
-       /* Schedule LSPs for processing, if needed. */
-       zvrf = vrf_info_lookup(VRF_DEFAULT);
-       if (mpls_should_lsps_be_processed(zvrf)) {
-               if (IS_ZEBRA_DEBUG_MPLS)
-                       zlog_debug(
-                               "%u: Scheduling all LSPs upon RIB completion",
-                               zvrf_id(zvrf));
-               zebra_mpls_lsp_schedule(zvrf);
-               mpls_unmark_lsps_for_processing(zvrf);
-       }
 }
 
 /* Dispatch the meta queue by picking, processing and unlocking the next RN from
@@ -2340,6 +2398,19 @@ static void rib_queue_init(void)
        return;
 }
 
+rib_dest_t *zebra_rib_create_dest(struct route_node *rn)
+{
+       rib_dest_t *dest;
+
+       dest = XCALLOC(MTYPE_RIB_DEST, sizeof(rib_dest_t));
+       dest->nht = list_new();
+       route_lock_node(rn); /* rn route table reference */
+       rn->info = dest;
+       dest->rnode = rn;
+
+       return dest;
+}
+
 /* RIB updates are processed via a queue of pointers to route_nodes.
  *
  * The queue length is bounded by the maximal size of the routing table,
@@ -2392,10 +2463,7 @@ static void rib_link(struct route_node *rn, struct route_entry *re, int process)
                if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                        rnode_debug(rn, re->vrf_id, "rn %p adding dest", rn);
 
-               dest = XCALLOC(MTYPE_RIB_DEST, sizeof(rib_dest_t));
-               route_lock_node(rn); /* rn route table reference */
-               rn->info = dest;
-               dest->rnode = rn;
+               dest = zebra_rib_create_dest(rn);
        }
 
        head = dest->routes;
@@ -2654,7 +2722,7 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id)
         * revalidation
         * of the rest of the RE.
         */
-       if (dest->selected_fib && !RIB_SYSTEM_ROUTE(dest->selected_fib)) {
+       if (dest->selected_fib) {
                changed = 1;
                if (IS_ZEBRA_DEBUG_RIB) {
                        char buf[PREFIX_STRLEN];
@@ -2676,7 +2744,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
        struct route_table *table;
        struct route_node *rn;
        struct route_entry *same = NULL;
-       struct nexthop *nexthop;
        int ret = 0;
 
        if (!re)
@@ -2740,13 +2807,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
                        break;
        }
 
-       /* If this route is kernel route, set FIB flag to the route. */
-       if (RIB_SYSTEM_ROUTE(re)) {
-               SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
-               for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
-                       SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
-       }
-
        /* Link new re to node.*/
        if (IS_ZEBRA_DEBUG_RIB) {
                rnode_debug(rn, re->vrf_id,
@@ -3222,10 +3282,8 @@ void rib_close_table(struct route_table *table)
                        if (info->safi == SAFI_UNICAST)
                                hook_call(rib_update, rn, NULL);
 
-                       if (!RIB_SYSTEM_ROUTE(dest->selected_fib)) {
-                               rib_uninstall_kernel(rn, dest->selected_fib);
-                               dest->selected_fib = NULL;
-                       }
+                       rib_uninstall_kernel(rn, dest->selected_fib);
+                       dest->selected_fib = NULL;
                }
        }
 }
index 52637c6062d01ee4679cb17ec3f198f1bdf34f66..a1519e45cd6d7415471430a5d7ca5fdb7365d812 100644 (file)
@@ -94,6 +94,61 @@ char *rnh_str(struct rnh *rnh, char *buf, int size)
        return buf;
 }
 
+static void zebra_rnh_remove_from_routing_table(struct rnh *rnh)
+{
+       struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id);
+       struct route_table *table = zvrf->table[rnh->afi][SAFI_UNICAST];
+       struct route_node *rn;
+       rib_dest_t *dest;
+
+       if (!table)
+               return;
+
+       rn = route_node_match(table, &rnh->resolved_route);
+       if (!rn)
+               return;
+
+       if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+               char buf[PREFIX_STRLEN];
+               char buf1[PREFIX_STRLEN];
+
+               zlog_debug("%s: %u:%s removed from tracking on %s",
+                          __PRETTY_FUNCTION__, rnh->vrf_id,
+                          prefix2str(&rnh->node->p, buf, sizeof(buf)),
+                          srcdest_rnode2str(rn, buf1, sizeof(buf)));
+       }
+
+       dest = rib_dest_from_rnode(rn);
+       listnode_delete(dest->nht, rnh);
+       route_unlock_node(rn);
+}
+
+static void zebra_rnh_store_in_routing_table(struct rnh *rnh)
+{
+       struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id);
+       struct route_table *table = zvrf->table[rnh->afi][SAFI_UNICAST];
+       struct route_node *rn;
+       rib_dest_t *dest;
+
+       rn = route_node_match(table, &rnh->resolved_route);
+       if (!rn)
+               return;
+
+       if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+               char buf[PREFIX_STRLEN];
+               char buf1[PREFIX_STRLEN];
+
+               zlog_debug("%s: %u:%s added for tracking on %s",
+                          __PRETTY_FUNCTION__, rnh->vrf_id,
+                          prefix2str(&rnh->node->p, buf, sizeof(buf)),
+                          srcdest_rnode2str(rn, buf1, sizeof(buf)));
+       }
+
+       dest = rib_dest_from_rnode(rn);
+       listnode_add(dest->nht, rnh);
+       route_unlock_node(rn);
+}
+
 struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
                          bool *exists)
 {
@@ -101,12 +156,13 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
        struct route_node *rn;
        struct rnh *rnh = NULL;
        char buf[PREFIX2STR_BUFFER];
+       afi_t afi = family2afi(p->family);
 
        if (IS_ZEBRA_DEBUG_NHT) {
                prefix2str(p, buf, sizeof(buf));
                zlog_debug("%u: Add RNH %s type %d", vrfid, buf, type);
        }
-       table = get_rnh_table(vrfid, family2afi(PREFIX_FAMILY(p)), type);
+       table = get_rnh_table(vrfid, afi, type);
        if (!table) {
                prefix2str(p, buf, sizeof(buf));
                flog_warn(EC_ZEBRA_RNH_NO_TABLE,
@@ -124,13 +180,26 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
 
        if (!rn->info) {
                rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
+
+               /*
+                * The resolved route is already 0.0.0.0/0 or
+                * 0::0/0 due to the calloc right above, but
+                * we should set the family so that future
+                * comparisons can just be done
+                */
+               rnh->resolved_route.family = p->family;
                rnh->client_list = list_new();
                rnh->vrf_id = vrfid;
+               rnh->type = type;
+               rnh->seqno = 0;
+               rnh->afi = afi;
                rnh->zebra_pseudowire_list = list_new();
                route_lock_node(rn);
                rn->info = rnh;
                rnh->node = rn;
                *exists = false;
+
+               zebra_rnh_store_in_routing_table(rnh);
        } else
                *exists = true;
 
@@ -161,9 +230,30 @@ struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
 
 void zebra_free_rnh(struct rnh *rnh)
 {
+       struct zebra_vrf *zvrf;
+       struct route_table *table;
+
+       zebra_rnh_remove_from_routing_table(rnh);
        rnh->flags |= ZEBRA_NHT_DELETED;
        list_delete(&rnh->client_list);
        list_delete(&rnh->zebra_pseudowire_list);
+
+       zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id);
+       table = zvrf->table[family2afi(rnh->resolved_route.family)][SAFI_UNICAST];
+
+       if (table) {
+               struct route_node *rern;
+
+               rern = route_node_match(table, &rnh->resolved_route);
+               if (rern) {
+                       rib_dest_t *dest;
+
+                       route_unlock_node(rern);
+
+                       dest = rib_dest_from_rnode(rern);
+                       listnode_delete(dest->nht, rnh);
+               }
+       }
        free_state(rnh->vrf_id, rnh->state, rnh->node);
        XFREE(MTYPE_RNH, rnh);
 }
@@ -344,6 +434,16 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi,
            && !prefix_same(&nrn->p, &rn->p))
                return NULL;
 
+       if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+               char buf[PREFIX_STRLEN];
+               char buf1[PREFIX_STRLEN];
+
+               zlog_debug("%s: %u:%s Resolved Import Entry to %s",
+                          __PRETTY_FUNCTION__, rnh->vrf_id,
+                          prefix2str(&rnh->node->p, buf, sizeof(buf)),
+                          srcdest_rnode2str(rn, buf1, sizeof(buf)));
+       }
+
        /* Identify appropriate route entry. */
        RNODE_FOREACH_RE (rn, re) {
                if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)
@@ -354,6 +454,10 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi,
 
        if (re)
                *prn = rn;
+
+       if (!re && IS_ZEBRA_DEBUG_NHT_DETAILED)
+               zlog_debug("\tRejected due to removed or is a bgp route");
+
        return re;
 }
 
@@ -361,9 +465,10 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi,
  * See if a tracked route entry for import (by BGP) has undergone any
  * change, and if so, notify the client.
  */
-static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, afi_t afi,
+static void zebra_rnh_eval_import_check_entry(struct zebra_vrf *zvrf, afi_t afi,
                                              int force, struct route_node *nrn,
                                              struct rnh *rnh,
+                                             struct route_node *prn,
                                              struct route_entry *re)
 {
        int state_changed = 0;
@@ -371,25 +476,40 @@ static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, afi_t afi,
        char bufn[INET6_ADDRSTRLEN];
        struct listnode *node;
 
+       zebra_rnh_remove_from_routing_table(rnh);
+       if (prn) {
+               prefix_copy(&rnh->resolved_route, &prn->p);
+       } else {
+               int family = rnh->resolved_route.family;
+
+               memset(&rnh->resolved_route.family, 0, sizeof(struct prefix));
+               rnh->resolved_route.family = family;
+       }
+       zebra_rnh_store_in_routing_table(rnh);
+
        if (re && (rnh->state == NULL)) {
                if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
                        state_changed = 1;
        } else if (!re && (rnh->state != NULL))
                state_changed = 1;
 
-       if (compare_state(re, rnh->state))
+       if (compare_state(re, rnh->state)) {
                copy_state(rnh, re, nrn);
+               state_changed = 1;
+       }
 
        if (state_changed || force) {
                if (IS_ZEBRA_DEBUG_NHT) {
                        prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
-                       zlog_debug("%u:%s: Route import check %s %s\n", vrfid,
+                       zlog_debug("%u:%s: Route import check %s %s",
+                                  zvrf->vrf->vrf_id,
                                   bufn, rnh->state ? "passed" : "failed",
                                   state_changed ? "(state changed)" : "");
                }
                /* state changed, notify clients */
                for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
-                       send_client(rnh, client, RNH_IMPORT_CHECK_TYPE, vrfid);
+                       send_client(rnh, client,
+                                   RNH_IMPORT_CHECK_TYPE, zvrf->vrf->vrf_id);
                }
        }
 }
@@ -412,7 +532,7 @@ static void zebra_rnh_notify_protocol_clients(struct zebra_vrf *zvrf, afi_t afi,
        if (IS_ZEBRA_DEBUG_NHT) {
                prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
                if (prn && re) {
-                       prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
+                       srcdest_rnode2str(prn, bufp, INET6_ADDRSTRLEN);
                        zlog_debug("%u:%s: NH resolved over route %s",
                                   zvrf->vrf->vrf_id, bufn, bufp);
                } else
@@ -545,19 +665,43 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
         * most-specific match. Do similar logic as in zebra_rib.c
         */
        while (rn) {
+               if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
+                       char buf[PREFIX_STRLEN];
+                       char buf1[PREFIX_STRLEN];
+
+                       zlog_debug("%s: %u:%s Possible Match to %s",
+                                  __PRETTY_FUNCTION__, rnh->vrf_id,
+                                  prefix2str(&rnh->node->p, buf, sizeof(buf)),
+                                  srcdest_rnode2str(rn, buf1, sizeof(buf)));
+               }
+
                /* Do not resolve over default route unless allowed &&
                 * 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(rn->p.family)) {
+                       if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+                               zlog_debug(
+                                       "\tNot allowed to resolve through default prefix");
                        return NULL;
+               }
 
                /* Identify appropriate route entry. */
                RNODE_FOREACH_RE (rn, re) {
-                       if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
+                       if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) {
+                               if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+                                       zlog_debug(
+                                               "\tRoute Entry %s removed",
+                                               zebra_route_string(re->type));
                                continue;
-                       if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
+                       }
+                       if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
+                               if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+                                       zlog_debug(
+                                               "\tRoute Entry %s !selected",
+                                               zebra_route_string(re->type));
                                continue;
+                       }
 
                        /* Just being SELECTED isn't quite enough - must
                         * have an installed nexthop to be useful.
@@ -567,8 +711,13 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
                                        break;
                        }
 
-                       if (nexthop == NULL)
+                       if (nexthop == NULL) {
+                               if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+                                       zlog_debug(
+                                               "\tRoute Entry %s no nexthops",
+                                               zebra_route_string(re->type));
                                continue;
+                       }
 
                        if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) {
                                if ((re->type == ZEBRA_ROUTE_CONNECT)
@@ -594,10 +743,14 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
                        return re;
                }
 
-               if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
+               if (!CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
                        rn = rn->parent;
-               else
+               else {
+                       if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+                               zlog_debug(
+                                       "\tNexthop must be connected, cannot recurse up");
                        return NULL;
+               }
        }
 
        return NULL;
@@ -629,11 +782,20 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
         * the resolving route has some change (e.g., metric), there is a state
         * change.
         */
-       if (!prefix_same(&rnh->resolved_route, &prn->p)) {
+       zebra_rnh_remove_from_routing_table(rnh);
+       if (!prefix_same(&rnh->resolved_route, prn ? NULL : &prn->p)) {
                if (prn)
                        prefix_copy(&rnh->resolved_route, &prn->p);
-               else
+               else {
+                       /*
+                        * Just quickly store the family of the resolved
+                        * route so that we can reset it in a second here
+                        */
+                       int family = rnh->resolved_route.family;
+
                        memset(&rnh->resolved_route, 0, sizeof(struct prefix));
+                       rnh->resolved_route.family = family;
+               }
 
                copy_state(rnh, re, nrn);
                state_changed = 1;
@@ -641,6 +803,7 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
                copy_state(rnh, re, nrn);
                state_changed = 1;
        }
+       zebra_rnh_store_in_routing_table(rnh);
 
        if (state_changed || force) {
                /* NOTE: Use the "copy" of resolving route stored in 'rnh' i.e.,
@@ -689,8 +852,8 @@ static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, afi_t afi,
 
        /* Process based on type of entry. */
        if (type == RNH_IMPORT_CHECK_TYPE)
-               zebra_rnh_eval_import_check_entry(zvrf->vrf->vrf_id, afi, force,
-                                                 nrn, rnh, re);
+               zebra_rnh_eval_import_check_entry(zvrf, afi, force, nrn, rnh,
+                                                 prn, re);
        else
                zebra_rnh_eval_nexthop_entry(zvrf, afi, force, nrn, rnh, prn,
                                             re);
@@ -775,7 +938,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty,
 
        table = get_rnh_table(vrfid, afi, type);
        if (!table) {
-               zlog_debug("print_rnhs: rnh table not found\n");
+               zlog_debug("print_rnhs: rnh table not found");
                return;
        }
 
@@ -790,7 +953,6 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty,
 static void free_state(vrf_id_t vrf_id, struct route_entry *re,
                       struct route_node *rn)
 {
-
        if (!re)
                return;
 
@@ -1025,7 +1187,7 @@ static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi,
 
        ntable = get_rnh_table(vrf_id, afi, type);
        if (!ntable) {
-               zlog_debug("cleanup_rnh_client: rnh table not found\n");
+               zlog_debug("cleanup_rnh_client: rnh table not found");
                return -1;
        }
 
index 00ee60dc1a8c7efff632598ef28209abd4523744..7d823c7acc7a4dd652cd26755c7a9815043a04fd 100644 (file)
 #include "prefix.h"
 #include "vty.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t;
+
 /* Nexthop structure. */
 struct rnh {
        uint8_t flags;
@@ -36,6 +42,12 @@ struct rnh {
        /* VRF identifier. */
        vrf_id_t vrf_id;
 
+       afi_t afi;
+
+       rnh_type_t type;
+
+       uint32_t seqno;
+
        struct route_entry *state;
        struct prefix resolved_route;
        struct list *client_list;
@@ -51,8 +63,6 @@ struct rnh {
        int filtered[ZEBRA_ROUTE_MAX];
 };
 
-typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t;
-
 extern int zebra_rnh_ip_default_route;
 extern int zebra_rnh_ipv6_default_route;
 
@@ -83,4 +93,9 @@ extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
 extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty,
                                  rnh_type_t);
 extern char *rnh_str(struct rnh *rnh, char *buf, int size);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /*_ZEBRA_RNH_H */
index abd2ad78f750fc49ba9106ec5612d004c8968428..6a630e1ac089d9b2785e8f67a37e0784b7780bcc 100644 (file)
 
 #include "lib/routemap.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern void zebra_route_map_init(void);
 extern void zebra_routemap_config_write_protocol(struct vty *vty,
                                                 struct zebra_vrf *vrf);
@@ -48,4 +52,8 @@ zebra_nht_route_map_check(afi_t afi, int client_proto, const struct prefix *p,
                          struct zebra_vrf *zvrf, struct route_entry *,
                          struct nexthop *nexthop);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index c3b861c2424b0f16a93c9f90f15bb12bb31ce4ae..9e09cbca3fb546efa986f93e9c4b56be956dd9a0 100644 (file)
@@ -164,14 +164,33 @@ static void zebra_router_free_table(struct zebra_router_table *zrt)
 {
        void *table_info;
 
-       rib_close_table(zrt->table);
-
        table_info = route_table_get_info(zrt->table);
        route_table_finish(zrt->table);
+       RB_REMOVE(zebra_router_table_head, &zrouter.tables, zrt);
+
        XFREE(MTYPE_RIB_TABLE_INFO, table_info);
        XFREE(MTYPE_ZEBRA_NS, zrt);
 }
 
+void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid,
+                               afi_t afi, safi_t safi)
+{
+       struct zebra_router_table finder;
+       struct zebra_router_table *zrt;
+
+       memset(&finder, 0, sizeof(finder));
+       finder.afi = afi;
+       finder.safi = safi;
+       finder.tableid = tableid;
+       finder.ns_id = zvrf->zns->ns_id;
+       zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder);
+
+       if (!zrt)
+               return;
+
+       zebra_router_free_table(zrt);
+}
+
 uint32_t zebra_router_get_next_sequence(void)
 {
        return 1
index a60a0b7be9aeac6d705b111e2e901fd5abe4ae81..72b5e9b9b1e0088c392268f7fe8eb301a2fed031 100644 (file)
 
 #include "zebra/zebra_ns.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*
  * This header file contains the idea of a router and as such
  * owns data that is associated with a router from zebra's
@@ -122,6 +126,8 @@ extern struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf,
 extern struct route_table *zebra_router_get_table(struct zebra_vrf *zvrf,
                                                  uint32_t tableid, afi_t afi,
                                                  safi_t safi);
+extern void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid,
+                                      afi_t afi, safi_t safi);
 
 extern int zebra_router_config_write(struct vty *vty);
 
@@ -142,4 +148,9 @@ static inline struct zebra_vrf *zebra_vrf_get_evpn(void)
        return zrouter.evpn_vrf ? zrouter.evpn_vrf
                                : zebra_vrf_lookup_by_id(VRF_DEFAULT);
 }
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index d42aad0d24fe834e64210e95388cb6df14e0841b..2d721ec8a1a53ca6e8a396e438b0184ace37ceb8 100644 (file)
@@ -167,6 +167,11 @@ static int zebra_vrf_disable(struct vrf *vrf)
 
        /* Remove all routes. */
        for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+               route_table_finish(zvrf->rnh_table[afi]);
+               zvrf->rnh_table[afi] = NULL;
+               route_table_finish(zvrf->import_check_table[afi]);
+               zvrf->import_check_table[afi] = NULL;
+
                for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
                        rib_close_table(zvrf->table[afi][safi]);
        }
@@ -208,13 +213,11 @@ static int zebra_vrf_disable(struct vrf *vrf)
                 * table, see rib_close_table above
                 * we no-longer need this pointer.
                 */
-               for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
+               for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
+                       zebra_router_release_table(zvrf, zvrf->table_id, afi,
+                                                  safi);
                        zvrf->table[afi][safi] = NULL;
-
-               route_table_finish(zvrf->rnh_table[afi]);
-               zvrf->rnh_table[afi] = NULL;
-               route_table_finish(zvrf->import_check_table[afi]);
-               zvrf->import_check_table[afi] = NULL;
+               }
        }
 
        return 0;
@@ -256,19 +259,19 @@ static int zebra_vrf_delete(struct vrf *vrf)
 
        /* release allocated memory */
        for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
-               void *table_info;
-
                for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
                        table = zvrf->table[afi][safi];
                        if (table) {
-                               table_info = route_table_get_info(table);
-                               route_table_finish(table);
-                               XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                               zebra_router_release_table(zvrf, zvrf->table_id,
+                                                          afi, safi);
+                               zvrf->table[afi][safi] = NULL;
                        }
                }
 
-               route_table_finish(zvrf->rnh_table[afi]);
-               route_table_finish(zvrf->import_check_table[afi]);
+               if (zvrf->rnh_table[afi])
+                       route_table_finish(zvrf->rnh_table[afi]);
+               if (zvrf->import_check_table[afi])
+                       route_table_finish(zvrf->import_check_table[afi]);
        }
 
        /* Cleanup EVPN states for vrf */
@@ -351,7 +354,12 @@ void zebra_rtable_node_cleanup(struct route_table *table,
                rib_unlink(node, re);
        }
 
-       XFREE(MTYPE_RIB_DEST, node->info);
+       if (node->info) {
+               rib_dest_t *dest = node->info;
+
+               list_delete(&dest->nht);
+               XFREE(MTYPE_RIB_DEST, node->info);
+       }
 }
 
 static void zebra_rnhtable_node_cleanup(struct route_table *table,
@@ -367,10 +375,19 @@ static void zebra_rnhtable_node_cleanup(struct route_table *table,
 static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
                                   safi_t safi)
 {
+       struct route_node *rn;
+       struct prefix p;
+
        assert(!zvrf->table[afi][safi]);
 
        zvrf->table[afi][safi] =
                zebra_router_get_table(zvrf, zvrf->table_id, afi, safi);
+
+       memset(&p, 0, sizeof(p));
+       p.family = afi2family(afi);
+
+       rn = srcdest_rnode_get(zvrf->table[afi][safi], &p, NULL);
+       zebra_rib_create_dest(rn);
 }
 
 /* Allocate new zebra VRF. */
index f6566d02ac8eea9d65d0eca25b0002b30d5198e1..524c175b79cd1c21e3d2b60a4325de450aa1c083 100644 (file)
 #include <zebra/zebra_pw.h>
 #include <lib/vxlan.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* MPLS (Segment Routing) global block */
 typedef struct mpls_srgb_t_ {
        uint32_t start_label;
@@ -203,4 +207,9 @@ extern void zebra_vrf_init(void);
 
 extern void zebra_rtable_node_cleanup(struct route_table *table,
                                      struct route_node *node);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* ZEBRA_VRF_H */
index 899ba21171d0730194b931855acdbbf1508e6189..ad6184200530249369696646b5a6bdba16638d02 100644 (file)
@@ -383,6 +383,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
        json_object *json_labels = NULL;
        time_t uptime;
        struct tm *tm;
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
 
        uptime = time(NULL);
        uptime -= re->uptime;
@@ -407,6 +408,10 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
                        json_object_boolean_true_add(json_route, "selected");
 
+               if (dest->selected_fib == re)
+                       json_object_boolean_true_add(json_route,
+                                                    "destSelected");
+
                json_object_int_add(json_route, "distance",
                                    re->distance);
                json_object_int_add(json_route, "metric", re->metric);
@@ -420,12 +425,6 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
                        json_object_boolean_true_add(json_route, "queued");
 
-               if (re->type != ZEBRA_ROUTE_CONNECT) {
-                       json_object_int_add(json_route, "distance",
-                                           re->distance);
-                       json_object_int_add(json_route, "metric", re->metric);
-               }
-
                if (re->tag)
                        json_object_int_add(json_route, "tag", re->tag);
 
@@ -1370,7 +1369,7 @@ static void vty_show_ip_route_summary(struct vty *vty,
                        else
                                rib_cnt[re->type]++;
 
-                       if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
+                       if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
                                fib_cnt[ZEBRA_ROUTE_TOTAL]++;
 
                                if (is_ibgp)
index 70c5aa7c8a68ed601858397fac69812cae3563db..1add5cbf1b73003fb08321d09e2d3f19bde18911 100644 (file)
@@ -2191,6 +2191,8 @@ static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
 
        memcpy(&n->emac, mac, ETH_ALEN);
        n->state = ZEBRA_NEIGH_INACTIVE;
+       n->zvni = zvni;
+       n->dad_ip_auto_recovery_timer = NULL;
 
        /* Associate the neigh to mac */
        zmac = zvni_mac_lookup(zvni, mac);
@@ -2212,6 +2214,9 @@ static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n)
        if (zmac)
                listnode_delete(zmac->neigh_list, n);
 
+       /* Cancel auto recovery */
+       THREAD_OFF(n->dad_ip_auto_recovery_timer);
+
        /* Free the VNI hash entry and allocated memory. */
        tmp_n = hash_release(zvni->neigh_table, n);
        XFREE(MTYPE_NEIGH, tmp_n);
@@ -2987,8 +2992,12 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
        }
 
        zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
-       if (!zvrf)
+       if (!zvrf) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("\tUnable to find vrf for: %d",
+                                  zvni->vxlan_if->vrf_id);
                return -1;
+       }
 
        /* Check if the neighbor exists. */
        n = zvni_neigh_lookup(zvni, ip);
@@ -3018,6 +3027,9 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
                        cur_is_router = !!CHECK_FLAG(n->flags,
                                                     ZEBRA_NEIGH_ROUTER_FLAG);
                        if (!mac_different && is_router == cur_is_router) {
+                               if (IS_ZEBRA_DEBUG_VXLAN)
+                                       zlog_debug(
+                                               "\tIgnoring entry mac is the same and is_router == cur_is_router");
                                n->ifindex = ifp->ifindex;
                                return 0;
                        }
@@ -3046,6 +3058,11 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
                                        return zvni_neigh_send_add_to_client(
                                                        zvni->vni, ip, macaddr,
                                                        n->flags, n->loc_seq);
+                               else {
+                                       if (IS_ZEBRA_DEBUG_VXLAN)
+                                               zlog_debug(
+                                                       "\tNeighbor active and frozen");
+                               }
                                return 0;
                        }
 
@@ -3186,6 +3203,10 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
        if (!neigh_on_hold)
                return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
                                             n->flags, n->loc_seq);
+       else {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("\tNeighbor on hold not sending");
+       }
        return 0;
 }
 
@@ -3292,6 +3313,9 @@ static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr)
        mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc);
        assert(mac);
 
+       mac->zvni = zvni;
+       mac->dad_mac_auto_recovery_timer = NULL;
+
        mac->neigh_list = list_new();
        mac->neigh_list->cmp = neigh_list_cmp;
 
@@ -3305,6 +3329,9 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac)
 {
        zebra_mac_t *tmp_mac;
 
+       /* Cancel auto recovery */
+       THREAD_OFF(mac->dad_mac_auto_recovery_timer);
+
        list_delete(&mac->neigh_list);
 
        /* Free the VNI hash entry and allocated memory. */
@@ -7580,7 +7607,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
        if (!zvni) {
                if (IS_ZEBRA_DEBUG_VXLAN)
                        zlog_debug(
-                               "Add/Update %sMAC %s intf %s(%u) VID %u, could not find VNI",
+                               "\tAdd/Update %sMAC %s intf %s(%u) VID %u, could not find VNI",
                                sticky ? "sticky " : "",
                                prefix_mac2str(macaddr, buf, sizeof(buf)),
                                ifp->name, ifp->ifindex, vid);
@@ -7588,15 +7615,20 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
        }
 
        if (!zvni->vxlan_if) {
-               zlog_debug(
-                       "VNI %u hash %p doesn't have intf upon local MAC ADD",
-                       zvni->vni, zvni);
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug(
+                               "\tVNI %u hash %p doesn't have intf upon local MAC ADD",
+                               zvni->vni, zvni);
                return -1;
        }
 
        zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
-       if (!zvrf)
+       if (!zvrf) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("\tNo Vrf found for vrf_id: %d",
+                                  zvni->vxlan_if->vrf_id);
                return -1;
+       }
 
        /* Check if we need to create or update or it is a NO-OP. */
        mac = zvni_mac_lookup(zvni, macaddr);
@@ -7646,7 +7678,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
                            && mac->fwd_info.local.vid == vid) {
                                if (IS_ZEBRA_DEBUG_VXLAN)
                                        zlog_debug(
-                                               "Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, "
+                                               "\tAdd/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, "
                                                "entry exists and has not changed ",
                                                sticky ? "sticky " : "",
                                                prefix_mac2str(macaddr, buf,
index 409f1c3f7ff544edb4996dbb83e691c67b4cd83e..2ff92970d777a825b36148ea058b7340a938fcf8 100644 (file)
 #include "zebra/zebra_vrf.h"
 #include "zebra/zserv.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Is EVPN enabled? */
 #define EVPN_ENABLED(zvrf)  (zvrf)->advertise_all_vni
 static inline int is_evpn_enabled(void)
@@ -207,4 +211,8 @@ extern int zebra_vxlan_clear_dup_detect_vni(struct vty *vty,
                                            struct zebra_vrf *zvrf,
                                            vni_t vni);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_VXLAN_H */
index c36d156359f305d965108169864d5346e62204b1..5081c08d1931a484a661743c462450202b77b394 100644 (file)
 
 #include <zebra.h>
 
-#include <zebra.h>
-
 #include "if.h"
 #include "linklist.h"
 #include "zebra_vxlan.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define ERR_STR_SZ 256
 
 /* definitions */
@@ -421,4 +423,8 @@ struct nh_walk_ctx {
        struct json_object *json;
 };
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_VXLAN_PRIVATE_H */
index 6532491cefe5821c3a774108cdb4f349bfcf1b05..f5bb3aabb767428bccadcc61c4d33745784d2c39 100644 (file)
@@ -773,6 +773,18 @@ static int zserv_accept(struct thread *thread)
        return 0;
 }
 
+void zserv_close(void)
+{
+       /*
+        * On shutdown, let's close the socket down
+        * so that long running processes of killing the
+        * routing table doesn't leave us in a bad
+        * state where a client tries to reconnect
+        */
+       close(zsock);
+       zsock = -1;
+}
+
 void zserv_start(char *path)
 {
        int ret;
index ac016e65f3e19563b394fd6723e0bd46cafe0c59..86863d961c2bf961f87dd727f172b65027a6ce9c 100644 (file)
 #include "zebra/zebra_vrf.h"  /* for zebra_vrf */
 /* clang-format on */
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Default port information. */
 #define ZEBRA_VTY_PORT                2601
 
@@ -179,6 +183,13 @@ extern unsigned int multipath_num;
  */
 extern void zserv_init(void);
 
+/*
+ * Stop the Zebra API server.
+ *
+ * closes the socket
+ */
+extern void zserv_close(void);
+
 /*
  * Start Zebra API server.
  *
@@ -234,4 +245,8 @@ extern void zserv_read_file(char *input);
 /* TODO */
 int zebra_finalize(struct thread *event);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_ZEBRA_H */