/* BEGIN_ICS_COPYRIGHT5 ****************************************

Copyright (c) 2015-2020, Intel Corporation

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Intel Corporation nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 * ** END_ICS_COPYRIGHT5   ****************************************/

/*
 * FILE NAME
 *    sm_diag.c
 *
 * DESCRIPTION
 *    FMI sm_diag utility used to control and diagnose a local SM instance
 *
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <signal.h>
#include <time.h>
#include "hsm_config_client_api.h"
#include "hsm_config_client_data.h"
#include "hsm_com_client_data.h"
#include "cs_g.h"
#include "ifs_g.h"

extern int   getopt(int, char *const *, const char *);

typedef struct command_s{
	char *name;
	int (*cmdPtr)(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
	fm_mgr_type_t mgr;
	char *desc;
}command_t;

/* function prototypes */
int mgr_force_sweep(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_restore_priority(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_broadcast_xml_config(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_get_counters(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_reset_counters(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int pm_get_counters(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int pm_reset_counters(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_state_dump(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int mgr_log_level(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int mgr_log_mode(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int mgr_log_mask(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_perf_debug_toggle(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sa_perf_debug_toggle(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int mgr_rmpp_debug_toggle(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int mgr_debug_toggle(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_force_rebalance_toggle(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_adaptive_routing(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_start(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_fast_mode_start(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_stop(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_inject_packets(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_inject_at_node(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_inject_packets_each_sweep(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_path_length(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_show_loop_paths(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_min_isl_redundancy(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_show_switch_lfts(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_show_loop_topology(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_show_config(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_looptest_fast(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_force_attribute_rewrite(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_skip_attr_write(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_pause_sweeps(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);
int sm_resume_sweeps(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]);

int             optind = 1;     /* index into parent argv vector */
char           *optarg;         /* argument associated with option */

static command_t commandList[] = {
	{"smForceSweep", mgr_force_sweep, FM_MGR_SM, "Make the SM sweep now"},
	{"smRestorePriority", sm_restore_priority, FM_MGR_SM, "Restore the normal priority of the SM (if it is\n                           currently elevated)"},
	{"smShowCounters", sm_get_counters, FM_MGR_SM, "Get statistics and performance counters from the SM"},
	{"smResetCounters",sm_reset_counters, FM_MGR_SM, "Reset SM statistics and performance counters"},
	{"smStateDump",sm_state_dump, FM_MGR_SM, "Dump Internal SM state into directory specified"},
	{"smLogLevel", mgr_log_level, FM_MGR_SM, "Set the SM logging level (0=NONE+, 1=WARN+, 2=NOTICE+,\n                           3=INFO+, 4=VERBOSE+, 5=DEBUG2+, 6=DEBUG4+, 7=TRACE+)"},
	{"smLogMode", mgr_log_mode, FM_MGR_SM, "Set the SM log mode flags (0/1 1=downgrade\n                           non-actionable, 0/2 2=logfile only)"},
	{"smLogMask", mgr_log_mask, FM_MGR_SM, "Set the SM log mask for a specific subsystem to the\n                           value given see /etc/opa-fm/opafm.xml\n                           or /usr/share/opa-fm/opafm.xml\n                           for a list of subsystems and mask bit meanings"},
	{"smPerfDebug", sm_perf_debug_toggle, FM_MGR_SM, "Toggle performance debug output for SM"},
	{"saPerfDebug", sa_perf_debug_toggle, FM_MGR_SM, "Toggle performance debug output for SA"},
	{"saRmppDebug", mgr_rmpp_debug_toggle, FM_MGR_SM, "Toggle Rmpp debug output for SA"},
	// these commands can be issued direct to PM without issue
	{"pmShowCounters", pm_get_counters, FM_MGR_PM, "Get statistics and performance counters about the PM"},
	{"pmResetCounters",pm_reset_counters, FM_MGR_PM, "Reset statistics and performance counters about the PM"},
	{"pmDebug", mgr_debug_toggle, FM_MGR_PM, "Toggle debug output for PM"},
	{"pmRmppDebug", mgr_rmpp_debug_toggle, FM_MGR_PM, "Toggle Rmpp debug output for PM"},
	{"feLogLevel", mgr_log_level, FM_MGR_FE, "Set the FE logging level (0=NONE+, 1=WARN+, 2=NOTICE+,\n                           3=INFO+, 4=VERBOSE+, 5=DEBUG2+, 6=DEBUG4+, 7=TRACE+)"},
	{"feLogMode", mgr_log_mode, FM_MGR_FE, "Set the FE log mode flags (0/1 1=downgrade\n                           non-actionable, 0/2 2=logfile only)"},
	{"feLogMask", mgr_log_mask, FM_MGR_FE, "Set the FE log mask for a specific subsystem to the\n                           value given see /etc/opa-fm/opafm.xml\n                           or /usr/share/opa-fm/opafm.xml\n                           for a list of subsystems and mask bit meanings"},
	{"feDebug", mgr_debug_toggle, FM_MGR_FE, "Toggle debug output for FE"},
	{"feRmppDebug", mgr_rmpp_debug_toggle, FM_MGR_FE, "Toggle Rmpp debug output for FE"},
	{"smLooptestStart", sm_looptest_start, FM_MGR_SM, "START loop test in normal mode - specify the number of\n                           256 byte packets (default=0)"},
	{"smLooptestFastModeStart", sm_looptest_fast_mode_start, FM_MGR_SM, "START loop test in fast mode - specify the number of\n                           256 byte packets (default=5)"},
	{"smLooptestStop", sm_looptest_stop, FM_MGR_SM, "STOP the loop test (puts switch LFTs back to normal)"},
	//{"smLooptestFastMode", sm_looptest_fast, FM_MGR_SM, "1 to turn loop test fast mode ON, 0 to turn OFF"},
	{"smLooptestInjectPackets", sm_looptest_inject_packets, FM_MGR_SM, "Enter numPkts to send to all switch loops\n                           (default=1)"},
	{"smLooptestInjectAtNode", sm_looptest_inject_at_node, FM_MGR_SM, "Enter the switch node index to inject loop packets\n                           (default=0)"},
	{"smLooptestInjectEachSweep", sm_looptest_inject_packets_each_sweep, FM_MGR_SM, "1 to inject packets each sweep, 0 to stop injecting\n                           each sweep"},
	{"smLooptestPathLength", sm_looptest_path_length, FM_MGR_SM, "Sets the loop path length 2-4 (default=3)"},
	{"smLooptestMinISLRedundancy", sm_looptest_min_isl_redundancy, FM_MGR_SM, "Sets the minimum number of loops in which to \n                           include each ISL (default=4)"},
	{"smLooptestShowLoopPaths",sm_looptest_show_loop_paths, FM_MGR_SM, "Displays the loop paths given node index or all loop\n                           paths (default=all)"},
	{"smLooptestShowSwitchLft",sm_looptest_show_switch_lfts, FM_MGR_SM, "Displays a switch LFT given node index or all switches\n                           LFTs (default=all)"},
	{"smLooptestShowTopology",sm_looptest_show_loop_topology, FM_MGR_SM, "Displays the topology for the SM Loop Test"},
	{"smLooptestShowConfig",sm_looptest_show_config, FM_MGR_SM, "Displays the current active loop configuration"},
	{"smForceRebalance", sm_force_rebalance_toggle, FM_MGR_SM, "Toggle Force Rebalance setting for SM"},
	{"smAdaptiveRouting", sm_adaptive_routing, FM_MGR_SM, "Displays or modifies Adaptive Routing settings\n                           (enable/disable, frequency, threshold) for SM.\n                           Display (no arg), Disable=0, Enable=1. Additional arguments\n                           can be used to update the frequency and threshold.\n                           -f (frequency, valid values are from 0 to 7)\n                           -t (threshold, valid values are from 0 to 7)\n                           If frequency or threshold are not provided, they will be reset to default."},
	{"smForceAttributeRewrite", sm_force_attribute_rewrite, FM_MGR_SM, "Set rewriting of all attributes upon resweeping.\n                           Disable=0, Enable=1"},
	{"smSkipAttrWrite", sm_skip_attr_write, FM_MGR_SM, "Bitmask of attributes to be skipped(not written) during\n                           sweeps (-help for list)"},
	{"smPauseSweeps", sm_pause_sweeps, FM_MGR_SM, "Pause SM sweeps"},
	{"smResumeSweeps", sm_resume_sweeps, FM_MGR_SM, "Resume SM sweeps"},
// JPW - may implement in future as part of the maint mode feature
//	{"smBroadcastConfig", sm_broadcast_xml_config, FM_MGR_SM, "Broadcast the XML configuration file to STANDBY and INACTIVE SM's"},
};

static int commandListLen = (sizeof(commandList)/sizeof(commandList[0]));


void usage(char *cmd)
{
	int i;

	fprintf(stderr, "Usage: %s", cmd);
	fprintf(stderr, " [options] cmd [args]\n\n");

	fprintf(stderr, "options:\n");
	fprintf(stderr, "  --help		- show this help text\n");
	fprintf(stderr, "  -i fm_instance	- FM instance to connect to (0 - default)\n\n");
	fprintf(stderr, "cmd:\n");
	for(i=0;i<commandListLen;i++){
		fprintf(stderr, "  %-21s %s\n",commandList[i].name,commandList[i].desc);
	}
	fflush(stderr);

}

int mgr_force_sweep(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_FORCE_SWEEP, mgr, 0, NULL, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "mgr_force_sweep: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("mgr_force_sweep: Successfully sent Force Sweep control to local mgr instance\n");
    }
	return 0;
}

int sm_broadcast_xml_config(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_BROADCAST_XML_CONFIG, mgr, 0, NULL, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_broadcast_xml_config: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("sm_broadcast_xml_config: Successfully sent XML broadcast config command to local mgr instance\n");
    }
	return 0;
}

int sm_restore_priority(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_RESTORE_PRIORITY, mgr, 0, NULL, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_restore_priority: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("sm_restore_priority: Successfully sent Relinquish Master control to local mgr instance\n");
    }
	return 0;
}

#define BUF_SZ 16384

int sm_get_counters(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	uint8_t data[BUF_SZ];
	time_t timeNow;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_GET_COUNTERS, mgr, BUF_SZ, data, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_get_counters: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		time(&timeNow);
		data[BUF_SZ-1]=0;
		printf("%35s: %s%s", "SM Counters as of", ctime(&timeNow), (char*) data);
    }
	return 0;
}

#define MAX_VESW 4095
#define MIN_VESW 1
#define ALL_VESW -1
#define MIN_VESW_COUNT 1
#define MAX_VESW_COUNT 20

int pm_get_counters(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	uint8_t data[BUF_SZ];
	time_t timeNow;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_PM_GET_COUNTERS, mgr, BUF_SZ, data, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "pm_get_counters: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		time(&timeNow);
		data[BUF_SZ-1]=0;
		printf("PM Counters as of %s%s", ctime(&timeNow), (char*) data);
    }
	return 0;
}

int sm_reset_counters(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_RESET_COUNTERS, mgr, 0, NULL, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_reset_counters: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("sm_reset_counters: Successfully sent reset command "
		       "to the SM\n");
    }
	return 0;
}

int pm_reset_counters(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_PM_RESET_COUNTERS, mgr, 0, NULL, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "pm_reset_counters: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("pm_reset_counters: Successfully sent reset command "
		       "to the PM\n");
    }
	return 0;
}

int sm_state_dump(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
    char dirName[256];

	if (argc == 1 && strlen(argv[0]) < 256) {
		StringCopy(dirName, argv[0], sizeof(dirName));
	} else {
		sprintf(dirName, "/tmp");
	}

	printf("Sending command to dump the SM state into the directory %s\n", dirName);

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_DUMP_STATE, mgr, 
								  strlen(dirName) + 1, dirName, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_state_dump: Failed to retrieve data: \n"
			   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
			   res, fm_mgr_get_error_str(res),ret_code,
			   fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent state dump command to local SM instance\n");
	}

	return 0;
}

int mgr_log_level(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	uint32_t 				loglevel=0;

	if (argc == 1) {
		loglevel = atol(argv[0]);
		if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_LOG_LEVEL, mgr, sizeof(loglevel), (void *)&loglevel, &ret_code)) != FM_CONF_OK)
		{
			fprintf(stderr, "mgr_log_level: Failed to retrieve data: \n"
				   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
				   res, fm_mgr_get_error_str(res),ret_code,
				   fm_mgr_get_resp_error_str(ret_code));
		} else {
			printf("mgr_log_level: Successfully sent Log Level control to local mgr instance\n");
		}
	} else {
		fprintf(stderr, "mgr_log_level: must specify the log level parameter (1 > 5): \n");
	}

	return 0;
}

int mgr_log_mode(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	uint32_t				logmode=0;

	if (argc == 1) {
		logmode = atol(argv[0]);
		if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_LOG_MODE, mgr, sizeof(logmode), (void *)&logmode, &ret_code)) != FM_CONF_OK)
		{
			fprintf(stderr, "mgr_log_mode: Failed to retrieve data: \n"
				   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
				   res, fm_mgr_get_error_str(res),ret_code,
				   fm_mgr_get_resp_error_str(ret_code));
		} else {
			printf("mgr_log_mode: Successfully sent Log Mode control to local mgr instance\n");
		}
	} else {
		fprintf(stderr, "mgr_log_mode: must specify the log mode parameter (1 > 5): \n");
	}

	return 0;
}


int mgr_log_mask(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	uint32_t				mask=0;
	char buf[32];			// 32 bit mask followed by subsystem name

	if (argc == 2) {
		mask = strtoul(argv[1], NULL, 0);
		//mask = hton32(mask);	// TBD - endian issues seem to be ignored here
		memcpy(buf, &mask, sizeof(mask));
		strncpy(buf+sizeof(mask), argv[0], sizeof(buf)-sizeof(mask));
		buf[sizeof(buf)-1] = '\0';
		if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_LOG_MASK, mgr, sizeof(buf), (void *)&buf[0], &ret_code)) != FM_CONF_OK)
		{
			fprintf(stderr, "mgr_log_mask: Failed to retrieve data: \n"
				   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
				   res, fm_mgr_get_error_str(res),ret_code,
				   fm_mgr_get_resp_error_str(ret_code));
		} else {
			printf("mgr_log_mask: Successfully sent Log Mask control to local mgr instance\n");
		}
	} else {
		fprintf(stderr, "mgr_log_mask: must specify the subsystem and mask\n");
	}

	return 0;
}


int sm_perf_debug_toggle(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_PERF_DEBUG_TOGGLE, mgr, 0, NULL, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_perf_debug_toggle: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent SM Perf Debug output control to local SM instance\n");
    }
	return 0;
}

int sa_perf_debug_toggle(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SA_PERF_DEBUG_TOGGLE, mgr, 0, NULL, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sa_perf_debug_toggle: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent SA Perf Debug output control to local SM instance\n");
    }
	return 0;
}

int mgr_rmpp_debug_toggle(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_RMPP_DEBUG_TOGGLE, mgr, 0, NULL, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sa_rmpp_debug_toggle: Failed to retrieve data: \n"
			   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
			   res, fm_mgr_get_error_str(res),ret_code,
			   fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent Rmpp Debug output control to local Manager instance\n");
	}
	return 0;
}

int mgr_debug_toggle(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_DEBUG_TOGGLE, mgr, 0, NULL, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "mgr_debug_toggle: Failed to retrieve data: \n"
			   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
			   res, fm_mgr_get_error_str(res),ret_code,
			   fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent Debug output control to local Manager instance\n");
	}
	return 0;
}

int sm_force_rebalance_toggle(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_FORCE_REBALANCE_TOGGLE, mgr, 0, NULL, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_force_rebalance_toggle: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent SM Force Rebalance control to local SM instance\n");
    }
	return 0;
}

int sm_adaptive_routing(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t			res;
	fm_msg_ret_code_t			ret_code;
	fm_ar_config_t				ar_config;

	int					arg;
	const char				* options="f:t:";

	if (argc >= 1) {
		ar_config.enable = atol(argv[0]);
		if (ar_config.enable != 0 && ar_config.enable != 1) {
			fprintf(stderr, "sm_adaptive_routing: Invalid argument %s. Valid values are 0 or 1.\n", argv[0]);
			return 1;
		}
		ar_config.frequency = -1;
		ar_config.threshold = -1;
		optind = 1;  // reset the optind used by getopt to 1
		while(-1 != (arg = getopt(argc, argv, options))) {
			switch(arg) {
				case 'f':
					ar_config.frequency = atol(optarg);
					if (AR_FREQUENCY_UPPER < ar_config.frequency) {
						fprintf(stderr, "sm_adaptive_routing: Invalid argument for frequency %s. Valid values are from %d to %d.\n", optarg, AR_FREQUENCY_LOWER, AR_FREQUENCY_UPPER);
						return 1;
					}
					break;
				case 't':
					ar_config.threshold = atol(optarg);
					if (AR_THRESHOLD_UPPER < ar_config.threshold) {
						fprintf(stderr, "sm_adaptive_routing: Invalid argument for threshold %s. Valid values are from %d to %d.\n", optarg, AR_THRESHOLD_LOWER, AR_THRESHOLD_UPPER);
						return 1;
					}
					break;
			}
		}

		if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_SET_ADAPTIVE_ROUTING, mgr, sizeof(ar_config), (void*)&ar_config, &ret_code)) != FM_CONF_OK)
		{
			fprintf(stderr, "sm_adaptive_routing: Failed to retrieve data: \n"
		       	"\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       	res, fm_mgr_get_error_str(res),ret_code,
		       	fm_mgr_get_resp_error_str(ret_code));
		} else {
			printf("Successfully sent SM Adaptive Routing control to local SM instance\n");
    	}

	} else if (argc == 0) {
		if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_GET_ADAPTIVE_ROUTING, mgr, sizeof(ar_config), (void*)&ar_config, &ret_code)) != FM_CONF_OK)
		{
			fprintf(stderr, "sm_adaptive_routing: Failed to retrieve data: \n"
		       	"\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       	res, fm_mgr_get_error_str(res),ret_code,
		       	fm_mgr_get_resp_error_str(ret_code));
		} else {
			printf("SM Adaptive Routing is %s\n", ar_config.enable ? "enabled" : "disabled");
			printf("SM Adaptive Routing Frequency is %u\n", ar_config.frequency);
			printf("SM Adaptive Routing Threshold is %u\n", ar_config.threshold);
		}
	}
	return 0;
}

int sm_pause_sweeps(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {

	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_PAUSE_SWEEPS, mgr, 0, NULL, &ret_code)) != FM_CONF_OK) {
		fprintf(stderr, "sm_pause_sweeps: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("sm_pause_sweeps: Successfully sent Pause SM Sweeps command to local mgr instance\n");
    }

	return 0;
}

int sm_resume_sweeps(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {

	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_RESUME_SWEEPS, mgr, 0, NULL, &ret_code)) != FM_CONF_OK) {
		fprintf(stderr, "sm_pause_sweeps: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("sm_resume_sweeps: Successfully sent Resume SM Sweeps command to local mgr instance\n");
    }

	return 0;
}

