From: Donald Sharp Date: Wed, 29 Apr 2020 14:49:21 +0000 (-0400) Subject: lib, zebra: Add ZAPI_NHG_ADD|DELETE X-Git-Tag: base_7.6~489^2~53 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=2f35a820bf51f114c3c382f65c2dd3e1e9b67194;p=matthieu%2Ffrr.git lib, zebra: Add ZAPI_NHG_ADD|DELETE Add the ability to send a NHG from an upper level protocol down to zebra. ZAPI_NHG_ADD encompasses both the addition and replace semantics ( If the id passed down does not exist yet, it's Add, else it's a replace ). Effectively zebra will take this nhg passed down save the nhg in the id hash for nhg's and then create the appropriate nhg's and finally install them into the linux kernel. Notification will be the ZAPI_NHG_NOTIFY_OWNER zapi message for normal success/failure messaging to the installing protocol. This work is being done to allow us to work with EVPN MH which needs the ability to modify NHG's that BGP will own and operate on. Signed-off-by: Donald Sharp --- diff --git a/lib/zclient.c b/lib/zclient.c index b0549bf84e..9ff3a8eea3 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1017,6 +1017,51 @@ done: return ret; } +extern void zclient_nhg_del(struct zclient *zclient, uint32_t id) +{ + struct stream *s = zclient->obuf; + + stream_reset(s); + zclient_create_header(s, ZEBRA_NHG_DEL, VRF_DEFAULT); + + stream_putw(s, zclient->redist_default); + stream_putl(s, id); + + stream_putw_at(s, 0, stream_get_endp(s)); +} + +static void zclient_nhg_writer(struct stream *s, uint16_t proto, int cmd, + uint32_t id, size_t nhops, + struct zapi_nexthop *znh) +{ + size_t i; + + stream_reset(s); + + zapi_nexthop_group_sort(znh, nhops); + + zclient_create_header(s, cmd, VRF_DEFAULT); + + stream_putw(s, proto); + stream_putl(s, id); + stream_putw(s, nhops); + for (i = 0; i < nhops; i++) { + zapi_nexthop_encode(s, znh, 0, 0); + znh++; + } + + stream_putw_at(s, 0, stream_get_endp(s)); +} + +extern void zclient_nhg_add(struct zclient *zclient, uint32_t id, + size_t nhops, struct zapi_nexthop *znh) +{ + struct stream *s = zclient->obuf; + + zclient_nhg_writer(s, zclient->redist_default, ZEBRA_NHG_ADD, id, nhops, + znh); +} + int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) { struct zapi_nexthop *api_nh; @@ -1171,8 +1216,8 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) /* * Decode a single zapi nexthop object */ -static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, - uint32_t api_flags, uint32_t api_message) +int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, + uint32_t api_flags, uint32_t api_message) { int i, ret = -1; @@ -1432,6 +1477,22 @@ int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule) return 0; } +bool zapi_nhg_notify_decode(struct stream *s, uint32_t *id, + enum zapi_nhg_notify_owner *note) +{ + uint16_t read_id; + + STREAM_GETL(s, read_id); + STREAM_GET(note, s, sizeof(*note)); + + *id = read_id; + + return true; + +stream_failure: + return false; +} + bool zapi_route_notify_decode(struct stream *s, struct prefix *p, uint32_t *tableid, enum zapi_route_notify_owner *note) @@ -3733,6 +3794,11 @@ static int zclient_read(struct thread *thread) (*zclient->rule_notify_owner)(command, zclient, length, vrf_id); break; + case ZEBRA_NHG_NOTIFY_OWNER: + if (zclient->nhg_notify_owner) + (*zclient->nhg_notify_owner)(command, zclient, length, + vrf_id); + break; case ZEBRA_GET_LABEL_CHUNK: if (zclient->label_chunk) (*zclient->label_chunk)(command, zclient, length, diff --git a/lib/zclient.h b/lib/zclient.h index d2f559c45d..40f345a1be 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -209,6 +209,9 @@ typedef enum { ZEBRA_MLAG_CLIENT_REGISTER, ZEBRA_MLAG_CLIENT_UNREGISTER, ZEBRA_MLAG_FORWARD_MSG, + ZEBRA_NHG_ADD, + ZEBRA_NHG_DEL, + ZEBRA_NHG_NOTIFY_OWNER, ZEBRA_ERROR, ZEBRA_CLIENT_CAPABILITIES, ZEBRA_OPAQUE_MESSAGE, @@ -354,6 +357,7 @@ struct zclient { int (*mlag_process_up)(void); int (*mlag_process_down)(void); int (*mlag_handle_msg)(struct stream *msg, int len); + int (*nhg_notify_owner)(ZAPI_CALLBACK_ARGS); int (*handle_error)(enum zebra_error_types error); int (*opaque_msg_handler)(ZAPI_CALLBACK_ARGS); int (*opaque_register_handler)(ZAPI_CALLBACK_ARGS); @@ -592,6 +596,13 @@ enum zapi_route_notify_owner { ZAPI_ROUTE_REMOVE_FAIL, }; +enum zapi_nhg_notify_owner { + ZAPI_NHG_FAIL_INSTALL, + ZAPI_NHG_INSTALLED, + ZAPI_NHG_REMOVED, + ZAPI_NHG_REMOVE_FAIL, +}; + enum zapi_rule_notify_owner { ZAPI_RULE_FAIL_INSTALL, ZAPI_RULE_INSTALLED, @@ -861,7 +872,11 @@ extern int zclient_send_rnh(struct zclient *zclient, int command, int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, uint32_t api_flags, uint32_t api_message); extern int zapi_route_encode(uint8_t, struct stream *, struct zapi_route *); -extern int zapi_route_decode(struct stream *, struct zapi_route *); +extern int zapi_route_decode(struct stream *s, struct zapi_route *api); +extern int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, + uint32_t api_flags, uint32_t api_message); +bool zapi_nhg_notify_decode(struct stream *s, uint32_t *id, + enum zapi_nhg_notify_owner *note); bool zapi_route_notify_decode(struct stream *s, struct prefix *p, uint32_t *tableid, enum zapi_route_notify_owner *note); @@ -872,6 +887,11 @@ bool zapi_ipset_notify_decode(struct stream *s, uint32_t *unique, enum zapi_ipset_notify_owner *note); +extern void zclient_nhg_add(struct zclient *zclient, + uint32_t id, size_t nhops, + struct zapi_nexthop *znh); +extern void zclient_nhg_del(struct zclient *zclient, uint32_t id); + #define ZEBRA_IPSET_NAME_SIZE 32 bool zapi_ipset_entry_notify_decode(struct stream *s, diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 1301a577f2..2d04da5052 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -712,6 +712,34 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, return zserv_send_message(client, s); } +static int nhg_notify(uint16_t type, uint16_t instance, uint16_t id, + enum zapi_nhg_notify_owner note) +{ + struct zserv *client; + struct stream *s; + + client = zserv_find_client(type, instance); + if (!client) { + if (IS_ZEBRA_DEBUG_PACKET) { + zlog_debug("Not Notifying Owner: %u(%u) about %u(%d)", + type, instance, id, note); + } + return 0; + } + + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + stream_reset(s); + + zclient_create_header(s, ZEBRA_NHG_NOTIFY_OWNER, VRF_DEFAULT); + + stream_putw(s, id); + stream_put(s, ¬e, sizeof(note)); + + stream_putw_at(s, 0, stream_get_endp(s)); + + return zserv_send_message(client, s); +} + /* * Common utility send route notification, called from a path using a * route_entry and from a path using a dataplane context. @@ -1431,9 +1459,9 @@ bool zserv_nexthop_num_warn(const char *caller, const struct prefix *p, /* * Create a new nexthop based on a zapi nexthop. */ -static struct nexthop *nexthop_from_zapi(struct route_entry *re, - const struct zapi_nexthop *api_nh, - const struct zapi_route *api) +static struct nexthop *nexthop_from_zapi(const struct zapi_nexthop *api_nh, + uint32_t flags, struct prefix *p, + uint16_t backup_nexthop_num) { struct nexthop *nexthop = NULL; struct ipaddr vtep_ip; @@ -1471,14 +1499,14 @@ static struct nexthop *nexthop_from_zapi(struct route_entry *re, /* Special handling for IPv4 routes sourced from EVPN: * the nexthop and associated MAC need to be installed. */ - if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) { + if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) { memset(&vtep_ip, 0, sizeof(struct ipaddr)); vtep_ip.ipa_type = IPADDR_V4; memcpy(&(vtep_ip.ipaddr_v4), &(api_nh->gate.ipv4), sizeof(struct in_addr)); zebra_vxlan_evpn_vrf_route_add( api_nh->vrf_id, &api_nh->rmac, - &vtep_ip, &api->prefix); + &vtep_ip, p); } break; case NEXTHOP_TYPE_IPV6: @@ -1505,14 +1533,14 @@ static struct nexthop *nexthop_from_zapi(struct route_entry *re, /* Special handling for IPv6 routes sourced from EVPN: * the nexthop and associated MAC need to be installed. */ - if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) { + if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) { memset(&vtep_ip, 0, sizeof(struct ipaddr)); vtep_ip.ipa_type = IPADDR_V6; memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6), sizeof(struct in6_addr)); zebra_vxlan_evpn_vrf_route_add( api_nh->vrf_id, &api_nh->rmac, - &vtep_ip, &api->prefix); + &vtep_ip, p); } break; case NEXTHOP_TYPE_BLACKHOLE: @@ -1560,7 +1588,7 @@ static struct nexthop *nexthop_from_zapi(struct route_entry *re, for (i = 0; i < api_nh->backup_num; i++) { /* Validate backup index */ - if (api_nh->backup_idx[i] < api->backup_nexthop_num) { + if (api_nh->backup_idx[i] < backup_nexthop_num) { nexthop->backup_idx[i] = api_nh->backup_idx[i]; } else { if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT) @@ -1578,33 +1606,29 @@ done: return nexthop; } -static bool zapi_read_nexthops(struct zserv *client, struct zapi_route *api, - struct route_entry *re, +static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, + struct zapi_nexthop *nhops, uint32_t flags, + uint32_t message, uint16_t nexthop_num, + uint16_t backup_nh_num, struct nexthop_group **png, struct nhg_backup_info **pbnhg) { struct nexthop_group *ng = NULL; struct nhg_backup_info *bnhg = NULL; - uint16_t nexthop_num, i;; - struct zapi_nexthop *nhops; + uint16_t i; struct nexthop *last_nh = NULL; assert(!(png && pbnhg)); - if (png) { + if (png) *png = ng = nexthop_group_new(); - nexthop_num = api->nexthop_num; - nhops = api->nexthops; - } - if (pbnhg && api->backup_nexthop_num > 0) { + if (pbnhg && backup_nh_num > 0) { if (IS_ZEBRA_DEBUG_RECV) - zlog_debug("%s: adding %d backup nexthops", - __func__, api->backup_nexthop_num); + zlog_debug("%s: adding %d backup nexthops", __func__, + backup_nh_num); - nexthop_num = api->backup_nexthop_num; *pbnhg = bnhg = zebra_nhg_backup_alloc(); - nhops = api->backup_nexthops; } /* @@ -1620,7 +1644,7 @@ static bool zapi_read_nexthops(struct zserv *client, struct zapi_route *api, struct zapi_nexthop *api_nh = &nhops[i]; /* Convert zapi nexthop */ - nexthop = nexthop_from_zapi(re, api_nh, api); + nexthop = nexthop_from_zapi(api_nh, flags, p, backup_nh_num); if (!nexthop) { flog_warn( EC_ZEBRA_NEXTHOP_CREATION_FAILED, @@ -1643,7 +1667,7 @@ static bool zapi_read_nexthops(struct zserv *client, struct zapi_route *api, nexthop->backup_num = 0; } - if (CHECK_FLAG(api->message, ZAPI_MESSAGE_SRTE)) { + if (CHECK_FLAG(message, ZAPI_MESSAGE_SRTE)) { SET_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE); nexthop->srte_color = api_nh->srte_color; } @@ -1705,6 +1729,83 @@ static bool zapi_read_nexthops(struct zserv *client, struct zapi_route *api, return true; } +static void zread_nhg_del(ZAPI_HANDLER_ARGS) +{ + struct stream *s = msg; + uint32_t id; + uint16_t proto; + + STREAM_GETW(s, proto); + STREAM_GETL(s, id); + + /* + * Delete the received nhg id + * id is incremented to make compiler happy right now + * it should be removed in future code work. + */ + nhg_notify(proto, client->instance, id, ZAPI_NHG_REMOVED); + + return; + +stream_failure: + flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED, + "%s: Nexthop group deletion failed", __func__); + return; +} + +static void zread_nhg_reader(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + uint32_t id; + size_t nhops, i; + struct zapi_nexthop zapi_nexthops[MULTIPATH_NUM]; + struct nexthop_group *nhg = NULL; + struct prefix p; + uint16_t proto; + + memset(&p, 0, sizeof(p)); + + s = msg; + + STREAM_GETW(s, proto); + STREAM_GETL(s, id); + STREAM_GETW(s, nhops); + + if (zserv_nexthop_num_warn(__func__, &p, nhops)) + return; + + for (i = 0; i < nhops; i++) { + struct zapi_nexthop *znh = &zapi_nexthops[i]; + + 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, &p, zapi_nexthops, 0, 0, nhops, 0, &nhg, + NULL)) { + flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED, + "%s: Nexthop Group Creation failed", + __func__); + return; + } + /* + * Install the nhg + */ + nhg_notify(proto, client->instance, id, ZAPI_NHG_INSTALLED); + + return; + +stream_failure: + flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED, + "%s: Nexthop Group creation failed with some sort of stream read failure", + __func__); + return; +} + static void zread_route_add(ZAPI_HANDLER_ARGS) { struct stream *s; @@ -1770,8 +1871,13 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) zebra_route_string(client->proto), &api.prefix); } - if (!zapi_read_nexthops(client, &api, re, &ng, NULL) || - !zapi_read_nexthops(client, &api, re, NULL, &bnhg)) { + if (!zapi_read_nexthops(client, &api.prefix, api.nexthops, api.flags, + api.message, api.nexthop_num, + api.backup_nexthop_num, &ng, NULL) + || !zapi_read_nexthops(client, &api.prefix, api.backup_nexthops, + api.flags, api.message, + api.backup_nexthop_num, + api.backup_nexthop_num, NULL, &bnhg)) { XFREE(MTYPE_RE, re); return; } @@ -3095,7 +3201,10 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_MLAG_CLIENT_UNREGISTER] = zebra_mlag_client_unregister, [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg, [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities, - [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover}; + [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover, + [ZEBRA_NHG_ADD] = zread_nhg_reader, + [ZEBRA_NHG_DEL] = zread_nhg_del, +}; /* * Process a batch of zapi messages.