]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #10701 from rampxxxx/feat_isis_json_show_cmds
authorRuss White <russ@riw.us>
Tue, 8 Mar 2022 16:15:25 +0000 (11:15 -0500)
committerGitHub <noreply@github.com>
Tue, 8 Mar 2022 16:15:25 +0000 (11:15 -0500)
Feat isis json show cmds

1  2 
doc/user/isisd.rst
isisd/isis_adjacency.c
isisd/isis_adjacency.h
isisd/isis_lsp.c
isisd/isis_lsp.h
isisd/isis_pdu.c
isisd/isis_spf.c

diff --combined doc/user/isisd.rst
index f7d42d820085e82d5c88d306a4af6a4844b41dbe,873d9e30dd5406d2dd85b320c69acb56b4aa9997..d2859670dd15e6cdbbd35613f94542d8c7368300
@@@ -272,7 -272,7 +272,7 @@@ ISIS interfac
  Showing ISIS information
  ========================
  
- .. clicmd:: show isis summary
+ .. clicmd:: show isis [vrf <NAME|all>] summary [json]
  
     Show summary information about ISIS.
  
  
     Show information about ISIS node.
  
- .. clicmd:: show isis interface [detail] [IFNAME]
+ .. clicmd:: show isis [vrf <NAME|all>] interface [detail] [IFNAME] [json]
  
     Show state and configuration of ISIS specified interface, or all interfaces
     if no interface is given with or without details.
  
- .. clicmd:: show isis neighbor [detail] [SYSTEMID]
+ .. clicmd:: show isis [vrf <NAME|all>] neighbor [detail] [SYSTEMID] [json]
  
     Show state and information of ISIS specified neighbor, or all neighbors if
     no system id is given with or without details.
  
- .. clicmd:: show isis database [detail] [LSPID]
+ .. clicmd:: show isis [vrf <NAME|all>] database [detail] [LSPID] [json]
  
     Show the ISIS database globally, for a specific LSP id without or with
     details.
@@@ -396,6 -396,13 +396,6 @@@ Known limitations
     may not exceed 65535. Optionally sets also the Segment Routing Local Block.
     The negative command always unsets both.
  
 -.. clicmd:: segment-routing local-block (16-1048575) (16-1048575)
 -
 -   Set the Segment Routing Local Block i.e. the label range used by MPLS
 -   to store label in the MPLS FIB for Adjacency SID. Note that the block size
 -   may not exceed 65535. This command is deprecated in favor of the combined
 -   'segment-routing global-block A B local-block C D' command.
 -
  .. clicmd:: segment-routing node-msd (1-16)
  
     Set the Maximum Stack Depth supported by the router. The value depend of the
diff --combined isisd/isis_adjacency.c
index 06909c4306a40f1b76584dcabcce2d439f9f6658,7681e37b263bcd57d087da5195c50ea8b46d9317..2729dce382f3057da65f65d4a2598a8e47e637c4
@@@ -448,7 -448,7 +448,7 @@@ const char *isis_adj_yang_state(enum is
        }
  }
  
 -int isis_adj_expire(struct thread *thread)
 +void isis_adj_expire(struct thread *thread)
  {
        struct isis_adjacency *adj;
  
  
        /* trigger the adj expire event */
        isis_adj_state_change(&adj, ISIS_ADJ_DOWN, "holding time expired");
 -
 -      return 0;
  }
  
