]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #2220 from LabNConsulting/working/master/fix-asan
authorQuentin Young <qlyoung@users.noreply.github.com>
Tue, 22 May 2018 15:15:28 +0000 (11:15 -0400)
committerGitHub <noreply@github.com>
Tue, 22 May 2018 15:15:28 +0000 (11:15 -0400)
*: fix compile with -enable-address-sanitizer configured

69 files changed:
Makefile.am
README
SERVICES [deleted file]
bgpd/bgp_clist.c
bgpd/bgp_ecommunity.c
bgpd/bgp_ecommunity.h
bgpd/bgp_evpn.c
bgpd/bgp_evpn.h
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_flowspec.c
bgpd/bgp_lcommunity.c
bgpd/bgp_lcommunity.h
bgpd/bgp_mplsvpn.c
bgpd/bgp_nht.c
bgpd/bgp_route.c
bgpd/bgp_routemap.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.h
doc/Makefile.am
doc/developer/.gitignore
doc/developer/Makefile.am [new file with mode: 0644]
doc/developer/Makefile.in [deleted file]
doc/developer/building-frr-on-ubuntu1804.rst
doc/manpages/.gitignore
doc/manpages/Makefile.am [new file with mode: 0644]
doc/manpages/Makefile.in [deleted file]
doc/user/.gitignore
doc/user/Makefile.am [new file with mode: 0644]
doc/user/Makefile.in [deleted file]
doc/user/getting-started.rst [new file with mode: 0644]
doc/user/index.rst
doc/user/installation.rst
doc/user/overview.rst
doc/user/routemap.rst
doc/user/setup.rst [new file with mode: 0644]
doc/user/zebra.rst
lib/command.c
lib/command.h
lib/stream.c
lib/stream.h
lib/zclient.c
ospf6d/ospf6_asbr.c
ospf6d/ospf6_intra.c
pbrd/pbr_nht.c
pbrd/pbr_nht.h
pbrd/pbr_vty.c
redhat/frr.spec.in
sharpd/sharp_main.c
sharpd/sharp_vty.c
sharpd/sharp_zebra.c
sharpd/sharp_zebra.h
tests/Makefile.am
vtysh/vtysh.c
vtysh/vtysh.h
vtysh/vtysh_main.c
zebra/label_manager.c
zebra/label_manager.h
zebra/main.c
zebra/redistribute.c
zebra/rib.h
zebra/rt_netlink.c
zebra/zapi_msg.c
zebra/zebra_rib.c
zebra/zebra_routemap.c
zebra/zebra_routemap.h
zebra/zebra_vxlan.c
zebra/zebra_vxlan_private.h

index 3b8deb5884e364228a780f36b5afbf034127dff5..431696430393199eacb7b6eff64ad40bdf9e5a29 100644 (file)
@@ -83,7 +83,6 @@ rc_SCRIPTS = \
 endif
 
 EXTRA_DIST += \
-       SERVICES \
        aclocal.m4 \
        update-autotools \
        m4/README.txt \
diff --git a/README b/README
index 95ed0d3fc299bbd3b97c81b77ca8149ed57b0cfd..7600ec54cca656f596639fc8c3a48df6b86ed6e1 100644 (file)
--- a/README
+++ b/README
@@ -9,7 +9,7 @@ See doc/user/bugs.rst for information on how to report bugs.
 
 See doc/developer/workflow.rst for information on contributing.
 
-Free RRRouting is free software. See the file COPYING for copying conditions.
+See the file COPYING for copying conditions.
 
 Public email discussion can be found at https://lists.frrouting.org/listinfo
 
diff --git a/SERVICES b/SERVICES
deleted file mode 100644 (file)
index f7f92a7..0000000
--- a/SERVICES
+++ /dev/null
@@ -1,24 +0,0 @@
-# As long as this software is in alpha testing it is not yet included
-# in /etc/services files. This means that you may need to add the following
-# lines into your /etc/services file on your hosts.
-# 
-# --- Please add this to your /etc/services ---
-
-#
-# GNU Zebra services
-#
-
-zebrasrv       2600/tcp
-zebra          2601/tcp
-ripd           2602/tcp
-ripng          2603/tcp
-ospfd          2604/tcp
-bgpd           2605/tcp
-ospf6d         2606/tcp
-ospfapi                2607/tcp
-isisd          2608/tcp
-babeld         2609/tcp
-nhrpd          2610/tcp
-pimd           2611/tcp
-ldpd           2612/tcp
-eigrpd         2613/tcp
index d1bc7f6e535a849bfb9530c9069792d186d1fd67..7cf14775496cdb2bb6e8f0cc9eb04f2c5bb20b31 100644 (file)
@@ -512,7 +512,7 @@ static int lcommunity_regexp_match(struct lcommunity *com, regex_t *reg)
        if (com == NULL || com->size == 0)
                str = "";
        else
-               str = lcommunity_str(com);
+               str = lcommunity_str(com, false);
 
        /* Regular expression match.  */
        if (regexec(reg, str, 0, NULL, 0) == 0)
@@ -986,13 +986,8 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
        entry->any = (str ? 0 : 1);
        entry->u.lcom = lcom;
        entry->reg = regex;
-       if (lcom)
-               entry->config = lcommunity_lcom2str(
-                       lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST);
-       else if (regex)
-               entry->config = XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str);
-       else
-               entry->config = NULL;
+       entry->config =
+               (regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
 
        /* Do not put duplicated community entry.  */
        if (community_list_dup_check(list, entry))
index 85b9ffd8ca27ea859481c37df30df96d02bf19ea..99fe80f055497d5ebe0fec3050404a5f3340b210 100644 (file)
@@ -52,6 +52,11 @@ struct ecommunity *ecommunity_new(void)
                                            sizeof(struct ecommunity));
 }
 
+void ecommunity_strfree(char **s)
+{
+       XFREE(MTYPE_ECOMMUNITY_STR, *s);
+}
+
 /* Allocate ecommunities.  */
 void ecommunity_free(struct ecommunity **ecom)
 {
index 88bdb5e2ae026cec5f4c64aceca4530c0ceeede7..2f59308d65fd1f0f0eedfbfa9637c61ea0e3da25 100644 (file)
@@ -156,6 +156,7 @@ extern void ecommunity_unintern(struct ecommunity **);
 extern unsigned int ecommunity_hash_make(void *);
 extern struct ecommunity *ecommunity_str2com(const char *, int, int);
 extern char *ecommunity_ecom2str(struct ecommunity *, int, int);
+extern void ecommunity_strfree(char **s);
 extern int ecommunity_match(const struct ecommunity *,
                            const struct ecommunity *);
 extern char *ecommunity_str(struct ecommunity *);
index ee53beb191d2f553a5d17179fc53afb9c8a201e7..8394c3a7b7dcb62b9d51c1fe7c195a89e0b4ca62 100644 (file)
@@ -327,6 +327,12 @@ static int evpn_route_target_cmp(struct ecommunity *ecom1,
        return strcmp(ecom1->str, ecom2->str);
 }
 
+static void evpn_xxport_delete_ecomm(void *val)
+{
+       struct ecommunity *ecomm = val;
+       ecommunity_free(&ecomm);
+}
+
 /*
  * Mask off global-admin field of specified extended community (RT),
  * just retain the local-admin field.
@@ -452,6 +458,8 @@ static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl)
        struct ecommunity_val eval;
        struct ecommunity *ecomadd;
 
+       if (bgp->advertise_autort_rfc8365)
+               vni |= EVPN_AUTORT_VXLAN;
        encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
 
        ecomadd = ecommunity_new();
@@ -3232,6 +3240,35 @@ static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf)
                update_routes_for_vni(bgp_def, vpn);
 }
 
+/*
+ * Handle autort change for a given VNI.
+ */
+static void update_autort_vni(struct hash_backet *backet, struct bgp *bgp)
+{
+       struct bgpevpn *vpn = backet->data;
+
+       if (!vpn) {
+               zlog_warn("%s: VNI hash entry for VNI not found", __PRETTY_FUNCTION__);
+               return;
+       }
+
+       if (!is_import_rt_configured(vpn)) {
+               if (is_vni_live(vpn))
+                       bgp_evpn_uninstall_routes(bgp, vpn);
+               bgp_evpn_unmap_vni_from_its_rts(bgp, vpn);
+               list_delete_all_node(vpn->import_rtl);
+               bgp_evpn_derive_auto_rt_import(bgp, vpn);
+               if (is_vni_live(vpn))
+                       bgp_evpn_install_routes(bgp, vpn);
+       }
+       if (!is_export_rt_configured(vpn)) {
+               list_delete_all_node(vpn->export_rtl);
+               bgp_evpn_derive_auto_rt_export(bgp, vpn);
+               if (is_vni_live(vpn))
+                       bgp_evpn_handle_export_rt_change(bgp, vpn);
+       }
+}
+
 /*
  * Public functions.
  */
@@ -3343,6 +3380,8 @@ void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni, struct list *rtl)
        struct ecommunity *ecom, *ecom_auto;
        struct ecommunity_val eval;
 
+       if (bgp->advertise_autort_rfc8365)
+               vni |= EVPN_AUTORT_VXLAN;
        encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
 
        ecom_auto = ecommunity_new();
@@ -3502,6 +3541,17 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw)
        }
 }
 
+/*
+ * Handle change to auto-RT algorithm - update and advertise local routes.
+ */
+void bgp_evpn_handle_autort_change(struct bgp *bgp)
+{
+       hash_iterate(bgp->vnihash,
+                    (void (*)(struct hash_backet *,
+                              void*))update_autort_vni,
+                    bgp);
+}
+
 /*
  * Handle change to export RT - update and advertise local routes.
  */
@@ -4050,8 +4100,10 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
        /* Initialize route-target import and export lists */
        vpn->import_rtl = list_new();
        vpn->import_rtl->cmp = (int (*)(void *, void *))evpn_route_target_cmp;
+       vpn->import_rtl->del = evpn_xxport_delete_ecomm;
        vpn->export_rtl = list_new();
        vpn->export_rtl->cmp = (int (*)(void *, void *))evpn_route_target_cmp;
+       vpn->export_rtl->del = evpn_xxport_delete_ecomm;
        bf_assign_index(bm->rd_idspace, vpn->rd_id);
        derive_rd_rt_for_vni(bgp, vpn);
 
@@ -4601,10 +4653,11 @@ void bgp_evpn_init(struct bgp *bgp)
        bgp->vrf_import_rtl = list_new();
        bgp->vrf_import_rtl->cmp =
                (int (*)(void *, void *))evpn_route_target_cmp;
-
+       bgp->vrf_import_rtl->del = evpn_xxport_delete_ecomm;
        bgp->vrf_export_rtl = list_new();
        bgp->vrf_export_rtl->cmp =
                (int (*)(void *, void *))evpn_route_target_cmp;
+       bgp->vrf_export_rtl->del = evpn_xxport_delete_ecomm;
        bgp->l2vnis = list_new();
        bgp->l2vnis->cmp = (int (*)(void *, void *))vni_hash_cmp;
 }
index dd8d6e2e8e903cced9e3ecceb9c6464fc451af2a..8e954159c04f20d20a6965dd8fb600e2ae241445 100644 (file)
@@ -25,6 +25,7 @@
 #include "bgpd.h"
 
 #define EVPN_ROUTE_STRLEN 200 /* Must be >> MAC + IPv6 strings. */
+#define EVPN_AUTORT_VXLAN 0x10000000
 
 static inline int is_evpn_enabled(void)
 {
index 1efde3a71934c0c56312fd55b92dc9d7faeb9537..39a08e70364a6bf1b2e1b33096a76883020e8993 100644 (file)
@@ -395,6 +395,7 @@ extern void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
                                                   struct ecommunity *ecomdel);
 extern int bgp_evpn_handle_export_rt_change(struct bgp *bgp,
                                            struct bgpevpn *vpn);
+extern void bgp_evpn_handle_autort_change(struct bgp *bgp);
 extern void bgp_evpn_handle_vrf_rd_change(struct bgp *bgp_vrf, int withdraw);
 extern void bgp_evpn_handle_rd_change(struct bgp *bgp, struct bgpevpn *vpn,
                                      int withdraw);
index fd3c2294724a76f548494b1baf5e0542158de128..e920bbb212b3d2e10cb2b2a15f7cb507d96ea558 100644 (file)
@@ -2513,6 +2513,24 @@ static void evpn_unset_advertise_all_vni(struct bgp *bgp)
        bgp_zebra_advertise_all_vni(bgp, bgp->advertise_all_vni);
        bgp_evpn_cleanup_on_disable(bgp);
 }
+
+/*
+ * EVPN - use RFC8365 to auto-derive RT
+ */
+static void evpn_set_advertise_autort_rfc8365(struct bgp *bgp)
+{
+       bgp->advertise_autort_rfc8365 = 1;
+       bgp_evpn_handle_autort_change(bgp);
+}
+
+/*
+ * EVPN - don't use RFC8365 to auto-derive RT
+ */
+static void evpn_unset_advertise_autort_rfc8365(struct bgp *bgp)
+{
+       bgp->advertise_autort_rfc8365 = 0;
+       bgp_evpn_handle_autort_change(bgp);
+}
 #endif /* HAVE_CUMULUS */
 
 static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
@@ -2666,6 +2684,35 @@ DEFUN (no_bgp_evpn_advertise_all_vni,
        return CMD_SUCCESS;
 }
 
+DEFUN (bgp_evpn_advertise_autort_rfc8365,
+       bgp_evpn_advertise_autort_rfc8365_cmd,
+       "autort rfc8365-compatible",
+       "Auto-derivation of RT\n"
+       "Auto-derivation of RT using RFC8365\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+
+       if (!bgp)
+               return CMD_WARNING;
+       evpn_set_advertise_autort_rfc8365(bgp);
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_advertise_autort_rfc8365,
+       no_bgp_evpn_advertise_autort_rfc8365_cmd,
+       "no autort rfc8365-compatible",
+       NO_STR
+       "Auto-derivation of RT\n"
+       "Auto-derivation of RT using RFC8365\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+
+       if (!bgp)
+               return CMD_WARNING;
+       evpn_unset_advertise_autort_rfc8365(bgp);
+       return CMD_SUCCESS;
+}
+
 DEFUN (bgp_evpn_default_originate,
        bgp_evpn_default_originate_cmd,
        "default-originate <ipv4 | ipv6>",
@@ -4389,6 +4436,9 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
        if (bgp->advertise_all_vni)
                vty_out(vty, "  advertise-all-vni\n");
 
+       if (bgp->advertise_autort_rfc8365)
+               vty_out(vty, "  autort rfc8365-compatible\n");
+
        if (bgp->advertise_gw_macip)
                vty_out(vty, "  advertise-default-gw\n");
 
@@ -4476,6 +4526,8 @@ void bgp_ethernetvpn_init(void)
 #if defined(HAVE_CUMULUS)
        install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd);
        install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd);
+       install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_autort_rfc8365_cmd);
+       install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_autort_rfc8365_cmd);
        install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_default_gw_cmd);
        install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
        install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_cmd);
index 5db7e37089bf49e7953b3c2c31536eb71e232d61..6eb1e39884d386233a7ecd6e2f1a762fae213dd5 100644 (file)
@@ -166,6 +166,9 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
                                         BGP_FLOWSPEC_NLRI_STRING_MAX,
                                         "EC{%s}",
                                        s == NULL ? "none" : s);
+
+                               if (s)
+                                       ecommunity_strfree(&s);
                        }
                        snprintf(local_string, BGP_FLOWSPEC_NLRI_STRING_MAX,
                                 "FS Rx %s %s %s %s", withdraw ?
index 09b3a8718a6a1ac63872e5f491c0c86c3d687099..33f4d139b8271027baecad6b7355a119f578024b 100644 (file)
@@ -160,15 +160,6 @@ struct lcommunity *lcommunity_dup(struct lcommunity *lcom)
        return new;
 }
 
-/* Retrun string representation of communities attribute. */
-char *lcommunity_str(struct lcommunity *lcom)
-{
-       if (!lcom->str)
-               lcom->str =
-                       lcommunity_lcom2str(lcom, LCOMMUNITY_FORMAT_DISPLAY);
-       return lcom->str;
-}
-
 /* Merge two Large Communities Attribute structure.  */
 struct lcommunity *lcommunity_merge(struct lcommunity *lcom1,
                                    struct lcommunity *lcom2)
@@ -186,6 +177,80 @@ struct lcommunity *lcommunity_merge(struct lcommunity *lcom1,
        return lcom1;
 }
 
+static void set_lcommunity_string(struct lcommunity *lcom, bool make_json)
+{
+       int i;
+       int len;
+       bool first = 1;
+       char *str_buf;
+       char *str_pnt;
+       uint8_t *pnt;
+       uint32_t global, local1, local2;
+       json_object *json_lcommunity_list = NULL;
+       json_object *json_string = NULL;
+
+#define LCOMMUNITY_STR_DEFAULT_LEN 32
+
+       if (!lcom)
+               return;
+
+       if (make_json) {
+               lcom->json = json_object_new_object();
+               json_lcommunity_list = json_object_new_array();
+       }
+
+       if (lcom->size == 0) {
+               str_buf = XMALLOC(MTYPE_LCOMMUNITY_STR, 1);
+               str_buf[0] = '\0';
+
+               if (make_json) {
+                       json_object_string_add(lcom->json, "string", "");
+                       json_object_object_add(lcom->json, "list",
+                                              json_lcommunity_list);
+               }
+
+               lcom->str = str_buf;
+               return;
+       }
+
+       str_buf = str_pnt =
+               XMALLOC(MTYPE_LCOMMUNITY_STR,
+                       (LCOMMUNITY_STR_DEFAULT_LEN * lcom->size) + 1);
+
+       for (i = 0; i < lcom->size; i++) {
+               if (first)
+                       first = 0;
+               else
+                       *str_pnt++ = ' ';
+
+               pnt = lcom->val + (i * LCOMMUNITY_SIZE);
+               pnt = ptr_get_be32(pnt, &global);
+               pnt = ptr_get_be32(pnt, &local1);
+               pnt = ptr_get_be32(pnt, &local2);
+               (void)pnt;
+
+               len = sprintf(str_pnt, "%u:%u:%u", global, local1, local2);
+               if (make_json) {
+                       json_string = json_object_new_string(str_pnt);
+                       json_object_array_add(json_lcommunity_list,
+                                             json_string);
+               }
+
+               str_pnt += len;
+       }
+
+       str_buf =
+               XREALLOC(MTYPE_LCOMMUNITY_STR, str_buf, str_pnt - str_buf + 1);
+
+       if (make_json) {
+               json_object_string_add(lcom->json, "string", str_buf);
+               json_object_object_add(lcom->json, "list",
+                                      json_lcommunity_list);
+       }
+
+       lcom->str = str_buf;
+}
+
 /* Intern Large Communities Attribute.  */
 struct lcommunity *lcommunity_intern(struct lcommunity *lcom)
 {
@@ -201,8 +266,7 @@ struct lcommunity *lcommunity_intern(struct lcommunity *lcom)
        find->refcnt++;
 
        if (!find->str)
-               find->str =
-                       lcommunity_lcom2str(find, LCOMMUNITY_FORMAT_DISPLAY);
+               set_lcommunity_string(find, false);
 
        return find;
 }
@@ -225,6 +289,21 @@ void lcommunity_unintern(struct lcommunity **lcom)
        }
 }
 
+/* Retrun string representation of communities attribute. */
+char *lcommunity_str(struct lcommunity *lcom, bool make_json)
+{
+       if (!lcom)
+               return NULL;
+
+       if (make_json && !lcom->json && lcom->str)
+               XFREE(MTYPE_LCOMMUNITY_STR, lcom->str);
+
+       if (!lcom->str)
+               set_lcommunity_string(lcom, make_json);
+
+       return lcom->str;
+}
+
 /* Utility function to make hash key.  */
 unsigned int lcommunity_hash_make(void *arg)
 {
@@ -388,59 +467,6 @@ int lcommunity_include(struct lcommunity *lcom, uint8_t *ptr)
        return 0;
 }
 