int sm_looptest_start(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	int						numpkts=0;
	uint8_t 				data[BUF_SZ];

	if (argc > 1) {
		printf("Error: only 1 argument expected\n");
		return 0;
	}
	if (argc == 1) {
		numpkts = atol(argv[0]);
		if (numpkts < 0 || numpkts > 10) {
			printf("Error: number of packets must be from 0 to 10\n");
			return 0;
		}
	}
	*(int*)data = numpkts;
	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_START, mgr, 
								  BUF_SZ, data, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_looptest_start: Failed to retrieve data: \n"
			   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
			   res, fm_mgr_get_error_str(res),ret_code,
			   fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent Loop Test START control (%d inject packets) to local SM instance\n", numpkts);
		data[BUF_SZ-1]=0;
		printf("%s", (char*) data);
	}
	return 0;
}

int sm_looptest_fast_mode_start(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	int						numpkts=5;
	uint8_t 				data[BUF_SZ];

	if (argc > 1) {
		printf("Error: only 1 argument expected\n");
		return 0;
	}
	if (argc == 1) {
		numpkts = atol(argv[0]);
		if (numpkts < 0 || numpkts > 10) {
			printf("Error: number of packets must be from 0 to 10\n");
			return 0;
		}
	}
	*(int*)data = numpkts;
	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_FAST_MODE_START, mgr, 
								  BUF_SZ, data, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_looptest_fast_mode_start: Failed to retrieve data: \n"
			   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
			   res, fm_mgr_get_error_str(res),ret_code,
			   fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent Loop Test Fast Mode START control (%d inject packets) to local SM instance\n", numpkts);
		data[BUF_SZ-1]=0;
		printf("%s", (char*) data);
	}
	return 0;
}

