diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 03d5cd984f..ccb888cf53 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -3102,43 +3102,6 @@ int bgp_zebra_update(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type) } -int zclient_capabilities_send(uint32_t cmd, struct zclient *zclient, - struct zapi_cap *api) -{ - struct stream *s; - - if (zclient == NULL) - return -1; - - s = zclient->obuf; - stream_reset(s); - zclient_create_header(s, cmd, 0); - stream_putl(s, api->cap); - switch (api->cap) { - case ZEBRA_CLIENT_GR_CAPABILITIES: - case ZEBRA_CLIENT_RIB_STALE_TIME: - stream_putl(s, api->stale_removal_time); - stream_putl(s, api->vrf_id); - break; - case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: - case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: - stream_putl(s, api->afi); - stream_putl(s, api->safi); - stream_putl(s, api->vrf_id); - break; - case ZEBRA_CLIENT_GR_DISABLE: - stream_putl(s, api->vrf_id); - break; - default: - break; - } - - /* Put length at the first point of the stream */ - stream_putw_at(s, 0, stream_get_endp(s)); - - return zclient_send_message(zclient); -} - /* Send RIB stale timer update */ int bgp_zebra_stale_timer_update(struct bgp *bgp) { diff --git a/doc/developer/zebra.rst b/doc/developer/zebra.rst index 74a8605bf2..e3526d1843 100644 --- a/doc/developer/zebra.rst +++ b/doc/developer/zebra.rst @@ -169,175 +169,201 @@ Zebra Protocol Commands +------------------------------------+-------+ | ZEBRA_INTERFACE_SET_MASTER | 6 | +------------------------------------+-------+ -| ZEBRA_ROUTE_ADD | 7 | +| ZEBRA_INTERFACE_SET_PROTODOWN | 7 | +------------------------------------+-------+ -| ZEBRA_ROUTE_DELETE | 8 | +| ZEBRA_ROUTE_ADD | 8 | +------------------------------------+-------+ -| ZEBRA_ROUTE_NOTIFY_OWNER | 9 | +| ZEBRA_ROUTE_DELETE | 9 | +------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_ADD | 10 | +| ZEBRA_ROUTE_NOTIFY_OWNER | 10 | +------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_DELETE | 11 | +| ZEBRA_REDISTRIBUTE_ADD | 11 | +------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_DEFAULT_ADD | 12 | +| ZEBRA_REDISTRIBUTE_DELETE | 12 | +------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_DEFAULT_DELETE | 13 | +| ZEBRA_REDISTRIBUTE_DEFAULT_ADD | 13 | +------------------------------------+-------+ -| ZEBRA_ROUTER_ID_ADD | 14 | +| ZEBRA_REDISTRIBUTE_DEFAULT_DELETE | 14 | +------------------------------------+-------+ -| ZEBRA_ROUTER_ID_DELETE | 15 | +| ZEBRA_ROUTER_ID_ADD | 15 | +------------------------------------+-------+ -| ZEBRA_ROUTER_ID_UPDATE | 16 | +| ZEBRA_ROUTER_ID_DELETE | 16 | +------------------------------------+-------+ -| ZEBRA_HELLO | 17 | +| ZEBRA_ROUTER_ID_UPDATE | 17 | +------------------------------------+-------+ -| ZEBRA_CAPABILITIES | 18 | +| ZEBRA_HELLO | 18 | +------------------------------------+-------+ -| ZEBRA_NEXTHOP_REGISTER | 19 | +| ZEBRA_CAPABILITIES | 19 | +------------------------------------+-------+ -| ZEBRA_NEXTHOP_UNREGISTER | 20 | +| ZEBRA_NEXTHOP_REGISTER | 20 | +------------------------------------+-------+ -| ZEBRA_NEXTHOP_UPDATE | 21 | +| ZEBRA_NEXTHOP_UNREGISTER | 21 | +------------------------------------+-------+ -| ZEBRA_INTERFACE_NBR_ADDRESS_ADD | 22 | +| ZEBRA_NEXTHOP_UPDATE | 22 | +------------------------------------+-------+ -| ZEBRA_INTERFACE_NBR_ADDRESS_DELETE | 23 | +| ZEBRA_INTERFACE_NBR_ADDRESS_ADD | 23 | +------------------------------------+-------+ -| ZEBRA_INTERFACE_BFD_DEST_UPDATE | 24 | +| ZEBRA_INTERFACE_NBR_ADDRESS_DELETE | 24 | +------------------------------------+-------+ -| ZEBRA_IMPORT_ROUTE_REGISTER | 25 | +| ZEBRA_INTERFACE_BFD_DEST_UPDATE | 25 | +------------------------------------+-------+ -| ZEBRA_IMPORT_ROUTE_UNREGISTER | 26 | +| ZEBRA_IMPORT_ROUTE_REGISTER | 26 | +------------------------------------+-------+ -| ZEBRA_IMPORT_CHECK_UPDATE | 27 | +| ZEBRA_IMPORT_ROUTE_UNREGISTER | 27 | +------------------------------------+-------+ -| ZEBRA_BFD_DEST_REGISTER | 28 | +| ZEBRA_IMPORT_CHECK_UPDATE | 28 | +------------------------------------+-------+ -| ZEBRA_BFD_DEST_DEREGISTER | 29 | +| ZEBRA_BFD_DEST_REGISTER | 29 | +------------------------------------+-------+ -| ZEBRA_BFD_DEST_UPDATE | 30 | +| ZEBRA_BFD_DEST_DEREGISTER | 30 | +------------------------------------+-------+ -| ZEBRA_BFD_DEST_REPLAY | 31 | +| ZEBRA_BFD_DEST_UPDATE | 31 | +------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_ROUTE_ADD | 32 | +| ZEBRA_BFD_DEST_REPLAY | 32 | +------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_ROUTE_DEL | 33 | +| ZEBRA_REDISTRIBUTE_ROUTE_ADD | 33 | +------------------------------------+-------+ -| ZEBRA_VRF_UNREGISTER | 34 | +| ZEBRA_REDISTRIBUTE_ROUTE_DEL | 34 | +------------------------------------+-------+ -| ZEBRA_VRF_ADD | 35 | +| ZEBRA_VRF_UNREGISTER | 35 | +------------------------------------+-------+ -| ZEBRA_VRF_DELETE | 36 | +| ZEBRA_VRF_ADD | 36 | +------------------------------------+-------+ -| ZEBRA_VRF_LABEL | 37 | +| ZEBRA_VRF_DELETE | 37 | +------------------------------------+-------+ -| ZEBRA_INTERFACE_VRF_UPDATE | 38 | +| ZEBRA_VRF_LABEL | 38 | +------------------------------------+-------+ -| ZEBRA_BFD_CLIENT_REGISTER | 39 | +| ZEBRA_INTERFACE_VRF_UPDATE | 39 | +------------------------------------+-------+ -| ZEBRA_BFD_CLIENT_DEREGISTER | 40 | +| ZEBRA_BFD_CLIENT_REGISTER | 40 | +------------------------------------+-------+ -| ZEBRA_INTERFACE_ENABLE_RADV | 41 | +| ZEBRA_BFD_CLIENT_DEREGISTER | 41 | +------------------------------------+-------+ -| ZEBRA_INTERFACE_DISABLE_RADV | 42 | +| ZEBRA_INTERFACE_ENABLE_RADV | 42 | +------------------------------------+-------+ -| ZEBRA_IPV3_NEXTHOP_LOOKUP_MRIB | 43 | +| ZEBRA_INTERFACE_DISABLE_RADV | 43 | +------------------------------------+-------+ -| ZEBRA_INTERFACE_LINK_PARAMS | 44 | +| ZEBRA_IPV3_NEXTHOP_LOOKUP_MRIB | 44 | +------------------------------------+-------+ -| ZEBRA_MPLS_LABELS_ADD | 45 | +| ZEBRA_INTERFACE_LINK_PARAMS | 45 | +------------------------------------+-------+ -| ZEBRA_MPLS_LABELS_DELETE | 46 | +| ZEBRA_MPLS_LABELS_ADD | 46 | +------------------------------------+-------+ -| ZEBRA_IPMR_ROUTE_STATS | 47 | +| ZEBRA_MPLS_LABELS_DELETE | 47 | +------------------------------------+-------+ -| ZEBRA_LABEL_MANAGER_CONNECT | 48 | +| ZEBRA_MPLS_LABELS_REPLACE | 48 | +------------------------------------+-------+ -| ZEBRA_LABEL_MANAGER_CONNECT_ASYNC | 49 | +| ZEBRA_IPMR_ROUTE_STATS | 49 | +------------------------------------+-------+ -| ZEBRA_GET_LABEL_CHUNK | 50 | +| ZEBRA_LABEL_MANAGER_CONNECT | 50 | +------------------------------------+-------+ -| ZEBRA_RELEASE_LABEL_CHUNK | 51 | +| ZEBRA_LABEL_MANAGER_CONNECT_ASYNC | 51 | +------------------------------------+-------+ -| ZEBRA_FEC_REGISTER | 52 | +| ZEBRA_GET_LABEL_CHUNK | 52 | +------------------------------------+-------+ -| ZEBRA_FEC_UNREGISTER | 53 | +| ZEBRA_RELEASE_LABEL_CHUNK | 53 | +------------------------------------+-------+ -| ZEBRA_FEC_UPDATE | 54 | +| ZEBRA_FEC_REGISTER | 54 | +------------------------------------+-------+ -| ZEBRA_ADVERTISE_DEFAULT_GW | 55 | +| ZEBRA_FEC_UNREGISTER | 55 | +------------------------------------+-------+ -| ZEBRA_ADVERTISE_SUBNET | 56 | +| ZEBRA_FEC_UPDATE | 56 | +------------------------------------+-------+ -| ZEBRA_ADVERTISE_ALL_VNI | 57 | +| ZEBRA_ADVERTISE_DEFAULT_GW | 57 | +------------------------------------+-------+ -| ZEBRA_LOCAL_ES_ADD | 58 | +| ZEBRA_ADVERTISE_SVI_MACIP | 58 | +------------------------------------+-------+ -| ZEBRA_LOCAL_ES_DEL | 59 | +| ZEBRA_ADVERTISE_SUBNET | 59 | +------------------------------------+-------+ -| ZEBRA_VNI_ADD | 60 | +| ZEBRA_ADVERTISE_ALL_VNI | 60 | +------------------------------------+-------+ -| ZEBRA_VNI_DEL | 61 | +| ZEBRA_LOCAL_ES_ADD | 61 | +------------------------------------+-------+ -| ZEBRA_L3VNI_ADD | 62 | +| ZEBRA_LOCAL_ES_DEL | 62 | +------------------------------------+-------+ -| ZEBRA_L3VNI_DEL | 63 | +| ZEBRA_VNI_ADD | 63 | +------------------------------------+-------+ -| ZEBRA_REMOTE_VTEP_ADD | 64 | +| ZEBRA_VNI_DEL | 64 | +------------------------------------+-------+ -| ZEBRA_REMOTE_VTEP_DEL | 65 | +| ZEBRA_L3VNI_ADD | 65 | +------------------------------------+-------+ -| ZEBRA_MACIP_ADD | 66 | +| ZEBRA_L3VNI_DEL | 66 | +------------------------------------+-------+ -| ZEBRA_MACIP_DEL | 67 | +| ZEBRA_REMOTE_VTEP_ADD | 67 | +------------------------------------+-------+ -| ZEBRA_IP_PREFIX_ROUTE_ADD | 68 | +| ZEBRA_REMOTE_VTEP_DEL | 68 | +------------------------------------+-------+ -| ZEBRA_IP_PREFIX_ROUTE_DEL | 69 | +| ZEBRA_MACIP_ADD | 69 | +------------------------------------+-------+ -| ZEBRA_REMOTE_MACIP_ADD | 70 | +| ZEBRA_MACIP_DEL | 70 | +------------------------------------+-------+ -| ZEBRA_REMOTE_MACIP_DEL | 71 | +| ZEBRA_IP_PREFIX_ROUTE_ADD | 71 | +------------------------------------+-------+ -| ZEBRA_PW_ADD | 72 | +| ZEBRA_IP_PREFIX_ROUTE_DEL | 72 | +------------------------------------+-------+ -| ZEBRA_PW_DELETE | 73 | +| ZEBRA_REMOTE_MACIP_ADD | 73 | +------------------------------------+-------+ -| ZEBRA_PW_SET | 74 | +| ZEBRA_REMOTE_MACIP_DEL | 74 | +------------------------------------+-------+ -| ZEBRA_PW_UNSET | 75 | +| ZEBRA_DUPLICATE_ADDR_DETECTION | 75 | +------------------------------------+-------+ -| ZEBRA_PW_STATUS_UPDATE | 76 | +| ZEBRA_PW_ADD | 76 | +------------------------------------+-------+ -| ZEBRA_RULE_ADD | 77 | +| ZEBRA_PW_DELETE | 77 | +------------------------------------+-------+ -| ZEBRA_RULE_DELETE | 78 | +| ZEBRA_PW_SET | 78 | +------------------------------------+-------+ -| ZEBRA_RULE_NOTIFY_OWNER | 79 | +| ZEBRA_PW_UNSET | 79 | +------------------------------------+-------+ -| ZEBRA_TABLE_MANAGER_CONNECT | 80 | +| ZEBRA_PW_STATUS_UPDATE | 80 | +------------------------------------+-------+ -| ZEBRA_GET_TABLE_CHUNK | 81 | +| ZEBRA_RULE_ADD | 81 | +------------------------------------+-------+ -| ZEBRA_RELEASE_TABLE_CHUNK | 82 | +| ZEBRA_RULE_DELETE | 82 | +------------------------------------+-------+ -| ZEBRA_IPSET_CREATE | 83 | +| ZEBRA_RULE_NOTIFY_OWNER | 83 | +------------------------------------+-------+ -| ZEBRA_IPSET_DESTROY | 84 | +| ZEBRA_TABLE_MANAGER_CONNECT | 84 | +------------------------------------+-------+ -| ZEBRA_IPSET_ENTRY_ADD | 85 | +| ZEBRA_GET_TABLE_CHUNK | 85 | +------------------------------------+-------+ -| ZEBRA_IPSET_ENTRY_DELETE | 86 | +| ZEBRA_RELEASE_TABLE_CHUNK | 86 | +------------------------------------+-------+ -| ZEBRA_IPSET_NOTIFY_OWNER | 87 | +| ZEBRA_IPSET_CREATE | 87 | +------------------------------------+-------+ -| ZEBRA_IPSET_ENTRY_NOTIFY_OWNER | 88 | +| ZEBRA_IPSET_DESTROY | 88 | +------------------------------------+-------+ -| ZEBRA_IPTABLE_ADD | 89 | +| ZEBRA_IPSET_ENTRY_ADD | 89 | +------------------------------------+-------+ -| ZEBRA_IPTABLE_DELETE | 90 | +| ZEBRA_IPSET_ENTRY_DELETE | 90 | +------------------------------------+-------+ -| ZEBRA_IPTABLE_NOTIFY_OWNER | 91 | +| ZEBRA_IPSET_NOTIFY_OWNER | 91 | +------------------------------------+-------+ -| ZEBRA_VXLAN_FLOOD_CONTROL | 92 | +| ZEBRA_IPSET_ENTRY_NOTIFY_OWNER | 92 | ++------------------------------------+-------+ +| ZEBRA_IPTABLE_ADD | 93 | ++------------------------------------+-------+ +| ZEBRA_IPTABLE_DELETE | 94 | ++------------------------------------+-------+ +| ZEBRA_IPTABLE_NOTIFY_OWNER | 95 | ++------------------------------------+-------+ +| ZEBRA_VXLAN_FLOOD_CONTROL | 96 | ++------------------------------------+-------+ +| ZEBRA_VXLAN_SG_ADD | 97 | ++------------------------------------+-------+ +| ZEBRA_VXLAN_SG_DEL | 98 | ++------------------------------------+-------+ +| ZEBRA_VXLAN_SG_REPLAY | 99 | ++------------------------------------+-------+ +| ZEBRA_MLAG_PROCESS_UP | 100 | ++------------------------------------+-------+ +| ZEBRA_MLAG_PROCESS_DOWN | 101 | ++------------------------------------+-------+ +| ZEBRA_MLAG_CLIENT_REGISTER | 102 | ++------------------------------------+-------+ +| ZEBRA_MLAG_CLIENT_UNREGISTER | 103 | ++------------------------------------+-------+ +| ZEBRA_MLAG_FORWARD_MSG | 104 | ++------------------------------------+-------+ +| ZEBRA_CLIENT_CAPABILITIES | 105 | +------------------------------------+-------+ diff --git a/lib/log.c b/lib/log.c index 798b776d00..d7034ce930 100644 --- a/lib/log.c +++ b/lib/log.c @@ -1094,7 +1094,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_VXLAN_SG_DEL), DESC_ENTRY(ZEBRA_VXLAN_SG_REPLAY), DESC_ENTRY(ZEBRA_ERROR), -}; + DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES)}; #undef DESC_ENTRY static const struct zebra_desc_table unknown = {0, "unknown", '?'}; diff --git a/lib/zclient.c b/lib/zclient.c index 7ddf0085de..d879063460 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -3300,31 +3300,71 @@ void zclient_interface_set_master(struct zclient *client, zclient_send_message(client); } -/* Process capabilities message from zebra */ -int zapi_capabilities_decode(struct stream *s, struct zapi_cap *api) +/* + * Send capabilities message to zebra + */ +int32_t zclient_capabilities_send(uint32_t cmd, struct zclient *zclient, + struct zapi_cap *api) { + + struct stream *s; + + if (zclient == NULL) + return -1; + + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, cmd, 0); + stream_putl(s, api->cap); + + switch (api->cap) { + case ZEBRA_CLIENT_GR_CAPABILITIES: + case ZEBRA_CLIENT_RIB_STALE_TIME: + stream_putl(s, api->stale_removal_time); + stream_putl(s, api->vrf_id); + break; + case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: + case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: + stream_putl(s, api->afi); + stream_putl(s, api->safi); + stream_putl(s, api->vrf_id); + break; + case ZEBRA_CLIENT_GR_DISABLE: + stream_putl(s, api->vrf_id); + break; + } + + /* Put length at the first point of the stream */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + +/* + * Process capabilities message from zebra + */ +int32_t zapi_capabilities_decode(struct stream *s, struct zapi_cap *api) +{ + memset(api, 0, sizeof(*api)); STREAM_GETL(s, api->cap); switch (api->cap) { case ZEBRA_CLIENT_GR_CAPABILITIES: case ZEBRA_CLIENT_RIB_STALE_TIME: - STREAM_GETL(s, api->stale_removal_time); - STREAM_GETL(s, api->vrf_id); - break; + STREAM_GETL(s, api->stale_removal_time); + STREAM_GETL(s, api->vrf_id); + break; case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: - STREAM_GETL(s, api->afi); - STREAM_GETL(s, api->safi); - STREAM_GETL(s, api->vrf_id); - break; + STREAM_GETL(s, api->afi); + STREAM_GETL(s, api->safi); + STREAM_GETL(s, api->vrf_id); + break; case ZEBRA_CLIENT_GR_DISABLE: - STREAM_GETL(s, api->vrf_id); - break; - default: - break; + STREAM_GETL(s, api->vrf_id); + break; } - stream_failure: return 0; } diff --git a/lib/zclient.h b/lib/zclient.h index bbc70c3835..9a230d3f34 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -73,13 +73,17 @@ typedef uint16_t zebra_size_t; #define ZEBRA_FEC_REGISTER_LABEL 0x1 #define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x2 -/* Client Graceful Restart */ -#define ZEBRA_CLIENT_GR_CAPABILITIES 0x1 -#define ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE 0x2 -#define ZEBRA_CLIENT_ROUTE_UPDATE_PENDING 0x3 -#define ZEBRA_CLIENT_GR_DISABLE 0x4 -#define ZEBRA_CLIENT_RIB_STALE_TIME 0x5 -#define ZEBRA_CLIENT_GR_ENABLED(X) (X & ZEBRA_CLIENT_GR_CAPABILITIES) +/* Client capabilities */ +enum zserv_client_capabilities { + ZEBRA_CLIENT_GR_CAPABILITIES = 1, + ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE = 2, + ZEBRA_CLIENT_ROUTE_UPDATE_PENDING = 3, + ZEBRA_CLIENT_GR_DISABLE = 4, + ZEBRA_CLIENT_RIB_STALE_TIME +}; + +/* Macro to check if there GR enabled. */ +#define ZEBRA_CLIENT_GR_ENABLED(X) (X == ZEBRA_CLIENT_GR_CAPABILITIES) extern struct sockaddr_storage zclient_addr; extern socklen_t zclient_addr_len; @@ -196,7 +200,7 @@ typedef enum { } zebra_message_types_t; enum zebra_error_types { - ZEBRA_UNKNOWN_ERROR, /* Error of unknown type */ + ZEBRA_UNKNOWN_ERROR, /* Error of unknown type */ ZEBRA_NO_VRF, /* Vrf in header was not found */ ZEBRA_INVALID_MSG_TYPE, /* No handler found for msg type */ }; @@ -233,11 +237,11 @@ struct zclient_capabilities { /* Graceful Restart Capabilities message */ struct zapi_cap { - uint32_t cap; - uint32_t stale_removal_time; - afi_t afi; - safi_t safi; - vrf_id_t vrf_id; + enum zserv_client_capabilities cap; + uint32_t stale_removal_time; + afi_t afi; + safi_t safi; + vrf_id_t vrf_id; }; /* Structure for the zebra client. */ @@ -777,6 +781,11 @@ extern bool zapi_nexthop_update_decode(struct stream *s, /* Decode the zebra error message */ extern bool zapi_error_decode(struct stream *s, enum zebra_error_types *error); +/* Encode and decode restart capabilities */ +extern int32_t zclient_capabilities_send(uint32_t cmd, struct zclient *zclient, + struct zapi_cap *api); +extern int32_t zapi_capabilities_decode(struct stream *s, struct zapi_cap *api); + static inline void zapi_route_set_blackhole(struct zapi_route *api, enum blackhole_type bh_type) { @@ -794,7 +803,4 @@ extern void zclient_send_mlag_deregister(struct zclient *client); extern void zclient_send_mlag_data(struct zclient *client, struct stream *client_s); -extern int zclient_capabilities_send(uint32_t cmd, struct zclient *zclient, - struct zapi_cap *api); -extern int zapi_capabilities_decode(struct stream *s, struct zapi_cap *api); #endif /* _ZEBRA_ZCLIENT_H */ diff --git a/zebra/main.c b/zebra/main.c index 75f825e507..f23702d878 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -151,6 +151,10 @@ static void sigint(void) zebra_dplane_pre_finish(); + /* Clean up GR related info. */ + zebra_gr_stale_client_cleanup(zrouter.stale_client_list); + list_delete_all_node(zrouter.stale_client_list); + for (ALL_LIST_ELEMENTS(zrouter.client_list, ln, nn, client)) zserv_close_client(client); diff --git a/zebra/subdir.am b/zebra/subdir.am index 77ed5a6caa..1d49de5410 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -17,6 +17,7 @@ vtysh_scan += \ $(top_srcdir)/zebra/zebra_routemap.c \ $(top_srcdir)/zebra/zebra_vty.c \ $(top_srcdir)/zebra/zserv.c \ + $(top_srcdir)/zebra/zebra_gr.c \ # end # can be loaded as DSO - always include for vtysh @@ -101,6 +102,7 @@ zebra_zebra_SOURCES = \ zebra/table_manager.c \ zebra/zapi_msg.c \ zebra/zebra_errors.c \ + zebra/zebra_gr.c \ # end zebra/debug_clippy.c: $(CLIPPY_DEPS) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 4fa7a3c164..83b8b8cb66 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1775,6 +1775,8 @@ static void zread_hello(ZAPI_HANDLER_ARGS) client->instance = instance; } + /* Graceful restart processing for client connect */ + zebra_gr_client_reconnect(client); zsend_capabilities(client, zvrf); zebra_vrf_update_all(client); stream_failure: @@ -2668,6 +2670,7 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_MLAG_CLIENT_REGISTER] = zebra_mlag_client_register, [ZEBRA_MLAG_CLIENT_UNREGISTER] = zebra_mlag_client_unregister, [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg, + [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities }; #if defined(HANDLE_ZAPI_FUZZING) diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c new file mode 100644 index 0000000000..e8c7304f44 --- /dev/null +++ b/zebra/zebra_gr.c @@ -0,0 +1,684 @@ +/* + * Zebra GR related helper functions. + * + * Portions: + * Copyright (C) 2019 VMware, Inc. + * et al. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "lib/prefix.h" +#include "lib/command.h" +#include "lib/if.h" +#include "lib/thread.h" +#include "lib/stream.h" +#include "lib/memory.h" +#include "lib/table.h" +#include "lib/network.h" +#include "lib/sockunion.h" +#include "lib/log.h" +#include "lib/zclient.h" +#include "lib/privs.h" +#include "lib/network.h" +#include "lib/buffer.h" +#include "lib/nexthop.h" +#include "lib/vrf.h" +#include "lib/libfrr.h" +#include "lib/sockopt.h" + +#include "zebra/zebra_router.h" +#include "zebra/debug.h" +#include "zebra/zapi_msg.h" + + +/* + * Forward declaration. + */ +static struct zserv *zebra_gr_find_stale_client(struct zserv *client); +static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread); +static int32_t zebra_gr_delete_stale_routes(struct client_gr_info *info); +static void zebra_gr_process_client_stale_routes(struct zserv *client, + vrf_id_t vrf_id); + +/* + * Debug macros. + */ +#define LOG_GR(msg, ...) \ + do { \ + if (IS_ZEBRA_DEBUG_EVENT) \ + zlog_debug(msg, ##__VA_ARGS__); \ + } while (0) + + +/* + * Client connection functions + */ + +/* + * Function to clean all the stale clients, + * function will also clean up all per instance + * capabilities that are exchanged. + */ +void zebra_gr_stale_client_cleanup(struct list *client_list) +{ + struct listnode *node, *nnode; + struct zserv *s_client = NULL; + struct client_gr_info *info, *ninfo; + + /* Find the stale client */ + for (ALL_LIST_ELEMENTS(client_list, node, nnode, s_client)) { + + LOG_GR("%s: Stale client %s is being deleted", __func__, + zebra_route_string(s_client->proto)); + + TAILQ_FOREACH_SAFE (info, &s_client->gr_info_queue, gr_info, + ninfo) { + + /* Cancel the stale timer */ + if (info->t_stale_removal != NULL) { + THREAD_OFF(info->t_stale_removal); + info->t_stale_removal = NULL; + /* Process the stale routes */ + thread_execute( + zrouter.master, + zebra_gr_route_stale_delete_timer_expiry, + info, 1); + } + } + } +} + +/* + * A helper function to create client info. + */ +static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client) +{ + struct client_gr_info *info; + + info = XCALLOC(MTYPE_TMP, sizeof(struct client_gr_info)); + + TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info); + return info; +} + +/* + * A helper function to delte and destory client info. + */ +static void zebra_gr_client_info_delte(struct zserv *client, + struct client_gr_info *info) +{ + TAILQ_REMOVE(&(client->gr_info_queue), info, gr_info); + + THREAD_OFF(info->t_stale_removal); + + if (info->current_prefix) + XFREE(MTYPE_TMP, info->current_prefix); + + LOG_GR("%s: Instance info is being deleted for client %s", __func__, + zebra_route_string(client->proto)); + + /* Delete all the stale routes. */ + info->delete = true; + zebra_gr_delete_stale_routes(info); + + XFREE(MTYPE_TMP, info); +} + +/* + * Function to handle client when it disconnect. + */ +int32_t zebra_gr_client_disconnect(struct zserv *client) +{ + struct zserv *stale_client; + struct timeval tv; + struct client_gr_info *info = NULL; + + /* Find the stale client */ + stale_client = zebra_gr_find_stale_client(client); + + /* + * We should never be here. + */ + if (stale_client) { + LOG_GR("%s: Stale client %s exist, we should not be here!", + __func__, zebra_route_string(client->proto)); + assert(0); + } + + client->restart_time = monotime(&tv); + + /* For all the GR instance start the starle removal timer. */ + TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + if (ZEBRA_CLIENT_GR_ENABLED(info->capabilities) + && (info->t_stale_removal == NULL)) { + thread_add_timer( + zrouter.master, + zebra_gr_route_stale_delete_timer_expiry, info, + info->stale_removal_time, + &info->t_stale_removal); + info->current_afi = AFI_IP; + info->stale_client_ptr = client; + info->stale_client = true; + LOG_GR("%s: Client %s Stale timer update to %d", + __func__, zebra_route_string(client->proto), + info->stale_removal_time); + } + } + + listnode_add(zrouter.stale_client_list, client); + + return 0; +} + +/* + * Function to delete stale client + */ +static void zebra_gr_delete_stale_client(struct client_gr_info *info) +{ + struct client_gr_info *bgp_info; + struct zserv *s_client = NULL; + + s_client = info->stale_client_ptr; + + if (!s_client || !info->stale_client) + return; + + /* + * If there are bgp instances with the stale delete timer pending + * then stale client is not deleted + */ + if ((s_client->gr_instance_count > 0) && info->gr_enable) + s_client->gr_instance_count--; + + TAILQ_REMOVE(&(s_client->gr_info_queue), info, gr_info); + + LOG_GR("%s: Client %s gr count %d", __func__, + zebra_route_string(s_client->proto), + s_client->gr_instance_count); + + TAILQ_FOREACH (bgp_info, &s_client->gr_info_queue, gr_info) { + if (bgp_info->t_stale_removal != NULL) + return; + } + + LOG_GR("%s: Client %s is being deleted", __func__, + zebra_route_string(s_client->proto)); + + TAILQ_INIT(&(s_client->gr_info_queue)); + listnode_delete(zrouter.stale_client_list, s_client); + if (info->stale_client) + XFREE(MTYPE_TMP, s_client); + XFREE(MTYPE_TMP, info); +} + +/* + * Function to find stale client. + */ +static struct zserv *zebra_gr_find_stale_client(struct zserv *client) +{ + struct listnode *node, *nnode; + struct zserv *stale_client; + + /* Find the stale client */ + for (ALL_LIST_ELEMENTS(zrouter.stale_client_list, node, nnode, + stale_client)) { + if (client->proto == stale_client->proto + && client->instance == stale_client->instance) { + return stale_client; + } + } + + return NULL; +} + +/* + * Function to handle reconnect of client post restart. + */ +void zebra_gr_client_reconnect(struct zserv *client) +{ + struct listnode *node, *nnode; + struct zserv *old_client = NULL; + struct client_gr_info *info = NULL; + + /* Find the stale client */ + for (ALL_LIST_ELEMENTS(zrouter.stale_client_list, node, nnode, + old_client)) { + if (client->proto == old_client->proto + && client->instance == old_client->instance) + break; + } + + /* Copy the timers */ + if (old_client) { + client->gr_instance_count = old_client->gr_instance_count; + client->restart_time = old_client->restart_time; + + LOG_GR("%s : old client %s, gr_instance_count %d", __func__, + zebra_route_string(old_client->proto), + old_client->gr_instance_count); + + if (TAILQ_FIRST(&old_client->gr_info_queue)) { + TAILQ_CONCAT(&client->gr_info_queue, + &old_client->gr_info_queue, gr_info); + TAILQ_INIT(&old_client->gr_info_queue); + } + + TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + info->stale_client_ptr = client; + info->stale_client = false; + } + + /* Delete the stale client */ + listnode_delete(zrouter.stale_client_list, old_client); + /* Delete old client */ + XFREE(MTYPE_TMP, old_client); + } +} + +/* + * Functions to deal with capabilities + */ + +/* + * Update the graceful restart information + * for the client instance. + * This function handles all the capabilties that are received. + */ +static void zebra_client_update_info(struct zserv *client, struct zapi_cap *api) +{ + struct client_gr_info *info = NULL; + + /* Find the bgp information for the specified vrf id */ + TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + if (info->vrf_id == api->vrf_id) + break; + } + + + /* + * If the command is delete, then cancel the stale timer and + * delete the bgp info + */ + switch (api->cap) { + case ZEBRA_CLIENT_GR_DISABLE: + if (!info) + return; + + LOG_GR("%s: Client %s instance GR disabled count %d", __func__, + zebra_route_string(client->proto), + client->gr_instance_count); + + if ((info->gr_enable) && (client->gr_instance_count > 0)) + client->gr_instance_count--; + + zebra_gr_client_info_delte(client, info); + break; + case ZEBRA_CLIENT_GR_CAPABILITIES: + /* Allocate bgp info */ + if (!info) + info = zebra_gr_client_info_create(client); + + /* Udpate other parameters */ + if (!info->gr_enable) { + client->gr_instance_count++; + + LOG_GR("%s: Cient %s GR enabled count %d", __func__, + zebra_route_string(client->proto), + client->gr_instance_count); + + info->capabilities = api->cap; + info->stale_removal_time = api->stale_removal_time; + info->vrf_id = api->vrf_id; + info->gr_enable = true; + } + break; + case ZEBRA_CLIENT_RIB_STALE_TIME: + LOG_GR("%s: Client %s stale time update event", __func__, + zebra_route_string(client->proto)); + + /* Update the stale removal timer */ + if (info && info->t_stale_removal == NULL) { + + LOG_GR("%s: Stale time: %d is now update to: %d", + __func__, info->stale_removal_time, + api->stale_removal_time); + + info->stale_removal_time = api->stale_removal_time; + } + + break; + case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: + LOG_GR( + "%s: Client %s route update complete for AFI %d, SAFI %d", + __func__, zebra_route_string(client->proto), api->afi, + api->safi); + if (info) + info->route_sync[api->afi][api->safi] = true; + break; + case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: + LOG_GR("%s: Client %s route update pending for AFI %d, SAFI %d", + __func__, zebra_route_string(client->proto), api->afi, + api->safi); + if (info) + info->af_enabled[api->afi][api->safi] = true; + break; + } +} + +/* + * Handler for capabilities that are received from client. + */ +static void zebra_client_capabilities_handler(struct zserv *client, + struct zapi_cap *api) +{ + switch (api->cap) { + case ZEBRA_CLIENT_GR_CAPABILITIES: + case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: + case ZEBRA_CLIENT_GR_DISABLE: + case ZEBRA_CLIENT_RIB_STALE_TIME: + /* + * For all the cases we need to update the client info. + */ + zebra_client_update_info(client, api); + break; + case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: + /* + * After client info has been updated delete all + * stale routes + */ + zebra_client_update_info(client, api); + zebra_gr_process_client_stale_routes(client, api->vrf_id); + break; + } +} + +/* + * Function to decode and call appropriate functions + * to handle client capabilities. + */ +void zread_client_capabilities(ZAPI_HANDLER_ARGS) +{ + struct zapi_cap api; + struct stream *s; + + s = msg; + + if (zapi_capabilities_decode(s, &api)) { + LOG_GR("%s: Error in reading capabilities for client %s", + __func__, zebra_route_string(client->proto)); + return; + } + + /* Call the capabilities handler */ + zebra_client_capabilities_handler(client, &api); +} + + +/* + * Stale route handling + */ + +/* + * Delete all the stale routes that have not been refreshed + * post restart. + */ +static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread) +{ + struct client_gr_info *info; + int32_t cnt = 0; + struct zserv *client; + + info = THREAD_ARG(thread); + info->t_stale_removal = NULL; + client = (struct zserv *)info->stale_client_ptr; + + /* Set the flag to indicate all stale route deletion */ + if (thread->u.val == 1) + info->delete = true; + + cnt = zebra_gr_delete_stale_routes(info); + + /* Retsart the timer */ + if (cnt > 0) { + LOG_GR("%s: Client %s processed %d routes. Start timer again", + __func__, zebra_route_string(client->proto), cnt); + + thread_add_timer(zrouter.master, + zebra_gr_route_stale_delete_timer_expiry, info, + ZEBRA_DEFAULT_STALE_UPDATE_DELAY, + &info->t_stale_removal); + } else { + /* No routes to delete for the VRF */ + LOG_GR("%s: Client %s all starle routes processed", __func__, + zebra_route_string(client->proto)); + + if (info->current_prefix != NULL) + XFREE(MTYPE_TMP, info->current_prefix); + info->current_prefix = NULL; + info->current_afi = 0; + zebra_gr_delete_stale_client(info); + } + return 0; +} + + +/* + * Function to process to check if route entry is stale + * or has been updated. + */ +static void zebra_gr_process_route_entry(struct zserv *client, + struct route_node *rn, + struct route_entry *re) +{ + char buf[PREFIX2STR_BUFFER]; + + if ((client == NULL) || (rn == NULL) || (re == NULL)) + return; + + /* If the route is not refreshed after restart, delete the entry */ + if (re->uptime < client->restart_time) { + if (IS_ZEBRA_DEBUG_RIB) { + prefix2str(&rn->p, buf, sizeof(buf)); + zlog_debug("%s: Client %s stale route %s is deleted", + __func__, zebra_route_string(client->proto), + buf); + } + rib_delnode(rn, re); + } +} + +/* + * This function walks through the route table for all vrf and deletes + * the stale routes for the restarted client specified by the protocol + * type + */ +static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, + struct zebra_vrf *zvrf) +{ + struct route_node *rn, *curr; + struct route_entry *re; + struct route_entry *next; + struct route_table *table; + int32_t n = 0; + struct prefix *p; + afi_t afi, curr_afi; + uint8_t proto; + uint16_t instance; + struct zserv *s_client; + + if ((info == NULL) || (zvrf == NULL)) + return -1; + + s_client = info->stale_client_ptr; + if (s_client == NULL) { + LOG_GR("%s: Stale client not present", __func__); + return -1; + } + + proto = s_client->proto; + instance = s_client->instance; + curr_afi = info->current_afi; + + LOG_GR("%s: Client %s stale routes are being deleted", __func__, + zebra_route_string(proto)); + + /* Process routes for all AFI */ + for (afi = curr_afi; afi < AFI_MAX; afi++) { + table = zvrf->table[afi][SAFI_UNICAST]; + p = info->current_prefix; + + if (table) { + /* + * If the current prefix is NULL then get the first + * route entry in the table + */ + if (p == NULL) { + rn = route_top(table); + if (rn == NULL) + continue; + p = XCALLOC(MTYPE_TMP, sizeof(struct prefix)); + if (p == NULL) + return -1; + curr = rn; + prefix_copy(p, &rn->p); + } else + /* Get the next route entry */ + curr = route_table_get_next(table, p); + + for (rn = curr; rn; rn = srcdest_route_next(rn)) { + RNODE_FOREACH_RE_SAFE (rn, re, next) { + if (CHECK_FLAG(re->status, + ROUTE_ENTRY_REMOVED)) + continue; + /* If the route refresh is received + * after restart then do not delete + * the route + */ + if (re->type == proto + && re->instance == instance) { + zebra_gr_process_route_entry( + s_client, rn, re); + n++; + } + + /* If the max route count is reached + * then timer thread will be restarted + * Store the current prefix and afi + */ + if ((n >= ZEBRA_MAX_STALE_ROUTE_COUNT) + && (info->delete == false)) { + prefix_copy(p, &rn->p); + info->current_afi = afi; + info->current_prefix = p; + return n; + } + } + } + } + /* + * Reset the current prefix to indicate processing completion + * of the current AFI + */ + if (info->current_prefix) { + XFREE(MTYPE_TMP, info->current_prefix); + info->current_prefix = NULL; + } + continue; + } + return 0; +} + +/* + * Delete the stale routes when client is restarted and routes are not + * refreshed within the stale timeout + */ +static int32_t zebra_gr_delete_stale_routes(struct client_gr_info *info) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + uint64_t cnt = 0; + + if (info == NULL) + return -1; + + /* Get the current VRF */ + vrf = vrf_lookup_by_id(info->vrf_id); + if (vrf == NULL) { + LOG_GR("%s: Invalid VRF %d", __func__, info->vrf_id); + return -1; + } + + zvrf = vrf->info; + if (zvrf == NULL) { + LOG_GR("%s: Invalid VRF entry %d", __func__, info->vrf_id); + return -1; + } + + cnt = zebra_gr_delete_stale_route(info, zvrf); + return cnt; +} + +/* + * This function checks if route update for all AFI, SAFI is completed + * and cancels the stale timer + */ +static void zebra_gr_process_client_stale_routes(struct zserv *client, + vrf_id_t vrf_id) +{ + struct client_gr_info *info = NULL; + afi_t afi; + safi_t safi; + + TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + if (info->vrf_id == vrf_id) + break; + } + + if (info == NULL) + return; + + /* Check if route update completed for all AFI, SAFI */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) { + if (info->af_enabled[afi][safi]) { + if (!info->route_sync[afi][safi]) { + LOG_GR( + "%s: Client %s route update not completed for AFI %d, SAFI %d", + __func__, zebra_route_string( + client->proto), + afi, safi); + return; + } + } + } + + /* + * Route update completed for all AFI, SAFI + * Cancel the stale timer and process the routes + */ + if (info->t_stale_removal) { + LOG_GR("%s: Client %s cancled stale delete timer vrf %d", + __func__, zebra_route_string(client->proto), + info->vrf_id); + THREAD_OFF(info->t_stale_removal); + thread_execute(zrouter.master, + zebra_gr_route_stale_delete_timer_expiry, info, + 0); + } +} diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index d8ad8a6864..59bd0e55f0 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -117,6 +117,9 @@ struct zebra_router { /* Lists of clients who have connected to us */ struct list *client_list; + /* List of clients in GR */ + struct list *stale_client_list; + struct zebra_router_table_head tables; /* L3-VNI hash table (for EVPN). Only in default instance */ diff --git a/zebra/zserv.c b/zebra/zserv.c index cca926f3b0..2a5352a1da 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -557,6 +557,9 @@ DEFINE_KOOH(zserv_client_close, (struct zserv *client), (client)); */ static void zserv_client_free(struct zserv *client) { + if (client == NULL) + return; + hook_call(zserv_client_close, client); /* Close file descriptor. */ @@ -565,11 +568,14 @@ static void zserv_client_free(struct zserv *client) close(client->sock); - nroutes = rib_score_proto(client->proto, client->instance); - zlog_notice( - "client %d disconnected. %lu %s routes removed from the rib", - client->sock, nroutes, - zebra_route_string(client->proto)); + if (!client->gr_instance_count) { + nroutes = rib_score_proto(client->proto, + client->instance); + zlog_notice( + "client %d disconnected %lu %s routes removed from the rib", + client->sock, nroutes, + zebra_route_string(client->proto)); + } client->sock = -1; } @@ -600,7 +606,25 @@ static void zserv_client_free(struct zserv *client) } vrf_bitmap_free(client->ridinfo); - XFREE(MTYPE_TMP, client); + /* + * If any instance are graceful restart enabled, + * client is not deleted + */ + if (!client->gr_instance_count) { + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("%s: Deleting client %s", __func__, + zebra_route_string(client->proto)); + XFREE(MTYPE_TMP, client); + } else { + /* Handle cases where client has GR instance. */ + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("%s: client %s restart enabled", __func__, + zebra_route_string(client->proto)); + if (zebra_gr_client_disconnect(client) < 0) + zlog_err( + "%s: GR enabled but could not handle disconnect event", + __func__); + } } void zserv_close_client(struct zserv *client) @@ -670,6 +694,7 @@ static struct zserv *zserv_client_create(int sock) pthread_mutex_init(&client->ibuf_mtx, NULL); pthread_mutex_init(&client->obuf_mtx, NULL); client->wb = buffer_new(0); + TAILQ_INIT(&(client->gr_info_queue)); atomic_store_explicit(&client->connect_time, (uint32_t) monotime(NULL), memory_order_relaxed); @@ -861,12 +886,14 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen) return buf; } +/* Display client info details */ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) { char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF]; char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF]; time_t connect_time, last_read_time, last_write_time; uint32_t last_read_cmd, last_write_cmd; + struct client_gr_info *info = NULL; vty_out(vty, "Client: %s", zebra_route_string(client->proto)); if (client->instance) @@ -945,12 +972,100 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) vty_out(vty, "MAC-IP add notifications: %d\n", client->macipadd_cnt); vty_out(vty, "MAC-IP delete notifications: %d\n", client->macipdel_cnt); + TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id)); + vty_out(vty, "Capabilities : "); + switch (info->capabilities) { + case ZEBRA_CLIENT_GR_CAPABILITIES: + vty_out(vty, "Graceful Restart\n"); + break; + case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: + case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: + case ZEBRA_CLIENT_GR_DISABLE: + case ZEBRA_CLIENT_RIB_STALE_TIME: + vty_out(vty, "None\n"); + break; + } + } + #if defined DEV_BUILD vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n", client->ibuf_fifo->count, client->ibuf_fifo->max_count, client->obuf_fifo->count, client->obuf_fifo->max_count); #endif vty_out(vty, "\n"); +} + +/* Display stale client information */ +static void zebra_show_stale_client_detail(struct vty *vty, + struct zserv *client) +{ + char buf[PREFIX2STR_BUFFER]; + struct tm *tm; + struct timeval tv; + time_t uptime; + struct client_gr_info *info = NULL; + struct zserv *s = NULL; + + if (client->instance) + vty_out(vty, " Instance: %d", client->instance); + + TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id)); + vty_out(vty, "Capabilities : "); + switch (info->capabilities) { + case ZEBRA_CLIENT_GR_CAPABILITIES: + vty_out(vty, "Graceful Restart\n"); + break; + case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: + case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: + case ZEBRA_CLIENT_GR_DISABLE: + case ZEBRA_CLIENT_RIB_STALE_TIME: + vty_out(vty, "None\n"); + break; + } + + if (ZEBRA_CLIENT_GR_ENABLED(info->capabilities)) { + if (info->stale_client_ptr) { + s = (struct zserv *)(info->stale_client_ptr); + uptime = monotime(&tv); + uptime -= s->restart_time; + tm = gmtime(&uptime); + vty_out(vty, "Last restart time : "); + if (uptime < ONE_DAY_SECOND) + vty_out(vty, "%02d:%02d:%02d", + tm->tm_hour, tm->tm_min, + tm->tm_sec); + else if (uptime < ONE_WEEK_SECOND) + vty_out(vty, "%dd%02dh%02dm", + tm->tm_yday, tm->tm_hour, + tm->tm_min); + else + vty_out(vty, "%02dw%dd%02dh", + tm->tm_yday / 7, + tm->tm_yday - ((tm->tm_yday / 7) + * 7), + tm->tm_hour); + vty_out(vty, " ago\n"); + + vty_out(vty, "Stalepath removal time: %d sec\n", + info->stale_removal_time); + if (info->t_stale_removal) { + vty_out(vty, + "Stale delete timer: %ld sec\n", + thread_timer_remain_second( + info->t_stale_removal)); + } + } + vty_out(vty, "Current AFI : %d\n", info->current_afi); + if (info->current_prefix) { + prefix2str(info->current_prefix, buf, + sizeof(buf)); + vty_out(vty, "Current prefix : %s\n", buf); + } + } + } + vty_out(vty, "\n"); return; } @@ -1002,8 +1117,12 @@ DEFUN (show_zebra_client, struct listnode *node; struct zserv *client; - for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { zebra_show_client_detail(vty, client); + vty_out(vty, "Stale Client Information\n"); + vty_out(vty, "------------------------\n"); + zebra_show_stale_client_detail(vty, client); + } return CMD_SUCCESS; } @@ -1047,6 +1166,7 @@ void zserv_init(void) { /* Client list init. */ zrouter.client_list = list_new(); + zrouter.stale_client_list = list_new(); /* Misc init. */ zsock = -1; diff --git a/zebra/zserv.h b/zebra/zserv.h index d8d82a52ec..77ea19202f 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -52,6 +52,42 @@ extern "C" { #define ZEBRA_RMAP_DEFAULT_UPDATE_TIMER 5 /* disabled by default */ + +/* Stale route marker timer */ +#define ZEBRA_DEFAULT_STALE_UPDATE_DELAY 1 + +/* Count of stale routes processed in timer context */ +#define ZEBRA_MAX_STALE_ROUTE_COUNT 50000 + +/* Graceful Restart information */ +struct client_gr_info { + /* VRF for which GR enabled */ + vrf_id_t vrf_id; + + /* AFI */ + afi_t current_afi; + + /* Stale time and GR cap */ + uint32_t stale_removal_time; + enum zserv_client_capabilities capabilities; + + /* GR commands */ + bool delete; + bool gr_enable; + bool stale_client; + + /* Route sync and enable flags for AFI/SAFI */ + bool af_enabled[AFI_MAX][SAFI_MAX]; + bool route_sync[AFI_MAX][SAFI_MAX]; + + /* Book keeping */ + struct prefix *current_prefix; + void *stale_client_ptr; + struct thread *t_stale_removal; + + TAILQ_ENTRY(client_gr_info) gr_info; +}; + /* Client structure. */ struct zserv { /* Client pthread */ @@ -170,6 +206,19 @@ struct zserv { _Atomic uint32_t last_read_cmd; /* command code of last message written */ _Atomic uint32_t last_write_cmd; + + /* + * Number of instances configured with + * graceful restart + */ + uint32_t gr_instance_count; + time_t restart_time; + + /* + * Graceful restart information for + * each instance + */ + TAILQ_HEAD(info_list, client_gr_info) gr_info_queue; }; #define ZAPI_HANDLER_ARGS \ @@ -230,7 +279,6 @@ extern int zserv_send_message(struct zserv *client, struct stream *msg); */ extern struct zserv *zserv_find_client(uint8_t proto, unsigned short instance); - /* * Close a client. * @@ -242,7 +290,6 @@ extern struct zserv *zserv_find_client(uint8_t proto, unsigned short instance); */ extern void zserv_close_client(struct zserv *client); - /* * Log a ZAPI message hexdump. * @@ -265,6 +312,16 @@ extern void zserv_read_file(char *input); /* TODO */ int zebra_finalize(struct thread *event); +/* + * Graceful restart functions. + */ +extern int zebra_gr_client_disconnect(struct zserv *client); +extern void zebra_gr_client_reconnect(struct zserv *client); +extern void zebra_gr_stale_client_cleanup(struct list *client_list); +extern void zread_client_capabilities(struct zserv *client, struct zmsghdr *hdr, + struct stream *msg, + struct zebra_vrf *zvrf); + #ifdef __cplusplus } #endif