-/* Convert large community attribute to string.
-   The large coms will be in 65535:65531:0 format.
-*/
-char *lcommunity_lcom2str(struct lcommunity *lcom, int format)
-{
-       int i;
-       uint8_t *pnt;
-#define LCOMMUNITY_STR_DEFAULT_LEN  40
-       int str_size;
-       int str_pnt;
-       char *str_buf;
-       int len = 0;
-       int first = 1;
-       uint32_t globaladmin, localdata1, localdata2;
-
-       if (lcom->size == 0) {
-               str_buf = XMALLOC(MTYPE_LCOMMUNITY_STR, 1);
-               str_buf[0] = '\0';
-               return str_buf;
-       }
-
-       /* Prepare buffer.  */
-       str_buf = XMALLOC(MTYPE_LCOMMUNITY_STR, LCOMMUNITY_STR_DEFAULT_LEN + 1);
-       str_size = LCOMMUNITY_STR_DEFAULT_LEN + 1;
-       str_pnt = 0;
-
-       for (i = 0; i < lcom->size; i++) {
-               /* Make it sure size is enough.  */
-               while (str_pnt + LCOMMUNITY_STR_DEFAULT_LEN >= str_size) {
-                       str_size *= 2;
-                       str_buf = XREALLOC(MTYPE_LCOMMUNITY_STR, str_buf,
-                                          str_size);
-               }
-
-               /* Space between each value.  */
-               if (!first)
-                       str_buf[str_pnt++] = ' ';
-
-               pnt = lcom->val + (i * LCOMMUNITY_SIZE);
-
-               pnt = ptr_get_be32(pnt, &globaladmin);
-               pnt = ptr_get_be32(pnt, &localdata1);
-               pnt = ptr_get_be32(pnt, &localdata2);
-               (void)pnt; /* consume value */
-
-               len = sprintf(str_buf + str_pnt, "%u:%u:%u", globaladmin,
-                             localdata1, localdata2);
-               str_pnt += len;
-               first = 0;
-       }
-       return str_buf;
-}
-
 int lcommunity_match(const struct lcommunity *lcom1,
                     const struct lcommunity *lcom2)
 {
index 78841accf3f2af5319f3c2127a77bdb42a9b8386..c88a016396720c8267eeba59e3593f09728d05f0 100644 (file)
 #ifndef _QUAGGA_BGP_LCOMMUNITY_H
 #define _QUAGGA_BGP_LCOMMUNITY_H
 
-/* Extended communities attribute string format.  */
-#define LCOMMUNITY_FORMAT_ROUTE_MAP            0
-#define LCOMMUNITY_FORMAT_COMMUNITY_LIST       1
-#define LCOMMUNITY_FORMAT_DISPLAY              2
+#include "lib/json.h"
 
 /* Large Communities value is twelve octets long.  */
 #define LCOMMUNITY_SIZE                        12
@@ -40,6 +37,9 @@ struct lcommunity {
        /* Large Communities value.  */
        uint8_t *val;
 
+       /* Large Communities as a json object */
+       json_object *json;
+
        /* Human readable format string.  */
        char *str;
 };
@@ -65,10 +65,9 @@ extern void lcommunity_unintern(struct lcommunity **);
 extern unsigned int lcommunity_hash_make(void *);
 extern struct hash *lcommunity_hash(void);
 extern struct lcommunity *lcommunity_str2com(const char *);
-extern char *lcommunity_lcom2str(struct lcommunity *, int);
 extern int lcommunity_match(const struct lcommunity *,
                            const struct lcommunity *);
-extern char *lcommunity_str(struct lcommunity *);
+extern char *lcommunity_str(struct lcommunity *, bool make_json);
 extern int lcommunity_include(struct lcommunity *lcom, uint8_t *ptr);
 extern void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr);
 #endif /* _QUAGGA_BGP_LCOMMUNITY_H */