int sm_looptest_stop(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	uint8_t data[BUF_SZ];

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_STOP, mgr, BUF_SZ, data, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_looptest_stop: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent Loop Test STOP control to local SM instance\n");
		data[BUF_SZ-1]=0;
		printf("%s", (char*) data);
    }
	return 0;
}

int sm_looptest_inject_packets(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	int						numpkts=1;
	uint8_t                 data[BUF_SZ];

	if (argc > 1) {
		printf("Error: only 1 argument expected\n");
		return 0;
	}
	if (argc == 1) {
		numpkts = atol(argv[0]);
		if (numpkts < 1 || numpkts > 10) {
			printf("Error: number of packets must be from 1 to 10\n");
			return 0;
		}
	}
	*(int*)data = numpkts;
	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_INJECT_PACKETS, mgr, 
								  BUF_SZ, data, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_looptest_inject_packets: Failed to retrieve data: \n"
			   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
			   res, fm_mgr_get_error_str(res),ret_code,
			   fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent Loop Test Inject %d Packets control to local SM instance\n", numpkts);
		data[BUF_SZ-1]=0;
		printf("%s", (char*) data);
	}
	return 0;
}

int sm_looptest_inject_at_node(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	int						nodeidx=0;
	uint8_t                 data[BUF_SZ];

	if (argc > 1) {
		printf("Error: only 1 argument expected\n");
		return 0;
	}
	if (argc == 1) {
		nodeidx = atol(argv[0]);
	}
	*(int*)data = nodeidx;
	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_INJECT_ATNODE, mgr, 
								  BUF_SZ, data, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_looptest_inject_at_node: Failed to retrieve data: \n"
			   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
			   res, fm_mgr_get_error_str(res),ret_code,
			   fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent Loop Test Inject Packets at Node index %d control to local SM instance\n", 
			   nodeidx);
		data[BUF_SZ-1]=0;
		printf("%s", (char*) data);
	}
	return 0;
}

