diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index b0f2947ec6..e1cdfc30ea 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -258,6 +258,11 @@ void isis_adj_state_change(struct isis_adjacency *adj, reason ? reason : "unspecified"); } +#ifndef FABRICD + /* send northbound notification */ + isis_notif_adj_state_change(adj, new_state, reason); +#endif /* ifndef FABRICD */ + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { del = false; for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) { diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c index 183879cadf..03a775faf5 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -2658,6 +2658,56 @@ void isis_notif_authentication_failure(const struct isis_circuit *circuit, nb_notification_send(xpath, arguments); } +/* + * XPath: + * /frr-isisd:adjacency-state-change + */ +void isis_notif_adj_state_change(const struct isis_adjacency *adj, + int new_state, const char *reason) +{ + const char *xpath = "/frr-isisd:adjacency-state-change"; + struct list *arguments = yang_data_list_new(); + char xpath_arg[XPATH_MAXLEN]; + struct yang_data *data; + struct isis_circuit *circuit = adj->circuit; + struct isis_area *area = circuit->area; + struct isis_dynhn *dyn = dynhn_find_by_id(adj->sysid); + + notif_prep_instance_hdr(xpath, area, "default", arguments); + notif_prepr_iface_hdr(xpath, circuit, arguments); + if (dyn) { + snprintf(xpath_arg, sizeof(xpath_arg), "%s/neighbor", xpath); + data = yang_data_new_string(xpath_arg, dyn->hostname); + listnode_add(arguments, data); + } + snprintf(xpath_arg, sizeof(xpath_arg), "%s/neighbor-system-id", xpath); + data = yang_data_new_string(xpath_arg, sysid_print(adj->sysid)); + listnode_add(arguments, data); + + snprintf(xpath_arg, sizeof(xpath_arg), "%s/state", xpath); + switch (new_state) { + case ISIS_ADJ_DOWN: + data = yang_data_new_string(xpath_arg, "down"); + break; + case ISIS_ADJ_UP: + data = yang_data_new_string(xpath_arg, "up"); + break; + case ISIS_ADJ_INITIALIZING: + data = yang_data_new_string(xpath_arg, "init"); + break; + default: + data = yang_data_new_string(xpath_arg, "failed"); + } + listnode_add(arguments, data); + if (new_state == ISIS_ADJ_DOWN) { + snprintf(xpath_arg, sizeof(xpath_arg), "%s/reason", xpath); + data = yang_data_new_string(xpath_arg, reason); + listnode_add(arguments, data); + } + + nb_notification_send(xpath, arguments); +} + /* clang-format off */ const struct frr_yang_module_info frr_isisd_info = { .name = "frr-isisd", diff --git a/isisd/isisd.h b/isisd/isisd.h index 6d7f0a485c..d1547c2fa5 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -240,6 +240,8 @@ isis_notif_authentication_type_failure(const struct isis_circuit *circuit, extern void isis_notif_authentication_failure(const struct isis_circuit *circuit, const char *raw_pdu); +extern void isis_notif_adj_state_change(const struct isis_adjacency *adj, + int new_state, const char *reason); /* Master of threads. */ extern struct thread_master *master;