diff --git a/lib/zclient.c b/lib/zclient.c index 13eba4c790..b7d240b4e8 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1017,9 +1017,10 @@ done: return ret; } -static int zapi_nhg_encode(struct stream *s, uint16_t proto, int cmd, - struct zapi_nhg *api_nhg) +int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg) { + int i; + if (cmd != ZEBRA_NHG_DEL && cmd != ZEBRA_NHG_ADD) { flog_err(EC_LIB_ZAPI_ENCODE, "%s: Specified zapi NHG command (%d) doesn't exist\n", @@ -1030,17 +1031,26 @@ static int zapi_nhg_encode(struct stream *s, uint16_t proto, int cmd, stream_reset(s); zclient_create_header(s, cmd, VRF_DEFAULT); - stream_putw(s, proto); + stream_putw(s, api_nhg->proto); stream_putl(s, api_nhg->id); if (cmd == ZEBRA_NHG_ADD) { + /* Nexthops */ zapi_nexthop_group_sort(api_nhg->nexthops, api_nhg->nexthop_num); stream_putw(s, api_nhg->nexthop_num); - for (int i = 0; i < api_nhg->nexthop_num; i++) + for (i = 0; i < api_nhg->nexthop_num; i++) zapi_nexthop_encode(s, &api_nhg->nexthops[i], 0, 0); + + /* Backup nexthops */ + + stream_putw(s, api_nhg->backup_nexthop_num); + + for (i = 0; i < api_nhg->backup_nexthop_num; i++) + zapi_nexthop_encode(s, &api_nhg->backup_nexthops[i], 0, + 0); } stream_putw_at(s, 0, stream_get_endp(s)); @@ -1050,8 +1060,9 @@ static int zapi_nhg_encode(struct stream *s, uint16_t proto, int cmd, int zclient_nhg_send(struct zclient *zclient, int cmd, struct zapi_nhg *api_nhg) { - if (zapi_nhg_encode(zclient->obuf, zclient->redist_default, cmd, - api_nhg)) + api_nhg->proto = zclient->redist_default; + + if (zapi_nhg_encode(zclient->obuf, cmd, api_nhg)) return -1; return zclient_send_message(zclient); diff --git a/lib/zclient.h b/lib/zclient.h index b41f291554..959a101395 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -442,9 +442,14 @@ struct zapi_nexthop { * ZAPI Nexthop Group. For use with protocol creation of nexthop groups. */ struct zapi_nhg { + uint16_t proto; uint32_t id; + uint16_t nexthop_num; struct zapi_nexthop nexthops[MULTIPATH_NUM]; + + uint16_t backup_nexthop_num; + struct zapi_nexthop backup_nexthops[MULTIPATH_NUM]; }; /* @@ -907,6 +912,9 @@ bool zapi_ipset_notify_decode(struct stream *s, uint32_t *unique, enum zapi_ipset_notify_owner *note); + +extern int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg); +extern int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg); extern int zclient_nhg_send(struct zclient *zclient, int cmd, struct zapi_nhg *api_nhg); diff --git a/sharpd/sharp_nht.c b/sharpd/sharp_nht.c index 9f31552720..5b3fe2583e 100644 --- a/sharpd/sharp_nht.c +++ b/sharpd/sharp_nht.c @@ -133,11 +133,15 @@ static void sharp_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc, { struct sharp_nhg lookup; struct sharp_nhg *snhg; + struct nexthop_group_cmd *bnhgc = NULL; strlcpy(lookup.name, nhgc->name, sizeof(lookup.name)); snhg = sharp_nhg_rb_find(&nhg_head, &lookup); - nhg_add(snhg->id, &nhgc->nhg); + if (nhgc->backup_list_name[0]) + bnhgc = nhgc_find(nhgc->backup_list_name); + + nhg_add(snhg->id, &nhgc->nhg, (bnhgc ? &bnhgc->nhg : NULL)); } static void sharp_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, @@ -145,11 +149,15 @@ static void sharp_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, { struct sharp_nhg lookup; struct sharp_nhg *snhg; + struct nexthop_group_cmd *bnhgc = NULL; strlcpy(lookup.name, nhgc->name, sizeof(lookup.name)); snhg = sharp_nhg_rb_find(&nhg_head, &lookup); - nhg_add(snhg->id, &nhgc->nhg); + if (nhgc->backup_list_name[0]) + bnhgc = nhgc_find(nhgc->backup_list_name); + + nhg_add(snhg->id, &nhgc->nhg, (bnhgc ? &bnhgc->nhg : NULL)); } static void sharp_nhgroup_delete_cb(const char *name) diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 50129c2363..d167e8e277 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -357,7 +357,8 @@ void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label) zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP); } -void nhg_add(uint32_t id, const struct nexthop_group *nhg) +void nhg_add(uint32_t id, const struct nexthop_group *nhg, + const struct nexthop_group *backup_nhg) { struct zapi_nhg api_nhg = {}; struct zapi_nexthop *api_nh; @@ -378,6 +379,22 @@ void nhg_add(uint32_t id, const struct nexthop_group *nhg) api_nhg.nexthop_num++; } + if (backup_nhg) { + for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) { + if (api_nhg.backup_nexthop_num >= MULTIPATH_NUM) { + zlog_warn( + "%s: number of backup nexthops greater than max multipath size, truncating", + __func__); + break; + } + api_nh = &api_nhg.backup_nexthops + [api_nhg.backup_nexthop_num]; + + zapi_backup_nexthop_from_nexthop(api_nh, nh); + api_nhg.backup_nexthop_num++; + } + } + zclient_nhg_send(zclient, ZEBRA_NHG_ADD, &api_nhg); } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 69d7343cc4..4a767ababf 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -29,7 +29,8 @@ int sharp_zclient_create(uint32_t session_id); int sharp_zclient_delete(uint32_t session_id); extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label); -extern void nhg_add(uint32_t id, const struct nexthop_group *nhg); +extern void nhg_add(uint32_t id, const struct nexthop_group *nhg, + const struct nexthop_group *backup_nhg); extern void nhg_del(uint32_t id); extern void route_add(const struct prefix *p, vrf_id_t, uint8_t instance, uint32_t nhgid, const struct nexthop_group *nhg, diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 7ed3a41ae1..1d8c5c7cc0 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1732,84 +1732,134 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, return true; } +int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg) +{ + uint16_t i; + struct zapi_nexthop *znh; + + STREAM_GETW(s, api_nhg->proto); + STREAM_GETL(s, api_nhg->id); + + if (cmd == ZEBRA_NHG_DEL) + goto done; + + /* Nexthops */ + STREAM_GETW(s, api_nhg->nexthop_num); + + if (zserv_nexthop_num_warn(__func__, NULL, api_nhg->nexthop_num)) + return -1; + + if (api_nhg->nexthop_num <= 0) { + flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED, + "%s: No nexthops sent", __func__); + return -1; + } + + for (i = 0; i < api_nhg->nexthop_num; i++) { + znh = &((api_nhg->nexthops)[i]); + + if (zapi_nexthop_decode(s, znh, 0, 0) != 0) { + flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED, + "%s: Nexthop creation failed", __func__); + return -1; + } + } + + /* Backup Nexthops */ + STREAM_GETW(s, api_nhg->backup_nexthop_num); + + if (zserv_nexthop_num_warn(__func__, NULL, api_nhg->backup_nexthop_num)) + return -1; + + for (i = 0; i < api_nhg->backup_nexthop_num; i++) { + znh = &((api_nhg->backup_nexthops)[i]); + + if (zapi_nexthop_decode(s, znh, 0, 0) != 0) { + flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED, + "%s: Backup Nexthop creation failed", + __func__); + return -1; + } + } + +done: + return 0; + +stream_failure: + flog_warn( + EC_ZEBRA_NEXTHOP_CREATION_FAILED, + "%s: Nexthop Group decode failed with some sort of stream read failure", + __func__); + return -1; +} + static void zread_nhg_del(ZAPI_HANDLER_ARGS) { - struct stream *s = msg; - uint32_t id; - uint16_t proto; + struct stream *s; + struct zapi_nhg api_nhg = {}; struct nhg_hash_entry *nhe; - STREAM_GETW(s, proto); - STREAM_GETL(s, id); + s = msg; + if (zapi_nhg_decode(s, hdr->command, &api_nhg) < 0) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Unable to decode zapi_nhg sent", + __func__); + return; + } /* * Delete the received nhg id */ - nhe = zebra_nhg_proto_del(id, proto); + nhe = zebra_nhg_proto_del(api_nhg.id, api_nhg.proto); if (nhe) { zebra_nhg_decrement_ref(nhe); - nhg_notify(proto, client->instance, id, ZAPI_NHG_REMOVED); + nhg_notify(api_nhg.proto, client->instance, api_nhg.id, + ZAPI_NHG_REMOVED); } else - nhg_notify(proto, client->instance, id, ZAPI_NHG_REMOVE_FAIL); - - return; - -stream_failure: - flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED, - "%s: Nexthop group deletion failed", __func__); - return; + nhg_notify(api_nhg.proto, client->instance, api_nhg.id, + ZAPI_NHG_REMOVE_FAIL); } static void zread_nhg_add(ZAPI_HANDLER_ARGS) { struct stream *s; - uint32_t id; - size_t nhops, i; - struct zapi_nexthop zapi_nexthops[MULTIPATH_NUM]; + struct zapi_nhg api_nhg = {}; struct nexthop_group *nhg = NULL; - uint16_t proto; + struct nhg_backup_info *bnhg = NULL; struct nhg_hash_entry *nhe; s = msg; - - STREAM_GETW(s, proto); - STREAM_GETL(s, id); - STREAM_GETW(s, nhops); - - if (zserv_nexthop_num_warn(__func__, NULL, nhops)) - return; - - if (nhops <= 0) { - flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED, - "%s: No nexthops sent", __func__); + if (zapi_nhg_decode(s, hdr->command, &api_nhg) < 0) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Unable to decode zapi_nhg sent", + __func__); return; } - for (i = 0; i < nhops; i++) { - struct zapi_nexthop *znh = &zapi_nexthops[i]; + if ((!zapi_read_nexthops(client, NULL, api_nhg.nexthops, 0, 0, + api_nhg.nexthop_num, + api_nhg.backup_nexthop_num, &nhg, NULL)) + || (!zapi_read_nexthops(client, NULL, api_nhg.backup_nexthops, 0, 0, + api_nhg.backup_nexthop_num, + api_nhg.backup_nexthop_num, NULL, &bnhg))) { - if (zapi_nexthop_decode(s, znh, 0, 0) != 0) { - flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED, - "%s: Nexthop creation failed", __func__); - return; - } - } - - if (!zapi_read_nexthops(client, NULL, zapi_nexthops, 0, 0, nhops, 0, - &nhg, NULL)) { flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED, "%s: Nexthop Group Creation failed", __func__); + + nexthop_group_delete(&nhg); + zebra_nhg_backup_free(&bnhg); return; } /* * Create the nhg */ - nhe = zebra_nhg_proto_add(id, proto, nhg, 0); + nhe = zebra_nhg_proto_add(api_nhg.id, api_nhg.proto, nhg, 0); nexthop_group_delete(&nhg); + zebra_nhg_backup_free(&bnhg); /* * TODO: @@ -1818,18 +1868,11 @@ static void zread_nhg_add(ZAPI_HANDLER_ARGS) * Resolution is going to need some more work. */ if (nhe) - nhg_notify(proto, client->instance, id, ZAPI_NHG_INSTALLED); + nhg_notify(api_nhg.proto, client->instance, api_nhg.id, + ZAPI_NHG_INSTALLED); else - nhg_notify(proto, client->instance, id, ZAPI_NHG_FAIL_INSTALL); - - return; - -stream_failure: - flog_warn( - EC_ZEBRA_NEXTHOP_CREATION_FAILED, - "%s: Nexthop Group creation failed with some sort of stream read failure", - __func__); - return; + nhg_notify(api_nhg.proto, client->instance, api_nhg.id, + ZAPI_NHG_FAIL_INSTALL); } static void zread_route_add(ZAPI_HANDLER_ARGS) @@ -1911,6 +1954,9 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) api.flags, api.message, api.backup_nexthop_num, api.backup_nexthop_num, NULL, &bnhg))) { + + nexthop_group_delete(&ng); + zebra_nhg_backup_free(&bnhg); XFREE(MTYPE_RE, re); return; } diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 1ed7ff00e5..6aa9ba0ebc 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2759,6 +2759,14 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type, * Once resolution is figured out, we won't need this! */ for (ALL_NEXTHOPS_PTR(nhg, newhop)) { + if (CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + if (IS_ZEBRA_DEBUG_NHG) + zlog_debug( + "%s: id %u, backup nexthops not supported", + __func__, id); + return NULL; + } + if (newhop->type == NEXTHOP_TYPE_BLACKHOLE) { if (IS_ZEBRA_DEBUG_NHG) zlog_debug(