+ /*
+  * show isis neighbor [detail] json
+  */
+ void isis_adj_print_json(struct isis_adjacency *adj, struct json_object *json,
+                        char detail)
+ {
+       json_object *iface_json, *ipv4_addr_json, *ipv6_link_json,
+               *ipv6_non_link_json, *topo_json, *dis_flaps_json,
+               *area_addr_json, *adj_sid_json;
+       time_t now;
+       struct isis_dynhn *dyn;
+       int level;
+       char buf[256];
+       json_object_string_add(json, "adj", isis_adj_name(adj));
+       if (detail == ISIS_UI_LEVEL_BRIEF) {
+               if (adj->circuit)
+                       json_object_string_add(json, "interface",
+                                              adj->circuit->interface->name);
+               else
+                       json_object_string_add(json, "interface",
+                                              "NULL circuit!");
+               json_object_int_add(json, "level", adj->level);
+               json_object_string_add(json, "state",
+                                      adj_state2string(adj->adj_state));
+               now = time(NULL);
+               if (adj->last_upd) {
+                       if (adj->last_upd + adj->hold_time < now)
+                               json_object_string_add(json, "last-upd",
+                                                      "expiring");
+                       else
+                               json_object_string_add(
+                                       json, "expires-in",
+                                       time2string(adj->last_upd +
+                                                   adj->hold_time - now));
+               }
+               json_object_string_add(json, "snpa", snpa_print(adj->snpa));
+       }
+       if (detail == ISIS_UI_LEVEL_DETAIL) {
+               struct sr_adjacency *sra;
+               struct listnode *anode;
+               level = adj->level;
+               iface_json = json_object_new_object();
+               json_object_object_add(json, "interface", iface_json);
+               if (adj->circuit)
+                       json_object_string_add(iface_json, "name",
+                                              adj->circuit->interface->name);
+               else
+                       json_object_string_add(iface_json, "name",
+                                              "null-circuit");
+               json_object_int_add(json, "level", adj->level);
+               json_object_string_add(iface_json, "state",
+                                      adj_state2string(adj->adj_state));
+               now = time(NULL);
+               if (adj->last_upd) {
+                       if (adj->last_upd + adj->hold_time < now)
+                               json_object_string_add(iface_json, "last-upd",
+                                                      "expiring");
+                       else
+                               json_object_string_add(
+                                       json, "expires-in",
+                                       time2string(adj->last_upd +
+                                                   adj->hold_time - now));
+               } else
+                       json_object_string_add(json, "expires-in",
+                                              time2string(adj->hold_time));
+               json_object_int_add(iface_json, "adj-flaps", adj->flaps);
+               json_object_string_add(iface_json, "last-ago",
+                                      time2string(now - adj->last_flap));
+               json_object_string_add(iface_json, "circuit-type",
+                                      circuit_t2string(adj->circuit_t));
+               json_object_string_add(iface_json, "speaks",
+                                      nlpid2string(&adj->nlpids));
+               if (adj->mt_count != 1 ||
+                   adj->mt_set[0] != ISIS_MT_IPV4_UNICAST) {
+                       topo_json = json_object_new_object();
+                       json_object_object_add(iface_json, "topologies",
+                                              topo_json);
+                       for (unsigned int i = 0; i < adj->mt_count; i++) {
+                               snprintfrr(buf, sizeof(buf), "topo-%d", i);
+                               json_object_string_add(
+                                       topo_json, buf,
+                                       isis_mtid2str(adj->mt_set[i]));
+                       }
+               }
+               json_object_string_add(iface_json, "snpa",
+                                      snpa_print(adj->snpa));
+               if (adj->circuit &&
+                   (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
+                       dyn = dynhn_find_by_id(adj->circuit->isis, adj->lanid);
+                       if (dyn) {
+                               snprintfrr(buf, sizeof(buf), "%s-%02x",
+                                          dyn->hostname,
+                                          adj->lanid[ISIS_SYS_ID_LEN]);
+                               json_object_string_add(iface_json, "lan-id",
+                                                      buf);
+                       } else {
+                               snprintfrr(buf, sizeof(buf), "%s-%02x",
+                                          sysid_print(adj->lanid),
+                                          adj->lanid[ISIS_SYS_ID_LEN]);
+                               json_object_string_add(iface_json, "lan-id",
+                                                      buf);
+                       }
+                       json_object_int_add(iface_json, "lan-prio",
+                                           adj->prio[adj->level - 1]);
+                       dis_flaps_json = json_object_new_object();
+                       json_object_object_add(iface_json, "dis-flaps",
+                                              dis_flaps_json);
+                       json_object_string_add(
+                               dis_flaps_json, "dis-record",
+                               isis_disflag2string(
+                                       adj->dis_record[ISIS_LEVELS + level - 1]
+                                               .dis));
+                       json_object_int_add(dis_flaps_json, "last",
+                                           adj->dischanges[level - 1]);
+                       json_object_string_add(
+                               dis_flaps_json, "ago",
+                               time2string(now - (adj->dis_record[ISIS_LEVELS +
+                                                                  level - 1]
+                                                          .last_dis_change)));
+               }
+               if (adj->area_address_count) {
+                       area_addr_json = json_object_new_object();
+                       json_object_object_add(iface_json, "area-address",
+                                              area_addr_json);
+                       for (unsigned int i = 0; i < adj->area_address_count;
+                            i++) {
+                               json_object_string_add(
+                                       area_addr_json, "isonet",
+                                       isonet_print(adj->area_addresses[i]
+                                                            .area_addr,
+                                                    adj->area_addresses[i]
+                                                            .addr_len));
+                       }
+               }
+               if (adj->ipv4_address_count) {
+                       ipv4_addr_json = json_object_new_object();
+                       json_object_object_add(iface_json, "ipv4-address",
+                                              ipv4_addr_json);
+                       for (unsigned int i = 0; i < adj->ipv4_address_count;
+                            i++){
+                               inet_ntop(AF_INET, &adj->ipv4_addresses[i], buf,
+                                         sizeof(buf));
+                       json_object_string_add(ipv4_addr_json, "ipv4", buf);
+               }
+               }
+               if (adj->ll_ipv6_count) {
+                       ipv6_link_json = json_object_new_object();
+                       json_object_object_add(iface_json, "ipv6-link-local",
+                                              ipv6_link_json);
+                       for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
+                               char buf[INET6_ADDRSTRLEN];
+                               inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i], buf,
+                                         sizeof(buf));
+                               json_object_string_add(ipv6_link_json, "ipv6",
+                                                      buf);
+                       }
+               }
+               if (adj->global_ipv6_count) {
+                       ipv6_non_link_json = json_object_new_object();
+                       json_object_object_add(iface_json, "ipv6-global",
+                                              ipv6_non_link_json);
+                       for (unsigned int i = 0; i < adj->global_ipv6_count;
+                            i++) {
+                               char buf[INET6_ADDRSTRLEN];
+                               inet_ntop(AF_INET6, &adj->global_ipv6_addrs[i],
+                                         buf, sizeof(buf));
+                               json_object_string_add(ipv6_non_link_json,
+                                                      "ipv6", buf);
+                       }
+               }
+               adj_sid_json = json_object_new_object();
+               json_object_object_add(iface_json, "adj-sid", adj_sid_json);
+               for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, anode, sra)) {
+                       const char *adj_type;
+                       const char *backup;
+                       uint32_t sid;
+                       switch (sra->adj->circuit->circ_type) {
+                       case CIRCUIT_T_BROADCAST:
+                               adj_type = "LAN Adjacency-SID";
+                               sid = sra->u.ladj_sid->sid;
+                               break;
+                       case CIRCUIT_T_P2P:
+                               adj_type = "Adjacency-SID";
+                               sid = sra->u.adj_sid->sid;
+                               break;
+                       default:
+                               continue;
+                       }
+                       backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)"
+                                                                  : "";
+                       json_object_string_add(adj_sid_json, "nexthop",
+                                              (sra->nexthop.family == AF_INET)
+                                                      ? "IPv4"
+                                                      : "IPv6");
+                       json_object_string_add(adj_sid_json, "adj-type",
+                                              adj_type);
+                       json_object_string_add(adj_sid_json, "is-backup",
+                                              backup);
+                       json_object_int_add(adj_sid_json, "sid", sid);
+               }
+       }
+       return;
+ }
  /*
   * show isis neighbor [detail]
   */