int sm_looptest_inject_packets_each_sweep(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	int						inject=1;
	uint8_t                 data[BUF_SZ];

	if (argc > 1) {
		printf("Error: only 1 argument expected\n");
		return 0;
	}
	if (argc == 1) {
		inject = atol(argv[0]);
	}
	*(int*)data = inject;
	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_INJECT_EACH_SWEEP, mgr, 
								  BUF_SZ, data, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_looptest_inject_packets_each_sweep: Failed to retrieve data: \n"
			   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
			   res, fm_mgr_get_error_str(res),ret_code,
			   fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent Loop Test Inject Packet Each Sweep %d control to local SM instance\n", inject);
		data[BUF_SZ-1]=0;
		printf("%s", (char*) data);
	}
	return 0;
}

int sm_looptest_path_length(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	int						plen=3;
	uint8_t                 data[BUF_SZ];

	if (argc > 1) {
		printf("Error: only 1 argument expected\n");
		return 0;
	}

	if (argc == 1) {
		plen = atol(argv[0]);
		if (plen < 2 || plen > 4) {
			printf("Error: length must be 2-4\n");
			return 0;
		}
	}
	*(int*)data = plen;
	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_PATH_LEN, mgr, 
								  BUF_SZ, data, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_looptest_path_length: Failed to retrieve data: \n"
			   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
			   res, fm_mgr_get_error_str(res),ret_code,
			   fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent Loop Test Path Length set to %d control to local SM instance\n", plen);
		data[BUF_SZ-1]=0;
		printf("%s", (char*) data);
	}
	return 0;
}

