lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220704054114.22582-2-matt@traverse.com.au>
Date:   Mon,  4 Jul 2022 05:41:13 +0000
From:   Mathew McBride <matt@...verse.com.au>
To:     Michal Kubecek <mkubecek@...e.cz>
Cc:     netdev@...r.kernel.org, Mathew McBride <matt@...verse.com.au>
Subject: [PATCH ethtool 1/2] ethtool: add JSON output to --module-info

This provides JSON output support for 'ethtool -m' / --module-info

To make presenting the module data as simple as possible,
both the raw bytes/codes and formatted descriptions are provided
where available.

A sample output (edited and formatted for brevity) is shown below:
$ ethtool --json -m eth8
[
	{
		"identifier": 3,
		"identifier_description": "SFP",
		"vendor_name": "UBNT",
		"vendor_oui": "00:00:00",
		"vendor_pn": "UF-MM-10G",
		"vendor_sn": "FT17072604079",
		"date_code": "170727__",
		"extended_identifier": 4,
		"extended_identifier_description": "GBIC/SFP defined by 2-wire interface ID",
		"connector": 7,
		"connector_description": "LC",
		"transceiver_codes": [
			16,
			0,
			0,
			0,
			64,
			64,
			12,
			85,
			0
		],
		"transceiver_types": [
			"10G Ethernet: 10G Base-SR"
		],
		"encoding": 6,
		"encoding_description": "64B/66B",
		"bitrate_nominal": 10300,
		"rate_identifier": 0,
		"rate_identifier_description": "unspecified",
		"laser_wavelength": 850,
		"vendor_rev": "",
		"option_byte1": 0,
		"option_byte2": 26,
		"option_descriptions": [
			"RX_LOS implemented",
			"TX_FAULT implemented",
			"TX_DISABLE implemented"
		],
		"br_margin_max": 0,
		"br_margin_min": 0,
		"optical_diagnostics_supported": true,
		"bias_current": 11.516,
		"tx_power": 0.4872,
		"module_temp": 47.1719,
		"module_voltage": 3.2784
	}
]