diff --combined isisd/isis_adjacency.h
index 4d84c5ca4d96ea49aa6022951fc3b5fb132a2ff0,b8e2d6f577cd52e6300593a16b31c5ef77b3ab13..7467a619cb16c7dc102aac9cd400c69c9221149d
@@@ -141,13 -141,15 +141,15 @@@ void isis_adj_state_change(struct isis_
                           enum isis_adj_state state, const char *reason);
  void isis_adj_print(struct isis_adjacency *adj);
  const char *isis_adj_yang_state(enum isis_adj_state state);
 -int isis_adj_expire(struct thread *thread);
 +void isis_adj_expire(struct thread *thread);
  void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
                        char detail);
+ void isis_adj_print_json(struct isis_adjacency *adj, struct json_object *json,
+                        char detail);
  void isis_adj_build_neigh_list(struct list *adjdb, struct list *list);
  void isis_adj_build_up_list(struct list *adjdb, struct list *list);
  int isis_adj_usage2levels(enum isis_adj_usage usage);
 -int isis_bfd_startup_timer(struct thread *thread);
 +void isis_bfd_startup_timer(struct thread *thread);
  const char *isis_adj_name(const struct isis_adjacency *adj);
  
  #endif /* ISIS_ADJACENCY_H */
diff --combined isisd/isis_lsp.c
index 463d26f6c7f638bf462e105fcdb872e8b86a280d,de31c60553afb46902c9a6e201a30f4aac130e97..eb7e9e725e34c218b43cfc19201815d60e97741e
@@@ -62,9 -62,9 +62,9 @@@
  
  DEFINE_MTYPE_STATIC(ISISD, ISIS_LSP, "ISIS LSP");
  
 -static int lsp_refresh(struct thread *thread);
 -static int lsp_l1_refresh_pseudo(struct thread *thread);
 -static int lsp_l2_refresh_pseudo(struct thread *thread);
 +static void lsp_refresh(struct thread *thread);
 +static void lsp_l1_refresh_pseudo(struct thread *thread);
 +static void lsp_l2_refresh_pseudo(struct thread *thread);
  
  static void lsp_destroy(struct isis_lsp *lsp);
  
