From 064d4355ca82c924ec928c67150f243f17f56139 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Wed, 6 Dec 2017 18:20:48 -0800 Subject: [PATCH 01/84] ospf6d: Fix External routes ECMP Handle RFC 2328 16.4 Calculating AS external routes with ECMP For ASBR route, if it is learnt via new LSA and contains different nexthop list. First lookup route in ospf6 route table if it exists, merge nexthop list to existing and call the callback to install into FIB (zebra). Delete created new route as it is identical to existing entry in route table. Ticket:CM-16139 Testing Done: Run two ASBR with 2 ECMP paths from each DUT neighbor receievs 4 ECMP path to a external route. ospf6 installs all 4 ECMP path to FIB/RIB Signed-off-by: Chirag Shah --- ospf6d/ospf6_abr.c | 10 +- ospf6d/ospf6_area.c | 4 +- ospf6d/ospf6_asbr.c | 275 ++++++++++++++++++++++++++++++++++++++++-- ospf6d/ospf6_asbr.h | 2 + ospf6d/ospf6_intra.c | 3 +- ospf6d/ospf6_memory.c | 1 + ospf6d/ospf6_memory.h | 1 + ospf6d/ospf6_route.c | 50 +++++++- ospf6d/ospf6_route.h | 9 ++ ospf6d/ospf6_spf.c | 1 + ospf6d/ospf6_top.c | 14 +++ 11 files changed, 354 insertions(+), 16 deletions(-) diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index d270b9547e..8847611492 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -901,6 +901,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) ospf6_route_copy_nexthops(route, abr_entry); + /* (7) If the routes are identical, copy the next hops over to existing route. ospf6's route table implementation will otherwise string both routes, but keep the older one as the best route since the routes @@ -910,6 +911,12 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) if (old && (ospf6_route_cmp(route, old) == 0)) { ospf6_route_merge_nexthops(old, route); + + if (is_debug) + zlog_debug("%s: Update route: %s nh count %u", + __PRETTY_FUNCTION__, + buf, listcount(route->nh_list)); + /* Update RIB/FIB */ if (table->hook_add) (*table->hook_add)(old); @@ -918,7 +925,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) ospf6_route_delete(route); } else { if (is_debug) - zlog_debug("Install route: %s", buf); + zlog_debug("Install route: %s nh count %u", + buf, listcount(route->nh_list)); /* ospf6_ia_add_nw_route (table, &prefix, route); */ ospf6_route_add(route, table); } diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index bd5e2bd1d3..252e4a4545 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -117,7 +117,9 @@ static void ospf6_area_lsdb_hook_remove(struct ospf6_lsa *lsa) static void ospf6_area_route_hook_add(struct ospf6_route *route) { - struct ospf6_route *copy = ospf6_route_copy(route); + struct ospf6_route *copy; + + copy = ospf6_route_copy(route); ospf6_route_add(copy, ospf6->route_table); } diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 5fbf2dafa5..745b87b890 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -173,11 +173,136 @@ static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa) return ntohl(network_order); } +void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, + struct ospf6_route *route) +{ + struct ospf6_route *old_route; + struct ospf6_path *ecmp_path, *o_path = NULL; + struct listnode *anode; + struct listnode *nnode, *rnode, *rnext; + struct ospf6_nexthop *nh, *rnh; + char buf[PREFIX2STR_BUFFER]; + bool route_found = false; + + for (old_route = old; old_route; old_route = old_route->next) { + if (ospf6_route_is_same(old_route, route) && + (old_route->path.type == route->path.type) && + (old_route->path.cost == route->path.cost) && + (old_route->path.u.cost_e2 == route->path.u.cost_e2)) { + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&old_route->prefix, buf, + sizeof(buf)); + zlog_debug("%s: old route %s path cost %u [%u]", + __PRETTY_FUNCTION__, buf, + old_route->path.cost, + ospf6_route_is_same(old_route, + route)); + } + route_found = true; + /* check if this path exists already in + * route->paths list, if so, replace nh_list + * from asbr_entry. + */ + for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode, + o_path)) { + if ((o_path->origin.id == route->path.origin.id) + && (o_path->origin.adv_router == + route->path.origin.adv_router)) + break; + } + /* If path is not found in old_route paths's list, + * add a new path to route paths list and merge + * nexthops in route->path->nh_list. + * Otherwise replace existing path's nh_list. + */ + if (o_path == NULL) { + ecmp_path = ospf6_path_dup(&route->path); + + /* Add a nh_list to new ecmp path */ + ospf6_copy_nexthops(ecmp_path->nh_list, + route->nh_list); + /* Merge nexthop to existing route's nh_list */ + ospf6_route_merge_nexthops(old_route, route); + + /* Update RIB/FIB */ + if (ospf6->route_table->hook_add) + (*ospf6->route_table->hook_add) + (old_route); + + /* Add the new path to route's path list */ + listnode_add_sort(old_route->paths, ecmp_path); + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&route->prefix, buf, + sizeof(buf)); + zlog_debug("%s: route %s another path added with nh %u, Paths %u", + __PRETTY_FUNCTION__, buf, + listcount(ecmp_path->nh_list), + old_route->paths ? + listcount(old_route->paths) + : 0); + } + } else { + for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, + nnode, nh)) { + for (ALL_LIST_ELEMENTS( + old_route->nh_list, + rnode, rnext, rnh)) { + if (!ospf6_nexthop_is_same(rnh, + nh)) + continue; + + listnode_delete( + old_route->nh_list, + rnh); + ospf6_nexthop_delete(rnh); + } + } + list_delete_all_node(o_path->nh_list); + ospf6_copy_nexthops(o_path->nh_list, + route->nh_list); + + /* Merge nexthop to existing route's nh_list */ + ospf6_route_merge_nexthops(old_route, + route); + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&route->prefix, + buf, sizeof(buf)); + zlog_debug("%s: existing route %s with effective nh count %u", + __PRETTY_FUNCTION__, buf, + old_route->nh_list ? + listcount(old_route->nh_list) + : 0); + } + + /* Update RIB/FIB */ + if (ospf6->route_table->hook_add) + (*ospf6->route_table->hook_add) + (old_route); + + } + /* Delete the new route its info added to existing + * route. + */ + ospf6_route_delete(route); + break; + } + } + + if (!route_found) { + /* Add new route to existing node in ospf6 route table. */ + ospf6_route_add(route, ospf6->route_table); + } +} + void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; struct prefix asbr_id; - struct ospf6_route *asbr_entry, *route; + struct ospf6_route *asbr_entry, *route, *old; + struct ospf6_path *path; char buf[PREFIX2STR_BUFFER]; external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( @@ -245,12 +370,34 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa) ospf6_route_copy_nexthops(route, asbr_entry); + path = ospf6_path_dup(&route->path); + ospf6_copy_nexthops(path->nh_list, asbr_entry->nh_list); + listnode_add_sort(route->paths, path); + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug("AS-External route add: %s", buf); + zlog_debug("%s: AS-External %u route add %s cost %u(%u) nh %u", + __PRETTY_FUNCTION__, + (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1) + ? 1 : 2, buf, route->path.cost, + route->path.u.cost_e2, + listcount(route->nh_list)); + } + + old = ospf6_route_lookup(&route->prefix, ospf6->route_table); + if (!old) { + /* Add the new route to ospf6 instance route table. */ + ospf6_route_add(route, ospf6->route_table); + } else { + /* RFC 2328 16.4 (6) + * ECMP: Keep new equal preference path in current + * route's path list, update zebra with new effective + * list along with addition of ECMP path. + */ + ospf6_asbr_update_route_ecmp_path(old, route); } - ospf6_route_add(route, ospf6->route_table); } void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) @@ -291,16 +438,126 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) nroute = ospf6_route_next(route); if (route->type != OSPF6_DEST_TYPE_NETWORK) continue; - if (route->path.origin.type != lsa->header->type) - continue; - if (route->path.origin.id != lsa->header->id) - continue; - if (route->path.origin.adv_router != lsa->header->adv_router) + + /* Route has multiple ECMP paths remove, + * matching path and update effective route's nh list. + */ + if (listcount(route->paths) > 1) { + struct listnode *anode, *anext; + struct listnode *nnode, *rnode, *rnext; + struct ospf6_nexthop *nh, *rnh; + struct ospf6_path *o_path; + bool nh_updated = false; + + /* Iterate all paths of route to find maching with LSA + * remove from route path list. If route->path is same, + * replace from paths list. + */ + for (ALL_LIST_ELEMENTS(route->paths, anode, anext, + o_path)) { + if (o_path->origin.type != lsa->header->type) + continue; + if (o_path->origin.id != lsa->header->id) + continue; + if (o_path->origin.adv_router != + lsa->header->adv_router) + continue; + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&prefix, buf, sizeof(buf)); + zlog_debug( + "%s: route %s path found with nh %u", + __PRETTY_FUNCTION__, buf, + listcount(o_path->nh_list)); + } + + /* Remove found path's nh_list from + * the route's nh_list. + */ + for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, + nnode, nh)) { + for (ALL_LIST_ELEMENTS(route->nh_list, + rnode, rnext, rnh)) { + if (!ospf6_nexthop_is_same(rnh, + nh)) + continue; + listnode_delete(route->nh_list, + rnh); + ospf6_nexthop_delete(rnh); + } + } + /* Delete the path from route's path list */ + listnode_delete(route->paths, o_path); + ospf6_path_free(o_path); + nh_updated = true; + } + + if (nh_updated) { + /* Iterate all paths and merge nexthop, + * unlesss any of the nexthop similar to + * ones deleted as part of path deletion. + */ + + for (ALL_LIST_ELEMENTS(route->paths, anode, + anext, o_path)) { + ospf6_merge_nexthops(route->nh_list, + o_path->nh_list); + } + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&route->prefix, buf, + sizeof(buf)); + zlog_debug("%s: AS-External %u route %s update paths %u nh %u" + , __PRETTY_FUNCTION__, + (route->path.type == + OSPF6_PATH_TYPE_EXTERNAL1) + ? 1 : 2, buf, + listcount(route->paths), + listcount(route->nh_list)); + } + + /* Update RIB/FIB w/ effective nh_list */ + if (ospf6->route_table->hook_add) + (*ospf6->route_table->hook_add)(route); + + /* route's path is similar to lsa header, + * replace route's path with route's + * paths list head. + */ + if (route->path.origin.id == lsa->header->id && + route->path.origin.adv_router == + lsa->header->adv_router) { + struct ospf6_path *h_path; + + h_path = (struct ospf6_path *) + listgetdata(listhead(route->paths)); + route->path.origin.type = + h_path->origin.type; + route->path.origin.id = + h_path->origin.id; + route->path.origin.adv_router = + h_path->origin.adv_router; + } + } continue; + } else { + if (route->path.origin.type != lsa->header->type) + continue; + if (route->path.origin.id != lsa->header->id) + continue; + if (route->path.origin.adv_router != + lsa->header->adv_router) + continue; + } if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug("AS-External route remove: %s", buf); + zlog_debug("%s: AS-External %u route remove %s cost %u(%u) nh %u", + __PRETTY_FUNCTION__, + route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 + ? 1 : 2, buf, route->path.cost, + route->path.u.cost_e2, + listcount(route->nh_list)); } ospf6_route_remove(route, ospf6->route_table); } diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index 73053452e6..7f4665ac2b 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -93,5 +93,7 @@ extern void ospf6_asbr_send_externals_to_area(struct ospf6_area *); extern int config_write_ospf6_debug_asbr(struct vty *vty); extern void install_element_ospf6_debug_asbr(void); +extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, + struct ospf6_route *route); #endif /* OSPF6_ASBR_H */ diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index b1d940952c..77653ea33f 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -1404,7 +1404,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa) if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) { prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug(" route %s add", buf); + zlog_debug(" route %s add with nh count %u", buf, + listcount(route->nh_list)); } ospf6_route_add(route, oa->route_table); diff --git a/ospf6d/ospf6_memory.c b/ospf6d/ospf6_memory.c index 56c232d6da..1c3523b43d 100644 --- a/ospf6d/ospf6_memory.c +++ b/ospf6d/ospf6_memory.c @@ -41,4 +41,5 @@ DEFINE_MTYPE(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex") DEFINE_MTYPE(OSPF6D, OSPF6_SPFTREE, "OSPF6 SPF tree") DEFINE_MTYPE(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop") DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info") +DEFINE_MTYPE(OSPF6D, OSPF6_PATH, "OSPF6 Path") DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other") diff --git a/ospf6d/ospf6_memory.h b/ospf6d/ospf6_memory.h index fe72ee3669..548af5e321 100644 --- a/ospf6d/ospf6_memory.h +++ b/ospf6d/ospf6_memory.h @@ -40,6 +40,7 @@ DECLARE_MTYPE(OSPF6_VERTEX) DECLARE_MTYPE(OSPF6_SPFTREE) DECLARE_MTYPE(OSPF6_NEXTHOP) DECLARE_MTYPE(OSPF6_EXTERNAL_INFO) +DECLARE_MTYPE(OSPF6_PATH) DECLARE_MTYPE(OSPF6_OTHER) #endif /* _QUAGGA_OSPF6_MEMORY_H */ diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 281757222d..735b28a693 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -215,7 +215,7 @@ void ospf6_copy_nexthops(struct list *dst, struct list *src) if (ospf6_nexthop_is_set(nh)) { nh_new = ospf6_nexthop_create(); ospf6_nexthop_copy(nh_new, nh); - listnode_add(dst, nh_new); + listnode_add_sort(dst, nh_new); } } } @@ -231,7 +231,7 @@ void ospf6_merge_nexthops(struct list *dst, struct list *src) if (!ospf6_route_find_nexthop(dst, nh)) { nh_new = ospf6_nexthop_create(); ospf6_nexthop_copy(nh_new, nh); - listnode_add(dst, nh_new); + listnode_add_sort(dst, nh_new); } } } @@ -338,7 +338,7 @@ int ospf6_route_get_first_nh_index(struct ospf6_route *route) return (-1); } -static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b) +int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b) { if (a->ifindex < b->ifindex) return -1; @@ -351,6 +351,36 @@ static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b) return 0; } +static int ospf6_path_cmp(struct ospf6_path *a, struct ospf6_path *b) +{ + if (a->origin.adv_router < b->origin.adv_router) + return -1; + else if (a->origin.adv_router > b->origin.adv_router) + return 1; + else + return 0; +} + +void ospf6_path_free(struct ospf6_path *op) +{ + if (op->nh_list) + list_delete_and_null(&op->nh_list); + XFREE(MTYPE_OSPF6_PATH, op); +} + +struct ospf6_path *ospf6_path_dup(struct ospf6_path *path) +{ + struct ospf6_path *new; + + new = XCALLOC(MTYPE_OSPF6_PATH, sizeof(struct ospf6_path)); + memcpy(new, path, sizeof(struct ospf6_path)); + new->nh_list = list_new(); + new->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp; + new->nh_list->del = (void (*) (void *))ospf6_nexthop_delete; + + return new; +} + struct ospf6_route *ospf6_route_create(void) { struct ospf6_route *route; @@ -358,6 +388,9 @@ struct ospf6_route *ospf6_route_create(void) route->nh_list = list_new(); route->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp; route->nh_list->del = (void (*) (void *))ospf6_nexthop_delete; + route->paths = list_new(); + route->paths->cmp = (int (*)(void *, void *))ospf6_path_cmp; + route->paths->del = (void (*)(void *))ospf6_path_free; return route; } @@ -366,6 +399,8 @@ void ospf6_route_delete(struct ospf6_route *route) if (route) { if (route->nh_list) list_delete_and_null(&route->nh_list); + if (route->paths) + list_delete_and_null(&route->paths); XFREE(MTYPE_OSPF6_ROUTE, route); } } @@ -464,7 +499,13 @@ ospf6_route_lookup_identical(struct ospf6_route *route, for (target = ospf6_route_lookup(&route->prefix, table); target; target = target->next) { - if (ospf6_route_is_identical(target, route)) + if (target->type == route->type && + (memcmp(&target->prefix, &route->prefix, + sizeof(struct prefix)) == 0) && + target->path.type == route->path.type && + target->path.cost == route->path.cost && + target->path.u.cost_e2 == route->path.u.cost_e2 && + ospf6_route_cmp_nexthops(target, route) == 0) return target; } return NULL; @@ -1083,6 +1124,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route) vty_out(vty, "Metric: %d (%d)\n", route->path.cost, route->path.u.cost_e2); + vty_out(vty, "Paths count: %u\n", route->paths->count); vty_out(vty, "Nexthop count: %u\n", route->nh_list->count); /* Nexthops */ vty_out(vty, "Nexthop:\n"); diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index 9eacadbdb7..b759828c39 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -96,6 +96,9 @@ struct ospf6_path { u_int32_t cost_config; } u; u_int32_t tag; + + /* nh list for this path */ + struct list *nh_list; }; #define OSPF6_PATH_TYPE_NONE 0 @@ -149,6 +152,9 @@ struct ospf6_route { /* path */ struct ospf6_path path; + /* List of Paths. */ + struct list *paths; + /* nexthop */ struct list *nh_list; }; @@ -256,6 +262,7 @@ extern void ospf6_linkstate_prefix2str(struct prefix *prefix, char *buf, int size); extern struct ospf6_nexthop *ospf6_nexthop_create(void); +extern int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b); extern void ospf6_nexthop_delete(struct ospf6_nexthop *nh); extern void ospf6_clear_nexthops(struct list *nh_list); extern int ospf6_num_nexthops(struct list *nh_list); @@ -331,5 +338,7 @@ extern int config_write_ospf6_debug_route(struct vty *vty); extern void install_element_ospf6_debug_route(void); extern void ospf6_route_init(void); extern void ospf6_clean(void); +extern void ospf6_path_free(struct ospf6_path *op); +extern struct ospf6_path *ospf6_path_dup(struct ospf6_path *path); #endif /* OSPF6_ROUTE_H */ diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 340d90159f..6e6d8a7f00 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -145,6 +145,7 @@ static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa) v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END(lsa->header) + 3); v->nh_list = list_new(); + v->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp; v->nh_list->del = (void (*) (void *))ospf6_nexthop_delete; v->parent = NULL; diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index e0844765d3..5d1144335b 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -95,6 +95,13 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route) static void ospf6_top_brouter_hook_add(struct ospf6_route *route) { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + char buf[PREFIX2STR_BUFFER]; + + prefix2str(&route->prefix, buf, sizeof(buf)); + zlog_debug("%s: brouter %s add with nh count %u", + __PRETTY_FUNCTION__, buf, listcount(route->nh_list)); + } ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix)); ospf6_asbr_lsentry_add(route); ospf6_abr_originate_summary(route); @@ -102,6 +109,13 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route) static void ospf6_top_brouter_hook_remove(struct ospf6_route *route) { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + char buf[PREFIX2STR_BUFFER]; + + prefix2str(&route->prefix, buf, sizeof(buf)); + zlog_debug("%s: brouter %s del with nh count %u", + __PRETTY_FUNCTION__, buf, listcount(route->nh_list)); + } route->flag |= OSPF6_ROUTE_REMOVE; ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix)); ospf6_asbr_lsentry_remove(route); From 08ee8e223170edc764118eb6c303ee70a702b6bd Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 8 Jan 2018 16:40:49 -0500 Subject: [PATCH 02/84] vtysh: optimize printout routine When printing responses from a client, vtysh searches through every response it receives twice. Once is to look for the terminating sequence and the other is to translate \n to \0, which is used with the line processing callback capability. However: * There's no need to search all of the output for the terminator, we can just check the last 4 bytes. * In most scenarios we won't have a callback. Therefore we don't need to process the output and can just dump it. Together these optimizations have a significant impact on the total runtime of talkative CLI commands, such as `sh ip bgp json` which runs roughly 1000% faster when dumping 1,000,000 routes. Signed-off-by: Quentin Young --- vtysh/vtysh.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 76343ded60..d113279a4d 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -138,16 +138,25 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line, bufvalid += nread; - end = memmem(buf, bufvalid - buf, terminator, - sizeof(terminator)); - if (end + sizeof(terminator) + 1 > bufvalid) + if (bufvalid - buf >= 4) + end = memmem(bufvalid - 4, 4, terminator, + sizeof(terminator)); + + if (end && end + sizeof(terminator) + 1 > bufvalid) /* found \0\0\0 but return code hasn't been read yet */ end = NULL; if (end) ret = end[sizeof(terminator)]; - while (bufvalid > buf && (end > buf || !end)) { - size_t textlen = (end ? end : bufvalid) - buf; + /* + * calculate # bytes we have, up to & not including the + * terminator if present + */ + size_t textlen = (end ? end : bufvalid) - buf; + + /* feed line processing callback if present */ + while (callback && bufvalid > buf && (end > buf || !end)) { + textlen = (end ? end : bufvalid) - buf; char *eol = memchr(buf, '\n', textlen); if (eol) /* line break */ @@ -165,8 +174,7 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line, /* continue reading */ break; - /* eol is at a line end now, either \n => \0 or \0\0\0 - */ + /* eol is at line end now, either \n => \0 or \0\0\0 */ assert(eol && eol <= bufvalid); if (fp) { @@ -186,6 +194,14 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line, end -= eol - buf; } + /* else if no callback, dump raw */ + if (!callback) { + if (fp) + fwrite(buf, 1, textlen, fp); + memmove(buf, buf + textlen, bufvalid - buf - textlen); + bufvalid -= textlen; + } + if (bufvalid == buf + bufsz) { char *new; bufsz *= 2; From 0bbb9e72f21ec65809b43c56652f6b1fc04a0542 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Tue, 9 Jan 2018 13:59:33 -0500 Subject: [PATCH 03/84] lib: add MTYPE for synchronization primitives Signed-off-by: Quentin Young --- lib/frr_pthread.c | 1 + lib/frr_pthread.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index 19dfbaf54b..de522e5ef9 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -26,6 +26,7 @@ #include "hash.h" DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread"); +DEFINE_MTYPE(LIB, PTHREAD_PRIM, "POSIX synchronization primitives"); static unsigned int next_id = 0; diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h index f6000340a7..7915b43a46 100644 --- a/lib/frr_pthread.h +++ b/lib/frr_pthread.h @@ -21,8 +21,11 @@ #define _FRR_PTHREAD_H #include +#include "memory.h" #include "thread.h" +DECLARE_MTYPE(PTHREAD_PRIM); + struct frr_pthread { /* pthread id */ From f09a656d24204cf607ec3a0842439cf922d21f15 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Tue, 9 Jan 2018 14:27:44 -0500 Subject: [PATCH 04/84] bgpd: improve bgp thread startup characteristics Replace atomic spinlock with condition variable. Signed-off-by: Quentin Young --- bgpd/bgp_io.c | 72 ++++++++++++++++++++++++++++++++++++--------------- bgpd/bgp_io.h | 21 +++++++-------- bgpd/bgpd.c | 8 +++--- 3 files changed, 64 insertions(+), 37 deletions(-) diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index cc9c1bda56..c9662e2121 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -50,20 +50,37 @@ static bool validate_header(struct peer *); #define BGP_IO_TRANS_ERR (1 << 0) // EAGAIN or similar occurred #define BGP_IO_FATAL_ERR (1 << 1) // some kind of fatal TCP error -/* Start and stop routines for I/O pthread + control variables +/* Plumbing & control variables for thread lifecycle * ------------------------------------------------------------------------ */ -_Atomic bool bgp_io_thread_run; -_Atomic bool bgp_io_thread_started; - -void bgp_io_init() -{ - bgp_io_thread_run = false; - bgp_io_thread_started = false; -} +bool bgp_io_thread_run; +pthread_mutex_t *running_cond_mtx; +pthread_cond_t *running_cond; /* Unused callback for thread_add_read() */ static int bgp_io_dummy(struct thread *thread) { return 0; } +/* Poison pill task */ +static int bgp_io_finish(struct thread *thread) +{ + bgp_io_thread_run = false; + return 0; +} + +/* Extern lifecycle control functions. init -> start -> stop + * ------------------------------------------------------------------------ */ +void bgp_io_init() +{ + bgp_io_thread_run = false; + + running_cond_mtx = XCALLOC(MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t)); + running_cond = XCALLOC(MTYPE_PTHREAD_PRIM, sizeof(pthread_cond_t)); + + pthread_mutex_init(running_cond_mtx, NULL); + pthread_cond_init(running_cond, NULL); + + pthread_mutex_lock(running_cond_mtx); +} + void *bgp_io_start(void *arg) { struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); @@ -79,9 +96,12 @@ void *bgp_io_start(void *arg) struct thread task; - atomic_store_explicit(&bgp_io_thread_run, true, memory_order_seq_cst); - atomic_store_explicit(&bgp_io_thread_started, true, - memory_order_seq_cst); + bgp_io_thread_run = true; + pthread_mutex_lock(running_cond_mtx); + { + pthread_cond_signal(running_cond); + } + pthread_mutex_unlock(running_cond_mtx); while (bgp_io_thread_run) { if (thread_fetch(fpt->master, &task)) { @@ -95,29 +115,33 @@ void *bgp_io_start(void *arg) return NULL; } -static int bgp_io_finish(struct thread *thread) +void bgp_io_wait_running() { - atomic_store_explicit(&bgp_io_thread_run, false, memory_order_seq_cst); - return 0; + while (!bgp_io_thread_run) + pthread_cond_wait(running_cond, running_cond_mtx); } int bgp_io_stop(void **result, struct frr_pthread *fpt) { thread_add_event(fpt->master, &bgp_io_finish, NULL, 0, NULL); pthread_join(fpt->thread, result); + + pthread_mutex_unlock(running_cond_mtx); + pthread_mutex_destroy(running_cond_mtx); + pthread_cond_destroy(running_cond); + + XFREE(MTYPE_PTHREAD_PRIM, running_cond_mtx); + XFREE(MTYPE_PTHREAD_PRIM, running_cond); + return 0; } /* Extern API -------------------------------------------------------------- */ -void bgp_io_running(void) -{ - while (!atomic_load_explicit(&bgp_io_thread_started, - memory_order_seq_cst)) - frr_pthread_yield(); -} void bgp_writes_on(struct peer *peer) { + assert(bgp_io_thread_run); + assert(peer->status != Deleted); assert(peer->obuf); assert(peer->ibuf); @@ -135,6 +159,8 @@ void bgp_writes_on(struct peer *peer) void bgp_writes_off(struct peer *peer) { + assert(bgp_io_thread_run); + struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); thread_cancel_async(fpt->master, &peer->t_write, NULL); @@ -145,6 +171,8 @@ void bgp_writes_off(struct peer *peer) void bgp_reads_on(struct peer *peer) { + assert(bgp_io_thread_run); + assert(peer->status != Deleted); assert(peer->ibuf); assert(peer->fd); @@ -164,6 +192,8 @@ void bgp_reads_on(struct peer *peer) void bgp_reads_off(struct peer *peer) { + assert(bgp_io_thread_run); + struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); thread_cancel_async(fpt->master, &peer->t_read, NULL); diff --git a/bgpd/bgp_io.h b/bgpd/bgp_io.h index 73587366d7..7cfd1db710 100644 --- a/bgpd/bgp_io.h +++ b/bgpd/bgp_io.h @@ -31,21 +31,11 @@ /** * Initializes data structures and flags for the write thread. * - * This function should be called from the main thread before + * This function must be called from the main thread before * bgp_writes_start() is invoked. */ extern void bgp_io_init(void); -/** - * Ensure that the BGP IO thread is actually up and running - * - * This function must be called immediately after the thread - * has been created for running. This is because we want - * to make sure that the io thread is ready before other - * threads start attempting to use it. - */ -extern void bgp_io_running(void); - /** * Start function for write thread. * @@ -53,6 +43,15 @@ extern void bgp_io_running(void); */ extern void *bgp_io_start(void *arg); +/** + * Wait until the IO thread is ready to accept jobs. + * + * This function must be called immediately after the thread has been created + * for running. Use of other functions before calling this one will result in + * undefined behavior. + */ +extern void bgp_io_wait_running(void); + /** * Start function for write thread. * diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 4d8e4ffe37..0a46cf42dc 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -7438,13 +7438,11 @@ void bgp_pthreads_run() pthread_attr_setschedpolicy(&attr, SCHED_FIFO); /* - * Please ensure that the io thread is running - * by calling bgp_io_running. The BGP threads - * depend on it being running when we start - * looking for it. + * I/O related code assumes the thread is ready for work at all times, + * so we wait until it is. */ frr_pthread_run(PTHREAD_IO, &attr, NULL); - bgp_io_running(); + bgp_io_wait_running(); frr_pthread_run(PTHREAD_KEEPALIVES, &attr, NULL); } From f42ebe8a6750ba86d7a0550bfa6d11c446315b5a Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Wed, 10 Jan 2018 11:20:09 -0500 Subject: [PATCH 05/84] bgpd: move startup sync lock around Condition needs to be set inside critical section, otherwise i/o thread can deadlock. Also unlock mutex once finished with it, no need to hold the lock for the life of the program. Signed-off-by: Quentin Young --- bgpd/bgp_io.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index c9662e2121..6861b0ee22 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -78,6 +78,7 @@ void bgp_io_init() pthread_mutex_init(running_cond_mtx, NULL); pthread_cond_init(running_cond, NULL); + /* unlocked in bgp_io_wait_running() */ pthread_mutex_lock(running_cond_mtx); } @@ -96,9 +97,9 @@ void *bgp_io_start(void *arg) struct thread task; - bgp_io_thread_run = true; pthread_mutex_lock(running_cond_mtx); { + bgp_io_thread_run = true; pthread_cond_signal(running_cond); } pthread_mutex_unlock(running_cond_mtx); @@ -119,6 +120,9 @@ void bgp_io_wait_running() { while (!bgp_io_thread_run) pthread_cond_wait(running_cond, running_cond_mtx); + + /* locked in bgp_io_init() */ + pthread_mutex_unlock(running_cond_mtx); } int bgp_io_stop(void **result, struct frr_pthread *fpt) @@ -126,7 +130,6 @@ int bgp_io_stop(void **result, struct frr_pthread *fpt) thread_add_event(fpt->master, &bgp_io_finish, NULL, 0, NULL); pthread_join(fpt->thread, result); - pthread_mutex_unlock(running_cond_mtx); pthread_mutex_destroy(running_cond_mtx); pthread_cond_destroy(running_cond); From dc7b3caefbd8baccb7fc3787a774e78d1a96636f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 10 Jan 2018 19:01:57 -0500 Subject: [PATCH 06/84] zebra: Add one-shot thread to recheck speed There are certain interfaces that when brought up and we receive the netlink notification about it, the speed of the interface is not set correctly. This creates a one-shot thread that will wait 15 seconds and then requery the speed and if it is different it will renotify the running daemons. The kernel should notify us on speed changes, unfortunately this is not done currently via a netlink message as you would think. As I understand it there is some in-fighting about the proper way to approach this issue and due to the way the kernel release cycle works we are a ways off from getting this fixed. This is a `hack` to make us work correctly while we wait for the true answer. Signed-off-by: Donald Sharp --- zebra/if_netlink.c | 5 +++++ zebra/interface.c | 33 +++++++++++++++++++++++++++++++++ zebra/interface.h | 2 ++ zebra/rt.h | 1 + zebra/rt_socket.c | 5 +++++ 5 files changed, 46 insertions(+) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index f73506bf91..14905b738b 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -387,6 +387,11 @@ static int get_iflink_speed(const char *ifname) return (ecmd.speed_hi << 16) | ecmd.speed; } +uint32_t kernel_get_speed(struct interface *ifp) +{ + return get_iflink_speed(ifp->name); +} + static int netlink_extract_bridge_info(struct rtattr *link_data, struct zebra_l2info_bridge *bridge_info) { diff --git a/zebra/interface.c b/zebra/interface.c index 18588ee52c..906f796136 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -57,8 +57,29 @@ DEFINE_HOOK(zebra_if_extra_info, (struct vty *vty, struct interface *ifp), DEFINE_HOOK(zebra_if_config_wr, (struct vty *vty, struct interface *ifp), (vty, ifp)) + static void if_down_del_nbr_connected(struct interface *ifp); +static int if_zebra_speed_update(struct thread *thread) +{ + struct interface *ifp = THREAD_ARG(thread); + struct zebra_if *zif = ifp->info; + uint32_t new_speed; + + zif->speed_update = NULL; + + new_speed = kernel_get_speed(ifp); + if (new_speed != ifp->speed) { + zlog_info("%s: %s old speed: %u new speed: %u", + __PRETTY_FUNCTION__, ifp->name, + ifp->speed, new_speed); + ifp->speed = new_speed; + if_add_update(ifp); + } + + return 1; +} + static void zebra_if_node_destroy(route_table_delegate_t *delegate, struct route_table *table, struct route_node *node) @@ -119,6 +140,16 @@ static int if_zebra_new_hook(struct interface *ifp) route_table_init_with_delegate(&zebra_if_table_delegate); ifp->info = zebra_if; + + /* + * Some platforms are telling us that the interface is + * up and ready to go. When we check the speed we + * sometimes get the wrong value. Wait a couple + * of seconds and ask again. Hopefully it's all settled + * down upon startup. + */ + thread_add_timer(zebrad.master, if_zebra_speed_update, + ifp, 15, &zebra_if->speed_update); return 0; } @@ -141,6 +172,8 @@ static int if_zebra_delete_hook(struct interface *ifp) list_delete_and_null(&rtadv->AdvPrefixList); #endif /* HAVE_RTADV */ + THREAD_OFF(zebra_if->speed_update); + XFREE(MTYPE_TMP, zebra_if); } diff --git a/zebra/interface.h b/zebra/interface.h index 61c3359f3b..e13721448c 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -273,6 +273,8 @@ struct zebra_if { /* Link fields - for sub-interfaces. */ ifindex_t link_ifindex; struct interface *link; + + struct thread *speed_update; }; DECLARE_HOOK(zebra_if_extra_info, (struct vty *vty, struct interface *ifp), diff --git a/zebra/rt.h b/zebra/rt.h index 7f5bb4dd34..bb4ff5bee8 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -98,6 +98,7 @@ extern void kernel_lsp_pass_fail(zebra_lsp_t *lsp, extern int mpls_kernel_init(void); +extern uint32_t kernel_get_speed(struct interface *ifp); extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); extern int kernel_add_vtep(vni_t vni, struct interface *ifp, struct in_addr *vtep_ip); diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 0d1a80e737..0c29f0650c 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -473,4 +473,9 @@ extern int kernel_interface_set_master(struct interface *master, return 0; } +uint32_t kernel_get_speed(struct interface *ifp) +{ + return ifp->speed; +} + #endif /* !HAVE_NETLINK */ From 89898ced5fd06b57912227af2275c41592c30f0a Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Thu, 11 Jan 2018 17:07:07 -0500 Subject: [PATCH 07/84] bgpd: preserve admin shutdown on peer-group add When a peer configured with administrative shutdown is added to a peer group, the administrative shutdown status is discarded and the peer will enter the BGP FSM. This is not what we want. Preserve the flag instead. Signed-off-by: Quentin Young --- bgpd/bgpd.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d76d5b0b7e..2e660c20eb 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -866,8 +866,7 @@ static void peer_af_flag_reset(struct peer *peer, afi_t afi, safi_t safi) /* peer global config reset */ static void peer_global_config_reset(struct peer *peer) { - - int v6only; + int saved_flags = 0; peer->change_local_as = 0; peer->ttl = (peer_sort(peer) == BGP_PEER_IBGP ? MAXTTL : 1); @@ -885,13 +884,11 @@ static void peer_global_config_reset(struct peer *peer) else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; - /* This is a per-peer specific flag and so we must preserve it */ - v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); - + /* These are per-peer specific flags and so we must preserve them */ + saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN); peer->flags = 0; - - if (v6only) - SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + SET_FLAG(peer->flags, saved_flags); peer->config = 0; peer->holdtime = 0; @@ -2342,7 +2339,7 @@ static void peer_group2peer_config_copy(struct peer_group *group, struct peer *peer) { struct peer *conf; - int v6only; + int saved_flags = 0; conf = group->conf; @@ -2360,14 +2357,11 @@ static void peer_group2peer_config_copy(struct peer_group *group, /* GTSM hops */ peer->gtsm_hops = conf->gtsm_hops; - /* this flag is per-neighbor and so has to be preserved */ - v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); - - /* peer flags apply */ + /* These are per-peer specific flags and so we must preserve them */ + saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN); peer->flags = conf->flags; - - if (v6only) - SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY); + SET_FLAG(peer->flags, saved_flags); /* peer config apply */ peer->config = conf->config; From 0136788cd3685ab3f7c97aef1fb321b1862363a1 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Thu, 11 Jan 2018 21:33:34 -0500 Subject: [PATCH 08/84] bgpd: fix summary line reporting routes with RDs (no json case) Signed-off-by: Lou Berger --- bgpd/bgp_route.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 81b605ad79..ccccead3d7 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -8117,6 +8117,9 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, struct bgp_node *rn, *next; unsigned long output_cum = 0; unsigned long total_cum = 0; + bool show_msg; + + show_msg = (!use_json && type == bgp_show_type_normal); for (rn = bgp_table_top(table); rn; rn = next) { next = bgp_route_next(rn); @@ -8132,8 +8135,19 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, output_arg, use_json, rd, next == NULL, &output_cum, &total_cum); + if (next == NULL) + show_msg = false; } } + if (show_msg) { + if (output_cum == 0) + vty_out(vty, "No BGP prefixes displayed, %ld exist\n", + total_cum); + else + vty_out(vty, + "\nDisplayed %ld routes and %ld total paths\n", + output_cum, total_cum); + } if (use_json) vty_out(vty, " } }"); return CMD_SUCCESS; From 0cb76b9d8dd1925d34fe84f1c24c2a7890444e97 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 8 Jan 2018 08:57:44 -0500 Subject: [PATCH 09/84] lib: Add notice of when we can remove some deprecated code. The zapi_ipv4_route, zapi_ipv6_route and zapi_ipv4_route_ipv6_nexthop functions are deprecated. Add notice of when we can remove the deprecated code from the system. Signed-off-by: Donald Sharp --- lib/zclient.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/zclient.h b/lib/zclient.h index cc34fd9d2c..869b9b7d68 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -420,6 +420,11 @@ extern struct interface *zebra_interface_vrf_update_read(struct stream *s, vrf_id_t *new_vrf_id); extern void zebra_interface_if_set_value(struct stream *, struct interface *); extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid); + +#if CONFDATE > 20180823 +CPP_NOTICE("zapi_ipv4_route, zapi_ipv6_route, zapi_ipv4_route_ipv6_nexthop as well as the zapi_ipv4 and zapi_ipv6 data structures should be removed now"); +#endif + extern int zapi_ipv4_route(u_char, struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *) __attribute__((deprecated)); From 14fcc65cbbcd3d1684b879a10a0d8564c238e0e6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 5 Jan 2018 09:21:55 -0500 Subject: [PATCH 10/84] lib: Allow interface lookup by VRF_UNKNOWN Modify if_lookup_by_index to accept a VRF_UNKNOWN as a vrf_id. This will cause it to look in all vrf's for the interface pointer. Subsequently all if_XXXX functions that call this function will also get this behavior. VRF_UNKNOWN *should* not be used for interface creation as that this will break some core assumptions. This work is part of allowing vrf route leaking. Currently it is possible to create a route in the linux kernel that has a nexthop across vrf boundaries. Signed-off-by: Donald Sharp --- lib/if.c | 12 ++++++++++++ lib/if.h | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/lib/if.c b/lib/if.c index 8e6a9a6968..fdcd563a5d 100644 --- a/lib/if.c +++ b/lib/if.c @@ -219,6 +219,18 @@ struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id) struct vrf *vrf; struct interface if_tmp; + if (vrf_id == VRF_UNKNOWN) { + struct interface *ifp; + + RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) { + ifp = if_lookup_by_index(ifindex, vrf->vrf_id); + if (ifp) + return ifp; + } + + return NULL; + } + vrf = vrf_lookup_by_id(vrf_id); if (!vrf) return NULL; diff --git a/lib/if.h b/lib/if.h index eb8af2041b..79f96a7c45 100644 --- a/lib/if.h +++ b/lib/if.h @@ -452,6 +452,13 @@ struct nbr_connected { /* Prototypes. */ extern int if_cmp_name_func(char *, char *); +/* + * Passing in VRF_UNKNOWN is a valid thing to do, unless we + * are creating a new interface. + * + * This is useful for vrf route-leaking. So more than anything + * else think before you use VRF_UNKNOWN + */ extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id); extern struct interface *if_create(const char *name, vrf_id_t vrf_id); extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id); From 8f43b4d8868b340a7c61e55372b01f070abfb491 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 12 Jan 2018 09:20:30 -0500 Subject: [PATCH 11/84] zebra: Add nh_vrf_id to 'struct route_entry` With VRF route-leaking we need to know what vrf the nexthops are in compared to this vrf. This code adds the nh_vrf_id to the route entry and sets it up correctly for the non-route-leaking case. The assumption here is that future commits will make the nh_vrf_id *different* than the vrf_id. Signed-off-by: Donald Sharp --- zebra/rib.h | 1 + zebra/rt_netlink.c | 1 + zebra/zebra_rib.c | 1 + zebra/zebra_rnh.c | 2 ++ zebra/zebra_static.c | 1 + zebra/zserv.c | 5 +++++ 6 files changed, 11 insertions(+) diff --git a/zebra/rib.h b/zebra/rib.h index c7e83480ca..c92f540771 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -59,6 +59,7 @@ struct route_entry { /* VRF identifier. */ vrf_id_t vrf_id; + vrf_id_t nh_vrf_id; /* Which routing table */ uint32_t table; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a77814668d..cb3f598eb9 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -453,6 +453,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl, re->metric = metric; re->mtu = mtu; re->vrf_id = vrf_id; + re->nh_vrf_id = vrf_id; re->table = table; re->nexthop_num = 0; re->uptime = time(NULL); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 41e14459b1..8caa39427b 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2514,6 +2514,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, re->mtu = mtu; re->table = table_id; re->vrf_id = vrf_id; + re->nh_vrf_id = vrf_id; re->nexthop_num = 0; re->uptime = time(NULL); re->tag = tag; diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 33d0b3a641..3fc496ebb7 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -951,6 +951,8 @@ static void copy_state(struct rnh *rnh, struct route_entry *re, state->type = re->type; state->distance = re->distance; state->metric = re->metric; + state->vrf_id = re->vrf_id; + state->nh_vrf_id = re->vrf_id; route_entry_copy_nexthops(state, re->nexthop); rnh->state = state; diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index 751ea08a38..7fdc4908b4 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -155,6 +155,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, re->metric = 0; re->mtu = 0; re->vrf_id = si->vrf_id; + re->nh_vrf_id = si->vrf_id; re->table = si->vrf_id ? (zebra_vrf_lookup_by_id(si->vrf_id))->table_id diff --git a/zebra/zserv.c b/zebra/zserv.c index 7eded89f6d..6c453516bd 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1146,6 +1146,7 @@ static int zread_route_add(struct zserv *client, u_short length, re->flags = api.flags; re->uptime = time(NULL); re->vrf_id = vrf_id; + re->nh_vrf_id = vrf_id; re->table = zvrf->table_id; if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { @@ -1372,6 +1373,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, /* VRF ID */ re->vrf_id = zvrf_id(zvrf); + re->nh_vrf_id = zvrf_id(zvrf); /* Nexthop parse. */ if (CHECK_FLAG(message, ZAPI_MESSAGE_NEXTHOP)) { @@ -1581,6 +1583,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, /* VRF ID */ re->vrf_id = zvrf_id(zvrf); + re->nh_vrf_id = zvrf_id(zvrf); /* We need to give nh-addr, nh-ifindex with the same next-hop object * to the re to ensure that IPv6 multipathing works; need to coalesce @@ -1866,6 +1869,8 @@ static int zread_ipv6_add(struct zserv *client, u_short length, /* VRF ID */ re->vrf_id = zvrf_id(zvrf); + re->nh_vrf_id = zvrf_id(zvrf); + re->table = zvrf->table_id; ret = rib_add_multipath(AFI_IP6, safi, &p, src_pp, re); From 99b9d9609f57d283d79c72c89848d7ac5f000f0b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 8 Jan 2018 09:56:08 -0500 Subject: [PATCH 12/84] zebra: Use the correct vrf id to lookup the ifp pointer Use the nexthop vrf_id to properly lookup the ifp pointer for display purposes. Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 3 ++- zebra/zebra_vty.c | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 8caa39427b..6f9b855908 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -911,7 +911,8 @@ static unsigned nexthop_active_check(struct route_node *rn, zlog_debug( "%u:%s: Filtering out with NH out %s due to route map", re->vrf_id, buf, - ifindex2ifname(nexthop->ifindex, re->vrf_id)); + ifindex2ifname(nexthop->ifindex, + re->nh_vrf_id)); } UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 82b0157ad3..a0d2930c89 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -539,7 +539,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, if (nexthop->ifindex) vty_out(vty, ", via %s", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: @@ -549,12 +549,12 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, if (nexthop->ifindex) vty_out(vty, ", via %s", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); break; case NEXTHOP_TYPE_IFINDEX: vty_out(vty, " directly connected, %s", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); break; case NEXTHOP_TYPE_BLACKHOLE: vty_out(vty, " unreachable"); @@ -715,7 +715,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_string_add( json_nexthop, "interfaceName", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); } break; case NEXTHOP_TYPE_IPV6: @@ -734,7 +734,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_string_add( json_nexthop, "interfaceName", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); } break; @@ -747,7 +747,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_string_add( json_nexthop, "interfaceName", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); break; case NEXTHOP_TYPE_BLACKHOLE: json_object_boolean_true_add(json_nexthop, @@ -881,7 +881,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (nexthop->ifindex) vty_out(vty, ", %s", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: @@ -891,12 +891,13 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (nexthop->ifindex) vty_out(vty, ", %s", ifindex2ifname(nexthop->ifindex, - re->vrf_id)); + re->nh_vrf_id)); break; case NEXTHOP_TYPE_IFINDEX: vty_out(vty, " is directly connected, %s", - ifindex2ifname(nexthop->ifindex, re->vrf_id)); + ifindex2ifname(nexthop->ifindex, + re->nh_vrf_id)); break; case NEXTHOP_TYPE_BLACKHOLE: vty_out(vty, " unreachable"); From 8795f90448e45e674ea60da83c2ad571ff2f9fec Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 8 Jan 2018 10:21:09 -0500 Subject: [PATCH 13/84] zebra: Add nh_vrf_id to rib_add Add to the rib_add function the ability to pass in the nexthops vrf. Additionally when we decode the netlink message from the linux kernel, properly figure out the nexthops vrf_id. Signed-off-by: Donald Sharp --- zebra/connected.c | 6 ++++-- zebra/kernel_socket.c | 4 ++-- zebra/rib.h | 4 ++-- zebra/rt_netlink.c | 24 +++++++++++++++++++++++- zebra/rtread_getmsg.c | 5 +++-- zebra/zebra_rib.c | 9 +++++---- 6 files changed, 39 insertions(+), 13 deletions(-) diff --git a/zebra/connected.c b/zebra/connected.c index 7b949c5041..d34fd9021a 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -238,10 +238,12 @@ void connected_up(struct interface *ifp, struct connected *ifc) break; } - rib_add(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, + rib_add(afi, SAFI_UNICAST, ifp->vrf_id, ifp->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0); - rib_add(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, + rib_add(afi, SAFI_MULTICAST, ifp->vrf_id, ifp->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0); if (IS_ZEBRA_DEBUG_RIB_DETAILED) { diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 9fd7bb1c24..ba028ed09c 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1048,7 +1048,7 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) - rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, + rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, &nh, 0, 0, 0, 0, 0); else @@ -1096,7 +1096,7 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) - rib_add(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, + rib_add(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, &nh, 0, 0, 0, 0, 0); else diff --git a/zebra/rib.h b/zebra/rib.h index c92f540771..6e3a85c1d1 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -294,8 +294,8 @@ extern void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re); /* NOTE: * All rib_add function will not just add prefix into RIB, but * also implicitly withdraw equal prefix of same type. */ -extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, - u_short instance, int flags, struct prefix *p, +extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, vrf_id_t nh_vrf_id, + int type, u_short instance, int flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, u_int32_t table_id, u_int32_t metric, u_int32_t mtu, uint8_t distance, route_tag_t tag); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index cb3f598eb9..384656a573 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -403,6 +403,9 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl, afi = AFI_IP6; if (h->nlmsg_type == RTM_NEWROUTE) { + struct interface *ifp; + vrf_id_t nh_vrf_id = vrf_id; + if (!tb[RTA_MULTIPATH]) { struct nexthop nh; size_t sz = (afi == AFI_IP) ? 4 : 16; @@ -434,7 +437,14 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl, if (gate) memcpy(&nh.gate, gate, sz); - rib_add(afi, SAFI_UNICAST, vrf_id, proto, + if (index) { + ifp = if_lookup_by_index(index, + VRF_UNKNOWN); + if (ifp) + nh_vrf_id = ifp->vrf_id; + } + + rib_add(afi, SAFI_UNICAST, vrf_id, nh_vrf_id, proto, 0, flags, &p, NULL, &nh, table, metric, mtu, distance, tag); } else { @@ -465,6 +475,18 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl, break; index = rtnh->rtnh_ifindex; + if (index) { + /* + * Yes we are looking this up + * for every nexthop and just + * using the last one looked + * up right now + */ + ifp = if_lookup_by_index(index, + VRF_UNKNOWN); + if (ifp) + re->nh_vrf_id = ifp->vrf_id; + } gate = 0; if (rtnh->rtnh_len > sizeof(*rtnh)) { memset(tb, 0, sizeof(tb)); diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 69e45f9a6c..ba45f54ad2 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -97,8 +97,9 @@ static void handle_route_entry(mib2_ipRouteEntry_t *routeEntry) nh.type = NEXTHOP_TYPE_IPV4; nh.gate.ipv4.s_addr = routeEntry->ipRouteNextHop; - rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, - zebra_flags, &prefix, NULL, &nh, 0, 0, 0, 0, 0); + rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, VRF_DEFAULT, + ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &prefix, NULL, + &nh, 0, 0, 0, 0, 0); } void route_read(struct zebra_ns *zns) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 6f9b855908..b1f0f70093 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2497,9 +2497,10 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, } -int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, - int flags, struct prefix *p, struct prefix_ipv6 *src_p, - const struct nexthop *nh, u_int32_t table_id, u_int32_t metric, +int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, vrf_id_t nh_vrf_id, + int type, u_short instance, int flags, struct prefix *p, + struct prefix_ipv6 *src_p, const struct nexthop *nh, + u_int32_t table_id, u_int32_t metric, u_int32_t mtu, uint8_t distance, route_tag_t tag) { struct route_entry *re; @@ -2515,7 +2516,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, re->mtu = mtu; re->table = table_id; re->vrf_id = vrf_id; - re->nh_vrf_id = vrf_id; + re->nh_vrf_id = nh_vrf_id; re->nexthop_num = 0; re->uptime = time(NULL); re->tag = tag; From 007dbee65cef24561da54cfbf5c4d24052db002a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 8 Jan 2018 10:34:48 -0500 Subject: [PATCH 14/84] zebra: When handling nexthops use the correct vrf When we are handling nexthops in zebra, use the appropriate vrf to figure out if the nexthops are active or not. Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b1f0f70093..fd1b273c8e 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -256,7 +256,7 @@ struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re, if (src) nexthop->src.ipv4 = *src; nexthop->ifindex = ifindex; - ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id); + ifp = if_lookup_by_index(nexthop->ifindex, re->nh_vrf_id); /*Pending: need to think if null ifp here is ok during bootup? There was a crash because ifp here was coming to be NULL */ if (ifp) @@ -416,7 +416,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, * address in the routing table. */ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) { - ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id); + ifp = if_lookup_by_index(nexthop->ifindex, re->nh_vrf_id); if (ifp && connected_is_unnumbered(ifp)) { if (if_is_operative(ifp)) return 1; @@ -444,7 +444,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, break; } /* Lookup table. */ - table = zebra_vrf_table(afi, SAFI_UNICAST, re->vrf_id); + table = zebra_vrf_table(afi, SAFI_UNICAST, re->nh_vrf_id); if (!table) return 0; @@ -832,7 +832,7 @@ static unsigned nexthop_active_check(struct route_node *rn, family = 0; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: - ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id); + ifp = if_lookup_by_index(nexthop->ifindex, re->nh_vrf_id); if (ifp && if_is_operative(ifp)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else @@ -860,7 +860,8 @@ static unsigned nexthop_active_check(struct route_node *rn, if (rn->p.family != AF_INET) family = AFI_IP6; if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) { - ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id); + ifp = if_lookup_by_index(nexthop->ifindex, + re->nh_vrf_id); if (ifp && if_is_operative(ifp)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); else From 2793a0980dc02ba3179c5af4468943d9d6879b62 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 8 Jan 2018 10:43:07 -0500 Subject: [PATCH 15/84] zebra: When displaying nexthop information show correct vrf If the vrf for the nexthop is different than the vrf the route is in, display the nexthops vrf. Signed-off-by: Donald Sharp --- zebra/zebra_vty.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index a0d2930c89..c56df82053 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -576,6 +576,14 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, default: break; } + + if (re->vrf_id != re->nh_vrf_id) { + struct vrf *vrf = + vrf_lookup_by_id(re->nh_vrf_id); + + vty_out(vty, "(vrf %s)", vrf->name); + } + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) vty_out(vty, " (duplicate nexthop removed)"); @@ -774,6 +782,14 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, break; } + if (re->nh_vrf_id != re->vrf_id) { + struct vrf *vrf = + vrf_lookup_by_id(re->nh_vrf_id); + + json_object_string_add(json_nexthop, + "vrf", + vrf->name); + } if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) json_object_boolean_true_add(json_nexthop, "duplicate"); @@ -918,6 +934,14 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, default: break; } + + if (re->nh_vrf_id != re->vrf_id) { + struct vrf *vrf = + vrf_lookup_by_id(re->nh_vrf_id); + + vty_out(vty, "(vrf %s)", vrf->name); + } + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) vty_out(vty, " inactive"); From d5b2119cb418c47a70eb931a4ccdb6e6f078619f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 8 Jan 2018 11:17:02 -0500 Subject: [PATCH 16/84] *: Send/receive the nexthop vrf_id Modify the code to send and receive to/from zebra the nexthops vrf_id. Signed-off-by: Donald Sharp --- babeld/kernel.c | 1 + bgpd/bgp_zebra.c | 2 ++ bgpd/rfapi/vnc_zebra.c | 1 + eigrpd/eigrp_zebra.c | 2 ++ isisd/isis_zebra.c | 2 ++ lib/zclient.c | 5 +++++ lib/zclient.h | 1 + nhrpd/nhrp_route.c | 2 ++ ospf6d/ospf6_zebra.c | 3 +++ ospfd/ospf_zebra.c | 4 ++++ ripd/rip_zebra.c | 1 + ripngd/ripng_zebra.c | 1 + sharpd/sharp_zebra.c | 2 ++ zebra/zserv.c | 3 ++- 14 files changed, 29 insertions(+), 1 deletion(-) diff --git a/babeld/kernel.c b/babeld/kernel.c index 8c4fc953e7..6b673c487c 100644 --- a/babeld/kernel.c +++ b/babeld/kernel.c @@ -166,6 +166,7 @@ zebra_route(int add, int family, const unsigned char *pref, unsigned short plen, api.type = ZEBRA_ROUTE_BABEL; api.safi = SAFI_UNICAST; api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.prefix = quagga_prefix; if(metric >= KERNEL_INFINITY) { diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 30e3c6f31d..de170fdd01 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1001,6 +1001,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, memset(&api, 0, sizeof(api)); memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr)); api.vrf_id = bgp->vrf_id; + api.nh_vrf_id = bgp->vrf_id; api.type = ZEBRA_ROUTE_BGP; api.safi = safi; api.prefix = *p; @@ -1253,6 +1254,7 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi) memset(&api, 0, sizeof(api)); memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr)); api.vrf_id = peer->bgp->vrf_id; + api.nh_vrf_id = peer->bgp->vrf_id; api.type = ZEBRA_ROUTE_BGP; api.safi = safi; api.prefix = *p; diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c index f8b38468f5..cba611a774 100644 --- a/bgpd/rfapi/vnc_zebra.c +++ b/bgpd/rfapi/vnc_zebra.c @@ -394,6 +394,7 @@ static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count, memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_VNC; api.safi = SAFI_UNICAST; api.prefix = *p; diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index 00438f2f47..f18d39d575 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -366,6 +366,7 @@ void eigrp_zebra_route_add(struct prefix *p, struct list *successors) memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_EIGRP; api.safi = SAFI_UNICAST; memcpy(&api.prefix, p, sizeof(*p)); @@ -407,6 +408,7 @@ void eigrp_zebra_route_delete(struct prefix *p) memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_EIGRP; api.safi = SAFI_UNICAST; memcpy(&api.prefix, p, sizeof(*p)); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 573b81591c..0512a18a2a 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -261,6 +261,7 @@ static void isis_zebra_route_add_route(struct prefix *prefix, memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_ISIS; api.safi = SAFI_UNICAST; api.prefix = *prefix; @@ -329,6 +330,7 @@ static void isis_zebra_route_del_route(struct prefix *prefix, memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_ISIS; api.safi = SAFI_UNICAST; api.prefix = *prefix; diff --git a/lib/zclient.c b/lib/zclient.c index 4177ce1a71..8f9536f5a2 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -942,6 +942,8 @@ int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api) } stream_putw(s, api->nexthop_num); + if (api->nexthop_num) + stream_putw(s, api->nh_vrf_id); for (i = 0; i < api->nexthop_num; i++) { api_nh = &api->nexthops[i]; @@ -1091,6 +1093,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) return -1; } + if (api->nexthop_num) + STREAM_GETW(s, api->nh_vrf_id); + for (i = 0; i < api->nexthop_num; i++) { api_nh = &api->nexthops[i]; diff --git a/lib/zclient.h b/lib/zclient.h index 869b9b7d68..083372a9d2 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -281,6 +281,7 @@ struct zapi_route { u_int32_t mtu; vrf_id_t vrf_id; + vrf_id_t nh_vrf_id; struct ethaddr rmac; }; diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 2612d8e045..2f084f8422 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -95,6 +95,8 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix memset(&api, 0, sizeof(api)); api.type = ZEBRA_ROUTE_NHRP; api.safi = SAFI_UNICAST; + api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.prefix = *p; switch (type) { diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index cc87c499ee..2a419ddfc6 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -337,6 +337,7 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request) memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF6; api.safi = SAFI_UNICAST; api.prefix = *dest; @@ -387,6 +388,7 @@ void ospf6_zebra_add_discard(struct ospf6_route *request) if (!CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) { memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF6; api.safi = SAFI_UNICAST; api.prefix = *dest; @@ -420,6 +422,7 @@ void ospf6_zebra_delete_discard(struct ospf6_route *request) if (CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) { memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF6; api.safi = SAFI_UNICAST; api.prefix = *dest; diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 66be29dbb4..58e8a921d5 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -389,6 +389,7 @@ void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *p, memset(&api, 0, sizeof(api)); api.vrf_id = ospf->vrf_id; + api.nh_vrf_id = ospf->vrf_id; api.type = ZEBRA_ROUTE_OSPF; api.instance = ospf->instance; api.safi = SAFI_UNICAST; @@ -466,6 +467,7 @@ void ospf_zebra_delete(struct ospf *ospf, struct prefix_ipv4 *p, memset(&api, 0, sizeof(api)); api.vrf_id = ospf->vrf_id; + api.nh_vrf_id = ospf->vrf_id; api.type = ZEBRA_ROUTE_OSPF; api.instance = ospf->instance; api.safi = SAFI_UNICAST; @@ -487,6 +489,7 @@ void ospf_zebra_add_discard(struct ospf *ospf, struct prefix_ipv4 *p) memset(&api, 0, sizeof(api)); api.vrf_id = ospf->vrf_id; + api.nh_vrf_id = ospf->vrf_id; api.type = ZEBRA_ROUTE_OSPF; api.instance = ospf->instance; api.safi = SAFI_UNICAST; @@ -506,6 +509,7 @@ void ospf_zebra_delete_discard(struct ospf *ospf, struct prefix_ipv4 *p) memset(&api, 0, sizeof(api)); api.vrf_id = ospf->vrf_id; + api.nh_vrf_id = ospf->vrf_id; api.type = ZEBRA_ROUTE_OSPF; api.instance = ospf->instance; api.safi = SAFI_UNICAST; diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 041635e153..52a5d93c4f 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -48,6 +48,7 @@ static void rip_zebra_ipv4_send(struct route_node *rp, u_char cmd) memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_RIP; api.safi = SAFI_UNICAST; diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 18a8d14f09..ea069d877f 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -48,6 +48,7 @@ static void ripng_zebra_ipv6_send(struct route_node *rp, u_char cmd) memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_RIPNG; api.safi = SAFI_UNICAST; api.prefix = rp->p; diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 4a5ae13c43..25bb512a8b 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -159,6 +159,7 @@ void route_add(struct prefix *p, struct nexthop *nh) memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_SHARP; api.safi = SAFI_UNICAST; memcpy(&api.prefix, p, sizeof(*p)); @@ -180,6 +181,7 @@ void route_delete(struct prefix *p) memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_SHARP; api.safi = SAFI_UNICAST; memcpy(&api.prefix, p, sizeof(*p)); diff --git a/zebra/zserv.c b/zebra/zserv.c index 6c453516bd..1520fc883a 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -602,6 +602,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p, memset(&api, 0, sizeof(api)); api.vrf_id = re->vrf_id; + api.nh_vrf_id = re->nh_vrf_id; api.type = re->type; api.instance = re->instance; api.flags = re->flags; @@ -1146,7 +1147,7 @@ static int zread_route_add(struct zserv *client, u_short length, re->flags = api.flags; re->uptime = time(NULL); re->vrf_id = vrf_id; - re->nh_vrf_id = vrf_id; + re->nh_vrf_id = api.nh_vrf_id; re->table = zvrf->table_id; if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { From 9ceac4c7cf902ac80d422bc5dcebf15305770eb6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 8 Jan 2018 16:09:07 -0500 Subject: [PATCH 17/84] lib: Increment zapi version number Signed-off-by: Donald Sharp --- lib/zclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zclient.h b/lib/zclient.h index 083372a9d2..72e71631d2 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -227,7 +227,7 @@ struct zserv_header { * always set to 255 in new zserv. */ uint8_t version; -#define ZSERV_VERSION 4 +#define ZSERV_VERSION 5 vrf_id_t vrf_id; uint16_t command; }; From f84fc2c9553621648bbaa0c0938cd1b60608e14b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 9 Jan 2018 14:47:11 -0500 Subject: [PATCH 18/84] zebra: Move NS/VRF initialization earlier Move the NS/VRF initialization code for zebra to an earlier point in startup. In the future we will have code that will want to install_element into a VRF_NODE from zebra_vty.c Signed-off-by: Donald Sharp --- zebra/main.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/zebra/main.c b/zebra/main.c index e26c8e3d69..19b16936d9 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -300,6 +300,13 @@ int main(int argc, char **argv) zebra_if_init(); zebra_debug_init(); router_id_cmd_init(); + + /* + * Initialize NS( and implicitly the VRF module), and make kernel + * routing socket. */ + zebra_ns_init(); + + zebra_vty_init(); access_list_init(); prefix_list_init(); #if defined(HAVE_RTADV) @@ -317,16 +324,6 @@ int main(int argc, char **argv) /* For debug purpose. */ /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ - /* Initialize NS( and implicitly the VRF module), and make kernel - * routing socket. */ - zebra_ns_init(); - - /* - * Initialize show/config command after the vrf initialization is - * complete - */ - zebra_vty_init(); - #if defined(HANDLE_ZAPI_FUZZING) if (fuzzing) { zserv_read_file(fuzzing); From 2f03bc8f72de03461b2be732162521fd6b837d49 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 9 Jan 2018 16:25:45 -0500 Subject: [PATCH 19/84] zebra: Add zebra_static_route_leak function Add a function to handle the route leaking of a static route. Signed-off-by: Donald Sharp --- zebra/zebra_vty.c | 51 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index c56df82053..45e204dcc9 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -78,13 +78,16 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, #define CMD_VNI_RANGE "(1-16777215)" /* General function for static route. */ -static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, - const char *negate, const char *dest_str, - const char *mask_str, const char *src_str, - const char *gate_str, const char *ifname, - const char *flag_str, const char *tag_str, - const char *distance_str, const char *vrf_id_str, - const char *label_str) +static int zebra_static_route_leak(struct vty *vty, + struct zebra_vrf *zvrf, + struct zebra_vrf *nh_zvrf, + afi_t afi, safi_t safi, + const char *negate, const char *dest_str, + const char *mask_str, const char *src_str, + const char *gate_str, const char *ifname, + const char *flag_str, const char *tag_str, + const char *distance_str, + const char *label_str) { int ret; u_char distance; @@ -95,7 +98,6 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, struct in_addr mask; enum static_blackhole_type bh_type = 0; route_tag_t tag = 0; - struct zebra_vrf *zvrf; u_char type; struct static_nh_label snh_label; @@ -145,14 +147,6 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, if (tag_str) tag = strtoul(tag_str, NULL, 10); - /* VRF id */ - zvrf = zebra_vrf_lookup_by_name(vrf_id_str); - - if (!zvrf) { - vty_out(vty, "%% vrf %s is not defined\n", vrf_id_str); - return CMD_WARNING_CONFIG_FAILED; - } - /* Labels */ memset(&snh_label, 0, sizeof(struct static_nh_label)); if (label_str) { @@ -247,6 +241,31 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, return CMD_SUCCESS; } +static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, + const char *negate, const char *dest_str, + const char *mask_str, const char *src_str, + const char *gate_str, const char *ifname, + const char *flag_str, const char *tag_str, + const char *distance_str, const char *vrf_id_str, + const char *label_str) +{ + struct zebra_vrf *zvrf; + + /* VRF id */ + zvrf = zebra_vrf_lookup_by_name(vrf_id_str); + + if (!zvrf) { + vty_out(vty, "%% vrf %s is not defined\n", vrf_id_str); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, zvrf, afi, safi, + negate, dest_str, mask_str, src_str, + gate_str, ifname, flag_str, tag_str, + distance_str, label_str); +} + + /* Static unicast routes for multicast RPF lookup. */ DEFPY (ip_mroute_dist, ip_mroute_dist_cmd, From cbb0dbf6bd49df140ae838b8013c15513d976b4d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 8 Jan 2018 19:11:17 -0500 Subject: [PATCH 20/84] zebra: Add the zvrf pointer to the 'struct static_route' Signed-off-by: Donald Sharp --- zebra/zebra_static.c | 7 +++++-- zebra/zebra_static.h | 2 ++ zebra/zebra_vty.c | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index 7fdc4908b4..3423518bba 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -155,7 +155,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, re->metric = 0; re->mtu = 0; re->vrf_id = si->vrf_id; - re->nh_vrf_id = si->vrf_id; + re->nh_vrf_id = si->nh_vrf_id; re->table = si->vrf_id ? (zebra_vrf_lookup_by_id(si->vrf_id))->table_id @@ -379,6 +379,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, struct prefix_ipv6 *src_p, union g_addr *gate, const char *ifname, enum static_blackhole_type bh_type, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, + struct zebra_vrf *nh_zvrf, struct static_nh_label *snh_label) { struct route_node *rn; @@ -440,6 +441,8 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, si->bh_type = bh_type; si->tag = tag; si->vrf_id = zvrf_id(zvrf); + si->nh_vrf_id = zvrf_id(nh_zvrf); + if (ifname) strlcpy(si->ifname, ifname, sizeof(si->ifname)); si->ifindex = IFINDEX_INTERNAL; @@ -494,7 +497,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, else { struct interface *ifp; - ifp = if_lookup_by_name(ifname, zvrf_id(zvrf)); + ifp = if_lookup_by_name(ifname, zvrf_id(nh_zvrf)); if (ifp && ifp->ifindex != IFINDEX_INTERNAL) { si->ifindex = ifp->ifindex; static_install_route(afi, safi, p, src_p, si); diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h index 68fe73b0a3..234e3e4036 100644 --- a/zebra/zebra_static.h +++ b/zebra/zebra_static.h @@ -54,6 +54,7 @@ struct static_route { /* VRF identifier. */ vrf_id_t vrf_id; + vrf_id_t nh_vrf_id; /* Administrative distance. */ u_char distance; @@ -89,6 +90,7 @@ extern int static_add_route(afi_t, safi_t safi, u_char type, struct prefix *p, const char *ifname, enum static_blackhole_type bh_type, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, + struct zebra_vrf *nh_zvrf, struct static_nh_label *snh_label); extern int static_delete_route(afi_t, safi_t safi, u_char type, diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 45e204dcc9..ece4428c43 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -233,7 +233,8 @@ static int zebra_static_route_leak(struct vty *vty, if (!negate) static_add_route(afi, safi, type, &p, src_p, gatep, ifname, - bh_type, tag, distance, zvrf, &snh_label); + bh_type, tag, distance, zvrf, nh_zvrf, + &snh_label); else static_delete_route(afi, safi, type, &p, src_p, gatep, ifname, tag, distance, zvrf, &snh_label); From ab32921c8a6a531cc51cbc659ec5abce43d9420a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 10 Jan 2018 09:32:16 -0500 Subject: [PATCH 21/84] zebra: Cleanup vrf_config_write Optimize vrf_config_write a tiny bit to be a bit more efficient. Signed-off-by: Donald Sharp --- zebra/zebra_vrf.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 1ae9eac61f..ae8cb3450e 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -476,12 +476,13 @@ static int vrf_config_write(struct vty *vty) if (!zvrf) continue; - if (strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) { - vty_out(vty, "vrf %s\n", zvrf_name(zvrf)); - if (zvrf->l3vni) - vty_out(vty, " vni %u\n", zvrf->l3vni); - vty_out(vty, "!\n"); - } + if (vrf->vrf_id == VRF_DEFAULT) + continue; + + vty_out(vty, "vrf %s\n", zvrf_name(zvrf)); + if (zvrf->l3vni) + vty_out(vty, " vni %u\n", zvrf->l3vni); + vty_out(vty, "!\n"); } return 0; } From b2ffa06b4f648f193e53fdde9c3e9dd55d8e494d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 10 Jan 2018 10:21:16 -0500 Subject: [PATCH 22/84] zebra: Add vrf level 'ip route ...' commands Add the ability to accept 'ip route ...' commands from within a vrf context. Signed-off-by: Donald Sharp --- zebra/zebra_vty.c | 248 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index ece4428c43..a9f95c1028 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -407,6 +407,37 @@ DEFPY(ip_route_blackhole, tag_str, distance_str, vrf, label); } +DEFPY(ip_route_blackhole_vrf, + ip_route_blackhole_vrf_cmd, + "[no] ip route\ + \ + $flag \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + }]", + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + MPLS_LABEL_HELPSTR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct zebra_vrf *zvrf = vrf->info; + + return zebra_static_route_leak(vty, zvrf, zvrf, + AFI_IP, SAFI_UNICAST, no, prefix, + mask_str, NULL, NULL, NULL, flag, + tag_str, distance_str, label); +} + DEFPY(ip_route_address_interface, ip_route_address_interface_cmd, "[no] ip route\ @@ -443,6 +474,55 @@ DEFPY(ip_route_address_interface, tag_str, distance_str, vrf, label); } +DEFPY(ip_route_address_interface_vrf, + ip_route_address_interface_vrf_cmd, + "[no] ip route\ + \ + A.B.C.D$gate \ + INTERFACE$ifname \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |nexthop-vrf NAME \ + }]", + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name. Specify 'Null0' (case-insensitive) for a \ + null route.\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + const char *flag = NULL; + struct zebra_vrf *zvrf = vrf->info; + struct zebra_vrf *nh_zvrf; + + if (ifname && !strncasecmp(ifname, "Null0", 5)) { + flag = "Null0"; + ifname = NULL; + } + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP, SAFI_UNICAST, no, prefix, + mask_str, NULL, gate_str, ifname, flag, + tag_str, distance_str, label); +} + DEFPY(ip_route, ip_route_cmd, "[no] ip route\ @@ -477,6 +557,53 @@ DEFPY(ip_route, tag_str, distance_str, vrf, label); } +DEFPY(ip_route_vrf, + ip_route_vrf_cmd, + "[no] ip route\ + \ + \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |nexthop-vrf NAME \ + }]", + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct zebra_vrf *zvrf = vrf->info; + struct zebra_vrf *nh_zvrf; + + const char *flag = NULL; + if (ifname && !strncasecmp(ifname, "Null0", 5)) { + flag = "Null0"; + ifname = NULL; + } + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP, SAFI_UNICAST, no, prefix, + mask_str, NULL, gate_str, ifname, flag, + tag_str, distance_str, label); +} + /* New RIB. Detailed information for IPv4 route. */ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, int mcast) @@ -1772,6 +1899,38 @@ DEFPY(ipv6_route_blackhole, tag_str, distance_str, vrf, label); } +DEFPY(ipv6_route_blackhole_vrf, + ipv6_route_blackhole_vrf_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + $flag \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + }]", + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "Null interface\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + MPLS_LABEL_HELPSTR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct zebra_vrf *zvrf = vrf->info; + + return zebra_static_route_leak(vty, zvrf, zvrf, + AFI_IP6, SAFI_UNICAST, no, prefix_str, + NULL, from_str, NULL, NULL, flag, + tag_str, distance_str, label); +} + DEFPY(ipv6_route_address_interface, ipv6_route_address_interface_cmd, "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ @@ -1802,6 +1961,48 @@ DEFPY(ipv6_route_address_interface, tag_str, distance_str, vrf, label); } +DEFPY(ipv6_route_address_interface_vrf, + ipv6_route_address_interface_vrf_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + X:X::X:X$gate \ + INTERFACE$ifname \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |nexthop-vrf NAME \ + }]", + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct zebra_vrf *zvrf = vrf->info; + struct zebra_vrf *nh_zvrf; + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP6, SAFI_UNICAST, no, prefix_str, + NULL, from_str, gate_str, ifname, NULL, + tag_str, distance_str, label); +} + DEFPY(ipv6_route, ipv6_route_cmd, "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ @@ -1831,6 +2032,47 @@ DEFPY(ipv6_route, tag_str, distance_str, vrf, label); } +DEFPY(ipv6_route_vrf, + ipv6_route_vrf_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |nexthop-vrf NAME \ + }]", + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct zebra_vrf *zvrf = vrf->info; + struct zebra_vrf *nh_zvrf; + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP6, SAFI_UNICAST, no, prefix_str, + NULL, from_str, gate_str, ifname, NULL, + tag_str, distance_str, label); +} + /* * Show IPv6 mroute command.Used to dump * the Multicast routing table. @@ -2904,8 +3146,11 @@ void zebra_vty_init(void) install_element(CONFIG_NODE, &ip_multicast_mode_cmd); install_element(CONFIG_NODE, &no_ip_multicast_mode_cmd); install_element(CONFIG_NODE, &ip_route_blackhole_cmd); + install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd); install_element(CONFIG_NODE, &ip_route_address_interface_cmd); + install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd); install_element(CONFIG_NODE, &ip_route_cmd); + install_element(VRF_NODE, &ip_route_vrf_cmd); install_element(CONFIG_NODE, &ip_zebra_import_table_distance_cmd); install_element(CONFIG_NODE, &no_ip_zebra_import_table_cmd); install_element(CONFIG_NODE, &zebra_workqueue_timer_cmd); @@ -2927,8 +3172,11 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_ip_rpf_addr_cmd); install_element(CONFIG_NODE, &ipv6_route_blackhole_cmd); + install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd); install_element(CONFIG_NODE, &ipv6_route_address_interface_cmd); + install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd); install_element(CONFIG_NODE, &ipv6_route_cmd); + install_element(VRF_NODE, &ipv6_route_vrf_cmd); install_element(CONFIG_NODE, &ip_nht_default_route_cmd); install_element(CONFIG_NODE, &no_ip_nht_default_route_cmd); install_element(CONFIG_NODE, &ipv6_nht_default_route_cmd); From 37728041b634b2ef96fe5ff120964fe3ba0b8114 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 10 Jan 2018 09:48:54 -0500 Subject: [PATCH 23/84] zebra: Move `ip route ...` generation to vrf control Move the code that generates the 'show run' output for 'ip route' to be controlled by the vrf config generation code. Since it really belongs there. Signed-off-by: Donald Sharp --- zebra/rib.h | 2 + zebra/zebra_vrf.c | 15 +++-- zebra/zebra_vty.c | 160 +++++++++++++++++++++++----------------------- 3 files changed, 91 insertions(+), 86 deletions(-) diff --git a/zebra/rib.h b/zebra/rib.h index 6e3a85c1d1..664afd01b8 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -440,6 +440,8 @@ DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason), extern void zebra_vty_init(void); +extern int static_config(struct vty *vty, struct zebra_vrf *zvrf, + afi_t afi, safi_t safi, const char *cmd); extern pid_t pid; #endif /*_ZEBRA_RIB_H */ diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index ae8cb3450e..95426683a8 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -476,13 +476,18 @@ static int vrf_config_write(struct vty *vty) if (!zvrf) continue; - if (vrf->vrf_id == VRF_DEFAULT) - continue; + if (vrf->vrf_id != VRF_DEFAULT) + vty_out(vty, "vrf %s\n", zvrf_name(zvrf)); - vty_out(vty, "vrf %s\n", zvrf_name(zvrf)); - if (zvrf->l3vni) + static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route"); + static_config(vty, zvrf, AFI_IP, SAFI_MULTICAST, "ip mroute"); + static_config(vty, zvrf, AFI_IP6, SAFI_UNICAST, "ipv6 route"); + + if (vrf->vrf_id != VRF_DEFAULT && zvrf->l3vni) vty_out(vty, " vni %u\n", zvrf->l3vni); - vty_out(vty, "!\n"); + + if (vrf->vrf_id != VRF_DEFAULT) + vty_out(vty, "!\n"); } return 0; } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index a9f95c1028..bace9314d5 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1775,97 +1775,98 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, } /* Write static route configuration. */ -static int static_config(struct vty *vty, afi_t afi, safi_t safi, - const char *cmd) +int static_config(struct vty *vty, struct zebra_vrf *zvrf, + afi_t afi, safi_t safi, const char *cmd) { + char spacing[100]; struct route_node *rn; struct static_route *si; struct route_table *stable; - struct vrf *vrf; - struct zebra_vrf *zvrf; char buf[SRCDEST2STR_BUFFER]; int write = 0; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - if (!(zvrf = vrf->info)) - continue; - if ((stable = zvrf->stable[afi][safi]) == NULL) - continue; + if ((stable = zvrf->stable[afi][safi]) == NULL) + return write; - for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) - for (si = rn->info; si; si = si->next) { - vty_out(vty, "%s %s", cmd, - srcdest_rnode2str(rn, buf, sizeof buf)); + sprintf(spacing, "%s%s", + (zvrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ", + cmd); - switch (si->type) { - case STATIC_IPV4_GATEWAY: - vty_out(vty, " %s", - inet_ntoa(si->addr.ipv4)); + for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) + for (si = rn->info; si; si = si->next) { + vty_out(vty, "%s %s", spacing, + srcdest_rnode2str(rn, buf, sizeof buf)); + + switch (si->type) { + case STATIC_IPV4_GATEWAY: + vty_out(vty, " %s", + inet_ntoa(si->addr.ipv4)); + break; + case STATIC_IPV6_GATEWAY: + vty_out(vty, " %s", + inet_ntop(AF_INET6, + &si->addr.ipv6, buf, + sizeof buf)); + break; + case STATIC_IFNAME: + vty_out(vty, " %s", si->ifname); + break; + case STATIC_BLACKHOLE: + switch (si->bh_type) { + case STATIC_BLACKHOLE_DROP: + vty_out(vty, " blackhole"); break; - case STATIC_IPV6_GATEWAY: - vty_out(vty, " %s", - inet_ntop(AF_INET6, - &si->addr.ipv6, buf, - sizeof buf)); + case STATIC_BLACKHOLE_NULL: + vty_out(vty, " Null0"); break; - case STATIC_IFNAME: - vty_out(vty, " %s", si->ifname); - break; - case STATIC_BLACKHOLE: - switch (si->bh_type) { - case STATIC_BLACKHOLE_DROP: - vty_out(vty, " blackhole"); - break; - case STATIC_BLACKHOLE_NULL: - vty_out(vty, " Null0"); - break; - case STATIC_BLACKHOLE_REJECT: - vty_out(vty, " reject"); - break; - } - break; - case STATIC_IPV4_GATEWAY_IFNAME: - vty_out(vty, " %s %s", - inet_ntop(AF_INET, - &si->addr.ipv4, buf, - sizeof buf), - si->ifname); - break; - case STATIC_IPV6_GATEWAY_IFNAME: - vty_out(vty, " %s %s", - inet_ntop(AF_INET6, - &si->addr.ipv6, buf, - sizeof buf), - si->ifname); + case STATIC_BLACKHOLE_REJECT: + vty_out(vty, " reject"); break; } - - if (si->tag) - vty_out(vty, " tag %" ROUTE_TAG_PRI, - si->tag); - - if (si->distance - != ZEBRA_STATIC_DISTANCE_DEFAULT) - vty_out(vty, " %d", si->distance); - - if (si->vrf_id != VRF_DEFAULT) - vty_out(vty, " vrf %s", - zvrf_name(zvrf)); - - /* Label information */ - if (si->snh_label.num_labels) - vty_out(vty, " label %s", - mpls_label2str( - si->snh_label - .num_labels, - si->snh_label.label, - buf, sizeof buf, 0)); - - vty_out(vty, "\n"); - - write = 1; + break; + case STATIC_IPV4_GATEWAY_IFNAME: + vty_out(vty, " %s %s", + inet_ntop(AF_INET, + &si->addr.ipv4, buf, + sizeof buf), + si->ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + vty_out(vty, " %s %s", + inet_ntop(AF_INET6, + &si->addr.ipv6, buf, + sizeof buf), + si->ifname); + break; } - } + + if (si->tag) + vty_out(vty, " tag %" ROUTE_TAG_PRI, + si->tag); + + if (si->distance + != ZEBRA_STATIC_DISTANCE_DEFAULT) + vty_out(vty, " %d", si->distance); + + if (si->nh_vrf_id != si->vrf_id) { + struct vrf *vrf; + + vrf = vrf_lookup_by_id(si->nh_vrf_id); + vty_out(vty, " nexthop-vrf %s", + (vrf) ? vrf->name : "Unknown"); + } + + /* Label information */ + if (si->snh_label.num_labels) + vty_out(vty, " label %s", + mpls_label2str(si->snh_label.num_labels, + si->snh_label.label, + buf, sizeof buf, 0)); + + vty_out(vty, "\n"); + + write = 1; + } return write; } @@ -2706,11 +2707,8 @@ static int zebra_ip_config(struct vty *vty) { int write = 0; - write += static_config(vty, AFI_IP, SAFI_UNICAST, "ip route"); - write += static_config(vty, AFI_IP, SAFI_MULTICAST, "ip mroute"); - write += static_config(vty, AFI_IP6, SAFI_UNICAST, "ipv6 route"); - write += zebra_import_table_config(vty); + return write; } From 5e2105220428ca5ba9e80d9810a5ba32c4b18466 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 11 Jan 2018 11:47:04 -0500 Subject: [PATCH 24/84] zebra: Encode the ifindex over netlink In order for routes to be leaked the ifindex must be sent down into the kernel over the netlink protocol. So send it( we always figure it out ) when we add the route. Signed-off-by: Donald Sharp --- zebra/rt_netlink.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 384656a573..1092327fe9 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -963,10 +963,17 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, routedesc, inet6_ntoa(nexthop->gate.ipv6), label_buf, nexthop->ifindex); } - if (nexthop->type == NEXTHOP_TYPE_IFINDEX - || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { + + /* + * We have the ifindex so we should always send it + * This is especially useful if we are doing route + * leaking. + */ + if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex); + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { if (cmd == RTM_NEWROUTE) { if (nexthop->rmap_src.ipv4.s_addr) addattr_l(nlmsg, req_size, RTA_PREFSRC, @@ -984,8 +991,6 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, } if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { - addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex); - if (cmd == RTM_NEWROUTE) { if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) addattr_l(nlmsg, req_size, RTA_PREFSRC, @@ -1164,11 +1169,18 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, routedesc, inet6_ntoa(nexthop->gate.ipv6), label_buf, nexthop->ifindex); } + + /* + * We have figured out the ifindex so we should always send it + * This is especially useful if we are doing route + * leaking. + */ + if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) + rtnh->rtnh_ifindex = nexthop->ifindex; + /* ifindex */ if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFINDEX) { - rtnh->rtnh_ifindex = nexthop->ifindex; - if (nexthop->rmap_src.ipv4.s_addr) *src = &nexthop->rmap_src; else if (nexthop->src.ipv4.s_addr) @@ -1180,8 +1192,6 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, "nexthop via if %u", routedesc, nexthop->ifindex); } else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { - rtnh->rtnh_ifindex = nexthop->ifindex; - if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "netlink_route_multipath() (%s): " From 5bdd34db693867fbfd80d2fe3fc4bc056cc02b0f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 11 Jan 2018 11:51:46 -0500 Subject: [PATCH 25/84] zebra: Allow static non interface based routes to leak Allow this to work: vrf DONNA ip route 4.3.2.1/32 192.168.1.5 nexthop-vrf EVA The static route code was not properly telling the nexthop resolution code what vrf to use. Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 4 ++-- zebra/zebra_routemap.c | 2 +- zebra/zebra_static.c | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index fd1b273c8e..16dafa6b89 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -397,7 +397,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (set) { UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE); - zebra_deregister_rnh_static_nexthops(re->vrf_id, + zebra_deregister_rnh_static_nexthops(re->nh_vrf_id, nexthop->resolved, top); nexthops_free(nexthop->resolved); nexthop->resolved = NULL; @@ -904,7 +904,7 @@ static unsigned nexthop_active_check(struct route_node *rn, memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr)); /* It'll get set if required inside */ - ret = zebra_route_map_check(family, re->type, p, nexthop, re->vrf_id, + ret = zebra_route_map_check(family, re->type, p, nexthop, re->nh_vrf_id, re->tag); if (ret == RMAP_DENYMATCH) { if (IS_ZEBRA_DEBUG_RIB) { diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 61af60b5da..89cb2fc488 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -1329,7 +1329,7 @@ route_map_result_t zebra_nht_route_map_check(int family, int client_proto, struct nh_rmap_obj nh_obj; nh_obj.nexthop = nexthop; - nh_obj.vrf_id = re->vrf_id; + nh_obj.vrf_id = re->nh_vrf_id; nh_obj.source_protocol = re->type; nh_obj.metric = re->metric; nh_obj.tag = re->tag; diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index 3423518bba..fa5f0d9c48 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -91,7 +91,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.family = AF_INET; nh_p.prefixlen = IPV4_MAX_BITLEN; nh_p.u.prefix4 = si->addr.ipv4; - zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); + zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); break; case STATIC_IPV4_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv4_ifindex_add( @@ -111,7 +111,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.family = AF_INET6; nh_p.prefixlen = IPV6_MAX_BITLEN; nh_p.u.prefix6 = si->addr.ipv6; - zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); + zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); break; case STATIC_IPV6_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv6_ifindex_add( @@ -141,7 +141,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, */ if (si->type == STATIC_IPV4_GATEWAY || si->type == STATIC_IPV6_GATEWAY) - zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, + zebra_evaluate_rnh(si->nh_vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p); else rib_queue_add(rn); @@ -170,7 +170,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.family = AF_INET; nh_p.prefixlen = IPV4_MAX_BITLEN; nh_p.u.prefix4 = si->addr.ipv4; - zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); + zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); break; case STATIC_IPV4_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv4_ifindex_add( @@ -190,7 +190,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.family = AF_INET6; nh_p.prefixlen = IPV6_MAX_BITLEN; nh_p.u.prefix6 = si->addr.ipv6; - zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); + zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); break; case STATIC_IPV6_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv6_ifindex_add( @@ -222,7 +222,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, if (si->type == STATIC_IPV4_GATEWAY || si->type == STATIC_IPV6_GATEWAY) { rib_addnode(rn, re, 0); - zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, + zebra_evaluate_rnh(si->nh_vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p); } else rib_addnode(rn, re, 1); From 61408536df768ec97b235b463453b64f4e813369 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 11 Jan 2018 12:20:50 -0500 Subject: [PATCH 26/84] zebra: Add ability for default vrf to route-leak Allow the end user to specify static routes that leak across vrf's in the default vrf. Signed-off-by: Donald Sharp --- zebra/zebra_vty.c | 114 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 98 insertions(+), 16 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index bace9314d5..5df846354e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -449,6 +449,7 @@ DEFPY(ip_route_address_interface, |(1-255)$distance \ |vrf NAME \ |label WORD \ + |nexthop-vrf NAME \ }]", NO_STR IP_STR "Establish static routes\n" @@ -462,16 +463,36 @@ DEFPY(ip_route_address_interface, "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR) + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) { + struct zebra_vrf *zvrf; + struct zebra_vrf *nh_zvrf; + const char *flag = NULL; if (ifname && !strncasecmp(ifname, "Null0", 5)) { flag = "Null0"; ifname = NULL; } - return zebra_static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix, - mask_str, NULL, gate_str, ifname, flag, - tag_str, distance_str, vrf, label); + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + zvrf = zebra_vrf_lookup_by_name(vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP, SAFI_UNICAST, no, prefix, + mask_str, NULL, gate_str, ifname, flag, + tag_str, distance_str, label); } DEFPY(ip_route_address_interface_vrf, @@ -533,6 +554,7 @@ DEFPY(ip_route, |(1-255)$distance \ |vrf NAME \ |label WORD \ + |nexthop-vrf NAME \ }]", NO_STR IP_STR "Establish static routes\n" @@ -545,16 +567,36 @@ DEFPY(ip_route, "Tag value\n" "Distance value for this route\n" VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR) + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) { + struct zebra_vrf *zvrf; + struct zebra_vrf *nh_zvrf; const char *flag = NULL; + if (ifname && !strncasecmp(ifname, "Null0", 5)) { flag = "Null0"; ifname = NULL; } - return zebra_static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix, - mask_str, NULL, gate_str, ifname, flag, - tag_str, distance_str, vrf, label); + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + zvrf = zebra_vrf_lookup_by_name(vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP, SAFI_UNICAST, no, prefix, + mask_str, NULL, gate_str, ifname, flag, + tag_str, distance_str, label); } DEFPY(ip_route_vrf, @@ -1942,6 +1984,7 @@ DEFPY(ipv6_route_address_interface, |(1-255)$distance \ |vrf NAME \ |label WORD \ + |nexthop-vrf NAME \ }]", NO_STR IPV6_STR @@ -1955,11 +1998,30 @@ DEFPY(ipv6_route_address_interface, "Tag value\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR) + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) { - return zebra_static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str, - NULL, from_str, gate_str, ifname, NULL, - tag_str, distance_str, vrf, label); + struct zebra_vrf *zvrf; + struct zebra_vrf *nh_zvrf; + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + zvrf = zebra_vrf_lookup_by_name(vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP6, SAFI_UNICAST, no, prefix_str, + NULL, from_str, gate_str, ifname, NULL, + tag_str, distance_str, label); } DEFPY(ipv6_route_address_interface_vrf, @@ -2013,6 +2075,7 @@ DEFPY(ipv6_route, |(1-255)$distance \ |vrf NAME \ |label WORD \ + |nexthop-vrf NAME \ }]", NO_STR IPV6_STR @@ -2026,11 +2089,30 @@ DEFPY(ipv6_route, "Tag value\n" "Distance value for this prefix\n" VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR) + MPLS_LABEL_HELPSTR + VRF_CMD_HELP_STR) { - return zebra_static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str, - NULL, from_str, gate_str, ifname, NULL, - tag_str, distance_str, vrf, label); + struct zebra_vrf *zvrf; + struct zebra_vrf *nh_zvrf; + + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + zvrf = zebra_vrf_lookup_by_name(vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, + AFI_IP6, SAFI_UNICAST, no, prefix_str, + NULL, from_str, gate_str, ifname, NULL, + tag_str, distance_str, label); } DEFPY(ipv6_route_vrf, From c4368918e4a6ff93364c2160d7da3197e86a81b6 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Fri, 12 Jan 2018 15:31:16 +0000 Subject: [PATCH 27/84] BGP "allowas-in" should accept AS paths with "local-as" Signed-off-by: Daniel Walton For issue #1548 --- bgpd/bgp_route.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 81b605ad79..d45f780f1b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2711,7 +2711,9 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* AS path local-as loop check. */ if (peer->change_local_as) { - if (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) + if (peer->allowas_in[afi][safi]) + aspath_loop_count = peer->allowas_in[afi][safi]; + else if (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) aspath_loop_count = 1; if (aspath_loop_check(attr->aspath, peer->change_local_as) From 193a5a9579f3245fd3ca14c491bb1a091cd67814 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 12 Jan 2018 12:35:19 -0500 Subject: [PATCH 28/84] vtysh: add ability to output to file Add ability to set file destination for all vtysh output, with the exception of tab-complete and similar meta output. This is useful for inline recording of some information without exiting the shell. Signed-off-by: Quentin Young --- vtysh/vtysh.c | 135 ++++++++++++++++++++++++++++++--------------- vtysh/vtysh.h | 1 + vtysh/vtysh_main.c | 2 + 3 files changed, 93 insertions(+), 45 deletions(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 76343ded60..9ec1ade0e3 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -46,6 +46,9 @@ DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy") +/* Destination for vtysh output */ +FILE *outputfile; + /* Struct VTY. */ struct vty *vty; @@ -375,21 +378,21 @@ static int vtysh_execute_func(const char *line, int pager) fprintf(stdout, "%% Command incomplete.\n"); break; case CMD_SUCCESS_DAEMON: { - /* FIXME: Don't open pager for exit commands. popen() causes - * problems - * if exited from vtysh at all. This hack shouldn't cause any - * problem - * but is really ugly. */ - if (pager && vtysh_pager_name + /* + * FIXME: Don't open pager for exit commands. popen() causes + * problems if exited from vtysh at all. This hack shouldn't + * cause any problem but is really ugly. + */ + fp = outputfile; + if (pager && vtysh_pager_name && outputfile == stdout && (strncmp(line, "exit", 4) != 0)) { fp = popen(vtysh_pager_name, "w"); if (fp == NULL) { perror("popen failed for pager"); - fp = stdout; + fp = outputfile; } else closepager = 1; - } else - fp = stdout; + } if (!strcmp(cmd->string, "configure terminal")) { for (i = 0; i < array_size(vtysh_client); i++) { @@ -405,7 +408,7 @@ static int vtysh_execute_func(const char *line, int pager) if (vline == NULL) { if (pager && vtysh_pager_name && fp - && closepager) { + && fp != outputfile && closepager) { if (pclose(fp) == -1) { perror("pclose failed for pager"); } @@ -455,7 +458,7 @@ static int vtysh_execute_func(const char *line, int pager) (*cmd->func)(cmd, vty, 0, NULL); } } - if (pager && vtysh_pager_name && fp && closepager) { + if (pager && vtysh_pager_name && fp && closepager && fp != outputfile) { if (pclose(fp) == -1) { perror("pclose failed for pager"); } @@ -537,19 +540,19 @@ int vtysh_mark_file(const char *filename) switch (vty->node) { case LDP_IPV4_IFACE_NODE: if (strncmp(vty_buf_copy, " ", 3)) { - fprintf(stdout, " end\n"); + fprintf(outputfile, " end\n"); vty->node = LDP_IPV4_NODE; } break; case LDP_IPV6_IFACE_NODE: if (strncmp(vty_buf_copy, " ", 3)) { - fprintf(stdout, " end\n"); + fprintf(outputfile, " end\n"); vty->node = LDP_IPV6_NODE; } break; case LDP_PSEUDOWIRE_NODE: if (strncmp(vty_buf_copy, " ", 2)) { - fprintf(stdout, " end\n"); + fprintf(outputfile, " end\n"); vty->node = LDP_L2VPN_NODE; } break; @@ -558,7 +561,7 @@ int vtysh_mark_file(const char *filename) } if (vty_buf_trimmed[0] == '!' || vty_buf_trimmed[0] == '#') { - fprintf(stdout, "%s", vty->buf); + fprintf(outputfile, "%s", vty->buf); continue; } @@ -566,7 +569,7 @@ int vtysh_mark_file(const char *filename) vline = cmd_make_strvec(vty->buf); if (vline == NULL) { - fprintf(stdout, "%s", vty->buf); + fprintf(outputfile, "%s", vty->buf); continue; } @@ -609,15 +612,15 @@ int vtysh_mark_file(const char *filename) || prev_node == BGP_IPV6M_NODE || prev_node == BGP_EVPN_NODE) && (tried == 1)) { - fprintf(stdout, "exit-address-family\n"); + fprintf(outputfile, "exit-address-family\n"); } else if ((prev_node == BGP_EVPN_VNI_NODE) && (tried == 1)) { - fprintf(stdout, "exit-vni\n"); + fprintf(outputfile, "exit-vni\n"); } else if ((prev_node == KEYCHAIN_KEY_NODE) && (tried == 1)) { - fprintf(stdout, "exit\n"); + fprintf(outputfile, "exit\n"); } else if (tried) { - fprintf(stdout, "end\n"); + fprintf(outputfile, "end\n"); } } /* If command didn't succeed in any node, continue with return @@ -667,12 +670,12 @@ int vtysh_mark_file(const char *filename) u_int i; int cmd_stat = CMD_SUCCESS; - fprintf(stdout, "%s", vty->buf); + fprintf(outputfile, "%s", vty->buf); for (i = 0; i < array_size(vtysh_client); i++) { if (cmd->daemon & vtysh_client[i].flag) { cmd_stat = vtysh_client_execute( &vtysh_client[i], vty->buf, - stdout); + outputfile); if (cmd_stat != CMD_SUCCESS) break; } @@ -686,7 +689,7 @@ int vtysh_mark_file(const char *filename) } } /* This is the end */ - fprintf(stdout, "\nend\n"); + fprintf(outputfile, "\nend\n"); vty_close(vty); XFREE(MTYPE_VTYSH_CMD, vty_buf_copy); @@ -749,7 +752,7 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp) if (cmd->daemon & vtysh_client[i].flag) { cmd_stat = vtysh_client_execute( &vtysh_client[i], vty->buf, - stdout); + outputfile); /* * CMD_WARNING - Can mean that the * command was @@ -1854,7 +1857,7 @@ DEFUN (vtysh_show_thread, fprintf(stdout, "Thread statistics for %s:\n", vtysh_client[i].name); ret = vtysh_client_execute(&vtysh_client[i], line, - stdout); + outputfile); fprintf(stdout, "\n"); } return ret; @@ -1875,7 +1878,7 @@ DEFUN (vtysh_show_work_queues, fprintf(stdout, "Work queue statistics for %s:\n", vtysh_client[i].name); ret = vtysh_client_execute(&vtysh_client[i], line, - stdout); + outputfile); fprintf(stdout, "\n"); } @@ -1905,7 +1908,7 @@ DEFUN (vtysh_show_work_queues_daemon, } ret = vtysh_client_execute(&vtysh_client[i], "show work-queues\n", - stdout); + outputfile); return ret; } @@ -1932,9 +1935,9 @@ static int show_per_daemon(const char *line, const char *headline) for (i = 0; i < array_size(vtysh_client); i++) if (vtysh_client[i].fd >= 0) { - fprintf(stdout, headline, vtysh_client[i].name); + fprintf(outputfile, headline, vtysh_client[i].name); ret = vtysh_client_execute(&vtysh_client[i], line, - stdout); + outputfile); fprintf(stdout, "\n"); } @@ -2226,20 +2229,19 @@ DEFUN (vtysh_write_terminal, { u_int i; char line[] = "do write terminal\n"; - FILE *fp = NULL; + FILE *fp = outputfile; - if (vtysh_pager_name) { + if (fp == stdout && vtysh_pager_name) { fp = popen(vtysh_pager_name, "w"); if (fp == NULL) { perror("popen"); exit(1); } - } else - fp = stdout; + } - vty_out(vty, "Building configuration...\n"); - vty_out(vty, "\nCurrent configuration:\n"); - vty_out(vty, "!\n"); + fprintf(outputfile, "Building configuration...\n"); + fprintf(outputfile, "\nCurrent configuration:\n"); + fprintf(outputfile, "!\n"); for (i = 0; i < array_size(vtysh_client); i++) if ((argc < 3) @@ -2251,7 +2253,7 @@ DEFUN (vtysh_write_terminal, vtysh_config_dump(fp); - if (vtysh_pager_name && fp) { + if (vtysh_pager_name && fp && fp != outputfile) { fflush(fp); if (pclose(fp) == -1) { perror("pclose"); @@ -2260,7 +2262,7 @@ DEFUN (vtysh_write_terminal, fp = NULL; } - vty_out(vty, "end\n"); + fprintf(outputfile, "end\n"); return CMD_SUCCESS; } @@ -2429,7 +2431,7 @@ DEFUN (vtysh_write_memory, char line[] = "do write memory\n"; u_int i; - fprintf(stdout, + fprintf(outputfile, "Note: this version of vtysh never writes vtysh.conf\n"); /* If integrated frr.conf explicitely set. */ @@ -2441,7 +2443,7 @@ DEFUN (vtysh_write_memory, if (i < array_size(vtysh_client) && vtysh_client[i].fd != -1) ret = vtysh_client_execute(&vtysh_client[i], "do write integrated", - stdout); + outputfile); if (ret != CMD_SUCCESS) { printf("\nWarning: attempting direct configuration write without " @@ -2452,10 +2454,10 @@ DEFUN (vtysh_write_memory, return ret; } - fprintf(stdout, "Building Configuration...\n"); + fprintf(outputfile, "Building Configuration...\n"); for (i = 0; i < array_size(vtysh_client); i++) - ret = vtysh_client_execute(&vtysh_client[i], line, stdout); + ret = vtysh_client_execute(&vtysh_client[i], line, outputfile); return ret; } @@ -2484,7 +2486,7 @@ DEFUN (vtysh_terminal_length, lines = strtol(argv[idx_number]->arg, &endptr, 10); if (lines < 0 || lines > 512 || *endptr != '\0') { - vty_out(vty, "length is malformed\n"); + fprintf(outputfile, "length is malformed\n"); return CMD_WARNING; } @@ -2527,8 +2529,8 @@ DEFUN (vtysh_show_daemons, for (i = 0; i < array_size(vtysh_client); i++) if (vtysh_client[i].fd >= 0) - vty_out(vty, " %s", vtysh_client[i].name); - vty_out(vty, "\n"); + fprintf(outputfile, " %s", vtysh_client[i].name); + fprintf(outputfile, "\n"); return CMD_SUCCESS; } @@ -2703,6 +2705,38 @@ DEFUN (config_list, return cmd_list_cmds(vty, argc == 2); } +DEFUN (vtysh_output_file, + vtysh_output_file_cmd, + "output file FILE", + "Direct vtysh output to file\n" + "Direct vtysh output to file\n" + "Path to dump output to\n") +{ + const char *path = argv[argc - 1]->arg; + outputfile = fopen(path, "a"); + if (!outputfile) { + fprintf(stdout, "Failed to open file '%s': %s\n", path, + safe_strerror(errno)); + outputfile = stdout; + } + return CMD_SUCCESS; +} + +DEFUN (no_vtysh_output_file, + no_vtysh_output_file_cmd, + "no output file [FILE]", + NO_STR + "Direct vtysh output to file\n" + "Direct vtysh output to file\n" + "Path to dump output to\n") +{ + if (outputfile != stdout) { + fclose(outputfile); + outputfile = stdout; + } + return CMD_SUCCESS; +} + DEFUN(find, find_cmd, "find COMMAND...", @@ -2736,6 +2770,8 @@ static void vtysh_install_default(enum node_type node) { install_element(node, &config_list_cmd); install_element(node, &find_cmd); + install_element(node, &vtysh_output_file_cmd); + install_element(node, &no_vtysh_output_file_cmd); } /* Making connection to protocol daemon. */ @@ -2964,6 +3000,12 @@ static const struct cmd_variable_handler vtysh_var_handler[] = { .completions = vtysh_autocomplete}, {.completions = NULL}}; +void vtysh_uninit() +{ + if (outputfile != stdout) + fclose(outputfile); +} + void vtysh_init_vty(void) { /* Make vty structure. */ @@ -2971,6 +3013,9 @@ void vtysh_init_vty(void) vty->type = VTY_SHELL; vty->node = VIEW_NODE; + /* set default output */ + outputfile = stdout; + /* Initialize commands. */ cmd_init(0); cmd_variable_handler_register(vtysh_var_handler); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index c584d7a905..ab13182094 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -63,6 +63,7 @@ extern char frr_config[]; extern char vtydir[]; void vtysh_init_vty(void); +void vtysh_uninit(void); void vtysh_init_cmd(void); extern int vtysh_connect_all(const char *optional_daemon_name); void vtysh_readline_init(void); diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 57042f8e62..a4985c423c 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -644,6 +644,8 @@ int main(int argc, char **argv, char **env) while (vtysh_rl_gets()) vtysh_execute(line_read); + vtysh_uninit(); + history_truncate_file(history_file, 1000); printf("\n"); From a174be631a14e0271fde6858fcb4d7ab55165014 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 12 Jan 2018 14:57:57 -0500 Subject: [PATCH 29/84] bgpd: disallow invalid config at cli layer Remove the ability to attempt to configure a couple of options on directly connected neighbors that don't make sense for them, as well as the soft error handling code. Signed-off-by: Quentin Young --- bgpd/bgp_vty.c | 39 ++++++++------------------------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 50e5bcf096..ac2b494569 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3388,18 +3388,6 @@ static int peer_flag_modify_vty(struct vty *vty, const char *ip_str, if (!peer) return CMD_WARNING_CONFIG_FAILED; - /* - * If 'neighbor ', then this is for directly connected peers, - * we should not accept disable-connected-check. - */ - if (peer->conf_if && (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)) { - vty_out(vty, - "%s is directly connected peer, cannot accept disable-" - "connected-check\n", - ip_str); - return CMD_WARNING_CONFIG_FAILED; - } - if (!set && flag == PEER_FLAG_SHUTDOWN) peer_tx_shutdown_message_unset(peer); @@ -4490,9 +4478,9 @@ DEFUN (no_neighbor_ebgp_multihop, /* disable-connected-check */ DEFUN (neighbor_disable_connected_check, neighbor_disable_connected_check_cmd, - "neighbor ", + "neighbor ", NEIGHBOR_STR - NEIGHBOR_ADDR_STR2 + NEIGHBOR_ADDR_STR "one-hop away EBGP peer using loopback address\n" "Enforce EBGP neighbors perform multihop\n") { @@ -4503,10 +4491,10 @@ DEFUN (neighbor_disable_connected_check, DEFUN (no_neighbor_disable_connected_check, no_neighbor_disable_connected_check_cmd, - "no neighbor ", + "no neighbor ", NO_STR NEIGHBOR_STR - NEIGHBOR_ADDR_STR2 + NEIGHBOR_ADDR_STR "one-hop away EBGP peer using loopback address\n" "Enforce EBGP neighbors perform multihop\n") { @@ -5945,9 +5933,9 @@ ALIAS_HIDDEN( DEFUN (neighbor_ttl_security, neighbor_ttl_security_cmd, - "neighbor ttl-security hops (1-254)", + "neighbor ttl-security hops (1-254)", NEIGHBOR_STR - NEIGHBOR_ADDR_STR2 + NEIGHBOR_ADDR_STR "BGP ttl-security parameters\n" "Specify the maximum number of hops to the BGP peer\n" "Number of hops to BGP peer\n") @@ -5963,26 +5951,15 @@ DEFUN (neighbor_ttl_security, gtsm_hops = strtoul(argv[idx_number]->arg, NULL, 10); - /* - * If 'neighbor swpX', then this is for directly connected peers, - * we should not accept a ttl-security hops value greater than 1. - */ - if (peer->conf_if && (gtsm_hops > 1)) { - vty_out(vty, - "%s is directly connected peer, hops cannot exceed 1\n", - argv[idx_peer]->arg); - return CMD_WARNING_CONFIG_FAILED; - } - return bgp_vty_return(vty, peer_ttl_security_hops_set(peer, gtsm_hops)); } DEFUN (no_neighbor_ttl_security, no_neighbor_ttl_security_cmd, - "no neighbor ttl-security hops (1-254)", + "no neighbor ttl-security hops (1-254)", NO_STR NEIGHBOR_STR - NEIGHBOR_ADDR_STR2 + NEIGHBOR_ADDR_STR "BGP ttl-security parameters\n" "Specify the maximum number of hops to the BGP peer\n" "Number of hops to BGP peer\n") From f26845f9a63e1be1c87632281fb30a67752886f9 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Thu, 11 Jan 2018 12:50:08 -0500 Subject: [PATCH 30/84] bgpd: add neighbor autoshutdown Adds ability to specify that peers should be administratively shutdown when first configured. Signed-off-by: Quentin Young --- bgpd/bgp_vty.c | 17 ++++++++++++++++- bgpd/bgpd.c | 9 ++++++++- bgpd/bgpd.h | 3 +++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 50e5bcf096..443f299ab1 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2677,6 +2677,19 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, return bgp_vty_return(vty, ret); } +DEFUN (bgp_default_shutdown, + bgp_default_shutdown_cmd, + "[no] bgp default shutdown", + NO_STR + BGP_STR + "Configure BGP defaults\n" + "Do not automatically activate peers upon configuration\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->autoshutdown = !strmatch(argv[0]->text, "no"); + return CMD_SUCCESS; +} + DEFUN (neighbor_remote_as, neighbor_remote_as_cmd, "neighbor remote-as <(1-4294967295)|internal|external>", @@ -3223,7 +3236,6 @@ DEFUN (no_neighbor_password, return bgp_vty_return(vty, ret); } - DEFUN (neighbor_activate, neighbor_activate_cmd, "neighbor activate", @@ -11555,6 +11567,9 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_listen_range_cmd); install_element(BGP_NODE, &no_bgp_listen_range_cmd); + /* "neighbors auto-shutdown" command */ + install_element(BGP_NODE, &bgp_default_shutdown_cmd); + /* "neighbor remote-as" commands. */ install_element(BGP_NODE, &neighbor_remote_as_cmd); install_element(BGP_NODE, &neighbor_interface_config_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 2e660c20eb..a471bbaa9d 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1497,8 +1497,11 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, peer_af_create(peer, afi, safi); } + /* auto shutdown if configured */ + if (bgp->autoshutdown) + peer_flag_set(peer, PEER_FLAG_SHUTDOWN); /* Set up peer's events and timers. */ - if (!active && peer_active(peer)) + else if (!active && peer_active(peer)) bgp_timer_set(peer); return peer; @@ -7140,6 +7143,10 @@ int bgp_config_write(struct vty *vty) vty_out(vty, " bgp default subgroup-pkt-queue-max %u\n", bgp->default_subgroup_pkt_queue_max); + /* BGP default autoshutdown neighbors */ + if (bgp->autoshutdown) + vty_out(vty, " bgp default auto-shutdown\n"); + /* BGP client-to-client reflection. */ if (bgp_flag_check(bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT)) vty_out(vty, " no bgp client-to-client reflection\n"); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 20b99c171e..1e2b4c8cd7 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -386,6 +386,9 @@ struct bgp { /* Actual coalesce time */ uint32_t coalesce_time; + /* Auto-shutdown new peers */ + bool autoshutdown; + u_int32_t addpath_tx_id; int addpath_tx_used[AFI_MAX][SAFI_MAX]; From b40c50627a20e96bc7d85abd4524fd8ca4e730a2 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Sun, 14 Jan 2018 15:42:06 -0500 Subject: [PATCH 31/84] bgpd: fix handling of nhp_ary when exporting vrf routes to zebra Signed-off-by: Lou Berger --- bgpd/rfapi/vnc_zebra.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c index f8b38468f5..e0e58e9559 100644 --- a/bgpd/rfapi/vnc_zebra.c +++ b/bgpd/rfapi/vnc_zebra.c @@ -385,6 +385,8 @@ static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count, struct zapi_route api; struct zapi_nexthop *api_nh; int i; + struct in_addr **nhp_ary4 = nhp_ary; + struct in6_addr **nhp_ary6 = nhp_ary; if (!nhp_count) { vnc_zlog_debug_verbose("%s: empty nexthop list, skipping", @@ -402,20 +404,16 @@ static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count, SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = MIN(nhp_count, multipath_num); for (i = 0; i < api.nexthop_num; i++) { - struct in_addr *nhp_ary4; - struct in6_addr *nhp_ary6; api_nh = &api.nexthops[i]; switch (p->family) { case AF_INET: - nhp_ary4 = nhp_ary; - memcpy(&api_nh->gate.ipv4, &nhp_ary4[i], + memcpy(&api_nh->gate.ipv4, nhp_ary4[i], sizeof(api_nh->gate.ipv4)); api_nh->type = NEXTHOP_TYPE_IPV4; break; case AF_INET6: - nhp_ary6 = nhp_ary; - memcpy(&api_nh->gate.ipv6, &nhp_ary6[i], + memcpy(&api_nh->gate.ipv6, nhp_ary6[i], sizeof(api_nh->gate.ipv6)); api_nh->type = NEXTHOP_TYPE_IPV6; break; From 43855e3d47c25704afb52d65fcf44e56f87c00c4 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Mon, 8 Jan 2018 16:53:53 -0800 Subject: [PATCH 32/84] ospf6d: Add protocol stats and show command Add OSPFv3 Protocol incoming/outgoing packets stats. r3# show ipv6 ospf6 interface traffic Interface HELLO DB-Desc LS-Req LS-Update LS-Ack Rx/Tx Rx/Tx Rx/Tx Rx/Tx Rx/Tx -------------------------------------------------------------------------------------------- swp1 3/4 2/2 0/2 8/6 3/2 swp2 3/4 2/2 0/1 7/3 2/0 swp3 0/4 0/0 0/0 0/0 0/0 Signed-off-by: Chirag Shah --- ospf6d/ospf6_interface.c | 99 ++++++++++++++++++++++++++++++++++++++++ ospf6d/ospf6_interface.h | 13 ++++++ ospf6d/ospf6_message.c | 32 ++++++++++++- 3 files changed, 142 insertions(+), 2 deletions(-) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 98f93b06e6..fc6c46c7e7 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -1008,6 +1008,103 @@ DEFUN (show_ipv6_ospf6_interface, return CMD_SUCCESS; } +static int ospf6_interface_show_traffic(struct vty *vty, + uint32_t vrf_id, + struct interface *intf_ifp, + int display_once) +{ + struct interface *ifp; + struct vrf *vrf = NULL; + struct ospf6_interface *oi = NULL; + + vrf = vrf_lookup_by_id(vrf_id); + + if (!display_once) { + vty_out(vty, "\n"); + vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s\n", + "Interface", " HELLO", " DB-Desc", " LS-Req", + " LS-Update", " LS-Ack"); + vty_out(vty, "%-10s%-18s%-18s%-17s%-17s%-17s\n", "", + " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx"); + vty_out(vty, + "--------------------------------------------------------------------------------------------\n"); + } + + if (intf_ifp == NULL) { + FOR_ALL_INTERFACES (vrf, ifp) { + if (ifp->info) + oi = (struct ospf6_interface *)ifp->info; + else + continue; + + vty_out(vty, + "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n", + oi->interface->name, oi->hello_in, + oi->hello_out, + oi->db_desc_in, oi->db_desc_out, + oi->ls_req_in, oi->ls_req_out, + oi->ls_upd_in, oi->ls_upd_out, + oi->ls_ack_in, oi->ls_ack_out); + } + } else { + oi = intf_ifp->info; + if (oi == NULL) + return CMD_WARNING; + + vty_out(vty, + "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n", + oi->interface->name, oi->hello_in, + oi->hello_out, + oi->db_desc_in, oi->db_desc_out, + oi->ls_req_in, oi->ls_req_out, + oi->ls_upd_in, oi->ls_upd_out, + oi->ls_ack_in, oi->ls_ack_out); + } + + return CMD_SUCCESS; +} + +/* show interface */ +DEFUN (show_ipv6_ospf6_interface_traffic, + show_ipv6_ospf6_interface_traffic_cmd, + "show ipv6 ospf6 interface traffic [IFNAME]", + SHOW_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + "Protocol Packet counters\n" + IFNAME_STR) +{ + int idx_ifname = 0; + int display_once = 0; + char *intf_name = NULL; + struct interface *ifp = NULL; + + if (argv_find(argv, argc, "IFNAME", &idx_ifname)) { + intf_name = argv[idx_ifname]->arg; + ifp = if_lookup_by_name(intf_name, VRF_DEFAULT); + if (ifp == NULL) { + vty_out(vty, + "No such Interface: %s\n", + intf_name); + return CMD_WARNING; + } + if (ifp->info == NULL) { + vty_out(vty, + " OSPF not enabled on this interface %s\n", + intf_name); + return 0; + } + } + + ospf6_interface_show_traffic(vty, VRF_DEFAULT, ifp, + display_once); + + + return CMD_SUCCESS; +} + + DEFUN (show_ipv6_ospf6_interface_ifname_prefix, show_ipv6_ospf6_interface_ifname_prefix_cmd, "show ipv6 ospf6 interface IFNAME prefix [] []", @@ -1841,6 +1938,8 @@ void ospf6_interface_init(void) install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd); install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd); + install_element(VIEW_NODE, + &show_ipv6_ospf6_interface_traffic_cmd); install_element(INTERFACE_NODE, &ipv6_ospf6_cost_cmd); install_element(INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd); diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 3844132366..b67d9a9f2e 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -117,6 +117,19 @@ struct ospf6_interface { /* BFD information */ void *bfd_info; + /* Statistics Fields */ + u_int32_t hello_in; + u_int32_t hello_out; + u_int32_t db_desc_in; + u_int32_t db_desc_out; + u_int32_t ls_req_in; + u_int32_t ls_req_out; + u_int32_t ls_upd_in; + u_int32_t ls_upd_out; + u_int32_t ls_ack_in; + u_int32_t ls_ack_out; + u_int32_t discarded; + QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(ospf6_interface) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 1307b374a5..d76438ea50 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -321,6 +321,8 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, backupseen++; } + oi->hello_in++; + /* Execute neighbor events */ thread_execute(master, hello_received, on, 0); if (twoway) @@ -776,6 +778,8 @@ static void ospf6_dbdesc_recv(struct in6_addr *src, struct in6_addr *dst, dbdesc->reserved2 = 0; } + oi->db_desc_in++; + if (ntohl(oh->router_id) < ntohl(ospf6->router_id)) ospf6_dbdesc_recv_master(oh, on); else if (ntohl(ospf6->router_id) < ntohl(oh->router_id)) @@ -811,6 +815,8 @@ static void ospf6_lsreq_recv(struct in6_addr *src, struct in6_addr *dst, return; } + oi->ls_req_in++; + /* Process each request */ for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header)); p + sizeof(struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END(oh); @@ -1370,6 +1376,8 @@ static void ospf6_lsupdate_recv(struct in6_addr *src, struct in6_addr *dst, lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh + sizeof(struct ospf6_header)); + oi->ls_upd_in++; + /* Process LSAs */ for (p = (char *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate)); p < OSPF6_MESSAGE_END(oh) @@ -1407,6 +1415,8 @@ static void ospf6_lsack_recv(struct in6_addr *src, struct in6_addr *dst, return; } + oi->ls_ack_in++; + for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header)); p + sizeof(struct ospf6_lsa_header) <= OSPF6_MESSAGE_END(oh); p += sizeof(struct ospf6_lsa_header)) { @@ -1777,6 +1787,8 @@ int ospf6_hello_send(struct thread *thread) oh->type = OSPF6_MESSAGE_TYPE_HELLO; oh->length = htons(p - sendbuf); + oi->hello_out++; + ospf6_send(oi->linklocal_addr, &allspfrouters6, oi, oh); return 0; } @@ -1852,6 +1864,8 @@ int ospf6_dbdesc_send(struct thread *thread) else dst = &on->linklocal_addr; + on->ospf6_if->db_desc_out++; + ospf6_send(on->ospf6_if->linklocal_addr, dst, on->ospf6_if, oh); return 0; @@ -1955,6 +1969,8 @@ int ospf6_lsreq_send(struct thread *thread) oh->type = OSPF6_MESSAGE_TYPE_LSREQ; oh->length = htons(p - sendbuf); + on->ospf6_if->ls_req_out++; + if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) ospf6_send(on->ospf6_if->linklocal_addr, &allspfrouters6, on->ospf6_if, oh); @@ -1979,6 +1995,8 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on, { if (on) { + on->ospf6_if->ls_upd_out++; + if ((on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) || (on->ospf6_if->state == OSPF6_INTERFACE_DR) || (on->ospf6_if->state == OSPF6_INTERFACE_BDR)) { @@ -1989,6 +2007,9 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on, &on->linklocal_addr, on->ospf6_if, oh); } } else if (oi) { + + oi->ls_upd_out++; + if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT) || (oi->state == OSPF6_INTERFACE_DR) || (oi->state == OSPF6_INTERFACE_BDR)) { @@ -2185,8 +2206,11 @@ int ospf6_lsupdate_send_interface(struct thread *thread) lsupdate->lsa_number = htonl(lsa_cnt); ospf6_send_lsupdate(NULL, oi, oh); - zlog_debug("%s: LSUpdate length %d", - __PRETTY_FUNCTION__, ntohs(oh->length)); + if (IS_OSPF6_DEBUG_MESSAGE( + OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) + zlog_debug("%s: LSUpdate length %d", + __PRETTY_FUNCTION__, + ntohs(oh->length)); memset(sendbuf, 0, iobuflen); oh = (struct ospf6_header *)sendbuf; @@ -2263,6 +2287,8 @@ int ospf6_lsack_send_neighbor(struct thread *thread) oh->type = OSPF6_MESSAGE_TYPE_LSACK; oh->length = htons(p - sendbuf); + on->ospf6_if->ls_ack_out++; + ospf6_send(on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); @@ -2288,6 +2314,8 @@ int ospf6_lsack_send_neighbor(struct thread *thread) oh->type = OSPF6_MESSAGE_TYPE_LSACK; oh->length = htons(p - sendbuf); + on->ospf6_if->ls_ack_out++; + ospf6_send(on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); } From 1406159faa6a617fe799ca61c1f4239445fab47a Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Mon, 15 Jan 2018 17:49:23 -0800 Subject: [PATCH 33/84] ospfd: Speed up show ip ospf [vrf all] route json Signed-off-by: Chirag Shah --- ospfd/ospf_vty.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 0541bfeee7..a1384eebdd 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -9496,9 +9496,9 @@ DEFUN (show_ip_ospf_route, } if (uj) { + /* Keep Non-pretty format */ vty_out(vty, "%s\n", - json_object_to_json_string_ext(json, - JSON_C_TO_STRING_PRETTY)); + json_object_to_json_string(json)); json_object_free(json); } @@ -9522,9 +9522,9 @@ DEFUN (show_ip_ospf_route, if (ospf) { ret = show_ip_ospf_route_common(vty, ospf, json, use_vrf); + /* Keep Non-pretty format */ if (uj) - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); + vty_out(vty, "%s\n", json_object_to_json_string(json)); } if (uj) From 42d745387a0b75f539b6ad45e32305199b59c53a Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 1 Dec 2017 14:44:32 -0500 Subject: [PATCH 34/84] lib: avoid crash when cancelling invalid rw job There are some observed instances where we end up trying to cancel a rw job based on a file descriptor that we don't have a reference on. The specific cancel function for rw jobs assumes it's called with a file descriptor that is valid within pollfds and will cause a segmentation fault by buffer overrun if this is not the case. Instead log it and move on. Since the fd does not exist this should patch over the buggy behavior and provide additional information to help in finding the root cause. Reviewed-by: Donald Sharp Signed-off-by: Quentin Young --- lib/thread.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/thread.c b/lib/thread.c index d26db88550..9d64663d9c 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -919,6 +919,8 @@ struct thread *funcname_thread_add_event(struct thread_master *m, */ static void thread_cancel_rw(struct thread_master *master, int fd, short state) { + bool found = false; + /* Cancel POLLHUP too just in case some bozo set it */ state |= POLLHUP; @@ -926,8 +928,18 @@ static void thread_cancel_rw(struct thread_master *master, int fd, short state) nfds_t i; for (i = 0; i < master->handler.pfdcount; i++) - if (master->handler.pfds[i].fd == fd) + if (master->handler.pfds[i].fd == fd) { + found = true; break; + } + + if (!found) { + zlog_debug( + "[!] Received cancellation request for nonexistent rw job"); + zlog_debug("[!] threadmaster: %s | fd: %d", + master->name ? master->name : "", fd); + return; + } /* NOT out event. */ master->handler.pfds[i].events &= ~(state); From 7dab10ce944919ba4588063ce3b5adc84fc78842 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Fri, 29 Dec 2017 21:01:07 -0800 Subject: [PATCH 35/84] ospfd: show ip ospf interface json output format Current json output does not differentiate start of interface objects. Adding "interfaces" keyword at the beginning of the interface list. This is useful when displaying vrf level output along with interface list. Ticket:CM-19115 Testing Done: show ip ospf vrf all interface json show ip ospf vrf all interface json show ip ospf interface json show ip ospf interface json Signed-off-by: Chirag Shah --- ospfd/ospf_vty.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index a1384eebdd..80758212c4 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3693,14 +3693,15 @@ static int show_ip_ospf_interface_common(struct vty *vty, struct ospf *ospf, { struct interface *ifp; struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id); - json_object *json_vrf = NULL; - json_object *json_interface_sub = NULL; + json_object *json_vrf = NULL, *json_intf_array = NULL; + json_object *json_interface_sub = NULL, *json_interface = NULL; if (use_json) { if (use_vrf) json_vrf = json_object_new_object(); else json_vrf = json; + json_intf_array = json_object_new_array(); } if (ospf->instance) { @@ -3714,21 +3715,29 @@ static int show_ip_ospf_interface_common(struct vty *vty, struct ospf *ospf, ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf); if (intf_name == NULL) { + if (use_json) + json_object_object_add(json_vrf, "interfaces", + json_intf_array); /* Show All Interfaces.*/ FOR_ALL_INTERFACES (vrf, ifp) { if (ospf_oi_count(ifp)) { - if (use_json) + if (use_json) { + json_interface = + json_object_new_object(); json_interface_sub = json_object_new_object(); - + } show_ip_ospf_interface_sub(vty, ospf, ifp, json_interface_sub, use_json); - if (use_json) + if (use_json) { + json_object_array_add(json_intf_array, + json_interface); json_object_object_add( - json_vrf, ifp->name, + json_interface, ifp->name, json_interface_sub); + } } } } else { @@ -3741,15 +3750,23 @@ static int show_ip_ospf_interface_common(struct vty *vty, struct ospf *ospf, else vty_out(vty, "No such interface name\n"); } else { - if (use_json) + if (use_json) { json_interface_sub = json_object_new_object(); + json_interface = json_object_new_object(); + json_object_object_add(json_vrf, "interfaces", + json_intf_array); + } show_ip_ospf_interface_sub( vty, ospf, ifp, json_interface_sub, use_json); - if (use_json) - json_object_object_add(json_vrf, ifp->name, + if (use_json) { + json_object_array_add(json_intf_array, + json_interface); + json_object_object_add(json_interface, + ifp->name, json_interface_sub); + } } } From 91437c67e684d04e8afd48c8ffe1812bb2ea0837 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Tue, 16 Jan 2018 15:44:14 -0500 Subject: [PATCH 36/84] frr: update README * Clarify that FRR implements as well as manages protocols * Move IS-IS out of "early support" * Add Babel - friends don't leave friends out of READMEs! * Add mention of further information Signed-off-by: Quentin Young --- README | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README b/README index bbad60087b..af14795a6a 100644 --- a/README +++ b/README @@ -1,12 +1,14 @@ -FRRouting is free software that manages various IPv4 and IPv6 routing -protocols. +FRRouting is free software that implements and manages various IPv4 and IPv6 +routing protocols. -Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, -RIPv2, RIPng, PIM-SM/MSDP and LDP as well as very early support for IS-IS, -EIGRP and NHRP. +Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, RIPng, +IS-IS, PIM-SM/MSDP, LDP and Babel as well as very early support for EIGRP and +NHRP. See the file REPORTING-BUGS to report bugs. +See COMMUNITY.md for information on contributing. + Free RRRouting is free software. See the file COPYING for copying conditions. Public email discussion can be found at https://lists.frrouting.org/listinfo From 9d877afc13d71bbf1b6fa4ec83f2b1e0d6896fd9 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 17 Jan 2018 15:57:50 +0000 Subject: [PATCH 37/84] tools: frr-reload 'vni' keyword does not always create a sub-context Signed-off-by: Daniel Walton --- tools/frr-reload.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 2c651ffbd5..0b7e80962c 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -434,7 +434,14 @@ end new_ctx = False log.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys) - elif "vni " in line: + # The 'vni' keyword under 'router bgp X/address-family l2vpn evpn' creates + # a sub-context but the 'vni' keyword in other places (such as 'vrf BLUE') + # does not. + elif ("vni " in line and + len(ctx_keys) == 2 and + ctx_keys[0].startswith('router bgp') and + ctx_keys[1] == 'address-family l2vpn evpn'): + main_ctx_key = [] # Save old context first From 044506e7f89a13efe2e0d51febd1f027da85aeda Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 17 Jan 2018 13:28:17 -0500 Subject: [PATCH 38/84] ospfd: LSDB_LOOP treat it as a loop. Inform the .clang-format file about LSDB_LOOP and put the proper indentation for this loop into the code. Signed-off-by: Donald Sharp --- .clang-format | 2 ++ ospfd/ospf_abr.c | 67 +++++++++++++++++++++--------------------- ospfd/ospf_apiserver.c | 33 ++++++++++++++------- ospfd/ospf_ase.c | 7 +++-- ospfd/ospf_ia.c | 4 +-- ospfd/ospf_lsa.c | 33 ++++++++++----------- ospfd/ospf_nsm.c | 18 ++++++------ ospfd/ospf_vty.c | 4 +-- ospfd/ospfd.c | 25 ++++++++-------- 9 files changed, 102 insertions(+), 91 deletions(-) diff --git a/.clang-format b/.clang-format index 21fe9d7c5e..cc5a95baf6 100644 --- a/.clang-format +++ b/.clang-format @@ -57,3 +57,5 @@ ForEachMacros: - SUBGRP_FOREACH_ADJ_SAFE - AF_FOREACH - FOREACH_AFI_SAFI + # ospfd + - LSDB_LOOP diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index f7aa94ad18..ea94bab6b3 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -327,8 +327,7 @@ static int ospf_abr_nssa_am_elected(struct ospf_area *area) struct router_lsa *rlsa; struct in_addr *best = NULL; - LSDB_LOOP(ROUTER_LSDB(area), rn, lsa) - { + LSDB_LOOP (ROUTER_LSDB(area), rn, lsa) { /* sanity checks */ if (!lsa || (lsa->data->type != OSPF_ROUTER_LSA) || IS_LSA_SELF(lsa)) @@ -978,7 +977,7 @@ static void ospf_abr_process_nssa_translates(struct ospf *ospf) inet_ntoa(area->area_id)); LSDB_LOOP(NSSA_LSDB(area), rn, lsa) - ospf_abr_translate_nssa(area, lsa); + ospf_abr_translate_nssa(area, lsa); } if (IS_DEBUG_OSPF_NSSA) @@ -1325,14 +1324,14 @@ ospf_abr_unapprove_translates(struct ospf *ospf) /* For NSSA Translations */ and we would want to flush any residuals anyway */ LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) { - UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED); - if (IS_DEBUG_OSPF_NSSA) - zlog_debug( - "ospf_abr_unapprove_translates(): " - "approved unset on link id %s", - inet_ntoa(lsa->data->id)); - } + if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) { + UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED); + if (IS_DEBUG_OSPF_NSSA) + zlog_debug( + "ospf_abr_unapprove_translates(): " + "approved unset on link id %s", + inet_ntoa(lsa->data->id)); + } if (IS_DEBUG_OSPF_NSSA) zlog_debug("ospf_abr_unapprove_translates(): Stop"); @@ -1355,24 +1354,24 @@ static void ospf_abr_unapprove_summaries(struct ospf *ospf) "considering area %s", inet_ntoa(area->area_id)); LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - if (ospf_lsa_is_self_originated(ospf, lsa)) { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "ospf_abr_unapprove_summaries(): " - "approved unset on summary link id %s", - inet_ntoa(lsa->data->id)); - UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED); - } + if (ospf_lsa_is_self_originated(ospf, lsa)) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "ospf_abr_unapprove_summaries(): " + "approved unset on summary link id %s", + inet_ntoa(lsa->data->id)); + UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED); + } LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - if (ospf_lsa_is_self_originated(ospf, lsa)) { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "ospf_abr_unapprove_summaries(): " - "approved unset on asbr-summary link id %s", - inet_ntoa(lsa->data->id)); - UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED); - } + if (ospf_lsa_is_self_originated(ospf, lsa)) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "ospf_abr_unapprove_summaries(): " + "approved unset on asbr-summary link id %s", + inet_ntoa(lsa->data->id)); + UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED); + } } if (IS_DEBUG_OSPF_EVENT) @@ -1633,7 +1632,7 @@ static void ospf_abr_remove_unapproved_translates(struct ospf *ospf) zlog_debug("ospf_abr_remove_unapproved_translates(): Start"); LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - ospf_abr_remove_unapproved_translates_apply(ospf, lsa); + ospf_abr_remove_unapproved_translates_apply(ospf, lsa); if (IS_DEBUG_OSPF_NSSA) zlog_debug("ospf_abr_remove_unapproved_translates(): Stop"); @@ -1657,14 +1656,14 @@ static void ospf_abr_remove_unapproved_summaries(struct ospf *ospf) inet_ntoa(area->area_id)); LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - if (ospf_lsa_is_self_originated(ospf, lsa)) - if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED)) - ospf_lsa_flush_area(lsa, area); + if (ospf_lsa_is_self_originated(ospf, lsa)) + if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED)) + ospf_lsa_flush_area(lsa, area); LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - if (ospf_lsa_is_self_originated(ospf, lsa)) - if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED)) - ospf_lsa_flush_area(lsa, area); + if (ospf_lsa_is_self_originated(ospf, lsa)) + if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED)) + ospf_lsa_flush_area(lsa, area); } if (IS_DEBUG_OSPF_EVENT) diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 8c1ad5ff0c..9ebaeffa69 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -1313,22 +1313,28 @@ int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver *apiserv, /* Check msg type. */ if (mask & Power2[OSPF_ROUTER_LSA]) LSDB_LOOP(ROUTER_LSDB(area), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback( + lsa, (void *)¶m, seqnum); if (mask & Power2[OSPF_NETWORK_LSA]) LSDB_LOOP(NETWORK_LSDB(area), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback( + lsa, (void *)¶m, seqnum); if (mask & Power2[OSPF_SUMMARY_LSA]) LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback( + lsa, (void *)¶m, seqnum); if (mask & Power2[OSPF_ASBR_SUMMARY_LSA]) LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback( + lsa, (void *)¶m, seqnum); if (mask & Power2[OSPF_OPAQUE_LINK_LSA]) LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback( + lsa, (void *)¶m, seqnum); if (mask & Power2[OSPF_OPAQUE_AREA_LSA]) LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback( + lsa, (void *)¶m, seqnum); } } @@ -1336,14 +1342,16 @@ int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver *apiserv, if (ospf->lsdb) { if (mask & Power2[OSPF_AS_EXTERNAL_LSA]) LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback(lsa, (void *)¶m, + seqnum); } /* For AS-external opaque LSAs */ if (ospf->lsdb) { if (mask & Power2[OSPF_OPAQUE_AS_LSA]) LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa) - apiserver_sync_callback(lsa, (void *)¶m, seqnum); + apiserver_sync_callback(lsa, (void *)¶m, + seqnum); } /* Send a reply back to client with return code */ @@ -1945,16 +1953,19 @@ void ospf_apiserver_flush_opaque_lsa(struct ospf_apiserver *apiserv, case OSPF_OPAQUE_LINK_LSA: for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) - apiserver_flush_opaque_type_callback(lsa, (void *)¶m, 0); + apiserver_flush_opaque_type_callback( + lsa, (void *)¶m, 0); break; case OSPF_OPAQUE_AREA_LSA: for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) - apiserver_flush_opaque_type_callback(lsa, (void *)¶m, 0); + apiserver_flush_opaque_type_callback( + lsa, (void *)¶m, 0); break; case OSPF_OPAQUE_AS_LSA: LSDB_LOOP(OPAQUE_LINK_LSDB(ospf), rn, lsa) - apiserver_flush_opaque_type_callback(lsa, (void *)¶m, 0); + apiserver_flush_opaque_type_callback(lsa, + (void *)¶m, 0); break; default: break; diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index 368987a2ba..d2af974833 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -649,7 +649,7 @@ static int ospf_ase_calculate_timer(struct thread *t) /* Calculate external route for each AS-external-LSA */ LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - ospf_ase_calculate_route(ospf, lsa); + ospf_ase_calculate_route(ospf, lsa); /* This version simple adds to the table all NSSA areas */ if (ospf->anyNSSA) @@ -661,11 +661,12 @@ static int ospf_ase_calculate_timer(struct thread *t) if (area->external_routing == OSPF_AREA_NSSA) LSDB_LOOP(NSSA_LSDB(area), rn, lsa) - ospf_ase_calculate_route(ospf, lsa); + ospf_ase_calculate_route(ospf, + lsa); } /* kevinm: And add the NSSA routes in ospf_top */ LSDB_LOOP(NSSA_LSDB(ospf), rn, lsa) - ospf_ase_calculate_route(ospf, lsa); + ospf_ase_calculate_route(ospf, lsa); /* Compare old and new external routing table and install the difference info zebra/kernel */ diff --git a/ospfd/ospf_ia.c b/ospfd/ospf_ia.c index c65d8b8743..e570f3337a 100644 --- a/ospfd/ospf_ia.c +++ b/ospfd/ospf_ia.c @@ -283,7 +283,7 @@ static void ospf_examine_summaries(struct ospf_area *area, struct route_node *rn; LSDB_LOOP(lsdb_rt, rn, lsa) - process_summary_lsa(area, rt, rtrs, lsa); + process_summary_lsa(area, rt, rtrs, lsa); } int ospf_area_is_transit(struct ospf_area *area) @@ -583,7 +583,7 @@ static void ospf_examine_transit_summaries(struct ospf_area *area, struct route_node *rn; LSDB_LOOP(lsdb_rt, rn, lsa) - process_transit_summary_lsa(area, rt, rtrs, lsa); + process_transit_summary_lsa(area, rt, rtrs, lsa); } void ospf_ia_routing(struct ospf *ospf, struct route_table *rt, diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index a2961992de..0f1dd63dfb 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -1872,8 +1872,7 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf, if (area->external_routing != OSPF_AREA_NSSA && !type7) continue; - LSDB_LOOP(NSSA_LSDB(area), rn, lsa) - { + LSDB_LOOP (NSSA_LSDB(area), rn, lsa) { if (lsa->data->id.s_addr == type5->data->id.s_addr) { type7 = lsa; @@ -3007,27 +3006,27 @@ int ospf_lsa_maxage_walker(struct thread *thread) for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) { LSDB_LOOP(ROUTER_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(NETWORK_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(NSSA_LSDB(area), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); } /* for AS-external-LSAs. */ if (ospf->lsdb) { LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa) - ospf_lsa_maxage_walker_remover(ospf, lsa); + ospf_lsa_maxage_walker_remover(ospf, lsa); } OSPF_TIMER_ON(ospf->t_maxage_walker, ospf_lsa_maxage_walker, @@ -3350,20 +3349,20 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf) } LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - ospf_lsa_flush_schedule(ospf, lsa); + ospf_lsa_flush_schedule(ospf, lsa); LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - ospf_lsa_flush_schedule(ospf, lsa); + ospf_lsa_flush_schedule(ospf, lsa); LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) - ospf_lsa_flush_schedule(ospf, lsa); + ospf_lsa_flush_schedule(ospf, lsa); LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) - ospf_lsa_flush_schedule(ospf, lsa); + ospf_lsa_flush_schedule(ospf, lsa); } if (need_to_flush_ase) { LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - ospf_lsa_flush_schedule(ospf, lsa); + ospf_lsa_flush_schedule(ospf, lsa); LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa) - ospf_lsa_flush_schedule(ospf, lsa); + ospf_lsa_flush_schedule(ospf, lsa); } /* diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index c87001294d..54d5dd5d16 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -280,37 +280,37 @@ static int nsm_negotiation_done(struct ospf_neighbor *nbr) ospf_proactively_arp(nbr); LSDB_LOOP(ROUTER_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); LSDB_LOOP(NETWORK_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); /* Process only if the neighbor is opaque capable. */ if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)) { LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); } if (CHECK_FLAG(nbr->options, OSPF_OPTION_NP)) { LSDB_LOOP(NSSA_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); } if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK && area->external_routing == OSPF_AREA_DEFAULT) LSDB_LOOP(EXTERNAL_LSDB(nbr->oi->ospf), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); if (CHECK_FLAG(nbr->options, OSPF_OPTION_O) && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK && area->external_routing == OSPF_AREA_DEFAULT)) LSDB_LOOP(OPAQUE_AS_LSDB(nbr->oi->ospf), rn, lsa) - ospf_db_summary_add(nbr, lsa); + ospf_db_summary_add(nbr, lsa); return 0; } diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index a1384eebdd..bc95118345 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -6167,7 +6167,7 @@ static void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf, show_database_header[type]); LSDB_LOOP(AREA_LSDB(area, type), rn, lsa) - show_lsa_summary(vty, lsa, self); + show_lsa_summary(vty, lsa, self); vty_out(vty, "\n"); } @@ -6189,7 +6189,7 @@ static void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf, vty_out(vty, "%s\n", show_database_header[type]); LSDB_LOOP(AS_LSDB(ospf, type), rn, lsa) - show_lsa_summary(vty, lsa, self); + show_lsa_summary(vty, lsa, self); vty_out(vty, "\n"); } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 1926197430..862e87e40f 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -159,8 +159,8 @@ void ospf_router_id_update(struct ospf *ospf) struct ospf_lsa *lsa; LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - if (IS_LSA_SELF(lsa)) - ospf_lsa_flush_schedule(ospf, lsa); + if (IS_LSA_SELF(lsa)) + ospf_lsa_flush_schedule(ospf, lsa); } ospf->router_id = router_id; @@ -183,8 +183,7 @@ void ospf_router_id_update(struct ospf *ospf) struct route_node *rn; struct ospf_lsa *lsa; - LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - { + LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa) { /* AdvRouter and Router ID is the same. */ if (IPV4_ADDR_SAME(&lsa->data->adv_router, &ospf->router_id)) { @@ -693,9 +692,9 @@ static void ospf_finish_final(struct ospf *ospf) stream_free(ospf->ibuf); LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa) - ospf_discard_from_db(ospf, ospf->lsdb, lsa); + ospf_discard_from_db(ospf, ospf->lsdb, lsa); LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) - ospf_discard_from_db(ospf, ospf->lsdb, lsa); + ospf_discard_from_db(ospf, ospf->lsdb, lsa); ospf_lsdb_delete_all(ospf->lsdb); ospf_lsdb_free(ospf->lsdb); @@ -830,20 +829,20 @@ static void ospf_area_free(struct ospf_area *area) /* Free LSDBs. */ LSDB_LOOP(ROUTER_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP(NETWORK_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP(NSSA_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) - ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_discard_from_db(area->ospf, area->lsdb, lsa); ospf_opaque_type10_lsa_term(area); ospf_lsdb_delete_all(area->lsdb); From 48a67e2c0a3958faa38fedfd54a1964c1d4c1688 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 17 Jan 2018 14:17:15 -0500 Subject: [PATCH 39/84] bgpd: Remove peer->hash as that it is unused The peer->hash pointer is allocating a bunch of memory but is never used. Remove. Signed-off-by: Donald Sharp --- bgpd/bgp_advertise.c | 6 ------ bgpd/bgpd.h | 3 --- 2 files changed, 9 deletions(-) diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index 840cc35751..29b6ca6bfa 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -246,8 +246,6 @@ void bgp_sync_init(struct peer *peer) BGP_ADV_FIFO_INIT(&sync->withdraw); BGP_ADV_FIFO_INIT(&sync->withdraw_low); peer->sync[afi][safi] = sync; - peer->hash[afi][safi] = hash_create(baa_hash_key, baa_hash_cmp, - "BGP Sync Hash"); } } @@ -260,9 +258,5 @@ void bgp_sync_delete(struct peer *peer) if (peer->sync[afi][safi]) XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]); peer->sync[afi][safi] = NULL; - - if (peer->hash[afi][safi]) - hash_free(peer->hash[afi][safi]); - peer->hash[afi][safi] = NULL; } } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index bf71e79743..c4ac4b0adb 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -919,9 +919,6 @@ struct peer { /* Send prefix count. */ unsigned long scount[AFI_MAX][SAFI_MAX]; - /* Announcement attribute hash. */ - struct hash *hash[AFI_MAX][SAFI_MAX]; - /* Notify data. */ struct bgp_notify notify; From 84b05ca19375d1578b41c5b082d8120530bd3991 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 18 Jan 2018 09:05:36 -0500 Subject: [PATCH 40/84] redhat: Build with FPM Build redhat rpm's with FPM. It's a module so not a bad idea. Signed-off-by: Donald Sharp --- redhat/frr.spec.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 4e05f7828c..20b96bb76f 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -22,7 +22,7 @@ %{!?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_fpm: %global with_fpm 1 } %{!?with_watchfrr: %global with_watchfrr 1 } %{!?with_bgp_vnc: %global with_bgp_vnc 0 } %{!?with_pimd: %global with_pimd 1 } @@ -554,6 +554,9 @@ rm -rf %{buildroot} %{_libdir}/lib*.so.0 %attr(755,root,root) %{_libdir}/lib*.so.0.* %endif +%if %{with_fpm} +%attr(755,root,root) %{_libdir}/frr/modules/zebra_fpm.so +%endif %attr(755,root,root) %{_libdir}/frr/modules/zebra_irdp.so %{_bindir}/* %config(noreplace) /etc/frr/[!v]*.conf* From 677f704de4f04bae34108bb1c91a9454c0b05daa Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 18 Jan 2018 09:17:57 -0500 Subject: [PATCH 41/84] zebra: Add some more debug information on read issues in FPM When we receive a read failure in handling a FPM read let's add a bit more information to what we think has gone wrong, in a hope that debugging will be a bit easier. Signed-off-by: Donald Sharp --- zebra/zebra_fpm.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 0d0a2cb3bf..a6e0882ff8 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -713,7 +713,15 @@ static int zfpm_read_cb(struct thread *thread) nbyte = stream_read_try(ibuf, zfpm_g->sock, FPM_MSG_HDR_LEN - already); if (nbyte == 0 || nbyte == -1) { - zfpm_connection_down("closed socket in read"); + if (nbyte == -1) { + char buffer[1024]; + + sprintf(buffer, "closed socket in read(%d): %s", + errno, safe_strerror(errno)); + zfpm_connection_down(buffer); + } + else + zfpm_connection_down("closed socket in read"); return 0; } @@ -743,7 +751,15 @@ static int zfpm_read_cb(struct thread *thread) nbyte = stream_read_try(ibuf, zfpm_g->sock, msg_len - already); if (nbyte == 0 || nbyte == -1) { - zfpm_connection_down("failed to read message"); + if (nbyte == -1) { + char buffer[1024]; + + sprintf(buffer, "failed to read message(%d) %s", + errno, safe_strerror(errno)); + zfpm_connection_down(buffer); + } + else + zfpm_connection_down("failed to read message"); return 0; } From 7bcc8dac13faa1503e5eb7d9c7dbbda54565f34f Mon Sep 17 00:00:00 2001 From: dturlupov Date: Fri, 19 Jan 2018 10:53:32 +0300 Subject: [PATCH 42/84] bgp: small fix for write to 'address-family l2vpn evpn' configuration --- bgpd/bgp_route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index ad3fac20f1..445ee8696b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10904,7 +10904,7 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp, &bgp_static->gatewayIp.u.prefix, buf2, sizeof(buf2)); vty_out(vty, - " network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s\n", + " network %s rd %s ethtag %u label %u esi %s gwip %s routermac %s\n", buf, rdbuf, p->u.prefix_evpn.eth_tag, decode_label(&bgp_static->label), esi, buf2, macrouter); From ee65c55e2a923dd9499baa3207d629a09600ba64 Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Fri, 19 Jan 2018 16:27:26 +0100 Subject: [PATCH 43/84] Doc: Update OSPF-TE and ISIS-TE example - In ospfd and isisd documentation, Traffic Engineering examples are referring to old interface syntax. Update both examples to 'link-param' syntax. Signed-off-by: Olivier Dugeon --- doc/isisd.texi | 55 +++++++++++++++++++++++++------------------------- doc/ospfd.texi | 55 +++++++++++++++++++++++++------------------------- 2 files changed, 56 insertions(+), 54 deletions(-) diff --git a/doc/isisd.texi b/doc/isisd.texi index bbc2896755..404698d805 100644 --- a/doc/isisd.texi +++ b/doc/isisd.texi @@ -373,36 +373,37 @@ log file /var/log/zebra.log ! interface eth0 ip address 10.2.2.2/24 - mpls-te on - mpls-te link metric 10 - mpls-te link max-bw 1.25e+06 - mpls-te link max-rsv-bw 1.25e+06 - mpls-te link unrsv-bw 0 1.25e+06 - mpls-te link unrsv-bw 1 1.25e+06 - mpls-te link unrsv-bw 2 1.25e+06 - mpls-te link unrsv-bw 3 1.25e+06 - mpls-te link unrsv-bw 4 1.25e+06 - mpls-te link unrsv-bw 5 1.25e+06 - mpls-te link unrsv-bw 6 1.25e+06 - mpls-te link unrsv-bw 7 1.25e+06 - mpls-te link rsc-clsclr 0xab + link-params + enable + metric 100 + max-bw 1.25e+07 + max-rsv-bw 1.25e+06 + unrsv-bw 0 1.25e+06 + unrsv-bw 1 1.25e+06 + unrsv-bw 2 1.25e+06 + unrsv-bw 3 1.25e+06 + unrsv-bw 4 1.25e+06 + unrsv-bw 5 1.25e+06 + unrsv-bw 6 1.25e+06 + unrsv-bw 7 1.25e+06 + admin-grp 0xab ! interface eth1 ip address 10.1.1.1/24 - mpls-te on - mpls-te link metric 10 - mpls-te link max-bw 1.25e+06 - mpls-te link max-rsv-bw 1.25e+06 - mpls-te link unrsv-bw 0 1.25e+06 - mpls-te link unrsv-bw 1 1.25e+06 - mpls-te link unrsv-bw 2 1.25e+06 - mpls-te link unrsv-bw 3 1.25e+06 - mpls-te link unrsv-bw 4 1.25e+06 - mpls-te link unrsv-bw 5 1.25e+06 - mpls-te link unrsv-bw 6 1.25e+06 - mpls-te link unrsv-bw 7 1.25e+06 - mpls-te link rsc-clsclr 0xab - mpls-te neighbor 10.1.1.2 as 65000 + link-params + enable + metric 100 + max-bw 1.25e+07 + max-rsv-bw 1.25e+06 + unrsv-bw 0 1.25e+06 + unrsv-bw 1 1.25e+06 + unrsv-bw 2 1.25e+06 + unrsv-bw 3 1.25e+06 + unrsv-bw 4 1.25e+06 + unrsv-bw 5 1.25e+06 + unrsv-bw 6 1.25e+06 + unrsv-bw 7 1.25e+06 + neighbor 10.1.1.2 as 65000 @end group @end example diff --git a/doc/ospfd.texi b/doc/ospfd.texi index cc33211510..26a7637048 100644 --- a/doc/ospfd.texi +++ b/doc/ospfd.texi @@ -843,36 +843,37 @@ log file /var/log/zebra.log ! interface eth0 ip address 198.168.1.1/24 - mpls-te on - mpls-te link metric 10 - mpls-te link max-bw 1.25e+06 - mpls-te link max-rsv-bw 1.25e+06 - mpls-te link unrsv-bw 0 1.25e+06 - mpls-te link unrsv-bw 1 1.25e+06 - mpls-te link unrsv-bw 2 1.25e+06 - mpls-te link unrsv-bw 3 1.25e+06 - mpls-te link unrsv-bw 4 1.25e+06 - mpls-te link unrsv-bw 5 1.25e+06 - mpls-te link unrsv-bw 6 1.25e+06 - mpls-te link unrsv-bw 7 1.25e+06 - mpls-te link rsc-clsclr 0xab + link-params + enable + admin-grp 0xa1 + metric 100 + max-bw 1.25e+07 + max-rsv-bw 1.25e+06 + unrsv-bw 0 1.25e+06 + unrsv-bw 1 1.25e+06 + unrsv-bw 2 1.25e+06 + unrsv-bw 3 1.25e+06 + unrsv-bw 4 1.25e+06 + unrsv-bw 5 1.25e+06 + unrsv-bw 6 1.25e+06 + unrsv-bw 7 1.25e+06 ! interface eth1 ip address 192.168.2.1/24 - mpls-te on - mpls-te link metric 10 - mpls-te link max-bw 1.25e+06 - mpls-te link max-rsv-bw 1.25e+06 - mpls-te link unrsv-bw 0 1.25e+06 - mpls-te link unrsv-bw 1 1.25e+06 - mpls-te link unrsv-bw 2 1.25e+06 - mpls-te link unrsv-bw 3 1.25e+06 - mpls-te link unrsv-bw 4 1.25e+06 - mpls-te link unrsv-bw 5 1.25e+06 - mpls-te link unrsv-bw 6 1.25e+06 - mpls-te link unrsv-bw 7 1.25e+06 - mpls-te link rsc-clsclr 0xab - mpls-te neighbor 192.168.2.2 as 65000 + link-params + enable + metric 10 + max-bw 1.25e+07 + max-rsv-bw 1.25e+06 + unrsv-bw 0 1.25e+06 + unrsv-bw 1 1.25e+06 + unrsv-bw 2 1.25e+06 + unrsv-bw 3 1.25e+06 + unrsv-bw 4 1.25e+06 + unrsv-bw 5 1.25e+06 + unrsv-bw 6 1.25e+06 + unrsv-bw 7 1.25e+06 + neighbor 192.168.2.2 as 65000 @end group @end example From 2bc7673f110a92c7a20f170daf9b34d8c8190f8a Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Fri, 19 Jan 2018 18:17:53 -0800 Subject: [PATCH 44/84] ospfd: show ip ospf neighbor json output format Current json output does not differentiate start of neighbor ip object. Adding "neighbors" keyword at the beginning of neighbor list. This is useful when displaying vrf level output along with neighbors list. Ticket:CM-19097 Testing Done: show ip ospf neighbor json show ip ospf vrf all neighbor json Signed-off-by: Chirag Shah --- ospfd/ospf_interface.c | 22 ++++++++++++++++++++++ ospfd/ospf_interface.h | 2 +- ospfd/ospf_vty.c | 19 +++++++++++++++---- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index e8700e7eb0..c8f758525e 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -51,6 +51,28 @@ DEFINE_QOBJ_TYPE(ospf_interface) DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd)) DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd)) +int ospf_interface_neighbor_count(struct ospf_interface *oi) +{ + int count = 0; + struct route_node *rn; + struct ospf_neighbor *nbr = NULL; + + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; + if (nbr) { + /* Do not show myself. */ + if (nbr == oi->nbr_self) + continue; + /* Down state is not shown. */ + if (nbr->state == NSM_Down) + continue; + count++; + } + } + + return count; +} + int ospf_if_get_output_cost(struct ospf_interface *oi) { /* If all else fails, use default OSPF cost */ diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 829a3f4297..ab02444f7d 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -314,8 +314,8 @@ extern struct crypt_key *ospf_crypt_key_lookup(struct list *, u_char); extern struct crypt_key *ospf_crypt_key_new(void); extern void ospf_crypt_key_add(struct list *, struct crypt_key *); extern int ospf_crypt_key_delete(struct list *, u_char); - extern u_char ospf_default_iftype(struct interface *ifp); +extern int ospf_interface_neighbor_count(struct ospf_interface *oi); /* Set all multicast memberships appropriately based on the type and state of the interface. */ diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index e2aa445572..6681473153 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -4300,13 +4300,15 @@ static int show_ip_ospf_neighbor_common(struct vty *vty, struct ospf *ospf, { struct ospf_interface *oi; struct listnode *node; - json_object *json_vrf = NULL; + json_object *json_vrf = NULL, *json_nbr_array = NULL; + json_object *json_nbr_sub = NULL; if (use_json) { if (use_vrf) json_vrf = json_object_new_object(); else json_vrf = json; + json_nbr_array = json_object_new_array(); } if (ospf->instance) { @@ -4320,9 +4322,19 @@ static int show_ip_ospf_neighbor_common(struct vty *vty, struct ospf *ospf, ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf); if (!use_json) show_ip_ospf_neighbour_header(vty); + else + json_object_object_add(json_vrf, "neighbors", + json_nbr_array); - for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) - show_ip_ospf_neighbor_sub(vty, oi, json_vrf, use_json); + for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { + if (ospf_interface_neighbor_count(oi) == 0) + continue; + if (use_json) { + json_nbr_sub = json_object_new_object(); + json_object_array_add(json_nbr_array, json_nbr_sub); + } + show_ip_ospf_neighbor_sub(vty, oi, json_nbr_sub, use_json); + } if (use_json) { if (use_vrf) { @@ -4698,7 +4710,6 @@ static int show_ip_ospf_neighbor_int_common(struct vty *vty, struct ospf *ospf, ospf_show_vrf_name(ospf, vty, json, use_vrf); - /*ifp = if_lookup_by_name(argv[arg_base]->arg, ospf->vrf_id);*/ ifp = if_lookup_by_name_all_vrf(argv[arg_base]->arg); if (!ifp) { if (use_json) From 4030583f6a80ac9c620937d1d526438bfd881280 Mon Sep 17 00:00:00 2001 From: vivek Date: Sat, 20 Jan 2018 13:21:05 -0800 Subject: [PATCH 45/84] zebra: Install connected routes during VRF change only if interface is up During VRF change handling, the connected route for the interface should be installed only if the interface is up. Otherwise, we end up with duplicate connected routes which can lead to other problems. Signed-off-by: Vivek Venkatraman Reviewed-by: Don Slice Ticket: CM-19364 Reviewed By: CCR-7099 Testing Done: Manual verification --- zebra/interface.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zebra/interface.c b/zebra/interface.c index 906f796136..07570e64bf 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -768,7 +768,8 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) zebra_interface_vrf_update_add(ifp, old_vrf_id); /* Install connected routes (in new VRF). */ - if_install_connected(ifp); + if (if_is_operative(ifp)) + if_install_connected(ifp); static_ifindex_update(ifp, true); From a9ff90c41b0a95195d19d451ee83eb460e1599d0 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 14 Dec 2017 16:01:36 +0100 Subject: [PATCH 46/84] lib: increase vrf_id from 16 bit to 32 bit identifier This is a preparatory work for configuring vrf/frr over netns vrf structure is being changed to 32 bit, and the VRF will have the possibility to have a backend made up of NETNS. Let's put some history. Initially the 32 bit was because one wanted to map on vrf_id both the VRFLITE and the NSID. Initially, one would have liked to make zebra configure at the same time both vrf lite and vrf from netns in a flat way. From the show running perspective, one would have had both kind of vrfs, thatone would configure on the same way. however, it leads to inconsistencies in concepts, because it mixes vrf vrf with vrf, and vrf is not always mapped with netns. For instance, logical-router could also be used with netns. In that case, it would not be possible to map vrf with netns. There was an other reason why 32 bit is proposed. this is because some systems handle NSID to 32 bits. As vrf lite exists only on Linux, there are other systems that would like to use an other vrf backend than vrf lite. The netns backend for vrf will be used for that too. for instance, for windows or freebsd, some similar netns concept exists; so it will be easier to reuse netns backend for vrf, than reusing vrflite backend for vrf. This commit is here to extend vrf_id to 32 bits. Following commits in a second step will help in enable a VRF backend. Signed-off-by: Philippe Guibert --- lib/vrf.c | 6 +++--- lib/vrf.h | 3 +-- lib/zclient.c | 12 ++++++------ lib/zclient.h | 4 ++-- lib/zebra.h | 2 +- zebra/zebra_ptm.c | 2 +- zebra/zserv.c | 10 +++++----- 7 files changed, 19 insertions(+), 20 deletions(-) diff --git a/lib/vrf.c b/lib/vrf.c index 3c34b95262..b4ed24cbff 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -94,7 +94,7 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name) int new = 0; if (debug_vrf) - zlog_debug("VRF_GET: %s(%d)", name, vrf_id); + zlog_debug("VRF_GET: %s(%u)", name, vrf_id); /* Nothing to see, move along here */ if (!name && vrf_id == VRF_UNKNOWN) @@ -268,7 +268,7 @@ void *vrf_info_lookup(vrf_id_t vrf_id) */ #define VRF_BITMAP_NUM_OF_GROUPS 8 -#define VRF_BITMAP_NUM_OF_BITS_IN_GROUP (UINT16_MAX / VRF_BITMAP_NUM_OF_GROUPS) +#define VRF_BITMAP_NUM_OF_BITS_IN_GROUP (UINT32_MAX / VRF_BITMAP_NUM_OF_GROUPS) #define VRF_BITMAP_NUM_OF_BYTES_IN_GROUP \ (VRF_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */ @@ -355,7 +355,7 @@ static void vrf_autocomplete(vector comps, struct cmd_token *token) struct vrf *vrf = NULL; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - if (vrf->vrf_id != 0) + if (vrf->vrf_id != VRF_DEFAULT) vector_set(comps, XSTRDUP(MTYPE_COMPLETION, vrf->name)); } } diff --git a/lib/vrf.h b/lib/vrf.h index 9afca4c6fb..7e625769e7 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -32,8 +32,7 @@ /* The default VRF ID */ #define VRF_DEFAULT 0 -#define VRF_UNKNOWN UINT16_MAX -#define VRF_ALL UINT16_MAX - 1 +#define VRF_UNKNOWN UINT32_MAX /* Pending: May need to refine this. */ #ifndef IFLA_VRF_MAX diff --git a/lib/zclient.c b/lib/zclient.c index 4177ce1a71..d4a7b45b97 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -291,7 +291,7 @@ void zclient_create_header(struct stream *s, uint16_t command, vrf_id_t vrf_id) stream_putw(s, ZEBRA_HEADER_SIZE); stream_putc(s, ZEBRA_HEADER_MARKER); stream_putc(s, ZSERV_VERSION); - stream_putw(s, vrf_id); + stream_putl(s, vrf_id); stream_putw(s, command); } @@ -306,7 +306,7 @@ int zclient_read_header(struct stream *s, int sock, u_int16_t *size, *size -= ZEBRA_HEADER_SIZE; STREAM_GETC(s, *marker); STREAM_GETC(s, *version); - STREAM_GETW(s, *vrf_id); + STREAM_GETL(s, *vrf_id); STREAM_GETW(s, *cmd); if (*version != ZSERV_VERSION || *marker != ZEBRA_HEADER_MARKER) { @@ -1677,7 +1677,7 @@ struct interface *zebra_interface_vrf_update_read(struct stream *s, { unsigned int ifindex; struct interface *ifp; - vrf_id_t new_id = VRF_DEFAULT; + vrf_id_t new_id; /* Get interface index. */ ifindex = stream_getl(s); @@ -2043,7 +2043,7 @@ static int zclient_read(struct thread *thread) length = stream_getw(zclient->ibuf); marker = stream_getc(zclient->ibuf); version = stream_getc(zclient->ibuf); - vrf_id = stream_getw(zclient->ibuf); + vrf_id = stream_getl(zclient->ibuf); command = stream_getw(zclient->ibuf); if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { @@ -2346,9 +2346,9 @@ void zclient_interface_set_master(struct zclient *client, zclient_create_header(s, ZEBRA_INTERFACE_SET_MASTER, master->vrf_id); - stream_putw(s, master->vrf_id); + stream_putl(s, master->vrf_id); stream_putl(s, master->ifindex); - stream_putw(s, slave->vrf_id); + stream_putl(s, slave->vrf_id); stream_putl(s, slave->ifindex); stream_putw_at(s, 0, stream_get_endp(s)); diff --git a/lib/zclient.h b/lib/zclient.h index cc34fd9d2c..00ad692718 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -40,7 +40,7 @@ #define ZEBRA_MAX_PACKET_SIZ 4096 /* Zebra header size. */ -#define ZEBRA_HEADER_SIZE 8 +#define ZEBRA_HEADER_SIZE 10 /* special socket path name to use TCP * @ is used as first character because that's abstract socket names on Linux @@ -227,7 +227,7 @@ struct zserv_header { * always set to 255 in new zserv. */ uint8_t version; -#define ZSERV_VERSION 4 +#define ZSERV_VERSION 5 vrf_id_t vrf_id; uint16_t command; }; diff --git a/lib/zebra.h b/lib/zebra.h index 1eb0c56252..b9a795d160 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -486,7 +486,7 @@ typedef u_int16_t zebra_size_t; typedef u_int16_t zebra_command_t; /* VRF ID type. */ -typedef u_int16_t vrf_id_t; +typedef uint32_t vrf_id_t; typedef uint32_t route_tag_t; #define ROUTE_TAG_MAX UINT32_MAX diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 769d2f5666..953f74ecec 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -432,7 +432,7 @@ static void if_bfd_session_update(struct interface *ifp, struct prefix *dp, } else { zlog_debug( "MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d " - "with src %s/%d and vrf %d %s event", + "with src %s/%d and vrf %u %s event", inet_ntop(dp->family, &dp->u.prefix, buf[0], INET6_ADDRSTRLEN), dp->prefixlen, diff --git a/zebra/zserv.c b/zebra/zserv.c index 7eded89f6d..6241a16389 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -155,7 +155,7 @@ void zserv_create_header(struct stream *s, uint16_t cmd, vrf_id_t vrf_id) stream_putw(s, ZEBRA_HEADER_SIZE); stream_putc(s, ZEBRA_HEADER_MARKER); stream_putc(s, ZSERV_VERSION); - stream_putw(s, vrf_id); + stream_putl(s, vrf_id); stream_putw(s, cmd); } @@ -508,7 +508,7 @@ int zsend_interface_vrf_update(struct zserv *client, struct interface *ifp, /* Fill in the ifIndex of the interface and its new VRF (id) */ stream_putl(s, ifp->ifindex); - stream_putw(s, vrf_id); + stream_putl(s, vrf_id); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -2472,11 +2472,11 @@ static int zread_interface_set_master(struct zserv *client, int ifindex; vrf_id_t vrf_id; - STREAM_GETW(s, vrf_id); + STREAM_GETL(s, vrf_id); STREAM_GETL(s, ifindex); master = if_lookup_by_index(ifindex, vrf_id); - STREAM_GETW(s, vrf_id); + STREAM_GETL(s, vrf_id); STREAM_GETL(s, ifindex); slave = if_lookup_by_index(ifindex, vrf_id); @@ -2714,7 +2714,7 @@ static int zebra_client_read(struct thread *thread) STREAM_GETW(client->ibuf, length); STREAM_GETC(client->ibuf, marker); STREAM_GETC(client->ibuf, version); - STREAM_GETW(client->ibuf, vrf_id); + STREAM_GETL(client->ibuf, vrf_id); STREAM_GETW(client->ibuf, command); if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { From 3bd74754c9200f5aa7f5bf5a93c621ee04f1e0a3 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 4 Jan 2018 14:30:28 +0100 Subject: [PATCH 47/84] lib: vrf_bitmap_groups increased from 8 to 1024 The number of vrf bitmap groups is increased so as to avoid consuming too much memory. This fix is related to a fork memory that occured when running pimd as daemon. A check on memory consumed shows that the memory consumed goes from 33480ko to 46888ko with that change. This is less compared to if the value of the bitmap groups is increased to 16 ( 852776ko). Signed-off-by: Philippe Guibert --- lib/vrf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vrf.c b/lib/vrf.c index b4ed24cbff..2fa3a9c0ef 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -267,7 +267,7 @@ void *vrf_info_lookup(vrf_id_t vrf_id) * VRF bit-map */ -#define VRF_BITMAP_NUM_OF_GROUPS 8 +#define VRF_BITMAP_NUM_OF_GROUPS 1024 #define VRF_BITMAP_NUM_OF_BITS_IN_GROUP (UINT32_MAX / VRF_BITMAP_NUM_OF_GROUPS) #define VRF_BITMAP_NUM_OF_BYTES_IN_GROUP \ (VRF_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */ From 3eca551fecb96994c076512e6e553d6035030865 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 10 Jan 2018 14:13:50 +0100 Subject: [PATCH 48/84] lib: ns_id_t changed to 32 bit Because the VRF_ID is mapped into 32 bit, and because when NETNS will be the backend of VRF, then the NS identifier must also be encoded as 32 bit. Also, the NS_UNKNOWN value is changed accordingly to UINT32_MAX. Also, the NS_UNKNOWN and NS_DEFAULT values are removed from zebra_ns.h and kept on ns.h header file. Signed-off-by: Philippe Guibert --- lib/ns.h | 5 +++-- zebra/zebra_ns.h | 3 --- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/ns.h b/lib/ns.h index c492d6600b..79b4cab04d 100644 --- a/lib/ns.h +++ b/lib/ns.h @@ -25,10 +25,11 @@ #include "openbsd-tree.h" #include "linklist.h" -typedef u_int16_t ns_id_t; +typedef u_int32_t ns_id_t; -/* The default NS ID */ +/* the default NS ID */ #define NS_DEFAULT 0 +#define NS_UNKNOWN UINT32_MAX /* Default netns directory (Linux) */ #define NS_RUN_DIR "/var/run/netns" diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 0c340d8d59..5d90b9be67 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -57,9 +57,6 @@ struct zebra_ns { #endif /* HAVE_RTADV */ }; -#define NS_DEFAULT 0 -#define NS_UNKNOWN UINT16_MAX - struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id); int zebra_ns_init(void); From fe3da9e7735d0fc8dc25d90b87be60c28fe66a5c Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 18 Dec 2017 12:07:22 +0100 Subject: [PATCH 49/84] ospfd: fix compilation issue with ospfd the change of vrf_id field from 16 bit to 32 bit leads to some changes in other daemon. Signed-off-by: Philippe Guibert --- ospfd/ospf_vty.c | 7 ++++--- ospfd/ospfd.c | 10 +++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index e2aa445572..6d28c2cdc5 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -218,7 +218,7 @@ DEFUN_NOSH (router_ospf, if (ospf->vrf_id != VRF_UNKNOWN) ospf->oi_running = 1; if (IS_DEBUG_OSPF_EVENT) - zlog_debug("Config command 'router ospf %d' received, vrf %s id %d oi_running %u", + zlog_debug("Config command 'router ospf %d' received, vrf %s id %u oi_running %u", instance, ospf->name ? ospf->name : "NIL", ospf->vrf_id, ospf->oi_running); VTY_PUSH_CONTEXT(OSPF_NODE, ospf); @@ -9600,7 +9600,7 @@ DEFUN (show_ip_ospf_vrfs, for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { json_object *json_vrf = NULL; const char *name = NULL; - int vrf_id_ui = 0; + int64_t vrf_id_ui = 0; count++; @@ -9614,7 +9614,8 @@ DEFUN (show_ip_ospf_vrfs, else name = ospf->name; - vrf_id_ui = (ospf->vrf_id == VRF_UNKNOWN) ? -1 : ospf->vrf_id; + vrf_id_ui = (ospf->vrf_id == VRF_UNKNOWN) ? -1 : + (int64_t) ospf->vrf_id; if (uj) { json_object_int_add(json_vrf, "vrfId", vrf_id_ui); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 862e87e40f..6d583e9b4a 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -240,7 +240,7 @@ static struct ospf *ospf_new(u_short instance, const char *name) new->name = XSTRDUP(MTYPE_OSPF_TOP, name); vrf = vrf_lookup_by_name(new->name); if (IS_DEBUG_OSPF_EVENT) - zlog_debug("%s: Create new ospf instance with vrf_name %s vrf_id %d", + zlog_debug("%s: Create new ospf instance with vrf_name %s vrf_id %u", __PRETTY_FUNCTION__, name, new->vrf_id); if (vrf) ospf_vrf_link(new, vrf); @@ -2013,7 +2013,7 @@ void ospf_vrf_unlink(struct ospf *ospf, struct vrf *vrf) static int ospf_vrf_new(struct vrf *vrf) { if (IS_DEBUG_OSPF_EVENT) - zlog_debug("%s: VRF Created: %s(%d)", __PRETTY_FUNCTION__, + zlog_debug("%s: VRF Created: %s(%u)", __PRETTY_FUNCTION__, vrf->name, vrf->vrf_id); return 0; @@ -2023,7 +2023,7 @@ static int ospf_vrf_new(struct vrf *vrf) static int ospf_vrf_delete(struct vrf *vrf) { if (IS_DEBUG_OSPF_EVENT) - zlog_debug("%s: VRF Deletion: %s(%d)", __PRETTY_FUNCTION__, + zlog_debug("%s: VRF Deletion: %s(%u)", __PRETTY_FUNCTION__, vrf->name, vrf->vrf_id); return 0; @@ -2036,7 +2036,7 @@ static int ospf_vrf_enable(struct vrf *vrf) vrf_id_t old_vrf_id = VRF_DEFAULT; if (IS_DEBUG_OSPF_EVENT) - zlog_debug("%s: VRF %s id %d enabled", + zlog_debug("%s: VRF %s id %u enabled", __PRETTY_FUNCTION__, vrf->name, vrf->vrf_id); ospf = ospf_lookup_by_name(vrf->name); @@ -2045,7 +2045,7 @@ static int ospf_vrf_enable(struct vrf *vrf) /* We have instance configured, link to VRF and make it "up". */ ospf_vrf_link(ospf, vrf); if (IS_DEBUG_OSPF_EVENT) - zlog_debug("%s: ospf linked to vrf %s vrf_id %d (old id %d)", + zlog_debug("%s: ospf linked to vrf %s vrf_id %u (old id %u)", __PRETTY_FUNCTION__, vrf->name, ospf->vrf_id, old_vrf_id); From a8bf7d9c9e6c7c852da1b5c9d27d5e227de7a9d3 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 18 Dec 2017 12:33:29 +0100 Subject: [PATCH 50/84] bgpd: fix compilation issue with bgpd Changes due to the change of vrf_id_t moved from 16 bits to 32 bits. Signed-off-by: Philippe Guibert --- bgpd/bgp_bfd.c | 4 ++-- bgpd/bgp_main.c | 6 +++--- bgpd/bgp_nht.c | 4 ++-- bgpd/bgp_route.c | 2 +- bgpd/bgp_vty.c | 20 ++++++++++++-------- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 2e277bfa5f..ce46b21f03 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -302,13 +302,13 @@ static int bgp_bfd_dest_update(int command, struct zclient *zclient, prefix2str(&dp, buf[0], sizeof(buf[0])); if (ifp) { zlog_debug( - "Zebra: vrf %d interface %s bfd destination %s %s", + "Zebra: vrf %u interface %s bfd destination %s %s", vrf_id, ifp->name, buf[0], bfd_get_status_str(status)); } else { prefix2str(&sp, buf[1], sizeof(buf[1])); zlog_debug( - "Zebra: vrf %d source %s bfd destination %s %s", + "Zebra: vrf %u source %s bfd destination %s %s", vrf_id, buf[1], buf[0], bfd_get_status_str(status)); } diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index a720d31a76..0508f4846d 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -232,7 +232,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) static int bgp_vrf_new(struct vrf *vrf) { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("VRF Created: %s(%d)", vrf->name, vrf->vrf_id); + zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id); return 0; } @@ -240,7 +240,7 @@ static int bgp_vrf_new(struct vrf *vrf) static int bgp_vrf_delete(struct vrf *vrf) { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("VRF Deletion: %s(%d)", vrf->name, vrf->vrf_id); + zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id); return 0; } @@ -251,7 +251,7 @@ static int bgp_vrf_enable(struct vrf *vrf) vrf_id_t old_vrf_id; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("VRF enable add %s id %d", vrf->name, vrf->vrf_id); + zlog_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id); bgp = bgp_lookup_by_name(vrf->name); if (bgp) { diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 625d4f8442..247884d294 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -336,7 +336,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) bgp = bgp_lookup_by_vrf_id(vrf_id); if (!bgp) { zlog_err( - "parse nexthop update: instance not found for vrf_id %d", + "parse nexthop update: instance not found for vrf_id %u", vrf_id); return; } @@ -389,7 +389,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) char buf[PREFIX2STR_BUFFER]; prefix2str(&p, buf, sizeof(buf)); zlog_debug( - "%d: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x", + "%u: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x", vrf_id, buf, metric, bnc->metric, nexthop_num, bnc->nexthop_num, bnc->flags); } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 061f5fb1e2..c7901f30dc 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7859,7 +7859,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, vty_out(vty, "{\n \"vrfId\": %d,\n \"vrfName\": \"%s\",\n \"tableVersion\": %" PRId64 ",\n \"routerId\": \"%s\",\n \"routes\": { ", - bgp->vrf_id == VRF_UNKNOWN ? -1 : bgp->vrf_id, + bgp->vrf_id == VRF_UNKNOWN ? -1 : (int)bgp->vrf_id, bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT ? "Default" : bgp->name, table->version, inet_ntoa(bgp->router_id)); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 19cfb2d91d..c98cf9c327 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6479,7 +6479,6 @@ DEFUN (show_bgp_vrfs, struct listnode *node, *nnode; int peers_cfg, peers_estb; json_object *json_vrf = NULL; - int vrf_id_ui; /* Skip Views. */ if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW) @@ -6513,8 +6512,10 @@ DEFUN (show_bgp_vrfs, type = "VRF"; } - vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN) ? -1 : bgp->vrf_id; + if (uj) { + int64_t vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN) ? -1 : + (int64_t)bgp->vrf_id; json_object_string_add(json_vrf, "type", type); json_object_int_add(json_vrf, "vrfId", vrf_id_ui); json_object_string_add(json_vrf, "routerId", @@ -6532,7 +6533,9 @@ DEFUN (show_bgp_vrfs, } else vty_out(vty, "%4s %-5d %-16s %9u %10u %-37s %-10u %-15s\n", - type, vrf_id_ui, inet_ntoa(bgp->router_id), + type, bgp->vrf_id == VRF_UNKNOWN ? + -1 : (int)bgp->vrf_id, + inet_ntoa(bgp->router_id), peers_cfg, peers_estb, name, bgp->l3vni, prefix_mac2str(&bgp->rmac, buf, sizeof(buf))); } @@ -6852,10 +6855,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, if (!count) { unsigned long ents; char memstrbuf[MTYPE_MEMSTR_LEN]; - int vrf_id_ui; + int64_t vrf_id_ui; vrf_id_ui = - (bgp->vrf_id == VRF_UNKNOWN) ? -1 : bgp->vrf_id; + (bgp->vrf_id == VRF_UNKNOWN) ? -1 : + (int64_t)bgp->vrf_id; /* Usage summary and header */ if (use_json) { @@ -6874,7 +6878,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, vty_out(vty, "BGP router identifier %s, local AS number %u vrf-id %d", inet_ntoa(bgp->router_id), bgp->as, - vrf_id_ui); + bgp->vrf_id == VRF_UNKNOWN ? -1 : + (int)bgp->vrf_id); vty_out(vty, "\n"); } @@ -9876,8 +9881,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty, json_object_int_add(json, "vrfId", (bgp->vrf_id == VRF_UNKNOWN) - ? -1 - : bgp->vrf_id); + ? -1 : (int64_t) bgp->vrf_id); json_object_string_add( json, "vrfName", (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) From 87ad28f48c368aa2f236345e9acd6ab0f5ea052e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 18 Dec 2017 12:42:12 +0100 Subject: [PATCH 51/84] pim: fix compilation issue with pim The change of vrf_id_t from 16 bit to 32 bit needs some changes in pim daemon. Signed-off-by: Philippe Guibert --- pimd/pim_instance.c | 4 ++-- pimd/pim_nht.c | 2 +- pimd/pim_zebra.c | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 1fccbaeafa..8da610a3a6 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -136,7 +136,7 @@ static int pim_vrf_new(struct vrf *vrf) { struct pim_instance *pim = pim_instance_init(vrf); - zlog_debug("VRF Created: %s(%d)", vrf->name, vrf->vrf_id); + zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id); if (pim == NULL) { zlog_err("%s %s: pim class init failure ", __FILE__, __PRETTY_FUNCTION__); @@ -159,7 +159,7 @@ static int pim_vrf_delete(struct vrf *vrf) { struct pim_instance *pim = vrf->info; - zlog_debug("VRF Deletion: %s(%d)", vrf->name, vrf->vrf_id); + zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id); pim_ssmpingd_destroy(pim); pim_instance_terminate(pim); diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index e2984e1d13..089639c77e 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -811,7 +811,7 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient, char buf[PREFIX2STR_BUFFER]; prefix2str(&p, buf, sizeof(buf)); zlog_debug( - "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%d up %ld rp %d", + "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d", __PRETTY_FUNCTION__, buf, pim->vrf->name, nexthop_num, pnc->nexthop_num, vrf_id, pnc->upstream_hash->count, listcount(pnc->rp_list)); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 689e9a7449..6e82558766 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -80,7 +80,7 @@ static int pim_zebra_if_add(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d", + "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); @@ -130,7 +130,7 @@ static int pim_zebra_if_del(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d", + "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); @@ -158,7 +158,7 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d", + "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); @@ -213,7 +213,7 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d", + "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); @@ -293,7 +293,7 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(p, buf, BUFSIZ); - zlog_debug("%s: %s(%d) connected IP address %s flags %u %s", + zlog_debug("%s: %s(%u) connected IP address %s flags %u %s", __PRETTY_FUNCTION__, c->ifp->name, vrf_id, buf, c->flags, CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" @@ -372,7 +372,7 @@ static int pim_zebra_if_address_del(int command, struct zclient *client, char buf[BUFSIZ]; prefix2str(p, buf, BUFSIZ); zlog_debug( - "%s: %s(%d) disconnected IP address %s flags %u %s", + "%s: %s(%u) disconnected IP address %s flags %u %s", __PRETTY_FUNCTION__, c->ifp->name, vrf_id, buf, c->flags, CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) From 2fcdb1b2d17703c3cbd152c37a9e221a92f644c7 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 11 Jan 2018 09:11:36 +0100 Subject: [PATCH 52/84] bgpd: bgp_redist_lookup param handles instances, not vrfs The VRF_DEFAULT parameter is incorrectly used. The 0 value for the bgp instance is passed instead. Signed-off-by: Philippe Guibert fixup bgpd: fix compilation issue with bgpd --- bgpd/rfapi/rfapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 1e3c5a0352..95666143a5 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -913,7 +913,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ * aspath: points to interned hash from aspath hash table */ - red = bgp_redist_lookup(bgp, afi, type, VRF_DEFAULT); + red = bgp_redist_lookup(bgp, afi, type, 0); if (red && red->redist_metric_flag) { attr.med = red->redist_metric; From 90ac32c209129ea0ce65a43e64a398216360e415 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 22 Jan 2018 09:38:45 +0100 Subject: [PATCH 53/84] zebra: replace 0 value on zebra with VRF_DEFAULT On some places of code, the VRF_DEFAULT define was not used. This commit is ensuring that the macros is well used. Signed-off-by: Philippe Guibert --- zebra/zebra_static.c | 2 +- zebra/zebra_vty.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index 751ea08a38..3dd5378f22 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -156,7 +156,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, re->mtu = 0; re->vrf_id = si->vrf_id; re->table = - si->vrf_id + (si->vrf_id != VRF_DEFAULT) ? (zebra_vrf_lookup_by_id(si->vrf_id))->table_id : zebrad.rtm_table_default; re->nexthop_num = 0; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 82b0157ad3..df461ab10c 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1181,7 +1181,7 @@ DEFUN (ip_nht_default_route, return CMD_SUCCESS; zebra_rnh_ip_default_route = 1; - zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(VRF_DEFAULT, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1197,7 +1197,7 @@ DEFUN (no_ip_nht_default_route, return CMD_SUCCESS; zebra_rnh_ip_default_route = 0; - zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(VRF_DEFAULT, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1212,7 +1212,7 @@ DEFUN (ipv6_nht_default_route, return CMD_SUCCESS; zebra_rnh_ipv6_default_route = 1; - zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(VRF_DEFAULT, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1228,7 +1228,7 @@ DEFUN (no_ipv6_nht_default_route, return CMD_SUCCESS; zebra_rnh_ipv6_default_route = 0; - zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(VRF_DEFAULT, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL); return CMD_SUCCESS; } @@ -1890,7 +1890,7 @@ DEFUN (show_vrf, RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { if (!(zvrf = vrf->info)) continue; - if (!zvrf_id(zvrf)) + if (zvrf_id(zvrf) == VRF_DEFAULT) continue; vty_out(vty, "vrf %s ", zvrf_name(zvrf)); From f1abb72c4eec8f5fe4f29dc9d0d3ee4811707f10 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 22 Jan 2018 09:55:26 +0100 Subject: [PATCH 54/84] zebra: replace 0 value on zebra with NS_DEFAULT On some places, macro NS_DEFAULT was not used. This commit is replacind on some identified places where 0 can be replaced with NS_DEFAULT macro. Signed-off-by: Philippe Guibert --- zebra/zebra_ns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 5ede948e0a..b3b9c6d18a 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -81,7 +81,7 @@ int zebra_ns_init(void) zebra_vrf_init(); - zebra_ns_enable(0, (void **)&dzns); + zebra_ns_enable(NS_DEFAULT, (void **)&dzns); return 0; } From 8ecdb26ec08cc66ade06e3d325fceaae7bed76f2 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sun, 21 Jan 2018 16:11:50 -0500 Subject: [PATCH 55/84] lib, zebra: Rename and place appropriately the label stack Fix and rename the label stack to be better named. Signed-off-by: Donald Sharp --- lib/mpls.h | 6 ++++++ lib/nexthop.c | 6 +++--- lib/nexthop.h | 9 +-------- zebra/rt_netlink.c | 4 ++-- zebra/rt_socket.c | 2 +- zebra/zebra_mpls.c | 4 ++-- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/mpls.h b/lib/mpls.h index bf98eecd81..6ef00375e8 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -81,6 +81,12 @@ typedef unsigned int mpls_lse_t; /* MPLS label value as a 32-bit (mostly we only care about the label value). */ typedef unsigned int mpls_label_t; +struct mpls_label_stack { + uint8_t num_labels; + uint8_t reserved[3]; + mpls_label_t label[0]; /* 1 or more labels */ +}; + /* The MPLS explicit-null label is 0 which means when you memset a mpls_label_t * to zero you have set that variable to explicit-null which was probably not * your intent. The work-around is to use one bit to indicate if the diff --git a/lib/nexthop.c b/lib/nexthop.c index f6b2c9788d..f531f27302 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -124,7 +124,7 @@ const char *nexthop_type_to_str(enum nexthop_types_t nh_type) */ int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2) { - struct nexthop_label *nhl1, *nhl2; + struct mpls_label_stack *nhl1, *nhl2; nhl1 = nh1->nh_label; nhl2 = nh2->nh_label; @@ -210,12 +210,12 @@ void nexthops_free(struct nexthop *nexthop) void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type, u_int8_t num_labels, mpls_label_t *label) { - struct nexthop_label *nh_label; + struct mpls_label_stack *nh_label; int i; nexthop->nh_label_type = type; nh_label = XCALLOC(MTYPE_NH_LABEL, - sizeof(struct nexthop_label) + sizeof(struct mpls_label_stack) + num_labels * sizeof(mpls_label_t)); nh_label->num_labels = num_labels; for (i = 0; i < num_labels; i++) diff --git a/lib/nexthop.h b/lib/nexthop.h index a727f37057..753e66643d 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -55,13 +55,6 @@ enum blackhole_type { ((type) == NEXTHOP_TYPE_IFINDEX || (type) == NEXTHOP_TYPE_BLACKHOLE) \ ? (type) : ((type) | 1) -/* Nexthop label structure. */ -struct nexthop_label { - u_int8_t num_labels; - u_int8_t reserved[3]; - mpls_label_t label[0]; /* 1 or more labels. */ -}; - /* Nexthop structure. */ struct nexthop { struct nexthop *next; @@ -107,7 +100,7 @@ struct nexthop { enum lsp_types_t nh_label_type; /* Label(s) associated with this nexthop. */ - struct nexthop_label *nh_label; + struct mpls_label_stack *nh_label; }; /* The following for loop allows to iterate over the nexthop diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a77814668d..2dc3771b25 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -803,7 +803,7 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, struct rtmsg *rtmsg, size_t req_size, int cmd) { - struct nexthop_label *nh_label; + struct mpls_label_stack *nh_label; mpls_lse_t out_lse[MPLS_MAX_LABELS]; char label_buf[256]; @@ -1003,7 +1003,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, struct rtmsg *rtmsg, union g_addr **src) { - struct nexthop_label *nh_label; + struct mpls_label_stack *nh_label; mpls_lse_t out_lse[MPLS_MAX_LABELS]; char label_buf[256]; diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 0c29f0650c..09fdf0b2d3 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -67,7 +67,7 @@ static int sin_masklen(struct in_addr mask) #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ #ifdef __OpenBSD__ -static int kernel_rtm_add_labels(struct nexthop_label *nh_label, +static int kernel_rtm_add_labels(struct mpls_label_stack *nh_label, struct sockaddr_mpls *smpls) { if (nh_label->num_labels > 1) { diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 4c6fb002dc..193aaa068a 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -104,7 +104,7 @@ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, ifindex_t ifindex, mpls_label_t out_label); static int nhlfe_del(zebra_nhlfe_t *snhlfe); static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe, - struct nexthop_label *nh_label); + struct mpls_label_stack *nh_label); static int mpls_lsp_uninstall_all(struct hash *lsp_table, zebra_lsp_t *lsp, enum lsp_types_t type); static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf, @@ -1217,7 +1217,7 @@ static int nhlfe_del(zebra_nhlfe_t *nhlfe) * Update label for NHLFE entry. */ static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe, - struct nexthop_label *nh_label) + struct mpls_label_stack *nh_label) { nhlfe->nexthop->nh_label->label[0] = nh_label->label[0]; } From 7cf15b250181f0b108c6b9e1899d3bb4f933e836 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 22 Jan 2018 08:16:27 -0500 Subject: [PATCH 56/84] zebra: use zclient_create_header The function zserv_create_header was exactly the same as zclient_create_header. Let's just have one in the system. Signed-off-by: Donald Sharp --- zebra/label_manager.c | 2 +- zebra/zebra_mpls.c | 2 +- zebra/zebra_mroute.c | 2 +- zebra/zebra_ptm_redistribute.c | 5 ++--- zebra/zebra_rnh.c | 2 +- zebra/zebra_vxlan.c | 10 ++++----- zebra/zserv.c | 40 +++++++++++++--------------------- zebra/zserv.h | 2 -- 8 files changed, 26 insertions(+), 39 deletions(-) diff --git a/zebra/label_manager.c b/zebra/label_manager.c index f38206d8e1..ace13eda71 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -121,7 +121,7 @@ static int reply_error(int cmd, struct zserv *zserv, vrf_id_t vrf_id) s = zserv->obuf; stream_reset(s); - zserv_create_header(s, cmd, vrf_id); + zclient_create_header(s, cmd, vrf_id); /* result */ stream_putc(s, 1); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 193aaa068a..61051ba87e 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -457,7 +457,7 @@ static int fec_send(zebra_fec_t *fec, struct zserv *client) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT); + zclient_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT); stream_putw(s, rn->p.family); stream_put_prefix(s, &rn->p); diff --git a/zebra/zebra_mroute.c b/zebra/zebra_mroute.c index 519c120a67..e9cd19ebe0 100644 --- a/zebra/zebra_mroute.c +++ b/zebra/zebra_mroute.c @@ -61,7 +61,7 @@ stream_failure: stream_reset(s); - zserv_create_header(s, ZEBRA_IPMR_ROUTE_STATS, zvrf_id(zvrf)); + zclient_create_header(s, ZEBRA_IPMR_ROUTE_STATS, zvrf_id(zvrf)); stream_put_in_addr(s, &mroute.sg.src); stream_put_in_addr(s, &mroute.sg.grp); stream_put(s, &mroute.lastused, sizeof(mroute.lastused)); diff --git a/zebra/zebra_ptm_redistribute.c b/zebra/zebra_ptm_redistribute.c index 1378ea186d..8fddd400cc 100644 --- a/zebra/zebra_ptm_redistribute.c +++ b/zebra/zebra_ptm_redistribute.c @@ -41,7 +41,7 @@ static int zsend_interface_bfd_update(int cmd, struct zserv *client, s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, vrf_id); + zclient_create_header(s, cmd, vrf_id); if (ifp) stream_putl(s, ifp->ifindex); else @@ -96,8 +96,7 @@ static int zsend_bfd_peer_replay(int cmd, struct zserv *client) s = client->obuf; stream_reset(s); - zserv_create_header( - s, cmd, VRF_DEFAULT); // Pending: adjust when multi-vrf bfd work + zclient_create_header(s, cmd, VRF_DEFAULT); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 33d0b3a641..825dea21bb 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -1000,7 +1000,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, vrf_id); + zclient_create_header(s, cmd, vrf_id); stream_putw(s, rn->p.family); switch (rn->p.family) { diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 0ef1802367..1690079f68 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1166,7 +1166,7 @@ static int zvni_macip_send_msg_to_client(vni_t vni, s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, VRF_DEFAULT); + zclient_create_header(s, cmd, VRF_DEFAULT); stream_putl(s, vni); stream_put(s, macaddr->octet, ETH_ALEN); if (ip) { @@ -2531,7 +2531,7 @@ static int zvni_send_add_to_client(zebra_vni_t *zvni) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT); + zclient_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT); stream_putl(s, zvni->vni); stream_put_in_addr(s, &zvni->local_vtep_ip); stream_put(s, &zvni->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */ @@ -2565,7 +2565,7 @@ static int zvni_send_del_to_client(vni_t vni) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_VNI_DEL, VRF_DEFAULT); + zclient_create_header(s, ZEBRA_VNI_DEL, VRF_DEFAULT); stream_putl(s, vni); /* Write packet size. */ @@ -3550,7 +3550,7 @@ static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_L3VNI_ADD, + zclient_create_header(s, ZEBRA_L3VNI_ADD, zl3vni_vrf_id(zl3vni)); stream_putl(s, zl3vni->vni); stream_put(s, &rmac, sizeof(struct ethaddr)); @@ -3586,7 +3586,7 @@ static int zl3vni_send_del_to_client(zebra_l3vni_t *zl3vni) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_L3VNI_DEL, + zclient_create_header(s, ZEBRA_L3VNI_DEL, zl3vni_vrf_id(zl3vni)); stream_putl(s, zl3vni->vni); diff --git a/zebra/zserv.c b/zebra/zserv.c index 6241a16389..604054f2ab 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -149,16 +149,6 @@ int zebra_server_send_message(struct zserv *client) return 0; } -void zserv_create_header(struct stream *s, uint16_t cmd, vrf_id_t vrf_id) -{ - /* length placeholder, caller can update */ - stream_putw(s, ZEBRA_HEADER_SIZE); - stream_putc(s, ZEBRA_HEADER_MARKER); - stream_putc(s, ZSERV_VERSION); - stream_putl(s, vrf_id); - stream_putw(s, cmd); -} - static void zserv_encode_interface(struct stream *s, struct interface *ifp) { /* Interface information. */ @@ -221,7 +211,7 @@ int zsend_interface_add(struct zserv *client, struct interface *ifp) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); zserv_encode_interface(s, ifp); client->ifadd_cnt++; @@ -236,7 +226,7 @@ int zsend_interface_delete(struct zserv *client, struct interface *ifp) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); zserv_encode_interface(s, ifp); client->ifdel_cnt++; @@ -250,7 +240,7 @@ int zsend_vrf_add(struct zserv *client, struct zebra_vrf *zvrf) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_VRF_ADD, zvrf_id(zvrf)); + zclient_create_header(s, ZEBRA_VRF_ADD, zvrf_id(zvrf)); zserv_encode_vrf(s, zvrf); client->vrfadd_cnt++; @@ -265,7 +255,7 @@ int zsend_vrf_delete(struct zserv *client, struct zebra_vrf *zvrf) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_VRF_DELETE, zvrf_id(zvrf)); + zclient_create_header(s, ZEBRA_VRF_DELETE, zvrf_id(zvrf)); zserv_encode_vrf(s, zvrf); client->vrfdel_cnt++; @@ -285,7 +275,7 @@ int zsend_interface_link_params(struct zserv *client, struct interface *ifp) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id); /* Add Interface Index */ stream_putl(s, ifp->ifindex); @@ -348,7 +338,7 @@ int zsend_interface_address(int cmd, struct zserv *client, s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, ifp->vrf_id); + zclient_create_header(s, cmd, ifp->vrf_id); stream_putl(s, ifp->ifindex); /* Interface address flag. */ @@ -393,7 +383,7 @@ static int zsend_interface_nbr_address(int cmd, struct zserv *client, s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, ifp->vrf_id); + zclient_create_header(s, cmd, ifp->vrf_id); stream_putl(s, ifp->ifindex); /* Prefix information. */ @@ -504,7 +494,7 @@ int zsend_interface_vrf_update(struct zserv *client, struct interface *ifp, s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf_id); /* Fill in the ifIndex of the interface and its new VRF (id) */ stream_putl(s, ifp->ifindex); @@ -581,7 +571,7 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp) s = client->obuf; stream_reset(s); - zserv_create_header(s, cmd, ifp->vrf_id); + zclient_create_header(s, cmd, ifp->vrf_id); zserv_encode_interface(s, ifp); if (cmd == ZEBRA_INTERFACE_UP) @@ -957,7 +947,7 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, stream_reset(s); /* Fill in result. */ - zserv_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, zvrf_id(zvrf)); + zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, zvrf_id(zvrf)); stream_put_in_addr(s, &addr); if (re) { @@ -1009,7 +999,7 @@ int zsend_route_notify_owner(u_char proto, u_short instance, s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, vrf_id); + zclient_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, vrf_id); stream_put(s, ¬e, sizeof(note)); @@ -1039,7 +1029,7 @@ int zsend_router_id_update(struct zserv *client, struct prefix *p, stream_reset(s); /* Message type. */ - zserv_create_header(s, ZEBRA_ROUTER_ID_UPDATE, vrf_id); + zclient_create_header(s, ZEBRA_ROUTER_ID_UPDATE, vrf_id); /* Prefix information. */ stream_putc(s, p->family); @@ -1063,7 +1053,7 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id); + zclient_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id); stream_write(s, pw->ifname, IF_NAMESIZE); stream_putl(s, pw->ifindex); stream_putl(s, pw->status); @@ -2089,7 +2079,7 @@ static int zsend_label_manager_connect_response(struct zserv *client, s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id); + zclient_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id); /* result */ stream_putc(s, result); @@ -2151,7 +2141,7 @@ static int zsend_assign_label_chunk_response(struct zserv *client, s = client->obuf; stream_reset(s); - zserv_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id); + zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id); if (lmc) { /* keep */ diff --git a/zebra/zserv.h b/zebra/zserv.h index 63db9d9eb9..4b3b0041b8 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -177,8 +177,6 @@ extern int zsend_route_notify_owner(u_char proto, u_short instance, vrf_id_t vrf_id, struct prefix *p, enum zapi_route_notify_owner note); -extern void zserv_create_header(struct stream *s, uint16_t cmd, - vrf_id_t vrf_id); extern void zserv_nexthop_num_warn(const char *, const struct prefix *, const unsigned int); extern int zebra_server_send_message(struct zserv *client); From f674dfe234515156eca7618bf2fc647ccfd34787 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Wed, 20 Sep 2017 00:05:25 -0300 Subject: [PATCH 57/84] zebra: implement recursive MPLS labels When a nexthop is resolved via a label based nexthop, copy the labels into the newly created recursive nexthop. Please note that this does not fix the case where we have a label based nexthop that is recursively resolved through *another* nexthop that is also label based. In this case we need to create a new label stack for those routes. Signed-off-by: Renato Westphal --- zebra/zebra_rib.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 41e14459b1..f7f05ba68a 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -372,6 +372,12 @@ static void nexthop_set_resolved(afi_t afi, struct nexthop *newhop, break; } + /* Copy labels of the resolved route */ + if (newhop->nh_label) + nexthop_add_labels(resolved_hop, newhop->nh_label_type, + newhop->nh_label->num_labels, + &newhop->nh_label->label[0]); + resolved_hop->rparent = nexthop; nexthop_add(&nexthop->resolved, resolved_hop); } From eb2277cf2dd8205e02d9bdf19814ddd1b299ceae Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Sun, 7 Jan 2018 09:41:53 -0500 Subject: [PATCH 58/84] bgpd: update last_update whenever obuf sent (to be consistent with last_write updates) Signed-off-by: Lou Berger --- bgpd/bgp_io.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index 98a8ec6e02..f4bfc90b7e 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -375,14 +375,10 @@ static uint16_t bgp_write(struct peer *peer) int num; int update_last_write = 0; unsigned int count = 0; - uint32_t oc; - uint32_t uo; + uint32_t uo = 0; uint16_t status = 0; uint32_t wpkt_quanta_old; - // save current # updates sent - oc = atomic_load_explicit(&peer->update_out, memory_order_relaxed); - // cache current write quanta wpkt_quanta_old = atomic_load_explicit(&peer->bgp->wpkt_quanta, memory_order_relaxed); @@ -419,6 +415,7 @@ static uint16_t bgp_write(struct peer *peer) case BGP_MSG_UPDATE: atomic_fetch_add_explicit(&peer->update_out, 1, memory_order_relaxed); + uo++; break; case BGP_MSG_NOTIFY: atomic_fetch_add_explicit(&peer->notify_out, 1, @@ -457,9 +454,12 @@ static uint16_t bgp_write(struct peer *peer) } done : { - /* Update last_update if UPDATEs were written. */ - uo = atomic_load_explicit(&peer->update_out, memory_order_relaxed); - if (uo > oc) + /* + * Update last_update if UPDATEs were written. + * Note: that these are only updated at end, + * not per message (i.e., per loop) + */ + if (uo) atomic_store_explicit(&peer->last_update, bgp_clock(), memory_order_relaxed); From 0d9e7f455e0c5cb4bfac9d0b955adcc529d56431 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 22 Jan 2018 18:16:59 -0500 Subject: [PATCH 59/84] lib: Cleanup some zclient clutter. The zclient code can be cleaned up a tiny bit and hopefully improve it's indentation some. Signed-off-by: Donald Sharp --- lib/zclient.c | 78 +++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index d4a7b45b97..b5372a32ee 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -389,25 +389,28 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id) vrf_id); /* Flush all redistribute request. */ - if (vrf_id == VRF_DEFAULT) - for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if (zclient->mi_redist[afi][i].enabled) { - struct listnode *node; - u_short *id; + if (vrf_id == VRF_DEFAULT) { + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { + if (!zclient->mi_redist[afi][i].enabled) + continue; - for (ALL_LIST_ELEMENTS_RO( - zclient->mi_redist[afi][i] - .instances, - node, id)) - if (!(i == zclient->redist_default - && *id == zclient->instance)) - zebra_redistribute_send( - ZEBRA_REDISTRIBUTE_ADD, - zclient, afi, i, - *id, - VRF_DEFAULT); - } + struct listnode *node; + u_short *id; + + for (ALL_LIST_ELEMENTS_RO( + zclient->mi_redist[afi][i] + .instances, node, id)) + if (!(i == zclient->redist_default + && *id == zclient->instance)) + zebra_redistribute_send( + ZEBRA_REDISTRIBUTE_ADD, + zclient, afi, i, + *id, + VRF_DEFAULT); + } + } + } /* Flush all redistribute request. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) @@ -451,25 +454,28 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id) vrf_id); /* Flush all redistribute request. */ - if (vrf_id == VRF_DEFAULT) - for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if (zclient->mi_redist[afi][i].enabled) { - struct listnode *node; - u_short *id; + if (vrf_id == VRF_DEFAULT) { + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { + if (!zclient->mi_redist[afi][i].enabled) + continue; - for (ALL_LIST_ELEMENTS_RO( - zclient->mi_redist[afi][i] - .instances, - node, id)) - if (!(i == zclient->redist_default - && *id == zclient->instance)) - zebra_redistribute_send( - ZEBRA_REDISTRIBUTE_DELETE, - zclient, afi, i, - *id, - VRF_DEFAULT); - } + struct listnode *node; + u_short *id; + + for (ALL_LIST_ELEMENTS_RO( + zclient->mi_redist[afi][i] + .instances, node, id)) + if (!(i == zclient->redist_default + && *id == zclient->instance)) + zebra_redistribute_send( + ZEBRA_REDISTRIBUTE_DELETE, + zclient, afi, i, + *id, + VRF_DEFAULT); + } + } + } /* Flush all redistribute request. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) From 09eef679fb19ef0a731f4a72009eed071847da19 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 22 Jan 2018 18:18:38 -0500 Subject: [PATCH 60/84] lib: Unset bitmap when not using it The zclient->redist bitmap for vrf's was being set again for the zclient_send_dereg_requests function. This should be a unset on tear down. Signed-off-by: Donald Sharp --- lib/zclient.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index b5372a32ee..9045b5b6ce 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -450,8 +450,8 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id) /* Set unwanted redistribute route. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) - vrf_bitmap_set(zclient->redist[afi][zclient->redist_default], - vrf_id); + vrf_bitmap_unset(zclient->redist[afi][zclient->redist_default], + vrf_id); /* Flush all redistribute request. */ if (vrf_id == VRF_DEFAULT) { From daeda3d7ff34ec1c4f26f987ec361364f5ef7b66 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 22 Jan 2018 18:22:09 -0500 Subject: [PATCH 61/84] pimd: No need to assert on the redist_default zclient_init sets the redist_default to the appropriate value, testing it with an assert doesn't really provide us with much of anything useful. Signed-off-by: Donald Sharp --- pimd/pim_zebra.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 6e82558766..2970dcee5e 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -765,8 +765,6 @@ void pim_zebra_init(void) zlog_info("zclient_init cleared redistribution request"); } - zassert(zclient->redist_default == ZEBRA_ROUTE_PIM); - /* Request all redistribution */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (i == zclient->redist_default) From 3c1925406846d0e2d981086ea4d3c9fb09dc8b4a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 22 Jan 2018 18:36:03 -0500 Subject: [PATCH 62/84] bgpd, lib, pimd: Abstract commands for nexthop tracking Abstract the code that sends the zapi message into zebra for the turn on/off of nexthop tracking for a prefix. Signed-off-by: Donald Sharp --- bgpd/bgp_nht.c | 29 +++++------------------------ lib/zclient.c | 27 +++++++++++++++++++++++++++ lib/zclient.h | 3 +++ pimd/pim_nht.c | 28 +--------------------------- 4 files changed, 36 insertions(+), 51 deletions(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 247884d294..a963838f5f 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -572,12 +572,11 @@ static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p) */ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) { - struct stream *s; struct prefix *p; + bool exact_match = false; int ret; - /* Check socket. */ - if (!zclient || zclient->sock < 0) + if (!zclient) return; /* Don't try to register if Zebra doesn't know of this instance. */ @@ -585,32 +584,14 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) return; p = &(bnc->node->p); - s = zclient->obuf; - stream_reset(s); - zclient_create_header(s, command, bnc->bgp->vrf_id); if ((command == ZEBRA_NEXTHOP_REGISTER || command == ZEBRA_IMPORT_ROUTE_REGISTER) && (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED) || CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))) - stream_putc(s, 1); - else - stream_putc(s, 0); + exact_match = true; - stream_putw(s, PREFIX_FAMILY(p)); - stream_putc(s, p->prefixlen); - switch (PREFIX_FAMILY(p)) { - case AF_INET: - stream_put_in_addr(s, &p->u.prefix4); - break; - case AF_INET6: - stream_put(s, &(p->u.prefix6), 16); - break; - default: - break; - } - stream_putw_at(s, 0, stream_get_endp(s)); - - ret = zclient_send_message(zclient); + ret = zclient_send_rnh(zclient, command, p, + exact_match, bnc->bgp->vrf_id); /* TBD: handle the failure */ if (ret < 0) zlog_warn("sendmsg_nexthop: zclient_send_message() failed"); diff --git a/lib/zclient.c b/lib/zclient.c index 9045b5b6ce..9d863a3b26 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -614,6 +614,33 @@ static int zclient_connect(struct thread *t) return zclient_start(zclient); } +int zclient_send_rnh(struct zclient *zclient, int command, struct prefix *p, + bool exact_match, vrf_id_t vrf_id) +{ + struct stream *s; + + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, command, vrf_id); + stream_putc(s, (exact_match) ? 1 : 0); + + stream_putw(s, PREFIX_FAMILY(p)); + stream_putc(s, p->prefixlen); + switch (PREFIX_FAMILY(p)) { + case AF_INET: + stream_put_in_addr(s, &p->u.prefix4); + break; + case AF_INET6: + stream_put(s, &(p->u.prefix6), 16); + break; + default: + break; + } + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + /* * "xdr_encode"-like interface that allows daemon (client) to send * a message to zebra server for a route that needs to be diff --git a/lib/zclient.h b/lib/zclient.h index 00ad692718..847c2904d0 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -478,6 +478,9 @@ extern int zapi_ipv4_route_ipv6_nexthop(u_char, struct zclient *, struct zapi_ipv6 *) __attribute__((deprecated)); extern int zclient_route_send(u_char, struct zclient *, struct zapi_route *); +extern int zclient_send_rnh(struct zclient *zclient, int command, + struct prefix *p, bool exact_match, + vrf_id_t vrf_id); extern int zapi_route_encode(u_char, struct stream *, struct zapi_route *); extern int zapi_route_decode(struct stream *, struct zapi_route *); bool zapi_route_notify_decode(struct stream *s, struct prefix *p, diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 089639c77e..ccef796724 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -47,40 +47,14 @@ void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient, struct pim_nexthop_cache *pnc, int command) { - struct stream *s; struct prefix *p; int ret; - /* Check socket. */ - if (!zclient || zclient->sock < 0) - return; - p = &(pnc->rpf.rpf_addr); - s = zclient->obuf; - stream_reset(s); - zclient_create_header(s, command, pim->vrf_id); - /* get update for all routes for a prefix */ - stream_putc(s, 0); - - stream_putw(s, PREFIX_FAMILY(p)); - stream_putc(s, p->prefixlen); - switch (PREFIX_FAMILY(p)) { - case AF_INET: - stream_put_in_addr(s, &p->u.prefix4); - break; - case AF_INET6: - stream_put(s, &(p->u.prefix6), 16); - break; - default: - break; - } - stream_putw_at(s, 0, stream_get_endp(s)); - - ret = zclient_send_message(zclient); + ret = zclient_send_rnh(zclient, command, p, false, pim->vrf_id); if (ret < 0) zlog_warn("sendmsg_nexthop: zclient_send_message() failed"); - if (PIM_DEBUG_PIM_NHT) { char buf[PREFIX2STR_BUFFER]; prefix2str(p, buf, sizeof(buf)); From da086a3ba69a87904f2cb10c75a16ee82b671bf4 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Wed, 17 Jan 2018 10:55:46 -0800 Subject: [PATCH 63/84] ospf6d: spf calculation w/ multiple router lsas An OSPFv3 enabled Router can originate or receive multiple Link State-IDs for Router LSAs. As per RFC 5340 A 4.3, more than one Router LSAs, from given Vertex is considered (as concatenated) single large Router LSA. Created hidden show command to simulate concatenated large LSA from advertising/self Router LSAs. Ticket:CM-19329 Reviewed By: Testing Done: Simulate 160 subinterfaces between R1 === R2--R3, This triggers R1 and R2 to generate multiple link state IDs for Router LSAs. During SPF calculation only aggregated single router LSA processed and SPF tree formed. Signed-off-by: Chirag Shah --- ospf6d/ospf6_area.c | 2 + ospf6d/ospf6_area.h | 1 + ospf6d/ospf6_lsa.c | 2 +- ospf6d/ospf6_lsa.h | 1 + ospf6d/ospf6_spf.c | 345 ++++++++++++++++++++++++++------------------ ospf6d/ospf6_spf.h | 4 + ospf6d/ospf6d.c | 44 ++++++ 7 files changed, 261 insertions(+), 138 deletions(-) diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 252e4a4545..ed624c6ae4 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -221,6 +221,7 @@ struct ospf6_area *ospf6_area_create(u_int32_t area_id, struct ospf6 *o, int df) oa->lsdb->hook_add = ospf6_area_lsdb_hook_add; oa->lsdb->hook_remove = ospf6_area_lsdb_hook_remove; oa->lsdb_self = ospf6_lsdb_create(oa); + oa->temp_router_lsa_lsdb = ospf6_lsdb_create(oa); oa->spf_table = OSPF6_ROUTE_TABLE_CREATE(AREA, SPF_RESULTS); oa->spf_table->scope = oa; @@ -279,6 +280,7 @@ void ospf6_area_delete(struct ospf6_area *oa) ospf6_lsdb_delete(oa->lsdb); ospf6_lsdb_delete(oa->lsdb_self); + ospf6_lsdb_delete(oa->temp_router_lsa_lsdb); ospf6_spf_table_finish(oa->spf_table); ospf6_route_table_delete(oa->spf_table); diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index d212d92387..b7cd9b4b09 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -55,6 +55,7 @@ struct ospf6_area { struct ospf6_lsdb *lsdb; struct ospf6_lsdb *lsdb_self; + struct ospf6_lsdb *temp_router_lsa_lsdb; struct ospf6_route_table *spf_table; struct ospf6_route_table *route_table; diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 82f75b153e..cca4616c16 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -191,7 +191,7 @@ int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2) /* ospf6 age functions */ /* calculate birth */ -static void ospf6_lsa_age_set(struct ospf6_lsa *lsa) +void ospf6_lsa_age_set(struct ospf6_lsa *lsa) { struct timeval now; diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 3536d33d19..db446a3287 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -252,5 +252,6 @@ extern void ospf6_lsa_terminate(void); extern int config_write_ospf6_debug_lsa(struct vty *vty); extern void install_element_ospf6_debug_lsa(void); +extern void ospf6_lsa_age_set(struct ospf6_lsa *lsa); #endif /* OSPF6_LSA_H */ diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 6e6d8a7f00..17ce1771e2 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -163,21 +163,20 @@ static void ospf6_vertex_delete(struct ospf6_vertex *v) } static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, - struct ospf6_vertex *v, - uint32_t link_id) + struct ospf6_vertex *v) { - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa = NULL; u_int16_t type = 0; u_int32_t id = 0, adv_router = 0; if (VERTEX_IS_TYPE(NETWORK, v)) { type = htons(OSPF6_LSTYPE_ROUTER); - id = link_id; + id = htonl(0); adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc); } else { if (ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc)) { type = htons(OSPF6_LSTYPE_ROUTER); - id = link_id; + id = htonl(0); adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc); } else if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, lsdesc)) { type = htons(OSPF6_LSTYPE_NETWORK); @@ -186,19 +185,22 @@ static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, } } - lsa = ospf6_lsdb_lookup(type, id, adv_router, v->area->lsdb); - + if (type == htons(OSPF6_LSTYPE_NETWORK)) + lsa = ospf6_lsdb_lookup(type, id, adv_router, v->area->lsdb); + else + lsa = ospf6_create_single_router_lsa(v->area, v->area->lsdb, + adv_router); if (IS_OSPF6_DEBUG_SPF(PROCESS)) { char ibuf[16], abuf[16]; inet_ntop(AF_INET, &id, ibuf, sizeof(ibuf)); inet_ntop(AF_INET, &adv_router, abuf, sizeof(abuf)); if (lsa) - zlog_debug(" Link to: %s , V %s id %u", lsa->name, - v->name, link_id); + zlog_debug(" Link to: %s len %u, V %s", lsa->name, + ntohs(lsa->header->length), v->name); else - zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s id %u", + zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s", ospf6_lstype_name(type), ibuf, abuf, - v->name, link_id); + v->name); } return lsa; @@ -461,17 +463,14 @@ void ospf6_spf_calculation(u_int32_t router_id, struct ospf6_vertex *root, *v, *w; int size; caddr_t lsdesc; - struct ospf6_lsa *lsa, *self_rtr_lsa = NULL, *rtr_lsa = NULL; - const struct route_node *end = NULL; + struct ospf6_lsa *lsa; struct in6_addr address; - struct ospf6_lsdb *lsdb = NULL; ospf6_spf_table_finish(result_table); /* Install the calculating router itself as the root of the SPF tree */ /* construct root vertex */ - lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_ROUTER), htonl(0), router_id, - oa->lsdb_self); + 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__, @@ -479,8 +478,6 @@ void ospf6_spf_calculation(u_int32_t router_id, return; } - self_rtr_lsa = lsa; - /* initialize */ candidate_list = pqueue_create(); candidate_list->cmp = ospf6_vertex_cmp; @@ -510,139 +507,63 @@ void ospf6_spf_calculation(u_int32_t router_id, && ospf6_router_is_stub_router(v->lsa))) continue; - if (VERTEX_IS_TYPE(ROUTER, v)) { - /* First fetch root Router LSAs from lsdb_self */ - if (v->lsa == self_rtr_lsa) - lsdb = oa->lsdb_self; - else - lsdb = v->area->lsdb; + /* For each LS description in the just-added vertex V's LSA */ + size = (VERTEX_IS_TYPE(ROUTER, v) + ? sizeof(struct ospf6_router_lsdesc) + : sizeof(struct ospf6_network_lsdesc)); + for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4; + lsdesc + size <= OSPF6_LSA_END(v->lsa->header); + lsdesc += size) { + lsa = ospf6_lsdesc_lsa(lsdesc, v); + if (lsa == NULL) + continue; - /* Iterating multiple ROUTER LSAs from same adv router - * with different Link State ID */ - end = ospf6_lsdb_head(lsdb, 2, - htons(OSPF6_LSTYPE_ROUTER), - v->lsa->header->adv_router, - &rtr_lsa); - while (rtr_lsa) { - if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug("%s: Next LSA %s to process" - ,__PRETTY_FUNCTION__, - rtr_lsa->name); - size = sizeof(struct ospf6_router_lsdesc); - /* For each LS description in the just-added vertex V's LSA */ - for (lsdesc = OSPF6_LSA_HEADER_END( - rtr_lsa->header) + 4; - lsdesc + size <= OSPF6_LSA_END( - rtr_lsa->header); - lsdesc += size) { - lsa = ospf6_lsdesc_lsa(lsdesc, v, - rtr_lsa->header->id); - if (lsa == NULL) - continue; + if (OSPF6_LSA_IS_MAXAGE(lsa)) + continue; - if (OSPF6_LSA_IS_MAXAGE(lsa)) - continue; + if (!ospf6_lsdesc_backlink(lsa, lsdesc, v)) + continue; - if (!ospf6_lsdesc_backlink(lsa, - lsdesc, v)) - continue; - - w = ospf6_vertex_create(lsa); - w->area = oa; - w->parent = v; - w->link_id = rtr_lsa->header->id; - - if (VERTEX_IS_TYPE(ROUTER, v)) { - w->cost = v->cost - + ROUTER_LSDESC_GET_METRIC(lsdesc); - w->hops = - v->hops - + (VERTEX_IS_TYPE(NETWORK, w) - ? 0 : 1); - } else /* NETWORK */ { - w->cost = v->cost; - w->hops = v->hops + 1; - } - - /* nexthop calculation */ - if (w->hops == 0) - ospf6_add_nexthop(w->nh_list, - ROUTER_LSDESC_GET_IFID(lsdesc) - , NULL); - else if (w->hops == 1 && v->hops == 0) - ospf6_nexthop_calc(w, v, lsdesc); - else { - ospf6_copy_nexthops(w->nh_list, - v->nh_list); - } - - /* add new candidate to the candidate_list */ - if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug( - " New candidate: %s hops %d cost %d", - w->name, w->hops, - w->cost); - pqueue_enqueue(w, candidate_list); - } - /* Fetch next Link state ID Router LSA */ - rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); - } - } else { - /* For each LS description in the just-added vertex V's LSA */ - size = (VERTEX_IS_TYPE(ROUTER, v) - ? sizeof(struct ospf6_router_lsdesc) - : sizeof(struct ospf6_network_lsdesc)); - for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4; - lsdesc + size <= OSPF6_LSA_END(v->lsa->header); - lsdesc += size) { - lsa = ospf6_lsdesc_lsa(lsdesc, v, v->link_id); - if (lsa == NULL) - continue; - - if (OSPF6_LSA_IS_MAXAGE(lsa)) - continue; - - if (!ospf6_lsdesc_backlink(lsa, lsdesc, v)) - continue; - - w = ospf6_vertex_create(lsa); - w->area = oa; - w->parent = v; - if (VERTEX_IS_TYPE(ROUTER, v)) { - w->cost = v->cost + w = ospf6_vertex_create(lsa); + w->area = oa; + w->parent = v; + if (VERTEX_IS_TYPE(ROUTER, v)) { + w->cost = v->cost + ROUTER_LSDESC_GET_METRIC(lsdesc); - w->hops = - v->hops - + (VERTEX_IS_TYPE(NETWORK, w) ? - 0 : 1); - } else /* NETWORK */ { - w->cost = v->cost; - w->hops = v->hops + 1; - } + w->hops = + v->hops + + (VERTEX_IS_TYPE(NETWORK, w) ? 0 : 1); + } else { + /* NETWORK */ + w->cost = v->cost; + w->hops = v->hops + 1; + } - /* nexthop calculation */ - if (w->hops == 0) - ospf6_add_nexthop(w->nh_list, + /* nexthop calculation */ + if (w->hops == 0) + ospf6_add_nexthop( + w->nh_list, ROUTER_LSDESC_GET_IFID(lsdesc), NULL); - else if (w->hops == 1 && v->hops == 0) - ospf6_nexthop_calc(w, v, lsdesc); - else { - ospf6_copy_nexthops(w->nh_list, - v->nh_list); - } + else if (w->hops == 1 && v->hops == 0) + ospf6_nexthop_calc(w, v, lsdesc); + else + ospf6_copy_nexthops(w->nh_list, v->nh_list); - /* add new candidate to the candidate_list */ - if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug( + + /* add new candidate to the candidate_list */ + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug( " New candidate: %s hops %d cost %d", w->name, w->hops, w->cost); - pqueue_enqueue(w, candidate_list); - } + pqueue_enqueue(w, candidate_list); } } + pqueue_delete(candidate_list); + ospf6_remove_temp_router_lsa(oa); + oa->spf_calculation++; } @@ -1029,3 +950,153 @@ void ospf6_spf_init(void) install_element(OSPF6_NODE, &ospf6_timers_throttle_spf_cmd); install_element(OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd); } + +/* Create Aggregated Large Router-LSA from multiple Link-State IDs + * RFC 5340 A 4.3: + * When more than one router-LSA is received from a single router, + * the links are processed as if concatenated into a single LSA.*/ +struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, + struct ospf6_lsdb *lsdb, + uint32_t adv_router) +{ + struct ospf6_lsa *lsa = NULL; + struct ospf6_lsa *rtr_lsa = NULL; + struct ospf6_lsa_header *lsa_header = NULL; + uint8_t *new_header = NULL; + const struct route_node *end = NULL; + uint16_t lsa_length, total_lsa_length = 0, num_lsa = 0; + u_int16_t type = 0; + char ifbuf[16]; + uint32_t interface_id; + caddr_t lsd; + + lsa_length = sizeof(struct ospf6_lsa_header) + + sizeof(struct ospf6_router_lsa); + total_lsa_length = lsa_length; + type = htons(OSPF6_LSTYPE_ROUTER); + + /* First check Aggregated LSA formed earlier in Cache */ + lsa = ospf6_lsdb_lookup(type, htonl(0), adv_router, + area->temp_router_lsa_lsdb); + if (lsa) + return lsa; + + inet_ntop(AF_INET, &adv_router, ifbuf, sizeof(ifbuf)); + + /* Determine total LSA length from all link state ids */ + end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa); + while (rtr_lsa) { + lsa = rtr_lsa; + if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) { + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + continue; + } + lsa_header = (struct ospf6_lsa_header *) rtr_lsa->header; + total_lsa_length += (ntohs(lsa_header->length) + - lsa_length); + num_lsa++; + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + } + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s: adv_router %s num_lsa %u to convert.", + __PRETTY_FUNCTION__, ifbuf, num_lsa); + if (num_lsa == 1) + return lsa; + + if (num_lsa == 0) { + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s: adv_router %s not found in LSDB.", + __PRETTY_FUNCTION__, ifbuf); + return NULL; + } + + /* Allocate memory for this LSA */ + new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, total_lsa_length); + if (!new_header) + return NULL; + + /* LSA information structure */ + lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA, + sizeof(struct ospf6_lsa)); + if (!lsa) { + free(new_header); + return NULL; + } + + lsa->header = (struct ospf6_lsa_header *)new_header; + + lsa->lsdb = area->temp_router_lsa_lsdb; + + /* Fill Larger LSA Payload */ + end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa); + if (rtr_lsa) { + if (!OSPF6_LSA_IS_MAXAGE(rtr_lsa)) { + /* Append first Link State ID LSA */ + lsa_header = (struct ospf6_lsa_header *)rtr_lsa->header; + memcpy(new_header, lsa_header, + ntohs(lsa_header->length)); + /* Assign new lsa length as aggregated length. */ + ((struct ospf6_lsa_header *)new_header)->length = + htons(total_lsa_length); + new_header += ntohs(lsa_header->length); + num_lsa--; + } + } + + /* Print LSA Name */ + ospf6_lsa_printbuf(lsa, lsa->name, sizeof(lsa->name)); + + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + while (rtr_lsa) { + if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) { + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + continue; + } + + if (IS_OSPF6_DEBUG_SPF(PROCESS)) { + lsd = OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4; + interface_id = ROUTER_LSDESC_GET_IFID(lsd); + inet_ntop(AF_INET, &interface_id, ifbuf, sizeof(ifbuf)); + zlog_debug("%s: Next Router LSA %s to aggreat with len %u interface_id %s", + __PRETTY_FUNCTION__, rtr_lsa->name, + ntohs(lsa_header->length), ifbuf); + } + + /* Append Next Link State ID LSA */ + lsa_header = (struct ospf6_lsa_header *) rtr_lsa->header; + memcpy(new_header, (OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4), + (ntohs(lsa_header->length) - lsa_length)); + new_header += (ntohs(lsa_header->length) - lsa_length); + num_lsa--; + + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + } + + /* Calculate birth of this lsa */ + ospf6_lsa_age_set(lsa); + + /* Store Aggregated LSA into area temp lsdb */ + ospf6_lsdb_add(lsa, area->temp_router_lsa_lsdb); + + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s: LSA %s id %u type 0%x len %u num_lsa %u", + __PRETTY_FUNCTION__, lsa->name, + ntohl(lsa->header->id), ntohs(lsa->header->type), + ntohs(lsa->header->length), num_lsa); + + return lsa; +} + +void ospf6_remove_temp_router_lsa(struct ospf6_area *area) +{ + struct ospf6_lsa *lsa = NULL; + + for (ALL_LSDB(area->temp_router_lsa_lsdb, lsa)) { + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s Remove LSA %s lsa->lock %u lsdb count %u", + __PRETTY_FUNCTION__, + lsa->name, lsa->lock, + area->temp_router_lsa_lsdb->count); + ospf6_lsdb_remove(lsa, area->temp_router_lsa_lsdb); + } +} diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h index dbb88d12ba..f294b8d34f 100644 --- a/ospf6d/ospf6_spf.h +++ b/ospf6d/ospf6_spf.h @@ -149,5 +149,9 @@ extern int config_write_ospf6_debug_spf(struct vty *vty); extern void install_element_ospf6_debug_spf(void); extern void ospf6_spf_init(void); extern void ospf6_spf_reason_string(unsigned int reason, char *buf, int size); +extern struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, + struct ospf6_lsdb *lsdb, + uint32_t adv_router); +extern void ospf6_remove_temp_router_lsa(struct ospf6_area *area); #endif /* OSPF6_SPF_H */ diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index d28d9dd064..bbc1cc18f6 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -360,6 +360,49 @@ DEFUN (show_ipv6_ospf6_database_router, return CMD_SUCCESS; } +DEFUN_HIDDEN (show_ipv6_ospf6_database_aggr_router, + show_ipv6_ospf6_database_aggr_router_cmd, + "show ipv6 ospf6 database aggr adv-router A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Aggregated Router LSA\n" + "Search by Advertising Router\n" + "Specify Advertising Router as IPv4 address notation\n") +{ + int level = OSPF6_LSDB_SHOW_LEVEL_DETAIL; + uint16_t type = htons(OSPF6_LSTYPE_ROUTER); + int idx_ipv4 = 6; + struct listnode *i; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_lsdb *lsdb; + uint32_t adv_router = 0; + + inet_pton(AF_INET, argv[idx_ipv4]->arg, &adv_router); + + for (ALL_LIST_ELEMENTS_RO(o->area_list, i, oa)) { + if (adv_router == o->router_id) + lsdb = oa->lsdb_self; + else + lsdb = oa->lsdb; + if (ospf6_create_single_router_lsa(oa, lsdb, + adv_router) == NULL) { + vty_out(vty, "Adv router is not found in LSDB."); + return CMD_SUCCESS; + } + ospf6_lsdb_show(vty, level, &type, NULL, NULL, + oa->temp_router_lsa_lsdb); + /* Remove the temp cache */ + ospf6_remove_temp_router_lsa(oa); + } + + vty_out(vty, "\n"); + + return CMD_SUCCESS; +} + DEFUN (show_ipv6_ospf6_database_type_id, show_ipv6_ospf6_database_type_id_cmd, "show ipv6 ospf6 database linkstate-id A.B.C.D []", @@ -1219,6 +1262,7 @@ void ospf6_init(void) install_element( VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd); + install_element(VIEW_NODE, &show_ipv6_ospf6_database_aggr_router_cmd); /* Make ospf protocol socket. */ ospf6_serv_sock(); From 139a482cf0fad8056dcd53b554f467079d0b7e68 Mon Sep 17 00:00:00 2001 From: Olivier Dugeon Date: Tue, 23 Jan 2018 16:15:58 +0100 Subject: [PATCH 64/84] OSPFD: Solve Issue #1652 Issue 1652 was related to OSPF Crash on termination when ospf is configured to flood self Opaque LSA e.g TE or RI Opaque LSA. Analysis: The problem resides in free_opaque_info_per_type() line 576 of ospf_opaque.c. Once LSA flush, the function removes by calling listnode_delete() function the opaque_info_per_type data structure. However, this is also performed at the upper level function ospf_opaque_type10lsa_term() which call list_delete_and_null() function. This result into a double free pointer exception. Solution: Remove call to listnode_delete() calls in free_opaque_info_per_type() function as it is done by list_delete_and_null(). Delete lines 592 - 615. Remove also second call to ospf_opaque_type10lsa_term() in ospfd.c line 848. Signed-off-by: Olivier Dugeon --- ospfd/ospf_opaque.c | 24 ------------------------ ospfd/ospfd.c | 1 - 2 files changed, 25 deletions(-) diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 6f9da92542..1bd6bf8d4c 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -589,30 +589,6 @@ static void free_opaque_info_per_type(void *val) ospf_opaque_lsa_flush_schedule(lsa); } - /* Remove "oipt" from its owner's self-originated LSA list. */ - switch (oipt->lsa_type) { - case OSPF_OPAQUE_LINK_LSA: { - struct ospf_interface *oi = - (struct ospf_interface *)(oipt->owner); - listnode_delete(oi->opaque_lsa_self, oipt); - break; - } - case OSPF_OPAQUE_AREA_LSA: { - struct ospf_area *area = (struct ospf_area *)(oipt->owner); - listnode_delete(area->opaque_lsa_self, oipt); - break; - } - case OSPF_OPAQUE_AS_LSA: { - struct ospf *top = (struct ospf *)(oipt->owner); - listnode_delete(top->opaque_lsa_self, oipt); - break; - } - default: - zlog_warn("free_opaque_info_per_type: Unexpected LSA-type(%u)", - oipt->lsa_type); - break; /* This case may not exist. */ - } - OSPF_TIMER_OFF(oipt->t_opaque_lsa_self); list_delete_and_null(&oipt->id_list); XFREE(MTYPE_OPAQUE_INFO_PER_TYPE, oipt); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 1926197430..d3ad7772f9 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -845,7 +845,6 @@ static void ospf_area_free(struct ospf_area *area) LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) ospf_discard_from_db(area->ospf, area->lsdb, lsa); - ospf_opaque_type10_lsa_term(area); ospf_lsdb_delete_all(area->lsdb); ospf_lsdb_free(area->lsdb); From a127f33b977ea6e119d1b3bb94805b9d756b80a9 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 18 Dec 2017 13:19:22 -0500 Subject: [PATCH 65/84] bgpd: fix race condition causing occasional assert If a BGP message header fails validation we send a BGP NOTIFICATION from the I/O thread. At this time we clear the output buffer, push a NOTIFICATION and then call the manual write function for errors. But in between the push and the write the main thread could have pushed some other message. Thus we need to hold the lock for the duration of the function. TOCTTOU. Signed-off-by: Quentin Young --- bgpd/bgp_packet.c | 52 ++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index eed5fdc65d..0ce2466f52 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -545,19 +545,26 @@ void bgp_open_send(struct peer *peer) bgp_writes_on(peer); } -/* This is only for sending NOTIFICATION message to neighbor. */ +/* + * Writes NOTIFICATION message directly to a peer socket without waiting for + * the I/O thread. + * + * There must be exactly one stream on the peer->obuf FIFO, and the data within + * this stream must match the format of a BGP NOTIFICATION message. + * Transmission is best-effort. + * + * @requires peer->io_mtx + * @param peer + * @return 0 + */ static int bgp_write_notify(struct peer *peer) { int ret, val; u_char type; struct stream *s; - pthread_mutex_lock(&peer->io_mtx); - { - /* There should be at least one packet. */ - s = stream_fifo_pop(peer->obuf); - } - pthread_mutex_unlock(&peer->io_mtx); + /* There should be at least one packet. */ + s = stream_fifo_pop(peer->obuf); if (!s) return 0; @@ -622,6 +629,14 @@ static int bgp_write_notify(struct peer *peer) * This function attempts to write the packet from the thread it is called * from, to ensure the packet gets out ASAP. * + * This function may be called from multiple threads. Since the function + * modifies I/O buffer(s) in the peer, these are locked for the duration of the + * call to prevent tampering from other threads. + * + * Delivery of the NOTIFICATION is attempted once and is best-effort. After + * return, the peer structure *must* be reset; no assumptions about session + * state are valid. + * * @param peer * @param code BGP error code * @param sub_code BGP error subcode @@ -634,6 +649,10 @@ void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code, struct stream *s; int length; + /* Lock I/O mutex to prevent other threads from pushing packets */ + pthread_mutex_lock(&peer->io_mtx); + /* ============================================== */ + /* Allocate new stream. */ s = stream_new(BGP_MAX_PACKET_SIZE); @@ -651,20 +670,8 @@ void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code, /* Set BGP packet length. */ length = bgp_packet_set_size(s); - /* - * Turn off keepalive generation for peer. This is necessary because - * otherwise between the time we wipe the output buffer and the time we - * push the NOTIFY onto it, the KA generation thread could have pushed - * a KEEPALIVE in the middle. - */ - bgp_keepalives_off(peer); - /* wipe output buffer */ - pthread_mutex_lock(&peer->io_mtx); - { - stream_fifo_clean(peer->obuf); - } - pthread_mutex_unlock(&peer->io_mtx); + stream_fifo_clean(peer->obuf); /* * If possible, store last packet for debugging purposes. This check is @@ -728,9 +735,12 @@ void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code, peer->last_reset = PEER_DOWN_NOTIFY_SEND; /* Add packet to peer's output queue */ - bgp_packet_add(peer, s); + stream_fifo_push(peer->obuf, s); bgp_write_notify(peer); + + /* ============================================== */ + pthread_mutex_unlock(&peer->io_mtx); } /* From 7d974ba3b72ce8c4e46201a3c8b60e1680406883 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 24 Jan 2018 08:22:57 -0500 Subject: [PATCH 66/84] zebra: Modify southbound interface to pass `struct route_node` The route_node that we are working on is going to be interesting to the kernel_route_rib_pass_fail. So I am setting up the code to allow me to pass it. This will be done in a subsuquent commit. Signed-off-by: Donald Sharp --- zebra/rt.h | 8 +++++--- zebra/rt_netlink.c | 9 +++++---- zebra/rt_socket.c | 9 +++++---- zebra/zebra_rib.c | 7 ++++--- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/zebra/rt.h b/zebra/rt.h index bb4ff5bee8..54d45b889a 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -60,15 +60,17 @@ enum southbound_results { * semantics so we will end up with a delete than * a re-add. */ -extern void kernel_route_rib(struct prefix *p, struct prefix *src_p, - struct route_entry *old, struct route_entry *new); +extern void kernel_route_rib(struct route_node *rn, struct prefix *p, + struct prefix *src_p, struct route_entry *old, + struct route_entry *new); /* * So route install/failure may not be immediately known * so let's separate it out and allow the result to * be passed back up. */ -extern void kernel_route_rib_pass_fail(struct prefix *p, +extern void kernel_route_rib_pass_fail(struct route_node *rn, + struct prefix *p, struct route_entry *re, enum southbound_results res); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 0221162a30..20cc292e11 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1642,8 +1642,9 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) return suc; } -void kernel_route_rib(struct prefix *p, struct prefix *src_p, - struct route_entry *old, struct route_entry *new) +void kernel_route_rib(struct route_node *rn, struct prefix *p, + struct prefix *src_p, struct route_entry *old, + struct route_entry *new) { int ret = 0; @@ -1672,7 +1673,7 @@ void kernel_route_rib(struct prefix *p, struct prefix *src_p, ret = netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 0); } - kernel_route_rib_pass_fail(p, new, + kernel_route_rib_pass_fail(rn, p, new, (!ret) ? SOUTHBOUND_INSTALL_SUCCESS : SOUTHBOUND_INSTALL_FAILURE); @@ -1682,7 +1683,7 @@ void kernel_route_rib(struct prefix *p, struct prefix *src_p, if (old) { ret = netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0); - kernel_route_rib_pass_fail(p, old, + kernel_route_rib_pass_fail(rn, p, old, (!ret) ? SOUTHBOUND_DELETE_SUCCESS : SOUTHBOUND_DELETE_FAILURE); diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 09fdf0b2d3..6d4af1203c 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -387,8 +387,9 @@ static int kernel_rtm(int cmd, struct prefix *p, struct route_entry *re) return 0; } -void kernel_route_rib(struct prefix *p, struct prefix *src_p, - struct route_entry *old, struct route_entry *new) +void kernel_route_rib(struct route_node *rn, struct prefix *p, + struct prefix *src_p, struct route_entry *old, + struct route_entry *new) { int route = 0; @@ -410,12 +411,12 @@ void kernel_route_rib(struct prefix *p, struct prefix *src_p, zlog_err("Can't lower privileges"); if (new) { - kernel_route_rib_pass_fail(p, new, + kernel_route_rib_pass_fail(rn, p, new, (!route) ? SOUTHBOUND_INSTALL_SUCCESS : SOUTHBOUND_INSTALL_FAILURE); } else { - kernel_route_rib_pass_fail(p, old, + kernel_route_rib_pass_fail(rn, p, old, (!route) ? SOUTHBOUND_DELETE_SUCCESS : SOUTHBOUND_DELETE_FAILURE); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 78077a4b3d..83eff7bdcf 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -998,7 +998,8 @@ int zebra_rib_labeled_unicast(struct route_entry *re) return 1; } -void kernel_route_rib_pass_fail(struct prefix *p, struct route_entry *re, +void kernel_route_rib_pass_fail(struct route_node *rn, struct prefix *p, + struct route_entry *re, enum southbound_results res) { struct nexthop *nexthop; @@ -1083,7 +1084,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, * the kernel. */ hook_call(rib_update, rn, "installing in kernel"); - kernel_route_rib(p, src_p, old, re); + kernel_route_rib(rn, p, src_p, old, re); zvrf->installs++; return; @@ -1110,7 +1111,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) * the kernel. */ hook_call(rib_update, rn, "uninstalling from kernel"); - kernel_route_rib(p, src_p, re, NULL); + kernel_route_rib(rn, p, src_p, re, NULL); zvrf->removals++; return; From a45dc9742c3e4e504f66bf18b7bc9da3c218233a Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 22 Jan 2018 14:23:55 -0500 Subject: [PATCH 67/84] lib: streamline frr_pthreads, add default loop Some work on FRR's pthread wrapper. * Provide a built-in way to synchronize thread startup * Make utility functions take frr_pthread * instead of its integer ID * Pass frr_pthread * as pthread start function argument * Correct some comment styling * Rename some variables to match naming conventions in the file * Change parameter ordering in stop function prototype to follow the convention in the other functions * Default new frr_pthreads to using a vanilla event loop For the last point, the original goal when designing the implementation of pthreads into FRR was to be able to use the thread.c event based system inside pthreads. This code essentially encapuslates all the thread.c functionality into an easy to use pthread out of the box. Creating a new frr_pthread with a null attributes field will cause the created frr_pthread to run a thread.c event loop. The upshot of this is that it is now possible to safely run existing functions in a pthread in roughly 3 lines of code. It also serves as an example / starting point for others. Signed-off-by: Quentin Young --- lib/frr_pthread.c | 229 ++++++++++++++++++++++++++++++++-------------- lib/frr_pthread.h | 142 +++++++++++++++++++--------- 2 files changed, 256 insertions(+), 115 deletions(-) diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index de522e5ef9..72b47ae5c3 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -1,5 +1,5 @@ /* - * Utilities and interfaces for managing POSIX threads + * Utilities and interfaces for managing POSIX threads within FRR. * Copyright (C) 2017 Cumulus Networks * * This program is free software; you can redistribute it and/or modify @@ -25,79 +25,99 @@ #include "memory.h" #include "hash.h" -DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread"); +DEFINE_MTYPE(LIB, FRR_PTHREAD, "FRR POSIX Thread"); DEFINE_MTYPE(LIB, PTHREAD_PRIM, "POSIX synchronization primitives"); +/* id for next created pthread */ static unsigned int next_id = 0; -/* Hash table of all frr_pthreads along with synchronization primitive(s) and - * hash table callbacks. - * ------------------------------------------------------------------------ */ -static struct hash *pthread_table; -static pthread_mutex_t pthread_table_mtx = PTHREAD_MUTEX_INITIALIZER; +/* default frr_pthread start/stop routine prototypes */ +static void *fpt_run(void *arg); +static int fpt_halt(struct frr_pthread *fpt, void **res); -/* pthread_table->hash_cmp */ -static int pthread_table_hash_cmp(const void *value1, const void *value2) +/* default frr_pthread attributes */ +struct frr_pthread_attr frr_pthread_attr_default = { + .id = 0, + .start = fpt_run, + .stop = fpt_halt, + .name = "Anonymous", +}; + +/* hash table to keep track of all frr_pthreads */ +static struct hash *frr_pthread_hash; +static pthread_mutex_t frr_pthread_hash_mtx = PTHREAD_MUTEX_INITIALIZER; + +/* frr_pthread_hash->hash_cmp */ +static int frr_pthread_hash_cmp(const void *value1, const void *value2) { const struct frr_pthread *tq1 = value1; const struct frr_pthread *tq2 = value2; - return (tq1->id == tq2->id); + return (tq1->attr.id == tq2->attr.id); } -/* pthread_table->hash_key */ -static unsigned int pthread_table_hash_key(void *value) +/* frr_pthread_hash->hash_key */ +static unsigned int frr_pthread_hash_key(void *value) { - return ((struct frr_pthread *)value)->id; + return ((struct frr_pthread *)value)->attr.id; } + /* ------------------------------------------------------------------------ */ void frr_pthread_init() { - pthread_mutex_lock(&pthread_table_mtx); + pthread_mutex_lock(&frr_pthread_hash_mtx); { - pthread_table = hash_create(pthread_table_hash_key, - pthread_table_hash_cmp, NULL); + frr_pthread_hash = hash_create(frr_pthread_hash_key, + frr_pthread_hash_cmp, NULL); } - pthread_mutex_unlock(&pthread_table_mtx); + pthread_mutex_unlock(&frr_pthread_hash_mtx); } void frr_pthread_finish() { - pthread_mutex_lock(&pthread_table_mtx); + pthread_mutex_lock(&frr_pthread_hash_mtx); { - hash_clean(pthread_table, + hash_clean(frr_pthread_hash, (void (*)(void *))frr_pthread_destroy); - hash_free(pthread_table); + hash_free(frr_pthread_hash); } - pthread_mutex_unlock(&pthread_table_mtx); + pthread_mutex_unlock(&frr_pthread_hash_mtx); } -struct frr_pthread *frr_pthread_new(const char *name, unsigned int id, - void *(*start_routine)(void *), - int (*stop_routine)(void **, - struct frr_pthread *)) +struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr) { static struct frr_pthread holder = {0}; struct frr_pthread *fpt = NULL; - pthread_mutex_lock(&pthread_table_mtx); + attr = attr ? attr : &frr_pthread_attr_default; + + pthread_mutex_lock(&frr_pthread_hash_mtx); { - holder.id = id; + holder.attr.id = attr->id; - if (!hash_lookup(pthread_table, &holder)) { - struct frr_pthread *fpt = XCALLOC( - MTYPE_FRR_PTHREAD, sizeof(struct frr_pthread)); - fpt->id = id; - fpt->master = thread_master_create(name); - fpt->start_routine = start_routine; - fpt->stop_routine = stop_routine; - fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name); + if (!hash_lookup(frr_pthread_hash, &holder)) { + fpt = XCALLOC(MTYPE_FRR_PTHREAD, + sizeof(struct frr_pthread)); + /* create new thread master */ + fpt->master = thread_master_create(attr->name); + /* set attributes */ + fpt->attr = *attr; + if (attr == &frr_pthread_attr_default) + fpt->attr.id = frr_pthread_get_id(); + /* initialize startup synchronization primitives */ + fpt->running_cond_mtx = XCALLOC( + MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t)); + fpt->running_cond = XCALLOC(MTYPE_PTHREAD_PRIM, + sizeof(pthread_cond_t)); + pthread_mutex_init(fpt->running_cond_mtx, NULL); + pthread_cond_init(fpt->running_cond, NULL); - hash_get(pthread_table, fpt, hash_alloc_intern); + /* insert into global thread hash */ + hash_get(frr_pthread_hash, fpt, hash_alloc_intern); } } - pthread_mutex_unlock(&pthread_table_mtx); + pthread_mutex_unlock(&frr_pthread_hash_mtx); return fpt; } @@ -105,7 +125,11 @@ struct frr_pthread *frr_pthread_new(const char *name, unsigned int id, void frr_pthread_destroy(struct frr_pthread *fpt) { thread_master_free(fpt->master); - XFREE(MTYPE_FRR_PTHREAD, fpt->name); + + pthread_mutex_destroy(fpt->running_cond_mtx); + pthread_cond_destroy(fpt->running_cond); + XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond_mtx); + XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond); XFREE(MTYPE_FRR_PTHREAD, fpt); } @@ -114,74 +138,82 @@ struct frr_pthread *frr_pthread_get(unsigned int id) static struct frr_pthread holder = {0}; struct frr_pthread *fpt; - pthread_mutex_lock(&pthread_table_mtx); + pthread_mutex_lock(&frr_pthread_hash_mtx); { - holder.id = id; - fpt = hash_lookup(pthread_table, &holder); + holder.attr.id = id; + fpt = hash_lookup(frr_pthread_hash, &holder); } - pthread_mutex_unlock(&pthread_table_mtx); + pthread_mutex_unlock(&frr_pthread_hash_mtx); return fpt; } -int frr_pthread_run(unsigned int id, const pthread_attr_t *attr, void *arg) +int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr) { - struct frr_pthread *fpt = frr_pthread_get(id); int ret; - if (!fpt) - return -1; + ret = pthread_create(&fpt->thread, attr, fpt->attr.start, fpt); - ret = pthread_create(&fpt->thread, attr, fpt->start_routine, arg); - - /* Per pthread_create(3), the contents of fpt->thread are undefined if - * pthread_create() did not succeed. Reset this value to zero. */ + /* + * Per pthread_create(3), the contents of fpt->thread are undefined if + * pthread_create() did not succeed. Reset this value to zero. + */ if (ret < 0) memset(&fpt->thread, 0x00, sizeof(fpt->thread)); return ret; } -/** - * Calls the stop routine for the frr_pthread and resets any relevant fields. - * - * @param fpt - the frr_pthread to stop - * @param result - pointer to result pointer - * @return the return code from the stop routine - */ -static int frr_pthread_stop_actual(struct frr_pthread *fpt, void **result) +void frr_pthread_wait_running(struct frr_pthread *fpt) { - int ret = (*fpt->stop_routine)(result, fpt); + pthread_mutex_lock(fpt->running_cond_mtx); + { + while (!fpt->running) + pthread_cond_wait(fpt->running_cond, + fpt->running_cond_mtx); + } + pthread_mutex_unlock(fpt->running_cond_mtx); +} + +void frr_pthread_notify_running(struct frr_pthread *fpt) +{ + pthread_mutex_lock(fpt->running_cond_mtx); + { + fpt->running = true; + pthread_cond_signal(fpt->running_cond); + } + pthread_mutex_unlock(fpt->running_cond_mtx); +} + +int frr_pthread_stop(struct frr_pthread *fpt, void **result) +{ + int ret = (*fpt->attr.stop)(fpt, result); memset(&fpt->thread, 0x00, sizeof(fpt->thread)); return ret; } -int frr_pthread_stop(unsigned int id, void **result) -{ - struct frr_pthread *fpt = frr_pthread_get(id); - return frr_pthread_stop_actual(fpt, result); -} - -/** +/* * Callback for hash_iterate to stop all frr_pthread's. */ static void frr_pthread_stop_all_iter(struct hash_backet *hb, void *arg) { struct frr_pthread *fpt = hb->data; - frr_pthread_stop_actual(fpt, NULL); + frr_pthread_stop(fpt, NULL); } void frr_pthread_stop_all() { - pthread_mutex_lock(&pthread_table_mtx); + pthread_mutex_lock(&frr_pthread_hash_mtx); { - hash_iterate(pthread_table, frr_pthread_stop_all_iter, NULL); + hash_iterate(frr_pthread_hash, frr_pthread_stop_all_iter, NULL); } - pthread_mutex_unlock(&pthread_table_mtx); + pthread_mutex_unlock(&frr_pthread_hash_mtx); } unsigned int frr_pthread_get_id() { + /* just a sanity check, this should never happen */ + assert(next_id <= INT_MAX - 1); return next_id++; } @@ -189,3 +221,60 @@ void frr_pthread_yield(void) { (void)sched_yield(); } + +/* + * ---------------------------------------------------------------------------- + * Default Event Loop + * ---------------------------------------------------------------------------- + */ + +/* dummy task for sleeper pipe */ +static int fpt_dummy(struct thread *thread) +{ + return 0; +} + +/* poison pill task to end event loop */ +static int fpt_finish(struct thread *thread) +{ + struct frr_pthread *fpt = THREAD_ARG(thread); + atomic_store_explicit(&fpt->running, false, memory_order_relaxed); + return 0; +} + +/* stop function, called from other threads to halt this one */ +static int fpt_halt(struct frr_pthread *fpt, void **res) +{ + thread_add_event(fpt->master, &fpt_finish, fpt, 0, NULL); + pthread_join(fpt->thread, res); + fpt = NULL; + + return 0; +} + +/* entry pthread function & main event loop */ +static void *fpt_run(void *arg) +{ + struct frr_pthread *fpt = arg; + fpt->master->owner = pthread_self(); + + int sleeper[2]; + pipe(sleeper); + thread_add_read(fpt->master, &fpt_dummy, NULL, sleeper[0], NULL); + + fpt->master->handle_signals = false; + + frr_pthread_notify_running(fpt); + + struct thread task; + while (atomic_load_explicit(&fpt->running, memory_order_relaxed)) { + if (thread_fetch(fpt->master, &task)) { + thread_call(&task); + } + } + + close(sleeper[1]); + close(sleeper[0]); + + return NULL; +} diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h index 7915b43a46..2cc50196a8 100644 --- a/lib/frr_pthread.h +++ b/lib/frr_pthread.h @@ -1,5 +1,5 @@ /* - * Utilities and interfaces for managing POSIX threads + * Utilities and interfaces for managing POSIX threads within FRR. * Copyright (C) 2017 Cumulus Networks * * This program is free software; you can redistribute it and/or modify @@ -21,39 +21,73 @@ #define _FRR_PTHREAD_H #include +#include "frratomic.h" #include "memory.h" #include "thread.h" +DECLARE_MTYPE(FRR_PTHREAD); DECLARE_MTYPE(PTHREAD_PRIM); +struct frr_pthread; +struct frr_pthread_attr; + +struct frr_pthread_attr { + int id; + void *(*start)(void *); + int (*stop)(struct frr_pthread *, void **); + const char *name; +}; + struct frr_pthread { /* pthread id */ pthread_t thread; - /* frr thread identifier */ - unsigned int id; - /* thread master for this pthread's thread.c event loop */ struct thread_master *master; - /* start routine */ - void *(*start_routine)(void *); + /* caller-specified data; start & stop funcs, name, id */ + struct frr_pthread_attr attr; - /* stop routine */ - int (*stop_routine)(void **, struct frr_pthread *); + /* + * Notification mechanism for allowing pthreads to notify their parents + * when they are ready to do work. This mechanism has two associated + * functions: + * + * - frr_pthread_wait_running() + * This function should be called by the spawning thread after + * frr_pthread_run(). It safely waits until the spawned thread + * indicates that is ready to do work by posting to the condition + * variable. + * + * - frr_pthread_notify_running() + * This function should be called by the spawned thread when it is + * ready to do work. It will wake up any threads waiting on the + * previously described condition. + */ + pthread_cond_t *running_cond; + pthread_mutex_t *running_cond_mtx; + _Atomic bool running; - /* the (hopefully descriptive) name of this thread */ - char *name; + /* + * Fake thread-specific storage. No constraints on usage. Helpful when + * creating reentrant pthread implementations. Can be used to pass + * argument to pthread entry function. + */ + void *data; }; -/* Initializes this module. +extern struct frr_pthread_attr frr_pthread_attr_default; + +/* + * Initializes this module. * * Must be called before using any of the other functions. */ void frr_pthread_init(void); -/* Uninitializes this module. +/* + * Uninitializes this module. * * Destroys all registered frr_pthread's and internal data structures. * @@ -62,34 +96,23 @@ void frr_pthread_init(void); */ void frr_pthread_finish(void); -/* Creates a new frr_pthread. +/* + * Creates a new frr_pthread with the given attributes. * - * If the provided ID is already assigned to an existing frr_pthread, the - * return value will be NULL. - * - * @param name - the name of the thread. Doesn't have to be unique, but it - * probably should be. This value is copied and may be safely free'd upon - * return. - * - * @param id - the integral ID of the thread. MUST be unique. The caller may - * use this id to retrieve the thread. - * - * @param start_routine - start routine for the pthread, will be passed to - * pthread_create (see those docs for details) - * - * @param stop_routine - stop routine for the pthread, called to terminate the - * thread. This function should gracefully stop the pthread and clean up any - * thread-specific resources. The passed pointer is used to return a data - * result. + * The 'attr' argument should be filled out with the desired attributes, + * including ID, start and stop functions and the desired name. Alternatively, + * if attr is NULL, the default attributes will be used. The pthread will be + * set up to run a basic threadmaster loop and the name will be "Anonymous". + * Scheduling tasks onto the threadmaster in the 'master' field of the returned + * frr_pthread will cause them to run on that pthread. * + * @param attr - the thread attributes * @return the created frr_pthread upon success, or NULL upon failure */ -struct frr_pthread *frr_pthread_new(const char *name, unsigned int id, - void *(*start_routine)(void *), - int (*stop_routine)(void **, - struct frr_pthread *)); +struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr); -/* Destroys an frr_pthread. +/* + * Destroys an frr_pthread. * * Assumes that the associated pthread, if any, has already terminated. * @@ -97,38 +120,66 @@ struct frr_pthread *frr_pthread_new(const char *name, unsigned int id, */ void frr_pthread_destroy(struct frr_pthread *fpt); -/* Gets an existing frr_pthread by its id. +/* + * Gets an existing frr_pthread by its id. * * @return frr_thread associated with the provided id, or NULL on error */ struct frr_pthread *frr_pthread_get(unsigned int id); -/* Creates a new pthread and binds it to a frr_pthread. +/* + * Creates a new pthread and binds it to a frr_pthread. * * This function is a wrapper for pthread_create. The first parameter is the * frr_pthread to bind the created pthread to. All subsequent arguments are - * passed unmodified to pthread_create(). + * passed unmodified to pthread_create(). The frr_pthread * provided will be + * used as the argument to the pthread entry function. If it is necessary to + * pass additional data, the 'data' field in the frr_pthread may be used. * * This function returns the same code as pthread_create(). If the value is * zero, the provided frr_pthread is bound to a running POSIX thread. If the * value is less than zero, the provided frr_pthread is guaranteed to be a * clean instance that may be susbsequently passed to frr_pthread_run(). * - * @param id - frr_pthread to bind the created pthread to + * @param fpt - frr_pthread * to run * @param attr - see pthread_create(3) - * @param arg - see pthread_create(3) * * @return see pthread_create(3) */ -int frr_pthread_run(unsigned int id, const pthread_attr_t *attr, void *arg); +int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr); -/* Stops an frr_pthread with a result. +/* + * Waits until the specified pthread has finished setting up and is ready to + * begin work. * - * @param id - frr_pthread to stop + * If the pthread's code makes use of the startup synchronization mechanism, + * this function should be called before attempting to use the functionality + * exposed by the pthread. It waits until the 'running' condition is satisfied + * (see struct definition of frr_pthread). + * + * @param fpt - the frr_pthread * to wait on + */ +void frr_pthread_wait_running(struct frr_pthread *fpt); + +/* + * Notifies other pthreads that the calling thread has finished setting up and + * is ready to begin work. + * + * This will allow any other pthreads waiting in 'frr_pthread_wait_running' to + * proceed. + * + * @param fpt - the frr_pthread * that has finished setting up + */ +void frr_pthread_notify_running(struct frr_pthread *fpt); + +/* + * Stops a frr_pthread with a result. + * + * @param fpt - frr_pthread * to stop * @param result - where to store the thread's result, if any. May be NULL if a * result is not needed. */ -int frr_pthread_stop(unsigned int id, void **result); +int frr_pthread_stop(struct frr_pthread *fpt, void **result); /* Stops all frr_pthread's. */ void frr_pthread_stop_all(void); @@ -136,7 +187,8 @@ void frr_pthread_stop_all(void); /* Yields the current thread of execution */ void frr_pthread_yield(void); -/* Returns a unique identifier for use with frr_pthread_new(). +/* + * Returns a unique identifier for use with frr_pthread_new(). * * Internally, this is an integer that increments after each call to this * function. Because the number of pthreads created should never exceed INT_MAX From a715eab3ce7b3aedcd8f809fc7f7f512f29cceb9 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Wed, 24 Jan 2018 11:07:27 -0500 Subject: [PATCH 68/84] bgpd: update pthreads to use lib changes Use the new threading facilities provided in lib/ to streamline the threads used in bgpd. In particular, all of the lifecycle code has been removed from the I/O thread and replaced with the default loop. Did not do the same to the keepalives thread as it is much smaller (doesn't need the event system). Also cleaned up some comments to match the style guide. Signed-off-by: Quentin Young --- bgpd/bgp_io.c | 138 ++++++++---------------------------------- bgpd/bgp_io.h | 17 ------ bgpd/bgp_keepalives.c | 86 +++++++++++++------------- bgpd/bgp_keepalives.h | 2 +- bgpd/bgpd.c | 39 ++++++------ 5 files changed, 92 insertions(+), 190 deletions(-) diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index f4bfc90b7e..59b2d1cdaa 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -51,100 +51,12 @@ static bool validate_header(struct peer *); #define BGP_IO_TRANS_ERR (1 << 0) // EAGAIN or similar occurred #define BGP_IO_FATAL_ERR (1 << 1) // some kind of fatal TCP error -/* Plumbing & control variables for thread lifecycle - * ------------------------------------------------------------------------ */ -bool bgp_io_thread_run; -pthread_mutex_t *running_cond_mtx; -pthread_cond_t *running_cond; - -/* Unused callback for thread_add_read() */ -static int bgp_io_dummy(struct thread *thread) { return 0; } - -/* Poison pill task */ -static int bgp_io_finish(struct thread *thread) -{ - bgp_io_thread_run = false; - return 0; -} - -/* Extern lifecycle control functions. init -> start -> stop - * ------------------------------------------------------------------------ */ -void bgp_io_init() -{ - bgp_io_thread_run = false; - - running_cond_mtx = XCALLOC(MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t)); - running_cond = XCALLOC(MTYPE_PTHREAD_PRIM, sizeof(pthread_cond_t)); - - pthread_mutex_init(running_cond_mtx, NULL); - pthread_cond_init(running_cond, NULL); - - /* unlocked in bgp_io_wait_running() */ - pthread_mutex_lock(running_cond_mtx); -} - -void *bgp_io_start(void *arg) -{ - struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); - fpt->master->owner = pthread_self(); - - // fd so we can sleep in poll() - int sleeper[2]; - pipe(sleeper); - thread_add_read(fpt->master, &bgp_io_dummy, NULL, sleeper[0], NULL); - - // we definitely don't want to handle signals - fpt->master->handle_signals = false; - - struct thread task; - - pthread_mutex_lock(running_cond_mtx); - { - bgp_io_thread_run = true; - pthread_cond_signal(running_cond); - } - pthread_mutex_unlock(running_cond_mtx); - - while (bgp_io_thread_run) { - if (thread_fetch(fpt->master, &task)) { - thread_call(&task); - } - } - - close(sleeper[1]); - close(sleeper[0]); - - return NULL; -} - -void bgp_io_wait_running() -{ - while (!bgp_io_thread_run) - pthread_cond_wait(running_cond, running_cond_mtx); - - /* locked in bgp_io_init() */ - pthread_mutex_unlock(running_cond_mtx); -} - -int bgp_io_stop(void **result, struct frr_pthread *fpt) -{ - thread_add_event(fpt->master, &bgp_io_finish, NULL, 0, NULL); - pthread_join(fpt->thread, result); - - pthread_mutex_destroy(running_cond_mtx); - pthread_cond_destroy(running_cond); - - XFREE(MTYPE_PTHREAD_PRIM, running_cond_mtx); - XFREE(MTYPE_PTHREAD_PRIM, running_cond); - - return 0; -} - -/* Extern API -------------------------------------------------------------- */ +/* Thread external API ----------------------------------------------------- */ void bgp_writes_on(struct peer *peer) { - assert(bgp_io_thread_run); + struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); + assert(fpt->running); assert(peer->status != Deleted); assert(peer->obuf); @@ -154,8 +66,6 @@ void bgp_writes_on(struct peer *peer) assert(!peer->t_connect_check_w); assert(peer->fd); - struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); - thread_add_write(fpt->master, bgp_process_writes, peer, peer->fd, &peer->t_write); SET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON); @@ -163,9 +73,8 @@ void bgp_writes_on(struct peer *peer) void bgp_writes_off(struct peer *peer) { - assert(bgp_io_thread_run); - struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); + assert(fpt->running); thread_cancel_async(fpt->master, &peer->t_write, NULL); THREAD_OFF(peer->t_generate_updgrp_packets); @@ -175,7 +84,8 @@ void bgp_writes_off(struct peer *peer) void bgp_reads_on(struct peer *peer) { - assert(bgp_io_thread_run); + struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); + assert(fpt->running); assert(peer->status != Deleted); assert(peer->ibuf); @@ -186,8 +96,6 @@ void bgp_reads_on(struct peer *peer) assert(!peer->t_connect_check_w); assert(peer->fd); - struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); - thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd, &peer->t_read); @@ -196,9 +104,8 @@ void bgp_reads_on(struct peer *peer) void bgp_reads_off(struct peer *peer) { - assert(bgp_io_thread_run); - struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO); + assert(fpt->running); thread_cancel_async(fpt->master, &peer->t_read, NULL); THREAD_OFF(peer->t_process_packet); @@ -206,9 +113,9 @@ void bgp_reads_off(struct peer *peer) UNSET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON); } -/* Internal functions ------------------------------------------------------- */ +/* Thread internal functions ----------------------------------------------- */ -/** +/* * Called from I/O pthread when a file descriptor has become ready for writing. */ static int bgp_process_writes(struct thread *thread) @@ -231,11 +138,13 @@ static int bgp_process_writes(struct thread *thread) } pthread_mutex_unlock(&peer->io_mtx); - if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) { /* no problem */ + /* no problem */ + if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) { } + /* problem */ if (CHECK_FLAG(status, BGP_IO_FATAL_ERR)) { - reschedule = false; /* problem */ + reschedule = false; fatal = true; } @@ -250,7 +159,7 @@ static int bgp_process_writes(struct thread *thread) return 0; } -/** +/* * Called from I/O pthread when a file descriptor has become ready for reading, * or has hung up. * @@ -321,8 +230,10 @@ static int bgp_process_reads(struct thread *thread) /* if this fails we are seriously screwed */ assert(pktsize <= BGP_MAX_PACKET_SIZE); - /* If we have that much data, chuck it into its own - * stream and append to input queue for processing. */ + /* + * If we have that much data, chuck it into its own + * stream and append to input queue for processing. + */ if (ringbuf_remain(ibw) >= pktsize) { struct stream *pkt = stream_new(pktsize); assert(ringbuf_get(ibw, pktbuf, pktsize) == pktsize); @@ -356,7 +267,7 @@ static int bgp_process_reads(struct thread *thread) return 0; } -/** +/* * Flush peer output buffer. * * This function pops packets off of peer->obuf and writes them to peer->fd. @@ -379,7 +290,6 @@ static uint16_t bgp_write(struct peer *peer) uint16_t status = 0; uint32_t wpkt_quanta_old; - // cache current write quanta wpkt_quanta_old = atomic_load_explicit(&peer->bgp->wpkt_quanta, memory_order_relaxed); @@ -398,7 +308,7 @@ static uint16_t bgp_write(struct peer *peer) } goto done; - } else if (num != writenum) // incomplete write + } else if (num != writenum) stream_forward_getp(s, num); } while (num != writenum); @@ -427,8 +337,10 @@ static uint16_t bgp_write(struct peer *peer) if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); - /* Handle Graceful Restart case where the state changes - * to Connect instead of Idle */ + /* + * Handle Graceful Restart case where the state changes + * to Connect instead of Idle. + */ BGP_EVENT_ADD(peer, BGP_Stop); goto done; @@ -472,7 +384,7 @@ done : { return status; } -/** +/* * Reads a chunk of data from peer->fd into peer->ibuf_work. * * @return status flag (see top-of-file) diff --git a/bgpd/bgp_io.h b/bgpd/bgp_io.h index 7cfd1db710..14a12d3705 100644 --- a/bgpd/bgp_io.h +++ b/bgpd/bgp_io.h @@ -28,14 +28,6 @@ #include "bgpd/bgpd.h" #include "frr_pthread.h" -/** - * Initializes data structures and flags for the write thread. - * - * This function must be called from the main thread before - * bgp_writes_start() is invoked. - */ -extern void bgp_io_init(void); - /** * Start function for write thread. * @@ -43,15 +35,6 @@ extern void bgp_io_init(void); */ extern void *bgp_io_start(void *arg); -/** - * Wait until the IO thread is ready to accept jobs. - * - * This function must be called immediately after the thread has been created - * for running. Use of other functions before calling this one will result in - * undefined behavior. - */ -extern void bgp_io_wait_running(void); - /** * Start function for write thread. * diff --git a/bgpd/bgp_keepalives.c b/bgpd/bgp_keepalives.c index afa280a799..a6976109a8 100644 --- a/bgpd/bgp_keepalives.c +++ b/bgpd/bgp_keepalives.c @@ -36,14 +36,14 @@ #include "bgpd/bgp_keepalives.h" /* clang-format on */ -/** +/* * Peer KeepAlive Timer. * Associates a peer with the time of its last keepalive. */ struct pkat { - // the peer to send keepalives to + /* the peer to send keepalives to */ struct peer *peer; - // absolute time of last keepalive sent + /* absolute time of last keepalive sent */ struct timeval last; }; @@ -52,9 +52,6 @@ static pthread_mutex_t *peerhash_mtx; static pthread_cond_t *peerhash_cond; static struct hash *peerhash; -/* Thread control flag. */ -bool bgp_keepalives_thread_run = false; - static struct pkat *pkat_new(struct peer *peer) { struct pkat *pkat = XMALLOC(MTYPE_TMP, sizeof(struct pkat)); @@ -100,10 +97,10 @@ static void peer_process(struct hash_backet *hb, void *arg) static struct timeval tolerance = {0, 100000}; - // calculate elapsed time since last keepalive + /* calculate elapsed time since last keepalive */ monotime_since(&pkat->last, &elapsed); - // calculate difference between elapsed time and configured time + /* calculate difference between elapsed time and configured time */ ka.tv_sec = pkat->peer->v_keepalive; timersub(&ka, &elapsed, &diff); @@ -118,10 +115,10 @@ static void peer_process(struct hash_backet *hb, void *arg) bgp_keepalive_send(pkat->peer); monotime(&pkat->last); memset(&elapsed, 0x00, sizeof(struct timeval)); - diff = ka; // time until next keepalive == peer keepalive time + diff = ka; } - // if calculated next update for this peer < current delay, use it + /* if calculated next update for this peer < current delay, use it */ if (next_update->tv_sec <= 0 || timercmp(&diff, next_update, <)) *next_update = diff; } @@ -139,29 +136,9 @@ static unsigned int peer_hash_key(void *arg) return (uintptr_t)pkat->peer; } -void bgp_keepalives_init() -{ - peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t)); - peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t)); - - // initialize mutex - pthread_mutex_init(peerhash_mtx, NULL); - - // use monotonic clock with condition variable - pthread_condattr_t attrs; - pthread_condattr_init(&attrs); - pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC); - pthread_cond_init(peerhash_cond, &attrs); - pthread_condattr_destroy(&attrs); - - // initialize peer hashtable - peerhash = hash_create_size(2048, peer_hash_key, peer_hash_cmp, NULL); -} - +/* Cleanup handler / deinitializer. */ static void bgp_keepalives_finish(void *arg) { - bgp_keepalives_thread_run = false; - if (peerhash) { hash_clean(peerhash, pkat_del); hash_free(peerhash); @@ -177,32 +154,50 @@ static void bgp_keepalives_finish(void *arg) XFREE(MTYPE_TMP, peerhash_cond); } -/** +/* * Entry function for peer keepalive generation pthread. - * - * bgp_keepalives_init() must be called prior to this. */ void *bgp_keepalives_start(void *arg) { + struct frr_pthread *fpt = arg; + fpt->master->owner = pthread_self(); + struct timeval currtime = {0, 0}; struct timeval aftertime = {0, 0}; struct timeval next_update = {0, 0}; struct timespec next_update_ts = {0, 0}; + peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t)); + peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t)); + + /* initialize mutex */ + pthread_mutex_init(peerhash_mtx, NULL); + + /* use monotonic clock with condition variable */ + pthread_condattr_t attrs; + pthread_condattr_init(&attrs); + pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC); + pthread_cond_init(peerhash_cond, &attrs); + pthread_condattr_destroy(&attrs); + + /* initialize peer hashtable */ + peerhash = hash_create_size(2048, peer_hash_key, peer_hash_cmp, NULL); pthread_mutex_lock(peerhash_mtx); - // register cleanup handler + /* register cleanup handler */ pthread_cleanup_push(&bgp_keepalives_finish, NULL); - bgp_keepalives_thread_run = true; + /* notify anybody waiting on us that we are done starting up */ + frr_pthread_notify_running(fpt); - while (bgp_keepalives_thread_run) { + while (atomic_load_explicit(&fpt->running, memory_order_relaxed)) { if (peerhash->count > 0) pthread_cond_timedwait(peerhash_cond, peerhash_mtx, &next_update_ts); else while (peerhash->count == 0 - && bgp_keepalives_thread_run) + && atomic_load_explicit(&fpt->running, + memory_order_relaxed)) pthread_cond_wait(peerhash_cond, peerhash_mtx); monotime(&currtime); @@ -219,7 +214,7 @@ void *bgp_keepalives_start(void *arg) TIMEVAL_TO_TIMESPEC(&next_update, &next_update_ts); } - // clean up + /* clean up */ pthread_cleanup_pop(1); return NULL; @@ -229,6 +224,9 @@ void *bgp_keepalives_start(void *arg) void bgp_keepalives_on(struct peer *peer) { + struct frr_pthread *fpt = frr_pthread_get(PTHREAD_KEEPALIVES); + assert(fpt->running); + /* placeholder bucket data to use for fast key lookups */ static struct pkat holder = {0}; @@ -253,6 +251,9 @@ void bgp_keepalives_on(struct peer *peer) void bgp_keepalives_off(struct peer *peer) { + struct frr_pthread *fpt = frr_pthread_get(PTHREAD_KEEPALIVES); + assert(fpt->running); + /* placeholder bucket data to use for fast key lookups */ static struct pkat holder = {0}; @@ -283,10 +284,13 @@ void bgp_keepalives_wake() pthread_mutex_unlock(peerhash_mtx); } -int bgp_keepalives_stop(void **result, struct frr_pthread *fpt) +int bgp_keepalives_stop(struct frr_pthread *fpt, void **result) { - bgp_keepalives_thread_run = false; + assert(fpt->running); + + atomic_store_explicit(&fpt->running, false, memory_order_relaxed); bgp_keepalives_wake(); + pthread_join(fpt->thread, result); return 0; } diff --git a/bgpd/bgp_keepalives.h b/bgpd/bgp_keepalives.h index 1fbd035b9e..d1cb7d2462 100644 --- a/bgpd/bgp_keepalives.h +++ b/bgpd/bgp_keepalives.h @@ -88,6 +88,6 @@ extern void bgp_keepalives_wake(void); /** * Stops the thread and blocks until it terminates. */ -int bgp_keepalives_stop(void **result, struct frr_pthread *fpt); +int bgp_keepalives_stop(struct frr_pthread *fpt, void **result); #endif /* _FRR_BGP_KEEPALIVES_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 7db73043cc..19f0c8cabf 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -7470,30 +7470,33 @@ static void bgp_pthreads_init() { frr_pthread_init(); - frr_pthread_new("BGP i/o thread", PTHREAD_IO, bgp_io_start, - bgp_io_stop); - frr_pthread_new("BGP keepalives thread", PTHREAD_KEEPALIVES, - bgp_keepalives_start, bgp_keepalives_stop); - - /* pre-run initialization */ - bgp_keepalives_init(); - bgp_io_init(); + struct frr_pthread_attr io = { + .id = PTHREAD_IO, + .start = frr_pthread_attr_default.start, + .stop = frr_pthread_attr_default.stop, + .name = "BGP I/O thread", + }; + struct frr_pthread_attr ka = { + .id = PTHREAD_KEEPALIVES, + .start = bgp_keepalives_start, + .stop = bgp_keepalives_stop, + .name = "BGP Keepalives thread", + }; + frr_pthread_new(&io); + frr_pthread_new(&ka); } void bgp_pthreads_run() { - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + struct frr_pthread *io = frr_pthread_get(PTHREAD_IO); + struct frr_pthread *ka = frr_pthread_get(PTHREAD_KEEPALIVES); - /* - * I/O related code assumes the thread is ready for work at all times, - * so we wait until it is. - */ - frr_pthread_run(PTHREAD_IO, &attr, NULL); - bgp_io_wait_running(); + frr_pthread_run(io, NULL); + frr_pthread_run(ka, NULL); - frr_pthread_run(PTHREAD_KEEPALIVES, &attr, NULL); + /* Wait until threads are ready. */ + frr_pthread_wait_running(io); + frr_pthread_wait_running(ka); } void bgp_pthreads_finish() From cadc5f3377eec33c17e5cc230b0671c884c3fcca Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Wed, 24 Jan 2018 15:53:07 -0500 Subject: [PATCH 69/84] tests: make tests happy for pthread changes Signed-off-by: Quentin Young --- tests/bgpd/test_aspath.c | 6 +++++- tests/bgpd/test_capability.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index 56808bc8ad..9e5cb7fe54 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -25,8 +25,9 @@ #include "privs.h" #include "queue.h" #include "filter.h" +#include "frr_pthread.h" -#include "bgpd/bgpd.h" +#include "bgpd/bgpd.c" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_packet.h" @@ -1272,6 +1273,9 @@ static int handle_attr_test(struct aspath_tests *t) struct aspath *asp; size_t datalen; + bgp_pthreads_init(); + frr_pthread_get(PTHREAD_KEEPALIVES)->running = true; + asp = make_aspath(t->segment->asdata, t->segment->len, 0); peer.curr = stream_new(BGP_MAX_PACKET_SIZE); diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index a5092708e2..3d5518f3b7 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -27,8 +27,9 @@ #include "memory.h" #include "queue.h" #include "filter.h" +#include "frr_pthread.h" -#include "bgpd/bgpd.h" +#include "bgpd/bgpd.c" #include "bgpd/bgp_open.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_packet.h" @@ -915,6 +916,9 @@ int main(void) vrf_init(NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); + bgp_pthreads_init(); + frr_pthread_get(PTHREAD_KEEPALIVES)->running = true; + if (fileno(stdout) >= 0) tty = isatty(fileno(stdout)); From 096476ddb09fd7bf8946c5429bd9903dd33f3d78 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Wed, 24 Jan 2018 17:47:17 -0500 Subject: [PATCH 70/84] bgpd: check flags before attempting keepalive ops If a peer already has keepalives turned on when asking to turn them on, return immediately. Same thing for turning them off. Signed-off-by: Quentin Young --- bgpd/bgp_keepalives.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bgpd/bgp_keepalives.c b/bgpd/bgp_keepalives.c index a6976109a8..5a48c7013e 100644 --- a/bgpd/bgp_keepalives.c +++ b/bgpd/bgp_keepalives.c @@ -224,6 +224,9 @@ void *bgp_keepalives_start(void *arg) void bgp_keepalives_on(struct peer *peer) { + if (CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON)) + return; + struct frr_pthread *fpt = frr_pthread_get(PTHREAD_KEEPALIVES); assert(fpt->running); @@ -251,6 +254,9 @@ void bgp_keepalives_on(struct peer *peer) void bgp_keepalives_off(struct peer *peer) { + if (!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON)) + return; + struct frr_pthread *fpt = frr_pthread_get(PTHREAD_KEEPALIVES); assert(fpt->running); From ed216282b6ce3da844e254506d390807fcc0ad36 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 24 Jan 2018 09:16:39 -0500 Subject: [PATCH 71/84] zebra: Move selected_fib assignment The dest->selected_fib assignment needs to happen after the install and should be controlled by the southbound api return of success or failure. Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 78 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 16 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 83eff7bdcf..c200e2dbb3 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1004,9 +1004,13 @@ void kernel_route_rib_pass_fail(struct route_node *rn, struct prefix *p, { struct nexthop *nexthop; char buf[PREFIX_STRLEN]; + rib_dest_t *dest; + + dest = rib_dest_from_rnode(rn); switch (res) { case SOUTHBOUND_INSTALL_SUCCESS: + dest->selected_fib = re; for (ALL_NEXTHOPS(re->nexthop, nexthop)) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; @@ -1020,16 +1024,37 @@ void kernel_route_rib_pass_fail(struct route_node *rn, struct prefix *p, p, ZAPI_ROUTE_INSTALLED); break; case SOUTHBOUND_INSTALL_FAILURE: + /* + * I am not sure this is the right thing to do here + * but the code always set selected_fib before + * this assignment was moved here. + */ + dest->selected_fib = re; + zsend_route_notify_owner(re->type, re->instance, re->vrf_id, p, ZAPI_ROUTE_FAIL_INSTALL); zlog_warn("%u:%s: Route install failed", re->vrf_id, prefix2str(p, buf, sizeof(buf))); break; case SOUTHBOUND_DELETE_SUCCESS: + /* + * The case where selected_fib is not re is + * when we have received a system route + * that is overriding our installed route + * as such we should leave the selected_fib + * pointer alone + */ + if (dest->selected_fib == re) + dest->selected_fib = NULL; for (ALL_NEXTHOPS(re->nexthop, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); break; case SOUTHBOUND_DELETE_FAILURE: + /* + * Should we set this to NULL if the + * delete fails? + */ + dest->selected_fib = NULL; zlog_warn("%u:%s: Route Deletion failure", re->vrf_id, prefix2str(p, buf, sizeof(buf))); break; @@ -1133,8 +1158,6 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re) /* If labeled-unicast route, uninstall transit LSP. */ if (zebra_rib_labeled_unicast(re)) zebra_mpls_lsp_uninstall(info->zvrf, rn, re); - - dest->selected_fib = NULL; } if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) { @@ -1219,7 +1242,6 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, return; } - dest->selected_fib = new; if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rn, buf, sizeof(buf)); @@ -1233,6 +1255,8 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (!RIB_SYSTEM_ROUTE(new)) rib_install_kernel(rn, new, NULL); + else + dest->selected_fib = new; UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); } @@ -1257,8 +1281,17 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); - - dest->selected_fib = NULL; + else { + /* + * 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; + } /* Update nexthop for route, reset changed flag. */ nexthop_active_update(rn, old, 1); @@ -1272,7 +1305,6 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, { struct nexthop *nexthop = NULL; int nh_active = 0; - int installed = 1; rib_dest_t *dest = rib_dest_from_rnode(rn); /* @@ -1322,11 +1354,23 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, zebra_mpls_lsp_install(zvrf, rn, new); rib_install_kernel(rn, new, old); + } else { + /* + * We do not need to install the + * selected route because it + * is already isntalled by + * the system( ie not us ) + * so just mark it as winning + * we do need to ensure that + * if we uninstall a route + * from ourselves we don't + * over write this pointer + */ + dest->selected_fib = NULL; } - /* If install succeeded or system route, cleanup flags * for prior route. */ - if (installed && new != old) { + if (new != old) { if (RIB_SYSTEM_ROUTE(new)) { if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); @@ -1337,10 +1381,6 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, NEXTHOP_FLAG_FIB); } } - - /* Update for redistribution. */ - if (installed) - dest->selected_fib = new; } /* @@ -1348,7 +1388,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, * failed, we * may need to uninstall and delete for redistribution. */ - if (!nh_active || !installed) { + if (!nh_active) { if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rn, buf, sizeof(buf)); @@ -1375,7 +1415,8 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); - dest->selected_fib = NULL; + else + dest->selected_fib = NULL; } } else { /* @@ -1388,12 +1429,12 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, * to add routes. */ if (!RIB_SYSTEM_ROUTE(new)) { - int in_fib = 0; + bool in_fib = false; for (ALL_NEXTHOPS(new->nexthop, nexthop)) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) { - in_fib = 1; + in_fib = true; break; } if (!in_fib) @@ -2440,6 +2481,11 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, UNSET_FLAG(rtnh->flags, NEXTHOP_FLAG_FIB); + /* + * This is a non FRR route + * as such we should mark + * it as deleted + */ dest->selected_fib = NULL; } else { /* This means someone else, other than Zebra, From ea38ced19f5f08bcb6bc0742624693c2ff81b028 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Wed, 24 Jan 2018 21:05:27 -0200 Subject: [PATCH 72/84] ospfd: allow multiple options in the redistribute command Other variants of the redistribute command (e.g. "redistribute (1-65535) ..." already accept multiple options. Fixes Issue #1670. Signed-off-by: Renato Westphal --- ospfd/ospf_vty.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 6d28c2cdc5..3b18d152e8 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -8116,7 +8116,7 @@ DEFUN (no_ip_ospf_area, DEFUN (ospf_redistribute_source, ospf_redistribute_source_cmd, - "redistribute " FRR_REDIST_STR_OSPFD " []", + "redistribute " FRR_REDIST_STR_OSPFD " [{metric (0-16777214)|metric-type (1-2)|route-map WORD}]", REDIST_STR FRR_REDIST_HELP_STR_OSPFD "Metric for redistributed routes\n" @@ -8150,12 +8150,12 @@ DEFUN (ospf_redistribute_source, return CMD_WARNING_CONFIG_FAILED; } /* Get metric type. */ - else if (argv_find(argv, argc, "(1-2)", &idx)) { + if (argv_find(argv, argc, "(1-2)", &idx)) { if (!str2metric_type(argv[idx]->arg, &type)) return CMD_WARNING_CONFIG_FAILED; } /* Get route-map */ - else if (argv_find(argv, argc, "WORD", &idx)) { + if (argv_find(argv, argc, "WORD", &idx)) { ospf_routemap_set(red, argv[idx]->arg); } else ospf_routemap_unset(red); @@ -8165,7 +8165,7 @@ DEFUN (ospf_redistribute_source, DEFUN (no_ospf_redistribute_source, no_ospf_redistribute_source_cmd, - "no redistribute " FRR_REDIST_STR_OSPFD " []", + "no redistribute " FRR_REDIST_STR_OSPFD " [{metric (0-16777214)|metric-type (1-2)|route-map WORD}]", NO_STR REDIST_STR FRR_REDIST_HELP_STR_OSPFD @@ -8355,7 +8355,7 @@ DEFUN (no_ospf_distribute_list_out, /* Default information originate. */ DEFUN (ospf_default_information_originate, ospf_default_information_originate_cmd, - "default-information originate []", + "default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}]", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" @@ -8379,17 +8379,17 @@ DEFUN (ospf_default_information_originate, if (argv_find(argv, argc, "always", &idx)) default_originate = DEFAULT_ORIGINATE_ALWAYS; /* Get metric value */ - else if (argv_find(argv, argc, "(0-16777214)", &idx)) { + if (argv_find(argv, argc, "(0-16777214)", &idx)) { if (!str2metric(argv[idx]->arg, &metric)) return CMD_WARNING_CONFIG_FAILED; } /* Get metric type. */ - else if (argv_find(argv, argc, "(1-2)", &idx)) { + if (argv_find(argv, argc, "(1-2)", &idx)) { if (!str2metric_type(argv[idx]->arg, &type)) return CMD_WARNING_CONFIG_FAILED; } /* Get route-map */ - else if (argv_find(argv, argc, "WORD", &idx)) + if (argv_find(argv, argc, "WORD", &idx)) ospf_routemap_set(red, argv[idx]->arg); else ospf_routemap_unset(red); @@ -8400,7 +8400,7 @@ DEFUN (ospf_default_information_originate, DEFUN (no_ospf_default_information_originate, no_ospf_default_information_originate_cmd, - "no default-information originate []", + "no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}]", NO_STR "Control distribution of default information\n" "Distribute a default route\n" From ded42248750dee84fe0a5ce73905568bac188d78 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Wed, 24 Jan 2018 16:41:07 -0800 Subject: [PATCH 73/84] ospfd: clean route map prefixlist vrf during exit Call Route-map, prefix-list clean up routines and vrf clearnup during ospf daemon exit routine. Signed-off-by: Chirag Shah --- ospfd/ospfd.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 89b08552a8..e6f19369ef 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -32,6 +32,7 @@ #include "log.h" #include "sockunion.h" /* for inet_aton () */ #include "zclient.h" +#include "routemap.h" #include "plist.h" #include "sockopt.h" #include "bfd.h" @@ -554,6 +555,20 @@ void ospf_terminate(void) for (ALL_LIST_ELEMENTS(om->ospf, node, nnode, ospf)) ospf_finish(ospf); + /* Cleanup route maps */ + route_map_add_hook(NULL); + route_map_delete_hook(NULL); + route_map_event_hook(NULL); + route_map_finish(); + + /* reverse prefix_list_init */ + prefix_list_add_hook(NULL); + prefix_list_delete_hook(NULL); + prefix_list_reset(); + + /* Cleanup vrf info */ + ospf_vrf_terminate(); + /* Deliberately go back up, hopefully to thread scheduler, as * One or more ospf_finish()'s may have deferred shutdown to a timer * thread From 9cc4624852c87f6011a57b7acdd72391586571c7 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 24 Jan 2018 20:53:40 -0500 Subject: [PATCH 74/84] zebra: Fix crash in ptm code The code change to switch from stream_getX to STREAM_GETX added a goto statement to be handled for a failure case. The failure case was properly handled but the normal case was not tested properly and there exists a situation where we would free the out_ctxt 2 times. Prevent that from happening. Signed-off-by: Donald Sharp --- zebra/zebra_ptm.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 953f74ecec..7f5fd472f1 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -816,6 +816,8 @@ int zebra_ptm_bfd_dst_register(struct zserv *client, u_short length, ptm_cb.out_data); zebra_ptm_send_message(ptm_cb.out_data, data_len); + return 0; + stream_failure: ptm_lib_cleanup_msg(ptm_hdl, out_ctxt); return 0; @@ -946,6 +948,8 @@ int zebra_ptm_bfd_dst_deregister(struct zserv *client, u_short length, zebra_ptm_send_message(ptm_cb.out_data, data_len); + return 0; + stream_failure: ptm_lib_cleanup_msg(ptm_hdl, out_ctxt); return 0; @@ -957,7 +961,7 @@ int zebra_ptm_bfd_client_register(struct zserv *client, { struct stream *s; unsigned int pid; - void *out_ctxt; + void *out_ctxt = NULL; char tmp_buf[64]; int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF; @@ -999,7 +1003,12 @@ int zebra_ptm_bfd_client_register(struct zserv *client, SET_FLAG(ptm_cb.client_flags[client->proto], ZEBRA_PTM_BFD_CLIENT_FLAG_REG); + + return 0; + stream_failure: + if (out_ctxt) + ptm_lib_cleanup_msg(ptm_hdl, out_ctxt); return 0; } From 3946bdcc814dd5d86e0881efb5e88002cf1eee26 Mon Sep 17 00:00:00 2001 From: Don Slice Date: Thu, 25 Jan 2018 17:45:40 +0000 Subject: [PATCH 75/84] bgpd: remove poorly located bestpath json output The bestpath multipath-relax setting was added to the output of "show ip bgp neighbor json" several months ago but this is not the correct place to display that information and this fix removes it from there. The multipath-relax setting was also added to the output of "show ip bgp sum json" which is fine. Signed-off-by: Don Slice --- bgpd/bgp_vty.c | 1 - 1 file changed, 1 deletion(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index c98cf9c327..83842e5763 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9847,7 +9847,6 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp, } if (use_json) { - bgp_show_bestpath_json(bgp, json); vty_out(vty, "%s\n", json_object_to_json_string_ext( json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); From 7ebe625c3a45a7cb671e651464aa33db04b96091 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 26 Jan 2018 17:15:44 -0500 Subject: [PATCH 76/84] Revert "bgpd: disallow invalid config at cli layer" This reverts commit a174be631a14e0271fde6858fcb4d7ab55165014. Turns out we need that variable to accept peer groups. --- bgpd/bgp_vty.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index c98cf9c327..c011dd7486 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3415,6 +3415,18 @@ static int peer_flag_modify_vty(struct vty *vty, const char *ip_str, if (!peer) return CMD_WARNING_CONFIG_FAILED; + /* + * If 'neighbor ', then this is for directly connected peers, + * we should not accept disable-connected-check. + */ + if (peer->conf_if && (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)) { + vty_out(vty, + "%s is directly connected peer, cannot accept disable-" + "connected-check\n", + ip_str); + return CMD_WARNING_CONFIG_FAILED; + } + if (!set && flag == PEER_FLAG_SHUTDOWN) peer_tx_shutdown_message_unset(peer); @@ -4505,9 +4517,9 @@ DEFUN (no_neighbor_ebgp_multihop, /* disable-connected-check */ DEFUN (neighbor_disable_connected_check, neighbor_disable_connected_check_cmd, - "neighbor ", + "neighbor ", NEIGHBOR_STR - NEIGHBOR_ADDR_STR + NEIGHBOR_ADDR_STR2 "one-hop away EBGP peer using loopback address\n" "Enforce EBGP neighbors perform multihop\n") { @@ -4518,10 +4530,10 @@ DEFUN (neighbor_disable_connected_check, DEFUN (no_neighbor_disable_connected_check, no_neighbor_disable_connected_check_cmd, - "no neighbor ", + "no neighbor ", NO_STR NEIGHBOR_STR - NEIGHBOR_ADDR_STR + NEIGHBOR_ADDR_STR2 "one-hop away EBGP peer using loopback address\n" "Enforce EBGP neighbors perform multihop\n") { @@ -5960,9 +5972,9 @@ ALIAS_HIDDEN( DEFUN (neighbor_ttl_security, neighbor_ttl_security_cmd, - "neighbor ttl-security hops (1-254)", + "neighbor ttl-security hops (1-254)", NEIGHBOR_STR - NEIGHBOR_ADDR_STR + NEIGHBOR_ADDR_STR2 "BGP ttl-security parameters\n" "Specify the maximum number of hops to the BGP peer\n" "Number of hops to BGP peer\n") @@ -5978,15 +5990,26 @@ DEFUN (neighbor_ttl_security, gtsm_hops = strtoul(argv[idx_number]->arg, NULL, 10); + /* + * If 'neighbor swpX', then this is for directly connected peers, + * we should not accept a ttl-security hops value greater than 1. + */ + if (peer->conf_if && (gtsm_hops > 1)) { + vty_out(vty, + "%s is directly connected peer, hops cannot exceed 1\n", + argv[idx_peer]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + return bgp_vty_return(vty, peer_ttl_security_hops_set(peer, gtsm_hops)); } DEFUN (no_neighbor_ttl_security, no_neighbor_ttl_security_cmd, - "no neighbor ttl-security hops (1-254)", + "no neighbor ttl-security hops (1-254)", NO_STR NEIGHBOR_STR - NEIGHBOR_ADDR_STR + NEIGHBOR_ADDR_STR2 "BGP ttl-security parameters\n" "Specify the maximum number of hops to the BGP peer\n" "Number of hops to BGP peer\n") From e6149ab4b8e3fc66a369503616a03bac062f0a21 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 27 Jan 2018 05:28:51 -0500 Subject: [PATCH 77/84] zebra: Fix to get correct nexthop-vrf The nexthop_vrf should be looked up as appropriate, If the nexthop_vrf was specified use that, else use the vrf context of what was passed in. Signed-off-by: Donald Sharp --- zebra/zebra_vty.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 92e1076b2e..7b5ab1ef5c 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -475,12 +475,15 @@ DEFPY(ip_route_address_interface, ifname = NULL; } - nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", - nexthop_vrf); - return CMD_WARNING_CONFIG_FAILED; - } + if (nexthop_vrf) { + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + } else + nh_zvrf = zebra_vrf_lookup_by_name(vrf); zvrf = zebra_vrf_lookup_by_name(vrf); if (!nh_zvrf) { @@ -579,12 +582,15 @@ DEFPY(ip_route, ifname = NULL; } - nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", - nexthop_vrf); - return CMD_WARNING_CONFIG_FAILED; - } + if (nexthop_vrf) { + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + } else + nh_zvrf = zebra_vrf_lookup_by_name(vrf); zvrf = zebra_vrf_lookup_by_name(vrf); if (!nh_zvrf) { From 17a217216d2a3be320c7e4694656bf8fcc4c5b0d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 27 Jan 2018 18:56:30 -0500 Subject: [PATCH 78/84] zebra: Fix failure to parse src If src happens to point at all 0's due to not initializing it and if the address passed in is not a v6 address then we would not set src in the AF_INET6 call and would fail the (src.ipv4.s_addr && inet_pton(AF_INET...) call. Thus causing us to return a NULL and make the routemap code think there was an issue. Signed-off-by: Donald Sharp --- zebra/zebra_routemap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 89cb2fc488..4c619e5782 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -1193,7 +1193,7 @@ static void *route_set_src_compile(const char *arg) union g_addr src, *psrc; if ((inet_pton(AF_INET6, arg, &src.ipv6) == 1) - || (src.ipv4.s_addr && (inet_pton(AF_INET, arg, &src.ipv4) == 1))) { + || (inet_pton(AF_INET, arg, &src.ipv4) == 1)) { psrc = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(union g_addr)); *psrc = src; return psrc; From ff21655441a64c427b3e373272e7b4564a8a1bb1 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Mon, 29 Jan 2018 14:55:16 -0500 Subject: [PATCH 79/84] doc: change vpnvX -> ipvX vpn Signed-off-by: Lou Berger --- doc/bgpd.texi | 4 ++-- doc/vnc.texi | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/bgpd.texi b/doc/bgpd.texi index d62c3a7516..c36646cb34 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -826,8 +826,8 @@ Identifiers (SAFI). In addition to unicast information, VPN information @cite{RFC4364} and @cite{RFC4659}, and Encapsulation information @cite{RFC5512} is supported. -@deffn {Command} {show ip bgp vpnv4 all} {} -@deffnx {Command} {show ipv6 bgp vpn all} {} +@deffn {Command} {show ip bgp ipv4 vpn} {} +@deffnx {Command} {show ipv6 bgp ipv6 vpn} {} Print active IPV4 or IPV6 routes advertised via the VPN SAFI. @end deffn diff --git a/doc/vnc.texi b/doc/vnc.texi index c44519a9f3..6ccf74839d 100644 --- a/doc/vnc.texi +++ b/doc/vnc.texi @@ -1010,7 +1010,7 @@ router bgp 64512 neighbor 192.168.1.101 remote-as 64512 neighbor 192.168.1.102 remote-as 64512 - address-family vpnv4 + address-family ipv4 vpn neighbor 192.168.1.101 activate neighbor 192.168.1.102 activate exit-address-family @@ -1043,7 +1043,7 @@ router bgp 64512 neighbor 192.168.1.100 remote-as 64512 neighbor 192.168.1.102 remote-as 64512 - address-family vpnv4 + address-family ipv4 vpn neighbor 192.168.1.100 activate neighbor 192.168.1.102 activate exit-address-family @@ -1066,7 +1066,7 @@ router bgp 64512 neighbor 192.168.1.101 remote-as 64512 neighbor 192.168.1.102 remote-as 64512 - address-family vpnv4 + address-family ipv4 vpn neighbor 192.168.1.100 activate neighbor 192.168.1.101 activate exit-address-family @@ -1131,7 +1131,7 @@ router bgp 64512 neighbor 172.16.2.2 route-reflector-client exit-address-family ! - address-family vpnv4 unicast + address-family ipv4 vpn neighbor 192.168.1.102 activate neighbor 192.168.1.103 activate neighbor 192.168.1.104 activate @@ -1161,7 +1161,7 @@ router bgp 64512 no neighbor 192.168.1.103 activate exit-address-family ! - address-family vpnv4 unicast + address-family ipv4 vpn neighbor 192.168.1.101 activate neighbor 192.168.1.102 activate neighbor 192.168.1.103 activate @@ -1250,7 +1250,7 @@ router bgp 64512 neighbor 192.168.1.102 route-reflector-client exit-address-family - address-family vpnv4 + address-family ipv4 vpn neighbor 192.168.1.101 activate neighbor 192.168.1.102 activate @@ -1269,7 +1269,7 @@ router bgp 64512 neighbor 192.168.1.100 remote-as 64512 - address-family vpnv4 + address-family ipv4 vpn neighbor 192.168.1.100 activate exit-address-family @@ -1290,7 +1290,7 @@ router bgp 64512 neighbor 192.168.1.100 remote-as 64512 - address-family vpnv4 + address-family ipv4 vpn neighbor 192.168.1.100 activate exit-address-family @@ -1381,7 +1381,7 @@ router bgp 64512 neighbor 192.168.1.100 remote-as 64512 - address-family vpnv4 + address-family ipv4 vpn neighbor 192.168.1.100 activate exit-address-family @@ -1402,7 +1402,7 @@ router bgp 64512 neighbor 192.168.1.100 remote-as 64512 - address-family vpnv4 + address-family ipv4 vpn neighbor 192.168.1.100 activate exit-address-family @@ -1450,7 +1450,7 @@ router bgp 64512 neighbor 192.168.1.102 description iBGP-client-192-168-1-102 neighbor 192.168.1.102 route-reflector-client - address-family vpnv4 + address-family ipv4 vpn neighbor 192.168.1.101 activate neighbor 192.168.1.102 activate neighbor 192.168.1.104 activate @@ -1470,7 +1470,7 @@ router bgp 64512 neighbor 192.168.1.100 remote-as 64512 neighbor 192.168.1.104 remote-as 64512 - address-family vpnv4 + address-family ipv4 vpn neighbor 192.168.1.100 activate neighbor 192.168.1.104 activate exit-address-family @@ -1493,7 +1493,7 @@ router bgp 64512 neighbor 192.168.1.100 remote-as 64512 neighbor 192.168.1.104 remote-as 64512 - address-family vpnv4 + address-family ipv4 vpn neighbor 192.168.1.100 activate neighbor 192.168.1.104 activate exit-address-family From 3bb7cd7f56649ef17eeada95c132de1146c5fc92 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Mon, 29 Jan 2018 15:03:03 -0500 Subject: [PATCH 80/84] doc: remove references to encap safi Signed-off-by: Lou Berger --- doc/bgpd.texi | 11 ++--------- doc/vnc.texi | 17 +++++++---------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/doc/bgpd.texi b/doc/bgpd.texi index c36646cb34..83483f5697 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -823,7 +823,7 @@ Network Layer protocols. BGP supports multiple Address Family Identifier (AFI), namely IPv4 and IPv6. Support is also provided for multiple sets of per-AFI information via Subsequent Address Family Identifiers (SAFI). In addition to unicast information, VPN information -@cite{RFC4364} and @cite{RFC4659}, and Encapsulation information +@cite{RFC4364} and @cite{RFC4659}, and Encapsulation attribute @cite{RFC5512} is supported. @deffn {Command} {show ip bgp ipv4 vpn} {} @@ -831,14 +831,7 @@ Identifiers (SAFI). In addition to unicast information, VPN information Print active IPV4 or IPV6 routes advertised via the VPN SAFI. @end deffn -@deffn {Command} {show ip bgp encap all} {} -@deffnx {Command} {show ipv6 bgp encap all} {} -Print active IPV4 or IPV6 routes advertised via the Encapsulation SAFI. -@end deffn - -@deffn {Command} {show bgp ipv4 encap summary} {} -@deffnx {Command} {show bgp ipv4 vpn summary} {} -@deffnx {Command} {show bgp ipv6 encap summary} {} +@deffn {Command} {show bgp ipv4 vpn summary} {} @deffnx {Command} {show bgp ipv6 vpn summary} {} Print a summary of neighbor connections for the specified AFI/SAFI combination. @end deffn diff --git a/doc/vnc.texi b/doc/vnc.texi index 6ccf74839d..6193d3c906 100644 --- a/doc/vnc.texi +++ b/doc/vnc.texi @@ -22,8 +22,8 @@ BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VN information between NVAs. BGP based IP VPN support is defined in @cite{RFC4364, BGP/MPLS IP Virtual Private Networks (VPNs)}, and @cite{RFC4659, BGP-MPLS IP Virtual Private Network (VPN) Extension for -IPv6 VPN }. Both the Encapsulation Subsequent Address Family Identifier -(SAFI) and the Tunnel Encapsulation Attribute, @cite{RFC5512, The BGP +IPv6 VPN }. Encapsulation information is provided via +the Tunnel Encapsulation Attribute, @cite{RFC5512, The BGP Encapsulation Subsequent Address Family Identifier (SAFI) and the BGP Tunnel Encapsulation Attribute}, are supported. @@ -83,12 +83,10 @@ operating within a VN. @node General VNC Configuration @subsection General VNC Configuration -@deffn {VNC} {vnc advertise-un-method encap-safi|encap-attr} {} -Advertise NVE underlay-network IP addresses using the encapsulation SAFI -(@code{encap-safi}) or the UN address sub-TLV of the Tunnel Encapsulation attribute -(@code{encap-attr}). When @code{encap-safi} is used, neighbors under -@code{address-family encap} and/or @code{address-family encapv6} must be -configured. The default is @code{encap-attr}. +@deffn {VNC} {vnc advertise-un-method encap-attr} {} +Advertise NVE underlay-network IP addresses using +the UN address sub-TLV of the Tunnel Encapsulation attribute +(@code{encap-attr}). The default is @code{encap-attr}. @end deffn @node RFP Related Configuration @@ -356,8 +354,7 @@ by receiving NVAs. The second form, @code{rt import} specifies an @var{import rt-list}, which is a filter for incoming routes. In order to be made available to NVEs in the group, -incoming BGP VPN and @w{ENCAP} @w{SAFI} (when @code{vnc -advertise-un-method encap-safi} is set) routes must have +incoming BGP VPN @w{SAFI} routes must have RT lists that have at least one route target in common with the group's @var{import rt-list}. From e65dfe7e566f35586b3372f68de825a91df812d5 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 29 Jan 2018 15:18:28 -0500 Subject: [PATCH 81/84] zebra: Cleanup error handling of nexthop vrf and vrf The error handling of the nexthop vrf and the vrf for what was specified on the cli was not as clean as it should have been. Signed-off-by: Donald Sharp --- zebra/zebra_vty.c | 49 +++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 7b5ab1ef5c..f0be862221 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -475,20 +475,21 @@ DEFPY(ip_route_address_interface, ifname = NULL; } - if (nexthop_vrf) { - nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", - nexthop_vrf); - return CMD_WARNING_CONFIG_FAILED; - } - } else - nh_zvrf = zebra_vrf_lookup_by_name(vrf); - zvrf = zebra_vrf_lookup_by_name(vrf); + if (!zvrf) { + vty_out(vty, "%% vrf %s is not defined\n", + vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nexthop_vrf) + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + else + nh_zvrf = zvrf; + if (!nh_zvrf) { vty_out(vty, "%% nexthop vrf %s is not defined\n", - vrf); + nexthop_vrf); return CMD_WARNING_CONFIG_FAILED; } @@ -582,23 +583,25 @@ DEFPY(ip_route, ifname = NULL; } - if (nexthop_vrf) { - nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", - nexthop_vrf); - return CMD_WARNING_CONFIG_FAILED; - } - } else - nh_zvrf = zebra_vrf_lookup_by_name(vrf); - zvrf = zebra_vrf_lookup_by_name(vrf); - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", + if (!zvrf) { + vty_out(vty, "%% vrf %s is not defined\n", vrf); return CMD_WARNING_CONFIG_FAILED; } + if (nexthop_vrf) + nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf); + else + nh_zvrf = zvrf; + + if (!nh_zvrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", + nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return zebra_static_route_leak(vty, zvrf, nh_zvrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str, NULL, gate_str, ifname, flag, From c7974c0f1a7acedd1d5c4d9dff73ae8b42595c56 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 29 Jan 2018 15:38:03 -0500 Subject: [PATCH 82/84] lib: When we shutdown we would leak interface description Signed-off-by: Donald Sharp desc) + XFREE(MTYPE_TMP, ifp->desc); + XFREE(MTYPE_IF, ifp); } From 7d38890de8b16014249381ea497bc18d285d5278 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 29 Jan 2018 16:20:41 -0500 Subject: [PATCH 83/84] zebra: On shutdown actually delete rn's assoc w/ other_tables Zebra stores routes coming from the kernel for non-default tables. This information on shutdown was being leaked because we never cleaned it up. Allow for this to happen now. Signed-off-by: Donald Sharp --- zebra/zebra_vrf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 95426683a8..246a7e7e4c 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -456,6 +456,7 @@ struct route_table *zebra_vrf_other_route_table(afi_t afi, u_int32_t table_id, info->afi = afi; info->safi = SAFI_UNICAST; table->info = info; + table->cleanup = zebra_rtable_node_cleanup; zvrf->other_table[afi][table_id] = table; } From 951da4357187f3206d434a6887beafc475ad631e Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Mon, 29 Jan 2018 18:03:08 -0800 Subject: [PATCH 84/84] ospfd: Fix default-info and redis cmd options Fix default-information parsing of metric-type, route-map. show running to display metic-type 2. metric, metric-type and route-map can be configured in any order, running-config displays in specific order.. Signed-off-by: Chirag Shah --- ospfd/ospf_vty.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index cac35c1eca..c923a6f35e 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -8160,11 +8160,13 @@ DEFUN (ospf_redistribute_source, if (!str2metric(argv[idx]->arg, &metric)) return CMD_WARNING_CONFIG_FAILED; } + idx = 1; /* Get metric type. */ if (argv_find(argv, argc, "(1-2)", &idx)) { if (!str2metric_type(argv[idx]->arg, &type)) return CMD_WARNING_CONFIG_FAILED; } + idx = 1; /* Get route-map */ if (argv_find(argv, argc, "WORD", &idx)) { ospf_routemap_set(red, argv[idx]->arg); @@ -8389,16 +8391,19 @@ DEFUN (ospf_default_information_originate, /* Check whether "always" was specified */ if (argv_find(argv, argc, "always", &idx)) default_originate = DEFAULT_ORIGINATE_ALWAYS; + idx = 1; /* Get metric value */ if (argv_find(argv, argc, "(0-16777214)", &idx)) { if (!str2metric(argv[idx]->arg, &metric)) return CMD_WARNING_CONFIG_FAILED; } + idx = 1; /* Get metric type. */ if (argv_find(argv, argc, "(1-2)", &idx)) { if (!str2metric_type(argv[idx]->arg, &type)) return CMD_WARNING_CONFIG_FAILED; } + idx = 1; /* Get route-map */ if (argv_find(argv, argc, "WORD", &idx)) ospf_routemap_set(red, argv[idx]->arg); @@ -10231,8 +10236,12 @@ static int config_write_ospf_distribute(struct vty *vty, struct ospf *ospf) if (red->dmetric.value >= 0) vty_out(vty, " metric %d", red->dmetric.value); + if (red->dmetric.type == EXTERNAL_METRIC_TYPE_1) vty_out(vty, " metric-type 1"); + else if (red->dmetric.type == + EXTERNAL_METRIC_TYPE_2) + vty_out(vty, " metric-type 2"); if (ROUTEMAP_NAME(red)) vty_out(vty, " route-map %s",