int sm_looptest_show_loop_paths(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t		res;
	fm_msg_ret_code_t			ret_code;
	fm_config_interation_data_t	interationData;
	uint8_t 					data[BUF_SZ];
	int							index = -1;
	int							start;

	if (argc > 1) {
		printf("Error: only 1 argument expected\n");
		return 0;
	}
	if (argc == 1) {
		index = atol(argv[0]);
	}
	memset(&interationData, 0, sizeof(fm_config_interation_data_t));
	interationData.start = start = 1;
	interationData.index = index;
	while (!interationData.done) {
		memcpy(data, &interationData, sizeof(fm_config_interation_data_t));
		if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_SHOW_PATHS, mgr,
						BUF_SZ, data, &ret_code)) != FM_CONF_OK) {
			fprintf(stderr, "sm_looptest_show_loop_paths: Failed to retrieve data: \n"
		   		"\tError:(%d) %s \n\tRet code:(%d) %s\n",
		   		res, fm_mgr_get_error_str(res),ret_code,
		   	fm_mgr_get_resp_error_str(ret_code));
			return 0;
		}
		if (start) {
			if (index == -1)
				printf("Successfully sent Loop Test Path show for node index (all) to local SM instance\n");
			else
				printf("Successfully sent Loop Test Path show for node index %d to local SM instance\n", index);
			start = 0;
		}
		memcpy(&interationData, data, sizeof(fm_config_interation_data_t));
		printf("%s", interationData.intermediateBuffer);
	}
	return 0;
}