Signed-off-by: Mathew McBride <matt@...verse.com.au>
---
 ethtool.c    |   5 +
 sff-common.c | 213 +++++++++++++++--------
 sff-common.h |  17 +-
 sfpdiag.c    |  64 ++++++-
 sfpid.c      | 478 +++++++++++++++++++++++++++++++--------------------
 5 files changed, 522 insertions(+), 255 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index 911f26b..83bbde8 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -4897,6 +4897,8 @@ static int do_getmodule(struct cmd_context *ctx)
 		    (eeprom->len != modinfo.eeprom_len)) {
 			geeprom_dump_hex = 1;
 		} else if (!geeprom_dump_hex) {
+			new_json_obj(ctx->json);
+			open_json_object(NULL);
 			switch (modinfo.type) {
 #ifdef ETHTOOL_ENABLE_PRETTY_DUMP
 			case ETH_MODULE_SFF_8079:
@@ -4916,6 +4918,8 @@ static int do_getmodule(struct cmd_context *ctx)
 				geeprom_dump_hex = 1;
 				break;
 			}
+			close_json_object();
+			delete_json_obj();
 		}
 		if (geeprom_dump_hex)
 			dump_hex(stdout, eeprom->data,
@@ -5925,6 +5929,7 @@ static const struct option args[] = {
 		.opts	= "-m|--dump-module-eeprom|--module-info",
 		.func	= do_getmodule,
 		.nlfunc = nl_getmodule,
+		.json	= true,
 		.help	= "Query/Decode Module EEPROM information and optical diagnostics if available",
 		.xhelp	= "		[ raw on|off ]\n"
 			  "		[ hex on|off ]\n"
diff --git a/sff-common.c b/sff-common.c
index e951cf1..2d7c995 100644
--- a/sff-common.c
+++ b/sff-common.c
@@ -62,218 +62,257 @@ void sff8024_show_oui(const __u8 *id, int id_offset)
 
 void sff8024_show_identifier(const __u8 *id, int id_offset)
 {
-	printf("\t%-41s : 0x%02x", "Identifier", id[id_offset]);
+	char identifier_description[64];
+
 	switch (id[id_offset]) {
 	case SFF8024_ID_UNKNOWN:
-		printf(" (no module present, unknown, or unspecified)\n");
+		strncpy(identifier_description,
+			 "no module present, unknown, or unspecified", 64);
 		break;
 	case SFF8024_ID_GBIC:
-		printf(" (GBIC)\n");
+		strncpy(identifier_description, "GBIC", 64);
 		break;
 	case SFF8024_ID_SOLDERED_MODULE:
-		printf(" (module soldered to motherboard)\n");
+		strncpy(identifier_description,
+			 "module soldered to motherboard", 64);
 		break;
 	case SFF8024_ID_SFP:
-		printf(" (SFP)\n");
+		strncpy(identifier_description, "SFP", 64);
 		break;
 	case SFF8024_ID_300_PIN_XBI:
-		printf(" (300 pin XBI)\n");
+		strncpy(identifier_description, "300 pin XBI", 64);
 		break;
 	case SFF8024_ID_XENPAK:
-		printf(" (XENPAK)\n");
+		strncpy(identifier_description, "XENPAK", 64);
 		break;
 	case SFF8024_ID_XFP:
-		printf(" (XFP)\n");
+		strncpy(identifier_description, "XFP", 64);
 		break;
 	case SFF8024_ID_XFF:
-		printf(" (XFF)\n");
+		strncpy(identifier_description, "XFF", 64);
 		break;
 	case SFF8024_ID_XFP_E:
-		printf(" (XFP-E)\n");
+		strncpy(identifier_description, "XFP-E", 64);
 		break;
 	case SFF8024_ID_XPAK:
-		printf(" (XPAK)\n");
+		strncpy(identifier_description, "XPAK", 64);
 		break;
 	case SFF8024_ID_X2:
-		printf(" (X2)\n");
+		strncpy(identifier_description, "X2", 64);
 		break;
 	case SFF8024_ID_DWDM_SFP:
-		printf(" (DWDM-SFP)\n");
+		strncpy(identifier_description, "DWDM-SFP", 64);
 		break;
 	case SFF8024_ID_QSFP:
-		printf(" (QSFP)\n");
+		strncpy(identifier_description, "QSFP", 64);
 		break;
 	case SFF8024_ID_QSFP_PLUS:
-		printf(" (QSFP+)\n");
+		strncpy(identifier_description, "QSFP+", 64);
 		break;
 	case SFF8024_ID_CXP:
-		printf(" (CXP)\n");
+		strncpy(identifier_description, "CXP", 64);
 		break;
 	case SFF8024_ID_HD4X:
-		printf(" (Shielded Mini Multilane HD 4X)\n");
+		strncpy(identifier_description,
+			 "Shielded Mini Multilane HD 4X", 64);
 		break;
 	case SFF8024_ID_HD8X:
-		printf(" (Shielded Mini Multilane HD 8X)\n");
+		strncpy(identifier_description,
+			 "Shielded Mini Multilane HD 8X", 64);
 		break;
 	case SFF8024_ID_QSFP28:
-		printf(" (QSFP28)\n");
+		strncpy(identifier_description, "QSFP28", 64);
 		break;
 	case SFF8024_ID_CXP2:
-		printf(" (CXP2/CXP28)\n");
+		strncpy(identifier_description, "CXP2/CXP28", 64);
 		break;
 	case SFF8024_ID_CDFP:
-		printf(" (CDFP Style 1/Style 2)\n");
+		strncpy(identifier_description, "CDFP Style 1/Style 2", 64);
 		break;
 	case SFF8024_ID_HD4X_FANOUT:
-		printf(" (Shielded Mini Multilane HD 4X Fanout Cable)\n");
+		strncpy(identifier_description,
+			 "Shielded Mini Multilane HD 4X Fanout Cable", 64);
 		break;
 	case SFF8024_ID_HD8X_FANOUT:
-		printf(" (Shielded Mini Multilane HD 8X Fanout Cable)\n");
+		strncpy(identifier_description,
+			 "Shielded Mini Multilane HD 8X Fanout Cable", 64);
 		break;
 	case SFF8024_ID_CDFP_S3:
-		printf(" (CDFP Style 3)\n");
+		strncpy(identifier_description, "CDFP Style 3", 64);
 		break;
 	case SFF8024_ID_MICRO_QSFP:
-		printf(" (microQSFP)\n");
+		strncpy(identifier_description, "microQSFP", 64);
 		break;
 	case SFF8024_ID_QSFP_DD:
-		printf(" (QSFP-DD Double Density 8X Pluggable Transceiver (INF-8628))\n");
+		strncpy(identifier_description,
+			 "QSFP-DD Double Density 8X Pluggable Transceiver (INF-8628)", 64);
 		break;
 	case SFF8024_ID_OSFP:
-		printf(" (OSFP 8X Pluggable Transceiver)\n");
+		strncpy(identifier_description,
+			 "OSFP 8X Pluggable Transceiver", 64);
 		break;
 	case SFF8024_ID_DSFP:
-		printf(" (DSFP Dual Small Form Factor Pluggable Transceiver)\n");
+		strncpy(identifier_description,
+			 "DSFP Dual Small Form Factor Pluggable Transceiver", 64);
 		break;
 	default:
-		printf(" (reserved or unknown)\n");
+		strncpy(identifier_description, "reserved or unknown", 64);
 		break;
 	}
+	if (is_json_context()) {
+		print_int(PRINT_JSON, "identifier", "0x%02x", id[id_offset]);
+		print_string(PRINT_JSON, "identifier_description",
+			     "%s", identifier_description);
+	} else {
+		printf("\t%-41s : 0x%02x (%s)\n", "Identifier",
+		       id[id_offset], identifier_description);
+	}
 }
 
 void sff8024_show_connector(const __u8 *id, int ctor_offset)
 {
-	printf("\t%-41s : 0x%02x", "Connector", id[ctor_offset]);
+	char connector_description[64];
+
 	switch (id[ctor_offset]) {
 	case  SFF8024_CTOR_UNKNOWN:
-		printf(" (unknown or unspecified)\n");
+		strncpy(connector_description, "unknown or unspecified", 64);
 		break;
 	case SFF8024_CTOR_SC:
-		printf(" (SC)\n");
+		strncpy(connector_description, "SC", 64);
 		break;
 	case SFF8024_CTOR_FC_STYLE_1:
-		printf(" (Fibre Channel Style 1 copper)\n");
+		strncpy(connector_description, "Fibre Channel Style 1 copper", 64);
 		break;
 	case SFF8024_CTOR_FC_STYLE_2:
-		printf(" (Fibre Channel Style 2 copper)\n");
+		strncpy(connector_description, "Fibre Channel Style 2 copper", 64);
 		break;
 	case SFF8024_CTOR_BNC_TNC:
-		printf(" (BNC/TNC)\n");
+		strncpy(connector_description, "BNC/TNC", 64);
 		break;
 	case SFF8024_CTOR_FC_COAX:
-		printf(" (Fibre Channel coaxial headers)\n");
+		strncpy(connector_description, "Fibre Channel coaxial headers", 64);
 		break;
 	case SFF8024_CTOR_FIBER_JACK:
-		printf(" (FibreJack)\n");
+		strncpy(connector_description, "FibreJack", 64);
 		break;
 	case SFF8024_CTOR_LC:
-		printf(" (LC)\n");
+		strncpy(connector_description, "LC", 64);
 		break;
 	case SFF8024_CTOR_MT_RJ:
-		printf(" (MT-RJ)\n");
+		strncpy(connector_description, "MT-RJ", 64);
 		break;
 	case SFF8024_CTOR_MU:
-		printf(" (MU)\n");
+		strncpy(connector_description, "MU", 64);
 		break;
 	case SFF8024_CTOR_SG:
-		printf(" (SG)\n");
+		strncpy(connector_description, "SG", 64);
 		break;
 	case SFF8024_CTOR_OPT_PT:
-		printf(" (Optical pigtail)\n");
+		strncpy(connector_description, "Optical pigtail", 64);
 		break;
 	case SFF8024_CTOR_MPO:
-		printf(" (MPO Parallel Optic)\n");
+		strncpy(connector_description, "MPO Parallel Optic", 64);
 		break;
 	case SFF8024_CTOR_MPO_2:
-		printf(" (MPO Parallel Optic - 2x16)\n");
+		strncpy(connector_description, "MPO Parallel Optic - 2x16", 64);
 		break;
 	case SFF8024_CTOR_HSDC_II:
-		printf(" (HSSDC II)\n");
+		strncpy(connector_description, "HSSDC II", 64);
 		break;
 	case SFF8024_CTOR_COPPER_PT:
-		printf(" (Copper pigtail)\n");
+		strncpy(connector_description, "Copper pigtail", 64);
 		break;
 	case SFF8024_CTOR_RJ45:
-		printf(" (RJ45)\n");
+		strncpy(connector_description, "RJ45", 64);
 		break;
 	case SFF8024_CTOR_NO_SEPARABLE:
-		printf(" (No separable connector)\n");
+		strncpy(connector_description, "No separable connector", 64);
 		break;
 	case SFF8024_CTOR_MXC_2x16:
-		printf(" (MXC 2x16)\n");
+		strncpy(connector_description, "MXC 2x16", 64);
 		break;
 	case SFF8024_CTOR_CS_OPTICAL:
-		printf(" (CS optical connector)\n");
+		strncpy(connector_description, "CS optical connector", 64);
 		break;
 	case SFF8024_CTOR_CS_OPTICAL_MINI:
-		printf(" (Mini CS optical connector)\n");
+		strncpy(connector_description, "Mini CS optical connector", 64);
 		break;
 	case SFF8024_CTOR_MPO_2X12:
-		printf(" (MPO 2x12)\n");
+		strncpy(connector_description, "MPO 2x12", 64);
 		break;
 	case SFF8024_CTOR_MPO_1X16:
-		printf(" (MPO 1x16)\n");
+		strncpy(connector_description, "MPO 1x16", 64);
 		break;
 	default:
-		printf(" (reserved or unknown)\n");
+		strncpy(connector_description, "reserved or unknown", 64);
 		break;
 	}
+
+	if (is_json_context()) {
+		print_int(PRINT_JSON, "connector", "%0x02x", id[ctor_offset]);
+		print_string(PRINT_JSON, "connector_description",
+			     "%s", connector_description);
+	} else {
+		printf("\t%-41s : 0x%02x (%s)\n", "Connector",
+		       id[ctor_offset], connector_description);
+	}
 }
 
 void sff8024_show_encoding(const __u8 *id, int encoding_offset, int sff_type)
 {
-	printf("\t%-41s : 0x%02x", "Encoding", id[encoding_offset]);
+	char encoding_description[64];
+
 	switch (id[encoding_offset]) {
 	case SFF8024_ENCODING_UNSPEC:
-		printf(" (unspecified)\n");
+		strncpy(encoding_description, "unspecified", 64);
 		break;
 	case SFF8024_ENCODING_8B10B:
-		printf(" (8B/10B)\n");
+		strncpy(encoding_description, "8B/10B", 64);
 		break;
 	case SFF8024_ENCODING_4B5B:
-		printf(" (4B/5B)\n");
+		strncpy(encoding_description, "4B/5B", 64);
 		break;
 	case SFF8024_ENCODING_NRZ:
-		printf(" (NRZ)\n");
+		strncpy(encoding_description, "NRZ", 64);
 		break;
 	case SFF8024_ENCODING_4h:
 		if (sff_type == ETH_MODULE_SFF_8472)
-			printf(" (Manchester)\n");
+			strncpy(encoding_description, "Manchester", 64);
 		else if (sff_type == ETH_MODULE_SFF_8636)
-			printf(" (SONET Scrambled)\n");
+			strncpy(encoding_description, "SONET Scrambled", 64);
 		break;
 	case SFF8024_ENCODING_5h:
 		if (sff_type == ETH_MODULE_SFF_8472)
-			printf(" (SONET Scrambled)\n");
+			strncpy(encoding_description, "SONET Scrambled", 64);
 		else if (sff_type == ETH_MODULE_SFF_8636)
-			printf(" (64B/66B)\n");
+			strncpy(encoding_description, "64B/66B", 64);
 		break;
 	case SFF8024_ENCODING_6h:
 		if (sff_type == ETH_MODULE_SFF_8472)
-			printf(" (64B/66B)\n");
+			strncpy(encoding_description, "64B/66B", 64);
 		else if (sff_type == ETH_MODULE_SFF_8636)
-			printf(" (Manchester)\n");
+			strncpy(encoding_description, "Manchester", 64);
 		break;
 	case SFF8024_ENCODING_256B:
-		printf(" ((256B/257B (transcoded FEC-enabled data))\n");
+		strncpy(encoding_description,
+			"256B/257B (transcoded FEC-enabled data)", 64);
 		break;
 	case SFF8024_ENCODING_PAM4:
-		printf(" (PAM4)\n");
+		strncpy(encoding_description, "PAM4", 64);
 		break;
 	default:
-		printf(" (reserved or unknown)\n");
+		strncpy(encoding_description, "reserved or unknown", 64);
 		break;
 	}
+
+	if (is_json_context()) {
+		print_int(PRINT_JSON, "encoding", "0x%02x", id[encoding_offset]);
+		print_string(PRINT_JSON, "encoding_description",
+			     "%s", encoding_description);
+	} else {
+		printf("\t%-41s : 0x%02x (%s)\n", "Encoding",
+		       id[encoding_offset], encoding_description);
+	}
 }
 
 void sff_show_thresholds(struct sff_diags sd)
@@ -324,6 +363,44 @@ void sff_show_thresholds(struct sff_diags sd)
 		     sd.rx_power[LWARN]);
 }
 
