|
Packit Service |
3470d1 |
/* Query SA for Switch Cost Matrix data
|
|
Packit Service |
3470d1 |
* and print it to a file. Monitor for any
|
|
Packit Service |
3470d1 |
* changes and update.
|
|
Packit Service |
3470d1 |
*
|
|
Packit Service |
3470d1 |
*/
|
|
Packit Service |
3470d1 |
// core API
|
|
Packit Service |
3470d1 |
#include <opamgt.h>
|
|
Packit Service |
3470d1 |
// swcost query
|
|
Packit Service |
3470d1 |
#include <opamgt_sa.h>
|
|
Packit Service |
3470d1 |
// fabric change notice
|
|
Packit Service |
3470d1 |
#include <opamgt_sa_notice.h>
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
#include <stdio.h>
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
typedef struct opa_switch{
|
|
Packit Service |
3470d1 |
STL_LID lid;
|
|
Packit Service |
3470d1 |
const char * name;
|
|
Packit Service |
3470d1 |
struct opa_switch *next;
|
|
Packit Service |
3470d1 |
}opa_switch;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
FILE * matrix_file;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
void free_cost(uint16_t ***cost, int num_rows){
|
|
Packit Service |
3470d1 |
int i;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
if (!*cost) return;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
for(i = 0; i < num_rows; ++i) {
|
|
Packit Service |
3470d1 |
if ((*cost)[i]) {
|
|
Packit Service |
3470d1 |
free((*cost)[i]);
|
|
Packit Service |
3470d1 |
(*cost)[i] = NULL;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
free(*cost);
|
|
Packit Service |
3470d1 |
*cost = NULL;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
void free_switch_list(opa_switch **switchlist_head)
|
|
Packit Service |
3470d1 |
{
|
|
Packit Service |
3470d1 |
if (!*switchlist_head) return;
|
|
Packit Service |
3470d1 |
opa_switch * temp = *switchlist_head, *temp2;
|
|
Packit Service |
3470d1 |
while(temp){
|
|
Packit Service |
3470d1 |
temp2 = temp->next;
|
|
Packit Service |
3470d1 |
free(temp);
|
|
Packit Service |
3470d1 |
temp = temp2;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
*switchlist_head = NULL;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
/* Helper function to get the associated name for a particular lid
|
|
Packit Service |
3470d1 |
*/
|
|
Packit Service |
3470d1 |
const char * get_name(STL_LID lid, STL_NODE_RECORD *node_records, int num_node_records)
|
|
Packit Service |
3470d1 |
{
|
|
Packit Service |
3470d1 |
int i;
|
|
Packit Service |
3470d1 |
for (i = 0; i < num_node_records; ++i) {
|
|
Packit Service |
3470d1 |
if (node_records[i].RID.LID == lid)
|
|
Packit Service |
3470d1 |
return (const char*) node_records[i].NodeDesc.NodeString;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
return "";
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
/* Print Cost Matrix using the Switch Names
|
|
Packit Service |
3470d1 |
*/
|
|
Packit Service |
3470d1 |
void print_matrix(uint16_t **cost, opa_switch *switchlist_head)
|
|
Packit Service |
3470d1 |
{
|
|
Packit Service |
3470d1 |
fprintf(matrix_file, "%64s", "");
|
|
Packit Service |
3470d1 |
opa_switch * iter = switchlist_head;
|
|
Packit Service |
3470d1 |
while(iter){
|
|
Packit Service |
3470d1 |
// Node Descriptions are up to 64 bytes
|
|
Packit Service |
3470d1 |
fprintf(matrix_file, "%64s", iter->name);
|
|
Packit Service |
3470d1 |
iter = iter->next;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
fprintf(matrix_file, "\n");
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
iter = switchlist_head;
|
|
Packit Service |
3470d1 |
opa_switch * iter2;
|
|
Packit Service |
3470d1 |
while(iter) {
|
|
Packit Service |
3470d1 |
fprintf(matrix_file, "%-64s", iter->name);
|
|
Packit Service |
3470d1 |
iter2 = switchlist_head;
|
|
Packit Service |
3470d1 |
while(iter2) {
|
|
Packit Service |
3470d1 |
if(cost[iter->lid])
|
|
Packit Service |
3470d1 |
fprintf(matrix_file, "%64d" , cost[iter->lid][iter2->lid]);
|
|
Packit Service |
3470d1 |
iter2 = iter2->next;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
iter = iter->next;
|
|
Packit Service |
3470d1 |
fprintf(matrix_file, "\n");
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
fprintf(matrix_file, "\n\n\n");
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
int main(int argc, char **argv)
|
|
Packit Service |
3470d1 |
{
|
|
Packit Service |
3470d1 |
OMGT_STATUS_T status = OMGT_STATUS_SUCCESS;
|
|
Packit Service |
3470d1 |
int exitcode = 0;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
struct omgt_port *port = NULL;
|
|
Packit Service |
3470d1 |
omgt_sa_selector_t selector;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
int num_classportinfo_records, num_fabricinfo_records, num_cost_records, num_switch_records;
|
|
Packit Service |
3470d1 |
int num_nodes = 0;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
STL_CLASS_PORT_INFO *classportinfo_records = NULL;
|
|
Packit Service |
3470d1 |
STL_FABRICINFO_RECORD *fabricinfo_records = NULL;
|
|
Packit Service |
3470d1 |
STL_SWITCH_COST_RECORD *cost_records = NULL;
|
|
Packit Service |
3470d1 |
STL_NODE_RECORD *switch_records = NULL;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
STL_NOTICE *notice = NULL;
|
|
Packit Service |
3470d1 |
size_t notice_len = 0;
|
|
Packit Service |
3470d1 |
struct omgt_port *context = NULL;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
uint16_t **cost = NULL;
|
|
Packit Service |
3470d1 |
int i,j;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
if (argc < 2) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "Usage: %s <output_file>\n", argv[0]);
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto done;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
matrix_file = fopen(argv[1], "w");
|
|
Packit Service |
3470d1 |
if (!matrix_file) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "could not open output file for writing\n");
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto done;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
// create a session
|
|
Packit Service |
3470d1 |
status = omgt_open_port_by_num(&port, 1, 1, NULL);
|
|
Packit Service |
3470d1 |
if (OMGT_STATUS_SUCCESS != status) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "failed to open port\n");
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto close_file;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
// Determine if SA has Switch Cost Record capabiility
|
|
Packit Service |
3470d1 |
selector.InputType = InputTypeNoInput;
|
|
Packit Service |
3470d1 |
status = omgt_sa_get_classportinfo_records(port, &selector, &num_classportinfo_records, &classportinfo_records);
|
|
Packit Service |
3470d1 |
if (OMGT_STATUS_SUCCESS != status || num_classportinfo_records != 1) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "failed to execute classportinfo record query. MADStatus=0x%x\n", omgt_get_sa_mad_status(port));
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto close_port;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
if (! (classportinfo_records[0].CapMask && STL_SA_CAPABILITY2_SWCOSTRECORD_SUPPORT)) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "SA does not support switchcost records\n");
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto close_port;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
// Register for Cost Matrix Change Trap
|
|
Packit Service |
3470d1 |
if ((status = omgt_sa_register_trap(port, STL_TRAP_COST_MATRIX_CHANGE, port)) != OMGT_STATUS_SUCCESS) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, " Error: Could not register for Trap %u: %s (%u)\n",
|
|
Packit Service |
3470d1 |
STL_TRAP_COST_MATRIX_CHANGE, omgt_status_totext(status), status);
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto close_port;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
opa_switch *head_switch = NULL, *temp_switch = NULL;
|
|
Packit Service |
3470d1 |
while(!exitcode){
|
|
Packit Service |
3470d1 |
selector.InputType = InputTypeNoInput;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
/* Query SA for fabric information to determine how big to make
|
|
Packit Service |
3470d1 |
* our own cost matrix storage
|
|
Packit Service |
3470d1 |
*/
|
|
Packit Service |
3470d1 |
status = omgt_sa_get_fabric_info_records(port, &selector, &num_fabricinfo_records, &fabricinfo_records);
|
|
Packit Service |
3470d1 |
if (OMGT_STATUS_SUCCESS != status || num_fabricinfo_records < 1) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "failed to get fabricinfo. MADStatus=0x%x\n", omgt_get_sa_mad_status(port));
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto cleanup;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
/* Using total number of nodes will allocate more space than necessary,
|
|
Packit Service |
3470d1 |
* but allows simpler processing of cost data
|
|
Packit Service |
3470d1 |
*/
|
|
Packit Service |
3470d1 |
num_nodes = fabricinfo_records[0].NumSwitches + fabricinfo_records[0].NumHFIs;
|
|
Packit Service |
3470d1 |
if ((cost = calloc(1, num_nodes * sizeof(uint16_t*))) == NULL) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "failed to allocate memory\n");
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto cleanup;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
/* Query SA for switch records so we can have the names of the switches
|
|
Packit Service |
3470d1 |
* as the cost records are defined with LIDs
|
|
Packit Service |
3470d1 |
*/
|
|
Packit Service |
3470d1 |
selector.InputType = InputTypeNodeType; // select records by type
|
|
Packit Service |
3470d1 |
selector.InputValue.NodeRecord.NodeType = IBA_NODE_SWITCH; // select only Switches
|
|
Packit Service |
3470d1 |
status = omgt_sa_get_node_records(port, &selector, &num_switch_records, &switch_records);
|
|
Packit Service |
3470d1 |
if (OMGT_STATUS_SUCCESS != status) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "failed to execute node record query. MADStatus=0x%x\n", omgt_get_sa_mad_status(port));
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto cleanup;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
/* Create a linked list of switches in this fabric
|
|
Packit Service |
3470d1 |
*/
|
|
Packit Service |
3470d1 |
for (i = 0; i < num_switch_records; ++i) {
|
|
Packit Service |
3470d1 |
opa_switch * next_switch;
|
|
Packit Service |
3470d1 |
if ((next_switch = malloc(sizeof(opa_switch))) == NULL) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "failed to allocate memory\n");
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto cleanup;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
next_switch->lid = switch_records[i].RID.LID;
|
|
Packit Service |
3470d1 |
next_switch->name = get_name(switch_records[i].RID.LID, switch_records, num_switch_records);
|
|
Packit Service |
3470d1 |
next_switch->next = NULL;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
if (temp_switch)
|
|
Packit Service |
3470d1 |
temp_switch->next = next_switch;
|
|
Packit Service |
3470d1 |
else
|
|
Packit Service |
3470d1 |
head_switch = next_switch;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
temp_switch = next_switch;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
temp_switch = NULL;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
// reset selector to appropriate type for cost query
|
|
Packit Service |
3470d1 |
selector.InputType = InputTypeNoInput;
|
|
Packit Service |
3470d1 |
status = omgt_sa_get_switchcost_records(port, &selector, &num_cost_records, &cost_records);
|
|
Packit Service |
3470d1 |
if (OMGT_STATUS_SUCCESS != status) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "failed to execute cost record query. MADStatus=0x%x\n", omgt_get_sa_mad_status(port));
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto cleanup;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
/* Copy returned Cost matrix data into our own format
|
|
Packit Service |
3470d1 |
* When requesting the entire matrix, only the lower
|
|
Packit Service |
3470d1 |
* diagonal is returned as it is symmetric
|
|
Packit Service |
3470d1 |
*/
|
|
Packit Service |
3470d1 |
int slid, dlid;
|
|
Packit Service |
3470d1 |
STL_SWITCH_COST_RECORD cost_record;
|
|
Packit Service |
3470d1 |
for (i = 0; i < num_cost_records; ++i) {
|
|
Packit Service |
3470d1 |
cost_record = cost_records[i];
|
|
Packit Service |
3470d1 |
slid = cost_record.SLID;
|
|
Packit Service |
3470d1 |
/* Cost records contain 64 entries, but all may not be filled
|
|
Packit Service |
3470d1 |
* Checking the DLID is > 0 ensures the entry is valid
|
|
Packit Service |
3470d1 |
*/
|
|
Packit Service |
3470d1 |
for (j = 0; j < STL_SWITCH_COST_NUM_ENTRIES && cost_record.Cost[j].DLID > 0; ++j) {
|
|
Packit Service |
3470d1 |
dlid = cost_record.Cost[j].DLID;
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
// Initialize all entries in cost to zero.
|
|
Packit Service |
3470d1 |
// The entries of interest will be overwritten with
|
|
Packit Service |
3470d1 |
// actual cost values from the SA
|
|
Packit Service |
3470d1 |
if (!cost[slid]) {
|
|
Packit Service |
3470d1 |
if ((cost[slid] = calloc(1, num_nodes * sizeof(uint16_t))) == NULL) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "failed to allocate memory\n");
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto cleanup;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
if (!cost[dlid]) {
|
|
Packit Service |
3470d1 |
if ((cost[dlid] = calloc(1, num_nodes * sizeof(uint16_t))) == NULL) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "failed to allocate memory\n");
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto cleanup;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
// add this cost to matrix for slid/dlid
|
|
Packit Service |
3470d1 |
cost[slid][dlid] = cost[dlid][slid] = cost_record.Cost[j].value;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
print_matrix(cost, head_switch);
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
printf("\nMonitoring for any changes...\n");
|
|
Packit Service |
3470d1 |
fflush(matrix_file);
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
// monitor cluster for changes, -1 = indefinite wait time
|
|
Packit Service |
3470d1 |
if ((status = omgt_sa_get_notice_report(port, ¬ice, ¬ice_len, (void **)&context, -1)) != OMGT_STATUS_SUCCESS) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "Error: Could not wait for Notice: %s (%u)\n",
|
|
Packit Service |
3470d1 |
omgt_status_totext(status), status);
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto cleanup;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
// we only registered for Cost Matrix Change notice, if we got something else it's an error
|
|
Packit Service |
3470d1 |
if (notice->Attributes.Generic.TrapNumber != STL_TRAP_COST_MATRIX_CHANGE) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "Unhandled Trap Received: %u\n", notice->Attributes.Generic.TrapNumber);
|
|
Packit Service |
3470d1 |
exitcode = 1;
|
|
Packit Service |
3470d1 |
goto cleanup;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
cleanup:
|
|
Packit Service |
3470d1 |
if (notice) {
|
|
Packit Service |
3470d1 |
free(notice);
|
|
Packit Service |
3470d1 |
notice = NULL;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
if (fabricinfo_records) {
|
|
Packit Service |
3470d1 |
omgt_sa_free_records(fabricinfo_records);
|
|
Packit Service |
3470d1 |
fabricinfo_records = NULL;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
if (cost_records) {
|
|
Packit Service |
3470d1 |
omgt_sa_free_records(cost_records);
|
|
Packit Service |
3470d1 |
cost_records = NULL;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
if (switch_records) {
|
|
Packit Service |
3470d1 |
omgt_sa_free_records(switch_records);
|
|
Packit Service |
3470d1 |
switch_records = NULL;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
free_switch_list(&head_switch);
|
|
Packit Service |
3470d1 |
free_cost(&cost, num_nodes);
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
} //end while
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
if ((status = omgt_sa_unregister_trap(port, STL_TRAP_COST_MATRIX_CHANGE)) != OMGT_STATUS_SUCCESS) {
|
|
Packit Service |
3470d1 |
fprintf(stderr, "Error: Could not unregister for Trap %u: %s (%u)\n",
|
|
Packit Service |
3470d1 |
STL_TRAP_COST_MATRIX_CHANGE, omgt_status_totext(status), status);
|
|
Packit Service |
3470d1 |
if (!exitcode) exitcode = 1;
|
|
Packit Service |
3470d1 |
}
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
close_port:
|
|
Packit Service |
3470d1 |
if (classportinfo_records) omgt_sa_free_records(classportinfo_records);
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
//close our session
|
|
Packit Service |
3470d1 |
omgt_close_port(port);
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
close_file:
|
|
Packit Service |
3470d1 |
fclose(matrix_file);
|
|
Packit Service |
3470d1 |
|
|
Packit Service |
3470d1 |
done:
|
|
Packit Service |
3470d1 |
return exitcode;
|
|
Packit Service |
3470d1 |
}
|