From 8c15fa95a81fe0062556e3b64df29509eeb035e6 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 5 Aug 2019 15:30:05 -0400 Subject: [PATCH 1/2] lib: Add tail check before nexthop insertion Add a tail check to see if we can just put the nexthop at the end of the already sorted list before iteration. Signed-off-by: Stephen Worley --- lib/nexthop_group.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 5602018b30..abe2096cec 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -60,6 +60,16 @@ nexthop_group_cmd_compare(const struct nexthop_group_cmd *nhgc1, return strcmp(nhgc1->name, nhgc2->name); } +static struct nexthop *nexthop_group_tail(const struct nexthop_group *nhg) +{ + struct nexthop *nexthop = nhg->nexthop; + + while (nexthop && nexthop->next) + nexthop = nexthop->next; + + return nexthop; +} + uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg) { struct nexthop *nhop; @@ -129,7 +139,20 @@ void _nexthop_add(struct nexthop **target, struct nexthop *nexthop) void _nexthop_group_add_sorted(struct nexthop_group *nhg, struct nexthop *nexthop) { - struct nexthop *position, *prev; + struct nexthop *position, *prev, *tail; + + /* Try to just append to the end first + * This trust it is already sorted + */ + + tail = nexthop_group_tail(nhg); + + if (tail && (nexthop_cmp(tail, nexthop) < 0)) { + tail->next = nexthop; + nexthop->prev = tail; + + return; + } for (position = nhg->nexthop, prev = NULL; position; prev = position, position = position->next) { From 3c6e0bd4726f43bd0ab96c26747022bff03b119d Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Mon, 19 Aug 2019 15:56:45 -0400 Subject: [PATCH 2/2] lib: Sort zapi_nexthops on the encode Sort nexthops before we push them to zebra. This offloads the nexthop sorting zebra is doing onto the upper level protocols so that when it gets to zebra and we construct a group, it just has to append them to the tail for every nexthop. Signed-off-by: Stephen Worley --- lib/nexthop.c | 9 +++--- lib/nexthop.h | 3 ++ lib/zclient.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 5 deletions(-) diff --git a/lib/nexthop.c b/lib/nexthop.c index 0984c1a168..cf5bed3d62 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -65,9 +65,8 @@ static int _nexthop_labels_cmp(const struct nexthop *nh1, return memcmp(nhl1->label, nhl2->label, nhl1->num_labels); } -static int _nexthop_g_addr_cmp(enum nexthop_types_t type, - const union g_addr *addr1, - const union g_addr *addr2) +int nexthop_g_addr_cmp(enum nexthop_types_t type, const union g_addr *addr1, + const union g_addr *addr2) { int ret = 0; @@ -92,13 +91,13 @@ static int _nexthop_g_addr_cmp(enum nexthop_types_t type, static int _nexthop_gateway_cmp(const struct nexthop *nh1, const struct nexthop *nh2) { - return _nexthop_g_addr_cmp(nh1->type, &nh1->gate, &nh2->gate); + return nexthop_g_addr_cmp(nh1->type, &nh1->gate, &nh2->gate); } static int _nexthop_source_cmp(const struct nexthop *nh1, const struct nexthop *nh2) { - return _nexthop_g_addr_cmp(nh1->type, &nh1->src, &nh2->src); + return nexthop_g_addr_cmp(nh1->type, &nh1->src, &nh2->src); } static int _nexthop_cmp_no_labels(const struct nexthop *next1, diff --git a/lib/nexthop.h b/lib/nexthop.h index 20401cd581..9dd5fc6fd3 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -142,6 +142,9 @@ extern bool nexthop_same(const struct nexthop *nh1, const struct nexthop *nh2); extern bool nexthop_same_no_labels(const struct nexthop *nh1, const struct nexthop *nh2); extern int nexthop_cmp(const struct nexthop *nh1, const struct nexthop *nh2); +extern int nexthop_g_addr_cmp(enum nexthop_types_t type, + const union g_addr *addr1, + const union g_addr *addr2); extern const char *nexthop_type_to_str(enum nexthop_types_t nh_type); extern bool nexthop_labels_match(const struct nexthop *nh1, diff --git a/lib/zclient.c b/lib/zclient.c index 6937700199..cb9f927235 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -765,6 +765,92 @@ int zclient_route_send(uint8_t cmd, struct zclient *zclient, return zclient_send_message(zclient); } +static int zapi_nexthop_labels_cmp(const struct zapi_nexthop *next1, + const struct zapi_nexthop *next2) +{ + if (next1->label_num > next2->label_num) + return 1; + + if (next1->label_num < next2->label_num) + return -1; + + return memcmp(next1->labels, next2->labels, next1->label_num); +} + +static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1, + const struct zapi_nexthop *next2) +{ + int ret = 0; + + if (next1->vrf_id < next2->vrf_id) + return -1; + + if (next1->vrf_id > next2->vrf_id) + return 1; + + if (next1->type < next2->type) + return -1; + + if (next1->type > next2->type) + return 1; + + switch (next1->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV6: + ret = nexthop_g_addr_cmp(next1->type, &next1->gate, + &next2->gate); + if (ret != 0) + return ret; + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFINDEX: + ret = nexthop_g_addr_cmp(next1->type, &next1->gate, + &next2->gate); + if (ret != 0) + return ret; + /* Intentional Fall-Through */ + case NEXTHOP_TYPE_IFINDEX: + if (next1->ifindex < next2->ifindex) + return -1; + + if (next1->ifindex > next2->ifindex) + return 1; + break; + case NEXTHOP_TYPE_BLACKHOLE: + if (next1->bh_type < next2->bh_type) + return -1; + + if (next1->bh_type > next2->bh_type) + return 1; + break; + } + + return 0; +} + +static int zapi_nexthop_cmp(const void *item1, const void *item2) +{ + int ret = 0; + + const struct zapi_nexthop *next1 = item1; + const struct zapi_nexthop *next2 = item2; + + ret = zapi_nexthop_cmp_no_labels(next1, next2); + if (ret != 0) + return ret; + + ret = zapi_nexthop_labels_cmp(next1, next2); + + return ret; +} + +static void zapi_nexthop_group_sort(struct zapi_nexthop *nh_grp, + uint16_t nexthop_num) +{ + qsort(nh_grp, nexthop_num, sizeof(struct zapi_nexthop), + &zapi_nexthop_cmp); +} + int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) { struct zapi_nexthop *api_nh; @@ -820,6 +906,8 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) return -1; } + zapi_nexthop_group_sort(api->nexthops, api->nexthop_num); + stream_putw(s, api->nexthop_num); for (i = 0; i < api->nexthop_num; i++) {