@@@ -733,8 -733,48 +733,48 @@@ static const char *lsp_bits2string(uint
  }
  
  /* this function prints the lsp on show isis database */
- void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost,
-              struct isis *isis)
+ void lsp_print_common(struct isis_lsp *lsp, struct vty *vty, struct json_object *json,
+              char dynhost, struct isis *isis)
+ {
+       if (json) {
+               return lsp_print_json(lsp, json, dynhost, isis);
+       } else {
+               return lsp_print_vty(lsp, vty, dynhost, isis);
+       }
+ }
+ void lsp_print_json(struct isis_lsp *lsp, struct json_object *json,
+              char dynhost, struct isis *isis)
+ {
+       char LSPid[255];
+       char age_out[8];
+       char b[200];
+       json_object *own_json;
+       char buf[256];
+       lspid_print(lsp->hdr.lsp_id, LSPid, sizeof(LSPid), dynhost, 1, isis);
+       own_json = json_object_new_object();
+       json_object_object_add(json, "lsp", own_json);
+       json_object_string_add(own_json, "id", LSPid);
+       json_object_string_add(own_json, "own", lsp->own_lsp ? "*" : " ");
+       json_object_int_add(json, "pdu-len", lsp->hdr.pdu_len);
+       snprintfrr(buf, sizeof(buf), "0x%08x", lsp->hdr.seqno);
+       json_object_string_add(json, "seq-number", buf);
+       snprintfrr(buf, sizeof(buf), "0x%04hx", lsp->hdr.checksum);
+       json_object_string_add(json, "chksum", buf);
+       if (lsp->hdr.rem_lifetime == 0) {
+               snprintf(age_out, sizeof(age_out), "(%d)", lsp->age_out);
+               age_out[7] = '\0';
+               json_object_string_add(json, "holdtime", age_out);
+       } else {
+               json_object_int_add(json, "holdtime", lsp->hdr.rem_lifetime);
+       }
+       json_object_string_add(
+               json, "att-p-ol", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b)));
+ }
+ void lsp_print_vty(struct isis_lsp *lsp, struct vty *vty,
+              char dynhost, struct isis *isis)
  {
        char LSPid[255];
        char age_out[8];
        vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b)));
  }
  