index 55365df2995ffa8580d4e23ab3aae15b831842ff..bcc448119c169b4dedae419e53c479b72336634d 100644 (file)
@@ -565,10 +565,11 @@ leak_update(
        if (nexthop_self_flag)
                bgp_info_set_flag(bn, new, BGP_INFO_ANNC_NH_SELF);
 
+       bgp_info_extra_get(new);
+
        if (num_labels)
                setlabels(new, label, num_labels);
 
-       bgp_info_extra_get(new);
        new->extra->parent = bgp_info_lock(parent);
 
        if (bgp_orig)
@@ -582,7 +583,7 @@ leak_update(
        struct bgp *bgp_nexthop = bgp;
        int nh_valid;
 
-       if (new->extra && new->extra->bgp_orig)
+       if (new->extra->bgp_orig)
                bgp_nexthop = new->extra->bgp_orig;
 
        /*
index 8b6ff3fa222312f5e36a5c92a7eca15b7c7bd12a..2c9e379299783eebd64d8ad91b5d9ebedd31799f 100644 (file)
@@ -88,7 +88,7 @@ int bgp_find_nexthop(struct bgp_info *path, int connected)
 
 static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
 {
-       if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) {
+       if (LIST_EMPTY(&(bnc->paths)) && bnc->nht_info) {
                if (BGP_DEBUG(nht, NHT)) {
                        char buf[PREFIX2STR_BUFFER];
                        zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
index 997d708baf5d11eaebc15dbf7192ebd2fc33cce6..7bfeee9669a00e37fe1dd6dd228c9f1c9eca3c61 100644 (file)
@@ -6509,7 +6509,7 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
                                ? true
                                : false;
        bool nexthop_othervrf = false;
-       vrf_id_t nexthop_vrfid;
+       vrf_id_t nexthop_vrfid = VRF_DEFAULT;
        const char *nexthop_vrfname = "Default";
 
        if (json_paths)
@@ -7414,7 +7414,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
        json_object *json_cluster_list = NULL;
        json_object *json_cluster_list_list = NULL;
        json_object *json_ext_community = NULL;
-       json_object *json_lcommunity = NULL;
        json_object *json_last_update = NULL;
        json_object *json_pmsi = NULL;
        json_object *json_nexthop_global = NULL;
@@ -8041,13 +8040,12 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
                /* Line 6 display Large community */
                if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
                        if (json_paths) {
-                               json_lcommunity = json_object_new_object();
-                               json_object_string_add(json_lcommunity,
-                                                      "string",
-                                                      attr->lcommunity->str);
+                               if (!attr->lcommunity->json)
+                                       lcommunity_str(attr->lcommunity, true);
+                               json_object_lock(attr->lcommunity->json);
                                json_object_object_add(json_path,
                                                       "largeCommunity",
-                                                      json_lcommunity);
+                                                      attr->lcommunity->json);
                        } else {
                                vty_out(vty, "      Large Community: %s\n",
                                        attr->lcommunity->str);
index 63400f7d313ce61acfb422128cc9e1e7aaeb0a52..8c92f7ff3229f34e2d8c1416e2ff11f223ab0d67 100644 (file)
@@ -338,9 +338,8 @@ static route_map_result_t route_match_ip_address(void *rule,
                                                 void *object)
 {
        struct access_list *alist;
-       /* struct prefix_ipv4 match; */
 
-       if (type == RMAP_BGP) {
+       if (type == RMAP_BGP && prefix->family == AF_INET) {
                alist = access_list_lookup(AFI_IP, (char *)rule);
                if (alist == NULL)
                        return RMAP_NOMATCH;
@@ -382,7 +381,7 @@ static route_map_result_t route_match_ip_next_hop(void *rule,
        struct bgp_info *bgp_info;
        struct prefix_ipv4 p;
 
-       if (type == RMAP_BGP) {
+       if (type == RMAP_BGP && prefix->family == AF_INET) {
                bgp_info = object;
                p.family = AF_INET;
                p.prefix = bgp_info->attr->nexthop;
@@ -430,7 +429,7 @@ static route_map_result_t route_match_ip_route_source(void *rule,
        struct peer *peer;
        struct prefix_ipv4 p;
 
-       if (type == RMAP_BGP) {
+       if (type == RMAP_BGP && prefix->family == AF_INET) {
                bgp_info = object;
                peer = bgp_info->peer;
 
@@ -478,7 +477,7 @@ route_match_ip_address_prefix_list(void *rule, struct prefix *prefix,
 {
        struct prefix_list *plist;
 
-       if (type == RMAP_BGP) {
+       if (type == RMAP_BGP && prefix->family == AF_INET) {
                plist = prefix_list_lookup(AFI_IP, (char *)rule);
                if (plist == NULL)
                        return RMAP_NOMATCH;
@@ -515,7 +514,7 @@ route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix,
        struct bgp_info *bgp_info;
        struct prefix_ipv4 p;
 
-       if (type == RMAP_BGP) {
+       if (type == RMAP_BGP && prefix->family == AF_INET) {
                bgp_info = object;
                p.family = AF_INET;
                p.prefix = bgp_info->attr->nexthop;
@@ -558,7 +557,7 @@ route_match_ip_route_source_prefix_list(void *rule, struct prefix *prefix,
        struct peer *peer;
        struct prefix_ipv4 p;
 
-       if (type == RMAP_BGP) {
+       if (type == RMAP_BGP && prefix->family == AF_INET) {
                bgp_info = object;
                peer = bgp_info->peer;
 
@@ -2239,7 +2238,7 @@ static route_map_result_t route_match_ipv6_address(void *rule,
 {
        struct access_list *alist;
 
-       if (type == RMAP_BGP) {
+       if (type == RMAP_BGP && prefix->family == AF_INET6) {
                alist = access_list_lookup(AFI_IP6, (char *)rule);
                if (alist == NULL)
                        return RMAP_NOMATCH;
@@ -2326,7 +2325,7 @@ route_match_ipv6_address_prefix_list(void *rule, struct prefix *prefix,
 {
        struct prefix_list *plist;
 
-       if (type == RMAP_BGP) {
+       if (type == RMAP_BGP && prefix->family == AF_INET6) {
                plist = prefix_list_lookup(AFI_IP6, (char *)rule);
                if (plist == NULL)
                        return RMAP_NOMATCH;
index b8c81232bb24147f22fa57e57455132f3370bc9f..f4f4e63264e2af2bee7c02c0a809b62f03dd4032 100644 (file)
@@ -553,39 +553,46 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                     const char *arg)
 {
        int ret;
+       bool found = false;
        struct peer *peer;
        struct listnode *node, *nnode;
 
        /* Clear all neighbors. */
        /*
         * Pass along pointer to next node to peer_clear() when walking all
-        * nodes
-        * on the BGP instance as that may get freed if it is a doppelganger
+        * nodes on the BGP instance as that may get freed if it is a
+        * doppelganger
         */
        if (sort == clear_all) {
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+                       if (!peer->afc[afi][safi])
+                               continue;
+
                        if (stype == BGP_CLEAR_SOFT_NONE)
                                ret = peer_clear(peer, &nnode);
-                       else if (peer->afc[afi][safi])
-                               ret = peer_clear_soft(peer, afi, safi, stype);
                        else
-                               ret = 0;
+                               ret = peer_clear_soft(peer, afi, safi, stype);
 
                        if (ret < 0)
                                bgp_clear_vty_error(vty, peer, afi, safi, ret);
+                       else
+                               found = true;
                }
 
                /* This is to apply read-only mode on this clear. */
                if (stype == BGP_CLEAR_SOFT_NONE)
                        bgp->update_delay_over = 0;
 
+               if (!found)
+                       vty_out(vty, "%%BGP: No %s peer configured",
+                               afi_safi_print(afi, safi));
+
                return CMD_SUCCESS;
        }
 
-       /* Clear specified neighbors. */
+       /* Clear specified neighbor. */
        if (sort == clear_peer) {
                union sockunion su;
-               int ret;
 
                /* Make sockunion for lookup. */
                ret = str2sockunion(arg, &su);
@@ -610,7 +617,9 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                        }
                }
 
-               if (stype == BGP_CLEAR_SOFT_NONE)
+               if (!peer->afc[afi][safi])
+                       ret = BGP_ERR_AF_UNCONFIGURED;
+               else if (stype == BGP_CLEAR_SOFT_NONE)
                        ret = peer_clear(peer, NULL);
                else
                        ret = peer_clear_soft(peer, afi, safi, stype);
@@ -621,7 +630,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                return CMD_SUCCESS;
        }
 
-       /* Clear all peer-group members. */
+       /* Clear all neighbors belonging to a specific peer-group. */
        if (sort == clear_group) {
                struct peer_group *group;
 
@@ -632,27 +641,37 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                }
 
                for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-                       if (stype == BGP_CLEAR_SOFT_NONE) {
-                               peer_clear(peer, NULL);
-                               continue;
-                       }
-
                        if (!peer->afc[afi][safi])
                                continue;
 
-                       ret = peer_clear_soft(peer, afi, safi, stype);
+                       if (stype == BGP_CLEAR_SOFT_NONE)
+                               ret = peer_clear(peer, NULL);
+                       else
+                               ret = peer_clear_soft(peer, afi, safi, stype);
 
                        if (ret < 0)
                                bgp_clear_vty_error(vty, peer, afi, safi, ret);
+                       else
+                               found = true;
                }
+
+               if (!found)
+                       vty_out(vty,
+                               "%%BGP: No %s peer belonging to peer-group %s is configured\n",
+                               afi_safi_print(afi, safi), arg);
+
                return CMD_SUCCESS;
        }
 
+       /* Clear all external (eBGP) neighbors. */
        if (sort == clear_external) {
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
                        if (peer->sort == BGP_PEER_IBGP)
                                continue;
 
+                       if (!peer->afc[afi][safi])
+                               continue;
+
                        if (stype == BGP_CLEAR_SOFT_NONE)
                                ret = peer_clear(peer, &nnode);
                        else
@@ -660,33 +679,44 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
 
                        if (ret < 0)
                                bgp_clear_vty_error(vty, peer, afi, safi, ret);
+                       else
+                               found = true;
                }
+
+               if (!found)
+                       vty_out(vty,
+                               "%%BGP: No external %s peer is configured\n",
+                               afi_safi_print(afi, safi));
+
                return CMD_SUCCESS;
        }
 
+       /* Clear all neighbors belonging to a specific AS. */
        if (sort == clear_as) {
-               as_t as;
-               int find = 0;
-
-               as = strtoul(arg, NULL, 10);
+               as_t as = strtoul(arg, NULL, 10);
 
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
                        if (peer->as != as)
                                continue;
 
-                       find = 1;
-                       if (stype == BGP_CLEAR_SOFT_NONE)
+                       if (!peer->afc[afi][safi])
+                               ret = BGP_ERR_AF_UNCONFIGURED;
+                       else if (stype == BGP_CLEAR_SOFT_NONE)
                                ret = peer_clear(peer, &nnode);
                        else
                                ret = peer_clear_soft(peer, afi, safi, stype);
 
                        if (ret < 0)
                                bgp_clear_vty_error(vty, peer, afi, safi, ret);
+                       else
+                               found = true;
                }
-               if (!find)
+
+               if (!found)
                        vty_out(vty,
-                               "%%BGP: No peer is configured with AS %s\n",
-                               arg);
+                               "%%BGP: No %s peer is configured with AS %s\n",
+                               afi_safi_print(afi, safi), arg);
+
                return CMD_SUCCESS;
        }
 
@@ -10859,7 +10889,7 @@ static void lcommunity_show_all_iterator(struct hash_backet *backet,
 
        lcom = (struct lcommunity *)backet->data;
        vty_out(vty, "[%p] (%ld) %s\n", (void *)lcom, lcom->refcnt,
-               lcommunity_str(lcom));
+               lcommunity_str(lcom, false));
 }
 
 /* Show BGP's community internal data. */
@@ -13606,6 +13636,24 @@ DEFUN (no_ip_community_list_expanded_all,
        return CMD_SUCCESS;
 }
 
+/* Return configuration string of community-list entry.  */
+static const char *community_list_config_str(struct community_entry *entry)
+{
+       const char *str;
+
+       if (entry->any)
+               str = "";
+       else {
+               if (entry->style == COMMUNITY_LIST_STANDARD)
+                       str = community_str(entry->u.com, false);
+               else if (entry->style == LARGE_COMMUNITY_LIST_STANDARD)
+                       str = lcommunity_str(entry->u.lcom, false);
+               else
+                       str = entry->config;
+       }
+       return str;
+}
+
 static void community_list_show(struct vty *vty, struct community_list *list)
 {
        struct community_entry *entry;
@@ -13631,9 +13679,7 @@ static void community_list_show(struct vty *vty, struct community_list *list)
                else
                        vty_out(vty, "    %s %s\n",
                                community_direct_str(entry->direct),
-                               entry->style == COMMUNITY_LIST_STANDARD
-                                       ? community_str(entry->u.com, false)
-                                       : entry->config);
+                               community_list_config_str(entry));
        }
 }
 
@@ -13985,9 +14031,7 @@ static void lcommunity_list_show(struct vty *vty, struct community_list *list)
                else
                        vty_out(vty, "    %s %s\n",
                                community_direct_str(entry->direct),
-                               entry->style == EXTCOMMUNITY_LIST_STANDARD
-                                       ? entry->u.ecom->str
-                                       : entry->config);
+                               community_list_config_str(entry));
        }
 }
 
@@ -14222,9 +14266,7 @@ static void extcommunity_list_show(struct vty *vty, struct community_list *list)
                else
                        vty_out(vty, "    %s %s\n",
                                community_direct_str(entry->direct),
-                               entry->style == EXTCOMMUNITY_LIST_STANDARD
-                                       ? entry->u.ecom->str
-                                       : entry->config);
+                               community_list_config_str(entry));
        }
 }
 
@@ -14275,22 +14317,6 @@ DEFUN (show_ip_extcommunity_list_arg,
        return CMD_SUCCESS;
 }
 
-/* Return configuration string of community-list entry.  */
-static const char *community_list_config_str(struct community_entry *entry)
-{
-       const char *str;
-
-       if (entry->any)
-               str = "";
-       else {
-               if (entry->style == COMMUNITY_LIST_STANDARD)
-                       str = community_str(entry->u.com, false);
-               else
-                       str = entry->config;
-       }
-       return str;
-}
-
 /* Display community-list and extcommunity-list configuration.  */
 static int community_list_config_write(struct vty *vty)
 {
index 52a246387ee2d945dbf1406c5c797005a06b5db8..4a909d8cdc0247b5c0bb94fcc1b0eb4c248a5f4b 100644 (file)
@@ -2391,12 +2391,25 @@ static void bgp_zebra_process_label_chunk(
        uint8_t response_keep;
        uint32_t first;
        uint32_t last;
+       uint8_t proto;
+       unsigned short instance;
 
        s = zclient->ibuf;
+       STREAM_GETC(s, proto);
+       STREAM_GETW(s, instance);
        STREAM_GETC(s, response_keep);
        STREAM_GETL(s, first);
        STREAM_GETL(s, last);
 
+       if (zclient->redist_default != proto) {
+               zlog_err("Got LM msg with wrong proto %u", proto);
+               return;
+       }
+       if (zclient->instance != instance) {
+               zlog_err("Got LM msg with wrong instance %u", proto);
+               return;
+       }
+
        if (first > last ||
                first < MPLS_LABEL_UNRESERVED_MIN ||
                last > MPLS_LABEL_UNRESERVED_MAX) {
index 1ad6a5c9c8dd0b01dc58b79c5322a0f8a8d7f9ca..340851e8d90ce1c3544ed556ecd23860eb47d9df 100644 (file)
@@ -481,6 +481,9 @@ struct bgp {
        /* EVPN enable - advertise local VNIs and their MACs etc. */
        int advertise_all_vni;
 
+       /* EVPN - use RFC 8365 to auto-derive RT */
+       int advertise_autort_rfc8365;
+
        /* Hash table of Import RTs to EVIs */
        struct hash *import_rt_hash;
 
index 8fa057424a0e02e35e76d07ab382a5097e5fc9db..a0ff314786a5cf9365cd34a344568756675eb677 100644 (file)
@@ -140,7 +140,7 @@ EXTRA_DIST = frr-sphinx.mk \
        manpages/index.rst \
        manpages/isisd.rst \
        manpages/ldpd.rst \
-       manpages/Makefile \
+       manpages/Makefile.am \
        manpages/mtracebis.rst \
        manpages/nhrpd.rst \
        manpages/ospf6d.rst \
@@ -182,7 +182,7 @@ EXTRA_DIST = frr-sphinx.mk \
        developer/index.rst \
        developer/ldpd-basic-test-setup.md \
        developer/library.rst \
-       developer/Makefile \
+       developer/Makefile.in \
        developer/memtypes.rst \
        developer/modules.rst \
        developer/next-hop-tracking.rst \
@@ -195,16 +195,18 @@ EXTRA_DIST = frr-sphinx.mk \
        user/babeld.rst \
        user/basic.rst \
        user/bgp.rst \
+       user/bugs.rst \
        user/conf.py \
        user/eigrpd.rst \
        user/filter.rst \
+       user/getting-started.rst \
        user/glossary.rst \
        user/index.rst \
        user/installation.rst \
        user/ipv6.rst \
        user/isisd.rst \
        user/kernel.rst \
-       user/Makefile \
+       user/Makefile.am \
        user/nhrpd.rst \
        user/ospf6d.rst \
        user/ospfd.rst \
@@ -217,6 +219,7 @@ EXTRA_DIST = frr-sphinx.mk \
        user/routemap.rst \
        user/routeserver.rst \
        user/rpki.rst \
+       user/setup.rst \
        user/sharp.rst \
        user/snmp.rst \
        user/snmptrap.rst \
index 2e7d8573f180f02d77aa6f713fa9af14fb7ec305..81c60dc0a32ad27327ddce0a1aafc0dfffdf5bce 100644 (file)
@@ -1,3 +1,2 @@
 /_templates
 /_build
-!/Makefile.in
diff --git a/doc/developer/Makefile.am b/doc/developer/Makefile.am
new file mode 100644 (file)
index 0000000..76758f9
--- /dev/null
@@ -0,0 +1,8 @@
+# This is necessary to support VPATH builds.
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+# This variable is used as the documentation source location in frr-sphinx.mk
+SOURCESDIR = @srcdir@
+
+include @srcdir@/../frr-sphinx.mk
diff --git a/doc/developer/Makefile.in b/doc/developer/Makefile.in
deleted file mode 100644 (file)
index 76758f9..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# This is necessary to support VPATH builds.
-srcdir = @srcdir@
-VPATH = @srcdir@
-
-# This variable is used as the documentation source location in frr-sphinx.mk
-SOURCESDIR = @srcdir@
-
-include @srcdir@/../frr-sphinx.mk
index 17edb7ef4f9138e34a11a0395479a6b00112dac8..d9fc37c17272798351dbd250bb5f8a3b2027c64f 100644 (file)
@@ -1,17 +1,56 @@
 Ubuntu 18.04LTS
 ===============================================
 
-Install required packages
+Install dependencies
 -------------------------
+Required packages
+^^^^^^^^^^^^^^^^^
 
-Add packages:
+::
+
+    sudo apt-get install \
+        git \
+        autoconf \
+        automake \
+        libtool \
+        make \
+        gawk \
+        libreadline-dev \
+        texinfo \
+        pkg-config \
+        libpam0g-dev \
+        libjson-c-dev \
+        bison \
+        flex \
+        python-pytest \
+        libc-ares-dev \
+        python3-dev \
+        libsystemd-dev \
+        python-ipaddr \
+        python3-sphinx
+
+Optional packages
+^^^^^^^^^^^^^^^^^
+
+Dependencies for additional functionality can be installed as-desired.
+
+Protobuf
+~~~~~~~~
 
 ::
 
-    apt-get install git autoconf automake libtool make gawk libreadline-dev \
-       texinfo pkg-config libpam0g-dev libjson-c-dev bison flex \
-       python-pytest libc-ares-dev python3-dev libsystemd-dev python-ipaddr \
-       python3-sphinx
+    sudo apt-get install \
+        protobuf-c-compiler \
+        libprotobuf-c-dev
+
+ZeroMQ
+~~~~~~
+
+::
+
+    sudo apt-get install \
+        libzmq5 \
+        libzmq3-dev
 
 Get FRR, compile it and install it (from Git)
 ---------------------------------------------
@@ -30,15 +69,21 @@ Add frr groups and user
        --gecos "FRR suite" --shell /sbin/nologin frr
     sudo usermod -a -G frrvty frr
 
-Download Source, configure and compile it
+Download source
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-(You may prefer different options on configure statement. These are just
-an example.)
-
 ::
 
     git clone https://github.com/frrouting/frr.git frr
+
+Configure
+^^^^^^^^^
+Options below are provided as an example.
+
+.. seealso:: *Installation* section of user guide
+
+::
+
     cd frr
     ./bootstrap.sh
     ./configure \
@@ -62,6 +107,23 @@ an example.)
         --enable-systemd=yes \
         --with-pkg-git-version \
         --with-pkg-extra-version=-MyOwnFRRVersion
+
+If optional packages were installed, the associated feature may now be
+enabled.
+
+.. option:: --enable-protobuf
+
+Enable support for protobuf transport
+
+.. option:: --enable-zeromq
+
+Enable support for ZeroMQ transport
+
+Compile
+^^^^^^^
+
+::
+
     make
     make check
     sudo make install
@@ -69,6 +131,21 @@ an example.)
 Create empty FRR configuration files
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+Although not strictly necessary, it's good practice to create empty
+configuration files _before_ starting FRR. This assures that the permissions 
+are correct. If the files are not already present, FRR will create them.
+
+It's also important to consider _which_ files to create. FRR supports writing
+configuration to a monolithic file, ``/etc/frr/frr.conf``, which is not
+recommended
+.. seealso:: *VTYSH* section of user guide
+
+The presence of ``/etc/frr/frr.conf`` on startup implicitly configures FRR to
+ignore daemon-specific configuration files.
+
+Daemon-specific configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
 ::
 
     sudo install -m 755 -o frr -g frr -d /var/log/frr
@@ -83,7 +160,15 @@ Create empty FRR configuration files
     sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf
     sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf
     sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf
-    sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf
+
+Monolithic configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    sudo install -m 755 -o frr -g frr -d /var/log/frr
+    sudo install -m 775 -o frr -g frrvty -d /etc/frr
+    sudo install -m 640 -o frr -g frr /dev/null /etc/frr/frr.conf
 
 Enable IPv4 & IPv6 forwarding
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -101,7 +186,22 @@ other settings)
     #  based on Router Advertisements for this host
     net.ipv6.conf.all.forwarding=1
 
-Enable MPLS Forwarding (with Linux Kernel >= 4.5)
+Add MPLS kernel modules
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default.
+To enable, add the following lines to ``/etc/modules-load.d/modules.conf``:
+
+::
+
+    # Load MPLS Kernel Modules
+    mpls_router
+    mpls_iptunnel
+
+**Reboot** or use ``sysctl -p`` to apply the same config to the running
+system
+
+Enable MPLS Forwarding
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Edit ``/etc/sysctl.conf`` and the following lines. Make sure to add a
@@ -116,20 +216,6 @@ MPLS
     net.mpls.conf.eth2.input=1
     net.mpls.platform_labels=100000
 
-Add MPLS kernel modules
-^^^^^^^^^^^^^^^^^^^^^^^
-
-Add the following lines to ``/etc/modules-load.d/modules.conf``:
-
-::
-
-    # Load MPLS Kernel Modules
-    mpls-router
-    mpls-iptunnel
-
-**Reboot** or use ``sysctl -p`` to apply the same config to the running
-system
-
 Install the systemd service (if rebooted from last step, change directory back to frr directory)
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index 2e7d8573f180f02d77aa6f713fa9af14fb7ec305..81c60dc0a32ad27327ddce0a1aafc0dfffdf5bce 100644 (file)
@@ -1,3 +1,2 @@
 /_templates
 /_build
-!/Makefile.in
diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
new file mode 100644 (file)
index 0000000..009c723
--- /dev/null
@@ -0,0 +1,48 @@
+# This is necessary to support VPATH builds.
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+# This variable is used as the documentation source location in frr-sphinx.mk
+SOURCESDIR = @srcdir@
+
+include @srcdir@/../frr-sphinx.mk
+
+# -----------------------------------------------------------------------------
+# Automake requires that 3rd-party Makefiles recognize these targets.
+# -----------------------------------------------------------------------------
+# install
+# install-data
+# install-exec
+# uninstall
+# install-dvi
+# install-html
+# install-info
+# install-ps
+# install-pdf
+# installdirs
+# check
+# installcheck
+# mostlyclean
+# clean
+# distclean
+# maintainer-clean
+# dvi
+# pdf
+# ps
+# info
+# html
+# tags
+# ctags
+
+# These targets are automatically generated by Sphinx but conflict with
+# implicitly defined Automake rules, so we manually override them to nothing.
+# The other option is deleting the Sphinx-generated rules, which suppresses the
+# warning but kinda screws up the symmetry between Makefiles.
+info: ;
+html: ;
+
+all: man
+
+install-data: man
+
+install: install-data
diff --git a/doc/manpages/Makefile.in b/doc/manpages/Makefile.in
deleted file mode 100644 (file)
index f28746c..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-# This is necessary to support VPATH builds.
-srcdir = @srcdir@
-VPATH = @srcdir@
-
-# This variable is used as the documentation source location in frr-sphinx.mk
-SOURCESDIR = @srcdir@
-
-include @srcdir@/../frr-sphinx.mk
-
-# -----------------------------------------------------------------------------
-# Automake requires that 3rd-party Makefiles recognize these targets.
-# -----------------------------------------------------------------------------
-# install
-# install-data
-# install-exec
-# uninstall
-# install-dvi
-# install-html
-# install-info
-# install-ps
-# install-pdf
-# installdirs
-# check
-# installcheck
-# mostlyclean
-# clean
-# distclean
-# maintainer-clean
-# dvi
-# pdf
-# ps
-# info
-# html
-# tags
-# ctags
-
-# ignore these targets
-EMPTY_AUTOMAKE_TARGETS = dvi pdf ps tags ctags distdir installdirs check installcheck install-dvi install-ps install-html install-pdf install-info install-exec
-.PHONY: $(EMPTY_AUTOMAKE_TARGETS)
-$(EMPTY_AUTOMAKE_TARGETS):
-
-# These targets are automatically generated by Sphinx but conflict with
-# implicitly defined Automake rules, so we manually override them to nothing.
-# The other option is deleting the Sphinx-generated rules, which suppresses the
-# warning but kinda screws up the symmetry between Makefiles.
-info: ;
-html: ;
-
-all: man
-
-install-data: man
-
-install: install-data
-
-mostlyclean distclean maintainer-clean: clean
index 2e7d8573f180f02d77aa6f713fa9af14fb7ec305..81c60dc0a32ad27327ddce0a1aafc0dfffdf5bce 100644 (file)
@@ -1,3 +1,2 @@
 /_templates
 /_build
-!/Makefile.in
diff --git a/doc/user/Makefile.am b/doc/user/Makefile.am
new file mode 100644 (file)
index 0000000..64af2ff
--- /dev/null
@@ -0,0 +1,55 @@
+# This is necessary to support VPATH builds.
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+# This variable is used as the documentation source location in frr-sphinx.mk
+SOURCESDIR = @srcdir@
+
+include @srcdir@/../frr-sphinx.mk
+
+# -----------------------------------------------------------------------------
+# Automake requires that 3rd-party Makefiles recognize these targets.
+# -----------------------------------------------------------------------------
+# install
+# install-data
+# install-exec
+# uninstall
+# install-dvi
+# install-html
+# install-info
+# install-ps
+# install-pdf
+# installdirs
+# check
+# installcheck
+# mostlyclean
+# clean
+# distclean
+# maintainer-clean
+# dvi
+# pdf
+# ps
+# info
+# html
+# tags
+# ctags
+
+# When building 'all', the logic is that we want to make docs that are easily
+# readable by the person that just built them. Technically the reST source is
+# readable in its own right, but we'll also build info and html because those
+# offer sequentially better reading experiences. PDF is not built by default
+# because it takes quite a while.
+all: info
+
+# info and html already have built-in sphinx rules; pdf goes to latexpdf
+pdf: latexpdf
+
+# install user manual as info file
+install-info: info
+       install -d ${DESTDIR}${infodir}
+       gzip < _build/texinfo/frr.info > ${DESTDIR}${infodir}/frr.info.gz
+       install-info _build/texinfo/frr.info ${DESTDIR}${infodir}/dir
+
+install-data: install-info
+
+install: install-data
diff --git a/doc/user/Makefile.in b/doc/user/Makefile.in
deleted file mode 100644 (file)
index 77c6abf..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-# This is necessary to support VPATH builds.
-srcdir = @srcdir@
-VPATH = @srcdir@
-
-# This variable is used as the documentation source location in frr-sphinx.mk
-SOURCESDIR = @srcdir@
-
-include @srcdir@/../frr-sphinx.mk
-
-# -----------------------------------------------------------------------------
-# Automake requires that 3rd-party Makefiles recognize these targets.
-# -----------------------------------------------------------------------------
-# install
-# install-data
-# install-exec
-# uninstall
-# install-dvi
-# install-html
-# install-info
-# install-ps
-# install-pdf
-# installdirs
-# check
-# installcheck
-# mostlyclean
-# clean
-# distclean
-# maintainer-clean
-# dvi
-# pdf
-# ps
-# info
-# html
-# tags
-# ctags
-
-# ignore these targets
-EMPTY_AUTOMAKE_TARGETS = dvi ps tags ctags distdir install-exec install-dvi install-ps installdirs check installcheck install-html install-pdf install-data install
-.PHONY: $(EMPTY_AUTOMAKE_TARGETS)
-$(EMPTY_AUTOMAKE_TARGETS):
-
-# When building 'all', the logic is that we want to make docs that are easily
-# readable by the person that just built them. Technically the reST source is
-# readable in its own right, but we'll also build info and html because those
-# offer sequentially better reading experiences. PDF is not built by default
-# because it takes quite a while.
-all: info
-
-# info and html already have built-in sphinx rules; pdf goes to latexpdf
-pdf: latexpdf
-
-# install user manual as info file
-install-info: info
-       install -d ${DESTDIR}${infodir}
-       gzip < _build/texinfo/frr.info > ${DESTDIR}${infodir}/frr.info.gz
-       install-info _build/texinfo/frr.info ${DESTDIR}${infodir}/dir
-
-install-data: install-info
-
-install: install-data
-
-mostlyclean distclean maintainer-clean: clean
diff --git a/doc/user/getting-started.rst b/doc/user/getting-started.rst
new file mode 100644 (file)
index 0000000..4ef293c
--- /dev/null
@@ -0,0 +1,9 @@
+***************
+Getting Started
+***************
+
+.. toctree::
+   :maxdepth: 2
+
+   installation
+   setup
index f20ff8ec2b6ced8fe7a7fe1398047b17e705a11c..7118022df763a53f3190aabddfe3e2c3b0dae9a9 100644 (file)
@@ -5,7 +5,7 @@ FRRouting User Guide
    :maxdepth: 2
 
    overview
-   installation
+   getting-started
    basic
    vtysh
    filter
index 700a727d8f5ce14a95fafd81a4c5bd566eda72c6..7a430fdf980e238ac2f4d31eb20b117c9a941e54 100644 (file)
@@ -1,8 +1,7 @@
 .. _installation:
 
-************
 Installation
-************
+============
 
 .. index:: How to install FRR
 .. index:: Installation
@@ -10,46 +9,73 @@ Installation
 .. index:: Building the system
 .. index:: Making FRR
 
-Several distributions provide packages for FRR. Check your distribution's
-repositories to find out if a suitable version is available.
+This section covers the basics of building, installing and setting up FRR.
 
-FRR depends on various libraries depending on your operating system.
+From Packages
+-------------
 
-After installing these dependencies, change to the frr source directory and
-issue the following commands:
+The project publishes packages for Red Hat, Centos, Debian and Ubuntu on the
+`GitHub releases <https://github.com/FRRouting/frr/releases>`_. page. External
+contributors offer packages for many other platforms including \*BSD, Alpine,
+Gentoo, Docker, and others. There is currently no documentation on how to use
+those but we hope to add it soon.
 
-::
+From Snapcraft
+--------------
 
-  $ ./bootstrap.sh
-  $ ./configure
-  $ make
-  $ make install
+In addition to traditional packages the project also builds and publishes
+universal Snap images, available at https://snapcraft.io/frr.
 
+From Source
+-----------
 
-.. _configure-the-software:
+Building FRR from source is the best way to ensure you have the latest features
+and bug fixes. Details for each supported platform, including dependency
+package listings, permissions, and other gotchas, are in the developer's
+documentation. This section provides a brief overview on the process.
 
-Configure the Software
-======================
+Getting the Source
+^^^^^^^^^^^^^^^^^^
 
+FRR's source is available on the project
+`GitHub page <https://github.com/FRRouting/frr>`_.
 
-.. _the-configure-script:
+.. code-block:: shell
 
-The Configure Script
---------------------
+   git clone https://github.com/FRRouting/frr.git
 
-.. index:: Configuration options
+When building from Git there are several branches to choose from. The
+``master`` branch is the primary development branch. It should be considered
+unstable. Each release has its own branch named ``stable/X.X``, where ``X.X``
+is the release version.
 
-.. index:: Options for configuring
+In addition, release tarballs are published on the GitHub releases page
+`here <https://github.com/FRRouting/frr/releases>`_.
 
-.. index:: Build options
+Configuration
+^^^^^^^^^^^^^
 
+.. index:: Configuration options
+.. index:: Options for configuring
+.. index:: Build options
 .. index:: Distribution configuration
-
 .. index:: Options to `./configure`
 
-FRR has an excellent configure script which automatically detects most
-host configurations.  There are several additional configure options to
-customize the build to include or exclude specific features and dependencies.
+FRR has an excellent configure script which automatically detects most host
+configurations. There are several additional configure options to customize the
+build to include or exclude specific features and dependencies.
+
+First, update the build system. Change into your FRR source directory and issue:
+
+.. code-block:: shell
+
+   ./bootstrap.sh
+
+This will install any missing build scripts and update the Autotools
+configuration. Once this is done you can move on to choosing your configuration
+options from the list below.
+
+.. _frr-configuration:
 
 .. program:: configure
 
@@ -202,10 +228,9 @@ options to the configuration script.
 .. _least-privilege-support:
 
 Least-Privilege Support
------------------------
+"""""""""""""""""""""""
 
 .. index:: FRR Least-Privileges
-
 .. index:: FRR Privileges
 
 Additionally, you may configure zebra to drop its elevated privileges
@@ -240,112 +265,54 @@ only Linux), FRR will retain only minimal capabilities required and will only
 raise these capabilities for brief periods. On systems without libcap, FRR will
 run as the user specified and only raise its UID to 0 for brief periods.
 
-.. _linux-notes:
-
 Linux Notes
------------
-
-.. index:: Configuring FRR
+"""""""""""
 
 .. index:: Building on Linux boxes
-
 .. index:: Linux configurations
 
-There are several options available only to GNU/Linux systems [#]_.
-If you use GNU/Linux, make sure that the current kernel configuration is what
-you want.  FRR will run with any kernel configuration but some recommendations
-do exist.
-
-
-- :makevar:`CONFIG_NETLINK`
-  Kernel/User Netlink socket. This is a brand new feature which enables an
-  advanced interface between the Linux kernel and zebra (:ref:`kernel-interface`).
-- :makevar:`CONFIG_RTNETLINK`
-  Routing messages.
-  This makes it possible to receive Netlink routing messages.  If you
-  specify this option, *zebra* can detect routing information
-  updates directly from the kernel (:ref:`kernel-interface`).
-- :makevar:`CONFIG_IP_MULTICAST`
-  IP: multicasting.
-  This option should be specified when you use *ripd* (:ref:`rip`) or
-  *ospfd* (:ref:`ospfv2`) because these protocols use multicast.
-
-IPv6 support has been added in GNU/Linux kernel version 2.2.  If you
-try to use the FRR IPv6 feature on a GNU/Linux kernel, please
-make sure the following libraries have been installed.  Please note that
-these libraries will not be needed when you uses GNU C library 2.1
-or upper.
-
-- inet6-apps
-
-  The `inet6-apps` package includes basic IPv6 related libraries such
-  as `inet_ntop` and `inet_pton`.  Some basic IPv6 programs such
-  as *ping*, *ftp*, and *inetd* are also
-  included. The `inet-apps` can be found at
-  `ftp://ftp.inner.net/pub/ipv6/ <ftp://ftp.inner.net/pub/ipv6/>`_.
-
-- net-tools
-
-  The `net-tools` package provides an IPv6 enabled interface and routing
-  utility.  It contains *ifconfig*, *route*, *netstat*, and other tools.
-  `net-tools` may be found at http://www.tazenda.demon.co.uk/phil/net-tools/.
-
-.. _build-the-software:
-
-Build the Software
-==================
-
-After configuring the software, you will need to compile it for your system.
-Simply issue the command *make* in the root of the source directory and the
-software will be compiled. Cliff Notes versions of different compilation
-examples can be found in the Developer's Manual Appendix.  If you have *any*
-problems at this stage, please send a bug report :ref:`bug-reports`.
-
-::
-
-  $ ./bootstrap.sh
-  $ ./configure <appropriate to your system>
-  $ make
-
+There are several options available only to GNU/Linux systems.  If you use
+GNU/Linux, make sure that the current kernel configuration is what you want.
+FRR will run with any kernel configuration but some recommendations do exist.
 
-Install the Software
-====================
+:makevar:`CONFIG_NETLINK`
+   Kernel/User Netlink socket. This is a enables an advanced interface between
+   the Linux kernel and *zebra* (:ref:`kernel-interface`).
 
-Installing the software to your system consists of copying the compiled
-programs and supporting files to a standard location. After the
-installation process has completed, these files have been copied
-from your work directory to :file:`/usr/local/bin`, and :file:`/usr/local/etc`.
+:makevar:`CONFIG_RTNETLINK`
+   This makes it possible to receive Netlink routing messages.  If you specify
+   this option, *zebra* can detect routing information updates directly from
+   the kernel (:ref:`kernel-interface`).
 
-To install the FRR suite, issue the following command at your shell
-prompt:::
+:makevar:`CONFIG_IP_MULTICAST`
+   This option enables IP multicast and should be specified when you use *ripd*
+   (:ref:`rip`) or *ospfd* (:ref:`ospfv2`) because these protocols use
+   multicast.
 
-  $ make install
+Building
+^^^^^^^^
 
-FRR daemons have their own terminal interface or VTY.  After
-installation, you have to setup each beast's port number to connect to
-them. Please add the following entries to :file:`/etc/services`.
+Once you have chosen your configure options, run the configure script and pass
+the options you chose:
 
-::
+.. code-block:: shell
 
-  zebrasrv      2600/tcp                 # zebra service
-  zebra         2601/tcp                 # zebra vty
-  ripd          2602/tcp                 # RIPd vty
-  ripngd        2603/tcp                 # RIPngd vty
-  ospfd         2604/tcp                 # OSPFd vty
-  bgpd          2605/tcp                 # BGPd vty
-  ospf6d        2606/tcp                 # OSPF6d vty
-  ospfapi       2607/tcp                 # ospfapi
-  isisd         2608/tcp                 # ISISd vty
-  nhrpd         2610/tcp                 # nhrpd vty
-  pimd          2611/tcp                 # PIMd vty
+   ./configure \
+       --prefix=/usr \
+       --enable-exampledir=/usr/share/doc/frr/examples/ \
+       --localstatedir=/var/run/frr \
+       --sbindir=/usr/lib/frr \
+       --sysconfdir=/etc/frr \
+       --enable-pimd \
+       --enable-watchfrr \
+       ...
 
+After configuring the software, you are ready to build and install it for your
+system.
 
-If you use a FreeBSD newer than 2.2.8, the above entries are already
-added to :file:`/etc/services` so there is no need to add it. If you
-specify a port number when starting the daemon, these entries may not be
-needed.
+.. code-block:: shell
 
-You may need to make changes to the config files in
-|INSTALL_PREFIX_ETC|. :ref:`config-commands`.
+   make && sudo make install
 
-.. [#] GNU/Linux has very flexible kernel configuration features.
+If everything finishes successfully, FRR should be installed. You should now
+skip to the section on :ref:`basic-setup`.
index 38d55d68ad969e92ee375bdc2af20f044b3b9297..eb24970bee7bd3d99492e600d27f5a573b855631 100644 (file)
@@ -20,6 +20,8 @@ can use FRR library as your program's client user interface.
 
 FRR is distributed under the GNU General Public License.
 
+FRR is a fork of `Quagga <http://www.quagga.net/>`_.
+
 .. _about-frr:
 
 About FRR
@@ -235,7 +237,8 @@ How to get FRR
 The official FRR website is located at |PACKAGE_URL| and contains further
 information, as well as links to additional resources.
 
-FRR is a fork of `Quagga <http://www.quagga.net/>`_.
+Several distributions provide packages for FRR. Check your distribution's
+repositories to find out if a suitable version is available.
 
 Mailing Lists
 =============
index bddf2ba26d0cee7dd5f2e8f07df58912aea6bd39..8080e001f197a609ca61e4e3092695cf76d8605f 100644 (file)
@@ -180,6 +180,18 @@ Route Map Match Command
   interface name specified if the neighbor was specified
   in this manner.
 
+.. index:: match source-protocol PROTOCOL_NAME
+.. clicmd:: match source-protocol PROTOCOL_NAME
+
+  This is a ZEBRA specific match command.  Matches the
+  originating protocol specified.
+
+.. index:: match source-instance NUMBER
+.. clicmd:: match source-instance NUMBER
+
+  This is a ZEBRA specific match command.  The number is a range from (0-255).
+  Matches the originating protocols instance specified.
+
 .. _route-map-set-command:
 
 Route Map Set Command
diff --git a/doc/user/setup.rst b/doc/user/setup.rst
new file mode 100644 (file)
index 0000000..9971c43
--- /dev/null
@@ -0,0 +1,155 @@
+.. _basic-setup:
+
+Basic Setup
+============
+
+After installing FRR, some basic configuration must be completed before it is
+ready to use.
+
+Daemons File
+------------
+After a fresh install, starting FRR will do nothing. This is because daemons
+must be explicitly enabled by editing a file in your configuration directory.
+This file is usually located at :file:`/etc/frr/daemons` and determines which
+daemons are activated when issuing a service start / stop command via init or
+systemd. The file initially looks like this:
+
+::
+
+   zebra=no
+   bgpd=no
+   ospfd=no
+   ospf6d=no
+   ripd=no
+   ripngd=no
+   isisd=no
+   pimd=no
+   ldpd=no
+   nhrpd=no
+   eigrpd=no
+   babeld=no
+   sharpd=no
+   pbrd=no
+
+To enable a particular daemon, simply change the corresponding 'no' to 'yes'.
+Subsequent service restarts should start the daemon.
+
+Daemons Configuration File
+--------------------------
+There is another file that controls the default options passed to daemons when
+starting FRR as a service. This file is located in your configuration
+directory, usually at :file:`/etc/frr/daemons.conf`.
+
+This file has several parts. Here is an example:
+
+::
+
+   #
+   # If this option is set the /etc/init.d/frr script automatically loads
+   # the config via "vtysh -b" when the servers are started.
+   # Check /etc/pam.d/frr if you intend to use "vtysh"!
+   #
+   vtysh_enable=yes
+   zebra_options=" -r -s 90000000 --daemon -A 127.0.0.1"
+   bgpd_options="   --daemon -A 127.0.0.1"
+   ospfd_options="  --daemon -A 127.0.0.1"
+   ospf6d_options=" --daemon -A ::1"
+   ripd_options="   --daemon -A 127.0.0.1"
+   ripngd_options=" --daemon -A ::1"
+   isisd_options="  --daemon -A 127.0.0.1"
+   pimd_options="  --daemon -A 127.0.0.1"
+   ldpd_options="  --daemon -A 127.0.0.1"
+   nhrpd_options="  --daemon -A 127.0.0.1"
+   eigrpd_options="  --daemon -A 127.0.0.1"
+   babeld_options="  --daemon -A 127.0.0.1"
+   sharpd_options="  --daemon -A 127.0.0.1"
+   pbrd_options="  --daemon -A 127.0.0.1"
+
+   # The list of daemons to watch is automatically generated by the init script.
+   watchfrr_enable=yes
+   watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB)
+
+   # If valgrind_enable is 'yes' the frr daemons will be started via valgrind.
+   # The use case for doing so is tracking down memory leaks, etc in frr.
+   valgrind_enable=no
+   valgrind=/usr/bin/valgrind
+
+Breaking this file down:
+
+::
+
+   vtysh_enable=yes
+
+As the comment says, this causes :ref:`VTYSH <vty-shell>` to apply
+configuration when starting the daemons. This is useful for a variety of
+reasons touched on in the VTYSH documentation and should generally be enabled.
+
+::
+
+   zebra_options=" -r -s 90000000 --daemon -A 127.0.0.1"
+   bgpd_options="   --daemon -A 127.0.0.1"
+   ...
+
+The next set of lines controls what options are passed to daemons when started
+from the service script. Usually daemons will have ``--daemon`` and ``-A
+<address>`` specified in order to daemonize and listen for VTY commands on a
+particular address.
+
+::
+
+   # The list of daemons to watch is automatically generated by the init script.
+   watchfrr_enable=yes
+   watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB)
+
+Options for the ``watchfrr``, the watchdog daemon.
+
+::
+
+   valgrind_enable=no
+   valgrind=/usr/bin/valgrind
+
+Whether or not to start FRR daemons under Valgrind. This is primarily useful
+for gathering information for bug reports and for developers.
+``valgrind_enable`` should be ``no`` for production use.
+
+Services
+--------
+FRR daemons have their own terminal interface or VTY.  After installation, it's
+a good idea to setup each daemon's port number to connect to them. To do this
+add the following entries to :file:`/etc/services`.
+
+::
+
+   zebrasrv      2600/tcp                # zebra service
+   zebra         2601/tcp                # zebra vty
+   ripd          2602/tcp                # RIPd vty
+   ripngd        2603/tcp                # RIPngd vty
+   ospfd         2604/tcp                # OSPFd vty
+   bgpd          2605/tcp                # BGPd vty
+   ospf6d        2606/tcp                # OSPF6d vty
+   ospfapi       2607/tcp                # ospfapi
+   isisd         2608/tcp                # ISISd vty
+   babeld        2609/tcp                 # BABELd vty
+   nhrpd         2610/tcp                # nhrpd vty
+   pimd          2611/tcp                # PIMd vty
+   ldpd          2612/tcp                 # LDPd vty
+   eigprd        2613/tcp                 # EIGRPd vty
+
+
+If you use a FreeBSD newer than 2.2.8, the above entries are already added to
+:file:`/etc/services` so there is no need to add it. If you specify a port
+number when starting the daemon, these entries may not be needed.
+
+You may need to make changes to the config files in |INSTALL_PREFIX_ETC|.
+
+systemd
+-------
+Although not installed when installing from source, FRR provides a service file
+for use with ``systemd``. It is located in :file:`tools/frr.service` in the Git
+repository. If ``systemctl status frr.service`` indicates that the FRR service
+is not found, copy the service file from the Git repository into your preferred
+location. A good place is usually ``/etc/systemd/system/``.
+
+After issuing a ``systemctl daemon-reload``, you should be able to start the
+FRR service via ``systemctl start frr``. If this fails, or no daemons are
+started. check the ``journalctl`` logs for an indication of what went wrong.
index 9d927359baabdadc9ee706cb6586bc28ccb0b055..a2cf3627ac2da3b9372ef0f71b5d74f0dd887e6c 100644 (file)
@@ -47,6 +47,14 @@ Besides the common invocation options (:ref:`common-invocation-options`), the
 
    .. seealso:: :ref:`vrf`
 
+.. option:: --v6-rr-semantics
+
+   The linux kernel is receiving the ability to use the same route
+   replacement semantics for v6 that v4 uses.  If you are using a
+   kernel that supports this functionality then run *Zebra* with this
+   option and we will use Route Replace Semantics instead of delete
+   than add.
+
 .. _interface-commands:
 
 Interface Commands
index 69e301fcfabc511205799ede1f835b1174633968..0fa6bde3345262ecff39774896ae304c6775a793 100644 (file)
@@ -1960,19 +1960,17 @@ DEFUN (no_config_password,
        bool warned = false;
 
        if (host.password) {
-               vty_out(vty,
-                       "Please be aware that removing the password is a security risk and "
-                       "you should think twice about this command\n");
-               warned = true;
+               if (!vty_shell_serv(vty)) {
+                       vty_out(vty, NO_PASSWD_CMD_WARNING);
+                       warned = true;
+               }
                XFREE(MTYPE_HOST, host.password);
        }
        host.password = NULL;
 
        if (host.password_encrypt) {
-               if (!warned)
-                       vty_out(vty,
-                               "Please be aware that removing the password is a security risk "
-                               "and you should think twice about this command\n");
+               if (!warned && !vty_shell_serv(vty))
+                       vty_out(vty, NO_PASSWD_CMD_WARNING);
                XFREE(MTYPE_HOST, host.password_encrypt);
        }
        host.password_encrypt = NULL;
@@ -2044,19 +2042,17 @@ DEFUN (no_config_enable_password,
        bool warned = false;
 
        if (host.enable) {
-               vty_out(vty,
-                       "Please be aware that removing the password is a security risk and "
-                       "you should think twice about this command\n");
-               warned = true;
+               if (!vty_shell_serv(vty)) {
+                       vty_out(vty, NO_PASSWD_CMD_WARNING);
+                       warned = true;
+               }
                XFREE(MTYPE_HOST, host.enable);
        }
        host.enable = NULL;
 
        if (host.enable_encrypt) {
-               if (!warned)
-                       vty_out(vty,
-                               "Please be aware that removing the password is a security risk "
-                               "and you should think twice about this command\n");
+               if (!warned && !vty_shell_serv(vty))
+                       vty_out(vty, NO_PASSWD_CMD_WARNING);
                XFREE(MTYPE_HOST, host.enable_encrypt);
        }
        host.enable_encrypt = NULL;
index 9ba53e0907441176c639024b7c73ccc06c51fda2..8d9c39b0ea05ec9805d656e69b7e0b1b7c86c624 100644 (file)
@@ -376,6 +376,10 @@ struct cmd_node {
 
 #define CONF_BACKUP_EXT ".sav"
 
+/* Command warnings. */
+#define NO_PASSWD_CMD_WARNING                                                  \
+       "Please be aware that removing the password is a security risk and you should think twice about this command.\n"
+
 /* IPv4 only machine should not accept IPv6 address for peer's IP
    address.  So we replace VTY command string like below. */
 #define NEIGHBOR_ADDR_STR  "Neighbor address\nIPv6 address\n"
index c4edd3d5bff3e622f8fc35a01c67ad7e0389b0cb..aba4c20166175e27049d126def18c4315e95e25e 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <zebra.h>
 #include <stddef.h>
+#include <pthread.h>
 
 #include "stream.h"
 #include "memory.h"
@@ -1101,6 +1102,7 @@ struct stream_fifo *stream_fifo_new(void)
        struct stream_fifo *new;
 
        new = XCALLOC(MTYPE_STREAM_FIFO, sizeof(struct stream_fifo));
+       pthread_mutex_init(&new->mtx, NULL);
        return new;
 }
 
@@ -1115,7 +1117,16 @@ void stream_fifo_push(struct stream_fifo *fifo, struct stream *s)
        fifo->tail = s;
        fifo->tail->next = NULL;
 
-       fifo->count++;
+       atomic_fetch_add_explicit(&fifo->count, 1, memory_order_release);
+}
+
+void stream_fifo_push_safe(struct stream_fifo *fifo, struct stream *s)
+{
+       pthread_mutex_lock(&fifo->mtx);
+       {
+               stream_fifo_push(fifo, s);
+       }
+       pthread_mutex_unlock(&fifo->mtx);
 }
 
 /* Delete first stream from fifo. */
@@ -1131,7 +1142,8 @@ struct stream *stream_fifo_pop(struct stream_fifo *fifo)
                if (fifo->head == NULL)
                        fifo->tail = NULL;
 
-               fifo->count--;
+               atomic_fetch_sub_explicit(&fifo->count, 1,
+                                         memory_order_release);
 
                /* ensure stream is scrubbed of references to this fifo */
                s->next = NULL;
@@ -1140,12 +1152,37 @@ struct stream *stream_fifo_pop(struct stream_fifo *fifo)
        return s;
 }
 
-/* Return first fifo entry. */
+struct stream *stream_fifo_pop_safe(struct stream_fifo *fifo)
+{
+       struct stream *ret;
+
+       pthread_mutex_lock(&fifo->mtx);
+       {
+               ret = stream_fifo_pop(fifo);
+       }
+       pthread_mutex_unlock(&fifo->mtx);
+
+       return ret;
+}
+
 struct stream *stream_fifo_head(struct stream_fifo *fifo)
 {
        return fifo->head;
 }
 
+struct stream *stream_fifo_head_safe(struct stream_fifo *fifo)
+{
+       struct stream *ret;
+
+       pthread_mutex_lock(&fifo->mtx);
+       {
+               ret = stream_fifo_head(fifo);
+       }
+       pthread_mutex_unlock(&fifo->mtx);
+
+       return ret;
+}
+
 void stream_fifo_clean(struct stream_fifo *fifo)
 {
        struct stream *s;
@@ -1156,11 +1193,26 @@ void stream_fifo_clean(struct stream_fifo *fifo)
                stream_free(s);
        }
        fifo->head = fifo->tail = NULL;
-       fifo->count = 0;
+       atomic_store_explicit(&fifo->count, 0, memory_order_release);
+}
+
+void stream_fifo_clean_safe(struct stream_fifo *fifo)
+{
+       pthread_mutex_lock(&fifo->mtx);
+       {
+               stream_fifo_clean(fifo);
+       }
+       pthread_mutex_unlock(&fifo->mtx);
+}
+
+size_t stream_fifo_count_safe(struct stream_fifo *fifo)
+{
+       return atomic_load_explicit(&fifo->count, memory_order_acquire);
 }
 
 void stream_fifo_free(struct stream_fifo *fifo)
 {
        stream_fifo_clean(fifo);
+       pthread_mutex_destroy(&fifo->mtx);
        XFREE(MTYPE_STREAM_FIFO, fifo);
 }
index cc74e22a6723a7187cfd05a667660d906957943a..e5d325e43ed4940dd65f421d6152e60d892a9d81 100644 (file)
@@ -22,6 +22,9 @@
 #ifndef _ZEBRA_STREAM_H
 #define _ZEBRA_STREAM_H
 
+#include <pthread.h>
+
+#include "frratomic.h"
 #include "mpls.h"
 #include "prefix.h"
 
@@ -107,7 +110,11 @@ struct stream {
 
 /* First in first out queue structure. */
 struct stream_fifo {
-       size_t count;
+       /* lock for mt-safe operations */
+       pthread_mutex_t mtx;
+
+       /* number of streams in this fifo */
+       _Atomic size_t count;
 
        struct stream *head;
        struct stream *tail;
@@ -240,12 +247,94 @@ extern int stream_empty(struct stream *); /* is the stream empty? */
 /* deprecated */
 extern uint8_t *stream_pnt(struct stream *);
 
-/* Stream fifo. */
+/*
+ * Operations on struct stream_fifo.
+ *
+ * Each function has a safe variant, which ensures that the operation performed
+ * is atomic with respect to the operations performed by all other safe
+ * variants. In other words, the safe variants lock the stream_fifo's mutex
+ * before performing their action. These are provided for convenience when
+ * using stream_fifo in a multithreaded context, to alleviate the need for the
+ * caller to implement their own synchronization around the stream_fifo.
+ *
+ * The following functions do not have safe variants. The caller must ensure
+ * that these operations are performed safely in a multithreaded context:
+ * - stream_fifo_new
+ * - stream_fifo_free
+ */
+
+/*
+ * Create a new stream_fifo.
+ *
+ * Returns:
+ *    newly created stream_fifo
+ */
 extern struct stream_fifo *stream_fifo_new(void);
+
+/*
+ * Push a stream onto a stream_fifo.
+ *
+ * fifo
+ *    the stream_fifo to push onto
+ *
+ * s
+ *    the stream to push onto the stream_fifo
+ */
 extern void stream_fifo_push(struct stream_fifo *fifo, struct stream *s);
+extern void stream_fifo_push_safe(struct stream_fifo *fifo, struct stream *s);
+
+/*
+ * Pop a stream off a stream_fifo.
+ *
+ * fifo
+ *    the stream_fifo to pop from
+ *
+ * Returns:
+ *    the next stream in the stream_fifo
+ */
 extern struct stream *stream_fifo_pop(struct stream_fifo *fifo);
+extern struct stream *stream_fifo_pop_safe(struct stream_fifo *fifo);
+
+/*
+ * Retrieve the next stream from a stream_fifo without popping it.
+ *
+ * fifo
+ *    the stream_fifo to operate on
+ *
+ * Returns:
+ *    the next stream that would be returned from stream_fifo_pop
+ */
 extern struct stream *stream_fifo_head(struct stream_fifo *fifo);
+extern struct stream *stream_fifo_head_safe(struct stream_fifo *fifo);
+
+/*
+ * Remove all streams from a stream_fifo.
+ *
+ * fifo
+ *    the stream_fifo to clean
+ */
 extern void stream_fifo_clean(struct stream_fifo *fifo);
+extern void stream_fifo_clean_safe(struct stream_fifo *fifo);
+
+/*
+ * Retrieve number of streams on a stream_fifo.
+ *
+ * fifo
+ *    the stream_fifo to retrieve the count for
+ *
+ * Returns:
+ *    the number of streams on the stream_fifo
+ */
+extern size_t stream_fifo_count_safe(struct stream_fifo *fifo);
+
+/*
+ * Free a stream_fifo.
+ *
+ * Calls stream_fifo_clean, then deinitializes the stream_fifo and frees it.
+ *
+ * fifo
+ *    the stream_fifo to free
+ */
 extern void stream_fifo_free(struct stream_fifo *fifo);
 
 /* This is here because "<< 24" is particularly problematic in C.
index 05bd907589ce4940273098b9c56c6750a2d7e57b..0f7cf350dbad7e1a5a3c4b3a659a8c6c10825664 100644 (file)
@@ -1237,9 +1237,8 @@ stream_failure:
        return 0;
 }
 
-static void zapi_encode_prefix(struct stream *s,
-                             struct prefix *p,
-                             uint8_t family)
+static void zapi_encode_prefix(struct stream *s, struct prefix *p,
+                              uint8_t family)
 {
        struct prefix any;
 
@@ -1254,8 +1253,7 @@ static void zapi_encode_prefix(struct stream *s,
        stream_put(s, &p->u.prefix, prefix_blen(p));
 }
 
-int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s,
-                        struct pbr_rule *zrule)
+int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule)
 {
        stream_reset(s);
        zclient_create_header(s, cmd, zrule->vrf_id);
@@ -1271,11 +1269,11 @@ int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s,
 
        zapi_encode_prefix(s, &(zrule->filter.src_ip),
                           zrule->filter.src_ip.family);
-       stream_putw(s, zrule->filter.src_port);  /* src port */
+       stream_putw(s, zrule->filter.src_port); /* src port */
        zapi_encode_prefix(s, &(zrule->filter.dst_ip),
                           zrule->filter.src_ip.family);
-       stream_putw(s, zrule->filter.dst_port);  /* dst port */
-       stream_putw(s, zrule->filter.fwmark);    /* fwmark */
+       stream_putw(s, zrule->filter.dst_port); /* dst port */
+       stream_putw(s, zrule->filter.fwmark);   /* fwmark */
 
        stream_putl(s, zrule->action.table);
        stream_putl(s, zrule->ifindex);
@@ -1323,8 +1321,8 @@ bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno,
        STREAM_GETL(s, ifi);
 
        if (zclient_debug)
-               zlog_debug("%s: %u %u %u %u", __PRETTY_FUNCTION__,
-                          seq, prio, uni, ifi);
+               zlog_debug("%s: %u %u %u %u", __PRETTY_FUNCTION__, seq, prio,
+                          uni, ifi);
        *seqno = seq;
        *priority = prio;
        *unique = uni;
@@ -1336,9 +1334,8 @@ stream_failure:
        return false;
 }
 
-bool zapi_ipset_notify_decode(struct stream *s,
-                             uint32_t *unique,
-                            enum zapi_ipset_notify_owner *note)
+bool zapi_ipset_notify_decode(struct stream *s, uint32_t *unique,
+                             enum zapi_ipset_notify_owner *note)
 {
        uint32_t uni;
 
@@ -1356,10 +1353,9 @@ stream_failure:
        return false;
 }
 
-bool zapi_ipset_entry_notify_decode(struct stream *s,
-               uint32_t *unique,
-               char *ipset_name,
-               enum zapi_ipset_entry_notify_owner *note)
+bool zapi_ipset_entry_notify_decode(struct stream *s, uint32_t *unique,
+                                   char *ipset_name,
+                                   enum zapi_ipset_entry_notify_owner *note)
 {
        uint32_t uni;
 
@@ -1367,8 +1363,7 @@ bool zapi_ipset_entry_notify_decode(struct stream *s,
 
        STREAM_GETL(s, uni);
 
-       STREAM_GET(ipset_name, s,
-                  ZEBRA_IPSET_NAME_SIZE);
+       STREAM_GET(ipset_name, s, ZEBRA_IPSET_NAME_SIZE);
 
        if (zclient_debug)
                zlog_debug("%s: %u", __PRETTY_FUNCTION__, uni);
@@ -1414,7 +1409,7 @@ struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh)
         */
        if (znh->label_num) {
                nexthop_add_labels(n, ZEBRA_LSP_NONE, znh->label_num,
-                       znh->labels);
+                                  znh->labels);
        }
 
        return n;
@@ -1475,7 +1470,7 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
                if (nhr->nexthops[i].label_num)
                        STREAM_GET(&nhr->nexthops[i].labels[0], s,
                                   nhr->nexthops[i].label_num
-                                  * sizeof(mpls_label_t));
+                                          * sizeof(mpls_label_t));
        }
 
        return true;
@@ -1898,8 +1893,9 @@ struct connected *zebra_interface_address_read(int type, struct stream *s,
                                zlog_warn(
                                        "warning: interface %s address %s "
                                        "with peer flag set, but no peer address!",
-                                       ifp->name, prefix2str(ifc->address, buf,
-                                                             sizeof buf));
+                                       ifp->name,
+                                       prefix2str(ifc->address, buf,
+                                                  sizeof buf));
                                UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
                        }
                }
@@ -2065,7 +2061,7 @@ int lm_label_manager_connect(struct zclient *zclient)
        uint8_t result;
 
        if (zclient_debug)
-               zlog_debug("Connecting to Label Manager");
+               zlog_debug("Connecting to Label Manager (LM)");
 
        if (zclient->sock < 0)
                return -1;
@@ -2085,33 +2081,45 @@ int lm_label_manager_connect(struct zclient *zclient)
 
        ret = writen(zclient->sock, s->data, stream_get_endp(s));
        if (ret < 0) {
-               zlog_err("%s: can't write to zclient->sock", __func__);
+               zlog_err("Can't write to zclient sock");
                close(zclient->sock);
                zclient->sock = -1;
                return -1;
        }
        if (ret == 0) {
-               zlog_err("%s: zclient->sock connection closed", __func__);
+               zlog_err("Zclient sock closed");
                close(zclient->sock);
                zclient->sock = -1;
                return -1;
        }
        if (zclient_debug)
-               zlog_debug("%s: Label manager connect request (%d bytes) sent",
-                          __func__, ret);
+               zlog_debug("LM connect request sent (%d bytes)", ret);
 
        /* read response */
        if (zclient_read_sync_response(zclient, ZEBRA_LABEL_MANAGER_CONNECT)
            != 0)
                return -1;
 
-       /* result */
        s = zclient->ibuf;
+
+       /* read instance and proto */
+       uint8_t proto = stream_getc(s);
+       uint16_t instance = stream_getw(s);
+
+       /* sanity */
+       if (proto != zclient->redist_default)
+               zlog_err(
+                       "Wrong proto (%u) in LM connect response. Should be %u",
+                       proto, zclient->redist_default);
+       if (instance != zclient->instance)
+               zlog_err(
+                       "Wrong instId (%u) in LM connect response. Should be %u",
+                       instance, zclient->instance);
+
+       /* result code */
        result = stream_getc(s);
        if (zclient_debug)
-               zlog_debug(
-                       "%s: Label Manager connect response received, result %u",
-                       __func__, result);
+               zlog_debug("LM connect-response received, result %u", result);
 
        return (int)result;
 }
@@ -2124,10 +2132,8 @@ int lm_label_manager_connect(struct zclient *zclient)
  * @param chunk_size Amount of labels requested
  * @result 0 on success, -1 otherwise
  */
-int zclient_send_get_label_chunk(
-       struct zclient  *zclient,
-       uint8_t         keep,
-       uint32_t        chunk_size)
+int zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep,
+                                uint32_t chunk_size)
 {
        struct stream *s;
 
@@ -2141,6 +2147,10 @@ int zclient_send_get_label_chunk(
        stream_reset(s);
 
        zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, VRF_DEFAULT);
+       /* proto */
+       stream_putc(s, zclient->redist_default);
+       /* instance */
+       stream_putw(s, zclient->instance);
        stream_putc(s, keep);
        stream_putl(s, chunk_size);
 
@@ -2180,6 +2190,10 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
        s = zclient->obuf;
        stream_reset(s);
        zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, VRF_DEFAULT);
+       /* proto */
+       stream_putc(s, zclient->redist_default);
+       /* instance */
+       stream_putw(s, zclient->instance);
        /* keep */
        stream_putc(s, keep);
        /* chunk size */
@@ -2189,26 +2203,39 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
 
        ret = writen(zclient->sock, s->data, stream_get_endp(s));
        if (ret < 0) {
-               zlog_err("%s: can't write to zclient->sock", __func__);
+               zlog_err("Can't write to zclient sock");
                close(zclient->sock);
                zclient->sock = -1;
                return -1;
        }
        if (ret == 0) {
-               zlog_err("%s: zclient->sock connection closed", __func__);
+               zlog_err("Zclient sock closed");
                close(zclient->sock);
                zclient->sock = -1;
                return -1;
        }
        if (zclient_debug)
-               zlog_debug("%s: Label chunk request (%d bytes) sent", __func__,
-                          ret);
+               zlog_debug("Label chunk request (%d bytes) sent", ret);
 
        /* read response */
        if (zclient_read_sync_response(zclient, ZEBRA_GET_LABEL_CHUNK) != 0)
                return -1;
 
+       /* parse response */
        s = zclient->ibuf;
+
+       /* read proto and instance */
+       uint8_t proto = stream_getc(s);
+       uint16_t instance = stream_getw(s);
+
+       /* sanities */
+       if (proto != zclient->redist_default)
+               zlog_err("Wrong proto (%u) in get chunk response. Should be %u",
+                        proto, zclient->redist_default);
+       if (instance != zclient->instance)
+               zlog_err("Wrong instId (%u) in get chunk response Should be %u",
+                        instance, zclient->instance);
+
        /* keep */
        response_keep = stream_getc(s);
        /* start and end labels */
@@ -2218,19 +2245,18 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
        /* not owning this response */
        if (keep != response_keep) {
                zlog_err(
-                       "%s: Invalid Label chunk: %u - %u, keeps mismatch %u != %u",
-                       __func__, *start, *end, keep, response_keep);
+                       "Invalid Label chunk: %u - %u, keeps mismatch %u != %u",
+                       *start, *end, keep, response_keep);
        }
        /* sanity */
        if (*start > *end || *start < MPLS_LABEL_UNRESERVED_MIN
            || *end > MPLS_LABEL_UNRESERVED_MAX) {
-               zlog_err("%s: Invalid Label chunk: %u - %u", __func__, *start,
-                        *end);
+               zlog_err("Invalid Label chunk: %u - %u", *start, *end);
                return -1;
        }
 
        if (zclient_debug)
-               zlog_debug("Label Chunk assign: %u - %u (%u) ", *start, *end,
+               zlog_debug("Label Chunk assign: %u - %u (%u)", *start, *end,
                           response_keep);
 
        return 0;
@@ -2251,7 +2277,7 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
        struct stream *s;
 
        if (zclient_debug)
-               zlog_debug("Releasing Label Chunk");
+               zlog_debug("Releasing Label Chunk %u - %u", start, end);
 
        if (zclient->sock < 0)
                return -1;
@@ -2261,6 +2287,10 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
        stream_reset(s);
        zclient_create_header(s, ZEBRA_RELEASE_LABEL_CHUNK, VRF_DEFAULT);
 
+       /* proto */
+       stream_putc(s, zclient->redist_default);
+       /* instance */
+       stream_putw(s, zclient->instance);
        /* start */
        stream_putl(s, start);
        /* end */
@@ -2271,13 +2301,13 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
 
        ret = writen(zclient->sock, s->data, stream_get_endp(s));
        if (ret < 0) {
-               zlog_err("%s: can't write to zclient->sock", __func__);
+               zlog_err("Can't write to zclient sock");
                close(zclient->sock);
                zclient->sock = -1;
                return -1;
        }
        if (ret == 0) {
-               zlog_err("%s: zclient->sock connection closed", __func__);
+               zlog_err("Zclient sock connection closed");
                close(zclient->sock);
                zclient->sock = -1;
                return -1;
@@ -2325,8 +2355,7 @@ int tm_table_manager_connect(struct zclient *zclient)
                return -1;
 
        if (zclient_debug)
-               zlog_debug("%s: Table manager connect request sent",
-                          __func__);
+               zlog_debug("%s: Table manager connect request sent", __func__);
 
        /* read response */
        if (zclient_read_sync_response(zclient, ZEBRA_TABLE_MANAGER_CONNECT)
@@ -2789,7 +2818,7 @@ static int zclient_read(struct thread *thread)
        case ZEBRA_GET_LABEL_CHUNK:
                if (zclient->label_chunk)
                        (*zclient->label_chunk)(command, zclient, length,
-                                                     vrf_id);
+                                               vrf_id);
                break;
        case ZEBRA_IPSET_NOTIFY_OWNER:
                if (zclient->ipset_notify_owner)
index 0fe0cada391d10b712ab7f7bd314f9ce8089b330..8bd0683f14da5add8fc8f16d2fced19b21085877 100644 (file)
@@ -260,12 +260,12 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                                        listnode_delete(old_route->nh_list,
                                                        rnh);
                                        ospf6_nexthop_delete(rnh);
-                                       route_updated = true;
                                }
                        }
 
                        listnode_delete(old_route->paths, o_path);
                        ospf6_path_free(o_path);
+                       route_updated = true;
 
                        /* Current route's path (adv_router info) is similar
                         * to route being added.
@@ -273,6 +273,19 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                         * Update FIB with effective NHs.
                         */
                        if (listcount(old_route->paths)) {
+                               for (ALL_LIST_ELEMENTS(old_route->paths,
+                                               anode, anext, o_path)) {
+                                       ospf6_merge_nexthops(
+                                               old_route->nh_list,
+                                               o_path->nh_list);
+                               }
+                               /* Update RIB/FIB with effective
+                                * nh_list
+                                */
+                               if (ospf6->route_table->hook_add)
+                                       (*ospf6->route_table->hook_add)
+                                               (old_route);
+
                                if (old_route->path.origin.id
                                            == route->path.origin.id
                                    && old_route->path.origin.adv_router
@@ -290,23 +303,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                                        old_route->path.origin.adv_router =
                                                h_path->origin.adv_router;
                                }
-
-                               if (route_updated) {
-                                       for (ALL_LIST_ELEMENTS(old_route->paths,
-                                                              anode, anext,
-                                                              o_path)) {
-                                               ospf6_merge_nexthops(
-                                                       old_route->nh_list,
-                                                       o_path->nh_list);
-                                       }
-                                       /* Update RIB/FIB with effective
-                                        * nh_list
-                                        */
-                                       if (ospf6->route_table->hook_add)
-                                               (*ospf6->route_table->hook_add)(
-                                                       old_route);
-                                       break;
-                               }
+                               break;
                        } else {
                                if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
                                        prefix2str(&old_route->prefix, buf,
@@ -374,13 +371,6 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                                /* Add a nh_list to new ecmp path */
                                ospf6_copy_nexthops(ecmp_path->nh_list,
                                                    route->nh_list);
-                               /* Merge nexthop to existing route's nh_list */
-                               ospf6_route_merge_nexthops(old_route, route);
-
-                               /* Update RIB/FIB */
-                               if (ospf6->route_table->hook_add)
-                                       (*ospf6->route_table->hook_add)(
-                                               old_route);
 
                                /* Add the new path to route's path list */
                                listnode_add_sort(old_route->paths, ecmp_path);
@@ -400,46 +390,52 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                                                listcount(old_route->nh_list));
                                }
                        } else {
-                               for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
-                                                         nnode, nh)) {
-                                       for (ALL_LIST_ELEMENTS(
-                                                    old_route->nh_list, rnode,
-                                                    rnext, rnh)) {
-                                               if (!ospf6_nexthop_is_same(rnh,
-                                                                          nh))
-                                                       continue;
-
-                                               listnode_delete(
-                                                       old_route->nh_list,
-                                                       rnh);
-                                               ospf6_nexthop_delete(rnh);
-                                       }
-                               }
                                list_delete_all_node(o_path->nh_list);
                                ospf6_copy_nexthops(o_path->nh_list,
                                                    route->nh_list);
+                       }
 
-                               /* Merge nexthop to existing route's nh_list */
-                               ospf6_route_merge_nexthops(old_route, route);
+                       /* Reset nexthop lists, rebuild from brouter table
+                        * for each adv. router.
+                        */
+                       list_delete_all_node(old_route->nh_list);
 
-                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
-                                       prefix2str(&route->prefix, buf,
-                                                  sizeof(buf));
-                                       zlog_debug(
-                                               "%s: existing route %s with effective nh count %u",
-                                               __PRETTY_FUNCTION__, buf,
-                                               old_route->nh_list
-                                                       ? listcount(
-                                                                 old_route
-                                                                         ->nh_list)
-                                                       : 0);
+                       for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
+                                                 o_path)) {
+                               struct ospf6_route *asbr_entry;
+
+                               asbr_entry = ospf6_route_lookup(
+                                                       &o_path->ls_prefix,
+                                                       ospf6->brouter_table);
+                               if (asbr_entry == NULL) {
+                                       if (IS_OSPF6_DEBUG_EXAMIN(
+                                                       AS_EXTERNAL)) {
+                                               prefix2str(&old_route->prefix,
+                                                          buf, sizeof(buf));
+                                               zlog_debug("%s: ls_prfix %s asbr_entry not found.",
+                                                          __PRETTY_FUNCTION__,
+                                                          buf);
+                                       }
+                                       continue;
                                }
+                               ospf6_route_merge_nexthops(old_route,
+                                                          asbr_entry);
+                       }
 
