"LSA age is more than Grace interval",
};
+static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa);
static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr);
static unsigned int ospf_enable_rtr_hash_key(const void *data)
*/
void ospf_gr_helper_init(struct ospf *ospf)
{
+ int rc;
+
if (IS_DEBUG_OSPF_GR_HELPER)
zlog_debug("%s, GR Helper init.", __PRETTY_FUNCTION__);
ospf->enable_rtr_list =
hash_create(ospf_enable_rtr_hash_key, ospf_enable_rtr_hash_cmp,
"OSPF enable router hash");
+
+ rc = ospf_register_opaque_functab(
+ OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, show_ospf_grace_lsa_info, NULL, NULL,
+ NULL, NULL);
+ if (rc != 0) {
+ flog_warn(EC_OSPF_OPAQUE_REGISTRATION,
+ "%s: Failed to register Grace LSA functions",
+ __func__);
+ }
}
/*
zlog_debug("%s, GR helper deinit.", __PRETTY_FUNCTION__);
ospf_enable_rtr_hash_destroy(ospf);
+
+ ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA);
}
/*
{
ospf->only_planned_restart = planned_only;
}
+
+/*
+ * Api to display the grace LSA information.
+ *
+ * vty
+ * vty pointer.
+ * lsa
+ * Grace LSA.
+ * json
+ * json object
+ *
+ * Returns:
+ * Nothing.
+ */
+static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa)
+{
+ struct lsa_header *lsah = NULL;
+ struct tlv_header *tlvh = NULL;
+ struct grace_tlv_graceperiod *gracePeriod;
+ struct grace_tlv_restart_reason *grReason;
+ struct grace_tlv_restart_addr *restartAddr;
+ uint16_t length = 0;
+ int sum = 0;
+
+ lsah = (struct lsa_header *)lsa->data;
+
+ length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
+
+ vty_out(vty, " TLV info:\n");
+
+ for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+ tlvh = TLV_HDR_NEXT(tlvh)) {
+ switch (ntohs(tlvh->type)) {
+ case GRACE_PERIOD_TYPE:
+ gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
+ sum += TLV_SIZE(tlvh);
+
+ vty_out(vty, " Grace period:%d\n",
+ ntohl(gracePeriod->interval));
+ break;
+ case RESTART_REASON_TYPE:
+ grReason = (struct grace_tlv_restart_reason *)tlvh;
+ sum += TLV_SIZE(tlvh);
+
+ vty_out(vty, " Restart reason:%s\n",
+ ospf_restart_reason_desc[grReason->reason]);
+ break;
+ case RESTARTER_IP_ADDR_TYPE:
+ restartAddr = (struct grace_tlv_restart_addr *)tlvh;
+ sum += TLV_SIZE(tlvh);
+
+ vty_out(vty, " Restarter address:%s\n",
+ inet_ntoa(restartAddr->addr));
+ break;
+ default:
+ break;
+ }
+ }
+}
" Thread Link State Update Retransmission %s\n\n",
nbr->t_ls_upd != NULL ? "on" : "off");
+ if (!use_json) {
+ vty_out(vty, " Graceful restart Helper info:\n");
+
+ if (OSPF_GR_IS_ACTIVE_HELPER(nbr)) {
+ vty_out(vty,
+ " Graceful Restart HELPER Status : Inprogress.\n");
+
+ vty_out(vty,
+ " Graceful Restart grace period time: %d (seconds).\n",
+ nbr->gr_helper_info.recvd_grace_period);
+ vty_out(vty, " Graceful Restart reason: %s.\n",
+ ospf_restart_reason_desc
+ [nbr->gr_helper_info
+ .gr_restart_reason]);
+ } else {
+ vty_out(vty,
+ " Graceful Restart HELPER Status : None\n");
+ }
+
+ if (nbr->gr_helper_info.rejected_reason
+ != OSPF_HELPER_REJECTED_NONE)
+ vty_out(vty, " Helper rejected reason: %s.\n",
+ ospf_rejected_reason_desc
+ [nbr->gr_helper_info.rejected_reason]);
+
+ if (nbr->gr_helper_info.helper_exit_reason
+ != OSPF_GR_HELPER_EXIT_NONE)
+ vty_out(vty, " Last helper exit reason: %s.\n\n",
+ ospf_exit_reason_desc
+ [nbr->gr_helper_info
+ .helper_exit_reason]);
+ else
+ vty_out(vty, "\n");
+ } else {
+ json_object_string_add(json_neigh, "grHelperStatus",
+ OSPF_GR_IS_ACTIVE_HELPER(nbr) ?
+ "Inprogress"
+ : "None");
+ if (OSPF_GR_IS_ACTIVE_HELPER(nbr)) {
+ json_object_int_add(
+ json_neigh, "graceInterval",
+ nbr->gr_helper_info.recvd_grace_period);
+ json_object_string_add(
+ json_neigh, "grRestartReason",
+ ospf_restart_reason_desc
+ [nbr->gr_helper_info
+ .gr_restart_reason]);
+ }
+
+ if (nbr->gr_helper_info.rejected_reason
+ != OSPF_HELPER_REJECTED_NONE)
+ json_object_string_add(
+ json_neigh, "helperRejectReason",
+ ospf_rejected_reason_desc
+ [nbr->gr_helper_info.rejected_reason]);
+
+ if (nbr->gr_helper_info.helper_exit_reason
+ != OSPF_GR_HELPER_EXIT_NONE)
+ json_object_string_add(
+ json_neigh, "helperExitReason",
+ ospf_exit_reason_desc
+ [nbr->gr_helper_info
+ .helper_exit_reason]);
+ }
+
ospf_bfd_show_info(vty, nbr->bfd_info, json_neigh, use_json, 0);
if (use_json)
return CMD_SUCCESS;
}
+
+static int ospf_print_vty_helper_dis_rtr_walkcb(struct hash_bucket *backet,
+ void *arg)
+{
+ struct advRtr *rtr = backet->data;
+ struct vty *vty = (struct vty *)arg;
+ static unsigned int count;
+
+ vty_out(vty, "%-6s,", inet_ntoa(rtr->advRtrAddr));
+ count++;
+
+ if (count % 5 == 0)
+ vty_out(vty, "\n");
+
+ return HASHWALK_CONTINUE;
+}
+
+static int ospf_show_gr_helper_details(struct vty *vty, struct ospf *ospf,
+ uint8_t use_vrf, json_object *json,
+ bool uj, bool detail)
+{
+ struct listnode *node;
+ struct ospf_interface *oi;
+ json_object *json_vrf = NULL;
+
+ if (uj) {
+ if (use_vrf)
+ json_vrf = json_object_new_object();
+ else
+ json_vrf = json;
+ }
+
+ if (ospf->instance) {
+ if (uj)
+ json_object_int_add(json, "ospfInstance",
+ ospf->instance);
+ else
+ vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance);
+ }
+
+ ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf);
+
+ if (uj) {
+ if (use_vrf) {
+ if (ospf->vrf_id == VRF_DEFAULT)
+ json_object_object_add(json, "default",
+ json_vrf);
+ else
+ json_object_object_add(json, ospf->name,
+ json_vrf);
+ }
+ } else
+ vty_out(vty, "\n");
+
+ /* Show Router ID. */
+ if (uj) {
+ json_object_string_add(json_vrf, "routerId",
+ inet_ntoa(ospf->router_id));
+ } else {
+ vty_out(vty, "\n OSPF Router with ID (%s)\n\n",
+ inet_ntoa(ospf->router_id));
+ }
+
+ if (!uj) {
+
+ if (ospf->is_helper_supported)
+ vty_out(vty,
+ " Graceful restart helper support enabled.\n");
+ else
+ vty_out(vty,
+ " Graceful restart helper support disabled.\n");
+
+ if (ospf->strict_lsa_check)
+ vty_out(vty, " Strict LSA check is enabled.\n");
+ else
+ vty_out(vty, " Strict LSA check is disabled.\n");
+
+ if (ospf->only_planned_restart)
+ vty_out(vty,
+ " Helper supported for planned restarts only.\n");
+ else
+ vty_out(vty,
+ " Helper supported for Planned and Unplanned Restarts.\n");
+
+ vty_out(vty,
+ " Supported Graceful restart interval: %d(in seconds).\n",
+ ospf->supported_grace_time);
+
+ if (OSPF_HELPER_ENABLE_RTR_COUNT(ospf)) {
+ vty_out(vty, " Enable Router list:\n");
+ vty_out(vty, " ");
+ hash_walk(ospf->enable_rtr_list,
+ ospf_print_vty_helper_dis_rtr_walkcb, vty);
+ vty_out(vty, "\n\n");
+ }
+
+ if (ospf->last_exit_reason != OSPF_GR_HELPER_EXIT_NONE) {
+ vty_out(vty, " Last Helper exit Reason :%s\n",
+ ospf_exit_reason_desc[ospf->last_exit_reason]);
+ }
+
+ if (ospf->active_restarter_cnt)
+ vty_out(vty,
+ " Number of Active neighbours in graceful restart: %d\n",
+ ospf->active_restarter_cnt);
+ else
+ vty_out(vty, "\n");
+
+ } else {
+ json_object_string_add(
+ json_vrf, "helperSupport",
+ (ospf->is_helper_supported) ? "Enabled" : "Disabled");
+ json_object_string_add(json_vrf, "strictLsaCheck",
+ (ospf->strict_lsa_check) ? "Enabled"
+ : "Disabled");
+ json_object_string_add(
+ json_vrf, "restartSupoort",
+ (ospf->only_planned_restart)
+ ? "Planned Restart only"
+ : "Planned and Unplanned Restarts");
+
+ json_object_int_add(json_vrf, "supportedGracePeriod",
+ ospf->supported_grace_time);
+
+ if (ospf->last_exit_reason != OSPF_GR_HELPER_EXIT_NONE)
+ json_object_string_add(
+ json_vrf, "LastExitReason",
+ ospf_exit_reason_desc[ospf->last_exit_reason]);
+
+ if (ospf->active_restarter_cnt)
+ json_object_int_add(json_vrf, "activeRestarterCnt",
+ ospf->active_restarter_cnt);
+ }
+
+
+ if (detail) {
+ int cnt = 1;
+ json_object *json_neighbors = NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
+ struct route_node *rn;
+ struct ospf_neighbor *nbr;
+ json_object *json_neigh;
+
+ if (ospf_interface_neighbor_count(oi) == 0)
+ continue;
+
+ if (uj) {
+ json_object_object_get_ex(json_vrf, "Neighbors",
+ &json_neighbors);
+ if (!json_neighbors) {
+ json_neighbors =
+ json_object_new_object();
+ json_object_object_add(json_vrf,
+ "Neighbors",
+ json_neighbors);
+ }
+ }
+
+ for (rn = route_top(oi->nbrs); rn;
+ rn = route_next(rn)) {
+
+ if (!rn->info)
+ continue;
+
+ nbr = rn->info;
+
+ if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
+ continue;
+
+ if (!uj) {
+ vty_out(vty, " Neighbour %d :\n", cnt);
+ vty_out(vty, " Address : %s\n",
+ inet_ntoa(nbr->address.u
+ .prefix4));
+ vty_out(vty, " Routerid : %s\n",
+ inet_ntoa(nbr->router_id));
+ vty_out(vty,
+ " Received Grace period : %d(in seconds).\n",
+ nbr->gr_helper_info
+ .recvd_grace_period);
+ vty_out(vty,
+ " Actual Grace period : %d(in seconds)\n",
+ nbr->gr_helper_info
+ .actual_grace_period);
+ vty_out(vty,
+ " Remaining GraceTime:%ld(in seconds).\n",
+ thread_timer_remain_second(
+ nbr->gr_helper_info
+ .t_grace_timer));
+ vty_out(vty,
+ " Graceful Restart reason: %s.\n\n",
+ ospf_restart_reason_desc
+ [nbr->gr_helper_info
+ .gr_restart_reason]);
+ cnt++;
+ } else {
+ json_neigh = json_object_new_object();
+ json_object_string_add(
+ json_neigh, "srcAddr",
+ inet_ntoa(nbr->src));
+
+ json_object_string_add(
+ json_neigh, "routerid",
+ inet_ntoa(nbr->router_id));
+ json_object_int_add(
+ json_neigh,
+ "recvdGraceInterval",
+ nbr->gr_helper_info
+ .recvd_grace_period);
+ json_object_int_add(
+ json_neigh,
+ "actualGraceInterval",
+ nbr->gr_helper_info
+ .actual_grace_period);
+ json_object_int_add(
+ json_neigh, "remainGracetime",
+ thread_timer_remain_second(
+ nbr->gr_helper_info
+ .t_grace_timer));
+ json_object_string_add(
+ json_neigh, "restartReason",
+ ospf_restart_reason_desc
+ [nbr->gr_helper_info
+ .gr_restart_reason]);
+ json_object_object_add(
+ json_neighbors,
+ inet_ntoa(nbr->src),
+ json_neigh);
+ }
+ }
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ip_ospf_gr_helper,
+ show_ip_ospf_gr_helper_cmd,
+ "show ip ospf [vrf <NAME|all>] graceful-restart helper [detail] [json]",
+ SHOW_STR
+ IP_STR
+ "OSPF information\n"
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "OSPF Graceful Restart\n"
+ "Helper details in the router\n"
+ "Detailed informtion\n"
+ JSON_STR)
+{
+ char *vrf_name = NULL;
+ bool all_vrf = false;
+ int ret = CMD_SUCCESS;
+ int idx_vrf = 0;
+ int idx = 0;
+ uint8_t use_vrf = 0;
+ bool uj = use_json(argc, argv);
+ struct ospf *ospf = NULL;
+ json_object *json = NULL;
+ struct listnode *node = NULL;
+ int inst = 0;
+ bool detail = false;
+
+ OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+
+ if (argv_find(argv, argc, "detail", &idx))
+ detail = true;
+
+ if (uj)
+ json = json_object_new_object();
+
+ /* vrf input is provided */
+ if (vrf_name) {
+ use_vrf = 1;
+
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
+ if (!ospf->oi_running)
+ continue;
+
+ ret = ospf_show_gr_helper_details(
+ vty, ospf, use_vrf, json, uj, detail);
+ }
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return ret;
+ }
+
+ ospf = ospf_lookup_by_inst_name(inst, vrf_name);
+
+ if (ospf == NULL || !ospf->oi_running) {
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ } else
+ vty_out(vty, "%% OSPF instance not found\n");
+
+ return CMD_SUCCESS;
+ }
+
+ } else {
+ /* Default Vrf */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+
+ if (ospf == NULL || !ospf->oi_running) {
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ } else
+ vty_out(vty, "%% OSPF instance not found\n");
+
+ return CMD_SUCCESS;
+ }
+
+ ospf_show_gr_helper_details(vty, ospf, use_vrf, json, uj,
+ detail);
+ }
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+
+ return CMD_SUCCESS;
+}
/* Graceful Restart HELPER commands end */
static void config_write_stub_router(struct vty *vty, struct ospf *ospf)
/* "show ip ospf vrfs" commands. */
install_element(VIEW_NODE, &show_ip_ospf_vrfs_cmd);
+
+ /* "show ip ospf gr-helper details" command */
+ install_element(VIEW_NODE, &show_ip_ospf_gr_helper_cmd);
}