From 72261ecd22495d23ce80a699bb799694981fffe8 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 7 Feb 2019 14:55:06 +0100 Subject: [PATCH 001/142] lib: interface handling where zebra not yet ready other daemons need to sync with zebra to get to know which vrf backend is available. in that time, there may be interface configuration available. in that specific case, the vrf backend returned is not known. A specific return value is sent back. This will be useful to know which specific algorithm to apply. Signed-off-by: Philippe Guibert --- lib/if.c | 1 + lib/vrf.c | 4 ++++ lib/vrf.h | 5 +++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/if.c b/lib/if.c index 0fd65da03a..6ae75939e7 100644 --- a/lib/if.c +++ b/lib/if.c @@ -1281,6 +1281,7 @@ static int lib_interface_create(enum nb_event event, vrf->name); return NB_ERR_VALIDATION; } + if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) { ifp = if_lookup_by_name_all_vrf(ifname); if (ifp && ifp->vrf_id != vrf->vrf_id) { diff --git a/lib/vrf.c b/lib/vrf.c index f9f14822cb..c0dd7f5cf7 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -56,6 +56,7 @@ struct vrf_id_head vrfs_by_id = RB_INITIALIZER(&vrfs_by_id); struct vrf_name_head vrfs_by_name = RB_INITIALIZER(&vrfs_by_name); static int vrf_backend; +static int vrf_backend_configured; static struct zebra_privs_t *vrf_daemon_privs; static char vrf_default_name[VRF_NAMSIZ] = VRF_DEFAULT_NAME_INTERNAL; @@ -613,12 +614,15 @@ int vrf_is_backend_netns(void) int vrf_get_backend(void) { + if (!vrf_backend_configured) + return VRF_BACKEND_UNKNOWN; return vrf_backend; } void vrf_configure_backend(int vrf_backend_netns) { vrf_backend = vrf_backend_netns; + vrf_backend_configured = 1; } int vrf_handler_create(struct vty *vty, const char *vrfname, diff --git a/lib/vrf.h b/lib/vrf.h index e80796f480..1a850f218f 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -97,8 +97,9 @@ RB_PROTOTYPE(vrf_name_head, vrf, name_entry, vrf_name_compare) DECLARE_QOBJ_TYPE(vrf) /* Allow VRF with netns as backend */ -#define VRF_BACKEND_VRF_LITE 0 -#define VRF_BACKEND_NETNS 1 +#define VRF_BACKEND_VRF_LITE 0 +#define VRF_BACKEND_NETNS 1 +#define VRF_BACKEND_UNKNOWN 2 extern struct vrf_id_head vrfs_by_id; extern struct vrf_name_head vrfs_by_name; From b0b97a7f6103202884311ae52c7bac202c83d24e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 11 Feb 2019 13:48:12 +0100 Subject: [PATCH 002/142] lib: handling vrf backend unknown case on interface search algorithm, at initialisation, when reading config file, the vrf backend may not be yet known ( because zebra did not sync yet with daemon). For that, avoid searching interface name in a separate vrf. This change of behaviour is induced because the assumption is done that at config startup, the user is not wrong with the interface configuration to use. Every usage of vrf_get_backend() should then be wisely adapted in order to handle that init state. Signed-off-by: Philippe Guibert --- lib/if.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/if.c b/lib/if.c index 6ae75939e7..910a38d4cb 100644 --- a/lib/if.c +++ b/lib/if.c @@ -397,6 +397,7 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id) struct interface *ifp; switch (vrf_get_backend()) { + case VRF_BACKEND_UNKNOWN: case VRF_BACKEND_NETNS: ifp = if_lookup_by_name(name, vrf_id); if (ifp) @@ -1282,6 +1283,10 @@ static int lib_interface_create(enum nb_event event, return NB_ERR_VALIDATION; } + /* if VRF is netns or not yet known - init for instance + * then assumption is that passed config is exact + * then the user intent was not to use an other iface + */ if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) { ifp = if_lookup_by_name_all_vrf(ifname); if (ifp && ifp->vrf_id != vrf->vrf_id) { From e5a501c2edd1f3f18ac0ce4c5d415c97cbfd0cc6 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 14 Feb 2019 20:00:14 -0200 Subject: [PATCH 003/142] lib: consolidate nexthop-group deletion in a single place Reuse the nhgl_delete() function to avoid code duplication. Signed-off-by: Renato Westphal --- lib/nexthop_group.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 23ea96f75c..57609b648f 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -322,13 +322,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc, return; list_delete_node(nhgc->nhg_list, node); - - if (nh->nhvrf_name) - XFREE(MTYPE_TMP, nh->nhvrf_name); - if (nh->intf) - XFREE(MTYPE_TMP, nh->intf); - - XFREE(MTYPE_TMP, nh); + nhgl_delete(nh); } static bool nexthop_group_parse_nexthop(struct nexthop *nhop, From b43bb64f82f599ec9fec0cb89bd2dd05cb54ab87 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 14 Feb 2019 20:00:14 -0200 Subject: [PATCH 004/142] lib: change how nexthop groups store nexthop addresses Use a pointer to a sockunion instead of a full sockunion in the nexthop_hold structure. This prepares the ground for the next commit, which will make nexthop addresses optional (in this commit we assume nh->addr will never be NULL, but this will change). Signed-off-by: Renato Westphal --- lib/nexthop_group.c | 16 +++++++++------- lib/nexthop_group.h | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 57609b648f..4c35d7c96c 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -192,7 +192,7 @@ static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2) { int ret; - ret = sockunion_cmp(&nh1->addr, &nh2->addr); + ret = sockunion_cmp(nh1->addr, nh2->addr); if (ret) return ret; @@ -211,6 +211,8 @@ static void nhgl_delete(struct nexthop_hold *nh) if (nh->nhvrf_name) XFREE(MTYPE_TMP, nh->nhvrf_name); + sockunion_free(nh->addr); + XFREE(MTYPE_TMP, nh); } @@ -295,7 +297,7 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc, if (intf) nh->intf = XSTRDUP(MTYPE_TMP, intf); - nh->addr = *addr; + nh->addr = sockunion_dup(addr); listnode_add_sort(nhgc->nhg_list, nh); } @@ -310,7 +312,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc, for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) { if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 && - sockunion_cmp(addr, &nh->addr) == 0 && + sockunion_cmp(addr, nh->addr) == 0 && nhgc_cmp_helper(intf, nh->intf) == 0) break; } @@ -478,7 +480,7 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty, vty_out(vty, "nexthop "); - vty_out(vty, "%s", sockunion2str(&nh->addr, buf, sizeof(buf))); + vty_out(vty, "%s", sockunion2str(nh->addr, buf, sizeof(buf))); if (nh->intf) vty_out(vty, " %s", nh->intf); @@ -522,7 +524,7 @@ void nexthop_group_enable_vrf(struct vrf *vrf) struct nexthop nhop; struct nexthop *nh; - if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr, + if (!nexthop_group_parse_nexthop(&nhop, nhh->addr, nhh->intf, nhh->nhvrf_name)) continue; @@ -558,7 +560,7 @@ void nexthop_group_disable_vrf(struct vrf *vrf) struct nexthop nhop; struct nexthop *nh; - if (!nexthop_group_parse_nexthop(&nhop, &nhh->addr, + if (!nexthop_group_parse_nexthop(&nhop, nhh->addr, nhh->intf, nhh->nhvrf_name)) continue; @@ -596,7 +598,7 @@ void nexthop_group_interface_state_change(struct interface *ifp, struct nexthop nhop; if (!nexthop_group_parse_nexthop( - &nhop, &nhh->addr, nhh->intf, + &nhop, nhh->addr, nhh->intf, nhh->nhvrf_name)) continue; diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index b14cbb5b5c..c6e290eeea 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -68,7 +68,7 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh, struct nexthop_hold { char *nhvrf_name; - union sockunion addr; + union sockunion *addr; char *intf; }; From 1c869b64180e9a3d33e9bfec7113418231489522 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 14 Feb 2019 20:00:14 -0200 Subject: [PATCH 005/142] lib: add support for interface nexthops on nexthop groups This patch adds support to nexthops of type NEXTHOP_TYPE_IFINDEX to nexthop-groups. This should be especially useful when dealing with p2p interfaces like tunnels that don't have IP addresses assigned to them. NOTE: nh->addr can be NULL now, so we should always perform a null check before dereferencing this pointer. Signed-off-by: Renato Westphal --- lib/nexthop_group.c | 84 +++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 4c35d7c96c..d8cabf62be 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -188,11 +188,25 @@ static int nhgc_cmp_helper(const char *a, const char *b) return strcmp(a, b); } +static int nhgc_addr_cmp_helper(const union sockunion *a, const union sockunion *b) +{ + if (!a && !b) + return 0; + + if (a && !b) + return -1; + + if (!a && b) + return 1; + + return sockunion_cmp(a, b); +} + static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2) { int ret; - ret = sockunion_cmp(nh1->addr, nh2->addr); + ret = nhgc_addr_cmp_helper(nh1->addr, nh2->addr); if (ret) return ret; @@ -211,7 +225,8 @@ static void nhgl_delete(struct nexthop_hold *nh) if (nh->nhvrf_name) XFREE(MTYPE_TMP, nh->nhvrf_name); - sockunion_free(nh->addr); + if (nh->addr) + sockunion_free(nh->addr); XFREE(MTYPE_TMP, nh); } @@ -296,8 +311,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc, nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name); if (intf) nh->intf = XSTRDUP(MTYPE_TMP, intf); - - nh->addr = sockunion_dup(addr); + if (addr) + nh->addr = sockunion_dup(addr); listnode_add_sort(nhgc->nhg_list, nh); } @@ -312,7 +327,7 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc, for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) { if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 && - sockunion_cmp(addr, nh->addr) == 0 && + nhgc_addr_cmp_helper(addr, nh->addr) == 0 && nhgc_cmp_helper(intf, nh->intf) == 0) break; } @@ -345,36 +360,45 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop, nhop->vrf_id = vrf->vrf_id; - if (addr->sa.sa_family == AF_INET) { - nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr; - if (intf) { - nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX; - nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id); - if (nhop->ifindex == IFINDEX_INTERNAL) - return false; - } else - nhop->type = NEXTHOP_TYPE_IPV4; - } else { - memcpy(&nhop->gate.ipv6, &addr->sin6.sin6_addr, 16); - if (intf) { - nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX; - nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id); - if (nhop->ifindex == IFINDEX_INTERNAL) - return false; - } else - nhop->type = NEXTHOP_TYPE_IPV6; + if (intf) { + nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id); + if (nhop->ifindex == IFINDEX_INTERNAL) + return false; } + if (addr) { + if (addr->sa.sa_family == AF_INET) { + nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr; + if (intf) + nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + else + nhop->type = NEXTHOP_TYPE_IPV4; + } else { + nhop->gate.ipv6 = addr->sin6.sin6_addr; + if (intf) + nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + else + nhop->type = NEXTHOP_TYPE_IPV6; + } + } else + nhop->type = NEXTHOP_TYPE_IFINDEX; + return true; } DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, - "[no] nexthop $addr [INTERFACE]$intf [nexthop-vrf NAME$name]", + "[no] nexthop\ + <\ + $addr [INTERFACE$intf]\ + |INTERFACE$intf\ + >\ + [nexthop-vrf NAME$name]", NO_STR "Specify one of the nexthops in this ECMP group\n" "v4 Address\n" "v6 Address\n" "Interface to use\n" + "Interface to use\n" "If the nexthop is in a different vrf tell us\n" "The nexthop-vrf Name\n") { @@ -383,13 +407,6 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, struct nexthop *nh; bool legal; - /* - * This is impossible to happen as that the cli parser refuses - * to let you get here without an addr, but the SA system - * does not understand this intricacy - */ - assert(addr); - legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name); if (nhop.type == NEXTHOP_TYPE_IPV6 @@ -478,9 +495,10 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty, { char buf[100]; - vty_out(vty, "nexthop "); + vty_out(vty, "nexthop"); - vty_out(vty, "%s", sockunion2str(nh->addr, buf, sizeof(buf))); + if (nh->addr) + vty_out(vty, " %s", sockunion2str(nh->addr, buf, sizeof(buf))); if (nh->intf) vty_out(vty, " %s", nh->intf); From aafac994dc97702821563ed05d9513f802438a31 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 14 Feb 2019 20:00:14 -0200 Subject: [PATCH 006/142] pbrd: rename nh_afi variables to nh_type to better convey their meaning Signed-off-by: Renato Westphal --- pbrd/pbr_nht.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 6103bd7db5..bc40caf1a0 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -50,7 +50,7 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, static void pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg, - enum nexthop_types_t nh_afi); + enum nexthop_types_t nh_type); /* * Nexthop refcount. @@ -274,7 +274,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, struct pbr_nexthop_group_cache *pnhgc; struct pbr_nexthop_cache pnhc_find = {}; struct pbr_nexthop_cache *pnhc; - enum nexthop_types_t nh_afi = nhop->type; + enum nexthop_types_t nh_type = nhop->type; /* find pnhgc by name */ strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name)); @@ -296,7 +296,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, if (pnhgc->nhh->count) pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg); else - pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_afi); + pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_type); pbr_map_check_nh_group_change(nhgc->name); } @@ -372,7 +372,7 @@ void pbr_nht_route_removed_for_table(uint32_t table_id) * - AFI_MAX on error */ static afi_t pbr_nht_which_afi(struct nexthop_group nhg, - enum nexthop_types_t nh_afi) + enum nexthop_types_t nh_type) { struct nexthop *nexthop; afi_t install_afi = AFI_MAX; @@ -380,14 +380,14 @@ static afi_t pbr_nht_which_afi(struct nexthop_group nhg, v6 = v4 = bh = false; - if (!nh_afi) { + if (!nh_type) { for (ALL_NEXTHOPS(nhg, nexthop)) { - nh_afi = nexthop->type; + nh_type = nexthop->type; break; } } - switch (nh_afi) { + switch (nh_type) { case NEXTHOP_TYPE_IFINDEX: break; case NEXTHOP_TYPE_IPV4: @@ -423,9 +423,9 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg) { afi_t install_afi; - enum nexthop_types_t nh_afi = 0; + enum nexthop_types_t nh_type = 0; - install_afi = pbr_nht_which_afi(nhg, nh_afi); + install_afi = pbr_nht_which_afi(nhg, nh_type); route_add(pnhgc, nhg, install_afi); } @@ -433,11 +433,11 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, static void pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg, - enum nexthop_types_t nh_afi) + enum nexthop_types_t nh_type) { afi_t install_afi; - install_afi = pbr_nht_which_afi(nhg, nh_afi); + install_afi = pbr_nht_which_afi(nhg, nh_type); pnhgc->installed = false; pnhgc->valid = false; @@ -526,7 +526,7 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms) struct listnode *node; struct pbr_map_interface *pmi; struct nexthop *nh; - enum nexthop_types_t nh_afi = 0; + enum nexthop_types_t nh_type = 0; if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) { for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) @@ -542,13 +542,13 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms) pnhgc = hash_lookup(pbr_nhg_hash, &find); nh = pbrms->nhg->nexthop; - nh_afi = nh->type; + nh_type = nh->type; lup.nexthop = nh; pnhc = hash_lookup(pnhgc->nhh, &lup); pnhc->parent = NULL; hash_release(pnhgc->nhh, pnhc); pbr_nh_delete(&pnhc); - pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_afi); + pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_type); hash_release(pbr_nhg_hash, pnhgc); From 268c24ee9ee2510d6b4922053285254644609a0f Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 14 Feb 2019 20:00:15 -0200 Subject: [PATCH 007/142] pbrd: fix detection of inconsistent nexthop groups Commit ff9799c31 broke the detection of nexthop groups that contain both v4 and v6 nexthops. Move the switch statement back to the ALL_NEXTHOPS loop to fix this issue. Further, make pbr_nht_which_afi() return AFI_MAX only if all nexthops from the group are either NEXTHOP_TYPE_IFINDEX or NEXTHOP_TYPE_BLACKHOLE. Signed-off-by: Renato Westphal --- pbrd/pbr_nht.c | 54 +++++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index bc40caf1a0..e196b4fe2c 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -378,33 +378,47 @@ static afi_t pbr_nht_which_afi(struct nexthop_group nhg, afi_t install_afi = AFI_MAX; bool v6, v4, bh; + if (nh_type) { + switch (nh_type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + return AFI_IP; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + return AFI_IP6; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_BLACKHOLE: + return AFI_MAX; + } + } + v6 = v4 = bh = false; - if (!nh_type) { - for (ALL_NEXTHOPS(nhg, nexthop)) { - nh_type = nexthop->type; + for (ALL_NEXTHOPS(nhg, nexthop)) { + nh_type = nexthop->type; + + switch (nh_type) { + case NEXTHOP_TYPE_IFINDEX: + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + v6 = true; + install_afi = AFI_IP; + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + v4 = true; + install_afi = AFI_IP6; + break; + case NEXTHOP_TYPE_BLACKHOLE: + bh = true; break; } } - switch (nh_type) { - case NEXTHOP_TYPE_IFINDEX: - break; - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - v6 = true; - install_afi = AFI_IP; - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - v4 = true; - install_afi = AFI_IP6; - break; - case NEXTHOP_TYPE_BLACKHOLE: - bh = true; + /* Interface and/or blackhole nexthops only. */ + if (!v4 && !v6) install_afi = AFI_MAX; - break; - } if (!bh && v6 && v4) DEBUGD(&pbr_dbg_nht, From a106a4087b47e180e32c66e139449bcf2660578f Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 14 Feb 2019 20:00:15 -0200 Subject: [PATCH 008/142] pbrd: add support for interface nexthops Now that nexthop groups can contain interface nexthops, make the necessary adjustments in pbrd to handle them appropriately. For normal IP nexthops, pbrd uses the NHT callbacks to validate these nexthops (i.e. check if they are reachable). NHT can't be used for interface nexthops though. To work around this issue, use the interface event callbacks from the zclient API to validate interface nexthops (an interface nexthop is valid only if the corresponding interface is up and running). Signed-off-by: Renato Westphal --- pbrd/pbr_nht.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++- pbrd/pbr_nht.h | 5 ++++ pbrd/pbr_zebra.c | 6 +++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index e196b4fe2c..b269ce0cdf 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -157,7 +157,7 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2) switch (pbrnc1->nexthop->type) { case NEXTHOP_TYPE_IFINDEX: - return true; + return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: return pbrnc1->nexthop->gate.ipv4.s_addr @@ -264,6 +264,14 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc, pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg); pbr_map_check_nh_group_change(nhgc->name); + + if (nhop->type == NEXTHOP_TYPE_IFINDEX) { + struct interface *ifp; + + ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id); + if (ifp) + pbr_nht_nexthop_interface_update(ifp); + } } void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, @@ -667,6 +675,7 @@ bool pbr_nht_nexthop_group_valid(const char *name) struct pbr_nht_individual { struct zapi_route *nhr; + struct interface *ifp; uint32_t valid; }; @@ -730,6 +739,56 @@ void pbr_nht_nexthop_update(struct zapi_route *nhr) hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr); } +static void +pbr_nht_individual_nexthop_interface_update_lookup(struct hash_backet *b, + void *data) +{ + struct pbr_nexthop_cache *pnhc = b->data; + struct pbr_nht_individual *pnhi = data; + bool old_valid; + + old_valid = pnhc->valid; + + if (pnhc->nexthop->type == NEXTHOP_TYPE_IFINDEX + && pnhc->nexthop->ifindex == pnhi->ifp->ifindex) + pnhc->valid = !!if_is_up(pnhi->ifp); + + DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name, + old_valid, pnhc->valid); + + if (pnhc->valid) + pnhi->valid += 1; +} + +static void pbr_nht_nexthop_interface_update_lookup(struct hash_backet *b, + void *data) +{ + struct pbr_nexthop_group_cache *pnhgc = b->data; + struct pbr_nht_individual pnhi; + bool old_valid; + + old_valid = pnhgc->valid; + + pnhi.ifp = data; + pnhi.valid = 0; + hash_iterate(pnhgc->nhh, + pbr_nht_individual_nexthop_interface_update_lookup, &pnhi); + + /* + * If any of the specified nexthops are valid we are valid + */ + pnhgc->valid = !!pnhi.valid; + + if (old_valid != pnhgc->valid) + pbr_map_check_nh_group_change(pnhgc->name); +} + +void pbr_nht_nexthop_interface_update(struct interface *ifp) +{ + hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_update_lookup, + ifp); +} + static uint32_t pbr_nhg_hash_key(void *arg) { struct pbr_nexthop_group_cache *nhgc = diff --git a/pbrd/pbr_nht.h b/pbrd/pbr_nht.h index d37803fbe3..4ef41cede7 100644 --- a/pbrd/pbr_nht.h +++ b/pbrd/pbr_nht.h @@ -117,5 +117,10 @@ extern void pbr_nht_show_nexthop_group(struct vty *vty, const char *name); */ extern void pbr_nht_nexthop_update(struct zapi_route *nhr); +/* + * When we get a callback from zebra about an interface status update. + */ +extern void pbr_nht_nexthop_interface_update(struct interface *ifp); + extern void pbr_nht_init(void); #endif diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 425bc04b4d..37209d4819 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -75,6 +75,8 @@ static int interface_add(int command, struct zclient *zclient, if (!ifp->info) pbr_if_new(ifp); + pbr_nht_nexthop_interface_update(ifp); + return 0; } @@ -144,6 +146,8 @@ static int interface_state_up(int command, struct zclient *zclient, DEBUGD(&pbr_dbg_zebra, "%s: %s is up", __PRETTY_FUNCTION__, ifp->name); + pbr_nht_nexthop_interface_update(ifp); + return 0; } @@ -157,6 +161,8 @@ static int interface_state_down(int command, struct zclient *zclient, DEBUGD(&pbr_dbg_zebra, "%s: %s is down", __PRETTY_FUNCTION__, ifp->name); + pbr_nht_nexthop_interface_update(ifp); + return 0; } From 9c0fd85360422b79e75e6ee5eeb1df5a9439e952 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 14 Feb 2019 20:00:15 -0200 Subject: [PATCH 009/142] pbrd: change the "set nexthop" command to accept interface nexthops In addition to nexthop groups, pbrd also supports the "set nexthop" command to specify the nexthop of a PBR map. This adds convenience when multiple nexthops aren't necessary. Change this command to support interface nexthops (without IP addresses) like nexthop groups do. At the end of the command, call pbr_nht_nexthop_interface_update() otherwise the interface nexthop won't be validated until we receive an interface up/down notification from zebra through the zapi protocol. Signed-off-by: Renato Westphal --- pbrd/pbr_vty.c | 82 +++++++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index a4b87f99d9..0aedb98476 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -221,13 +221,19 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd, } DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, - "[no] set nexthop $addr [INTERFACE]$intf [nexthop-vrf NAME$name]", + "[no] set nexthop\ + <\ + $addr [INTERFACE$intf]\ + |INTERFACE$intf\ + >\ + [nexthop-vrf NAME$name]", NO_STR "Set for the PBR-MAP\n" "Specify one of the nexthops in this map\n" "v4 Address\n" "v6 Address\n" "Interface to use\n" + "Interface to use\n" "If the nexthop is in a different vrf tell us\n" "The nexthop-vrf Name\n") { @@ -255,45 +261,39 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, memset(&nhop, 0, sizeof(nhop)); nhop.vrf_id = vrf->vrf_id; - /* - * Make SA happy. CLIPPY is not going to give us a NULL - * addr. - */ - assert(addr); - if (addr->sa.sa_family == AF_INET) { - nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr; - if (intf) { - nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX; - nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id); - if (nhop.ifindex == IFINDEX_INTERNAL) { - vty_out(vty, - "Specified Intf %s does not exist in vrf: %s\n", - intf, vrf->name); - return CMD_WARNING_CONFIG_FAILED; - } - } else - nhop.type = NEXTHOP_TYPE_IPV4; - } else { - memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16); - if (intf) { - nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX; - nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id); - if (nhop.ifindex == IFINDEX_INTERNAL) { - vty_out(vty, - "Specified Intf %s does not exist in vrf: %s\n", - intf, vrf->name); - return CMD_WARNING_CONFIG_FAILED; - } - } else { - if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { - vty_out(vty, - "Specified a v6 LL with no interface, rejecting\n"); - return CMD_WARNING_CONFIG_FAILED; - } - nhop.type = NEXTHOP_TYPE_IPV6; + if (intf) { + nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id); + if (nhop.ifindex == IFINDEX_INTERNAL) { + vty_out(vty, + "Specified Intf %s does not exist in vrf: %s\n", + intf, vrf->name); + return CMD_WARNING_CONFIG_FAILED; } } + if (addr) { + if (addr->sa.sa_family == AF_INET) { + nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr; + if (intf) + nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX; + else + nhop.type = NEXTHOP_TYPE_IPV4; + } else { + nhop.gate.ipv6 = addr->sin6.sin6_addr; + if (intf) + nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX; + else { + if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { + vty_out(vty, + "Specified a v6 LL with no interface, rejecting\n"); + return CMD_WARNING_CONFIG_FAILED; + } + nhop.type = NEXTHOP_TYPE_IPV6; + } + } + } else + nhop.type = NEXTHOP_TYPE_IFINDEX; + if (pbrms->nhg) nh = nexthop_exists(pbrms->nhg, &nhop); else { @@ -335,6 +335,14 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, pbr_map_check(pbrms); } + if (nhop.type == NEXTHOP_TYPE_IFINDEX) { + struct interface *ifp; + + ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id); + if (ifp) + pbr_nht_nexthop_interface_update(ifp); + } + return CMD_SUCCESS; } From 7dce96f0e413e1c6c9d1d68196716e0343c14f6a Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 14 Feb 2019 20:00:15 -0200 Subject: [PATCH 010/142] lib, pbrd: fix indentation of a few commands When displaying the running configuration, we should use a single space to indent commands when necessary (and not two spaces). Signed-off-by: Renato Westphal --- lib/nexthop_group.c | 2 +- pbrd/pbr_vty.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index d8cabf62be..bf298c6dec 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -520,7 +520,7 @@ static int nexthop_group_write(struct vty *vty) vty_out(vty, "nexthop-group %s\n", nhgc->name); for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) { - vty_out(vty, " "); + vty_out(vty, " "); nexthop_group_write_nexthop_internal(vty, nh); } diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 0aedb98476..d1ce82190d 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -612,18 +612,18 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty, vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno); if (pbrms->src) - vty_out(vty, " match src-ip %s\n", + vty_out(vty, " match src-ip %s\n", prefix2str(pbrms->src, buff, sizeof(buff))); if (pbrms->dst) - vty_out(vty, " match dst-ip %s\n", + vty_out(vty, " match dst-ip %s\n", prefix2str(pbrms->dst, buff, sizeof(buff))); if (pbrms->nhgrp_name) - vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name); + vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name); if (pbrms->nhg) { - vty_out(vty, " set "); + vty_out(vty, " set "); nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop); } From e60eb780e48396088c58131ff0af7b828fa93baa Mon Sep 17 00:00:00 2001 From: Sri Mohana Singamsetty Date: Wed, 20 Feb 2019 11:56:22 -0800 Subject: [PATCH 011/142] FRR: Python script to generate support bundle for FRR This has a python script that helps in collecting various CLI show command outputs in an automated way. This commit has two files. 1.Text Configuration file: support_bundle_commands.conf - This file has list of CLI show commands to be executed. This file will be in tools/etc/frr/ directory. On executing command "sudo install -m 644 tools/etc/frr/ support_bundle_commands.conf /etc/frr/support_bundle_commands.conf", as part of FRR installation, this file will be copied into /etc/frr directory. 2.Python script file: generate_support_bundle.py - This file has the python code that has the below functionality. * It reads the support_bundle_commands.conf file. For each process present in the conf file, it creates a support_bundle file. For example, it creates bgp_support_bundle.log file for BGP and zebra_support_bundle.log file for Zebra. These files will be created in /var/log/frr/ directory. This is where regular FRR log files are also stored currently. * The script reads the CLI command specified between CLI_START and CLI_END key words for each process. It will execute the commands one by one. * For each such command, the script also appends the current time stamp at which the CLI command is executed. * In case of successful execution of the CLI command, it will copy the CLI output into the above support bundle file. * In case of CLI command failure, it will capture the error thrown and the error is also written into the same file. * A small snippet of the output file is as below. >>[2019-01-02 13:55:23.318987]show bgp summary IPv4 Unicast Summary: BGP router identifier 203.0.113.1, local AS number 65000 vrf-id 0 BGP table version 4 RIB entries 7, using 1176 bytes of memory Peers 1, using 21 KiB of memory Peer groups 1, using 64 bytes of memory Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd 203.0.113.2 4 65001 34 34 0 0 0 00:29:47 2 Total number of neighbors 1 >>[2019-01-02 13:55:23.619953]show ip bgp BGP table version is 4, local router ID is 203.0.113.1, vrf id 0 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Signed-off-by: Sri Mohana Singamsetty --- tools/etc/frr/support_bundle_commands.conf | 83 ++++++++++++++++ tools/generate_support_bundle.py | 110 +++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 tools/etc/frr/support_bundle_commands.conf create mode 100644 tools/generate_support_bundle.py diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf new file mode 100644 index 0000000000..d52824ff07 --- /dev/null +++ b/tools/etc/frr/support_bundle_commands.conf @@ -0,0 +1,83 @@ +# FRR Support Bundle Command List +# Do Not modify the lines that start with +# PROC_NAME, CMD_LIST_START and CMD_LIST_END +# Add the new command for each process between +# CMD_LIST_START and CMD_LIST_END lines + +# BGP Support Bundle Command List +PROC_NAME:bgp +CMD_LIST_START +show bgp summary +show ip bgp +show ip bgp neighbors +show ip bgp summary +show ip bgp statistics + +show ip bgp update-groups advertise-queue +show ip bgp update-groups advertised-routes +show ip bgp update-groups packet-queue +show ip bgp update-groups statistics +show ip bgp peer-group +show ip bgp memory + +show bgp ipv6 +show bgp ipv6 neighbors +show bgp ipv6 summary +show bgp ipv6 update-groups advertise-queue +show bgp ipv6 update-groups advertised-routes +show bgp ipv6 update-groups packet-queue +show bgp ipv6 update-groups statistics +show ip bgp statistics + +show bgp evpn route +CMD_LIST_END + +# Zebra Support Bundle Command List +PROC_NAME:zebra +CMD_LIST_START +show zebra +show zebra client summary +show ip route + +show route-map +show memory +show interface +show vrf +show error all +show work-queues +show running-config +show thread cpu +show thread poll +show daemons +show version +CMD_LIST_END + +# OSPF Support Bundle Command List +# PROC_NAME:ospf +# CMD_LIST_START +# CMD_LIST_END + +# RIP Support Bundle Command List +# PROC_NAME:rip +# CMD_LIST_START +# CMD_LIST_END + +# ISIS Support Bundle Command List +# PROC_NAME:isis +# CMD_LIST_START +# CMD_LIST_END + +# BFD Support Bundle Command List +# PROC_NAME:bfd +# CMD_LIST_START +# CMD_LIST_END + +# STATIC Support Bundle Command List +# PROC_NAME:static +# CMD_LIST_START +# CMD_LIST_END + +# PIM Support Bundle Command List +# PROC_NAME:pim +# CMD_LIST_START +# CMD_LIST_END diff --git a/tools/generate_support_bundle.py b/tools/generate_support_bundle.py new file mode 100644 index 0000000000..118ca113a5 --- /dev/null +++ b/tools/generate_support_bundle.py @@ -0,0 +1,110 @@ +######################################################## +### Python Script to generate the FRR support bundle ### +######################################################## +import os +import subprocess +import datetime + +TOOLS_DIR="tools/" +ETC_DIR="/etc/frr/" +LOG_DIR="/var/log/frr/" +SUCCESS = 1 +FAIL = 0 + +inputFile = ETC_DIR + "support_bundle_commands.conf" + +# Open support bundle configuration file +def openConfFile(i_file): + try: + with open(i_file) as supportBundleConfFile: + lines = filter(None, (line.rstrip() for line in supportBundleConfFile)) + return lines + except IOError: + return ([]) + +# Create the output file name +def createOutputFile(procName): + fileName = procName + "_support_bundle.log" + oldFile = LOG_DIR + fileName + cpFileCmd = "cp " + oldFile + " " + oldFile + ".prev" + rmFileCmd = "rm -rf " + oldFile + print "Making backup of " + oldFile + os.system(cpFileCmd) + print "Removing " + oldFile + os.system(rmFileCmd) + return fileName + +# Open the output file for this process +def openOutputFile(fileName): + crt_file_cmd = LOG_DIR + fileName + print crt_file_cmd + try: + outputFile = open(crt_file_cmd, "w") + return outputFile + except IOError: + return () + +# Close the output file for this process +def closeOutputFile(file): + try: + file.close() + return SUCCESS + except IOError: + return FAIL + +# Execute the command over vtysh and store in the +# output file +def executeCommand(cmd, outputFile): + cmd_exec_str = "vtysh -c \"" + cmd + "\" " + try: + cmd_output = subprocess.check_output(cmd_exec_str, shell=True) + try: + dateTime = datetime.datetime.now() + outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n") + outputFile.write(cmd_output) + outputFile.write("########################################################\n") + outputFile.write('\n') + except: + print "Writing to ouptut file Failed" + except subprocess.CalledProcessError as e: + dateTime = datetime.datetime.now() + outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n") + outputFile.write(e.output) + outputFile.write("########################################################\n") + outputFile.write('\n') + print "Error:" + e.output + + +# Process the support bundle configuration file +# and call appropriate functions +def processConfFile(lines): + for line in lines: + if line[0][0] == '#': + continue + cmd_line = line.split(':') + if cmd_line[0] == "PROC_NAME": + outputFileName = createOutputFile(cmd_line[1]) + if outputFileName: + print outputFileName, "created for", cmd_line[1] + elif cmd_line[0] == "CMD_LIST_START": + outputFile = openOutputFile(outputFileName) + if outputFile: + print outputFileName, "opened" + else: + print outputFileName, "open failed" + return FAIL + elif cmd_line[0] == "CMD_LIST_END": + if closeOutputFile(outputFile): + print outputFileName, "closed" + else: + print outputFileName, "close failed" + else: + print "Execute:" , cmd_line[0] + executeCommand(cmd_line[0], outputFile) + +# Main Function +lines = openConfFile(inputFile) +if not lines: + print "File support_bundle_commands.conf not present in /etc/frr/ directory" +else: + processConfFile(lines) From d1927ebe5f4384e3a871d1bc2b996e73bfb61985 Mon Sep 17 00:00:00 2001 From: Akhilesh Samineni Date: Sun, 24 Feb 2019 15:00:31 +0530 Subject: [PATCH 012/142] bgpd: 'show bgp [ipv4|ipv6] neighbors' displays all address family neighbors Display only ipv4 neighbors when 'show bgp ipv4 neighbors' command is issued. Display only ipv6 neighbors when 'show bgp ipv6 neighbors' command is issued. Take the address family of the peer address into account, while displaying the neighbors. Signed-off-by: Akhilesh Samineni --- bgpd/bgp_vty.c | 77 +++++++++++++++++++++++++++++++++++++++++++++----- bgpd/bgpd.h | 3 ++ 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index a6d985ab9f..99dc4adb8f 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -8499,7 +8499,7 @@ const char *afi_safi_json(afi_t afi, safi_t safi) } /* Show BGP peer's information. */ -enum show_type { show_all, show_peer }; +enum show_type { show_all, show_peer, show_ipv4_all, show_ipv6_all, show_ipv4_peer, show_ipv6_peer }; static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p, afi_t afi, safi_t safi, @@ -10896,6 +10896,14 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp, struct peer *peer; int find = 0; bool nbr_output = false; + afi_t afi = AFI_MAX; + safi_t safi = SAFI_MAX; + + if (type == show_ipv4_peer || type == show_ipv4_all) { + afi = AFI_IP; + } else if (type == show_ipv6_peer || type == show_ipv6_all) { + afi = AFI_IP6; + } for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) @@ -10924,17 +10932,54 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp, } } break; + case show_ipv4_peer: + case show_ipv6_peer: + FOREACH_SAFI (safi) { + if (peer->afc[afi][safi]) { + if (conf_if) { + if ((peer->conf_if + && !strcmp(peer->conf_if, conf_if)) + || (peer->hostname + && !strcmp(peer->hostname, conf_if))) { + find = 1; + bgp_show_peer(vty, peer, use_json, + json); + break; + } + } else { + if (sockunion_same(&peer->su, su)) { + find = 1; + bgp_show_peer(vty, peer, use_json, + json); + break; + } + } + } + } + break; + case show_ipv4_all: + case show_ipv6_all: + FOREACH_SAFI (safi) { + if (peer->afc[afi][safi]) { + bgp_show_peer(vty, peer, use_json, json); + nbr_output = true; + break; + } + } + break; } } - if (type == show_peer && !find) { + if ((type == show_peer || type == show_ipv4_peer || + type == show_ipv6_peer) && !find) { if (use_json) json_object_boolean_true_add(json, "bgpNoSuchNeighbor"); else vty_out(vty, "%% No such neighbor in this view/vrf\n"); } - if (type != show_peer && !nbr_output && !use_json) + if (type != show_peer && type != show_ipv4_peer && + type != show_ipv6_peer && !nbr_output && !use_json) vty_out(vty, "%% No BGP neighbors found\n"); if (use_json) { @@ -11000,7 +11045,8 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty, : bgp->name); } - if (type == show_peer) { + if (type == show_peer || type == show_ipv4_peer || + type == show_ipv6_peer) { ret = str2sockunion(ip_str, &su); if (ret < 0) bgp_show_neighbor(vty, bgp, type, NULL, ip_str, @@ -11009,7 +11055,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty, bgp_show_neighbor(vty, bgp, type, &su, NULL, use_json, json); } else { - bgp_show_neighbor(vty, bgp, show_all, NULL, NULL, + bgp_show_neighbor(vty, bgp, type, NULL, NULL, use_json, json); } json_object_free(json); @@ -11102,6 +11148,7 @@ DEFUN (show_ip_bgp_neighbors, char *vrf = NULL; char *sh_arg = NULL; enum show_type sh_type; + afi_t afi = AFI_MAX; bool uj = use_json(argc, argv); @@ -11117,13 +11164,29 @@ DEFUN (show_ip_bgp_neighbors, vrf = argv[idx + 1]->arg; idx++; + + if (argv_find(argv, argc, "ipv4", &idx)) { + sh_type = show_ipv4_all; + afi = AFI_IP; + } else if (argv_find(argv, argc, "ipv6", &idx)) { + sh_type = show_ipv6_all; + afi = AFI_IP6; + } else { + sh_type = show_all; + } + if (argv_find(argv, argc, "A.B.C.D", &idx) || argv_find(argv, argc, "X:X::X:X", &idx) || argv_find(argv, argc, "WORD", &idx)) { sh_type = show_peer; sh_arg = argv[idx]->arg; - } else - sh_type = show_all; + } + + if (sh_type == show_peer && afi == AFI_IP) { + sh_type = show_ipv4_peer; + } else if (sh_type == show_peer && afi == AFI_IP6) { + sh_type = show_ipv6_peer; + } return bgp_show_neighbor_vty(vty, vrf, sh_type, sh_arg, uj); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index e58c46e240..0b283599d5 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -99,6 +99,9 @@ enum bgp_af_index { for (afi = AFI_IP; afi < AFI_MAX; afi++) \ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +#define FOREACH_SAFI(safi) \ + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) + extern struct frr_pthread *bgp_pth_io; extern struct frr_pthread *bgp_pth_ka; From bbe598df214486db57a0fd72a3c9875c0dfc2006 Mon Sep 17 00:00:00 2001 From: Sarita Patra Date: Fri, 22 Feb 2019 01:38:41 -0800 Subject: [PATCH 013/142] pimd: added comments for upstream and channel_oil new values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added comments which explains the new values for existing fields and new fields in the upstream and channel_oil data structure. Following are the summary of the behaviour change in PIM code. Scenario 1 : RP doesn’t exist/RP not reachable Event: Join received Current behaviour: No upstream gets created Changed behaviour: Upstream data structure created with below info upstream_addr: INADDR_ANY channel_oil iif: MAXVIF channel_oil is_valid: FALSE (flag introduced to indicate if this entry is valid to get installed in hardware) RPF details: Not valid Join state: NOT_JOINED Kernal installed: FALSE Scenario 2: Dummy upstream exists Event: RP configured Current Behaviour: upstream address updated for the dummy upstream created. Changed Behaviour: upstream_addr: RP address channel_oil iif: MAXVIF channel_oil is_valid: FALSE RPF details: only RP address updated Join state: NOT_JOINED Kernel installed: FALSE Scenario 3: Dummy upstream exists Event: RP becomes reachable Current Behaviour: Update channel oil, rpf details in the upstream and install in hardware Changed Behaviour: upstream_addr: RP Adress channel_oil iif: MAXVIF channel_oil is_valid: FALSE RPF details: RPF details updated via NHT callback Join state: JOINED Kernel installed: TRUE Scenario 4: MRoute exists Event: RP gets deleted Current behaviour: Nothing got updated in him upstream and channel oil, join timer still runs. Mroute still exists in kernel. Changed behaviour: upstream_addr: INADDR_ANY channel_oil iif: MAXVIF channel_oil is_valid: FALSE RPF details: Not valid Join state: NOT_JOINED (also sent prune towards deleted RPF nbr) Kernel installed: FALSE Scenario 5: MRoute Exists Event: RP unreachable Current behaviour: Nothing got updated in him upstream and channel oil, join timer still runs. Mroute sdeleted from kernel. Changed behaviour: upstream_addr: RP address channel_oil iif: MAXVIF channel_oil is_valid: FALSE RPF details: only RP address updated Join state: NOT_JOINED (also sent prune towards deleted RPF nbr) Kernel installed: FALSE Scenario 6: Mroute exists Event: Better RP configured with precise group range & reachable. Current behaviour: No effect on existing route. Changed behaviour: Upstream address: Better RP RPF interface: towards the better RP Join state: JOINED (Send a prune towards the old RP and send a join towards the better RP) Scenario 7: Mroute exists Event: RP deleted and another RP with broad group range fits this group & reachable Current behaviour: No effect on current behaviour Changed behaviour: Upstream address: next available RP RPF interface: towards the next available RP Join state: JOINED (Send a prune towards the old RP and send a join towards the better RP) Signed-off-by: Sarita Patra --- pimd/pim_oil.h | 20 ++++++++++++++++++++ pimd/pim_upstream.h | 24 ++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index 94d3840e98..fef414cc85 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -64,12 +64,32 @@ struct channel_counts { Each channel_oil.oil is used to control an (S,G) entry in the Kernel Multicast Forwarding Cache. + + There is a case when we create a channel_oil but don't install in the kernel + + Case where (S, G) entry not installed in the kernel: + FRR receives IGMP/PIM (*, G) join and RP is not configured or + not-reachable, then create a channel_oil for the group G with the incoming + interface(channel_oil.oil.mfcc_parent) as invalid i.e "MAXVIF" and populate + the outgoing interface where join is received. Keep this entry in the stack, + but don't install in the kernel(channel_oil.installed = 0). + + Case where (S, G) entry installed in the kernel: + When RP is configured and is reachable for the group G, and receiving a + join if channel_oil is already present then populate the incoming interface + and install the entry in the kernel, if channel_oil not present, then create + a new_channel oil(channel_oil.installed = 1). + + is_valid: indicate if this entry is valid to get installed in kernel. + installed: indicate if this entry is installed in the kernel. + */ struct channel_oil { struct pim_instance *pim; struct mfcctl oil; + bool is_valid; int installed; int oil_inherited_rescan; int oil_size; diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index f44b95c811..70e70140d1 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -88,10 +88,30 @@ enum pim_upstream_sptbit { /* Upstream (S,G) channel in Joined state - (S,G) in the "Not Joined" state is not represented - See RFC 4601: 4.5.7. Sending (S,G) Join/Prune Message + + upstream_addr : Who we are talking to. + For (*, G), upstream_addr is RP address or INADDR_ANY(if RP not configured) + For (S, G), upstream_addr is source address + + rpf: contains the nexthop information to whom we are talking to. + + join_state: JOINED/NOTJOINED + + In the case when FRR receives IGMP/PIM (*, G) join for group G and RP is not + configured, then create a pim_upstream with the below information. + pim_upstream->upstream address: INADDR_ANY + pim_upstream->rpf: Unknown + pim_upstream->state: NOTJOINED + + When a new RP gets configured for G, find the corresponding pim upstream (*,G) + entries and update the upstream address as new RP address if it the better one + for the group G. + + When RP becomes reachable, populate the nexthop information in + pim_upstream->rpf and update the state to JOINED. + */ struct pim_upstream { struct pim_upstream *parent; From d8bed89dca5955fe298c108afe78b13a95469cea Mon Sep 17 00:00:00 2001 From: Sarita Patra Date: Fri, 22 Feb 2019 01:47:58 -0800 Subject: [PATCH 014/142] pimd: Handling dummy upstream in "show ip pim upstream" When FRR receives IGMP/PIM (*, G) join and RP is not configured or not reachable, then we are creating a dummy upstream with incoming interface as NULL. Added some null checks for the incoming interface, while displaying the pim upstream information in the cli command "show ip pim upstream". Signed-off-by: Sarita Patra --- pimd/pim_cmd.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 193eddf68a..2d4c237d0f 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2370,9 +2370,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, up->t_join_timer); /* - * If we have a J/P timer for the neighbor display that + * If the upstream is not dummy and it has a J/P timer for the + * neighbor display that */ - if (!up->t_join_timer) { + if (!up->t_join_timer && up->rpf.source_nexthop.interface) { struct pim_neighbor *nbr; nbr = pim_neighbor_find( @@ -2412,8 +2413,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, json_row = json_object_new_object(); json_object_pim_upstream_add(json_row, up); json_object_string_add( - json_row, "inboundInterface", - up->rpf.source_nexthop.interface->name); + json_row, "inboundInterface", + up->rpf.source_nexthop.interface + ? up->rpf.source_nexthop.interface->name + : "Unknown"); /* * The RPF address we use is slightly different @@ -2463,8 +2466,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, } else { vty_out(vty, "%-10s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n", - up->rpf.source_nexthop.interface->name, src_str, - grp_str, state_str, uptime, join_timer, + up->rpf.source_nexthop.interface + ? up->rpf.source_nexthop.interface->name + : "Unknown", + src_str, grp_str, state_str, uptime, join_timer, rs_timer, ka_timer, up->ref_count); } } From 957d93eaf2ce5fe4969b406dc5e44677bf60ce5b Mon Sep 17 00:00:00 2001 From: Sarita Patra Date: Fri, 22 Feb 2019 01:59:07 -0800 Subject: [PATCH 015/142] pimd: Handling Null incoming interface of dummy upstream When FRR receives IGMP/PIM (*, G) join and RP is not configured or not reachable, then we are creating a dummy upstream with incoming interface as NULL and upstream address as INADDR_ANY. Added upstream address and incoming interface validation where it is necessary, before doing any operation on the upstream. Signed-off-by: Sarita Patra --- pimd/pim_igmp_mtrace.c | 7 +++ pimd/pim_join.c | 6 +-- pimd/pim_jp_agg.c | 14 +++++- pimd/pim_mroute.c | 10 ++++- pimd/pim_nht.c | 9 ++-- pimd/pim_rpf.c | 6 +++ pimd/pim_upstream.c | 98 +++++++++++++++++++++++++++++++++++++----- pimd/pim_zebra.c | 8 ++++ 8 files changed, 137 insertions(+), 21 deletions(-) diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c index 1fb624a6a0..f51e0c0d2f 100644 --- a/pimd/pim_igmp_mtrace.c +++ b/pimd/pim_igmp_mtrace.c @@ -133,6 +133,13 @@ static bool mtrace_fwd_info(struct pim_instance *pim, if (!up) return false; + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return false; + } + ifp_in = up->rpf.source_nexthop.interface; nh_addr = up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4; total = htonl(MTRACE_UNKNOWN_COUNT); diff --git a/pimd/pim_join.c b/pimd/pim_join.c index ae5032be73..cbacaf3ea8 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -439,9 +439,6 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) size_t packet_size = 0; size_t group_size = 0; - on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface, - rpf->rpf_addr.u.prefix4); - if (rpf->source_nexthop.interface) pim_ifp = rpf->source_nexthop.interface->info; else { @@ -450,6 +447,9 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) return -1; } + on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface, + rpf->rpf_addr.u.prefix4); + if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, diff --git a/pimd/pim_jp_agg.c b/pimd/pim_jp_agg.c index 7726ffda57..06a9e6d0d6 100644 --- a/pimd/pim_jp_agg.c +++ b/pimd/pim_jp_agg.c @@ -213,8 +213,18 @@ void pim_jp_agg_upstream_verification(struct pim_upstream *up, bool ignore) { #ifdef PIM_JP_AGG_DEBUG struct interface *ifp; - struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info; - struct pim_instance *pim = pim_ifp->pim; + struct pim_interface *pim_ifp; + struct pim_instance *pim; + + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + + pim_ifp = up->rpf.source_nexthop.interface->info; + pim = pim_ifp->pim; FOR_ALL_INTERFACES (pim->vrf, ifp) { pim_ifp = ifp->info; diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index dd9e21cae8..67b1a95f74 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -234,7 +234,8 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, up->channel_oil->cc.pktcnt++; PIM_UPSTREAM_FLAG_SET_FHR(up->flags); // resolve mfcc_parent prior to mroute_add in channel_add_oif - if (up->channel_oil->oil.mfcc_parent >= MAXVIFS) { + if (up->rpf.source_nexthop.interface && + up->channel_oil->oil.mfcc_parent >= MAXVIFS) { int vif_index = 0; vif_index = pim_if_find_vifindex_by_ifindex( pim_ifp->pim, @@ -301,6 +302,13 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, return 0; } + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return 0; + } + pim_ifp = up->rpf.source_nexthop.interface->info; rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL; diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 2d808639b5..8c24bcdaed 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -283,7 +283,7 @@ static int pim_update_upstream_nh_helper(struct hash_backet *backet, void *arg) } /* update kernel multicast forwarding cache (MFC) */ - if (up->channel_oil) { + if (up->rpf.source_nexthop.interface) { ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex; vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex); @@ -306,9 +306,10 @@ static int pim_update_upstream_nh_helper(struct hash_backet *backet, void *arg) if (PIM_DEBUG_PIM_NHT) { zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s", - __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name, - old.source_nexthop.interface->name, - up->rpf.source_nexthop.interface->name); + __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name, + old.source_nexthop.interface + ? old.source_nexthop.interface->name : "Unknwon", + up->rpf.source_nexthop.interface->name); } return HASHWALK_CONTINUE; diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 814d2e076b..d689b276b7 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -205,6 +205,12 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, struct prefix src, grp; bool neigh_needed = true; + if (up->upstream_addr.s_addr == INADDR_ANY) { + zlog_debug("%s: RP is not configured yet for %s", + __PRETTY_FUNCTION__, up->sg_str); + return PIM_RPF_OK; + } + saved.source_nexthop = rpf->source_nexthop; saved.rpf_addr = rpf->rpf_addr; diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index c6ab8f5a2a..cd0610eb82 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -238,6 +238,13 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, void pim_upstream_send_join(struct pim_upstream *up) { + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + if (PIM_DEBUG_TRACE) { char rpf_str[PREFIX_STRLEN]; pim_addr_dump("", &up->rpf.rpf_addr, rpf_str, @@ -263,6 +270,13 @@ static int on_join_timer(struct thread *t) up = THREAD_ARG(t); + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return 0; + } + /* * In the case of a HFR we will not ahve anyone to send this to. */ @@ -286,6 +300,13 @@ static void join_timer_stop(struct pim_upstream *up) { struct pim_neighbor *nbr; + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + THREAD_OFF(up->t_join_timer); nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, @@ -301,6 +322,13 @@ void join_timer_start(struct pim_upstream *up) { struct pim_neighbor *nbr = NULL; + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + if (up->rpf.source_nexthop.interface) { nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, up->rpf.rpf_addr.u.prefix4); @@ -356,6 +384,13 @@ void pim_upstream_join_suppress(struct pim_upstream *up, long t_joinsuppress_msec; long join_timer_remain_msec; + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface), 1000 * holdtime); @@ -389,6 +424,13 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, long join_timer_remain_msec; int t_override_msec; + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface); @@ -511,6 +553,18 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, { enum pim_upstream_state old_state = up->join_state; + if (up->upstream_addr.s_addr == INADDR_ANY) { + zlog_debug("%s: RPF not configured for %s", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + + if (!up->rpf.source_nexthop.interface) { + zlog_debug("%s: RP not reachable for %s", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + if (PIM_DEBUG_PIM_EVENTS) { zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s", __PRETTY_FUNCTION__, up->sg_str, @@ -558,11 +612,14 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, && !I_am_RP(pim, up->sg.grp)) { if (PIM_DEBUG_PIM_TRACE_DETAIL) zlog_debug( - "%s: *,G IIF %s S,G IIF %s ", - __PRETTY_FUNCTION__, - up->parent->rpf.source_nexthop - .interface->name, - up->rpf.source_nexthop.interface->name); + "%s: *,G IIF %s S,G IIF %s ", + __PRETTY_FUNCTION__, + up->parent->rpf.source_nexthop.interface ? + up->parent->rpf.source_nexthop.interface->name + : "Unknown", + up->rpf.source_nexthop.interface ? + up->rpf.source_nexthop.interface->name : + "Unknown"); pim_jp_agg_single_upstream_send(&up->parent->rpf, up->parent, 1 /* (W,G) Join */); @@ -783,7 +840,7 @@ struct pim_upstream *pim_upstream_add(struct pim_instance *pim, zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d", __PRETTY_FUNCTION__, name, up->sg_str, buf, up->rpf.source_nexthop.interface ? - up->rpf.source_nexthop.interface->name : "NIL" , + up->rpf.source_nexthop.interface->name : "Unknown" , found, up->ref_count); } else zlog_debug("%s(%s): (%s) failure to create", @@ -973,7 +1030,9 @@ void pim_upstream_rpf_interface_changed(struct pim_upstream *up, (old_rpf_ifp == ch->interface) && /* RPF_interface(S) stopped being I */ (ch->upstream->rpf.source_nexthop - .interface != ch->interface)) { + .interface) && + (ch->upstream->rpf.source_nexthop + .interface != ch->interface)) { assert_action_a5(ch); } } /* PIM_IFASSERT_I_AM_LOSER */ @@ -1339,6 +1398,13 @@ static int pim_upstream_register_stop_timer(struct thread *t) case PIM_REG_JOIN: break; case PIM_REG_PRUNE: + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return 0; + } + pim_ifp = up->rpf.source_nexthop.interface->info; if (!pim_ifp) { if (PIM_DEBUG_TRACE) @@ -1515,11 +1581,19 @@ void pim_upstream_find_new_rpf(struct pim_instance *pim) * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr */ for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) { + if (up->upstream_addr.s_addr == INADDR_ANY) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: RP not configured for Upstream %s", + __PRETTY_FUNCTION__, up->sg_str); + continue; + } + if (pim_rpf_addr_is_inaddr_any(&up->rpf)) { if (PIM_DEBUG_TRACE) zlog_debug( - "Upstream %s without a path to send join, checking", - up->sg_str); + "%s: Upstream %s without a path to send join, checking", + __PRETTY_FUNCTION__, up->sg_str); pim_rpf_update(pim, up, NULL, 1); } } @@ -1586,7 +1660,8 @@ static bool pim_upstream_kat_start_ok(struct pim_upstream *up) /* "iif == RPF_interface(S)" check has to be done by the kernel or hw * so we will skip that here */ - if (pim_if_connected_to_source(up->rpf.source_nexthop.interface, + if (up->rpf.source_nexthop.interface && + pim_if_connected_to_source(up->rpf.source_nexthop.interface, up->sg.src)) { return true; } @@ -1679,7 +1754,8 @@ static void pim_upstream_sg_running(void *arg) } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time); - if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) { + if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) && + (up->rpf.source_nexthop.interface)) { pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface); } return; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 11ca6e8a10..2c5c7f6174 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -535,6 +535,14 @@ static void scan_upstream_rpf_cache(struct pim_instance *pim) struct pim_rpf old; struct prefix nht_p; + if (up->upstream_addr.s_addr == INADDR_ANY) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: RP not configured for Upstream %s", + __PRETTY_FUNCTION__, up->sg_str); + continue; + } + nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; From 732c209c985da005791fcc3ecd88c443c7c74cd6 Mon Sep 17 00:00:00 2001 From: Sarita Patra Date: Fri, 22 Feb 2019 03:05:29 -0800 Subject: [PATCH 016/142] pimd: create dummy (*,G) upstream when RP not configured/reachable In this commit, we are creating a dummy upstream & dummy channel_oil for (*, G) when RP is not configured or not reachable. Dummy upstream: Dummy channel oil: Signed-off-by: Sarita Patra --- pimd/pim_oil.c | 20 ++-- pimd/pim_rp.c | 3 +- pimd/pim_upstream.c | 64 +++++------ pimd/pim_zebra.c | 260 +++++++++++++++++++++++++------------------- 4 files changed, 192 insertions(+), 155 deletions(-) diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 2e12d728cf..5042db8e57 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -168,13 +168,15 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, return c_oil; } - ifp = pim_if_find_by_vif_index(pim, input_vif_index); - if (!ifp) { - /* warning only */ - zlog_warn( - "%s: (S,G)=%s could not find input interface for input_vif_index=%d", - __PRETTY_FUNCTION__, pim_str_sg_dump(sg), - input_vif_index); + if (input_vif_index != MAXVIFS) { + ifp = pim_if_find_by_vif_index(pim, input_vif_index); + if (!ifp) { + /* warning only */ + zlog_warn( + "%s: (S,G)=%s could not find input interface for input_vif_index=%d", + __PRETTY_FUNCTION__, pim_str_sg_dump(sg), + input_vif_index); + } } c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil)); @@ -188,6 +190,10 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, c_oil->installed = 0; c_oil->up = pim_upstream_find(pim, sg); c_oil->pim = pim; + if (input_vif_index != MAXVIFS) + c_oil->is_valid = 1; + else + c_oil->is_valid = 0; listnode_add_sort(pim->channel_oil_list, c_oil); diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 08f2ffc4ea..d46f3d853f 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -870,7 +870,7 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group) * the rp configured and the source address * * If we have don't have a RP configured and the source address is * - * then return failure. + * then set the upstream addr as INADDR_ANY and return failure. * */ int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, @@ -891,6 +891,7 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__); + up->s_addr = INADDR_ANY; return 0; } diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index cd0610eb82..2a2b944354 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -668,15 +668,14 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, ch->upstream = up; up = hash_get(pim->upstream_hash, up, hash_alloc_intern); + /* Set up->upstream_addr as INADDR_ANY, if RP is not + * configured and retain the upstream data structure + */ if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src, sg->grp)) { if (PIM_DEBUG_TRACE) zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__); - - hash_release(pim->upstream_hash, up); - XFREE(MTYPE_PIM_UPSTREAM, up); - return NULL; } up->parent = pim_upstream_find_parent(pim, up); @@ -716,45 +715,34 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, if (up->sg.src.s_addr != INADDR_ANY) wheel_add_item(pim->upstream_sg_wheel, up); - rpf_result = pim_rpf_update(pim, up, NULL, 1); - if (rpf_result == PIM_RPF_FAILURE) { - struct prefix nht_p; + if (up->upstream_addr.s_addr == INADDR_ANY) + /* Create a dummmy channel oil with incoming ineterface MAXVIFS, + * since RP is not configured + */ + up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS); - if (PIM_DEBUG_TRACE) - zlog_debug( - "%s: Attempting to create upstream(%s), Unable to RPF for source", - __PRETTY_FUNCTION__, up->sg_str); - - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = up->upstream_addr; - pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); - - if (up->parent) { - listnode_delete(up->parent->sources, up); - up->parent = NULL; + else { + rpf_result = pim_rpf_update(pim, up, NULL, 1); + if (rpf_result == PIM_RPF_FAILURE) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: Attempting to create upstream(%s), Unable to RPF for source", + __PRETTY_FUNCTION__, up->sg_str); + /* Create a dummmy channel oil with incoming ineterface + * MAXVIFS, since RP is not reachable + */ + up->channel_oil = pim_channel_oil_add( + pim, &up->sg, MAXVIFS); } - if (up->sg.src.s_addr != INADDR_ANY) - wheel_remove_item(pim->upstream_sg_wheel, up); - - pim_upstream_remove_children(pim, up); - if (up->sources) - list_delete(&up->sources); - - list_delete(&up->ifchannels); - - hash_release(pim->upstream_hash, up); - XFREE(MTYPE_PIM_UPSTREAM, up); - return NULL; + if (up->rpf.source_nexthop.interface) { + pim_ifp = up->rpf.source_nexthop.interface->info; + if (pim_ifp) + up->channel_oil = pim_channel_oil_add(pim, + &up->sg, pim_ifp->mroute_vif_index); + } } - if (up->rpf.source_nexthop.interface) { - pim_ifp = up->rpf.source_nexthop.interface->info; - if (pim_ifp) - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, pim_ifp->mroute_vif_index); - } listnode_add_sort(pim->upstream_list, up); if (PIM_DEBUG_TRACE) { diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 2c5c7f6174..6a5e6e726f 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -569,10 +569,9 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) int input_iface_vif_index; int old_vif_index; - if (!pim_rp_set_upstream_addr(c_oil->pim, &vif_source, + pim_rp_set_upstream_addr(c_oil->pim, &vif_source, c_oil->oil.mfcc_origin, - c_oil->oil.mfcc_mcastgrp)) - return; + c_oil->oil.mfcc_mcastgrp); if (in_vif_index) input_iface_vif_index = in_vif_index; @@ -958,112 +957,141 @@ void igmp_source_forward_start(struct pim_instance *pim, struct pim_upstream *up = NULL; if (!pim_rp_set_upstream_addr(pim, &vif_source, - source->source_addr, sg.grp)) - return; + source->source_addr, sg.grp)) { + /*Create a dummy channel oil */ + source->source_channel_oil = + pim_channel_oil_add(pim, &sg, MAXVIFS); - /* Register addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = vif_source; - memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache)); - - src.family = AF_INET; - src.prefixlen = IPV4_MAX_BITLEN; - src.u.prefix4 = vif_source; // RP or Src address - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = sg.grp; - - if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL, - &out_pnc)) { - if (out_pnc.nexthop_num) { - up = pim_upstream_find(pim, &sg); - memset(&nexthop, 0, sizeof(nexthop)); - if (up) - memcpy(&nexthop, - &up->rpf.source_nexthop, - sizeof(struct pim_nexthop)); - pim_ecmp_nexthop_search(pim, &out_pnc, &nexthop, - &src, &grp, 0); - if (nexthop.interface) - input_iface_vif_index = - pim_if_find_vifindex_by_ifindex( - pim, - nexthop.interface->ifindex); - } else { - if (PIM_DEBUG_ZEBRA) { - char buf1[INET_ADDRSTRLEN]; - char buf2[INET_ADDRSTRLEN]; - pim_inet4_dump("", - nht_p.u.prefix4, buf1, - sizeof(buf1)); - pim_inet4_dump("", - grp.u.prefix4, buf2, - sizeof(buf2)); + if (!source->source_channel_oil) { + if (PIM_DEBUG_IGMP_TRACE) { zlog_debug( - "%s: NHT Nexthop not found for addr %s grp %s", - __PRETTY_FUNCTION__, buf1, - buf2); - } - } - } else - input_iface_vif_index = - pim_ecmp_fib_lookup_if_vif_index(pim, &src, - &grp); - - if (PIM_DEBUG_ZEBRA) { - char buf2[INET_ADDRSTRLEN]; - pim_inet4_dump("", vif_source, buf2, - sizeof(buf2)); - zlog_debug("%s: NHT %s vif_source %s vif_index:%d ", - __PRETTY_FUNCTION__, pim_str_sg_dump(&sg), - buf2, input_iface_vif_index); - } - - if (input_iface_vif_index < 1) { - if (PIM_DEBUG_IGMP_TRACE) { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", source->source_addr, - source_str, sizeof(source_str)); - zlog_debug( - "%s %s: could not find input interface for source %s", - __FILE__, __PRETTY_FUNCTION__, - source_str); - } - return; - } - - /* - Protect IGMP against adding looped MFC entries created by both - source and receiver attached to the same interface. See TODO - T22. - */ - if (input_iface_vif_index == pim_oif->mroute_vif_index) { - /* ignore request for looped MFC entry */ - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug( - "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d", - __PRETTY_FUNCTION__, - pim_str_sg_dump(&sg), - source->source_group->group_igmp_sock - ->fd, - source->source_group->group_igmp_sock - ->interface->name, - input_iface_vif_index); - } - return; - } - - source->source_channel_oil = - pim_channel_oil_add(pim, &sg, input_iface_vif_index); - if (!source->source_channel_oil) { - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug( "%s %s: could not create OIL for channel (S,G)=%s", __FILE__, __PRETTY_FUNCTION__, pim_str_sg_dump(&sg)); + } + return; + } + } + + else { + /* Register addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = vif_source; + memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache)); + + src.family = AF_INET; + src.prefixlen = IPV4_MAX_BITLEN; + src.u.prefix4 = vif_source; // RP or Src address + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = sg.grp; + + if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL, + &out_pnc)) { + if (out_pnc.nexthop_num) { + up = pim_upstream_find(pim, &sg); + memset(&nexthop, 0, sizeof(nexthop)); + if (up) + memcpy(&nexthop, + &up->rpf.source_nexthop, + sizeof(struct pim_nexthop)); + pim_ecmp_nexthop_search(pim, &out_pnc, + &nexthop, + &src, &grp, 0); + if (nexthop.interface) + input_iface_vif_index = + pim_if_find_vifindex_by_ifindex( + pim, + nexthop.interface->ifindex); + } else { + if (PIM_DEBUG_ZEBRA) { + char buf1[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; + + pim_inet4_dump("", + nht_p.u.prefix4, buf1, + sizeof(buf1)); + pim_inet4_dump("", + grp.u.prefix4, buf2, + sizeof(buf2)); + zlog_debug( + "%s: NHT Nexthop not found for addr %s grp %s", + __PRETTY_FUNCTION__, buf1, + buf2); + } + } + } else + input_iface_vif_index = + pim_ecmp_fib_lookup_if_vif_index(pim, &src, + &grp); + + if (PIM_DEBUG_ZEBRA) { + char buf2[INET_ADDRSTRLEN]; + + pim_inet4_dump("", vif_source, buf2, + sizeof(buf2)); + zlog_debug("%s: NHT %s vif_source %s vif_index:%d ", + __PRETTY_FUNCTION__, + pim_str_sg_dump(&sg), + buf2, input_iface_vif_index); + } + + if (input_iface_vif_index < 1) { + if (PIM_DEBUG_IGMP_TRACE) { + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump("", + source->source_addr, + source_str, sizeof(source_str)); + zlog_debug( + "%s %s: could not find input interface for source %s", + __FILE__, __PRETTY_FUNCTION__, + source_str); + } + source->source_channel_oil = + pim_channel_oil_add(pim, &sg, MAXVIFS); + } + + else { + /* + * Protect IGMP against adding looped MFC + * entries created by both source and receiver + * attached to the same interface. See TODO + * T22. + */ + if (input_iface_vif_index == + pim_oif->mroute_vif_index) { + /* ignore request for looped MFC entry + */ + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug( + "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d", + __PRETTY_FUNCTION__, + pim_str_sg_dump(&sg), + source->source_group + ->group_igmp_sock->fd, + source->source_group + ->group_igmp_sock + ->interface->name, + input_iface_vif_index); + } + return; + } + + source->source_channel_oil = + pim_channel_oil_add(pim, &sg, + input_iface_vif_index); + if (!source->source_channel_oil) { + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug( + "%s %s: could not create OIL for channel (S,G)=%s", + __FILE__, + __PRETTY_FUNCTION__, + pim_str_sg_dump(&sg)); + } + return; + } } - return; } } @@ -1196,15 +1224,13 @@ void pim_forward_start(struct pim_ifchannel *ch) sizeof(upstream_str)); zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)", __PRETTY_FUNCTION__, source_str, group_str, ch->interface->name, - upstream_str); + inet_ntoa(up->upstream_addr)); } /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS, as part of mroute_del called by pim_forward_stop. */ - if (!up->channel_oil - || (up->channel_oil - && up->channel_oil->oil.mfcc_parent >= MAXVIFS)) { + if ((up->upstream_addr.s_addr != INADDR_ANY) && (!up->channel_oil)) { struct prefix nht_p, src, grp; struct pim_nexthop_cache out_pnc; @@ -1275,17 +1301,33 @@ void pim_forward_start(struct pim_ifchannel *ch) __FILE__, __PRETTY_FUNCTION__, source_str); } - return; + up->channel_oil = pim_channel_oil_add(pim, &up->sg, + MAXVIFS); } + + else { + up->channel_oil = pim_channel_oil_add(pim, &up->sg, + input_iface_vif_index); + if (!up->channel_oil) { + if (PIM_DEBUG_PIM_TRACE) + zlog_debug( + "%s %s: could not create OIL for channel (S,G)=%s", + __FILE__, __PRETTY_FUNCTION__, + up->sg_str); + return; + } + } + if (PIM_DEBUG_TRACE) { struct interface *in_intf = pim_if_find_by_vif_index( pim, input_iface_vif_index); zlog_debug( "%s: Update channel_oil IIF %s VIFI %d entry %s ", __PRETTY_FUNCTION__, - in_intf ? in_intf->name : "NIL", + in_intf ? in_intf->name : "Unknown", input_iface_vif_index, up->sg_str); } + up->channel_oil = pim_channel_oil_add(pim, &up->sg, input_iface_vif_index); if (!up->channel_oil) { From c3156184f95fc4db5ba6ca58294262cb384dec5d Mon Sep 17 00:00:00 2001 From: Sarita Patra Date: Fri, 22 Feb 2019 03:31:56 -0800 Subject: [PATCH 017/142] pimd: Don't install dummy channel oil entry into Kernel If the channel oil is dummy(channel_oil->is_valid != True), then don't install entry into the kernel. Signed-off-by: Sarita Patra --- pimd/pim_oil.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 5042db8e57..35801aa49e 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -453,25 +453,31 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL; - if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) { - if (PIM_DEBUG_MROUTE) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", - channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("", - channel_oil->oil.mfcc_origin, source_str, - sizeof(source_str)); - zlog_debug( - "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)", - __FILE__, __PRETTY_FUNCTION__, oif->name, - pim_ifp->mroute_vif_index, source_str, - group_str); - } + /* channel_oil->is_valid indicate if this entry is valid to get + * installed in kernel. + */ + if (channel_oil->is_valid) { + if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) { + if (PIM_DEBUG_MROUTE) { + char group_str[INET_ADDRSTRLEN]; + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump("", + channel_oil->oil.mfcc_mcastgrp, + group_str, sizeof(group_str)); + pim_inet4_dump("", + channel_oil->oil.mfcc_origin, source_str, + sizeof(source_str)); + zlog_debug( + "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, oif->name, + pim_ifp->mroute_vif_index, source_str, + group_str); + } - channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl; - return -5; + channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] + = old_ttl; + return -5; + } } channel_oil->oif_creation[pim_ifp->mroute_vif_index] = From 640b8d93abcddc6634ed778a9e669639a53b9b0b Mon Sep 17 00:00:00 2001 From: Sarita Patra Date: Fri, 22 Feb 2019 06:37:06 -0800 Subject: [PATCH 018/142] pimd: clear rp_info source_nexthop when RP becomes not reachable When route to RP gets modified, FRR receives a notification from zebra, and call the function pim_update_rp_nh() to compute the new nexthop and will update the source_nexthop information of rp_info. This is not working for the case when RP becomes not reachable. Fix: When FRR receives a notification from zebra saying RP becomes not reachable, then delete the source_nexthop informatio of rp_info. Signed-off-by: Sarita Patra --- pimd/pim_nht.c | 20 +++++++++++++++++--- pimd/pim_nht.h | 1 + 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 8c24bcdaed..8777566595 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -39,6 +39,7 @@ #include "pim_jp_agg.h" #include "pim_zebra.h" #include "pim_zlookup.h" +#include "pim_rp.h" /** * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister @@ -207,6 +208,17 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, } } +void pim_rp_nexthop_del(struct rp_info *rp_info) +{ + rp_info->rp.source_nexthop.interface = NULL; + rp_info->rp.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = + PIM_NET_INADDR_ANY; + rp_info->rp.source_nexthop.mrib_metric_preference = + router->infinite_assert_metric.metric_preference; + rp_info->rp.source_nexthop.mrib_route_metric = + router->infinite_assert_metric.route_metric; +} + /* Update RP nexthop info based on Nexthop update received from Zebra.*/ static void pim_update_rp_nh(struct pim_instance *pim, struct pim_nexthop_cache *pnc) @@ -220,9 +232,11 @@ static void pim_update_rp_nh(struct pim_instance *pim, continue; // Compute PIM RPF using cached nexthop - pim_ecmp_nexthop_search(pim, pnc, &rp_info->rp.source_nexthop, - &rp_info->rp.rpf_addr, &rp_info->group, - 1); + if (!pim_ecmp_nexthop_search(pim, pnc, + &rp_info->rp.source_nexthop, + &rp_info->rp.rpf_addr, &rp_info->group, + 1)) + pim_rp_nexthop_del(rp_info); } } diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index 796fbf9731..6eff7bbc89 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -68,4 +68,5 @@ void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient, void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p); int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim, struct prefix *src, struct prefix *grp); +void pim_rp_nexthop_del(struct rp_info *rp_info); #endif From 1250cb5df29b7ac663fc57ee75ec18899cb6e608 Mon Sep 17 00:00:00 2001 From: Sarita Patra Date: Fri, 22 Feb 2019 07:29:24 -0800 Subject: [PATCH 019/142] pimd: clear upstream rpf information when RP becomes not reachable When route to RP gets modified, FRR receives a notification from zebra, and call the function pim_resolve_upstream_nh() to compute the nexthop and update upstream->rpf structure. Issue: In case when RP becomes not reachable, FRR only uninstall the mroute from the kernal, but not update the upstream->rpf structure. Fix: When FRR receives a notification from zebra saying RP becomes not reachable, then update the following fields. 1. update channel_oil incoming interface as MAXVIFS 2. Un-install the mroute from the kernel. 3. Switch upstream state from JOINED to NOTJOINED. 4. Clear the nexthop information of the upstream. Signed-off-by: Sarita Patra --- pimd/pim_nht.c | 2 +- pimd/pim_rpf.c | 28 +++++++++++++ pimd/pim_rpf.h | 3 +- pimd/pim_upstream.c | 2 +- pimd/pim_zebra.c | 97 ++++++++++++++++++++++++++------------------- 5 files changed, 89 insertions(+), 43 deletions(-) diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 8777566595..37970923c1 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -292,7 +292,7 @@ static int pim_update_upstream_nh_helper(struct hash_backet *backet, void *arg) old.source_nexthop.interface = up->rpf.source_nexthop.interface; rpf_result = pim_rpf_update(pim, up, &old, 0); if (rpf_result == PIM_RPF_FAILURE) { - pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); + pim_upstream_rpf_clear(pim, up); return HASHWALK_CONTINUE; } diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index d689b276b7..8adf253e55 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -313,6 +313,34 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, return PIM_RPF_OK; } +/* + * In the case of RP deletion and RP unreachablity, + * uninstall the mroute in the kernel and clear the + * rpf information in the pim upstream and pim channel + * oil data structure. + */ +void pim_upstream_rpf_clear(struct pim_instance *pim, + struct pim_upstream *up) +{ + if (up->rpf.source_nexthop.interface) { + if (up->channel_oil) { + up->channel_oil->oil.mfcc_parent = MAXVIFS; + up->channel_oil->is_valid = 0; + pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); + + } + pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED); + up->rpf.source_nexthop.interface = NULL; + up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = + PIM_NET_INADDR_ANY; + up->rpf.source_nexthop.mrib_metric_preference = + router->infinite_assert_metric.metric_preference; + up->rpf.source_nexthop.mrib_route_metric = + router->infinite_assert_metric.route_metric; + up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY; + } +} + /* RFC 4601: 4.1.6. State Summarization Macros diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h index b9fe162f21..a4793df667 100644 --- a/pimd/pim_rpf.h +++ b/pimd/pim_rpf.h @@ -64,7 +64,8 @@ int pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, struct pim_upstream *up, struct pim_rpf *old, uint8_t is_new); - +void pim_upstream_rpf_clear(struct pim_instance *pim, + struct pim_upstream *up); int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf); int pim_rpf_addr_is_inaddr_any(struct pim_rpf *rpf); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 2a2b944354..f1fb99832b 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -941,7 +941,7 @@ void pim_upstream_update_join_desired(struct pim_instance *pim, PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags); /* switched from false to true */ - if (is_join_desired && !was_join_desired) { + if (is_join_desired) { pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED); return; } diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 6a5e6e726f..78cccd5877 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -472,55 +472,72 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, struct pim_upstream *up, struct pim_rpf *old) { - struct pim_neighbor *nbr; + if (old->source_nexthop.interface) { + struct pim_neighbor *nbr; - nbr = pim_neighbor_find(old->source_nexthop.interface, - old->rpf_addr.u.prefix4); - if (nbr) - pim_jp_agg_remove_group(nbr->upstream_jp_agg, up); + nbr = pim_neighbor_find(old->source_nexthop.interface, + old->rpf_addr.u.prefix4); + if (nbr) + pim_jp_agg_remove_group(nbr->upstream_jp_agg, up); - /* - * We have detected a case where we might need - * to rescan the inherited o_list so do it. - */ - if (up->channel_oil->oil_inherited_rescan) { - pim_upstream_inherited_olist_decide(pim, up); - up->channel_oil->oil_inherited_rescan = 0; + /* + * We have detected a case where we might need + * to rescan the inherited o_list so do it. + */ + if (up->channel_oil->oil_inherited_rescan) { + pim_upstream_inherited_olist_decide(pim, up); + up->channel_oil->oil_inherited_rescan = 0; + } + + if (up->join_state == PIM_UPSTREAM_JOINED) { + /* + * If we come up real fast we can be here + * where the mroute has not been installed + * so install it. + */ + if (!up->channel_oil->installed) + pim_mroute_add(up->channel_oil, + __PRETTY_FUNCTION__); + + /* + * RFC 4601: 4.5.7. Sending (S,G) + * Join/Prune Messages + * + * Transitions from Joined State + * + * RPF'(S,G) changes not due to an Assert + * + * The upstream (S,G) state machine remains + * in Joined state. Send Join(S,G) to the new + * upstream neighbor, which is the new value + * of RPF'(S,G). Send Prune(S,G) to the old + * upstream neighbor, which is the old value + * of RPF'(S,G). Set the Join Timer (JT) to + * expire after t_periodic seconds. + */ + pim_jp_agg_switch_interface(old, &up->rpf, up); + + pim_upstream_join_timer_restart(up, old); + } /* up->join_state == PIM_UPSTREAM_JOINED */ } - if (up->join_state == PIM_UPSTREAM_JOINED) { + else { /* - * If we come up real fast we can be here - * where the mroute has not been installed - * so install it. + * We have detected a case where we might need + * to rescan the inherited o_list so do it. */ + if (up->channel_oil->oil_inherited_rescan) { + pim_upstream_inherited_olist_decide(pim, up); + up->channel_oil->oil_inherited_rescan = 0; + } + if (!up->channel_oil->installed) pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); + } - /* - * RFC 4601: 4.5.7. Sending (S,G) - * Join/Prune Messages - * - * Transitions from Joined State - * - * RPF'(S,G) changes not due to an Assert - * - * The upstream (S,G) state machine remains - * in Joined state. Send Join(S,G) to the new - * upstream neighbor, which is the new value - * of RPF'(S,G). Send Prune(S,G) to the old - * upstream neighbor, which is the old value - * of RPF'(S,G). Set the Join Timer (JT) to - * expire after t_periodic seconds. - */ - pim_jp_agg_switch_interface(old, &up->rpf, up); - - pim_upstream_join_timer_restart(up, old); - } /* up->join_state == PIM_UPSTREAM_JOINED */ - - /* FIXME can join_desired actually be changed by - pim_rpf_update() - returning PIM_RPF_CHANGED ? */ + /* FIXME can join_desired actually be changed by pim_rpf_update() + * returning PIM_RPF_CHANGED ? + */ pim_upstream_update_join_desired(pim, up); } From 28309df0517fb3601297230321dd37ed88e2b88b Mon Sep 17 00:00:00 2001 From: Sarita Patra Date: Fri, 22 Feb 2019 08:42:19 -0800 Subject: [PATCH 020/142] pimd: update pim upstream structure when RP gets configured When a new RP is configured, find all the (*, G) upstream whose group belongs to the new RP and then update the upstream structure with the below fields. 1. De-register for the old RP. 2. Set the upstream address as new RP 3. Register for the new RP. 4. Update the upstream rpf information and kernel multicast forwarding cache(MFC), if the new RP is reachable. Signed-off-by: Sarita Patra --- pimd/pim_rp.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++- pimd/pim_rp.h | 3 ++ 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index d46f3d853f..8f748f9907 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -45,7 +45,9 @@ #include "pim_iface.h" #include "pim_msdp.h" #include "pim_nht.h" - +#include "pim_mroute.h" +#include "pim_oil.h" +#include "pim_zebra.h" /* Cleanup pim->rpf_hash each node data */ void pim_rp_list_hash_clean(void *data) @@ -201,7 +203,7 @@ static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, /* * Given a group, return the rp_info for that group */ -static struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, +struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, const struct prefix *group) { struct listnode *node; @@ -334,6 +336,77 @@ static void pim_rp_check_interfaces(struct pim_instance *pim, } } +void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) +{ + struct pim_rpf old_rpf; + enum pim_rpf_result rpf_result; + struct in_addr old_upstream_addr; + struct in_addr new_upstream_addr; + struct prefix nht_p; + + old_upstream_addr = up->upstream_addr; + pim_rp_set_upstream_addr(pim, &new_upstream_addr, up->sg.src, + up->sg.grp); + + if (PIM_DEBUG_TRACE) + zlog_debug("%s: pim upstream update for old upstream %s", + __PRETTY_FUNCTION__, + inet_ntoa(old_upstream_addr)); + + if (old_upstream_addr.s_addr == new_upstream_addr.s_addr) + return; + + /* Lets consider a case, where a PIM upstream has a better RP as a + * result of a new RP configuration with more precise group range. + * This upstream has to be added to the upstream hash of new RP's + * NHT(pnc) and has to be removed from old RP's NHT upstream hash + */ + if (old_upstream_addr.s_addr != INADDR_ANY) { + /* Deregister addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = old_upstream_addr; + if (PIM_DEBUG_TRACE) { + char buf[PREFIX2STR_BUFFER]; + + prefix2str(&nht_p, buf, sizeof(buf)); + zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT", + __PRETTY_FUNCTION__, up->sg_str, buf); + } + pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); + } + + /* Update the upstream address */ + up->upstream_addr = new_upstream_addr; + + old_rpf.source_nexthop.interface = up->rpf.source_nexthop.interface; + + rpf_result = pim_rpf_update(pim, up, &old_rpf, 1); + if (rpf_result == PIM_RPF_FAILURE) + pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); + + /* update kernel multicast forwarding cache (MFC) */ + if (up->rpf.source_nexthop.interface && up->channel_oil) { + ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex; + int vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex); + /* Pass Current selected NH vif index to mroute download */ + if (vif_index) + pim_scan_individual_oil(up->channel_oil, vif_index); + else { + if (PIM_DEBUG_PIM_NHT) + zlog_debug( + "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid", + __PRETTY_FUNCTION__, up->sg_str, + up->rpf.source_nexthop.interface->name); + } + } + + if (rpf_result == PIM_RPF_CHANGED) + pim_zebra_upstream_rpf_changed(pim, up, &old_rpf); + + pim_zebra_update_all_interfaces(pim); +} + int pim_rp_new(struct pim_instance *pim, const char *rp, const char *group_range, const char *plist) { @@ -348,6 +421,8 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, struct prefix temp; struct pim_nexthop_cache pnc; struct route_node *rn; + struct pim_upstream *up; + struct listnode *upnode; rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info)); @@ -469,6 +544,27 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, "%s: NHT Register rp_all addr %s grp %s ", __PRETTY_FUNCTION__, buf, buf1); } + + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, + up)) { + /* Find (*, G) upstream whose RP is not + * configured yet + */ + if ((up->upstream_addr.s_addr == INADDR_ANY) + && (up->sg.src.s_addr == INADDR_ANY)) { + struct prefix grp; + struct rp_info *trp_info; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + trp_info = pim_rp_find_match_group(pim, + &grp); + if (trp_info == rp_all) + pim_upstream_update(pim, up); + } + } + memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all, &pnc)) { @@ -536,6 +632,21 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, rn->lock); } + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { + if (up->sg.src.s_addr == INADDR_ANY) { + struct prefix grp; + struct rp_info *trp_info; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + trp_info = pim_rp_find_match_group(pim, &grp); + + if (trp_info == rp_info) + pim_upstream_update(pim, up); + } + } + /* Register addr with Zebra NHT */ nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 672a696319..7769864c08 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -71,4 +71,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj); void pim_resolve_rp_nh(struct pim_instance *pim); int pim_rp_list_cmp(void *v1, void *v2); +struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, + const struct prefix *group); +void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up); #endif From 8cfd72682e5be5d4da9543655b11e8b1f92ed6e8 Mon Sep 17 00:00:00 2001 From: Sarita Patra Date: Fri, 22 Feb 2019 10:08:59 -0800 Subject: [PATCH 021/142] pimd: update pim upstream structure when RP gets deleted When a RP gets deleted, find all the (*, G) upstream whose group belongs to the deleted RP. case 1: if the group belongs to any other rp, then call pim_upstream_update() to update the upstream addr and rpf information. case 2: If no RP found for the group, then clear the pim upstream address and rpf information. Signed-off-by: Sarita Patra --- pimd/pim_rp.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 8f748f9907..86028749ac 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -689,6 +689,9 @@ int pim_rp_del(struct pim_instance *pim, const char *rp, struct prefix nht_p; struct route_node *rn; bool was_plist = false; + struct rp_info *trp_info; + struct pim_upstream *up; + struct listnode *upnode; if (group_range == NULL) result = str2prefix("224.0.0.0/4", &group); @@ -733,6 +736,23 @@ int pim_rp_del(struct pim_instance *pim, const char *rp, rp_all = pim_rp_find_match_group(pim, &g_all); if (rp_all == rp_info) { + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { + /* Find the upstream (*, G) whose upstream address is + * same as the deleted RP + */ + if ((up->upstream_addr.s_addr == rp_addr.s_addr) && + (up->sg.src.s_addr == INADDR_ANY)) { + struct prefix grp; + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + trp_info = pim_rp_find_match_group(pim, &grp); + if (trp_info == rp_all) { + pim_upstream_rpf_clear(pim, up); + up->upstream_addr.s_addr = INADDR_ANY; + } + } + } rp_all->rp.rpf_addr.family = AF_INET; rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE; rp_all->i_am_rp = 0; @@ -767,6 +787,34 @@ int pim_rp_del(struct pim_instance *pim, const char *rp, pim_rp_refresh_group_to_rp_mapping(pim); + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { + /* Find the upstream (*, G) whose upstream address is same as + * the deleted RP + */ + if ((up->upstream_addr.s_addr == rp_addr.s_addr) && + (up->sg.src.s_addr == INADDR_ANY)) { + struct prefix grp; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + + trp_info = pim_rp_find_match_group(pim, &grp); + + /* RP not found for the group grp */ + if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) { + pim_upstream_rpf_clear(pim, up); + pim_rp_set_upstream_addr(pim, + &up->upstream_addr, + up->sg.src, up->sg.grp); + } + + /* RP found for the group grp */ + else + pim_upstream_update(pim, up); + } + } + XFREE(MTYPE_PIM_RP, rp_info); return PIM_SUCCESS; } @@ -793,6 +841,7 @@ void pim_rp_setup(struct pim_instance *pim) else { if (PIM_DEBUG_PIM_NHT_RP) { char buf[PREFIX2STR_BUFFER]; + prefix2str(&nht_p, buf, sizeof(buf)); zlog_debug( "%s: NHT Local Nexthop not found for RP %s ", From 246445a372bab081f56190dd0bf32ccad2331284 Mon Sep 17 00:00:00 2001 From: Sarita Patra Date: Sat, 23 Feb 2019 04:40:19 -0800 Subject: [PATCH 022/142] pimd: Handling delete nexthop track for PIM upstream address When RP gets deleted, find all the (*, G) upstream whose group belongs to the deleted RP, release the upstream from pnc->upstream_hash in the function pim_delete_tracked_nexthop(). Signed-off-by: Sarita Patra --- pimd/pim_nht.c | 26 +++++++++++++++++++++++++- pimd/pim_upstream.c | 28 ++++++++++++++++++---------- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 37970923c1..f897965172 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -171,6 +171,8 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, struct pim_nexthop_cache *pnc = NULL; struct pim_nexthop_cache lookup; struct zclient *zclient = NULL; + struct listnode *upnode = NULL; + struct pim_upstream *upstream = NULL; zclient = pim_zebra_zclient_get(); @@ -178,8 +180,30 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, lookup.rpf.rpf_addr = *addr; pnc = hash_lookup(pim->rpf_hash, &lookup); if (pnc) { - if (rp) + if (rp) { + /* Release the (*, G)upstream from pnc->upstream_hash, + * whose Group belongs to the RP getting deleted + */ + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, + upstream)) { + struct prefix grp; + struct rp_info *trp_info; + + if (upstream->sg.src.s_addr != INADDR_ANY) + continue; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = upstream->sg.grp; + + trp_info = pim_rp_find_match_group(pim, &grp); + if (trp_info == rp) + hash_release(pnc->upstream_hash, + upstream); + } listnode_delete(pnc->rp_list, rp); + } + if (up) hash_release(pnc->upstream_hash, up); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index f1fb99832b..9cf25f0f92 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -219,17 +219,25 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, pim_msdp_up_del(pim, &up->sg); } - /* Deregister addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = up->upstream_addr; - if (PIM_DEBUG_TRACE) { - char buf[PREFIX2STR_BUFFER]; - prefix2str(&nht_p, buf, sizeof(buf)); - zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT", - __PRETTY_FUNCTION__, up->sg_str, buf); + /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT + * and assign up->upstream_addr as INADDR_ANY. + * So before de-registering the upstream address, check if is not equal + * to INADDR_ANY. This is done in order to avoid de-registering for + * 255.255.255.255 which is maintained for some reason.. + */ + if (up->upstream_addr.s_addr != INADDR_ANY) { + /* Deregister addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = up->upstream_addr; + if (PIM_DEBUG_TRACE) { + char buf[PREFIX2STR_BUFFER]; + prefix2str(&nht_p, buf, sizeof(buf)); + zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT", + __PRETTY_FUNCTION__, up->sg_str, buf); + } + pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); } - pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); XFREE(MTYPE_PIM_UPSTREAM, up); From 7452e879c353fabb5d6797bb241b023dcf1e801e Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 28 Feb 2019 08:19:21 +0000 Subject: [PATCH 023/142] bgpd: Leak EVPN-installed routes IPv4 or IPv6 unicast routes which are imported from EVPN routes (type-2 or type-5) and installed in a BGP instance can be leaked to another instance. Signed-off-by: Vivek Venkatraman Reviewed-by: Anuradha Karuppiah Reviewed-by: Donald Sharp --- bgpd/bgp_evpn.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 1471bd9829..1c65d69ef4 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2508,6 +2508,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* Perform route selection and update zebra, if required. */ bgp_process(bgp_vrf, rn, afi, safi); + /* Process for route leaking. */ + vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi); + return ret; } @@ -2673,6 +2676,9 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, if (!pi) return 0; + /* Process for route leaking. */ + vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi); + bgp_aggregate_decrement(bgp_vrf, &rn->p, pi, afi, safi); /* Mark entry for deletion */ From 12d6100c52d14f7501cd04ffbb6a4f1b10ec3cd6 Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 28 Feb 2019 08:30:51 +0000 Subject: [PATCH 024/142] bgpd: Refine check for which routes can be exported into VPN A non-imported route or a non-VPN imported route is a candidate to be exported into the VPN routing table for leaking to other BGP instances or advertisement into BGP/MPLS VPN. The former is a local or learnt IPv4 or IPv6 route. The latter is an IPv4 or IPv6 route that is based on a received EVPN type-2 or type-5 route. Implement a function to specify if a route can be exported into VPN and use in the appropriate places. Signed-off-by: Vivek Venkatraman Reviewed-by: Anuradha Karuppiah Reviewed-by: Donald Sharp --- bgpd/bgp_mplsvpn.c | 9 ++++++--- bgpd/bgp_mplsvpn.h | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 4baac3e57a..461fef4387 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -683,11 +683,10 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ return; } - /* loop check - should not be an imported route. */ - if (path_vrf->extra && path_vrf->extra->bgp_orig) + /* Is this route exportable into the VPN table? */ + if (!is_route_injectable_into_vpn(path_vrf)) return; - if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) { if (debug) zlog_debug("%s: %s skipping: %s", __func__, @@ -912,6 +911,10 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */ return; } + /* Is this route exportable into the VPN table? */ + if (!is_route_injectable_into_vpn(path_vrf)) + return; + if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) { if (debug) zlog_debug("%s: skipping: %s", __func__, debugmsg); diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 5b989e1853..c557b784af 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -226,6 +226,32 @@ static inline void vpn_leak_postchange(vpn_policy_direction_t direction, } } +/* Flag if the route is injectable into VPN. This would be either a + * non-imported route or a non-VPN imported route. + */ +static inline bool is_route_injectable_into_vpn(struct bgp_path_info *pi) +{ + struct bgp_path_info *parent_pi; + struct bgp_table *table; + struct bgp_node *rn; + + if (pi->sub_type != BGP_ROUTE_IMPORTED || + !pi->extra || + !pi->extra->parent) + return true; + + parent_pi = (struct bgp_path_info *)pi->extra->parent; + rn = parent_pi->net; + if (!rn) + return true; + table = bgp_node_table(rn); + if (table && + (table->afi == AFI_IP || table->afi == AFI_IP6) && + table->safi == SAFI_MPLS_VPN) + return false; + return true; +} + extern void vpn_policy_routemap_event(const char *rmap_name); extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey); From 0a2f9ac170f19a8739146838120a1518cd370029 Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 28 Feb 2019 11:11:01 +0000 Subject: [PATCH 025/142] bgpd: No nexthop tracking for EVPN-imported leaked routes IPv4 or IPv6 unicast routes which are imported from EVPN routes (type-2 or type-5) and installed in a BGP instance and then leaked do not need any nexthop tracking, as any tracking should happen in the source instance. Signed-off-by: Vivek Venkatraman Reviewed-by: Anuradha Karuppiah Reviewed-by: Donald Sharp --- bgpd/bgp_evpn.h | 6 ++++++ bgpd/bgp_mplsvpn.c | 14 +++++++++++--- bgpd/bgp_route.h | 18 ++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 5c3d4ce3aa..c2fed76a0a 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -101,6 +101,12 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri) return 0; } +/* Flag if the route path's family is EVPN. */ +static inline bool is_pi_family_evpn(struct bgp_path_info *pi) +{ + return is_pi_family_matching(pi, AFI_L2VPN, SAFI_EVPN); +} + extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p, struct attr *src_attr, afi_t afi, diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 461fef4387..1e2706f152 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -46,6 +46,7 @@ #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nht.h" +#include "bgpd/bgp_evpn.h" #if ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -552,8 +553,12 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ if (bpi->extra && bpi->extra->bgp_orig) bgp_nexthop = bpi->extra->bgp_orig; - /* No nexthop tracking for redistributed routes */ - if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE) + /* + * No nexthop tracking for redistributed routes or for + * EVPN-imported routes that get leaked. + */ + if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE || + is_pi_family_evpn(bpi_ultimate)) nh_valid = 1; else /* @@ -614,8 +619,11 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ * No nexthop tracking for redistributed routes because * their originating protocols will do the tracking and * withdraw those routes if the nexthops become unreachable + * This also holds good for EVPN-imported routes that get + * leaked. */ - if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE) + if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE || + is_pi_family_evpn(bpi_ultimate)) nh_valid = 1; else /* diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 85325a93cf..1527571278 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -341,6 +341,24 @@ static inline int bgp_fibupd_safi(safi_t safi) return 0; } +/* Flag if the route path's family matches params. */ +static inline bool is_pi_family_matching(struct bgp_path_info *pi, + afi_t afi, safi_t safi) +{ + struct bgp_table *table; + struct bgp_node *rn; + + rn = pi->net; + if (!rn) + return false; + table = bgp_node_table(rn); + if (table && + table->afi == afi && + table->safi == safi) + return true; + return false; +} + /* Prototypes. */ extern void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi, struct peer *peer, afi_t afi, safi_t safi); From abf386be5edbd3ca2ce13a2f275edc1625f0993a Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 28 Feb 2019 11:18:10 +0000 Subject: [PATCH 026/142] bgpd: Remove route sub-type checks in route-leak withdraw The check on which routes are exportable is a superset, so remove the route sub-type checks. Also, this change is needed to handle EVPN-imported leaked routes correctly. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_mplsvpn.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 1e2706f152..39b0e2f1c8 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -901,15 +901,6 @@ void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */ path_vrf->type, path_vrf->sub_type); } - if (path_vrf->sub_type != BGP_ROUTE_NORMAL - && path_vrf->sub_type != BGP_ROUTE_STATIC - && path_vrf->sub_type != BGP_ROUTE_REDISTRIBUTE) { - - if (debug) - zlog_debug("%s: wrong sub_type %d", __func__, - path_vrf->sub_type); - return; - } if (!bgp_vpn) return; From f106e3a72d37173b68f3f253d70a4af4ab7a7726 Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 28 Feb 2019 16:01:38 +0000 Subject: [PATCH 027/142] bgpd: Allow EVPN-sourced routes to be leaked back into EVPN Refine check on whether a route can be injected into EVPN to allow EVPN-sourced routes to be injected back into another instance. Signed-off-by: Vivek Venkatraman Reviewed-by: Anuradha Karuppiah Reviewed-by: Donald Sharp --- bgpd/bgp_evpn.c | 11 +++++++---- bgpd/bgp_evpn.h | 26 ++++++++++++++++++++++++++ bgpd/bgp_route.c | 10 ++++++---- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 1c65d69ef4..361df826fa 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -4234,11 +4234,13 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi) table = bgp_vrf->rib[afi][safi]; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { - /* Only care about "selected" routes - non-imported. */ + /* Only care about "selected" routes. Also ensure that + * these are routes that are injectable into EVPN. + */ /* TODO: Support for AddPath for EVPN. */ for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) - && (!pi->extra || !pi->extra->parent)) { + && is_route_injectable_into_evpn(pi)) { bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, afi, safi); break; @@ -4305,12 +4307,13 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, table = bgp_vrf->rib[afi][safi]; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { /* Need to identify the "selected" route entry to use its - * attribute. Also, we only consider "non-imported" routes. + * attribute. Also, ensure that the route is injectable + * into EVPN. * TODO: Support for AddPath for EVPN. */ for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) - && (!pi->extra || !pi->extra->parent)) { + && is_route_injectable_into_evpn(pi)) { /* apply the route-map */ if (bgp_vrf->adv_cmd_rmap[afi][safi].map) { diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index c2fed76a0a..0027ae51a4 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -107,6 +107,32 @@ static inline bool is_pi_family_evpn(struct bgp_path_info *pi) return is_pi_family_matching(pi, AFI_L2VPN, SAFI_EVPN); } +/* Flag if the route is injectable into EVPN. This would be either a + * non-imported route or a non-EVPN imported route. + */ +static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi) +{ + struct bgp_path_info *parent_pi; + struct bgp_table *table; + struct bgp_node *rn; + + if (pi->sub_type != BGP_ROUTE_IMPORTED || + !pi->extra || + !pi->extra->parent) + return true; + + parent_pi = (struct bgp_path_info *)pi->extra->parent; + rn = parent_pi->net; + if (!rn) + return true; + table = bgp_node_table(rn); + if (table && + table->afi == AFI_L2VPN && + table->safi == SAFI_EVPN) + return false; + return true; +} + extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p, struct attr *src_attr, afi_t afi, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 7ddc10ae01..0b6c536f5a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2476,8 +2476,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, /* advertise/withdraw type-5 routes */ if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { - if (advertise_type5_routes(bgp, afi) && new_select && - (!new_select->extra || !new_select->extra->parent)) { + if (advertise_type5_routes(bgp, afi) && + new_select && + is_route_injectable_into_evpn(new_select)) { /* apply the route-map */ if (bgp->adv_cmd_rmap[afi][safi].map) { @@ -2500,8 +2501,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, afi, safi); } - } else if (advertise_type5_routes(bgp, afi) && old_select && - (!old_select->extra || !old_select->extra->parent)) + } else if (advertise_type5_routes(bgp, afi) && + old_select && + is_route_injectable_into_evpn(old_select)) bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi); } From 9544ddb28842e5e73e86880f3b12fa52bf264817 Mon Sep 17 00:00:00 2001 From: vivek Date: Fri, 1 Mar 2019 06:45:04 +0000 Subject: [PATCH 028/142] bgpd: Correctly identify VPN-imported routes in a VRF Refine check that looks for VPN routes imported into a VRF because a VRF can have other imported routes too like IPv4 and IPv6 unicast routes sourced from EVPN type-2 and type-5 routes. Signed-off-by: Vivek Venkatraman Reviewed-by: Anuradha Karuppiah Reviewed-by: Donald Sharp --- bgpd/bgp_mplsvpn.c | 5 ++++- bgpd/bgp_mplsvpn.h | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 39b0e2f1c8..2d3ff8b695 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1355,7 +1355,10 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */ for (bpi = bgp_node_get_bgp_path_info(bn); bpi; bpi = bpi->next) { - if (bpi->extra && bpi->extra->bgp_orig != bgp_vrf) { + if (bpi->extra + && bpi->extra->bgp_orig != bgp_vrf + && bpi->extra->parent + && is_pi_family_vpn(bpi->extra->parent)) { /* delete route */ bgp_aggregate_decrement(bgp_vrf, &bn->p, bpi, diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index c557b784af..2ef9570aac 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -252,6 +252,13 @@ static inline bool is_route_injectable_into_vpn(struct bgp_path_info *pi) return true; } +/* Flag if the route path's family is VPN. */ +static inline bool is_pi_family_vpn(struct bgp_path_info *pi) +{ + return (is_pi_family_matching(pi, AFI_IP, SAFI_MPLS_VPN) || + is_pi_family_matching(pi, AFI_IP6, SAFI_MPLS_VPN)); +} + extern void vpn_policy_routemap_event(const char *rmap_name); extern vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey); From 744c63be132a4644c7c3799a0f0d2a07bfc5b98a Mon Sep 17 00:00:00 2001 From: vivek Date: Fri, 1 Mar 2019 07:10:53 +0000 Subject: [PATCH 029/142] zebra: Use next hop's VRF for EVPN-based routes Ensure that the next hop's VRF is used for IPv4 and IPv6 unicast routes sourced from EVPN routes, for next hop and Router MAC tracking and install. This way, leaked routes from other instances are handled properly. Signed-off-by: Vivek Venkatraman Reviewed-by: Anuradha Karuppiah Reviewed-by: Donald Sharp --- zebra/zapi_msg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 9b91289dec..ef9917d4e6 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1463,8 +1463,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) &(api_nh->gate.ipv4), sizeof(struct in_addr)); zebra_vxlan_evpn_vrf_route_add( - vrf_id, &api_nh->rmac, &vtep_ip, - &api.prefix); + api_nh->vrf_id, &api_nh->rmac, + &vtep_ip, &api.prefix); } break; case NEXTHOP_TYPE_IPV6: @@ -1493,8 +1493,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6), sizeof(struct in6_addr)); zebra_vxlan_evpn_vrf_route_add( - vrf_id, &api_nh->rmac, &vtep_ip, - &api.prefix); + api_nh->vrf_id, &api_nh->rmac, + &vtep_ip, &api.prefix); } break; case NEXTHOP_TYPE_BLACKHOLE: From 08e68f925e274989c09249449c12f8870604ad5d Mon Sep 17 00:00:00 2001 From: vivek Date: Fri, 1 Mar 2019 07:17:16 +0000 Subject: [PATCH 030/142] bgpd: Recursively determine if route's source is EVPN With leaking of IPv4 or IPv6 unicast routes whose source is a EVPN type-2 or type-5 route between VRFs, the determination of whether the route's source is EVPN has to be made recursively. This is used during route install to pass along appropriate parameters to zebra. Signed-off-by: Vivek Venkatraman Reviewed-by: Anuradha Karuppiah Reviewed-by: Donald Sharp --- bgpd/bgp_evpn.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 0027ae51a4..dfe141c40e 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -88,8 +88,13 @@ static inline int is_route_parent_evpn(struct bgp_path_info *ri) !ri->extra->parent) return 0; - /* See if the parent is of family L2VPN/EVPN */ - parent_ri = (struct bgp_path_info *)ri->extra->parent; + /* Determine parent recursively */ + for (parent_ri = ri->extra->parent; + parent_ri->extra && parent_ri->extra->parent; + parent_ri = parent_ri->extra->parent) + ; + + /* See if of family L2VPN/EVPN */ rn = parent_ri->net; if (!rn) return 0; From 0cf08685d2ed61659ba11695d142b56ebbc13a9f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 28 Feb 2019 07:51:41 -0500 Subject: [PATCH 031/142] sharpd: Setup route installation to be able to select vrf to use Modify the sharp code to allow for vrf route installation. At this point in time the code is nascent. Future commits will turn on this behavior. Signed-off-by: Donald Sharp --- sharpd/sharp_globals.h | 1 + sharpd/sharp_vty.c | 9 +++++++-- sharpd/sharp_zebra.c | 29 ++++++++++++++++------------- sharpd/sharp_zebra.h | 15 ++++++++------- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h index 065fb092d4..4e5c933667 100644 --- a/sharpd/sharp_globals.h +++ b/sharpd/sharp_globals.h @@ -38,6 +38,7 @@ struct sharp_routes { int32_t repeat; uint8_t inst; + vrf_id_t vrf_id; struct timeval t_start; struct timeval t_end; diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 9018cfb359..72a46d5e6d 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -195,12 +195,15 @@ DEFPY (install_routes, sg.r.nhop.type = NEXTHOP_TYPE_IPV6; } + sg.r.nhop.vrf_id = VRF_DEFAULT; sg.r.nhop_group.nexthop = &sg.r.nhop; } sg.r.inst = instance; + sg.r.vrf_id = VRF_DEFAULT; rts = routes; - sharp_install_routes_helper(&prefix, sg.r.inst, &sg.r.nhop_group, rts); + sharp_install_routes_helper(&prefix, sg.r.vrf_id, + sg.r.inst, &sg.r.nhop_group, rts); return CMD_SUCCESS; } @@ -266,8 +269,10 @@ DEFPY (remove_routes, } sg.r.inst = instance; + sg.r.vrf_id = VRF_DEFAULT; rts = routes; - sharp_remove_routes_helper(&prefix, sg.r.inst, rts); + sharp_remove_routes_helper(&prefix, sg.r.vrf_id, + sg.r.inst, rts); return CMD_SUCCESS; } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 4682dbc73a..942040b802 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -131,8 +131,8 @@ static int interface_state_down(int command, struct zclient *zclient, return 0; } -void sharp_install_routes_helper(struct prefix *p, uint8_t instance, - struct nexthop_group *nhg, +void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, + uint8_t instance, struct nexthop_group *nhg, uint32_t routes) { uint32_t temp, i; @@ -148,7 +148,7 @@ void sharp_install_routes_helper(struct prefix *p, uint8_t instance, monotime(&sg.r.t_start); for (i = 0; i < routes; i++) { - route_add(p, (uint8_t)instance, nhg); + route_add(p, vrf_id, (uint8_t)instance, nhg); if (v4) p->u.prefix4.s_addr = htonl(++temp); else @@ -156,8 +156,8 @@ void sharp_install_routes_helper(struct prefix *p, uint8_t instance, } } -void sharp_remove_routes_helper(struct prefix *p, uint8_t instance, - uint32_t routes) +void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id, + uint8_t instance, uint32_t routes) { uint32_t temp, i; bool v4 = false; @@ -172,7 +172,7 @@ void sharp_remove_routes_helper(struct prefix *p, uint8_t instance, monotime(&sg.r.t_start); for (i = 0; i < routes; i++) { - route_delete(p, (uint8_t)instance); + route_delete(p, vrf_id, (uint8_t)instance); if (v4) p->u.prefix4.s_addr = htonl(++temp); else @@ -190,12 +190,14 @@ static void handle_repeated(bool installed) if (installed) { sg.r.removed_routes = 0; - sharp_remove_routes_helper(&p, sg.r.inst, sg.r.total_routes); + sharp_remove_routes_helper(&p, sg.r.vrf_id, + sg.r.inst, sg.r.total_routes); } if (installed) { sg.r.installed_routes = 0; - sharp_install_routes_helper(&p, sg.r.inst, &sg.r.nhop_group, + sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst, + &sg.r.nhop_group, sg.r.total_routes); } } @@ -255,7 +257,8 @@ void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label) zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP); } -void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg) +void route_add(struct prefix *p, vrf_id_t vrf_id, + uint8_t instance, struct nexthop_group *nhg) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -263,7 +266,7 @@ void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg) int i = 0; memset(&api, 0, sizeof(api)); - api.vrf_id = VRF_DEFAULT; + api.vrf_id = vrf_id; api.type = ZEBRA_ROUTE_SHARP; api.instance = instance; api.safi = SAFI_UNICAST; @@ -274,7 +277,7 @@ void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg) for (ALL_NEXTHOPS_PTR(nhg, nh)) { api_nh = &api.nexthops[i]; - api_nh->vrf_id = VRF_DEFAULT; + api_nh->vrf_id = nh->vrf_id; api_nh->type = nh->type; switch (nh->type) { case NEXTHOP_TYPE_IPV4: @@ -305,12 +308,12 @@ void route_add(struct prefix *p, uint8_t instance, struct nexthop_group *nhg) zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); } -void route_delete(struct prefix *p, uint8_t instance) +void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance) { struct zapi_route api; memset(&api, 0, sizeof(api)); - api.vrf_id = VRF_DEFAULT; + api.vrf_id = vrf_id; api.type = ZEBRA_ROUTE_SHARP; api.safi = SAFI_UNICAST; api.instance = instance; diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index b219022f02..7c3c39c892 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -25,15 +25,16 @@ extern void sharp_zebra_init(void); extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label); -extern void route_add(struct prefix *p, uint8_t instance, +extern void route_add(struct prefix *p, vrf_id_t, uint8_t instance, struct nexthop_group *nhg); -extern void route_delete(struct prefix *p, uint8_t instance); +extern void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance); extern void sharp_zebra_nexthop_watch(struct prefix *p, bool import, bool watch, bool connected); -extern void sharp_install_routes_helper(struct prefix *p, uint8_t instance, - struct nexthop_group *nhg, - uint32_t routes); -extern void sharp_remove_routes_helper(struct prefix *p, uint8_t instance, - uint32_t routes); +extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, + uint8_t instance, + struct nexthop_group *nhg, + uint32_t routes); +extern void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id, + uint8_t instance, uint32_t routes); #endif From 4a7d47374b44399077913c6378a0fd002f89925c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 28 Feb 2019 08:09:53 -0500 Subject: [PATCH 032/142] sharpd: Add cli to allow vrf route installation Add a bit of code to allow the end user to specify a [vrf NAME] for route installation/deletion. Signed-off-by: Donald Sharp --- sharpd/sharp_vty.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 72a46d5e6d..21fa3cf744 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -132,10 +132,12 @@ DEFPY (install_routes_data_dump, DEFPY (install_routes, install_routes_cmd, - "sharp install routes |nexthop-group NAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", + "sharp install routes [vrf NAME$name] |nexthop-group NAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", "Sharp routing Protocol\n" "install some routes\n" "Routes to install\n" + "The vrf we would like to install into if non-default\n" + "The NAME of the vrf\n" "v4 Address to start /32 generation at\n" "v6 Address to start /32 generation at\n" "Nexthop to use(Can be an IPv4 or IPv6 address)\n" @@ -149,6 +151,7 @@ DEFPY (install_routes, "Should we repeat this command\n" "How many times to repeat this command\n") { + struct vrf *vrf; struct prefix prefix; uint32_t rts; @@ -176,6 +179,13 @@ DEFPY (install_routes, } sg.r.orig_prefix = prefix; + vrf = vrf_lookup_by_name(name ? name : VRF_DEFAULT_NAME); + if (!vrf) { + vty_out(vty, "The vrf NAME specified: %s does not exist\n", + name ? name : VRF_DEFAULT_NAME); + return CMD_WARNING; + } + if (nexthop_group) { struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group); if (!nhgc) { @@ -195,12 +205,12 @@ DEFPY (install_routes, sg.r.nhop.type = NEXTHOP_TYPE_IPV6; } - sg.r.nhop.vrf_id = VRF_DEFAULT; + sg.r.nhop.vrf_id = vrf->vrf_id; sg.r.nhop_group.nexthop = &sg.r.nhop; } sg.r.inst = instance; - sg.r.vrf_id = VRF_DEFAULT; + sg.r.vrf_id = vrf->vrf_id; rts = routes; sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, &sg.r.nhop_group, rts); @@ -240,16 +250,19 @@ DEFPY(vrf_label, vrf_label_cmd, DEFPY (remove_routes, remove_routes_cmd, - "sharp remove routes (1-1000000)$routes [instance (0-255)$instance]", + "sharp remove routes [vrf NAME$name] (1-1000000)$routes [instance (0-255)$instance]", "Sharp Routing Protocol\n" "Remove some routes\n" "Routes to remove\n" + "The vrf we would like to remove from if non-default\n" + "The NAME of the vrf\n" "v4 Starting spot\n" "v6 Starting spot\n" "Routes to uninstall\n" "instance to use\n" "Value of instance\n") { + struct vrf *vrf; struct prefix prefix; sg.r.total_routes = routes; @@ -268,8 +281,15 @@ DEFPY (remove_routes, prefix.u.prefix6 = start6; } + vrf = vrf_lookup_by_name(name ? name : VRF_DEFAULT_NAME); + if (!vrf) { + vty_out(vty, "The vrf NAME specified: %s does not exist\n", + name ? name : VRF_DEFAULT_NAME); + return CMD_WARNING; + } + sg.r.inst = instance; - sg.r.vrf_id = VRF_DEFAULT; + sg.r.vrf_id = vrf->vrf_id; rts = routes; sharp_remove_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, rts); From 91529dc88d20394b64488ade43ec48454f5eb7c6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 28 Feb 2019 08:12:32 -0500 Subject: [PATCH 033/142] sharpd: Add ability to pass vrf we want to watch Add the ability for the sharp zebra code to pass down the vrf that we want to watch. At this point in time, we cannot use it. Signed-off-by: Donald Sharp --- sharpd/sharp_vty.c | 6 ++++-- sharpd/sharp_zebra.c | 4 ++-- sharpd/sharp_zebra.h | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 21fa3cf744..74550d82d4 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -63,7 +63,8 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, p.family = AF_INET6; sharp_nh_tracker_get(&p); - sharp_zebra_nexthop_watch(&p, type_import, true, !!connected); + sharp_zebra_nexthop_watch(&p, VRF_DEFAULT, type_import, + true, !!connected); return CMD_SUCCESS; } @@ -92,7 +93,8 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, p.family = AF_INET; sharp_nh_tracker_get(&p); - sharp_zebra_nexthop_watch(&p, type_import, true, !!connected); + sharp_zebra_nexthop_watch(&p, VRF_DEFAULT, type_import, + true, !!connected); return CMD_SUCCESS; } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 942040b802..f1e83628c2 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -323,7 +323,7 @@ void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance) return; } -void sharp_zebra_nexthop_watch(struct prefix *p, bool import, +void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, bool watch, bool connected) { int command; @@ -340,7 +340,7 @@ void sharp_zebra_nexthop_watch(struct prefix *p, bool import, command = ZEBRA_IMPORT_ROUTE_UNREGISTER; } - if (zclient_send_rnh(zclient, command, p, connected, VRF_DEFAULT) < 0) + if (zclient_send_rnh(zclient, command, p, connected, vrf_id) < 0) zlog_warn("%s: Failure to send nexthop to zebra", __PRETTY_FUNCTION__); } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 7c3c39c892..57ffcc7690 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -28,8 +28,8 @@ extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label); extern void route_add(struct prefix *p, vrf_id_t, uint8_t instance, struct nexthop_group *nhg); extern void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance); -extern void sharp_zebra_nexthop_watch(struct prefix *p, bool import, - bool watch, bool connected); +extern void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, + bool import, bool watch, bool connected); extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, From a3b6aa82db8f0caf9e04d93e0c74849db1cc63b6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 28 Feb 2019 08:24:20 -0500 Subject: [PATCH 034/142] sharpd: Add code to allow nexthops to be watched from non-default vrf Add a bit of code to the sharp cli to allow it to specify a non-default vrf. Signed-off-by: Donald Sharp --- sharpd/sharp_vty.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 74550d82d4..fbcbbe3fdc 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -39,17 +39,28 @@ #endif DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, - "sharp watch X:X::X:X$nhop [connected$connected]", + "sharp watch [vrf NAME$name] X:X::X:X$nhop [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" + "The vrf we would like to watch if non-default\n" + "The NAME of the vrf\n" "Watch for nexthop changes\n" "Watch for import check changes\n" "The v6 nexthop to signal for watching\n" "Should the route be connected\n") { + struct vrf *vrf; struct prefix p; bool type_import; + if (!name) + name = VRF_DEFAULT_NAME; + vrf = vrf_lookup_by_name(name); + if (!vrf) { + vty_out(vty, "The vrf NAME specified: %s does not exist\n", + name); + return CMD_WARNING; + } if (n) type_import = false; @@ -63,24 +74,36 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, p.family = AF_INET6; sharp_nh_tracker_get(&p); - sharp_zebra_nexthop_watch(&p, VRF_DEFAULT, type_import, + sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, true, !!connected); return CMD_SUCCESS; } DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, - "sharp watch A.B.C.D$nhop [connected$connected]", + "sharp watch [vrf NAME$name] A.B.C.D$nhop [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" + "The vrf we would like to watch if non-default\n" + "The NAME of the vrf\n" "Watch for nexthop changes\n" "Watch for import check changes\n" "The v4 nexthop to signal for watching\n" "Should the route be connected\n") { + struct vrf *vrf; struct prefix p; bool type_import; + if (!name) + name = VRF_DEFAULT_NAME; + vrf = vrf_lookup_by_name(name); + if (!vrf) { + vty_out(vty, "The vrf NAME specified: %s does not exist\n", + name); + return CMD_WARNING; + } + memset(&p, 0, sizeof(p)); if (n) @@ -93,7 +116,7 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, p.family = AF_INET; sharp_nh_tracker_get(&p); - sharp_zebra_nexthop_watch(&p, VRF_DEFAULT, type_import, + sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, true, !!connected); return CMD_SUCCESS; @@ -181,10 +204,13 @@ DEFPY (install_routes, } sg.r.orig_prefix = prefix; - vrf = vrf_lookup_by_name(name ? name : VRF_DEFAULT_NAME); + if (!name) + name = VRF_DEFAULT_NAME; + + vrf = vrf_lookup_by_name(name); if (!vrf) { vty_out(vty, "The vrf NAME specified: %s does not exist\n", - name ? name : VRF_DEFAULT_NAME); + name); return CMD_WARNING; } From bd4fb6158ddafa10b86a3a382934ed7a8c6e7afc Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 28 Feb 2019 09:11:41 -0500 Subject: [PATCH 035/142] zebra: Upon vrf deletion, actually release this data. When a vrf is deleted we need to tell the zebra_router that we have finished using the tables we are keeping track of. This will allow us to properly cleanup the data structures associated with them. This fixes this valgrind error found: ==8579== Invalid read of size 8 ==8579== at 0x430034: zvrf_id (zebra_vrf.h:167) ==8579== by 0x432366: rib_process (zebra_rib.c:1580) ==8579== by 0x432366: process_subq (zebra_rib.c:2092) ==8579== by 0x432366: meta_queue_process (zebra_rib.c:2188) ==8579== by 0x48C99FE: work_queue_run (workqueue.c:291) ==8579== by 0x48C3788: thread_call (thread.c:1607) ==8579== by 0x48A2E9E: frr_run (libfrr.c:1011) ==8579== by 0x41316A: main (main.c:473) ==8579== Address 0x5aeb750 is 0 bytes inside a block of size 4,424 free'd ==8579== at 0x4839A0C: free (vg_replace_malloc.c:540) ==8579== by 0x438914: zebra_vrf_delete (zebra_vrf.c:279) ==8579== by 0x48C4225: vrf_delete (vrf.c:243) ==8579== by 0x48C4225: vrf_delete (vrf.c:217) ==8579== by 0x4151CE: netlink_vrf_change (if_netlink.c:364) ==8579== by 0x416810: netlink_link_change (if_netlink.c:1189) ==8579== by 0x41C1FC: netlink_parse_info (kernel_netlink.c:904) ==8579== by 0x41C2D3: kernel_read (kernel_netlink.c:389) ==8579== by 0x48C3788: thread_call (thread.c:1607) ==8579== by 0x48A2E9E: frr_run (libfrr.c:1011) ==8579== by 0x41316A: main (main.c:473) ==8579== Block was alloc'd at ==8579== at 0x483AB1A: calloc (vg_replace_malloc.c:762) ==8579== by 0x48A6030: qcalloc (memory.c:110) ==8579== by 0x4389EF: zebra_vrf_alloc (zebra_vrf.c:382) ==8579== by 0x438A42: zebra_vrf_new (zebra_vrf.c:93) ==8579== by 0x48C40AD: vrf_get (vrf.c:209) ==8579== by 0x415144: netlink_vrf_change (if_netlink.c:319) ==8579== by 0x415E90: netlink_interface (if_netlink.c:653) ==8579== by 0x41C1FC: netlink_parse_info (kernel_netlink.c:904) ==8579== by 0x4163E8: interface_lookup_netlink (if_netlink.c:760) ==8579== by 0x42BB37: zebra_ns_enable (zebra_ns.c:130) ==8579== by 0x42BC5E: zebra_ns_init (zebra_ns.c:208) ==8579== by 0x4130F4: main (main.c:401) This can be found by: `ip link del ` then `ip link add type vrf table X` again and then attempting to use the vrf. Signed-off-by: Donald Sharp --- zebra/zebra_router.c | 21 +++++++++++++++++++++ zebra/zebra_router.h | 2 ++ zebra/zebra_vrf.c | 13 +++++++------ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index c3b861c242..cabc8be8dd 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -168,10 +168,31 @@ static void zebra_router_free_table(struct zebra_router_table *zrt) table_info = route_table_get_info(zrt->table); route_table_finish(zrt->table); + RB_REMOVE(zebra_router_table_head, &zrouter.tables, zrt); + XFREE(MTYPE_RIB_TABLE_INFO, table_info); XFREE(MTYPE_ZEBRA_NS, zrt); } +void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid, + afi_t afi, safi_t safi) +{ + struct zebra_router_table finder; + struct zebra_router_table *zrt; + + memset(&finder, 0, sizeof(finder)); + finder.afi = afi; + finder.safi = safi; + finder.tableid = tableid; + finder.ns_id = zvrf->zns->ns_id; + zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder); + + if (!zrt) + return; + + zebra_router_free_table(zrt); +} + uint32_t zebra_router_get_next_sequence(void) { return 1 diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index fb28495917..e5043f38ae 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -117,6 +117,8 @@ extern struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf, extern struct route_table *zebra_router_get_table(struct zebra_vrf *zvrf, uint32_t tableid, afi_t afi, safi_t safi); +extern void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid, + afi_t afi, safi_t safi); extern int zebra_router_config_write(struct vty *vty); diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index d18305495b..390c01dc67 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -208,8 +208,11 @@ static int zebra_vrf_disable(struct vrf *vrf) * table, see rib_close_table above * we no-longer need this pointer. */ - for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { + zebra_router_release_table(zvrf, zvrf->table_id, afi, + safi); zvrf->table[afi][safi] = NULL; + } route_table_finish(zvrf->rnh_table[afi]); zvrf->rnh_table[afi] = NULL; @@ -256,14 +259,12 @@ static int zebra_vrf_delete(struct vrf *vrf) /* release allocated memory */ for (afi = AFI_IP; afi <= AFI_IP6; afi++) { - void *table_info; - for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { table = zvrf->table[afi][safi]; if (table) { - table_info = route_table_get_info(table); - route_table_finish(table); - XFREE(MTYPE_RIB_TABLE_INFO, table_info); + zebra_router_release_table(zvrf, zvrf->table_id, + afi, safi); + zvrf->table[afi][safi] = NULL; } } From 390485fdc96dbdd56c42d1db5d73c985411f8b4b Mon Sep 17 00:00:00 2001 From: Don Slice Date: Sat, 2 Mar 2019 19:40:17 +0000 Subject: [PATCH 036/142] bpgd: resolve more neighbor peer-group issues Found in testing that in a certain sequence, a neighbor's peer-group membership would be lost. This fix resolves that issue. Additionally found that "no neighbor swp1 remote-as 2" would sometimes leave the config with "neighbor swp1 remote-as 0" rather than removing from the config. That one is also resolved. Signed-off-by: Don Slice --- bgpd/bgp_vty.c | 17 +++++++++++------ bgpd/bgpd.c | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 93d22087bb..8cb20c5e7f 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2841,18 +2841,23 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, as = strtoul(as_str, NULL, 10); } - /* If peer is peer group, call proper function. */ + /* If peer is peer group or interface peer, call proper function. */ ret = str2sockunion(peer_str, &su); if (ret < 0) { - /* Check for peer by interface */ + struct peer *peer; + + /* Check if existing interface peer */ + peer = peer_lookup_by_conf_if(bgp, peer_str); + ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, afi, safi); - if (ret < 0) { + + /* if not interface peer, check peer-group settings */ + if (ret < 0 && !peer) { ret = peer_group_remote_as(bgp, peer_str, &as, as_type); if (ret < 0) { vty_out(vty, - "%% Create the peer-group or interface first or specify \"interface\" keyword\n"); - vty_out(vty, "%% if using an unnumbered interface neighbor\n"); + "%% Create the peer-group or interface first\n"); return CMD_WARNING_CONFIG_FAILED; } return CMD_SUCCESS; @@ -3251,7 +3256,7 @@ DEFUN (no_neighbor_interface_peer_group_remote_as, /* look up for neighbor by interface name config. */ peer = peer_lookup_by_conf_if(bgp, argv[idx_word]->arg); if (peer) { - peer_as_change(peer, 0, AS_SPECIFIED); + peer_as_change(peer, 0, AS_UNSPECIFIED); return CMD_SUCCESS; } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a920cfeeec..1a73301e43 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2722,7 +2722,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, peer->sort = group->conf->sort; } - if (!group->conf->as) { + if (!group->conf->as && peer_sort(peer)) { if (peer_sort(group->conf) != BGP_PEER_INTERNAL && peer_sort(group->conf) != peer_sort(peer)) { if (as) From 58e39d522b1d55cdd58ce5833298bf23aa27ce05 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Sat, 2 Mar 2019 17:45:14 -0300 Subject: [PATCH 037/142] ripd: fix removal of configured passive interfaces libyang-0.16-rc3 fixed a bug [1] in which data would be auto-deleted when it shouldn't. The problem is that the "no passive-interface" command was relying on that wrong behavior, so the command was affected when the libyang bug was fixed. Adapt the command to do the right thing in order to get rid of the problem (regardless of the libyang version being used). "passive-interface default" still has problems though, but that will be addressed separetely in the future. Fixes #3870. [1] https://github.com/CESNET/libyang/commit/8af82206908 Signed-off-by: Renato Westphal --- ripd/rip_cli.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c index 6fbcdc059b..62aaad5d97 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -378,10 +378,19 @@ DEFPY (rip_passive_interface, "Suppress routing updates on an interface\n" "Interface name\n") { - nb_cli_enqueue_change(vty, "./passive-interface", - no ? NB_OP_DESTROY : NB_OP_CREATE, ifname); - nb_cli_enqueue_change(vty, "./non-passive-interface", - no ? NB_OP_CREATE : NB_OP_DESTROY, ifname); + bool passive_default = + yang_dnode_get_bool(vty->candidate_config->dnode, "%s%s", + VTY_CURR_XPATH, "/passive-default"); + + if (passive_default) { + nb_cli_enqueue_change(vty, "./non-passive-interface", + no ? NB_OP_CREATE : NB_OP_DESTROY, + ifname); + } else { + nb_cli_enqueue_change(vty, "./passive-interface", + no ? NB_OP_DESTROY : NB_OP_CREATE, + ifname); + } return nb_cli_apply_changes(vty, NULL); } From cacbffafc9f2e133d3c76f081635f67ae504d124 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 28 Feb 2019 19:49:28 -0300 Subject: [PATCH 038/142] lib: simplify code that calculates configuration diffs This is just a small refactoring to reduce code duplication. No behavior changes intended. Signed-off-by: Renato Westphal --- lib/northbound.c | 79 ++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 47 deletions(-) diff --git a/lib/northbound.c b/lib/northbound.c index 15139aa8d0..fd71579ff0 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -348,40 +348,39 @@ static void nb_config_diff_del_changes(struct nb_config_cbs *changes) * configurations. Given a new subtree, calculate all new YANG data nodes, * excluding default leafs and leaf-lists. This is a recursive function. */ -static void nb_config_diff_new_subtree(const struct lyd_node *dnode, - struct nb_config_cbs *changes) +static void nb_config_diff_created(const struct lyd_node *dnode, + struct nb_config_cbs *changes) { + enum nb_operation operation; struct lyd_node *child; - LY_TREE_FOR (dnode->child, child) { - enum nb_operation operation; - - switch (child->schema->nodetype) { - case LYS_LEAF: - case LYS_LEAFLIST: - if (lyd_wd_default((struct lyd_node_leaf_list *)child)) - break; - - if (nb_operation_is_valid(NB_OP_CREATE, child->schema)) - operation = NB_OP_CREATE; - else if (nb_operation_is_valid(NB_OP_MODIFY, - child->schema)) - operation = NB_OP_MODIFY; - else - continue; - - nb_config_diff_add_change(changes, operation, child); - break; - case LYS_CONTAINER: - case LYS_LIST: - if (nb_operation_is_valid(NB_OP_CREATE, child->schema)) - nb_config_diff_add_change(changes, NB_OP_CREATE, - child); - nb_config_diff_new_subtree(child, changes); - break; - default: + switch (dnode->schema->nodetype) { + case LYS_LEAF: + case LYS_LEAFLIST: + if (lyd_wd_default((struct lyd_node_leaf_list *)dnode)) break; + + if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema)) + operation = NB_OP_CREATE; + else if (nb_operation_is_valid(NB_OP_MODIFY, dnode->schema)) + operation = NB_OP_MODIFY; + else + return; + + nb_config_diff_add_change(changes, operation, dnode); + break; + case LYS_CONTAINER: + case LYS_LIST: + if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema)) + nb_config_diff_add_change(changes, NB_OP_CREATE, dnode); + + /* Process child nodes recursively. */ + LY_TREE_FOR (dnode->child, child) { + nb_config_diff_created(child, changes); } + break; + default: + break; } } @@ -399,42 +398,28 @@ static void nb_config_diff(const struct nb_config *config1, for (int i = 0; diff->type[i] != LYD_DIFF_END; i++) { LYD_DIFFTYPE type; struct lyd_node *dnode; - enum nb_operation operation; type = diff->type[i]; switch (type) { case LYD_DIFF_CREATED: dnode = diff->second[i]; - - if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema)) - operation = NB_OP_CREATE; - else if (nb_operation_is_valid(NB_OP_MODIFY, - dnode->schema)) - operation = NB_OP_MODIFY; - else - continue; + nb_config_diff_created(dnode, changes); break; case LYD_DIFF_DELETED: dnode = diff->first[i]; - operation = NB_OP_DESTROY; + nb_config_diff_add_change(changes, NB_OP_DESTROY, + dnode); break; case LYD_DIFF_CHANGED: dnode = diff->second[i]; - operation = NB_OP_MODIFY; + nb_config_diff_add_change(changes, NB_OP_MODIFY, dnode); break; case LYD_DIFF_MOVEDAFTER1: case LYD_DIFF_MOVEDAFTER2: default: continue; } - - nb_config_diff_add_change(changes, operation, dnode); - - if (type == LYD_DIFF_CREATED - && CHECK_FLAG(dnode->schema->nodetype, - LYS_CONTAINER | LYS_LIST)) - nb_config_diff_new_subtree(dnode, changes); } lyd_free_diff(diff); From 1912caa2caf14936379df830e028d1492a061988 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 28 Feb 2019 19:54:47 -0300 Subject: [PATCH 039/142] lib: fix removal of yang non-presence containers Non-presence containers don't have "destroy" callbacks. So, once a np-container is deleted, we need to call the "destroy" callbacks of its child nodes instead. This commit doesn't fix any real problem as of now since all np-containers from the FRR YANG modules contain or one more mandatory child nodes, so they can't be deleted (libyang will add missing np-containers when validating data). Nevertheless, upcoming YANG modules should benefit from this change. Signed-off-by: Renato Westphal --- lib/northbound.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/northbound.c b/lib/northbound.c index fd71579ff0..edf7e0eca6 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -384,6 +384,26 @@ static void nb_config_diff_created(const struct lyd_node *dnode, } } +static void nb_config_diff_deleted(const struct lyd_node *dnode, + struct nb_config_cbs *changes) +{ + if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema)) + nb_config_diff_add_change(changes, NB_OP_DESTROY, dnode); + else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) { + struct lyd_node *child; + + /* + * Non-presence containers need special handling since they + * don't have "destroy" callbacks. In this case, what we need to + * do is to call the "destroy" callbacks of their child nodes + * when applicable (i.e. optional nodes). + */ + LY_TREE_FOR (dnode->child, child) { + nb_config_diff_deleted(child, changes); + } + } +} + /* Calculate the delta between two different configurations. */ static void nb_config_diff(const struct nb_config *config1, const struct nb_config *config2, @@ -408,8 +428,7 @@ static void nb_config_diff(const struct nb_config *config1, break; case LYD_DIFF_DELETED: dnode = diff->first[i]; - nb_config_diff_add_change(changes, NB_OP_DESTROY, - dnode); + nb_config_diff_deleted(dnode, changes); break; case LYD_DIFF_CHANGED: dnode = diff->second[i]; From 3de708125ec2f2d737bd5e6285a8e6ab23fed094 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 5 Mar 2019 10:29:35 -0500 Subject: [PATCH 040/142] pimd: Ensure DR election happens when both sides change prio Suppose we have 2 routers A and B. Both Router A and B have the same priority of 1000. Router A is the elected DR. Now suppose B lowers his priority to 1. He still looses the DR election and we are not sending a hello with the new priority. Immediately after this A's priority is also lowered to 1, it looses the election and sends the hello. B receives this hello and elects A as the DR( since it has the better ip address) At this point A believes B is the DR, and B believes A is the DR until such time that the normal hello from B is sent to A, which if timed correctly can be a significant amount of time). This code just causes a hello to be sent if the priority is changed. Now both sides will be able to converge quickly Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index eaec002a73..be1074fdf4 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -6353,8 +6353,8 @@ DEFUN (interface_ip_pim_drprio, pim_ifp->pim_dr_priority = strtol(argv[idx_number]->arg, NULL, 10); if (old_dr_prio != pim_ifp->pim_dr_priority) { - if (pim_if_dr_election(ifp)) - pim_hello_restart_now(ifp); + pim_if_dr_election(ifp); + pim_hello_restart_now(ifp); } return CMD_SUCCESS; @@ -6379,8 +6379,8 @@ DEFUN (interface_no_ip_pim_drprio, if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) { pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY; - if (pim_if_dr_election(ifp)) - pim_hello_restart_now(ifp); + pim_if_dr_election(ifp); + pim_hello_restart_now(ifp); } return CMD_SUCCESS; From 456a4697e541a9cb7f268f63cfed0466f003381e Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Tue, 5 Mar 2019 10:40:26 -0800 Subject: [PATCH 041/142] bgpd: prevent type-5 route creation if bgp_vrf->l3_vni is 0 After a router reboot the L3 network via it converges before the L2 network. This is because MLAG intentionally holds down bridge-access and vxlan-network ports for some time (MLAG init-delay) to prevent traffic from switching to a router that is not fully ready. This also means that routes (from vrf-peering sessions) that qualify for evpn type-5 advertisments are available long before the L3-VNI is available for that tenant VRF. In these windows bgpd was adding these evpn-type-5 routes with a L3-VNI of 0 (which was not fixed up after the L3-VNI became available) - BGP routing table entry for 100.0.0.1:2:[5]:[0]:[0]:[32]:[200.1.1.1] Paths: (1 available, best #1) Advertised to non peer-group peers: MSP1(uplink-1) MSP2(uplink-2) Route [5]:[0]:[0]:[32]:[200.1.1.1] VNI 0 >>>>>>>> 65001 65535 36.0.0.9 from 0.0.0.0 (27.0.0.9) Origin incomplete, metric 0, valid, sourced, local, bestpath-from-AS 65001, best Extended Community: ET:8 RT:5544:4001 Rmac:44:38:39:ff:ff:01 AddPath ID: RX 0, TX 327 Last update: Wed Feb 27 18:37:10 2019 Fix is to defer creating type-5 routes till the L3-VNI is available for that tenant VRF (this was already being done for most cases; fixup takes care of some that missed the check). Ticket: CM-24022 Signed-off-by: Anuradha Karuppiah --- bgpd/bgp_evpn_vty.c | 3 ++- bgpd/bgp_routemap.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 8437c4024e..fb2d9da533 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3358,7 +3358,8 @@ DEFUN (bgp_evpn_advertise_type5, } /* advertise type-5 routes */ - bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi); + if (advertise_type5_routes(bgp_vrf, afi)) + bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi); return CMD_SUCCESS; } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 17109281bc..68d784409a 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3399,7 +3399,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, "Processing route_map %s update on advertise type5 route command", rmap_name); - if (route_update) { + if (route_update && advertise_type5_routes(bgp, afi)) { bgp_evpn_withdraw_type5_routes(bgp, afi, safi); bgp_evpn_advertise_type5_routes(bgp, afi, safi); } From 47e0a3b46b221b180ef6aeed5a492ffbe80344f0 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Mar 2019 10:44:34 -0500 Subject: [PATCH 042/142] configure: Default to 16 way ecmp on compilation If a person who is compiling FRR does not specify the multipath number on configure we are defaulting to a ecmp of 1. Let's change this to 16. In this day and age most everything supports actual ecmp. Signed-off-by: Donald Sharp --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fcfc4bd2fb..9ae196fcb1 100755 --- a/configure.ac +++ b/configure.ac @@ -765,7 +765,7 @@ AC_DEFINE_UNQUOTED([CONFIGFILE_MASK], [${enable_configfile_mask}], [Mask for con enable_logfile_mask=${enable_logfile_mask:-0600} AC_DEFINE_UNQUOTED([LOGFILE_MASK], [${enable_logfile_mask}], [Mask for log files]) -MPATH_NUM=1 +MPATH_NUM=16 case "${enable_multipath}" in 0) From b16b7e07564e0c6dd86c72628ebf28abd180c9f2 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Mar 2019 10:47:21 -0500 Subject: [PATCH 043/142] doc: Update documentation about multipath Signed-off-by: Donald Sharp --- doc/user/installation.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 4e1582ccd8..e191ebd035 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -275,7 +275,8 @@ options from the list below. For backwards compatability with older configure options when setting X = 0, we will build FRR with 64 way ECMP. This is needed because there are hardcoded arrays that FRR builds towards, so we need to know how big to - make these arrays at build time. + make these arrays at build time. Additionally if this parameter is + not passed in FRR will default to 16 ECMP. .. option:: --enable-shell-access From 140d2d7ff5db4a83ff4b8ed1e95d3d48368b9603 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Wed, 6 Mar 2019 10:53:49 -0500 Subject: [PATCH 044/142] zebra: Remove unused sockaddr variable This variable does nothing, removing it. Signed-off-by: Stephen Worley --- zebra/rt_netlink.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 18cf389d5e..9cea1d3c79 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1438,7 +1438,6 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) { int bytelen; - struct sockaddr_nl snl; struct nexthop *nexthop = NULL; unsigned int nexthop_num; int family; @@ -1747,11 +1746,6 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) } skip: - - /* Destination netlink address. */ - memset(&snl, 0, sizeof(snl)); - snl.nl_family = AF_NETLINK; - /* Talk to netlink socket. */ return netlink_talk_info(netlink_talk_filter, &req.n, dplane_ctx_get_ns(ctx), 0); From dded74d5784072b4d1d90d4307a94f1171abf825 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Mar 2019 10:40:53 -0500 Subject: [PATCH 045/142] bgpd: Don't prevent views from being able to connect Views are perfectly valid and should be allowed to connect. In a bgp instance scenario the vrf_id will always be UNKNOWN, so allow it. Signed-off-by: Donald Sharp --- bgpd/bgp_fsm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index b70c8bbd63..447d8da613 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -310,7 +310,8 @@ void bgp_timer_set(struct peer *peer) status start timer is on unless peer is shutdown or peer is inactive. All other timer must be turned off */ if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer) - || peer->bgp->vrf_id == VRF_UNKNOWN) { + || (peer->bgp->inst_type != BGP_INSTANCE_TYPE_VIEW && + peer->bgp->vrf_id == VRF_UNKNOWN)) { BGP_TIMER_OFF(peer->t_start); } else { BGP_TIMER_ON(peer->t_start, bgp_start_timer, @@ -1422,7 +1423,8 @@ int bgp_start(struct peer *peer) return 0; } - if (peer->bgp->vrf_id == VRF_UNKNOWN) { + if (peer->bgp->inst_type != BGP_INSTANCE_TYPE_VIEW && + peer->bgp->vrf_id == VRF_UNKNOWN) { if (bgp_debug_neighbor_events(peer)) flog_err( EC_BGP_FSM, From 2435b7defe734ab42f8b30368ff842aa0a5b6c42 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 6 Mar 2019 17:50:04 -0300 Subject: [PATCH 046/142] bfdd: fix single hop IPv6 configurations Don't assume IPv6 will always be multi hop and handle the single hop link-local address case. Signed-off-by: Rafael Zalamena --- bfdd/bfd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index be6f2caa44..36133f5727 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -208,13 +208,17 @@ int bfd_session_enable(struct bfd_session *bs) /* Set the IPv6 scope id for link-local addresses. */ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) { - sin6 = &bs->mhop.peer.sa_sin6; + sin6 = (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) + ? &bs->mhop.peer.sa_sin6 + : &bs->shop.peer.sa_sin6; if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) sin6->sin6_scope_id = bs->ifp != NULL ? bs->ifp->ifindex : IFINDEX_INTERNAL; - sin6 = &bs->mhop.local.sa_sin6; + sin6 = (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) + ? &bs->mhop.local.sa_sin6 + : &bs->local_address.sa_sin6; if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) sin6->sin6_scope_id = bs->ifp != NULL ? bs->ifp->ifindex From 210ec2a0d63263be7178d494e044d6e570cd2f16 Mon Sep 17 00:00:00 2001 From: Akhilesh Samineni Date: Thu, 7 Mar 2019 13:17:25 +0530 Subject: [PATCH 047/142] bgpd: Incorrect number of peers count in "show bgp ipv6 summary output The "show bgp ipv6 summary" output displays incorrect number of peers count. sonic# show bgp ipv6 summary IPv6 Unicast Summary: BGP router identifier 10.1.0.1, local AS number 65100 vrf-id 0 BGP table version 0 RIB entries 0, using 0 bytes of memory Peers 5, using 103 KiB of memory Peer groups 1, using 64 bytes of memory Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd 2003::1 4 65099 0 0 0 0 0 never Active 2088::1 4 65100 0 0 0 0 0 never Active 3021::2 4 65100 0 0 0 0 0 never Active Total number of neighbors 3 sonic# In the above output, the peers count displays as 5 but the actual peer count is 3, i.e.. 3 neighbors are activated in ipv6 unicast address family. Displayed peer count (5) is the number of the neighbors activated in a BGP instance. Fix : Now the peers count displays the number of neighbors activated per afi/safi. After Fix: sonic# show bgp ipv6 summary IPv6 Unicast Summary: BGP router identifier 10.1.0.1, local AS number 65100 vrf-id 0 BGP table version 0 RIB entries 0, using 0 bytes of memory Peers 3, using 62 KiB of memory Peer groups 1, using 64 bytes of memory Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd 2003::1 4 65099 0 0 0 0 0 never Active 2088::1 4 65100 0 0 0 0 0 never Active 3021::2 4 65100 0 0 0 0 0 never Active Total number of neighbors 3 sonic# Signed-off-by: Akhilesh Samineni --- bgpd/bgp_vty.c | 4 ++-- bgpd/bgpd.c | 9 +++++++++ bgpd/bgpd.h | 3 +++ .../all-protocol-startup/r1/show_bgp_ipv6_summary.ref | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 93d22087bb..f111ad3c7f 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -8031,7 +8031,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, json, "ribMemory", ents * sizeof(struct bgp_node)); - ents = listcount(bgp->peer); + ents = bgp->af_peer_count[afi][safi]; json_object_int_add(json, "peerCount", ents); json_object_int_add(json, "peerMemory", ents * sizeof(struct peer)); @@ -8071,7 +8071,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, bgp_node))); /* Peer related usage */ - ents = listcount(bgp->peer); + ents = bgp->af_peer_count[afi][safi]; vty_out(vty, "Peers %ld, using %s of memory\n", ents, mtype_memstr( diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a920cfeeec..e7361ca0c6 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -707,6 +707,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi) { struct peer_af *af; int afid; + struct bgp *bgp; if (!peer) return NULL; @@ -715,6 +716,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi) if (afid >= BGP_AF_MAX) return NULL; + bgp = peer->bgp; assert(peer->peer_af_array[afid] == NULL); /* Allocate new peer af */ @@ -725,6 +727,7 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi) af->safi = safi; af->afid = afid; af->peer = peer; + bgp->af_peer_count[afi][safi]++; return af; } @@ -747,6 +750,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi) { struct peer_af *af; int afid; + struct bgp *bgp; if (!peer) return -1; @@ -759,6 +763,7 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi) if (!af) return -1; + bgp = peer->bgp; bgp_stop_announce_route_timer(af); if (PAF_SUBGRP(af)) { @@ -768,8 +773,12 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi) af->subgroup->id, peer->host); } + update_subgroup_remove_peer(af->subgroup, af); + if (bgp->af_peer_count[afi][safi]) + bgp->af_peer_count[afi][safi]--; + peer->peer_af_array[afid] = NULL; XFREE(MTYPE_BGP_PEER_AF, af); return 0; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index c7d137c76c..8f8696438b 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -374,6 +374,9 @@ struct bgp { #define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 7) #define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 8) + /* BGP per AF peer count */ + uint32_t af_peer_count[AFI_MAX][SAFI_MAX]; + /* Route table for next-hop lookup cache. */ struct bgp_table *nexthop_cache_table[AFI_MAX]; diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref index 6777cd9fc3..85388c738d 100644 --- a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref @@ -1,7 +1,7 @@ BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0 BGP table version 1 RIB entries 1, using XXXX bytes of memory -Peers 4, using XXXX KiB of memory +Peers 2, using XXXX KiB of memory Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd fc00:0:0:8::1000 4 100 0 0 0 0 0 never Active From e93a6fbb4f2e144d31ce56da67af3fe308905049 Mon Sep 17 00:00:00 2001 From: Tuetuopay Date: Tue, 5 Mar 2019 19:19:28 +0100 Subject: [PATCH 048/142] zebra: Treat ifaces withouth IPv4 as unnumbered The current definition of an unnumberd interface as an interface with a /32 IPv4 is too restrictive, especially for EVPN symmetric routing since commit 2b83602b2 "*: Explicitly mark nexthop of EVPN-sourced routes as onlink". It removes the bypass check wether the nexthop is an EVPN VTEP, and relies on the SVI to be unnumberd to bypass the gateway lookup. While this works great if the SVI has an IP, it might not, and the test falls flat and EVPN type 5 routes are not installed into the RIB. Sample interface setup, where vxlan-blue is the L3VNI and br-blue the SVI: +----------+ | | | vrf-blue | | | +---+--+---+ | | +-------+ +-----------+ | | +----+----+ +---------+---------+ | | | br1 | | br-blue | | 10.0.0.1/24 | | | +-+-------+-------+-+ +----+----+ | | | | | | | +-----+------+ +-----+--+ +--+---+ +-+----+ | | | | | | | | | vxlan-blue | | vxlan1 | | eth1 | | eth2 | | | | | | | | | +------------+ +--------+ +------+ +------+ For inter-VNI routing, the SVI has no reason to have an IP, but it still needs type-5 routes from remote VTEPs. This commit expands the definition of an unnumberd interface to an interface having a /32 IPv4 or no IPv4 at all. Signed-off-by: Tuetuopay --- zebra/connected.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/connected.c b/zebra/connected.c index c449855f6d..128f397552 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -594,5 +594,5 @@ int connected_is_unnumbered(struct interface *ifp) return CHECK_FLAG(connected->flags, ZEBRA_IFA_UNNUMBERED); } - return 0; + return 1; } From 16d697870b6e6597cda52625d895d4c6233c91b0 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Thu, 28 Feb 2019 16:23:21 -0500 Subject: [PATCH 049/142] zebra: rename pseudowire destination api In prep for adding nexthop info for pws, rename the accessor for the pw destination. Add a nexthop-group to the pw data in the dataplane module. Signed-off-by: Mark Stapp --- zebra/zebra_dplane.c | 21 +++++++++++++++++---- zebra/zebra_dplane.h | 2 +- zebra/zebra_mpls_openbsd.c | 2 +- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 894914e576..63ac7666f4 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -111,10 +111,13 @@ struct dplane_pw_info { int af; int status; uint32_t flags; - union g_addr nexthop; + union g_addr dest; mpls_label_t local_label; mpls_label_t remote_label; + /* Nexthops */ + struct nexthop_group nhg; + union pw_protocol_fields fields; }; @@ -386,6 +389,15 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx) case DPLANE_OP_PW_INSTALL: case DPLANE_OP_PW_UNINSTALL: + /* Free allocated nexthops */ + if ((*pctx)->u.pw.nhg.nexthop) { + /* This deals with recursive nexthops too */ + nexthops_free((*pctx)->u.pw.nhg.nexthop); + + (*pctx)->u.pw.nhg.nexthop = NULL; + } + break; + case DPLANE_OP_NONE: break; } @@ -814,12 +826,12 @@ int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx) return ctx->u.pw.status; } -const union g_addr *dplane_ctx_get_pw_nexthop( +const union g_addr *dplane_ctx_get_pw_dest( const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); - return &(ctx->u.pw.nexthop); + return &(ctx->u.pw.dest); } const union pw_protocol_fields *dplane_ctx_get_pw_proto( @@ -1056,6 +1068,7 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, /* This name appears to be c-string, so we use string copy. */ strlcpy(ctx->u.pw.ifname, pw->ifname, sizeof(ctx->u.pw.ifname)); + ctx->zd_vrf_id = pw->vrf_id; ctx->u.pw.ifindex = pw->ifindex; ctx->u.pw.type = pw->type; @@ -1064,7 +1077,7 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, ctx->u.pw.remote_label = pw->remote_label; ctx->u.pw.flags = pw->flags; - ctx->u.pw.nexthop = pw->nexthop; + ctx->u.pw.dest = pw->nexthop; ctx->u.pw.fields = pw->data; diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 81226961e8..84da20f2a7 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -215,7 +215,7 @@ int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx); int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx); int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx); -const union g_addr *dplane_ctx_get_pw_nexthop( +const union g_addr *dplane_ctx_get_pw_dest( const struct zebra_dplane_ctx *ctx); const union pw_protocol_fields *dplane_ctx_get_pw_proto( const struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c index ade36cbce4..12ec84b92f 100644 --- a/zebra/zebra_mpls_openbsd.c +++ b/zebra/zebra_mpls_openbsd.c @@ -342,7 +342,7 @@ static enum zebra_dplane_result kmpw_install(struct zebra_dplane_ctx *ctx) /* pseudowire nexthop */ memset(&ss, 0, sizeof(ss)); - gaddr = dplane_ctx_get_pw_nexthop(ctx); + gaddr = dplane_ctx_get_pw_dest(ctx); switch (dplane_ctx_get_pw_af(ctx)) { case AF_INET: sa_in->sin_family = AF_INET; From 09cd307c621c69c09ce3c1a0c012e9e0aa8eeb58 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Fri, 1 Mar 2019 13:33:17 -0500 Subject: [PATCH 050/142] zebra: dplane pseudowires including nexthop info Add nexthop info to the data that the zebra dataplane captures when programming pseudowires. Signed-off-by: Mark Stapp --- zebra/zebra_dplane.c | 41 +++++++++++++++++++++++++++++++++++++++++ zebra/zebra_dplane.h | 2 ++ 2 files changed, 43 insertions(+) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 63ac7666f4..e4bc3a85a8 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -842,6 +842,14 @@ const union pw_protocol_fields *dplane_ctx_get_pw_proto( return &(ctx->u.pw.fields); } +const struct nexthop_group * +dplane_ctx_get_pw_nhg(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.pw.nhg); +} + /* * End of dplane context accessors */ @@ -1051,6 +1059,12 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, struct zebra_pw *pw) { + struct prefix p; + afi_t afi; + struct route_table *table; + struct route_node *rn; + struct route_entry *re; + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u", dplane_op2str(op), pw->ifname, pw->local_label, @@ -1081,6 +1095,33 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, ctx->u.pw.fields = pw->data; + /* Capture nexthop info for the pw destination. We need to look + * up and use zebra datastructs, but we're running in the zebra + * pthread here so that should be ok. + */ + memcpy(&p.u, &pw->nexthop, sizeof(pw->nexthop)); + p.family = pw->af; + p.prefixlen = ((pw->af == AF_INET) ? + IPV4_MAX_PREFIXLEN : IPV6_MAX_PREFIXLEN); + + afi = (pw->af == AF_INET) ? AFI_IP : AFI_IP6; + table = zebra_vrf_table(afi, SAFI_UNICAST, pw->vrf_id); + if (table) { + rn = route_node_match(table, &p); + if (rn) { + RNODE_FOREACH_RE(rn, re) { + if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) + break; + } + + if (re) + copy_nexthops(&(ctx->u.pw.nhg.nexthop), + re->ng.nexthop, NULL); + + route_unlock_node(rn); + } + } + return AOK; } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 84da20f2a7..4cd8031d73 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -219,6 +219,8 @@ const union g_addr *dplane_ctx_get_pw_dest( const struct zebra_dplane_ctx *ctx); const union pw_protocol_fields *dplane_ctx_get_pw_proto( const struct zebra_dplane_ctx *ctx); +const struct nexthop_group *dplane_ctx_get_pw_nhg( + const struct zebra_dplane_ctx *ctx); /* Namespace info - esp. for netlink communication */ const struct zebra_dplane_info *dplane_ctx_get_ns( From 81793ac145e5f8c0c18d677062dcc85405bebe33 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Thu, 7 Mar 2019 13:09:51 -0500 Subject: [PATCH 051/142] zebra: use const in dplane pw nhlfe accessors Use const in the accessors for pseudowire nhlfe data; pull that through the kernel-facing apis that use that data. Signed-off-by: Mark Stapp --- zebra/rt_netlink.c | 26 +++++++++++++------------- zebra/zebra_dplane.c | 5 +++-- zebra/zebra_dplane.h | 5 +++-- zebra/zebra_mpls_openbsd.c | 6 +++--- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 9cea1d3c79..2ba1f89071 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -927,7 +927,7 @@ static void _netlink_route_nl_add_gateway_info(uint8_t route_family, uint8_t gw_family, struct nlmsghdr *nlmsg, size_t req_size, int bytelen, - struct nexthop *nexthop) + const struct nexthop *nexthop) { if (route_family == AF_MPLS) { struct gw_family_t gw_fam; @@ -954,7 +954,7 @@ static void _netlink_route_rta_add_gateway_info(uint8_t route_family, struct rtattr *rta, struct rtnexthop *rtnh, size_t req_size, int bytelen, - struct nexthop *nexthop) + const struct nexthop *nexthop) { if (route_family == AF_MPLS) { struct gw_family_t gw_fam; @@ -990,7 +990,7 @@ static void _netlink_route_rta_add_gateway_info(uint8_t route_family, * @param req_size: The size allocated for the message. */ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, - struct nexthop *nexthop, + const struct nexthop *nexthop, struct nlmsghdr *nlmsg, struct rtmsg *rtmsg, size_t req_size, int cmd) @@ -1009,7 +1009,7 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, label_buf[0] = '\0'; assert(nexthop); - for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) { + for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) { char label_buf1[20]; nh_label = nh->nh_label; @@ -1175,11 +1175,11 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, * the prefsrc should be stored. */ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, - struct nexthop *nexthop, + const struct nexthop *nexthop, struct rtattr *rta, struct rtnexthop *rtnh, struct rtmsg *rtmsg, - union g_addr **src) + const union g_addr **src) { struct mpls_label_stack *nh_label; mpls_lse_t out_lse[MPLS_MAX_LABELS]; @@ -1200,7 +1200,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, label_buf[0] = '\0'; assert(nexthop); - for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) { + for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) { char label_buf1[20]; nh_label = nh->nh_label; @@ -1342,7 +1342,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, } static inline void _netlink_mpls_build_singlepath(const char *routedesc, - zebra_nhlfe_t *nhlfe, + const zebra_nhlfe_t *nhlfe, struct nlmsghdr *nlmsg, struct rtmsg *rtmsg, size_t req_size, int cmd) @@ -1358,9 +1358,9 @@ static inline void _netlink_mpls_build_singlepath(const char *routedesc, static inline void -_netlink_mpls_build_multipath(const char *routedesc, zebra_nhlfe_t *nhlfe, +_netlink_mpls_build_multipath(const char *routedesc, const zebra_nhlfe_t *nhlfe, struct rtattr *rta, struct rtnexthop *rtnh, - struct rtmsg *rtmsg, union g_addr **src) + struct rtmsg *rtmsg, const union g_addr **src) { int bytelen; uint8_t family; @@ -1655,7 +1655,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *)buf; struct rtnexthop *rtnh; - union g_addr *src1 = NULL; + const union g_addr *src1 = NULL; rta->rta_type = RTA_MULTIPATH; rta->rta_len = RTA_LENGTH(0); @@ -2744,7 +2744,7 @@ int kernel_upd_neigh(struct interface *ifp, struct ipaddr *ip, int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) { mpls_lse_t lse; - zebra_nhlfe_t *nhlfe; + const zebra_nhlfe_t *nhlfe; struct nexthop *nexthop = NULL; unsigned int nexthop_num; const char *routedesc; @@ -2847,7 +2847,7 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *)buf; struct rtnexthop *rtnh; - union g_addr *src1 = NULL; + const union g_addr *src1 = NULL; rta->rta_type = RTA_MULTIPATH; rta->rta_len = RTA_LENGTH(0); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index e4bc3a85a8..df26a8534c 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -756,14 +756,15 @@ uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx) return ctx->u.lsp.flags; } -zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx) +const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); return ctx->u.lsp.nhlfe_list; } -zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx) +const zebra_nhlfe_t * +dplane_ctx_get_best_nhlfe(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 4cd8031d73..149ff8dc60 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -203,8 +203,9 @@ const struct nexthop_group *dplane_ctx_get_old_ng( mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx); uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx); -zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx); -zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx); +const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const struct zebra_dplane_ctx *ctx); +const zebra_nhlfe_t *dplane_ctx_get_best_nhlfe( + const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx); /* Accessors for pseudowire information */ diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c index 12ec84b92f..977a8eaf3c 100644 --- a/zebra/zebra_mpls_openbsd.c +++ b/zebra/zebra_mpls_openbsd.c @@ -43,7 +43,7 @@ struct { } kr_state; static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, - zebra_nhlfe_t *nhlfe) + const zebra_nhlfe_t *nhlfe) { struct iovec iov[5]; struct rt_msghdr hdr; @@ -135,7 +135,7 @@ static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, #endif static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label, - zebra_nhlfe_t *nhlfe) + const zebra_nhlfe_t *nhlfe) { struct iovec iov[5]; struct rt_msghdr hdr; @@ -238,7 +238,7 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label, static int kernel_lsp_cmd(struct zebra_dplane_ctx *ctx) { - zebra_nhlfe_t *nhlfe; + const zebra_nhlfe_t *nhlfe; struct nexthop *nexthop = NULL; unsigned int nexthop_num = 0; int action; From 03915806658ee08ced540b728d6111c4610002f5 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Thu, 7 Mar 2019 12:36:47 -0800 Subject: [PATCH 052/142] bgpd: vrl route-leak show with all vrfs option VRF Route Leak's show bgp vrf all ipv4 unicast route-leak is not supported with `all` keyword. Testing Done: bl1# show bgp vrf all ipv4 unicast route-leak Instance default: This VRF is not importing IPv4 Unicast routes from any other VRF This VRF is not exporting IPv4 Unicast routes to any other VRF Instance vrf3: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf1 Import RT(s): 144.1.1.2:10 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf1 RD: 144.1.3.2:9 Export RT: 144.1.3.2:9 Instance vrf1: This VRF is importing IPv4 Unicast routes from the following VRFs: vrf3 Import RT(s): 144.1.3.2:9 This VRF is exporting IPv4 Unicast routes to the following VRFs: vrf3 RD: 144.1.1.2:10 Export RT: 144.1.1.2:10 Signed-off-by: Chirag Shah --- bgpd/bgp_vty.c | 76 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 11 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index d426e65c53..a07528f490 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -11267,8 +11267,9 @@ DEFUN (show_ip_bgp_attr_info, return CMD_SUCCESS; } -static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi, - safi_t safi, bool use_json) +static int bgp_show_route_leak_vty(struct vty *vty, const char *name, + afi_t afi, safi_t safi, + bool use_json, json_object *json) { struct bgp *bgp; struct listnode *node; @@ -11277,13 +11278,10 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi, char *ecom_str; vpn_policy_direction_t dir; - if (use_json) { - json_object *json = NULL; + if (json) { json_object *json_import_vrfs = NULL; json_object *json_export_vrfs = NULL; - json = json_object_new_object(); - bgp = name ? bgp_lookup_by_name(name) : bgp_get_default(); if (!bgp) { @@ -11354,11 +11352,12 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi, XFREE(MTYPE_ECOMMUNITY_STR, ecom_str); } - vty_out(vty, "%s\n", - json_object_to_json_string_ext(json, + if (use_json) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - + json_object_free(json); + } } else { bgp = name ? bgp_lookup_by_name(name) : bgp_get_default(); @@ -11422,6 +11421,54 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, afi_t afi, return CMD_SUCCESS; } +static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi, + safi_t safi, bool use_json) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + char *vrf_name = NULL; + json_object *json = NULL; + json_object *json_vrf = NULL; + json_object *json_vrfs = NULL; + + if (use_json) { + json = json_object_new_object(); + json_vrfs = json_object_new_object(); + } + + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + + if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) + vrf_name = bgp->name; + + if (use_json) { + json_vrf = json_object_new_object(); + } else { + vty_out(vty, "\nInstance %s:\n", + (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) + ? VRF_DEFAULT_NAME : bgp->name); + } + bgp_show_route_leak_vty(vty, vrf_name, afi, safi, 0, json_vrf); + if (use_json) { + if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) + json_object_object_add(json_vrfs, + VRF_DEFAULT_NAME, json_vrf); + else + json_object_object_add(json_vrfs, vrf_name, + json_vrf); + } + } + + if (use_json) { + json_object_object_add(json, "vrfs", json_vrfs); + vty_out(vty, "%s\n", json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + /* "show [ip] bgp route-leak" command. */ DEFUN (show_ip_bgp_route_leak, show_ip_bgp_route_leak_cmd, @@ -11441,6 +11488,7 @@ DEFUN (show_ip_bgp_route_leak, bool uj = use_json(argc, argv); int idx = 0; + json_object *json = NULL; /* show [ip] bgp */ if (argv_find(argv, argc, "ip", &idx)) { @@ -11470,7 +11518,13 @@ DEFUN (show_ip_bgp_route_leak, return CMD_WARNING; } - return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj); + if (vrf && strmatch(vrf, "all")) + return bgp_show_all_instance_route_leak_vty(vty, afi, safi, uj); + + if (uj) + json = json_object_new_object(); + + return bgp_show_route_leak_vty(vty, vrf, afi, safi, uj, json); } static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi, From 2ec19f003c8aff14dcef1256d1e914c659ae4002 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 8 Mar 2019 10:30:27 -0500 Subject: [PATCH 053/142] zebra: Remove duplicate NUD_PERMANENT check The check for an entry being NUD_PERMANENT has already been done there is no need to do it twice. Signed-off-by: Donald Sharp --- zebra/rt_netlink.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 9cea1d3c79..32dc8791bc 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2045,10 +2045,6 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) * so perform an implicit delete of any local entry (if it exists). */ if (h->nlmsg_type == RTM_NEWNEIGH) { - /* Drop "permanent" entries. */ - if (ndm->ndm_state & NUD_PERMANENT) - return 0; - if (IS_ZEBRA_IF_VXLAN(ifp)) return zebra_vxlan_check_del_local_mac(ifp, br_if, &mac, vid); From 28bd0652ac396bf14577c96eb93b5c835a505a4b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 8 Mar 2019 10:46:55 -0500 Subject: [PATCH 054/142] zebra: Add some debugs to neighbor entry processing When we get a neighbor entry in zebra we start processing it. Let's add some additional debugs to the processing so that when it bails out and we don't use the data, we know the reason. This should help in debugging the problems from why bgp does not appear to have data associated with a neighbor entry in the kernel. Signed-off-by: Donald Sharp --- zebra/rt_netlink.c | 90 +++++++++++++++++++++++++++++++-------------- zebra/zebra_vxlan.c | 35 ++++++++++++++---- 2 files changed, 91 insertions(+), 34 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 32dc8791bc..2a297409fe 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1965,23 +1965,38 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) /* The interface should exist. */ ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), ndm->ndm_ifindex); - if (!ifp || !ifp->info) + if (!ifp || !ifp->info) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("\t%s without associated interface: %u", + __PRETTY_FUNCTION__, ndm->ndm_ifindex); return 0; + } /* The interface should be something we're interested in. */ - if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) + if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("\t%s Not interested in %s, not a slave", + __PRETTY_FUNCTION__, ifp->name); return 0; + } /* Drop "permanent" entries. */ - if (ndm->ndm_state & NUD_PERMANENT) + if (ndm->ndm_state & NUD_PERMANENT) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("\t%s Entry is PERMANENT, dropping", + __PRETTY_FUNCTION__); return 0; + } zif = (struct zebra_if *)ifp->info; if ((br_if = zif->brslave_info.br_if) == NULL) { - zlog_debug("%s family %s IF %s(%u) brIF %u - no bridge master", - nl_msg_type_to_str(h->nlmsg_type), - nl_family_to_str(ndm->ndm_family), ifp->name, - ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "%s family %s IF %s(%u) brIF %u - no bridge master", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex, + zif->brslave_info.bridge_ifindex); return 0; } @@ -1990,20 +2005,24 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len); if (!tb[NDA_LLADDR]) { - zlog_debug("%s family %s IF %s(%u) brIF %u - no LLADDR", - nl_msg_type_to_str(h->nlmsg_type), - nl_family_to_str(ndm->ndm_family), ifp->name, - ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s family %s IF %s(%u) brIF %u - no LLADDR", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex, + zif->brslave_info.bridge_ifindex); return 0; } if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) { - zlog_debug( - "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %lu", - nl_msg_type_to_str(h->nlmsg_type), - nl_family_to_str(ndm->ndm_family), ifp->name, - ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex, - (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR])); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %lu", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex, + zif->brslave_info.bridge_ifindex, + (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR])); return 0; } @@ -2036,8 +2055,12 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) prefix_mac2str(&mac, buf, sizeof(buf)), dst_present ? dst_buf : ""); - if (filter_vlan && vid != filter_vlan) + if (filter_vlan && vid != filter_vlan) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("\tFiltered due to filter vlan: %d", + filter_vlan); return 0; + } /* If add or update, do accordingly if learnt on a "local" interface; if * the notification is over VxLAN, this has to be related to @@ -2061,8 +2084,11 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id) * Ignore the notification from VxLan driver as it is also generated * when mac moves from remote to local. */ - if (dst_present) + if (dst_present) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("\tNo Destination Present"); return 0; + } if (IS_ZEBRA_IF_VXLAN(ifp)) return zebra_vxlan_check_readd_remote_mac(ifp, br_if, &mac, @@ -2375,6 +2401,9 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) /* if kernel deletes our rfc5549 neighbor entry, re-install it */ if (h->nlmsg_type == RTM_DELNEIGH && (ndm->ndm_state & NUD_PERMANENT)) { netlink_handle_5549(ndm, zif, ifp, &ip); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "\tNeighbor Entry Received is a 5549 entry, finished"); return 0; } @@ -2400,20 +2429,27 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) return 0; } else if (IS_ZEBRA_IF_BRIDGE(ifp)) link_if = ifp; - else + else { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "\tNeighbor Entry received is not on a VLAN or a BRIDGE, ignoring"); return 0; + } memset(&mac, 0, sizeof(struct ethaddr)); if (h->nlmsg_type == RTM_NEWNEIGH) { if (tb[NDA_LLADDR]) { if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) { - zlog_debug( - "%s family %s IF %s(%u) - LLADDR is not MAC, len %lu", - nl_msg_type_to_str(h->nlmsg_type), - nl_family_to_str(ndm->ndm_family), - ifp->name, ndm->ndm_ifindex, - (unsigned long)RTA_PAYLOAD( - tb[NDA_LLADDR])); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "%s family %s IF %s(%u) - LLADDR is not MAC, len %lu", + nl_msg_type_to_str( + h->nlmsg_type), + nl_family_to_str( + ndm->ndm_family), + ifp->name, ndm->ndm_ifindex, + (unsigned long)RTA_PAYLOAD( + tb[NDA_LLADDR])); return 0; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 9a7d20bc49..00fc230851 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2986,8 +2986,12 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, } zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); - if (!zvrf) + if (!zvrf) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("\tUnable to find vrf for: %d", + zvni->vxlan_if->vrf_id); return -1; + } /* Check if the neighbor exists. */ n = zvni_neigh_lookup(zvni, ip); @@ -3017,6 +3021,9 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, cur_is_router = !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); if (!mac_different && is_router == cur_is_router) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "\tIgnoring entry mac is the same and is_router == cur_is_router"); n->ifindex = ifp->ifindex; return 0; } @@ -3045,6 +3052,11 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, return zvni_neigh_send_add_to_client( zvni->vni, ip, macaddr, n->flags, n->loc_seq); + else { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "\tNeighbor active and frozen"); + } return 0; } @@ -3185,6 +3197,10 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, if (!neigh_on_hold) return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags, n->loc_seq); + else { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("\tNeighbor on hold not sending"); + } return 0; } @@ -7579,7 +7595,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, if (!zvni) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Add/Update %sMAC %s intf %s(%u) VID %u, could not find VNI", + "\tAdd/Update %sMAC %s intf %s(%u) VID %u, could not find VNI", sticky ? "sticky " : "", prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, ifp->ifindex, vid); @@ -7587,15 +7603,20 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, } if (!zvni->vxlan_if) { - zlog_debug( - "VNI %u hash %p doesn't have intf upon local MAC ADD", - zvni->vni, zvni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "\tVNI %u hash %p doesn't have intf upon local MAC ADD", + zvni->vni, zvni); return -1; } zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); - if (!zvrf) + if (!zvrf) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("\tNo Vrf found for vrf_id: %d", + zvni->vxlan_if->vrf_id); return -1; + } /* Check if we need to create or update or it is a NO-OP. */ mac = zvni_mac_lookup(zvni, macaddr); @@ -7645,7 +7666,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, && mac->fwd_info.local.vid == vid) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, " + "\tAdd/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, " "entry exists and has not changed ", sticky ? "sticky " : "", prefix_mac2str(macaddr, buf, From 41dc8c14c6c0e34bc319c83613bf5359475eea89 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 8 Mar 2019 15:38:00 -0500 Subject: [PATCH 055/142] zebra: Cleanup rnh table information before deleting underlying tables Cleaup the rnh tables on shutdown before we cleanup tables. As that this will remove any need to do rnh processing as part of shutdown. Signed-off-by: Donald Sharp --- zebra/zebra_vrf.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 1300ca24f3..90f94902f3 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -167,6 +167,11 @@ static int zebra_vrf_disable(struct vrf *vrf) /* Remove all routes. */ for (afi = AFI_IP; afi <= AFI_IP6; afi++) { + route_table_finish(zvrf->rnh_table[afi]); + zvrf->rnh_table[afi] = NULL; + route_table_finish(zvrf->import_check_table[afi]); + zvrf->import_check_table[afi] = NULL; + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) rib_close_table(zvrf->table[afi][safi]); } @@ -213,11 +218,6 @@ static int zebra_vrf_disable(struct vrf *vrf) safi); zvrf->table[afi][safi] = NULL; } - - route_table_finish(zvrf->rnh_table[afi]); - zvrf->rnh_table[afi] = NULL; - route_table_finish(zvrf->import_check_table[afi]); - zvrf->import_check_table[afi] = NULL; } return 0; @@ -268,8 +268,10 @@ static int zebra_vrf_delete(struct vrf *vrf) } } - route_table_finish(zvrf->rnh_table[afi]); - route_table_finish(zvrf->import_check_table[afi]); + if (zvrf->rnh_table[afi]) + route_table_finish(zvrf->rnh_table[afi]); + if (zvrf->import_check_table[afi]) + route_table_finish(zvrf->import_check_table[afi]); } /* Cleanup EVPN states for vrf */ From 1e03ae0dc7e183dccca38e92ab079bd51ca83fc9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 9 Mar 2019 20:28:49 -0500 Subject: [PATCH 056/142] zebra: Allow json output to give a bit more data The dest->selected_fib should be reported in json output so that we can debug subtle conditions a bit better in the future. Signed-off-by: Donald Sharp --- zebra/zebra_vty.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 537820f7ea..b0884f22cf 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -383,6 +383,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object *json_labels = NULL; time_t uptime; struct tm *tm; + rib_dest_t *dest = rib_dest_from_rnode(rn); uptime = time(NULL); uptime -= re->uptime; @@ -407,6 +408,10 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) json_object_boolean_true_add(json_route, "selected"); + if (dest->selected_fib == re) + json_object_boolean_true_add(json_route, + "destSelected"); + json_object_int_add(json_route, "distance", re->distance); json_object_int_add(json_route, "metric", re->metric); From 79b4a6fcebd7cca550c9661f54f48f74df12e5ea Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 11 Mar 2019 15:09:15 -0300 Subject: [PATCH 057/142] bfdd: change session lookup data structure Use simplier data structure key to avoid having to do complex and error-prone key building (e.g. avoid expecting caller to know IPv6 scope id, interface index, vrf index etc...). Signed-off-by: Rafael Zalamena --- bfdd/bfd.c | 526 +++++++++++++++++---------------------------- bfdd/bfd.h | 53 ++--- bfdd/bfd_packet.c | 60 +++--- bfdd/bfdd_vty.c | 105 +++++---- bfdd/config.c | 46 ++-- bfdd/ptm_adapter.c | 83 ++----- 6 files changed, 340 insertions(+), 533 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 36133f5727..ea059cc1c2 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -36,7 +36,9 @@ DEFINE_QOBJ_TYPE(bfd_session); /* * Prototypes */ -static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc); +void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, + struct sockaddr_any *local, bool mhop, const char *ifname, + const char *vrfname); static uint32_t ptm_bfd_gen_ID(void); static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd); @@ -52,66 +54,47 @@ static void bs_down_handler(struct bfd_session *bs, int nstate); static void bs_init_handler(struct bfd_session *bs, int nstate); static void bs_up_handler(struct bfd_session *bs, int nstate); +/* Zeroed array with the size of an IPv6 address. */ +struct in6_addr zero_addr; /* * Functions */ -static struct bfd_session *bs_peer_waiting_find(struct bfd_peer_cfg *bpc) +void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, + struct sockaddr_any *local, bool mhop, const char *ifname, + const char *vrfname) { - struct bfd_session_observer *bso; - struct bfd_session *bs = NULL; - bool is_shop, is_ipv4; - - TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { - bs = bso->bso_bs; - - is_shop = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH); - is_ipv4 = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6); - /* Quick checks first. */ - if (is_shop != (!bpc->bpc_mhop)) - continue; - if (is_ipv4 != bpc->bpc_ipv4) - continue; - - /* - * Slow lookup without hash because we don't have all - * information yet. - */ - if (is_shop) { - if (strcmp(bs->ifname, bpc->bpc_localif)) - continue; - if (memcmp(&bs->shop.peer, &bpc->bpc_peer, - sizeof(bs->shop.peer))) - continue; - - break; - } - - if (strcmp(bs->vrfname, bpc->bpc_vrfname)) - continue; - if (memcmp(&bs->mhop.peer, &bpc->bpc_peer, - sizeof(bs->mhop.peer))) - continue; - if (memcmp(&bs->mhop.local, &bpc->bpc_local, - sizeof(bs->mhop.local))) - continue; + memset(key, 0, sizeof(*key)); + switch (peer->sa_sin.sin_family) { + case AF_INET: + key->family = AF_INET; + memcpy(&key->peer, &peer->sa_sin.sin_addr, + sizeof(peer->sa_sin.sin_addr)); + memcpy(&key->local, &local->sa_sin.sin_addr, + sizeof(local->sa_sin.sin_addr)); + break; + case AF_INET6: + key->family = AF_INET6; + memcpy(&key->peer, &peer->sa_sin6.sin6_addr, + sizeof(peer->sa_sin6.sin6_addr)); + memcpy(&key->local, &local->sa_sin6.sin6_addr, + sizeof(local->sa_sin6.sin6_addr)); break; } - if (bso == NULL) - bs = NULL; - return bs; + key->mhop = mhop; + if (ifname && ifname[0]) + strlcpy(key->ifname, ifname, sizeof(key->ifname)); + if (vrfname && vrfname[0]) + strlcpy(key->vrfname, vrfname, sizeof(key->vrfname)); } struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) { struct bfd_session *bs; struct peer_label *pl; - struct interface *ifp; - struct vrf *vrf; - struct bfd_mhop_key mhop; - struct bfd_shop_key shop; + struct bfd_key key; /* Try to find label first. */ if (bpc->bpc_has_label) { @@ -123,38 +106,10 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) } /* Otherwise fallback to peer/local hash lookup. */ - if (bpc->bpc_mhop) { - memset(&mhop, 0, sizeof(mhop)); - mhop.peer = bpc->bpc_peer; - mhop.local = bpc->bpc_local; - if (bpc->bpc_has_vrfname) { - vrf = vrf_lookup_by_name(bpc->bpc_vrfname); - if (vrf == NULL) - return NULL; + gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop, + bpc->bpc_localif, bpc->bpc_vrfname); - mhop.vrfid = vrf->vrf_id; - } - - bs = bfd_mhop_lookup(mhop); - } else { - memset(&shop, 0, sizeof(shop)); - shop.peer = bpc->bpc_peer; - if (bpc->bpc_has_localif) { - ifp = if_lookup_by_name_all_vrf(bpc->bpc_localif); - if (ifp == NULL) - return NULL; - - shop.ifindex = ifp->ifindex; - } - - bs = bfd_shop_lookup(shop); - } - - if (bs != NULL) - return bs; - - /* Search for entries that are incomplete. */ - return bs_peer_waiting_find(bpc); + return bfd_key_lookup(key); } /* @@ -165,7 +120,6 @@ struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) */ int bfd_session_enable(struct bfd_session *bs) { - struct sockaddr_in6 *sin6; struct interface *ifp = NULL; struct vrf *vrf = NULL; int psock; @@ -174,8 +128,8 @@ int bfd_session_enable(struct bfd_session *bs) * If the interface or VRF doesn't exist, then we must register * the session but delay its start. */ - if (bs->ifname[0] != 0) { - ifp = if_lookup_by_name_all_vrf(bs->ifname); + if (bs->key.ifname[0]) { + ifp = if_lookup_by_name_all_vrf(bs->key.ifname); if (ifp == NULL) { log_error( "session-enable: specified interface doesn't exists."); @@ -184,15 +138,17 @@ int bfd_session_enable(struct bfd_session *bs) vrf = vrf_lookup_by_id(ifp->vrf_id); if (vrf == NULL) { - log_error("session-enable: specified VRF doesn't exists."); + log_error( + "session-enable: specified VRF doesn't exists."); return 0; } } - if (bs->vrfname[0] != 0) { - vrf = vrf_lookup_by_name(bs->vrfname); + if (bs->key.vrfname[0]) { + vrf = vrf_lookup_by_name(bs->key.vrfname); if (vrf == NULL) { - log_error("session-enable: specified VRF doesn't exists."); + log_error( + "session-enable: specified VRF doesn't exists."); return 0; } } @@ -202,32 +158,10 @@ int bfd_session_enable(struct bfd_session *bs) if (bs->vrf == NULL) bs->vrf = vrf_lookup_by_id(VRF_DEFAULT); - if (bs->ifname[0] != 0 && - BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) + if (bs->key.ifname[0] + && BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) bs->ifp = ifp; - /* Set the IPv6 scope id for link-local addresses. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) { - sin6 = (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) - ? &bs->mhop.peer.sa_sin6 - : &bs->shop.peer.sa_sin6; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) - sin6->sin6_scope_id = bs->ifp != NULL - ? bs->ifp->ifindex - : IFINDEX_INTERNAL; - - sin6 = (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) - ? &bs->mhop.local.sa_sin6 - : &bs->local_address.sa_sin6; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) - sin6->sin6_scope_id = bs->ifp != NULL - ? bs->ifp->ifindex - : IFINDEX_INTERNAL; - - bs->local_ip.sa_sin6 = *sin6; - bs->local_address.sa_sin6 = *sin6; - } - /* * Get socket for transmitting control packets. Note that if we * could use the destination port (3784) for the source @@ -251,25 +185,6 @@ int bfd_session_enable(struct bfd_session *bs) bfd_recvtimer_update(bs); ptm_bfd_start_xmt_timer(bs, false); - /* Registrate session into data structures. */ - bs->discrs.my_discr = ptm_bfd_gen_ID(); - bfd_id_insert(bs); - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - if (vrf != NULL) - bs->mhop.vrfid = vrf->vrf_id; - else - bs->mhop.vrfid = VRF_DEFAULT; - - bfd_mhop_insert(bs); - } else { - if (ifp != NULL) - bs->shop.ifindex = ifp->ifindex; - else - bs->shop.ifindex = IFINDEX_INTERNAL; - - bfd_shop_insert(bs); - } - return 0; } @@ -292,13 +207,6 @@ void bfd_session_disable(struct bfd_session *bs) bfd_echo_recvtimer_delete(bs); bfd_xmttimer_delete(bs); bfd_echo_xmttimer_delete(bs); - - /* Unregister session from hashes to avoid unwanted activation. */ - bfd_id_delete(bs->discrs.my_discr); - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) - bfd_mhop_delete(bs->mhop); - else - bfd_shop_delete(bs->shop); } static uint32_t ptm_bfd_gen_ID(void) @@ -442,21 +350,20 @@ static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa, if (bs == NULL) return NULL; - /* Remove unused fields. */ - switch (sa->sa_sin.sin_family) { + switch (bs->key.family) { case AF_INET: - sa->sa_sin.sin_port = 0; - if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin)) == 0) - return bs; + if (memcmp(&sa->sa_sin.sin_addr, &bs->key.peer, + sizeof(sa->sa_sin.sin_addr))) + return NULL; break; case AF_INET6: - sa->sa_sin6.sin6_port = 0; - if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin6)) == 0) - return bs; + if (memcmp(&sa->sa_sin6.sin6_addr, &bs->key.peer, + sizeof(sa->sa_sin6.sin6_addr))) + return NULL; break; } - return NULL; + return bs; } struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, @@ -465,32 +372,30 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, ifindex_t ifindex, vrf_id_t vrfid, bool is_mhop) { - struct bfd_session *l_bfd = NULL; - struct bfd_mhop_key mhop; - struct bfd_shop_key shop; + struct interface *ifp; + struct vrf *vrf; + struct bfd_key key; /* Find our session using the ID signaled by the remote end. */ if (cp->discrs.remote_discr) return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr)); /* Search for session without using discriminator. */ - if (is_mhop) { - memset(&mhop, 0, sizeof(mhop)); - mhop.peer = *peer; - mhop.local = *local; - mhop.vrfid = vrfid; + ifp = if_lookup_by_index(ifindex, vrfid); + if (vrfid == VRF_DEFAULT) { + /* + * Don't use the default vrf, otherwise we won't find + * sessions that doesn't specify it. + */ + vrf = NULL; + } else + vrf = vrf_lookup_by_id(vrfid); - l_bfd = bfd_mhop_lookup(mhop); - } else { - memset(&shop, 0, sizeof(shop)); - shop.peer = *peer; - shop.ifindex = ifindex; - - l_bfd = bfd_shop_lookup(shop); - } + gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL, + vrf ? vrf->name : NULL); /* XXX maybe remoteDiscr should be checked for remoteHeard cases. */ - return l_bfd; + return bfd_key_lookup(key); } int bfd_xmt_cb(struct thread *t) @@ -705,6 +610,9 @@ static void bfd_session_free(struct bfd_session *bs) bfd_session_disable(bs); + bfd_key_delete(bs->key); + bfd_id_delete(bs->discrs.my_discr); + /* Remove observer if any. */ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { if (bso->bso_bs != bs) @@ -747,29 +655,51 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc) * start. See `bfd_session_enable` for more information. */ if (bpc->bpc_has_localif) - strlcpy(bfd->ifname, bpc->bpc_localif, sizeof(bfd->ifname)); + strlcpy(bfd->key.ifname, bpc->bpc_localif, + sizeof(bfd->key.ifname)); if (bpc->bpc_has_vrfname) - strlcpy(bfd->vrfname, bpc->bpc_vrfname, sizeof(bfd->vrfname)); + strlcpy(bfd->key.vrfname, bpc->bpc_vrfname, + sizeof(bfd->key.vrfname)); /* Add observer if we have moving parts. */ - if (bfd->ifname[0] || bfd->vrfname[0]) + if (bfd->key.ifname[0] || bfd->key.vrfname[0]) bs_observer_add(bfd); /* Copy remaining data. */ if (bpc->bpc_ipv4 == false) BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6); - if (bpc->bpc_mhop) { - BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH); - bfd->mhop.peer = bpc->bpc_peer; - bfd->mhop.local = bpc->bpc_local; - } else { - bfd->shop.peer = bpc->bpc_peer; + bfd->key.family = (bpc->bpc_ipv4) ? AF_INET : AF_INET6; + switch (bfd->key.family) { + case AF_INET: + memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin.sin_addr, + sizeof(bpc->bpc_peer.sa_sin.sin_addr)); + memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin.sin_addr, + sizeof(bpc->bpc_local.sa_sin.sin_addr)); + break; + + case AF_INET6: + memcpy(&bfd->key.peer, &bpc->bpc_peer.sa_sin6.sin6_addr, + sizeof(bpc->bpc_peer.sa_sin6.sin6_addr)); + memcpy(&bfd->key.local, &bpc->bpc_local.sa_sin6.sin6_addr, + sizeof(bpc->bpc_local.sa_sin6.sin6_addr)); + break; + + default: + assert(1); + break; } - bfd->local_ip = bpc->bpc_local; - bfd->local_address = bpc->bpc_local; + if (bpc->bpc_mhop) + BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH); + + bfd->key.mhop = bpc->bpc_mhop; + + /* Registrate session into data structures. */ + bfd_key_insert(bfd); + bfd->discrs.my_discr = ptm_bfd_gen_ID(); + bfd_id_insert(bfd); /* Try to enable session and schedule for packet receive/send. */ if (bfd_session_enable(bfd) == -1) { @@ -1223,35 +1153,26 @@ void integer2timestr(uint64_t time, char *buf, size_t buflen) snprintf(buf, buflen, "%u second(s)", second); } -const char *bs_to_string(struct bfd_session *bs) +const char *bs_to_string(const struct bfd_session *bs) { static char buf[256]; + char addr_buf[INET6_ADDRSTRLEN]; int pos; bool is_mhop = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH); pos = snprintf(buf, sizeof(buf), "mhop:%s", is_mhop ? "yes" : "no"); - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - pos += snprintf(buf + pos, sizeof(buf) - pos, - " peer:%s local:%s", satostr(&bs->mhop.peer), - satostr(&bs->mhop.local)); - - if (bs->mhop.vrfid != VRF_DEFAULT) - snprintf(buf + pos, sizeof(buf) - pos, " vrf:%u", - bs->mhop.vrfid); - } else { - pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s", - satostr(&bs->shop.peer)); - - if (bs->local_address.sa_sin.sin_family) - pos += snprintf(buf + pos, sizeof(buf) - pos, - " local:%s", - satostr(&bs->local_address)); - - if (bs->shop.ifindex) - snprintf(buf + pos, sizeof(buf) - pos, " ifindex:%u", - bs->shop.ifindex); - } - + pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s", + inet_ntop(bs->key.family, &bs->key.peer, addr_buf, + sizeof(addr_buf))); + pos += snprintf(buf + pos, sizeof(buf) - pos, " local:%s", + inet_ntop(bs->key.family, &bs->key.local, addr_buf, + sizeof(addr_buf))); + if (bs->key.vrfname[0]) + pos += snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s", + bs->key.vrfname); + if (bs->key.ifname[0]) + pos += snprintf(buf + pos, sizeof(buf) - pos, " ifname:%s", + bs->key.ifname); return buf; } @@ -1263,10 +1184,10 @@ int bs_observer_add(struct bfd_session *bs) bso->bso_bs = bs; bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH); if (bso->bso_isinterface) - strlcpy(bso->bso_entryname, bs->ifname, + strlcpy(bso->bso_entryname, bs->key.ifname, sizeof(bso->bso_entryname)); else - strlcpy(bso->bso_entryname, bs->vrfname, + strlcpy(bso->bso_entryname, bs->key.vrfname, sizeof(bso->bso_entryname)); TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry); @@ -1280,21 +1201,59 @@ void bs_observer_del(struct bfd_session_observer *bso) XFREE(MTYPE_BFDD_SESSION_OBSERVER, bso); } +void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc) +{ + memset(bpc, 0, sizeof(*bpc)); + + bpc->bpc_ipv4 = (bs->key.family == AF_INET); + bpc->bpc_mhop = bs->key.mhop; + + switch (bs->key.family) { + case AF_INET: + bpc->bpc_peer.sa_sin.sin_family = AF_INET; + memcpy(&bpc->bpc_peer.sa_sin.sin_addr, &bs->key.peer, + sizeof(bpc->bpc_peer.sa_sin.sin_addr)); + + if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) { + bpc->bpc_local.sa_sin.sin_family = AF_INET6; + memcpy(&bpc->bpc_local.sa_sin.sin_addr, &bs->key.peer, + sizeof(bpc->bpc_local.sa_sin.sin_addr)); + } + break; + + case AF_INET6: + bpc->bpc_peer.sa_sin.sin_family = AF_INET6; + memcpy(&bpc->bpc_peer.sa_sin6.sin6_addr, &bs->key.peer, + sizeof(bpc->bpc_peer.sa_sin6.sin6_addr)); + + bpc->bpc_local.sa_sin6.sin6_family = AF_INET6; + memcpy(&bpc->bpc_local.sa_sin6.sin6_addr, &bs->key.peer, + sizeof(bpc->bpc_local.sa_sin6.sin6_addr)); + break; + } + + if (bs->key.ifname[0]) { + bpc->bpc_has_localif = true; + strlcpy(bpc->bpc_localif, bs->key.ifname, + sizeof(bpc->bpc_localif)); + } + + if (bs->key.vrfname[0]) { + bpc->bpc_has_vrfname = true; + strlcpy(bpc->bpc_vrfname, bs->key.vrfname, + sizeof(bpc->bpc_vrfname)); + } +} + /* * BFD hash data structures to find sessions. */ static struct hash *bfd_id_hash; -static struct hash *bfd_shop_hash; -static struct hash *bfd_mhop_hash; +static struct hash *bfd_key_hash; static unsigned int bfd_id_hash_do(void *p); -static unsigned int bfd_shop_hash_do(void *p); -static unsigned int bfd_mhop_hash_do(void *p); - -static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop); -static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop); -static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop); +static unsigned int bfd_key_hash_do(void *p); static void _bfd_free(struct hash_bucket *hb, void *arg __attribute__((__unused__))); @@ -1315,73 +1274,20 @@ static bool bfd_id_hash_cmp(const void *n1, const void *n2) } /* BFD hash for single hop. */ -static unsigned int bfd_shop_hash_do(void *p) +static unsigned int bfd_key_hash_do(void *p) { struct bfd_session *bs = p; - return jhash(&bs->shop, sizeof(bs->shop), 0); + return jhash(&bs->key, sizeof(bs->key), 0); } -static bool bfd_shop_hash_cmp(const void *n1, const void *n2) +static bool bfd_key_hash_cmp(const void *n1, const void *n2) { const struct bfd_session *bs1 = n1, *bs2 = n2; - return memcmp(&bs1->shop, &bs2->shop, sizeof(bs1->shop)) == 0; + return memcmp(&bs1->key, &bs2->key, sizeof(bs1->key)) == 0; } -/* BFD hash for multi hop. */ -static unsigned int bfd_mhop_hash_do(void *p) -{ - struct bfd_session *bs = p; - - return jhash(&bs->mhop, sizeof(bs->mhop), 0); -} - -static bool bfd_mhop_hash_cmp(const void *n1, const void *n2) -{ - const struct bfd_session *bs1 = n1, *bs2 = n2; - - return memcmp(&bs1->mhop, &bs2->mhop, sizeof(bs1->mhop)) == 0; -} - -/* Helper functions */ -static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop) -{ - bs->shop = *shop; - - /* Remove unused fields. */ - switch (bs->shop.peer.sa_sin.sin_family) { - case AF_INET: - bs->shop.peer.sa_sin.sin_port = 0; - break; - case AF_INET6: - bs->shop.peer.sa_sin6.sin6_port = 0; - break; - } -} - -static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop) -{ - _shop_key(bs, shop); - bs->shop.ifindex = IFINDEX_INTERNAL; -} - -static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop) -{ - bs->mhop = *mhop; - - /* Remove unused fields. */ - switch (bs->mhop.peer.sa_sin.sin_family) { - case AF_INET: - bs->mhop.peer.sa_sin.sin_port = 0; - bs->mhop.local.sa_sin.sin_port = 0; - break; - case AF_INET6: - bs->mhop.peer.sa_sin6.sin6_port = 0; - bs->mhop.local.sa_sin6.sin6_port = 0; - break; - } -} /* * Hash public interface / exported functions. @@ -1397,34 +1303,35 @@ struct bfd_session *bfd_id_lookup(uint32_t id) return hash_lookup(bfd_id_hash, &bs); } -struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop) +struct bfd_session *bfd_key_lookup(struct bfd_key key) { struct bfd_session bs, *bsp; - _shop_key(&bs, &shop); + bs.key = key; + bsp = hash_lookup(bfd_key_hash, &bs); - bsp = hash_lookup(bfd_shop_hash, &bs); - if (bsp == NULL && bs.shop.ifindex != 0) { - /* - * Since the local interface spec is optional, try - * searching the key without it as well. - */ - _shop_key2(&bs, &shop); - bsp = hash_lookup(bfd_shop_hash, &bs); + /* Handle cases where local-address is optional. */ + if (bsp == NULL && bs.key.family == AF_INET) { + memset(&bs.key.local, 0, sizeof(bs.key.local)); + bsp = hash_lookup(bfd_key_hash, &bs); + } + + /* Handle cases where ifname is optional. */ + bs.key = key; + if (bsp == NULL && bs.key.ifname[0]) { + memset(bs.key.ifname, 0, sizeof(bs.key.ifname)); + bsp = hash_lookup(bfd_key_hash, &bs); + + /* Handle cases where local-address and ifname are optional. */ + if (bsp == NULL && bs.key.family == AF_INET) { + memset(&bs.key.local, 0, sizeof(bs.key.local)); + bsp = hash_lookup(bfd_key_hash, &bs); + } } return bsp; } -struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop) -{ - struct bfd_session bs; - - _mhop_key(&bs, &mhop); - - return hash_lookup(bfd_mhop_hash, &bs); -} - /* * Delete functions. * @@ -1444,31 +1351,18 @@ struct bfd_session *bfd_id_delete(uint32_t id) return hash_release(bfd_id_hash, &bs); } -struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop) +struct bfd_session *bfd_key_delete(struct bfd_key key) { struct bfd_session bs, *bsp; - _shop_key(&bs, &shop); - bsp = hash_release(bfd_shop_hash, &bs); - if (bsp == NULL && shop.ifindex != 0) { - /* - * Since the local interface spec is optional, try - * searching the key without it as well. - */ - _shop_key2(&bs, &shop); - bsp = hash_release(bfd_shop_hash, &bs); + bs.key = key; + bsp = hash_lookup(bfd_key_hash, &bs); + if (bsp == NULL && key.ifname[0]) { + memset(bs.key.ifname, 0, sizeof(bs.key.ifname)); + bsp = hash_lookup(bfd_key_hash, &bs); } - return bsp; -} - -struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop) -{ - struct bfd_session bs; - - _mhop_key(&bs, &mhop); - - return hash_release(bfd_mhop_hash, &bs); + return hash_release(bfd_key_hash, bsp); } /* Iteration functions. */ @@ -1477,14 +1371,9 @@ void bfd_id_iterate(hash_iter_func hif, void *arg) hash_iterate(bfd_id_hash, hif, arg); } -void bfd_shop_iterate(hash_iter_func hif, void *arg) +void bfd_key_iterate(hash_iter_func hif, void *arg) { - hash_iterate(bfd_shop_hash, hif, arg); -} - -void bfd_mhop_iterate(hash_iter_func hif, void *arg) -{ - hash_iterate(bfd_mhop_hash, hif, arg); + hash_iterate(bfd_key_hash, hif, arg); } /* @@ -1498,24 +1387,17 @@ bool bfd_id_insert(struct bfd_session *bs) return (hash_get(bfd_id_hash, bs, hash_alloc_intern) == bs); } -bool bfd_shop_insert(struct bfd_session *bs) +bool bfd_key_insert(struct bfd_session *bs) { - return (hash_get(bfd_shop_hash, bs, hash_alloc_intern) == bs); -} - -bool bfd_mhop_insert(struct bfd_session *bs) -{ - return (hash_get(bfd_mhop_hash, bs, hash_alloc_intern) == bs); + return (hash_get(bfd_key_hash, bs, hash_alloc_intern) == bs); } void bfd_initialize(void) { bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp, - "BFD discriminator hash"); - bfd_shop_hash = hash_create(bfd_shop_hash_do, bfd_shop_hash_cmp, - "BFD single hop hash"); - bfd_mhop_hash = hash_create(bfd_mhop_hash_do, bfd_mhop_hash_cmp, - "BFD multihop hop hash"); + "BFD session discriminator hash"); + bfd_key_hash = hash_create(bfd_key_hash_do, bfd_key_hash_cmp, + "BFD session hash"); } static void _bfd_free(struct hash_bucket *hb, @@ -1536,11 +1418,9 @@ void bfd_shutdown(void) * assert() here to make sure it really happened. */ bfd_id_iterate(_bfd_free, NULL); - assert(bfd_shop_hash->count == 0); - assert(bfd_mhop_hash->count == 0); + assert(bfd_key_hash->count == 0); /* Now free the hashes themselves. */ hash_free(bfd_id_hash); - hash_free(bfd_shop_hash); - hash_free(bfd_mhop_hash); + hash_free(bfd_key_hash); } diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 7451ca82a3..1556012296 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -173,15 +173,13 @@ enum bfd_session_flags { #define BFD_CHECK_FLAG(field, flag) (field & flag) /* BFD session hash keys */ -struct bfd_shop_key { - struct sockaddr_any peer; - ifindex_t ifindex; -}; - -struct bfd_mhop_key { - struct sockaddr_any peer; - struct sockaddr_any local; - vrf_id_t vrfid; +struct bfd_key { + uint16_t family; + uint8_t mhop; + struct in6_addr peer; + struct in6_addr local; + char ifname[MAXNAMELEN]; + char vrfname[MAXNAMELEN]; }; struct bfd_session_stats { @@ -227,19 +225,14 @@ struct bfd_session { uint8_t polling; /* This and the localDiscr are the keys to state info */ + struct bfd_key key; struct peer_label *pl; - union { - struct bfd_shop_key shop; - struct bfd_mhop_key mhop; - }; - int sock; struct sockaddr_any local_address; - struct sockaddr_any local_ip; struct interface *ifp; struct vrf *vrf; - char ifname[MAXNAMELEN]; - char vrfname[MAXNAMELEN]; + + int sock; /* BFD session flags */ enum bfd_session_flags flags; @@ -531,38 +524,28 @@ const char *satostr(struct sockaddr_any *sa); const char *diag2str(uint8_t diag); int strtosa(const char *addr, struct sockaddr_any *sa); void integer2timestr(uint64_t time, char *buf, size_t buflen); -const char *bs_to_string(struct bfd_session *bs); +const char *bs_to_string(const struct bfd_session *bs); int bs_observer_add(struct bfd_session *bs); void bs_observer_del(struct bfd_session_observer *bso); +void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc); + /* BFD hash data structures interface */ void bfd_initialize(void); void bfd_shutdown(void); struct bfd_session *bfd_id_lookup(uint32_t id); -struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop); -struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop); -struct bfd_vrf *bfd_vrf_lookup(int vrf_id); -struct bfd_iface *bfd_iface_lookup(const char *ifname); +struct bfd_session *bfd_key_lookup(struct bfd_key key); struct bfd_session *bfd_id_delete(uint32_t id); -struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop); -struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop); -struct bfd_vrf *bfd_vrf_delete(int vrf_id); -struct bfd_iface *bfd_iface_delete(const char *ifname); +struct bfd_session *bfd_key_delete(struct bfd_key key); bool bfd_id_insert(struct bfd_session *bs); -bool bfd_shop_insert(struct bfd_session *bs); -bool bfd_mhop_insert(struct bfd_session *bs); -bool bfd_vrf_insert(struct bfd_vrf *vrf); -bool bfd_iface_insert(struct bfd_iface *iface); +bool bfd_key_insert(struct bfd_session *bs); typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg); void bfd_id_iterate(hash_iter_func hif, void *arg); -void bfd_shop_iterate(hash_iter_func hif, void *arg); -void bfd_mhop_iterate(hash_iter_func hif, void *arg); -void bfd_vrf_iterate(hash_iter_func hif, void *arg); -void bfd_iface_iterate(hash_iter_func hif, void *arg); +void bfd_key_iterate(hash_iter_func hif, void *arg); /* Export callback functions for `event.c`. */ extern struct thread_master *master; @@ -572,6 +555,8 @@ int bfd_echo_recvtimer_cb(struct thread *t); int bfd_xmt_cb(struct thread *t); int bfd_echo_xmt_cb(struct thread *t); +extern struct in6_addr zero_addr; + /* * bfdd_vty.c diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 8601bd2e40..69d27ed698 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -79,7 +79,10 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data, if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) { memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; - sin6.sin6_addr = bs->shop.peer.sa_sin6.sin6_addr; + memcpy(&sin6.sin6_addr, &bs->key.peer, sizeof(sin6.sin6_addr)); + if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) + sin6.sin6_scope_id = bs->ifp->ifindex; + sin6.sin6_port = (port) ? *port : (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) @@ -92,7 +95,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data, } else { memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; - sin.sin_addr = bs->shop.peer.sa_sin.sin_addr; + memcpy(&sin.sin_addr, &bs->key.peer, sizeof(sin.sin_addr)); sin.sin_port = (port) ? *port : (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) @@ -120,7 +123,7 @@ int _ptm_bfd_send(struct bfd_session *bs, uint16_t *port, const void *data, void ptm_bfd_echo_snd(struct bfd_session *bfd) { - struct sockaddr_any *sa; + struct sockaddr *sa; socklen_t salen; int sd; struct bfd_echo_pkt bep; @@ -135,31 +138,34 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd) bep.len = BFD_ECHO_PKT_LEN; bep.my_discr = htonl(bfd->discrs.my_discr); - sa = BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MH) ? &bfd->mhop.peer - : &bfd->shop.peer; if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) { sd = bglobal.bg_echov6; - sin6 = sa->sa_sin6; + memset(&sin6, 0, sizeof(sin6)); + memcpy(&sin6.sin6_addr, &bfd->key.peer, sizeof(sin6.sin6_addr)); + if (bfd->ifp && IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) + sin6.sin6_scope_id = bfd->ifp->ifindex; + sin6.sin6_port = htons(BFD_DEF_ECHO_PORT); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin6.sin6_len = sizeof(sin6); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ - sa = (struct sockaddr_any *)&sin6; + sa = (struct sockaddr *)&sin6; salen = sizeof(sin6); } else { sd = bglobal.bg_echo; - sin = sa->sa_sin; + memset(&sin6, 0, sizeof(sin6)); + memcpy(&sin.sin_addr, &bfd->key.peer, sizeof(sin.sin_addr)); sin.sin_port = htons(BFD_DEF_ECHO_PORT); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin.sin_len = sizeof(sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ - sa = (struct sockaddr_any *)&sin; + sa = (struct sockaddr *)&sin; salen = sizeof(sin); } - if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep), - (struct sockaddr *)sa, salen) + if (bp_udp_send(sd, BFD_TTL_VAL, (uint8_t *)&bep, sizeof(bep), sa, + salen) == -1) return; @@ -602,8 +608,8 @@ int bfd_recv_cb(struct thread *t) bfd->mh_ttl, BFD_TTL_VAL); return 0; } - } else if (bfd->local_ip.sa_sin.sin_family == AF_UNSPEC) { - bfd->local_ip = local; + } else if (bfd->local_address.sa_sin.sin_family == AF_UNSPEC) { + bfd->local_address = local; } /* @@ -917,25 +923,26 @@ int bp_peer_socket(const struct bfd_session *bs) return -1; } - if (bs->shop.ifindex != IFINDEX_INTERNAL) { - if (bp_bind_dev(sd, bs->ifp->name) != 0) { + if (bs->key.ifname[0]) { + if (bp_bind_dev(sd, bs->key.ifname) != 0) { close(sd); return -1; } - } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) && - bs->mhop.vrfid != VRF_DEFAULT) { - if (bp_bind_dev(sd, bs->vrf->name) != 0) { + } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) + && bs->key.vrfname[0]) { + if (bp_bind_dev(sd, bs->key.vrfname) != 0) { close(sd); return -1; } } /* Find an available source port in the proper range */ - sin = bs->local_ip.sa_sin; + memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin.sin_len = sizeof(sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ + memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr)); if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) sin.sin_addr.s_addr = INADDR_ANY; @@ -987,20 +994,23 @@ int bp_peer_socketv6(const struct bfd_session *bs) } /* Find an available source port in the proper range */ - sin6 = bs->local_ip.sa_sin6; + memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin6.sin6_len = sizeof(sin6); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ + memcpy(&sin6.sin6_addr, &bs->key.local, sizeof(sin6.sin6_addr)); + if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) + sin6.sin6_scope_id = bs->ifp->ifindex; - if (bs->shop.ifindex != IFINDEX_INTERNAL) { - if (bp_bind_dev(sd, bs->ifp->name) != 0) { + if (bs->key.ifname[0]) { + if (bp_bind_dev(sd, bs->key.ifname) != 0) { close(sd); return -1; } - } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) && - bs->mhop.vrfid != VRF_DEFAULT) { - if (bp_bind_dev(sd, bs->vrf->name) != 0) { + } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) + && bs->key.vrfname[0]) { + if (bp_bind_dev(sd, bs->key.vrfname) != 0) { close(sd); return -1; } diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index c77cd08be8..f4f38c7f1d 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -79,7 +79,6 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, const char *local_str, const char *ifname, const char *vrfname); - /* * Commands definition. */ @@ -369,22 +368,25 @@ DEFPY(bfd_no_peer, bfd_no_peer_cmd, */ static void _display_peer_header(struct vty *vty, struct bfd_session *bs) { - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer)); + char addr_buf[INET6_ADDRSTRLEN]; + + vty_out(vty, "\tpeer %s", + inet_ntop(bs->key.family, &bs->key.peer, addr_buf, + sizeof(addr_buf))); + + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) vty_out(vty, " multihop"); - vty_out(vty, " local-address %s", satostr(&bs->mhop.local)); - if (bs->vrfname[0]) - vty_out(vty, " vrf %s", bs->vrfname); - vty_out(vty, "\n"); - } else { - vty_out(vty, "\tpeer %s", satostr(&bs->shop.peer)); - if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) - vty_out(vty, " local-address %s", - satostr(&bs->local_address)); - if (bs->ifname[0]) - vty_out(vty, " interface %s", bs->ifname); - vty_out(vty, "\n"); - } + + if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) + vty_out(vty, " local-address %s", + inet_ntop(bs->key.family, &bs->key.local, addr_buf, + sizeof(addr_buf))); + + if (bs->key.vrfname[0]) + vty_out(vty, " vrf %s", bs->key.vrfname); + if (bs->key.ifname[0]) + vty_out(vty, " interface %s", bs->key.ifname); + vty_out(vty, "\n"); if (bs->pl) vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label); @@ -453,22 +455,25 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs) static struct json_object *_peer_json_header(struct bfd_session *bs) { struct json_object *jo = json_object_new_object(); + char addr_buf[INET6_ADDRSTRLEN]; - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { + if (bs->key.mhop) json_object_boolean_true_add(jo, "multihop"); - json_object_string_add(jo, "peer", satostr(&bs->mhop.peer)); - json_object_string_add(jo, "local", satostr(&bs->mhop.local)); - if (bs->vrfname[0]) - json_object_string_add(jo, "vrf", bs->vrfname); - } else { + else json_object_boolean_false_add(jo, "multihop"); - json_object_string_add(jo, "peer", satostr(&bs->shop.peer)); - if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) - json_object_string_add(jo, "local", - satostr(&bs->local_address)); - if (bs->ifname[0]) - json_object_string_add(jo, "interface", bs->ifname); - } + + json_object_string_add(jo, "peer", + inet_ntop(bs->key.family, &bs->key.peer, + addr_buf, sizeof(addr_buf))); + if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) + json_object_string_add(jo, "local", + inet_ntop(bs->key.family, &bs->key.local, + addr_buf, sizeof(addr_buf))); + + if (bs->key.vrfname[0]) + json_object_string_add(jo, "vrf", bs->key.vrfname); + if (bs->key.ifname[0]) + json_object_string_add(jo, "interface", bs->key.ifname); if (bs->pl) json_object_string_add(jo, "label", bs->pl->pl_label); @@ -916,22 +921,25 @@ static int bfdd_write_config(struct vty *vty) static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs) { - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - vty_out(vty, " peer %s", satostr(&bs->mhop.peer)); + char addr_buf[INET6_ADDRSTRLEN]; + + vty_out(vty, " peer %s", + inet_ntop(bs->key.family, &bs->key.peer, addr_buf, + sizeof(addr_buf))); + + if (bs->key.mhop) vty_out(vty, " multihop"); - vty_out(vty, " local-address %s", satostr(&bs->mhop.local)); - if (bs->vrfname[0]) - vty_out(vty, " vrf %s", bs->vrfname); - vty_out(vty, "\n"); - } else { - vty_out(vty, " peer %s", satostr(&bs->shop.peer)); - if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) - vty_out(vty, " local-address %s", - satostr(&bs->local_address)); - if (bs->ifname[0]) - vty_out(vty, " interface %s", bs->ifname); - vty_out(vty, "\n"); - } + + if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) + vty_out(vty, " local-address %s", + inet_ntop(bs->key.family, &bs->key.local, addr_buf, + sizeof(addr_buf))); + + if (bs->key.vrfname[0]) + vty_out(vty, " vrf %s", bs->key.vrfname); + if (bs->key.ifname[0]) + vty_out(vty, " interface %s", bs->key.ifname); + vty_out(vty, "\n"); if (bs->sock == -1) vty_out(vty, " ! vrf or interface doesn't exist\n"); @@ -980,16 +988,7 @@ static void _bfdd_peer_write_config_iter(struct hash_bucket *hb, void *arg) static int bfdd_peer_write_config(struct vty *vty) { - struct bfd_session_observer *bso; - bfd_id_iterate(_bfdd_peer_write_config_iter, vty); - TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { - /* Only print disabled sessions here. */ - if (bso->bso_bs->sock != -1) - continue; - - _bfdd_peer_write_config(vty, bso->bso_bs); - } return 1; } diff --git a/bfdd/config.c b/bfdd/config.c index 17e155e41d..cd57ea9fe3 100644 --- a/bfdd/config.c +++ b/bfdd/config.c @@ -309,24 +309,7 @@ static int parse_peer_label_config(struct json_object *jo, log_debug("\tpeer-label: %s", sval); /* Translate the label into BFD address keys. */ - bpc->bpc_ipv4 = !BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_IPV6); - bpc->bpc_mhop = BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_MH); - if (bpc->bpc_mhop) { - bpc->bpc_peer = pl->pl_bs->mhop.peer; - bpc->bpc_local = pl->pl_bs->mhop.local; - if (pl->pl_bs->mhop.vrfid != VRF_DEFAULT) { - bpc->bpc_has_vrfname = true; - strlcpy(bpc->bpc_vrfname, pl->pl_bs->vrf->name, - sizeof(bpc->bpc_vrfname)); - } - } else { - bpc->bpc_peer = pl->pl_bs->shop.peer; - if (pl->pl_bs->ifname[0]) { - bpc->bpc_has_localif = true; - strlcpy(bpc->bpc_localif, pl->pl_bs->ifname, - sizeof(bpc->bpc_localif)); - } - } + bs_to_bpc(pl->pl_bs, bpc); return 0; } @@ -519,6 +502,8 @@ int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr, static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs) { + char addr_buf[INET6_ADDRSTRLEN]; + /* Add peer 'key' information. */ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) json_object_boolean_true_add(jo, "ipv6"); @@ -528,21 +513,26 @@ static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs) if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { json_object_boolean_true_add(jo, "multihop"); json_object_string_add(jo, "peer-address", - satostr(&bs->mhop.peer)); + inet_ntop(bs->key.family, &bs->key.peer, + addr_buf, sizeof(addr_buf))); json_object_string_add(jo, "local-address", - satostr(&bs->mhop.local)); - if (bs->vrfname[0]) - json_object_string_add(jo, "vrf-name", bs->vrfname); + inet_ntop(bs->key.family, &bs->key.local, + addr_buf, sizeof(addr_buf))); + if (bs->key.vrfname[0]) + json_object_string_add(jo, "vrf-name", bs->key.vrfname); } else { json_object_boolean_false_add(jo, "multihop"); json_object_string_add(jo, "peer-address", - satostr(&bs->shop.peer)); - if (bs->local_address.sa_sin.sin_family != AF_UNSPEC) - json_object_string_add(jo, "local-address", - satostr(&bs->local_address)); - if (bs->ifname[0]) + inet_ntop(bs->key.family, &bs->key.peer, + addr_buf, sizeof(addr_buf))); + if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) + json_object_string_add( + jo, "local-address", + inet_ntop(bs->key.family, &bs->key.local, + addr_buf, sizeof(addr_buf))); + if (bs->key.ifname[0]) json_object_string_add(jo, "local-interface", - bs->ifname); + bs->key.ifname); } if (bs->pl) diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 5610c352fb..d85bd26705 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -55,7 +55,7 @@ static struct zclient *zclient; /* * Prototypes */ -static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa); +static int _ptm_msg_address(struct stream *msg, int family, const void *addr); static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa); static int _ptm_msg_read(struct stream *msg, int command, @@ -127,24 +127,24 @@ static void debug_printbpc(const char *func, unsigned int line, #define DEBUG_PRINTBPC(bpc) #endif /* BFD_DEBUG */ -static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa) +static int _ptm_msg_address(struct stream *msg, int family, const void *addr) { - switch (sa->sa_sin.sin_family) { + stream_putc(msg, family); + + switch (family) { case AF_INET: - stream_putc(msg, sa->sa_sin.sin_family); - stream_put_in_addr(msg, &sa->sa_sin.sin_addr); + stream_put(msg, addr, sizeof(struct in_addr)); stream_putc(msg, 32); break; case AF_INET6: - stream_putc(msg, sa->sa_sin6.sin6_family); - stream_put(msg, &sa->sa_sin6.sin6_addr, - sizeof(sa->sa_sin6.sin6_addr)); + stream_put(msg, addr, sizeof(struct in6_addr)); stream_putc(msg, 128); break; default: - return -1; + assert(0); + break; } return 0; @@ -153,7 +153,6 @@ static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa) int ptm_bfd_notify(struct bfd_session *bs) { struct stream *msg; - struct sockaddr_any sac; bs->stats.znotification++; @@ -195,10 +194,7 @@ int ptm_bfd_notify(struct bfd_session *bs) stream_putl(msg, IFINDEX_INTERNAL); /* BFD destination prefix information. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) - _ptm_msg_address(msg, &bs->mhop.peer); - else - _ptm_msg_address(msg, &bs->shop.peer); + _ptm_msg_address(msg, bs->key.family, &bs->key.peer); /* BFD status */ switch (bs->ses_state) { @@ -218,34 +214,7 @@ int ptm_bfd_notify(struct bfd_session *bs) } /* BFD source prefix information. */ - if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - _ptm_msg_address(msg, &bs->mhop.local); - } else { - if (bs->local_address.sa_sin.sin_family) - _ptm_msg_address(msg, &bs->local_address); - else if (bs->local_address.sa_sin.sin_family) - _ptm_msg_address(msg, &bs->local_ip); - else { - sac = bs->shop.peer; - switch (sac.sa_sin.sin_family) { - case AF_INET: - memset(&sac.sa_sin.sin_addr, 0, - sizeof(sac.sa_sin.sin_family)); - break; - case AF_INET6: - memset(&sac.sa_sin6.sin6_addr, 0, - sizeof(sac.sa_sin6.sin6_family)); - break; - - default: - assert(false); - break; - } - - /* No local address found yet, so send zeroes. */ - _ptm_msg_address(msg, &sac); - } - } + _ptm_msg_address(msg, bs->key.family, &bs->key.local); /* Write packet size. */ stream_putw_at(msg, 0, stream_get_endp(msg)); @@ -290,7 +259,6 @@ stream_failure: static int _ptm_msg_read(struct stream *msg, int command, struct bfd_peer_cfg *bpc, struct ptm_client **pc) { - struct interface *ifp; uint32_t pid; uint8_t ttl __attribute__((unused)); size_t ifnamelen; @@ -385,31 +353,6 @@ static int _ptm_msg_read(struct stream *msg, int command, if (bpc->bpc_has_localif) { STREAM_GET(bpc->bpc_localif, msg, ifnamelen); bpc->bpc_localif[ifnamelen] = 0; - - /* - * IPv6 link-local addresses must use scope id, - * otherwise the session lookup will always fail - * and we'll have multiple sessions showing up. - * - * This problem only happens with single hop - * since it is not possible to have link-local - * address for multi hop sessions. - */ - if (bpc->bpc_ipv4 == false - && IN6_IS_ADDR_LINKLOCAL( - &bpc->bpc_peer.sa_sin6.sin6_addr)) { - ifp = if_lookup_by_name_all_vrf( - bpc->bpc_localif); - if (ifp == NULL) { - log_error( - "ptm-read: interface %s doesn't exists", - bpc->bpc_localif); - return -1; - } - - bpc->bpc_peer.sa_sin6.sin6_scope_id = - ifp->ifindex; - } } } @@ -608,7 +551,7 @@ static void bfdd_sessions_enable_interface(struct interface *ifp) /* Interface name mismatch. */ bs = bso->bso_bs; - if (strcmp(ifp->name, bs->ifname)) + if (strcmp(ifp->name, bs->key.ifname)) continue; /* Skip enabled sessions. */ if (bs->sock != -1) @@ -630,7 +573,7 @@ static void bfdd_sessions_disable_interface(struct interface *ifp) /* Interface name mismatch. */ bs = bso->bso_bs; - if (strcmp(ifp->name, bs->ifname)) + if (strcmp(ifp->name, bs->key.ifname)) continue; /* Skip disabled sessions. */ if (bs->sock == -1) From 261e0ba94d24cc28462a12eda23d9ed8ce747765 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 11 Mar 2019 21:26:13 -0300 Subject: [PATCH 058/142] bfdd: don't enable sessions without local-address When the local-address configured by the peer doesn't exist, then we must observe the session until the mentioned address comes up. Signed-off-by: Rafael Zalamena --- bfdd/bfd.c | 27 +++++++++++++++++++++------ bfdd/bfd.h | 6 +++++- bfdd/bfdd_vty.c | 3 ++- bfdd/ptm_adapter.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index ea059cc1c2..c8adf82a83 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -162,6 +162,13 @@ int bfd_session_enable(struct bfd_session *bs) && BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0) bs->ifp = ifp; + /* Sanity check: don't leak open sockets. */ + if (bs->sock != -1) { + zlog_debug("session-enable: previous socket open"); + close(bs->sock); + bs->sock = -1; + } + /* * Get socket for transmitting control packets. Note that if we * could use the destination port (3784) for the source @@ -170,11 +177,11 @@ int bfd_session_enable(struct bfd_session *bs) if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6) == 0) { psock = bp_peer_socket(bs); if (psock == -1) - return -1; + return 0; } else { psock = bp_peer_socketv6(bs); if (psock == -1) - return -1; + return 0; } /* @@ -662,10 +669,6 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc) strlcpy(bfd->key.vrfname, bpc->bpc_vrfname, sizeof(bfd->key.vrfname)); - /* Add observer if we have moving parts. */ - if (bfd->key.ifname[0] || bfd->key.vrfname[0]) - bs_observer_add(bfd); - /* Copy remaining data. */ if (bpc->bpc_ipv4 == false) BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6); @@ -708,6 +711,10 @@ struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc) return NULL; } + /* Add observer if we have moving parts. */ + if (bfd->key.ifname[0] || bfd->key.vrfname[0] || bfd->sock == -1) + bs_observer_add(bfd); + /* Apply other configurations. */ _bfd_session_update(bfd, bpc); @@ -1190,6 +1197,14 @@ int bs_observer_add(struct bfd_session *bs) strlcpy(bso->bso_entryname, bs->key.vrfname, sizeof(bso->bso_entryname)); + /* Handle socket binding failures caused by missing local addresses. */ + if (bs->sock == -1) { + bso->bso_isaddress = true; + bso->bso_addr.family = bs->key.family; + memcpy(&bso->bso_addr.u.prefix, &bs->key.local, + sizeof(bs->key.local)); + } + TAILQ_INSERT_TAIL(&bglobal.bg_obslist, bso, bso_entry); return 0; diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 1556012296..a69ff9a1a7 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -274,7 +274,11 @@ struct bfd_state_str_list { struct bfd_session_observer { struct bfd_session *bso_bs; bool bso_isinterface; - char bso_entryname[MAXNAMELEN]; + bool bso_isaddress; + union { + char bso_entryname[MAXNAMELEN]; + struct prefix bso_addr; + }; TAILQ_ENTRY(bfd_session_observer) bso_entry; }; diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index f4f38c7f1d..c139492076 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -942,7 +942,8 @@ static void _bfdd_peer_write_config(struct vty *vty, struct bfd_session *bs) vty_out(vty, "\n"); if (bs->sock == -1) - vty_out(vty, " ! vrf or interface doesn't exist\n"); + vty_out(vty, + " ! vrf, interface or local-address doesn't exist\n"); if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER) vty_out(vty, " detect-multiplier %d\n", bs->detect_mult); diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index d85bd26705..b44d13f132 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -634,6 +634,48 @@ static int bfdd_interface_vrf_update(int command __attribute__((__unused__)), return 0; } +static void bfdd_sessions_enable_address(struct connected *ifc) +{ + struct bfd_session_observer *bso; + struct bfd_session *bs; + struct prefix prefix; + + TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { + if (bso->bso_isaddress == false) + continue; + + /* Skip enabled sessions. */ + bs = bso->bso_bs; + if (bs->sock != -1) + continue; + + /* Check address. */ + prefix = bso->bso_addr; + prefix.prefixlen = ifc->address->prefixlen; + if (prefix_cmp(&prefix, ifc->address)) + continue; + + /* Try to enable it. */ + bfd_session_enable(bs); + } +} + +static int bfdd_interface_address_update(int cmd, struct zclient *zc, + zebra_size_t len + __attribute__((__unused__)), + vrf_id_t vrfid) +{ + struct connected *ifc; + + ifc = zebra_interface_address_read(cmd, zc->ibuf, vrfid); + if (ifc == NULL) + return 0; + + bfdd_sessions_enable_address(ifc); + + return 0; +} + void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv) { zclient = zclient_new(master, &zclient_options_default); @@ -656,6 +698,10 @@ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv) /* Learn about interface VRF. */ zclient->interface_vrf_update = bfdd_interface_vrf_update; + + /* Learn about new addresses being registered. */ + zclient->interface_address_add = bfdd_interface_address_update; + zclient->interface_address_delete = bfdd_interface_address_update; } void bfdd_zclient_stop(void) From 812f5a3d3b42617326ab62ae95b5a9c283da2e7f Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Thu, 7 Mar 2019 16:44:08 -0300 Subject: [PATCH 059/142] topotests: add new bfd topology with IPv6 New BFD topology using IPv6 and multi hop peer to cover more daemon features. This topology also tests BFD integration with BGP, OSPF and OSPF6. Signed-off-by: Rafael Zalamena --- tests/topotests/bfd-topo2/__init__.py | 0 tests/topotests/bfd-topo2/r1/bfdd.conf | 5 + tests/topotests/bfd-topo2/r1/bgpd.conf | 13 ++ tests/topotests/bfd-topo2/r1/ipv4_routes.json | 68 +++++++ tests/topotests/bfd-topo2/r1/ipv6_routes.json | 63 ++++++ tests/topotests/bfd-topo2/r1/peers.json | 29 +++ tests/topotests/bfd-topo2/r1/zebra.conf | 6 + tests/topotests/bfd-topo2/r2/bgpd.conf | 16 ++ tests/topotests/bfd-topo2/r2/ipv4_routes.json | 108 ++++++++++ tests/topotests/bfd-topo2/r2/ipv6_routes.json | 63 ++++++ tests/topotests/bfd-topo2/r2/ospf6d.conf | 9 + tests/topotests/bfd-topo2/r2/ospfd.conf | 9 + tests/topotests/bfd-topo2/r2/peers.json | 42 ++++ tests/topotests/bfd-topo2/r2/zebra.conf | 15 ++ tests/topotests/bfd-topo2/r3/ipv4_routes.json | 109 ++++++++++ tests/topotests/bfd-topo2/r3/ipv6_routes.json | 2 + tests/topotests/bfd-topo2/r3/ospfd.conf | 8 + tests/topotests/bfd-topo2/r3/peers.json | 16 ++ tests/topotests/bfd-topo2/r3/zebra.conf | 6 + tests/topotests/bfd-topo2/r4/bfdd.conf | 5 + tests/topotests/bfd-topo2/r4/ipv4_routes.json | 24 +++ tests/topotests/bfd-topo2/r4/ipv6_routes.json | 63 ++++++ tests/topotests/bfd-topo2/r4/ospf6d.conf | 8 + tests/topotests/bfd-topo2/r4/peers.json | 29 +++ tests/topotests/bfd-topo2/r4/zebra.conf | 6 + tests/topotests/bfd-topo2/test_bfd_topo2.dot | 73 +++++++ tests/topotests/bfd-topo2/test_bfd_topo2.jpg | Bin 0 -> 24206 bytes tests/topotests/bfd-topo2/test_bfd_topo2.py | 191 ++++++++++++++++++ 28 files changed, 986 insertions(+) create mode 100644 tests/topotests/bfd-topo2/__init__.py create mode 100644 tests/topotests/bfd-topo2/r1/bfdd.conf create mode 100644 tests/topotests/bfd-topo2/r1/bgpd.conf create mode 100644 tests/topotests/bfd-topo2/r1/ipv4_routes.json create mode 100644 tests/topotests/bfd-topo2/r1/ipv6_routes.json create mode 100644 tests/topotests/bfd-topo2/r1/peers.json create mode 100644 tests/topotests/bfd-topo2/r1/zebra.conf create mode 100644 tests/topotests/bfd-topo2/r2/bgpd.conf create mode 100644 tests/topotests/bfd-topo2/r2/ipv4_routes.json create mode 100644 tests/topotests/bfd-topo2/r2/ipv6_routes.json create mode 100644 tests/topotests/bfd-topo2/r2/ospf6d.conf create mode 100644 tests/topotests/bfd-topo2/r2/ospfd.conf create mode 100644 tests/topotests/bfd-topo2/r2/peers.json create mode 100644 tests/topotests/bfd-topo2/r2/zebra.conf create mode 100644 tests/topotests/bfd-topo2/r3/ipv4_routes.json create mode 100644 tests/topotests/bfd-topo2/r3/ipv6_routes.json create mode 100644 tests/topotests/bfd-topo2/r3/ospfd.conf create mode 100644 tests/topotests/bfd-topo2/r3/peers.json create mode 100644 tests/topotests/bfd-topo2/r3/zebra.conf create mode 100644 tests/topotests/bfd-topo2/r4/bfdd.conf create mode 100644 tests/topotests/bfd-topo2/r4/ipv4_routes.json create mode 100644 tests/topotests/bfd-topo2/r4/ipv6_routes.json create mode 100644 tests/topotests/bfd-topo2/r4/ospf6d.conf create mode 100644 tests/topotests/bfd-topo2/r4/peers.json create mode 100644 tests/topotests/bfd-topo2/r4/zebra.conf create mode 100644 tests/topotests/bfd-topo2/test_bfd_topo2.dot create mode 100644 tests/topotests/bfd-topo2/test_bfd_topo2.jpg create mode 100644 tests/topotests/bfd-topo2/test_bfd_topo2.py diff --git a/tests/topotests/bfd-topo2/__init__.py b/tests/topotests/bfd-topo2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bfd-topo2/r1/bfdd.conf b/tests/topotests/bfd-topo2/r1/bfdd.conf new file mode 100644 index 0000000000..5c2571bdbd --- /dev/null +++ b/tests/topotests/bfd-topo2/r1/bfdd.conf @@ -0,0 +1,5 @@ +bfd + peer 2001:db8:4::1 multihop local-address 2001:db8:1::1 + no shutdown + ! +! diff --git a/tests/topotests/bfd-topo2/r1/bgpd.conf b/tests/topotests/bfd-topo2/r1/bgpd.conf new file mode 100644 index 0000000000..1623b4578b --- /dev/null +++ b/tests/topotests/bfd-topo2/r1/bgpd.conf @@ -0,0 +1,13 @@ +router bgp 101 + bgp router-id 10.254.254.1 + neighbor r2g peer-group + neighbor r2g remote-as external + neighbor r2g bfd + neighbor r1-eth0 interface peer-group r2g + address-family ipv4 unicast + redistribute connected + exit-address-family + address-family ipv6 unicast + neighbor r2g activate + exit-address-family +! diff --git a/tests/topotests/bfd-topo2/r1/ipv4_routes.json b/tests/topotests/bfd-topo2/r1/ipv4_routes.json new file mode 100644 index 0000000000..8a2ec25baa --- /dev/null +++ b/tests/topotests/bfd-topo2/r1/ipv4_routes.json @@ -0,0 +1,68 @@ +{ + "10.0.3.0/24": [ + { + "distance": 20, + "protocol": "bgp", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.0.3.0/24", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r1-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv6" + } + ] + } + ], + "10.254.254.2/32": [ + { + "distance": 20, + "protocol": "bgp", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.254.254.2/32", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r1-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv6" + } + ] + } + ], + "10.254.254.1/32": [ + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.254.254.1/32", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "lo", + "interfaceIndex": 1, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r1/ipv6_routes.json b/tests/topotests/bfd-topo2/r1/ipv6_routes.json new file mode 100644 index 0000000000..618853bd42 --- /dev/null +++ b/tests/topotests/bfd-topo2/r1/ipv6_routes.json @@ -0,0 +1,63 @@ +{ + "2001:db8:4::/64": [ + { + "distance": 20, + "protocol": "bgp", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "2001:db8:4::/64", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r1-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv6" + } + ] + } + ], + "2001:db8:1::/64": [ + { + "distance": 20, + "protocol": "bgp", + "internalFlags": 0, + "metric": 0, + "internalStatus": 2, + "prefix": "2001:db8:1::/64", + "nexthops": [ + { + "interfaceName": "r1-eth0", + "interfaceIndex": 2, + "flags": 1, + "active": true, + "afi": "ipv6" + } + ] + }, + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "2001:db8:1::/64", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "r1-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r1/peers.json b/tests/topotests/bfd-topo2/r1/peers.json new file mode 100644 index 0000000000..b14351cd81 --- /dev/null +++ b/tests/topotests/bfd-topo2/r1/peers.json @@ -0,0 +1,29 @@ +[ + { + "multihop":true, + "peer":"2001:db8:4::1", + "local":"2001:db8:1::1", + "status":"up", + "diagnostic":"ok", + "remote-diagnostic":"ok", + "receive-interval":300, + "transmit-interval":300, + "echo-interval":0, + "remote-receive-interval":300, + "remote-transmit-interval":300, + "remote-echo-interval":50 + }, + { + "multihop":false, + "interface":"r1-eth0", + "status":"up", + "diagnostic":"ok", + "remote-diagnostic":"ok", + "receive-interval":300, + "transmit-interval":300, + "echo-interval":0, + "remote-receive-interval":300, + "remote-transmit-interval":300, + "remote-echo-interval":50 + } +] diff --git a/tests/topotests/bfd-topo2/r1/zebra.conf b/tests/topotests/bfd-topo2/r1/zebra.conf new file mode 100644 index 0000000000..7fe5eb218f --- /dev/null +++ b/tests/topotests/bfd-topo2/r1/zebra.conf @@ -0,0 +1,6 @@ +interface lo + ip address 10.254.254.1/32 +! +interface r1-eth0 + ipv6 address 2001:db8:1::1/64 +! diff --git a/tests/topotests/bfd-topo2/r2/bgpd.conf b/tests/topotests/bfd-topo2/r2/bgpd.conf new file mode 100644 index 0000000000..bf42d21812 --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/bgpd.conf @@ -0,0 +1,16 @@ +router bgp 102 + bgp router-id 10.254.254.2 + neighbor r2g peer-group + neighbor r2g remote-as external + neighbor r2g bfd + neighbor r2-eth0 interface peer-group r2g + ! + address-family ipv4 unicast + redistribute connected + exit-address-family + ! + address-family ipv6 unicast + redistribute connected + neighbor r2g activate + exit-address-family +! diff --git a/tests/topotests/bfd-topo2/r2/ipv4_routes.json b/tests/topotests/bfd-topo2/r2/ipv4_routes.json new file mode 100644 index 0000000000..b9d8afb430 --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/ipv4_routes.json @@ -0,0 +1,108 @@ +{ + "10.0.3.0/24": [ + { + "distance": 110, + "protocol": "ospf", + "internalFlags": 0, + "metric": 10, + "internalStatus": 2, + "prefix": "10.0.3.0/24", + "nexthops": [ + { + "active": true, + "directlyConnected": true, + "flags": 1, + "interfaceIndex": 3, + "interfaceName": "r2-eth1" + } + ] + }, + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.0.3.0/24", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "r2-eth1", + "interfaceIndex": 3, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ], + "10.254.254.3/32": [ + { + "distance": 110, + "protocol": "ospf", + "internalFlags": 8, + "metric": 20, + "selected": true, + "installed": true, + "prefix": "10.254.254.3/32", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r2-eth1", + "ip": "10.0.3.1", + "interfaceIndex": 3, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.2/32": [ + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.254.254.2/32", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "lo", + "interfaceIndex": 1, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ], + "10.254.254.1/32": [ + { + "distance": 20, + "protocol": "bgp", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.254.254.1/32", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r2-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv6" + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r2/ipv6_routes.json b/tests/topotests/bfd-topo2/r2/ipv6_routes.json new file mode 100644 index 0000000000..004e7588aa --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/ipv6_routes.json @@ -0,0 +1,63 @@ +{ + "2001:db8:4::/64": [ + { + "distance": 110, + "protocol": "ospf6", + "internalFlags": 0, + "metric": 10, + "internalStatus": 2, + "prefix": "2001:db8:4::/64", + "nexthops": [ + { + "active": true, + "directlyConnected": true, + "flags": 1, + "interfaceIndex": 4, + "interfaceName": "r2-eth2" + } + ] + }, + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "2001:db8:4::/64", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "r2-eth2", + "interfaceIndex": 4, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ], + "2001:db8:1::/64": [ + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "2001:db8:1::/64", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "r2-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r2/ospf6d.conf b/tests/topotests/bfd-topo2/r2/ospf6d.conf new file mode 100644 index 0000000000..f1cdb50285 --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/ospf6d.conf @@ -0,0 +1,9 @@ +interface r2-eth2 + ipv6 ospf6 bfd +! +router ospf6 + ospf6 router-id 10.254.254.2 + redistribute connected + redistribute bgp + interface r2-eth2 area 0.0.0.1 +! diff --git a/tests/topotests/bfd-topo2/r2/ospfd.conf b/tests/topotests/bfd-topo2/r2/ospfd.conf new file mode 100644 index 0000000000..8e0c45980d --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/ospfd.conf @@ -0,0 +1,9 @@ +interface r2-eth1 + ip ospf area 0.0.0.1 + ip ospf bfd +! +router ospf + ospf router-id 10.254.254.2 + redistribute connected + redistribute bgp +! diff --git a/tests/topotests/bfd-topo2/r2/peers.json b/tests/topotests/bfd-topo2/r2/peers.json new file mode 100644 index 0000000000..29075fcc80 --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/peers.json @@ -0,0 +1,42 @@ +[ + { + "status": "up", + "transmit-interval": 300, + "remote-receive-interval": 300, + "echo-interval": 0, + "diagnostic": "ok", + "multihop": false, + "interface": "r2-eth0", + "remote-transmit-interval": 300, + "receive-interval": 300, + "remote-echo-interval": 50, + "remote-diagnostic": "ok" + }, + { + "status": "up", + "transmit-interval": 300, + "remote-receive-interval": 300, + "echo-interval": 0, + "diagnostic": "ok", + "multihop": false, + "interface": "r2-eth2", + "remote-transmit-interval": 300, + "receive-interval": 300, + "remote-echo-interval": 50, + "remote-diagnostic": "ok" + }, + { + "status": "up", + "transmit-interval": 300, + "remote-receive-interval": 300, + "echo-interval": 0, + "diagnostic": "ok", + "multihop": false, + "interface": "r2-eth1", + "remote-transmit-interval": 300, + "receive-interval": 300, + "remote-echo-interval": 50, + "remote-diagnostic": "ok", + "peer": "10.0.3.1" + } +] diff --git a/tests/topotests/bfd-topo2/r2/zebra.conf b/tests/topotests/bfd-topo2/r2/zebra.conf new file mode 100644 index 0000000000..cccbf6574a --- /dev/null +++ b/tests/topotests/bfd-topo2/r2/zebra.conf @@ -0,0 +1,15 @@ +ip forwarding +ipv6 forwarding +! +interface lo + ip address 10.254.254.2/32 +! +interface r2-eth0 + ipv6 address 2001:db8:1::2/64 +! +interface r2-eth1 + ip address 10.0.3.2/24 +! +interface r2-eth2 + ipv6 address 2001:db8:4::2/64 +! diff --git a/tests/topotests/bfd-topo2/r3/ipv4_routes.json b/tests/topotests/bfd-topo2/r3/ipv4_routes.json new file mode 100644 index 0000000000..14dfc692fe --- /dev/null +++ b/tests/topotests/bfd-topo2/r3/ipv4_routes.json @@ -0,0 +1,109 @@ +{ + "10.0.3.0/24": [ + { + "distance": 110, + "protocol": "ospf", + "internalFlags": 0, + "metric": 10, + "internalStatus": 0, + "prefix": "10.0.3.0/24", + "nexthops": [ + { + "active": true, + "directlyConnected": true, + "flags": 1, + "interfaceIndex": 2, + "interfaceName": "r3-eth0" + } + ] + }, + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.0.3.0/24", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "r3-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ], + "10.254.254.3/32": [ + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.254.254.3/32", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "lo", + "interfaceIndex": 1, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ], + "10.254.254.2/32": [ + { + "distance": 110, + "protocol": "ospf", + "internalFlags": 8, + "metric": 20, + "selected": true, + "installed": true, + "prefix": "10.254.254.2/32", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r3-eth0", + "ip": "10.0.3.2", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.1/32": [ + { + "distance": 110, + "protocol": "ospf", + "internalFlags": 8, + "metric": 20, + "selected": true, + "installed": true, + "prefix": "10.254.254.1/32", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r3-eth0", + "ip": "10.0.3.2", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv4" + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r3/ipv6_routes.json b/tests/topotests/bfd-topo2/r3/ipv6_routes.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/bfd-topo2/r3/ipv6_routes.json @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/bfd-topo2/r3/ospfd.conf b/tests/topotests/bfd-topo2/r3/ospfd.conf new file mode 100644 index 0000000000..cf2a1bdf76 --- /dev/null +++ b/tests/topotests/bfd-topo2/r3/ospfd.conf @@ -0,0 +1,8 @@ +interface r3-eth0 + ip ospf area 0.0.0.1 + ip ospf bfd +! +router ospf + ospf router-id 10.254.254.3 + redistribute connected +! diff --git a/tests/topotests/bfd-topo2/r3/peers.json b/tests/topotests/bfd-topo2/r3/peers.json new file mode 100644 index 0000000000..6698bff201 --- /dev/null +++ b/tests/topotests/bfd-topo2/r3/peers.json @@ -0,0 +1,16 @@ +[ + { + "status": "up", + "transmit-interval": 300, + "remote-receive-interval": 300, + "echo-interval": 0, + "diagnostic": "ok", + "multihop": false, + "interface": "r3-eth0", + "remote-transmit-interval": 300, + "receive-interval": 300, + "remote-echo-interval": 50, + "remote-diagnostic": "ok", + "peer": "10.0.3.2" + } +] diff --git a/tests/topotests/bfd-topo2/r3/zebra.conf b/tests/topotests/bfd-topo2/r3/zebra.conf new file mode 100644 index 0000000000..96fd08c729 --- /dev/null +++ b/tests/topotests/bfd-topo2/r3/zebra.conf @@ -0,0 +1,6 @@ +interface lo + ip address 10.254.254.3/32 +! +interface r3-eth0 + ip address 10.0.3.1/24 +! diff --git a/tests/topotests/bfd-topo2/r4/bfdd.conf b/tests/topotests/bfd-topo2/r4/bfdd.conf new file mode 100644 index 0000000000..fdb4412446 --- /dev/null +++ b/tests/topotests/bfd-topo2/r4/bfdd.conf @@ -0,0 +1,5 @@ +bfd + peer 2001:db8:1::1 multihop local-address 2001:db8:4::1 + no shutdown + ! +! diff --git a/tests/topotests/bfd-topo2/r4/ipv4_routes.json b/tests/topotests/bfd-topo2/r4/ipv4_routes.json new file mode 100644 index 0000000000..ae1e97b017 --- /dev/null +++ b/tests/topotests/bfd-topo2/r4/ipv4_routes.json @@ -0,0 +1,24 @@ +{ + "10.254.254.4/32": [ + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "10.254.254.4/32", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "lo", + "interfaceIndex": 1, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r4/ipv6_routes.json b/tests/topotests/bfd-topo2/r4/ipv6_routes.json new file mode 100644 index 0000000000..33608b45aa --- /dev/null +++ b/tests/topotests/bfd-topo2/r4/ipv6_routes.json @@ -0,0 +1,63 @@ +{ + "2001:db8:4::/64": [ + { + "distance": 110, + "protocol": "ospf6", + "internalFlags": 0, + "metric": 10, + "internalStatus": 2, + "prefix": "2001:db8:4::/64", + "nexthops": [ + { + "active": true, + "directlyConnected": true, + "flags": 1, + "interfaceIndex": 2, + "interfaceName": "r4-eth0" + } + ] + }, + { + "distance": 0, + "protocol": "connected", + "internalFlags": 8, + "metric": 0, + "selected": true, + "installed": true, + "prefix": "2001:db8:4::/64", + "internalStatus": 32, + "nexthops": [ + { + "directlyConnected": true, + "interfaceName": "r4-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true + } + ] + } + ], + "2001:db8:1::/64": [ + { + "distance": 110, + "protocol": "ospf6", + "internalFlags": 8, + "metric": 10, + "selected": true, + "installed": true, + "prefix": "2001:db8:1::/64", + "internalStatus": 34, + "nexthops": [ + { + "interfaceName": "r4-eth0", + "interfaceIndex": 2, + "fib": true, + "flags": 3, + "active": true, + "afi": "ipv6" + } + ] + } + ] +} diff --git a/tests/topotests/bfd-topo2/r4/ospf6d.conf b/tests/topotests/bfd-topo2/r4/ospf6d.conf new file mode 100644 index 0000000000..756597d6f8 --- /dev/null +++ b/tests/topotests/bfd-topo2/r4/ospf6d.conf @@ -0,0 +1,8 @@ +interface r4-eth0 + ipv6 ospf6 bfd +! +router ospf6 + ospf6 router-id 10.254.254.4 + redistribute connected + interface r4-eth0 area 0.0.0.1 +! diff --git a/tests/topotests/bfd-topo2/r4/peers.json b/tests/topotests/bfd-topo2/r4/peers.json new file mode 100644 index 0000000000..83101eb47f --- /dev/null +++ b/tests/topotests/bfd-topo2/r4/peers.json @@ -0,0 +1,29 @@ +[ + { + "multihop":true, + "peer":"2001:db8:1::1", + "local":"2001:db8:4::1", + "status":"up", + "diagnostic":"ok", + "remote-diagnostic":"ok", + "receive-interval":300, + "transmit-interval":300, + "echo-interval":0, + "remote-receive-interval":300, + "remote-transmit-interval":300, + "remote-echo-interval":50 + }, + { + "multihop":false, + "interface":"r4-eth0", + "status":"up", + "diagnostic":"ok", + "remote-diagnostic":"ok", + "receive-interval":300, + "transmit-interval":300, + "echo-interval":0, + "remote-receive-interval":300, + "remote-transmit-interval":300, + "remote-echo-interval":50 + } +] diff --git a/tests/topotests/bfd-topo2/r4/zebra.conf b/tests/topotests/bfd-topo2/r4/zebra.conf new file mode 100644 index 0000000000..e4f8fd8514 --- /dev/null +++ b/tests/topotests/bfd-topo2/r4/zebra.conf @@ -0,0 +1,6 @@ +interface lo + ip address 10.254.254.4/32 +! +interface r4-eth0 + ipv6 address 2001:db8:4::1/64 +! diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.dot b/tests/topotests/bfd-topo2/test_bfd_topo2.dot new file mode 100644 index 0000000000..6b68fb398f --- /dev/null +++ b/tests/topotests/bfd-topo2/test_bfd_topo2.dot @@ -0,0 +1,73 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph template { + label="bfd-topo2"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon + label="r2", + fillcolor="#f08080", + style=filled, + ]; + r3 [ + shape=doubleoctagon + label="r3", + fillcolor="#f08080", + style=filled, + ]; + r4 [ + shape=doubleoctagon + label="r4", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + sw1 [ + shape=oval, + label="sw1\n2001:db8:1::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n10.0.3.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw3 [ + shape=oval, + label="sw3\n2001:db8:4::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- sw1 [label="eth0"]; + r2 -- sw1 [label="eth0"]; + + r2 -- sw2 [label="eth1"]; + r3 -- sw2 [label="eth0"]; + + r2 -- sw3 [label="eth2"]; + r4 -- sw3 [label="eth0"]; +} diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.jpg b/tests/topotests/bfd-topo2/test_bfd_topo2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..35fe562a80b74baad7a922e7a1485326019149f8 GIT binary patch literal 24206 zcmc$_1yo$yvM#)^K!5}Z?oJ36EVw%a*PtOlkj6bo8VT+YAi-(e-7Po-cZZzw=cy=U)p&OP^k|9IoA9s##U@tFLN4%su=7uoYzFWdH;O06>7hfQLmu z5MES zl#-T_m6KP{(A3h_(S4(5YG(f4!qUpx*~Qh(-Q$C2z^A~V;E>R;xcJWriAi6+CPT7w za`W;F3X7_$YijH28ycHBySjUN`}zmIPfSit&&PXn{!6X}022uTK6ywufGBWv z^Bm%f{-;rr=HBgTADkIkZvH;qv~Fbvf0d^T?27HAvLhHPMv~+Em=SPgXp}jvY;8UQ%1 z80FrmT-L4s$Ts6DPTn4j?E#kkWE&<^FDaDivPgvKoty|E>Fb@8QdV?kWzj7Zm6@i_sDLFC^`m0y)+3n)B?_@UsbiT%gWe$=?$ zY)G@ky>DqgYY<-S#>Z9b>=Gry8fm=3!kdwW@urpK(07p!+32*&SjJ~z+SM?5LM z#GrfwpG2#mM;;h6Rcv<}>%-R0!mU5=XfI7eO0$EQ@=W$=1*!sI-!G1oUgu>u){@{e z3yPCR|5fp_fBnKh_A)yB0oZYBflm#oF^uQ0*J_8EE)T%_b-|B}_7A{g_E6Cs$*Bk6 zL}2m(h?=DAttWA2NvAql$?B5eRHG0N4b7>N$KCE9 z&0ey!?Nl{Y8cRk{Ove{XgWkpL8)KKRHza+usR6w;!vEM|x-XP*`10E*g6E9%YMA$% zQe}&JxXM3$9CF03ap>V55;n8YRt3)+r41B*o^pScEs<+sNm~iOBdI&%f_e{pO>Xr7 z^jZG(3sA_PHC*uL%Oc^Lrx^!Jvi9AF4*)y>GTx(kX24MOz^4nQ*E1W+=JDMWq*E?l z41!7ragy9>>5F&y?*i^29DCA^;J^5{ZuO}}Xw4hqT4I$Dmn)(~E=)%Q8Ntu!hz)%w zF<4oLN?HL79_XiVFC14SJINXAkCWOXCMUvw>xnI^rcy3EVLN#+TyiJa=CA+C$&Ooo zE=RCEgo@U+C4FweD+)TfWAwaomO@{(YJSfF>mpKQ*G-AAO*GVp*a@rD(vj3fO&Y-a z7Xu%Edb%~CB#Bp}4;hEaiax==C|X@bq37RBu(Mu`b{*5x+Ea8GbEy0FpiCXgn$7`% zNc8}05)<=;uoM7EZzwKH5nrgFTPG*@@kJdE1)(G@6X<9&?>Gi5* zU0!9JM9)Xj)I|~HeGM*&*!zxk%RJf0gY_40d(%`QYvXh$m2lt&_o@G%0hiqtvAx=n zy!}}Xm}JRnsLCUt%QGt4tk0@7PVRje*CP1yfhxF0Mp&+_h{-e^FPRuuE=`g)8?gjS z0&S1^yUpF3bz1@%TN#aYa^YV3h%Pc6oTx2C-!hInI;0&h?Y95k`HCYx*YR7A6-qBy z_hqT+CKHCSxb`JZvDA5{BHh!fG#SQAA4jhn%NPXg>$}Q`OXH~`{ELCgRl4t)y>Hsp z^rVI6zBF+gG?;yxV)^x}IQr9{PFfW$SQ-XBy@lD=0x*vfsW#eE?;?WjbqnNP0odtj z9o|KxjHiR=tTgIfLdx+i!XkL**Z#23%aCLe&LaQw*F$2reM5FCg(Z6`2?qNeYtx>o zr90tH`bO5t{??xNtBd6tUt-wiSX&{=tH)%O(Bc|313RVW>Yd$*K)$n%Hz@dIv)GG8 zHRrO}@6jPa?}H@r|2*8jJHwEcd-_~Jgc>wDluv1+W2C8 zpXqj6uHYY=V2Cadq)kK>;m<6m>Bx7=C*TV86#1!v4=Z0IE`hW(3d{t25YnEx%I#Zt zYen?pv7o}I*z*Wpp@5lY>odcb2q(dv){lT0n{P-Jgq^L{%_?6#|5(b%0=M%^J;Jrx zC%9z|Uybytp&aE?VKLl?ZBZ+KUD!XbM-oB`+fM0Dw)0OSk@YL3ZELj8z72r z7RvCnxI{&oaw&F>6JkAm9pKN<`~XZ46(cD{(oC|db8Cv@u4%q~%KW0*QIC9%j0H4s zE{sFomMXo!$2-fpy61!`yxfandRrhs^8i%6fa2-U+QPMMg4QWisVy!o$+KKrsV3a5 zMldpVM94?XH(IMYUAt(@CF3I_WXRSz&Z3O<)h`_@kAIkeG)})-JIsvpLq#70N2{di zBu$3=4);-6n7Z!Zlk2IA;zsVn*O)#KDzq4|o3xO?{Ri@p(gNrqa}VyqZW~KItZ&xT z=8d&>6`nR&*L)A|-lMPfVbkg*<pmjhq^5$omI_1(kny$P3lt7p zj>=B**jgye+IowYha5jy=(nlm15|k54zj=_IL1cPmP)q1aHt>Vc~~@LLCAS%rFj+RjzHem)vd`#p771^3(pE9W$= zv=j~-z6`KlRm_W@wd~i~+mgXGjdRr&j6aZnrr72gFc6zng zEE0qrK|6?VhNsD8xTuf+Y)Kl&=J4s7vtN9~t+wk?xhr{1k{bcXik?i$g17^rN3Xmx znw_v5q{~Te7Lr-r6m|0*qoE#cJJQUs3l-VyeSTK4AV*$u6O+6t3-5-;MA_zK?Msf! z5MLVc`+2;RedwkeO@-uf=6XQ%4S9PKAAq@=1KV&`g&B#k(S6KT z&5U2$%ix8wq<^dH5utyauURiA`BQe^P<|1mK3II%K`t+S;d#RnXBIc)!opS>Pdga< zfBVI6-}w81@Ll`?pnrc0`{uTKBjR~({{-BRPII5NMW}v98SQ&2rFCzUod8AD8@}G^ZLe(Y zu;*oxJIeZf>~E7@!;OgWVT)LaX1!u7yl-zzODQ;#J10B2KENYn^Vj|p%kG0rm*l~Pd`L6NN;`o}G8oCq{bQ5h%~%f|SeJIjjREsa@esqL9XD1G zj9>!F&c-}FV^c3f_vD9E>fG#$=e*@7SaYHe-F2L$!iFP=S=O}}8;D0mdK*bGy702);pmK9 zc^QbC`2lnzMD}|MoK8K{)lnWuuhZfyl;;DBYghZsXwO|$=%c1?H?<$>rfDa;@Gs$NWv2Qp{GUV`cFKJ|&JO@Bqi_3u`%J=WrSa0Y z$F=2O{-3BV?L#l#VtnPQ0bJn&KiF?J9O02{z1efU7N1~+^F%nMKga{ph?&*64sh*9 z%z_Mm4*UTh{&fDc5{=@Gd@SDIv<7#l(JaWpW?kL6)QQ`6~$%cJ=Ey$;Y6Qa(t1aDNdIhStOJel z{8O!IAx{XAO*ke<#m^nW-Dv5oGwgXL;y)RfY3^Og_91U0?cbTFKWkdqBbeuD27e%P z!rJi)Flfsc9!WA`NZJVJgGM4MKPrm(ISA)@h;BcDN2NBh1VL>%RM_Igs0G{zn@!O{ zJi?Eb?JwlbW@`uy_d?bczo?#}^WN1N-+A5d6`F%V1&bKr@`<_wy*dTL9pvJdLbLXw zf#ojDq3m~*EZS>}-ZxU4;crHrzHAeU6rZJUv^v+%zz9z1?~*i(hS%6}di*|+MUpAQ zQWDPM%CjTxy|lR?=>-=R^AWqZwLHe53Sk*AoHS-wm_1C`;sNL$e*n-%5*`3)-Uoo9 z`TU@%I{$Uw z5w-CzOCQ({RG2w)@=@B_ZAv6%RY-Tk2)U3 z&lz1XN&uxg;c%nojLW7 z>WepirrzAL+TSyNM^9dQJq-=do31UvX3I0610DcOj*AGdv%W^22{q|ABY(u6x1e;q z+UYV4wYp?OLETVCf-I2l53p;;y3_+;UM0*i(^#sfufG{AeI00m-_m?)Ub2WAQ+>(I zs7nXGA?hg~>qILqq_MWXwKi^H5ACPF7Bijtb90j&@qIB0$>Lps*?_aFTc|LR&$0~O z{U$9eh3XKtaJq-W!qwx9u7n)QqRd$q8Phd4Yvkf%(Mj2Ia(S;JO9_@sS6Pt|-CdD^ z(+98THpZe7hU;Q~EbCeEJR$9lTpKWZ$97OJO)xKb6r}1VS_Yu5mYN7K?LV99dav%k zRa|r@_q-5JJP=Q`@8rRGyczJF66Hz6uJMHi_;g!BcZ$>Dtun!E?g|`En0M4*bQSgvCsd>v6FaaPULng84V4- z_d9z4S`EF`WRaOLIdU9n0;Qx8G@tq+jOj?dgVYFxP48(ZY!CThbY2RO4!V%&4=X#u zVhapk{mQ)@Jt>Ej0T-oB&x<(zV1HlojH2u9%`z1%DzT-NNHv73)_!vkZTfLa1Fo8< z__A*>Q_5O;CJDKds0dpzysnzD4V8OyiyvQt3$E%zB_r513N=^_a~;(8=nW_Lx4ua` z!=XqPdoeK9lCw!?+9>RanGF2k@nO_E`DpY2e9X_rYA)!^X!!)5G$U_cG!hoe4e}^6 zkOt#V(+%sc=a09fsMoh}+PjDC0j<$L1p$=+<&%$r z&iMD2^^9RW^xnD))KM0zux<_j16;Q(EX^YhH5=v0w|5mx;7&t*bE^0FN-^8gW63VZ zu>M(ji8Xk-Of<6bf_&dyz9C|vF7o847wurWzhUO5`pMBw&tt(dx~q}#rOQ&36Ik(j z{K2O=^B`MF)7)TfB{otcqcJPQ5owtd8?OJ;C9BBkftTK{gOgDFLTD^;<`6p?95{dN6KsbyU_8c(9pR2*hSc5yXNqi(Fy$p_)k_K`=`K= zdqAgiSxPZ_@&ItA4Nnoc9XmR6N}^*{H@`)XmmhP@z|YKZX?hhL*}Esb=qPa0n}4sj zalM!!zEb+{LP`_;e`^L-=uFllLdxbZ(hr3R*DZE=A75&Zw~^0v;3qc{k}T~Rk*{{E z#y732cps9FTJK)4W6bT?vyNHW^YHiG$Yi-JZYM2@cD98zAWhWKgz-_!nMBft;=Q1G zj-KfPJoV4ePk;ND1nBRRp}&3BQe0+Mo>Cy)$Iyp-U9bo=w)5fSD|S(Rq;p40LHPh= z5`29Cd}AMgKxdMl!56xBj%#unauvF{pmq*|dB9sbHa5xu)KaEn3`aOuos`E$;GJY( z8qRE*c0B+Wh?AlxxS}V8tQSv6CS1}NSb+wtEROHp2Xj}sF#-!y-%MA!OZ?tf`Gp?K3#$^z`cF^=-%tB?*V8sF z28_9#tK1<|)F9YvpVBX{WU~dXxkUX`S7s~QB(ASOZH~RlnBW+7_R|xgJXy~3!z_uW zpS~YNZEj25)(?g%hUT5K9@`Fp^!MH7xu5Kn?(XGNUE#;uuj|93vO!N20{5wwcXC?UUp$SU^3QuLE@q5yEbx+=$b4#UY zjmfg-Rv)ELc`jCpay|f)uSAd1rzb3LR?^DnSdUVisypSie+0>pYkfW|5%lL0Bl!ax z{q?NcG|ru}J9L$7n9$w*c7Ufz&~#5)5)LZ+g5iZMlsxbcI`Eoa4cy$Yf-f{qWiFR? z2`I$IZI@&(%@&A;UosN)I-rV7Pr_Fvj0-S#6hL%x|qn^H9ytZ-Iy1L|C+b{2R_@NtR0?(9)A*DftPy5d8TzJ*Ha2u zS}fM!B|&u}np;z$CUB8(*N-!n6I1ZTBf1 z)?$x|8CE2f_VHxFc^<`_>Z&J=n*H7W2BuVOM6nU4Q7;S$4O{JTR<7N32!_G-c1eyZ zHW9JI&u|+ThI-^o0tQCJvv2MtZ|!>{AIuweMiTtBi)CL&pVW`r44{S;P|WtQo^}=1=Bl$`k*>{X zDHD7EDjH1>XTDlM=B^zxjAxG*Rj23B7A`e!zy6R#HWd_y?QNwraw8ZCKhrpMDRf`= zXdBEeeiR_3GjitwN+jbr-irS0zHAs*1bIOds6_-|0?g6VFq++00zz``d}VZh0M-c^5xG^TZp{Rh9}n}St?XSvxK?K@v9!mmjR2>gX z&U0A1Dy*H99Ev{#qIhoN2+_5Sv=v^dZam!nOb|+~wFJ+oSvvsCi1;Z@7|Cq@G#ii7 zD;QtA`ovG{5ffxtnyMgKRe36GPh1D_%`sGQI7mTd$_3|nE1W(V-!-?eGE471PH2}^ z*xUCz`5D4J%*pDm(Vo`PK3$e0j)(ht`?*|z+myOQG;<*laq*RiKy`fgD-w~6pWoRJ z7S@^P4z|+S6h6_u?J!PZaRR;}M~t_1?73d(p#C@}?Rymtq731oX2|8anDN)DGmmIU zNWe=VRgHOsM3&(>cS?R7a$s{@`-Iyn)ZYA=;+A1{wKBf@D`H)=TfdlPLDdC?`$zG1 z%gS+K`MJjADza7WmLy2dh_By$ENm3-xOrcuVU_=0!CeO~l{%3QPl<=-aKWqUtYz?f zkS;>5)-wJWIe`m|8a9h5NHIMzE=INzzMkdk&29UB_Lkj1i}B!SKI+HQa*PYt%iFGo zvbgHnG%V#)6u;`J((cMlftU0~jO4^bP9=gk20x}+!S(VL?r;Lx@*ZR=A~*h4Z;t+$+q#73-MlbyVN{E=<3WL{@mS>Ff*fW%$42 zMcP;_R zw9Fvdh&V6RN6`Oll~5BS%lUJ3ZD@{^n0 z6E8R}DdY@-i`33;dN+cMk*xHq7}bDx_hO^+Q!!c=2LK*6#|@tRdsAmN);*QPh{WxZ z0$CkF(?;#NGi&70%eG^D#qH1lGqZGv@1Dzrj_6vcr;qxE=A`{bC=V-}Bjz@?loRuF zGgss|1k@}>WC|shKQYn&0L12u4?vB-5f#@dbn3zIy&N}&3zxn3` z!kL+2PamhI2jDKc4f_G`JbwVB#!zuyeQCN1ypwj#zn1NG)BBuks{bLmb!tM9ow}uA zMxLmmpOKGZS;-b`U417rejF8BN}r=ARngM-I<=^o^Cc?!ht7;K*K%1%R6Pv--(Otn zp_6yfloK_}633kauA6$=+2k{kq|VZ|mg`<(W|ASqa1Fa@s@A|-N`E2E-ki5@|8+_Jea&f^olZ=h zAlXNgU@nYCi>&jdHa!=70>^7zZberld46t*FuBj&=RFuDu_k^fiqh4{6s`MHpr}(E z5u#H(3T82I^|o~N^fwsZ=uti#vl39Z&)YlzPZ)yIqC{*tT#qrX!}e89qC*a9nYerF z&Uw5Fa}tdtKRA}eahSv?I|w%=FTkcPt|PNo$!YZzepX(7N^muRDXBZOxjz-3U6j2|~972b*o)5{vO6QCTGKvmG6lu$ncs zG=#0Ja5QcubpCEbKy1`lH#F|H_t@lE6!usNDjn{2%Jp&fh~A5DB+c6i}q`?g_XEsPL0 znD!~k@2p57H6!(7Tf**V)#*v&nHl7R}~DbaNe%S+zNQY)(T zm;Hnu5s^bk&u=p~$s%Soe%y=f-`aP7q-v~BoOcCe{X&KD=s0yKeM$-krX4m5j@@TOkq`;SoC{79GK9J68iFd3R&0xA`Jnza-jw9 zT?BooO-%8D=v(TgZHJdz*Ad=GNvJ`VmB=cFhR*6XBPX5WnKskWcqXlGz<0DOv?tK% z_FyQ65~uKsZ5(@&)=9D97koOjj>x_$>RjI#!!9hT6+s@EA@BIcXrjd)p~y>2-W-F^ zQOltVtD7D<&dcRpgNl+_`;bE+F}7sNgTgDcz=0(9rQI5sw~p5ODADsa*Z>&Aqv!!p z>1;VR%@w3uzH6y8PRcuQ-Q70|kS1rnw@KO|x4*Yr-BX{iH=A-v0S(yXRegvNozElk z=-450y$(FlFC>7M}VR<;5d2hta>taX6zwrQvaUa5u&hY5(8x* zfFpX9!z&dBfoXOeYuetn$L#@9@==9WES#fx3fn7d3UXzpHrSdm`It|!ObwwXpcR7J znfGBg#5t2tFUN2niB-hkTxGDV4}D|MU7l)&)a%Yd>r)fLSZ}-y?t{1%+OHeKVn{!{>?5-7WL%v@Sp|XV>bC? zzRlQ*LBC02r+I9`mW6s@y|Y8tQGhm#@T=(wL57v1)d!HX4KaP#-h!MiZg&JK5-qY5 zCvznv5N7NP?)ZbG`+XJ)Uq^|&@9UOosjO;lyG04i?VhP~$HJVD-8RUY>zA}6J@@_4 z!*XM7aP6j~uXs||YIacb9NG_P6jN+*r zXy2G5pvy&Z63cZUd%i2&Ti8y@(!0;sYWJU@amdpFDlgQgqbmkVkk+xV_gC42UF<6t zGJb{ZqmTOwt0SD(*B$!%GVcl`U%xoHb~k9zy%@{AD3#cL%@l(9g*+Nz%!TooO)x+k zE4&;!@$Mw*iycG=Y;F7~Xv{00bPK+)_=+wR9Ep(WT3=33;#dcBNpg!x`zk2&RyjJn(+)dS!M zMUBFD6)wG77!5q4t(eLYEMr}wtXj#qvCKZIzXgq!d1}F#;a4}c-N~-YEy;G( zh}*UzKO*N~H!pt|DXhR`6wi@9{@wFFRmb|p%)5Gt1g}1ipU>(T`~?C2r3L!$TcYy@ zXrxKyX^UtgsyV(PO(g@a_ydOCQsdgP0Sfx9c5BM$ReuM`tG5c#(Jk^`582m zisRHm@7+L+zR=DDF)%@{}{hG0u&QE!cd9n{)yx4%x0g2i= zn5Yj{-9@6ga%w%)euKx8D@``U|5eOmu$u|i+!4=v@3r@`9Tr%Z-i|Hd=(=W)Bfh7- zz#j~gbQ8@rfJD6~JMjBRf3552>gD)ux##fnnCYG&a1R2hoKgfAo8AiQRx~qa`friJ z#AeLRS3T?{r#f!kVoe=XPUY=#+lAg|y!qX@UK&#Lyx!d&G{_U$X@T%h$`1HGXzjyz!Wf_MEwX8*72)CiE0@ASo@~sk_ z68GziL%sc8Tj;m}##q$t@whn*m*l-Ef1ySz=Yy}q(l>`W`Fs`9$bKz%Cs~4NNkJBe z7Ol8!mf~^~5@crI%{UW%EpfzSoY8%=wVjt=nu@%zaF0&Cv~hnassL0Mcx*^lH+eC? zVVHJB*|*4(v4{n)&~B+*}X<(b-JA%@PfNtk8&oi=lmv7imYwgFS0sM@TojMX& z@+C=xh#89{;?tSPU|DT4cyn{u7{r&a-?de?^BH|~7(K6mK6c{5$`ZmHeLoqk+v=5y zH_1Ul!kEBIbCVeHewwciRIet&V~KqWaUXNk+k5|v&`F5=INPO{EdImmYi%`V)&@MnL`#D$y+aa!`xTVaP>Rmz^C>TA!-+ce|u zh2b?(PriJD$_(3zK)#!Jg`IRWcb%rRpyZU}a@$gkvfV9B%EGdb#-SqEk>6!YyIi_z zDYC@+yinHs{(0HQRVd4&JK3 zlm9pS{(4`#k@4%~Waj~>FC2wUmdqLV#$3l8>%9^{jyKSkw#Hr=Lbi-J>^q89|0ybN z$cpFua{ImIsc3}h1Mp@o@`b%e?R(>UbP|u#q!5jJ_W%a_o2w}k@I8jD@o%RX%KIno zqR@_e$HLdt+E8h?e)-*!1Ip(6u~rz*87p;i@=i8uZw@vx!@@SOL)9oN8pD%sz+{_0-;=3y!$a6!*HYvxh9@REsCT||!f%E!=5u_z5g`x`RC7FXedp<83U2Q97fcwy?2ZShvE= zrE%M6wy<%Q(;U9hFC&N>v%<{&jTEf2YaX>2x55k~S}!i^I391B3v1=Z*zWc{zMj^n z1U#HZh~CBZ9YSzIV9V60@CC|Tf6MqAx*rZ6Iv7k<=?VOGueS-!i~ zT$IRe4#;3HGk|I335jo5{_=Sy@x@cNP$3^0R8x@sHJFR5FG5I>^5y|}bVPY^SR?~q zD=0M!3D@z|9Kmbt*m|bLKCu>R@M7%O(OsSA*fb(l#OZv#gn4F2asq9f5yv zqVP<}(mBgiN$u@)QGec~>}>>v>w7gs=)9EXwkVSG^SgUul7X^|{e9BP|EFAPYSJVd z3GlHX-{ekna+{KW=RyYwe>I}U`-6L;=V8?YFeq4a%hM~29D@D~Dh@3*_B5 z>lW{E#nn0D%pyB8T`G$%;HRz-lH@=(y6ewD>H)Es+2$n{_g`cOuj@9B^(&>xaOhNf zD|>xkKrm5|GLdRUa;wNvi1E}qaCMv41(o1q4w=6lt(62dt8v8WYOjnjcQf33|Spd8M^95TR zKU-55-UP)7;c7s|Lmb{A?6Z_m^vBB;|zJG_47<|8jz|U^Nt8~JK z=?gH9fkLwPjvXyXHxB&V_MAZ4Z0*~UxGHL8mbD;7q?Uax^Ak>(b%{d*c^~(%g@$}P{> zD&yNlSKm$LO7#=HxSs#;Eb6O}x+k;0!leMcxhrN4XYB7)Jh8%?kf&zl=>%+mY`lkz zhCDvC>9e3NWjD!6QCxK;^IJ$56XqZ0-PL@Om%=mOR*k!x9Qptx4GZ6W#k!qagGD@1 zL=6>^Tw6^ttcT4__T9D5b=7(FmBd812v5R(m3lJe@i0WT{&PclvHW3rCFw(s@j#ge z$i_Xw-B35aj&yAaXWZ<<@q!zZR-9}lt9Y1wptomRS-@XqIliAV`guX#UkGh|H!C(?R;$?AiQ%#&5m8Oy zCw3%Hg#h1Qs|Pk znimOTz>Zq+4uDHdivcYi1nGMTy42VD^HGU^ilRp^687CyA6H!-`kP^({Y`BpScLHG z&MpDJC)tqb4ob+WCsj3!r^|1yjZES8GoV9AN91PfqOOUp-eR5BIcLC|wd|9sOlCHR zCTk-vGot3pjdG$a>sKXZ?ofqeok{Lr8~#^nHFe3xP{(0`Y|*i2!;VewvrCqgO0Aqg z?vZY6?+CbRu#q-7MEMYfc$ee($?;5yOCJDiUH!V?5ARqf_O8^T2Poe8oBK3N){~*^ zIr?(+Sqm7jmVO;m({dRUJve+Z(JwdQla3eeu2DN;O#3>nwa?~JnzDQZ~nseow`0G@;t)yA7KfO3}%tw-A|FDluPeqv+(D4JP(6I zT-LnuzZ>%6#gZ!wJc}yW`=Ct`RJETmZEIHpI$yWN<(zdaxOIiNw0&|VdH~YHIJKHC zcdX-C6&rV^v}^@ni&~SmwHQoNb+a5Lm3%OITADD(h{Za~goqy~r}rR0r!A~kM#G;* zFkMWfAfi1|h0F?59#5{2Z5)Ik~bV6EU)8e`uVVG(H^)o(6*zE~;hrIUTw}-hrKPke52bg${R9 zUcJe>p{VkdcJKPC>Kk<75_?jyeqQp$uk}wI)AjAFT@S)3l7 z+r0wJo_||&jE@LNb;}dvs)95YN8=b6?_DNq2hFV5%z*8@!arL`g~Z_5s^=s!PQ85! z6^Sle26-Z15nP@yWZSbOPIS?IlBvq-_~pw;-bcRU$tq>91-d1IVo2K4#r0w^2M1nO zypY7CEWl4&Gkou3-&yBbx-N@XP0Ljxc4)vsX2Do1=dG9nHe0lQckEg^-i`9k?SqQY z3xtMrEWi!EK>`tj5^G_;^fd8J*>?N4#^epVUBECCyQtWg?}vuT$w&&a-fPP!a8>oC z8*7|XgJ85b^u`wy7T+Uq(Dv+9BpXyLHeof}Y?5@~C7V$D*s#Q@1OrSU*Fkh~#3Ce_ zXH7V4f-=AhB8urf6*5n{9c%ywj~emd+!J-HC{7#A7%hC?!sX-RvctD5#IPY%!VYA_ zH~Lw?Y1m|aXjXj`W4ipjCK8LEq-f&;Fgk|5!QyRPXl%$7e(<#O>R@75f|pRW>@at} z-qi2h=NrdLQ_oZ>sg@7N`{8v7M$5}|>{O&w(*kHt9jv|d)5T<^T^Kw@Sg5tnKwCvs z{by)R=oBgE=TjV9mk0QM=9}nb7){cW#CoMZ;YM;l<2~wKUP(P2CC+3Wn}Afavk%4S zVi11>&1($$w4aTV&i#OM-Do$lx{e-=wUM?Z+$pVWXxX28wpZkv6oWK^aHNRkkzyOt zTM>E)W;!N*8cRFF*iSLrD8|a{Y^mjs)d>^%Rs|&rwo=H0Db>Y}^%KvCZ6UE07@4Ng zj$*=(|A@rjPtL*ScT(*Y;o-LGgNL_*EaO$Zo8Xpm3h;8-QG?2p^2_pQD7mtTt;?YC z!PduNu8KG@(Pa!Gk}H$?GA(B?l(C;h_mvM^N-4X@FODfk)_;)e0|i2!6f_p zao3^tOeYs4IUF_7IYzP{#|s85XPFs<@9LeeHHcXpb2#YKXmTvGv^3uW0tm_lKa!ch zzRx}G8Mcq88g}P_p$yHEy2~LR0)biv2z`hF>xQ(q42v3sUZr+XRLsw+zkgU$ zebRm6fmG{=>ydAm)cKKd%GTAAL`mSvhVwq!@~ke4xi(76&whP?h?XL--gs6#=R#1| zn=7w_AfALa0}=w(Z9n97cyjnfG%!eEjB&?vo9l%dGF=FV{4` zI&cuNZ+Ij)IbF$Ge(x@b!7S(_GQzB=+wIW(vN#o%UwBox2ien(ENc5w{r;5tS&f$p znli!&$CT#`r$?gI9q3UsGMbIig4L6bk)N@|;uwpTOX9-)BB`Zwy1UOyW@l^qdvlC_ zA}ImOcagW1_3rsX&b?Ou(sRT}Ty&@j!&7u;7P{n{Cw_$Szc#YnOv!05=QF_*{~W_l z8oED5ru6_2UI!UtS?chujq(qRT9IU}QGbQt zg6VklLcvyFLZj(7WW!`;?i#*NI>m)`va!}GvezFRRLcyK#=_28K0E+!wIJp$(0%d7 zy{txbiXrFhEx&Q~>jSzNtSgCLtVY^ez9UU{!KUYslCgDfyH(IBR^Ua_HflO(m+*E) zA~F-sIc#df8Q!olctwG%d=A=DEjj< zu=tEC>Ak)FBovMH-78$F%KNmh^{9qR@ll>`cnD)^2DYPNP{sh=Y3^%QW5o#u%iJij z72Do#n1MuOY@CiU&Qa4d`pc58=J-oWU(6%qN?`-UsAt)^9mRs!)&fp@OxU+dJuNZq zU&$)?FiZUf{n0vvu%*?FF?Kg3S|-f6TgPo#3syldqn>Zry<8W~dS~eqN9{Lr#8IV(TY`9SaQSYUNF+=9^3hfJW z%q{BcUyc7bt%&(Rk&Q~Jv9H_I?*FK=XrO>M)LYu}C`-ysCmi?14e;z&yvE$#P5B+Y zZO-z2&^oP+g+-0FhK&;-&)LU6(DBQ;=2YiSx>S1Y5Pe@Gk&7`dlkV-0<~YPMp8-6# zx8+_0HH&B$t*=&kndoDw#oEk<8<(!$3l9jzA8Qw~~7pC^|ojF z_^Vd@$4#PZjJE>;`^n!^x_R{&2i7CmZ26vwEIzfUvG>{I%s6@3uAw^ql$9Js(%q@f zEpDmBslT%DT}-c;+a)?bL%4o3Xy3J=rXg&d@U}{7?ejfaVUawa5@8SS-bd=lt&{o? zlctO-MV_ss1e6v-x#jqQUKO&`r!QZWBnkv2K|JESDy^>r^w%-i*WN03W!K0 zIV{LqUjBB@U*amPD0kYE+ZO8?bm=HutwvPYeTKX6aOv!vE1Ho0ljCE% z8C2|n$MM@w7+!IIG?pF_M~c{PMX;~8E;qT<&#J;1w-jDLti5D)bdHA< zGX1FmD(YM)q+^)d=S+}flN2XQ-`R^)<480M`^D1jcnrh03lq>KZBUbwgLiZx3@}uf z|F3q=JE*CxUE@Kq3#bT6k%*y5Riq0 z$XnI!Md~%aaV>mUTDg#~$?S)i=r*qco@gH}D_kh92EcXbZMi-JxD}U+hqcSZ&D7|t zwk50I3cS_QlC^kd4pQQSDmn9e(q{>6SK_-zU|O7A8sDQe2E_53^zM0iB}*z*xUnhC zm2;!vd`rXL@%6|dZLj6Xod>k_Cwp^gICEzhu5`Ct#U1C36(G*__)ah3=e*Rm$5L(r zJK&t#lq5JI;XcmAtO*y*m4Q;F@ku=S3yahp$Ljyhpe4C~Yek{&xPX+BR|P-yO%~WK zL#A{X>oZ1m6jNO84r+4VuWOdp@7y+U;J+J8Zg8ZUng3u}yA}u3gk|TPh-i#=IQ-nh z`L$1(f}cO#YU+@IV3y{;I2?MwHaU>A@|8W#{J%CPe{FxX7`^Fmrvnn9fVYbldWQ`8 zR)RfFhdn*>_^~RNWwLLci`?INvKiB8&|4VEX$B)-`HHY-9+oHwuB&xC57Lm`)j^O# zsVx9#$Pt-n6BYi9bYO&AxMd22$;tTkxn|^X<+hG5_n!dEK>C;-KYu5teZ^(3L|8t4 z;R33NV|;8hhmkv)nZJ$w(TnE?Ki+-vKgHJWX>oZa>nYhrNEb7=u35p?Wo~B9@sjM_ zg$QtU@kO4;Q=1x;@*EW)mPKp*VGT}vh5ijDZBY(Hp6B0VW}4&hb&QN&TntD};IU2kY(a5G)minnf}=-K>;>vjv86;g|ksQ8eiH zQM0w&G|GC!Vtfc~&!j;Uk;+U@8BZ$&v(!0AZ+rS|A3!i0HU=RNic2A9&;a}v|Bf~Q z1~w4uRIv;(#mxC-?1a`XVt!MNGkI`1xSl7VQC*EQn@R5=Q_@A!O+2&;tL0YnB>mfE zOnPi3(vT1-u2xAMC<&gLI@8^h#7P*I}={(<#IHs7)b%kCzDv ziFQs)UQQ=!BQN%Zkzmi>Weg9X(2Lvpf`c#iA2#lP!JnvhZu9ip%niK>5O=uWIXuVr zdN;UJ9mRKU3|BMQyehsuBCJ2+abIah`1?UM|ER34qWMpS?D9mTb^h|-9JbeeqUoe& zf`p{p*45lLq_4>=2&sj_iy$FAR0?dIb$|k-8<6S8qLc2ozvv%(J-MC@p(`zRD>)`3 zPtATKSX8nm9VBU?NF+|(%{G0H+vs`P(PY$6i#42P+sw-gRgh!c8=0E9LwO_E;~v+u z^0|-*w|~t%T!`Sw`~1QPBI3&gdE0O%_gsY<;ymivP3L9GJeNI-mZu&Dl zHr4a-1E9_ceX@LucFT3x3r~tj%%0z7{9&80my2zPHlB#PH!^YlrCQfz!`o!`&Eg2^ zGlv{3@f@3txKf73dz`aQ44-lB1sT~zl;o(M_7+mfhyAQT7A7LoI@K&ONqL#$xjIMM z6LFtYnOmI1W20_Eu_Q%EFVAX6IOOJpKEZtiT5Ab~a-v*PFY07A+T8~3JZ|c5gPu7?O6lPZyg7Zlon0d+ ztIVHi!qG#wRIe3gX*Q-lXEstRhxX(@54~+*kgo{dQQOmzLNJnRtaizlZ}0(s1QSkX zCI=4j*h@V&YmX%S$W(;#J%v7$Rc$iEWrFF<>)SKJBsIOh#DXIcejwxXBtyJKOeS?bM6r5*2i5I}|H#u`; zP198E(KRAd8>D)S>k;UC3YelGuo@JScxWFMizbPPN*;l_K7O6GZfQR&7`!T#CU)S1 z>M^k!NuyEY%H_`aVpYtuI?k z2wWU*O@RF_PF=^v0zZ4VTV`l+->%d~o>rS2S1B&F?i#yej-IdStFTKW?>WA}7Z3=R ziBAG_-}omB>@u>+KXCB`kiyA!=Y6RA(C}h+vQN+D>3If|$VY2Msfvijq)U(mvvuno zhG3?tzA-)RChxD)Uv}Ixv{fi1(%#6&X3f%~>g4AJjy4Mn?yrmD`=!VT2Lwy`X&~?G z$D)qsJc|jn`z8Gj0MB%wFfP@<6puT=$}{i>$y;P3?<7!+*;7?gJ!4O@0cxAXAU^zw(m}5##SW;U7n#xHnr}5@u}XzT z2CKvO!{%BjrUhHYef*6xZR+GlipNUdCF)#t>P~*}h?(iYQ3ya#G@gge0EljPIy<+sbh95p_z5K)@_gAE;)(D(4SDrKs9R zo<@DF>_;`LAG#8!tq#v%KFKp=0$3E-QlkH=C#)8Jg)$qXF2ty23BW=317_UsUo(vW zWl>fsI_RCfes85$6@8ns7r-?N1bHh)d2Ws%AI7oSAQe=*3lQfyXD|!q4tJjxV;HPV z5G}T~BhRV|ygvf1#5Et@%$(AE*L?)Kl+5Ua9Nf?AAAc6Mzx*Kse9x)$cOvyrQp&_+ zXeeI`ulyCNWIR6$z9Az+?c{J&nWHs#-%w1;=L7o=_|im-C;vn`uO$rdM2*0H;!wk= z$dbrZvERu{0#P@S-CvwZ*TEHMuGciUASD-OX%{|Q(Tg7QH*(p1YwT#DQiWydujg~bA#Ny7QH_7-|I#7Tv_L{_^ajG%web=-QfZA!Qm$K ztx$)c8mzEY=@f+zOzlx`KIFap$F!273M~F>?o4wfuf{l-Y|@&%fsodM-XxTzczn$V z7rAGb3PPJ|{kIJCxK8)YPEi^#@3p6f`o|!5+jv$W@==;$!607 zriOW|-{yw=m52I5HPJGZSgX1o^K}WgTS0`Hr!+?%bUM>N;wy^N(2t>bQ zr5V#+*!AKPVt27CD2BHGBDufVx2h_mMN!57-NQ9(K8=v$4R!Vs+q3AThU*+|!_1)m z5^%mH#3)~{BsX!7rXvS*zmW3$2lQv>=QEy0YXD8*Ux|uew)Ol^rtR;~Wji@3n8+Y` zeq^>o{MNTtc%Xafv$I!Zcup*MaN7Df>35p;Ah6GK2^_L>#o)?_n|&CuZC_cdh5|*N z;dbOI1r|8Q#ut~n6Co+wNYCsmw<^SbhB}I9wB+jbmRr?C*x1XBj|}@lOa||1e2BPH zVvo>!OAM%}%&nX_J_x0JvDaQJ{J}$VUZOJS-1G7hde0fve%rx5_=K3axYV)m0q{-w z2wd(Es-D0ER!K2wPa7q>nzr65A(U*`UV>Z~9N2xl@@nQ#$T!BUsLxw+`m2OjQ@$ly8kJq2gl=VQ>< zve%AialSN}7p2xda2p$=^Lb1T52aHWZF&J*>IP zje!l@hPq~74i^lF!un}@biU9xaV&fNHCizV?Sv{QYIO35zn44zI_9mVEHZ7_6eZrU zu-^Tq3M**(YE4-7c`lcAjlVbxUi)sC@$90$)0^vSifNN)^fgkuv|M+g{Q~Tsdj3v!8M^%Q%p1v| zd{n+(7ksuiy(S z^%%e2*x%}n%cA|5?xAa_2MR#fe!&%(n;tknQQa_iq1`v3Wu zg?4l}0&N@u(M)v0!E;(~&k^Y7-Z1S5B(~FaqD(MjD?RxL1nnQ+-bFV=E@?q&=-kQ` z0G9{{!EpaP{Lg^>jYyvE)Yf_ig*?Frwi@|Y!$qgR^J%KcB9+fF{U~9hkQDp6KfADp zu$it(vs|U$u4-=lX;eu7XzpDa05?~*(j

r Date: Tue, 12 Mar 2019 16:42:04 -0400 Subject: [PATCH 060/142] doc: include fabricd in see-also programs Signed-off-by: Quentin Young --- doc/manpages/defines.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manpages/defines.rst b/doc/manpages/defines.rst index e1f7ec4ce8..cdf5e1967e 100644 --- a/doc/manpages/defines.rst +++ b/doc/manpages/defines.rst @@ -1,3 +1,3 @@ .. |synopsis-options| replace:: [-d|-t|-dt] [-C] [-f config-file] [-i pid-file] [-z zclient-path] [-u user] [-g group] [-A vty-addr] [-P vty-port] [-M module[:options]] [-N pathspace] [--vty_socket vty-path] [--moduledir module-path] .. |synopsis-options-hv| replace:: [-h] [-v] -.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), mtracebis(8) +.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), fabricd(8), mtracebis(8) From 1af62044d9cfa7267484b85625e77231a7829e30 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 12 Mar 2019 20:44:31 -0400 Subject: [PATCH 061/142] ospfd: When converting to ms divide by 1000 When converting to miliseconds divide by 1000 not the other way around. Signed-off-by: Donald Sharp --- ospfd/ospf_vty.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index bb22f211a7..2ab480e9d7 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3512,7 +3512,7 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, oi->output_cost); json_object_int_add( json_interface_sub, "transmitDelayMsecs", - 1000 / OSPF_IF_PARAM(oi, transmit_delay)); + OSPF_IF_PARAM(oi, transmit_delay) / 1000); json_object_string_add(json_interface_sub, "state", lookup_msg(ospf_ism_state_msg, oi->state, NULL)); @@ -3616,20 +3616,20 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, if (OSPF_IF_PARAM(oi, fast_hello) == 0) json_object_int_add( json_interface_sub, "timerMsecs", - 1000 / OSPF_IF_PARAM(oi, v_hello)); + OSPF_IF_PARAM(oi, v_hello) / 1000); else json_object_int_add( json_interface_sub, "timerMsecs", - 1000 / OSPF_IF_PARAM(oi, fast_hello)); + OSPF_IF_PARAM(oi, fast_hello) / 1000); json_object_int_add(json_interface_sub, "timerDeadMsecs", - 1000 / OSPF_IF_PARAM(oi, v_wait)); + OSPF_IF_PARAM(oi, v_wait) / 1000); json_object_int_add(json_interface_sub, "timerWaitMsecs", - 1000 / OSPF_IF_PARAM(oi, v_wait)); + OSPF_IF_PARAM(oi, v_wait) / 1000); json_object_int_add( json_interface_sub, "timerRetransmit", - 1000 / OSPF_IF_PARAM(oi, retransmit_interval)); + OSPF_IF_PARAM(oi, retransmit_interval) / 1000); } else { vty_out(vty, " Timer intervals configured,"); vty_out(vty, " Hello "); From 50ad4b42c1fcb08608c4b0ea4bc59566e97b6fe2 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Wed, 13 Mar 2019 15:25:46 -0400 Subject: [PATCH 062/142] ospfd: fix some json timer output Fix a few json output values: a few are in seconds, not msecs, and one is a number-per-second, not a duration. Signed-off-by: Mark Stapp --- ospfd/ospf_vty.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 2ab480e9d7..b5d8739fcb 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3029,13 +3029,13 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf, if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED) json_object_int_add( - json_vrf, "postStartEnabledMsecs", - ospf->stub_router_startup_time / 1000); + json_vrf, "postStartEnabledSecs", + ospf->stub_router_startup_time); if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) json_object_int_add( - json_vrf, "preShutdownEnabledMsecs", - ospf->stub_router_shutdown_time / 1000); + json_vrf, "preShutdownEnabledSecs", + ospf->stub_router_shutdown_time); } else { vty_out(vty, " Stub router advertisement is configured\n"); @@ -3511,8 +3511,8 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "cost", oi->output_cost); json_object_int_add( - json_interface_sub, "transmitDelayMsecs", - OSPF_IF_PARAM(oi, transmit_delay) / 1000); + json_interface_sub, "transmitDelaySecs", + OSPF_IF_PARAM(oi, transmit_delay)); json_object_string_add(json_interface_sub, "state", lookup_msg(ospf_ism_state_msg, oi->state, NULL)); @@ -3616,20 +3616,20 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, if (OSPF_IF_PARAM(oi, fast_hello) == 0) json_object_int_add( json_interface_sub, "timerMsecs", - OSPF_IF_PARAM(oi, v_hello) / 1000); + OSPF_IF_PARAM(oi, v_hello) * 1000); else json_object_int_add( json_interface_sub, "timerMsecs", - OSPF_IF_PARAM(oi, fast_hello) / 1000); + 1000 / OSPF_IF_PARAM(oi, fast_hello)); json_object_int_add(json_interface_sub, - "timerDeadMsecs", - OSPF_IF_PARAM(oi, v_wait) / 1000); + "timerDeadSecs", + OSPF_IF_PARAM(oi, v_wait)); json_object_int_add(json_interface_sub, - "timerWaitMsecs", - OSPF_IF_PARAM(oi, v_wait) / 1000); + "timerWaitSecs", + OSPF_IF_PARAM(oi, v_wait)); json_object_int_add( - json_interface_sub, "timerRetransmit", - OSPF_IF_PARAM(oi, retransmit_interval) / 1000); + json_interface_sub, "timerRetransmitSecs", + OSPF_IF_PARAM(oi, retransmit_interval)); } else { vty_out(vty, " Timer intervals configured,"); vty_out(vty, " Hello "); From 2f04c4f033a5efce6f9cb3b4bbeec40ba2292785 Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Fri, 8 Mar 2019 15:34:09 -0800 Subject: [PATCH 063/142] bgp: fix misc evpn prefix match problems caused by using incorrect prefixlen The evpn route prefix len was being hardcoded to 224 bits while the length of a mac-ip addr is actually 288. Because of this many problems were seen in the evpn-tests. The sample below is from a test that does a vm-move to verify extended-evpn-mac-mobility - IP1-M1 => IP2->M1. You can see two local neighs but only one was inserted into the per-vni route table. root@TORC11:~# net show evpn arp vni 1001 |grep "2001:fee1:0:1::10\|2001:fee1:0:1::11" 2001:fee1:0:1::10 local active 00:54:6f:7c:74:64 2001:fee1:0:1::11 local active 00:54:6f:7c:74:64 root@TORC11:~# net show bgp l2vpn evpn route vni 1001 |grep "2001:fee1:0:1::10\|2001:fee1:0:1::11" *> [2]:[0]:[48]:[00:54:6f:7c:74:64]:[128]:[2001:fee1:0:1::11] root@TORC11:~# Similarly other traffic loss problems were seen because of one prefix updating another prefix's route. I think the 224-bits came from the packet format definition of type-2 routes. However the way FRR maintains the key is very different than the format in the packet so it seems best to just sizeof the addr. Signed-off-by: Anuradha Karuppiah --- bgpd/bgp_evpn_private.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index c7f2671b78..785139865e 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -30,8 +30,9 @@ #define RT_ADDRSTRLEN 28 -/* EVPN prefix lengths. This reprsent the sizeof struct prefix_evpn */ -#define EVPN_ROUTE_PREFIXLEN 224 +/* EVPN prefix lengths. This represents the sizeof struct evpn_addr + * in bits */ +#define EVPN_ROUTE_PREFIXLEN (sizeof(struct evpn_addr) * 8) /* EVPN route types. */ typedef enum { From 7e20406f0345c2f152a66b20a31044a9d4c59e7c Mon Sep 17 00:00:00 2001 From: Don Slice Date: Wed, 13 Mar 2019 17:41:40 +0000 Subject: [PATCH 064/142] Revert "bgpd: fix updating redist bitmask when vrf_id changes" This reverts commit 48c74f88259c8f706035d6fc80765f4a6f6594f7. --- bgpd/bgp_zebra.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 5f0b20e029..4285955034 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1829,9 +1829,8 @@ void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if ((old_vrf_id == VRF_UNKNOWN) - || vrf_bitmap_check(zclient->redist[afi][i], - old_vrf_id)) { + if (vrf_bitmap_check(zclient->redist[afi][i], + old_vrf_id)) { vrf_bitmap_unset(zclient->redist[afi][i], old_vrf_id); vrf_bitmap_set(zclient->redist[afi][i], From fc2408ec18117e34aed8aec1559019732eeefdc7 Mon Sep 17 00:00:00 2001 From: Don Slice Date: Wed, 13 Mar 2019 18:41:29 +0000 Subject: [PATCH 065/142] bgpd: move bgp_update_redist_vrf_bitmaps to bgp_zebra.c for wider use beyond bgp_vty Signed-off-by: Don Slice --- bgpd/bgp_vty.c | 23 ----------------------- bgpd/bgp_zebra.c | 23 +++++++++++++++++++++++ bgpd/bgp_zebra.h | 1 + 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index b059ef2205..ff1b02d8e4 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2055,29 +2055,6 @@ DEFUN (no_bgp_graceful_restart_preserve_fw, return CMD_SUCCESS; } -static void bgp_redistribute_redo(struct bgp *bgp) -{ - afi_t afi; - int i; - struct list *red_list; - struct listnode *node; - struct bgp_redist *red; - - for (afi = AFI_IP; afi < AFI_MAX; afi++) { - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - - red_list = bgp->redist[afi][i]; - if (!red_list) - continue; - - for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) { - bgp_redistribute_resend(bgp, afi, i, - red->instance); - } - } - } -} - /* "bgp graceful-shutdown" configuration */ DEFUN (bgp_graceful_shutdown, bgp_graceful_shutdown_cmd, diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 4285955034..ca25a1d4c6 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1820,6 +1820,29 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, return CMD_SUCCESS; } +void bgp_redistribute_redo(struct bgp *bgp) +{ + afi_t afi; + int i; + struct list *red_list; + struct listnode *node; + struct bgp_redist *red; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { + + red_list = bgp->redist[afi][i]; + if (!red_list) + continue; + + for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) { + bgp_redistribute_resend(bgp, afi, i, + red->instance); + } + } + } +} + /* Update redistribute vrf bitmap during triggers like restart networking or delete/add VRFs */ void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id) diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index fc19c5e17f..b912870b80 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -49,6 +49,7 @@ extern void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer); extern void bgp_zebra_instance_register(struct bgp *); extern void bgp_zebra_instance_deregister(struct bgp *); +extern void bgp_redistribute_redo(struct bgp *bgp); extern struct bgp_redist *bgp_redist_lookup(struct bgp *, afi_t, uint8_t, unsigned short); extern struct bgp_redist *bgp_redist_add(struct bgp *, afi_t, uint8_t, From 401d56cc5238173ba24bf8460821710bd745ca9e Mon Sep 17 00:00:00 2001 From: Don Slice Date: Thu, 14 Mar 2019 15:17:47 +0000 Subject: [PATCH 066/142] bgpd: fix redistribution into vrf when networking is restarted Found that previous fix for this issue caused collatoral damage and reverted that fix. This fix clears the vrf_bitmaps when the vrf is disabled/deleted and then re-applies the redist config when the vrf is re-enabled. Ticket: CM-24231 Signed-off-by: Don Slice --- bgpd/bgp_main.c | 8 ++++---- bgpd/bgp_zebra.c | 11 ++++------- bgpd/bgpd.h | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 47e7c1686f..ac579b1bf0 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -281,9 +281,9 @@ static int bgp_vrf_enable(struct vrf *vrf) bgp_vrf_link(bgp, vrf); bgp_handle_socket(bgp, vrf, old_vrf_id, true); - /* Update any redistribute vrf bitmaps if the vrf_id changed */ + /* Update any redistribution if vrf_id changed */ if (old_vrf_id != bgp->vrf_id) - bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id); + bgp_redistribute_redo(bgp); bgp_instance_up(bgp); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); @@ -330,9 +330,9 @@ static int bgp_vrf_disable(struct vrf *vrf) /* We have instance configured, unlink from VRF and make it * "down". */ bgp_vrf_unlink(bgp, vrf); - /* Update any redistribute vrf bitmaps if the vrf_id changed */ + /* Delete any redistribute vrf bitmaps if the vrf_id changed */ if (old_vrf_id != bgp->vrf_id) - bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id); + bgp_unset_redist_vrf_bitmaps(bgp, old_vrf_id); bgp_instance_down(bgp); } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index ca25a1d4c6..d9749863ec 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1843,9 +1843,9 @@ void bgp_redistribute_redo(struct bgp *bgp) } } -/* Update redistribute vrf bitmap during triggers like - restart networking or delete/add VRFs */ -void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id) +/* Unset redistribute vrf bitmap during triggers like + restart networking or delete VRFs */ +void bgp_unset_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id) { int i; afi_t afi; @@ -1853,12 +1853,9 @@ void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (vrf_bitmap_check(zclient->redist[afi][i], - old_vrf_id)) { + old_vrf_id)) vrf_bitmap_unset(zclient->redist[afi][i], old_vrf_id); - vrf_bitmap_set(zclient->redist[afi][i], - bgp->vrf_id); - } return; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 9ca09101e9..66fe6a6f4e 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1904,7 +1904,7 @@ static inline void bgp_vrf_unlink(struct bgp *bgp, struct vrf *vrf) bgp->vrf_id = VRF_UNKNOWN; } -extern void bgp_update_redist_vrf_bitmaps(struct bgp *, vrf_id_t); +extern void bgp_unset_redist_vrf_bitmaps(struct bgp *, vrf_id_t); /* For benefit of rfapi */ extern struct peer *peer_new(struct bgp *bgp); From 9165c5f5ff9586e4688b3cbac265d3593f1231cc Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Thu, 14 Mar 2019 18:41:15 +0000 Subject: [PATCH 067/142] *: remove trailing newlines from zlog messages Zlog puts its own newlines on, and doing this makes logs look nasty. Signed-off-by: Quentin Young --- bgpd/bgp_addpath.c | 2 +- bgpd/bgp_mplsvpn.c | 2 +- eigrpd/eigrp_fsm.c | 8 ++++---- isisd/isis_pdu.c | 6 +++--- lib/vrf.c | 2 +- lib/zclient.c | 8 ++++---- ospf6d/ospf6_area.c | 6 +++--- ospf6d/ospf6_asbr.c | 2 +- ospf6d/ospf6_spf.c | 2 +- ospfd/ospf_api.c | 6 +++--- ospfd/ospf_apiserver.c | 4 ++-- ospfd/ospf_ri.c | 6 +++--- ospfd/ospf_snmp.c | 2 +- ospfd/ospf_spf.c | 4 ++-- ospfd/ospf_sr.c | 2 +- pimd/pim_register.c | 2 +- ripngd/ripng_interface.c | 4 ++-- zebra/irdp_main.c | 2 +- zebra/irdp_packet.c | 4 ++-- zebra/kernel_netlink.c | 2 +- zebra/kernel_socket.c | 2 +- zebra/rt_netlink.c | 2 +- zebra/zebra_ptm.c | 4 ++-- zebra/zebra_rnh.c | 6 +++--- 24 files changed, 45 insertions(+), 45 deletions(-) diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c index c7fd1ba0e2..63373cb9a7 100644 --- a/bgpd/bgp_addpath.c +++ b/bgpd/bgp_addpath.c @@ -384,7 +384,7 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, } } - zlog_info("Resetting peer %s%s due to change in addpath config\n", + zlog_info("Resetting peer %s%s due to change in addpath config", CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) ? "group " : "", peer->host); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 765170d1a5..446d094c94 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -995,7 +995,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */ == bgp_vrf) { /* delete route */ if (debug) - zlog_debug("%s: deleting it\n", + zlog_debug("%s: deleting it", __func__); bgp_aggregate_decrement(bgp_vpn, &bn->p, bpi, afi, safi); diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c index 22f5a5ddb1..4d6d73e202 100644 --- a/eigrpd/eigrp_fsm.c +++ b/eigrpd/eigrp_fsm.c @@ -314,7 +314,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) if (prefix->rij->count) return EIGRP_FSM_KEEP_STATE; - zlog_info("All reply received\n"); + zlog_info("All reply received"); if (head->reported_distance < prefix->fdistance) { return EIGRP_FSM_EVENT_LR_FCS; } @@ -344,7 +344,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } else if (prefix->rij->count) { return EIGRP_FSM_KEEP_STATE; } else { - zlog_info("All reply received\n"); + zlog_info("All reply received"); return EIGRP_FSM_EVENT_LR; } } else if (msg->packet_type == EIGRP_OPC_UPDATE @@ -366,7 +366,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) if (prefix->rij->count) { return EIGRP_FSM_KEEP_STATE; } else { - zlog_info("All reply received\n"); + zlog_info("All reply received"); if (head->reported_distance < prefix->fdistance) { return EIGRP_FSM_EVENT_LR_FCS; @@ -390,7 +390,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } else if (prefix->rij->count) { return EIGRP_FSM_KEEP_STATE; } else { - zlog_info("All reply received\n"); + zlog_info("All reply received"); return EIGRP_FSM_EVENT_LR; } } else if (msg->packet_type == EIGRP_OPC_UPDATE diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 107de47f3d..8e9302963d 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -131,7 +131,7 @@ static int process_p2p_hello(struct iih_info *iih) if (tw_adj) { if (tw_adj->state > ISIS_THREEWAY_DOWN) { if (isis->debugs & DEBUG_ADJ_PACKETS) { - zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d\n", + zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d", iih->circuit->area->area_tag, iih->circuit->interface->name, tw_adj->state); @@ -144,7 +144,7 @@ static int process_p2p_hello(struct iih_info *iih) || tw_adj->neighbor_circuit_id != (uint32_t) iih->circuit->idx)) { if (isis->debugs & DEBUG_ADJ_PACKETS) { - zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.\n", + zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.", iih->circuit->area->area_tag, iih->circuit->interface->name); } @@ -1523,7 +1523,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, } if (fabricd_initial_sync_is_complete(circuit->area) && resync_needed) - zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!\n"); + zlog_warn("OpenFabric: Needed to resync LSPDB using CSNP!"); retval = ISIS_OK; out: diff --git a/lib/vrf.c b/lib/vrf.c index df93bc33b9..ab47f242fd 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -662,7 +662,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname, "VRF %u is already configured with VRF %s\n", vrf->vrf_id, vrf->name); else - zlog_info("VRF %u is already configured with VRF %s\n", + zlog_info("VRF %u is already configured with VRF %s", vrf->vrf_id, vrf->name); return CMD_WARNING_CONFIG_FAILED; } diff --git a/lib/zclient.c b/lib/zclient.c index 9db1dd74f2..55f2393c56 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2504,7 +2504,7 @@ static int zclient_read(struct thread *thread) length -= ZEBRA_HEADER_SIZE; if (zclient_debug) - zlog_debug("zclient 0x%p command 0x%x VRF %u\n", + zlog_debug("zclient 0x%p command 0x%x VRF %u", (void *)zclient, command, vrf_id); switch (command) { @@ -2574,14 +2574,14 @@ static int zclient_read(struct thread *thread) break; case ZEBRA_NEXTHOP_UPDATE: if (zclient_debug) - zlog_debug("zclient rcvd nexthop update\n"); + zlog_debug("zclient rcvd nexthop update"); if (zclient->nexthop_update) (*zclient->nexthop_update)(command, zclient, length, vrf_id); break; case ZEBRA_IMPORT_CHECK_UPDATE: if (zclient_debug) - zlog_debug("zclient rcvd import check update\n"); + zlog_debug("zclient rcvd import check update"); if (zclient->import_check_update) (*zclient->import_check_update)(command, zclient, length, vrf_id); @@ -2608,7 +2608,7 @@ static int zclient_read(struct thread *thread) break; case ZEBRA_FEC_UPDATE: if (zclient_debug) - zlog_debug("zclient rcvd fec update\n"); + zlog_debug("zclient rcvd fec update"); if (zclient->fec_update) (*zclient->fec_update)(command, zclient, length); break; diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 76722aad10..484e5adae6 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -138,11 +138,11 @@ static void ospf6_area_stub_update(struct ospf6_area *area) if (IS_AREA_STUB(area)) { if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER)) - zlog_debug("Stubbing out area for if %s\n", area->name); + zlog_debug("Stubbing out area for if %s", area->name); OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E); } else if (IS_AREA_ENABLED(area)) { if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER)) - zlog_debug("Normal area for if %s\n", area->name); + zlog_debug("Normal area for if %s", area->name); OSPF6_OPT_SET(area->options, OSPF6_OPT_E); ospf6_asbr_send_externals_to_area(area); } @@ -450,7 +450,7 @@ DEFUN (area_range, range->path.u.cost_config = cost; - zlog_debug("%s: for prefix %s, flag = %x\n", __func__, + zlog_debug("%s: for prefix %s, flag = %x", __func__, argv[idx_ipv6_prefixlen]->arg, range->flag); if (range->rnode == NULL) { ospf6_route_add(range, oa->range_table); diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 3153c29aa1..2795bb9abd 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1006,7 +1006,7 @@ void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa) for (ALL_LSDB(oa->ospf6->lsdb, lsa)) { if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) { - zlog_debug("%s: Flooding AS-External LSA %s\n", + zlog_debug("%s: Flooding AS-External LSA %s", __func__, lsa->name); ospf6_flood_area(NULL, lsa, oa); } diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index d4f6f6f4ae..f08426fb47 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -475,7 +475,7 @@ void ospf6_spf_calculation(uint32_t router_id, lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id); if (lsa == NULL) { if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug("%s: No router LSA for area %s\n", __func__, + zlog_debug("%s: No router LSA for area %s", __func__, oa->name); return; } diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index a3b337a0c0..f06e45392e 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -74,12 +74,12 @@ void api_opaque_lsa_print(struct lsa_header *data) olsa = (struct opaque_lsa *)data; opaquelen = ntohs(data->length) - OSPF_LSA_HEADER_SIZE; - zlog_debug("apiserver_lsa_print: opaquelen=%d\n", opaquelen); + zlog_debug("apiserver_lsa_print: opaquelen=%d", opaquelen); for (i = 0; i < opaquelen; i++) { zlog_debug("0x%x ", olsa->mydata[i]); } - zlog_debug("\n"); + zlog_debug(" "); } /* ----------------------------------------------------------- @@ -242,7 +242,7 @@ const char *ospf_api_errname(int errcode) void msg_print(struct msg *msg) { if (!msg) { - zlog_debug("msg_print msg=NULL!\n"); + zlog_debug("msg_print msg=NULL!"); return; } diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index d0ee818722..6b9ff6556c 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -2024,7 +2024,7 @@ int ospf_apiserver_del_if(struct interface *ifp) /* zlog_warn for debugging */ zlog_warn("ospf_apiserver_del_if"); - zlog_warn("ifp name=%s status=%d index=%d\n", ifp->name, ifp->status, + zlog_warn("ifp name=%s status=%d index=%d", ifp->name, ifp->status, ifp->ifindex); oi = ospf_apiserver_if_lookup_by_ifp(ifp); @@ -2110,7 +2110,7 @@ void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa) for (i = 0; i < opaquelen; i++) { zlog_debug("0x%x ", olsa->data[i]); } - zlog_debug("\n"); + zlog_debug(""); } return; } diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index 4a0d4add15..5f01edfbdf 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -1372,14 +1372,14 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh) } else { - zlog_debug(" Segment Routing Algorithm TLV:\n"); + zlog_debug(" Segment Routing Algorithm TLV:"); for (i = 0; i < ntohs(algo->header.length); i++) switch (algo->value[i]) { case 0: - zlog_debug(" Algorithm %d: SPF\n", i); + zlog_debug(" Algorithm %d: SPF", i); break; case 1: - zlog_debug(" Algorithm %d: Strict SPF\n", i); + zlog_debug(" Algorithm %d: Strict SPF", i); break; default: zlog_debug( diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index f068efc8db..c26545344a 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -901,7 +901,7 @@ static struct ospf_lsa *lsdb_lookup_next(struct ospf_area *area, uint8_t *type, /* Sanity check, if LSA type unknwon merley skip any LSA */ if ((i < OSPF_MIN_LSA) || (i >= OSPF_MAX_LSA)) { - zlog_debug("Strange request with LSA type %d\n", i); + zlog_debug("Strange request with LSA type %d", i); return NULL; } diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 9c223facd3..74dba273e6 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -1140,13 +1140,13 @@ ospf_rtrs_print (struct route_table *rtrs) if (path->nexthop.s_addr == 0) { if (IS_DEBUG_OSPF_EVENT) - zlog_debug (" directly attached to %s\r\n", + zlog_debug (" directly attached to %s\r", ifindex2ifname (path->ifindex), VRF_DEFAULT); } else { if (IS_DEBUG_OSPF_EVENT) - zlog_debug (" via %s, %s\r\n", + zlog_debug (" via %s, %s\r", inet_ntoa (path->nexthop), ifindex2ifname (path->ifindex), VRF_DEFAULT); } diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index f0ddf7cc0a..a493520868 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -1600,7 +1600,7 @@ static int ospf_sr_update_schedule(struct thread *t) monotime(&stop_time); if (IS_DEBUG_OSPF_SR) - zlog_debug("SR (%s): SPF Processing Time(usecs): %lld\n", + zlog_debug("SR (%s): SPF Processing Time(usecs): %lld", __func__, (stop_time.tv_sec - start_time.tv_sec) * 1000000LL + (stop_time.tv_usec - start_time.tv_usec)); diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 4b402de634..a4965b8ffe 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -97,7 +97,7 @@ void pim_register_stop_send(struct interface *ifp, struct prefix_sg *sg, pinfo = (struct pim_interface *)ifp->info; if (!pinfo) { if (PIM_DEBUG_PIM_TRACE) - zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__); + zlog_debug("%s: No pinfo!", __PRETTY_FUNCTION__); return; } if (pim_msg_send(pinfo->pim_sock_fd, src, originator, buffer, diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index e5dc6e6af6..ea32b622a6 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -90,7 +90,7 @@ static int ripng_multicast_join(struct interface *ifp) * group on * an interface that has just gone down. */ - zlog_warn("ripng join on %s EADDRINUSE (ignoring)\n", + zlog_warn("ripng join on %s EADDRINUSE (ignoring)", ifp->name); return 0; /* not an error */ } @@ -124,7 +124,7 @@ static int ripng_multicast_leave(struct interface *ifp) ret = setsockopt(ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq, sizeof(mreq)); if (ret < 0) - zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s\n", + zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s", safe_strerror(errno)); if (IS_RIPNG_DEBUG_EVENT) diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c index a9734056bc..38d241eaa5 100644 --- a/zebra/irdp_main.c +++ b/zebra/irdp_main.c @@ -241,7 +241,7 @@ int irdp_send_thread(struct thread *t_advert) timer = MAX_INITIAL_ADVERT_INTERVAL; if (irdp->flags & IF_DEBUG_MISC) - zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name, + zlog_debug("IRDP: New timer for %s set to %u", ifp->name, timer); irdp->t_advertise = NULL; diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index 774d84d66d..2804787620 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -166,7 +166,7 @@ static void parse_irdp_packet(char *p, int len, struct interface *ifp) case ICMP_ROUTERSOLICIT: if (irdp->flags & IF_DEBUG_MESSAGES) - zlog_debug("IRDP: RX Solicit on %s from %s\n", + zlog_debug("IRDP: RX Solicit on %s from %s", ifp->name, inet_ntoa(src)); process_solicit(ifp); @@ -253,7 +253,7 @@ int irdp_read_raw(struct thread *r) if (!(irdp->flags & IF_ACTIVE)) { if (irdp->flags & IF_DEBUG_MISC) - zlog_debug("IRDP: RX ICMP for disabled interface %s\n", + zlog_debug("IRDP: RX ICMP for disabled interface %s", ifp->name); return 0; } diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 2f850c6338..c5fbfd4481 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -652,7 +652,7 @@ static void netlink_parse_extended_ack(struct nlmsghdr *h) off = *(uint32_t *)RTA_DATA(tb[NLMSGERR_ATTR_OFFS]); if (off > h->nlmsg_len) { - zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS\n"); + zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS"); } else if (!(h->nlmsg_flags & NLM_F_CAPPED)) { /* * Header of failed message diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 792756efeb..ad46191903 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -622,7 +622,7 @@ int ifm_read(struct if_msghdr *ifm) * RTA_IFP) is required. */ if (!ifnlen) { - zlog_debug("Interface index %d (new) missing ifname\n", + zlog_debug("Interface index %d (new) missing ifname", ifm->ifm_index); return -1; } diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index c56e2f316d..cf61eb6cb4 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -835,7 +835,7 @@ int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) { /* If this is not route add/delete message print warning. */ - zlog_debug("Kernel message: %s NS %u\n", + zlog_debug("Kernel message: %s NS %u", nl_msg_type_to_str(h->nlmsg_type), ns_id); return 0; } diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index cc5e38e690..bb352dc2ff 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -328,7 +328,7 @@ DEFUN (zebra_ptm_enable_if, if (!old_ptm_enable && ptm_cb.ptm_enable) { if (!if_is_operative(ifp) && send_linkdown) { if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("%s: Bringing down interface %s\n", + zlog_debug("%s: Bringing down interface %s", __func__, ifp->name); if_down(ifp); } @@ -354,7 +354,7 @@ DEFUN (no_zebra_ptm_enable_if, ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF; if (if_is_no_ptm_operative(ifp) && send_linkup) { if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("%s: Bringing up interface %s\n", + zlog_debug("%s: Bringing up interface %s", __func__, ifp->name); if_up(ifp); } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 52637c6062..f601ab7e7b 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -383,7 +383,7 @@ static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, afi_t afi, if (state_changed || force) { if (IS_ZEBRA_DEBUG_NHT) { prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); - zlog_debug("%u:%s: Route import check %s %s\n", vrfid, + zlog_debug("%u:%s: Route import check %s %s", vrfid, bufn, rnh->state ? "passed" : "failed", state_changed ? "(state changed)" : ""); } @@ -775,7 +775,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, table = get_rnh_table(vrfid, afi, type); if (!table) { - zlog_debug("print_rnhs: rnh table not found\n"); + zlog_debug("print_rnhs: rnh table not found"); return; } @@ -1025,7 +1025,7 @@ static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, ntable = get_rnh_table(vrf_id, afi, type); if (!ntable) { - zlog_debug("cleanup_rnh_client: rnh table not found\n"); + zlog_debug("cleanup_rnh_client: rnh table not found"); return -1; } From aed536d44ff6b612109e669c4ca2bff4d4312ad9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 14 Mar 2019 17:03:26 -0400 Subject: [PATCH 068/142] pimd: Free up zlookup structure late When we are shutting down, delay the zlookup free to as late as possible since we may need it still Signed-off-by: Donald Sharp --- pimd/pimd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pimd/pimd.c b/pimd/pimd.c index 656b000579..889a83a136 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -127,8 +127,6 @@ void pim_terminate(void) { struct zclient *zclient; - pim_free(); - /* reverse prefix_list_init */ prefix_list_add_hook(NULL); prefix_list_delete_hook(NULL); @@ -142,6 +140,8 @@ void pim_terminate(void) zclient_free(zclient); } + pim_free(); pim_router_terminate(); + frr_fini(); } From b900245adc2f2666fab0db18dbe2280ec1f7ef84 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 11 Mar 2019 09:39:19 -0400 Subject: [PATCH 069/142] zebra: System routes sometimes can not be properly selected System Routes if received over the netlink bus in a specific pattern that causes an update operation for that route in zebra can leave the dest->selected_fib pointer NULL, while having the ZEBRA_FLAG_SELECTED flag set. Specifically one way to achieve this is to do this: `ip addr del 4.5.6.7/32 dev swp1 ; ip addr add 4.5.6.7/32 dev swp1 metric 9` Why is this a big deal? Because nexthop tracking is looking at ZEBRA_FLAG_SELECTED to know if we can use a route, while nexthop active checking uses dest->selected_fib. So imagine we have bgp registering a nexthop. nexthop tracking in the above case will be able to choose the 4.5.6.7/32 route if that is what the nexthop is, due to the ZEBRA_FLAG_SELECTED being properly set. BGP then allows the peers connection to come up and we install routes with a 4.5.6.7 nexthop. The rib processing for route installation will then look at the 4.5.6.7 route see no dest->selected_fib and then start walking up the tree to resolve the route. In our case we could easily hit the default route and be unable to resolve the route. Which then becomes inactive in the rib so we never attempt to install it. This commit fixes this problem because when the rib_process decides that we need to update the fib( ie replace old w/ new ), the replacement with new was not setting the `dest->selected_fib` pointer to the new route_entry, when the route was a system route. Ticket: CM-24203 Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 2014aa3bed..5fa51ada45 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1405,7 +1405,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, * from ourselves we don't * over write this pointer */ - dest->selected_fib = NULL; + dest->selected_fib = new; } /* If install succeeded or system route, cleanup flags * for prior route. */ From f116689efba19b9aee2425b6359da2befce205d1 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 15 Mar 2019 11:32:41 -0400 Subject: [PATCH 070/142] pimd: Display drpriority as a unsigned int There existed output code that used %d for a uint32_t switch to a %u. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index f521704f1b..012c3b4f1d 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1191,7 +1191,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim, vty_out(vty, "Designated Router\n"); vty_out(vty, "-----------------\n"); vty_out(vty, "Address : %s\n", dr_str); - vty_out(vty, "Priority : %d(%d)\n", + vty_out(vty, "Priority : %u(%d)\n", pim_ifp->pim_dr_priority, pim_ifp->pim_dr_num_nondrpri_neighbors); vty_out(vty, "Uptime : %s\n", dr_uptime); From d346c2e955ced1b7f579662365bf69cee4c2078c Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Fri, 15 Mar 2019 09:13:42 -0700 Subject: [PATCH 071/142] zebra: EVPN DAD trigger was causing zebra to crash Duplicate address detection and recovery was relying on the l2-vni backptr in the neighbor entry which was simply not initialized resulting in a NULL pointer access in a setup with dup-addressed VMs - VM1:{IP1,M1} and VM2:{IP1,M2} Call stack: (gdb) bt 6 at lib/sigevent.c:249 nbr=nbr@entry=0x559347f901d0, vtep_ip=..., vtep_ip@entry=..., do_dad=do_dad@entry=true, is_dup_detect=is_dup_detect@entry=0x7ffc7f6be59f, is_local=is_local@entry=true) at ./lib/ipaddr.h:86 ip=0x7ffc7f6be6f0, ifp=0x559347f901d0, zvni=0x559347f86800) at zebra/zebra_vxlan.c:3152 (More stack frames follow...) (gdb) p nbr->zvni $8 = (zebra_vni_t *) 0x0 <<<<<<<<<<<<<<<<<<<< (gdb) Signed-off-by: Anuradha Karuppiah --- zebra/zebra_vxlan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 00fc230851..b44c314d5b 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2190,6 +2190,7 @@ static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip, memcpy(&n->emac, mac, ETH_ALEN); n->state = ZEBRA_NEIGH_INACTIVE; + n->zvni = zvni; /* Associate the neigh to mac */ zmac = zvni_mac_lookup(zvni, mac); From 064e2f32807a549e777d829cd35e3bd941e95c06 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Sun, 17 Mar 2019 13:25:16 -0400 Subject: [PATCH 072/142] libs: fix race in privs changes Use the privs struct mutex more strictly, to ensure that the privs are at the level the caller expects when the apis return. Signed-off-by: Mark Stapp --- lib/privs.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/lib/privs.c b/lib/privs.c index 3ce8e0d57a..59f24afe4a 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -708,19 +708,19 @@ struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs, /* If we're already elevated, just return */ pthread_mutex_lock(&(privs->mutex)); - if (++privs->refcount > 1) { - pthread_mutex_unlock(&(privs->mutex)); - return privs; + { + if (++(privs->refcount) == 1) { + errno = 0; + if (privs->change(ZPRIVS_RAISE)) { + zlog_err("%s: Failed to raise privileges (%s)", + funcname, safe_strerror(errno)); + } + errno = save_errno; + privs->raised_in_funcname = funcname; + } } pthread_mutex_unlock(&(privs->mutex)); - errno = 0; - if (privs->change(ZPRIVS_RAISE)) { - zlog_err("%s: Failed to raise privileges (%s)", - funcname, safe_strerror(errno)); - } - errno = save_errno; - privs->raised_in_funcname = funcname; return privs; } @@ -733,19 +733,20 @@ void _zprivs_lower(struct zebra_privs_t **privs) /* Don't lower privs if there's another caller */ pthread_mutex_lock(&(*privs)->mutex); - if (--((*privs)->refcount) > 0) { - pthread_mutex_unlock(&(*privs)->mutex); - return; + { + if (--((*privs)->refcount) == 0) { + errno = 0; + if ((*privs)->change(ZPRIVS_LOWER)) { + zlog_err("%s: Failed to lower privileges (%s)", + (*privs)->raised_in_funcname, + safe_strerror(errno)); + } + errno = save_errno; + (*privs)->raised_in_funcname = NULL; + } } pthread_mutex_unlock(&(*privs)->mutex); - errno = 0; - if ((*privs)->change(ZPRIVS_LOWER)) { - zlog_err("%s: Failed to lower privileges (%s)", - (*privs)->raised_in_funcname, safe_strerror(errno)); - } - errno = save_errno; - (*privs)->raised_in_funcname = NULL; *privs = NULL; } From 47e3ce59c434dbde996373268896c595ba8a6bf4 Mon Sep 17 00:00:00 2001 From: Sarita Patra Date: Mon, 18 Mar 2019 20:22:04 -0700 Subject: [PATCH 073/142] pimd: Addressing the review comments Signed-off-by: Sarita Patra --- pimd/pim_oil.c | 10 +++------- pimd/pim_oil.h | 1 - pimd/pim_rpf.c | 1 - pimd/pim_upstream.c | 33 +++++++++++---------------------- 4 files changed, 14 insertions(+), 31 deletions(-) diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 35801aa49e..55d26113f7 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -190,10 +190,6 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, c_oil->installed = 0; c_oil->up = pim_upstream_find(pim, sg); c_oil->pim = pim; - if (input_vif_index != MAXVIFS) - c_oil->is_valid = 1; - else - c_oil->is_valid = 0; listnode_add_sort(pim->channel_oil_list, c_oil); @@ -453,10 +449,10 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL; - /* channel_oil->is_valid indicate if this entry is valid to get - * installed in kernel. + /* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not + * valid to get installed in kernel. */ - if (channel_oil->is_valid) { + if (channel_oil->oil.mfcc_parent != MAXVIFS) { if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) { if (PIM_DEBUG_MROUTE) { char group_str[INET_ADDRSTRLEN]; diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index fef414cc85..5dd4e8b326 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -89,7 +89,6 @@ struct channel_oil { struct pim_instance *pim; struct mfcctl oil; - bool is_valid; int installed; int oil_inherited_rescan; int oil_size; diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 8adf253e55..ee145a5b51 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -325,7 +325,6 @@ void pim_upstream_rpf_clear(struct pim_instance *pim, if (up->rpf.source_nexthop.interface) { if (up->channel_oil) { up->channel_oil->oil.mfcc_parent = MAXVIFS; - up->channel_oil->is_valid = 0; pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); } diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 9cf25f0f92..cb89e30a50 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -306,19 +306,13 @@ static int on_join_timer(struct thread *t) static void join_timer_stop(struct pim_upstream *up) { - struct pim_neighbor *nbr; - - if (!up->rpf.source_nexthop.interface) { - if (PIM_DEBUG_TRACE) - zlog_debug("%s: up %s RPF is not present", - __PRETTY_FUNCTION__, up->sg_str); - return; - } + struct pim_neighbor *nbr = NULL; THREAD_OFF(up->t_join_timer); - nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + if (up->rpf.source_nexthop.interface) + nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, + up->rpf.rpf_addr.u.prefix4); if (nbr) pim_jp_agg_remove_group(nbr->upstream_jp_agg, up); @@ -330,13 +324,6 @@ void join_timer_start(struct pim_upstream *up) { struct pim_neighbor *nbr = NULL; - if (!up->rpf.source_nexthop.interface) { - if (PIM_DEBUG_TRACE) - zlog_debug("%s: up %s RPF is not present", - __PRETTY_FUNCTION__, up->sg_str); - return; - } - if (up->rpf.source_nexthop.interface) { nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, up->rpf.rpf_addr.u.prefix4); @@ -562,14 +549,16 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, enum pim_upstream_state old_state = up->join_state; if (up->upstream_addr.s_addr == INADDR_ANY) { - zlog_debug("%s: RPF not configured for %s", - __PRETTY_FUNCTION__, up->sg_str); + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug("%s: RPF not configured for %s", + __PRETTY_FUNCTION__, up->sg_str); return; } if (!up->rpf.source_nexthop.interface) { - zlog_debug("%s: RP not reachable for %s", - __PRETTY_FUNCTION__, up->sg_str); + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug("%s: RP not reachable for %s", + __PRETTY_FUNCTION__, up->sg_str); return; } @@ -949,7 +938,7 @@ void pim_upstream_update_join_desired(struct pim_instance *pim, PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags); /* switched from false to true */ - if (is_join_desired) { + if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) { pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED); return; } From d0a456858edb2bf9c5e06da42ef419d7bb55b294 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Tue, 19 Mar 2019 10:47:00 -0400 Subject: [PATCH 074/142] ospfd: remove empty debug Remove empty debug line - empty format string generates a compile warning. Signed-off-by: Mark Stapp --- ospfd/ospf_apiserver.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 6b9ff6556c..d6f1fba28b 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -2110,7 +2110,6 @@ void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa) for (i = 0; i < opaquelen; i++) { zlog_debug("0x%x ", olsa->data[i]); } - zlog_debug(""); } return; } From 2e73695a3c36b32078c4c9a0c1b51c3d9e5aaf66 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Tue, 19 Mar 2019 20:18:49 +0000 Subject: [PATCH 075/142] tests: point topotests docker img to new location The topotests docker image has moved from frrouting/frr to frrouting/topotests. Update accordingly. Signed-off-by: Quentin Young --- tests/topotests/docker/build.sh | 2 +- tests/topotests/docker/frr-topotests.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/topotests/docker/build.sh b/tests/topotests/docker/build.sh index 344fb2ffcb..70ce2efe85 100755 --- a/tests/topotests/docker/build.sh +++ b/tests/topotests/docker/build.sh @@ -26,5 +26,5 @@ cd "$(dirname "$0")"/.. exec docker build --pull \ --compress \ - -t frrouting/frr:topotests-latest \ + -t frrouting/topotests:latest \ . diff --git a/tests/topotests/docker/frr-topotests.sh b/tests/topotests/docker/frr-topotests.sh index 6d8bea0002..ef916abcf3 100755 --- a/tests/topotests/docker/frr-topotests.sh +++ b/tests/topotests/docker/frr-topotests.sh @@ -136,7 +136,7 @@ if [ -z "$TOPOTEST_BUILDCACHE" ]; then fi if [ "${TOPOTEST_PULL:-1}" = "1" ]; then - docker pull frrouting/frr:topotests-latest + docker pull frrouting/topotests:latest fi set -- --rm -i \ @@ -149,7 +149,7 @@ set -- --rm -i \ -e "TOPOTEST_SANITIZER=$TOPOTEST_SANITIZER" \ --privileged \ $TOPOTEST_OPTIONS \ - frrouting/frr:topotests-latest "$@" + frrouting/topotests:latest "$@" if [ -t 0 ]; then set -- -t "$@" From 5ff7d1be75ab685a93e797569b5cf11a748c5890 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 19 Mar 2019 17:22:58 -0300 Subject: [PATCH 076/142] bfdd: fix JSON API local-address translation Get the local-address from the right key struct member. Signed-off-by: Rafael Zalamena --- bfdd/bfd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index c8adf82a83..08e8e06580 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -1231,7 +1231,7 @@ void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc) if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) { bpc->bpc_local.sa_sin.sin_family = AF_INET6; - memcpy(&bpc->bpc_local.sa_sin.sin_addr, &bs->key.peer, + memcpy(&bpc->bpc_local.sa_sin.sin_addr, &bs->key.local, sizeof(bpc->bpc_local.sa_sin.sin_addr)); } break; @@ -1242,7 +1242,7 @@ void bs_to_bpc(struct bfd_session *bs, struct bfd_peer_cfg *bpc) sizeof(bpc->bpc_peer.sa_sin6.sin6_addr)); bpc->bpc_local.sa_sin6.sin6_family = AF_INET6; - memcpy(&bpc->bpc_local.sa_sin6.sin6_addr, &bs->key.peer, + memcpy(&bpc->bpc_local.sa_sin6.sin6_addr, &bs->key.local, sizeof(bpc->bpc_local.sa_sin6.sin6_addr)); break; } From 4cf4e8329797811a10baa4dda8e0d490af5503cb Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 19 Mar 2019 17:25:00 -0300 Subject: [PATCH 077/142] bfdd: fix echo loopback function Add the address family to the sockaddr structure otherwise `sendmsg` will fail with `EAFNOSUPPORT`. Signed-off-by: Rafael Zalamena --- bfdd/bfd_packet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 69d27ed698..93677ec85a 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -141,6 +141,7 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd) if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6)) { sd = bglobal.bg_echov6; memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; memcpy(&sin6.sin6_addr, &bfd->key.peer, sizeof(sin6.sin6_addr)); if (bfd->ifp && IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) sin6.sin6_scope_id = bfd->ifp->ifindex; @@ -155,6 +156,7 @@ void ptm_bfd_echo_snd(struct bfd_session *bfd) } else { sd = bglobal.bg_echo; memset(&sin6, 0, sizeof(sin6)); + sin.sin_family = AF_INET; memcpy(&sin.sin_addr, &bfd->key.peer, sizeof(sin.sin_addr)); sin.sin_port = htons(BFD_DEF_ECHO_PORT); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN From 47bf0432d3e47807b95531aa64aab0c39ddcacce Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Tue, 12 Mar 2019 18:41:01 -0700 Subject: [PATCH 078/142] bgpd: router mac same as self skip route install When a bgp-peer comes up prior to l3vnis are up in bgpd. The EVPN routes (type-2/type-5) are learnt via peer. The routes can have one of interface's MAC in rmac attribute. The self rmac check would bypass as l3vni is not present. Once l3vni has come up in bgpd, while installing evpn routes in vrf table, perform rmac attribute check against self mac. The routes with rmac of ours will be removed via re-scan of routes during bgp_mac_rescan_all_evpn_tables when interface mac is added to bgp. Ticket:CM-24224 Reviewed By:CCR-8423 Testing Done: Signed-off-by: Chirag Shah --- bgpd/bgp_evpn.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 19cda453f5..6ced286dde 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -48,6 +48,7 @@ #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_addpath.h" +#include "bgpd/bgp_mac.h" /* * Definitions and external declarations. @@ -2945,6 +2946,41 @@ static int install_uninstall_routes_for_es(struct bgp *bgp, return 0; } +/* This API will scan evpn routes for checking attribute's rmac + * macthes with bgp instance router mac. It avoid installing + * route into bgp vrf table and remote rmac in bridge table. + */ +static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf, + struct prefix_evpn *evp, + struct bgp_path_info *pi) +{ + /* evpn route could have learnt prior to L3vni has come up, + * perform rmac check before installing route and + * remote router mac. + * The route will be removed from global bgp table once + * SVI comes up with MAC and stored in hash, triggers + * bgp_mac_rescan_all_evpn_tables. + */ + if (pi->attr && + memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) { + if (bgp_debug_update(pi->peer, NULL, NULL, 1)) { + char buf1[PREFIX_STRLEN]; + char attr_str[BUFSIZ] = {0}; + + bgp_dump_attr(pi->attr, attr_str, BUFSIZ); + + zlog_debug("%s: bgp %u prefix %s with attr %s - DENIED due to self mac", + __func__, bgp_vrf->vrf_id, + prefix2str(evp, buf1, sizeof(buf1)), + attr_str); + } + + return 1; + } + + return 0; +} + /* * Install or uninstall mac-ip routes are appropriate for this * particular VRF. @@ -3001,6 +3037,10 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install) continue; if (is_route_matching_for_vrf(bgp_vrf, pi)) { + if (bgp_evpn_route_rmac_self_check( + bgp_vrf, evp, pi)) + continue; + if (install) ret = install_evpn_route_entry_in_vrf( bgp_vrf, evp, pi); From 9e97ff0308d3ac642f73503de825075770099d50 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Tue, 19 Mar 2019 17:06:10 -0700 Subject: [PATCH 079/142] bgpd: l3vni add-del handle non-defualt rd During L3VNI add, non-default RD value is not replayed correctly. Instead of picking non-default value it picks up auto RD value which is derived based on router-id. Indentation issue: Remove additional space from L3VNI running config output. Ticket:CM-24320 Reviewed By:CCR-8437 Testing Done: Bring up evpn configuration with L3vni up with non-default RD value, perform peerlink flap, l3vni flap which removes all VNIS and readds with RD and RT values. The configured RD and RTs are replayed. Post L3VNI flap router bgp 5546 vrf vrf2 ! address-family l2vpn evpn rd 45.0.66.2:6 route-target import 20001:1 route-target export 20001:1 exit-address-family TORC11# show bgp l2vpn evpn vni 4002 VNI: 4002 (known to the kernel) Type: L3 Tenant VRF: vrf2 RD: 45.0.66.2:6 Originator IP: 36.0.0.11 Advertise-gw-macip : n/a Import Route Target: 20001:1 Export Route Target: 20001:1 Signed-off-by: Chirag Shah --- bgpd/bgp_evpn.c | 3 +++ bgpd/bgp_evpn_vty.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 19cda453f5..31e820c615 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -5041,6 +5041,9 @@ void bgp_evpn_derive_auto_rt_export(struct bgp *bgp, struct bgpevpn *vpn) */ void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp) { + if (is_vrf_rd_configured(bgp)) + return; + form_auto_rd(bgp->router_id, bgp->vrf_rd_id, &bgp->vrf_prd); } diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index fb2d9da533..ba72761003 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -5212,7 +5212,7 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, vty_out(vty, " default-originate ipv6\n"); if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD)) - vty_out(vty, " rd %s\n", + vty_out(vty, " rd %s\n", prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1))); /* import route-target */ From ed74032b7fba70bde4bfc118690b38e49d057c69 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 16 Mar 2019 21:25:59 -0400 Subject: [PATCH 080/142] bfdd: Prevent uninited use of data Running valgrind w/ bfdd and shut/no shuting interfaces can result in this valgrind issue: ==20279== Conditional jump or move depends on uninitialised value(s) ==20279== at 0x115848: bfdd_sessions_enable_address (ptm_adapter.c:644) ==20279== by 0x115848: bfdd_interface_address_update (ptm_adapter.c:674) ==20279== by 0x48D8CAB: zclient_read (zclient.c:2698) ==20279== by 0x48CCEE3: thread_call (thread.c:1603) ==20279== by 0x48A84EF: frr_run (libfrr.c:1011) ==20279== by 0x10DAC3: main (bfdd.c:236) ==20279== When creating the bso data structure set the bso_isaddress to false as a default value. Signed-off-by: Donald Sharp --- bfdd/bfd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 08e8e06580..3575ba7a00 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -1187,7 +1187,8 @@ int bs_observer_add(struct bfd_session *bs) { struct bfd_session_observer *bso; - bso = XMALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso)); + bso = XCALLOC(MTYPE_BFDD_SESSION_OBSERVER, sizeof(*bso)); + bso->bso_isaddress = false; bso->bso_bs = bs; bso->bso_isinterface = !BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH); if (bso->bso_isinterface) From 23fbacb455e3e8127917782042463551f142b4c1 Mon Sep 17 00:00:00 2001 From: "F. Aragon" Date: Wed, 20 Mar 2019 16:45:32 +0100 Subject: [PATCH 081/142] zebra: copy-paste error (Coverity 1479148) Signed-off-by: F. Aragon --- zebra/zebra_rib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5fa51ada45..77cb38855d 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1932,7 +1932,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) dplane_ctx_get_vrf(ctx), dest_str, old_re); } else - UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); + UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED); } switch (op) { From 86439e8d5f9793b9685c686ceef196017e865e41 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 18 Sep 2018 09:43:46 -0400 Subject: [PATCH 082/142] Add code to test some very basic pim functionality Add code to send a S,G stream and make sure the RP see's it. Add code to send a *,G report and make sure the RP see's it. This is just some *very* basic functionality testing to ensure that we don't break anything basic. Signed-off-by: Donald Sharp --- tests/topotests/pim-basic/mcast-rx.py | 83 +++++++++++++ tests/topotests/pim-basic/mcast-tx.py | 72 ++++++++++++ tests/topotests/pim-basic/r1/frr.conf | 19 +++ tests/topotests/pim-basic/r1/pimd.conf | 1 + tests/topotests/pim-basic/r1/zebra.conf | 1 + tests/topotests/pim-basic/r2/frr.conf | 14 +++ tests/topotests/pim-basic/r2/pimd.conf | 1 + tests/topotests/pim-basic/r2/zebra.conf | 1 + tests/topotests/pim-basic/test_pim.py | 150 ++++++++++++++++++++++++ 9 files changed, 342 insertions(+) create mode 100755 tests/topotests/pim-basic/mcast-rx.py create mode 100755 tests/topotests/pim-basic/mcast-tx.py create mode 100644 tests/topotests/pim-basic/r1/frr.conf create mode 100644 tests/topotests/pim-basic/r1/pimd.conf create mode 100644 tests/topotests/pim-basic/r1/zebra.conf create mode 100644 tests/topotests/pim-basic/r2/frr.conf create mode 100644 tests/topotests/pim-basic/r2/pimd.conf create mode 100644 tests/topotests/pim-basic/r2/zebra.conf create mode 100644 tests/topotests/pim-basic/test_pim.py diff --git a/tests/topotests/pim-basic/mcast-rx.py b/tests/topotests/pim-basic/mcast-rx.py new file mode 100755 index 0000000000..9e3484e12a --- /dev/null +++ b/tests/topotests/pim-basic/mcast-rx.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# +# mcast-rx.py +# +# Copyright (c) 2018 Cumulus Networks, Inc. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND Cumulus Networks DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# +""" +Subscribe to a multicast group so that the kernel sends an IGMP JOIN +for the multicast group we subscribed to. +""" + +import argparse +import logging +import re +import os +import socket +import subprocess +import struct +import sys +import time + + +def ifname_to_ifindex(ifname): + output = subprocess.check_output("ip link show %s" % ifname, shell=True) + first_line = output.split('\n')[0] + re_index = re.search('^(\d+):', first_line) + + if re_index: + return int(re_index.group(1)) + + log.error("Could not parse the ifindex for %s out of\n%s" % (ifname, first_line)) + return None + + +# Thou shalt be root +if os.geteuid() != 0: + sys.stderr.write('ERROR: You must have root privileges\n') + sys.exit(1) + + +logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)5s: %(message)s') + +# Color the errors and warnings in red +logging.addLevelName(logging.ERROR, "\033[91m %s\033[0m" % logging.getLevelName(logging.ERROR)) +logging.addLevelName(logging.WARNING, "\033[91m%s\033[0m" % logging.getLevelName(logging.WARNING)) +log = logging.getLogger(__name__) + +parser = argparse.ArgumentParser(description='Multicast RX utility', + version='1.0.0') +parser.add_argument('group', help='Multicast IP') +parser.add_argument('ifname', help='Interface name') +parser.add_argument('--port', help='UDP port', default=1000) +parser.add_argument('--sleep', help='Time to sleep before we stop waiting', + default = 5) +args = parser.parse_args() + +# Create the datagram socket +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +sock.bind((args.group, args.port)) + +newpid = os.fork() + +if newpid == 0: + ifindex = ifname_to_ifindex(args.ifname) + mreq = struct.pack("=4sLL", socket.inet_aton(args.group), socket.INADDR_ANY, ifindex) + sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) + time.sleep(float(args.sleep)) + sock.close() diff --git a/tests/topotests/pim-basic/mcast-tx.py b/tests/topotests/pim-basic/mcast-tx.py new file mode 100755 index 0000000000..c469e47d4c --- /dev/null +++ b/tests/topotests/pim-basic/mcast-tx.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +# +# mcast-tx.py +# +# Copyright (c) 2018 Cumulus Networks, Inc. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND Cumulus Networks DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import argparse +import logging +import socket +import struct +import time + + +logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)5s: %(message)s') + +# Color the errors and warnings in red +logging.addLevelName(logging.ERROR, "\033[91m %s\033[0m" % logging.getLevelName(logging.ERROR)) +logging.addLevelName(logging.WARNING, "\033[91m%s\033[0m" % logging.getLevelName(logging.WARNING)) +log = logging.getLogger(__name__) + +parser = argparse.ArgumentParser(description='Multicast packet generator', version='1.0.0') +parser.add_argument('group', help='Multicast IP') +parser.add_argument('ifname', help='Interface name') +parser.add_argument('--port', type=int, help='UDP port number', default=1000) +parser.add_argument('--ttl', type=int, help='time-to-live', default=20) +parser.add_argument('--count', type=int, help='Packets to send', default=1) +parser.add_argument('--interval', type=int, help='ms between packets', default=100) +args = parser.parse_args() + +# Create the datagram socket +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + +# IN.SO_BINDTODEVICE is not defined in some releases of python but it is 25 +# https://github.com/sivel/bonding/issues/10 +# +# Bind our socket to ifname +sock.setsockopt(socket.SOL_SOCKET, + 25, + struct.pack("%ds" % len(args.ifname), args.ifname)) + +# We need to make sure our sendto() finishes before we close the socket +sock.setblocking(1) + +# Set the time-to-live +sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, struct.pack('b', args.ttl)) + +ms = args.interval / 1000.0 + +# Send data to the multicast group +for x in xrange(args.count): + log.info('TX multicast UDP packet to %s:%d on %s' % (args.group, args.port, args.ifname)) + sent = sock.sendto('foobar %d' % x, (args.group, args.port)) + + if args.count > 1 and ms: + time.sleep(ms) + +sock.close() diff --git a/tests/topotests/pim-basic/r1/frr.conf b/tests/topotests/pim-basic/r1/frr.conf new file mode 100644 index 0000000000..36433f73f8 --- /dev/null +++ b/tests/topotests/pim-basic/r1/frr.conf @@ -0,0 +1,19 @@ +hostname r1 +interface r1-eth0 + ip address 10.0.20.1/24 +! +interface lo + ip address 10.254.0.1/32 +! +hostname r1 +! +! +interface r1-eth0 + ip igmp + ip pim sm +! +interface lo + ip pim sm +! +ip pim rp 10.254.0.1 + diff --git a/tests/topotests/pim-basic/r1/pimd.conf b/tests/topotests/pim-basic/r1/pimd.conf new file mode 100644 index 0000000000..faf7543ba8 --- /dev/null +++ b/tests/topotests/pim-basic/r1/pimd.conf @@ -0,0 +1 @@ +hostname r1 diff --git a/tests/topotests/pim-basic/r1/zebra.conf b/tests/topotests/pim-basic/r1/zebra.conf new file mode 100644 index 0000000000..faf7543ba8 --- /dev/null +++ b/tests/topotests/pim-basic/r1/zebra.conf @@ -0,0 +1 @@ +hostname r1 diff --git a/tests/topotests/pim-basic/r2/frr.conf b/tests/topotests/pim-basic/r2/frr.conf new file mode 100644 index 0000000000..6473a466b4 --- /dev/null +++ b/tests/topotests/pim-basic/r2/frr.conf @@ -0,0 +1,14 @@ +hostname r2 +interface r2-eth0 + ip address 10.0.20.2/24 +! +interface lo + ip address 10.254.0.2/32 +! +hostname r2 +interface r2-eth0 + ip address 10.0.21.2/24 +! +interface lo + ip address 10.254.0.2/32 +! diff --git a/tests/topotests/pim-basic/r2/pimd.conf b/tests/topotests/pim-basic/r2/pimd.conf new file mode 100644 index 0000000000..932cff6f3b --- /dev/null +++ b/tests/topotests/pim-basic/r2/pimd.conf @@ -0,0 +1 @@ +hostname r2 diff --git a/tests/topotests/pim-basic/r2/zebra.conf b/tests/topotests/pim-basic/r2/zebra.conf new file mode 100644 index 0000000000..932cff6f3b --- /dev/null +++ b/tests/topotests/pim-basic/r2/zebra.conf @@ -0,0 +1 @@ +hostname r2 diff --git a/tests/topotests/pim-basic/test_pim.py b/tests/topotests/pim-basic/test_pim.py new file mode 100644 index 0000000000..5d4f4b8587 --- /dev/null +++ b/tests/topotests/pim-basic/test_pim.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python + +# +# test_pim.py +# +# Copyright (c) 2018 Cumulus Networks, Inc. +# Donald Sharp +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND Cumulus Networks DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_pim.py: Test pim +""" + +import os +import sys +import pytest + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +from mininet.topo import Topo + +class PIMTopo(Topo): + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + for routern in range(1, 3): + tgen.add_router('r{}'.format(routern)) + + # r1 <- sw1 -> r2 + sw = tgen.add_switch('sw1') + sw.add_link(tgen.gears['r1']) + sw.add_link(tgen.gears['r2']) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(PIMTopo, mod.__name__) + tgen.start_topology() + + # For all registered routers, load the zebra configuration file + for rname, router in tgen.routers().iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_PIM, + os.path.join(CWD, '{}/pimd.conf'.format(rname)) + ) + + # After loading the configurations, this function loads configured daemons. + tgen.start_router() + for rname, router in tgen.routers().iteritems(): + router.run("vtysh -f {}".format(os.path.join(CWD, '{}/frr.conf'.format(rname)))) + + #tgen.mininet_cli() + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_pim_send_mcast_stream(): + "Establish a Multicast stream from r2 -> r1 and then ensure S,G is created as appropriate" + logger.info("Establish a Mcast stream from r2->r1 and then ensure S,G created") + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears['r2'] + r1 = tgen.gears['r1'] + + # Let's establish a S,G stream from r2 -> r1 + CWD = os.path.dirname(os.path.realpath(__file__)) + out2 = r2.run("{}/mcast-tx.py --ttl 5 --count 5 --interval 10 229.1.1.1 r2-eth0 > /tmp/bar".format(CWD)) + + # Let's see that it shows up and we have established some basic state + out1 = r1.vtysh_cmd("show ip pim upstream json", isjson=True) + + sg = out1['229.1.1.1']['10.0.20.2'] + assert sg['firstHopRouter'] == 1 + assert sg['joinState'] == "NotJoined" + assert sg['regState'] == "RegPrune" + assert sg['inboundInterface'] == "r1-eth0" + #tgen.mininet_cli() + + +def test_pim_igmp_report(): + "Send a igmp report from r2->r1 and ensure that the *,G state is created on r1" + logger.info("Send a igmp report from r2-r1 and ensure *,G created") + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears['r2'] + r1 = tgen.gears['r1'] + + # Let's send a igmp report from r2->r1 + CWD = os.path.dirname(os.path.realpath(__file__)) + out2 = r2.run("{}/mcast-rx.py 229.1.1.2 r2-eth0 &".format(CWD)) + + out1 = r1.vtysh_cmd("show ip pim upstream json", isjson=True) + starg = out1['229.1.1.2']['*'] + assert starg['sourceIgmp'] == 1 + assert starg['joinState'] == "Joined" + assert starg['regState'] == "RegNoInfo" + assert starg['sptBit'] == 0 + #tgen.mininet_cli() + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip('Memory leak test/report is disabled') + + tgen.report_memory_leaks() + + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From 79d70a4c1b2c3901fa409979674cb0fcf704c8fa Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 20 Mar 2019 14:03:57 -0300 Subject: [PATCH 083/142] topotests: pim-basic: fix some rough edges Move daemon configuration to appropriated files and use `json_cmp` to assert the values we expect. Signed-off-by: Rafael Zalamena --- tests/topotests/pim-basic/r1/frr.conf | 19 ---------- tests/topotests/pim-basic/r1/pimd.conf | 9 +++++ tests/topotests/pim-basic/r1/zebra.conf | 7 ++++ tests/topotests/pim-basic/r2/frr.conf | 14 -------- tests/topotests/pim-basic/r2/zebra.conf | 7 ++++ tests/topotests/pim-basic/test_pim.py | 46 +++++++++++++++---------- 6 files changed, 50 insertions(+), 52 deletions(-) delete mode 100644 tests/topotests/pim-basic/r1/frr.conf delete mode 100644 tests/topotests/pim-basic/r2/frr.conf diff --git a/tests/topotests/pim-basic/r1/frr.conf b/tests/topotests/pim-basic/r1/frr.conf deleted file mode 100644 index 36433f73f8..0000000000 --- a/tests/topotests/pim-basic/r1/frr.conf +++ /dev/null @@ -1,19 +0,0 @@ -hostname r1 -interface r1-eth0 - ip address 10.0.20.1/24 -! -interface lo - ip address 10.254.0.1/32 -! -hostname r1 -! -! -interface r1-eth0 - ip igmp - ip pim sm -! -interface lo - ip pim sm -! -ip pim rp 10.254.0.1 - diff --git a/tests/topotests/pim-basic/r1/pimd.conf b/tests/topotests/pim-basic/r1/pimd.conf index faf7543ba8..5740c66e24 100644 --- a/tests/topotests/pim-basic/r1/pimd.conf +++ b/tests/topotests/pim-basic/r1/pimd.conf @@ -1 +1,10 @@ hostname r1 +! +interface r1-eth0 + ip igmp + ip pim sm +! +interface lo + ip pim sm +! +ip pim rp 10.254.0.1 diff --git a/tests/topotests/pim-basic/r1/zebra.conf b/tests/topotests/pim-basic/r1/zebra.conf index faf7543ba8..2bf71294d0 100644 --- a/tests/topotests/pim-basic/r1/zebra.conf +++ b/tests/topotests/pim-basic/r1/zebra.conf @@ -1 +1,8 @@ hostname r1 +! +interface r1-eth0 + ip address 10.0.20.1/24 +! +interface lo + ip address 10.254.0.1/32 +! diff --git a/tests/topotests/pim-basic/r2/frr.conf b/tests/topotests/pim-basic/r2/frr.conf deleted file mode 100644 index 6473a466b4..0000000000 --- a/tests/topotests/pim-basic/r2/frr.conf +++ /dev/null @@ -1,14 +0,0 @@ -hostname r2 -interface r2-eth0 - ip address 10.0.20.2/24 -! -interface lo - ip address 10.254.0.2/32 -! -hostname r2 -interface r2-eth0 - ip address 10.0.21.2/24 -! -interface lo - ip address 10.254.0.2/32 -! diff --git a/tests/topotests/pim-basic/r2/zebra.conf b/tests/topotests/pim-basic/r2/zebra.conf index 932cff6f3b..cb30858f58 100644 --- a/tests/topotests/pim-basic/r2/zebra.conf +++ b/tests/topotests/pim-basic/r2/zebra.conf @@ -1 +1,8 @@ hostname r2 +! +interface r2-eth0 + ip address 10.0.20.2/24 +! +interface lo + ip address 10.254.0.2/32 +! diff --git a/tests/topotests/pim-basic/test_pim.py b/tests/topotests/pim-basic/test_pim.py index 5d4f4b8587..6d54b8f2f0 100644 --- a/tests/topotests/pim-basic/test_pim.py +++ b/tests/topotests/pim-basic/test_pim.py @@ -71,10 +71,7 @@ def setup_module(mod): # After loading the configurations, this function loads configured daemons. tgen.start_router() - for rname, router in tgen.routers().iteritems(): - router.run("vtysh -f {}".format(os.path.join(CWD, '{}/frr.conf'.format(rname)))) - #tgen.mininet_cli() def teardown_module(mod): "Teardown the pytest environment" @@ -98,17 +95,22 @@ def test_pim_send_mcast_stream(): # Let's establish a S,G stream from r2 -> r1 CWD = os.path.dirname(os.path.realpath(__file__)) - out2 = r2.run("{}/mcast-tx.py --ttl 5 --count 5 --interval 10 229.1.1.1 r2-eth0 > /tmp/bar".format(CWD)) + r2.run("{}/mcast-tx.py --ttl 5 --count 5 --interval 10 229.1.1.1 r2-eth0 > /tmp/bar".format(CWD)) # Let's see that it shows up and we have established some basic state - out1 = r1.vtysh_cmd("show ip pim upstream json", isjson=True) + out = r1.vtysh_cmd("show ip pim upstream json", isjson=True) + expected = { + '229.1.1.1': { + '10.0.20.2': { + 'firstHopRouter': 1, + 'joinState': 'NotJoined', + 'regState': 'RegPrune', + 'inboundInterface': 'r1-eth0', + } + } + } - sg = out1['229.1.1.1']['10.0.20.2'] - assert sg['firstHopRouter'] == 1 - assert sg['joinState'] == "NotJoined" - assert sg['regState'] == "RegPrune" - assert sg['inboundInterface'] == "r1-eth0" - #tgen.mininet_cli() + assert topotest.json_cmp(out, expected) is None, 'failed to converge pim' def test_pim_igmp_report(): @@ -125,15 +127,21 @@ def test_pim_igmp_report(): # Let's send a igmp report from r2->r1 CWD = os.path.dirname(os.path.realpath(__file__)) - out2 = r2.run("{}/mcast-rx.py 229.1.1.2 r2-eth0 &".format(CWD)) + r2.run("{}/mcast-rx.py 229.1.1.2 r2-eth0 &".format(CWD)) - out1 = r1.vtysh_cmd("show ip pim upstream json", isjson=True) - starg = out1['229.1.1.2']['*'] - assert starg['sourceIgmp'] == 1 - assert starg['joinState'] == "Joined" - assert starg['regState'] == "RegNoInfo" - assert starg['sptBit'] == 0 - #tgen.mininet_cli() + out = r1.vtysh_cmd("show ip pim upstream json", isjson=True) + expected = { + '229.1.1.2': { + '*': { + 'sourceIgmp': 1, + 'joinState': 'Joined', + 'regState': 'RegNoInfo', + 'sptBit': 0, + } + } + } + + assert topotest.json_cmp(out, expected) is None, 'failed to converge pim' def test_memory_leak(): From 56f0bea71861da9107da86b2e880dadaa64ac52b Mon Sep 17 00:00:00 2001 From: Ruben Kerkhof Date: Wed, 20 Mar 2019 20:08:33 +0100 Subject: [PATCH 084/142] doc: fix a couple of typos Found with https://github.com/codespell-project/codespell Signed-off-by: Ruben Kerkhof --- doc/developer/building-frr-for-centos6.rst | 4 ++-- doc/developer/building-frr-for-centos7.rst | 2 +- doc/developer/building-frr-for-fedora24.rst | 2 +- doc/developer/building-frr-for-freebsd10.rst | 2 +- doc/developer/building-frr-for-freebsd11.rst | 2 +- doc/developer/building-frr-for-freebsd9.rst | 2 +- doc/developer/building-frr-for-openwrt.rst | 4 ++-- doc/developer/hooks.rst | 2 +- doc/developer/logging.rst | 2 +- doc/developer/memtypes.rst | 2 +- doc/developer/ospf-api.rst | 4 ++-- doc/developer/ospf-sr.rst | 18 +++++++++--------- doc/developer/topotests-snippets.rst | 12 ++++++------ doc/developer/topotests.rst | 4 ++-- doc/developer/vtysh.rst | 6 +++--- doc/developer/workflow.rst | 2 +- doc/user/basic.rst | 2 +- doc/user/bgp.rst | 14 +++++++------- doc/user/flowspec.rst | 4 ++-- doc/user/installation.rst | 2 +- doc/user/ospfd.rst | 2 +- doc/user/pbr.rst | 2 +- doc/user/pim.rst | 4 ++-- doc/user/sharp.rst | 2 +- doc/user/zebra.rst | 4 ++-- 25 files changed, 53 insertions(+), 53 deletions(-) diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst index c57573cb9f..f54d6beb80 100644 --- a/doc/developer/building-frr-for-centos6.rst +++ b/doc/developer/building-frr-for-centos6.rst @@ -24,7 +24,7 @@ CentOS 6 restrictions: PIMd is needed - MPLS is not supported on ``CentOS 6``. MPLS requires Linux Kernel 4.5 or higher (LDP can be built, but may have limited use without MPLS) -- Zebra is unable to detect what bridge/vrf an interface is associcated +- Zebra is unable to detect what bridge/vrf an interface is associated with (IFLA\_INFO\_SLAVE\_KIND does not exist in the kernel headers, you can use a newer kernel + headers to get this functionality) - frr\_reload.py will not work, as this requires Python 2.7, and CentOS @@ -235,7 +235,7 @@ settings):: # Controls source route verification net.ipv4.conf.default.rp_filter = 0 -Load the modifed sysctl's on the system: +Load the modified sysctl's on the system: .. code-block:: shell diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst index 8f82cd6c9a..df7ba1d974 100644 --- a/doc/developer/building-frr-for-centos7.rst +++ b/doc/developer/building-frr-for-centos7.rst @@ -127,7 +127,7 @@ following content: net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1 -Load the modifed sysctl's on the system: +Load the modified sysctl's on the system: :: diff --git a/doc/developer/building-frr-for-fedora24.rst b/doc/developer/building-frr-for-fedora24.rst index 2edf9b3e44..a8f305b6c0 100644 --- a/doc/developer/building-frr-for-fedora24.rst +++ b/doc/developer/building-frr-for-fedora24.rst @@ -126,7 +126,7 @@ required MPLS similar to ``net.mpls.conf.eth0.input=1``) net.mpls.conf.eth2.input=1 net.mpls.platform_labels=100000 -Load the modifed sysctl's on the system: +Load the modified sysctl's on the system: :: diff --git a/doc/developer/building-frr-for-freebsd10.rst b/doc/developer/building-frr-for-freebsd10.rst index a6539309a2..5d0a7f6cbb 100644 --- a/doc/developer/building-frr-for-freebsd10.rst +++ b/doc/developer/building-frr-for-freebsd10.rst @@ -11,7 +11,7 @@ FreeBSD 10 restrictions: Install required packages ------------------------- -Add packages: (Allow the install of the package managment tool if this +Add packages: (Allow the install of the package management tool if this is first package install and asked) :: diff --git a/doc/developer/building-frr-for-freebsd11.rst b/doc/developer/building-frr-for-freebsd11.rst index 16d06e0a66..c85255e6ee 100644 --- a/doc/developer/building-frr-for-freebsd11.rst +++ b/doc/developer/building-frr-for-freebsd11.rst @@ -11,7 +11,7 @@ FreeBSD 11 restrictions: Install required packages ------------------------- -Add packages: (Allow the install of the package managment tool if this +Add packages: (Allow the install of the package management tool if this is first package install and asked) .. code-block:: shell diff --git a/doc/developer/building-frr-for-freebsd9.rst b/doc/developer/building-frr-for-freebsd9.rst index 36492fb886..4009f1b8d3 100644 --- a/doc/developer/building-frr-for-freebsd9.rst +++ b/doc/developer/building-frr-for-freebsd9.rst @@ -11,7 +11,7 @@ FreeBSD 9 restrictions: Install required packages ------------------------- -Add packages: (Allow the install of the package managment tool if this +Add packages: (Allow the install of the package management tool if this is first package install and asked) :: diff --git a/doc/developer/building-frr-for-openwrt.rst b/doc/developer/building-frr-for-openwrt.rst index b9be1b5226..8f72ab5d9d 100644 --- a/doc/developer/building-frr-for-openwrt.rst +++ b/doc/developer/building-frr-for-openwrt.rst @@ -63,10 +63,10 @@ Usage ----- Edit ``/usr/sbin/frr.init`` and add/remove the daemons name in section -``DAEMONS=`` or don't install unneded packages For example: zebra bgpd ldpd +``DAEMONS=`` or don't install unneeded packages For example: zebra bgpd ldpd isisd nhrpd ospfd ospf6d pimd ripd ripngd -Enable the serivce +Enable the service ^^^^^^^^^^^^^^^^^^ - ``service frr enable`` diff --git a/doc/developer/hooks.rst b/doc/developer/hooks.rst index 4140a0d171..10fe6b9c43 100644 --- a/doc/developer/hooks.rst +++ b/doc/developer/hooks.rst @@ -6,7 +6,7 @@ Hooks Libfrr provides type-safe subscribable hook points where other pieces of code can add one or more callback functions. "type-safe" in this case applies to the function pointers used for subscriptions. The -implementations checks (at compile-time) wheter a callback to be added has +implementations checks (at compile-time) whether a callback to be added has the appropriate function signature (parameters) for the hook. Example: diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst index 4338d900e6..1dc1885158 100644 --- a/doc/developer/logging.rst +++ b/doc/developer/logging.rst @@ -18,7 +18,7 @@ maybe by a syslog collector from all routers.) Therefore, anything that needs to get the user in the loop—and only these things—are warnings or errors. -Note that this doesn't neccessarily mean the user needs to fix something in +Note that this doesn't necessarily mean the user needs to fix something in the FRR instance. It also includes when we detect something else needs fixing, for example another router, the system we're running on, or the configuration. The common point is that the user should probably do diff --git a/doc/developer/memtypes.rst b/doc/developer/memtypes.rst index 43cbe002cf..153131bab9 100644 --- a/doc/developer/memtypes.rst +++ b/doc/developer/memtypes.rst @@ -3,7 +3,7 @@ Memtypes ======== -FRR includes wrappers arround ``malloc()`` and ``free()`` that count the number +FRR includes wrappers around ``malloc()`` and ``free()`` that count the number of objects currently allocated, for each of a defined ``MTYPE``. To this extent, there are *memory groups* and *memory types*. Each memory diff --git a/doc/developer/ospf-api.rst b/doc/developer/ospf-api.rst index 90fc52efd0..f4f38a63e9 100644 --- a/doc/developer/ospf-api.rst +++ b/doc/developer/ospf-api.rst @@ -284,7 +284,7 @@ Each message begins with the following header: The message type field can take one of the following values: +-------------------------------+---------+ -| Messages to OSPF deamon | Value | +| Messages to OSPF daemon | Value | +===============================+=========+ | MSG\_REGISTER\_OPAQUETYPE | 1 | +-------------------------------+---------+ @@ -300,7 +300,7 @@ The message type field can take one of the following values: +-------------------------------+---------+ +-----------------------------+---------+ -| Messages from OSPF deamon | Value | +| Messages from OSPF daemon | Value | +=============================+=========+ | MSG\_REPLY | 10 | +-----------------------------+---------+ diff --git a/doc/developer/ospf-sr.rst b/doc/developer/ospf-sr.rst index 4a673b155b..23bc803d76 100644 --- a/doc/developer/ospf-sr.rst +++ b/doc/developer/ospf-sr.rst @@ -31,7 +31,7 @@ Implementation details Concepts ^^^^^^^^ -Segment Routing used 3 differents OPAQUE LSA in OSPF to carry the various +Segment Routing used 3 different OPAQUE LSA in OSPF to carry the various information: * **Router Information:** flood the Segment Routing capabilities of the node. @@ -40,7 +40,7 @@ information: * **Extended Link:** flood the Adjaceny and Lan Adjacency Segment Identifier * **Extended Prefix:** flood the Prefix Segment Identifier -The implementation follow previous TE and Router Information codes. It used the +The implementation follows previous TE and Router Information codes. It used the OPAQUE LSA functions defined in ospf_opaque.[c,h] as well as the OSPF API. This latter is mandatory for the implementation as it provides the Callback to Segment Routing functions (see below) when an Extended Link / Prefix or Router @@ -71,7 +71,7 @@ The figure below shows the relation between the various files: (4.0.0.0), Extended Prefix (7.0.0.X) and Link (8.0.0.X) by ospf_ri.c, respectively ospf_ext.c. * ospf_ri.c send back to ospf_sr.c received Router Information LSA and update - Self Router Information LSA with paramters provided by ospf_sr.c i.e. SRGB + Self Router Information LSA with parameters provided by ospf_sr.c i.e. SRGB and MSD. It use ospf_opaque.c functions to send/received these Opaque LSAs. * ospf_ext.c send back to ospf_sr.c received Extended Prefix and Link Opaque LSA and send self Extended Prefix and Link Opaque LSA through ospf_opaque.c @@ -129,8 +129,8 @@ Opaque LSA it is the `ospf_opaque_lsa_install_hook()`. For deletion, it is Note that incoming LSA which is already present in the LSDB will be inserted after the old instance of this LSA remove from the LSDB. Thus, after the first time, each incoming LSA will trigger a `delete` following by an `install`. This -is not very helpfull to handle real LSA deletion. In fact, LSA deletion is done -by Flushing LSA i.e. flood LSA after seting its age to MAX_AGE. Then, a garbage +is not very helpful to handle real LSA deletion. In fact, LSA deletion is done +by Flushing LSA i.e. flood LSA after setting its age to MAX_AGE. Then, a garbage function has the role to remove all LSA with `age == MAX_AGE` in the LSDB. So, to handle LSA Flush, the best is to look to the LSA age to determine if it is an installation or a future deletion i.e. the flushed LSA is first store in the @@ -144,7 +144,7 @@ introduced. When this command is activated, function `ospf_router_info_update_sr()` is called to indicate to Router Information process that Segment Routing TLVs must be flood. Same function is called to modify the Segment Routing Global Block (SRGB) and Maximum Stack Depth (MSD) -TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possiblity +TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possibility to modify this TLV is offer by the code. When Opaque LSA Tyep 4 i.e. Router Information are stored in LSDB, function @@ -159,8 +159,8 @@ Extended Link Prefix LSAs ^^^^^^^^^^^^^^^^^^^^^^^^^ Like for Router Information, Segment Routing is activate at the Extended -Link/Prefix level with new `segment-routing on` command. This trigger -automtically the flooding of Extended Link LSA for all ospf interface where +Link/Prefix level with new `segment-routing on` command. This triggers +automatically the flooding of Extended Link LSA for all ospf interfaces where adjacency is full. For Extended Prefix LSA, the new CLI command `segment-routing prefix ...` will trigger the flooding of Prefix SID TLV/SubTLVs. @@ -255,7 +255,7 @@ The first segment-routing statement enable it. The Second one set the SRGB, third line the MSD and finally, set the Prefix SID index for a given prefix. Note that only prefix of Loopback interface could be configured with a Prefix SID. It is possible to add `no-php-flag` at the end of the prefix command to -disbale Penultimate Hop Popping. This advertises peers that they MUST NOT pop +disable Penultimate Hop Popping. This advertises to peers that they MUST NOT pop the MPLS label prior to sending the packet. Known limitations diff --git a/doc/developer/topotests-snippets.rst b/doc/developer/topotests-snippets.rst index 649229b433..fb3c928a77 100644 --- a/doc/developer/topotests-snippets.rst +++ b/doc/developer/topotests-snippets.rst @@ -48,17 +48,17 @@ A sample of this snippet in a test can be found `here Interacting with equipment ^^^^^^^^^^^^^^^^^^^^^^^^^^ -You might want to interact with the topology equipments during the tests and +You might want to interact with the topology equipment during the tests and there are different ways to do so. Notes: -1. When using the Topogen API, all the equipments code derive from ``Topogear`` +1. When using the Topogen API, all the equipment code derives from ``Topogear`` (`lib/topogen.py `__). If you feel brave you can look by - yourself how the abstractions that will be mentioned here works. + yourself how the abstractions that will be mentioned here work. 2. When not using the ``Topogen`` API there is only one way to interact with - the equipments, which is by calling the ``mininet`` API functions directly + the equipment, which is by calling the ``mininet`` API functions directly to spawn commands. Interacting with the Linux sandbox @@ -149,7 +149,7 @@ Translating vtysh JSON output into Python structures: .. note:: - ``vtysh_(multi)cmd`` is only available for router type of equipments. + ``vtysh_(multi)cmd`` is only available for router types of equipment. Invoking mininet CLI ^^^^^^^^^^^^^^^^^^^^ @@ -195,7 +195,7 @@ Loading JSON from a file: Comparing JSON output ^^^^^^^^^^^^^^^^^^^^^ -After obtaining JSON output formated with Python data structures, you may use +After obtaining JSON output formatted with Python data structures, you may use it to assert a minimalist schema: .. code:: py diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index aa06c8dffd..605b9c9a0c 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -151,7 +151,7 @@ Collect Memory Leak Information ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FRR processes have the capabilities to report remaining memory allocations upon -exit. To enable the reporting of the memory, define an enviroment variable +exit. To enable the reporting of the memory, define an environment variable ``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.:: export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" @@ -410,7 +410,7 @@ Defining the Topology The first step to write a new test is to define the topology. This step can be done in many ways, but the recommended is to use Graphviz to generate a drawing of the topology. It allows us to see the topology graphically and to see the -names of equipments, links and addresses. +names of equipment, links and addresses. Here is an example of Graphviz dot file that generates the template topology :file:`tests/topotests/example-test/test_template.dot` (the inlined code might diff --git a/doc/developer/vtysh.rst b/doc/developer/vtysh.rst index 4a52eb0544..160676a7b1 100644 --- a/doc/developer/vtysh.rst +++ b/doc/developer/vtysh.rst @@ -43,7 +43,7 @@ simplifying the output. This is discussed in :ref:`vtysh-configuration`. Command Extraction ------------------ -When VTYSH is a built, a Perl script named :file:`extract.pl` searches the FRR +When VTYSH is built, a Perl script named :file:`extract.pl` searches the FRR codebase looking for ``DEFUN``'s. It extracts these ``DEFUN``'s, transforms them into ``DEFSH``'s and appends them to ``vtysh_cmd.c``. Each ``DEFSH`` contains the name of the command plus ``_vtysh``, as well as a flag that @@ -167,7 +167,7 @@ Protocol VTYSH communicates with FRR daemons by way of domain socket. Each daemon creates its own socket, typically in :file:`/var/run/frr/.vty`. The protocol is very simple. In the VTYSH to daemon direction, messages are simply -NULL-terminated strings, whose content are CLI commands. Here is a typical +NUL-terminated strings, whose content are CLI commands. Here is a typical message from VTYSH to a daemon: :: @@ -178,7 +178,7 @@ message from VTYSH to a daemon: 00000010: 6c0a 00 l.. -The response format has some more data in it. First is a NULL-terminated string +The response format has some more data in it. First is a NUL-terminated string containing the plaintext response, which is just the output of the command that was sent in the request. This is displayed to the user. The plaintext response is followed by 3 null marker bytes, followed by a 1-byte status code that diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 1bb0886fd5..0ecdf14af0 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -128,7 +128,7 @@ branch is required. The work can be shared by multiple people. In all cases, the must be at least one person that is in charge of the maintenance branch. The person on people responsible for a maintenance branch must be a FRR maintainer. Note that they may choose to abandon support for the maintenance branch at any time. If -noone takes over the responsibility of the LTS branch, then the support will be +no one takes over the responsibility of the LTS branch, then the support will be discontinued. The LTS branch duties are the following ones: diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 8201fdf1b9..8fbea29ee7 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -390,7 +390,7 @@ Terminal Mode Commands .. index:: find COMMAND... .. clicmd:: find COMMAND... - This commmand performs a simple substring search across all defined commands + This command performs a simple substring search across all defined commands in all modes. As an example, suppose you're in enable mode and can't remember where the command to turn OSPF segment routing on is: diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 5b453e75c3..77cac72eeb 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1145,7 +1145,7 @@ is 4 octet long. The following format is used to define the community value. ``graceful-shutdown`` represents well-known communities value ``GRACEFUL_SHUTDOWN`` ``0xFFFF0000`` ``65535:0``. :rfc:`8326` implements the purpose Graceful BGP Session Shutdown to reduce the amount of - lost traffic when taking BGP sessions down for maintainance. The use + lost traffic when taking BGP sessions down for maintenance. The use of the community needs to be supported from your peers side to actually have any effect. @@ -1176,20 +1176,20 @@ is 4 octet long. The following format is used to define the community value. ``llgr-stale`` ``llgr-stale`` represents well-known communities value ``LLGR_STALE`` ``0xFFFF0006`` ``65535:6``. - Assigned and intented only for use with routers supporting the + Assigned and intended only for use with routers supporting the Long-lived Graceful Restart Capability as described in [Draft-IETF-uttaro-idr-bgp-persistence]_. - Routers recieving routes with this community may (depending on + Routers receiving routes with this community may (depending on implementation) choose allow to reject or modify routes on the presence or absence of this community. ``no-llgr`` ``no-llgr`` represents well-known communities value ``NO_LLGR`` ``0xFFFF0007`` ``65535:7``. - Assigned and intented only for use with routers supporting the + Assigned and intended only for use with routers supporting the Long-lived Graceful Restart Capability as described in [Draft-IETF-uttaro-idr-bgp-persistence]_. - Routers recieving routes with this community may (depending on + Routers receiving routes with this community may (depending on implementation) choose allow to reject or modify routes on the presence or absence of this community. @@ -1251,7 +1251,7 @@ UPDATE messages. There are two types of community list: standard - This type accepts an explicit value for the atttribute. + This type accepts an explicit value for the attribute. expanded This type accepts a regular expression. Because the regex must be @@ -2469,7 +2469,7 @@ certainly contains silly mistakes, if not serious flaws. route-map rm-no-export permit 20 ! route-map rm-blackhole permit 10 - description blackhole, up-pref and ensure it cant escape this AS + description blackhole, up-pref and ensure it can not escape this AS set ip next-hop 127.0.0.1 set local-preference 10 set community additive no-export diff --git a/doc/user/flowspec.rst b/doc/user/flowspec.rst index f6af88cac8..b274afe8a2 100644 --- a/doc/user/flowspec.rst +++ b/doc/user/flowspec.rst @@ -167,7 +167,7 @@ set. That VRF will then be selected. The below full configuration example depicts how Route Targets are configured and how VRFs and cross VRF configuration is done. Note that the VRF are mapped on Linux Network Namespaces. For data traffic to cross VRF boundaries, virtual ethernet -interfaces are created with private IP adressing scheme. +interfaces are created with private IP addressing scheme. .. code-block:: frr @@ -322,7 +322,7 @@ There are some other known issues: - The validation procedure depicted in :rfc:`5575` is not available. This validation procedure has not been implemented, as this feature was not - used in the existing setups you shared wih us. + used in the existing setups you shared with us. - The filtering action shaper value, if positive, is not used to apply shaping. diff --git a/doc/user/installation.rst b/doc/user/installation.rst index e191ebd035..964297292f 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -272,7 +272,7 @@ options from the list below. .. option:: --enable-multipath=X Compile FRR with up to X way ECMP supported. This number can be from 0-999. - For backwards compatability with older configure options when setting X = 0, + For backwards compatibility with older configure options when setting X = 0, we will build FRR with 64 way ECMP. This is needed because there are hardcoded arrays that FRR builds towards, so we need to know how big to make these arrays at build time. Additionally if this parameter is diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index b6a7cd5de0..ad0a8639a3 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -218,7 +218,7 @@ To start OSPF process you have to specify the OSPF router. SPF-triggering event occurs within the hold-time of the previous SPF calculation. - This command supercedes the *timers spf* command in previous FRR + This command supersedes the *timers spf* command in previous FRR releases. .. index:: max-metric router-lsa [on-startup|on-shutdown] (5-86400) diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index 638767c557..6230bf777a 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -88,7 +88,7 @@ end destination. When a incoming packet matches the destination prefix specified, take the packet and forward according to the nexthops specified. This command accepts - both v4 and v6 prefixes. This command is used in conjuction of the + both v4 and v6 prefixes. This command is used in conjunction of the :clicmd:`match src-ip PREFIX` command for matching. .. clicmd:: set nexthop-group NAME diff --git a/doc/user/pim.rst b/doc/user/pim.rst index feb77db1e1..f4611c520b 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -210,8 +210,8 @@ is in a vrf, enter the interface command with the vrf keyword at the end. Set the IGMP version used on this interface. The default value is 3. -.. index:: ip multicat boundary oil WORD -.. clicmd:: ip multicat boundary oil WORD +.. index:: ip multicast boundary oil WORD +.. clicmd:: ip multicast boundary oil WORD Set a pim multicast boundary, based upon the WORD prefix-list. If a pim join or IGMP report is received on this interface and the Group is denied by the diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index ca8f1f512f..4568c2a901 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -29,7 +29,7 @@ documented elsewhere. Using SHARP =========== -All sharp commands are under the enable node and preceeded by the ``sharp`` +All sharp commands are under the enable node and preceded by the ``sharp`` keyword. At present, no sharp commands will be preserved in the config. .. index:: sharp install diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 9dfe1ea39c..a7bf0c74da 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -380,7 +380,7 @@ At startup, FRR detects the presence of that file. It detects that the file statistics information matches the same file statistics information as `/proc/self/ns/net` ( through stat() function). As statistics information matches, then `vrf0` stands for the new default namespace name. -Consequently, the VRF naming `Default` will be overriden by the new discovered +Consequently, the VRF naming `Default` will be overridden by the new discovered namespace name `vrf0`. For those who don't use VRF backend with *Linux network namespace*, it is @@ -422,7 +422,7 @@ in routing entry, and can be configured like a route: .. index:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL .. clicmd:: [no] ip route NETWORK MASK GATEWAY|INTERFACE label LABEL - NETWORK ans MASK stand for the IP prefix entry to be added as static + NETWORK and MASK stand for the IP prefix entry to be added as static route entry. GATEWAY is the gateway IP address to reach, in order to reach the prefix. INTERFACE is the interface behind which the prefix is located. From f6aa36f5c6b29dd62a706fde4d8fd0f8debb3ae8 Mon Sep 17 00:00:00 2001 From: Ruben Kerkhof Date: Wed, 20 Mar 2019 21:20:31 +0100 Subject: [PATCH 085/142] doc: address review comment 'cannot' feels more natural Signed-off-by: Ruben Kerkhof --- doc/user/bgp.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 77cac72eeb..06f95a9bc3 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -2469,7 +2469,7 @@ certainly contains silly mistakes, if not serious flaws. route-map rm-no-export permit 20 ! route-map rm-blackhole permit 10 - description blackhole, up-pref and ensure it can not escape this AS + description blackhole, up-pref and ensure it cannot escape this AS set ip next-hop 127.0.0.1 set local-preference 10 set community additive no-export From 73fb891892e10155ce1e9c264cab14e59b8e74f7 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Wed, 20 Mar 2019 21:25:04 +0000 Subject: [PATCH 086/142] Revert "Merge pull request #3982 from pacovn/Coverity_1479148_copy_paste" This reverts commit 3a3704fe365a25b9644a938f674effb3e6084c56, reversing changes made to 5a3c6e736dca3639a1b49cdf305b909736f721de. --- zebra/zebra_rib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 77cb38855d..5fa51ada45 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1932,7 +1932,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) dplane_ctx_get_vrf(ctx), dest_str, old_re); } else - UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED); + UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); } switch (op) { From 749afd7dcef9f3fcc3f30b27722fb26c990529e1 Mon Sep 17 00:00:00 2001 From: Rubens Figueiredo Date: Wed, 20 Mar 2019 14:24:25 +0100 Subject: [PATCH 087/142] doc: route reflector documentation Signed-off-by: Rubens Figueiredo --- doc/user/bgp.rst | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 5b453e75c3..3aee1940bc 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -511,8 +511,8 @@ cause may lead to routing instability or oscillation across multiple speakers in iBGP topologies. This can occur with full-mesh iBGP, but is particularly problematic in non-full-mesh iBGP topologies that further reduce the routing information known to each speaker. This has primarily been documented with iBGP -route-reflection topologies. However, any route-hiding technologies potentially -could also exacerbate oscillation with MED. +:ref:`route-reflection ` topologies. However, any +route-hiding technologies potentially could also exacerbate oscillation with MED. This second issue occurs where speakers each have only a subset of routes, and there are cycles in the preferences between different combinations of routes - @@ -2240,10 +2240,15 @@ Displaying Routes by AS Path Route Reflector =============== -.. note:: This documentation is woefully incomplete. +BGP routers connected inside the same AS through BGP belong to an internal +BGP session, or IBGP. In order to prevent routing table loops, IBGP does not +advertise IBGP-learned routes to other routers in the same session. As such, +IBGP requires a full mesh of all peers. For large networks, this quickly becomes +unscalable. Introducing route reflectors removes the need for the full-mesh. -.. index:: bgp cluster-id A.B.C.D -.. clicmd:: bgp cluster-id A.B.C.D +When route reflectors are configured, these will reflect the routes announced +by the peers configured as clients. A route reflector client is configured +with: .. index:: neighbor PEER route-reflector-client .. clicmd:: neighbor PEER route-reflector-client @@ -2251,6 +2256,13 @@ Route Reflector .. index:: no neighbor PEER route-reflector-client .. clicmd:: no neighbor PEER route-reflector-client +To avoid single points of failure, multiple route reflectors can be configured. + +A cluster is a collection of route reflectors and their clients, and is used +by route reflectors to avoid looping. + +.. index:: bgp cluster-id A.B.C.D +.. clicmd:: bgp cluster-id A.B.C.D .. _routing-policy: From 81b834a59d314094552468091feb70d7bd01ff8d Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 19 Feb 2019 00:44:01 +0100 Subject: [PATCH 088/142] redhat: switch to new init script Drop the special versions of frr.init/frr.service/daemons from redhat/ and use the generic versions instead. Tested-by: Liam McBirnie Signed-off-by: David Lamparter --- Makefile.am | 3 - redhat/daemons | 86 ------- redhat/frr.init | 577 --------------------------------------------- redhat/frr.service | 24 -- redhat/frr.spec.in | 11 +- 5 files changed, 4 insertions(+), 697 deletions(-) delete mode 100644 redhat/daemons delete mode 100755 redhat/frr.init delete mode 100644 redhat/frr.service diff --git a/Makefile.am b/Makefile.am index 6e3c2a4181..43bad72545 100644 --- a/Makefile.am +++ b/Makefile.am @@ -175,9 +175,6 @@ EXTRA_DIST += \ python/clidef.py \ python/clippy/__init__.py \ \ - redhat/frr.init \ - redhat/frr.service \ - redhat/daemons \ redhat/frr.logrotate \ redhat/frr.pam \ redhat/frr.spec \ diff --git a/redhat/daemons b/redhat/daemons deleted file mode 100644 index 7f3ff36df9..0000000000 --- a/redhat/daemons +++ /dev/null @@ -1,86 +0,0 @@ -# This file tells the frr package which daemons to start. -# -# Entries are in the format: =(yes|no|priority) -# 0, "no" = disabled -# 1, "yes" = highest priority -# 2 .. 10 = lower priorities -# -# For daemons which support multiple instances, a 2nd line listing -# the instances can be added. Eg for ospfd: -# ospfd=yes -# ospfd_instances="1,2" -# -# Priorities were suggested by Dancer . -# They're used to start the FRR daemons in more than one step -# (for example start one or two at network initialization and the -# rest later). The number of FRR daemons being small, priorities -# must be between 1 and 9, inclusive (or the initscript has to be -# changed). /etc/init.d/frr then can be started as -# -# /etc/init.d/frr > -# -# where priority 0 is the same as 'stop', priority 10 or 'start' -# means 'start all' -# -# Sample configurations for these daemons can be found in -# /usr/share/doc/frr/examples/. -# -# ATTENTION: -# -# When activation a daemon at the first time, a config file, even if it is -# empty, has to be present *and* be owned by the user and group "frr", else -# the daemon will not be started by /etc/init.d/frr. The permissions should -# be u=rw,g=r,o=. -# When using "vtysh" such a config file is also needed. It should be owned by -# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. -# -watchfrr_enable=yes -watchfrr_options="-r '/usr/lib/frr/frr restart %s' -s '/usr/lib/frr/frr start %s' -k '/usr/lib/frr/frr stop %s'" -# -zebra=no -bgpd=no -ospfd=no -ospf6d=no -ripd=no -ripngd=no -isisd=no -ldpd=no -pimd=no -nhrpd=no -eigrpd=no -babeld=no -sharpd=no -pbrd=no -staticd=no -bfdd=no -fabricd=no - -# -# Command line options for the daemons -# -zebra_options=("-A 127.0.0.1") -bgpd_options=("-A 127.0.0.1") -ospfd_options=("-A 127.0.0.1") -ospf6d_options=("-A ::1") -ripd_options=("-A 127.0.0.1") -ripngd_options=("-A ::1") -isisd_options=("-A 127.0.0.1") -ldpd_options=("-A 127.0.0.1") -pimd_options=("-A 127.0.0.1") -nhrpd_options=("-A 127.0.0.1") -eigrpd_options=("-A 127.0.0.1") -babeld_options=("-A 127.0.0.1") -sharpd_options=("-A 127.0.0.1") -pbrd_options=("-A 127.0.0.1") -staticd_options=("-A 127.0.0.1") -bfdd_options=("-A 127.0.0.1") -fabricd_options=("-A 127.0.0.1") - -# -# If the vtysh_enable is yes, then the unified config is read -# and applied if it exists. If no unified frr.conf exists -# then the per-daemon .conf files are used) -# If vtysh_enable is no or non-existant, the frr.conf is ignored. -# it is highly suggested to have this set to yes -vtysh_enable=yes - diff --git a/redhat/frr.init b/redhat/frr.init deleted file mode 100755 index b59656adcd..0000000000 --- a/redhat/frr.init +++ /dev/null @@ -1,577 +0,0 @@ -#!/bin/bash -# -# /etc/rc.d/init.d/frr -# -# Start/Stop the FRR Routing daemons -# -# -# chkconfig: 2345 15 85 -# -# description: FRRouting (FRR) is a routing suite for IP routing protocols -# like BGP, OSPF, RIP and others. This script contols the main -# daemon "frr" as well as the individual protocol daemons. -# -### BEGIN INIT INFO -# Provides: frr -# Required-Start: $local_fs $network $syslog -# Required-Stop: $local_fs $syslog -# Should-Start: $syslog -# Should-Stop: $network $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Start/Stop the FRR Routing daemons -# Description: FRRouting (FRR) is a routing suite for IP routing protocols -# like BGP, OSPF, RIP and others. This script contols the main -# daemon "frr" as well as the individual protocol daemons. -### END INIT INFO - -PATH=/bin:/usr/bin:/sbin:/usr/sbin -D_PATH=/usr/lib/frr -C_PATH=/etc/frr -V_PATH=/var/run/frr - -# Local Daemon selection may be done by using /etc/frr/daemons. -# See /usr/share/doc/frr/README.Debian.gz for further information. -# Keep zebra first and do not list watchfrr! -DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd pimd pbrd ldpd nhrpd eigrpd babeld staticd sharpd bfdd fabricd" -MAX_INSTANCES=5 -RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py - -. /etc/init.d/functions - -# Print the name of the pidfile. -pidfile() -{ - echo "$V_PATH/$1.pid" -} - -# Print the name of the vtysh. -vtyfile() -{ - echo "$V_PATH/$1.vty" -} - -# Check if daemon is started by using the pidfile. -started() -{ - [ ! -e `pidfile $1` ] && return 3 - if [ -n "$2" ] && [ "$2" == "log" ]; then - status -p `pidfile $1` $1 && return 0 || return $? - else - kill -0 `cat \`pidfile $1\`` 2> /dev/null || return 1 - return 0 - fi -} - -# Loads the config via vtysh -b if configured to do so. -vtysh_b () -{ - # Rember, that all variables have been incremented by 1 in convert_daemon_prios() - if [ "$vtysh_enable" = 2 -a -f $C_PATH/frr.conf ]; then - /usr/bin/vtysh -b -n - fi -} - -# Check if the daemon is activated and if its executable and config files -# are in place. -# params: daemon name -# returns: 0=ok, 1=error -check_daemon() -{ - # If the integrated config file is used the others are not checked. - if [ -r "$C_PATH/frr.conf" ]; then - return 0 - fi - - # vtysh_enable has no config file nor binary so skip check. - # (Not sure why vtysh_enable is in this list but does not hurt) - if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then - # check for daemon binary - if [ ! -x "$D_PATH/$1" ]; then return 1; fi - - # check for config file - if [ -n "$2" ]; then - if [ ! -r "$C_PATH/$1-$2.conf" ]; then - touch "$C_PATH/$1-$2.conf" - chown frr:frr "$C_PATH/$1-$2.conf" - fi - elif [ ! -r "$C_PATH/$1.conf" ]; then - touch "$C_PATH/$1.conf" - chown frr:frr "$C_PATH/$1.conf" - fi - fi - return 0 -} - -# Starts the server if it's not already running according to the pid file. -# The Frr daemons creates the pidfile when starting. -start() -{ - local dmn inst - dmn="$1" - inst="$2" - - ulimit -n $MAX_FDS > /dev/null 2> /dev/null - if [ "$dmn" = "watchfrr" ]; then - - # We may need to restart watchfrr if new daemons are added and/or - # removed - if started "$dmn" ; then - stop watchfrr - else - # Echo only once. watchfrr is printed in the stop above - echo -n " $dmn" - fi - - if [ -e /var/run/frr/watchfrr.started ] ; then - rm /var/run/frr/watchfrr.started - fi - # redhat /etc/init.d/functions daemon() re-expands args :( - # eval "set - $watchfrr_options" - daemon --pidfile=`pidfile $dmn` "$D_PATH/$dmn" -d "$watchfrr_options" - RETVAL=$? - [ $RETVAL -ne 0 ] && break - for i in `seq 1 10`; - do - if [ -e /var/run/frr/watchfrr.started ] ; then - RETVAL=0 - break - else - sleep 1 - fi - done - RETVAL=1 - elif [ -n "$inst" ]; then - echo -n " $dmn-$inst" - if ! check_daemon $dmn $inst ; then - echo -n " (binary does not exist)" - return; - fi - daemon --pidfile=`pidfile $dmn-$inst` "$D_PATH/$dmn" -d `eval echo "$""$dmn""_options"` -n "$inst" - RETVAL=$? - else - echo -n " $dmn " - if ! check_daemon $dmn; then - echo " (binary does not exist)" - return; - fi - daemon --pidfile=`pidfile $dmn` "$D_PATH/$dmn" -d `eval echo "$""$dmn""_options"` - RETVAL=$? - fi - echo - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$dmn - return $RETVAL -} - -# Stop the daemon given in the parameter, printing its name to the terminal. -stop() -{ - local inst - - if [ -n "$2" ]; then - inst="$1-$2" - else - inst="$1" - fi - - if ! started "$inst" ; then - # echo -n " ($inst)" - return 0 - else - echo -n " $inst" - PIDFILE=`pidfile $inst` - PID=`cat $PIDFILE 2>/dev/null` - killproc -p "$PIDFILE" "$D_PATH/$1" - RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f $lockfile - rm -f `pidfile $inst` - rm -f `vtyfile $inst` - echo - return $RETVAL - fi -} - -# Converts values from /etc/frr/daemons to all-numeric values. -convert_daemon_prios() -{ - for name in $DAEMONS zebra vtysh_enable watchfrr_enable; do - # First, assign the value set by the user to $value - eval value=\${${name}:0:3} - - # Daemon not activated or entry missing? - if [ "$value" = "no" -o "$value" = "" ]; then value=0; fi - - # These strings parsed for backwards compatibility. - if [ "$value" = "yes" -o "$value" = "true" ]; then - value=1; - fi - - # Zebra is threatened special. It must be between 0=off and the first - # user assigned value "1" so we increase all other enabled daemons' values. - if [ "$name" != "zebra" -a "$value" -gt 0 ]; then value=`expr "$value" + 1`; fi - - # If e.g. name is zebra then we set "zebra=yes". - eval $name=$value - done -} - -# Starts watchfrr for all wanted daemons. -start_watchfrr() -{ - local daemon_name - local daemon_prio - local found_one - local daemon_inst - - # Start the monitor daemon only if desired. - if [ 0 -eq "$watchfrr_enable" ]; then - return - fi - - # Check variable type - if declare -p watchfrr_options | grep -q '^declare \-a'; then - # old array support - watchfrr_options="${watchfrr_options[@]}" - fi - - # Which daemons have been started? - found_one=0 - for daemon_name in $DAEMONS; do - eval daemon_prio=\$$daemon_name - if [ "$daemon_prio" -gt 0 ]; then - eval "daemon_inst=\${${daemon_name}_instances//,/ }" - if [ -n "$daemon_inst" ]; then - for inst in ${daemon_inst}; do - eval "inst_disable=\${${daemon_name}_${inst}}" - if [ -z ${inst_disable} ] || [ ${inst_disable} != 0 ]; then - if check_daemon $daemon_name $inst; then - watchfrr_options="$watchfrr_options ${daemon_name}-${inst}" - fi - fi - done - else - if check_daemon $daemon_name; then - watchfrr_options="$watchfrr_options $daemon_name" - fi - fi - found_one=1 - fi - done - - # Start if at least one daemon is activated. - if [ $found_one -eq 1 ]; then - echo "Starting FRRouting monitor daemon:" - start watchfrr - fi -} - -# Stopps watchfrr. -stop_watchfrr() -{ - echo "Stopping FRRouting monitor daemon:" - stop watchfrr -} - -# Stops all daemons that have a lower level of priority than the given. -# (technically if daemon_prio >= wanted_prio) -stop_prio() -{ - local wanted_prio - local daemon_prio - local daemon_list - local daemon_inst - local inst - - if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then - daemon=${BASH_REMATCH[1]} - inst=${BASH_REMATCH[2]} - else - daemon="$2" - fi - - wanted_prio=$1 - daemon_list=${daemon:-$DAEMONS} - - echo "Stopping FRRouting daemons (prio:$wanted_prio):" - - for prio_i in `seq 10 -1 $wanted_prio`; do - for daemon_name in $daemon_list; do - eval daemon_prio=\${${daemon_name}:0:3} - daemon_inst="" - if [ $daemon_prio -eq $prio_i ]; then - eval "daemon_inst=\${${daemon_name}_instances//,/ }" - if [ -n "$daemon_inst" ]; then - for i in ${daemon_inst}; do - if [ -n "$inst" ] && [ "$i" == "$inst" ]; then - stop "$daemon_name" "$inst" - elif [ x"$inst" == x ]; then - stop "$daemon_name" "$i" - fi - done - else - stop "$daemon_name" - fi - fi - done - done - - if [ -z "$inst" ]; then - # Now stop other daemons that're prowling, coz the daemons file changed - echo "Stopping other FRRouting daemons" - if [ -n "$daemon" ]; then - eval "file_list_suffix="$V_PATH"/"$daemon*"" - else - eval "file_list_suffix="$V_PATH/*"" - fi - for pidfile in $file_list_suffix.pid; do - if [ -f "$pidfile" ]; then - filename=${pidfile##*/} - daemon=${filename%.*} - echo -n " $daemon" - killproc -p "$pidfile" "$daemon" - RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f $lockfile - rm -f "$pidfile" - echo - fi - done - echo -n "Removing remaining .vty files" - for vtyfile in $file_list_suffix.vty; do - rm -rf "$vtyfile" - done - echo - fi -} - -# Starts all daemons that have a higher level of priority than the given. -# (technically if daemon_prio <= wanted_prio) -start_prio() -{ - local wanted_prio - local daemon_prio - local daemon_list - local daemon_name - local daemon_inst - local inst - - if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then - daemon=${BASH_REMATCH[1]} - inst=${BASH_REMATCH[2]} - else - daemon="$2" - fi - - wanted_prio=$1 - daemon_list=${daemon:-$DAEMONS} - - echo "Starting FRRouting daemons (prio:$wanted_prio):" - - for prio_i in `seq 1 $wanted_prio`; do - for daemon_name in $daemon_list; do - eval daemon_prio=\$${daemon_name} - daemon_inst="" - if [ $daemon_prio -eq $prio_i ]; then - eval "daemon_inst=\${${daemon_name}_instances//,/ }" - if [ -n "$daemon_inst" ]; then - if [ `echo "$daemon_inst" | wc -w` -gt ${MAX_INSTANCES} ]; then - echo "Max instances supported is ${MAX_INSTANCES}. Aborting" - exit 1 - fi - # Check if we're starting again by switching from single instance - # to MI version - if started "$daemon_name"; then - PIDFILE=`pidfile $daemon_name` - killproc -p "$PIDFILE" "$daemon_name" - rm -f `pidfile $1` - rm -f `vtyfile $1` - fi - - for i in ${daemon_inst}; do - if [ -n "$inst" ] && [ "$i" == "$inst" ]; then - start "$daemon_name" "$inst" - elif [ x"$inst" == x ]; then - start "$daemon_name" "$i" - fi - done - else - # Check if we're starting again by switching from - # single instance to MI version - eval "file_list_suffix="$V_PATH"/"$daemon_name-*"" - for pidfile in $file_list_suffix.pid; do - if [ -f "$pidfile" ]; then - killproc -p "$pidfile" "$daemon_name" - rm -rf "$pidfile" - fi - done - for vtyfile in $file_list_suffix.vty; do - rm -rf "$vtyfile" - done - - start "$daemon_name" - fi - fi - done - done -} - -check_status() -{ - local daemon_name - local daemon_prio - local daemon_inst - local failed_status=0 - - if [ -n "$1" ] && [[ "$1" =~ (.*)-(.*) ]]; then - daemon=${BASH_REMATCH[1]} - inst=${BASH_REMATCH[2]} - else - daemon="$1" - fi - - daemon_list=${daemon:-$DAEMONS} - - # Which daemons have been started? - for daemon_name in $daemon_list; do - eval daemon_prio=\$$daemon_name - if [ "$daemon_prio" -gt 0 ]; then - eval "daemon_inst=\${${daemon_name}_instances//,/ }" - if [ -n "$daemon_inst" ]; then - for i in ${daemon_inst}; do - if [ -n "$inst" -a "$inst" = "$i" ]; then - started "$1" "log" || failed_status=$? - elif [ -z "$inst" ]; then - started "$daemon_name-$i" "log" || failed_status=$? - fi - done - else - started "$daemon_name" "log" || failed_status=$? - fi - fi - done - - # All daemons that need to have been started are up and running - return $failed_status -} - -######################################################### -# Main program # -######################################################### - -# Config broken but script must exit silently. -[ ! -r "$C_PATH/daemons" ] && exit 0 - -# Load configuration -. "$C_PATH/daemons" - -# Read configuration variable file if it is present -[ -r /etc/sysconfig/frr ] && . /etc/sysconfig/frr - -MAX_INSTANCES=${MAX_INSTANCES:=5} - -# Set priority of un-startable daemons to 'no' and substitute 'yes' to '0' -convert_daemon_prios - -if [ ! -d $V_PATH ]; then - echo "Creating $V_PATH" - mkdir -p $V_PATH - chown frr:frr $V_PATH - chmod 755 /$V_PATH -fi - -if [ -n "$3" ] && [ "$3" != "all" ]; then - dmn="$2"-"$3" -elif [ -n "$2" ] && [ "$2" != "all" ]; then - dmn="$2" -fi - -case "$1" in - start) - # Try to load this necessary (at least for 2.6) module. - if [ -d /lib/modules/`uname -r` ] ; then - echo "Loading capability module if not yet done." - LC_ALL=C modprobe -a capability 2>&1 | egrep -v "(not found|Can't locate)" - fi - - # Start all daemons - cd $C_PATH/ - if [ "$2" != "watchfrr" ]; then - start_prio 10 $dmn - fi - start_watchfrr - vtysh_b - ;; - - 1|2|3|4|5|6|7|8|9|10) - # Stop/start daemons for the appropriate priority level - stop_prio $1 - start_prio $1 - vtysh_b - ;; - - stop|0) - # Stop all daemons at level '0' or 'stop' - stop_watchfrr - if [ "$dmn" != "watchfrr" ]; then - [ -n "${dmn}" ] && eval "${dmn/-/_}=0" - stop_prio 0 $dmn - fi - - if [ -z "$dmn" -o "$dmn" = "zebra" ]; then - echo "Removing all routes made by zebra." - ip route flush proto zebra - # At least in CentOS/RHEL 6, iproute2 doesn't know - # about the new protocol names, so we have to flush them - # by number (it also doesn't support rt_protos.d - ip route flush proto 186 - ip route flush proto 187 - ip route flush proto 188 - ip route flush proto 189 - ip route flush proto 190 - ip route flush proto 191 - ip route flush proto 192 - ip route flush proto 193 - ip route flush proto 194 - else - [ -n "$dmn" ] && eval "${dmn/-/_}=0" - start_watchfrr - fi - ;; - - reload) - # Just apply the commands that have changed, no restart necessary - if [ ! -x "$RELOAD_SCRIPT" ]; then - echo "frr-reload - reload not supported. Use restart or install frr-pythontools package" - exit 1 - fi - NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}" - if [ ! -r $NEW_CONFIG_FILE ]; then - echo "Unable to read configuration file $NEW_CONFIG_FILE. Only supporting integrated config" - exit 1 - fi - echo "Applying only incremental changes to running configuration from frr.conf" - "$RELOAD_SCRIPT" --reload /etc/frr/frr.conf - exit $? - ;; - - status) - check_status $dmn - exit $? - ;; - - restart|force-reload) - $0 stop $dmn - sleep 1 - $0 start $dmn - ;; - - *) - echo "Usage: /etc/init.d/frr {start|stop|status|reload|restart|force-reload|} [daemon]" - echo " E.g. '/etc/init.d/frr 5' would start all daemons with a prio 1-5." - echo " reload applies only modifications from the running config to all daemons." - echo " reload neither restarts starts any daemon nor starts any new ones." - echo " Read /usr/share/doc/frr/README.Debian for details." - exit 1 - ;; -esac - -exit 0 diff --git a/redhat/frr.service b/redhat/frr.service deleted file mode 100644 index 01934a94e2..0000000000 --- a/redhat/frr.service +++ /dev/null @@ -1,24 +0,0 @@ -[Unit] -Description=FRRouting (FRR) -Wants=network.target -After=network-pre.target systemd-sysctl.service -Before=network.target -OnFailure=heartbeat-failed@%n.service - -[Service] -Nice=-5 -Type=forking -NotifyAccess=all -StartLimitInterval=3m -StartLimitBurst=3 -TimeoutSec=2m -WatchdogSec=60s -RestartSec=5 -Restart=on-abnormal -LimitNOFILE=1024 -ExecStart=/usr/lib/frr/frr start -ExecStop=/usr/lib/frr/frr stop -ExecReload=/usr/lib/frr/frr reload - -[Install] -WantedBy=multi-user.target diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 78b1f7c87c..36f9259865 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -376,15 +376,13 @@ rm -vf %{buildroot}%{_libdir}/frr/libyang_plugins/*.la # install /etc sources %if "%{initsystem}" == "systemd" mkdir -p %{buildroot}%{_unitdir} -install -m644 %{zeb_rh_src}/frr.service %{buildroot}%{_unitdir}/frr.service -install %{zeb_rh_src}/frr.init %{buildroot}%{_sbindir}/frr +install -m644 %{zeb_src}/tools/frr.service %{buildroot}%{_unitdir}/frr.service %else mkdir -p %{buildroot}%{_initddir} -install %{zeb_rh_src}/frr.init %{buildroot}%{_sbindir}/frr -ln -s %{_sbindir}/frr %{buildroot}%{_initddir}/frr +ln -s %{_sbindir}/frrinit.sh %{buildroot}%{_initddir}/frr %endif -install %{zeb_rh_src}/daemons %{buildroot}%{_sysconfdir}/frr +install %{zeb_src}/tools/etc/frr/daemons %{buildroot}%{_sysconfdir}/frr # add rpki module to daemon %if %{with_rpki} sed -i -e 's/^\(bgpd_options=\)\(.*\)\(".*\)/\1\2 -M rpki\3/' %{buildroot}%{_sysconfdir}/frr/daemons @@ -474,7 +472,7 @@ zebra_spec_add_service fabricd 2618/tcp "Fabricd vty" # Fix bad path in previous config files # Config files won't get replaced by default, so we do this ugly hack to fix it -%__sed -i 's|/etc/init.d/|%{_sbindir}/|g' %{configdir}/daemons 2> /dev/null || true +%__sed -i 's|watchfrr_options=|#watchfrr_options=|g' %{configdir}/daemons 2> /dev/null || true # With systemd, watchfrr is mandatory. Fix config to make sure it's enabled if # we install or upgrade to a frr built with systemd @@ -632,7 +630,6 @@ fi %else %{_initddir}/frr %endif -%{_sbindir}/frr %config(noreplace) %{_sysconfdir}/pam.d/frr %config(noreplace) %{_sysconfdir}/logrotate.d/frr %{_sbindir}/frr-reload From 33b397711ba753e64ab7e69b2bc6c673e244e7c5 Mon Sep 17 00:00:00 2001 From: Ruben Kerkhof Date: Thu, 21 Mar 2019 14:50:53 +0100 Subject: [PATCH 089/142] tools: fix two typos in daemons file Signed-off-by: Ruben Kerkhof --- tools/etc/frr/daemons | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons index 0fca541137..2abff422c9 100644 --- a/tools/etc/frr/daemons +++ b/tools/etc/frr/daemons @@ -5,7 +5,7 @@ # # ATTENTION: # -# When activation a daemon at the first time, a config file, even if it is +# When activating a daemon for the first time, a config file, even if it is # empty, has to be present *and* be owned by the user and group "frr", else # the daemon will not be started by /etc/init.d/frr. The permissions should # be u=rw,g=r,o=. From 924947e4128627a6e97a67ee0503a7bd7a6bab6c Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Thu, 21 Mar 2019 18:50:25 +0000 Subject: [PATCH 090/142] doc: fix underline level Signed-off-by: Quentin Young --- doc/developer/workflow.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 1bb0886fd5..5687d6971a 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -371,7 +371,7 @@ system in which submissions from an individual representing one company should be merged by someone unaffiliated with that company. Guidelines for code review -"""""""""""""""""""""""""" +-------------------------- - As a rule of thumb, the depth of the review should be proportional to the scope and / or impact of the patch. From 07ff01d255170b24518c97e1346794a59d7cd7e0 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 22 Mar 2019 15:56:11 +0100 Subject: [PATCH 091/142] doc: permit maintenance on more than the 2 last maintenance releases it is possible to do some ponctual backporting of bug fixes, on older than the 2 last maintenance releases. Signed-off-by: Philippe Guibert --- doc/developer/workflow.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 1bb0886fd5..12c6373d53 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -99,9 +99,14 @@ Bugfix releases are made as needed at 1 month intervals until the next ``MAJOR.MINOR`` release branch is pulled. Depending on the severity of the bugs, bugfix releases may occur sooner. -Bugfixes are applied to the two most recent releases. Security fixes are -backported to all releases less than or equal to at least one year old. Security -fixes may also be backported to older releases depending on severity. +Bugfixes are applied to the two most recent releases. However, backporting of bug +fixes to older than the two most recent releases will not be prevented, if acked +under the classical development workflow applying for a pull request. + +Security fixes are backported to all releases less than or equal to at least one +year old. Security fixes may also be backported to older releases depending on +severity. + Long term support branches ( LTS ) ----------------------------------------- From 9251d1f596b15963d9b5d7729a84b96332c54f62 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Thu, 21 Mar 2019 21:08:52 +0000 Subject: [PATCH 092/142] doc: move rpm build doc to dev docs ------------{ <(O.O)> }------------ Signed-off-by: Quentin Young --- Makefile.am | 1 - doc/developer/building-frr-for-centos6.rst | 7 +- doc/developer/building-frr-for-centos7.rst | 5 +- doc/developer/building-frr-for-fedora24.rst | 5 +- doc/developer/packaging-debian.rst | 2 + doc/developer/packaging-redhat.rst | 85 ++++++++++++++ doc/developer/packaging.rst | 1 + doc/developer/subdir.am | 5 +- redhat/README.rpm_build.md | 119 -------------------- 9 files changed, 99 insertions(+), 131 deletions(-) create mode 100644 doc/developer/packaging-redhat.rst delete mode 100644 redhat/README.rpm_build.md diff --git a/Makefile.am b/Makefile.am index 6e3c2a4181..8797a8e5ff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -181,7 +181,6 @@ EXTRA_DIST += \ redhat/frr.logrotate \ redhat/frr.pam \ redhat/frr.spec \ - redhat/README.rpm_build.md \ \ snapcraft/snapcraft.yaml \ snapcraft/README.snap_build.md \ diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst index c57573cb9f..fb58d5925a 100644 --- a/doc/developer/building-frr-for-centos6.rst +++ b/doc/developer/building-frr-for-centos6.rst @@ -1,9 +1,10 @@ +.. _building-centos6: + CentOS 6 ======================================== -(As an alternative to this installation, you may prefer to create a FRR -rpm package yourself and install that package instead. See instructions -in redhat/README.rpm\_build.md on how to build a rpm package) +This document describes installation from source. If you want to build an RPM, +see :ref:`packaging-redhat`. Instructions are tested with ``CentOS 6.8`` on ``x86_64`` platform diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst index 8f82cd6c9a..1cec5f40d6 100644 --- a/doc/developer/building-frr-for-centos7.rst +++ b/doc/developer/building-frr-for-centos7.rst @@ -1,9 +1,8 @@ CentOS 7 ======================================== -(As an alternative to this installation, you may prefer to create a FRR -rpm package yourself and install that package instead. See instructions -in redhat/README.rpm\_build.md on how to build a rpm package) +This document describes installation from source. If you want to build an RPM, +see :ref:`packaging-redhat`. CentOS 7 restrictions: ---------------------- diff --git a/doc/developer/building-frr-for-fedora24.rst b/doc/developer/building-frr-for-fedora24.rst index 2edf9b3e44..db3fa8256c 100644 --- a/doc/developer/building-frr-for-fedora24.rst +++ b/doc/developer/building-frr-for-fedora24.rst @@ -1,9 +1,8 @@ Fedora 24 ========================================= -(As an alternative to this installation, you may prefer to create a FRR -rpm package yourself and install that package instead. See instructions -in redhat/README.rpm\_build.md on how to build a rpm package) +This document describes installation from source. If you want to build an RPM, +see :ref:`packaging-redhat`. Install required packages ------------------------- diff --git a/doc/developer/packaging-debian.rst b/doc/developer/packaging-debian.rst index c660f98680..b57286d5a1 100644 --- a/doc/developer/packaging-debian.rst +++ b/doc/developer/packaging-debian.rst @@ -1,3 +1,5 @@ +.. _packaging-debian: + Packaging Debian ================ diff --git a/doc/developer/packaging-redhat.rst b/doc/developer/packaging-redhat.rst new file mode 100644 index 0000000000..f6b9931156 --- /dev/null +++ b/doc/developer/packaging-redhat.rst @@ -0,0 +1,85 @@ +.. _packaging-redhat: + +Packaging Red Hat +================= + +Tested on CentOS 6, CentOS 7 and Fedora 24. + +1. On CentOS 6, refer to :ref:`building-centos6` for details on installing + sufficiently up-to-date package versions to enable building FRR. + + Newer automake/autoconf/bison is only needed to build the RPM and is **not** + needed to install the binary RPM package. + +2. Install the build dependencies for your platform. Refer to the + platform-specific build documentation on how to do this. + +3. Install the following additional packages:: + + yum install rpm-build net-snmp-devel pam-devel libcap-devel + + If your platform uses systemd:: + + yum install systemd-devel + + If ``yum`` is not present on your system, use ``dnf`` instead. + +3. Checkout FRR:: + + git clone https://github.com/frrouting/frr.git frr + +4. Run Bootstrap and make distribution tar.gz:: + + cd frr + ./bootstrap.sh + ./configure --with-pkg-extra-version=-MyRPMVersion SPHINXBUILD=sphinx-build2.7 + make dist + + .. note:: + + The only ``configure`` option respected when building RPMs is + ``--with-pkg-extra-version``. + +5. Create RPM directory structure and populate with sources:: + + mkdir rpmbuild + mkdir rpmbuild/SOURCES + mkdir rpmbuild/SPECS + cp redhat/*.spec rpmbuild/SPECS/ + cp frr*.tar.gz rpmbuild/SOURCES/ + +6. Edit :file:`rpm/SPECS/frr.spec` with configuration as needed. + + Look at the beginning of the file and adjust the following parameters to + enable or disable features as required:: + + ############### FRRouting (FRR) configure options ################# + # with-feature options + %{!?with_pam: %global with_pam 0 } + %{!?with_ospfclient: %global with_ospfclient 1 } + %{!?with_ospfapi: %global with_ospfapi 1 } + %{!?with_irdp: %global with_irdp 1 } + %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_ldpd: %global with_ldpd 1 } + %{!?with_nhrpd: %global with_nhrpd 1 } + %{!?with_eigrp: %global with_eigrpd 1 } + %{!?with_shared: %global with_shared 1 } + %{!?with_multipath: %global with_multipath 256 } + %{!?frr_user: %global frr_user frr } + %{!?vty_group: %global vty_group frrvty } + %{!?with_fpm: %global with_fpm 0 } + %{!?with_watchfrr: %global with_watchfrr 1 } + %{!?with_bgp_vnc: %global with_bgp_vnc 0 } + %{!?with_pimd: %global with_pimd 1 } + %{!?with_rpki: %global with_rpki 0 } + +7. Build the RPM:: + + rpmbuild --define "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/frr.spec + + If building with RPKI, then download and install the additional RPKI + packages from + https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact + +If all works correctly, then you should end up with the RPMs under +:file:`rpmbuild/RPMS` and the source RPM under :file:`rpmbuild/SRPMS`. diff --git a/doc/developer/packaging.rst b/doc/developer/packaging.rst index 27e6e155fb..b174a9660c 100644 --- a/doc/developer/packaging.rst +++ b/doc/developer/packaging.rst @@ -7,3 +7,4 @@ Packaging maintainer-release-build packaging-debian + packaging-redhat diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index d769913674..a0c5e6fc9d 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -5,7 +5,6 @@ dev_RSTFILES = \ doc/developer/bgp-typecodes.rst \ doc/developer/bgpd.rst \ - doc/developer/building-frr-for-openwrt.rst \ doc/developer/building-frr-for-alpine.rst \ doc/developer/building-frr-for-centos6.rst \ doc/developer/building-frr-for-centos7.rst \ @@ -19,6 +18,7 @@ dev_RSTFILES = \ doc/developer/building-frr-for-netbsd7.rst \ doc/developer/building-frr-for-omnios.rst \ doc/developer/building-frr-for-openbsd6.rst \ + doc/developer/building-frr-for-openwrt.rst \ doc/developer/building-frr-for-ubuntu1404.rst \ doc/developer/building-frr-for-ubuntu1604.rst \ doc/developer/building-frr-for-ubuntu1804.rst \ @@ -37,8 +37,9 @@ dev_RSTFILES = \ doc/developer/ospf-api.rst \ doc/developer/ospf-sr.rst \ doc/developer/ospf.rst \ - doc/developer/packaging.rst \ doc/developer/packaging-debian.rst \ + doc/developer/packaging-redhat.rst + doc/developer/packaging.rst \ doc/developer/testing.rst \ doc/developer/topotests-snippets.rst \ doc/developer/topotests.rst \ diff --git a/redhat/README.rpm_build.md b/redhat/README.rpm_build.md deleted file mode 100644 index a3f095786d..0000000000 --- a/redhat/README.rpm_build.md +++ /dev/null @@ -1,119 +0,0 @@ -Building your own FRRouting RPM -====================================== -(Tested on CentOS 6, CentOS 7 and Fedora 24.) - -1. On CentOS 6 (which doesn't provide a bison/automake/autoconf of a recent enough version): - - Check out ../doc/developer/building-frr-for-centos6.rst for details on installing - a bison/automake/autoconf to support frr building. - - Newer automake/autoconf/bison is only needed to build the rpm and is - **not** needed to install the binary rpm package - -2. Install the build packages as documented in doc/developer/building-frr-for-xxxxx.rst and the following additional packages: - - yum install rpm-build net-snmp-devel pam-devel libcap-devel - - Additionally, on systems with systemd (CentOS 7, Fedora) - - yum install systemd-devel - - (use `dnf install` on new Fedora instead of `yum install`) - -3. Checkout FRR under a **unpriviledged** user account - - git clone https://github.com/frrouting/frr.git frr - -4. Run Bootstrap and make distribution tar.gz - - cd frr - ./bootstrap.sh - ./configure --with-pkg-extra-version=-MyRPMVersion \ - SPHINXBUILD=sphinx-build2.7 - make dist - - Note: configure parameters are not important for the RPM building - except the `with-pkg-extra-version` if you want to give the RPM a specific name to - mark your own unoffical build - -5. Create RPM directory structure and populate with sources - - mkdir rpmbuild - mkdir rpmbuild/SOURCES - mkdir rpmbuild/SPECS - cp redhat/*.spec rpmbuild/SPECS/ - cp frr*.tar.gz rpmbuild/SOURCES/ - -6. Edit rpm/SPECS/frr.spec with configuration as needed - Look at the beginning of the file and adjust the following parameters to enable or disable features as required: - - ############### FRRouting (FRR) configure options ################# - # with-feature options - %{!?with_pam: %global with_pam 0 } - %{!?with_ospfclient: %global with_ospfclient 1 } - %{!?with_ospfapi: %global with_ospfapi 1 } - %{!?with_irdp: %global with_irdp 1 } - %{!?with_rtadv: %global with_rtadv 1 } - %{!?with_ldpd: %global with_ldpd 1 } - %{!?with_nhrpd: %global with_nhrpd 1 } - %{!?with_eigrp: %global with_eigrpd 1 } - %{!?with_shared: %global with_shared 1 } - %{!?with_multipath: %global with_multipath 256 } - %{!?frr_user: %global frr_user frr } - %{!?vty_group: %global vty_group frrvty } - %{!?with_fpm: %global with_fpm 0 } - %{!?with_watchfrr: %global with_watchfrr 1 } - %{!?with_bgp_vnc: %global with_bgp_vnc 0 } - %{!?with_pimd: %global with_pimd 1 } - %{!?with_rpki: %global with_rpki 0 } - -7. Build the RPM - - rpmbuild --define "_topdir `pwd`/rpmbuild" -ba rpmbuild/SPECS/frr.spec - - If building with RPKI, then download and install the additional RPKI - packages from - https://ci1.netdef.org/browse/RPKI-RTRLIB/latestSuccessful/artifact - -DONE. - -If all works correctly, then you should end up with the RPMs under -`rpmbuild/RPMS` and the Source RPM under `rpmbuild/SRPMS` - - -Enabling daemons after installation of the package: ---------------------------------------------------- - -### init.d based systems (ie CentOS 6): - -1. Edit /etc/frr/daemons and enable required routing daemons (Zebra is probably needed for most deployments, so make sure to enable it.) - -2. Enable the daemons as needed to run after boot (Zebra is mandatory) - - chkconfig frr on - -3. Check your firewall / IPtables to make sure the routing protocols are -allowed. - -5. Start the FRR daemons (or reboot) - - service frr start - -Configuration is stored in `/etc/frr/*.conf` files and daemon selection is stored in `/etc/frr/daemons`. - - -### systemd based systems (ie CentOS 7, Fedora 24) - -1. Edit /etc/frr/daemons and enable required routing daemons (Zebra is probably needed for most deployments, so make sure to enable it.) - -2. Enable the frr daemons to run after boot. - - systemctl enable frr - -2. Check your firewall / IPtables to make sure the routing protocols are -allowed. - -3. Start the daemons (or reboot) - - systemctl start frr - -Configuration is stored in `/etc/frr/*.conf` files and daemon selection is stored in `/etc/frr/daemons`. - From d758f97a242719ba7e1b71c7f47d7d34b51feec0 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 22 Mar 2019 18:14:17 +0000 Subject: [PATCH 093/142] doc: update instructions for building libyang * Upstream libyang now works with FRR; use it * Install libyang to system library directories to satisfy pkg-config * Remove warnings about ABI version * Remove outdated binary package links * Cleanup formatting Validated that these instructions work on: - Fedora 24 - Fedora 28. - Ubuntu 18.04 Signed-off-by: Quentin Young --- doc/developer/building-libyang.rst | 78 +++++++++++++++--------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/doc/developer/building-libyang.rst b/doc/developer/building-libyang.rst index c45c294b75..41fe09e322 100644 --- a/doc/developer/building-libyang.rst +++ b/doc/developer/building-libyang.rst @@ -1,57 +1,55 @@ -The libyang library can be installed from third-party packages available `here -`_. +FRR depends on the relatively new ``libyang`` library to provide YANG/NETCONF +support. Unfortunately, most distributions do not yet offer a ``libyang`` +package from their repositories. Therefore we offer two options to install this +library. -Note: the libyang dev/devel packages need to be installed in addition -to the libyang core package in order to build FRR successfully. +**Option 1: Binary Install** + +The FRR project builds binary ``libyang`` packages, which we offer for download +`here `_. .. warning:: - libyang ABI version 0.16.74 or newer will be required to build FRR in the - near future since it significantly eases build and installation - considerations. "0.16-r3" is equal to 0.16.105 and will work, "0.16-r2" - is equal to 0.16.52 and will stop working. The CI artifacts will be - updated shortly. -For example, for CentOS 7.x: - -.. code-block:: shell - - wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/CentOS-7-x86_64-Packages/libyang-0.16.46-0.x86_64.rpm - wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/CentOS-7-x86_64-Packages/libyang-devel-0.16.46-0.x86_64.rpm - sudo rpm -i libyang-0.16.46-0.x86_64.rpm libyang-devel-0.16.46-0.x86_64.rpm - -or Ubuntu 18.04: - -.. code-block:: shell - - wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang-dev_0.16.46_amd64.deb - wget https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Ubuntu-18.04-x86_64-Packages/libyang_0.16.46_amd64.deb - sudo apt install libpcre3-dev - sudo dpkg -i libyang-dev_0.16.46_amd64.deb libyang_0.16.46_amd64.deb + ``libyang`` version 0.16.74 or newer is required to build FRR. .. note:: - For Debian-based systems, the official libyang package requires recent - versions of swig (3.0.12) and debhelper (11) which are only available in - Debian buster (10). However, libyang packages built on Debian buster can - be installed on both Debian jessie (8) and Debian stretch (9), as well as - various Ubuntu systems. The python3-yang package will not work, but the - other packages (libyang-dev is the one needed for FRR) will. -Alternatively, libyang can be built and installed manually by following -the steps below: + The ``libyang`` development packages need to be installed in addition to the + libyang core package in order to build FRR successfully. Make sure to + download and install those from the link above alongside the binary + packages. -.. code-block:: shell + Depending on your platform, you may also need to install the PCRE + development package. Typically this is ``libpcre-dev`` or ``pcre-devel``. - git clone https://github.com/opensourcerouting/libyang +.. note:: + + For Debian-based systems, the official ``libyang`` package requires recent + versions of ``swig`` (3.0.12) and ``debhelper`` (11) which are only + available in Debian buster (10). However, ``libyang`` packages built on + Debian buster can be installed on both Debian jessie (8) and Debian stretch + (9), as well as various Ubuntu systems. The ``python3-yang`` package will + not work, but the other packages (``libyang-dev`` is the one needed for FRR) + will. + +**Option 2: Source Install** + +.. note:: + + Ensure that the `libyang build requirements + `_ + are met before continuing. Usually this entails installing ``cmake`` and + ``libpcre-dev`` or ``pcre-devel``. + +.. code-block:: console + + git clone https://github.com/CESNET/libyang.git cd libyang - git checkout -b tmp origin/tmp mkdir build; cd build - cmake -DENABLE_LYD_PRIV=ON .. + cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr .. make sudo make install When building libyang on CentOS 6, it's also necessary to pass the ``-DENABLE_CACHE=OFF`` parameter to cmake. -Note: please check the `libyang build requirements -`_ -first. From 55328d8acac85f85f4bbc934b3af9be654214794 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Fri, 15 Mar 2019 19:09:25 -0700 Subject: [PATCH 094/142] zebra: add mac ip dad timers cleanup When MAC or IP deleted ensure to cleanup DAD timers. Signed-off-by: Chirag Shah --- zebra/zebra_vxlan.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index b44c314d5b..04209ded53 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2191,6 +2191,7 @@ static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip, memcpy(&n->emac, mac, ETH_ALEN); n->state = ZEBRA_NEIGH_INACTIVE; n->zvni = zvni; + n->dad_ip_auto_recovery_timer = NULL; /* Associate the neigh to mac */ zmac = zvni_mac_lookup(zvni, mac); @@ -2212,6 +2213,9 @@ static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n) if (zmac) listnode_delete(zmac->neigh_list, n); + /* Cancel auto recovery */ + THREAD_OFF(n->dad_ip_auto_recovery_timer); + /* Free the VNI hash entry and allocated memory. */ tmp_n = hash_release(zvni->neigh_table, n); XFREE(MTYPE_NEIGH, tmp_n); @@ -3308,6 +3312,9 @@ static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr) mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc); assert(mac); + mac->zvni = zvni; + mac->dad_mac_auto_recovery_timer = NULL; + mac->neigh_list = list_new(); mac->neigh_list->cmp = neigh_list_cmp; @@ -3321,6 +3328,9 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac) { zebra_mac_t *tmp_mac; + /* Cancel auto recovery */ + THREAD_OFF(mac->dad_mac_auto_recovery_timer); + list_delete(&mac->neigh_list); /* Free the VNI hash entry and allocated memory. */ From 5d799192ef5ddf9a5f953512d99bad106020ff50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20R=C3=B6thke?= Date: Sat, 23 Mar 2019 11:57:09 +0100 Subject: [PATCH 095/142] bgpd: add command to lookup prefixes in the rpki table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Röthke --- bgpd/bgp_rpki.c | 73 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index a38d78916c..b16b9f7b1e 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -125,7 +125,7 @@ static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket); static struct cache *find_cache(const uint8_t preference); static int add_tcp_cache(const char *host, const char *port, const uint8_t preference); -static void print_record(const struct pfx_record *record, void *data); +static void print_record(const struct pfx_record *record, struct vty *vty); static int is_synchronized(void); static int is_running(void); static void route_match_free(void *rule); @@ -271,17 +271,23 @@ static struct cache *find_cache(const uint8_t preference) return NULL; } -static void print_record(const struct pfx_record *record, void *data) +static void print_record(const struct pfx_record *record, struct vty *vty) { char ip[INET6_ADDRSTRLEN]; + + lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip)); + vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len, + record->max_len, record->asn); +} + +static void print_record_cb(const struct pfx_record *record, void *data) +{ struct rpki_for_each_record_arg *arg = data; struct vty *vty = arg->vty; (*arg->prefix_amount)++; - lrtr_ip_addr_to_str(&record->prefix, ip, sizeof(ip)); - vty_out(vty, "%-40s %3u - %3u %10u\n", ip, record->min_len, - record->max_len, record->asn); + print_record(record, vty); } static struct rtr_mgr_group *get_groups(void) @@ -663,10 +669,10 @@ static void print_prefix_table(struct vty *vty) vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS"); arg.prefix_amount = &number_of_ipv4_prefixes; - pfx_table_for_each_ipv4_record(pfx_table, print_record, &arg); + pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg); arg.prefix_amount = &number_of_ipv6_prefixes; - pfx_table_for_each_ipv6_record(pfx_table, print_record, &arg); + pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg); vty_out(vty, "Number of IPv4 Prefixes: %u\n", number_of_ipv4_prefixes); vty_out(vty, "Number of IPv6 Prefixes: %u\n", number_of_ipv6_prefixes); @@ -1179,6 +1185,58 @@ DEFUN (show_rpki_prefix_table, return CMD_SUCCESS; } +DEFPY (show_rpki_prefix, + show_rpki_prefix_cmd, + "show rpki prefix [(1-4294967295)$asn]", + SHOW_STR + RPKI_OUTPUT_STRING + "Lookup IP prefix and optionally ASN in prefix table\n" + "IPv4 prefix\n" + "IPv6 prefix\n" + "AS Number\n") +{ + + if (!is_synchronized()) { + vty_out(vty, "No Conection to RPKI cache server.\n"); + return CMD_WARNING; + } + + struct lrtr_ip_addr addr; + char addr_str[INET6_ADDRSTRLEN]; + size_t addr_len = strchr(prefix_str, '/') - prefix_str; + + memset(addr_str, 0, sizeof(addr_str)); + memcpy(addr_str, prefix_str, addr_len); + + if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) { + vty_out(vty, "Invalid IP prefix\n"); + return CMD_WARNING; + } + + struct pfx_record *matches = NULL; + unsigned int match_count = 0; + enum pfxv_state result; + + if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count, + asn, &addr, prefix->prefixlen, &result) + != PFX_SUCCESS) { + vty_out(vty, "Prefix lookup failed"); + return CMD_WARNING; + } + + vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", "Origin-AS"); + for (size_t i = 0; i < match_count; ++i) { + const struct pfx_record *record = &matches[i]; + + if (record->max_len >= prefix->prefixlen + && ((asn != 0 && asn == record->asn) || asn == 0)) { + print_record(&matches[i], vty); + } + } + + return CMD_SUCCESS; +} + DEFUN (show_rpki_cache_server, show_rpki_cache_server_cmd, "show rpki cache-server", @@ -1450,6 +1508,7 @@ static void install_cli_commands(void) install_element(ENABLE_NODE, &show_rpki_prefix_table_cmd); install_element(ENABLE_NODE, &show_rpki_cache_connection_cmd); install_element(ENABLE_NODE, &show_rpki_cache_server_cmd); + install_element(ENABLE_NODE, &show_rpki_prefix_cmd); /* Install debug commands */ install_element(CONFIG_NODE, &debug_rpki_cmd); From b7862d93ae2662d4dd2d4dd0de7232f4dc36924e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 24 Mar 2019 15:52:02 +0100 Subject: [PATCH 096/142] tools/frrcommon.sh: ignore 'declare' failures The "declare -p watchfrr_options" call is just to support backwards compatibility. If it fails, silently ignore that. Signed-off-by: David Lamparter --- tools/frrcommon.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in index 76a0d617ba..897e6d6558 100644 --- a/tools/frrcommon.sh.in +++ b/tools/frrcommon.sh.in @@ -291,7 +291,7 @@ load_old_config "$C_PATH/daemons.conf" load_old_config "/etc/default/frr" load_old_config "/etc/sysconfig/frr" -if declare -p watchfrr_options | grep -q '^declare \-a'; then +if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare \-a'; then log_warning_msg "watchfrr_options contains a bash array value." \ "The configured value is intentionally ignored since it is likely wrong." \ "Please remove or fix the setting." From 4cf8bb327cee48fff66cb01ba30803a811aba9b9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 25 Mar 2019 09:04:28 -0400 Subject: [PATCH 097/142] lib: Fixup missing log entries Add a few missing log entries to the macro to allow us to print out the zapi message type, since they were missing. Signed-off-by: Donald Sharp --- lib/log.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/log.c b/lib/log.c index e98040eb06..cf623a4c19 100644 --- a/lib/log.c +++ b/lib/log.c @@ -991,6 +991,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_ROUTER_ID_DELETE), DESC_ENTRY(ZEBRA_ROUTER_ID_UPDATE), DESC_ENTRY(ZEBRA_HELLO), + DESC_ENTRY(ZEBRA_CAPABILITIES), DESC_ENTRY(ZEBRA_NEXTHOP_REGISTER), DESC_ENTRY(ZEBRA_NEXTHOP_UNREGISTER), DESC_ENTRY(ZEBRA_NEXTHOP_UPDATE), @@ -1012,6 +1013,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_VRF_LABEL), DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE), DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER), + DESC_ENTRY(ZEBRA_BFD_CLIENT_DEREGISTER), DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV), DESC_ENTRY(ZEBRA_INTERFACE_DISABLE_RADV), DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB), @@ -1023,6 +1025,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC), DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK), DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK), + DESC_ENTRY(ZEBRA_FEC_REGISTER), + DESC_ENTRY(ZEBRA_FEC_UNREGISTER), + DESC_ENTRY(ZEBRA_FEC_UPDATE), DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI), DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW), DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP), @@ -1057,6 +1062,11 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_IPSET_DESTROY), DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD), DESC_ENTRY(ZEBRA_IPSET_ENTRY_DELETE), + DESC_ENTRY(ZEBRA_IPSET_NOTIFY_OWNER), + DESC_ENTRY(ZEBRA_IPSET_ENTRY_NOTIFY_OWNER), + DESC_ENTRY(ZEBRA_IPTABLE_ADD), + DESC_ENTRY(ZEBRA_IPTABLE_DELETE), + DESC_ENTRY(ZEBRA_IPTABLE_NOTIFY_OWNER), DESC_ENTRY(ZEBRA_VXLAN_FLOOD_CONTROL), }; #undef DESC_ENTRY From cdc6ed9016db730a7af3924e6a3e30a21be64675 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 25 Mar 2019 09:09:35 -0400 Subject: [PATCH 098/142] lib: Improve debugs in zclient.c Fixup a couple of places to improve debugging of what is going on in zclient.c. Signed-off-by: Donald Sharp --- lib/zclient.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index 55f2393c56..7b94f1d907 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -629,7 +629,7 @@ void zclient_init(struct zclient *zclient, int redist_default, } if (zclient_debug) - zlog_debug("zclient_start is called"); + zlog_debug("scheduling zclient connection"); zclient_event(ZCLIENT_SCHEDULE, zclient); } @@ -2504,8 +2504,9 @@ static int zclient_read(struct thread *thread) length -= ZEBRA_HEADER_SIZE; if (zclient_debug) - zlog_debug("zclient 0x%p command 0x%x VRF %u", - (void *)zclient, command, vrf_id); + zlog_debug("zclient 0x%p command %s VRF %u", + (void *)zclient, zserv_command_string(command), + vrf_id); switch (command) { case ZEBRA_CAPABILITIES: From 9570f7378bb9e000fc4e98fa2f0ef6356af4a548 Mon Sep 17 00:00:00 2001 From: Saravanan K Date: Mon, 25 Mar 2019 06:23:17 -0700 Subject: [PATCH 099/142] ospfd: Remaining packet calculation while fragmenting lsu, ls-ack and ls-req While fragmenting ospf ls packets, before appending the link state info, wrong value is checked to see if current packet can fit in another ls info. Because of this, when a lower mtu is configured, it couldn't fit in even 1 ls ack, which tries to send all the available ls ack in the list in loop. This keeps allocating memory to send the packet and ends up putting the packet buffer without ls-ack into deferred send que(ospf_ls_ack_send_delayed). This infinite loop causes infinite memory being allocated in a loop causing system to be unstable. This commit takes care of calculating the right value to compare for checking oif this buffer can fit in more. Signed-off-by: Saravanan K --- ospfd/ospf_packet.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index b3c91b9006..43c5e338b0 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -3447,7 +3447,14 @@ static int ospf_make_ls_req_func(struct stream *s, uint16_t *length, oi = nbr->oi; - /* LS Request packet overflows interface MTU. */ + /* LS Request packet overflows interface MTU + * delta is just number of bytes required for 1 LS Req + * ospf_packet_max will return the number of bytes can + * be accomodated without ospf header. So length+delta + * can be compared to ospf_packet_max + * to check if it can fit another lsreq in the same packet. + */ + if (*length + delta > ospf_packet_max(oi)) return 0; @@ -3466,7 +3473,7 @@ static int ospf_make_ls_req(struct ospf_neighbor *nbr, struct stream *s) { struct ospf_lsa *lsa; uint16_t length = OSPF_LS_REQ_MIN_SIZE; - unsigned long delta = stream_get_endp(s) + 12; + unsigned long delta = 12; struct route_table *table; struct route_node *rn; int i; @@ -3530,8 +3537,9 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update, assert(lsa->data); - /* Will it fit? */ - if (length + delta + ntohs(lsa->data->length) > size_noauth) + /* Will it fit? Minimum it has to fit atleast one */ + if ((length + delta + ntohs(lsa->data->length) > size_noauth) && + (count > 0)) break; /* Keep pointer to LS age. */ @@ -3568,13 +3576,21 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, { struct listnode *node, *nnode; uint16_t length = OSPF_LS_ACK_MIN_SIZE; - unsigned long delta = stream_get_endp(s) + 24; + unsigned long delta = OSPF_LSA_HEADER_SIZE; struct ospf_lsa *lsa; for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) { assert(lsa); - if (length + delta > ospf_packet_max(oi)) + /* LS Ack packet overflows interface MTU + * delta is just number of bytes required for + * 1 LS Ack(1 LS Hdr) ospf_packet_max will return + * the number of bytes can be accomodated without + * ospf header. So length+delta can be compared + * against ospf_packet_max to check if it can fit + * another ls header in the same packet. + */ + if ((length + delta) > ospf_packet_max(oi)) break; stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE); From 41533022a20bfea03fc5b8ce9456856a455b8d41 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 25 Mar 2019 15:01:56 +0100 Subject: [PATCH 100/142] zebra: remove duplicated json information the metric information is already present for connected routes. so remove that line. Signed-off-by: Philippe Guibert --- zebra/zebra_vty.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index b0884f22cf..82fbe68bfe 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -425,12 +425,6 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED)) json_object_boolean_true_add(json_route, "queued"); - if (re->type != ZEBRA_ROUTE_CONNECT) { - json_object_int_add(json_route, "distance", - re->distance); - json_object_int_add(json_route, "metric", re->metric); - } - if (re->tag) json_object_int_add(json_route, "tag", re->tag); From 51e94aa7b167b5197f634eec11dc456994787993 Mon Sep 17 00:00:00 2001 From: Emanuele Di Pascale Date: Mon, 25 Mar 2019 15:11:55 +0100 Subject: [PATCH 101/142] add cplusplus guards to all zebra headers Signed-off-by: Emanuele Di Pascale --- zebra/connected.h | 7 +++++++ zebra/debug.h | 8 ++++++++ zebra/if_netlink.h | 8 ++++++++ zebra/interface.h | 8 ++++++++ zebra/ioctl.h | 8 ++++++++ zebra/ioctl_solaris.h | 8 ++++++++ zebra/ipforward.h | 8 ++++++++ zebra/irdp.h | 7 +++++++ zebra/kernel_netlink.h | 8 ++++++++ zebra/kernel_socket.h | 8 ++++++++ zebra/label_manager.h | 8 ++++++++ zebra/redistribute.h | 9 +++++++++ zebra/rib.h | 9 +++++++++ zebra/router-id.h | 8 ++++++++ zebra/rt.h | 8 ++++++++ zebra/rt_netlink.h | 8 ++++++++ zebra/rtadv.h | 7 +++++++ zebra/rule_netlink.h | 8 ++++++++ zebra/table_manager.h | 8 ++++++++ zebra/zapi_msg.h | 8 ++++++++ zebra/zebra_dplane.h | 8 ++++++++ zebra/zebra_errors.h | 8 ++++++++ zebra/zebra_fpm_private.h | 9 +++++++++ zebra/zebra_l2.h | 9 +++++++++ zebra/zebra_memory.h | 8 ++++++++ zebra/zebra_mlag.h | 9 +++++++++ zebra/zebra_mpls.h | 7 +++++++ zebra/zebra_mroute.h | 8 ++++++++ zebra/zebra_netns_id.h | 8 ++++++++ zebra/zebra_netns_notify.h | 8 ++++++++ zebra/zebra_ns.h | 8 ++++++++ zebra/zebra_pbr.h | 8 ++++++++ zebra/zebra_ptm.h | 9 +++++++++ zebra/zebra_ptm_redistribute.h | 10 ++++++++++ zebra/zebra_pw.h | 8 ++++++++ zebra/zebra_rnh.h | 9 +++++++++ zebra/zebra_routemap.h | 8 ++++++++ zebra/zebra_router.h | 9 +++++++++ zebra/zebra_vrf.h | 9 +++++++++ zebra/zebra_vxlan.h | 8 ++++++++ zebra/zebra_vxlan_private.h | 10 ++++++++-- zebra/zserv.h | 8 ++++++++ 42 files changed, 343 insertions(+), 2 deletions(-) diff --git a/zebra/connected.h b/zebra/connected.h index faba30b0d5..7672bec006 100644 --- a/zebra/connected.h +++ b/zebra/connected.h @@ -28,6 +28,10 @@ #include "lib/if.h" #include "lib/prefix.h" +#ifdef __cplusplus +extern "C" { +#endif + extern struct connected *connected_check(struct interface *ifp, union prefixconstptr p); extern struct connected *connected_check_ptp(struct interface *ifp, @@ -58,4 +62,7 @@ extern void connected_delete_ipv6(struct interface *ifp, extern int connected_is_unnumbered(struct interface *); +#ifdef __cplusplus +} +#endif #endif /*_ZEBRA_CONNECTED_H */ diff --git a/zebra/debug.h b/zebra/debug.h index c79cd96c21..944ad6d68b 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -24,6 +24,10 @@ #include "lib/vty.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Debug flags. */ #define ZEBRA_DEBUG_EVENT 0x01 @@ -99,4 +103,8 @@ extern void zebra_debug_init(void); DECLARE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty)); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_DEBUG_H */ diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h index 65a266a519..710fd52558 100644 --- a/zebra/if_netlink.h +++ b/zebra/if_netlink.h @@ -23,11 +23,19 @@ #ifdef HAVE_NETLINK +#ifdef __cplusplus +extern "C" { +#endif + extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int interface_lookup_netlink(struct zebra_ns *zns); +#ifdef __cplusplus +} +#endif + #endif /* HAVE_NETLINK */ #endif /* _ZEBRA_IF_NETLINK_H */ diff --git a/zebra/interface.h b/zebra/interface.h index 1dbcf33fad..ce404e8253 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -28,6 +28,10 @@ #include "zebra/zebra_l2.h" +#ifdef __cplusplus +extern "C" { +#endif + /* For interface multicast configuration. */ #define IF_ZEBRA_MULTICAST_UNSPEC 0 #define IF_ZEBRA_MULTICAST_ON 1 @@ -432,4 +436,8 @@ extern int interface_list_proc(void); extern int ifaddr_proc_ipv6(void); #endif /* HAVE_PROC_NET_IF_INET6 */ +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_INTERFACE_H */ diff --git a/zebra/ioctl.h b/zebra/ioctl.h index 2a8ea77909..67ffd45a08 100644 --- a/zebra/ioctl.h +++ b/zebra/ioctl.h @@ -22,6 +22,10 @@ #ifndef _ZEBRA_IOCTL_H #define _ZEBRA_IOCTL_H +#ifdef __cplusplus +extern "C" { +#endif + /* Prototypes. */ extern void ifreq_set_name(struct ifreq *, struct interface *); extern int if_ioctl(unsigned long, caddr_t); @@ -53,4 +57,8 @@ extern struct connected *if_lookup_linklocal(struct interface *); #endif /* SOLARIS_IPV6 */ +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_IOCTL_H */ diff --git a/zebra/ioctl_solaris.h b/zebra/ioctl_solaris.h index 3507e563cd..363f382896 100644 --- a/zebra/ioctl_solaris.h +++ b/zebra/ioctl_solaris.h @@ -22,7 +22,15 @@ #ifndef _ZEBRA_IF_IOCTL_SOLARIS_H #define _ZEBRA_IF_IOCTL_SOLARIS_H +#ifdef __cplusplus +extern "C" { +#endif + void lifreq_set_name(struct lifreq *, const char *); int if_get_flags_direct(const char *, uint64_t *, unsigned int af); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_IF_IOCTL_SOLARIS_H */ diff --git a/zebra/ipforward.h b/zebra/ipforward.h index fe9f2db911..9884678c7a 100644 --- a/zebra/ipforward.h +++ b/zebra/ipforward.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_IPFORWARD_H #define _ZEBRA_IPFORWARD_H +#ifdef __cplusplus +extern "C" { +#endif + extern int ipforward(void); extern int ipforward_on(void); extern int ipforward_off(void); @@ -29,4 +33,8 @@ extern int ipforward_ipv6(void); extern int ipforward_ipv6_on(void); extern int ipforward_ipv6_off(void); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_IPFORWARD_H */ diff --git a/zebra/irdp.h b/zebra/irdp.h index 4800e75be3..3f4fa93460 100644 --- a/zebra/irdp.h +++ b/zebra/irdp.h @@ -28,6 +28,10 @@ #include "lib/vty.h" +#ifdef __cplusplus +extern "C" { +#endif + #define TRUE 1 #define FALSE 0 @@ -150,5 +154,8 @@ extern int irdp_read_raw(struct thread *r); extern void send_packet(struct interface *ifp, struct stream *s, uint32_t dst, struct prefix *p, uint32_t ttl); +#ifdef __cplusplus +} +#endif #endif /* _IRDP_H */ diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index 9918729eb6..076ca5c5c7 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -21,6 +21,10 @@ #ifndef _ZEBRA_KERNEL_NETLINK_H #define _ZEBRA_KERNEL_NETLINK_H +#ifdef __cplusplus +extern "C" { +#endif + #ifdef HAVE_NETLINK #define NL_RCV_PKT_BUF_SIZE 32768 @@ -68,4 +72,8 @@ extern int netlink_request(struct nlsock *nl, struct nlmsghdr *n); #endif /* HAVE_NETLINK */ +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_KERNEL_NETLINK_H */ diff --git a/zebra/kernel_socket.h b/zebra/kernel_socket.h index 096a21f782..15079d796d 100644 --- a/zebra/kernel_socket.h +++ b/zebra/kernel_socket.h @@ -22,6 +22,10 @@ #ifndef __ZEBRA_KERNEL_SOCKET_H #define __ZEBRA_KERNEL_SOCKET_H +#ifdef __cplusplus +extern "C" { +#endif + /* Error codes of zebra. */ #define ZEBRA_ERR_NOERROR 0 #define ZEBRA_ERR_RTEXIST -1 @@ -38,4 +42,8 @@ extern int rtm_write(int, union sockunion *, union sockunion *, enum blackhole_type, int); extern const struct message rtm_type_str[]; +#ifdef __cplusplus +} +#endif + #endif /* __ZEBRA_KERNEL_SOCKET_H */ diff --git a/zebra/label_manager.h b/zebra/label_manager.h index 3e3def5f98..3ea89fbfc3 100644 --- a/zebra/label_manager.h +++ b/zebra/label_manager.h @@ -31,6 +31,10 @@ #include "zebra/zserv.h" +#ifdef __cplusplus +extern "C" { +#endif + #define NO_PROTO 0 /* @@ -74,4 +78,8 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start, int release_daemon_label_chunks(struct zserv *client); void label_manager_close(void); +#ifdef __cplusplus +} +#endif + #endif /* _LABEL_MANAGER_H */ diff --git a/zebra/redistribute.h b/zebra/redistribute.h index f0dc79574c..74a593b240 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -29,6 +29,10 @@ #include "zebra/zserv.h" #include "zebra/rib.h" +#ifdef __cplusplus +extern "C" { +#endif + /* ZAPI command handlers */ extern void zebra_redistribute_add(ZAPI_HANDLER_ARGS); extern void zebra_redistribute_delete(ZAPI_HANDLER_ARGS); @@ -73,4 +77,9 @@ extern int is_zebra_import_table_enabled(afi_t, uint32_t table_id); extern int zebra_import_table_config(struct vty *); extern void zebra_import_table_rm_update(const char *rmap); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_REDISTRIBUTE_H */ diff --git a/zebra/rib.h b/zebra/rib.h index a478fffddb..ced6692b9b 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -35,6 +35,10 @@ #include "mpls.h" #include "srcdest_table.h" +#ifdef __cplusplus +extern "C" { +#endif + #define DISTANCE_INFINITY 255 #define ZEBRA_KERNEL_TABLE_MAX 252 /* support for no more than this rt tables */ @@ -464,4 +468,9 @@ extern void zebra_vty_init(void); extern pid_t pid; extern bool v6_rr_semantics; + +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_RIB_H */ diff --git a/zebra/router-id.h b/zebra/router-id.h index 6b15159fdb..f7d16853f1 100644 --- a/zebra/router-id.h +++ b/zebra/router-id.h @@ -30,6 +30,10 @@ #include "zclient.h" #include "if.h" +#ifdef __cplusplus +extern "C" { +#endif + extern void router_id_add_address(struct connected *); extern void router_id_del_address(struct connected *); extern void router_id_init(struct zebra_vrf *); @@ -37,4 +41,8 @@ extern void router_id_cmd_init(void); extern void router_id_write(struct vty *); extern void router_id_get(struct prefix *, vrf_id_t); +#ifdef __cplusplus +} +#endif + #endif diff --git a/zebra/rt.h b/zebra/rt.h index 4080b0ccb2..bc91edd802 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -31,6 +31,10 @@ #include "zebra/zebra_mpls.h" #include "zebra/zebra_dplane.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Update or delete a route, LSP, or pseudowire from the kernel, * using info from a dataplane context. @@ -91,4 +95,8 @@ extern void neigh_read_specific_ip(struct ipaddr *ip, struct interface *vlan_if); extern void route_read(struct zebra_ns *zns); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_RT_H */ diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 473ad98a3f..29e0152bb2 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -26,6 +26,10 @@ #include "zebra/zebra_mpls.h" #include "zebra/zebra_dplane.h" +#ifdef __cplusplus +extern "C" { +#endif + #define NL_DEFAULT_ROUTE_METRIC 20 /* @@ -79,6 +83,10 @@ extern int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, extern int netlink_neigh_read_specific_ip(struct ipaddr *ip, struct interface *vlan_if); +#ifdef __cplusplus +} +#endif + #endif /* HAVE_NETLINK */ #endif /* _ZEBRA_RT_NETLINK_H */ diff --git a/zebra/rtadv.h b/zebra/rtadv.h index f7c27ebcb3..53c497fc09 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -25,6 +25,10 @@ #include "vty.h" #include "zebra/interface.h" +#ifdef __cplusplus +extern "C" { +#endif + /* NB: RTADV is defined in zebra/interface.h above */ #if defined(HAVE_RTADV) @@ -137,5 +141,8 @@ extern void rtadv_cmd_init(void); extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS); extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS); +#ifdef __cplusplus +} +#endif #endif /* _ZEBRA_RTADV_H */ diff --git a/zebra/rule_netlink.h b/zebra/rule_netlink.h index 4547a1bb3b..8c4741dc06 100644 --- a/zebra/rule_netlink.h +++ b/zebra/rule_netlink.h @@ -26,6 +26,10 @@ #ifdef HAVE_NETLINK +#ifdef __cplusplus +extern "C" { +#endif + /* * Handle netlink notification informing a rule add or delete. */ @@ -36,6 +40,10 @@ extern int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); */ extern int netlink_rules_read(struct zebra_ns *zns); +#ifdef __cplusplus +} +#endif + #endif /* HAVE_NETLINK */ #endif /* _ZEBRA_RULE_NETLINK_H */ diff --git a/zebra/table_manager.h b/zebra/table_manager.h index 5196162c4c..4f78f5097e 100644 --- a/zebra/table_manager.h +++ b/zebra/table_manager.h @@ -27,6 +27,10 @@ #include "zebra/zserv.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * Table chunk struct * Client daemon which the chunk belongs to can be identified by either @@ -63,4 +67,8 @@ int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start, int release_daemon_table_chunks(struct zserv *client); void table_manager_disable(ns_id_t ns_id); +#ifdef __cplusplus +} +#endif + #endif /* _TABLE_MANAGER_H */ diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index b770b8e881..d30fa2d0ef 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -30,6 +30,10 @@ #include "zebra/zebra_pbr.h" #include "zebra/zebra_errors.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * This is called to process inbound ZAPI messages. * @@ -86,3 +90,7 @@ extern void zserv_nexthop_num_warn(const char *caller, const struct prefix *p, const unsigned int nexthop_num); extern void zsend_capabilities_all_clients(void); + +#ifdef __cplusplus +} +#endif diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 149ff8dc60..1246fcc8ec 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -30,6 +30,10 @@ #include "zebra/zserv.h" #include "zebra/zebra_mpls.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Key netlink info from zebra ns */ struct zebra_dplane_info { ns_id_t ns_id; @@ -394,4 +398,8 @@ void zebra_dplane_pre_finish(void); void zebra_dplane_finish(void); void zebra_dplane_shutdown(void); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_DPLANE_H */ diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 0af5f8a551..2b7831a408 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -23,6 +23,10 @@ #include "lib/ferr.h" +#ifdef __cplusplus +extern "C" { +#endif + enum zebra_log_refs { EC_ZEBRA_LM_RESPONSE = ZEBRA_FERR_START, EC_ZEBRA_LM_NO_SUCH_CLIENT, @@ -126,4 +130,8 @@ enum zebra_log_refs { void zebra_error_init(void); +#ifdef __cplusplus +} +#endif + #endif /* __EC_ZEBRAORS_H__ */ diff --git a/zebra/zebra_fpm_private.h b/zebra/zebra_fpm_private.h index 969ab6cfee..943aad9864 100644 --- a/zebra/zebra_fpm_private.h +++ b/zebra/zebra_fpm_private.h @@ -26,6 +26,10 @@ #include "zebra/debug.h" +#ifdef __cplusplus +extern "C" { +#endif + #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define zfpm_debug(...) \ @@ -61,4 +65,9 @@ extern int zfpm_protobuf_encode_route(rib_dest_t *dest, struct route_entry *re, uint8_t *in_buf, size_t in_buf_len); extern struct route_entry *zfpm_route_for_update(rib_dest_t *dest); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_FPM_PRIVATE_H */ diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 68c9d4a7a1..2e3e5b4a85 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -29,6 +29,10 @@ #include "vlan.h" #include "vxlan.h" +#ifdef __cplusplus +extern "C" { +#endif + /* zebra L2 interface information - bridge slave (linkage to bridge) */ struct zebra_l2info_brslave { ifindex_t bridge_ifindex; /* Bridge Master */ @@ -96,4 +100,9 @@ extern void zebra_l2if_update_bridge_slave(struct interface *ifp, extern void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_L2_H */ diff --git a/zebra/zebra_memory.h b/zebra/zebra_memory.h index de55478de2..667c73b227 100644 --- a/zebra/zebra_memory.h +++ b/zebra/zebra_memory.h @@ -24,6 +24,10 @@ #include "memory.h" +#ifdef __cplusplus +extern "C" { +#endif + DECLARE_MGROUP(ZEBRA) DECLARE_MTYPE(RTADV_PREFIX) DECLARE_MTYPE(ZEBRA_NS) @@ -37,4 +41,8 @@ DECLARE_MTYPE(RNH) DECLARE_MTYPE(DP_CTX) DECLARE_MTYPE(DP_PROV) +#ifdef __cplusplus +} +#endif + #endif /* _QUAGGA_ZEBRA_MEMORY_H */ diff --git a/zebra/zebra_mlag.h b/zebra/zebra_mlag.h index c5c147c833..90a5a41fa4 100644 --- a/zebra/zebra_mlag.h +++ b/zebra/zebra_mlag.h @@ -24,8 +24,17 @@ #include "mlag.h" +#ifdef __cplusplus +extern "C" { +#endif + void zebra_mlag_init(void); void zebra_mlag_terminate(void); enum mlag_role zebra_mlag_get_role(void); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index 39f084ad2f..f8c6c794a4 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -34,6 +34,9 @@ #include "zebra/zserv.h" #include "zebra/zebra_vrf.h" +#ifdef __cplusplus +extern "C" { +#endif /* Definitions and macros. */ @@ -534,4 +537,8 @@ static inline int mpls_should_lsps_be_processed(struct zebra_vrf *zvrf) /* Global variables. */ extern int mpls_enabled; +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_MPLS_H */ diff --git a/zebra/zebra_mroute.h b/zebra/zebra_mroute.h index 3385153600..3c12b82da3 100644 --- a/zebra/zebra_mroute.h +++ b/zebra/zebra_mroute.h @@ -24,6 +24,10 @@ #include "zebra/zserv.h" +#ifdef __cplusplus +extern "C" { +#endif + struct mcast_route_data { struct prefix_sg sg; unsigned int ifindex; @@ -32,4 +36,8 @@ struct mcast_route_data { void zebra_ipmr_route_stats(ZAPI_HANDLER_ARGS); +#ifdef __cplusplus +} +#endif + #endif diff --git a/zebra/zebra_netns_id.h b/zebra/zebra_netns_id.h index d6530e6694..7a5f6851f4 100644 --- a/zebra/zebra_netns_id.h +++ b/zebra/zebra_netns_id.h @@ -20,7 +20,15 @@ #include "zebra.h" #include "ns.h" +#ifdef __cplusplus +extern "C" { +#endif + extern ns_id_t zebra_ns_id_get(const char *netnspath); extern ns_id_t zebra_ns_id_get_default(void); +#ifdef __cplusplus +} +#endif + #endif /* __ZEBRA_NS_ID_H__ */ diff --git a/zebra/zebra_netns_notify.h b/zebra/zebra_netns_notify.h index 0ced749ae8..18939283a7 100644 --- a/zebra/zebra_netns_notify.h +++ b/zebra/zebra_netns_notify.h @@ -20,10 +20,18 @@ #ifndef _NETNS_NOTIFY_H #define _NETNS_NOTIFY_H +#ifdef __cplusplus +extern "C" { +#endif + extern void zebra_ns_notify_init(void); extern void zebra_ns_notify_parse(void); extern void zebra_ns_notify_close(void); extern struct zebra_privs_t zserv_privs; +#ifdef __cplusplus +} +#endif + #endif /* NETNS_NOTIFY_H */ diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 01af64c17b..dc79a83db0 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -28,6 +28,10 @@ #include "zebra/rib.h" #include "zebra/zebra_vrf.h" +#ifdef __cplusplus +extern "C" { +#endif + #ifdef HAVE_NETLINK /* Socket interface to kernel */ struct nlsock { @@ -68,4 +72,8 @@ int zebra_ns_final_shutdown(struct ns *ns); int zebra_ns_config_write(struct vty *vty, struct ns *ns); +#ifdef __cplusplus +} +#endif + #endif diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index 5b6c23896c..0d55491107 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -32,6 +32,10 @@ #include "rt.h" #include "pbr.h" +#ifdef __cplusplus +extern "C" { +#endif + struct zebra_pbr_rule { int sock; @@ -252,4 +256,8 @@ DECLARE_HOOK(zebra_pbr_ipset_entry_update, DECLARE_HOOK(zebra_pbr_ipset_update, (int cmd, struct zebra_pbr_ipset *ipset), (cmd, ipset)); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PBR_H */ diff --git a/zebra/zebra_ptm.h b/zebra/zebra_ptm.h index d0cdaf0bce..e578a02a94 100644 --- a/zebra/zebra_ptm.h +++ b/zebra/zebra_ptm.h @@ -31,6 +31,10 @@ extern const char ZEBRA_PTM_SOCK_NAME[]; #include "zebra/zserv.h" #include "zebra/interface.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Zebra ptm context block */ struct zebra_ptm_cb { int ptm_sock; /* ptm file descriptor. */ @@ -87,4 +91,9 @@ void zebra_ptm_if_init(struct zebra_if *zebra_ifp); void zebra_ptm_if_set_ptm_state(struct interface *ifp, struct zebra_if *zebra_ifp); void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/zebra/zebra_ptm_redistribute.h b/zebra/zebra_ptm_redistribute.h index c1b12bd0d1..4daf405825 100644 --- a/zebra/zebra_ptm_redistribute.h +++ b/zebra/zebra_ptm_redistribute.h @@ -21,7 +21,17 @@ #ifndef _ZEBRA_PTM_REDISTRIBUTE_H #define _ZEBRA_PTM_REDISTRIBUTE_H + +#ifdef __cplusplus +extern "C" { +#endif + extern void zebra_interface_bfd_update(struct interface *, struct prefix *, struct prefix *, int, vrf_id_t); extern void zebra_bfd_peer_replay_req(void); + +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_PTM_REDISTRIBUTE_H */ diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h index 9692fb4d40..bbb3776725 100644 --- a/zebra/zebra_pw.h +++ b/zebra/zebra_pw.h @@ -29,6 +29,10 @@ #include "zebra/zebra_vrf.h" +#ifdef __cplusplus +extern "C" { +#endif + #define PW_INSTALL_RETRY_INTERVAL 30 struct zebra_pw { @@ -74,4 +78,8 @@ void zebra_pw_init(struct zebra_vrf *); void zebra_pw_exit(struct zebra_vrf *); void zebra_pw_vty_init(void); +#ifdef __cplusplus +} +#endif + #endif /* ZEBRA_PW_H_ */ diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 00ee60dc1a..0e71e8a68d 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -25,6 +25,10 @@ #include "prefix.h" #include "vty.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Nexthop structure. */ struct rnh { uint8_t flags; @@ -83,4 +87,9 @@ extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force, extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, rnh_type_t); extern char *rnh_str(struct rnh *rnh, char *buf, int size); + +#ifdef __cplusplus +} +#endif + #endif /*_ZEBRA_RNH_H */ diff --git a/zebra/zebra_routemap.h b/zebra/zebra_routemap.h index abd2ad78f7..6a630e1ac0 100644 --- a/zebra/zebra_routemap.h +++ b/zebra/zebra_routemap.h @@ -24,6 +24,10 @@ #include "lib/routemap.h" +#ifdef __cplusplus +extern "C" { +#endif + extern void zebra_route_map_init(void); extern void zebra_routemap_config_write_protocol(struct vty *vty, struct zebra_vrf *vrf); @@ -48,4 +52,8 @@ zebra_nht_route_map_check(afi_t afi, int client_proto, const struct prefix *p, struct zebra_vrf *zvrf, struct route_entry *, struct nexthop *nexthop); +#ifdef __cplusplus +} +#endif + #endif diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index e5043f38ae..61f2902233 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -26,6 +26,10 @@ #include "zebra/zebra_ns.h" +#ifdef __cplusplus +extern "C" { +#endif + /* * This header file contains the idea of a router and as such * owns data that is associated with a router from zebra's @@ -129,4 +133,9 @@ extern void zebra_router_sweep_route(void); extern void zebra_router_show_table_summary(struct vty *vty); extern uint32_t zebra_router_get_next_sequence(void); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index e35101d833..502fc343c5 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -28,6 +28,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /* MPLS (Segment Routing) global block */ typedef struct mpls_srgb_t_ { uint32_t start_label; @@ -203,4 +207,9 @@ extern void zebra_vrf_init(void); extern void zebra_rtable_node_cleanup(struct route_table *table, struct route_node *node); + +#ifdef __cplusplus +} +#endif + #endif /* ZEBRA_VRF_H */ diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 2cf21ff90b..206f65044a 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -35,6 +35,10 @@ #include "zebra/zebra_vrf.h" #include "zebra/zserv.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Is EVPN enabled? */ #define EVPN_ENABLED(zvrf) (zvrf)->advertise_all_vni static inline int is_evpn_enabled(void) @@ -206,4 +210,8 @@ extern int zebra_vxlan_clear_dup_detect_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_VXLAN_H */ diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index c36d156359..5081c08d19 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -26,12 +26,14 @@ #include -#include - #include "if.h" #include "linklist.h" #include "zebra_vxlan.h" +#ifdef __cplusplus +extern "C" { +#endif + #define ERR_STR_SZ 256 /* definitions */ @@ -421,4 +423,8 @@ struct nh_walk_ctx { struct json_object *json; }; +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_VXLAN_PRIVATE_H */ diff --git a/zebra/zserv.h b/zebra/zserv.h index ac016e65f3..c4c3e1328b 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -40,6 +40,10 @@ #include "zebra/zebra_vrf.h" /* for zebra_vrf */ /* clang-format on */ +#ifdef __cplusplus +extern "C" { +#endif + /* Default port information. */ #define ZEBRA_VTY_PORT 2601 @@ -234,4 +238,8 @@ extern void zserv_read_file(char *input); /* TODO */ int zebra_finalize(struct thread *event); +#ifdef __cplusplus +} +#endif + #endif /* _ZEBRA_ZEBRA_H */ From 63374e1d8b3d825d1346abfade353f8c89548d77 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 22 Mar 2019 16:19:22 +0000 Subject: [PATCH 102/142] doc: update Fedora 24 build doc style Signed-off-by: Quentin Young --- doc/developer/building-frr-for-fedora24.rst | 223 ++++++++++---------- 1 file changed, 106 insertions(+), 117 deletions(-) diff --git a/doc/developer/building-frr-for-fedora24.rst b/doc/developer/building-frr-for-fedora24.rst index 708baec3ee..d2a939d41c 100644 --- a/doc/developer/building-frr-for-fedora24.rst +++ b/doc/developer/building-frr-for-fedora24.rst @@ -1,169 +1,158 @@ Fedora 24 -========================================= +========= This document describes installation from source. If you want to build an RPM, see :ref:`packaging-redhat`. -Install required packages -------------------------- +Installing Dependencies +----------------------- -Add packages: +.. code-block:: console -:: - - sudo dnf install git autoconf automake libtool make gawk \ - readline-devel texinfo net-snmp-devel groff pkgconfig \ - json-c-devel pam-devel pytest bison flex c-ares-devel \ - python3-devel python3-sphinx + sudo dnf install git autoconf automake libtool make gawk \ + readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \ + pam-devel pytest bison flex c-ares-devel python3-devel python3-sphinx .. include:: building-libyang.rst -Get FRR, compile it and install it (from Git) ---------------------------------------------- +Building & Installing FRR +------------------------- -**This assumes you want to build and install FRR from source and not -using any packages** +Compilation +^^^^^^^^^^^ -Add frr groups and user +Clone the FRR git repo and use the included ``configure`` script to configure +FRR's build time options to your liking. The full option listing can be +obtained by running ``./configure -h``. The options shown below are examples. + +.. code-block:: console + + git clone https://github.com/frrouting/frr.git frr + cd frr + ./bootstrap.sh + ./configure \ + --bindir=/usr/bin \ + --sbindir=/usr/lib/frr \ + --sysconfdir=/etc/frr \ + --libdir=/usr/lib/frr \ + --libexecdir=/usr/lib/frr \ + --localstatedir=/var/run/frr \ + --with-moduledir=/usr/lib/frr/modules \ + --enable-snmp=agentx \ + --enable-multipath=64 \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --disable-exampledir \ + --enable-fpm \ + --with-pkg-git-version \ + --with-pkg-extra-version=-MyOwnFRRVersion + make + sudo make install + +Add FRR groups and user ^^^^^^^^^^^^^^^^^^^^^^^ -:: +.. code-block:: console - sudo groupadd -g 92 frr - sudo groupadd -r -g 85 frrvty - sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \ - -c "FRR FRRouting suite" -d /var/run/frr frr + sudo groupadd -g 92 frr + sudo groupadd -r -g 85 frrvty + sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \ + -c "FRR FRRouting suite" -d /var/run/frr frr -Download Source, configure and compile it -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -(You may prefer different options on configure statement. These are just -an example.) - -:: - - git clone https://github.com/frrouting/frr.git frr - cd frr - ./bootstrap.sh - ./configure \ - --bindir=/usr/bin \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - --libdir=/usr/lib/frr \ - --libexecdir=/usr/lib/frr \ - --localstatedir=/var/run/frr \ - --with-moduledir=/usr/lib/frr/modules \ - --enable-snmp=agentx \ - --enable-multipath=64 \ - --enable-user=frr \ - --enable-group=frr \ - --enable-vty-group=frrvty \ - --disable-exampledir \ - --enable-fpm \ - --with-pkg-git-version \ - --with-pkg-extra-version=-MyOwnFRRVersion - make - make check - sudo make install Create empty FRR configuration files ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -:: +.. code-block:: console - sudo mkdir /var/log/frr - sudo mkdir /etc/frr - sudo touch /etc/frr/zebra.conf - sudo touch /etc/frr/bgpd.conf - sudo touch /etc/frr/ospfd.conf - sudo touch /etc/frr/ospf6d.conf - sudo touch /etc/frr/isisd.conf - sudo touch /etc/frr/ripd.conf - sudo touch /etc/frr/ripngd.conf - sudo touch /etc/frr/pimd.conf - sudo touch /etc/frr/ldpd.conf - sudo touch /etc/frr/nhrpd.conf - sudo touch /etc/frr/eigrpd.conf - sudo touch /etc/frr/babeld.conf - sudo chown -R frr:frr /etc/frr/ - sudo touch /etc/frr/vtysh.conf - sudo chown frr:frrvty /etc/frr/vtysh.conf - sudo chmod 640 /etc/frr/*.conf + sudo mkdir /var/log/frr + sudo mkdir /etc/frr + sudo touch /etc/frr/zebra.conf + sudo touch /etc/frr/bgpd.conf + sudo touch /etc/frr/ospfd.conf + sudo touch /etc/frr/ospf6d.conf + sudo touch /etc/frr/isisd.conf + sudo touch /etc/frr/ripd.conf + sudo touch /etc/frr/ripngd.conf + sudo touch /etc/frr/pimd.conf + sudo touch /etc/frr/ldpd.conf + sudo touch /etc/frr/nhrpd.conf + sudo touch /etc/frr/eigrpd.conf + sudo touch /etc/frr/babeld.conf + sudo chown -R frr:frr /etc/frr/ + sudo touch /etc/frr/vtysh.conf + sudo chown frr:frrvty /etc/frr/vtysh.conf + sudo chmod 640 /etc/frr/*.conf Install daemon config file ^^^^^^^^^^^^^^^^^^^^^^^^^^ -:: +.. code-block:: console - sudo install -p -m 644 redhat/daemons /etc/frr/ - sudo chown frr:frr /etc/frr/daemons + sudo install -p -m 644 redhat/daemons /etc/frr/ + sudo chown frr:frr /etc/frr/daemons -Edit /etc/frr/daemons as needed to select the required daemons -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Edit /etc/frr/daemons +^^^^^^^^^^^^^^^^^^^^^ Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc. -Enable the daemons as required by changing the value to ``yes`` +Enable the daemons as required by changing the value to ``yes``. Enable IP & IPv6 forwarding (and MPLS) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the -following content: (Please make sure to list all interfaces with -required MPLS similar to ``net.mpls.conf.eth0.input=1``) +Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the following +content (please make sure to list all interfaces with required MPLS similar to +``net.mpls.conf.eth0.input=1``): -:: +.. code-block:: console - # Sysctl for routing - # - # Routing: We need to forward packets - net.ipv4.conf.all.forwarding=1 - net.ipv6.conf.all.forwarding=1 - # - # Enable MPLS Label processing on all interfaces - net.mpls.conf.eth0.input=1 - net.mpls.conf.eth1.input=1 - net.mpls.conf.eth2.input=1 - net.mpls.platform_labels=100000 + # Sysctl for routing + # + # Routing: We need to forward packets + net.ipv4.conf.all.forwarding=1 + net.ipv6.conf.all.forwarding=1 + # + # Enable MPLS Label processing on all interfaces + net.mpls.conf.eth0.input=1 + net.mpls.conf.eth1.input=1 + net.mpls.conf.eth2.input=1 + net.mpls.platform_labels=100000 Load the modified sysctl's on the system: -:: +.. code-block:: console - sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf + sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf Create a new file ``/etc/modules-load.d/mpls.conf`` with the following content: -:: +.. code-block:: console - # Load MPLS Kernel Modules - mpls-router - mpls-iptunnel + # Load MPLS Kernel Modules + mpls-router + mpls-iptunnel And load the kernel modules on the running system: -:: +.. code-block:: console - sudo modprobe mpls-router mpls-iptunnel + sudo modprobe mpls-router mpls-iptunnel -Install frr Service and redhat init files -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service - sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr - -Enable required frr at startup -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - sudo systemctl enable frr - -Reboot or start FRR manually +Install system service files ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -:: +.. code-block:: console - sudo systemctl start frr + sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service + sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr + sudo systemctl enable frr + +Start FRR +^^^^^^^^^ + +.. code-block:: frr + + sudo systemctl start frr From ba8083e5ce997a5b49f609898a24887e13faccc3 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 22 Mar 2019 18:33:25 +0000 Subject: [PATCH 103/142] doc: update Fedora 24 build doc * Cross reference RPM build docs * Add perl and patch to build deps * Add libyang-pluginsdir to ./configure options * Change instructions to unified config Verified on Fedora 28. Signed-off-by: Quentin Young --- doc/developer/building-frr-for-fedora24.rst | 93 +++++++++------------ 1 file changed, 41 insertions(+), 52 deletions(-) diff --git a/doc/developer/building-frr-for-fedora24.rst b/doc/developer/building-frr-for-fedora24.rst index d2a939d41c..97a39c0580 100644 --- a/doc/developer/building-frr-for-fedora24.rst +++ b/doc/developer/building-frr-for-fedora24.rst @@ -11,15 +11,16 @@ Installing Dependencies sudo dnf install git autoconf automake libtool make gawk \ readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \ - pam-devel pytest bison flex c-ares-devel python3-devel python3-sphinx + pam-devel pytest bison flex c-ares-devel python3-devel python2-sphinx \ + perl-core patch .. include:: building-libyang.rst Building & Installing FRR ------------------------- -Compilation -^^^^^^^^^^^ +Compile +^^^^^^^ Clone the FRR git repo and use the included ``configure`` script to configure FRR's build time options to your liking. The full option listing can be @@ -38,6 +39,7 @@ obtained by running ``./configure -h``. The options shown below are examples. --libexecdir=/usr/lib/frr \ --localstatedir=/var/run/frr \ --with-moduledir=/usr/lib/frr/modules \ + --with-libyang-pluginsdir=/usr/lib/frr/libyang_plugins \ --enable-snmp=agentx \ --enable-multipath=64 \ --enable-user=frr \ @@ -50,7 +52,7 @@ obtained by running ``./configure -h``. The options shown below are examples. make sudo make install -Add FRR groups and user +Add FRR user and groups ^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: console @@ -60,74 +62,61 @@ Add FRR groups and user sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \ -c "FRR FRRouting suite" -d /var/run/frr frr - -Create empty FRR configuration files -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Install FRR configuration files +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: console - sudo mkdir /var/log/frr - sudo mkdir /etc/frr - sudo touch /etc/frr/zebra.conf - sudo touch /etc/frr/bgpd.conf - sudo touch /etc/frr/ospfd.conf - sudo touch /etc/frr/ospf6d.conf - sudo touch /etc/frr/isisd.conf - sudo touch /etc/frr/ripd.conf - sudo touch /etc/frr/ripngd.conf - sudo touch /etc/frr/pimd.conf - sudo touch /etc/frr/ldpd.conf - sudo touch /etc/frr/nhrpd.conf - sudo touch /etc/frr/eigrpd.conf - sudo touch /etc/frr/babeld.conf - sudo chown -R frr:frr /etc/frr/ - sudo touch /etc/frr/vtysh.conf - sudo chown frr:frrvty /etc/frr/vtysh.conf - sudo chmod 640 /etc/frr/*.conf + sudo install -m 775 -o frr -g frr -d /var/log/frr + sudo install -m 775 -o frr -g frrvty -d /etc/frr + sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons -Install daemon config file -^^^^^^^^^^^^^^^^^^^^^^^^^^ +Enable daemons +^^^^^^^^^^^^^^ -.. code-block:: console +Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the +section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons +as required by changing the value to ``yes``. - sudo install -p -m 644 redhat/daemons /etc/frr/ - sudo chown frr:frr /etc/frr/daemons - -Edit /etc/frr/daemons -^^^^^^^^^^^^^^^^^^^^^ - -Look for the section with ``watchfrr_enable=...`` and ``zebra=...`` etc. -Enable the daemons as required by changing the value to ``yes``. - -Enable IP & IPv6 forwarding (and MPLS) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Tweak sysctls +^^^^^^^^^^^^^ +Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and +MPLS (if supported by your platform). If your platform does not support MPLS, +skip the MPLS related configuration in this section. Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the following -content (please make sure to list all interfaces with required MPLS similar to -``net.mpls.conf.eth0.input=1``): +content: .. code-block:: console - # Sysctl for routing # - # Routing: We need to forward packets + # Enable packet forwarding + # net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1 # # Enable MPLS Label processing on all interfaces - net.mpls.conf.eth0.input=1 - net.mpls.conf.eth1.input=1 - net.mpls.conf.eth2.input=1 - net.mpls.platform_labels=100000 + # + #net.mpls.conf.eth0.input=1 + #net.mpls.conf.eth1.input=1 + #net.mpls.conf.eth2.input=1 + #net.mpls.platform_labels=100000 -Load the modified sysctl's on the system: +.. note:: + + MPLS must be invidividually enabled on each interface that requires it. See + the example in the config block above. + +Load the modifed sysctls on the system: .. code-block:: console sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf -Create a new file ``/etc/modules-load.d/mpls.conf`` with the following -content: +Create a new file ``/etc/modules-load.d/mpls.conf`` with the following content: .. code-block:: console @@ -141,8 +130,8 @@ And load the kernel modules on the running system: sudo modprobe mpls-router mpls-iptunnel -Install system service files -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Install service files +^^^^^^^^^^^^^^^^^^^^^ .. code-block:: console From 0ac848ab871b8464e7f44ac43ce104121833b69d Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 22 Mar 2019 19:03:57 +0000 Subject: [PATCH 104/142] doc: mv Fedora 24 docs to cover 24+ Tested these on Fedora 24 and 28, so they should be true for all versions in-between as well as Fedora 29 and all upcoming versions. Signed-off-by: Quentin Young --- ...ing-frr-for-fedora24.rst => building-frr-for-fedora.rst} | 6 ++++-- doc/developer/subdir.am | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) rename doc/developer/{building-frr-for-fedora24.rst => building-frr-for-fedora.rst} (98%) diff --git a/doc/developer/building-frr-for-fedora24.rst b/doc/developer/building-frr-for-fedora.rst similarity index 98% rename from doc/developer/building-frr-for-fedora24.rst rename to doc/developer/building-frr-for-fedora.rst index 97a39c0580..a24e5ef1c5 100644 --- a/doc/developer/building-frr-for-fedora24.rst +++ b/doc/developer/building-frr-for-fedora.rst @@ -1,9 +1,11 @@ -Fedora 24 -========= +Fedora 24+ +========== This document describes installation from source. If you want to build an RPM, see :ref:`packaging-redhat`. +These instructions have been tested on Fedora 24+. + Installing Dependencies ----------------------- diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index a0c5e6fc9d..6580dca58f 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -10,7 +10,7 @@ dev_RSTFILES = \ doc/developer/building-frr-for-centos7.rst \ doc/developer/building-frr-for-debian8.rst \ doc/developer/building-frr-for-debian9.rst \ - doc/developer/building-frr-for-fedora24.rst \ + doc/developer/building-frr-for-fedora.rst \ doc/developer/building-frr-for-freebsd10.rst \ doc/developer/building-frr-for-freebsd11.rst \ doc/developer/building-frr-for-freebsd9.rst \ From 6f875a362aee7f465e3cb25576324ea57a05f27d Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Mon, 25 Mar 2019 13:35:02 -0400 Subject: [PATCH 105/142] zebra: use the INSTALLED flag consistently in route summary The 'sho ip route summary' and 'sho ip route summary ' paths used different definitions of a 'fib' route. Use the route-entry 'INSTALLED' flag in both places. Signed-off-by: Mark Stapp --- zebra/zebra_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index b0884f22cf..f89293814e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1375,7 +1375,7 @@ static void vty_show_ip_route_summary(struct vty *vty, else rib_cnt[re->type]++; - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) { + if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) { fib_cnt[ZEBRA_ROUTE_TOTAL]++; if (is_ibgp) From 0d5e41c628f3f72983be354cde3a49498790b37e Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 25 Mar 2019 12:08:26 -0300 Subject: [PATCH 106/142] topotests/lib: fallback topology logdir if none was configured `param.get` always evaluates the second argument and it was causing two log directories being created for topologies using Topogen. Signed-off-by: Rafael Zalamena --- tests/topotests/lib/topotest.py | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 84358b94bc..e0da20e07f 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -63,23 +63,6 @@ class json_cmp_result(object): def __str__(self): return '\n'.join(self.errors) -def get_test_logdir(node=None, init=False): - """ - Return the current test log directory based on PYTEST_CURRENT_TEST - environment variable. - Optional paramters: - node: when set, adds the node specific log directory to the init dir - init: when set, initializes the log directory and fixes path permissions - """ - cur_test = os.environ['PYTEST_CURRENT_TEST'] - - ret = '/tmp/topotests/' + cur_test[0:cur_test.find(".py")].replace('/','.') - if node != None: - dir = ret + "/" + node - if init: - os.system('mkdir -p ' + dir) - os.system('chmod -R go+rw /tmp/topotests') - return ret def json_diff(d1, d2): """ @@ -612,7 +595,21 @@ class Router(Node): def __init__(self, name, **params): super(Router, self).__init__(name, **params) - self.logdir = params.get('logdir', get_test_logdir(name, True)) + self.logdir = params.get('logdir') + + # If this topology is using old API and doesn't have logdir + # specified, then attempt to generate an unique logdir. + if self.logdir is None: + cur_test = os.environ['PYTEST_CURRENT_TEST'] + self.logdir = ('/tmp/topotests/' + + cur_test[0:cur_test.find(".py")].replace('/', '.')) + + # If the logdir is not created, then create it and set the + # appropriated permissions. + if not os.path.isdir(self.logdir): + os.system('mkdir -p ' + self.logdir + '/' + name) + os.system('chmod -R go+rw /tmp/topotests') + self.daemondir = None self.hasmpls = False self.routertype = 'frr' From 87ba6e1e3ab2f45108f39ec71a2da96d66a6d18a Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 25 Mar 2019 14:47:49 -0300 Subject: [PATCH 107/142] topotests/lib: fix router specific log output Change the router log output to the previous folder so it doesn't get erased when starting the old API (unbreaks command/output logging on Topogen). Signed-off-by: Rafael Zalamena --- tests/topotests/lib/topogen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index 8688a13aef..d989240a16 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -586,9 +586,9 @@ class TopoRouter(TopoGear): os.system('chmod -R go+rw /tmp/topotests') # Open router log file - logfile = '{0}/{1}.log'.format(dir, name) - + logfile = '{0}/{1}.log'.format(self.logdir, name) self.logger = logger_config.get_logger(name=name, target=logfile) + self.tgen.topo.addNode(self.name, cls=self.cls, **params) def __str__(self): From c2793eda33af32952ddb4e92d835b5372e73357c Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 25 Mar 2019 20:21:10 +0000 Subject: [PATCH 108/142] doc: pull out compile instructions into snippet We're going to use this same snippet across every build doc so let's just pull it into its own include file now. Signed-off-by: Quentin Young --- doc/developer/conf.py | 2 +- doc/developer/include-compile.rst | 37 +++++++++++++++++++++++++++++++ doc/developer/subdir.am | 1 + 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 doc/developer/include-compile.rst diff --git a/doc/developer/conf.py b/doc/developer/conf.py index af8673e5fa..9acfab739a 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -131,7 +131,7 @@ language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst'] +exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst', 'include-compile.rst'] # The reST default role (used for this markup: `text`) to use for all # documents. diff --git a/doc/developer/include-compile.rst b/doc/developer/include-compile.rst new file mode 100644 index 0000000000..0ff0ae3ffe --- /dev/null +++ b/doc/developer/include-compile.rst @@ -0,0 +1,37 @@ +Clone the FRR git repo and use the included ``configure`` script to configure +FRR's build time options to your liking. The full option listing can be +obtained by running ``./configure -h``. The options shown below are examples. + +.. note:: + + If your platform uses ``systemd``, please make sure to add + ``--enable-systemd=yes`` to your configure options. + +.. code-block:: console + + git clone https://github.com/frrouting/frr.git frr + cd frr + ./bootstrap.sh + ./configure \ + --prefix=/usr \ + --includedir=\${prefix}/include \ + --enable-exampledir=\${prefix}/share/doc/frr/examples \ + --bindir=\${prefix}/bin \ + --sbindir=\${prefix}/lib/frr \ + --libdir=\${prefix}/lib/frr \ + --libexecdir=\${prefix}/lib/frr \ + --localstatedir=/var/run/frr \ + --sysconfdir=/etc/frr \ + --with-moduledir=\${prefix}/lib/frr/modules \ + --with-libyang-pluginsdir=\${prefix}/lib/frr/libyang_plugins \ + --enable-configfile-mask=0640 \ + --enable-logfile-mask=0640 \ + --enable-snmp=agentx \ + --enable-multipath=64 \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --with-pkg-git-version \ + --with-pkg-extra-version=-MyOwnFRRVersion + make + sudo make install diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index 6580dca58f..7ae48881ab 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -27,6 +27,7 @@ dev_RSTFILES = \ doc/developer/cli.rst \ doc/developer/conf.py \ doc/developer/hooks.rst \ + doc/developer/include-compile.rst \ doc/developer/index.rst \ doc/developer/library.rst \ doc/developer/logging.rst \ From 4ff6f66ac95c51485744e5ffaabcb0cc0cf8735f Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 25 Mar 2019 20:21:54 +0000 Subject: [PATCH 109/142] doc: reorganize fedora doc a bit * Use compile include snippet * Move daemons enable section to end * Fix a couple syntax errors Signed-off-by: Quentin Young --- doc/developer/building-frr-for-fedora.rst | 57 ++++++----------------- 1 file changed, 15 insertions(+), 42 deletions(-) diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst index a24e5ef1c5..6900aed0e0 100644 --- a/doc/developer/building-frr-for-fedora.rst +++ b/doc/developer/building-frr-for-fedora.rst @@ -21,39 +21,6 @@ Installing Dependencies Building & Installing FRR ------------------------- -Compile -^^^^^^^ - -Clone the FRR git repo and use the included ``configure`` script to configure -FRR's build time options to your liking. The full option listing can be -obtained by running ``./configure -h``. The options shown below are examples. - -.. code-block:: console - - git clone https://github.com/frrouting/frr.git frr - cd frr - ./bootstrap.sh - ./configure \ - --bindir=/usr/bin \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - --libdir=/usr/lib/frr \ - --libexecdir=/usr/lib/frr \ - --localstatedir=/var/run/frr \ - --with-moduledir=/usr/lib/frr/modules \ - --with-libyang-pluginsdir=/usr/lib/frr/libyang_plugins \ - --enable-snmp=agentx \ - --enable-multipath=64 \ - --enable-user=frr \ - --enable-group=frr \ - --enable-vty-group=frrvty \ - --disable-exampledir \ - --enable-fpm \ - --with-pkg-git-version \ - --with-pkg-extra-version=-MyOwnFRRVersion - make - sudo make install - Add FRR user and groups ^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,6 +31,11 @@ Add FRR user and groups sudo useradd -u 92 -g 92 -M -r -G frrvty -s /sbin/nologin \ -c "FRR FRRouting suite" -d /var/run/frr frr +Compile +^^^^^^^ + +.. include:: include-compile.rst + Install FRR configuration files ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,15 +48,9 @@ Install FRR configuration files sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons -Enable daemons -^^^^^^^^^^^^^^ - -Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the -section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons -as required by changing the value to ``yes``. - Tweak sysctls ^^^^^^^^^^^^^ + Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and MPLS (if supported by your platform). If your platform does not support MPLS, skip the MPLS related configuration in this section. @@ -92,7 +58,7 @@ skip the MPLS related configuration in this section. Create a new file ``/etc/sysctl.d/90-routing-sysctl.conf`` with the following content: -.. code-block:: console +:: # # Enable packet forwarding @@ -120,7 +86,7 @@ Load the modifed sysctls on the system: Create a new file ``/etc/modules-load.d/mpls.conf`` with the following content: -.. code-block:: console +:: # Load MPLS Kernel Modules mpls-router @@ -141,6 +107,13 @@ Install service files sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr sudo systemctl enable frr +Enable daemons +^^^^^^^^^^^^^^ + +Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the +section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons +as required by changing the value to ``yes``. + Start FRR ^^^^^^^^^ From 4983c2177f61429565ebc53ce6bdc3aa76ee98ab Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 25 Mar 2019 20:22:53 +0000 Subject: [PATCH 110/142] doc: update building.rst for new fedora doc Signed-off-by: Quentin Young --- doc/developer/building.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/developer/building.rst b/doc/developer/building.rst index 96559b0abe..c13fb10ffc 100644 --- a/doc/developer/building.rst +++ b/doc/developer/building.rst @@ -12,7 +12,7 @@ Building FRR building-frr-for-centos7 building-frr-for-debian8 building-frr-for-debian9 - building-frr-for-fedora24 + building-frr-for-fedora building-frr-for-freebsd10 building-frr-for-freebsd11 building-frr-for-freebsd9 From ae999ff8626cb06fc8493082dffc53d5500de4fa Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 25 Mar 2019 20:11:47 +0000 Subject: [PATCH 111/142] doc: update build docs for Ubuntu 18.04 * Update build package list * Update ./configure options * Fix some RST syntax errors * Use monolithic config examples * Use compile include snippet * Reorganize a bit Tested on Ubuntu 18.04 Signed-off-by: Quentin Young --- doc/developer/building-frr-for-ubuntu1804.rst | 205 +++++------------- 1 file changed, 51 insertions(+), 154 deletions(-) diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst index 089d5a216a..6f7f0acd11 100644 --- a/doc/developer/building-frr-for-ubuntu1804.rst +++ b/doc/developer/building-frr-for-ubuntu1804.rst @@ -1,55 +1,44 @@ Ubuntu 18.04 LTS ================ -Install dependencies --------------------- +This document describes installation from source. If you want to build a +``deb``, see :ref:`packaging-debian`. -Required packages -^^^^^^^^^^^^^^^^^ +Installing Dependencies +----------------------- -:: +.. code-block:: console + sudo apt update sudo apt-get install \ git autoconf automake libtool make gawk libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ - libc-ares-dev python3-dev libsystemd-dev python-ipaddress \ - python3-sphinx install-info build-essential libsystemd-dev + libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ + install-info build-essential libsystemd-dev libsnmp-dev perl .. include:: building-libyang.rst -Optional packages -^^^^^^^^^^^^^^^^^ - -Dependencies for additional functionality can be installed as-desired. - Protobuf -~~~~~~~~ +^^^^^^^^ -:: +.. code-block:: console - sudo apt-get install \ - protobuf-c-compiler \ - libprotobuf-c-dev + sudo apt-get install protobuf-c-compiler libprotobuf-c-dev ZeroMQ -~~~~~~ +^^^^^^ -:: +.. code-block:: console - sudo apt-get install \ - libzmq5 \ - libzmq3-dev + sudo apt-get install libzmq5 libzmq3-dev -Get FRR, compile it and install it (from Git) ---------------------------------------------- +Building & Installing FRR +------------------------- -**This assumes you want to build and install FRR from source and not -using any packages** - -Add frr groups and user +Add FRR user and groups ^^^^^^^^^^^^^^^^^^^^^^^ -:: +.. code-block:: console sudo groupadd -r -g 92 frr sudo groupadd -r -g 85 frrvty @@ -57,104 +46,29 @@ Add frr groups and user --gecos "FRR suite" --shell /sbin/nologin frr sudo usermod -a -G frrvty frr -Download source -^^^^^^^^^^^^^^^ - -:: - - git clone https://github.com/frrouting/frr.git frr - -Configure -^^^^^^^^^ -Options below are provided as an example. - -.. seealso:: *Installation* section of user guide - -.. code-block:: shell - - cd frr - ./bootstrap.sh - ./configure \ - --prefix=/usr \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - --enable-multipath=64 \ - --enable-user=frr \ - --enable-group=frr \ - --enable-vty-group=frrvty \ - --enable-configfile-mask=0640 \ - --enable-logfile-mask=0640 \ - --enable-fpm \ - --enable-systemd=yes \ - --with-pkg-git-version \ - --with-pkg-extra-version=-MyOwnFRRVersion - -If optional packages were installed, the associated feature may now be -enabled. - -.. option:: --enable-protobuf - -Enable support for protobuf transport - -.. option:: --enable-zeromq - -Enable support for ZeroMQ transport - Compile ^^^^^^^ -:: +.. include:: include-compile.rst - make - make check - sudo make install +Install FRR configuration files +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Create empty FRR configuration files -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. code-block:: console -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, :file:`/etc/frr/frr.conf`. - -.. seealso:: *VTYSH* section of user guide - -The presence of :file:`/etc/frr/frr.conf` on startup implicitly configures FRR -to ignore daemon-specific configuration files. - -Daemon-specific configuration -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - sudo install -m 755 -o frr -g frr -d /var/log/frr + sudo install -m 775 -o frr -g frr -d /var/log/frr sudo install -m 775 -o frr -g frrvty -d /etc/frr - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf + sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons -Monolithic configuration -~~~~~~~~~~~~~~~~~~~~~~~~ +Tweak sysctls +^^^^^^^^^^^^^ -:: - - sudo install -m 755 -o frr -g frr -d /var/log/frr - sudo install -m 775 -o frr -g frrvty -d /etc/frr - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/frr.conf - -Enable IPv4 & IPv6 forwarding -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and +MPLS (if supported by your platform). If your platform does not support MPLS, +skip the MPLS related configuration in this section. Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the other settings): @@ -169,8 +83,10 @@ other settings): # based on Router Advertisements for this host net.ipv6.conf.all.forwarding=1 +Reboot or use ``sysctl -p`` to apply the same config to the running system. + Add MPLS kernel modules -^^^^^^^^^^^^^^^^^^^^^^^ +""""""""""""""""""""""" Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`: @@ -181,10 +97,15 @@ enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`: mpls_router mpls_iptunnel -Reboot or use ``sysctl -p`` to apply the same config to the running system. + +And load the kernel modules on the running system: + +.. code-block:: console + + sudo modprobe mpls-router mpls-iptunnel Enable MPLS Forwarding -^^^^^^^^^^^^^^^^^^^^^^ +"""""""""""""""""""""" Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS. @@ -197,48 +118,24 @@ equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS. net.mpls.conf.eth2.input=1 net.mpls.platform_labels=100000 -Install the systemd service -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Install service files +^^^^^^^^^^^^^^^^^^^^^ -:: +.. code-block:: console sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service - sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons - sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf - sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf + sudo systemctl enable frr Enable daemons ^^^^^^^^^^^^^^ -Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for those -daemons you want to start by systemd. For example: +Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the +section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons +as required by changing the value to ``yes``. -:: - - zebra=yes - bgpd=yes - ospfd=yes - ospf6d=yes - ripd=yes - ripngd=yes - isisd=yes - -Enable the systemd service -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Enabling the systemd service causes FRR to be started upon boot. To enable it, -use the following command: - -.. code-block:: shell - - systemctl enable frr - -Start the systemd service -^^^^^^^^^^^^^^^^^^^^^^^^^ +Start FRR +^^^^^^^^^ .. code-block:: shell systemctl start frr - -After starting the service, you can use ``systemctl status frr`` to check its -status. From 4cebb2b6f66466e916de9c5171ce13cb6dbb3447 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 26 Mar 2019 01:03:06 -0400 Subject: [PATCH 112/142] zebra: Fix extended ack error message parsing Fix the macros for reading NLA attribute info from an extended error ack. We were processing the data using route attributes (rtattr) which is identical in size to nlattr but probably should not be used. Further, we were incorrectly calculating the length of the inner netlink message that cause the error. We have to read passed that in order to access all the nlattr's. Signed-off-by: Stephen Worley --- zebra/kernel_netlink.c | 46 ++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index c5fbfd4481..fe37a33358 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -606,50 +606,56 @@ const char *nl_rttype_to_str(uint8_t rttype) return lookup_msg(rttype_str, rttype, ""); } -#define NL_OK(nla, len) \ +#define NLA_OK(nla, len) \ ((len) >= (int)sizeof(struct nlattr) \ && (nla)->nla_len >= sizeof(struct nlattr) \ && (nla)->nla_len <= (len)) -#define NL_NEXT(nla, attrlen) \ - ((attrlen) -= RTA_ALIGN((nla)->nla_len), \ - (struct nlattr *)(((char *)(nla)) + RTA_ALIGN((nla)->nla_len))) -#define NL_RTA(r) \ - ((struct nlattr *)(((char *)(r)) \ - + NLMSG_ALIGN(sizeof(struct nlmsgerr)))) +#define NLA_NEXT(nla, attrlen) \ + ((attrlen) -= NLA_ALIGN((nla)->nla_len), \ + (struct nlattr *)(((char *)(nla)) + NLA_ALIGN((nla)->nla_len))) +#define NLA_LENGTH(len) (NLA_ALIGN(sizeof(struct nlattr)) + (len)) +#define NLA_DATA(nla) ((struct nlattr *)(((char *)(nla)) + NLA_LENGTH(0))) + +#define ERR_NLA(err, inner_len) \ + ((struct nlattr *)(((char *)(err)) \ + + NLMSG_ALIGN(sizeof(struct nlmsgerr)) \ + + NLMSG_ALIGN((inner_len)))) static void netlink_parse_nlattr(struct nlattr **tb, int max, struct nlattr *nla, int len) { - while (NL_OK(nla, len)) { + while (NLA_OK(nla, len)) { if (nla->nla_type <= max) tb[nla->nla_type] = nla; - nla = NL_NEXT(nla, len); + nla = NLA_NEXT(nla, len); } } static void netlink_parse_extended_ack(struct nlmsghdr *h) { - struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; - const struct nlmsgerr *err = - (const struct nlmsgerr *)((uint8_t *)h - + NLMSG_ALIGN( - sizeof(struct nlmsghdr))); + struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {}; + const struct nlmsgerr *err = (const struct nlmsgerr *)NLMSG_DATA(h); const struct nlmsghdr *err_nlh = NULL; - uint32_t hlen = sizeof(*err); + /* Length not including nlmsghdr */ + uint32_t len = 0; + /* Inner error netlink message length */ + uint32_t inner_len = 0; const char *msg = NULL; uint32_t off = 0; if (!(h->nlmsg_flags & NLM_F_CAPPED)) - hlen += h->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr)); + inner_len = (uint32_t)NLMSG_PAYLOAD(&err->msg, 0); - memset(tb, 0, sizeof(tb)); - netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, NL_RTA(h), hlen); + len = (uint32_t)(NLMSG_PAYLOAD(h, sizeof(struct nlmsgerr)) - inner_len); + + netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, ERR_NLA(err, inner_len), + len); if (tb[NLMSGERR_ATTR_MSG]) - msg = (const char *)RTA_DATA(tb[NLMSGERR_ATTR_MSG]); + msg = (const char *)NLA_DATA(tb[NLMSGERR_ATTR_MSG]); if (tb[NLMSGERR_ATTR_OFFS]) { - off = *(uint32_t *)RTA_DATA(tb[NLMSGERR_ATTR_OFFS]); + off = *(uint32_t *)NLA_DATA(tb[NLMSGERR_ATTR_OFFS]); if (off > h->nlmsg_len) { zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS"); From a55578f631e054d45ad14d74a0d45f53a0c634be Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 26 Mar 2019 10:28:09 +0100 Subject: [PATCH 113/142] tools/frr.in: Only attempt to load daemons.conf if present Apparently, the default changed to use `/etc/frr/daemons` instead of `/etc/frr/daemons.conf`. Therefore, we should ignore absence of the latter file, because its absence is not an actuall error but will cause a confusing error message like this: /etc/init.d/frr: line 507: /etc/frr/daemons.conf: No such file or directory --- tools/frr.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/frr.in b/tools/frr.in index a443191fd0..2e3a094589 100755 --- a/tools/frr.in +++ b/tools/frr.in @@ -504,7 +504,9 @@ check_status() # Load configuration . "$C_PATH/daemons" -. "$C_PATH/daemons.conf" +if [ -e "$C_PATH/daemons.conf" ]; then + . "$C_PATH/daemons.conf" +fi # Read configuration variable file if it is present [ -r /etc/default/frr ] && . /etc/default/frr From 13366862ccc976fa83978ea08879a7becef2bcb4 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 26 Mar 2019 09:11:28 -0400 Subject: [PATCH 114/142] bgpd: Split up warn message to allow finer grained understanding We have the same warn message in 3 spots, which makes it extremely hard to figure out which of the 3 has gone terribly wrong. Add a bit of code to disambiguate the 3 situations. Signed-off-by: Donald Sharp --- bgpd/bgp_attr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 226bf99d2c..bea46f3e45 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1715,7 +1715,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN); if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) { if (!peer->nexthop.ifp) { - zlog_warn("%s: interface not set appropriately to handle some attributes", + zlog_warn("%s: Received a V6/VPNV6 Global attribute but address is a V6 LL and we have no peer interface information, withdrawing", peer->host); return BGP_ATTR_PARSE_WITHDRAW; } @@ -1732,7 +1732,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN); if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) { if (!peer->nexthop.ifp) { - zlog_warn("%s: interface not set appropriately to handle some attributes", + zlog_warn("%s: Received V6/VPNV6 Global and LL attribute but global address is a V6 LL and we have no peer interface information, withdrawing", peer->host); return BGP_ATTR_PARSE_WITHDRAW; } @@ -1762,7 +1762,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, attr->mp_nexthop_len = IPV6_MAX_BYTELEN; } if (!peer->nexthop.ifp) { - zlog_warn("%s: Interface not set appropriately to handle this some attributes", + zlog_warn("%s: Received a V6 LL nexthop and we have no peer interface information, withdrawing", peer->host); return BGP_ATTR_PARSE_WITHDRAW; } From 727aebd6a324b0bfe7fa8a9fa31eecea99471883 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 26 Mar 2019 18:27:24 +0100 Subject: [PATCH 115/142] alpine: Move docker-start to Docker build The standard Alpine package should not install docker glue, so remove it from the APKBUILD and install it in the Dockerfile instead. --- alpine/APKBUILD.in | 1 - docker/alpine/Dockerfile | 1 + {alpine => docker/alpine}/docker-start | 6 ++++-- 3 files changed, 5 insertions(+), 3 deletions(-) rename {alpine => docker/alpine}/docker-start (51%) diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index 969b85f524..75613ae005 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -60,7 +60,6 @@ package() { cd "$builddir" make DESTDIR="$pkgdir" install - install -Dm755 "$srcdir"/docker-start "$pkgdir"$_sbindir install -Dm644 "$srcdir"/daemons "$pkgdir"$_sysconfdir install -d "$pkgdir"/etc/init.d ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index dd29358b07..f19f1e877b 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -32,4 +32,5 @@ RUN mkdir -p /pkgs/apk COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/ RUN apk add --no-cache tini RUN apk add --no-cache --allow-untrusted /pkgs/apk/x86_64/*.apk +COPY docker/alpine/docker-start /usr/lib/frr/docker-start ENTRYPOINT [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ] diff --git a/alpine/docker-start b/docker/alpine/docker-start similarity index 51% rename from alpine/docker-start rename to docker/alpine/docker-start index 43854ab142..52cfb664ce 100755 --- a/alpine/docker-start +++ b/docker/alpine/docker-start @@ -6,5 +6,7 @@ set -e # For volume mounts... ## chown -R frr:frr /etc/frr -/etc/init.d/frr start -exec sleep 10000d +/usr/lib/frr/frrinit.sh start + +# Sleep forever +exec tail -f /dev/null From e3f80e1e2fb7bfb2d5f5a61c03b6d78c6c2164fd Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 26 Mar 2019 12:56:23 +0100 Subject: [PATCH 116/142] docker/alpine: Unbreak build by using edge/testing As we need libyang, which is only part of Alpine Linux edge/testing, update the Dockerfile to use this repository. Also, update the Dockerfile to adhere more to best common practices. --- docker/alpine/Dockerfile | 77 ++++++++++++++++++++++------------- docker/alpine/alpine-build.sh | 11 ----- docker/alpine/builder | 1 - 3 files changed, 49 insertions(+), 40 deletions(-) delete mode 100755 docker/alpine/alpine-build.sh delete mode 100644 docker/alpine/builder diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index f19f1e877b..80ddb30d5b 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,36 +1,57 @@ -FROM alpine:3.7 as source-builder +# This stage builds a dist tarball from the source +FROM alpine:edge as source-builder ARG commit -RUN apk add --no-cache abuild acct alpine-sdk attr autoconf automake bash \ - binutils binutils-libs bison bsd-compat-headers build-base \ - c-ares c-ares-dev ca-certificates cryptsetup-libs curl \ - device-mapper-libs expat fakeroot flex fortify-headers g++ gcc gdbm \ - git gmp isl json-c json-c-dev kmod lddtree libacl libatomic libattr \ - libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc \ - libgomp libisoburn libisofs libltdl libressl libssh2 \ - libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1 \ - mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base \ - patch pax-utils pcre perl pkgconf python2 python2-dev readline \ - readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs \ - groff gzip bc py-sphinx -ADD . /src -RUN (cd /src && \ - ./bootstrap.sh && \ - ./configure \ + +RUN mkdir -p /src/alpine +COPY alpine/APKBUILD.in /src/alpine +RUN source /src/alpine/APKBUILD.in \ + && echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \ + && apk add \ + --no-cache \ + --update-cache \ + $makedepends \ + gzip + +COPY . /src +RUN cd /src \ + && ./bootstrap.sh \ + && ./configure \ --enable-numeric-version \ - --with-pkg-extra-version=_git$commit && \ - make dist) -FROM alpine:3.7 as alpine-builder -RUN apk add --no-cache abuild alpine-sdk && mkdir -p /pkgs/apk -ADD docker/alpine/alpine-build.sh /usr/bin/ -ADD docker/alpine/builder /etc/sudoers.d -COPY --from=source-builder /src/*.tar.gz /src/alpine/* /src/tools/etc/frr/daemons* /dist/ + --with-pkg-extra-version=_git$commit \ + && make dist + +# This stage builds an apk from the dist tarball +FROM alpine:edge as alpine-builder +# Don't use nocache here so that abuild can use the cache +RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \ + && apk add \ + --update-cache \ + abuild \ + alpine-conf \ + alpine-sdk \ + && setup-apkcache /var/cache/apk \ + && mkdir -p /pkgs/apk \ + && echo 'builder ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers + +COPY --from=source-builder /src/frr-*.tar.gz /src/alpine/* /dist/ RUN adduser -D -G abuild builder && chown -R builder /dist /pkgs USER builder -RUN /usr/bin/alpine-build.sh -FROM alpine:3.7 +RUN cd /dist \ + && abuild-keygen -a -n \ + && abuild checksum \ + && abuild -r -P /pkgs/apk + +# This stage installs frr from the apk +FROM alpine:edge RUN mkdir -p /pkgs/apk COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/ -RUN apk add --no-cache tini -RUN apk add --no-cache --allow-untrusted /pkgs/apk/x86_64/*.apk +RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \ + && apk add \ + --no-cache \ + --update-cache \ + tini \ + && apk add \ + --no-cache \ + --allow-untrusted /pkgs/apk/*/*.apk COPY docker/alpine/docker-start /usr/lib/frr/docker-start ENTRYPOINT [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ] diff --git a/docker/alpine/alpine-build.sh b/docker/alpine/alpine-build.sh deleted file mode 100755 index d4c0311122..0000000000 --- a/docker/alpine/alpine-build.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -set -e - -cd /dist - -sudo apk --update add alpine-conf -sudo setup-apkcache /var/cache/apk -abuild-keygen -a -n -abuild checksum -abuild -r -P /pkgs/apk diff --git a/docker/alpine/builder b/docker/alpine/builder deleted file mode 100644 index a950b8abaf..0000000000 --- a/docker/alpine/builder +++ /dev/null @@ -1 +0,0 @@ -builder ALL=(ALL) NOPASSWD:ALL From 82ebca27d61b88f7212eb674e494eac5a98b1bf0 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 26 Mar 2019 14:56:59 +0100 Subject: [PATCH 117/142] alpine/APKBUILD.in: Add libyang-dev dependency, drop binutils-libs We need libyang to build FRR, so add it to the make dependencies. Alpine will automatically detect it as runtime dependency, so no need to add it there. The package binutils-libs doesn't exist anymore, so remove it from the dependencies. --- alpine/APKBUILD.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index 75613ae005..340c91c176 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -9,13 +9,13 @@ license="GPL-2.0" depends="json-c c-ares ipsec-tools iproute2 python py-ipaddr bash" makedepends="ncurses-dev net-snmp-dev gawk texinfo perl acct autoconf automake bash - binutils binutils-libs bison bsd-compat-headers build-base + binutils bison bsd-compat-headers build-base c-ares c-ares-dev ca-certificates cryptsetup-libs curl device-mapper-libs expat fakeroot flex fortify-headers gdbm git gmp isl json-c-dev kmod lddtree libacl libatomic libattr libblkid libburn libbz2 libc-dev libcap libcurl libedit libffi libgcc libgomp libisoburn libisofs libltdl libressl libssh2 - libstdc++ libtool libuuid linux-headers lzip lzo m4 make mkinitfs mpc1 + libstdc++ libtool libuuid libyang-dev linux-headers lzip lzo m4 make mkinitfs mpc1 mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre perl pkgconf python2 python2-dev readline readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs From a4926e467ecd53ebf06793969838d063228b7744 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 26 Mar 2019 15:46:51 +0100 Subject: [PATCH 118/142] alpine/APKBUILD.in: Don't include daemons from srcdir The daemons file will be generated during the build, so there is no need to copy it over from the first stage. --- alpine/APKBUILD.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index 340c91c176..0f56a427dd 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -23,7 +23,7 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl checkdepends="pytest py-setuptools" install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall" subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg" -source="$pkgname-$pkgver.tar.gz docker-start daemons" +source="$pkgname-$pkgver.tar.gz" builddir="$srcdir"/$pkgname-$pkgver @@ -60,7 +60,7 @@ package() { cd "$builddir" make DESTDIR="$pkgdir" install - install -Dm644 "$srcdir"/daemons "$pkgdir"$_sysconfdir + install -Dm644 "$builddir"/tools/etc/frr/daemons "$pkgdir"$_sysconfdir install -d "$pkgdir"/etc/init.d ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr } From eb3400c12bb8474baa35eb29b77b5c84c4113132 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Tue, 26 Mar 2019 18:30:18 +0100 Subject: [PATCH 119/142] docker/alpine/build.sh: Install packages to docker/alpine The packages resulting from the Alpine build should be installed to docker/alpine and not to the general docker directory. --- docker/alpine/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/alpine/build.sh b/docker/alpine/build.sh index 40ed1194fe..5a79ebcdcb 100755 --- a/docker/alpine/build.sh +++ b/docker/alpine/build.sh @@ -12,6 +12,6 @@ commit=`printf '%u\n' 0x$c` docker build -f docker/alpine/Dockerfile \ --build-arg commit=$commit -t frr:alpine-$c . id=`docker create frr:alpine-$c` -docker cp ${id}:/pkgs/ docker +docker cp ${id}:/pkgs/ docker/alpine docker rm $id docker rmi frr:alpine-$c From 749461a631622b5f711ccddd2215ae475f6a57e6 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Tue, 26 Mar 2019 20:53:58 +0000 Subject: [PATCH 120/142] doc: exclude bfd-options.rst from toctree This is an include file, needs to be explicitly excluded to suppress Sphinx warnings. Signed-off-by: Quentin Young --- doc/manpages/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manpages/conf.py b/doc/manpages/conf.py index f57bc1d278..46240de1c0 100644 --- a/doc/manpages/conf.py +++ b/doc/manpages/conf.py @@ -129,7 +129,7 @@ language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build', 'common-options.rst', 'epilogue.rst', 'defines.rst'] +exclude_patterns = ['_build', 'common-options.rst', 'epilogue.rst', 'defines.rst', 'bfd-options.rst'] # The reST default role (used for this markup: `text`) to use for all # documents. From 650c632224a3813acde29e9860309174b572477c Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Tue, 26 Mar 2019 20:50:16 +0000 Subject: [PATCH 121/142] doc: update build docs for Ubuntu 16.04 Same updates as Ubuntu 18.04 doc Tested on Ubuntu 16.04 Signed-off-by: Quentin Young --- doc/developer/building-frr-for-ubuntu1604.rst | 230 ++++++++---------- 1 file changed, 96 insertions(+), 134 deletions(-) diff --git a/doc/developer/building-frr-for-ubuntu1604.rst b/doc/developer/building-frr-for-ubuntu1604.rst index 0762e07eb9..63cb9aa13a 100644 --- a/doc/developer/building-frr-for-ubuntu1604.rst +++ b/doc/developer/building-frr-for-ubuntu1604.rst @@ -1,172 +1,134 @@ -Ubuntu 16.04LTS -=============================================== +Ubuntu 16.04 LTS +================ -- MPLS is not supported on ``Ubuntu 16.04`` with default kernel. MPLS - requires Linux Kernel 4.5 or higher (LDP can be built, but may have - limited use without MPLS) For an updated Ubuntu Kernel, see - http://kernel.ubuntu.com/~kernel-ppa/mainline/ +This document describes installation from source. If you want to build a +``deb``, see :ref:`packaging-debian`. -Install required packages -------------------------- +Installing Dependencies +----------------------- -Add packages: - -:: +.. code-block:: console + apt-get update apt-get install \ - git autoconf automake libtool make gawk libreadline-dev texinfo dejagnu \ + git autoconf automake libtool make gawk libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ - libc-ares-dev python3-dev libsystemd-dev python-ipaddress \ - python3-sphinx install-info build-essential libsystemd-dev + libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ + install-info build-essential libsystemd-dev libsnmp-dev perl .. include:: building-libyang.rst -Get FRR, compile it and install it (from Git) ---------------------------------------------- +Building & Installing FRR +------------------------- -**This assumes you want to build and install FRR from source and not -using any packages** - -Add frr groups and user +Add FRR user and groups ^^^^^^^^^^^^^^^^^^^^^^^ -:: +.. code-block:: console - sudo groupadd -r -g 92 frr - sudo groupadd -r -g 85 frrvty - sudo adduser --system --ingroup frr --home /var/run/frr/ \ - --gecos "FRR suite" --shell /sbin/nologin frr - sudo usermod -a -G frrvty frr + sudo groupadd -r -g 92 frr + sudo groupadd -r -g 85 frrvty + sudo adduser --system --ingroup frr --home /var/run/frr/ \ + --gecos "FRR suite" --shell /sbin/nologin frr + sudo usermod -a -G frrvty frr -Download Source, configure and compile it -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Compile +^^^^^^^ -(You may prefer different options on configure statement. These are just -an example.) +.. include:: include-compile.rst + +Install FRR configuration files +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: console + + sudo install -m 775 -o frr -g frr -d /var/log/frr + sudo install -m 775 -o frr -g frrvty -d /etc/frr + sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons + +Tweak sysctls +^^^^^^^^^^^^^ + +Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and +MPLS (if supported by your platform). If your platform does not support MPLS, +skip the MPLS related configuration in this section. + +Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the +other settings): :: - git clone https://github.com/frrouting/frr.git frr - cd frr - ./bootstrap.sh - ./configure \ - --prefix=/usr \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - --enable-multipath=64 \ - --enable-user=frr \ - --enable-group=frr \ - --enable-vty-group=frrvty \ - --enable-configfile-mask=0640 \ - --enable-logfile-mask=0640 \ - --enable-fpm \ - --enable-systemd=yes \ - --with-pkg-git-version \ - --with-pkg-extra-version=-MyOwnFRRVersion - make - make check - sudo make install + # Uncomment the next line to enable packet forwarding for IPv4 + net.ipv4.ip_forward=1 -Create empty FRR configuration files -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + # Uncomment the next line to enable packet forwarding for IPv6 + # Enabling this option disables Stateless Address Autoconfiguration + # based on Router Advertisements for this host + net.ipv6.conf.all.forwarding=1 -:: - - sudo install -m 755 -o frr -g frr -d /var/log/frr - sudo install -m 775 -o frr -g frrvty -d /etc/frr - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf - sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf - -Enable IPv4 & IPv6 forwarding -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the -other settings) - -:: - - # Uncomment the next line to enable packet forwarding for IPv4 - net.ipv4.ip_forward=1 - - # Uncomment the next line to enable packet forwarding for IPv6 - # Enabling this option disables Stateless Address Autoconfiguration - # based on Router Advertisements for this host - net.ipv6.conf.all.forwarding=1 - -Enable MPLS Forwarding (with Linux Kernel >= 4.5) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Edit ``/etc/sysctl.conf`` and the following lines. Make sure to add a -line equal to ``net.mpls.conf.eth0.input`` or each interface used with -MPLS - -:: - - # Enable MPLS Label processing on all interfaces - net.mpls.conf.eth0.input=1 - net.mpls.conf.eth1.input=1 - net.mpls.conf.eth2.input=1 - net.mpls.platform_labels=100000 +Reboot or use ``sysctl -p`` to apply the same config to the running system. Add MPLS kernel modules -^^^^^^^^^^^^^^^^^^^^^^^ +""""""""""""""""""""""" -Add the following lines to ``/etc/modules-load.d/modules.conf``: +.. warning:: + + MPLS is not supported on Ubuntu 16.04 with the default kernel. MPLS requires + kernel 4.5 or higher. LDPD can be built, but may have limited use without + MPLS. For an updated Ubuntu Kernel, see + http://kernel.ubuntu.com/~kernel-ppa/mainline/ + +Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To +enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`: :: - # Load MPLS Kernel Modules - mpls-router - mpls-iptunnel + # 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) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +And load the kernel modules on the running system: + +.. code-block:: console + + sudo modprobe mpls-router mpls-iptunnel + +Enable MPLS Forwarding +"""""""""""""""""""""" + +Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line +equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS. :: - sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service - sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons - sudo install -m 644 tools/etc/frr/frr.conf /etc/frr/frr.conf - sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf + # Enable MPLS Label processing on all interfaces + net.mpls.conf.eth0.input=1 + net.mpls.conf.eth1.input=1 + net.mpls.conf.eth2.input=1 + net.mpls.platform_labels=100000 + +Install service files +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: console + + sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service + sudo systemctl enable frr Enable daemons ^^^^^^^^^^^^^^ -| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for - those daemons you want to start by systemd. -| For example. +Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the +section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons +as required by changing the value to ``yes``. -:: +Start FRR +^^^^^^^^^ - zebra=yes - bgpd=yes - ospfd=yes - ospf6d=yes - ripd=yes - ripngd=yes - isisd=yes +.. code-block:: console -Enable the systemd service -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- systemctl enable frr - -Start the systemd service -^^^^^^^^^^^^^^^^^^^^^^^^^ - -- systemctl start frr -- use ``systemctl status frr`` to check its status. + systemctl start frr From 0844023418119f774ad9981333d4bf1a5bc58593 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Tue, 26 Mar 2019 22:04:49 +0000 Subject: [PATCH 122/142] doc: update build docs for Ubuntu 14.04 Same as priors Tested on Ubuntu 14.04 Signed-off-by: Quentin Young --- doc/developer/building-frr-for-ubuntu1404.rst | 183 +++++++++--------- 1 file changed, 90 insertions(+), 93 deletions(-) diff --git a/doc/developer/building-frr-for-ubuntu1404.rst b/doc/developer/building-frr-for-ubuntu1404.rst index b1eaf57e8d..0942f19737 100644 --- a/doc/developer/building-frr-for-ubuntu1404.rst +++ b/doc/developer/building-frr-for-ubuntu1404.rst @@ -1,35 +1,30 @@ -Ubuntu 14.04LTS -=============================================== +Ubuntu 14.04 LTS +================ -- MPLS is not supported on ``Ubuntu 14.04`` with default kernel. MPLS - requires Linux Kernel 4.5 or higher (LDP can be built, but may have - limited use without MPLS) For an updated Ubuntu Kernel, see - http://kernel.ubuntu.com/~kernel-ppa/mainline/ +This document describes installation from source. If you want to build a +``deb``, see :ref:`packaging-debian`. -Install required packages -------------------------- +Installing Dependencies +----------------------- -Add packages: - -:: +.. code-block:: console + apt-get update apt-get install \ git autoconf automake libtool make gawk libreadline-dev texinfo \ - dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ - libc-ares-dev python3-dev python3-sphinx install-info build-essential + pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ + libc-ares-dev python3-dev python3-sphinx install-info build-essential \ + libsnmp-dev perl .. include:: building-libyang.rst -Get FRR, compile it and install it (from Git) ---------------------------------------------- +Building & Installing FRR +------------------------- -**This assumes you want to build and install FRR from source and not -using any packages** - -Add frr groups and user +Add FRR user and groups ^^^^^^^^^^^^^^^^^^^^^^^ -:: +.. code-block:: console sudo groupadd -r -g 92 frr sudo groupadd -r -g 85 frrvty @@ -37,102 +32,104 @@ Add frr groups and user --gecos "FRR suite" --shell /sbin/nologin frr sudo usermod -a -G frrvty frr -Download Source, configure and compile it -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Compile +^^^^^^^ -(You may prefer different options on configure statement. These are just -an example.) +.. include:: include-compile.rst + +Install FRR configuration files +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: console + + sudo install -m 775 -o frr -g frr -d /var/log/frr + sudo install -m 775 -o frr -g frrvty -d /etc/frr + sudo install -m 640 -o frr -g frrvty tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/frr.conf /etc/frr/frr.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/daemons.conf /etc/frr/daemons.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons + +Tweak sysctls +^^^^^^^^^^^^^ + +Some sysctls need to be changed in order to enable IPv4/IPv6 forwarding and +MPLS (if supported by your platform). If your platform does not support MPLS, +skip the MPLS related configuration in this section. + +Edit :file:`/etc/sysctl.conf` and uncomment the following values (ignore the +other settings): :: - git clone https://github.com/frrouting/frr.git frr - cd frr - ./bootstrap.sh - ./configure \ - --prefix=/usr \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ - --localstatedir=/var/run/frr \ - --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ - --enable-multipath=64 \ - --enable-user=frr \ - --enable-group=frr \ - --enable-vty-group=frrvty \ - --enable-configfile-mask=0640 \ - --enable-logfile-mask=0640 \ - --enable-fpm \ - --with-pkg-git-version \ - --with-pkg-extra-version=-MyOwnFRRVersion - make - make check - sudo make install + # Uncomment the next line to enable packet forwarding for IPv4 + net.ipv4.ip_forward=1 -Create empty FRR configuration files -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + # Uncomment the next line to enable packet forwarding for IPv6 + # Enabling this option disables Stateless Address Autoconfiguration + # based on Router Advertisements for this host + net.ipv6.conf.all.forwarding=1 + +Reboot or use ``sysctl -p`` to apply the same config to the running system. + +Add MPLS kernel modules +""""""""""""""""""""""" + +.. warning:: + + MPLS is not supported on Ubuntu 14.04 with the default kernel. MPLS requires + kernel 4.5 or higher. LDPD can be built, but may have limited use without + MPLS. For an updated Ubuntu Kernel, see + http://kernel.ubuntu.com/~kernel-ppa/mainline/ + +Ubuntu 18.04 ships with kernel 4.15. MPLS modules are present by default. To +enable, add the following lines to :file:`/etc/modules-load.d/modules.conf`: :: - sudo install -m 755 -o frr -g frr -d /var/log/frr - sudo install -m 775 -o frr -g frrvty -d /etc/frr - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospfd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ospf6d.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/isisd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ripngd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/pimd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/ldpd.conf - sudo install -m 640 -o frr -g frr /dev/null /etc/frr/nhrpd.conf - sudo install -m 640 -o frr -g frrvty /dev/null /etc/frr/vtysh.conf + # Load MPLS Kernel Modules + mpls_router + mpls_iptunnel -Enable IP & IPv6 forwarding -^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the -other settings) +And load the kernel modules on the running system: + +.. code-block:: console + + sudo modprobe mpls-router mpls-iptunnel + +Enable MPLS Forwarding +"""""""""""""""""""""" + +Edit :file:`/etc/sysctl.conf` and the following lines. Make sure to add a line +equal to :file:`net.mpls.conf.eth0.input` for each interface used with MPLS. :: - # Uncomment the next line to enable packet forwarding for IPv4 - net.ipv4.ip_forward=1 - - # Uncomment the next line to enable packet forwarding for IPv6 - # Enabling this option disables Stateless Address Autoconfiguration - # based on Router Advertisements for this host - net.ipv6.conf.all.forwarding=1 - -**Reboot** or use ``sysctl -p`` to apply the same config to the running -system + # Enable MPLS Label processing on all interfaces + net.mpls.conf.eth0.input=1 + net.mpls.conf.eth1.input=1 + net.mpls.conf.eth2.input=1 + net.mpls.platform_labels=100000 Install the init.d service ^^^^^^^^^^^^^^^^^^^^^^^^^^ -:: +.. code-block:: console - sudo install -m 755 tools/frr /etc/init.d/frr - sudo install -m 644 tools/etc/frr/daemons /etc/frr/daemons - sudo install -m 644 -o frr -g frr tools/etc/frr/vtysh.conf /etc/frr/vtysh.conf + sudo install -m 755 tools/frr /etc/init.d/frr Enable daemons ^^^^^^^^^^^^^^ -| Edit ``/etc/frr/daemons`` and change the value from "no" to "yes" for - those daemons you want to start by systemd. -| For example. - -:: - - zebra=yes - bgpd=yes - ospfd=yes - ospf6d=yes - ripd=yes - ripngd=yes - isisd=yes +Open :file:`/etc/frr/daemons` with your text editor of choice. Look for the +section with ``watchfrr_enable=...`` and ``zebra=...`` etc. Enable the daemons +as required by changing the value to ``yes``. Start the init.d service ^^^^^^^^^^^^^^^^^^^^^^^^ -- /etc/init.d/frr start -- use ``/etc/init.d/frr status`` to check its status. +.. code-block:: console + + /etc/init.d/frr start + +Use ``/etc/init.d/frr status`` to check its status. From eab6daa2a0462a5286a2a5fd6e17d17e3c49fa70 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 27 Mar 2019 13:29:04 +0100 Subject: [PATCH 123/142] docker/alpine: Update buildscript to keep the docker image around Don't delete the Alpine docker image after the build. Also, extract the packages from the build stage, so that we can remove them from the final image. --- .dockerignore | 1 + docker/alpine/Dockerfile | 7 ++++--- docker/alpine/build.sh | 33 +++++++++++++++++++++++---------- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/.dockerignore b/.dockerignore index f2fc34583d..d613e18dfc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,3 +5,4 @@ **/*.lo **/*.so **/.libs +docker/alpine/pkgs diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 80ddb30d5b..815983a394 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,6 +1,5 @@ # This stage builds a dist tarball from the source FROM alpine:edge as source-builder -ARG commit RUN mkdir -p /src/alpine COPY alpine/APKBUILD.in /src/alpine @@ -13,11 +12,12 @@ RUN source /src/alpine/APKBUILD.in \ gzip COPY . /src +ARG PKGVER RUN cd /src \ && ./bootstrap.sh \ && ./configure \ --enable-numeric-version \ - --with-pkg-extra-version=_git$commit \ + --with-pkg-extra-version="_git$PKGVER" \ && make dist # This stage builds an apk from the dist tarball @@ -52,6 +52,7 @@ RUN echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/reposit tini \ && apk add \ --no-cache \ - --allow-untrusted /pkgs/apk/*/*.apk + --allow-untrusted /pkgs/apk/*/*.apk \ + && rm -rf /pkgs COPY docker/alpine/docker-start /usr/lib/frr/docker-start ENTRYPOINT [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ] diff --git a/docker/alpine/build.sh b/docker/alpine/build.sh index 5a79ebcdcb..22a36877c0 100755 --- a/docker/alpine/build.sh +++ b/docker/alpine/build.sh @@ -1,17 +1,30 @@ #!/bin/sh set -e -set -v set -x ## -# commit must be converted to decimal +# Package version needs to be decimal ## -c=`git rev-parse --short=10 HEAD` -commit=`printf '%u\n' 0x$c` -docker build -f docker/alpine/Dockerfile \ - --build-arg commit=$commit -t frr:alpine-$c . -id=`docker create frr:alpine-$c` -docker cp ${id}:/pkgs/ docker/alpine -docker rm $id -docker rmi frr:alpine-$c +GITREV="$(git rev-parse --short=10 HEAD)" +PKGVER="$(printf '%u\n' 0x$GITREV)" + +docker build \ + --pull \ + --file=docker/alpine/Dockerfile \ + --build-arg="PKGVER=$PKGVER" \ + --tag="frr:alpine-builder-$GITREV" \ + --target=alpine-builder \ + . + +CONTAINER_ID="$(docker create "frr:alpine-builder-$GITREV")" +docker cp "${CONTAINER_ID}:/pkgs/" docker/alpine +docker rm "${CONTAINER_ID}" + +docker build \ + --file=docker/alpine/Dockerfile \ + --build-arg="PKGVER=$PKGVER" \ + --tag="frr:alpine-$GITREV" \ + . + +docker rmi "frr:alpine-builder-$GITREV" From 9c463972e712d129b8ea801bfede871181e6f455 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 9 Feb 2019 11:09:32 -0500 Subject: [PATCH 124/142] topotests: Add a bit more useful debugging to ldp-vpls-topo1 When something goes wrong with this test, having these turned on will help us debug zebra processing a bit better in the future without having to modify anything else. Signed-off-by: Donald Sharp --- tests/topotests/ldp-vpls-topo1/r1/zebra.conf | 6 ++++-- tests/topotests/ldp-vpls-topo1/r2/zebra.conf | 5 +++-- tests/topotests/ldp-vpls-topo1/r3/zebra.conf | 5 +++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/topotests/ldp-vpls-topo1/r1/zebra.conf b/tests/topotests/ldp-vpls-topo1/r1/zebra.conf index d0ec9f5d75..edfa1780a9 100644 --- a/tests/topotests/ldp-vpls-topo1/r1/zebra.conf +++ b/tests/topotests/ldp-vpls-topo1/r1/zebra.conf @@ -2,10 +2,12 @@ log file zebra.log ! hostname r1 ! -debug zebra rib +debug zebra kernel +debug zebra rib detailed +debug zebra dplane detailed debug zebra nht debug zebra pseudowires -debug zebra packet +debug zebra mpls ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/ldp-vpls-topo1/r2/zebra.conf b/tests/topotests/ldp-vpls-topo1/r2/zebra.conf index 8bd800714c..6b95efdce8 100644 --- a/tests/topotests/ldp-vpls-topo1/r2/zebra.conf +++ b/tests/topotests/ldp-vpls-topo1/r2/zebra.conf @@ -2,10 +2,11 @@ log file zebra.log ! hostname r2 ! -debug zebra rib +debug zebra rib detailed +debug zebra dplane detailed +debug zebra kernel debug zebra nht debug zebra pseudowires -debug zebra packet ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/ldp-vpls-topo1/r3/zebra.conf b/tests/topotests/ldp-vpls-topo1/r3/zebra.conf index 2ff61365b5..85ec68ff32 100644 --- a/tests/topotests/ldp-vpls-topo1/r3/zebra.conf +++ b/tests/topotests/ldp-vpls-topo1/r3/zebra.conf @@ -2,10 +2,11 @@ log file zebra.log ! hostname r3 ! -debug zebra rib +debug zebra rib detailed +debug zebra dplane detailed +debug zebra kernel debug zebra nht debug zebra pseudowires -debug zebra packet ! interface lo ip address 3.3.3.3/32 From 416745628e73d8889e43bb153e365aa5225f22a5 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 9 Feb 2019 16:38:34 -0500 Subject: [PATCH 125/142] zebra: When shutting down actually close the socket When shutting down and we have a very large table to shutdown and after we've intentionally closed all the client connections close the zebra zserv client socket. Signed-off-by: Donald Sharp --- zebra/main.c | 2 ++ zebra/zserv.c | 12 ++++++++++++ zebra/zserv.h | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/zebra/main.c b/zebra/main.c index c605050c57..184e798bd0 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -153,7 +153,9 @@ static void sigint(void) for (ALL_LIST_ELEMENTS(zrouter.client_list, ln, nn, client)) zserv_close_client(client); + zserv_close(); list_delete_all_node(zrouter.client_list); + zebra_ptm_finish(); if (retain_mode) diff --git a/zebra/zserv.c b/zebra/zserv.c index 6532491cef..f5bb3aabb7 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -773,6 +773,18 @@ static int zserv_accept(struct thread *thread) return 0; } +void zserv_close(void) +{ + /* + * On shutdown, let's close the socket down + * so that long running processes of killing the + * routing table doesn't leave us in a bad + * state where a client tries to reconnect + */ + close(zsock); + zsock = -1; +} + void zserv_start(char *path) { int ret; diff --git a/zebra/zserv.h b/zebra/zserv.h index c4c3e1328b..86863d961c 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -183,6 +183,13 @@ extern unsigned int multipath_num; */ extern void zserv_init(void); +/* + * Stop the Zebra API server. + * + * closes the socket + */ +extern void zserv_close(void); + /* * Start Zebra API server. * From 3f2b1b56ccb14f4250e3d6d31daf9d4e69cf6153 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sun, 10 Feb 2019 10:14:26 -0500 Subject: [PATCH 126/142] zebra: zebra_router.c does not own the data plane shutdown of tables When shutting down, the individual vrf's own the shutdown of the table and subsuquent removal from the routes from the kernel. Signed-off-by: Donald Sharp --- zebra/zebra_router.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index cabc8be8dd..9e09cbca3f 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -164,8 +164,6 @@ static void zebra_router_free_table(struct zebra_router_table *zrt) { void *table_info; - rib_close_table(zrt->table); - table_info = route_table_get_info(zrt->table); route_table_finish(zrt->table); RB_REMOVE(zebra_router_table_head, &zrouter.tables, zrt); From 9ef0c6ba876de49751fdd0ef8069adb3e8ef03ec Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 9 Feb 2019 10:45:42 -0500 Subject: [PATCH 127/142] zebra: Unset old_re as queued. When switching routes from one route type to another actually unset the old route as enqueued. Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5fa51ada45..77cb38855d 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1932,7 +1932,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) dplane_ctx_get_vrf(ctx), dest_str, old_re); } else - UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); + UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED); } switch (op) { From 7a230a9d0cd2ecf2183f0e679deb52c00e80a172 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 9 Feb 2019 10:51:33 -0500 Subject: [PATCH 128/142] zebra: On route install/update failure correctly indicate in rib When we get a route install failure from the kernel, actually indicate in the rib the status of the routes. Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 77cb38855d..aaf9c40271 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2010,9 +2010,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED); } else { - if (re) + if (re) { SET_FLAG(re->status, ROUTE_ENTRY_FAILED); - if (old_re) + UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + } if (old_re) SET_FLAG(old_re->status, ROUTE_ENTRY_FAILED); if (re) zsend_route_notify_owner(re, dest_pfx, From 3cdba47a82b21daf90816bcd31fe4ab005367079 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 8 Feb 2019 15:01:41 -0500 Subject: [PATCH 129/142] zebra: Modify code so that dplane is responsible for indicating success/fail of install We have several route types KERNEL and CONNECT that are handled via special case in the code. This was causing a lot of work keeping the two different classes of route types as special(SYSTEM OR NOT). Put the dplane in charge of the code that sets the bits for signalling route install/failure. This greatly simplifies the code calling path and makes all route types be handled exactly the same. Additionaly code that we want to run post data plane install can just work as per normal then, instead of having to know we need to run it when we have a special type of route. Signed-off-by: Donald Sharp flags, NEXTHOP_FLAG_RECURSIVE)) + continue; + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + } + } + } + return res; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index aaf9c40271..ad07331152 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1175,10 +1175,7 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re) if (zebra_rib_labeled_unicast(re)) zebra_mpls_lsp_uninstall(info->zvrf, rn, re); - if (!RIB_SYSTEM_ROUTE(re)) - rib_uninstall_kernel(rn, re); - else - UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + rib_uninstall_kernel(rn, re); dest->selected_fib = NULL; @@ -1258,8 +1255,6 @@ int rib_gc_dest(struct route_node *rn) static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, struct route_entry *new) { - rib_dest_t *dest = rib_dest_from_rnode(rn); - hook_call(rib_update, rn, "new route selected"); /* Update real nexthop. This may actually determine if nexthop is active @@ -1281,10 +1276,7 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (zebra_rib_labeled_unicast(new)) zebra_mpls_lsp_install(zvrf, rn, new); - if (!RIB_SYSTEM_ROUTE(new)) - rib_install_kernel(rn, new, NULL); - else - dest->selected_fib = new; + rib_install_kernel(rn, new, NULL); UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); } @@ -1292,7 +1284,6 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, struct route_entry *old) { - rib_dest_t *dest = rib_dest_from_rnode(rn); hook_call(rib_update, rn, "removing existing route"); /* Uninstall from kernel. */ @@ -1308,20 +1299,7 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (zebra_rib_labeled_unicast(old)) zebra_mpls_lsp_uninstall(zvrf, rn, old); - if (!RIB_SYSTEM_ROUTE(old)) - rib_uninstall_kernel(rn, old); - else { - UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED); - /* - * We are setting this to NULL here - * because that is what we traditionally - * have been doing. I am not positive - * that this is the right thing to do - * but let's leave the code alone - * for the RIB_SYSTEM_ROUTE case - */ - dest->selected_fib = NULL; - } + rib_uninstall_kernel(rn, old); /* Update nexthop for route, reset changed flag. */ /* Note: this code also handles the Linux case when an interface goes @@ -1340,9 +1318,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, struct route_entry *old, struct route_entry *new) { - struct nexthop *nexthop = NULL; int nh_active = 0; - rib_dest_t *dest = rib_dest_from_rnode(rn); /* * We have to install or update if a new route has been selected or @@ -1384,48 +1360,15 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (zebra_rib_labeled_unicast(old)) zebra_mpls_lsp_uninstall(zvrf, rn, old); - /* Non-system route should be installed. */ - if (!RIB_SYSTEM_ROUTE(new)) { - /* If labeled-unicast route, install transit - * LSP. */ - if (zebra_rib_labeled_unicast(new)) - zebra_mpls_lsp_install(zvrf, rn, new); + /* + * Non-system route should be installed. + * If labeled-unicast route, install transit + * LSP. + */ + if (zebra_rib_labeled_unicast(new)) + zebra_mpls_lsp_install(zvrf, rn, new); - rib_install_kernel(rn, new, old); - } else { - UNSET_FLAG(new->status, ROUTE_ENTRY_INSTALLED); - /* - * We do not need to install the - * selected route because it - * is already isntalled by - * the system( ie not us ) - * so just mark it as winning - * we do need to ensure that - * if we uninstall a route - * from ourselves we don't - * over write this pointer - */ - dest->selected_fib = new; - } - /* If install succeeded or system route, cleanup flags - * for prior route. */ - if (new != old) { - if (RIB_SYSTEM_ROUTE(new)) { - if (!RIB_SYSTEM_ROUTE(old)) - rib_uninstall_kernel(rn, old); - else - UNSET_FLAG( - old->status, - ROUTE_ENTRY_INSTALLED); - } else { - UNSET_FLAG(old->status, - ROUTE_ENTRY_INSTALLED); - for (nexthop = old->ng.nexthop; nexthop; - nexthop = nexthop->next) - UNSET_FLAG(nexthop->flags, - NEXTHOP_FLAG_FIB); - } - } + rib_install_kernel(rn, new, old); } /* @@ -1455,25 +1398,18 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (zebra_rib_labeled_unicast(old)) zebra_mpls_lsp_uninstall(zvrf, rn, old); - if (!RIB_SYSTEM_ROUTE(old)) - rib_uninstall_kernel(rn, old); - else { - UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED); - dest->selected_fib = NULL; - } + rib_uninstall_kernel(rn, old); } } else { /* * Same route selected; check if in the FIB and if not, - * re-install. This - * is housekeeping code to deal with race conditions in kernel - * with linux - * netlink reporting interface up before IPv4 or IPv6 protocol - * is ready + * re-install. This is housekeeping code to deal with + * race conditions in kernel with linux netlink reporting + * interface up before IPv4 or IPv6 protocol is ready * to add routes. */ - if (!RIB_SYSTEM_ROUTE(new) - && !CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED)) + if (!CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED) || + RIB_SYSTEM_ROUTE(new)) rib_install_kernel(rn, new, NULL); } @@ -1725,18 +1661,9 @@ static void rib_process(struct route_node *rn) UNSET_FLAG(new_selected->status, ROUTE_ENTRY_CHANGED); } - if (new_selected) { + if (new_selected) SET_FLAG(new_selected->flags, ZEBRA_FLAG_SELECTED); - /* Special case: new route is system route, so - * dataplane update will not be done - ensure we - * redistribute the route. - */ - if (RIB_SYSTEM_ROUTE(new_selected)) - redistribute_update(p, src_p, new_selected, - old_selected); - } - if (old_selected) { if (!new_selected) redistribute_delete(p, src_p, old_selected); @@ -1821,6 +1748,30 @@ done: return (result); } +static void zebra_rib_fixup_system(struct route_node *rn) +{ + struct route_entry *re; + + RNODE_FOREACH_RE(rn, re) { + struct nexthop *nhop; + + if (!RIB_SYSTEM_ROUTE(re)) + continue; + + if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) + continue; + + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + + for (ALL_NEXTHOPS(re->ng, nhop)) { + if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) + continue; + + SET_FLAG(nhop->flags, NEXTHOP_FLAG_FIB); + } + } +} + /* * Route-update results processing after async dataplane update. */ @@ -1987,6 +1938,17 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) NEXTHOP_FLAG_FIB); } + /* + * System routes are weird in that they + * allow multiple to be installed that match + * to the same prefix, so after we get the + * result we need to clean them up so that + * we can actually use them. + */ + if ((re && RIB_SYSTEM_ROUTE(re)) || + (old_re && RIB_SYSTEM_ROUTE(old_re))) + zebra_rib_fixup_system(rn); + if (zvrf) { zvrf->installs++; /* Set flag for nexthop tracking processing */ @@ -2053,6 +2015,17 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) prefix2str(dest_pfx, dest_str, sizeof(dest_str))); } + + /* + * System routes are weird in that they + * allow multiple to be installed that match + * to the same prefix, so after we get the + * result we need to clean them up so that + * we can actually use them. + */ + if ((re && RIB_SYSTEM_ROUTE(re)) || + (old_re && RIB_SYSTEM_ROUTE(old_re))) + zebra_rib_fixup_system(rn); break; default: break; @@ -2655,7 +2628,7 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id) * revalidation * of the rest of the RE. */ - if (dest->selected_fib && !RIB_SYSTEM_ROUTE(dest->selected_fib)) { + if (dest->selected_fib) { changed = 1; if (IS_ZEBRA_DEBUG_RIB) { char buf[PREFIX_STRLEN]; @@ -2677,7 +2650,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, struct route_table *table; struct route_node *rn; struct route_entry *same = NULL; - struct nexthop *nexthop; int ret = 0; if (!re) @@ -2741,13 +2713,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, break; } - /* If this route is kernel route, set FIB flag to the route. */ - if (RIB_SYSTEM_ROUTE(re)) { - SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - } - /* Link new re to node.*/ if (IS_ZEBRA_DEBUG_RIB) { rnode_debug(rn, re->vrf_id, @@ -3223,10 +3188,8 @@ void rib_close_table(struct route_table *table) if (info->safi == SAFI_UNICAST) hook_call(rib_update, rn, NULL); - if (!RIB_SYSTEM_ROUTE(dest->selected_fib)) { - rib_uninstall_kernel(rn, dest->selected_fib); - dest->selected_fib = NULL; - } + rib_uninstall_kernel(rn, dest->selected_fib); + dest->selected_fib = NULL; } } } From 735219e91d3ce30dfb090b7dc955a51754c6cb31 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 5 Feb 2019 21:27:02 -0500 Subject: [PATCH 130/142] zebra: Make the import_check look like nexthop_check Make the functions take the same parameters. Future commits will use this. Signed-off-by: Donald Sharp --- zebra/zebra_rnh.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index f601ab7e7b..8c866646bf 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -361,9 +361,10 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi, * See if a tracked route entry for import (by BGP) has undergone any * change, and if so, notify the client. */ -static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, afi_t afi, +static void zebra_rnh_eval_import_check_entry(struct zebra_vrf *zvrf, afi_t afi, int force, struct route_node *nrn, struct rnh *rnh, + struct route_node *prn, struct route_entry *re) { int state_changed = 0; @@ -383,13 +384,15 @@ static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, afi_t afi, if (state_changed || force) { if (IS_ZEBRA_DEBUG_NHT) { prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); - zlog_debug("%u:%s: Route import check %s %s", vrfid, + zlog_debug("%u:%s: Route import check %s %s", + zvrf->vrf->vrf_id, bufn, rnh->state ? "passed" : "failed", state_changed ? "(state changed)" : ""); } /* state changed, notify clients */ for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) { - send_client(rnh, client, RNH_IMPORT_CHECK_TYPE, vrfid); + send_client(rnh, client, + RNH_IMPORT_CHECK_TYPE, zvrf->vrf->vrf_id); } } } @@ -689,8 +692,8 @@ static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, afi_t afi, /* Process based on type of entry. */ if (type == RNH_IMPORT_CHECK_TYPE) - zebra_rnh_eval_import_check_entry(zvrf->vrf->vrf_id, afi, force, - nrn, rnh, re); + zebra_rnh_eval_import_check_entry(zvrf, afi, force, nrn, rnh, + prn, re); else zebra_rnh_eval_nexthop_entry(zvrf, afi, force, nrn, rnh, prn, re); From 27d0665c0aa47082d065303974dd698c222e7fdb Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Feb 2019 09:46:15 -0500 Subject: [PATCH 131/142] zebra: The prn value may be NULL do not allow deref The prn value as passed in may be NULL as such do not allow it to be derefed (even though it works now). Signed-off-by: Donald Sharp --- zebra/zebra_rnh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 8c866646bf..ad8ffda291 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -632,7 +632,7 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, * the resolving route has some change (e.g., metric), there is a state * change. */ - if (!prefix_same(&rnh->resolved_route, &prn->p)) { + if (!prefix_same(&rnh->resolved_route, prn ? NULL : &prn->p)) { if (prn) prefix_copy(&rnh->resolved_route, &prn->p); else From cead8cef16741d206354f2f3d6270568f735a616 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Feb 2019 10:23:07 -0500 Subject: [PATCH 132/142] zebra: Add the type we are working on to the rnh data structure Store the type we are working on w/ the rnh data structure. Signed-off-by: Donald Sharp --- zebra/zebra_rnh.c | 1 + zebra/zebra_rnh.h | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index ad8ffda291..fcb6585b35 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -126,6 +126,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type, rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh)); rnh->client_list = list_new(); rnh->vrf_id = vrfid; + rnh->type = type; rnh->zebra_pseudowire_list = list_new(); route_lock_node(rn); rn->info = rnh; diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 0e71e8a68d..574dcb27be 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -29,6 +29,8 @@ extern "C" { #endif +typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t; + /* Nexthop structure. */ struct rnh { uint8_t flags; @@ -40,6 +42,8 @@ struct rnh { /* VRF identifier. */ vrf_id_t vrf_id; + rnh_type_t type; + struct route_entry *state; struct prefix resolved_route; struct list *client_list; @@ -55,8 +59,6 @@ struct rnh { int filtered[ZEBRA_ROUTE_MAX]; }; -typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t; - extern int zebra_rnh_ip_default_route; extern int zebra_rnh_ipv6_default_route; From 87554d831f82d2baa73c2d7146ef79f691135645 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Feb 2019 10:53:48 -0500 Subject: [PATCH 133/142] zebra: Add the afi_t to the rnh Store the associated afi with the rnh, it will be useful in the future. Signed-off-by: Donald Sharp --- zebra/zebra_rnh.c | 4 +++- zebra/zebra_rnh.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index fcb6585b35..e64e64c974 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -101,12 +101,13 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type, struct route_node *rn; struct rnh *rnh = NULL; char buf[PREFIX2STR_BUFFER]; + afi_t afi = family2afi(p->family); if (IS_ZEBRA_DEBUG_NHT) { prefix2str(p, buf, sizeof(buf)); zlog_debug("%u: Add RNH %s type %d", vrfid, buf, type); } - table = get_rnh_table(vrfid, family2afi(PREFIX_FAMILY(p)), type); + table = get_rnh_table(vrfid, afi, type); if (!table) { prefix2str(p, buf, sizeof(buf)); flog_warn(EC_ZEBRA_RNH_NO_TABLE, @@ -127,6 +128,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type, rnh->client_list = list_new(); rnh->vrf_id = vrfid; rnh->type = type; + rnh->afi = afi; rnh->zebra_pseudowire_list = list_new(); route_lock_node(rn); rn->info = rnh; diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 574dcb27be..38c95877ed 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -42,6 +42,8 @@ struct rnh { /* VRF identifier. */ vrf_id_t vrf_id; + afi_t afi; + rnh_type_t type; struct route_entry *state; From a304e258be3cc6ea85ccac121025f881637f969f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Feb 2019 11:16:07 -0500 Subject: [PATCH 134/142] zebra: Set and track the resolved_route for the rnh as it changes. The resolved_route is the prefix we are using in the routing table to resolve this particular nexthop we are tracking. Add code to better track it's change. Signed-off-by: Donald Sharp --- zebra/zebra_rnh.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index e64e64c974..afc63efdba 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -125,6 +125,14 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type, if (!rn->info) { rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh)); + + /* + * The resolved route is already 0.0.0.0/0 or + * 0::0/0 due to the calloc right above, but + * we should set the family so that future + * comparisons can just be done + */ + rnh->resolved_route.family = p->family; rnh->client_list = list_new(); rnh->vrf_id = vrfid; rnh->type = type; @@ -375,14 +383,24 @@ static void zebra_rnh_eval_import_check_entry(struct zebra_vrf *zvrf, afi_t afi, char bufn[INET6_ADDRSTRLEN]; struct listnode *node; + if (prn) + prefix_copy(&rnh->resolved_route, &prn->p); + else { + int family = rnh->resolved_route.family; + + memset(&rnh->resolved_route.family, 0, sizeof(struct prefix)); + rnh->resolved_route.family = family; + } + if (re && (rnh->state == NULL)) { if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) state_changed = 1; } else if (!re && (rnh->state != NULL)) state_changed = 1; - if (compare_state(re, rnh->state)) + if (compare_state(re, rnh->state)) { copy_state(rnh, re, nrn); + } if (state_changed || force) { if (IS_ZEBRA_DEBUG_NHT) { @@ -638,8 +656,16 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, if (!prefix_same(&rnh->resolved_route, prn ? NULL : &prn->p)) { if (prn) prefix_copy(&rnh->resolved_route, &prn->p); - else + else { + /* + * Just quickly store the family of the resolved + * route so that we can reset it in a second here + */ + int family = rnh->resolved_route.family; + memset(&rnh->resolved_route, 0, sizeof(struct prefix)); + rnh->resolved_route.family = family; + } copy_state(rnh, re, nrn); state_changed = 1; From 434434f70404a3b491117442462b554e83764339 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Feb 2019 14:21:36 -0500 Subject: [PATCH 135/142] zebra: Abstract the rib_dest_t creation Abstract the creation of the rib_dest_t so that we can call it from multiple places. Signed-off-by: Donald Sharp --- zebra/rib.h | 5 +++++ zebra/zebra_rib.c | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index ced6692b9b..2e0a73aa8b 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -430,6 +430,11 @@ static inline struct zebra_vrf *rib_dest_vrf(rib_dest_t *dest) return rib_table_info(rib_dest_table(dest))->zvrf; } +/* + * Create the rib_dest_t and attach it to the specified node + */ +extern rib_dest_t *zebra_rib_create_dest(struct route_node *rn); + /* * rib_tables_iter_init */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index ad07331152..5d98d61645 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2314,6 +2314,18 @@ static void rib_queue_init(void) return; } +rib_dest_t *zebra_rib_create_dest(struct route_node *rn) +{ + rib_dest_t *dest; + + dest = XCALLOC(MTYPE_RIB_DEST, sizeof(rib_dest_t)); + route_lock_node(rn); /* rn route table reference */ + rn->info = dest; + dest->rnode = rn; + + return dest; +} + /* RIB updates are processed via a queue of pointers to route_nodes. * * The queue length is bounded by the maximal size of the routing table, @@ -2366,10 +2378,7 @@ static void rib_link(struct route_node *rn, struct route_entry *re, int process) if (IS_ZEBRA_DEBUG_RIB_DETAILED) rnode_debug(rn, re->vrf_id, "rn %p adding dest", rn); - dest = XCALLOC(MTYPE_RIB_DEST, sizeof(rib_dest_t)); - route_lock_node(rn); /* rn route table reference */ - rn->info = dest; - dest->rnode = rn; + dest = zebra_rib_create_dest(rn); } head = dest->routes; From c86ba6c283689d0fd9f7dce9c29fdbbea7d0a0b2 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Feb 2019 14:44:44 -0500 Subject: [PATCH 136/142] zebra: Add a base node for the zebra vrf tables Add a default route_node for our routing tables. This will allow us to know that we can hang data off the default route for processing. We will be hanging the nexthop tracking data structures off the rib_dest_t so that we can know which nexthops we need to handle. Effectively nexthops that we are tracking that are unresolved will be stored on the default route. When something changes in the rib tree we can work up the rn->parent pointer checking for nexthops we need to re-evaluate. Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 10 ++++++++++ zebra/zebra_vrf.c | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5d98d61645..6b837e4e36 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1204,6 +1204,16 @@ static int rib_can_delete_dest(rib_dest_t *dest) return 0; } + /* + * Unresolved rnh's are stored on the default route's list + * + * dest->rnode can also be the source prefix node in an + * ipv6 sourcedest table. Fortunately the prefix of a + * source prefix node can never be the default prefix. + */ + if (is_default_prefix(&dest->rnode->p)) + return 0; + /* * Don't delete the dest if we have to update the FPM about this * prefix. diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 90f94902f3..89bda4276e 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -370,10 +370,19 @@ static void zebra_rnhtable_node_cleanup(struct route_table *table, static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, safi_t safi) { + struct route_node *rn; + struct prefix p; + assert(!zvrf->table[afi][safi]); zvrf->table[afi][safi] = zebra_router_get_table(zvrf, zvrf->table_id, afi, safi); + + memset(&p, 0, sizeof(p)); + p.family = afi2family(afi); + + rn = srcdest_rnode_get(zvrf->table[afi][safi], &p, NULL); + zebra_rib_create_dest(rn); } /* Allocate new zebra VRF. */ From 699dae230db72cdb75c9e2c0237d602a48dbf61f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 6 Feb 2019 10:23:58 -0500 Subject: [PATCH 137/142] zebra: Modify NHT to occur when needed. Currently nexthop tracking is performed for all nexthops that are being tracked after a group of contexts are passed back from the data plane for post install processing. This is inefficient and leaves us sending nexthop tracking changes at an accelerated pace, when we think we've changed a route. Additionally every route change will cause us to relook at all nexthops we are tracking irrelevant if they are possibly related to the route change or not. Let's modify the code base to track the rnh's off of the rib table's rn, `rib_dest_t`. So after we process a node, install it into the data plane, in rib_process_result we can look at the `rib_dest_t` associated with the rn and see that a nexthop depended on this route node. If so, refigure it. Additionally we will store rnh's that are not resolved on the 0.0.0.0/0 nexthop tracking list. As such when a route node changes we can quickly walk up the rib tree and notice that it needs to be reprocessed as well. Signed-off-by: Donald Sharp --- zebra/rib.h | 11 +++++ zebra/zebra_rib.c | 106 +++++++++++++++++++++++++++++++++++----------- zebra/zebra_rnh.c | 70 ++++++++++++++++++++++++++++-- zebra/zebra_rnh.h | 2 + zebra/zebra_vrf.c | 7 ++- 5 files changed, 166 insertions(+), 30 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 2e0a73aa8b..3c68daf76c 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -144,6 +144,15 @@ typedef struct rib_dest_t_ { */ uint32_t flags; + /* + * The list of nht prefixes that have ended up + * depending on this route node. + * After route processing is returned from + * the data plane we will run evaluate_rnh + * on these prefixes. + */ + struct list *nht; + /* * Linkage to put dest on the FPM processing queue. */ @@ -359,6 +368,8 @@ extern struct route_table *rib_tables_iter_next(rib_tables_iter_t *iter); extern uint8_t route_distance(int type); +extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq); + /* * Inline functions. */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 6b837e4e36..be9a6af1fa 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1225,6 +1225,77 @@ static int rib_can_delete_dest(rib_dest_t *dest) return 1; } +void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) +{ + rib_dest_t *dest = rib_dest_from_rnode(rn); + struct listnode *node, *nnode; + struct rnh *rnh; + + /* + * We are storing the rnh's associated with + * the tracked nexthop as a list of the rn's. + * Unresolved rnh's are placed at the top + * of the tree list.( 0.0.0.0/0 for v4 and 0::0/0 for v6 ) + * As such for each rn we need to walk up the tree + * and see if any rnh's need to see if they + * would match a more specific route + */ + while (rn) { + if (!dest) { + rn = rn->parent; + if (rn) + dest = rib_dest_from_rnode(rn); + continue; + } + /* + * If we have any rnh's stored in the nht list + * then we know that this route node was used for + * nht resolution and as such we need to call the + * nexthop tracking evaluation code + */ + for (ALL_LIST_ELEMENTS(dest->nht, node, nnode, rnh)) { + struct zebra_vrf *zvrf = + zebra_vrf_lookup_by_id(rnh->vrf_id); + struct prefix *p = &rnh->node->p; + + if (IS_ZEBRA_DEBUG_NHT) { + char buf1[PREFIX_STRLEN]; + char buf2[PREFIX_STRLEN]; + + zlog_debug("%u:%s has Nexthop(%s) depending on it, evaluating %u:%u", + zvrf->vrf->vrf_id, + prefix2str(&rn->p, buf1, + sizeof(buf1)), + prefix2str(p, buf2, sizeof(buf2)), + seq, rnh->seqno); + } + + /* + * If we have evaluated this node on this pass + * already, due to following the tree up + * then we know that we can move onto the next + * rnh to process. + * + * Additionally we call zebra_evaluate_rnh + * when we gc the dest. In this case we know + * that there must be no other re's where + * we were originally as such we know that + * that sequence number is ok to respect. + */ + if (rnh->seqno == seq) + continue; + + rnh->seqno = seq; + zebra_evaluate_rnh(zvrf, family2afi(p->family), 0, + rnh->type, p); + } + + rn = rn->parent; + if (rn) + dest = rib_dest_from_rnode(rn); + } +} + /* * rib_gc_dest * @@ -1251,7 +1322,10 @@ int rib_gc_dest(struct route_node *rn) rnode_debug(rn, zvrf_id(zvrf), "removing dest from table"); } + zebra_rib_evaluate_rn_nexthops(rn, zebra_router_get_next_sequence()); + dest->rnode = NULL; + list_delete(&dest->nht); XFREE(MTYPE_RIB_DEST, dest); rn->info = NULL; @@ -1797,6 +1871,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) enum dplane_op_e op; enum zebra_dplane_result status; const struct prefix *dest_pfx, *src_pfx; + uint32_t seq; /* Locate rn and re(s) from ctx */ @@ -1873,11 +1948,13 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) break; } + seq = dplane_ctx_get_seq(ctx); + /* * Check sequence number(s) to detect stale results before continuing */ if (re) { - if (re->dplane_sequence != dplane_ctx_get_seq(ctx)) { + if (re->dplane_sequence != seq) { if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug("%u:%s Stale dplane result for re %p", dplane_ctx_get_vrf(ctx), @@ -2040,6 +2117,8 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) default: break; } + + zebra_rib_evaluate_rn_nexthops(rn, seq); done: if (rn) @@ -2099,32 +2178,8 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex) */ static void do_nht_processing(void) { - struct vrf *vrf; struct zebra_vrf *zvrf; - /* Evaluate nexthops for those VRFs which underwent route processing. - * This - * should limit the evaluation to the necessary VRFs in most common - * situations. - */ - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { - zvrf = vrf->info; - if (zvrf == NULL || !(zvrf->flags & ZEBRA_VRF_RIB_SCHEDULED)) - continue; - - if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHT) - zlog_debug("NHT processing check for zvrf %s", - zvrf_name(zvrf)); - - zvrf->flags &= ~ZEBRA_VRF_RIB_SCHEDULED; - zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL); - zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_IMPORT_CHECK_TYPE, - NULL); - zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL); - zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_IMPORT_CHECK_TYPE, - NULL); - } - /* Schedule LSPs for processing, if needed. */ zvrf = vrf_info_lookup(VRF_DEFAULT); if (mpls_should_lsps_be_processed(zvrf)) { @@ -2329,6 +2384,7 @@ rib_dest_t *zebra_rib_create_dest(struct route_node *rn) rib_dest_t *dest; dest = XCALLOC(MTYPE_RIB_DEST, sizeof(rib_dest_t)); + dest->nht = list_new(); route_lock_node(rn); /* rn route table reference */ rn->info = dest; dest->rnode = rn; diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index afc63efdba..32da05afb6 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -94,6 +94,41 @@ char *rnh_str(struct rnh *rnh, char *buf, int size) return buf; } +static void zebra_rnh_remove_from_routing_table(struct rnh *rnh) +{ + struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id); + struct route_table *table = zvrf->table[rnh->afi][SAFI_UNICAST]; + struct route_node *rn; + rib_dest_t *dest; + + if (!table) + return; + + rn = route_node_match(table, &rnh->resolved_route); + if (!rn) + return; + + dest = rib_dest_from_rnode(rn); + listnode_delete(dest->nht, rnh); + route_unlock_node(rn); +} + +static void zebra_rnh_store_in_routing_table(struct rnh *rnh) +{ + struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id); + struct route_table *table = zvrf->table[rnh->afi][SAFI_UNICAST]; + struct route_node *rn; + rib_dest_t *dest; + + rn = route_node_match(table, &rnh->resolved_route); + if (!rn) + return; + + dest = rib_dest_from_rnode(rn); + listnode_add(dest->nht, rnh); + route_unlock_node(rn); +} + struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type, bool *exists) { @@ -136,12 +171,15 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type, rnh->client_list = list_new(); rnh->vrf_id = vrfid; rnh->type = type; + rnh->seqno = 0; rnh->afi = afi; rnh->zebra_pseudowire_list = list_new(); route_lock_node(rn); rn->info = rnh; rnh->node = rn; *exists = false; + + zebra_rnh_store_in_routing_table(rnh); } else *exists = true; @@ -172,9 +210,30 @@ struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type) void zebra_free_rnh(struct rnh *rnh) { + struct zebra_vrf *zvrf; + struct route_table *table; + + zebra_rnh_remove_from_routing_table(rnh); rnh->flags |= ZEBRA_NHT_DELETED; list_delete(&rnh->client_list); list_delete(&rnh->zebra_pseudowire_list); + + zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id); + table = zvrf->table[family2afi(rnh->resolved_route.family)][SAFI_UNICAST]; + + if (table) { + struct route_node *rern; + + rern = route_node_match(table, &rnh->resolved_route); + if (rern) { + rib_dest_t *dest; + + route_unlock_node(rern); + + dest = rib_dest_from_rnode(rern); + listnode_delete(dest->nht, rnh); + } + } free_state(rnh->vrf_id, rnh->state, rnh->node); XFREE(MTYPE_RNH, rnh); } @@ -383,14 +442,16 @@ static void zebra_rnh_eval_import_check_entry(struct zebra_vrf *zvrf, afi_t afi, char bufn[INET6_ADDRSTRLEN]; struct listnode *node; - if (prn) + zebra_rnh_remove_from_routing_table(rnh); + if (prn) { prefix_copy(&rnh->resolved_route, &prn->p); - else { + } else { int family = rnh->resolved_route.family; memset(&rnh->resolved_route.family, 0, sizeof(struct prefix)); rnh->resolved_route.family = family; } + zebra_rnh_store_in_routing_table(rnh); if (re && (rnh->state == NULL)) { if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) @@ -618,7 +679,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, return re; } - if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + if (!CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) rn = rn->parent; else return NULL; @@ -653,6 +714,7 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, * the resolving route has some change (e.g., metric), there is a state * change. */ + zebra_rnh_remove_from_routing_table(rnh); if (!prefix_same(&rnh->resolved_route, prn ? NULL : &prn->p)) { if (prn) prefix_copy(&rnh->resolved_route, &prn->p); @@ -673,6 +735,7 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, copy_state(rnh, re, nrn); state_changed = 1; } + zebra_rnh_store_in_routing_table(rnh); if (state_changed || force) { /* NOTE: Use the "copy" of resolving route stored in 'rnh' i.e., @@ -822,7 +885,6 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, static void free_state(vrf_id_t vrf_id, struct route_entry *re, struct route_node *rn) { - if (!re) return; diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 38c95877ed..7d823c7acc 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -46,6 +46,8 @@ struct rnh { rnh_type_t type; + uint32_t seqno; + struct route_entry *state; struct prefix resolved_route; struct list *client_list; diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 89bda4276e..2d721ec8a1 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -354,7 +354,12 @@ void zebra_rtable_node_cleanup(struct route_table *table, rib_unlink(node, re); } - XFREE(MTYPE_RIB_DEST, node->info); + if (node->info) { + rib_dest_t *dest = node->info; + + list_delete(&dest->nht); + XFREE(MTYPE_RIB_DEST, node->info); + } } static void zebra_rnhtable_node_cleanup(struct route_table *table, From 50872b0804870e2f2ffaf5db8d3052af4003dc89 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 8 Feb 2019 09:11:47 -0500 Subject: [PATCH 138/142] zebra: Add detailed debugging command for NHT tracking Add a detailed debugging command for NHT tracking and add the detailed output to the log about why we make some decisions that we are. I tried to model this like the rib processing detailed debugs that we added a few months back. Signed-off-by: Donald Sharp --- zebra/debug.c | 28 +++++++++++++---- zebra/debug.h | 7 ++++- zebra/zebra_rib.c | 19 +++++++++--- zebra/zebra_rnh.c | 79 +++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 116 insertions(+), 17 deletions(-) diff --git a/zebra/debug.c b/zebra/debug.c index 87999a1bbc..8e5fb0ea10 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -87,7 +87,9 @@ DEFUN_NOSH (show_debugging_zebra, if (IS_ZEBRA_DEBUG_FPM) vty_out(vty, " Zebra FPM debugging is on\n"); - if (IS_ZEBRA_DEBUG_NHT) + if (IS_ZEBRA_DEBUG_NHT_DETAILED) + vty_out(vty, " Zebra detailed next-hop tracking debugging is on\n"); + else if (IS_ZEBRA_DEBUG_NHT) vty_out(vty, " Zebra next-hop tracking debugging is on\n"); if (IS_ZEBRA_DEBUG_MPLS) vty_out(vty, " Zebra MPLS debugging is on\n"); @@ -119,12 +121,19 @@ DEFUN (debug_zebra_events, DEFUN (debug_zebra_nht, debug_zebra_nht_cmd, - "debug zebra nht", + "debug zebra nht [detailed]", DEBUG_STR "Zebra configuration\n" - "Debug option set for zebra next hop tracking\n") + "Debug option set for zebra next hop tracking\n" + "Debug option set for detailed info\n") { + int idx = 0; + zebra_debug_nht = ZEBRA_DEBUG_NHT; + + if (argv_find(argv, argc, "detailed", &idx)) + zebra_debug_nht |= ZEBRA_DEBUG_NHT_DETAILED; + return CMD_SUCCESS; } @@ -320,11 +329,12 @@ DEFUN (no_debug_zebra_events, DEFUN (no_debug_zebra_nht, no_debug_zebra_nht_cmd, - "no debug zebra nht", + "no debug zebra nht [detailed]", NO_STR DEBUG_STR "Zebra configuration\n" - "Debug option set for zebra next hop tracking\n") + "Debug option set for zebra next hop tracking\n" + "Debug option set for detailed info\n") { zebra_debug_nht = 0; return CMD_SUCCESS; @@ -490,10 +500,15 @@ static int config_write_debug(struct vty *vty) vty_out(vty, "debug zebra fpm\n"); write++; } - if (IS_ZEBRA_DEBUG_NHT) { + + if (IS_ZEBRA_DEBUG_NHT_DETAILED) { + vty_out(vty, "debug zebra nht detailed\n"); + write++; + } else if (IS_ZEBRA_DEBUG_NHT) { vty_out(vty, "debug zebra nht\n"); write++; } + if (IS_ZEBRA_DEBUG_MPLS) { vty_out(vty, "debug zebra mpls\n"); write++; @@ -530,6 +545,7 @@ void zebra_debug_init(void) zebra_debug_pw = 0; zebra_debug_dplane = 0; zebra_debug_mlag = 0; + zebra_debug_nht = 0; install_node(&debug_node, config_write_debug); diff --git a/zebra/debug.h b/zebra/debug.h index 944ad6d68b..176226f7ae 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -44,7 +44,9 @@ extern "C" { #define ZEBRA_DEBUG_RIB_DETAILED 0x02 #define ZEBRA_DEBUG_FPM 0x01 -#define ZEBRA_DEBUG_NHT 0x01 + +#define ZEBRA_DEBUG_NHT 0x01 +#define ZEBRA_DEBUG_NHT_DETAILED 0x02 #define ZEBRA_DEBUG_MPLS 0x01 @@ -76,7 +78,10 @@ extern "C" { #define IS_ZEBRA_DEBUG_RIB_DETAILED (zebra_debug_rib & ZEBRA_DEBUG_RIB_DETAILED) #define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM) + #define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT) +#define IS_ZEBRA_DEBUG_NHT_DETAILED (zebra_debug_nht & ZEBRA_DEBUG_NHT_DETAILED) + #define IS_ZEBRA_DEBUG_MPLS (zebra_debug_mpls & ZEBRA_DEBUG_MPLS) #define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN) #define IS_ZEBRA_DEBUG_PW (zebra_debug_pw & ZEBRA_DEBUG_PW) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index be9a6af1fa..adf2f3928e 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1232,7 +1232,7 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) struct rnh *rnh; /* - * We are storing the rnh's associated with + * We are storing the rnh's associated withb * the tracked nexthop as a list of the rn's. * Unresolved rnh's are placed at the top * of the tree list.( 0.0.0.0/0 for v4 and 0::0/0 for v6 ) @@ -1241,6 +1241,13 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) * would match a more specific route */ while (rn) { + if (IS_ZEBRA_DEBUG_NHT_DETAILED) { + char buf[PREFIX_STRLEN]; + + zlog_debug("%s: %s Being examined for Nexthop Tracking", + __PRETTY_FUNCTION__, + srcdest_rnode2str(rn, buf, sizeof(buf))); + } if (!dest) { rn = rn->parent; if (rn) @@ -1258,13 +1265,13 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) zebra_vrf_lookup_by_id(rnh->vrf_id); struct prefix *p = &rnh->node->p; - if (IS_ZEBRA_DEBUG_NHT) { + if (IS_ZEBRA_DEBUG_NHT_DETAILED) { char buf1[PREFIX_STRLEN]; char buf2[PREFIX_STRLEN]; zlog_debug("%u:%s has Nexthop(%s) depending on it, evaluating %u:%u", zvrf->vrf->vrf_id, - prefix2str(&rn->p, buf1, + srcdest_rnode2str(rn, buf1, sizeof(buf1)), prefix2str(p, buf2, sizeof(buf2)), seq, rnh->seqno); @@ -1282,8 +1289,12 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) * we were originally as such we know that * that sequence number is ok to respect. */ - if (rnh->seqno == seq) + if (rnh->seqno == seq) { + if (IS_ZEBRA_DEBUG_NHT_DETAILED) + zlog_debug( + "\tNode processed and moved already"); continue; + } rnh->seqno = seq; zebra_evaluate_rnh(zvrf, family2afi(p->family), 0, diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 32da05afb6..d57087d462 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -108,6 +108,16 @@ static void zebra_rnh_remove_from_routing_table(struct rnh *rnh) if (!rn) return; + if (IS_ZEBRA_DEBUG_NHT_DETAILED) { + char buf[PREFIX_STRLEN]; + char buf1[PREFIX_STRLEN]; + + zlog_debug("%s: %u:%s removed from tracking on %s", + __PRETTY_FUNCTION__, rnh->vrf_id, + prefix2str(&rnh->node->p, buf, sizeof(buf)), + srcdest_rnode2str(rn, buf1, sizeof(buf))); + } + dest = rib_dest_from_rnode(rn); listnode_delete(dest->nht, rnh); route_unlock_node(rn); @@ -124,6 +134,16 @@ static void zebra_rnh_store_in_routing_table(struct rnh *rnh) if (!rn) return; + if (IS_ZEBRA_DEBUG_NHT_DETAILED) { + char buf[PREFIX_STRLEN]; + char buf1[PREFIX_STRLEN]; + + zlog_debug("%s: %u:%s added for tracking on %s", + __PRETTY_FUNCTION__, rnh->vrf_id, + prefix2str(&rnh->node->p, buf, sizeof(buf)), + srcdest_rnode2str(rn, buf1, sizeof(buf))); + } + dest = rib_dest_from_rnode(rn); listnode_add(dest->nht, rnh); route_unlock_node(rn); @@ -414,6 +434,16 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi, && !prefix_same(&nrn->p, &rn->p)) return NULL; + if (IS_ZEBRA_DEBUG_NHT_DETAILED) { + char buf[PREFIX_STRLEN]; + char buf1[PREFIX_STRLEN]; + + zlog_debug("%s: %u:%s Resolved Import Entry to %s", + __PRETTY_FUNCTION__, rnh->vrf_id, + prefix2str(&rnh->node->p, buf, sizeof(buf)), + srcdest_rnode2str(rn, buf1, sizeof(buf))); + } + /* Identify appropriate route entry. */ RNODE_FOREACH_RE (rn, re) { if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) @@ -424,6 +454,10 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi, if (re) *prn = rn; + + if (!re && IS_ZEBRA_DEBUG_NHT_DETAILED) + zlog_debug("\tRejected due to removed or is a bgp route"); + return re; } @@ -497,7 +531,7 @@ static void zebra_rnh_notify_protocol_clients(struct zebra_vrf *zvrf, afi_t afi, if (IS_ZEBRA_DEBUG_NHT) { prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); if (prn && re) { - prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN); + srcdest_rnode2str(prn, bufp, INET6_ADDRSTRLEN); zlog_debug("%u:%s: NH resolved over route %s", zvrf->vrf->vrf_id, bufn, bufp); } else @@ -630,19 +664,43 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, * most-specific match. Do similar logic as in zebra_rib.c */ while (rn) { + if (IS_ZEBRA_DEBUG_NHT_DETAILED) { + char buf[PREFIX_STRLEN]; + char buf1[PREFIX_STRLEN]; + + zlog_debug("%s: %u:%s Possible Match to %s", + __PRETTY_FUNCTION__, rnh->vrf_id, + prefix2str(&rnh->node->p, buf, sizeof(buf)), + srcdest_rnode2str(rn, buf1, sizeof(buf))); + } + /* Do not resolve over default route unless allowed && * match route to be exact if so specified */ if (is_default_prefix(&rn->p) - && !rnh_resolve_via_default(rn->p.family)) + && !rnh_resolve_via_default(rn->p.family)) { + if (IS_ZEBRA_DEBUG_NHT_DETAILED) + zlog_debug( + "\tNot allowed to resolve through default prefix"); return NULL; + } /* Identify appropriate route entry. */ RNODE_FOREACH_RE (rn, re) { - if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) + if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) { + if (IS_ZEBRA_DEBUG_NHT_DETAILED) + zlog_debug( + "\tRoute Entry %s removed", + zebra_route_string(re->type)); continue; - if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) + } + if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) { + if (IS_ZEBRA_DEBUG_NHT_DETAILED) + zlog_debug( + "\tRoute Entry %s !selected", + zebra_route_string(re->type)); continue; + } /* Just being SELECTED isn't quite enough - must * have an installed nexthop to be useful. @@ -652,8 +710,13 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, break; } - if (nexthop == NULL) + if (nexthop == NULL) { + if (IS_ZEBRA_DEBUG_NHT_DETAILED) + zlog_debug( + "\tRoute Entry %s no nexthops", + zebra_route_string(re->type)); continue; + } if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) { if ((re->type == ZEBRA_ROUTE_CONNECT) @@ -681,8 +744,12 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, if (!CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) rn = rn->parent; - else + else { + if (IS_ZEBRA_DEBUG_NHT_DETAILED) + zlog_debug( + "\tNexthop must be connected, cannot recurse up"); return NULL; + } } return NULL; From a1494c250ccf6737135f52b5bf660ca071e1c43f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 8 Feb 2019 17:14:30 -0500 Subject: [PATCH 139/142] zebra: Modify lsp processing to be invoked as needed LSP processing was a zvrf flag based upon a connected route coming or going. But this did not allow us to know that we should do lsp processing other than after the meta-queue processing was finished. Eventually we moved meta-queue processing of do_nht_processing to after the dataplane sent the main pthread some results. This of course left us with a timing hole where if a connected route came in and we received a data plane response *before* the meta queue was processed we would not do the work as necessary. Move the lsp processing to a flag off of the rib_dest_t. If it is marked then we need to process lsps. Signed-off-by: Donald Sharp --- zebra/connected.c | 6 +++--- zebra/rib.h | 2 ++ zebra/zebra_mpls.h | 37 +++++++++++++++++++++++++------------ zebra/zebra_rib.c | 32 ++++++++++++++++++++------------ 4 files changed, 50 insertions(+), 27 deletions(-) diff --git a/zebra/connected.c b/zebra/connected.c index 128f397552..7114a3286b 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -272,7 +272,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) ifp->vrf_id, ifp->name, prefix2str(&p, buf, sizeof(buf))); } - mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id)); + mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), &p); } } @@ -437,7 +437,7 @@ void connected_down(struct interface *ifp, struct connected *ifc) ifp->vrf_id, ifp->name, prefix2str(&p, buf, sizeof(buf))); } - mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id)); + mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), &p); } } @@ -471,7 +471,7 @@ static void connected_delete_helper(struct connected *ifc, struct prefix *p) ifp->vrf_id, ifp->name, prefix2str(p, buf, sizeof(buf))); } - mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id)); + mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), p); } } diff --git a/zebra/rib.h b/zebra/rib.h index 3c68daf76c..e26831e1a6 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -181,6 +181,8 @@ typedef struct rib_dest_t_ { */ #define RIB_DEST_UPDATE_FPM (1 << (ZEBRA_MAX_QINDEX + 2)) +#define RIB_DEST_UPDATE_LSPS (1 << (ZEBRA_MAX_QINDEX + 3)) + /* * Macro to iterate over each route for a destination (prefix). */ diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index f8c6c794a4..3a131e1aaf 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -510,28 +510,41 @@ static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type) return "Unknown"; } -static inline void mpls_mark_lsps_for_processing(struct zebra_vrf *zvrf) +static inline void mpls_mark_lsps_for_processing(struct zebra_vrf *zvrf, + struct prefix *p) { + struct route_table *table; + struct route_node *rn; + rib_dest_t *dest; + if (!zvrf) return; - zvrf->mpls_flags |= MPLS_FLAG_SCHEDULE_LSPS; -} - -static inline void mpls_unmark_lsps_for_processing(struct zebra_vrf *zvrf) -{ - if (!zvrf) + table = zvrf->table[family2afi(p->family)][SAFI_UNICAST]; + if (!table) return; - zvrf->mpls_flags &= ~MPLS_FLAG_SCHEDULE_LSPS; + rn = route_node_match(table, p); + if (!rn) + return; + + + dest = rib_dest_from_rnode(rn); + SET_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS); } -static inline int mpls_should_lsps_be_processed(struct zebra_vrf *zvrf) +static inline void mpls_unmark_lsps_for_processing(struct route_node *rn) { - if (!zvrf) - return 0; + rib_dest_t *dest = rib_dest_from_rnode(rn); - return ((zvrf->mpls_flags & MPLS_FLAG_SCHEDULE_LSPS) ? 1 : 0); + UNSET_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS); +} + +static inline int mpls_should_lsps_be_processed(struct route_node *rn) +{ + rib_dest_t *dest = rib_dest_from_rnode(rn); + + return !!CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS); } /* Global variables. */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index adf2f3928e..557e6876e2 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1785,6 +1785,24 @@ static void rib_process(struct route_node *rn) rib_gc_dest(rn); } +static void zebra_rib_evaluate_mpls(struct route_node *rn) +{ + rib_dest_t *dest = rib_dest_from_rnode(rn); + struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT); + + if (!dest) + return; + + if (CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_LSPS)) { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug( + "%u: Scheduling all LSPs upon RIB completion", + zvrf_id(zvrf)); + zebra_mpls_lsp_schedule(zvrf); + mpls_unmark_lsps_for_processing(rn); + } +} + /* * Utility to match route with dplane context data */ @@ -2130,6 +2148,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) } zebra_rib_evaluate_rn_nexthops(rn, seq); + zebra_rib_evaluate_mpls(rn); done: if (rn) @@ -2184,23 +2203,12 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex) return 1; } + /* * Perform next-hop tracking processing after RIB updates. */ static void do_nht_processing(void) { - struct zebra_vrf *zvrf; - - /* Schedule LSPs for processing, if needed. */ - zvrf = vrf_info_lookup(VRF_DEFAULT); - if (mpls_should_lsps_be_processed(zvrf)) { - if (IS_ZEBRA_DEBUG_MPLS) - zlog_debug( - "%u: Scheduling all LSPs upon RIB completion", - zvrf_id(zvrf)); - zebra_mpls_lsp_schedule(zvrf); - mpls_unmark_lsps_for_processing(zvrf); - } } /* Dispatch the meta queue by picking, processing and unlocking the next RN from From 9cb8322ed99eabb94f76a7c2aeb1b60d105e7440 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 12 Feb 2019 09:51:08 -0500 Subject: [PATCH 140/142] zebra: If we copy re than the state has changed After we have evaluated the rnh for an import-check type and we copy the re then we know that the state has changed and we should be notifying the end user about it. Signed-off-by: Donald Sharp --- zebra/zebra_rnh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index d57087d462..a1519e45cd 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -495,6 +495,7 @@ static void zebra_rnh_eval_import_check_entry(struct zebra_vrf *zvrf, afi_t afi, if (compare_state(re, rnh->state)) { copy_state(rnh, re, nrn); + state_changed = 1; } if (state_changed || force) { From 906b54ddba69293eb38430c241548aad8c273eae Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 21 Feb 2019 16:10:56 -0500 Subject: [PATCH 141/142] zebra: Re-evaluate the nexthop tracking if flags changed Routing protocols are allowed ( and even encouraged ) to modify the flags that influence the nexthop tracking. As such when we modify the tracking of a nexthop to go from, say, connected force or not we must re-evaluate the nexthop and send the results up to the interested parties. Signed-off-by: Donald Sharp --- zebra/zapi_msg.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 4e97c272fb..2eeb1f2788 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1036,6 +1036,8 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) uint8_t flags = 0; uint16_t type = cmd2type[hdr->command]; bool exist; + bool flag_changed = false; + uint8_t orig_flags; if (IS_ZEBRA_DEBUG_NHT) zlog_debug( @@ -1084,6 +1086,7 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) if (!rnh) return; + orig_flags = rnh->flags; if (type == RNH_NEXTHOP_TYPE) { if (flags && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) @@ -1101,9 +1104,12 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) UNSET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH); } + if (orig_flags != rnh->flags) + flag_changed = true; + zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf)); /* Anything not AF_INET/INET6 has been filtered out above */ - if (!exist) + if (!exist || flag_changed) zebra_evaluate_rnh(zvrf, family2afi(p.family), 1, type, &p); } From 9fb2b87997ac8a69133e5c157374eb2944671a27 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 22 Feb 2019 10:20:51 -0500 Subject: [PATCH 142/142] isisd, ospf6d, ripngd: Do not allow v6 LL's to be `redist connected` in The rib process of handling routes has been unified a bit more and as a result v6 LL routes are now showing up as a result of a `redistribute connected`. Doing anything with these routes is a policy decision that should be enforced by the individual routing daemons not by zebra. As such add a bit of code to isisd, ripngd and opsf6d to handle them. The bgp daemon already handles this situation. Signed-off-by: Donald Sharp --- isisd/isis_zebra.c | 4 ++++ ospf6d/ospf6_zebra.c | 3 +++ ripngd/ripng_zebra.c | 3 +++ 3 files changed, 10 insertions(+) diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index dfe74e325e..79d79f8911 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -362,6 +362,10 @@ static int isis_zebra_read(int command, struct zclient *zclient, if (zapi_route_decode(zclient->ibuf, &api) < 0) return -1; + if (api.prefix.family == AF_INET6 + && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6)) + return 0; + /* * Avoid advertising a false default reachability. (A default * route installed by IS-IS gets redistributed from zebra back diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 54f1735e7a..abdc82a738 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -226,6 +226,9 @@ static int ospf6_zebra_read_route(int command, struct zclient *zclient, if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) return 0; + if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6)) + return 0; + ifindex = api.nexthops[0].ifindex; nexthop = &api.nexthops[0].gate.ipv6; diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 28a57f25d0..c68c066f0c 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -126,6 +126,9 @@ static int ripng_zebra_read_route(int command, struct zclient *zclient, if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) return 0; + if (IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6)) + return 0; + nexthop = api.nexthops[0].gate.ipv6; ifindex = api.nexthops[0].ifindex;