-                               /* Update RIB/FIB */
-                               if (ospf6->route_table->hook_add)
-                                       (*ospf6->route_table->hook_add)(
-                                               old_route);
+                       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                               prefix2str(&route->prefix, buf, sizeof(buf));
+                               zlog_debug("%s: route %s with effective paths %u nh %u",
+                                          __PRETTY_FUNCTION__, buf,
+                                          old_route->paths ?
+                                          listcount(old_route->paths) : 0,
+                                          old_route->nh_list ?
+                                          listcount(old_route->nh_list) : 0);
                        }
+
+                       /* Update RIB/FIB */
+                       if (ospf6->route_table->hook_add)
+                               (*ospf6->route_table->hook_add)(old_route);
+
                        /* Delete the new route its info added to existing
                         * route.
                         */
@@ -509,8 +505,9 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
        route->path.origin.type = lsa->header->type;
        route->path.origin.id = lsa->header->id;
        route->path.origin.adv_router = lsa->header->adv_router;
-
        route->path.prefix_options = external->prefix.prefix_options;
+       memcpy(&route->path.ls_prefix, &asbr_id, sizeof(struct prefix));
+
        if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
                route->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
                route->path.metric_type = 2;
index 26e6deadae89636490f744d00f41cebc79f054cc..d99541ebaddfa8c28ae9a1423546b551921d3430 100644 (file)
@@ -2037,6 +2037,8 @@ static void ospf6_brouter_debug_print(struct ospf6_route *brouter)
        zlog_info("  options: %s router-bits: %s metric-type: %d metric: %d/%d",
                  options, capa, brouter->path.metric_type, brouter->path.cost,
                  brouter->path.u.cost_e2);