- void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost,
-                     struct isis *isis)
+ void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty,
+                            struct json_object *json, char dynhost,
+                            struct isis *isis)
  {
-       lsp_print(lsp, vty, dynhost, isis);
-       if (lsp->tlvs)
-               vty_multiline(vty, "  ", "%s", isis_format_tlvs(lsp->tlvs));
-       vty_out(vty, "\n");
+       if (json) {
+               lsp_print_json(lsp, json, dynhost, isis);
+               if (lsp->tlvs) {
+                       isis_format_tlvs(lsp->tlvs, json);
+               }
+       } else {
+               lsp_print_vty(lsp, vty, dynhost, isis);
+               if (lsp->tlvs)
+                       vty_multiline(vty, "  ", "%s",
+                                     isis_format_tlvs(lsp->tlvs, NULL));
+               vty_out(vty, "\n");
+       }
  }
  
  /* print all the lsps info in the local lspdb */
- int lsp_print_all(struct vty *vty, struct lspdb_head *head, char detail,
-                 char dynhost, struct isis *isis)
+ int lsp_print_all(struct vty *vty, struct json_object *json,
+                 struct lspdb_head *head, char detail, char dynhost,
+                 struct isis *isis)
  {
        struct isis_lsp *lsp;
        int lsp_count = 0;
  
        if (detail == ISIS_UI_LEVEL_BRIEF) {
                frr_each (lspdb, head, lsp) {
-                       lsp_print(lsp, vty, dynhost, isis);
+                       lsp_print_common(lsp, vty, json, dynhost, isis);
                        lsp_count++;
                }
        } else if (detail == ISIS_UI_LEVEL_DETAIL) {
                frr_each (lspdb, head, lsp) {
-                       lsp_print_detail(lsp, vty, dynhost, isis);
+                       lsp_print_detail(lsp, vty, json, dynhost, isis);
                        lsp_count++;
                }
        }
@@@ -1264,7 -1314,7 +1314,7 @@@ static void lsp_build(struct isis_lsp *
        if (!fragments) {
                zlog_warn("BUG: could not fragment own LSP:");
                log_multiline(LOG_WARNING, "    ", "%s",
-                             isis_format_tlvs(tlvs));
+                             isis_format_tlvs(tlvs, NULL));
                isis_free_tlvs(tlvs);
                return;
        }
@@@ -1447,7 -1497,7 +1497,7 @@@ static int lsp_regenerate(struct isis_a
  /*
   * Something has changed or periodic refresh -> regenerate LSP
   */
 -static int lsp_refresh(struct thread *thread)
 +static void lsp_refresh(struct thread *thread)
  {
        struct lsp_refresh_arg *arg = THREAD_ARG(thread);
  
        area->lsp_regenerate_pending[level - 1] = 0;
  
        if ((area->is_type & level) == 0)
 -              return ISIS_ERROR;
 +              return;
  
        /*
         * Throttle regeneration of LSPs (but not when BFD signalled a 'down'
                            area->area_tag, level);
                _lsp_regenerate_schedule(area, level, 0, false,
                                         __func__, __FILE__, __LINE__);
 -              return 0;
 +              return;
        }
  
        sched_debug(
                "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
                area->area_tag, level);
 -      return lsp_regenerate(area, level);
 +      lsp_regenerate(area, level);
  }
  
  int _lsp_regenerate_schedule(struct isis_area *area, int level,
@@@ -1827,7 -1877,7 +1877,7 @@@ static int lsp_regenerate_pseudo(struc
  /*
   * Something has changed or periodic refresh -> regenerate pseudo LSP
   */
 -static int lsp_l1_refresh_pseudo(struct thread *thread)
 +static void lsp_l1_refresh_pseudo(struct thread *thread)
  {
        struct isis_circuit *circuit;
        uint8_t id[ISIS_SYS_ID_LEN + 2];
                LSP_PSEUDO_ID(id) = circuit->circuit_id;
                LSP_FRAGMENT(id) = 0;
                lsp_purge_pseudo(id, circuit, IS_LEVEL_1);
 -              return ISIS_ERROR;
 +              return;
        }
  
 -      return lsp_regenerate_pseudo(circuit, IS_LEVEL_1);
 +      lsp_regenerate_pseudo(circuit, IS_LEVEL_1);
  }
  
 -static int lsp_l2_refresh_pseudo(struct thread *thread)
 +static void lsp_l2_refresh_pseudo(struct thread *thread)
  {
        struct isis_circuit *circuit;
        uint8_t id[ISIS_SYS_ID_LEN + 2];
                LSP_PSEUDO_ID(id) = circuit->circuit_id;
                LSP_FRAGMENT(id) = 0;
                lsp_purge_pseudo(id, circuit, IS_LEVEL_2);
 -              return ISIS_ERROR;
 +              return;
        }
  
 -      return lsp_regenerate_pseudo(circuit, IS_LEVEL_2);
 +      lsp_regenerate_pseudo(circuit, IS_LEVEL_2);
  }
  
  int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
   * Walk through LSPs for an area
   *  - set remaining lifetime
   */
 -int lsp_tick(struct thread *thread)
 +void lsp_tick(struct thread *thread)
  {
        struct isis_area *area;
        struct isis_lsp *lsp;
            && !isis_tx_queue_len(fabricd_init_c->tx_queue)) {
                fabricd_initial_sync_finish(area);
        }
 -
 -      return ISIS_OK;
  }
  
  void lsp_purge_pseudo(uint8_t *id, struct isis_circuit *circuit, int level)