int sm_looptest_min_isl_redundancy(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	int						plen=1;
	uint8_t                 data[BUF_SZ];

	if (argc > 1) {
		printf("Error: only 1 argument expected\n");
		return 0;
	}
	if (argc == 1) {
		plen = atol(argv[0]);
	}
	*(int*)data = plen;
	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_MIN_ISL_REDUNDANCY, mgr, 
								  BUF_SZ, data, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_looptest_path_min_isl_redundancy: Failed to retrieve data: \n"
			   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
			   res, fm_mgr_get_error_str(res),ret_code,
			   fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent Loop Test Min ISL redundancy set to %d control to local SM instance\n", plen);
		data[BUF_SZ-1]=0;
		printf("%s", (char*) data);
	}
	return 0;
}

int sm_looptest_fast(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	int						plen=1;

	if (argc > 1) {
		printf("Error: only 1 argument expected\n");
		return 0;
	}
	if (argc == 1) {
		plen = atol(argv[0]);
	}
	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_FAST, mgr, 
								  sizeof(plen), (void *)&plen, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_looptest_fast: Failed to retrieve data: \n"
			   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
			   res, fm_mgr_get_error_str(res),ret_code,
			   fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent Loop Test Fast Mode %d control to local SM instance\n", plen);
	}
	return 0;
}