+       zlog_info(" paths %u nh %u", listcount(brouter->paths),
+                  listcount(brouter->nh_list));
 }
 
 void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
index 5be96e86d00c030abd80036423b86586493e8941..a4a9233f72a138a94267e42edc4225adee79bf03 100644 (file)
@@ -470,18 +470,6 @@ void pbr_nht_change_group(const char *name)
        pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
 }
 
-/*
- * Since we are writing into the name field which is PBR_MAP_NAMELEN
- * size, we are expecting this to field to be at max 100 bytes.
- * Newer compilers understand that the %s portion may be up to
- * 100 bytes( because of the size of the string.  The %u portion
- * is expected to be 10 bytes.  So in `theory` there are situations
- * where we might truncate.  The reality this is never going to
- * happen( who is going to create a nexthop group name that is
- * over say 30 characters? ).  As such we are expecting the
- * calling function to subtract 10 from the size_t l before
- * we pass it in to get around this new gcc fun.
- */
 char *pbr_nht_nexthop_make_name(char *name, size_t l,
                                uint32_t seqno, char *buffer)
 {
@@ -497,7 +485,7 @@ void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms)
        struct pbr_nexthop_cache lookup;
 
        memset(&find, 0, sizeof(find));
-       pbr_nht_nexthop_make_name(pbrms->parent->name, PBR_MAP_NAMELEN - 10,
+       pbr_nht_nexthop_make_name(pbrms->parent->name, PBR_NHC_NAMELEN,
                                  pbrms->seqno, find.name);
        if (!pbrms->internal_nhg_name)
                pbrms->internal_nhg_name = XSTRDUP(MTYPE_TMP, find.name);
index 2cfb076f003b314f4a2586dcc69762780248c043..e6fdbfd04cb838ffb9a0e541c6294550115194c1 100644 (file)
 
 #include "pbr_map.h"
 
+#define PBR_NHC_NAMELEN PBR_MAP_NAMELEN + 10
+
 struct pbr_nexthop_group_cache {
-       char name[PBR_MAP_NAMELEN];
+       char name[PBR_NHC_NAMELEN];
 
        uint32_t table_id;
 
index b7d2b1a92890d253ccfc38c7d958fca7c918152f..7e0e8d632ba2bc2b447f94df8796252f02514e08 100644 (file)
@@ -269,7 +269,7 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
        if (pbrms->nhg)
                nh = nexthop_exists(pbrms->nhg, &nhop);
        else {
-               char buf[PBR_MAP_NAMELEN];
+               char buf[PBR_NHC_NAMELEN];
 
                if (no) {
                        vty_out(vty, "No nexthops to delete");
@@ -280,7 +280,7 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
                pbrms->internal_nhg_name =
                        XSTRDUP(MTYPE_TMP,
                                pbr_nht_nexthop_make_name(pbrms->parent->name,
-                                                         PBR_MAP_NAMELEN - 10,
+                                                         PBR_NHC_NAMELEN,
                                                          pbrms->seqno,
                                                          buf));
                nh = NULL;
index 8632a4fb2f0f7fa6c3bd2a54a8095a5ac09579e3..362be27a5f7b4d0b7ee90378c0cb31d682537639 100644 (file)
@@ -534,7 +534,7 @@ rm -rf %{buildroot}
 %defattr(-,root,root)
 %doc */*.sample* AUTHORS COPYING
 %doc doc/mpls
-%doc ChangeLog NEWS README SERVICES
+%doc ChangeLog NEWS README
 %if 0%{?frr_user:1}
 %dir %attr(751,%frr_user,%frr_user) %{_sysconfdir}
 %dir %attr(750,%frr_user,%frr_user) /var/log/frr 
index 1c80cf055aaf1bd18dc21bee2d7f504c7f6f82b0..a478b416bf7f687700db89c2493ec7f2b3cb6fef 100644 (file)
@@ -149,6 +149,8 @@ int main(int argc, char **argv, char **envp)
 
        vrf_init(NULL, NULL, NULL, NULL);
 
+       route_map_init();
+
        sharp_zebra_init();
 
        /* Get configuration file. */
index 4d19484a64172191d24818ff277677c114011459..956da9d4edd44baa4b13a4bcae40432346d0f987 100644 (file)
@@ -81,14 +81,16 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
 
 DEFPY (install_routes,
        install_routes_cmd,
-       "sharp install routes A.B.C.D$start nexthop A.B.C.D$nexthop (1-1000000)$routes",
+       "sharp install routes A.B.C.D$start nexthop A.B.C.D$nexthop (1-1000000)$routes [instance (0-255)$instance]",
        "Sharp routing Protocol\n"
        "install some routes\n"
        "Routes to install\n"
        "Address to start /32 generation at\n"
        "Nexthop to use\n"
        "Nexthop address\n"
-       "How many to create\n")
+       "How many to create\n"
+       "Instance to use\n"
+       "Instance\n")
 {
        int i;
        struct prefix p;
@@ -112,7 +114,7 @@ DEFPY (install_routes,
 
        temp = ntohl(p.u.prefix4.s_addr);
        for (i = 0; i < routes; i++) {
-               route_add(&p, &nhop);
+               route_add(&p, (uint8_t)instance, &nhop);
                p.u.prefix4.s_addr = htonl(++temp);
        }
 
@@ -151,17 +153,18 @@ DEFPY(vrf_label, vrf_label_cmd,
 
 DEFPY (remove_routes,
        remove_routes_cmd,
-       "sharp remove routes A.B.C.D$start (1-1000000)$routes",
+       "sharp remove routes A.B.C.D$start (1-1000000)$routes [instance (0-255)$instance]",
        "Sharp Routing Protocol\n"
        "Remove some routes\n"
        "Routes to remove\n"
        "Starting spot\n"
-       "Routes to uniinstall\n")
+       "Routes to uniinstall\n"
+       "instance to use\n"
+       "Value of instance\n")
 {
        int i;
        struct prefix p;
        uint32_t temp;
-
        total_routes = routes;
        removed_routes = 0;
 
@@ -175,7 +178,7 @@ DEFPY (remove_routes,
 
        temp = ntohl(p.u.prefix4.s_addr);
        for (i = 0; i < routes; i++) {
-               route_delete(&p);
+               route_delete(&p, (uint8_t)instance);
                p.u.prefix4.s_addr = htonl(++temp);
        }
 
index 999255e9254e08f812ab649da3f03326b9ec2093..fcb555170b8870d94c6422da6b370456d5a59db5 100644 (file)
@@ -176,7 +176,7 @@ void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label)
        zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP);
 }
 
-void route_add(struct prefix *p, struct nexthop *nh)
+void route_add(struct prefix *p, uint8_t instance, struct nexthop *nh)
 {
        struct zapi_route api;
        struct zapi_nexthop *api_nh;
@@ -184,6 +184,7 @@ void route_add(struct prefix *p, struct nexthop *nh)
        memset(&api, 0, sizeof(api));
        api.vrf_id = VRF_DEFAULT;
        api.type = ZEBRA_ROUTE_SHARP;
+       api.instance = instance;
        api.safi = SAFI_UNICAST;
        memcpy(&api.prefix, p, sizeof(*p));
 
@@ -200,7 +201,7 @@ void route_add(struct prefix *p, struct nexthop *nh)
        zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
 }
 
-void route_delete(struct prefix *p)
+void route_delete(struct prefix *p, uint8_t instance)
 {
        struct zapi_route api;
 
@@ -208,6 +209,7 @@ void route_delete(struct prefix *p)
        api.vrf_id = VRF_DEFAULT;
        api.type = ZEBRA_ROUTE_SHARP;
        api.safi = SAFI_UNICAST;
+       api.instance = instance;
        memcpy(&api.prefix, p, sizeof(*p));
        zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
 
index 0c906fc4ffd10fc97ed7ae2121fefb46527b50c1..58438ed01d821b2f9b8c1f9eda64062e493254e5 100644 (file)
@@ -25,7 +25,7 @@
 extern void sharp_zebra_init(void);
 
 extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label);
-extern void route_add(struct prefix *p, struct nexthop *nh);
-extern void route_delete(struct prefix *p);
+extern void route_add(struct prefix *p, uint8_t instance, struct nexthop *nh);
+extern void route_delete(struct prefix *p, uint8_t instance);
 extern void sharp_zebra_nexthop_watch(struct prefix *p, bool watch);
 #endif
index 703c1d05fc0c9280dc8fecb7808707ae353046b4..6a193259276d3cec9d3dc296b5edc3be199638e6 100644 (file)
@@ -215,6 +215,7 @@ EXTRA_DIST = \
     lib/test_ttable.refout \
     lib/test_zlog.py \
     lib/test_graph.py \
+    lib/test_graph.refout \
     ospf6d/test_lsdb.py \
     ospf6d/test_lsdb.in \
     ospf6d/test_lsdb.refout \
index 01ba00776781efeb93c14a57ffd3c2018a7f521c..30de9d7711b2b51e07f9ed9b64b4430f3321e8bc 100644 (file)
@@ -341,6 +341,7 @@ static int vtysh_execute_func(const char *line, int pager)
 
        if (user_mode) {
                if (strncmp("en", vector_slot(vline, 0), 2) == 0) {
+                       cmd_free_strvec(vline);
                        fprintf(stdout, "%% Command not allowed: enable\n");
                        return CMD_WARNING;
                }
@@ -845,27 +846,29 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp)
        return (retcode);
 }
 
-/* We don't care about the point of the cursor when '?' is typed. */
-static int vtysh_rl_describe(void)
+/*
+ * Function processes cli commands terminated with '?' character when entered
+ * through either 'vtysh' or 'vtysh -c' interfaces.
+ */
+static int vtysh_process_questionmark(const char *input, int input_len)
 {
-       int ret;
+       int ret, width = 0;
        unsigned int i;
-       vector vline;
-       vector describe;
-       int width;
+       vector vline, describe;
        struct cmd_token *token;
 
-       vline = cmd_make_strvec(rl_line_buffer);
+       if (!input)
+               return 1;
+
+       vline = cmd_make_strvec(input);
 
        /* In case of '> ?'. */
        if (vline == NULL) {
                vline = vector_init(1);
                vector_set(vline, NULL);
-       } else if (rl_end && isspace((int)rl_line_buffer[rl_end - 1]))
+       } else if (input_len && isspace((int)input[input_len - 1]))
                vector_set(vline, NULL);
 
-       fprintf(stdout, "\n");
-
        describe = cmd_describe_command(vline, vty, &ret);
 
        /* Ambiguous and no match error. */
@@ -874,7 +877,6 @@ static int vtysh_rl_describe(void)
                cmd_free_strvec(vline);
                vector_free(describe);
                fprintf(stdout, "%% Ambiguous command.\n");
-               rl_on_new_line();
                return 0;
                break;
        case CMD_ERR_NO_MATCH:
@@ -882,7 +884,6 @@ static int vtysh_rl_describe(void)
                if (describe)
                        vector_free(describe);
                fprintf(stdout, "%% There is no matched command.\n");
-               rl_on_new_line();
                return 0;
                break;
        }
@@ -932,9 +933,61 @@ static int vtysh_rl_describe(void)
        cmd_free_strvec(vline);
        vector_free(describe);
 
+       return 0;
+}
+
+/*
+ * Entry point for user commands terminated with '?' character and typed through
+ * the usual vtysh's stdin interface. This is the function being registered with
+ * readline() api's.
+ */
+static int vtysh_rl_describe(void)
+{
+       int ret;
+
+       fprintf(stdout, "\n");
+
+       ret = vtysh_process_questionmark(rl_line_buffer, rl_end);
        rl_on_new_line();
 
-       return 0;
+       return ret;
+}
+
+/*
+ * Function in charged of processing vtysh instructions terminating with '?'
+ * character and received through the 'vtysh -c' interface. If user's
+ * instruction is well-formatted, we will call the same processing routine
+ * utilized by the traditional vtysh's stdin interface.
+ */
+int vtysh_execute_command_questionmark(char *input)
+{
+       int input_len, qmark_count = 0;
+       const char *str;
+
+       if (!(input && *input))
+               return 1;
+
+       /* Finding out question_mark count and strlen */
+       for (str = input; *str; ++str) {
+               if (*str == '?')
+                       qmark_count++;
+       }
+       input_len = str - input;
+
+       /*
+        * Verify that user's input terminates in '?' and that patterns such as
+        * 'cmd ? subcmd ?' are prevented.
+        */
+       if (qmark_count != 1 || input[input_len - 1] != '?')
+               return 1;
+
+       /*
+        * Questionmark-processing function is not expecting to receive '?'
+        * character in input string.
+        */
+       input[input_len - 1] = '\0';
+
+       return vtysh_process_questionmark(input, input_len - 1);
 }
 
 /* Result of cmd_complete_command() call will be stored here
@@ -2372,6 +2425,8 @@ DEFUNSH(VTYSH_ALL, no_vtysh_config_password, no_vtysh_password_cmd,
        "no password", NO_STR
        "Modify the terminal connection password\n")
 {
+       vty_out(vty, NO_PASSWD_CMD_WARNING);
+
        return CMD_SUCCESS;
 }
 
@@ -2390,6 +2445,8 @@ DEFUNSH(VTYSH_ALL, no_vtysh_config_enable_password,
        "Modify enable password parameters\n"
        "Assign the privileged level password\n")
 {
+       vty_out(vty, NO_PASSWD_CMD_WARNING);
+
        return CMD_SUCCESS;
 }
 
index f3e58f309e8d85516864d05dc30b6678c1141dbf..ccfdd6557b425da2fda33c42419c026330030e05 100644 (file)
@@ -71,6 +71,7 @@ void vtysh_user_init(void);
 
 int vtysh_execute(const char *);
 int vtysh_execute_no_pager(const char *);
+int vtysh_execute_command_questionmark(char *input);
 
 char *vtysh_prompt(void);
 
index cd59d8094b95c35541f17cea470ba93a2c68397f..3dd70983bc27a8847a11670ce840f6d4594b3453 100644 (file)
@@ -611,7 +611,16 @@ int main(int argc, char **argv, char **env)
                        if (logfile)
                                log_it(cmd->line);
 
-                       ret = vtysh_execute_no_pager(cmd->line);
+                       /*
+                        * Parsing logic for regular commands will be different than
+                        * for those commands requiring further processing, such as
+                        * cli instructions terminating with question-mark character.
+                        */
+                       if (!vtysh_execute_command_questionmark(cmd->line))
+                               ret = CMD_SUCCESS;
+                       else
+                               ret = vtysh_execute_no_pager(cmd->line);
+
                        if (!no_error
                            && !(ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON
                                 || ret == CMD_WARNING))
index 190ac1e57f7ec7571f4306a7fb1fe3642bd30e16..f3fa3ba94efd618e9730c46527f8c2f64f14390f 100644 (file)
@@ -50,7 +50,6 @@ DEFINE_MTYPE_STATIC(LBL_MGR, LM_CHUNK, "Label Manager Chunk");
  * it will be a proxy to relay messages to external label manager
  * This zclient thus is to connect to it
  */
-static struct stream *ibuf;
 static struct stream *obuf;
 static struct zclient *zclient;
 bool lm_is_external;
@@ -60,7 +59,7 @@ static void delete_label_chunk(void *val)
        XFREE(MTYPE_LM_CHUNK, val);
 }
 