diff --combined isisd/isis_lsp.h
index f42d702b373b80deb13297a8daa00dfe15c21016,50cba106010e1e6654751e28c0c87ec1ecae5605..b13b2a35e6b0c6bedd0d7f85ef328a28cbf7d52f
@@@ -65,7 -65,7 +65,7 @@@ DECLARE_RBTREE_UNIQ(lspdb, struct isis_
  
  void lsp_db_init(struct lspdb_head *head);
  void lsp_db_fini(struct lspdb_head *head);
 -int lsp_tick(struct thread *thread);
 +void lsp_tick(struct thread *thread);
  
  int lsp_generate(struct isis_area *area, int level);
  #define lsp_regenerate_schedule(area, level, all_pseudo) \
@@@ -120,12 -120,19 +120,19 @@@ void lsp_update(struct isis_lsp *lsp, s
  void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno);
  void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost,
                 char frag, struct isis *isis);
- void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost,
-              struct isis *isis);
- void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost,
+ void lsp_print_common(struct isis_lsp *lsp, struct vty *vty,
+                     struct json_object *json, char dynhost,
                      struct isis *isis);
- int lsp_print_all(struct vty *vty, struct lspdb_head *head, char detail,
-                 char dynhost, struct isis *isis);
+ void lsp_print_vty(struct isis_lsp *lsp, struct vty *vty, char dynhost,
+                  struct isis *isis);
+ void lsp_print_json(struct isis_lsp *lsp, struct json_object *json,
+                   char dynhost, struct isis *isis);
+ void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty,
+                     struct json_object *json, char dynhost,
+                     struct isis *isis);
+ int lsp_print_all(struct vty *vty, struct json_object *json,
+                 struct lspdb_head *head, char detail, char dynhost,
+                 struct isis *isis);
  /* sets SRMflags for all active circuits of an lsp */
  void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set);
  