+void sff_show_thresholds_json(struct sff_diags sd)
+{
+	open_json_object("laser_bias_current");
+	PRINT_BIAS_JSON("high_alarm",	sd.bias_cur[HALRM]);
+	PRINT_BIAS_JSON("low_alarm",	sd.bias_cur[LALRM]);
+	PRINT_BIAS_JSON("high_warning", sd.bias_cur[HWARN]);
+	PRINT_BIAS_JSON("low_warning",	sd.bias_cur[HWARN]);
+	close_json_object();
+
+	open_json_object("laser_output_power");
+	PRINT_xX_PWR_JSON("high_alarm",		sd.tx_power[HALRM]);
+	PRINT_xX_PWR_JSON("low_alarm",		sd.tx_power[LALRM]);
+	PRINT_xX_PWR_JSON("high_warning",	sd.tx_power[LALRM]);
+	PRINT_xX_PWR_JSON("low_warning",	sd.tx_power[LALRM]);
+	close_json_object();
+
+	open_json_object("module_temperature");
+	PRINT_TEMP_JSON("high_alarm", sd.sfp_temp[HALRM]);
+	PRINT_TEMP_JSON("low_alarm", sd.sfp_temp[LALRM]);
+	PRINT_TEMP_JSON("high_warning", sd.sfp_temp[HWARN]);
+	PRINT_TEMP_JSON("low_warning", sd.sfp_temp[HWARN]);
+	close_json_object();
+
+	open_json_object("module_voltage");
+	PRINT_VCC_JSON("high_alarm", sd.sfp_voltage[HALRM]);
+	PRINT_VCC_JSON("low_alarm", sd.sfp_voltage[LALRM]);
+	PRINT_VCC_JSON("high_warning", sd.sfp_voltage[HWARN]);
+	PRINT_VCC_JSON("low_warning", sd.sfp_voltage[LWARN]);
+	close_json_object();
+
+	open_json_object("laser_rx_power");
+	PRINT_xX_PWR_JSON("high_alarm",		sd.rx_power[HALRM]);
+	PRINT_xX_PWR_JSON("low_alarm",		sd.rx_power[LALRM]);
+	PRINT_xX_PWR_JSON("high_warning",	sd.rx_power[LALRM]);
+	PRINT_xX_PWR_JSON("low_warning",	sd.rx_power[LALRM]);
+	close_json_object();
+}
+
 void sff_show_revision_compliance(const __u8 *id, int rev_offset)
 {
 	static const char *pfx =
diff --git a/sff-common.h b/sff-common.h
index dd12dda..9750273 100644
--- a/sff-common.h
+++ b/sff-common.h
@@ -134,19 +134,31 @@
 		printf("\t%-41s : %.4f mW / %.2f dBm\n", (string),         \
 		      (double)((var) / 10000.),                           \
 		       convert_mw_to_dbm((double)((var) / 10000.)))
+#define PRINT_xX_PWR_JSON(key, var)			       \
+		print_float(PRINT_JSON, key, "%.2f",	       \
+			    (double)((var) / 10000.))
 
+#define BIAS_DIV(value) ((double)(value / 500.))
 #define PRINT_BIAS(string, bias_cur)                             \
 		printf("\t%-41s : %.3f mA\n", (string),                       \
-		      (double)(bias_cur / 500.))
+		       BIAS_DIV(bias_cur))
+
+#define PRINT_BIAS_JSON(key, bias_cur)				\
+		print_float(PRINT_JSON, key, "%.3f", BIAS_DIV(bias_cur))
 
 #define PRINT_TEMP(string, temp)                                   \
 		printf("\t%-41s : %.2f degrees C / %.2f degrees F\n", \
 		      (string), (double)(temp / 256.),                \
 		      (double)(temp / 256. * 1.8 + 32.))
-
+#define PRINT_TEMP_JSON(key, temp)				   \
+		print_float(PRINT_JSON, key, "%.2f",		   \
+			    (double)(temp / 256.))
 #define PRINT_VCC(string, sfp_voltage)          \
 		printf("\t%-41s : %.4f V\n", (string),       \
 		      (double)(sfp_voltage / 10000.))
+#define PRINT_VCC_JSON(key, sfp_voltage)		\
+		print_float(PRINT_JSON, key, "%.4f",	\
+			    (double)(sfp_voltage / 10000.))
 
 # define PRINT_xX_THRESH_PWR(string, var, index)                       \
 		PRINT_xX_PWR(string, (var)[(index)])
@@ -199,6 +211,7 @@ void sff_show_value_with_unit(const __u8 *id, unsigned int reg,
 void sff_show_ascii(const __u8 *id, unsigned int first_reg,
 		    unsigned int last_reg, const char *name);
 void sff_show_thresholds(struct sff_diags sd);
+void sff_show_thresholds_json(struct sff_diags sd);
 
 void sff8024_show_oui(const __u8 *id, int id_offset);
 void sff8024_show_identifier(const __u8 *id, int id_offset);
diff --git a/sfpdiag.c b/sfpdiag.c
index 1fa8b7b..c180f2f 100644
--- a/sfpdiag.c
+++ b/sfpdiag.c
@@ -8,6 +8,7 @@
  *   by SFF Committee.
  */
 
+#include <ctype.h>
 #include <stdio.h>
 #include <math.h>
 #include <arpa/inet.h>
@@ -239,6 +240,62 @@ static void sff8472_parse_eeprom(const __u8 *id, struct sff_diags *sd)
 		sff8472_calibration(id, sd);
 }
 