-static int relay_response_back(struct zserv *zserv)
+static int relay_response_back(void)
 {
        int ret = 0;
        struct stream *src, *dst;
@@ -69,49 +68,72 @@ static int relay_response_back(struct zserv *zserv)
        uint8_t version;
        vrf_id_t vrf_id;
        uint16_t resp_cmd;
+       uint8_t proto;
+       const char *proto_str;
+       unsigned short instance;
+       struct zserv *zserv;
 
+       /* input buffer with msg from label manager */
        src = zclient->ibuf;
-       dst = obuf;
 
        stream_reset(src);
 
+       /* parse header */
        ret = zclient_read_header(src, zclient->sock, &size, &marker, &version,
                                  &vrf_id, &resp_cmd);
        if (ret < 0 && errno != EAGAIN) {
-               zlog_err("%s: Error reading Label Manager response: %s",
-                        __func__, strerror(errno));
+               zlog_err("Error reading Label Manager response: %s",
+                        strerror(errno));
                return -1;
        }
-       zlog_debug("%s: Label Manager response received, %d bytes", __func__,
-                  size);
+       zlog_debug("Label Manager response received, %d bytes", size);
        if (size == 0)
                return -1;
 
-       /* send response back */
+       /* Get the 'proto' field of the message */
+       proto = stream_getc(src);
+
+       /* Get the 'instance' field of the message */
+       instance = stream_getw(src);
+
+       proto_str = zebra_route_string(proto);
+
+       /* lookup the client to relay the msg to */
+       zserv = zebra_find_client(proto, instance);
+       if (!zserv) {
+               zlog_err(
+                       "Error relaying LM response: can't find client %s, instance %u",
+                       proto_str, instance);
+               return -1;
+       }
+       zlog_debug("Found client to relay LM response to client %s instance %u",
+                  proto_str, instance);
+
+       /* copy msg into output buffer */
+       dst = obuf;
        stream_copy(dst, src);
-       ret = writen(zserv->sock, src->data, stream_get_endp(src));
+
+       /* send response back */
+       ret = writen(zserv->sock, dst->data, stream_get_endp(dst));
        if (ret <= 0) {
-               zlog_err("%s: Error sending Label Manager response back: %s",
-                        __func__, strerror(errno));
+               zlog_err("Error relaying LM response to %s instance %u: %s",
+                        proto_str, instance, strerror(errno));
                return -1;
        }
-       zlog_debug("%s: Label Manager response (%d bytes) sent back", __func__,
-                  ret);
+       zlog_debug("Relayed LM response (%d bytes) to %s instance %u", ret,
+                  proto_str, instance);
 
        return 0;
 }
 
 static int lm_zclient_read(struct thread *t)
 {
-       struct zserv *zserv;
        int ret;
 
-       /* Get socket to zebra. */
-       zserv = THREAD_ARG(t);
        zclient->t_read = NULL;
 
        /* read response and send it back */
-       ret = relay_response_back(zserv);
+       ret = relay_response_back();
 
        return ret;
 }