int sm_looptest_show_switch_lfts(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t		res;
	fm_msg_ret_code_t			ret_code;
	uint8_t 					data[BUF_SZ];
	int							index=-1;
	fm_config_interation_data_t	interationData;
	int							start;

	if (argc > 1) {
		printf("Error: only 1 argument expected\n");
		return 0;
	}
	if (argc == 1) {
		index = atol(argv[0]);
	}
	memset(&interationData, 0, sizeof(fm_config_interation_data_t));
	interationData.start = start = 1;
	interationData.index = index;
	while (!interationData.done) {
		memcpy(data, &interationData, sizeof(fm_config_interation_data_t));
		if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_SHOW_LFTS, mgr,
						BUF_SZ, data, &ret_code)) != FM_CONF_OK) {
			fprintf(stderr, "sm_looptest_show_switch_lfts: Failed to retrieve data: \n"
		   		"\tError:(%d) %s \n\tRet code:(%d) %s\n",
		   		res, fm_mgr_get_error_str(res),ret_code,
		   	fm_mgr_get_resp_error_str(ret_code));
			return 0;
		}
		if (start) {
			start = 0;
			if (index == -1)
				printf("Successfully sent Loop Test LFT show for node index (all) to local SM instance\n");
			else
				printf("Successfully sent Loop Test LFT show for node index %d to local SM instance\n", index);
		}
		memcpy(&interationData, data, sizeof(fm_config_interation_data_t));
		printf("%s", interationData.intermediateBuffer);
	}
	return 0;
}

int sm_looptest_show_loop_topology(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t		res;
	fm_msg_ret_code_t			ret_code;
	uint8_t 					data[BUF_SZ];
	fm_config_interation_data_t	interationData;
	int							start;

	memset(&interationData, 0, sizeof(fm_config_interation_data_t));
	interationData.start = start = 1;
	interationData.index = 0;
	while (!interationData.done) {
		memcpy(data, &interationData, sizeof(fm_config_interation_data_t));
		if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_SHOW_TOPO, mgr,
						BUF_SZ, data, &ret_code)) != FM_CONF_OK) {
			fprintf(stderr, "sm_looptest_show_loop_topology: Failed to retrieve data: \n"
		   		"\tError:(%d) %s \n\tRet code:(%d) %s\n",
		   		res, fm_mgr_get_error_str(res),ret_code,
		   	fm_mgr_get_resp_error_str(ret_code));
			return 0;
		}
		if (start) {
			start = 0;
			printf("Successfully sent Loop Test topology show to local SM instance\n");
		}
		memcpy(&interationData, data, sizeof(fm_config_interation_data_t));
		printf("%s", interationData.intermediateBuffer);
	}
	return 0;
}

int sm_looptest_show_config(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	uint8_t data[BUF_SZ];

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_LOOP_TEST_SHOW_CONFIG, mgr, BUF_SZ, data, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_looptest_show_config: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent Loop Test configuration show to local SM instance\n");
		data[BUF_SZ-1]=0;
		printf("%s", (char*) data);
    }
	return 0;
}

int sm_force_attribute_rewrite(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	int attrRewrite = 0;
	
	if (argc > 1) {
		printf("Error: only 1 argument expected\n");
		return 0;
	}
	if (argc == 1) {
		attrRewrite = atol(argv[0]);
		if (attrRewrite < 0 || attrRewrite > 1) {
			printf("Error: attrRewrite must be either 0 (disable) or 1 (enable)\n");
			return 0;
		}
	}


	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_FORCE_ATTRIBUTE_REWRITE, mgr, sizeof(attrRewrite), (void*) &attrRewrite, &ret_code)) != FM_CONF_OK)
	{
		fprintf(stderr, "sm_force_attribute_rewrite: Failed to retrieve data: \n"
		       "\tError:(%d) %s \n\tRet code:(%d) %s\n",
		       res, fm_mgr_get_error_str(res),ret_code,
		       fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent set to %d of force attribute rewriting to local SM instance\n", attrRewrite);
	}
	return 0;
}