diff --combined isisd/isis_pdu.c
index 517c9ec5aa844167f597e206b3d98d149209544f,9a34f5699b56cc0d9e726613f2a83130b4f46da8..1a54d47f3c104ab71de248f6a231838632b7dc24
@@@ -1793,10 -1793,11 +1793,10 @@@ int isis_handle_pdu(struct isis_circui
        return retval;
  }
  
 -int isis_receive(struct thread *thread)
 +void isis_receive(struct thread *thread)
  {
        struct isis_circuit *circuit;
        uint8_t ssnpa[ETH_ALEN];
 -      int retval;
  
        /*
         * Get the circuit
  
        isis_circuit_stream(circuit, &circuit->rcv_stream);
  
 +#if ISIS_METHOD != ISIS_METHOD_BPF
 +      int retval;
 +
        retval = circuit->rx(circuit, ssnpa);
  
 -#if ISIS_METHOD != ISIS_METHOD_BPF
        if (retval == ISIS_OK)
 -              retval = isis_handle_pdu(circuit, ssnpa);
 -#endif //ISIS_METHOD != ISIS_METHOD_BPF
 +              isis_handle_pdu(circuit, ssnpa);
 +#else // ISIS_METHOD != ISIS_METHOD_BPF
 +      circuit->rx(circuit, ssnpa);
 +#endif
  
        /*
         * prepare for next packet.
         */
        if (!circuit->is_passive)
                isis_circuit_prepare(circuit);
 -
 -      return retval;
  }
  
  /*
@@@ -2016,7 -2015,7 +2016,7 @@@ int send_hello(struct isis_circuit *cir
        return retval;
  }
  
 -static int send_hello_cb(struct thread *thread)
 +static void send_hello_cb(struct thread *thread)
  {
        struct isis_circuit_arg *arg = THREAD_ARG(thread);
        assert(arg);
                send_hello(circuit, 1);
                send_hello_sched(circuit, ISIS_LEVEL1,
                                 1000 * circuit->hello_interval[1]);
 -              return ISIS_OK;
 +              return;
        }
  
        if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
                zlog_warn("ISIS-Hello (%s): Trying to send hello on unknown circuit type %d",
                          circuit->area->area_tag, circuit->circ_type);
 -              return ISIS_WARNING;
 +              return;
        }
  
        circuit->u.bc.t_send_lan_hello[level - 1] = NULL;
        if (!(circuit->is_type & level)) {
                zlog_warn("ISIS-Hello (%s): Trying to send L%d IIH in L%d-only circuit",
                          circuit->area->area_tag, level, 3 - level);
 -              return ISIS_WARNING;
 +              return;
        }
  
        if (circuit->u.bc.run_dr_elect[level - 1])
                isis_dr_elect(circuit, level);
  
 -      int rv = send_hello(circuit, level);
 +      send_hello(circuit, level);
  
        /* set next timer thread */
        send_hello_sched(circuit, level, 1000 * circuit->hello_interval[level - 1]);
 -      return rv;
  }
  
  static void _send_hello_sched(struct isis_circuit *circuit,
@@@ -2209,7 -2209,7 +2209,7 @@@ int send_csnp(struct isis_circuit *circ
                                circuit->interface->name,
                                stream_get_endp(circuit->snd_stream));
                        log_multiline(LOG_DEBUG, "              ", "%s",
-                                     isis_format_tlvs(tlvs));
+                                     isis_format_tlvs(tlvs, NULL));
                        if (IS_DEBUG_PACKET_DUMP)
                                zlog_dump_data(
                                        STREAM_DATA(circuit->snd_stream),
        return ISIS_OK;
  }
  
 -int send_l1_csnp(struct thread *thread)
 +void send_l1_csnp(struct thread *thread)
  {
        struct isis_circuit *circuit;
  
        thread_add_timer(master, send_l1_csnp, circuit,
                         isis_jitter(circuit->csnp_interval[0], CSNP_JITTER),
                         &circuit->t_send_csnp[0]);
 -
 -      return ISIS_OK;
  }
  
 -int send_l2_csnp(struct thread *thread)
 +void send_l2_csnp(struct thread *thread)
  {
        struct isis_circuit *circuit;
  
        thread_add_timer(master, send_l2_csnp, circuit,
                         isis_jitter(circuit->csnp_interval[1], CSNP_JITTER),
                         &circuit->t_send_csnp[1]);
 -
 -      return ISIS_OK;
  }
  
  /*
@@@ -2368,7 -2372,7 +2368,7 @@@ static int send_psnp(int level, struct 
                                circuit->interface->name,
                                stream_get_endp(circuit->snd_stream));
                        log_multiline(LOG_DEBUG, "              ", "%s",
-                                     isis_format_tlvs(tlvs));
+                                     isis_format_tlvs(tlvs, NULL));
                        if (IS_DEBUG_PACKET_DUMP)
                                zlog_dump_data(
                                        STREAM_DATA(circuit->snd_stream),
        return ISIS_OK;
  }
  
 -int send_l1_psnp(struct thread *thread)
 +void send_l1_psnp(struct thread *thread)
  {
  
        struct isis_circuit *circuit;
        thread_add_timer(master, send_l1_psnp, circuit,
                         isis_jitter(circuit->psnp_interval[0], PSNP_JITTER),
                         &circuit->t_send_psnp[0]);
 -
 -      return ISIS_OK;
  }
  
  /*
   *  7.3.15.4 action on expiration of partial SNP interval
   *  level 2
   */
 -int send_l2_psnp(struct thread *thread)
 +void send_l2_psnp(struct thread *thread)
  {
        struct isis_circuit *circuit;
  
        thread_add_timer(master, send_l2_psnp, circuit,
                         isis_jitter(circuit->psnp_interval[1], PSNP_JITTER),
                         &circuit->t_send_psnp[1]);
 -
 -      return ISIS_OK;
  }
  
  /*
diff --combined isisd/isis_spf.c
index 04b5cf1a67ea8f4cb5b819ae484838c2b5a763a2,f44e2afeeb166c4c26de617f644131cc40682dd3..d5b02f388152791eb67980294334467333379b30
@@@ -1832,7 -1832,7 +1832,7 @@@ void isis_spf_invalidate_routes(struct 
        tree->route_table_backup->cleanup = isis_route_node_cleanup;
  }
  
 -static int isis_run_spf_cb(struct thread *thread)
 +static void isis_run_spf_cb(struct thread *thread)
  {
        struct isis_spf_run *run = THREAD_ARG(thread);
        struct isis_area *area = run->area;
                if (IS_DEBUG_SPF_EVENTS)
                        zlog_warn("ISIS-SPF (%s) area does not share level",
                                  area->area_tag);
 -              return ISIS_WARNING;
 +              return;
        }
  
        isis_area_delete_backup_adj_sids(area, level);
                UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
  
        fabricd_run_spf(area);
 -
 -      return 0;
  }
  
  static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level)
@@@ -2683,3 -2685,15 +2683,15 @@@ void isis_spf_print(struct isis_spftre
  
        vty_out(vty, "      run count         : %u\n", spftree->runcount);
  }
+ void isis_spf_print_json(struct isis_spftree *spftree, struct json_object *json)
+ {
+       char uptime[MONOTIME_STRLEN];
+       time_t cur;
+       cur = time(NULL);
+       cur -= spftree->last_run_timestamp;
+       frrtime_to_interval(cur, uptime, sizeof(uptime));
+       json_object_string_add(json, "last-run-elapsed", uptime);
+       json_object_int_add(json, "last-run-duration-usec",
+                           spftree->last_run_duration);
+       json_object_int_add(json, "last-run-count", spftree->runcount);
+ }