summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_errors.c6
-rw-r--r--bgpd/bgp_errors.h1
-rw-r--r--bgpd/bgp_zebra.c6
-rw-r--r--bgpd/bgpd.c2
-rw-r--r--doc/developer/frr-release-procedure.rst15
-rw-r--r--doc/developer/logging.rst4
-rw-r--r--doc/user/index.rst1
-rw-r--r--doc/user/isisd.rst8
-rw-r--r--doc/user/pimv6.rst288
-rw-r--r--doc/user/subdir.am1
-rw-r--r--isisd/isis_adjacency.c214
-rw-r--r--isisd/isis_adjacency.h2
-rw-r--r--isisd/isis_circuit.c145
-rw-r--r--isisd/isis_circuit.h2
-rw-r--r--isisd/isis_lsp.c76
-rw-r--r--isisd/isis_lsp.h17
-rw-r--r--isisd/isis_pdu.c4
-rw-r--r--isisd/isis_spf.c12
-rw-r--r--isisd/isis_spf.h2
-rw-r--r--isisd/isis_tlvs.c1288
-rw-r--r--isisd/isis_tlvs.h2
-rw-r--r--isisd/isisd.c633
-rw-r--r--isisd/isisd.h12
-rw-r--r--lib/json.c13
-rw-r--r--lib/json.h22
-rw-r--r--lib/libfrr.c17
-rw-r--r--lib/libfrr.h11
-rw-r--r--lib/log_vty.c16
-rw-r--r--lib/prefix.c37
-rw-r--r--lib/zlog.c4
-rw-r--r--lib/zlog_live.c54
-rw-r--r--lib/zlog_live.h32
-rw-r--r--ospf6d/ospf6_gr.c2
-rw-r--r--ospfd/ospf_gr.c2
-rw-r--r--pimd/pim6_stubs.c34
-rw-r--r--pimd/pim_br.c10
-rw-r--r--pimd/pim_br.h6
-rw-r--r--pimd/pim_ifchannel.c2
-rw-r--r--pimd/pim_msg.h27
-rw-r--r--pimd/pim_nht.c30
-rw-r--r--pimd/pim_register.c59
-rw-r--r--pimd/pim_register.h5
-rw-r--r--pimd/pim_rp.c217
-rw-r--r--pimd/pim_zebra.c5
-rw-r--r--pimd/subdir.am2
-rw-r--r--tests/isisd/test_fuzz_isis_tlv.c8
-rw-r--r--tests/isisd/test_isis_spf.c2
-rw-r--r--tests/lib/test_printfrr.c18
-rw-r--r--tests/topotests/isis_topo1/test_isis_topo1.py88
-rw-r--r--vrrpd/Makefile4
-rw-r--r--vtysh/vtysh.c28
-rw-r--r--zebra/if_netlink.c32
-rw-r--r--zebra/interface.c19
-rw-r--r--zebra/interface.h2
-rw-r--r--zebra/zebra_evpn_mac.c28
-rw-r--r--zebra/zebra_evpn_neigh.c1
-rw-r--r--zebra/zebra_nhg.c35
-rw-r--r--zebra/zebra_ptm.c6
58 files changed, 2881 insertions, 738 deletions
diff --git a/bgpd/bgp_errors.c b/bgpd/bgp_errors.c
index f11717b41f..193c96a169 100644
--- a/bgpd/bgp_errors.c
+++ b/bgpd/bgp_errors.c
@@ -475,6 +475,12 @@ static struct log_ref ferr_bgp_err[] = {
.suggestion = "Get log files from router and open an issue",
},
{
+ .code = EC_BGP_NO_LL_ADDRESS_AVAILABLE,
+ .title = "BGP v6 peer with no LL address on outgoing interface",
+ .description = "BGP when using a v6 peer requires a v6 LL address to be configured on the outgoing interface as per RFC 4291 section 2.1",
+ .suggestion = "Add a v6 LL address to the outgoing interfaces as per RFC",
+ },
+ {
.code = END_FERR,
}
};
diff --git a/bgpd/bgp_errors.h b/bgpd/bgp_errors.h
index 20056d382a..0b71af3fc6 100644
--- a/bgpd/bgp_errors.h
+++ b/bgpd/bgp_errors.h
@@ -101,6 +101,7 @@ enum bgp_log_refs {
EC_BGP_ROUTER_ID_SAME,
EC_BGP_INVALID_BGP_INSTANCE,
EC_BGP_INVALID_ROUTE,
+ EC_BGP_NO_LL_ADDRESS_AVAILABLE,
};
extern void bgp_error_init(void);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index c0a9a38773..78eaac7806 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -882,6 +882,12 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote,
*/
if (!v6_ll_avail && if_is_loopback(ifp))
v6_ll_avail = true;
+ else {
+ flog_warn(
+ EC_BGP_NO_LL_ADDRESS_AVAILABLE,
+ "Interface: %s does not have a v6 LL address associated with it, waiting until one is created for it",
+ ifp->name);
+ }
} else
/* Link-local address. */
{
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 16488eb4a4..38a106359e 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1223,7 +1223,7 @@ int bgp_global_gr_init(struct bgp *bgp)
{
/*Event -> */
/*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/
- GLOBAL_INVALID, GLOBAL_HELPER,
+ GLOBAL_GR, GLOBAL_HELPER,
/*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/
GLOBAL_DISABLE, GLOBAL_INVALID
},
diff --git a/doc/developer/frr-release-procedure.rst b/doc/developer/frr-release-procedure.rst
index 6a7f9c4ca9..4ef0ca8416 100644
--- a/doc/developer/frr-release-procedure.rst
+++ b/doc/developer/frr-release-procedure.rst
@@ -204,7 +204,7 @@ Stage 3 - Publish
.. code-block:: console
- cp <old-version>.md <version>.md
+ cp content/release/<old-version>.md content/release/<new-version>.md
Paste the GitHub release announcement text into this document, and **remove
line breaks**. In other words, this::
@@ -220,10 +220,17 @@ Stage 3 - Publish
This is very important otherwise the announcement will be unreadable on the
website.
- Make sure to add a link to the GitHub releases page at the top.
+ To get the number of commiters and commits, here is a couple of handy commands:
+
+ .. code-block:: console
- Once finished, manually add a new entry into ``index.html`` to link to this
- new announcement. Look at past commits to see how to do this.
+ # The number of commits
+ % git log --oneline --no-merges base_8.2...base_8.1 | wc -l
+
+ # The number of commiters
+ % git shortlog --summary --no-merges base_8.2...base_8.1 | wc -l
+
+ Make sure to add a link to the GitHub releases page at the top.
#. Deploy the updated ``frr-www`` on the frrouting.org web server and verify
that the announcement text is visible.
diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst
index 4e6fc04206..7046361204 100644
--- a/doc/developer/logging.rst
+++ b/doc/developer/logging.rst
@@ -163,6 +163,10 @@ Networking data types
- :c:union:`prefixptr` (dereference to get :c:struct:`prefix`)
- :c:union:`prefixconstptr` (dereference to get :c:struct:`prefix`)
+ Options:
+
+ ``%pFXh``: (address only) :frrfmtout:`1.2.3.0` / :frrfmtout:`fe80::1234`
+
.. frrfmt:: %pPSG4 (struct prefix_sg *)
:frrfmtout:`(*,1.2.3.4)`
diff --git a/doc/user/index.rst b/doc/user/index.rst
index cadf4cb9cf..5a018a5583 100644
--- a/doc/user/index.rst
+++ b/doc/user/index.rst
@@ -54,6 +54,7 @@ Protocols
ospf6d
pathd
pim
+ pimv6
pbr
ripd
ripngd
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst
index f7d42d8200..d2859670dd 100644
--- a/doc/user/isisd.rst
+++ b/doc/user/isisd.rst
@@ -272,7 +272,7 @@ ISIS interface
Showing ISIS information
========================
-.. clicmd:: show isis summary
+.. clicmd:: show isis [vrf <NAME|all>] summary [json]
Show summary information about ISIS.
@@ -280,17 +280,17 @@ Showing ISIS information
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.
diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst
new file mode 100644
index 0000000000..e71cf4631c
--- /dev/null
+++ b/doc/user/pimv6.rst
@@ -0,0 +1,288 @@
+.. _pimv6:
+
+*****
+PIMv6
+*****
+
+PIMv6 -- Protocol Independent Multicast for IPv6
+
+*pim6d* supports pim-sm as well as MLD v1 and v2. PIMv6 is
+vrf aware and can work within the context of vrf's in order to
+do S,G mrouting.
+
+.. _starting-and-stopping-pim6d:
+
+Starting and Stopping pim6d
+===========================
+
+The default configuration file name of *pim6d*'s is :file:`pim6d.conf`. When
+invoked *pim6d* searches directory |INSTALL_PREFIX_ETC|. If
+:file:`pim6d.conf` is not there then next search current directory.
+
+*pim6d* requires zebra for proper operation. Additionally *pim6d* depends on
+routing properly setup and working in the network that it is working on.
+
+::
+
+ # zebra -d
+ # pim6d -d
+
+
+Please note that *zebra* must be invoked before *pim6d*.
+
+To stop *pim6d* please use::
+
+ kill `cat /var/run/pim6d.pid`
+
+Certain signals have special meanings to *pim6d*.
+
++---------+---------------------------------------------------------------------+
+| Signal | Meaning |
++=========+=====================================================================+
+| SIGUSR1 | Rotate the *pim6d* logfile |
++---------+---------------------------------------------------------------------+
+| SIGINT | *pim6d* sweeps all installed PIM mroutes then terminates gracefully.|
+| SIGTERM | |
++---------+---------------------------------------------------------------------+
+
+*pim6d* invocation options. Common options that can be specified
+(:ref:`common-invocation-options`).
+
+.. clicmd:: ipv6 pim rp X:X::X:X Y:Y::Y:Y/M
+
+ In order to use pimv6, it is necessary to configure a RP for join messages to
+ be sent to. Currently the only methodology to do this is via static rp
+ commands. All routers in the pimv6 network must agree on these values. The
+ first ipv6 address is the RP's address and the second value is the matching
+ prefix of group ranges covered. This command is vrf aware, to configure for
+ a vrf, enter the vrf submode.
+
+.. clicmd:: ipv6 pim rp X:X::X:X prefix-list WORD
+
+ This CLI helps in configuring RP address for a range of groups specified
+ by the prefix-list.
+
+.. clicmd:: ipv6 pim rp keep-alive-timer (1-65535)
+
+ Modify the time out value for a S,G flow from 1-65535 seconds at RP.
+ The normal keepalive period for the KAT(S,G) defaults to 210 seconds.
+ However, at the RP, the keepalive period must be at least the
+ Register_Suppression_Time, or the RP may time out the (S,G) state
+ before the next Null-Register arrives. Thus, the KAT(S,G) is set to
+ max(Keepalive_Period, RP_Keepalive_Period) when a Register-Stop is sent.
+ If choosing a value below 31 seconds be aware that some hardware platforms
+ cannot see data flowing in better than 30 second chunks. This command is
+ vrf aware, to configure for a vrf, enter the vrf submode.
+
+.. clicmd:: ipv6 pim spt-switchover infinity-and-beyond [prefix-list PLIST]
+
+ On the last hop router if it is desired to not switch over to the SPT tree
+ configure this command. Optional parameter prefix-list can be use to control
+ which groups to switch or not switch. If a group is PERMIT as per the
+ PLIST, then the SPT switchover does not happen for it and if it is DENY,
+ then the SPT switchover happens.
+ This command is vrf aware, to configure for a vrf,
+ enter the vrf submode.
+
+.. clicmd:: ipv6 pim join-prune-interval (1-65535)
+
+ Modify the join/prune interval that pim uses to the new value. Time is
+ specified in seconds. This command is vrf aware, to configure for a vrf,
+ enter the vrf submode. The default time is 60 seconds. If you enter
+ a value smaller than 60 seconds be aware that this can and will affect
+ convergence at scale.
+
+.. clicmd:: ipv6 pim keep-alive-timer (1-65535)
+
+ Modify the time out value for a S,G flow from 1-65535 seconds. If choosing
+ a value below 31 seconds be aware that some hardware platforms cannot see data
+ flowing in better than 30 second chunks. This command is vrf aware, to
+ configure for a vrf, enter the vrf submode.
+
+.. clicmd:: ipv6 pim packets (1-255)
+
+ When processing packets from a neighbor process the number of packets
+ incoming at one time before moving on to the next task. The default value is
+ 3 packets. This command is only useful at scale when you can possibly have
+ a large number of pim control packets flowing. This command is vrf aware, to
+ configure for a vrf, enter the vrf submode.
+
+.. clicmd:: ipv6 pim register-suppress-time (1-65535)
+
+ Modify the time that pim will register suppress a FHR will send register
+ notifications to the kernel. This command is vrf aware, to configure for a
+ vrf, enter the vrf submode.
+
+.. _pimv6-interface-configuration:
+
+PIMv6 Interface Configuration
+=============================
+
+PIMv6 interface commands allow you to configure an interface as either a Receiver
+or a interface that you would like to form pimv6 neighbors on. If the interface
+is in a vrf, enter the interface command with the vrf keyword at the end.
+
+.. clicmd:: ipv6 pim active-active
+
+ Turn on pim active-active configuration for a Vxlan interface. This
+ command will not do anything if you do not have the underlying ability
+ of a mlag implementation.
+
+.. clicmd:: ipv6 pim drpriority (1-4294967295)
+
+ Set the DR Priority for the interface. This command is useful to allow the
+ user to influence what node becomes the DR for a lan segment.
+
+.. clicmd:: ipv6 pim hello (1-65535) (1-65535)
+
+ Set the pim hello and hold interval for a interface.
+
+.. clicmd:: ipv6 pim
+
+ Tell pim that we would like to use this interface to form pim neighbors
+ over. Please note that this command does not enable the reception of MLD
+ reports on the interface. Refer to the next ``ipv6 mld`` command for MLD
+ management.
+
+.. clicmd:: ipv6 pim use-source X:X::X:X
+
+ If you have multiple addresses configured on a particular interface
+ and would like pim to use a specific source address associated with
+ that interface.
+
+.. clicmd:: ipv6 mld
+
+ Tell pim to receive MLD reports and Query on this interface. The default
+ version is v2. This command is useful on a LHR.
+
+.. clicmd:: ipv6 mld join X:X::X:X [Y:Y::Y:Y]
+
+ Join multicast group or source-group on an interface.
+
+.. clicmd:: ipv6 mld query-interval (1-65535)
+
+ Set the MLD query interval that PIM will use.
+
+.. clicmd:: ipv6 mld query-max-response-time (1-65535)
+
+ Set the MLD query response timeout value. If an report is not returned in
+ the specified time we will assume the S,G or \*,G has timed out.
+
+.. clicmd:: ipv6 mld version (1-2)
+
+ Set the MLD version used on this interface. The default value is 2.
+
+.. clicmd:: ipv6 multicast boundary oil WORD
+
+ Set a PIMv6 multicast boundary, based upon the WORD prefix-list. If a PIMv6
+ join or MLD report is received on this interface and the Group is denied by
+ the prefix-list, PIMv6 will ignore the join or report.
+
+.. clicmd:: ipv6 mld last-member-query-count (1-255)
+
+ Set the MLD last member query count. The default value is 2. 'no' form of
+ this command is used to configure back to the default value.
+
+.. clicmd:: ipv6 MLD last-member-query-interval (1-65535)
+
+ Set the MLD last member query interval in deciseconds. The default value is
+ 10 deciseconds. 'no' form of this command is used to to configure back to the
+ default value.
+
+.. clicmd:: ipv6 mroute INTERFACE X:X::X:X [Y:Y::Y:Y]
+
+ Set a static multicast route for a traffic coming on the current interface to
+ be forwarded on the given interface if the traffic matches the group address
+ and optionally the source address.
+
+.. _show-pimv6-information:
+
+Show PIMv6 Information
+======================
+
+All PIMv6 show commands are vrf aware and typically allow you to insert a
+specified vrf command if information is desired about a specific vrf. If no
+vrf is specified then the default vrf is assumed. Finally the special keyword
+'all' allows you to look at all vrfs for the command. Naming a vrf 'all' will
+cause great confusion.
+
+.. clicmd:: show ipv6 pim [vrf NAME] group-type [json]
+
+ Display SSM group ranges.
+
+.. clicmd:: show ipv6 pim interface
+
+ Display information about interfaces PIM is using.
+
+.. clicmd:: show ipv6 pim [vrf NAME] join [X:X::X:X [X:X::X:X]] [json]
+.. clicmd:: show ipv6 pim vrf all join [json]
+
+ Display information about PIM joins received. If one address is specified
+ then we assume it is the Group we are interested in displaying data on.
+ If the second address is specified then it is Source Group.
+
+.. clicmd:: show ipv6 pim [vrf NAME] local-membership [json]
+
+ Display information about PIM interface local-membership.
+
+.. clicmd:: show ipv6 pim [vrf NAME] neighbor [detail|WORD] [json]
+.. clicmd:: show ipv6 pim vrf all neighbor [detail|WORD] [json]
+
+ Display information about PIM neighbors.
+
+.. clicmd:: show ipv6 pim [vrf NAME] nexthop
+
+ Display information about pim nexthops that are being used.
+
+.. clicmd:: show ipv6 pim [vrf NAME] nexthop-lookup X:X::X:X X:X::X:X
+
+ Display information about a S,G pair and how the RPF would be chosen. This
+ is especially useful if there are ECMP's available from the RPF lookup.
+
+.. clicmd:: show ipv6 pim [vrf NAME] rp-info [json]
+.. clicmd:: show ipv6 pim vrf all rp-info [json]
+
+ Display information about RP's that are configured on this router.
+
+.. clicmd:: show ipv6 pim [vrf NAME] rpf [json]
+.. clicmd:: show ipv6 pim vrf all rpf [json]
+
+ Display information about currently being used S,G's and their RPF lookup
+ information. Additionally display some statistics about what has been
+ happening on the router.
+
+.. clicmd:: show ipv6 pim [vrf NAME] secondary
+
+ Display information about an interface and all the secondary addresses
+ associated with it.
+
+.. clicmd:: show ipv6 pim [vrf NAME] state [X:X::X:X [X:X::X:X]] [json]
+.. clicmd:: show ipv6 pim vrf all state [X:X::X:X [X:X::X:X]] [json]
+
+ Display information about known S,G's and incoming interface as well as the
+ OIL and how they were chosen.
+
+.. clicmd:: show ipv6 pim [vrf NAME] upstream [X:X::X:X [Y:Y::Y:Y]] [json]
+.. clicmd:: show ipv6 pim vrf all upstream [json]
+
+ Display upstream information about a S,G mroute. Allow the user to
+ specify sub Source and Groups that we are interested in.
+
+.. clicmd:: show ipv6 pim [vrf NAME] upstream-join-desired [json]
+
+ Display upstream information for S,G's and if we desire to
+ join the multicast tree
+
+.. clicmd:: show ipv6 pim [vrf NAME] upstream-rpf [json]
+
+ Display upstream information for S,G's and the RPF data associated with them.
+
+PIMv6 Debug Commands
+====================
+
+The debugging subsystem for PIMv6 behaves in accordance with how FRR handles
+debugging. You can specify debugging at the enable CLI mode as well as the
+configure CLI mode. If you specify debug commands in the configuration cli
+mode, the debug commands can be persistent across restarts of the FRR pim6d if
+the config was written out.
+
diff --git a/doc/user/subdir.am b/doc/user/subdir.am
index 31158cb5f7..14ace2c856 100644
--- a/doc/user/subdir.am
+++ b/doc/user/subdir.am
@@ -30,6 +30,7 @@ user_RSTFILES = \
doc/user/packet-dumps.rst \
doc/user/pathd.rst \
doc/user/pim.rst \
+ doc/user/pimv6.rst \
doc/user/ripd.rst \
doc/user/pbr.rst \
doc/user/ripngd.rst \
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 06909c4306..2729dce382 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -464,6 +464,220 @@ void isis_adj_expire(struct thread *thread)
}
/*
+ * 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]
*/
void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h
index 4d84c5ca4d..7467a619cb 100644
--- a/isisd/isis_adjacency.h
+++ b/isisd/isis_adjacency.h
@@ -144,6 +144,8 @@ const char *isis_adj_yang_state(enum isis_adj_state state);
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);
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 1b0447226d..da75f196ba 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -933,6 +933,151 @@ void circuit_update_nlpids(struct isis_circuit *circuit)
return;
}
+void isis_circuit_print_json(struct isis_circuit *circuit,
+ struct json_object *json, char detail)
+{
+ int level;
+ json_object *iface_json, *ipv4_addr_json, *ipv6_link_json,
+ *ipv6_non_link_json, *hold_json, *lan_prio_json, *levels_json,
+ *level_json;
+ char buf_prx[INET6_BUFSIZ];
+ char buf[255];
+
+ snprintfrr(buf, sizeof(buf), "0x%x", circuit->circuit_id);
+ if (detail == ISIS_UI_LEVEL_BRIEF) {
+ iface_json = json_object_new_object();
+ json_object_object_add(json, "interface", iface_json);
+ json_object_string_add(iface_json, "name",
+ circuit->interface->name);
+ json_object_string_add(iface_json, "circuit-id", buf);
+ json_object_string_add(iface_json, "state",
+ circuit_state2string(circuit->state));
+ json_object_string_add(iface_json, "type",
+ circuit_type2string(circuit->circ_type));
+ json_object_string_add(iface_json, "level",
+ circuit_t2string(circuit->is_type));
+ }
+
+ if (detail == ISIS_UI_LEVEL_DETAIL) {
+ struct listnode *node;
+ struct prefix *ip_addr;
+
+ iface_json = json_object_new_object();
+ json_object_object_add(json, "interface", iface_json);
+ json_object_string_add(iface_json, "name",
+ circuit->interface->name);
+ json_object_string_add(iface_json, "state",
+ circuit_state2string(circuit->state));
+ if (circuit->is_passive)
+ json_object_string_add(iface_json, "is-passive",
+ "passive");
+ else
+ json_object_string_add(iface_json, "is-passive",
+ "active");
+ json_object_string_add(iface_json, "circuit-id", buf);
+ json_object_string_add(iface_json, "type",
+ circuit_type2string(circuit->circ_type));
+ json_object_string_add(iface_json, "level",
+ circuit_t2string(circuit->is_type));
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ json_object_string_add(iface_json, "snpa",
+ snpa_print(circuit->u.bc.snpa));
+
+
+ levels_json = json_object_new_array();
+ json_object_object_add(iface_json, "levels", levels_json);
+ for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
+ if ((circuit->is_type & level) == 0)
+ continue;
+ level_json = json_object_new_object();
+ json_object_string_add(level_json, "level",
+ circuit_t2string(level));
+ if (circuit->area->newmetric)
+ json_object_int_add(level_json, "metric",
+ circuit->te_metric[0]);
+ else
+ json_object_int_add(level_json, "metric",
+ circuit->metric[0]);
+ if (!circuit->is_passive) {
+ json_object_int_add(level_json,
+ "active-neighbors",
+ circuit->upadjcount[0]);
+ json_object_int_add(level_json,
+ "hello-interval",
+ circuit->hello_interval[0]);
+ hold_json = json_object_new_object();
+ json_object_object_add(level_json, "holddown",
+ hold_json);
+ json_object_int_add(
+ hold_json, "count",
+ circuit->hello_multiplier[0]);
+ json_object_string_add(
+ hold_json, "pad",
+ (circuit->pad_hellos ? "yes" : "no"));
+ json_object_int_add(level_json, "cnsp-interval",
+ circuit->csnp_interval[0]);
+ json_object_int_add(level_json, "psnp-interval",
+ circuit->psnp_interval[0]);
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ lan_prio_json =
+ json_object_new_object();
+ json_object_object_add(level_json,
+ "lan",
+ lan_prio_json);
+ json_object_int_add(
+ lan_prio_json, "priority",
+ circuit->priority[0]);
+ json_object_string_add(
+ lan_prio_json, "is-dis",
+ (circuit->u.bc.is_dr[0]
+ ? "yes"
+ : "no"));
+ }
+ }
+ json_object_array_add(levels_json, level_json);
+ }
+
+ if (circuit->ip_addrs && listcount(circuit->ip_addrs) > 0) {
+ ipv4_addr_json = json_object_new_object();
+ json_object_object_add(iface_json, "ip-prefix",
+ ipv4_addr_json);
+ for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node,
+ ip_addr)) {
+ snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX",
+ ip_addr);
+ json_object_string_add(ipv4_addr_json, "ip",
+ buf_prx);
+ }
+ }
+ if (circuit->ipv6_link && listcount(circuit->ipv6_link) > 0) {
+ ipv6_link_json = json_object_new_object();
+ json_object_object_add(iface_json, "ipv6-link-locals",
+ ipv6_link_json);
+ for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node,
+ ip_addr)) {
+ snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX",
+ ip_addr);
+ json_object_string_add(ipv6_link_json, "ipv6",
+ buf_prx);
+ }
+ }
+ if (circuit->ipv6_non_link &&
+ listcount(circuit->ipv6_non_link) > 0) {
+ ipv6_non_link_json = json_object_new_object();
+ json_object_object_add(iface_json, "ipv6-prefixes",
+ ipv6_non_link_json);
+ for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node,
+ ip_addr)) {
+ snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX",
+ ip_addr);
+ json_object_string_add(ipv6_non_link_json,
+ "ipv6", buf_prx);
+ }
+ }
+ }
+ return;
+}
+
void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty,
char detail)
{
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index 7465780848..5ff0390c26 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -206,6 +206,8 @@ void isis_circuit_down(struct isis_circuit *);
void circuit_update_nlpids(struct isis_circuit *circuit);
void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty,
char detail);
+void isis_circuit_print_json(struct isis_circuit *circuit,
+ struct json_object *json, char detail);
size_t isis_circuit_pdu_size(struct isis_circuit *circuit);
void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream);
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 463d26f6c7..eb7e9e725e 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -733,8 +733,48 @@ static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size)
}
/* 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];
@@ -754,30 +794,40 @@ void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost,
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 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
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;
}
diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h
index f42d702b37..b13b2a35e6 100644
--- a/isisd/isis_lsp.h
+++ b/isisd/isis_lsp.h
@@ -120,12 +120,19 @@ void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
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 --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 517c9ec5aa..1a54d47f3c 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -2209,7 +2209,7 @@ int send_csnp(struct isis_circuit *circuit, int level)
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),
@@ -2368,7 +2368,7 @@ static int send_psnp(int level, struct isis_circuit *circuit)
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),
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 04b5cf1a67..d5b02f3881 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -2683,3 +2683,15 @@ void isis_spf_print(struct isis_spftree *spftree, struct vty *vty)
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);
+}
diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h
index 5b3aa59379..815db7b226 100644
--- a/isisd/isis_spf.h
+++ b/isisd/isis_spf.h
@@ -75,6 +75,8 @@ void isis_print_routes(struct vty *vty, struct isis_spftree *spftree,
bool prefix_sid, bool backup);
void isis_spf_init(void);
void isis_spf_print(struct isis_spftree *spftree, struct vty *vty);
+void isis_spf_print_json(struct isis_spftree *spftree,
+ struct json_object *json);
void isis_run_spf(struct isis_spftree *spftree);
struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
uint8_t *sysid,
diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
index f1aae7caf1..d3d59fb435 100644
--- a/isisd/isis_tlvs.c
+++ b/isisd/isis_tlvs.c
@@ -22,6 +22,7 @@
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
+#include <json-c/json_object.h>
#include <zebra.h>
#ifdef CRYPTO_INTERNAL
@@ -57,7 +58,8 @@ typedef void (*free_item_func)(struct isis_item *i);
typedef int (*unpack_item_func)(uint16_t mtid, uint8_t len, struct stream *s,
struct sbuf *log, void *dest, int indent);
typedef void (*format_item_func)(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent);
+ struct sbuf *buf, struct json_object *json,
+ int indent);
typedef struct isis_item *(*copy_item_func)(struct isis_item *i);
struct tlv_ops {
@@ -208,152 +210,430 @@ copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid)
/* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
- struct sbuf *buf, int indent,
- uint16_t mtid)
+ struct sbuf *buf, struct json_object *json,
+ int indent, uint16_t mtid)
{
+ char aux_buf[255];
+ char cnt_buf[255];
/* Standard metrics */
- if (IS_SUBTLV(exts, EXT_ADM_GRP))
- sbuf_push(buf, indent, "Administrative Group: 0x%x\n",
- exts->adm_group);
+ if (IS_SUBTLV(exts, EXT_ADM_GRP)) {
+ if (json) {
+ snprintfrr(aux_buf, sizeof(aux_buf), "0x%x",
+ exts->adm_group);
+ json_object_string_add(json, "adm-group", aux_buf);
+ } else
+ sbuf_push(buf, indent, "Administrative Group: 0x%x\n",
+ exts->adm_group);
+ }
if (IS_SUBTLV(exts, EXT_LLRI)) {
- sbuf_push(buf, indent, "Link Local ID: %u\n",
- exts->local_llri);
- sbuf_push(buf, indent, "Link Remote ID: %u\n",
- exts->remote_llri);
- }
- if (IS_SUBTLV(exts, EXT_LOCAL_ADDR))
- sbuf_push(buf, indent, "Local Interface IP Address(es): %pI4\n",
- &exts->local_addr);
- if (IS_SUBTLV(exts, EXT_NEIGH_ADDR))
- sbuf_push(buf, indent,
- "Remote Interface IP Address(es): %pI4\n",
- &exts->neigh_addr);
- if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6))
- sbuf_push(buf, indent,
- "Local Interface IPv6 Address(es): %pI6\n",
- &exts->local_addr6);
- if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6))
- sbuf_push(buf, indent,
- "Remote Interface IPv6 Address(es): %pI6\n",
- &exts->neigh_addr6);
- if (IS_SUBTLV(exts, EXT_MAX_BW))
- sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n",
- exts->max_bw);
- if (IS_SUBTLV(exts, EXT_MAX_RSV_BW))
- sbuf_push(buf, indent,
- "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
- exts->max_rsv_bw);
+ if (json) {
+ json_object_int_add(json, "link-local-id",
+ exts->local_llri);
+ json_object_int_add(json, "link-remote-id",
+ exts->remote_llri);
+ } else {
+ sbuf_push(buf, indent, "Link Local ID: %u\n",
+ exts->local_llri);
+ sbuf_push(buf, indent, "Link Remote ID: %u\n",
+ exts->remote_llri);
+ }
+ }
+ if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) {
+ if (json) {
+ inet_ntop(AF_INET, &exts->local_addr, aux_buf,
+ sizeof(aux_buf));
+ json_object_string_add(json, "local-iface-ip", aux_buf);
+ } else
+ sbuf_push(buf, indent,
+ "Local Interface IP Address(es): %pI4\n",
+ &exts->local_addr);
+ }
+ if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) {
+ if (json) {
+ inet_ntop(AF_INET, &exts->neigh_addr, aux_buf,
+ sizeof(aux_buf));
+ json_object_string_add(json, "remote-iface-ip",
+ aux_buf);
+ } else
+ sbuf_push(buf, indent,
+ "Remote Interface IP Address(es): %pI4\n",
+ &exts->neigh_addr);
+ }
+ if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) {
+ if (json) {
+ inet_ntop(AF_INET6, &exts->local_addr6, aux_buf,
+ sizeof(aux_buf));
+ json_object_string_add(json, "local-iface-ipv6",
+ aux_buf);
+ } else
+ sbuf_push(buf, indent,
+ "Local Interface IPv6 Address(es): %pI6\n",
+ &exts->local_addr6);
+ }
+ if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) {
+ if (json) {
+ inet_ntop(AF_INET6, &exts->neigh_addr6, aux_buf,
+ sizeof(aux_buf));
+ json_object_string_add(json, "remote-iface-ipv6",
+ aux_buf);
+ } else
+ sbuf_push(buf, indent,
+ "Remote Interface IPv6 Address(es): %pI6\n",
+ &exts->neigh_addr6);
+ }
+ if (IS_SUBTLV(exts, EXT_MAX_BW)) {
+ if (json) {
+ snprintfrr(aux_buf, sizeof(aux_buf), "%g",
+ exts->max_bw);
+ json_object_string_add(json, "max-bandwith-bytes-sec",
+ aux_buf);
+ } else
+ sbuf_push(buf, indent,
+ "Maximum Bandwidth: %g (Bytes/sec)\n",
+ exts->max_bw);
+ }
+ if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) {
+ if (json) {
+ snprintfrr(aux_buf, sizeof(aux_buf), "%g",
+ exts->max_rsv_bw);
+ json_object_string_add(
+ json, "max-res-bandwith-bytes-sec", aux_buf);
+ } else
+ sbuf_push(
+ buf, indent,
+ "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
+ exts->max_rsv_bw);
+ }
if (IS_SUBTLV(exts, EXT_UNRSV_BW)) {
- sbuf_push(buf, indent, "Unreserved Bandwidth:\n");
- for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
- sbuf_push(buf, indent + 2,
- "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
- j, exts->unrsv_bw[j],
- j + 1, exts->unrsv_bw[j + 1]);
+ if (json) {
+ struct json_object *unrsv_json;
+ unrsv_json = json_object_new_object();
+ json_object_object_add(json, "unrsv-bandwith-bytes-sec",
+ unrsv_json);
+ for (int j = 0; j < MAX_CLASS_TYPE; j += 1) {
+ snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", j);
+ snprintfrr(aux_buf, sizeof(aux_buf), "%g",
+ exts->unrsv_bw[j]);
+ json_object_string_add(unrsv_json, cnt_buf,
+ aux_buf);
+ }
+ } else {
+ sbuf_push(buf, indent, "Unreserved Bandwidth:\n");
+ for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
+ sbuf_push(
+ buf, indent + 2,
+ "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
+ j, exts->unrsv_bw[j], j + 1,
+ exts->unrsv_bw[j + 1]);
+ }
}
}
- if (IS_SUBTLV(exts, EXT_TE_METRIC))
- sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n",
- exts->te_metric);
- if (IS_SUBTLV(exts, EXT_RMT_AS))
- sbuf_push(buf, indent,
- "Inter-AS TE Remote AS number: %u\n",
- exts->remote_as);
- if (IS_SUBTLV(exts, EXT_RMT_IP))
- sbuf_push(buf, indent,
- "Inter-AS TE Remote ASBR IP address: %pI4\n",
- &exts->remote_ip);
+ if (IS_SUBTLV(exts, EXT_TE_METRIC)) {
+ if (json) {
+ json_object_int_add(json, "te-metric", exts->te_metric);
+ } else
+ sbuf_push(buf, indent,
+ "Traffic Engineering Metric: %u\n",
+ exts->te_metric);
+ }
+ if (IS_SUBTLV(exts, EXT_RMT_AS)) {
+ if (json) {
+ json_object_int_add(json, "inter-as-te-remote-as",
+ exts->remote_as);
+ } else
+ sbuf_push(buf, indent,
+ "Inter-AS TE Remote AS number: %u\n",
+ exts->remote_as);
+ }
+ if (IS_SUBTLV(exts, EXT_RMT_IP)) {
+ if (json) {
+ inet_ntop(AF_INET6, &exts->remote_ip, aux_buf,
+ sizeof(aux_buf));
+ json_object_string_add(
+ json, "inter-as-te-remote-asbr-ip", aux_buf);
+ } else
+ sbuf_push(buf, indent,
+ "Inter-AS TE Remote ASBR IP address: %pI4\n",
+ &exts->remote_ip);
+ }
/* Extended metrics */
- if (IS_SUBTLV(exts, EXT_DELAY))
- sbuf_push(buf, indent,
- "%s Average Link Delay: %u (micro-sec)\n",
- IS_ANORMAL(exts->delay) ? "Anomalous" : "Normal",
- exts->delay);
+ if (IS_SUBTLV(exts, EXT_DELAY)) {
+ if (json) {
+ struct json_object *avg_json;
+ avg_json = json_object_new_object();
+ json_object_object_add(json, "avg-delay", avg_json);
+ json_object_string_add(avg_json, "delay",
+ IS_ANORMAL(exts->delay)
+ ? "Anomalous"
+ : "Normal");
+ json_object_int_add(avg_json, "micro-sec", exts->delay);
+ } else
+ sbuf_push(buf, indent,
+ "%s Average Link Delay: %u (micro-sec)\n",
+ IS_ANORMAL(exts->delay) ? "Anomalous"
+ : "Normal",
+ exts->delay);
+ }
if (IS_SUBTLV(exts, EXT_MM_DELAY)) {
- sbuf_push(buf, indent, "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
- IS_ANORMAL(exts->min_delay) ? "Anomalous" : "Normal",
- exts->min_delay & TE_EXT_MASK,
- exts->max_delay & TE_EXT_MASK);
+ if (json) {
+ struct json_object *avg_json;
+ avg_json = json_object_new_object();
+ json_object_object_add(json, "max-min-delay", avg_json);
+ json_object_string_add(avg_json, "delay",
+ IS_ANORMAL(exts->min_delay)
+ ? "Anomalous"
+ : "Normal");
+ snprintfrr(aux_buf, sizeof(aux_buf), "%u / %u",
+ exts->min_delay & TE_EXT_MASK,
+ exts->max_delay & TE_EXT_MASK);
+ json_object_string_add(avg_json, "micro-sec", aux_buf);
+
+ } else
+ sbuf_push(
+ buf, indent,
+ "%s Min/Max Link Delay: %u / %u (micro-sec)\n",
+ IS_ANORMAL(exts->min_delay) ? "Anomalous"
+ : "Normal",
+ exts->min_delay & TE_EXT_MASK,
+ exts->max_delay & TE_EXT_MASK);
}
if (IS_SUBTLV(exts, EXT_DELAY_VAR)) {
- sbuf_push(buf, indent,
- "Delay Variation: %u (micro-sec)\n",
- exts->delay_var & TE_EXT_MASK);
- }
- if (IS_SUBTLV(exts, EXT_PKT_LOSS))
- sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n",
- IS_ANORMAL(exts->pkt_loss) ? "Anomalous" : "Normal",
- (float)((exts->pkt_loss & TE_EXT_MASK)
- * LOSS_PRECISION));
- if (IS_SUBTLV(exts, EXT_RES_BW))
- sbuf_push(buf, indent,
- "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
- exts->res_bw);
- if (IS_SUBTLV(exts, EXT_AVA_BW))
- sbuf_push(buf, indent,
- "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
- exts->ava_bw);
- if (IS_SUBTLV(exts, EXT_USE_BW))
- sbuf_push(buf, indent,
- "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
- exts->use_bw);
+ if (json) {
+ json_object_int_add(json, "delay-variation-micro-sec",
+ exts->delay_var & TE_EXT_MASK);
+ } else
+ sbuf_push(buf, indent,
+ "Delay Variation: %u (micro-sec)\n",
+ exts->delay_var & TE_EXT_MASK);
+ }
+ if (IS_SUBTLV(exts, EXT_PKT_LOSS)) {
+ if (json) {
+ snprintfrr(aux_buf, sizeof(aux_buf), "%g",
+ (float)((exts->pkt_loss & TE_EXT_MASK) *
+ LOSS_PRECISION));
+ struct json_object *link_json;
+ link_json = json_object_new_object();
+ json_object_object_add(json, "link-packet-loss",
+ link_json);
+ json_object_string_add(link_json, "loss",
+ IS_ANORMAL(exts->pkt_loss)
+ ? "Anomalous"
+ : "Normal");
+ json_object_string_add(link_json, "percentaje",
+ aux_buf);
+ } else
+ sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n",
+ IS_ANORMAL(exts->pkt_loss) ? "Anomalous"
+ : "Normal",
+ (float)((exts->pkt_loss & TE_EXT_MASK) *
+ LOSS_PRECISION));
+ }
+ if (IS_SUBTLV(exts, EXT_RES_BW)) {
+ if (json) {
+ snprintfrr(aux_buf, sizeof(aux_buf), "%g",
+ (exts->res_bw));
+ json_object_string_add(json,
+ "unidir-residual-band-bytes-sec",
+ aux_buf);
+ } else
+ sbuf_push(
+ buf, indent,
+ "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
+ exts->res_bw);
+ }
+ if (IS_SUBTLV(exts, EXT_AVA_BW)) {
+ if (json) {
+ snprintfrr(aux_buf, sizeof(aux_buf), "%g",
+ (exts->ava_bw));
+ json_object_string_add(
+ json, "unidir-available-band-bytes-sec",
+ aux_buf);
+ } else
+ sbuf_push(
+ buf, indent,
+ "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
+ exts->ava_bw);
+ }
+ if (IS_SUBTLV(exts, EXT_USE_BW)) {
+ if (json) {
+ snprintfrr(aux_buf, sizeof(aux_buf), "%g",
+ (exts->use_bw));
+ json_object_string_add(json,
+ "unidir-utilized-band-bytes-sec",
+ aux_buf);
+ } else
+ sbuf_push(
+ buf, indent,
+ "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
+ exts->use_bw);
+ }
/* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
struct isis_adj_sid *adj;
- for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj;
- adj = adj->next) {
- sbuf_push(
- buf, indent,
- "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
- adj->sid, adj->weight,
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? '1'
- : '0',
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? '1'
- : '0',
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? '1'
- : '0',
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? '1'
- : '0',
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? '1'
- : '0',
- adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
- ? '1'
- : '0');
- }
+ if (json) {
+ struct json_object *arr_adj_json, *flags_json;
+ arr_adj_json = json_object_new_array();
+ json_object_object_add(json, "adj-sid", arr_adj_json);
+ for (adj = (struct isis_adj_sid *)exts->adj_sid.head;
+ adj; adj = adj->next) {
+ snprintfrr(cnt_buf, sizeof(cnt_buf), "%d",
+ adj->sid);
+ flags_json = json_object_new_object();
+ json_object_int_add(flags_json, "sid",
+ adj->sid);
+ json_object_int_add(flags_json, "weight",
+ adj->weight);
+ json_object_string_add(
+ flags_json, "flag-f",
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
+ ? "1"
+ : "0");
+ json_object_string_add(
+ flags_json, "flag-b",
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
+ ? "1"
+ : "0");
+ json_object_string_add(
+ flags_json, "flag-v",
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
+ ? "1"
+ : "0");
+ json_object_string_add(
+ flags_json, "flag-l",
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
+ ? "1"
+ : "0");
+ json_object_string_add(
+ flags_json, "flag-s",
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
+ ? "1"
+ : "0");
+ json_object_string_add(
+ flags_json, "flag-p",
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
+ ? "1"
+ : "0");
+ json_object_array_add(arr_adj_json, flags_json);
+ }
+ } else
+ for (adj = (struct isis_adj_sid *)exts->adj_sid.head;
+ adj; adj = adj->next) {
+ sbuf_push(
+ buf, indent,
+ "Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
+ adj->sid, adj->weight,
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
+ ? '1'
+ : '0',
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
+ ? '1'
+ : '0',
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
+ ? '1'
+ : '0',
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
+ ? '1'
+ : '0',
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
+ ? '1'
+ : '0',
+ adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
+ ? '1'
+ : '0');
+ }
}
/* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
struct isis_lan_adj_sid *lan;
-
- for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head;
- lan; lan = lan->next) {
- continue;
- sbuf_push(buf, indent,
- "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
- " Neighbor-ID: %s\n",
- lan->sid, lan->weight,
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
- ? '1'
- : '0',
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
- ? '1'
- : '0',
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
- ? '1'
- : '0',
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
- ? '1'
- : '0',
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
- ? '1'
- : '0',
- lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
- ? '1'
- : '0',
- isis_format_id(lan->neighbor_id, 6));
- }
+ if (json) {
+ struct json_object *arr_adj_json, *flags_json;
+ arr_adj_json = json_object_new_array();
+ json_object_object_add(json, "lan-adj-sid",
+ arr_adj_json);
+ for (lan = (struct isis_lan_adj_sid *)
+ exts->adj_sid.head;
+ lan; lan = lan->next) {
+ if (((mtid == ISIS_MT_IPV4_UNICAST) &&
+ (lan->family != AF_INET)) ||
+ ((mtid == ISIS_MT_IPV6_UNICAST) &&
+ (lan->family != AF_INET6)))
+ continue;
+ snprintfrr(cnt_buf, sizeof(cnt_buf), "%d",
+ lan->sid);
+ flags_json = json_object_new_object();
+ json_object_int_add(flags_json, "sid",
+ lan->sid);
+ json_object_int_add(flags_json, "weight",
+ lan->weight);
+ json_object_string_add(
+ flags_json, "flag-f",
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
+ ? "1"
+ : "0");
+ json_object_string_add(
+ flags_json, "flag-b",
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
+ ? "1"
+ : "0");
+ json_object_string_add(
+ flags_json, "flag-v",
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
+ ? "1"
+ : "0");
+ json_object_string_add(
+ flags_json, "flag-l",
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
+ ? "1"
+ : "0");
+ json_object_string_add(
+ flags_json, "flag-s",
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
+ ? "1"
+ : "0");
+ json_object_string_add(
+ flags_json, "flag-p",
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
+ ? "1"
+ : "0");
+ json_object_array_add(arr_adj_json, flags_json);
+ }
+ } else
+
+ for (lan = (struct isis_lan_adj_sid *)
+ exts->lan_sid.head;
+ lan; lan = lan->next) {
+ if (((mtid == ISIS_MT_IPV4_UNICAST) &&
+ (lan->family != AF_INET)) ||
+ ((mtid == ISIS_MT_IPV6_UNICAST) &&
+ (lan->family != AF_INET6)))
+ continue;
+ sbuf_push(
+ buf, indent,
+ "Lan-Adjacency-SID: %u, Weight: %hhu, Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
+ " Neighbor-ID: %s\n",
+ lan->sid, lan->weight,
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
+ ? '1'
+ : '0',
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
+ ? '1'
+ : '0',
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
+ ? '1'
+ : '0',
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
+ ? '1'
+ : '0',
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
+ ? '1'
+ : '0',
+ lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
+ ? '1'
+ : '0',
+ isis_format_id(lan->neighbor_id, 6));
+ }
}
}
@@ -880,26 +1160,64 @@ static struct isis_item *copy_item_prefix_sid(struct isis_item *i)
}
static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf, struct json_object *json,
+ int indent)
{
struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
- sbuf_push(buf, indent, "SR Prefix-SID ");
- if (sid->flags & ISIS_PREFIX_SID_VALUE) {
- sbuf_push(buf, 0, "Label: %u, ", sid->value);
+ if (json) {
+ struct json_object *sr_json;
+ sr_json = json_object_new_object();
+ json_object_object_add(json, "sr", sr_json);
+ if (sid->flags & ISIS_PREFIX_SID_VALUE) {
+ json_object_int_add(sr_json, "label", sid->value);
+ } else {
+ json_object_int_add(sr_json, "index", sid->value);
+ }
+ json_object_int_add(sr_json, "alg", sid->algorithm);
+ json_object_string_add(
+ sr_json, "readvertised",
+ ((sid->flags & ISIS_PREFIX_SID_READVERTISED) ? "yes"
+ : ""));
+ json_object_string_add(
+ sr_json, "node",
+ ((sid->flags & ISIS_PREFIX_SID_NODE) ? "yes" : ""));
+ json_object_string_add(sr_json, "php",
+ ((sid->flags & ISIS_PREFIX_SID_NO_PHP)
+ ? "no-php"
+ : "php"));
+ json_object_string_add(
+ sr_json, "explicit-null",
+ ((sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL) ? "yes"
+ : ""));
+ json_object_string_add(
+ sr_json, "value",
+ ((sid->flags & ISIS_PREFIX_SID_VALUE) ? "yes" : ""));
+ json_object_string_add(
+ sr_json, "local",
+ ((sid->flags & ISIS_PREFIX_SID_LOCAL) ? "yes" : ""));
+
} else {
- sbuf_push(buf, 0, "Index: %u, ", sid->value);
+ sbuf_push(buf, indent, "SR Prefix-SID ");
+ if (sid->flags & ISIS_PREFIX_SID_VALUE) {
+ sbuf_push(buf, 0, "Label: %u, ", sid->value);
+ } else {
+ sbuf_push(buf, 0, "Index: %u, ", sid->value);
+ }
+ sbuf_push(buf, 0, "Algorithm: %hhu, ", sid->algorithm);
+ sbuf_push(buf, 0, "Flags:%s%s%s%s%s%s\n",
+ sid->flags & ISIS_PREFIX_SID_READVERTISED
+ ? " READVERTISED"
+ : "",
+ sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "",
+ sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO-PHP"
+ : " PHP",
+ sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL
+ ? " EXPLICIT-NULL"
+ : "",
+ sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "",
+ sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : "");
}
- sbuf_push(buf, 0, "Algorithm: %hhu, ", sid->algorithm);
- sbuf_push(buf, 0, "Flags:%s%s%s%s%s%s\n",
- sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED"
- : "",
- sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "",
- sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO-PHP" : " PHP",
- sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL"
- : "",
- sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "",
- sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : "");
}
static void free_item_prefix_sid(struct isis_item *i)
@@ -977,7 +1295,7 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
sid.value = stream_getl(s);
}
- format_item_prefix_sid(mtid, (struct isis_item *)&sid, log, indent + 2);
+ format_item_prefix_sid(mtid, (struct isis_item *)&sid, log, NULL, indent + 2);
append_item(&subtlvs->prefix_sids, copy_item_prefix_sid((struct isis_item *)&sid));
return 0;
}
@@ -997,14 +1315,21 @@ static struct prefix_ipv6 *copy_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p)
}
static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
- struct sbuf *buf, int indent)
+ struct sbuf *buf,
+ struct json_object *json,
+ int indent)
{
if (!p)
return;
char prefixbuf[PREFIX2STR_BUFFER];
- sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n",
- prefix2str(p, prefixbuf, sizeof(prefixbuf)));
+ if (json) {
+ prefix2str(p, prefixbuf, sizeof(prefixbuf));
+ json_object_string_add(json, "ipv6-src-prefix", prefixbuf);
+ } else {
+ sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n",
+ prefix2str(p, prefixbuf, sizeof(prefixbuf)));
+ }
}
static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
@@ -1080,7 +1405,8 @@ static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
struct isis_item_list *src, struct isis_item_list *dest);
static void format_items_(uint16_t mtid, enum isis_tlv_context context,
enum isis_tlv_type type, struct isis_item_list *items,
- struct sbuf *buf, int indent);
+ struct sbuf *buf, struct json_object *json,
+ int indent);
#define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
struct isis_item_list *items);
@@ -1124,12 +1450,12 @@ static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs)
}
static void format_subtlvs(struct isis_subtlvs *subtlvs, struct sbuf *buf,
- int indent)
+ struct json_object *json, int indent)
{
format_items(subtlvs->context, ISIS_SUBTLV_PREFIX_SID,
- &subtlvs->prefix_sids, buf, indent);
+ &subtlvs->prefix_sids, buf, json, indent);
- format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, indent);
+ format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, json, indent);
}
static void isis_free_subtlvs(struct isis_subtlvs *subtlvs)
@@ -1189,12 +1515,18 @@ static struct isis_item *copy_item_area_address(struct isis_item *i)
}
static void format_item_area_address(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf, struct json_object *json,
+ int indent)
{
struct isis_area_address *addr = (struct isis_area_address *)i;
- sbuf_push(buf, indent, "Area Address: %s\n",
- isonet_print(addr->addr, addr->len));
+ if (json) {
+ json_object_string_add(json, "area-addr",
+ isonet_print(addr->addr, addr->len));
+ } else {
+ sbuf_push(buf, indent, "Area Address: %s\n",
+ isonet_print(addr->addr, addr->len));
+ }
}
static void free_item_area_address(struct isis_item *i)
@@ -1251,7 +1583,7 @@ static int unpack_item_area_address(uint16_t mtid, uint8_t len,
stream_get(rv->addr, s, rv->len);
format_item_area_address(ISIS_MT_IPV4_UNICAST, (struct isis_item *)rv,
- log, indent + 2);
+ log, NULL, indent + 2);
append_item(&tlvs->area_addresses, (struct isis_item *)rv);
return 0;
out:
@@ -1271,12 +1603,21 @@ static struct isis_item *copy_item_oldstyle_reach(struct isis_item *i)
}
static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf,
+ struct json_object *json, int indent)
{
struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
- sbuf_push(buf, indent, "IS Reachability: %s (Metric: %hhu)\n",
- isis_format_id(r->id, 7), r->metric);
+ if (json) {
+ struct json_object *old_json;
+ old_json = json_object_new_object();
+ json_object_object_add(json, "old-reach-style", old_json);
+ json_object_string_add(old_json, "is-reach",
+ isis_format_id(r->id, 7));
+ json_object_int_add(old_json, "metric", r->metric);
+ } else
+ sbuf_push(buf, indent, "IS Reachability: %s (Metric: %hhu)\n",
+ isis_format_id(r->id, 7), r->metric);
}
static void free_item_oldstyle_reach(struct isis_item *i)
@@ -1327,7 +1668,7 @@ static int unpack_item_oldstyle_reach(uint16_t mtid, uint8_t len,
stream_forward_getp(s, 3); /* Skip other metrics */
stream_get(rv->id, s, 7);
- format_item_oldstyle_reach(mtid, (struct isis_item *)rv, log,
+ format_item_oldstyle_reach(mtid, (struct isis_item *)rv, log, NULL,
indent + 2);
append_item(&tlvs->oldstyle_reach, (struct isis_item *)rv);
return 0;
@@ -1344,11 +1685,17 @@ static struct isis_item *copy_item_lan_neighbor(struct isis_item *i)
}
static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf, struct json_object *json,
+ int indent)
{
struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
- sbuf_push(buf, indent, "LAN Neighbor: %s\n", isis_format_id(n->mac, 6));
+ if (json) {
+ json_object_string_add(json, "lan-neighbor",
+ isis_format_id(n->mac, 6));
+ } else
+ sbuf_push(buf, indent, "LAN Neighbor: %s\n",
+ isis_format_id(n->mac, 6));
}
static void free_item_lan_neighbor(struct isis_item *i)
@@ -1389,7 +1736,7 @@ static int unpack_item_lan_neighbor(uint16_t mtid, uint8_t len,
struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
stream_get(rv->mac, s, 6);
- format_item_lan_neighbor(mtid, (struct isis_item *)rv, log, indent + 2);
+ format_item_lan_neighbor(mtid, (struct isis_item *)rv, log, NULL, indent + 2);
append_item(&tlvs->lan_neighbor, (struct isis_item *)rv);
return 0;
}
@@ -1409,10 +1756,23 @@ static struct isis_item *copy_item_lsp_entry(struct isis_item *i)
}
static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf, struct json_object *json,
+ int indent)
{
struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
+ if (json) {
+ char buf[255];
+ struct json_object *lsp_json;
+ lsp_json = json_object_new_object();
+ json_object_object_add(json, "lsp-entry", lsp_json);
+ json_object_string_add(lsp_json, "id", isis_format_id(e->id, 8));
+ snprintfrr(buf,sizeof(buf),"0x%08x",e->seqno);
+ json_object_string_add(lsp_json, "seq", buf);
+ snprintfrr(buf,sizeof(buf),"0x%04hx",e->checksum);
+ json_object_string_add(lsp_json, "chksum", buf);
+ json_object_int_add(lsp_json, "lifetime", e->checksum);
+ } else
sbuf_push(buf, indent,
"LSP Entry: %s, seq 0x%08x, cksum 0x%04hx, lifetime %hus\n",
isis_format_id(e->id, 8), e->seqno, e->checksum,
@@ -1462,7 +1822,7 @@ static int unpack_item_lsp_entry(uint16_t mtid, uint8_t len, struct stream *s,
rv->seqno = stream_getl(s);
rv->checksum = stream_getw(s);
- format_item_lsp_entry(mtid, (struct isis_item *)rv, log, indent + 2);
+ format_item_lsp_entry(mtid, (struct isis_item *)rv, log, NULL, indent + 2);
append_item(&tlvs->lsp_entries, (struct isis_item *)rv);
return 0;
}
@@ -1484,19 +1844,40 @@ static struct isis_item *copy_item_extended_reach(struct isis_item *i)
}
static void format_item_extended_reach(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf,
+ struct json_object *json, int indent)
{
struct isis_extended_reach *r = (struct isis_extended_reach *)i;
- sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)",
- (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
- isis_format_id(r->id, 7), r->metric);
- if (mtid != ISIS_MT_IPV4_UNICAST)
- sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
- sbuf_push(buf, 0, "\n");
+ if (json) {
+ struct json_object *reach_json;
+ reach_json = json_object_new_object();
+ json_object_object_add(json, "ext-reach", reach_json);
+ json_object_string_add(
+ reach_json, "mt-id",
+ (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT");
+ json_object_string_add(reach_json, "id",
+ isis_format_id(r->id, 7));
+ json_object_int_add(reach_json, "metric", r->metric);
+ if (mtid != ISIS_MT_IPV4_UNICAST)
+ json_object_string_add(reach_json, "mt-name",
+ isis_mtid2str(mtid));
+
+ if (r->subtlvs)
+ format_item_ext_subtlvs(r->subtlvs, NULL, json,
+ indent + 2, mtid);
+ } else {
+ sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)",
+ (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
+ isis_format_id(r->id, 7), r->metric);
+ if (mtid != ISIS_MT_IPV4_UNICAST)
+ sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
+ sbuf_push(buf, 0, "\n");
- if (r->subtlvs)
- format_item_ext_subtlvs(r->subtlvs, buf, indent + 2, mtid);
+ if (r->subtlvs)
+ format_item_ext_subtlvs(r->subtlvs, buf, NULL,
+ indent + 2, mtid);
+ }
}
static void free_item_extended_reach(struct isis_item *i)
@@ -1579,7 +1960,7 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len,
}
}
- format_item_extended_reach(mtid, (struct isis_item *)rv, log,
+ format_item_extended_reach(mtid, (struct isis_item *)rv, log, NULL,
indent + 2);
append_item(items, (struct isis_item *)rv);
return 0;
@@ -1603,11 +1984,20 @@ static struct isis_item *copy_item_oldstyle_ip_reach(struct isis_item *i)
}
static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf,
+ struct json_object *json, int indent)
{
struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
char prefixbuf[PREFIX2STR_BUFFER];
+ if (json) {
+ struct json_object *old_json;
+ old_json = json_object_new_object();
+ json_object_object_add(json, "old-ip-reach-style", old_json);
+ json_object_string_add(old_json, "prefix",
+ prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)));
+ json_object_int_add(old_json, "metric", r->metric);
+ } else
sbuf_push(buf, indent, "IP Reachability: %s (Metric: %hhu)\n",
prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
r->metric);
@@ -1669,7 +2059,7 @@ static int unpack_item_oldstyle_ip_reach(uint16_t mtid, uint8_t len,
stream_get(&mask, s, 4);
rv->prefix.prefixlen = ip_masklen(mask);
- format_item_oldstyle_ip_reach(mtid, (struct isis_item *)rv, log,
+ format_item_oldstyle_ip_reach(mtid, (struct isis_item *)rv, log, NULL,
indent + 2);
append_item(dest, (struct isis_item *)rv);
return 0;
@@ -1689,17 +2079,32 @@ static void copy_tlv_protocols_supported(struct isis_protocols_supported *src,
}
static void format_tlv_protocols_supported(struct isis_protocols_supported *p,
- struct sbuf *buf, int indent)
+ struct sbuf *buf,
+ struct json_object *json, int indent)
{
if (!p || !p->count || !p->protocols)
return;
- sbuf_push(buf, indent, "Protocols Supported: ");
- for (uint8_t i = 0; i < p->count; i++) {
- sbuf_push(buf, 0, "%s%s", nlpid2str(p->protocols[i]),
- (i + 1 < p->count) ? ", " : "");
+ if (json) {
+ struct json_object *protocol_json;
+ char buf[255];
+
+ protocol_json = json_object_new_object();
+ json_object_object_add(json, "protocols-supported",
+ protocol_json);
+ for (uint8_t i = 0; i < p->count; i++) {
+ snprintfrr(buf, sizeof(buf), "%d", i);
+ json_object_string_add(protocol_json, buf,
+ nlpid2str(p->protocols[i]));
+ }
+ } else {
+ sbuf_push(buf, indent, "Protocols Supported: ");
+ for (uint8_t i = 0; i < p->count; i++) {
+ sbuf_push(buf, 0, "%s%s", nlpid2str(p->protocols[i]),
+ (i + 1 < p->count) ? ", " : "");
+ }
+ sbuf_push(buf, 0, "\n");
}
- sbuf_push(buf, 0, "\n");
}
static void free_tlv_protocols_supported(struct isis_protocols_supported *p)
@@ -1746,7 +2151,7 @@ static int unpack_tlv_protocols_supported(enum isis_tlv_context context,
tlvs->protocols_supported.protocols = XCALLOC(MTYPE_ISIS_TLV, tlv_len);
stream_get(tlvs->protocols_supported.protocols, s, tlv_len);
- format_tlv_protocols_supported(&tlvs->protocols_supported, log,
+ format_tlv_protocols_supported(&tlvs->protocols_supported, log, NULL,
indent + 2);
return 0;
}
@@ -1762,13 +2167,18 @@ static struct isis_item *copy_item_ipv4_address(struct isis_item *i)
}
static void format_item_ipv4_address(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf, struct json_object *json,
+ int indent)
{
struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
char addrbuf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &a->addr, addrbuf, sizeof(addrbuf));
- sbuf_push(buf, indent, "IPv4 Interface Address: %s\n", addrbuf);
+ if (json) {
+ json_object_string_add(json, "ipv4", addrbuf);
+ } else {
+ sbuf_push(buf, indent, "IPv4 Interface Address: %s\n", addrbuf);
+ }
}
static void free_item_ipv4_address(struct isis_item *i)
@@ -1809,7 +2219,7 @@ static int unpack_item_ipv4_address(uint16_t mtid, uint8_t len,
struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
stream_get(&rv->addr, s, 4);
- format_item_ipv4_address(mtid, (struct isis_item *)rv, log, indent + 2);
+ format_item_ipv4_address(mtid, (struct isis_item *)rv, log, NULL, indent + 2);
append_item(&tlvs->ipv4_address, (struct isis_item *)rv);
return 0;
}
@@ -1826,13 +2236,17 @@ static struct isis_item *copy_item_ipv6_address(struct isis_item *i)
}
static void format_item_ipv6_address(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf, struct json_object *json,
+ int indent)
{
struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
char addrbuf[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf));
- sbuf_push(buf, indent, "IPv6 Interface Address: %s\n", addrbuf);
+ if (json)
+ json_object_string_add(json, "ipv6", addrbuf);
+ else
+ sbuf_push(buf, indent, "IPv6 Interface Address: %s\n", addrbuf);
}
static void free_item_ipv6_address(struct isis_item *i)
@@ -1873,7 +2287,7 @@ static int unpack_item_ipv6_address(uint16_t mtid, uint8_t len,
struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
stream_get(&rv->addr, s, IPV6_MAX_BYTELEN);
- format_item_ipv6_address(mtid, (struct isis_item *)rv, log, indent + 2);
+ format_item_ipv6_address(mtid, (struct isis_item *)rv, log, NULL, indent + 2);
append_item(&tlvs->ipv6_address, (struct isis_item *)rv);
return 0;
}
@@ -1890,13 +2304,19 @@ static struct isis_item *copy_item_global_ipv6_address(struct isis_item *i)
}
static void format_item_global_ipv6_address(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf,
+ struct json_object *json,
+ int indent)
{
struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
char addrbuf[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf));
- sbuf_push(buf, indent, "Global IPv6 Interface Address: %s\n", addrbuf);
+ if (json)
+ json_object_string_add(json, "global-ipv6", addrbuf);
+ else
+ sbuf_push(buf, indent, "Global IPv6 Interface Address: %s\n",
+ addrbuf);
}
static void free_item_global_ipv6_address(struct isis_item *i)
@@ -1937,7 +2357,7 @@ static int unpack_item_global_ipv6_address(uint16_t mtid, uint8_t len,
struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
stream_get(&rv->addr, s, IPV6_MAX_BYTELEN);
- format_item_global_ipv6_address(mtid, (struct isis_item *)rv, log,
+ format_item_global_ipv6_address(mtid, (struct isis_item *)rv, log, NULL,
indent + 2);
append_item(&tlvs->global_ipv6_address, (struct isis_item *)rv);
return 0;
@@ -1956,14 +2376,23 @@ static struct isis_item *copy_item_mt_router_info(struct isis_item *i)
}
static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf,
+ struct json_object *json, int indent)
{
struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
- sbuf_push(buf, indent, "MT Router Info: %s%s%s\n",
- isis_mtid2str(info->mtid),
- info->overload ? " Overload" : "",
- info->attached ? " Attached" : "");
+ if (json) {
+ struct json_object *mt_json;
+ mt_json = json_object_new_object();
+ json_object_object_add(json, "mt", mt_json);
+ json_object_int_add(mt_json, "mtid", info->mtid);
+ json_object_string_add(mt_json, "overload", info->overload?"true":"false");
+ json_object_string_add(mt_json, "attached", info->attached?"true":"false");
+ } else
+ sbuf_push(buf, indent, "MT Router Info: %s%s%s\n",
+ isis_mtid2str(info->mtid),
+ info->overload ? " Overload" : "",
+ info->attached ? " Attached" : "");
}
static void free_item_mt_router_info(struct isis_item *i)
@@ -2015,7 +2444,7 @@ static int unpack_item_mt_router_info(uint16_t mtid, uint8_t len,
rv->attached = entry & ISIS_MT_AT_MASK;
rv->mtid = entry & ISIS_MT_MASK;
- format_item_mt_router_info(mtid, (struct isis_item *)rv, log,
+ format_item_mt_router_info(mtid, (struct isis_item *)rv, log, NULL,
indent + 2);
append_item(&tlvs->mt_router_info, (struct isis_item *)rv);
return 0;
@@ -2034,14 +2463,17 @@ static struct in_addr *copy_tlv_te_router_id(const struct in_addr *id)
}
static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf,
- int indent)
+ struct json_object *json, int indent)
{
if (!id)
return;
char addrbuf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf));
- sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf);
+ if (json)
+ json_object_string_add(json, "te-router-id", addrbuf);
+ else
+ sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf);
}
static void free_tlv_te_router_id(struct in_addr *id)
@@ -2085,7 +2517,7 @@ static int unpack_tlv_te_router_id(enum isis_tlv_context context,
tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, 4);
stream_get(tlvs->te_router_id, s, 4);
- format_tlv_te_router_id(tlvs->te_router_id, log, indent + 2);
+ format_tlv_te_router_id(tlvs->te_router_id, log, NULL, indent + 2);
return 0;
}
@@ -2107,22 +2539,46 @@ static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i)
}
static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf,
+ struct json_object *json, int indent)
{
struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
char prefixbuf[PREFIX2STR_BUFFER];
- sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s",
- (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
- prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric,
- r->down ? " Down" : "");
- if (mtid != ISIS_MT_IPV4_UNICAST)
- sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
- sbuf_push(buf, 0, "\n");
-
- if (r->subtlvs) {
- sbuf_push(buf, indent, " Subtlvs:\n");
- format_subtlvs(r->subtlvs, buf, indent + 4);
+ if (json) {
+ struct json_object *ext_json;
+ ext_json = json_object_new_object();
+ json_object_object_add(json, "ext-ip-reach", ext_json);
+ json_object_string_add(
+ json, "mt-id",
+ (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT");
+ json_object_string_add(
+ json, "ip-reach",
+ prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)));
+ json_object_int_add(json, "ip-reach-metric", r->metric);
+ json_object_string_add(json, "down", r->down ? "yes" : "");
+ if (mtid != ISIS_MT_IPV4_UNICAST)
+ json_object_string_add(json, "mt-name",
+ isis_mtid2str(mtid));
+ if (r->subtlvs) {
+ struct json_object *subtlv_json;
+ subtlv_json = json_object_new_object();
+ json_object_object_add(json, "subtlvs", subtlv_json);
+ format_subtlvs(r->subtlvs, NULL, subtlv_json, 0);
+ }
+ } else {
+ sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s",
+ (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
+ prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
+ r->metric, r->down ? " Down" : "");
+ if (mtid != ISIS_MT_IPV4_UNICAST)
+ sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
+ sbuf_push(buf, 0, "\n");
+
+ if (r->subtlvs) {
+ sbuf_push(buf, indent, " Subtlvs:\n");
+ format_subtlvs(r->subtlvs, buf, NULL, indent + 4);
+ }
}
}
@@ -2216,7 +2672,7 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
if (orig_prefix != rv->prefix.prefix.s_addr)
sbuf_push(log, indent + 2,
"WARNING: Prefix had hostbits set.\n");
- format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log,
+ format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log, NULL,
indent + 2);
if (control & ISIS_EXTENDED_IP_REACH_SUBTLV) {
@@ -2273,12 +2729,15 @@ static char *copy_tlv_dynamic_hostname(const char *hostname)
}
static void format_tlv_dynamic_hostname(const char *hostname, struct sbuf *buf,
- int indent)
+ struct json_object *json, int indent)
{
if (!hostname)
return;
- sbuf_push(buf, indent, "Hostname: %s\n", hostname);
+ if (json)
+ json_object_string_add(json, "hostname", hostname);
+ else
+ sbuf_push(buf, indent, "Hostname: %s\n", hostname);
}
static void free_tlv_dynamic_hostname(char *hostname)
@@ -2356,14 +2815,18 @@ static struct in6_addr *copy_tlv_te_router_id_ipv6(const struct in6_addr *id)
}
static void format_tlv_te_router_id_ipv6(const struct in6_addr *id,
- struct sbuf *buf, int indent)
+ struct sbuf *buf,
+ struct json_object *json, int indent)
{
if (!id)
return;
char addrbuf[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, id, addrbuf, sizeof(addrbuf));
- sbuf_push(buf, indent, "IPv6 TE Router ID: %s\n", addrbuf);
+ if (json)
+ json_object_string_add(json, "ipv6-te-router-id", addrbuf);
+ else
+ sbuf_push(buf, indent, "IPv6 TE Router ID: %s\n", addrbuf);
}
static void free_tlv_te_router_id_ipv6(struct in6_addr *id)
@@ -2409,7 +2872,7 @@ static int unpack_tlv_te_router_id_ipv6(enum isis_tlv_context context,
tlvs->te_router_id_ipv6 = XCALLOC(MTYPE_ISIS_TLV, IPV6_MAX_BYTELEN);
stream_get(tlvs->te_router_id_ipv6, s, IPV6_MAX_BYTELEN);
- format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, log, indent + 2);
+ format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, log, NULL, indent + 2);
return 0;
}
@@ -2429,26 +2892,50 @@ static struct isis_spine_leaf *copy_tlv_spine_leaf(
}
static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf,
- struct sbuf *buf, int indent)
+ struct sbuf *buf, struct json_object *json,
+ int indent)
{
if (!spine_leaf)
return;
- sbuf_push(buf, indent, "Spine-Leaf-Extension:\n");
- if (spine_leaf->has_tier) {
- if (spine_leaf->tier == ISIS_TIER_UNDEFINED) {
- sbuf_push(buf, indent, " Tier: undefined\n");
- } else {
- sbuf_push(buf, indent, " Tier: %hhu\n",
- spine_leaf->tier);
+ char aux_buf[255];
+
+ if (json) {
+ struct json_object *spine_json;
+ spine_json = json_object_new_object();
+ json_object_object_add(json, "spine-leaf-extension",
+ spine_json);
+ if (spine_leaf->has_tier) {
+ snprintfrr(aux_buf, sizeof(aux_buf), "%hhu",
+ spine_leaf->tier);
+ json_object_string_add(
+ spine_json, "tier",
+ (spine_leaf->tier == ISIS_TIER_UNDEFINED)
+ ? "undefined"
+ : aux_buf);
+ }
+ json_object_string_add(spine_json, "flag-leaf",
+ spine_leaf->is_leaf ? "yes" : "");
+ json_object_string_add(spine_json, "flag-spine",
+ spine_leaf->is_spine ? "yes" : "");
+ json_object_string_add(spine_json, "flag-backup",
+ spine_leaf->is_backup ? "yes" : "");
+ } else {
+ sbuf_push(buf, indent, "Spine-Leaf-Extension:\n");
+ if (spine_leaf->has_tier) {
+ if (spine_leaf->tier == ISIS_TIER_UNDEFINED) {
+ sbuf_push(buf, indent, " Tier: undefined\n");
+ } else {
+ sbuf_push(buf, indent, " Tier: %hhu\n",
+ spine_leaf->tier);
+ }
}
- }
-
- sbuf_push(buf, indent, " Flags:%s%s%s\n",
- spine_leaf->is_leaf ? " LEAF" : "",
- spine_leaf->is_spine ? " SPINE" : "",
- spine_leaf->is_backup ? " BACKUP" : "");
+ sbuf_push(buf, indent, " Flags:%s%s%s\n",
+ spine_leaf->is_leaf ? " LEAF" : "",
+ spine_leaf->is_spine ? " SPINE" : "",
+ spine_leaf->is_backup ? " BACKUP" : "");
+ }
}
static void free_tlv_spine_leaf(struct isis_spine_leaf *spine_leaf)
@@ -2562,25 +3049,45 @@ static struct isis_threeway_adj *copy_tlv_threeway_adj(
return rv;
}
-static void format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
- struct sbuf *buf, int indent)
+static void
+format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
+ struct sbuf *buf, struct json_object *json, int indent)
{
if (!threeway_adj)
return;
- sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n");
- sbuf_push(buf, indent, " State: %s (%d)\n",
- isis_threeway_state_name(threeway_adj->state),
- threeway_adj->state);
- sbuf_push(buf, indent, " Extended Local Circuit ID: %u\n",
- threeway_adj->local_circuit_id);
- if (!threeway_adj->neighbor_set)
- return;
+ if (json) {
+ struct json_object *three_json;
+ three_json = json_object_new_object();
+ json_object_object_add(json, "p2p-three-way-adj", three_json);
+ json_object_string_add(
+ three_json, "state-name",
+ isis_threeway_state_name(threeway_adj->state));
+ json_object_int_add(three_json, "state", threeway_adj->state);
+ json_object_int_add(three_json, "ext-local-circuit-id",
+ threeway_adj->local_circuit_id);
+ if (!threeway_adj->neighbor_set)
+ return;
+ json_object_string_add(
+ three_json, "neigh-system-id",
+ isis_format_id(threeway_adj->neighbor_id, 6));
+ json_object_int_add(three_json, "neigh-ext-circuit-id",
+ threeway_adj->neighbor_circuit_id);
+ } else {
+ sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n");
+ sbuf_push(buf, indent, " State: %s (%d)\n",
+ isis_threeway_state_name(threeway_adj->state),
+ threeway_adj->state);
+ sbuf_push(buf, indent, " Extended Local Circuit ID: %u\n",
+ threeway_adj->local_circuit_id);
+ if (!threeway_adj->neighbor_set)
+ return;
- sbuf_push(buf, indent, " Neighbor System ID: %s\n",
- isis_format_id(threeway_adj->neighbor_id, 6));
- sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %u\n",
- threeway_adj->neighbor_circuit_id);
+ sbuf_push(buf, indent, " Neighbor System ID: %s\n",
+ isis_format_id(threeway_adj->neighbor_id, 6));
+ sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %u\n",
+ threeway_adj->neighbor_circuit_id);
+ }
}
static void free_tlv_threeway_adj(struct isis_threeway_adj *threeway_adj)
@@ -2663,24 +3170,51 @@ static struct isis_item *copy_item_ipv6_reach(struct isis_item *i)
}
static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf, struct json_object *json,
+ int indent)
{
struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
char prefixbuf[PREFIX2STR_BUFFER];
- sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
- (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ",
- prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
- r->metric,
- r->down ? " Down" : "",
- r->external ? " External" : "");
- if (mtid != ISIS_MT_IPV4_UNICAST)
- sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
- sbuf_push(buf, 0, "\n");
-
- if (r->subtlvs) {
- sbuf_push(buf, indent, " Subtlvs:\n");
- format_subtlvs(r->subtlvs, buf, indent + 4);
+ if (json) {
+ struct json_object *reach_json;
+ reach_json = json_object_new_object();
+ json_object_object_add(json, "ipv6-reach", reach_json);
+ json_object_string_add(reach_json, "mt-id",
+ (mtid == ISIS_MT_IPV4_UNICAST) ? ""
+ : "mt");
+ json_object_string_add(
+ reach_json, "prefix",
+ prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)));
+ json_object_int_add(reach_json, "metric", r->metric);
+ json_object_string_add(reach_json, "down",
+ r->down ? "yes" : "");
+ json_object_string_add(reach_json, "external",
+ r->external ? "yes" : "");
+ if (mtid != ISIS_MT_IPV4_UNICAST)
+ json_object_string_add(reach_json, "mt-name",
+ isis_mtid2str(mtid));
+ if (r->subtlvs) {
+ struct json_object *subtlvs_json;
+ subtlvs_json = json_object_new_object();
+ json_object_object_add(json, "subtlvs", subtlvs_json);
+ format_subtlvs(r->subtlvs, NULL, subtlvs_json, 0);
+ }
+ } else {
+ sbuf_push(buf, indent,
+ "%sIPv6 Reachability: %s (Metric: %u)%s%s",
+ (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ",
+ prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
+ r->metric, r->down ? " Down" : "",
+ r->external ? " External" : "");
+ if (mtid != ISIS_MT_IPV4_UNICAST)
+ sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
+ sbuf_push(buf, 0, "\n");
+
+ if (r->subtlvs) {
+ sbuf_push(buf, indent, " Subtlvs:\n");
+ format_subtlvs(r->subtlvs, buf, NULL, indent + 4);
+ }
}
}
@@ -2773,7 +3307,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix)))
sbuf_push(log, indent + 2,
"WARNING: Prefix had hostbits set.\n");
- format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, indent + 2);
+ format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, NULL, indent + 2);
if (control & ISIS_IPV6_REACH_SUBTLV) {
consume += 1;
@@ -2834,6 +3368,77 @@ static struct isis_router_cap *copy_tlv_router_cap(
return rv;
}
+static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap,
+ struct json_object *json)
+{
+ char addrbuf[INET_ADDRSTRLEN];
+
+ if (!router_cap)
+ return;
+
+ /* Router ID and Flags */
+ struct json_object *cap_json;
+ cap_json = json_object_new_object();
+ json_object_object_add(json, "router-capability", cap_json);
+ inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf));
+ json_object_string_add(cap_json, "id", addrbuf);
+ json_object_string_add(
+ cap_json, "flag-d",
+ router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? "1" : "0");
+ json_object_string_add(
+ cap_json, "flag-s",
+ router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? "1" : "0");
+
+ /* Segment Routing Global Block as per RFC8667 section #3.1 */
+ if (router_cap->srgb.range_size != 0) {
+ struct json_object *gb_json;
+ gb_json = json_object_new_object();
+ json_object_object_add(json, "segment-routing-gb", gb_json);
+ json_object_string_add(gb_json, "ipv4",
+ IS_SR_IPV4(&router_cap->srgb) ? "1"
+ : "0");
+ json_object_string_add(gb_json, "ipv6",
+ IS_SR_IPV6(&router_cap->srgb) ? "1"
+ : "0");
+ json_object_int_add(gb_json, "global-block-base",
+ router_cap->srgb.lower_bound);
+ json_object_int_add(gb_json, "global-block-range",
+ router_cap->srgb.range_size);
+ }
+
+ /* Segment Routing Local Block as per RFC8667 section #3.3 */
+ if (router_cap->srlb.range_size != 0) {
+ struct json_object *lb_json;
+ lb_json = json_object_new_object();
+ json_object_object_add(json, "segment-routing-lb", lb_json);
+ json_object_int_add(lb_json, "global-block-base",
+ router_cap->srlb.lower_bound);
+ json_object_int_add(lb_json, "global-block-range",
+ router_cap->srlb.range_size);
+ }
+
+ /* Segment Routing Algorithms as per RFC8667 section #3.2 */
+ if (router_cap->algo[0] != SR_ALGORITHM_UNSET) {
+ char buf[255];
+ struct json_object *alg_json;
+ alg_json = json_object_new_object();
+ json_object_object_add(json, "segment-routing-algorithm",
+ alg_json);
+ for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+ if (router_cap->algo[i] != SR_ALGORITHM_UNSET) {
+ snprintfrr(buf, sizeof(buf), "%d", i);
+ json_object_string_add(alg_json, buf,
+ router_cap->algo[i] == 0
+ ? "SPF"
+ : "Strict SPF");
+ }
+ }
+
+ /* Segment Routing Node MSD as per RFC8491 section #2 */
+ if (router_cap->msd != 0)
+ json_object_int_add(json, "msd", router_cap->msd);
+}
+
static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
struct sbuf *buf, int indent)
{
@@ -3177,26 +3782,40 @@ static struct isis_item *copy_item_auth(struct isis_item *i)
}
static void format_item_auth(uint16_t mtid, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf, struct json_object *json,
+ int indent)
{
struct isis_auth *auth = (struct isis_auth *)i;
char obuf[768];
- sbuf_push(buf, indent, "Authentication:\n");
+ if (json)
+ json_object_string_add(json, "test-auth", "ok");
+ else
+ sbuf_push(buf, indent, "Authentication:\n");
switch (auth->type) {
case ISIS_PASSWD_TYPE_CLEARTXT:
zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length);
- sbuf_push(buf, indent, " Password: %s\n", obuf);
+ if (json)
+ json_object_string_add(json, "auth-pass", obuf);
+ else
+ sbuf_push(buf, indent, " Password: %s\n", obuf);
break;
case ISIS_PASSWD_TYPE_HMAC_MD5:
for (unsigned int j = 0; j < 16; j++) {
- snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j,
- "%02hhx", auth->value[j]);
+ snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j, "%02hhx",
+ auth->value[j]);
}
- sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf);
+ if (json)
+ json_object_string_add(json, "auth-hmac-md5", obuf);
+ else
+ sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf);
break;
default:
- sbuf_push(buf, indent, " Unknown (%hhu)\n", auth->type);
+ if (json)
+ json_object_int_add(json, "auth-unknown", auth->type);
+ else
+ sbuf_push(buf, indent, " Unknown (%hhu)\n",
+ auth->type);
break;
}
}
@@ -3270,7 +3889,7 @@ static int unpack_item_auth(uint16_t mtid, uint8_t len, struct stream *s,
rv->offset = stream_get_getp(s);
stream_get(rv->value, s, rv->length);
- format_item_auth(mtid, (struct isis_item *)rv, log, indent + 2);
+ format_item_auth(mtid, (struct isis_item *)rv, log, NULL, indent + 2);
append_item(&tlvs->isis_auth, (struct isis_item *)rv);
return 0;
}
@@ -3294,17 +3913,36 @@ static struct isis_purge_originator *copy_tlv_purge_originator(
}
static void format_tlv_purge_originator(struct isis_purge_originator *poi,
- struct sbuf *buf, int indent)
+ struct sbuf *buf,
+ struct json_object *json, int indent)
{
if (!poi)
return;
- sbuf_push(buf, indent, "Purge Originator Identification:\n");
- sbuf_push(buf, indent, " Generator: %s\n",
- isis_format_id(poi->generator, sizeof(poi->generator)));
- if (poi->sender_set) {
- sbuf_push(buf, indent, " Received-From: %s\n",
- isis_format_id(poi->sender, sizeof(poi->sender)));
+ if (json) {
+ struct json_object *purge_json;
+ purge_json = json_object_new_object();
+ json_object_object_add(json, "purge_originator", purge_json);
+
+ json_object_string_add(
+ purge_json, "id",
+ isis_format_id(poi->generator, sizeof(poi->generator)));
+ if (poi->sender_set) {
+ json_object_string_add(
+ purge_json, "rec-from",
+ isis_format_id(poi->sender,
+ sizeof(poi->sender)));
+ }
+ } else {
+ sbuf_push(buf, indent, "Purge Originator Identification:\n");
+ sbuf_push(
+ buf, indent, " Generator: %s\n",
+ isis_format_id(poi->generator, sizeof(poi->generator)));
+ if (poi->sender_set) {
+ sbuf_push(buf, indent, " Received-From: %s\n",
+ isis_format_id(poi->sender,
+ sizeof(poi->sender)));
+ }
}
}
@@ -3417,12 +4055,12 @@ static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
static void format_item(uint16_t mtid, enum isis_tlv_context context,
enum isis_tlv_type type, struct isis_item *i,
- struct sbuf *buf, int indent)
+ struct sbuf *buf, struct json_object *json, int indent)
{
const struct tlv_ops *ops = tlv_table[context][type];
if (ops && ops->format_item) {
- ops->format_item(mtid, i, buf, indent);
+ ops->format_item(mtid, i, buf, json, indent);
return;
}
@@ -3431,12 +4069,13 @@ static void format_item(uint16_t mtid, enum isis_tlv_context context,
static void format_items_(uint16_t mtid, enum isis_tlv_context context,
enum isis_tlv_type type, struct isis_item_list *items,
- struct sbuf *buf, int indent)
+ struct sbuf *buf, struct json_object *json,
+ int indent)
{
struct isis_item *i;
for (i = items->head; i; i = i->next)
- format_item(mtid, context, type, i, buf, indent);
+ format_item(mtid, context, type, i, buf, json, indent);
}
static void free_item(enum isis_tlv_context tlv_context,
@@ -3765,12 +4404,12 @@ static void free_mt_items(enum isis_tlv_context context,
static void format_mt_items(enum isis_tlv_context context,
enum isis_tlv_type type,
struct isis_mt_item_list *m, struct sbuf *buf,
- int indent)
+ struct json_object *json, int indent)
{
struct isis_item_list *n;
RB_FOREACH (n, isis_mt_item_list, m) {
- format_items_(n->mtid, context, type, n, buf, indent);
+ format_items_(n->mtid, context, type, n, buf, json, indent);
}
}
@@ -3917,87 +4556,100 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
return rv;
}
-static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
+static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, struct json_object *json, int indent)
{
- format_tlv_protocols_supported(&tlvs->protocols_supported, buf, indent);
+ format_tlv_protocols_supported(&tlvs->protocols_supported, buf, json,
+ indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, buf,
- indent);
+ json, indent);
- format_tlv_purge_originator(tlvs->purge_originator, buf, indent);
+ format_tlv_purge_originator(tlvs->purge_originator, buf, json, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
- &tlvs->area_addresses, buf, indent);
+ &tlvs->area_addresses, buf, json, indent);
if (tlvs->mt_router_info_empty) {
- sbuf_push(buf, indent, "MT Router Info: None\n");
+ if (json)
+ json_object_string_add(json, "mt-router-info", "none");
+ else
+ sbuf_push(buf, indent, "MT Router Info: None\n");
} else {
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
- &tlvs->mt_router_info, buf, indent);
+ &tlvs->mt_router_info, buf, json, indent);
}
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
- &tlvs->oldstyle_reach, buf, indent);
+ &tlvs->oldstyle_reach, buf, json, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
- &tlvs->lan_neighbor, buf, indent);
+ &tlvs->lan_neighbor, buf, json, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
- buf, indent);
-
- format_tlv_dynamic_hostname(tlvs->hostname, buf, indent);
- format_tlv_te_router_id(tlvs->te_router_id, buf, indent);
- format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, buf, indent);
- format_tlv_router_cap(tlvs->router_cap, buf, indent);
+ buf, json, indent);
+
+ format_tlv_dynamic_hostname(tlvs->hostname, buf, json, indent);
+ format_tlv_te_router_id(tlvs->te_router_id, buf, json, indent);
+ format_tlv_te_router_id_ipv6(tlvs->te_router_id_ipv6, buf, json,
+ indent);
+ if (json)
+ format_tlv_router_cap_json(tlvs->router_cap, json);
+ else
+ format_tlv_router_cap(tlvs->router_cap, buf, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
- &tlvs->extended_reach, buf, indent);
+ &tlvs->extended_reach, buf, json, indent);
format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
- buf, indent);
+ buf, json, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
- &tlvs->oldstyle_ip_reach, buf, indent);
+ &tlvs->oldstyle_ip_reach, buf, json, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
- &tlvs->oldstyle_ip_reach_ext, buf, indent);
+ &tlvs->oldstyle_ip_reach_ext, buf, json, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
- &tlvs->ipv4_address, buf, indent);
+ &tlvs->ipv4_address, buf, json, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
- &tlvs->ipv6_address, buf, indent);
+ &tlvs->ipv6_address, buf, json, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_GLOBAL_IPV6_ADDRESS,
- &tlvs->global_ipv6_address, buf, indent);
+ &tlvs->global_ipv6_address, buf, json, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
- &tlvs->extended_ip_reach, buf, indent);
+ &tlvs->extended_ip_reach, buf, json, indent);
format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
- &tlvs->mt_ip_reach, buf, indent);
+ &tlvs->mt_ip_reach, buf, json, indent);
format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
- buf, indent);
+ buf, json, indent);
format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
- &tlvs->mt_ipv6_reach, buf, indent);
+ &tlvs->mt_ipv6_reach, buf, json, indent);
- format_tlv_threeway_adj(tlvs->threeway_adj, buf, indent);
+ format_tlv_threeway_adj(tlvs->threeway_adj, buf, json, indent);
- format_tlv_spine_leaf(tlvs->spine_leaf, buf, indent);
+ format_tlv_spine_leaf(tlvs->spine_leaf, buf, json, indent);
}
-const char *isis_format_tlvs(struct isis_tlvs *tlvs)
+const char *isis_format_tlvs(struct isis_tlvs *tlvs, struct json_object *json)
{
- static struct sbuf buf;
+ if (json) {
+ format_tlvs(tlvs, NULL, json, 0);
+ return NULL;
+ } else {
+ static struct sbuf buf;
- if (!sbuf_buf(&buf))
- sbuf_init(&buf, NULL, 0);
+ if (!sbuf_buf(&buf))
+ sbuf_init(&buf, NULL, 0);
- sbuf_reset(&buf);
- format_tlvs(tlvs, &buf, 0);
- return sbuf_buf(&buf);
+ sbuf_reset(&buf);
+ format_tlvs(tlvs, &buf, NULL, 0);
+ return sbuf_buf(&buf);
+ }
}
void isis_free_tlvs(struct isis_tlvs *tlvs)
diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h
index 0c6ed11cb6..364e38aba1 100644
--- a/isisd/isis_tlvs.h
+++ b/isisd/isis_tlvs.h
@@ -549,7 +549,7 @@ void isis_free_tlvs(struct isis_tlvs *tlvs);
struct isis_tlvs *isis_alloc_tlvs(void);
int isis_unpack_tlvs(size_t avail_len, struct stream *stream,
struct isis_tlvs **dest, const char **error_log);
-const char *isis_format_tlvs(struct isis_tlvs *tlvs);
+const char *isis_format_tlvs(struct isis_tlvs *tlvs, struct json_object *json);
struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs);
struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size);
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 3fa2b7cc20..369b83396a 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -109,12 +109,19 @@ DEFINE_HOOK(isis_hook_db_overload, (const struct isis_area *area), (area));
int isis_area_get(struct vty *, const char *);
int area_net_title(struct vty *, const char *);
int area_clear_net_title(struct vty *, const char *);
-int show_isis_interface_common(struct vty *, const char *ifname, char,
- const char *vrf_name, bool all_vrf);
-int show_isis_neighbor_common(struct vty *, const char *id, char,
- const char *vrf_name, bool all_vrf);
-int clear_isis_neighbor_common(struct vty *, const char *id, const char *vrf_name,
+int show_isis_interface_common(struct vty *, struct json_object *json,
+ const char *ifname, char, const char *vrf_name,
bool all_vrf);
+int show_isis_interface_common_vty(struct vty *, const char *ifname, char,
+ const char *vrf_name, bool all_vrf);
+int show_isis_interface_common_json(struct json_object *json,
+ const char *ifname, char,
+ const char *vrf_name, bool all_vrf);
+int show_isis_neighbor_common(struct vty *, struct json_object *json,
+ const char *id, char, const char *vrf_name,
+ bool all_vrf);
+int clear_isis_neighbor_common(struct vty *, const char *id,
+ const char *vrf_name, bool all_vrf);
/* Link ISIS instance to VRF. */
void isis_vrf_link(struct isis *isis, struct vrf *vrf)
@@ -202,7 +209,7 @@ struct isis *isis_new(const char *vrf_name)
/*
* Default values
*/
- isis->max_area_addrs = 3;
+ isis->max_area_addrs = ISIS_DEFAULT_MAX_AREA_ADDRESSES;
isis->process_id = getpid();
isis->router_id = 0;
isis->area_list = list_new();
@@ -933,10 +940,125 @@ int area_clear_net_title(struct vty *vty, const char *net_title)
/*
* 'show isis interface' command
*/
-
-int show_isis_interface_common(struct vty *vty, const char *ifname, char detail,
+int show_isis_interface_common(struct vty *vty, struct json_object *json,
+ const char *ifname, char detail,
const char *vrf_name, bool all_vrf)
{
+ if (json) {
+ return show_isis_interface_common_json(json, ifname, detail,
+ vrf_name, all_vrf);
+ } else {
+ return show_isis_interface_common_vty(vty, ifname, detail,
+ vrf_name, all_vrf);
+ }
+}
+
+int show_isis_interface_common_json(struct json_object *json,
+ const char *ifname, char detail,
+ const char *vrf_name, bool all_vrf)
+{
+ struct listnode *anode, *cnode, *inode;
+ struct isis_area *area;
+ struct isis_circuit *circuit;
+ struct isis *isis;
+ struct json_object *areas_json, *area_json;
+ struct json_object *circuits_json, *circuit_json;
+ if (!im) {
+ // IS-IS Routing Process not enabled
+ json_object_string_add(json, "is-is-routing-process-enabled",
+ "no");
+ return CMD_SUCCESS;
+ }
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) {
+ areas_json = json_object_new_array();
+ json_object_object_add(json, "areas",
+ areas_json);
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list,
+ anode, area)) {
+ area_json = json_object_new_object();
+ json_object_string_add(
+ area_json, "area",
+ area->area_tag ? area->area_tag
+ : "null");
+ circuits_json = json_object_new_array();
+ json_object_object_add(area_json,
+ "circuits",
+ circuits_json);
+ for (ALL_LIST_ELEMENTS_RO(
+ area->circuit_list, cnode,
+ circuit)) {
+ circuit_json =
+ json_object_new_object();
+ json_object_int_add(
+ circuit_json, "circuit",
+ circuit->circuit_id);
+ if (!ifname)
+ isis_circuit_print_json(
+ circuit,
+ circuit_json,
+ detail);
+ else if (strcmp(circuit->interface->name, ifname) == 0)
+ isis_circuit_print_json(
+ circuit,
+ circuit_json,
+ detail);
+ json_object_array_add(
+ circuits_json,
+ circuit_json);
+ }
+ json_object_array_add(areas_json,
+ area_json);
+ }
+ }
+ return CMD_SUCCESS;
+ }
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis != NULL) {
+ areas_json = json_object_new_array();
+ json_object_object_add(json, "areas", areas_json);
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode,
+ area)) {
+ area_json = json_object_new_object();
+ json_object_string_add(area_json, "area",
+ area->area_tag
+ ? area->area_tag
+ : "null");
+
+ circuits_json = json_object_new_array();
+ json_object_object_add(area_json, "circuits",
+ circuits_json);
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list,
+ cnode, circuit)) {
+ circuit_json = json_object_new_object();
+ json_object_int_add(
+ circuit_json, "circuit",
+ circuit->circuit_id);
+ if (!ifname)
+ isis_circuit_print_json(
+ circuit, circuit_json,
+ detail);
+ else if (
+ strcmp(circuit->interface->name,
+ ifname) == 0)
+ isis_circuit_print_json(
+ circuit, circuit_json,
+ detail);
+ json_object_array_add(circuits_json,
+ circuit_json);
+ }
+ json_object_array_add(areas_json, area_json);
+ }
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+int show_isis_interface_common_vty(struct vty *vty, const char *ifname,
+ char detail, const char *vrf_name,
+ bool all_vrf)
+{
struct listnode *anode, *cnode, *inode;
struct isis_area *area;
struct isis_circuit *circuit;
@@ -990,8 +1112,7 @@ int show_isis_interface_common(struct vty *vty, const char *ifname, char detail,
circuit, vty, detail);
else if (
strcmp(circuit->interface->name,
- ifname)
- == 0)
+ ifname) == 0)
isis_circuit_print_vty(
circuit, vty, detail);
}
@@ -1003,63 +1124,90 @@ int show_isis_interface_common(struct vty *vty, const char *ifname, char detail,
DEFUN(show_isis_interface,
show_isis_interface_cmd,
- "show " PROTO_NAME " [vrf <NAME|all>] interface",
+ "show " PROTO_NAME " [vrf <NAME|all>] interface [json]",
SHOW_STR
PROTO_HELP
VRF_CMD_HELP_STR
"All VRFs\n"
+ "json output\n"
"IS-IS interface\n")
{
+ int res = CMD_SUCCESS;
const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false;
int idx_vrf = 0;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
- return show_isis_interface_common(vty, NULL, ISIS_UI_LEVEL_BRIEF,
- vrf_name, all_vrf);
+ if (uj)
+ json = json_object_new_object();
+ res = show_isis_interface_common(vty, json, NULL, ISIS_UI_LEVEL_BRIEF,
+ vrf_name, all_vrf);
+ if (uj)
+ vty_json(vty, json);
+ return res;
}
DEFUN(show_isis_interface_detail,
show_isis_interface_detail_cmd,
- "show " PROTO_NAME " [vrf <NAME|all>] interface detail",
+ "show " PROTO_NAME " [vrf <NAME|all>] interface detail [json]",
SHOW_STR
PROTO_HELP
VRF_CMD_HELP_STR
"All VRFs\n"
"IS-IS interface\n"
- "show detailed information\n")
+ "show detailed information\n"
+ "json output\n")
{
+ int res = CMD_SUCCESS;
const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false;
int idx_vrf = 0;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
- return show_isis_interface_common(vty, NULL, ISIS_UI_LEVEL_DETAIL,
- vrf_name, all_vrf);
+ if (uj)
+ json = json_object_new_object();
+ res = show_isis_interface_common(vty, json, NULL, ISIS_UI_LEVEL_DETAIL,
+ vrf_name, all_vrf);
+ if (uj)
+ vty_json(vty, json);
+ return res;
}
DEFUN(show_isis_interface_arg,
show_isis_interface_arg_cmd,
- "show " PROTO_NAME " [vrf <NAME|all>] interface WORD",
+ "show " PROTO_NAME " [vrf <NAME|all>] interface WORD [json]",
SHOW_STR
PROTO_HELP
VRF_CMD_HELP_STR
"All VRFs\n"
"IS-IS interface\n"
- "IS-IS interface name\n")
+ "IS-IS interface name\n"
+ "json output\n")
{
+ int res = CMD_SUCCESS;
int idx_word = 0;
const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false;
int idx_vrf = 0;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (uj)
+ json = json_object_new_object();
char *ifname = argv_find(argv, argc, "WORD", &idx_word)
? argv[idx_word]->arg
: NULL;
- return show_isis_interface_common(vty, ifname, ISIS_UI_LEVEL_DETAIL,
- vrf_name, all_vrf);
+ res = show_isis_interface_common(
+ vty, json, ifname, ISIS_UI_LEVEL_DETAIL, vrf_name, all_vrf);
+ if (uj)
+ vty_json(vty, json);
+ return res;
}
static int id_to_sysid(struct isis *isis, const char *id, uint8_t *sysid)
@@ -1079,8 +1227,65 @@ static int id_to_sysid(struct isis *isis, const char *id, uint8_t *sysid)
return 0;
}
-static void isis_neighbor_common(struct vty *vty, const char *id, char detail,
- struct isis *isis, uint8_t *sysid)
+static void isis_neighbor_common_json(struct json_object *json, const char *id,
+ char detail, struct isis *isis,
+ uint8_t *sysid)
+{
+ struct listnode *anode, *cnode, *node;
+ struct isis_area *area;
+ struct isis_circuit *circuit;
+ struct list *adjdb;
+ struct isis_adjacency *adj;
+ struct json_object *areas_json, *area_json;
+ struct json_object *circuits_json, *circuit_json;
+ int i;
+
+ areas_json = json_object_new_array();
+ json_object_object_add(json, "areas", areas_json);
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
+ area_json = json_object_new_object();
+ json_object_string_add(area_json, "area",
+ area->area_tag ? area->area_tag
+ : "null");
+ circuits_json = json_object_new_array();
+ json_object_object_add(area_json, "circuits", circuits_json);
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) {
+ circuit_json = json_object_new_object();
+ json_object_int_add(circuit_json, "circuit",
+ circuit->circuit_id);
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ for (i = 0; i < 2; i++) {
+ adjdb = circuit->u.bc.adjdb[i];
+ if (adjdb && adjdb->count) {
+ for (ALL_LIST_ELEMENTS_RO(
+ adjdb, node, adj))
+ if (!id ||
+ !memcmp(adj->sysid,
+ sysid,
+ ISIS_SYS_ID_LEN))
+ isis_adj_print_json(
+ adj,
+ circuit_json,
+ detail);
+ }
+ }
+ } else if (circuit->circ_type == CIRCUIT_T_P2P &&
+ circuit->u.p2p.neighbor) {
+ adj = circuit->u.p2p.neighbor;
+ if (!id ||
+ !memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
+ isis_adj_print_json(adj, circuit_json,
+ detail);
+ }
+ json_object_array_add(circuits_json, circuit_json);
+ }
+ json_object_array_add(areas_json, area_json);
+ }
+}
+
+static void isis_neighbor_common_vty(struct vty *vty, const char *id,
+ char detail, struct isis *isis,
+ uint8_t *sysid)
{
struct listnode *anode, *cnode, *node;
struct isis_area *area;
@@ -1103,9 +1308,8 @@ static void isis_neighbor_common(struct vty *vty, const char *id, char detail,
if (adjdb && adjdb->count) {
for (ALL_LIST_ELEMENTS_RO(
adjdb, node, adj))
- if (!id
- || !memcmp(
- adj->sysid,
+ if (!id ||
+ !memcmp(adj->sysid,
sysid,
ISIS_SYS_ID_LEN))
isis_adj_print_vty(
@@ -1114,24 +1318,35 @@ static void isis_neighbor_common(struct vty *vty, const char *id, char detail,
detail);
}
}
- } else if (circuit->circ_type == CIRCUIT_T_P2P
- && circuit->u.p2p.neighbor) {
+ } else if (circuit->circ_type == CIRCUIT_T_P2P &&
+ circuit->u.p2p.neighbor) {
adj = circuit->u.p2p.neighbor;
- if (!id
- || !memcmp(adj->sysid, sysid,
- ISIS_SYS_ID_LEN))
+ if (!id ||
+ !memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
isis_adj_print_vty(adj, vty, detail);
}
}
}
+}
+static void isis_neighbor_common(struct vty *vty, struct json_object *json,
+ const char *id, char detail, struct isis *isis,
+ uint8_t *sysid)
+{
+ if (json) {
+ isis_neighbor_common_json(json, id, detail,isis,sysid);
+ } else {
+ isis_neighbor_common_vty(vty, id, detail,isis,sysid);
+ }
}
+
/*
* 'show isis neighbor' command
*/
-int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
- const char *vrf_name, bool all_vrf)
+int show_isis_neighbor_common(struct vty *vty, struct json_object *json,
+ const char *id, char detail, const char *vrf_name,
+ bool all_vrf)
{
struct listnode *node;
uint8_t sysid[ISIS_SYS_ID_LEN];
@@ -1150,8 +1365,8 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
id);
return CMD_SUCCESS;
}
- isis_neighbor_common(vty, id, detail, isis,
- sysid);
+ isis_neighbor_common(vty, json, id, detail,
+ isis, sysid);
}
return CMD_SUCCESS;
}
@@ -1161,7 +1376,8 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
vty_out(vty, "Invalid system id %s\n", id);
return CMD_SUCCESS;
}
- isis_neighbor_common(vty, id, detail, isis, sysid);
+ isis_neighbor_common(vty, json, id, detail, isis,
+ sysid);
}
}
@@ -1254,64 +1470,91 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_
DEFUN(show_isis_neighbor,
show_isis_neighbor_cmd,
- "show " PROTO_NAME " [vrf <NAME|all>] neighbor",
+ "show " PROTO_NAME " [vrf <NAME|all>] neighbor [json]",
SHOW_STR
PROTO_HELP
VRF_CMD_HELP_STR
"All vrfs\n"
- "IS-IS neighbor adjacencies\n")
+ "IS-IS neighbor adjacencies\n"
+ "json output\n")
{
+ int res = CMD_SUCCESS;
const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false;
int idx_vrf = 0;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
- return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_BRIEF,
- vrf_name, all_vrf);
+ if (uj)
+ json = json_object_new_object();
+ res = show_isis_neighbor_common(vty, json, NULL, ISIS_UI_LEVEL_BRIEF,
+ vrf_name, all_vrf);
+ if (uj)
+ vty_json(vty, json);
+ return res;
}
DEFUN(show_isis_neighbor_detail,
show_isis_neighbor_detail_cmd,
- "show " PROTO_NAME " [vrf <NAME|all>] neighbor detail",
+ "show " PROTO_NAME " [vrf <NAME|all>] neighbor detail [json]",
SHOW_STR
PROTO_HELP
VRF_CMD_HELP_STR
"all vrfs\n"
"IS-IS neighbor adjacencies\n"
- "show detailed information\n")
+ "show detailed information\n"
+ "json output\n")
{
+ int res = CMD_SUCCESS;
const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false;
int idx_vrf = 0;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (uj)
+ json = json_object_new_object();
- return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_DETAIL,
- vrf_name, all_vrf);
+ res = show_isis_neighbor_common(vty, json, NULL, ISIS_UI_LEVEL_DETAIL,
+ vrf_name, all_vrf);
+ if (uj)
+ vty_json(vty, json);
+ return res;
}
DEFUN(show_isis_neighbor_arg,
show_isis_neighbor_arg_cmd,
- "show " PROTO_NAME " [vrf <NAME|all>] neighbor WORD",
+ "show " PROTO_NAME " [vrf <NAME|all>] neighbor WORD [json]",
SHOW_STR
PROTO_HELP
VRF_CMD_HELP_STR
"All vrfs\n"
"IS-IS neighbor adjacencies\n"
- "System id\n")
+ "System id\n"
+ "json output\n")
{
+ int res = CMD_SUCCESS;
int idx_word = 0;
const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false;
int idx_vrf = 0;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (uj)
+ json = json_object_new_object();
char *id = argv_find(argv, argc, "WORD", &idx_word)
? argv[idx_word]->arg
: NULL;
- return show_isis_neighbor_common(vty, id, ISIS_UI_LEVEL_DETAIL,
- vrf_name, all_vrf);
+ res = show_isis_neighbor_common(vty, json, id, ISIS_UI_LEVEL_DETAIL,
+ vrf_name, all_vrf);
+ if (uj)
+ vty_json(vty, json);
+ return res;
}
DEFUN(clear_isis_neighbor,
@@ -2056,7 +2299,152 @@ DEFUN(show_isis_spf_ietf, show_isis_spf_ietf_cmd,
return CMD_SUCCESS;
}
-static void common_isis_summary(struct vty *vty, struct isis *isis)
+
+static const char *pdu_counter_index_to_name_json(enum pdu_counter_index index)
+{
+ switch (index) {
+ case L1_LAN_HELLO_INDEX:
+ return "l1-iih";
+ case L2_LAN_HELLO_INDEX:
+ return "l2-iih";
+ case P2P_HELLO_INDEX:
+ return "p2p-iih";
+ case L1_LINK_STATE_INDEX:
+ return "l1-lsp";
+ case L2_LINK_STATE_INDEX:
+ return "l2-lsp";
+ case FS_LINK_STATE_INDEX:
+ return "fs-lsp";
+ case L1_COMPLETE_SEQ_NUM_INDEX:
+ return "l1-csnp";
+ case L2_COMPLETE_SEQ_NUM_INDEX:
+ return "l2-csnp";
+ case L1_PARTIAL_SEQ_NUM_INDEX:
+ return "l1-psnp";
+ case L2_PARTIAL_SEQ_NUM_INDEX:
+ return "l2-psnp";
+ default:
+ return "???????";
+ }
+}
+
+static void common_isis_summary_json(struct json_object *json,
+ struct isis *isis)
+{
+ int level;
+ json_object *areas_json, *area_json, *tx_pdu_json, *rx_pdu_json,
+ *levels_json, *level_json;
+ struct listnode *node, *node2;
+ struct isis_area *area;
+ time_t cur;
+ char uptime[MONOTIME_STRLEN];
+ char stier[5];
+ json_object_string_add(json, "vrf", isis->name);
+ json_object_int_add(json, "process-id", isis->process_id);
+ if (isis->sysid_set)
+ json_object_string_add(json, "system-id",
+ sysid_print(isis->sysid));
+
+ cur = time(NULL);
+ cur -= isis->uptime;
+ frrtime_to_interval(cur, uptime, sizeof(uptime));
+ json_object_string_add(json, "up-time", uptime);
+ if (isis->area_list)
+ json_object_int_add(json, "number-areas",
+ isis->area_list->count);
+ areas_json = json_object_new_array();
+ json_object_object_add(json, "areas", areas_json);
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ area_json = json_object_new_object();
+ json_object_string_add(area_json, "area",
+ area->area_tag ? area->area_tag
+ : "null");
+
+
+ if (fabricd) {
+ uint8_t tier = fabricd_tier(area);
+ snprintfrr(stier, sizeof(stier), "%s", &tier);
+ json_object_string_add(area_json, "tier",
+ tier == ISIS_TIER_UNDEFINED
+ ? "undefined"
+ : stier);
+ }
+
+ if (listcount(area->area_addrs) > 0) {
+ struct area_addr *area_addr;
+ for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node2,
+ area_addr)) {
+ json_object_string_add(
+ area_json, "net",
+ isonet_print(area_addr->area_addr,
+ area_addr->addr_len +
+ ISIS_SYS_ID_LEN +
+ 1));
+ }
+ }
+
+ tx_pdu_json = json_object_new_object();
+ json_object_object_add(area_json, "tx-pdu-type", tx_pdu_json);
+ for (int i = 0; i < PDU_COUNTER_SIZE; i++) {
+ if (!area->pdu_tx_counters[i])
+ continue;
+ json_object_int_add(tx_pdu_json,
+ pdu_counter_index_to_name_json(i),
+ area->pdu_tx_counters[i]);
+ }
+ json_object_int_add(tx_pdu_json, "lsp-rxmt",
+ area->lsp_rxmt_count);
+
+ rx_pdu_json = json_object_new_object();
+ json_object_object_add(area_json, "rx-pdu-type", rx_pdu_json);
+ for (int i = 0; i < PDU_COUNTER_SIZE; i++) {
+ if (!area->pdu_rx_counters[i])
+ continue;
+ json_object_int_add(rx_pdu_json,
+ pdu_counter_index_to_name_json(i),
+ area->pdu_rx_counters[i]);
+ }
+
+ levels_json = json_object_new_array();
+ json_object_object_add(area_json, "levels", levels_json);
+ for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
+ if ((area->is_type & level) == 0)
+ continue;
+ level_json = json_object_new_object();
+ json_object_int_add(level_json, "id", level);
+ json_object_int_add(level_json, "lsp0-regenerated",
+ area->lsp_gen_count[level - 1]);
+ json_object_int_add(level_json, "lsp-purged",
+ area->lsp_purge_count[level - 1]);
+ if (area->spf_timer[level - 1])
+ json_object_string_add(level_json, "spf",
+ "pending");
+ else
+ json_object_string_add(level_json, "spf",
+ "no pending");
+ json_object_int_add(level_json, "minimum-interval",
+ area->min_spf_interval[level - 1]);
+ if (area->spf_delay_ietf[level - 1])
+ json_object_string_add(
+ level_json, "ietf-spf-delay-activated",
+ "not used");
+ if (area->ip_circuits) {
+ isis_spf_print_json(
+ area->spftree[SPFTREE_IPV4][level - 1],
+ level_json);
+ }
+ if (area->ipv6_circuits) {
+ isis_spf_print_json(
+ area->spftree[SPFTREE_IPV6][level - 1],
+ level_json);
+ }
+ json_object_array_add(levels_json, level_json);
+ }
+ json_object_array_add(areas_json, area_json);
+ }
+}
+
+static void common_isis_summary_vty(struct vty *vty, struct isis *isis)
{
struct listnode *node, *node2;
struct isis_area *area;
@@ -2156,10 +2544,21 @@ static void common_isis_summary(struct vty *vty, struct isis *isis)
}
}
+static void common_isis_summary(struct vty *vty, struct json_object *json,
+ struct isis *isis)
+{
+ if (json) {
+ common_isis_summary_json(json, isis);
+ } else {
+ common_isis_summary_vty(vty, isis);
+ }
+}
+
DEFUN(show_isis_summary, show_isis_summary_cmd,
- "show " PROTO_NAME " [vrf <NAME|all>] summary",
+ "show " PROTO_NAME " [vrf <NAME|all>] summary [json]",
SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
"All VRFs\n"
+ "json output\n"
"summary\n")
{
struct listnode *node;
@@ -2167,25 +2566,30 @@ DEFUN(show_isis_summary, show_isis_summary_cmd,
struct isis *isis;
const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf)
if (!im) {
vty_out(vty, PROTO_NAME " is not running\n");
return CMD_SUCCESS;
}
+ if (uj)
+ json = json_object_new_object();
if (vrf_name) {
if (all_vrf) {
for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
- common_isis_summary(vty, isis);
+ common_isis_summary(vty, json, isis);
return CMD_SUCCESS;
}
isis = isis_lookup_by_vrfname(vrf_name);
if (isis != NULL)
- common_isis_summary(vty, isis);
+ common_isis_summary(vty, json, isis);
}
- vty_out(vty, "\n");
+ if (uj)
+ vty_json(vty, json);
return CMD_SUCCESS;
}
@@ -2250,9 +2654,40 @@ struct isis_lsp *lsp_for_sysid(struct lspdb_head *head, const char *sysid_str,
return lsp;
}
-void show_isis_database_lspdb(struct vty *vty, struct isis_area *area,
- int level, struct lspdb_head *lspdb,
- const char *sysid_str, int ui_level)
+void show_isis_database_lspdb_json(struct json_object *json,
+ struct isis_area *area, int level,
+ struct lspdb_head *lspdb,
+ const char *sysid_str, int ui_level)
+{
+ struct isis_lsp *lsp;
+ int lsp_count;
+
+ if (lspdb_count(lspdb) > 0) {
+ lsp = lsp_for_sysid(lspdb, sysid_str, area->isis);
+
+ if (lsp != NULL || sysid_str == NULL) {
+ json_object_int_add(json, "id", level + 1);
+ }
+
+ if (lsp) {
+ if (ui_level == ISIS_UI_LEVEL_DETAIL)
+ lsp_print_detail(lsp, NULL, json,
+ area->dynhostname, area->isis);
+ else
+ lsp_print_json(lsp, json, area->dynhostname,
+ area->isis);
+ } else if (sysid_str == NULL) {
+ lsp_count =
+ lsp_print_all(NULL, json, lspdb, ui_level,
+ area->dynhostname, area->isis);
+
+ json_object_int_add(json, "count", lsp_count);
+ }
+ }
+}
+void show_isis_database_lspdb_vty(struct vty *vty, struct isis_area *area,
+ int level, struct lspdb_head *lspdb,
+ const char *sysid_str, int ui_level)
{
struct isis_lsp *lsp;
int lsp_count;
@@ -2271,14 +2706,14 @@ void show_isis_database_lspdb(struct vty *vty, struct isis_area *area,
if (lsp) {
if (ui_level == ISIS_UI_LEVEL_DETAIL)
- lsp_print_detail(lsp, vty, area->dynhostname,
- area->isis);
+ lsp_print_detail(lsp, vty, NULL,
+ area->dynhostname, area->isis);
else
- lsp_print(lsp, vty, area->dynhostname,
- area->isis);
+ lsp_print_vty(lsp, vty, area->dynhostname,
+ area->isis);
} else if (sysid_str == NULL) {
lsp_count =
- lsp_print_all(vty, lspdb, ui_level,
+ lsp_print_all(vty, NULL, lspdb, ui_level,
area->dynhostname, area->isis);
vty_out(vty, " %u LSPs\n\n", lsp_count);
@@ -2286,7 +2721,43 @@ void show_isis_database_lspdb(struct vty *vty, struct isis_area *area,
}
}
-static void show_isis_database_common(struct vty *vty, const char *sysid_str,
+static void show_isis_database_json(struct json_object *json, const char *sysid_str,
+ int ui_level, struct isis *isis)
+{
+ struct listnode *node;
+ struct isis_area *area;
+ int level;
+ struct json_object *tag_area_json,*area_json, *lsp_json, *area_arr_json, *arr_json;
+ uint8_t area_cnt = 0;
+
+ if (isis->area_list->count == 0)
+ return;
+
+ area_arr_json = json_object_new_array();
+ json_object_object_add(json, "areas", area_arr_json);
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ area_json = json_object_new_object();
+ tag_area_json = json_object_new_object();
+ json_object_string_add(tag_area_json, "name",
+ area->area_tag ? area->area_tag
+ : "null");
+
+ arr_json = json_object_new_array();
+ json_object_object_add(area_json,"area",tag_area_json);
+ json_object_object_add(area_json,"levels",arr_json);
+ for (level = 0; level < ISIS_LEVELS; level++) {
+ lsp_json = json_object_new_object();
+ show_isis_database_lspdb_json(lsp_json, area, level,
+ &area->lspdb[level],
+ sysid_str, ui_level);
+ json_object_array_add(arr_json, lsp_json);
+ }
+ json_object_array_add(area_arr_json, area_json);
+ area_cnt++;
+ }
+}
+
+static void show_isis_database_vty(struct vty *vty, const char *sysid_str,
int ui_level, struct isis *isis)
{
struct listnode *node;
@@ -2301,11 +2772,22 @@ static void show_isis_database_common(struct vty *vty, const char *sysid_str,
area->area_tag ? area->area_tag : "null");
for (level = 0; level < ISIS_LEVELS; level++)
- show_isis_database_lspdb(vty, area, level,
+ show_isis_database_lspdb_vty(vty, area, level,
&area->lspdb[level], sysid_str,
ui_level);
}
}
+
+static void show_isis_database_common(struct vty *vty, struct json_object *json, const char *sysid_str,
+ int ui_level, struct isis *isis)
+{
+ if (json) {
+ show_isis_database_json(json, sysid_str, ui_level, isis);
+ } else {
+ show_isis_database_vty(vty, sysid_str, ui_level, isis);
+ }
+}
+
/*
* This function supports following display options:
* [ show isis database [detail] ]
@@ -2322,7 +2804,7 @@ static void show_isis_database_common(struct vty *vty, const char *sysid_str,
* [ show isis database detail <sysid>.<pseudo-id>-<fragment-number> ]
* [ show isis database detail <hostname>.<pseudo-id>-<fragment-number> ]
*/
-static int show_isis_database(struct vty *vty, const char *sysid_str,
+static int show_isis_database(struct vty *vty, struct json_object *json, const char *sysid_str,
int ui_level, const char *vrf_name, bool all_vrf)
{
struct listnode *node;
@@ -2331,28 +2813,30 @@ static int show_isis_database(struct vty *vty, const char *sysid_str,
if (vrf_name) {
if (all_vrf) {
for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
- show_isis_database_common(vty, sysid_str,
+ show_isis_database_common(vty, json, sysid_str,
ui_level, isis);
return CMD_SUCCESS;
}
isis = isis_lookup_by_vrfname(vrf_name);
if (isis)
- show_isis_database_common(vty, sysid_str, ui_level,
- isis);
+ show_isis_database_common(vty, json, sysid_str,
+ ui_level, isis);
}
return CMD_SUCCESS;
}
DEFUN(show_database, show_database_cmd,
- "show " PROTO_NAME " [vrf <NAME|all>] database [detail] [WORD]",
+ "show " PROTO_NAME " [vrf <NAME|all>] database [detail] [WORD] [json]",
SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
"All VRFs\n"
"Link state database\n"
"Detailed information\n"
- "LSP ID\n")
+ "LSP ID\n"
+ "json output\n")
{
+ int res = CMD_SUCCESS;
int idx = 0;
int idx_vrf = 0;
const char *vrf_name = VRF_DEFAULT_NAME;
@@ -2361,8 +2845,17 @@ DEFUN(show_database, show_database_cmd,
? ISIS_UI_LEVEL_DETAIL
: ISIS_UI_LEVEL_BRIEF;
char *id = argv_find(argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
+
ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
- return show_isis_database(vty, id, uilevel, vrf_name, all_vrf);
+ if (uj)
+ json = json_object_new_object();
+
+ res = show_isis_database(vty, json, id, uilevel, vrf_name, all_vrf);
+ if (uj)
+ vty_json(vty, json);
+ return res;
}
#ifdef FABRICD
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 7f8474a5f2..c313fd9ef7 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -89,6 +89,8 @@ struct isis_master {
};
#define F_ISIS_UNIT_TEST 0x01
+#define ISIS_DEFAULT_MAX_AREA_ADDRESSES 3
+
struct isis {
vrf_id_t vrf_id;
char *name;
@@ -305,9 +307,13 @@ int isis_area_passwd_cleartext_set(struct isis_area *area, int level,
const char *passwd, uint8_t snp_auth);
int isis_area_passwd_hmac_md5_set(struct isis_area *area, int level,
const char *passwd, uint8_t snp_auth);
-void show_isis_database_lspdb(struct vty *vty, struct isis_area *area,
- int level, struct lspdb_head *lspdb,
- const char *argv, int ui_level);
+void show_isis_database_lspdb_json(struct json_object *json,
+ struct isis_area *area, int level,
+ struct lspdb_head *lspdb, const char *argv,
+ int ui_level);
+void show_isis_database_lspdb_vty(struct vty *vty, struct isis_area *area,
+ int level, struct lspdb_head *lspdb,
+ const char *argv, int ui_level);
/* YANG paths */
#define ISIS_INSTANCE "/frr-isisd:isis/instance"
diff --git a/lib/json.c b/lib/json.c
index 854a3d59d1..d85a21215c 100644
--- a/lib/json.c
+++ b/lib/json.c
@@ -74,6 +74,19 @@ void json_object_string_addv(struct json_object *obj, const char *key,
json_object_object_add(obj, key, json_object_new_stringv(fmt, args));
}
+void json_object_object_addv(struct json_object *parent,
+ struct json_object *child, const char *keyfmt,
+ va_list args)
+{
+ char *text, buf[256];
+
+ text = vasnprintfrr(MTYPE_TMP, buf, sizeof(buf), keyfmt, args);
+ json_object_object_add(parent, text, child);
+
+ if (text != buf)
+ XFREE(MTYPE_TMP, text);
+}
+
void json_object_int_add(struct json_object *obj, const char *key, int64_t i)
{
json_object_object_add(obj, key, json_object_new_int64(i));
diff --git a/lib/json.h b/lib/json.h
index fcaa84c816..78c3836515 100644
--- a/lib/json.h
+++ b/lib/json.h
@@ -116,6 +116,28 @@ static inline struct json_object *json_object_new_stringf(const char *fmt, ...)
return ret;
}
+/* NOTE: argument order differs! (due to varargs)
+ * json_object_object_add(parent, key, child)
+ * json_object_object_addv(parent, child, key, va)
+ * json_object_object_addf(parent, child, key, ...)
+ * (would be weird to have the child inbetween the format string and args)
+ */
+PRINTFRR(3, 0)
+extern void json_object_object_addv(struct json_object *parent,
+ struct json_object *child,
+ const char *keyfmt, va_list args);
+PRINTFRR(3, 4)
+static inline void json_object_object_addf(struct json_object *parent,
+ struct json_object *child,
+ const char *keyfmt, ...)
+{
+ va_list args;
+
+ va_start(args, keyfmt);
+ json_object_object_addv(parent, child, keyfmt, args);
+ va_end(args);
+}
+
#define JSON_STR "JavaScript Object Notation\n"
/* NOTE: json-c lib has following commit 316da85 which
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 10b3aad89e..042c9d3704 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -333,6 +333,8 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
umask(0027);
+ log_args_init(daemon->early_logging);
+
opt_extend(&os_always);
if (!(di->flags & FRR_NO_SPLIT_CONFIG))
opt_extend(&os_cfg);
@@ -431,6 +433,8 @@ static int frr_opt(int opt)
static int vty_port_set = 0;
static int vty_addr_set = 0;
struct option_chain *oc;
+ struct log_arg *log_arg;
+ size_t arg_len;
char *err;
switch (opt) {
@@ -613,7 +617,10 @@ static int frr_opt(int opt)
di->privs->group = optarg;
break;
case OPTION_LOG:
- di->early_logging = optarg;
+ arg_len = strlen(optarg) + 1;
+ log_arg = XCALLOC(MTYPE_TMP, sizeof(*log_arg) + arg_len);
+ memcpy(log_arg->target, optarg, arg_len);
+ log_args_add_tail(di->early_logging, log_arg);
break;
case OPTION_LOGLEVEL:
di->early_loglevel = optarg;
@@ -706,10 +713,12 @@ static struct thread_master *master;
struct thread_master *frr_init(void)
{
struct option_chain *oc;
+ struct log_arg *log_arg;
struct frrmod_runtime *module;
struct zprivs_ids_t ids;
char p_instance[16] = "", p_pathspace[256] = "";
const char *dir;
+
dir = di->module_path ? di->module_path : frr_moduledir;
srandom(time(NULL));
@@ -739,7 +748,11 @@ struct thread_master *frr_init(void)
zlog_init(di->progname, di->logname, di->instance,
ids.uid_normal, ids.gid_normal);
- command_setup_early_logging(di->early_logging, di->early_loglevel);
+ while ((log_arg = log_args_pop(di->early_logging))) {
+ command_setup_early_logging(log_arg->target,
+ di->early_loglevel);
+ XFREE(MTYPE_TMP, log_arg);
+ }
if (!frr_zclient_addr(&zclient_addr, &zclient_addr_len,
frr_zclientpath)) {
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 65c1df9675..69054e4264 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -21,6 +21,7 @@
#ifndef _ZEBRA_FRR_H
#define _ZEBRA_FRR_H
+#include "typesafe.h"
#include "sigevent.h"
#include "privs.h"
#include "thread.h"
@@ -52,6 +53,14 @@ extern "C" {
*/
#define FRR_DETACH_LATER (1 << 6)
+PREDECL_DLIST(log_args);
+struct log_arg {
+ struct log_args_item itm;
+
+ char target[0];
+};
+DECLARE_DLIST(log_args, struct log_arg, itm);
+
enum frr_cli_mode {
FRR_CLI_CLASSIC = 0,
FRR_CLI_TRANSACTIONAL,
@@ -88,7 +97,7 @@ struct frr_daemon_info {
const char *pathspace;
bool zpathspace;
- const char *early_logging;
+ struct log_args_head early_logging[1];
const char *early_loglevel;
const char *proghelp;
diff --git a/lib/log_vty.c b/lib/log_vty.c
index 682c9ea372..ef33a39d4a 100644
--- a/lib/log_vty.c
+++ b/lib/log_vty.c
@@ -427,6 +427,22 @@ void command_setup_early_logging(const char *dest, const char *level)
set_log_file(&zt_file_cmdline, NULL, sep, nlevel);
return;
}
+ if (strcmp(type, "monitor") == 0 && sep) {
+ struct zlog_live_cfg cfg = {};
+ unsigned long fd;
+ char *endp;
+
+ sep++;
+ fd = strtoul(sep, &endp, 10);
+ if (!*sep || *endp) {
+ fprintf(stderr, "invalid monitor fd \"%s\"\n", sep);
+ exit(1);
+ }
+
+ zlog_live_open_fd(&cfg, nlevel, fd);
+ zlog_live_disown(&cfg);
+ return;
+ }
fprintf(stderr, "invalid log target \"%s\" (\"%s\")\n", type, dest);
exit(1);
diff --git a/lib/prefix.c b/lib/prefix.c
index 90ab48a13b..89c5be8f38 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -1071,6 +1071,26 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size)
return str;
}
+static ssize_t prefixhost2str(struct fbuf *fbuf, union prefixconstptr pu)
+{
+ const struct prefix *p = pu.p;
+ char buf[PREFIX2STR_BUFFER];
+
+ switch (p->family) {
+ case AF_INET:
+ case AF_INET6:
+ inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf));
+ return bputs(fbuf, buf);
+
+ case AF_ETHERNET:
+ prefix_mac2str(&p->u.prefix_eth, buf, sizeof(buf));
+ return bputs(fbuf, buf);
+
+ default:
+ return bprintfrr(fbuf, "{prefix.af=%dPF}", p->family);
+ }
+}
+
void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr,
char *buf, int buf_size)
{
@@ -1458,13 +1478,24 @@ printfrr_ext_autoreg_p("FX", printfrr_pfx);
static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
{
- char cbuf[PREFIX_STRLEN];
+ bool host_only = false;
+
+ if (ea->fmt[0] == 'h') {
+ ea->fmt++;
+ host_only = true;
+ }
if (!ptr)
return bputs(buf, "(null)");
- prefix2str(ptr, cbuf, sizeof(cbuf));
- return bputs(buf, cbuf);
+ if (host_only)
+ return prefixhost2str(buf, (struct prefix *)ptr);
+ else {
+ char cbuf[PREFIX_STRLEN];
+
+ prefix2str(ptr, cbuf, sizeof(cbuf));
+ return bputs(buf, cbuf);
+ }
}
printfrr_ext_autoreg_p("PSG4", printfrr_psg);
diff --git a/lib/zlog.c b/lib/zlog.c
index 85606d2624..e0bb34a258 100644
--- a/lib/zlog.c
+++ b/lib/zlog.c
@@ -401,7 +401,7 @@ void zlog_tls_buffer_flush(void)
return;
rcu_read_lock();
- frr_each (zlog_targets, &zlog_targets, zt) {
+ frr_each_safe (zlog_targets, &zlog_targets, zt) {
if (!zt->logfn)
continue;
@@ -431,7 +431,7 @@ static void vzlog_notls(const struct xref_logmsg *xref, int prio,
msg->stackbufsz = sizeof(stackbuf);
rcu_read_lock();
- frr_each (zlog_targets, &zlog_targets, zt) {
+ frr_each_safe (zlog_targets, &zlog_targets, zt) {
if (prio > zt->prio_min)
continue;
if (!zt->logfn)
diff --git a/lib/zlog_live.c b/lib/zlog_live.c
index fbe0e5ee49..931aa3461d 100644
--- a/lib/zlog_live.c
+++ b/lib/zlog_live.c
@@ -22,6 +22,7 @@
#include "frrcu.h"
#include "zlog.h"
#include "printfrr.h"
+#include "network.h"
DEFINE_MTYPE_STATIC(LOG, LOG_LIVE, "log vtysh live target");
@@ -39,6 +40,7 @@ struct zlt_live {
struct rcu_head head_self;
atomic_uint_fast32_t state;
+ atomic_uint_fast32_t lost_msgs;
};
static void zlog_live(struct zlog_target *zt, struct zlog_msg *msgs[],
@@ -63,14 +65,16 @@ static void zlog_live(struct zlog_target *zt, struct zlog_msg *msgs[],
for (i = 0; i < nmsgs; i++) {
const struct fmt_outpos *argpos;
- size_t n_argpos, arghdrlen;
+ size_t n_argpos, texthdrlen;
struct zlog_msg *msg = msgs[i];
int prio = zlog_msg_prio(msg);
+ const struct xref_logmsg *xref;
+ intmax_t pid, tid;
if (prio > zt->prio_min)
continue;
- zlog_msg_args(msg, &arghdrlen, &n_argpos, &argpos);
+ zlog_msg_args(msg, &texthdrlen, &n_argpos, &argpos);
mmh->msg_hdr.msg_iov = iov;
@@ -89,14 +93,29 @@ static void zlog_live(struct zlog_target *zt, struct zlog_msg *msgs[],
iov++;
zlog_msg_tsraw(msg, &ts);
+ zlog_msg_pid(msg, &pid, &tid);
+ xref = zlog_msg_xref(msg);
hdr->ts_sec = ts.tv_sec;
hdr->ts_nsec = ts.tv_nsec;
- hdr->prio = zlog_msg_prio(msg);
+ hdr->pid = pid;
+ hdr->tid = tid;
+ hdr->lost_msgs = atomic_load_explicit(&zte->lost_msgs,
+ memory_order_relaxed);
+ hdr->prio = prio;
hdr->flags = 0;
hdr->textlen = textlen;
- hdr->arghdrlen = arghdrlen;
+ hdr->texthdrlen = texthdrlen;
hdr->n_argpos = n_argpos;
+ if (xref) {
+ memcpy(hdr->uid, xref->xref.xrefdata->uid,
+ sizeof(hdr->uid));
+ hdr->ec = xref->ec;
+ } else {
+ memset(hdr->uid, 0, sizeof(hdr->uid));
+ hdr->ec = 0;
+ }
+ hdr->hdrlen = sizeof(*hdr) + sizeof(*argpos) * n_argpos;
mmh->msg_hdr.msg_iovlen = iov - mmh->msg_hdr.msg_iov;
mmh++;
@@ -109,6 +128,12 @@ static void zlog_live(struct zlog_target *zt, struct zlog_msg *msgs[],
for (size_t msgpos = 0; msgpos < msgtotal; msgpos += sent) {
sent = sendmmsg(fd, mmhs + msgpos, msgtotal - msgpos, 0);
+ if (sent <= 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ atomic_fetch_add_explicit(&zte->lost_msgs,
+ msgtotal - msgpos,
+ memory_order_relaxed);
+ break;
+ }
if (sent <= 0)
goto out_err;
}
@@ -134,7 +159,7 @@ static void zlog_live_sigsafe(struct zlog_target *zt, const char *text,
size_t len)
{
struct zlt_live *zte = container_of(zt, struct zlt_live, zt);
- struct zlog_live_hdr hdr[1];
+ struct zlog_live_hdr hdr[1] = {};
struct iovec iovs[2], *iov = iovs;
struct timespec ts;
int fd;
@@ -143,14 +168,12 @@ static void zlog_live_sigsafe(struct zlog_target *zt, const char *text,
if (fd < 0)
return;
- clock_gettime(CLOCK_MONOTONIC, &ts);
+ clock_gettime(CLOCK_REALTIME, &ts);
hdr->ts_sec = ts.tv_sec;
hdr->ts_nsec = ts.tv_nsec;
hdr->prio = LOG_CRIT;
- hdr->flags = 0;
hdr->textlen = len;
- hdr->n_argpos = 0;
iov->iov_base = (char *)hdr;
iov->iov_len = sizeof(hdr);
@@ -166,8 +189,6 @@ static void zlog_live_sigsafe(struct zlog_target *zt, const char *text,
void zlog_live_open(struct zlog_live_cfg *cfg, int prio_min, int *other_fd)
{
int sockets[2];
- struct zlt_live *zte;
- struct zlog_target *zt;
if (cfg->target)
zlog_live_close(cfg);
@@ -192,12 +213,23 @@ void zlog_live_open(struct zlog_live_cfg *cfg, int prio_min, int *other_fd)
shutdown(sockets[0], SHUT_RD);
*other_fd = sockets[1];
+ zlog_live_open_fd(cfg, prio_min, sockets[0]);
+}
+
+void zlog_live_open_fd(struct zlog_live_cfg *cfg, int prio_min, int fd)
+{
+ struct zlt_live *zte;
+ struct zlog_target *zt;
+
+ if (cfg->target)
+ zlog_live_close(cfg);
zt = zlog_target_clone(MTYPE_LOG_LIVE, NULL, sizeof(*zte));
zte = container_of(zt, struct zlt_live, zt);
cfg->target = zte;
- zte->fd = sockets[0];
+ set_nonblocking(fd);
+ zte->fd = fd;
zte->zt.prio_min = prio_min;
zte->zt.logfn = zlog_live;
zte->zt.logfn_sigsafe = zlog_live_sigsafe;
diff --git a/lib/zlog_live.h b/lib/zlog_live.h
index c948baeab1..55e60ae674 100644
--- a/lib/zlog_live.h
+++ b/lib/zlog_live.h
@@ -20,13 +20,42 @@
#include "printfrr.h"
struct zlog_live_hdr {
+ /* timestamp (CLOCK_REALTIME) */
uint64_t ts_sec;
uint32_t ts_nsec;
+
+ /* length of zlog_live_hdr, including variable length bits and
+ * possible future extensions - aka start of text
+ */
+ uint32_t hdrlen;
+
+ /* process & thread ID, meaning depends on OS */
+ int64_t pid;
+ int64_t tid;
+
+ /* number of lost messages due to best-effort non-blocking mode */
+ uint32_t lost_msgs;
+ /* syslog priority value */
uint32_t prio;
+ /* flags: currently unused */
uint32_t flags;
+ /* length of message text - extra data (e.g. future key/value metadata)
+ * may follow after it
+ */
uint32_t textlen;
+ /* length of "[XXXXX-XXXXX][EC 0] " header; consumer may want to skip
+ * over it if using the raw values below. Note that this text may be
+ * absent depending on "log error-category" and "log unique-id"
+ * settings
+ */
+ uint32_t texthdrlen;
+
+ /* xref unique identifier, "XXXXX-XXXXX\0" = 12 bytes */
+ char uid[12];
+ /* EC value */
+ uint32_t ec;
- uint32_t arghdrlen;
+ /* recorded printf formatting argument positions (variable length) */
uint32_t n_argpos;
struct fmt_outpos argpos[0];
};
@@ -41,6 +70,7 @@ struct zlog_live_cfg {
extern void zlog_live_open(struct zlog_live_cfg *cfg, int prio_min,
int *other_fd);
+extern void zlog_live_open_fd(struct zlog_live_cfg *cfg, int prio_min, int fd);
static inline bool zlog_live_is_null(struct zlog_live_cfg *cfg)
{
diff --git a/ospf6d/ospf6_gr.c b/ospf6d/ospf6_gr.c
index d618ed86e0..87407245b3 100644
--- a/ospf6d/ospf6_gr.c
+++ b/ospf6d/ospf6_gr.c
@@ -689,7 +689,7 @@ DEFPY(ospf6_graceful_restart_prepare, ospf6_graceful_restart_prepare_cmd,
"graceful-restart prepare ipv6 ospf",
"Graceful Restart commands\n"
"Prepare upcoming graceful restart\n" IPV6_STR
- "Prepare to restart the OSPFv3 process")
+ "Prepare to restart the OSPFv3 process\n")
{
ospf6_gr_prepare();
diff --git a/ospfd/ospf_gr.c b/ospfd/ospf_gr.c
index ee1ca256e3..2521f2fce0 100644
--- a/ospfd/ospf_gr.c
+++ b/ospfd/ospf_gr.c
@@ -730,7 +730,7 @@ DEFPY(graceful_restart_prepare, graceful_restart_prepare_cmd,
"Graceful Restart commands\n"
"Prepare upcoming graceful restart\n"
IP_STR
- "Prepare to restart the OSPF process")
+ "Prepare to restart the OSPF process\n")
{
struct ospf *ospf;
struct listnode *node;
diff --git a/pimd/pim6_stubs.c b/pimd/pim6_stubs.c
index dab46b2892..e689c7aca4 100644
--- a/pimd/pim6_stubs.c
+++ b/pimd/pim6_stubs.c
@@ -29,40 +29,6 @@
/*
* NH lookup / NHT
*/
-void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
- struct pim_nexthop_cache *pnc, int command)
-{
-}
-
-int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
- struct pim_nexthop *nexthop, struct prefix *src,
- struct prefix *grp, int neighbor_needed)
-{
- return 0;
-}
-
-int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr,
- struct pim_upstream *up, struct rp_info *rp,
- struct pim_nexthop_cache *out_pnc)
-{
- return 0;
-}
-
-void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
- struct pim_upstream *up, struct rp_info *rp)
-{
-}
-
-struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim,
- struct pim_rpf *rpf)
-{
- return NULL;
-}
-
-void pim_rp_nexthop_del(struct rp_info *rp_info)
-{
-}
-
void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr)
{
}
diff --git a/pimd/pim_br.c b/pimd/pim_br.c
index 3e64296deb..6ec6b11e7b 100644
--- a/pimd/pim_br.c
+++ b/pimd/pim_br.c
@@ -30,14 +30,12 @@
struct pim_br {
pim_sgaddr sg;
- struct in_addr pmbr;
+ pim_addr pmbr;
};
-struct in_addr pim_br_unknown = {.s_addr = 0};
-
static struct list *pim_br_list = NULL;
-struct in_addr pim_br_get_pmbr(pim_sgaddr *sg)
+pim_addr pim_br_get_pmbr(pim_sgaddr *sg)
{
struct listnode *node;
struct pim_br *pim_br;
@@ -47,10 +45,10 @@ struct in_addr pim_br_get_pmbr(pim_sgaddr *sg)
return pim_br->pmbr;
}
- return pim_br_unknown;
+ return PIMADDR_ANY;
}
-void pim_br_set_pmbr(pim_sgaddr *sg, struct in_addr br)
+void pim_br_set_pmbr(pim_sgaddr *sg, pim_addr br)
{
struct listnode *node, *next;
struct pim_br *pim_br;
diff --git a/pimd/pim_br.h b/pimd/pim_br.h
index ef24ef3c19..7b87c0f1fd 100644
--- a/pimd/pim_br.h
+++ b/pimd/pim_br.h
@@ -20,13 +20,11 @@
#ifndef PIM_BR_H
#define PIM_BR_H
-struct in_addr pim_br_get_pmbr(pim_sgaddr *sg);
+pim_addr pim_br_get_pmbr(pim_sgaddr *sg);
-void pim_br_set_pmbr(pim_sgaddr *sg, struct in_addr value);
+void pim_br_set_pmbr(pim_sgaddr *sg, pim_addr value);
void pim_br_clear_pmbr(pim_sgaddr *sg);
void pim_br_init(void);
-extern struct in_addr pim_br_unknown;
-
#endif
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c
index 956ab0d67c..f9fb8cf094 100644
--- a/pimd/pim_ifchannel.c
+++ b/pimd/pim_ifchannel.c
@@ -872,7 +872,7 @@ void pim_ifchannel_join_add(struct interface *ifp, pim_addr neigh_addr,
address of the join message is our primary address.
*/
if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
- zlog_warn("%s: Assert Loser recv Join%s from %pI4 on %s",
+ zlog_warn("%s: Assert Loser recv Join%s from %pPA on %s",
__func__, ch->sg_str, &neigh_addr, ifp->name);
assert_action_a5(ch);
diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h
index 522e94504a..456c356d9f 100644
--- a/pimd/pim_msg.h
+++ b/pimd/pim_msg.h
@@ -21,6 +21,9 @@
#define PIM_MSG_H
#include <netinet/in.h>
+#if PIM_IPV == 6
+#include <netinet/ip6.h>
+#endif
#include "pim_jp_agg.h"
@@ -181,6 +184,30 @@ struct pim_jp {
struct pim_jp_groups groups[1];
} __attribute__((packed));
+#if PIM_IPV == 4
+static inline pim_sgaddr pim_sgaddr_from_iphdr(const void *iphdr)
+{
+ const struct ip *ipv4_hdr = iphdr;
+ pim_sgaddr sg;
+
+ sg.src = ipv4_hdr->ip_src;
+ sg.grp = ipv4_hdr->ip_dst;
+
+ return sg;
+}
+#else
+static inline pim_sgaddr pim_sgaddr_from_iphdr(const void *iphdr)
+{
+ const struct ip6_hdr *ipv6_hdr = iphdr;
+ pim_sgaddr sg;
+
+ sg.src = ipv6_hdr->ip6_src;
+ sg.grp = ipv6_hdr->ip6_dst;
+
+ return sg;
+}
+#endif
+
void pim_msg_build_header(uint8_t *pim_msg, size_t pim_msg_size,
uint8_t pim_msg_type, bool no_fwd);
uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, struct in_addr addr);
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index 48dd565b25..80d214b2f7 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -162,6 +162,7 @@ int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr,
return 0;
}
+#if PIM_IPV == 4
void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr)
{
struct pim_nexthop_cache *pnc;
@@ -175,6 +176,7 @@ void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr)
pnc->bsr_count++;
}
+#endif /* PIM_IPV == 4 */
static void pim_nht_drop_maybe(struct pim_instance *pim,
struct pim_nexthop_cache *pnc)
@@ -244,6 +246,7 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
pim_nht_drop_maybe(pim, pnc);
}
+#if PIM_IPV == 4
void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr addr)
{
struct pim_nexthop_cache *pnc = NULL;
@@ -398,6 +401,7 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr,
}
return false;
}
+#endif /* PIM_IPV == 4 */
void pim_rp_nexthop_del(struct rp_info *rp_info)
{
@@ -482,23 +486,13 @@ static int pim_update_upstream_nh(struct pim_instance *pim,
uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp)
{
uint32_t hash_val;
- uint32_t s = 0, g = 0;
- if ((!src))
+ if (!src)
return 0;
- switch (src->family) {
- case AF_INET: {
- s = src->u.prefix4.s_addr;
- s = s == 0 ? 1 : s;
- if (grp)
- g = grp->u.prefix4.s_addr;
- } break;
- default:
- break;
- }
-
- hash_val = jhash_2words(g, s, 101);
+ hash_val = prefix_hash_key(src);
+ if (grp)
+ hash_val ^= prefix_hash_key(grp);
return hash_val;
}
@@ -549,9 +543,9 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
break;
}
- if (curr_route_valid
- && !pim_if_connected_to_source(nexthop->interface,
- src->u.prefix4)) {
+ if (curr_route_valid &&
+ !pim_if_connected_to_source(nexthop->interface,
+ src_addr)) {
nbr = pim_neighbor_find_prefix(
nexthop->interface,
&nexthop->mrib_nexthop_addr);
@@ -668,7 +662,7 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
nh_node->gate.ipv4;
#else
nexthop->mrib_nexthop_addr.u.prefix6 =
- nh_node->gate->ipv6;
+ nh_node->gate.ipv6;
#endif
nexthop->mrib_metric_preference = pnc->distance;
nexthop->mrib_route_metric = pnc->metric;
diff --git a/pimd/pim_register.c b/pimd/pim_register.c
index 2cc80f957c..8313c8d4f6 100644
--- a/pimd/pim_register.c
+++ b/pimd/pim_register.c
@@ -311,30 +311,26 @@ void pim_null_register_send(struct pim_upstream *up)
* }
* }
*/
-int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
- struct in_addr src_addr, uint8_t *tlv_buf,
- int tlv_buf_size)
+int pim_register_recv(struct interface *ifp, pim_addr dest_addr,
+ pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size)
{
int sentRegisterStop = 0;
- struct ip *ip_hdr;
+ const void *ip_hdr;
pim_sgaddr sg;
uint32_t *bits;
int i_am_rp = 0;
struct pim_interface *pim_ifp = ifp->info;
struct pim_instance *pim = pim_ifp->pim;
+ pim_addr rp_addr;
#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
- ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
+ ip_hdr = (tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
- if (!if_address_is_local(&dest_addr, AF_INET, pim->vrf->vrf_id)) {
- if (PIM_DEBUG_PIM_REG) {
- char dest[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<dst?>", dest_addr, dest, sizeof(dest));
+ if (!if_address_is_local(&dest_addr, PIM_AF, pim->vrf->vrf_id)) {
+ if (PIM_DEBUG_PIM_REG)
zlog_debug(
- "%s: Received Register message for destination address: %s that I do not own",
- __func__, dest);
- }
+ "%s: Received Register message for destination address: %pPA that I do not own",
+ __func__, &dest_addr);
return 0;
}
@@ -367,18 +363,14 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
* start of the actual Encapsulated data.
*/
memset(&sg, 0, sizeof(sg));
- sg.src = ip_hdr->ip_src;
- sg.grp = ip_hdr->ip_dst;
+ sg = pim_sgaddr_from_iphdr(ip_hdr);
i_am_rp = I_am_RP(pim, sg.grp);
- if (PIM_DEBUG_PIM_REG) {
- char src_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
- zlog_debug("Received Register message%pSG from %s on %s, rp: %d",
- &sg, src_str, ifp->name, i_am_rp);
- }
+ if (PIM_DEBUG_PIM_REG)
+ zlog_debug(
+ "Received Register message%pSG from %pPA on %s, rp: %d",
+ &sg, &src_addr, ifp->name, i_am_rp);
if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
if (pim_addr_is_any(sg.src)) {
@@ -390,9 +382,8 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
}
}
- if (i_am_rp
- && (dest_addr.s_addr
- == ((RP(pim, sg.grp))->rpf_addr.u.prefix4.s_addr))) {
+ rp_addr = pim_addr_from_prefix(&(RP(pim, sg.grp))->rpf_addr);
+ if (i_am_rp && (!pim_addr_cmp(dest_addr, rp_addr))) {
sentRegisterStop = 0;
if (pim->register_plist) {
@@ -407,31 +398,25 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
if (prefix_list_apply(plist, &src) == PREFIX_DENY) {
pim_register_stop_send(ifp, &sg, dest_addr,
src_addr);
- if (PIM_DEBUG_PIM_PACKETS) {
- char src_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<src?>", src_addr,
- src_str,
- sizeof(src_str));
+ if (PIM_DEBUG_PIM_PACKETS)
zlog_debug(
- "%s: Sending register-stop to %s for %pSG due to prefix-list denial, dropping packet",
- __func__, src_str, &sg);
- }
+ "%s: Sending register-stop to %pPA for %pSG due to prefix-list denial, dropping packet",
+ __func__, &src_addr, &sg);
return 0;
}
}
if (*bits & PIM_REGISTER_BORDER_BIT) {
- struct in_addr pimbr = pim_br_get_pmbr(&sg);
+ pim_addr pimbr = pim_br_get_pmbr(&sg);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug(
"%s: Received Register message with Border bit set",
__func__);
- if (pimbr.s_addr == pim_br_unknown.s_addr)
+ if (pim_addr_is_any(pimbr))
pim_br_set_pmbr(&sg, src_addr);
- else if (src_addr.s_addr != pimbr.s_addr) {
+ else if (pim_addr_cmp(src_addr, pimbr)) {
pim_register_stop_send(ifp, &sg, dest_addr,
src_addr);
if (PIM_DEBUG_PIM_PACKETS)
diff --git a/pimd/pim_register.h b/pimd/pim_register.h
index fd4284b802..0ebef40c58 100644
--- a/pimd/pim_register.h
+++ b/pimd/pim_register.h
@@ -32,9 +32,8 @@
int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size);
-int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
- struct in_addr src_addr, uint8_t *tlv_buf,
- int tlv_buf_size);
+int pim_register_recv(struct interface *ifp, pim_addr dest_addr,
+ pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size);
void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src,
struct pim_rpf *rpg, int null_register,
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index 25eabe6743..00a1e1b58c 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -77,26 +77,21 @@ int pim_rp_list_cmp(void *v1, void *v2)
{
struct rp_info *rp1 = (struct rp_info *)v1;
struct rp_info *rp2 = (struct rp_info *)v2;
+ int ret;
/*
* Sort by RP IP address
*/
- if (rp1->rp.rpf_addr.u.prefix4.s_addr
- < rp2->rp.rpf_addr.u.prefix4.s_addr)
- return -1;
-
- if (rp1->rp.rpf_addr.u.prefix4.s_addr
- > rp2->rp.rpf_addr.u.prefix4.s_addr)
- return 1;
+ ret = prefix_cmp(&rp1->rp.rpf_addr, &rp2->rp.rpf_addr);
+ if (ret)
+ return ret;
/*
* Sort by group IP address
*/
- if (rp1->group.u.prefix4.s_addr < rp2->group.u.prefix4.s_addr)
- return -1;
-
- if (rp1->group.u.prefix4.s_addr > rp2->group.u.prefix4.s_addr)
- return 1;
+ ret = prefix_cmp(&rp1->group, &rp2->group);
+ if (ret)
+ return ret;
return 0;
}
@@ -116,13 +111,12 @@ void pim_rp_init(struct pim_instance *pim)
if (!pim_get_all_mcast_group(&rp_info->group)) {
flog_err(EC_LIB_DEVELOPMENT,
- "Unable to convert 224.0.0.0/4 to prefix");
+ "Unable to convert all-multicast prefix");
list_delete(&pim->rp_list);
route_table_finish(pim->rp_table);
XFREE(MTYPE_PIM_RP, rp_info);
return;
}
- rp_info->group.family = AF_INET;
pim_addr_to_prefix(&rp_info->rp.rpf_addr, PIMADDR_ANY);
listnode_add(pim->rp_list, rp_info);
@@ -130,9 +124,9 @@ void pim_rp_init(struct pim_instance *pim)
rn = route_node_get(pim->rp_table, &rp_info->group);
rn->info = rp_info;
if (PIM_DEBUG_PIM_TRACE)
- zlog_debug(
- "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d",
- rn, rp_info, route_node_get_lock_count(rn));
+ zlog_debug("Allocated: %p for rp_info: %p(%pFX) Lock: %d", rn,
+ rp_info, &rp_info->group,
+ route_node_get_lock_count(rn));
}
void pim_rp_free(struct pim_instance *pim)
@@ -375,7 +369,7 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up)
up->sg.grp);
if (PIM_DEBUG_PIM_TRACE)
- zlog_debug("%s: pim upstream update for old upstream %pI4",
+ zlog_debug("%s: pim upstream update for old upstream %pPA",
__func__, &old_upstream_addr);
if (!pim_addr_cmp(old_upstream_addr, new_upstream_addr))
@@ -932,9 +926,7 @@ void pim_rp_setup(struct pim_instance *pim)
if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
continue;
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+ nht_p = rp_info->rp.rpf_addr;
pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL);
if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
@@ -1159,7 +1151,6 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj)
struct rp_info *prev_rp_info = NULL;
struct listnode *node;
char source[7];
- char buf[PREFIX_STRLEN];
json_object *json = NULL;
json_object *json_rp_rows = NULL;
@@ -1171,110 +1162,89 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj)
vty_out(vty,
"RP address group/prefix-list OIF I am RP Source\n");
for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
- if (!pim_rpf_addr_is_inaddr_any(&rp_info->rp)) {
- char buf[48];
+ if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
+ continue;
- if (rp_info->rp_src == RP_SRC_STATIC)
- strlcpy(source, "Static", sizeof(source));
- else if (rp_info->rp_src == RP_SRC_BSR)
- strlcpy(source, "BSR", sizeof(source));
+ if (rp_info->rp_src == RP_SRC_STATIC)
+ strlcpy(source, "Static", sizeof(source));
+ else if (rp_info->rp_src == RP_SRC_BSR)
+ strlcpy(source, "BSR", sizeof(source));
+ else
+ strlcpy(source, "None", sizeof(source));
+ if (uj) {
+ /*
+ * If we have moved on to a new RP then add the
+ * entry for the previous RP
+ */
+ if (prev_rp_info &&
+ prefix_cmp(&prev_rp_info->rp.rpf_addr,
+ &rp_info->rp.rpf_addr)) {
+ json_object_object_addf(
+ json, json_rp_rows, "%pFXh",
+ &prev_rp_info->rp.rpf_addr);
+ json_rp_rows = NULL;
+ }
+
+ if (!json_rp_rows)
+ json_rp_rows = json_object_new_array();
+
+ json_row = json_object_new_object();
+ json_object_string_addf(json_row, "rpAddress", "%pFXh",
+ &rp_info->rp.rpf_addr);
+ if (rp_info->rp.source_nexthop.interface)
+ json_object_string_add(
+ json_row, "outboundInterface",
+ rp_info->rp.source_nexthop
+ .interface->name);
else
- strlcpy(source, "None", sizeof(source));
- if (uj) {
- /*
- * If we have moved on to a new RP then add the
- * entry for the previous RP
- */
- if (prev_rp_info
- && prev_rp_info->rp.rpf_addr.u.prefix4
- .s_addr
- != rp_info->rp.rpf_addr.u.prefix4
- .s_addr) {
- json_object_object_add(
- json,
- inet_ntop(AF_INET,
- &prev_rp_info->rp
- .rpf_addr.u
- .prefix4,
- buf, sizeof(buf)),
- json_rp_rows);
- json_rp_rows = NULL;
- }
+ json_object_string_add(json_row,
+ "outboundInterface",
+ "Unknown");
+ if (rp_info->i_am_rp)
+ json_object_boolean_true_add(json_row, "iAmRP");
+ else
+ json_object_boolean_false_add(json_row,
+ "iAmRP");
- if (!json_rp_rows)
- json_rp_rows = json_object_new_array();
-
- json_row = json_object_new_object();
- json_object_string_addf(
- json_row, "rpAddress", "%pI4",
- &rp_info->rp.rpf_addr.u.prefix4);
- if (rp_info->rp.source_nexthop.interface)
- json_object_string_add(
- json_row, "outboundInterface",
- rp_info->rp.source_nexthop
- .interface->name);
- else
- json_object_string_add(
- json_row, "outboundInterface",
- "Unknown");
- if (rp_info->i_am_rp)
- json_object_boolean_true_add(json_row,
- "iAmRP");
- else
- json_object_boolean_false_add(json_row,
- "iAmRP");
+ if (rp_info->plist)
+ json_object_string_add(json_row, "prefixList",
+ rp_info->plist);
+ else
+ json_object_string_addf(json_row, "group",
+ "%pFX",
+ &rp_info->group);
+ json_object_string_add(json_row, "source", source);
- if (rp_info->plist)
- json_object_string_add(json_row,
- "prefixList",
- rp_info->plist);
- else
- json_object_string_addf(
- json_row, "group", "%pFX",
- &rp_info->group);
- json_object_string_add(json_row, "source",
- source);
+ json_object_array_add(json_rp_rows, json_row);
+ } else {
+ vty_out(vty, "%-15pFXh ", &rp_info->rp.rpf_addr);
- json_object_array_add(json_rp_rows, json_row);
- } else {
- vty_out(vty, "%-15s ",
- inet_ntop(AF_INET,
- &rp_info->rp.rpf_addr.u
- .prefix4,
- buf, sizeof(buf)));
-
- if (rp_info->plist)
- vty_out(vty, "%-18s ", rp_info->plist);
- else
- vty_out(vty, "%-18pFX ",
- &rp_info->group);
+ if (rp_info->plist)
+ vty_out(vty, "%-18s ", rp_info->plist);
+ else
+ vty_out(vty, "%-18pFX ", &rp_info->group);
- if (rp_info->rp.source_nexthop.interface)
- vty_out(vty, "%-16s ",
- rp_info->rp.source_nexthop
- .interface->name);
- else
- vty_out(vty, "%-16s ", "(Unknown)");
+ if (rp_info->rp.source_nexthop.interface)
+ vty_out(vty, "%-16s ",
+ rp_info->rp.source_nexthop
+ .interface->name);
+ else
+ vty_out(vty, "%-16s ", "(Unknown)");
- if (rp_info->i_am_rp)
- vty_out(vty, "yes");
- else
- vty_out(vty, "no");
+ if (rp_info->i_am_rp)
+ vty_out(vty, "yes");
+ else
+ vty_out(vty, "no");
- vty_out(vty, "%14s\n", source);
- }
- prev_rp_info = rp_info;
+ vty_out(vty, "%14s\n", source);
}
+ prev_rp_info = rp_info;
}
if (uj) {
if (prev_rp_info && json_rp_rows)
- json_object_object_add(
- json,
- inet_ntop(AF_INET,
- &prev_rp_info->rp.rpf_addr.u.prefix4,
- buf, sizeof(buf)),
- json_rp_rows);
+ json_object_object_addf(json, json_rp_rows, "%pFXh",
+ &prev_rp_info->rp.rpf_addr);
vty_json(vty, json);
}
@@ -1292,17 +1262,20 @@ void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr)
if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
continue;
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+ nht_p = rp_info->rp.rpf_addr;
memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
if (!pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info,
&pnc))
continue;
for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
- if (nh_node->gate.ipv4.s_addr != INADDR_ANY)
+#if PIM_IPV == 4
+ if (!pim_addr_is_any(nh_node->gate.ipv4))
+ continue;
+#else
+ if (!pim_addr_is_any(nh_node->gate.ipv6))
continue;
+#endif
struct interface *ifp1 = if_lookup_by_index(
nh_node->ifindex, pim->vrf->vrf_id);
@@ -1315,15 +1288,11 @@ void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr)
#else
nh_node->gate.ipv6 = nbr->source_addr;
#endif
- if (PIM_DEBUG_PIM_NHT_RP) {
- char str[PREFIX_STRLEN];
- pim_addr_dump("<nht_addr?>", &nht_p, str,
- sizeof(str));
+ if (PIM_DEBUG_PIM_NHT_RP)
zlog_debug(
- "%s: addr %s new nexthop addr %pPAs interface %s",
- __func__, str, &nbr->source_addr,
+ "%s: addr %pFXh new nexthop addr %pPAs interface %s",
+ __func__, &nht_p, &nbr->source_addr,
ifp1->name);
- }
}
}
}
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 0acd3c0694..526fdcbc27 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -454,10 +454,11 @@ static void pim_zebra_capabilities(struct zclient_capabilities *cap)
static zclient_handler *const pim_handlers[] = {
[ZEBRA_INTERFACE_ADDRESS_ADD] = pim_zebra_if_address_add,
[ZEBRA_INTERFACE_ADDRESS_DELETE] = pim_zebra_if_address_del,
+
+ [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update,
#if PIM_IPV == 4
[ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra,
[ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update,
- [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update,
[ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc,
[ZEBRA_VXLAN_SG_DEL] = pim_zebra_vxlan_sg_proc,
@@ -820,7 +821,7 @@ void pim_forward_start(struct pim_ifchannel *ch)
uint32_t mask = 0;
if (PIM_DEBUG_PIM_TRACE)
- zlog_debug("%s: (S,G)=%pSG oif=%s (%pI4)", __func__, &ch->sg,
+ zlog_debug("%s: (S,G)=%pSG oif=%s (%pPA)", __func__, &ch->sg,
ch->interface->name, &up->upstream_addr);
if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
diff --git a/pimd/subdir.am b/pimd/subdir.am
index 0fb5de7e09..d617be3cb7 100644
--- a/pimd/subdir.am
+++ b/pimd/subdir.am
@@ -37,6 +37,7 @@ pim_common = \
pimd/pim_nb.c \
pimd/pim_nb_config.c \
pimd/pim_neighbor.c \
+ pimd/pim_nht.c \
pimd/pim_oil.c \
pimd/pim_routemap.c \
pimd/pim_rp.c \
@@ -70,7 +71,6 @@ pimd_pimd_SOURCES = \
pimd/pim_msdp.c \
pimd/pim_msdp_packet.c \
pimd/pim_msdp_socket.c \
- pimd/pim_nht.c \
pimd/pim_pim.c \
pimd/pim_register.c \
pimd/pim_signals.c \
diff --git a/tests/isisd/test_fuzz_isis_tlv.c b/tests/isisd/test_fuzz_isis_tlv.c
index 97aade6578..8f0b92d0fc 100644
--- a/tests/isisd/test_fuzz_isis_tlv.c
+++ b/tests/isisd/test_fuzz_isis_tlv.c
@@ -108,12 +108,12 @@ static int test(FILE *input, FILE *output)
}
fprintf(output, "Unpack log:\n%s", log);
- const char *s_tlvs = isis_format_tlvs(tlvs);
+ const char *s_tlvs = isis_format_tlvs(tlvs, NULL);
fprintf(output, "Unpacked TLVs:\n%s", s_tlvs);
struct isis_item *orig_auth = tlvs->isis_auth.head;
tlvs->isis_auth.head = NULL;
- s_tlvs = isis_format_tlvs(tlvs);
+ s_tlvs = isis_format_tlvs(tlvs, NULL);
struct isis_tlvs *tlv_copy = isis_copy_tlvs(tlvs);
tlvs->isis_auth.head = orig_auth;
isis_free_tlvs(tlvs);
@@ -133,7 +133,7 @@ static int test(FILE *input, FILE *output)
}
char *orig_tlvs = XSTRDUP(MTYPE_TMP, s_tlvs);
- s_tlvs = isis_format_tlvs(tlvs);
+ s_tlvs = isis_format_tlvs(tlvs, NULL);
if (strcmp(orig_tlvs, s_tlvs)) {
fprintf(output,
@@ -166,7 +166,7 @@ static int test(FILE *input, FILE *output)
fprintf(output, "Could not pack fragment, too large.\n");
assert(0);
}
- sbuf_push(&fragment_format, 0, "%s", isis_format_tlvs(tlvs));
+ sbuf_push(&fragment_format, 0, "%s", isis_format_tlvs(tlvs, NULL));
isis_free_tlvs(tlvs);
}
list_delete(&fragments);
diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c
index a30f33ccad..971aba4c46 100644
--- a/tests/isisd/test_isis_spf.c
+++ b/tests/isisd/test_isis_spf.c
@@ -294,7 +294,7 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
/* Print the LDPDB. */
if (CHECK_FLAG(flags, F_DISPLAY_LSPDB))
- show_isis_database_lspdb(vty, area, level - 1,
+ show_isis_database_lspdb_vty(vty, area, level - 1,
&area->lspdb[level - 1], NULL,
ISIS_UI_LEVEL_DETAIL);
diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c
index 8f9d637afd..59d08ae82b 100644
--- a/tests/lib/test_printfrr.c
+++ b/tests/lib/test_printfrr.c
@@ -207,6 +207,24 @@ int main(int argc, char **argv)
assert(strcmp(p, "test#5") == 0);
XFREE(MTYPE_TMP, p);
+ struct prefix pfx;
+
+ str2prefix("192.168.1.23/24", &pfx);
+ printchk("192.168.1.23/24", "%pFX", &pfx);
+ printchk("192.168.1.23", "%pFXh", &pfx);
+
+ str2prefix("2001:db8::1234/64", &pfx);
+ printchk("2001:db8::1234/64", "%pFX", &pfx);
+ printchk("2001:db8::1234", "%pFXh", &pfx);
+
+ pfx.family = AF_UNIX;
+ printchk("UNK prefix", "%pFX", &pfx);
+ printchk("{prefix.af=AF_UNIX}", "%pFXh", &pfx);
+
+ str2prefix_eth("02:ca:fe:f0:0d:1e/48", (struct prefix_eth *)&pfx);
+ printchk("02:ca:fe:f0:0d:1e/48", "%pFX", &pfx);
+ printchk("02:ca:fe:f0:0d:1e", "%pFXh", &pfx);
+
struct prefix_sg sg;
sg.src.s_addr = INADDR_ANY;
sg.grp.s_addr = INADDR_ANY;
diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py
index 94c5faf2e0..014722387f 100644
--- a/tests/topotests/isis_topo1/test_isis_topo1.py
+++ b/tests/topotests/isis_topo1/test_isis_topo1.py
@@ -236,6 +236,94 @@ def test_isis_linux_route6_installation():
assert topotest.json_cmp(actual, expected) is None, assertmsg
+def test_isis_summary_json():
+ "Check json struct in show isis summary json"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking 'show isis summary json'")
+ for rname, router in tgen.routers().items():
+ logger.info("Checking router %s", rname)
+ json_output = tgen.gears[rname].vtysh_cmd("show isis summary json", isjson=True)
+ assertmsg = "Test isis summary json failed in '{}' data '{}'".format(rname, json_output)
+ assert json_output['vrf'] == "default", assertmsg
+ assert json_output['areas'][0]['area'] == "1", assertmsg
+ assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg
+
+
+def test_isis_interface_json():
+ "Check json struct in show isis interface json"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking 'show isis interface json'")
+ for rname, router in tgen.routers().items():
+ logger.info("Checking router %s", rname)
+ json_output = tgen.gears[rname].vtysh_cmd("show isis interface json", isjson=True)
+ assertmsg = "Test isis interface json failed in '{}' data '{}'".format(rname, json_output)
+ assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg
+
+ for rname, router in tgen.routers().items():
+ logger.info("Checking router %s", rname)
+ json_output = tgen.gears[rname].vtysh_cmd("show isis interface detail json", isjson=True)
+ assertmsg = "Test isis interface json failed in '{}' data '{}'".format(rname, json_output)
+ assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg
+
+
+def test_isis_neighbor_json():
+ "Check json struct in show isis neighbor json"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ #tgen.mininet_cli()
+ logger.info("Checking 'show isis neighbor json'")
+ for rname, router in tgen.routers().items():
+ logger.info("Checking router %s", rname)
+ json_output = tgen.gears[rname].vtysh_cmd("show isis neighbor json", isjson=True)
+ assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(rname, json_output)
+ assert json_output['areas'][0]['circuits'][0]['interface'] == rname+"-eth0", assertmsg
+
+ for rname, router in tgen.routers().items():
+ logger.info("Checking router %s", rname)
+ json_output = tgen.gears[rname].vtysh_cmd("show isis neighbor detail json", isjson=True)
+ assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(rname, json_output)
+ assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg
+
+
+def test_isis_database_json():
+ "Check json struct in show isis database json"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ #tgen.mininet_cli()
+ logger.info("Checking 'show isis database json'")
+ for rname, router in tgen.routers().items():
+ logger.info("Checking router %s", rname)
+ json_output = tgen.gears[rname].vtysh_cmd("show isis database json", isjson=True)
+ assertmsg = "Test isis database json failed in '{}' data '{}'".format(rname, json_output)
+ assert json_output['areas'][0]['area']['name'] == "1", assertmsg
+ assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg
+
+ for rname, router in tgen.routers().items():
+ logger.info("Checking router %s", rname)
+ json_output = tgen.gears[rname].vtysh_cmd("show isis database detail json", isjson=True)
+ assertmsg = "Test isis database json failed in '{}' data '{}'".format(rname, json_output)
+ assert json_output['areas'][0]['area']['name'] == "1", assertmsg
+ assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg
+
+
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
diff --git a/vrrpd/Makefile b/vrrpd/Makefile
index 027c6ee1f8..0abb1a6381 100644
--- a/vrrpd/Makefile
+++ b/vrrpd/Makefile
@@ -1,7 +1,7 @@
all: ALWAYS
- @$(MAKE) -s -C .. vrrp/vrrp
+ @$(MAKE) -s -C .. vrrpd/vrrpd
%: ALWAYS
- @$(MAKE) -s -C .. vrrp/$@
+ @$(MAKE) -s -C .. vrrpd/$@
Makefile:
#nothing
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index f8c6a1fc1d..ed1f1fb5bb 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -73,6 +73,7 @@ struct vtysh_client {
struct thread *log_reader;
int log_fd;
+ uint32_t lost_msgs;
};
static bool stderr_tty;
@@ -3654,6 +3655,15 @@ static void vtysh_log_read(struct thread *thread)
if (ret < 0 && ERRNO_IO_RETRY(errno))
return;
+ if (stderr_stdout_same) {
+#ifdef HAVE_RL_CLEAR_VISIBLE_LINE
+ rl_clear_visible_line();
+#else
+ puts("\r");
+#endif
+ fflush(stdout);
+ }
+
if (ret <= 0) {
struct timespec ts;
@@ -3677,17 +3687,17 @@ static void vtysh_log_read(struct thread *thread)
buf.hdr.ts_nsec = ts.tv_nsec;
buf.hdr.prio = LOG_ERR;
buf.hdr.flags = 0;
- buf.hdr.arghdrlen = 0;
+ buf.hdr.texthdrlen = 0;
buf.hdr.n_argpos = 0;
- }
+ } else {
+ int32_t lost_msgs = buf.hdr.lost_msgs - vclient->lost_msgs;
- if (stderr_stdout_same) {
-#ifdef HAVE_RL_CLEAR_VISIBLE_LINE
- rl_clear_visible_line();
-#else
- puts("\r");
-#endif
- fflush(stdout);
+ if (lost_msgs > 0) {
+ vclient->lost_msgs = buf.hdr.lost_msgs;
+ fprintf(stderr,
+ "%d log messages from %s lost (vtysh reading too slowly)\n",
+ lost_msgs, vclient->name);
+ }
}
text = buf.text + sizeof(buf.hdr.argpos[0]) * buf.hdr.n_argpos;
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index db8ee3236c..a75b165270 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -1876,6 +1876,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
} else {
bool was_bridge_slave, was_bond_slave;
uint8_t chgflags = ZEBRA_BRIDGE_NO_ACTION;
+ zif = ifp->info;
/* Interface update. */
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1909,9 +1910,21 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
netlink_to_zebra_link_type(ifi->ifi_type);
netlink_interface_update_hw_addr(tb, ifp);
+ if (tb[IFLA_PROTO_DOWN]) {
+ uint8_t protodown;
+
+ protodown = *(uint8_t *)RTA_DATA(
+ tb[IFLA_PROTO_DOWN]);
+ netlink_proc_dplane_if_protodown(zif,
+ !!protodown);
+ }
+
if (if_is_no_ptm_operative(ifp)) {
+ bool is_up = if_is_operative(ifp);
ifp->flags = ifi->ifi_flags & 0x0000fffff;
- if (!if_is_no_ptm_operative(ifp)) {
+ if (!if_is_no_ptm_operative(ifp) ||
+ CHECK_FLAG(zif->flags,
+ ZIF_FLAG_PROTODOWN)) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
"Intf %s(%u) has gone DOWN",
@@ -1927,7 +1940,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
zlog_debug(
"Intf %s(%u) PTM up, notifying clients",
name, ifp->ifindex);
- zebra_interface_up_update(ifp);
+ if_up(ifp, !is_up);
/* Update EVPN VNI when SVI MAC change
*/
@@ -1956,12 +1969,14 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
}
} else {
ifp->flags = ifi->ifi_flags & 0x0000fffff;
- if (if_is_operative(ifp)) {
+ if (if_is_operative(ifp) &&
+ !CHECK_FLAG(zif->flags,
+ ZIF_FLAG_PROTODOWN)) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
"Intf %s(%u) has come UP",
name, ifp->ifindex);
- if_up(ifp);
+ if_up(ifp, true);
if (IS_ZEBRA_IF_BRIDGE(ifp))
chgflags =
ZEBRA_BRIDGE_MASTER_UP;
@@ -1990,15 +2005,6 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave)
zebra_l2if_update_bond_slave(ifp, bond_ifindex,
!!bypass);
-
- if (tb[IFLA_PROTO_DOWN]) {
- uint8_t protodown;
-
- protodown = *(uint8_t *)RTA_DATA(
- tb[IFLA_PROTO_DOWN]);
- netlink_proc_dplane_if_protodown(ifp->info,
- !!protodown);
- }
}
zif = ifp->info;
diff --git a/zebra/interface.c b/zebra/interface.c
index fbd2aac005..a76f8741e0 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -224,9 +224,13 @@ static int if_zebra_new_hook(struct interface *ifp)
static void if_nhg_dependents_check_valid(struct nhg_hash_entry *nhe)
{
zebra_nhg_check_valid(nhe);
- if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID))
- /* Assuming uninstalled as well here */
- UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+ if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) {
+ /* If we're in shutdown, this interface event needs to clean
+ * up installed NHGs, so don't clear that flag directly.
+ */
+ if (!zrouter.in_shutdown)
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+ }
}
static void if_down_nhg_dependents(const struct interface *ifp)
@@ -517,7 +521,7 @@ void if_flags_update(struct interface *ifp, uint64_t newflags)
/* inoperative -> operative? */
ifp->flags = newflags;
if (if_is_operative(ifp))
- if_up(ifp);
+ if_up(ifp, true);
}
}
@@ -1045,7 +1049,7 @@ bool if_nhg_dependents_is_empty(const struct interface *ifp)
}
/* Interface is up. */
-void if_up(struct interface *ifp)
+void if_up(struct interface *ifp, bool install_connected)
{
struct zebra_if *zif;
struct interface *link_if;
@@ -1077,7 +1081,8 @@ void if_up(struct interface *ifp)
#endif
/* Install connected routes to the kernel. */
- if_install_connected(ifp);
+ if (install_connected)
+ if_install_connected(ifp);
/* Handle interface up for specific types for EVPN. Non-VxLAN interfaces
* are checked to see if (remote) neighbor entries need to be installed
@@ -2778,7 +2783,7 @@ int if_linkdetect(struct interface *ifp, bool detect)
/* Interface may come up after disabling link detection */
if (if_is_operative(ifp) && !if_was_operative)
- if_up(ifp);
+ if_up(ifp, true);
}
/* FIXME: Will defer status change forwarding if interface
does not come down! */
diff --git a/zebra/interface.h b/zebra/interface.h
index c19e494860..315a3170d8 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -486,7 +486,7 @@ extern void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp,
extern void if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(struct interface *ifp);
extern void if_delete_update(struct interface *ifp);
extern void if_add_update(struct interface *ifp);
-extern void if_up(struct interface *);
+extern void if_up(struct interface *ifp, bool install_connected);
extern void if_down(struct interface *);
extern void if_refresh(struct interface *);
extern void if_flags_update(struct interface *, uint64_t);
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
index e38766bc6b..74043e521c 100644
--- a/zebra/zebra_evpn_mac.c
+++ b/zebra/zebra_evpn_mac.c
@@ -1141,14 +1141,6 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
sizeof(mac_buf)));
}
- /* If the MAC is freed before the neigh we will end up
- * with a stale pointer against the neigh
- */
- if (!list_isempty(mac->neigh_list))
- zlog_warn("%s: MAC %pEA flags 0x%x neigh list not empty %d",
- __func__, &mac->macaddr, mac->flags,
- listcount(mac->neigh_list));
-
/* force de-ref any ES entry linked to the MAC */
zebra_evpn_es_mac_deref_entry(mac);
@@ -1161,6 +1153,26 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
/* Cancel auto recovery */
THREAD_OFF(mac->dad_mac_auto_recovery_timer);
+ /* If the MAC is freed before the neigh we will end up
+ * with a stale pointer against the neigh.
+ * The situation can arise when a MAC is in remote state
+ * and its associated neigh is local state.
+ * zebra_evpn_cfg_cleanup() cleans up remote neighs and MACs.
+ * Instead of deleting remote MAC, if its neigh list is non-empty
+ * (associated to local neighs), mark the MAC as AUTO.
+ */
+ if (!list_isempty(mac->neigh_list)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "MAC %pEA (flags 0x%x vni %u) has non-empty neigh list "
+ "count %u, mark MAC as AUTO",
+ &mac->macaddr, mac->flags, zevpn->vni,
+ listcount(mac->neigh_list));
+
+ SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ return 0;
+ }
+
list_delete(&mac->neigh_list);
/* Free the VNI hash entry and allocated memory. */
diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c
index f557e66384..01ac7c227f 100644
--- a/zebra/zebra_evpn_neigh.c
+++ b/zebra/zebra_evpn_neigh.c
@@ -2203,7 +2203,6 @@ int zebra_evpn_neigh_gw_macip_add(struct interface *ifp,
/* Only advertise in BGP if the knob is enabled */
if (advertise_gw_macip_enabled(zevpn)) {
- SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW);
/* Set Router flag (R-bit) */
if (ip->ipa_type == IPADDR_V6)
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index e1d28e1534..469a94a65b 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -1966,7 +1966,7 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop,
*/
static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
const struct prefix *top, int type, uint32_t flags,
- uint32_t *pmtu)
+ uint32_t *pmtu, vrf_id_t vrf_id)
{
struct prefix p;
struct route_table *table;
@@ -2061,13 +2061,13 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
return 1;
}
- if (top
- && ((top->family == AF_INET && top->prefixlen == IPV4_MAX_BITLEN
- && nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr)
- || (top->family == AF_INET6 && top->prefixlen == IPV6_MAX_BITLEN
- && memcmp(&nexthop->gate.ipv6, &top->u.prefix6,
- IPV6_MAX_BYTELEN)
- == 0))) {
+ if (top &&
+ ((top->family == AF_INET && top->prefixlen == IPV4_MAX_BITLEN &&
+ nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr) ||
+ (top->family == AF_INET6 && top->prefixlen == IPV6_MAX_BITLEN &&
+ memcmp(&nexthop->gate.ipv6, &top->u.prefix6, IPV6_MAX_BYTELEN) ==
+ 0)) &&
+ nexthop->vrf_id == vrf_id) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
" :%s: Attempting to install a max prefixlength route through itself",
@@ -2361,6 +2361,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
const struct prefix *p, *src_p;
struct zebra_vrf *zvrf;
uint32_t mtu = 0;
+ vrf_id_t vrf_id;
srcdest_rnode_prefixes(rn, &p, &src_p);
@@ -2389,10 +2390,12 @@ static unsigned nexthop_active_check(struct route_node *rn,
goto skip_check;
}
+
+ vrf_id = zvrf_id(rib_dest_vrf(rib_dest_from_rnode(rn)));
switch (nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
- if (nexthop_active(nexthop, nhe, &rn->p, re->type,
- re->flags, &mtu))
+ if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
+ &mtu, vrf_id))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -2400,16 +2403,16 @@ static unsigned nexthop_active_check(struct route_node *rn,
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
family = AFI_IP;
- if (nexthop_active(nexthop, nhe, &rn->p, re->type,
- re->flags, &mtu))
+ if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
+ &mtu, vrf_id))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
break;
case NEXTHOP_TYPE_IPV6:
family = AFI_IP6;
- if (nexthop_active(nexthop, nhe, &rn->p, re->type,
- re->flags, &mtu))
+ if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
+ &mtu, vrf_id))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -2419,8 +2422,8 @@ static unsigned nexthop_active_check(struct route_node *rn,
if (rn->p.family != AF_INET)
family = AFI_IP6;
- if (nexthop_active(nexthop, nhe, &rn->p, re->type,
- re->flags, &mtu))
+ if (nexthop_active(nexthop, nhe, &rn->p, re->type, re->flags,
+ &mtu, vrf_id))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c
index 68e5c391cf..c28e251e3a 100644
--- a/zebra/zebra_ptm.c
+++ b/zebra/zebra_ptm.c
@@ -350,7 +350,7 @@ DEFUN (no_zebra_ptm_enable_if,
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("%s: Bringing up interface %s",
__func__, ifp->name);
- if_up(ifp);
+ if_up(ifp, true);
}
}
@@ -553,7 +553,7 @@ static int zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt,
ifp->ptm_status = ZEBRA_PTM_STATUS_UP;
if (ifp->ptm_enable && if_is_no_ptm_operative(ifp)
&& send_linkup)
- if_up(ifp);
+ if_up(ifp, true);
} else if (!strcmp(cbl_str, ZEBRA_PTM_FAIL_STR)
&& (ifp->ptm_status != ZEBRA_PTM_STATUS_DOWN)) {
ifp->ptm_status = ZEBRA_PTM_STATUS_DOWN;
@@ -1163,7 +1163,7 @@ void zebra_ptm_reset_status(int ptm_disable)
zlog_debug(
"%s: Bringing up interface %s",
__func__, ifp->name);
- if_up(ifp);
+ if_up(ifp, true);
}
}
}