int sm_skip_attr_write(p_fm_config_conx_hdlt hdl, fm_mgr_type_t mgr, int argc, char *argv[]) {
	fm_mgr_config_errno_t	res;
	fm_msg_ret_code_t		ret_code;
	unsigned int attrSkip = 0;

	if (argc > 1) {
		printf("Error: only 1 argument or less expected\n");
		return 0;
	}
	if ((argc==0) || ((argc==1) && (strcmp(argv[0],"-help")==0)) ) {
		printf(" SM SKIP WRITE BITMASKS...\n");
		printf("   SM_SKIP_WRITE_PORTINFO        0x00000001  (Includes Port Info)\n");
		printf("   SM_SKIP_WRITE_SMINFO          0x00000002  (Includes Sm Info)\n");
		printf("   SM_SKIP_WRITE_GUID            0x00000004  (Includes GUID Info)\n");
		printf("   SM_SKIP_WRITE_SWITCHINFO      0x00000008  (Includes Switch Info)\n");
		printf("   SM_SKIP_WRITE_SWITCHLTV       0x00000010  (Includes Switch LTV)\n");
		printf("   SM_SKIP_WRITE_VLARB           0x00000020  (Includes VLArb Tables/Preempt Tables)\n");
		printf("   SM_SKIP_WRITE_MAPS            0x00000040  (Includes SL::SC, SC::SL, SC::VL)\n");
		printf("   SM_SKIP_WRITE_LFT             0x00000080  (Includes LFT and MFT)\n");
		printf("   SM_SKIP_WRITE_AR              0x00000100  (Includes PG table, PG FDB)\n");
		printf("   SM_SKIP_WRITE_PKEY            0x00000200\n");
		printf("   SM_SKIP_WRITE_CONG            0x00000400  (Includes HFI / Switch congestion)\n");
		printf("   SM_SKIP_WRITE_BFRCTRL         0x00000800\n");
		printf("   SM_SKIP_WRITE_NOTICE          0x00001000\n");
		printf("   SM_SKIP_WRITE_PORTSTATEINFO   0x00002000  (Includes PortStateInfo sets for cascade activation)\n");
		return  0;
	}

	attrSkip = strtol(argv[0],NULL,0);

	if((res = fm_mgr_simple_query(hdl, FM_ACT_GET, FM_DT_SM_SKIP_ATTRIBUTE_WRITE, mgr, sizeof(attrSkip), (void*) &attrSkip, &ret_code)) != FM_CONF_OK) {
		fprintf(stderr, "sm_skip_attr_write: Failed to retrieve data: \n"
			   "\tError:(%d) %s \n\tRet code:(%d) %s\n",
			   res, fm_mgr_get_error_str(res),ret_code,
			   fm_mgr_get_resp_error_str(ret_code));
	} else {
		printf("Successfully sent set to 0x%x of skip write to local SM instance\n", attrSkip);
	}
	return 0;
}


int main(int argc, char *argv[]) {
	p_fm_config_conx_hdlt	hdl = NULL;
	int						instance = 0;
	fm_mgr_config_errno_t	res;
	char					*rem_addr = NULL;
	char					*community = "public";
	char            		Opts[256];
    int             		arg;
	char 					*command;
	int						i;

	/* Get options at the command line (overide default values) */
    StringCopy(Opts, "+i:d:h-", sizeof(Opts));

    while ((arg = getopt(argc, argv, Opts)) != EOF) {
        switch (arg) {
		case 'h':
		case '-':
			usage(argv[0]);
			return(0);
		case 'i':
			instance = atol(optarg);
			break;
		case 'd':
			rem_addr = optarg;
			break;
		default:
			usage(argv[0]);
			return(-1);
		}
	}

	if(optind >= argc){
        fprintf(stderr, "Command required\n");
		usage(argv[0]);
		return -1;
	}

	command = argv[optind++];
	printf("Connecting to %s FM instance %d\n", (rem_addr==NULL) ? "LOCAL":rem_addr, instance);
	if((res = fm_mgr_config_init(&hdl,instance, rem_addr, community)) != FM_CONF_OK)
	{
		fprintf(stderr, "Failed to initialize the client handle: %d\n", res);
		goto cleanup;
	}

	if((res = fm_mgr_config_connect(hdl)) != FM_CONF_OK)
	{
		fprintf(stderr, "Failed to connect: (%d) %s\n",res,fm_mgr_get_error_str(res));
		goto cleanup;
	}

	for(i=0;i<commandListLen;i++){
		if(strcmp(command,commandList[i].name) == 0){
			res = commandList[i].cmdPtr(hdl, commandList[i].mgr, (argc - optind), &argv[optind]);
			goto cleanup;
		}
	}

	fprintf(stderr, "Command (%s) is not valid\n",command);
	usage(argv[0]);
	res = -1;

cleanup:
	if (hdl)
	{
		if (hdl->sm_hdl)
		{
			if (hdl->sm_hdl->c_path[0])
				unlink(hdl->sm_hdl->c_path);
		}
		if (hdl->pm_hdl)
		{
			if (hdl->pm_hdl->c_path[0])
				unlink(hdl->pm_hdl->c_path);
		}
		if (hdl->fe_hdl)
		{
			if (hdl->fe_hdl->c_path[0])
				unlink(hdl->fe_hdl->c_path);
		}
		free(hdl);
	}

	return res;
}