@@ -125,6 +147,10 @@ static int reply_error(int cmd, struct zserv *zserv, vrf_id_t vrf_id)
 
        zclient_create_header(s, cmd, vrf_id);
 
+       /* proto */
+       stream_putc(s, zserv->proto);
+       /* instance */
+       stream_putw(s, zserv->instance);
        /* result */
        stream_putc(s, 1);
 
@@ -148,38 +174,73 @@ static int reply_error(int cmd, struct zserv *zserv, vrf_id_t vrf_id)
  * @return 0 on success, -1 otherwise
  */
 int zread_relay_label_manager_request(int cmd, struct zserv *zserv,
-                                     vrf_id_t vrf_id)
+                                     struct stream *msg, vrf_id_t vrf_id)
 {
-       struct stream *src, *dst;
+       struct stream *dst;
        int ret = 0;
+       uint8_t proto;
+       const char *proto_str;
+       unsigned short instance;
 
        if (zclient->sock < 0) {
-               zlog_err(
-                       "%s: Error relaying label chunk request: no zclient socket",
-                       __func__);
+               zlog_err("Unable to relay LM request: no socket");
                reply_error(cmd, zserv, vrf_id);
                return -1;
        }
 
+       /* peek msg to get proto and instance id. This zebra, which acts as
+        * a proxy needs to have such values for each client in order to
+        * relay responses back to it.
+        */
+
+       /* Get the 'proto' field of incoming msg */
+       proto = stream_getc(msg);
+
+       /* Get the 'instance' field of incoming msg */
+       instance = stream_getw(msg);
+
+       /* stringify proto */
+       proto_str = zebra_route_string(proto);
+
+       /* check & set client proto if unset */
+       if (zserv->proto && zserv->proto != proto) {
+               zlog_warn("Client proto(%u) != msg proto(%u)", zserv->proto,
+                         proto);
+               return -1;
+       }
+
+       /* check & set client instance if unset */
+       if (zserv->instance && zserv->instance != instance) {
+               zlog_err("Client instance(%u) != msg instance(%u)",
+                        zserv->instance, instance);
+               return -1;
+       }
+
+       /* recall proto and instance */
+       zserv->instance = instance;
+       zserv->proto = proto;
+
        /* in case there's any incoming message enqueued, read and forward it */
        while (ret == 0)
-               ret = relay_response_back(zserv);
+               ret = relay_response_back();
 
-       /* Send request to external label manager */
-       src = ibuf;
+       /* get the msg buffer used toward the 'master' Label Manager */
        dst = zclient->obuf;
 
-       stream_copy(dst, src);
+       /* copy the message */
+       stream_copy(dst, msg);
 
+       /* Send request to external label manager */
        ret = writen(zclient->sock, dst->data, stream_get_endp(dst));
        if (ret <= 0) {
-               zlog_err("%s: Error relaying label chunk request: %s", __func__,
-                        strerror(errno));
+               zlog_err("Error relaying LM request from %s instance %u: %s",
+                        proto_str, instance, strerror(errno));
                reply_error(cmd, zserv, vrf_id);
                return -1;
        }
-       zlog_debug("%s: Label chunk request relayed. %d bytes sent", __func__,
-                  ret);
+       zlog_debug("Relayed LM request (%d bytes) from %s instance %u", ret,
+                  proto_str, instance);
+
 
        /* Release label chunk has no response */
        if (cmd == ZEBRA_RELEASE_LABEL_CHUNK)
@@ -187,7 +248,7 @@ int zread_relay_label_manager_request(int cmd, struct zserv *zserv,
 
        /* make sure we listen to the response */
        if (!zclient->t_read)
-               thread_add_read(zclient->master, lm_zclient_read, zserv,
+               thread_add_read(zclient->master, lm_zclient_read, NULL,
                                zclient->sock, &zclient->t_read);
 
        return 0;
@@ -276,7 +337,7 @@ void label_manager_init(char *lm_zserv_path)
 {
        /* this is an actual label manager */
        if (!lm_zserv_path) {
-               zlog_debug("Initializing own label manager");
+               zlog_debug("Initializing internal label manager");
                lm_is_external = false;
                lbl_mgr.lc_list = list_new();
                lbl_mgr.lc_list->del = delete_label_chunk;
@@ -287,7 +348,6 @@ void label_manager_init(char *lm_zserv_path)
                lm_zclient_init(lm_zserv_path);
        }
 
-       ibuf = stream_new(ZEBRA_MAX_PACKET_SIZ);
        obuf = stream_new(ZEBRA_MAX_PACKET_SIZ);
 
        hook_register(zapi_client_close, release_daemon_label_chunks);
@@ -393,6 +453,5 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
 void label_manager_close()
 {
        list_delete_and_null(&lbl_mgr.lc_list);
-       stream_free(ibuf);
        stream_free(obuf);
 }
index b998372224ad02cc679cfd19c6e7aeb8e51dafab..3e3def5f98bbf47eaf7a18e11cc6da2a4786c65d 100644 (file)
@@ -64,7 +64,7 @@ struct label_manager {
 bool lm_is_external;
 
 int zread_relay_label_manager_request(int cmd, struct zserv *zserv,
-                                     vrf_id_t vrf_id);
+                                     struct stream *msg, vrf_id_t vrf_id);
 void label_manager_init(char *lm_zserv_path);
 struct label_manager_chunk *assign_label_chunk(uint8_t proto,
                                               unsigned short instance,
index 9a495c89405705ebee6830e55bc79720af2d3151..da9fe95123c5dd3a3bd6707aaee8cd2d381e10f5 100644 (file)
@@ -75,24 +75,29 @@ int allow_delete = 0;
 /* Don't delete kernel route. */
 int keep_kernel_mode = 0;
 
+bool v6_rr_semantics = false;
+
 #ifdef HAVE_NETLINK
 /* Receive buffer size for netlink socket */
 uint32_t nl_rcvbufsize = 4194304;
 #endif /* HAVE_NETLINK */
 
+#define OPTION_V6_RR_SEMANTICS 2000
 /* Command line options. */
-struct option longopts[] = {{"batch", no_argument, NULL, 'b'},
-                           {"allow_delete", no_argument, NULL, 'a'},
-                           {"keep_kernel", no_argument, NULL, 'k'},
-                           {"socket", required_argument, NULL, 'z'},
-                           {"ecmp", required_argument, NULL, 'e'},
-                           {"label_socket", no_argument, NULL, 'l'},
-                           {"retain", no_argument, NULL, 'r'},
+struct option longopts[] = {
+       {"batch", no_argument, NULL, 'b'},
+       {"allow_delete", no_argument, NULL, 'a'},
+       {"keep_kernel", no_argument, NULL, 'k'},
+       {"socket", required_argument, NULL, 'z'},
+       {"ecmp", required_argument, NULL, 'e'},
+       {"label_socket", no_argument, NULL, 'l'},
+       {"retain", no_argument, NULL, 'r'},
 #ifdef HAVE_NETLINK
-                           {"vrfwnetns", no_argument, NULL, 'n'},
-                           {"nl-bufsize", required_argument, NULL, 's'},
+       {"vrfwnetns", no_argument, NULL, 'n'},
+       {"nl-bufsize", required_argument, NULL, 's'},
+       {"v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS},
 #endif /* HAVE_NETLINK */
-                           {0}};
+       {0}};
 
 zebra_capabilities_t _caps_p[] = {
        ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, ZCAP_NET_RAW,
@@ -224,21 +229,22 @@ int main(int argc, char **argv)
 #endif
                ,
                longopts,
-               "  -b, --batch        Runs in batch mode\n"
-               "  -a, --allow_delete Allow other processes to delete zebra routes\n"
-               "  -z, --socket       Set path of zebra socket\n"
-               "  -e, --ecmp         Specify ECMP to use.\n"
-               "  -l, --label_socket Socket to external label manager\n"
-               "  -k, --keep_kernel  Don't delete old routes which installed by zebra.\n"
-               "  -r, --retain       When program terminates, retain added route by zebra.\n"
+               "  -b, --batch           Runs in batch mode\n"
+               "  -a, --allow_delete    Allow other processes to delete zebra routes\n"
+               "  -z, --socket          Set path of zebra socket\n"
+               "  -e, --ecmp            Specify ECMP to use.\n"
+               "  -l, --label_socket    Socket to external label manager\n"
+               "  -k, --keep_kernel     Don't delete old routes which installed by zebra.\n"
+               "  -r, --retain          When program terminates, retain added route by zebra.\n"
 #ifdef HAVE_NETLINK
-               "  -n, --vrfwnetns    Set VRF with NetNS\n"
-               "  -s, --nl-bufsize   Set netlink receive buffer size\n"
+               "  -n, --vrfwnetns       Set VRF with NetNS\n"
+               "  -s, --nl-bufsize      Set netlink receive buffer size\n"
+               "      --v6-rr-semantics Use v6 RR semantics\n"
 #endif /* HAVE_NETLINK */
 #if defined(HANDLE_ZAPI_FUZZING)
-               "  -c <file>          Bypass normal startup use this file for tetsting of zapi"
+               "  -c <file>             Bypass normal startup use this file for tetsting of zapi"
 #endif
-               );
+       );
 
        while (1) {
                int opt = frr_getopt(argc, argv, NULL);
@@ -292,6 +298,9 @@ int main(int argc, char **argv)
                        logicalrouter_configure_backend(
                                LOGICALROUTER_BACKEND_OFF);
                        break;
+               case OPTION_V6_RR_SEMANTICS:
+                       v6_rr_semantics = true;
+                       break;
 #endif /* HAVE_NETLINK */
 #if defined(HANDLE_ZAPI_FUZZING)
                case 'c':
index 5a6565aec9cf145c0c6a1f814047a0dd920dcd55..b1387815bad85660d349cd630704ef9d21620760 100644 (file)
@@ -539,8 +539,8 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re,
        afi = family2afi(rn->p.family);
        if (rmap_name)
                ret = zebra_import_table_route_map_check(
-                       afi, re->type, &rn->p, re->ng.nexthop, re->vrf_id,
-                       re->tag, rmap_name);
+                       afi, re->type, re->instance, &rn->p, re->ng.nexthop,
+                       re->vrf_id, re->tag, rmap_name);
 
        if (ret != RMAP_MATCH) {
                UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED);
index 7b9e6d56a78f7e92e87b6039dd6a8105cfaef4f9..209f085ed13d7fc618d6b35096b3c061c6a2990c 100644 (file)
@@ -456,4 +456,5 @@ extern void static_config_install_delayed_routes(struct zebra_vrf *zvrf);
 
 extern pid_t pid;
 
+extern bool v6_rr_semantics;
 #endif /*_ZEBRA_RIB_H */
index 9510a0e12c2b452c02fa25b010d4647c65578b70..8ab70c8d4b0c3b7cabc97e8f0cedbabb70690b46 100644 (file)
@@ -1308,8 +1308,7 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
 
        struct zebra_ns *zns = zebra_ns_lookup(ns_id);
 
-       memset(&req.n, 0, sizeof(req.n));
-       memset(&req.ndm, 0, sizeof(req.ndm));
+       memset(&req, 0, sizeof(req));
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
        req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
@@ -1666,8 +1665,7 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
        struct zebra_ns *zns;
 
        zns = zvrf->zns;
-       memset(&req.n, 0, sizeof(req.n));
-       memset(&req.ndm, 0, sizeof(req.ndm));
+       memset(&req, 0, sizeof(req));
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
        req.n.nlmsg_flags = NLM_F_REQUEST;
@@ -1698,7 +1696,7 @@ void kernel_route_rib(struct route_node *rn, struct prefix *p,
        assert(old || new);
 
        if (new) {
-               if (p->family == AF_INET)
+               if (p->family == AF_INET || v6_rr_semantics)
                        ret = netlink_route_multipath(RTM_NEWROUTE, p, src_p,
                                                      new, (old) ? 1 : 0);
                else {
@@ -1759,8 +1757,7 @@ static int netlink_vxlan_flood_list_update(struct interface *ifp,
        struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
 
        zns = zvrf->zns;
-       memset(&req.n, 0, sizeof(req.n));
-       memset(&req.ndm, 0, sizeof(req.ndm));
+       memset(&req, 0, sizeof(req));
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
        req.n.nlmsg_flags = NLM_F_REQUEST;
@@ -2075,8 +2072,7 @@ static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid,
                return -1;
        }
 
-       memset(&req.n, 0, sizeof(req.n));
-       memset(&req.ndm, 0, sizeof(req.ndm));
+       memset(&req, 0, sizeof(req));
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
        req.n.nlmsg_flags = NLM_F_REQUEST;
@@ -2392,8 +2388,7 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip,
        struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
 
        zns = zvrf->zns;
-       memset(&req.n, 0, sizeof(req.n));
-       memset(&req.ndm, 0, sizeof(req.ndm));
+       memset(&req, 0, sizeof(req));
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
        req.n.nlmsg_flags = NLM_F_REQUEST;
index 6bd12391dbf223148baedb5735db572bfdf1cc60..9a18cc22f0c5500c090b7ef1c2cb56515129a187 100644 (file)
@@ -887,6 +887,10 @@ static int zsend_assign_label_chunk_response(struct zserv *client,
        zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id);
 
        if (lmc) {
+               /* proto */
+               stream_putc(s, lmc->proto);
+               /* instance */
+               stream_putw(s, lmc->instance);
                /* keep */
                stream_putc(s, lmc->keep);
                /* start and end labels */
@@ -912,6 +916,12 @@ static int zsend_label_manager_connect_response(struct zserv *client,
 
        zclient_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id);
 
+       /* proto */
+       stream_putc(s, client->proto);
+
+       /* instance */
+       stream_putw(s, client->instance);
+
        /* result */
        stream_putc(s, result);
 
@@ -2397,6 +2407,26 @@ static void zread_label_manager_connect(struct zserv *client,
 stream_failure:
        return;
 }
+static int msg_client_id_mismatch(const char *op, struct zserv *client,
+                                 uint8_t proto, unsigned int instance)
+{
+       if (proto != client->proto) {
+               zlog_err("%s: msg vs client proto mismatch, client=%u msg=%u",
+                        op, client->proto, proto);
+               /* TODO: fail when BGP sets proto and instance */
+               /* return 1; */
+       }
+
+       if (instance != client->instance) {
+               zlog_err(
+                       "%s: msg vs client instance mismatch, client=%u msg=%u",
+                       op, client->instance, instance);
+               /* TODO: fail when BGP sets proto and instance */
+               /* return 1; */
+       }
+
+       return 0;
+}
 
 static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
                                  vrf_id_t vrf_id)
@@ -2405,21 +2435,32 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
        uint8_t keep;
        uint32_t size;
        struct label_manager_chunk *lmc;
+       uint8_t proto;
+       unsigned short instance;
 
        /* Get input stream.  */
        s = msg;
 
        /* Get data. */
+       STREAM_GETC(s, proto);
+       STREAM_GETW(s, instance);
        STREAM_GETC(s, keep);
        STREAM_GETL(s, size);
 
+       /* detect client vs message (proto,instance) mismatch */
+       if (msg_client_id_mismatch("Get-label-chunk", client, proto, instance))
+               return;
+
        lmc = assign_label_chunk(client->proto, client->instance, keep, size);
        if (!lmc)
-               zlog_err("%s: Unable to assign Label Chunk of size %u",
-                        __func__, size);
+               zlog_err(
+                       "Unable to assign Label Chunk of size %u to %s instance %u",
+                       size, zebra_route_string(client->proto),
+                       client->instance);
        else
-               zlog_debug("Assigned Label Chunk %u - %u to %u", lmc->start,
-                          lmc->end, keep);
+               zlog_debug("Assigned Label Chunk %u - %u to %s instance %u",
+                          lmc->start, lmc->end,
+                          zebra_route_string(client->proto), client->instance);
        /* send response back */
        zsend_assign_label_chunk_response(client, vrf_id, lmc);
 
@@ -2431,14 +2472,23 @@ static void zread_release_label_chunk(struct zserv *client, struct stream *msg)
 {
        struct stream *s;
        uint32_t start, end;
+       uint8_t proto;
+       unsigned short instance;
 
        /* Get input stream.  */
        s = msg;
 
        /* Get data. */
+       STREAM_GETC(s, proto);
+       STREAM_GETW(s, instance);
        STREAM_GETL(s, start);
        STREAM_GETL(s, end);
 
+       /* detect client vs message (proto,instance) mismatch */
+       if (msg_client_id_mismatch("Release-label-chunk", client, proto,
+                                  instance))
+               return;
+
        release_label_chunk(client->proto, client->instance, start, end);
 
 stream_failure:
@@ -2452,7 +2502,7 @@ static void zread_label_manager_request(ZAPI_HANDLER_ARGS)
 
        /* external label manager */
        if (lm_is_external)
-               zread_relay_label_manager_request(hdr->command, client,
+               zread_relay_label_manager_request(hdr->command, client, msg,
                                                  zvrf_id(zvrf));
        /* this is a label manager */
        else {
index 7ec640164afcc57081cd5ba519379e93bd31d0d3..dec4ed06a97e5bd937d3cb61a087a975df35bef1 100644 (file)
@@ -924,7 +924,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
        memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
 
        /* It'll get set if required inside */
-       ret = zebra_route_map_check(family, re->type, p, nexthop,
+       ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
                                    nexthop->vrf_id, re->tag);
        if (ret == RMAP_DENYMATCH) {
                if (IS_ZEBRA_DEBUG_RIB) {
index 013e841a5caa70f0901f57cab772ae8c57d8af00..10ba88880a8935363f93d59715a9aecc6181371e 100644 (file)
@@ -49,6 +49,7 @@ struct nh_rmap_obj {
        struct nexthop *nexthop;
        vrf_id_t vrf_id;
        uint32_t source_protocol;
+       uint8_t instance;
        int metric;
        route_tag_t tag;
 };
@@ -287,7 +288,7 @@ DEFUN (no_match_ip_nexthop_prefix_len,
 
 DEFUN (match_source_protocol,
        match_source_protocol_cmd,
-       "match source-protocol <bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static>",
+       "match source-protocol <bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static|sharp>",
        MATCH_STR
        "Match protocol via which the route was learnt\n"
        "BGP protocol\n"
@@ -303,7 +304,8 @@ DEFUN (match_source_protocol,
        "Routes from directly connected peer\n"
        "Routes from system configuration\n"
        "Routes from kernel\n"
-       "Statically configured routes\n")
+       "Statically configured routes\n"
+       "SHARP process\n")
 {
        char *proto = argv[2]->text;
        int i;
@@ -319,7 +321,7 @@ DEFUN (match_source_protocol,
 
 DEFUN (no_match_source_protocol,
        no_match_source_protocol_cmd,
-       "no match source-protocol [<bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static>]",
+       "no match source-protocol [<bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static|sharp>]",
        NO_STR
        MATCH_STR
        "No match protocol via which the route was learnt\n"
@@ -336,13 +338,40 @@ DEFUN (no_match_source_protocol,
        "Routes from directly connected peer\n"
        "Routes from system configuration\n"
        "Routes from kernel\n"
-       "Statically configured routes\n")
+       "Statically configured routes\n"
+       "SHARP process\n")
 {
        char *proto = (argc == 4) ? argv[3]->text : NULL;
        return zebra_route_match_delete(vty, "source-protocol", proto,
                                        RMAP_EVENT_MATCH_DELETED);
 }
 
+DEFUN (match_source_instance,
+       match_source_instance_cmd,
+       "match source-instance (0-255)",
+       MATCH_STR
+       "Match the protocol's instance number\n"
+       "The instance number\n")
+{
+       char *instance = argv[2]->arg;
+
+       return zebra_route_match_add(vty, "source-instance", instance,
+                                    RMAP_EVENT_MATCH_ADDED);
+}
+
+DEFUN (no_match_source_instance,
+       no_match_source_instance_cmd,
+       "no match source-instance [(0-255)]",
+       NO_STR MATCH_STR
+       "Match the protocol's instance number\n"
+       "The instance number\n")
+{
+       char *instance = (argc == 4) ? argv[3]->arg : NULL;
+
+       return zebra_route_match_delete(vty, "source-instance", instance,
+                                       RMAP_EVENT_MATCH_ADDED);
+}
+
 /* set functions */
 
 DEFUN (set_src,
@@ -1172,6 +1201,47 @@ static struct route_map_rule_cmd route_match_source_protocol_cmd = {
        "source-protocol", route_match_source_protocol,
        route_match_source_protocol_compile, route_match_source_protocol_free};
 
+/* `source-instance` */
+static route_map_result_t route_match_source_instance(void *rule,
+                                                     struct prefix *prefix,
+                                                     route_map_object_t type,
+                                                     void *object)
+{
+       uint8_t *instance = (uint8_t *)rule;
+       struct nh_rmap_obj *nh_data;
+
+       if (type != RMAP_ZEBRA)
+               return RMAP_NOMATCH;
+
+       nh_data = (struct nh_rmap_obj *)object;
+       if (!nh_data)
+               return RMAP_DENYMATCH;
+
+       return (nh_data->instance == *instance) ? RMAP_MATCH : RMAP_NOMATCH;
+}
+
+static void *route_match_source_instance_compile(const char *arg)
+{
+       uint8_t *instance;
+       int i;
+
+       i = atoi(arg);
+       instance = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint8_t));
+
+       *instance = i;
+
+       return instance;
+}
+
+static void route_match_source_instance_free(void *rule)
+{
+       XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static struct route_map_rule_cmd route_match_source_instance_cmd = {
+       "source-instance", route_match_source_instance,
+       route_match_source_instance_compile, route_match_source_instance_free};
+
 /* `set src A.B.C.D' */
 
 /* Set src. */
@@ -1252,7 +1322,7 @@ void zebra_route_map_write_delay_timer(struct vty *vty)
 }
 
 route_map_result_t zebra_route_map_check(int family, int rib_type,
-                                        struct prefix *p,
+                                        uint8_t instance, struct prefix *p,
                                         struct nexthop *nexthop,
                                         vrf_id_t vrf_id, route_tag_t tag)
 {
@@ -1263,6 +1333,7 @@ route_map_result_t zebra_route_map_check(int family, int rib_type,
        nh_obj.nexthop = nexthop;
        nh_obj.vrf_id = vrf_id;
        nh_obj.source_protocol = rib_type;
+       nh_obj.instance = instance;
        nh_obj.metric = 0;
        nh_obj.tag = tag;
 
@@ -1296,9 +1367,10 @@ void zebra_del_import_table_route_map(afi_t afi, uint32_t table)
 }
 
 route_map_result_t
-zebra_import_table_route_map_check(int family, int re_type, struct prefix *p,
-                                  struct nexthop *nexthop, vrf_id_t vrf_id,
-                                  route_tag_t tag, const char *rmap_name)
+zebra_import_table_route_map_check(int family, int re_type, uint8_t instance,
+                                  struct prefix *p, struct nexthop *nexthop,
+                                  vrf_id_t vrf_id, route_tag_t tag,
+                                  const char *rmap_name)
 {
        struct route_map *rmap = NULL;
        route_map_result_t ret = RMAP_DENYMATCH;
@@ -1307,6 +1379,7 @@ zebra_import_table_route_map_check(int family, int re_type, struct prefix *p,
        nh_obj.nexthop = nexthop;
        nh_obj.vrf_id = vrf_id;
        nh_obj.source_protocol = re_type;
+       nh_obj.instance = instance;
        nh_obj.metric = 0;
        nh_obj.tag = tag;
 
@@ -1331,6 +1404,7 @@ route_map_result_t zebra_nht_route_map_check(int family, int client_proto,
        nh_obj.nexthop = nexthop;
        nh_obj.vrf_id = nexthop->vrf_id;
        nh_obj.source_protocol = re->type;
+       nh_obj.instance = re->instance;
        nh_obj.metric = re->metric;
        nh_obj.tag = re->tag;
 
@@ -1471,6 +1545,8 @@ void zebra_route_map_init()
        route_map_install_match(&route_match_ipv6_address_prefix_len_cmd);
        route_map_install_match(&route_match_ip_nexthop_prefix_len_cmd);
        route_map_install_match(&route_match_source_protocol_cmd);
+       route_map_install_match(&route_match_source_instance_cmd);
+
        /* */
        route_map_install_set(&route_set_src_cmd);
        /* */
@@ -1482,6 +1558,9 @@ void zebra_route_map_init()
        install_element(RMAP_NODE, &no_match_ip_address_prefix_len_cmd);
        install_element(RMAP_NODE, &match_source_protocol_cmd);
        install_element(RMAP_NODE, &no_match_source_protocol_cmd);
+       install_element(RMAP_NODE, &match_source_instance_cmd);
+       install_element(RMAP_NODE, &no_match_source_instance_cmd);
+
        /* */
        install_element(RMAP_NODE, &set_src_cmd);
        install_element(RMAP_NODE, &no_set_src_cmd);
index 14c7c58848020a9dbe48e5fc3012d4c826ef943b..20d425a2bcebb81a45844572b937bffb2b70f668 100644 (file)
@@ -34,14 +34,14 @@ extern void zebra_del_import_table_route_map(afi_t afi, uint32_t table);
 extern void zebra_route_map_write_delay_timer(struct vty *);
 
 extern route_map_result_t
-zebra_import_table_route_map_check(int family, int rib_type, struct prefix *p,
-                                  struct nexthop *nexthop, vrf_id_t vrf_id,
-                                  route_tag_t tag, const char *rmap_name);
-extern route_map_result_t zebra_route_map_check(int family, int rib_type,
-                                               struct prefix *p,
-                                               struct nexthop *nexthop,
-                                               vrf_id_t vrf_id,
-                                               route_tag_t tag);
+zebra_import_table_route_map_check(int family, int rib_type, uint8_t instance,
+                                  struct prefix *p, struct nexthop *nexthop,
+                                  vrf_id_t vrf_id, route_tag_t tag,
+                                  const char *rmap_name);
+extern route_map_result_t
+zebra_route_map_check(int family, int rib_type, uint8_t instance,
+                     struct prefix *p, struct nexthop *nexthop,
+                     vrf_id_t vrf_id, route_tag_t tag);
 extern route_map_result_t
 zebra_nht_route_map_check(int family, int client_proto, struct prefix *p,
                          struct route_entry *, struct nexthop *nexthop);
index 3278c86b992790b2d3fa47de18ef71cdf621cade..90604215e75dcd9899edba2a44f11efdcb0d1fd6 100644 (file)
@@ -56,7 +56,6 @@ DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor");
 
 /* definitions */
 
-
 /* static function declarations */
 static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p,
                                    uint16_t cmd);
@@ -183,6 +182,47 @@ static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac,
                              int uninstall);
 
 /* Private functions */
+static int host_rb_entry_compare(const struct host_rb_entry *hle1,
+                                const struct host_rb_entry *hle2)
+{
+       if (hle1->p.family < hle2->p.family)
+               return -1;
+
+       if (hle1->p.family > hle2->p.family)
+               return 1;
+
+       if (hle1->p.prefixlen < hle2->p.prefixlen)
+               return -1;
+
+       if (hle1->p.prefixlen > hle2->p.prefixlen)
+               return 1;
+
+       if (hle1->p.family == AF_INET) {
+               if (hle1->p.u.prefix4.s_addr < hle2->p.u.prefix4.s_addr)
+                       return -1;
+
+               if (hle1->p.u.prefix4.s_addr > hle2->p.u.prefix4.s_addr)
+                       return 1;
+
+               return 0;
+       } else {
+               zlog_warn("%s: Unexpected family type: %d", __PRETTY_FUNCTION__,
+                         hle1->p.family);
+               return 0;
+       }
+}
+RB_GENERATE(host_rb_tree_entry, host_rb_entry, hl_entry, host_rb_entry_compare);
+
+static uint32_t rb_host_count(struct host_rb_tree_entry *hrbe)
+{
+       struct host_rb_entry *hle;
+       uint32_t count = 0;
+
+       RB_FOREACH (hle, host_rb_tree_entry, hrbe)
+               count++;
+
+       return count;
+}
 
 /*
  * Return number of valid MACs in a VNI's MAC hash table - all
@@ -435,20 +475,20 @@ static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty,
 {
        char buf1[ETHER_ADDR_STRLEN];
        char buf2[INET6_ADDRSTRLEN];
-       struct listnode *node = NULL;
-       struct prefix *p = NULL;
        json_object *json_hosts = NULL;
+       struct host_rb_entry *hle;
 
        if (!json) {
                vty_out(vty, "Ip: %s\n",
                        ipaddr2str(&n->ip, buf2, sizeof(buf2)));
                vty_out(vty, "  RMAC: %s\n",
                        prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
-               vty_out(vty, "  Refcount: %d\n", listcount(n->host_list));
+               vty_out(vty, "  Refcount: %d\n",
+                       rb_host_count(&n->host_rb));
                vty_out(vty, "  Prefixes:\n");
-               for (ALL_LIST_ELEMENTS_RO(n->host_list, node, p))
+               RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
                        vty_out(vty, "    %s\n",
-                               prefix2str(p, buf2, sizeof(buf2)));
+                               prefix2str(&hle->p, buf2, sizeof(buf2)));
        } else {
                json_hosts = json_object_new_array();
                json_object_string_add(
@@ -456,11 +496,12 @@ static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty,
                json_object_string_add(
                        json, "routerMac",
                        prefix_mac2str(&n->emac, buf2, sizeof(buf2)));
-               json_object_int_add(json, "refCount", listcount(n->host_list));
-               for (ALL_LIST_ELEMENTS_RO(n->host_list, node, p))
+               json_object_int_add(json, "refCount",
+                                   rb_host_count(&n->host_rb));
+               RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
                        json_object_array_add(json_hosts,
                                              json_object_new_string(prefix2str(
-                                                     p, buf2, sizeof(buf2))));
+                                                                               &hle->p, buf2, sizeof(buf2))));
                json_object_object_add(json, "prefixList", json_hosts);
        }
 }
@@ -471,20 +512,19 @@ static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty,
 {
        char buf1[ETHER_ADDR_STRLEN];
        char buf2[PREFIX_STRLEN];
-       struct listnode *node = NULL;
-       struct prefix *p = NULL;
        json_object *json_hosts = NULL;
+       struct host_rb_entry *hle;
 
        if (!json) {
                vty_out(vty, "MAC: %s\n",
                        prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1)));
                vty_out(vty, " Remote VTEP: %s\n",
                        inet_ntoa(zrmac->fwd_info.r_vtep_ip));
-               vty_out(vty, " Refcount: %d\n", listcount(zrmac->host_list));
+               vty_out(vty, " Refcount: %d\n", rb_host_count(&zrmac->host_rb));
                vty_out(vty, "  Prefixes:\n");
-               for (ALL_LIST_ELEMENTS_RO(zrmac->host_list, node, p))
+               RB_FOREACH (hle, host_rb_tree_entry, &zrmac->host_rb)
                        vty_out(vty, "    %s\n",
-                               prefix2str(p, buf2, sizeof(buf2)));
+                               prefix2str(&hle->p, buf2, sizeof(buf2)));
        } else {
                json_hosts = json_object_new_array();
                json_object_string_add(
@@ -493,11 +533,12 @@ static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty,
                json_object_string_add(json, "vtepIp",
                                       inet_ntoa(zrmac->fwd_info.r_vtep_ip));
                json_object_int_add(json, "refCount",
-                                   listcount(zrmac->host_list));
-               for (ALL_LIST_ELEMENTS_RO(zrmac->host_list, node, p))
-                       json_object_array_add(json_hosts,
-                                             json_object_new_string(prefix2str(
-                                                     p, buf2, sizeof(buf2))));
+                                   rb_host_count(&zrmac->host_rb));
+               RB_FOREACH (hle, host_rb_tree_entry, &zrmac->host_rb)
+                       json_object_array_add(
+                               json_hosts,
+                               json_object_new_string(prefix2str(
+                                       &hle->p, buf2, sizeof(buf2))));
                json_object_object_add(json, "prefixList", json_hosts);
        }
 }
@@ -3042,42 +3083,38 @@ static void zl3vni_cleanup_all(struct hash_backet *backet, void *args)
        zebra_vxlan_process_l3vni_oper_down(zl3vni);
 }
 
-static int is_host_present_in_host_list(struct list *list, struct prefix *host)
+static void rb_find_or_add_host(struct host_rb_tree_entry *hrbe,
+                               struct prefix *host)
 {
-       struct listnode *node = NULL;
-       struct prefix *p = NULL;
+       struct host_rb_entry lookup;
+       struct host_rb_entry *hle;
 
-       for (ALL_LIST_ELEMENTS_RO(list, node, p)) {
-               if (prefix_same(p, host))
-                       return 1;
-       }
-       return 0;
-}
+       memset(&lookup, 0, sizeof(lookup));
+       memcpy(&lookup.p, host, sizeof(*host));
 
-static void host_list_add_host(struct list *list, struct prefix *host)
-{
-       struct prefix *p = NULL;
+       hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup);
+       if (hle)
+               return;
 
-       p = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct prefix));
-       memcpy(p, host, sizeof(struct prefix));
+       hle = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct host_rb_entry));
+       memcpy(hle, &lookup, sizeof(lookup));
 
-       listnode_add_sort(list, p);
+       RB_INSERT(host_rb_tree_entry, hrbe, hle);
 }
 
-static void host_list_delete_host(struct list *list, struct prefix *host)
+static void rb_delete_host(struct host_rb_tree_entry *hrbe, struct prefix *host)
 {
-       struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
-       struct prefix *p = NULL;
+       struct host_rb_entry lookup;
+       struct host_rb_entry *hle;
 
-       for (ALL_LIST_ELEMENTS(list, node, nnode, p)) {
-               if (prefix_same(p, host)) {
-                       XFREE(MTYPE_HOST_PREFIX, p);
-                       node_to_del = node;
-               }
-       }
+       memset(&lookup, 0, sizeof(lookup));
+       memcpy(&lookup.p, host, sizeof(*host));
+
+       hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup);
+       if (hle)
+               RB_REMOVE(host_rb_tree_entry, hrbe, hle);
 
-       if (node_to_del)
-               list_delete_node(list, node_to_del);
+       return;
 }
 
 /*
@@ -3123,8 +3160,7 @@ static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac)
        zrmac = hash_get(zl3vni->rmac_table, &tmp_rmac, zl3vni_rmac_alloc);
        assert(zrmac);
 
-       zrmac->host_list = list_new();
-       zrmac->host_list->cmp = (int (*)(void *, void *))prefix_cmp;
+       RB_INIT(host_rb_tree_entry, &zrmac->host_rb);
 
        SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE);
        SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC);
@@ -3138,10 +3174,14 @@ static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac)
 static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac)
 {
        zebra_mac_t *tmp_rmac;
+       struct host_rb_entry *hle;
 
-       if (zrmac->host_list)
-               list_delete_and_null(&zrmac->host_list);
-       zrmac->host_list = NULL;
+       while (!RB_EMPTY(host_rb_tree_entry, &zrmac->host_rb)) {
+               hle = RB_ROOT(host_rb_tree_entry, &zrmac->host_rb);
+
+               RB_REMOVE(host_rb_tree_entry, &zrmac->host_rb, hle);
+               XFREE(MTYPE_HOST_PREFIX, hle);
+       }
 
        tmp_rmac = hash_release(zl3vni->rmac_table, zrmac);
        if (tmp_rmac)
@@ -3231,8 +3271,8 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac,
                zl3vni_rmac_install(zl3vni, zrmac);
        }
 
-       if (!is_host_present_in_host_list(zrmac->host_list, host_prefix))
-               host_list_add_host(zrmac->host_list, host_prefix);
+       rb_find_or_add_host(&zrmac->host_rb, host_prefix);
+
        return 0;
 }
 
@@ -3241,9 +3281,9 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac,
 static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac,
                                  struct prefix *host_prefix)
 {
-       host_list_delete_host(zrmac->host_list, host_prefix);
-       if (list_isempty(zrmac->host_list)) {
+       rb_delete_host(&zrmac->host_rb, host_prefix);
 
+       if (RB_EMPTY(host_rb_tree_entry, &zrmac->host_rb)) {
                /* uninstall from kernel */
                zl3vni_rmac_uninstall(zl3vni, zrmac);
 
@@ -3296,8 +3336,7 @@ static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *ip,
        n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc);
        assert(n);
 
-       n->host_list = list_new();
-       n->host_list->cmp = (int (*)(void *, void *))prefix_cmp;
+       RB_INIT(host_rb_tree_entry, &n->host_rb);
 
        memcpy(&n->emac, mac, ETH_ALEN);
        SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
@@ -3312,10 +3351,14 @@ static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *ip,
 static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n)
 {
        zebra_neigh_t *tmp_n;
+       struct host_rb_entry *hle;
 
-       if (n->host_list)
-               list_delete_and_null(&n->host_list);
-       n->host_list = NULL;
+       while (!RB_EMPTY(host_rb_tree_entry, &n->host_rb)) {
+               hle = RB_ROOT(host_rb_tree_entry, &n->host_rb);
+
+               RB_REMOVE(host_rb_tree_entry, &n->host_rb, hle);
+               XFREE(MTYPE_HOST_PREFIX, hle);
+       }
 
        tmp_n = hash_release(zl3vni->nh_table, n);
        if (tmp_n)
@@ -3380,8 +3423,7 @@ static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip,
                zl3vni_nh_install(zl3vni, nh);
        }
 
-       if (!is_host_present_in_host_list(nh->host_list, host_prefix))
-               host_list_add_host(nh->host_list, host_prefix);
+       rb_find_or_add_host(&nh->host_rb, host_prefix);
 
        return 0;
 }
@@ -3390,9 +3432,9 @@ static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip,
 static void zl3vni_remote_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *nh,
                                 struct prefix *host_prefix)
 {
-       host_list_delete_host(nh->host_list, host_prefix);
-       if (list_isempty(nh->host_list)) {
+       rb_delete_host(&nh->host_rb, host_prefix);
 
+       if (RB_EMPTY(host_rb_tree_entry, &nh->host_rb)) {
                /* uninstall from kernel */
                zl3vni_nh_uninstall(zl3vni, nh);
 
index b4a8b5d4803ac5e9f29f3bdbe9f2dd4c616da87a..fa7075f2de875ccaea81645178f32336e10d28a6 100644 (file)
@@ -215,6 +215,15 @@ static inline void zl3vni_get_rmac(zebra_l3vni_t *zl3vni, struct ethaddr *rmac)
                memcpy(rmac->octet, zl3vni->svi_if->hw_addr, ETH_ALEN);
 }
 
+struct host_rb_entry {
+       RB_ENTRY(host_rb_entry) hl_entry;
+
+       struct prefix p;
+};
+
+RB_HEAD(host_rb_tree_entry, host_rb_entry);
+RB_PROTOTYPE(host_rb_tree_entry, host_rb_entry, hl_entry,
+            host_rb_entry_compare);
 /*
  * MAC hash table.
  *
@@ -253,7 +262,7 @@ struct zebra_mac_t_ {
        struct list *neigh_list;
 
        /* list of hosts pointing to this remote RMAC */
-       struct list *host_list;
+       struct host_rb_tree_entry host_rb;
 };
 
 /*
@@ -327,7 +336,7 @@ struct zebra_neigh_t_ {
        struct in_addr r_vtep_ip;
 
        /* list of hosts pointing to this remote NH entry */
-       struct list *host_list;
+       struct host_rb_tree_entry host_rb;
 };
 
 /*