+static __u8 sff8472_alarm_human_to_json(const char *orig_desc,
+					char *new_desc, size_t max_len)
+{
+	__u8 cur_pos = 0;
+
+	while (orig_desc[cur_pos] != '\0' && cur_pos < max_len) {
+		if (orig_desc[cur_pos] == ' ')
+			new_desc[cur_pos] = '_';
+		else if (orig_desc[cur_pos] >= 'A' && orig_desc[cur_pos] <= 'Z')
+			new_desc[cur_pos] = tolower(orig_desc[cur_pos]);
+		else
+			new_desc[cur_pos] = orig_desc[cur_pos];
+		cur_pos++;
+	}
+
+	new_desc[cur_pos] = '\0';
+	return cur_pos;
+}
+
+void sff8472_show_all_json(const __u8 *id, struct sff_diags *sd)
+{
+	char json_alarm_name[64];
+	int i;
+
+	if (is_json_context()) {
+		print_bool(PRINT_JSON, "optical_diagnostics_supported",
+			   NULL, sd->supports_dom);
+	}
+
+	if (!sd->supports_dom)
+		return;
+
+	PRINT_BIAS_JSON("bias_current",		sd->bias_cur[MCURR]);
+	PRINT_xX_PWR_JSON("tx_power",		sd->tx_power[MCURR]);
+	PRINT_TEMP_JSON("module_temp",		sd->sfp_temp[MCURR]);
+	PRINT_VCC_JSON("module_voltage",	sd->sfp_voltage[MCURR]);
+	PRINT_xX_PWR_JSON("rx_power",		sd->rx_power[MCURR]);
+	print_bool(PRINT_JSON, "rx_power_is_average", NULL, sd->rx_power_type);
+	print_bool(PRINT_JSON, "supports_alarms", NULL, sd->supports_alarms);
+	if (sd->supports_alarms) {
+		open_json_object("alarms");
+		for (i = 0; sff8472_aw_flags[i].str; ++i) {
+			sff8472_alarm_human_to_json(sff8472_aw_flags[i].str,
+						    &json_alarm_name[0],
+						    64);
+			print_bool(PRINT_JSON, json_alarm_name, NULL,
+				   id[SFF_A2_BASE + sff8472_aw_flags[i].offset]
+				   & sff8472_aw_flags[i].value);
+		}
+		close_json_object();
+		open_json_object("thresholds");
+		sff_show_thresholds_json(*sd);
+		close_json_object();
+	}
+}
+
 void sff8472_show_all(const __u8 *id)
 {
 	struct sff_diags sd = {0};
@@ -247,6 +304,11 @@ void sff8472_show_all(const __u8 *id)
 
 	sff8472_parse_eeprom(id, &sd);
 
+	if (is_json_context()) {
+		sff8472_show_all_json(id, &sd);
+		return;
+	}
+
 	if (!sd.supports_dom) {
 		printf("\t%-41s : No\n", "Optical diagnostics support");
 		return;
@@ -268,8 +330,8 @@ void sff8472_show_all(const __u8 *id)
 
 	printf("\t%-41s : %s\n", "Alarm/warning flags implemented",
 	       (sd.supports_alarms ? "Yes" : "No"));
-	if (sd.supports_alarms) {
 
+	if (sd.supports_alarms) {
 		for (i = 0; sff8472_aw_flags[i].str; ++i) {
 			printf("\t%-41s : %s\n", sff8472_aw_flags[i].str,
 			       id[SFF_A2_BASE + sff8472_aw_flags[i].offset]
diff --git a/sfpid.c b/sfpid.c
index 1bc45c1..d6ce88b 100644
--- a/sfpid.c
+++ b/sfpid.c
@@ -24,15 +24,28 @@ static void sff8079_show_identifier(const __u8 *id)
 
 static void sff8079_show_ext_identifier(const __u8 *id)
 {
-	printf("\t%-41s : 0x%02x", "Extended identifier", id[1]);
+	char ext_identifier_description[64];
+
 	if (id[1] == 0x00)
-		printf(" (GBIC not specified / not MOD_DEF compliant)\n");
+		strncpy(ext_identifier_description,
+			 "GBIC not specified / not MOD_DEF compliant", 64);
 	else if (id[1] == 0x04)
-		printf(" (GBIC/SFP defined by 2-wire interface ID)\n");
+		strncpy(ext_identifier_description,
+			 "GBIC/SFP defined by 2-wire interface ID", 64);
 	else if (id[1] <= 0x07)
-		printf(" (GBIC compliant with MOD_DEF %u)\n", id[1]);
+		snprintf(ext_identifier_description, 64,
+			 "GBIC compliant with MOD_DEF %u", id[1]);
 	else
-		printf(" (unknown)\n");
+		strncpy(ext_identifier_description, "unknown", 64);
+
+	if (is_json_context()) {
+		print_int(PRINT_JSON, "extended_identifier", NULL, id[1]);
+		print_string(PRINT_JSON, "extended_identifier_description",
+			     NULL, ext_identifier_description);
+	} else {
+		printf("\t%-41s : 0x%02x (%s)\n", "Extended identifier",
+		       id[1], ext_identifier_description);
+	}
 }
 
 static void sff8079_show_connector(const __u8 *id)
@@ -40,233 +53,244 @@ static void sff8079_show_connector(const __u8 *id)
 	sff8024_show_connector(id, 2);
 }
 
+static void print_transceiver_type(const char *desc)
+{
+	if (is_json_context())
+		print_string(PRINT_JSON, NULL, NULL, desc);
+	else
+		printf("\t%-41s : %s\n", "Transceiver type", desc);
+}
+
 static void sff8079_show_transceiver(const __u8 *id)
 {
-	static const char *pfx =
-		"\tTransceiver type                          :";
-
-	printf("\t%-41s : 0x%02x 0x%02x 0x%02x " \
-	       "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
-		   "Transceiver codes",
-	       id[3], id[4], id[5], id[6],
-	       id[7], id[8], id[9], id[10], id[36]);
+	int i;
+
+	if (!is_json_context()) {
+		printf("\t%-41s : 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		       "Transceiver codes",
+		       id[3], id[4], id[5], id[6],
+		       id[7], id[8], id[9], id[10], id[36]);
+	} else {
+		open_json_array("transceiver_codes", NULL);
+
+		for (i = 3; i < 11; i++)
+			print_int(PRINT_JSON, NULL, NULL, id[i]);
+
+		print_int(PRINT_JSON, NULL, NULL, id[36]);
+		close_json_array(NULL);
+		open_json_array("transceiver_types", NULL);
+	}
+
 	/* 10G Ethernet Compliance Codes */
 	if (id[3] & (1 << 7))
-		printf("%s 10G Ethernet: 10G Base-ER" \
-		       " [SFF-8472 rev10.4 onwards]\n", pfx);
+		print_transceiver_type("10G Ethernet: 10G Base-ER [SFF-8472 rev10.4 onwards]");
 	if (id[3] & (1 << 6))
-		printf("%s 10G Ethernet: 10G Base-LRM\n", pfx);
+		print_transceiver_type("10G Ethernet: 10G Base-LRM");
 	if (id[3] & (1 << 5))
-		printf("%s 10G Ethernet: 10G Base-LR\n", pfx);
+		print_transceiver_type("10G Ethernet: 10G Base-LR");
 	if (id[3] & (1 << 4))
-		printf("%s 10G Ethernet: 10G Base-SR\n", pfx);
+		print_transceiver_type("10G Ethernet: 10G Base-SR");
 	/* Infiniband Compliance Codes */
 	if (id[3] & (1 << 3))
-		printf("%s Infiniband: 1X SX\n", pfx);
+		print_transceiver_type("Infiniband: 1X SX");
 	if (id[3] & (1 << 2))
-		printf("%s Infiniband: 1X LX\n", pfx);
+		print_transceiver_type("Infiniband: 1X LX");
 	if (id[3] & (1 << 1))
-		printf("%s Infiniband: 1X Copper Active\n", pfx);
+		print_transceiver_type("Infiniband: 1X Copper Active");
 	if (id[3] & (1 << 0))
-		printf("%s Infiniband: 1X Copper Passive\n", pfx);
+		print_transceiver_type("Infiniband: 1X Copper Passive");
 	/* ESCON Compliance Codes */
 	if (id[4] & (1 << 7))
-		printf("%s ESCON: ESCON MMF, 1310nm LED\n", pfx);
+		print_transceiver_type("ESCON: ESCON MMF, 1310nm LED");
 	if (id[4] & (1 << 6))
-		printf("%s ESCON: ESCON SMF, 1310nm Laser\n", pfx);
+		print_transceiver_type("ESCON: ESCON SMF, 1310nm Laser");
 	/* SONET Compliance Codes */
 	if (id[4] & (1 << 5))
-		printf("%s SONET: OC-192, short reach\n", pfx);
+		print_transceiver_type("SONET: OC-192, short reach");
 	if (id[4] & (1 << 4))
-		printf("%s SONET: SONET reach specifier bit 1\n", pfx);
+		print_transceiver_type("SONET: SONET reach specifier bit 1");
 	if (id[4] & (1 << 3))
-		printf("%s SONET: SONET reach specifier bit 2\n", pfx);
+		print_transceiver_type("SONET: SONET reach specifier bit 2");
 	if (id[4] & (1 << 2))
-		printf("%s SONET: OC-48, long reach\n", pfx);
+		print_transceiver_type("SONET: OC-48, long reach");
 	if (id[4] & (1 << 1))
-		printf("%s SONET: OC-48, intermediate reach\n", pfx);
+		print_transceiver_type("SONET: OC-48, intermediate reach");
 	if (id[4] & (1 << 0))
-		printf("%s SONET: OC-48, short reach\n", pfx);
+		print_transceiver_type("SONET: OC-48, short reach");
 	if (id[5] & (1 << 6))
-		printf("%s SONET: OC-12, single mode, long reach\n", pfx);
+		print_transceiver_type("SONET: OC-12, single mode, long reach");
 	if (id[5] & (1 << 5))
-		printf("%s SONET: OC-12, single mode, inter. reach\n", pfx);
+		print_transceiver_type("SONET: OC-12, single mode, inter. reach");
 	if (id[5] & (1 << 4))
-		printf("%s SONET: OC-12, short reach\n", pfx);
+		print_transceiver_type("SONET: OC-12, short reach");
 	if (id[5] & (1 << 2))
-		printf("%s SONET: OC-3, single mode, long reach\n", pfx);
+		print_transceiver_type("SONET: OC-3, single mode, long reach");
 	if (id[5] & (1 << 1))
-		printf("%s SONET: OC-3, single mode, inter. reach\n", pfx);
+		print_transceiver_type("SONET: OC-3, single mode, inter. reach");
 	if (id[5] & (1 << 0))
-		printf("%s SONET: OC-3, short reach\n", pfx);
+		print_transceiver_type("SONET: OC-3, short reach");
 	/* Ethernet Compliance Codes */
 	if (id[6] & (1 << 7))
-		printf("%s Ethernet: BASE-PX\n", pfx);
+		print_transceiver_type("Ethernet: BASE-PX");
 	if (id[6] & (1 << 6))
-		printf("%s Ethernet: BASE-BX10\n", pfx);
+		print_transceiver_type("Ethernet: BASE-BX10");
 	if (id[6] & (1 << 5))
-		printf("%s Ethernet: 100BASE-FX\n", pfx);
+		print_transceiver_type("Ethernet: 100BASE-FX");
 	if (id[6] & (1 << 4))
-		printf("%s Ethernet: 100BASE-LX/LX10\n", pfx);
+		print_transceiver_type("Ethernet: 100BASE-LX/LX10");
 	if (id[6] & (1 << 3))
-		printf("%s Ethernet: 1000BASE-T\n", pfx);
+		print_transceiver_type("Ethernet: 1000BASE-T");
 	if (id[6] & (1 << 2))
-		printf("%s Ethernet: 1000BASE-CX\n", pfx);
+		print_transceiver_type("Ethernet: 1000BASE-CX");
 	if (id[6] & (1 << 1))
-		printf("%s Ethernet: 1000BASE-LX\n", pfx);
+		print_transceiver_type("Ethernet: 1000BASE-LX");
 	if (id[6] & (1 << 0))
-		printf("%s Ethernet: 1000BASE-SX\n", pfx);
+		print_transceiver_type("Ethernet: 1000BASE-SX");
 	/* Fibre Channel link length */
 	if (id[7] & (1 << 7))
-		printf("%s FC: very long distance (V)\n", pfx);
+		print_transceiver_type("FC: very long distance (V)");
 	if (id[7] & (1 << 6))
-		printf("%s FC: short distance (S)\n", pfx);
+		print_transceiver_type("FC: short distance (S)");
 	if (id[7] & (1 << 5))
-		printf("%s FC: intermediate distance (I)\n", pfx);
+		print_transceiver_type("FC: intermediate distance (I)");
 	if (id[7] & (1 << 4))
-		printf("%s FC: long distance (L)\n", pfx);
+		print_transceiver_type("FC: long distance (L)");
 	if (id[7] & (1 << 3))
-		printf("%s FC: medium distance (M)\n", pfx);
+		print_transceiver_type("FC: medium distance (M)");
 	/* Fibre Channel transmitter technology */
 	if (id[7] & (1 << 2))
-		printf("%s FC: Shortwave laser, linear Rx (SA)\n", pfx);
+		print_transceiver_type("FC: Shortwave laser, linear Rx (SA)");
 	if (id[7] & (1 << 1))
-		printf("%s FC: Longwave laser (LC)\n", pfx);
+		print_transceiver_type("FC: Longwave laser (LC)");
 	if (id[7] & (1 << 0))
-		printf("%s FC: Electrical inter-enclosure (EL)\n", pfx);
+		print_transceiver_type("FC: Electrical inter-enclosure (EL)");
 	if (id[8] & (1 << 7))
-		printf("%s FC: Electrical intra-enclosure (EL)\n", pfx);
+		print_transceiver_type("FC: Electrical intra-enclosure (EL)");
 	if (id[8] & (1 << 6))
-		printf("%s FC: Shortwave laser w/o OFC (SN)\n", pfx);
+		print_transceiver_type("FC: Shortwave laser w/o OFC (SN)");
 	if (id[8] & (1 << 5))
-		printf("%s FC: Shortwave laser with OFC (SL)\n", pfx);
+		print_transceiver_type("FC: Shortwave laser with OFC (SL)");
 	if (id[8] & (1 << 4))
-		printf("%s FC: Longwave laser (LL)\n", pfx);
+		print_transceiver_type("FC: Longwave laser (LL)");
 	if (id[8] & (1 << 3))
-		printf("%s Active Cable\n", pfx);
+		print_transceiver_type("Active Cable");
 	if (id[8] & (1 << 2))
-		printf("%s Passive Cable\n", pfx);
+		print_transceiver_type("Passive Cable");
 	if (id[8] & (1 << 1))
-		printf("%s FC: Copper FC-BaseT\n", pfx);
+		print_transceiver_type("FC: Copper FC-BaseT");
 	/* Fibre Channel transmission media */
 	if (id[9] & (1 << 7))
-		printf("%s FC: Twin Axial Pair (TW)\n", pfx);
+		print_transceiver_type("FC: Twin Axial Pair (TW)");
 	if (id[9] & (1 << 6))
-		printf("%s FC: Twisted Pair (TP)\n", pfx);
+		print_transceiver_type("FC: Twisted Pair (TP)");
 	if (id[9] & (1 << 5))
-		printf("%s FC: Miniature Coax (MI)\n", pfx);
+		print_transceiver_type("FC: Miniature Coax (MI)");
 	if (id[9] & (1 << 4))
-		printf("%s FC: Video Coax (TV)\n", pfx);
+		print_transceiver_type("FC: Video Coax (TV)");
 	if (id[9] & (1 << 3))
-		printf("%s FC: Multimode, 62.5um (M6)\n", pfx);
+		print_transceiver_type("FC: Multimode, 62.5um (M6)");
 	if (id[9] & (1 << 2))
-		printf("%s FC: Multimode, 50um (M5)\n", pfx);
+		print_transceiver_type("FC: Multimode, 50um (M5)");
 	if (id[9] & (1 << 0))
-		printf("%s FC: Single Mode (SM)\n", pfx);
+		print_transceiver_type("FC: Single Mode (SM)");
 	/* Fibre Channel speed */
 	if (id[10] & (1 << 7))
-		printf("%s FC: 1200 MBytes/sec\n", pfx);
+		print_transceiver_type("FC: 1200 MBytes/sec");
 	if (id[10] & (1 << 6))
-		printf("%s FC: 800 MBytes/sec\n", pfx);
+		print_transceiver_type("FC: 800 MBytes/sec");
 	if (id[10] & (1 << 4))
-		printf("%s FC: 400 MBytes/sec\n", pfx);
+		print_transceiver_type("FC: 400 MBytes/sec");
 	if (id[10] & (1 << 2))
-		printf("%s FC: 200 MBytes/sec\n", pfx);
+		print_transceiver_type("FC: 200 MBytes/sec");
 	if (id[10] & (1 << 0))
-		printf("%s FC: 100 MBytes/sec\n", pfx);
+		print_transceiver_type("FC: 100 MBytes/sec");
 	/* Extended Specification Compliance Codes from SFF-8024 */
 	if (id[36] == 0x1)
-		printf("%s Extended: 100G AOC or 25GAUI C2M AOC with worst BER of 5x10^(-5)\n", pfx);
+		print_transceiver_type("Extended: 100G AOC or 25GAUI C2M AOC with worst BER of 5x10^(-5)");
 	if (id[36] == 0x2)
-		printf("%s Extended: 100G Base-SR4 or 25GBase-SR\n", pfx);
+		print_transceiver_type("Extended: 100G Base-SR4 or 25GBase-SR");
 	if (id[36] == 0x3)
-		printf("%s Extended: 100G Base-LR4 or 25GBase-LR\n", pfx);
+		print_transceiver_type("Extended: 100G Base-LR4 or 25GBase-LR");
 	if (id[36] == 0x4)
-		printf("%s Extended: 100G Base-ER4 or 25GBase-ER\n", pfx);
+		print_transceiver_type("Extended: 100G Base-ER4 or 25GBase-ER");
 	if (id[36] == 0x8)
-		printf("%s Extended: 100G ACC or 25GAUI C2M ACC with worst BER of 5x10^(-5)\n", pfx);
+		print_transceiver_type("Extended: 100G ACC or 25GAUI C2M ACC with worst BER of 5x10^(-5)");
 	if (id[36] == 0xb)
-		printf("%s Extended: 100G Base-CR4 or 25G Base-CR CA-L\n", pfx);
+		print_transceiver_type("Extended: 100G Base-CR4 or 25G Base-CR CA-L");
 	if (id[36] == 0xc)
-		printf("%s Extended: 25G Base-CR CA-S\n", pfx);
+		print_transceiver_type("Extended: 25G Base-CR CA-S");
 	if (id[36] == 0xd)
-		printf("%s Extended: 25G Base-CR CA-N\n", pfx);
+		print_transceiver_type("Extended: 25G Base-CR CA-N");
 	if (id[36] == 0x16)
-		printf("%s Extended: 10Gbase-T with SFI electrical interface\n", pfx);
+		print_transceiver_type("Extended: 10Gbase-T with SFI electrical interface");
 	if (id[36] == 0x18)
-		printf("%s Extended: 100G AOC or 25GAUI C2M AOC with worst BER of 10^(-12)\n", pfx);
+		print_transceiver_type("Extended: 100G AOC or 25GAUI C2M AOC with worst BER of 10^(-12)");
 	if (id[36] == 0x19)
-		printf("%s Extended: 100G ACC or 25GAUI C2M ACC with worst BER of 10^(-12)\n", pfx);
+		print_transceiver_type("Extended: 100G ACC or 25GAUI C2M ACC with worst BER of 10^(-12)");
 	if (id[36] == 0x1a)
-		printf("%s Extended: 100GE-DWDM2 (DWDM transceiver using 2 wavelengths on a 1550 nm DWDM grid with a reach up to 80 km)\n",
-		       pfx);
+		print_transceiver_type("Extended: 100GE-DWDM2 (DWDM transceiver using 2 wavelengths on a 1550 nm DWDM with a reach up to 80 km)");
 	if (id[36] == 0x1b)
-		printf("%s Extended: 100G 1550nm WDM (4 wavelengths)\n", pfx);
+		print_transceiver_type("Extended: 100G 1550nm WDM (4 wavelengths)");
 	if (id[36] == 0x1c)
-		printf("%s Extended: 10Gbase-T Short Reach\n", pfx);
+		print_transceiver_type("Extended: 10Gbase-T Short Reach");
 	if (id[36] == 0x1d)
-		printf("%s Extended: 5GBASE-T\n", pfx);
+		print_transceiver_type("Extended: 5GBASE-T");
 	if (id[36] == 0x1e)
-		printf("%s Extended: 2.5GBASE-T\n", pfx);
+		print_transceiver_type("Extended: 2.5GBASE-T");
 	if (id[36] == 0x1f)
-		printf("%s Extended: 40G SWDM4\n", pfx);
+		print_transceiver_type("Extended: 40G SWDM4");
 	if (id[36] == 0x20)
-		printf("%s Extended: 100G SWDM4\n", pfx);
+		print_transceiver_type("Extended: 100G SWDM4");
 	if (id[36] == 0x21)
-		printf("%s Extended: 100G PAM4 BiDi\n", pfx);
+		print_transceiver_type("Extended: 100G PAM4 BiDi");
 	if (id[36] == 0x22)
-		printf("%s Extended: 4WDM-10 MSA (10km version of 100G CWDM4 with same RS(528,514) FEC in host system)\n",
-		       pfx);
+		print_transceiver_type("Extended: 4WDM-10 MSA (10km version of 100G CWDM4 with same RS(528,514) FEC in host system)");
 	if (id[36] == 0x23)
-		printf("%s Extended: 4WDM-20 MSA (20km version of 100GBASE-LR4 with RS(528,514) FEC in host system)\n",
-		       pfx);
+		print_transceiver_type("Extended: 4WDM-20 MSA (20km version of 100GBASE-LR4 with RS(528,514) FEC in host system)");
 	if (id[36] == 0x24)
-		printf("%s Extended: 4WDM-40 MSA (40km reach with APD receiver and RS(528,514) FEC in host system)\n",
-		       pfx);
+		print_transceiver_type("Extended: 4WDM-40 MSA (40km reach with APD receiver and RS(528,514) FEC in host system)");
 	if (id[36] == 0x25)
-		printf("%s Extended: 100GBASE-DR (clause 140), CAUI-4 (no FEC)\n", pfx);
+		print_transceiver_type("Extended: 100GBASE-DR (clause 140), CAUI-4 (no FEC)");
 	if (id[36] == 0x26)
-		printf("%s Extended: 100G-FR or 100GBASE-FR1 (clause 140), CAUI-4 (no FEC)\n", pfx);
+		print_transceiver_type("Extended: 100G-FR or 100GBASE-FR1 (clause 140), CAUI-4 (no FEC)");
 	if (id[36] == 0x27)
-		printf("%s Extended: 100G-LR or 100GBASE-LR1 (clause 140), CAUI-4 (no FEC)\n", pfx);
+		print_transceiver_type("Extended: 100G-LR or 100GBASE-LR1 (clause 140), CAUI-4 (no FEC)");
 	if (id[36] == 0x30)
-		printf("%s Extended: Active Copper Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 10-6 or below\n",
-		       pfx);
+		print_transceiver_type("Extended: Active Copper Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 10-6 or below");
 	if (id[36] == 0x31)
-		printf("%s Extended: Active Optical Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 10-6 or below\n",
-		       pfx);
+		print_transceiver_type("Extended: Active Optical Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 10-6 or below");
 	if (id[36] == 0x32)
-		printf("%s Extended: Active Copper Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 2.6x10-4 for ACC, 10-5 for AUI, or below\n",
-		       pfx);
+		print_transceiver_type("Extended: Active Copper Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 2.6x10-4 for ACC, 10-5 for AUI, or below");
 	if (id[36] == 0x33)
-		printf("%s Extended: Active Optical Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 2.6x10-4 for ACC, 10-5 for AUI, or below\n",
-		       pfx);
+		print_transceiver_type("Extended: Active Optical Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 2.6x10-4 for ACC, 10-5 for AUI, or below");
 	if (id[36] == 0x40)
-		printf("%s Extended: 50GBASE-CR, 100GBASE-CR2, or 200GBASE-CR4\n", pfx);
+		print_transceiver_type("Extended: 50GBASE-CR, 100GBASE-CR2, or 200GBASE-CR4");
 	if (id[36] == 0x41)
-		printf("%s Extended: 50GBASE-SR, 100GBASE-SR2, or 200GBASE-SR4\n", pfx);
+		print_transceiver_type("Extended: 50GBASE-SR, 100GBASE-SR2, or 200GBASE-SR4");
 	if (id[36] == 0x42)
-		printf("%s Extended: 50GBASE-FR or 200GBASE-DR4\n", pfx);
+		print_transceiver_type("Extended: 50GBASE-FR or 200GBASE-DR4");
 	if (id[36] == 0x43)
-		printf("%s Extended: 200GBASE-FR4\n", pfx);
+		print_transceiver_type("Extended: 200GBASE-FR4");
 	if (id[36] == 0x44)
-		printf("%s Extended: 200G 1550 nm PSM4\n", pfx);
+		print_transceiver_type("Extended: 200G 1550 nm PSM4");
 	if (id[36] == 0x45)
-		printf("%s Extended: 50GBASE-LR\n", pfx);
+		print_transceiver_type("Extended: 50GBASE-LR");
 	if (id[36] == 0x46)
-		printf("%s Extended: 200GBASE-LR4\n", pfx);
+		print_transceiver_type("Extended: 200GBASE-LR4");
 	if (id[36] == 0x50)
-		printf("%s Extended: 64GFC EA\n", pfx);
+		print_transceiver_type("Extended: 196GFC EA");
 	if (id[36] == 0x51)
-		printf("%s Extended: 64GFC SW\n", pfx);
+		print_transceiver_type("Extended: 196GFC SW");
 	if (id[36] == 0x52)
-		printf("%s Extended: 64GFC LW\n", pfx);
+		print_transceiver_type("Extended: 196GFC LW");
 	if (id[36] == 0x53)
-		printf("%s Extended: 128GFC EA\n", pfx);
+		print_transceiver_type("Extended: 128GFC EA");
 	if (id[36] == 0x54)
-		printf("%s Extended: 128GFC SW\n", pfx);
+		print_transceiver_type("Extended: 128GFC SW");
 	if (id[36] == 0x55)
-		printf("%s Extended: 128GFC LW\n", pfx);
+		print_transceiver_type("Extended: 128GFC LW");
+	if (is_json_context())
+		close_json_array(NULL);
 }
 
 static void sff8079_show_encoding(const __u8 *id)
@@ -276,130 +300,201 @@ static void sff8079_show_encoding(const __u8 *id)
 
 static void sff8079_show_rate_identifier(const __u8 *id)
 {
-	printf("\t%-41s : 0x%02x", "Rate identifier", id[13]);
+	char rate_identifier_description[72];
+
 	switch (id[13]) {
 	case 0x00:
-		printf(" (unspecified)\n");
+		snprintf(rate_identifier_description, 72, "unspecified");
 		break;
 	case 0x01:
-		printf(" (4/2/1G Rate_Select & AS0/AS1)\n");
+		snprintf(rate_identifier_description, 72,
+			 "4/2/1G Rate_Select & AS0/AS1");
 		break;
 	case 0x02:
-		printf(" (8/4/2G Rx Rate_Select only)\n");
+		snprintf(rate_identifier_description, 72,
+			 "8/4/2G Rx Rate_Select only");
 		break;
 	case 0x03:
-		printf(" (8/4/2G Independent Rx & Tx Rate_Select)\n");
+		snprintf(rate_identifier_description, 72,
+			 "8/4/2G Independent Rx & Tx Rate_Select");
 		break;
 	case 0x04:
-		printf(" (8/4/2G Tx Rate_Select only)\n");
+		snprintf(rate_identifier_description, 72,
+			 "8/4/2G Tx Rate_Select only");
 		break;
 	default:
-		printf(" (reserved or unknown)\n");
+		snprintf(rate_identifier_description, 72,
+			 "reserved or unknown");
 		break;
 	}
+	if (is_json_context()) {
+		print_int(PRINT_JSON, "rate_identifier", NULL, id[13]);
+		print_string(PRINT_JSON, "rate_identifier_description",
+			     NULL, rate_identifier_description);
+	} else {
+		printf("\t%-41s : 0x%02x (%s)\n", "Rate identifier",
+		       id[13], rate_identifier_description);
+	}
 }
 
 static void sff8079_show_oui(const __u8 *id)
 {
-	printf("\t%-41s : %02x:%02x:%02x\n", "Vendor OUI",
-	       id[37], id[38], id[39]);
+	char oui_value[16];
+
+	snprintf(oui_value, 16, "%02x:%02x:%02x", id[37], id[38], id[39]);
+
+	if (is_json_context())
+		print_string(PRINT_JSON, "vendor_oui", NULL, oui_value);
+	else
+		printf("\t%-41s : %s\n", "Vendor OUI", oui_value);
 }
 
 static void sff8079_show_wavelength_or_copper_compliance(const __u8 *id)
 {
+	char compliance_mode_buf[64];
+
 	if (id[8] & (1 << 2)) {
-		printf("\t%-41s : 0x%02x", "Passive Cu cmplnce.", id[60]);
 		switch (id[60]) {
 		case 0x00:
-			printf(" (unspecified)");
+			strncpy(compliance_mode_buf, "unspecified", 64);
 			break;
 		case 0x01:
-			printf(" (SFF-8431 appendix E)");
+			strncpy(compliance_mode_buf, "SFF-8431 appendix E", 64);
 			break;
 		default:
-			printf(" (unknown)");
+			strncpy(compliance_mode_buf, "unknown", 64);
 			break;
 		}
-		printf(" [SFF-8472 rev10.4 only]\n");
+		if (is_json_context()) {
+			print_int(PRINT_JSON, "passive_copper_compliance",
+				  "0x%02x", id[60]);
+			print_string(PRINT_JSON, "passive_copper_compliance_desc",
+				     NULL, compliance_mode_buf);
+		} else {
+			printf("\t%-41s : 0x%02x (%s)\n", "Passive Cu cmplnce.",
+			       id[60], compliance_mode_buf);
+		}
 	} else if (id[8] & (1 << 3)) {
-		printf("\t%-41s : 0x%02x", "Active Cu cmplnce.", id[60]);
 		switch (id[60]) {
 		case 0x00:
-			printf(" (unspecified)");
+			strncpy(compliance_mode_buf, "unspecified", 64);
 			break;
 		case 0x01:
-			printf(" (SFF-8431 appendix E)");
+			strncpy(compliance_mode_buf, "SFF-8431 appendix E", 64);
 			break;
 		case 0x04:
-			printf(" (SFF-8431 limiting)");
+			strncpy(compliance_mode_buf, "SFF-8431 limiting", 64);
 			break;
 		default:
-			printf(" (unknown)");
+			strncpy(compliance_mode_buf, "unknown", 64);
 			break;
 		}
-		printf(" [SFF-8472 rev10.4 only]\n");
+		if (is_json_context()) {
+			print_int(PRINT_JSON, "active_copper_compliance",
+				  "0x%02x", id[60]);
+			print_string(PRINT_JSON, "active_copper_compliance_desc",
+				     NULL, compliance_mode_buf);
+		} else {
+			printf("\t%-41s : 0x%02x (%s)\n", "Active Cu cmplnce.",
+			       id[60], compliance_mode_buf);
+		}
 	} else {
-		printf("\t%-41s : %unm\n", "Laser wavelength",
-		       (id[60] << 8) | id[61]);
+		if (is_json_context())
+			print_int(PRINT_JSON, "laser_wavelength", NULL,
+				  (id[60] << 8) | id[61]);
+		else
+			printf("\t%-41s : %unm\n", "Laser wavelength",
+			       (id[60] << 8) | id[61]);
+
 	}
 }
 
 static void sff8079_show_value_with_unit(const __u8 *id, unsigned int reg,
-					 const char *name, unsigned int mult,
-					 const char *unit)
+					 const char *name, const char *json_name,
+					 unsigned int mult, const char *unit)
 {
 	unsigned int val = id[reg];
 
-	printf("\t%-41s : %u%s\n", name, val * mult, unit);
+	if (is_json_context()) {
+		open_json_object(json_name);
+		print_int(PRINT_JSON, "value", NULL, val*mult);
+		print_string(PRINT_JSON, "unit", NULL, unit);
+		close_json_object();
+	} else {
+		printf("\t%-41s : %u%s\n", name, val * mult, unit);
+	}
 }
 
 static void sff8079_show_ascii(const __u8 *id, unsigned int first_reg,
-			       unsigned int last_reg, const char *name)
+			       unsigned int last_reg, const char *name,
+			       const char *json_name)
 {
-	unsigned int reg, val;
+	unsigned int reg, val, x = 0;
+	char value[64];
 
-	printf("\t%-41s : ", name);
 	while (first_reg <= last_reg && id[last_reg] == ' ')
 		last_reg--;
 	for (reg = first_reg; reg <= last_reg; reg++) {
 		val = id[reg];
-		putchar(((val >= 32) && (val <= 126)) ? val : '_');
+		value[x] = ((val >= 32) && (val <= 126)) ? val : '_';
+		x++;
 	}
-	printf("\n");
+	value[x] = '\0';
+
+	if (is_json_context())
+		print_string(PRINT_JSON, json_name, NULL, value);
+	else
+		printf("\t%-41s : %s\n", name, value);
+}
+
+static void print_option(const char *opt_desc)
+{
+	if (is_json_context())
+		print_string(PRINT_JSON, NULL, NULL, opt_desc);
+	else
+		printf("\t%-41s : %s\n", "Option", opt_desc);
 }
 
 static void sff8079_show_options(const __u8 *id)
 {
-	static const char *pfx =
-		"\tOption                                    :";
+	if (is_json_context()) {
+		print_int(PRINT_JSON, "option_byte1", NULL, id[64]);
+		print_int(PRINT_JSON, "option_byte2", NULL, id[65]);
+		open_json_array("option_descriptions", "");
+	} else {
+		printf("\t%-41s : 0x%02x 0x%02x\n", "Option values", id[64], id[65]);
+	}
 
-	printf("\t%-41s : 0x%02x 0x%02x\n", "Option values", id[64], id[65]);
 	if (id[65] & (1 << 1))
-		printf("%s RX_LOS implemented\n", pfx);
+		print_option("RX_LOS implemented");
 	if (id[65] & (1 << 2))
-		printf("%s RX_LOS implemented, inverted\n", pfx);
+		print_option("RX_LOS implemented, inverted");
 	if (id[65] & (1 << 3))
-		printf("%s TX_FAULT implemented\n", pfx);
+		print_option("TX_FAULT implemented");
 	if (id[65] & (1 << 4))
-		printf("%s TX_DISABLE implemented\n", pfx);
+		print_option("TX_DISABLE implemented");
 	if (id[65] & (1 << 5))
-		printf("%s RATE_SELECT implemented\n", pfx);
+		print_option("RATE_SELECT implemented");
 	if (id[65] & (1 << 6))
-		printf("%s Tunable transmitter technology\n", pfx);
+		print_option("Tunable transmitter technology");
 	if (id[65] & (1 << 7))
-		printf("%s Receiver decision threshold implemented\n", pfx);
+		print_option("Receiver decision threshold implemented");
 	if (id[64] & (1 << 0))
-		printf("%s Linear receiver output implemented\n", pfx);
+		print_option("Linear receiver output implemented");
 	if (id[64] & (1 << 1))
-		printf("%s Power level 2 requirement\n", pfx);
+		print_option("Power level 2 requirement");
 	if (id[64] & (1 << 2))
-		printf("%s Cooled transceiver implemented\n", pfx);
+		print_option("Cooled transceiver implemented");
 	if (id[64] & (1 << 3))
-		printf("%s Retimer or CDR implemented\n", pfx);
+		print_option("Retimer or CDR implemented");
 	if (id[64] & (1 << 4))
-		printf("%s Paging implemented\n", pfx);
+		print_option("Paging implemented");
 	if (id[64] & (1 << 5))
-		printf("%s Power level 3 requirement\n", pfx);
+		print_option("Power level 3 requirement");
+
+	if (is_json_context())
+		close_json_array(NULL);
+
 }
 
 static void sff8079_show_all_common(const __u8 *id)
@@ -423,26 +518,40 @@ static void sff8079_show_all_common(const __u8 *id)
 		sff8079_show_connector(id);
 		sff8079_show_transceiver(id);
 		sff8079_show_encoding(id);
-		printf("\t%-41s : %u%s\n", "BR, Nominal", br_nom, "MBd");
+		if (is_json_context())
+			print_int(PRINT_JSON, "bitrate_nominal", NULL, br_nom);
+		else
+			printf("\t%-41s : %u%s\n", "BR, Nominal", br_nom, "MBd");
 		sff8079_show_rate_identifier(id);
-		sff8079_show_value_with_unit(id, 14,
-					     "Length (SMF,km)", 1, "km");
-		sff8079_show_value_with_unit(id, 15, "Length (SMF)", 100, "m");
-		sff8079_show_value_with_unit(id, 16, "Length (50um)", 10, "m");
-		sff8079_show_value_with_unit(id, 17,
-					     "Length (62.5um)", 10, "m");
-		sff8079_show_value_with_unit(id, 18, "Length (Copper)", 1, "m");
-		sff8079_show_value_with_unit(id, 19, "Length (OM3)", 10, "m");
+		open_json_object("lengths");
+		sff8079_show_value_with_unit(id, 14, "Length (SMF,km)",
+					     "smf_km", 1, "km");
+		sff8079_show_value_with_unit(id, 15, "Length (SMF)",
+					     "smf", 100, "m");
+		sff8079_show_value_with_unit(id, 16, "Length (50um)",
+					     "50um", 10, "m");
+		sff8079_show_value_with_unit(id, 17, "Length (62.5um)",
+					     "62_5um", 10, "m");
+		sff8079_show_value_with_unit(id, 18, "Length (Copper)",
+					     "copper", 1, "m");
+		sff8079_show_value_with_unit(id, 19, "Length (OM3)",
+					     "om3", 10, "m");
+		close_json_object();
 		sff8079_show_wavelength_or_copper_compliance(id);
-		sff8079_show_ascii(id, 20, 35, "Vendor name");
+		sff8079_show_ascii(id, 20, 35, "Vendor name", "vendor_name");
 		sff8079_show_oui(id);
-		sff8079_show_ascii(id, 40, 55, "Vendor PN");
-		sff8079_show_ascii(id, 56, 59, "Vendor rev");
+		sff8079_show_ascii(id, 40, 55, "Vendor PN", "vendor_pn");
+		sff8079_show_ascii(id, 56, 59, "Vendor rev", "vendor_rev");
 		sff8079_show_options(id);
-		printf("\t%-41s : %u%s\n", "BR margin, max", br_max, "%");
-		printf("\t%-41s : %u%s\n", "BR margin, min", br_min, "%");
-		sff8079_show_ascii(id, 68, 83, "Vendor SN");
-		sff8079_show_ascii(id, 84, 91, "Date code");
+		if (is_json_context()) {
+			print_int(PRINT_JSON, "br_margin_max", NULL, br_max);
+			print_int(PRINT_JSON, "br_margin_min", NULL, br_min);
+		} else {
+			printf("\t%-41s : %u%s\n", "BR margin, max", br_max, "%");
+			printf("\t%-41s : %u%s\n", "BR margin, min", br_min, "%");
+		}
+		sff8079_show_ascii(id, 68, 83, "Vendor SN", "vendor_sn");
+		sff8079_show_ascii(id, 84, 91, "Date code", "date_code");
 	}
 }
 
@@ -485,7 +594,9 @@ int sff8079_show_all_nl(struct cmd_context *ctx)
 	if (ret)
 		goto out;
 
+	new_json_obj(ctx->json);
 	sff8079_show_all_common(buf);
+	close_json_object();
 
 	/* Finish if A2h page is not present */
 	if (!(buf[92] & (1 << 6)))
@@ -500,6 +611,5 @@ int sff8079_show_all_nl(struct cmd_context *ctx)
 	sff8472_show_all(buf);
 out:
 	free(buf);
-
 	return ret;
 }
-- 
2.30.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