]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #4017 from mjstapp/fix_summary_installed_flag
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 27 Mar 2019 12:40:12 +0000 (08:40 -0400)
committerGitHub <noreply@github.com>
Wed, 27 Mar 2019 12:40:12 +0000 (08:40 -0400)
zebra: use the INSTALLED flag consistently in route summary

132 files changed:
Makefile.am
bfdd/bfd.c
bfdd/bfd_packet.c
bgpd/bgp_attr.c
bgpd/bgp_evpn.c
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_rpki.c
doc/developer/building-frr-for-centos6.rst
doc/developer/building-frr-for-centos7.rst
doc/developer/building-frr-for-fedora24.rst
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-libyang.rst
doc/developer/hooks.rst
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/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
lib/if.c
lib/log.c
lib/nexthop_group.c
lib/nexthop_group.h
lib/privs.c
lib/vrf.c
lib/vrf.h
lib/zclient.c
ospfd/ospf_packet.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_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
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
tests/topotests/docker/build.sh
tests/topotests/docker/frr-topotests.sh
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.h
zebra/debug.h
zebra/if_netlink.h
zebra/interface.h
zebra/ioctl.h
zebra/ioctl_solaris.h
zebra/ipforward.h
zebra/irdp.h
zebra/kernel_netlink.c
zebra/kernel_netlink.h
zebra/kernel_socket.h
zebra/label_manager.h
zebra/redistribute.h
zebra/rib.h
zebra/router-id.h
zebra/rt.h
zebra/rt_netlink.h
zebra/rtadv.h
zebra/rule_netlink.h
zebra/table_manager.h
zebra/zapi_msg.h
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_mroute.h
zebra/zebra_netns_id.h
zebra/zebra_netns_notify.h
zebra/zebra_ns.h
zebra/zebra_pbr.h
zebra/zebra_ptm.h
zebra/zebra_ptm_redistribute.h
zebra/zebra_pw.h
zebra/zebra_rnh.h
zebra/zebra_routemap.h
zebra/zebra_router.h
zebra/zebra_vrf.c
zebra/zebra_vrf.h
zebra/zebra_vty.c
zebra/zebra_vxlan.h
zebra/zebra_vxlan_private.h
zebra/zserv.h

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 c8adf82a83140e30c136fbdfbb1bd1ed1c520dfa..3575ba7a008c9d5cb0af319f771bcf0d96e8cb15 100644 (file)
@@ -1187,7 +1187,8 @@ 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)
@@ -1231,7 +1232,7 @@ void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
 
                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.peer,
+                       memcpy(&bpc->bpc_local.sa_sin.sin_addr, &bs->key.local,
                               sizeof(bpc->bpc_local.sa_sin.sin_addr));
                }
                break;
@@ -1242,7 +1243,7 @@ void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
                       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.peer,
+               memcpy(&bpc->bpc_local.sa_sin6.sin6_addr, &bs->key.local,
                       sizeof(bpc->bpc_local.sa_sin6.sin6_addr));
                break;
        }
index 69d27ed698080ff77893b245e5f8b2e8ef612f65..93677ec85aceeb7709385a07c652682b843d73aa 100644 (file)
@@ -141,6 +141,7 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
        if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) {
                sd = bglobal.bg_echov6;
                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;
@@ -155,6 +156,7 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd)
        } else {
                sd = bglobal.bg_echo;
                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
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 19cda453f5f2c7d6439d87bfc75702799686a70a..3a61c0cd7402a5db096eddb910fee92c0b2f0852 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.
@@ -2945,6 +2946,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.
@@ -3001,6 +3037,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);
@@ -5041,6 +5081,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 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 fb2d9da533b532576d022671841760b784124d4a..ba72761003af58430cdea22cad7b02d7efa1aa4c 100644 (file)
@@ -5212,7 +5212,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 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 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:
 
 ::
 
index 2edf9b3e44915f6d6ee4d9c20f745a267ec1a335..708baec3eea00740113355a3472529af4542bdff 100644 (file)
@@ -1,9 +1,8 @@
 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)
+This document describes installation from source. If you want to build an RPM,
+see :ref:`packaging-redhat`.
 
 Install required packages
 -------------------------
@@ -126,7 +125,7 @@ required MPLS similar to ``net.mpls.conf.eth0.input=1``)
     net.mpls.conf.eth2.input=1
     net.mpls.platform_labels=100000
 
