DESC_ENTRY(ZEBRA_NHG_ADD),
DESC_ENTRY(ZEBRA_NHG_DEL),
DESC_ENTRY(ZEBRA_NHG_NOTIFY_OWNER),
- DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_REQUEST)};
+ DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_REQUEST),
+ DESC_ENTRY(ZEBRA_CLIENT_CLOSE_NOTIFY)};
#undef DESC_ENTRY
static const struct zebra_desc_table unknown = {0, "unknown", '?'};
return -1;
}
+/* Utility to decode client close notify info */
+int zapi_client_close_notify_decode(struct stream *s,
+ struct zapi_client_close_info *info)
+{
+ memset(info, 0, sizeof(*info));
+
+ STREAM_GETC(s, info->proto);
+ STREAM_GETW(s, info->instance);
+ STREAM_GETL(s, info->session_id);
+
+ return 0;
+
+stream_failure:
+
+ return -1;
+}
+
/* Zebra client message read function. */
static int zclient_read(struct thread *thread)
{
if (zclient->sr_policy_notify_status)
(*zclient->sr_policy_notify_status)(command, zclient,
length, vrf_id);
+ break;
+ case ZEBRA_CLIENT_CLOSE_NOTIFY:
+ if (zclient->zebra_client_close_notify)
+ (*zclient->zebra_client_close_notify)(command, zclient,
+ length, vrf_id);
+ break;
default:
break;
}
ZEBRA_OPAQUE_UNREGISTER,
ZEBRA_NEIGH_DISCOVER,
ZEBRA_ROUTE_NOTIFY_REQUEST,
+ ZEBRA_CLIENT_CLOSE_NOTIFY,
} zebra_message_types_t;
enum zebra_error_types {
int (*opaque_register_handler)(ZAPI_CALLBACK_ARGS);
int (*opaque_unregister_handler)(ZAPI_CALLBACK_ARGS);
int (*sr_policy_notify_status)(ZAPI_CALLBACK_ARGS);
+ int (*zebra_client_close_notify)(ZAPI_CALLBACK_ARGS);
};
/* Zebra API message flag. */
const struct interface *ifp,
const struct prefix *p);
+struct zapi_client_close_info {
+ /* Client session tuple */
+ uint8_t proto;
+ uint16_t instance;
+ uint32_t session_id;
+};
+
+/* Decode incoming client close notify */
+extern int zapi_client_close_notify_decode(struct stream *s,
+ struct zapi_client_close_info *info);
+
#ifdef __cplusplus
}
#endif
return zserv_send_message(client, s);
}
+/* Send client close notify to client */
+int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client)
+{
+ struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+ zclient_create_header(s, ZEBRA_CLIENT_CLOSE_NOTIFY, VRF_DEFAULT);
+
+ stream_putc(s, closed_client->proto);
+ stream_putw(s, closed_client->instance);
+ stream_putl(s, closed_client->session_id);
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return zserv_send_message(client, s);
+}
+
/* Send response to a table manager connect request to client */
static void zread_table_manager_connect(struct zserv *client,
struct stream *msg, vrf_id_t vrf_id)
struct ipaddr *endpoint, char *name,
int status);
+extern int zsend_client_close_notify(struct zserv *client,
+ struct zserv *closed_client);
+
#ifdef __cplusplus
}
#endif
return CMD_SUCCESS;
}
+static int zserv_client_close_cb(struct zserv *closed_client)
+{
+ struct listnode *node, *nnode;
+ struct zserv *client = NULL;
+
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ if (client->proto == closed_client->proto)
+ continue;
+
+ zsend_client_close_notify(client, closed_client);
+ }
+
+ return 0;
+}
+
void zserv_init(void)
{
/* Client list init. */
install_element(ENABLE_NODE, &show_zebra_client_cmd);
install_element(ENABLE_NODE, &show_zebra_client_summary_cmd);
+
+ hook_register(zserv_client_close, zserv_client_close_cb);
}