-Load the modifed sysctl's on the system:
+Load the modified sysctl's on the system:
 
 ::
 
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 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 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:
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..a0c5e6fc9d922b6f41c84c7d5e0ba694e84331e5 100644 (file)
@@ -5,7 +5,6 @@
 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 \
@@ -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 \
@@ -37,8 +37,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 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 e191ebd0351262a6ffb62b0b36c4b3ef611ec748..964297292f2ca6c418254eb5ebacb3c18d878069 100644 (file)
@@ -272,7 +272,7 @@ 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.  Additionally if this parameter is
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 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 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 ab47f242fd0468afa7457908bcab9c7cb3a236c2..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,
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 55f2393c563b01867f31ee01d3a474feb651ba14..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",
-                          (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:
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 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 012c3b4f1d219893d51c51b33e10091b87f009fe..f058b7adbfb26ffbe7c62fcbe94b7b188fb24fc9 100644 (file)
@@ -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);
                }
        }
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 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) {
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 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 "$@"
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 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 c79cd96c214d53e99c17f1e99c686df2a9da09f8..944ad6d68b44f4b3588b5c9d75a3424287074756 100644 (file)
 
 #include "lib/vty.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Debug flags. */
 #define ZEBRA_DEBUG_EVENT   0x01
 
@@ -99,4 +103,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 c5fbfd44814aad9a8f53b4220a8e11110ab93b0d..fe37a333581ed12244f62acce217dba9adddbe7c 100644 (file)
@@ -606,50 +606,56 @@ 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");
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 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 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..ced6692b9b1bfa5773d0dcc504abf5ca5b58daf8 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 */
 
@@ -464,4 +468,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..bc91edd802f2e8f0c372c5f5fb28df309a5545a6 100644 (file)
 #include "zebra/zebra_mpls.h"
 #include "zebra/zebra_dplane.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*
  * Update or delete a route, LSP, or pseudowire from the kernel,
  * using info from a dataplane context.
@@ -91,4 +95,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 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 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 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 149ff8dc607947fb4b225aa4a5d0e18fd9580900..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;
@@ -394,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..f8c6c794a4c64b634ed3f4c6adf07c168aae14d0 100644 (file)
@@ -34,6 +34,9 @@
 #include "zebra/zserv.h"
 #include "zebra/zebra_vrf.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 /* Definitions and macros. */
 
@@ -534,4 +537,8 @@ static inline int mpls_should_lsps_be_processed(struct zebra_vrf *zvrf)
 /* Global variables. */
 extern int mpls_enabled;
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /*_ZEBRA_MPLS_H */
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 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 00ee60dc1a8c7efff632598ef28209abd4523744..0e71e8a68da36eec9c8b4da4062365a504f2eab2 100644 (file)
 #include "prefix.h"
 #include "vty.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Nexthop structure. */
 struct rnh {
        uint8_t flags;
@@ -83,4 +87,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 e5043f38ae6aa12a1ec195bf482c569634945737..61f2902233114ca3ce8116aa253d47f3f1729227 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
@@ -129,4 +133,9 @@ extern void zebra_router_sweep_route(void);
 extern void zebra_router_show_table_summary(struct vty *vty);
 
 extern uint32_t zebra_router_get_next_sequence(void);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index 1300ca24f3f6627a0c1a93f7fbdc19cc0d24327d..90f94902f341c235b8a4aa8a7c8241f259e6762d 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]);
        }
@@ -213,11 +218,6 @@ static int zebra_vrf_disable(struct vrf *vrf)
                                                   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;
@@ -268,8 +268,10 @@ static int zebra_vrf_delete(struct vrf *vrf)
                        }
                }
 
-               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 */
index e35101d83313d6ba6a92c2df525cb505fd812bfc..502fc343c5805b5cffd857b00e7b2d3b05935e1e 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 f89293814e3f1594c6ee382baca16e43cea15287..97e841692b07ce9cac209b857e7a7805e92cecc8 100644 (file)
@@ -425,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);
 
index 2cf21ff90b649c0a2997e54513f0a97e05347294..206f65044aa82426ef581fdb11a155bf9e02dd88 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)
@@ -206,4 +210,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 ac016e65f3e19563b394fd6723e0bd46cafe0c59..c4c3e1328b5bb04974ce4bbad46dab0feaad07b8 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
 
@@ -234,4 +238,8 @@ extern void zserv_read_file(char *input);
 /* TODO */
 int zebra_finalize(struct thread *event);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_ZEBRA_H */