Viewing: lnetctl.c
// SPDX-License-Identifier: LGPL-2.1+
/*
* Copyright (c) 2014, 2017, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
*
* Author: Amir Shehata <amir.shehata@intel.com>
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <limits.h>
#include <libcfs/util/ioctl.h>
#include <libcfs/util/parser.h>
#include "lnetconfig/cyaml.h"
#include "lnetconfig/liblnetconfig.h"
#define LNET_CONFIGURE true
#define LNET_UNCONFIGURE false
static int jt_config_lnet(int argc, char **argv);
static int jt_unconfig_lnet(int argc, char **argv);
static int jt_add_route(int argc, char **argv);
static int jt_add_ni(int argc, char **argv);
static int jt_set_routing(int argc, char **argv);
static int jt_del_route(int argc, char **argv);
static int jt_del_ni(int argc, char **argv);
static int jt_show_route(int argc, char **argv);
static int jt_show_net(int argc, char **argv);
static int jt_show_routing(int argc, char **argv);
static int jt_show_stats(int argc, char **argv);
static int jt_show_peer(int argc, char **argv);
static int jt_show_recovery(int argc, char **argv);
static int jt_debug_nidlist(int argc, char **argv);
static int jt_show_global(int argc, char **argv);
static int jt_show_udsp(int argc, char **argv);
static int jt_set_tiny(int argc, char **argv);
static int jt_set_small(int argc, char **argv);
static int jt_set_large(int argc, char **argv);
static int jt_set_numa(int argc, char **argv);
static int jt_set_retry_count(int argc, char **argv);
static int jt_set_transaction_to(int argc, char **argv);
static int jt_set_recov_intrv(int argc, char **argv);
static int jt_set_rtr_sensitivity(int argc, char **argv);
static int jt_set_hsensitivity(int argc, char **argv);
static int jt_set_max_recovery_ping_interval(int argc, char **argv);
static int jt_reset_stats(int argc, char **argv);
static int jt_add_peer_nid(int argc, char **argv);
static int jt_del_peer_nid(int argc, char **argv);
static int jt_set_max_intf(int argc, char **argv);
static int jt_set_discovery(int argc, char **argv);
static int jt_set_drop_asym_route(int argc, char **argv);
static int jt_list_peer(int argc, char **argv);
static int jt_add_udsp(int argc, char **argv);
static int jt_del_udsp(int argc, char **argv);
static int jt_import(int argc, char **argv);
static int jt_export(int argc, char **argv);
static int jt_ping(int argc, char **argv);
static int jt_discover(int argc, char **argv);
static int jt_lnet(int argc, char **argv);
static int jt_route(int argc, char **argv);
static int jt_net(int argc, char **argv);
static int jt_routing(int argc, char **argv);
static int jt_set(int argc, char **argv);
static int jt_debug(int argc, char **argv);
static int jt_stats(int argc, char **argv);
static int jt_global(int argc, char **argv);
static int jt_peers(int argc, char **argv);
static int jt_set_ni_value(int argc, char **argv);
static int jt_set_peer_ni_value(int argc, char **argv);
static int jt_calc_service_id(int argc, char **argv);
static int jt_set_response_tracking(int argc, char **argv);
static int jt_set_recovery_limit(int argc, char **argv);
static int jt_udsp(int argc, char **argv);
static int jt_fault(int argc, char **argv);
static int jt_fault_drop(int argc, char **argv);
static int jt_fault_drop_add(int argc, char **argv);
static int jt_fault_drop_del(int argc, char **argv);
static int jt_fault_drop_reset(int argc, char **argv);
static int jt_fault_drop_show(int argc, char **argv);
static int jt_fault_delay(int argc, char **argv);
static int jt_fault_delay_add(int argc, char **argv);
static int jt_fault_delay_del(int argc, char **argv);
static int jt_fault_delay_reset(int argc, char **argv);
static int jt_fault_delay_show(int argc, char **argv);
static int jt_setup_mrrouting(int argc, char **argv);
static int jt_setup_sysctl(int argc, char **argv);
static int jt_calc_cpt_of_nid(int argc, char **argv);
static int jt_show_peer_debug_info(int argc, char **argv);
command_t cmd_list[] = {
{"lnet", jt_lnet, 0, "lnet {configure | unconfigure} [--all|--large]"},
{"route", jt_route, 0, "route {add | del | show | help}"},
{"net", jt_net, 0, "net {add | del | show | set | help}"},
{"routing", jt_routing, 0, "routing {show | help}"},
{"set", jt_set, 0, "set {tiny_buffers | small_buffers | large_buffers"
" | routing | numa_range | max_interfaces"
" | discovery | drop_asym_route | retry_count"
" | transaction_timeout | health_sensitivity"
" | recovery_interval | router_sensitivity"
" | response_tracking | recovery_limit}"},
{"import", jt_import, 0, "import FILE.yaml"},
{"export", jt_export, 0, "export FILE.yaml"},
{"stats", jt_stats, 0, "stats {show | help}"},
{"debug", jt_debug, 0, "debug {recovery {local | peer} | peer}"},
{"global", jt_global, 0, "global {show | help}"},
{"peer", jt_peers, 0, "peer {add | del | show | list | set | help}"},
{"ping", jt_ping, 0, "ping nid,[nid,...]"},
{"discover", jt_discover, 0, "discover nid[,nid,...]"},
{"service-id", jt_calc_service_id, 0, "Calculate IB Lustre service ID\n"},
{"udsp", jt_udsp, 0, "udsp {add | del | help}"},
{"fault", jt_fault, 0, "{drop | delay | help}"},
{"setup-mrrouting", jt_setup_mrrouting, 0,
"setup linux routing tables\n"},
{"setup-sysctl", jt_setup_sysctl, 0,
"setup linux sysctl parameter for large systems\n"},
{"cpt-of-nid", jt_calc_cpt_of_nid, 0,
"Calculate the CPTs associated with NIDs\n"
" usage:\n\tlnetctl cpt-of-nid nid[ nid ...]\n"},
{ 0, 0, 0, NULL }
};
command_t lnet_cmds[] = {
{"configure", jt_config_lnet, 0, "configure lnet\n"
"\t--all: load NI configuration from module parameters\n"
"\t--large: start LNet with large NIDs\n"},
{"unconfigure", jt_unconfig_lnet, 0, "unconfigure lnet\n"},
{ 0, 0, 0, NULL }
};
command_t route_cmds[] = {
{"add", jt_add_route, 0, "add a route\n"
"\t--net: net name (e.g. tcp0)\n"
"\t--gateway: gateway nid (e.g. 10.1.1.2@tcp)\n"
"\t--hop|hop-count: number to final destination (1 <= hops <= 255)\n"
"\t--priority: priority of route (0 - highest prio\n"
"\t--health_sensitivity: gateway health sensitivity (>= 1)\n"},
{"del", jt_del_route, 0, "delete a route\n"
"\t--net: net name (e.g. tcp0)\n"
"\t--gateway: gateway nid (e.g. 10.1.1.2@tcp)\n"},
{"show", jt_show_route, 0, "show routes\n"
"\t--net: net name (e.g. tcp0) to filter on\n"
"\t--gateway: gateway nid (e.g. 10.1.1.2@tcp) to filter on\n"
"\t--hop|hop-count: number to final destination (1 <= hops <= 255) to filter on\n"
"\t--priority: priority of route (0 - highest prio to filter on\n"
"\t--verbose: display detailed output per route\n"},
{ 0, 0, 0, NULL }
};
command_t net_cmds[] = {
{"add", jt_add_ni, 0, "add a network\n"
"\t--net: net name (e.g. tcp0)\n"
"\t--if: physical interface (e.g. eth0)\n"
"\t--nid: bring up NI based on the address of the specified LNet NID\n"
"\t--ip2net: specify networks based on IP address patterns\n"
"\t--peer-timeout: time to wait before declaring a peer dead\n"
"\t--peer-credits: define the max number of inflight messages\n"
"\t--peer-buffer-credits: the number of buffer credits per peer\n"
"\t--credits: Network Interface credits\n"
"\t--cpt: CPU Partitions configured net uses (e.g. [0,1]\n"
"\t--conns-per-peer: number of connections per peer\n"
"\t--skip-mr-route-setup: do not add linux route for the ni\n"
"\t--auth-key: Network authorization key (kfilnd only)\n"
"\t--traffic-class: Traffic class (kfilnd only)\n"
"\t--tos: IP's Type of Service\n"},
{"del", jt_del_ni, 0, "delete a network\n"
"\t--net: net name (e.g. tcp0)\n"
"\t--nid: shutdown NI based on the address of the specified LNet NID\n"
"\t--if: physical interface (e.g. eth0)\n"},
{"show", jt_show_net, 0, "show networks\n"
"\t--net: net name (e.g. tcp0) to filter on\n"
"\t--verbose: display detailed output per network."
" Optional argument of '2' outputs more stats\n"},
{"set", jt_set_ni_value, 0, "set local NI specific parameter\n"
"\t--nid: NI NID to set the value on\n"
"\t--net: network to set the value on (e.g. tcp, o2ib, kfi)\n"
"\t--lnd-timeout: set LND timeout (seconds) for LND used by --net argument\n"
"\t--health: specify health value to set\n"
"\t--conns-per-peer: number of connections per peer\n"
"\t--all: set all NIs value to the one specified\n"},
{ 0, 0, 0, NULL }
};
command_t routing_cmds[] = {
{"show", jt_show_routing, 0, "show routing information\n"},
{ 0, 0, 0, NULL }
};
command_t stats_cmds[] = {
{"show", jt_show_stats, 0, "show LNET statistics\n"},
{"reset", jt_reset_stats, 0, "reset LNET statistics\n"},
{ 0, 0, 0, NULL }
};
command_t debug_cmds[] = {
{"recovery", jt_show_recovery, 0, "list recovery queues\n"
"\t--local : list local recovery queue\n"
"\t--peer : list peer recovery queue\n"},
{"peer", jt_show_peer_debug_info, 0, "show peer debug info\n"
"\t--nid: peer's NID\n"},
{"nidlist", jt_debug_nidlist, 0, "debug nidlist parsing\n"},
{ 0, 0, 0, NULL }
};
command_t global_cmds[] = {
{"show", jt_show_global, 0, "show global variables\n"},
{ 0, 0, 0, NULL }
};
command_t set_cmds[] = {
{"tiny_buffers", jt_set_tiny, 0, "set tiny routing buffers\n"
"\tVALUE must be greater than 0\n"},
{"small_buffers", jt_set_small, 0, "set small routing buffers\n"
"\tVALUE must be greater than 0\n"},
{"large_buffers", jt_set_large, 0, "set large routing buffers\n"
"\tVALUE must be greater than 0\n"},
{"routing", jt_set_routing, 0, "enable/disable routing\n"
"\t0 - disable routing\n"
"\t1 - enable routing\n"},
{"numa_range", jt_set_numa, 0, "set NUMA range for NI selection\n"
"\tVALUE must be at least 0\n"},
{"max_interfaces", jt_set_max_intf, 0, "set the default value for "
"max interfaces\n"
"\tValue must be greater than 16\n"},
{"discovery", jt_set_discovery, 0, "enable/disable peer discovery\n"
"\t0 - disable peer discovery\n"
"\t1 - enable peer discovery (default)\n"},
{"drop_asym_route", jt_set_drop_asym_route, 0,
"drop/accept asymmetrical route messages\n"
"\t0 - accept asymmetrical route messages (default)\n"
"\t1 - drop asymmetrical route messages\n"},
{"retry_count", jt_set_retry_count, 0, "number of retries\n"
"\t0 - turn of retries\n"
"\t>0 - number of retries\n"},
{"transaction_timeout", jt_set_transaction_to, 0, "Message/Response timeout\n"
"\t>0 - timeout in seconds\n"},
{"health_sensitivity", jt_set_hsensitivity, 0, "sensitivity to failure\n"
"\t0 - turn off health evaluation\n"
"\t>0 - sensitivity value not more than 1000\n"},
{"recovery_interval", jt_set_recov_intrv, 0, "interval to ping in seconds (at least 1)\n"
"\t>0 - time in seconds between pings\n"},
{"router_sensitivity", jt_set_rtr_sensitivity, 0, "router sensitivity %\n"
"\t100 - router interfaces need to be fully healthy to be used\n"
"\t<100 - router interfaces can be used even if not healthy\n"},
{"response_tracking", jt_set_response_tracking, 0,
"Set the behavior of response tracking\n"
"\t0 - Only LNet pings and discovery pushes utilize response tracking\n"
"\t1 - GETs are eligible for response tracking\n"
"\t2 - PUTs are eligible for response tracking\n"
"\t3 - Both PUTs and GETs are eligible for response tracking (default)\n"
"\tNote: Regardless of the value of the response_tracking parameter LNet\n"
"\t pings and discovery pushes always utilize response tracking\n"},
{"recovery_limit", jt_set_recovery_limit, 0,
"Set how long LNet will attempt to recover unhealthy interfaces.\n"
"\t0 - Recover indefinitely (default)\n"
"\t>0 - Recover for the specified number of seconds.\n"},
{"max_recovery_ping_interval", jt_set_max_recovery_ping_interval, 0,
"maximum recovery ping interval\n"
"\t>0 - maximum recovery ping interval in seconds\n"},
{ 0, 0, 0, NULL }
};
command_t peer_cmds[] = {
{"add", jt_add_peer_nid, 0, "add a peer NID\n"
"\t--prim_nid: Primary NID of the peer.\n"
"\t--nid: one or more peer NIDs\n"
"\t--non_mr: create this peer as not Multi-Rail capable\n"
"\t--ip2nets: specify a range of nids per peer\n"
"\t--lock_prim: lock primary nid\n"},
{"del", jt_del_peer_nid, 0, "delete a peer NID\n"
"\t--prim_nid: Primary NID of the peer.\n"
"\t--nid: list of NIDs to remove. If none provided,\n"
"\t peer is deleted\n"
"\t--ip2nets: specify a range of nids per peer\n"
"\t--force: force-delete locked primary NID\n"},
{"show", jt_show_peer, 0, "show peer information\n"
"\t--nid: NID of peer to filter on.\n"
"\t--verbose: display detailed output per peer."
" Optional argument of '2' outputs more stats\n"},
{"list", jt_list_peer, 0, "list all peers\n"},
{"set", jt_set_peer_ni_value, 0, "set peer ni specific parameter\n"
"\t--nid: Peer NI NID to set the\n"
"\t--health: specify health value to set\n"
"\t--all: set all peer_nis values to the one specified\n"
"\t--state: set peer state (DANGEROUS: for test/debug only)"},
{ 0, 0, 0, NULL }
};
command_t udsp_cmds[] = {
{"add", jt_add_udsp, 0, "add a udsp\n"
"\t--src nid|net: ip2nets syntax specifying the local NID or network to match.\n"
"\t--dst nid: ip2nets syntax specifying the remote NID to match.\n"
"\t--rte nid: ip2nets syntax specifying the router NID to match.\n"
"\t--priority p: Assign priority value p where p >= 0.\n"
"\t Note: 0 is the highest priority.\n"
"\t--idx n: Insert the rule in the n'th position on the list of rules.\n"
"\t By default, rules are appended to the end of the rule list.\n"},
{"del", jt_del_udsp, 0, "delete a udsp\n"
"\t--all: Delete all rules.\n"
"\t--idx n: Delete the rule at index n.\n"},
{"show", jt_show_udsp, 0, "show udsps\n"
"\t--idx n: Show the rule at at index n.\n"
"\t By default, all rules are shown.\n"},
{ 0, 0, 0, NULL }
};
command_t fault_cmds[] = {
{"drop", jt_fault_drop, 0, "Manage drop rules\n"
"usage: lnetctl fault drop add [<options>] -r <rate>|-i <interval> -s <src> -d <dest>\n"
" or: lnetctl fault drop del -s <src> -d <dest>\n"
" or: lnetctl fault drop show\n"
" or: lnetctl fault drop reset\n" },
{"delay", jt_fault_delay, 0, "Manage delay rules\n"
"usage: lnetctl fault delay add [<options>] -r <rate>|-i <interval> -s <src> -d <dest>\n"
" or: lnetctl fault delay del -s <src> -d <dest>\n"
" or: lnetctl fault delay show\n"
" or: lnetctl fault delay reset\n" },
{ 0, 0, 0, NULL }
};
command_t fault_drop_cmds[] = {
{"add", jt_fault_drop_add, 0, "add LNet drop rule\n"
"\t--source nid: Drop messages originating from <nid>.\n"
"\t--dest nid: Drop messages destined for <nid>.\n"
"\t--rate r: Drop messages at specified rate (1/<r>).\n"
"\t--interval i: Drop messages at specified time interval (seconds).\n"
"\t--portal p: Drop messages on specified portal.\n"
"\t--message m: Drop messages of specified type <PUT|ACK|GET|REPLY>.\n"
"\t--health_error: Dropped messages simulate the specified health status\n"
"\t <local_timeout|remote_dropped|network_timeout|...>.\n" },
{"del", jt_fault_drop_del, 0, "delete LNet drop rules\n"
"\t--all: Delete all drop rules\n"
"\t--source nid: Delete drop rule with specified source NID\n"
"\t--dest nid: Delete drop rule with specified destination NID\n"},
{"reset", jt_fault_drop_reset, 0, "reset counters for all drop rules\n" },
{"show", jt_fault_drop_show, 0, "show drop rules\n" },
{ 0, 0, 0, NULL }
};
command_t fault_delay_cmds[] = {
{"add", jt_fault_delay_add, 0, "add LNet delay rule\n"
"\t--source nid: Delay messages originating from <nid>.\n"
"\t--dest nid: Delay messages destined for <nid>.\n"
"\t--rate r: Delay messages at specified rate (1/<r>).\n"
"\t--interval i: Delay messages at specified time interval (seconds).\n"
"\t--portal p: Delay messages on specified portal.\n"
"\t--message m: Delay messages of specified type <PUT|ACK|GET|REPLY>.\n"
"\t--latency: Delay sending a message (delay only).\n"},
{"del", jt_fault_delay_del, 0, "delete LNet delay rules\n"
"\t--all: Delete all delay rules\n"
"\t--source nid: Delete delay rule with specified source NID\n"
"\t--dest nid: Delete delay rule with specified destination NID\n"},
{"reset", jt_fault_delay_reset, 0, "reset counters for all delay rules\n" },
{"show", jt_fault_delay_show, 0, "show delay rules\n" },
{ 0, 0, 0, NULL }
};
static int parse_long(const char *number, long int *value)
{
char *end;
if (!number)
return -1;
*value = strtol(number, &end, 0);
if (end != NULL && *end != 0)
return -1;
return 0;
}
static int jt_setup_mrrouting(int argc, char **argv)
{
int rc;
struct cYAML *err_rc = NULL;
rc = lustre_lnet_setup_mrrouting(&err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_setup_sysctl(int argc, char **argv)
{
int rc;
struct cYAML *err_rc = NULL;
rc = lustre_lnet_setup_sysctl(&err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static inline void print_help(const command_t cmds[], const char *cmd_type,
const char *pc_name)
{
const command_t *cmd;
for (cmd = cmds; cmd->pc_name; cmd++) {
if (pc_name != NULL &&
strcmp(cmd->pc_name, pc_name) == 0) {
printf("%s %s: %s\n", cmd_type, cmd->pc_name,
cmd->pc_help);
return;
} else if (pc_name != NULL) {
continue;
}
printf("%s %s: %s\n", cmd_type, cmd->pc_name, cmd->pc_help);
}
}
/*
* Perform some basic input validation.
* Returns:
* LUSTRE_CFG_RC_BAD_PARAM: when minimum number of arguments has not been
* supplied
* > 0: when '-h' or '--help' has been supplied
* 0: when the "check" passes and command can continue execution
*/
static int check_cmd(const command_t *cmd_list, const char *cmd,
const char *sub_cmd, const int min_args,
int argc, char **argv)
{
int opt;
int rc = 0;
optind = 0;
opterr = 0;
const char *const short_options = "h";
static const struct option long_options[] = {
{ .name = "help", .has_arg = no_argument, .val = 'h' },
{ .name = NULL }
};
if (argc < min_args) {
print_help(cmd_list, cmd, sub_cmd);
rc = LUSTRE_CFG_RC_BAD_PARAM;
goto out;
} else if (argc > 2) {
return 0;
}
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'h':
print_help(cmd_list, cmd, sub_cmd);
rc = 1;
break;
default:
rc = 0;
break;
}
}
out:
opterr = 1;
optind = 0;
return rc;
}
static int jt_set_response_tracking(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "response_tracking", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse response_tracking value",
&err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_response_tracking(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_calc_service_id(int argc, char **argv)
{
int rc;
__u64 service_id;
rc = lustre_lnet_calc_service_id(&service_id);
if (rc != LUSTRE_CFG_RC_NO_ERR)
return rc;
/* cYAML currently doesn't support printing hex values.
* Therefore just print it locally here
*/
printf("service_id:\n value: 0x%llx\n",
(unsigned long long)(service_id));
return rc;
}
static int jt_set_recovery_limit(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "recovery_limit", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse recovery_limit value",
&err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_recovery_limit(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_max_intf(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "max_interfaces", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse max_interfaces value", &err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_max_intf(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_numa(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "numa_range", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse numa_range value", &err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_numa_range(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_recov_intrv(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "recovery_interval", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse recovery interval value", &err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_recov_intrv(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_rtr_sensitivity(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "router_sensitivity", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse router sensitivity value", &err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_rtr_sensitivity(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_hsensitivity(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "health_sensitivity", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse health sensitivity value", &err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_hsensitivity(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_reset_stats(int argc, char **argv)
{
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(stats_cmds, "stats", "reset", 0, argc, argv);
if (rc)
return rc;
rc = lustre_lnet_reset_stats(-1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_transaction_to(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "transaction_timeout", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse transaction timeout value", &err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_transaction_to(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_retry_count(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "retry_count", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse retry_count value", &err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_retry_count(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_discovery(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "discovery", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse discovery value", &err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_discovery(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_drop_asym_route(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "drop_asym_route", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse drop_asym_route value",
&err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_drop_asym_route(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_tiny(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "tiny_buffers", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse tiny_buffers value", &err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_buffers(value, -1, -1, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_small(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "small_buffers", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse small_buffers value", &err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_buffers(-1, value, -1, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_large(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "large_buffers", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse large_buffers value", &err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_buffers(-1, -1, value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_routing(int argc, char **argv)
{
long int value;
struct cYAML *err_rc = NULL;
int rc;
rc = check_cmd(set_cmds, "set", "routing", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0 || (value != 0 && value != 1)) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse routing value.\n"
"must be 0 for disable or 1 for enable",
&err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_routing(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_max_recovery_ping_interval(int argc, char **argv)
{
long int value;
int rc;
struct cYAML *err_rc = NULL;
rc = check_cmd(set_cmds, "set", "maximum recovery_interval", 2, argc, argv);
if (rc)
return rc;
rc = parse_long(argv[1], &value);
if (rc != 0) {
cYAML_build_error(-1, -1, "parser", "set",
"cannot parse maximum recovery interval value",
&err_rc);
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return -1;
}
rc = lustre_lnet_config_max_recovery_ping_interval(value, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static void yaml_lnet_print_error(int op, char *cmd, const char *errstr)
{
char errcode[INT_STRING_LEN];
yaml_emitter_t log;
yaml_event_t event;
const char *flag;
int rc;
snprintf(errcode, sizeof(errcode), "%d", errno);
yaml_emitter_initialize(&log);
yaml_emitter_set_indent(&log, LNET_DEFAULT_INDENT);
yaml_emitter_set_output_file(&log, stderr);
yaml_emitter_open(&log);
yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
if (strcmp(cmd, "lnet") == 0) {
flag = "configure";
goto skip_op;
}
switch (op) {
case NLM_F_CREATE:
flag = "add";
break;
case NLM_F_REPLACE:
flag = "set";
break;
case 0:
flag = "del";
break;
case -1:
flag = "manage";
break;
case NLM_F_DUMP:
default:
flag = "show";
break;
}
skip_op:
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)flag,
strlen(flag), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_sequence_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_SEQ_TAG,
1, YAML_ANY_SEQUENCE_STYLE);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)cmd,
strlen(cmd),
1, 0, YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"",
strlen(""),
1, 0, YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"errno",
strlen("errno"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)errcode,
strlen(errcode), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"descr",
strlen("descr"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)errstr,
strlen(errstr), 1, 0,
YAML_DOUBLE_QUOTED_SCALAR_STYLE);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_sequence_end_event_initialize(&event);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
yaml_document_end_event_initialize(&event, 0);
rc = yaml_emitter_emit(&log, &event);
if (rc == 0)
goto emitter_error;
rc = yaml_emitter_close(&log);
emitter_error:
if (rc == 0)
yaml_emitter_log_error(&log, stdout);
yaml_emitter_delete(&log);
}
static int yaml_lnet_cpt_of_nid_display(yaml_parser_t *reply)
{
yaml_document_t results;
yaml_emitter_t output;
int rc;
rc = yaml_parser_load(reply, &results);
if (rc == 0) {
yaml_lnet_print_error(NLM_F_DUMP, "cpt-of-nid",
yaml_parser_get_reader_error(reply));
yaml_document_delete(&results);
return -EINVAL;
}
rc = yaml_emitter_initialize(&output);
if (rc == 1) {
yaml_emitter_set_output_file(&output, stdout);
rc = yaml_emitter_dump(&output, &results);
}
yaml_document_delete(&results);
if (rc == 0) {
yaml_emitter_log_error(&output, stderr);
rc = -EINVAL;
}
yaml_emitter_delete(&output);
return 1;
}
static int yaml_lnet_cpt_of_nid(int start, int end, char **nids)
{
struct nl_sock *sk = NULL;
yaml_emitter_t request;
yaml_parser_t reply;
yaml_event_t event;
int i, rc;
/* Create Netlink emitter to send request to kernel */
sk = nl_socket_alloc();
if (!sk)
return -EOPNOTSUPP;
/* Setup parser to receive Netlink packets */
rc = yaml_parser_initialize(&reply);
if (rc == 0) {
nl_socket_free(sk);
return -EOPNOTSUPP;
}
rc = yaml_parser_set_input_netlink(&reply, sk, false);
if (rc == 0)
goto free_reply;
/* Create Netlink emitter to send request to kernel */
rc = yaml_emitter_initialize(&request);
if (rc == 0)
goto free_reply;
rc = yaml_emitter_set_output_netlink(&request, sk, LNET_GENL_NAME,
LNET_GENL_VERSION,
LNET_CMD_CPT_OF_NID, NLM_F_DUMP);
if (rc == 0)
goto emitter_error;
yaml_emitter_open(&request);
yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
rc = yaml_emitter_emit(&request, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(&request, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"cpt-of-nid",
strlen("cpt-of-nid"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&request, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(&request, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"nids",
strlen("nids"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&request, &event);
if (rc == 0)
goto emitter_error;
yaml_sequence_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_SEQ_TAG,
1, YAML_FLOW_SEQUENCE_STYLE);
rc = yaml_emitter_emit(&request, &event);
if (rc == 0)
goto emitter_error;
for (i = start; i < end; i++) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)nids[i],
strlen(nids[i]), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&request, &event);
if (rc == 0)
goto emitter_error;
}
yaml_sequence_end_event_initialize(&event);
rc = yaml_emitter_emit(&request, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&request, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&request, &event);
if (rc == 0)
goto emitter_error;
yaml_document_end_event_initialize(&event, 0);
rc = yaml_emitter_emit(&request, &event);
if (rc == 0)
goto emitter_error;
rc = yaml_emitter_close(&request);
emitter_error:
if (rc == 0) {
yaml_emitter_log_error(&request, stderr);
rc = -EINVAL;
} else {
rc = yaml_lnet_cpt_of_nid_display(&reply);
}
yaml_emitter_cleanup(&request);
free_reply:
if (rc == 0) {
yaml_lnet_print_error(NLM_F_DUMP, "cpt-of-nid",
yaml_parser_get_reader_error(&reply));
rc = -EINVAL;
}
yaml_parser_cleanup(&reply);
nl_socket_free(sk);
return rc == 1 ? 0 : rc;
}
static int jt_calc_cpt_of_nid(int argc, char **argv)
{
int rc, opt;
const char *const short_options = "h";
static const struct option long_options[] = {
{ .name = "help", .val = 'h' },
{ .name = NULL } };
rc = check_cmd(cmd_list, "", "cpt-of-nid", 2, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'h':
case '?':
print_help(cmd_list, "", "cpt-of-nid");
default:
return 0;
}
}
rc = yaml_lnet_cpt_of_nid(optind, argc, argv);
if (rc == -EOPNOTSUPP)
printf("Operation not supported\n");
return rc;
}
static int jt_config_lnet(int argc, char **argv)
{
struct cYAML *err_rc = NULL;
bool load_mod_params = false;
int flags = NLM_F_CREATE;
const char *msg = NULL;
int rc, opt;
const char *const short_options = "al";
static const struct option long_options[] = {
{ .name = "all", .has_arg = no_argument, .val = 'a' },
{ .name = "large", .has_arg = no_argument, .val = 'l' },
{ .name = NULL }
};
rc = check_cmd(lnet_cmds, "lnet", "configure", 0, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'a':
load_mod_params = true;
break;
case 'l':
flags |= NLM_F_APPEND;
break;
default:
return 0;
}
}
if (!load_mod_params)
flags |= NLM_F_EXCL;
rc = yaml_lnet_configure(flags, &msg);
if (rc != -EOPNOTSUPP) {
if (rc < 0) {
char errstr[256];
snprintf(errstr, sizeof(errstr),
"LNet configure error: %s", msg);
yaml_lnet_print_error(flags, "lnet", errstr);
}
return rc;
}
rc = lustre_lnet_config_ni_system(LNET_CONFIGURE, load_mod_params,
-1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_unconfig_lnet(int argc, char **argv)
{
struct cYAML *err_rc = NULL;
const char *msg = NULL;
int rc;
rc = check_cmd(lnet_cmds, "lnet", "unconfigure", 0, argc, argv);
if (rc)
return rc;
rc = yaml_lnet_configure(0, &msg);
if (rc != -EOPNOTSUPP) {
if (rc < 0) {
char errstr[256];
snprintf(errstr, sizeof(errstr),
"LNet configure error: %s", msg);
yaml_lnet_print_error(0, "lnet", errstr);
}
return rc;
}
rc = lustre_lnet_config_ni_system(LNET_UNCONFIGURE, 0, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int yaml_lnet_router_gateways(yaml_emitter_t *output, const char *nw,
const char *gw, int hops, int prio)
{
char num[INT_STRING_LEN];
yaml_event_t event;
int rc;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG, 1,
YAML_BLOCK_MAPPING_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto emitter_error;
if (nw) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"net",
strlen("net"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)nw,
strlen(nw), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto emitter_error;
}
if (gw) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"gateway",
strlen("gateway"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)gw,
strlen(gw), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto emitter_error;
}
if (hops != -1) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"hop",
strlen("hop"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto emitter_error;
snprintf(num, sizeof(num), "%d", hops);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)num,
strlen(num), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto emitter_error;
}
if (prio != -1) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"priority",
strlen("priority"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto emitter_error;
snprintf(num, sizeof(num), "%d", prio);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)num,
strlen(num), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto emitter_error;
}
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(output, &event);
emitter_error:
return rc;
}
static int yaml_lnet_route(char *nw, char *gw, int hops, int prio,
int version, int flags, FILE *fp)
{
struct nid_node head, *entry;
struct nl_sock *sk = NULL;
const char *msg = NULL;
yaml_emitter_t output;
yaml_parser_t reply;
yaml_event_t event;
int rc;
if (!(flags & NLM_F_DUMP) && (!nw || !gw)) {
fprintf(stdout, "missing mandatory parameters:'%s'\n",
(!nw && !gw) ? "net , gateway" :
!nw ? "net" : "gateway");
return -EINVAL;
}
/* Create Netlink emitter to send request to kernel */
sk = nl_socket_alloc();
if (!sk)
return -EOPNOTSUPP;
/* Setup parser to receive Netlink packets */
rc = yaml_parser_initialize(&reply);
if (rc == 0) {
nl_socket_free(sk);
return -EOPNOTSUPP;
}
rc = yaml_parser_set_input_netlink(&reply, sk, false);
if (rc == 0) {
msg = yaml_parser_get_reader_error(&reply);
goto free_reply;
}
/* Create Netlink emitter to send request to kernel */
rc = yaml_emitter_initialize(&output);
if (rc == 0) {
msg = "failed to initialize emitter";
goto free_reply;
}
rc = yaml_emitter_set_output_netlink(&output, sk, LNET_GENL_NAME,
version, LNET_CMD_ROUTES, flags);
if (rc == 0)
goto emitter_error;
yaml_emitter_open(&output);
yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"route",
strlen("route"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
/* NLM_F_DUMP can have no arguments */
if (nw || gw) {
NL_INIT_LIST_HEAD(&head.children);
nl_init_list_head(&head.list);
if (gw) {
rc = lustre_lnet_parse_nid_range(&head, gw, &msg);
if (rc < 0) {
lustre_lnet_free_list(&head);
yaml_emitter_cleanup(&output);
errno = rc;
rc = 0;
goto free_reply;
}
}
yaml_sequence_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_SEQ_TAG,
1,
YAML_BLOCK_SEQUENCE_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
if (!nl_list_empty(&head.children)) {
nl_list_for_each_entry(entry, &head.children, list) {
const char *nid = entry->nidstr;
rc = yaml_lnet_router_gateways(&output, nw, nid,
hops, prio);
if (rc == 0)
goto emitter_error;
}
} else {
rc = yaml_lnet_router_gateways(&output, nw, NULL, hops,
prio);
if (rc == 0)
goto emitter_error;
}
yaml_sequence_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
} else {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"",
strlen(""), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
}
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_document_end_event_initialize(&event, 0);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
rc = yaml_emitter_close(&output);
emitter_error:
if (rc == 0) {
yaml_emitter_log_error(&output, stderr);
rc = -EINVAL;
} else {
yaml_document_t errmsg;
rc = yaml_parser_load(&reply, &errmsg);
if (rc == 1 && (flags & NLM_F_DUMP)) {
yaml_emitter_t debug;
rc = yaml_emitter_initialize(&debug);
if (rc == 1) {
yaml_emitter_set_indent(&debug,
LNET_DEFAULT_INDENT);
yaml_emitter_set_output_file(&debug, fp);
rc = yaml_emitter_dump(&debug, &errmsg);
}
yaml_emitter_delete(&debug);
} else {
msg = yaml_parser_get_reader_error(&reply);
/* If we didn't find any routes just be silent */
if (msg && strcmp(msg, "No routes found") == 0)
rc = 1;
}
yaml_document_delete(&errmsg);
}
yaml_emitter_delete(&output);
free_reply:
if (rc == 0) {
yaml_lnet_print_error(flags, "route", msg);
rc = -EINVAL;
}
yaml_parser_cleanup(&reply);
nl_socket_free(sk);
return rc == 1 ? 0 : rc;
}
static int jt_add_route(int argc, char **argv)
{
char *network = NULL, *gateway = NULL;
long hop = -1, prio = -1;
struct cYAML *err_rc = NULL;
int rc, opt;
const char *const short_options = "n:g:c:p:";
static const struct option long_options[] = {
{ .name = "net", .has_arg = required_argument, .val = 'n' },
{ .name = "gateway", .has_arg = required_argument, .val = 'g' },
{ .name = "hop", .has_arg = required_argument, .val = 'c' },
{ .name = "hop-count", .has_arg = required_argument, .val = 'c' },
{ .name = "priority", .has_arg = required_argument, .val = 'p' },
{ .name = NULL }
};
rc = check_cmd(route_cmds, "route", "add", 0, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'n':
network = optarg;
break;
case 'g':
gateway = optarg;
break;
case 'c':
rc = parse_long(optarg, &hop);
if (rc != 0) {
/* ignore option */
hop = -1;
continue;
}
break;
case 'p':
rc = parse_long(optarg, &prio);
if (rc != 0) {
/* ingore option */
prio = -1;
continue;
}
break;
case '?':
print_help(route_cmds, "route", "add");
default:
return 0;
}
}
rc = yaml_lnet_route(network, gateway, hop, prio,
LNET_GENL_VERSION, NLM_F_CREATE, stdout);
if (rc <= 0) {
if (rc == -EOPNOTSUPP)
goto old_api;
return rc;
}
old_api:
rc = lustre_lnet_config_route(network, gateway, hop, prio, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int yaml_add_ni_tunables(yaml_emitter_t *output,
struct lnet_ioctl_config_lnd_tunables *tunables,
struct lnet_dlc_network_descr *nw_descr)
{
char num[INT_STRING_LEN];
yaml_event_t event;
int rc = 0;
if (tunables->lt_cmn.lct_peer_timeout < 0 &&
tunables->lt_cmn.lct_peer_tx_credits <= 0 &&
tunables->lt_cmn.lct_peer_rtr_credits <= 0 &&
tunables->lt_cmn.lct_max_tx_credits <= 0)
goto skip_general_settings;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"tunables",
strlen("tunables"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
if (tunables->lt_cmn.lct_peer_timeout >= 0) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"peer_timeout",
strlen("peer_timeout"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
snprintf(num, sizeof(num), "%u",
tunables->lt_cmn.lct_peer_timeout);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)num,
strlen(num), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
}
if (tunables->lt_cmn.lct_peer_tx_credits > 0) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"peer_credits",
strlen("peer_credits"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
snprintf(num, sizeof(num), "%u",
tunables->lt_cmn.lct_peer_tx_credits);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)num,
strlen(num), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
}
if (tunables->lt_cmn.lct_peer_rtr_credits > 0) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"peer_buffer_credits",
strlen("peer_buffer_credits"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
snprintf(num, sizeof(num), "%u",
tunables->lt_cmn.lct_peer_rtr_credits);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)num,
strlen(num), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
}
if (tunables->lt_cmn.lct_max_tx_credits > 0) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"credits",
strlen("credits"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
snprintf(num, sizeof(num), "%u",
tunables->lt_cmn.lct_max_tx_credits);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)num,
strlen(num), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
}
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
skip_general_settings:
if (tunables->lt_tun.lnd_tun_u.lnd_sock.lnd_conns_per_peer > 0 ||
tunables->lt_tun.lnd_tun_u.lnd_sock.lnd_tos >= 0 ||
#ifdef HAVE_KFILND
tunables->lt_tun.lnd_tun_u.lnd_kfi.lnd_auth_key > 0 ||
tunables->lt_tun.lnd_tun_u.lnd_kfi.lnd_traffic_class_str[0] ||
#endif
tunables->lt_tun.lnd_tun_u.lnd_o2ib.lnd_conns_per_peer > 0 ||
tunables->lt_tun.lnd_tun_u.lnd_o2ib.lnd_tos >= 0) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"lnd tunables",
strlen("lnd tunables"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
#ifdef HAVE_KFILND
if (tunables->lt_tun.lnd_tun_u.lnd_kfi.lnd_auth_key > 0) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"auth_key",
strlen("auth_key"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
snprintf(num, sizeof(num), "%u",
tunables->lt_tun.lnd_tun_u.lnd_kfi.lnd_auth_key);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)num,
strlen(num), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
}
if (tunables->lt_tun.lnd_tun_u.lnd_kfi.lnd_traffic_class_str[0]) {
char *tc = &tunables->lt_tun.lnd_tun_u.lnd_kfi.lnd_traffic_class_str[0];
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"traffic_class",
strlen("traffic_class"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)tc,
strlen(tc), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
}
#endif
if (tunables->lt_tun.lnd_tun_u.lnd_sock.lnd_conns_per_peer > 0 ||
tunables->lt_tun.lnd_tun_u.lnd_o2ib.lnd_conns_per_peer > 0) {
int cpp = 0;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"conns_per_peer",
strlen("conns_per_peer"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
if (nw_descr->nw_id == LNET_NET_ANY)
cpp = tunables->lt_tun.lnd_tun_u.lnd_sock.lnd_conns_per_peer;
else if (LNET_NETTYP(nw_descr->nw_id) == SOCKLND)
cpp = tunables->lt_tun.lnd_tun_u.lnd_sock.lnd_conns_per_peer;
else if (LNET_NETTYP(nw_descr->nw_id) == O2IBLND)
cpp = tunables->lt_tun.lnd_tun_u.lnd_o2ib.lnd_conns_per_peer;
snprintf(num, sizeof(num), "%u", cpp);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)num,
strlen(num), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
}
if (tunables->lt_tun.lnd_tun_u.lnd_sock.lnd_tos >= 0 ||
tunables->lt_tun.lnd_tun_u.lnd_o2ib.lnd_tos >= 0) {
int tos = 0;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"tos",
strlen("tos"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
if (LNET_NETTYP(nw_descr->nw_id) == SOCKLND)
tos = tunables->lt_tun.lnd_tun_u.lnd_sock.lnd_tos;
else if (LNET_NETTYP(nw_descr->nw_id) == O2IBLND)
tos = tunables->lt_tun.lnd_tun_u.lnd_o2ib.lnd_tos;
snprintf(num, sizeof(num), "%d", tos);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)num,
strlen(num), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(output, &event);
if (rc == 0)
goto error;
}
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(output, &event);
}
error:
return rc;
}
static int
lnet_yaml_emit_cpt_sequence(yaml_emitter_t *emitter, struct cfs_expr_list *cpts)
{
yaml_event_t event;
__u32 *cpt_array;
int count, i;
int rc = 0;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"CPT",
strlen("CPT"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
if (!yaml_emitter_emit(emitter, &event))
return 0;
yaml_sequence_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_SEQ_TAG,
1,
YAML_FLOW_SEQUENCE_STYLE);
if (!yaml_emitter_emit(emitter, &event))
return 0;
count = cfs_expr_list_values(cpts, LNET_MAX_SHOW_NUM_CPT, &cpt_array);
for (i = 0; i < count; i++) {
char core[INT_STRING_LEN];
snprintf(core, sizeof(core), "%u", cpt_array[i]);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)core,
strlen(core), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
if (!yaml_emitter_emit(emitter, &event))
goto out_free_expr;
}
yaml_sequence_end_event_initialize(&event);
if (!yaml_emitter_emit(emitter, &event))
goto out_free_expr;
rc = 1;
out_free_expr:
if (count > 0)
free(cpt_array);
return rc;
}
static int yaml_lnet_config_ni(char *net_id, char *ip2net,
struct lnet_dlc_network_descr *nw_descr,
struct lnet_ioctl_config_lnd_tunables *tunables,
int healthv, struct cfs_expr_list *global_cpts,
int version, int flags, FILE *fp)
{
struct lnet_dlc_intf_descr *intf;
struct nl_sock *sk = NULL;
const char *msg = NULL;
yaml_emitter_t output;
yaml_parser_t reply;
yaml_event_t event;
int rc;
if (!(flags & NLM_F_DUMP) && !ip2net && (!nw_descr || nw_descr->nw_id == 0)) {
fprintf(stdout, "missing mandatory parameters in NI config: '%s'\n",
(!nw_descr) ? "network , interface" :
(nw_descr->nw_id == 0) ? "network" : "interface");
return -EINVAL;
}
if ((flags == NLM_F_CREATE) && !ip2net && list_empty(&nw_descr->nw_intflist)) {
fprintf(stdout, "creating a local NI needs at least one interface\n");
return -EINVAL;
}
if ((flags == NLM_F_REPLACE) && list_empty(&nw_descr->nw_intflist)) {
fprintf(stdout, "updating a local NI needs at least one address\n");
return -EINVAL;
}
/* Create Netlink emitter to send request to kernel */
sk = nl_socket_alloc();
if (!sk)
return -EOPNOTSUPP;
/* Setup parser to receive Netlink packets */
rc = yaml_parser_initialize(&reply);
if (rc == 0) {
nl_socket_free(sk);
return -EOPNOTSUPP;
}
rc = yaml_parser_set_input_netlink(&reply, sk, false);
if (rc == 0) {
msg = yaml_parser_get_reader_error(&reply);
goto free_reply;
}
/* Create Netlink emitter to send request to kernel */
rc = yaml_emitter_initialize(&output);
if (rc == 0) {
msg = "failed to initialize emitter";
goto free_reply;
}
rc = yaml_emitter_set_output_netlink(&output, sk, LNET_GENL_NAME,
version, LNET_CMD_NETS, flags);
if (rc == 0)
goto emitter_error;
yaml_emitter_open(&output);
yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"net",
strlen("net"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
if (net_id || ip2net) {
char *key = net_id ? "net type" : "ip2net";
char *value = net_id ? net_id : ip2net;
yaml_sequence_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_SEQ_TAG,
1, YAML_ANY_SEQUENCE_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)key,
strlen(key),
1, 0, YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)value,
strlen(value), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
} else {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"",
strlen(""), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
goto no_net_id;
}
if (!nw_descr || list_empty(&nw_descr->nw_intflist))
goto skip_intf;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"local NI(s)",
strlen("local NI(s)"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_sequence_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_SEQ_TAG,
1, YAML_ANY_SEQUENCE_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
list_for_each_entry(intf, &nw_descr->nw_intflist,
intf_on_network) {
struct cfs_expr_list *cpt_expr = NULL;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
/* Use NI addresses instead of interface */
if (strchr(intf->intf_name, '@') ||
(strcmp(intf->intf_name, "<?>") == 0 &&
- flags == NLM_F_REPLACE)) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"nid",
strlen("nid"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)intf->intf_name,
strlen(intf->intf_name), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
} else {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"interfaces",
strlen("interfaces"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"0",
strlen("0"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)intf->intf_name,
strlen(intf->intf_name), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
}
if (tunables) {
rc = yaml_add_ni_tunables(&output, tunables, nw_descr);
if (rc == 0)
goto emitter_error;
}
if (flags == NLM_F_REPLACE && healthv > -1) {
char health[INT_STRING_LEN];
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"health stats",
strlen("health stats"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
/* Setup all mappings for data related to the 'health stats' */
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_BLOCK_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"health value",
strlen("health value"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
snprintf(health, sizeof(health), "%d", healthv);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)health,
strlen(health), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
}
if (intf->cpt_expr)
cpt_expr = intf->cpt_expr;
else if (global_cpts)
cpt_expr = global_cpts;
if (cpt_expr) {
rc = lnet_yaml_emit_cpt_sequence(&output, cpt_expr);
if (rc == 0)
goto emitter_error;
}
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
}
yaml_sequence_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
skip_intf:
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_sequence_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
no_net_id:
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_document_end_event_initialize(&event, 0);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
rc = yaml_emitter_close(&output);
emitter_error:
if (rc == 0) {
yaml_emitter_log_error(&output, stderr);
rc = -EINVAL;
} else {
yaml_document_t errmsg;
rc = yaml_parser_load(&reply, &errmsg);
if (rc == 1 && (flags & NLM_F_DUMP)) {
yaml_emitter_t debug;
rc = yaml_emitter_initialize(&debug);
if (rc == 1) {
yaml_emitter_set_indent(&debug,
LNET_DEFAULT_INDENT);
yaml_emitter_set_output_file(&debug, fp);
rc = yaml_emitter_dump(&debug, &errmsg);
}
yaml_emitter_delete(&debug);
} else {
msg = yaml_parser_get_reader_error(&reply);
}
yaml_document_delete(&errmsg);
}
yaml_emitter_cleanup(&output);
free_reply:
if (rc == 0) {
yaml_lnet_print_error(flags, "net", msg);
rc = -EINVAL;
}
yaml_parser_cleanup(&reply);
nl_socket_free(sk);
return rc == 1 ? 0 : rc;
}
static int kfi_intflist2cxi(struct list_head *nw_intflist)
{
struct lnet_dlc_intf_descr *intf;
int rc;
list_for_each_entry(intf, nw_intflist, intf_on_network) {
rc = lustre_lnet_kfi_intf2cxi(intf);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
fprintf(stderr, "couldn't query kfi intf %s",
intf->intf_name);
return rc;
}
}
return LUSTRE_CFG_RC_NO_ERR;
}
static int jt_add_ni(int argc, char **argv)
{
char *ip2net = NULL;
long int pto = -1, pc = -1, pbc = -1, cre = -1, cpp = -1, auth_key = -1;
char *traffic_class = NULL;
long int tos = -1;
struct cYAML *err_rc = NULL;
int rc, opt, cpt_rc = -1;
struct lnet_dlc_network_descr nw_descr;
struct cfs_expr_list *global_cpts = NULL;
struct lnet_ioctl_config_lnd_tunables tunables;
bool found = false;
bool skip_mr_route_setup = false;
const char *const short_options = "a:b:c:i:k:m:n:p:r:s:t:T:";
static const struct option long_options[] = {
{ .name = "auth-key", .has_arg = required_argument, .val = 'a' },
{ .name = "peer-buffer-credits",
.has_arg = required_argument, .val = 'b' },
{ .name = "peer-credits", .has_arg = required_argument, .val = 'c' },
{ .name = "if", .has_arg = required_argument, .val = 'i' },
{ .name = "skip-mr-route-setup",
.has_arg = no_argument, .val = 'k' },
{ .name = "conns-per-peer",
.has_arg = required_argument, .val = 'm' },
{ .name = "net", .has_arg = required_argument, .val = 'n' },
{ .name = "nid", .has_arg = required_argument, .val = 'N' },
{ .name = "ip2net", .has_arg = required_argument, .val = 'p' },
{ .name = "credits", .has_arg = required_argument, .val = 'r' },
{ .name = "cpt", .has_arg = required_argument, .val = 's' },
{ .name = "peer-timeout", .has_arg = required_argument, .val = 't' },
{ .name = "traffic-class", .has_arg = required_argument, .val = 'T' },
{ .name = "tos", .has_arg = required_argument, .val = 'S' },
{ .name = NULL } };
bool nid_request = false;
char *net_id = NULL;
memset(&tunables, 0, sizeof(tunables));
lustre_lnet_init_nw_descr(&nw_descr);
rc = check_cmd(net_cmds, "net", "add", 0, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'a':
rc = parse_long(optarg, &auth_key);
if (rc != 0) {
/* ignore option */
auth_key = -1;
continue;
}
break;
case 'b':
rc = parse_long(optarg, &pbc);
if (rc != 0) {
/* ignore option */
pbc = -1;
continue;
}
break;
case 'c':
rc = parse_long(optarg, &pc);
if (rc != 0) {
/* ignore option */
pc = -1;
continue;
}
break;
case 'i':
rc = lustre_lnet_parse_interfaces(optarg, &nw_descr);
if (rc != 0) {
cYAML_build_error(-1, -1, "ni", "add",
"bad interface list",
&err_rc);
goto failed;
}
break;
case 'k':
skip_mr_route_setup = true;
break;
case 'm':
rc = parse_long(optarg, &cpp);
if (rc != 0) {
/* ignore option */
cpp = -1;
continue;
}
break;
case 'n':
nw_descr.nw_id = libcfs_str2net(optarg);
net_id = optarg;
break;
case 'N':
rc = lustre_lnet_parse_interfaces(optarg, &nw_descr);
if (rc != 0) {
cYAML_build_error(-1, -1, "ni", "add",
"bad NID list",
&err_rc);
goto failed;
}
nid_request = true;
break;
case 'p':
ip2net = optarg;
break;
case 'r':
rc = parse_long(optarg, &cre);
if (rc != 0) {
/* ignore option */
cre = -1;
continue;
}
break;
case 's':
cpt_rc = cfs_expr_list_parse(optarg,
strlen(optarg), 0,
UINT_MAX, &global_cpts);
break;
case 't':
rc = parse_long(optarg, &pto);
if (rc != 0) {
/* ignore option */
pto = -1;
continue;
}
break;
case 'T':
traffic_class = optarg;
if (strlen(traffic_class) == 0 ||
strlen(traffic_class) >= LNET_MAX_STR_LEN) {
cYAML_build_error(-1, -1, "ni", "add",
"Invalid traffic-class argument",
&err_rc);
rc = LUSTRE_CFG_RC_BAD_PARAM;
goto failed;
}
break;
case 'S':
rc = parse_long(optarg, &tos);
if (rc || tos < -1 || tos > 0xff) {
cYAML_build_error(-1, -1, "ni", "add",
"Invalid ToS argument",
&err_rc);
rc = LUSTRE_CFG_RC_BAD_PARAM;
goto failed;
}
break;
case '?':
print_help(net_cmds, "net", "add");
default:
return 0;
}
}
if (nid_request) {
if (net_id) {
fprintf(stdout, "--net is invalid with --nid option\n");
return -EINVAL;
}
net_id = libcfs_net2str(nw_descr.nw_id);
}
#ifdef HAVE_KFILND
if (auth_key > 0 && LNET_NETTYP(nw_descr.nw_id) == KFILND) {
tunables.lt_tun.lnd_tun_u.lnd_kfi.lnd_auth_key = auth_key;
found = true;
}
if (traffic_class && LNET_NETTYP(nw_descr.nw_id) == KFILND &&
strlen(traffic_class) < LNET_MAX_STR_LEN) {
strcpy(&tunables.lt_tun.lnd_tun_u.lnd_kfi.lnd_traffic_class_str[0],
traffic_class);
found = true;
}
/* kfi can convert linux network device names to cxi devices */
if (LNET_NETTYP(nw_descr.nw_id) == KFILND) {
rc = kfi_intflist2cxi(&nw_descr.nw_intflist);
if (rc)
return rc;
}
#endif
if (LNET_NETTYP(nw_descr.nw_id) == SOCKLND) {
tunables.lt_tun.lnd_tun_u.lnd_sock.lnd_tos = tos;
found = true;
} else if (LNET_NETTYP(nw_descr.nw_id) == O2IBLND) {
tunables.lt_tun.lnd_tun_u.lnd_o2ib.lnd_tos = tos;
found = true;
}
if (LNET_NETTYP(nw_descr.nw_id) == SOCKLND && (cpp > -1)) {
tunables.lt_tun.lnd_tun_u.lnd_sock.lnd_conns_per_peer = cpp;
found = true;
} else if (LNET_NETTYP(nw_descr.nw_id) == O2IBLND && (cpp > -1)) {
tunables.lt_tun.lnd_tun_u.lnd_o2ib.lnd_conns_per_peer = cpp;
found = true;
}
tunables.lt_cmn.lct_peer_timeout = pto;
tunables.lt_cmn.lct_peer_tx_credits = pc;
tunables.lt_cmn.lct_peer_rtr_credits = pbc;
tunables.lt_cmn.lct_max_tx_credits = cre;
if (pto >= 0 || pc > 0 || pbc > 0 || cre > 0)
found = true;
if (found && LNET_NETTYP(nw_descr.nw_id) == O2IBLND)
tunables.lt_tun.lnd_tun_u.lnd_o2ib.lnd_map_on_demand = UINT_MAX;
rc = yaml_lnet_config_ni(net_id, ip2net, &nw_descr,
found ? &tunables : NULL, -1,
(cpt_rc == 0) ? global_cpts : NULL,
LNET_GENL_VERSION, NLM_F_CREATE, stdout);
if (rc <= 0) {
if (rc == -EOPNOTSUPP)
goto old_api;
if (global_cpts != NULL)
cfs_expr_list_free(global_cpts);
if (rc == 0 && !skip_mr_route_setup)
rc = lustre_lnet_setup_mrrouting(&err_rc);
return rc;
}
old_api:
rc = lustre_lnet_config_ni(&nw_descr,
(cpt_rc == 0) ? global_cpts: NULL,
ip2net, (found) ? &tunables : NULL,
cpp, &err_rc);
if (global_cpts != NULL)
cfs_expr_list_free(global_cpts);
failed:
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
if (rc == LUSTRE_CFG_RC_NO_ERR && !skip_mr_route_setup) {
err_rc = NULL;
rc = lustre_lnet_setup_mrrouting(&err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
}
return rc;
}
static int jt_del_route(int argc, char **argv)
{
char *network = NULL, *gateway = NULL;
struct cYAML *err_rc = NULL;
int rc, opt;
const char *const short_options = "n:g:";
static const struct option long_options[] = {
{ .name = "net", .has_arg = required_argument, .val = 'n' },
{ .name = "gateway", .has_arg = required_argument, .val = 'g' },
{ .name = NULL }
};
rc = check_cmd(route_cmds, "route", "del", 0, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'n':
network = optarg;
break;
case 'g':
gateway = optarg;
break;
case '?':
print_help(route_cmds, "route", "del");
default:
return 0;
}
}
rc = yaml_lnet_route(network, gateway, -1, -1, LNET_GENL_VERSION,
0, stdout);
if (rc <= 0) {
if (rc == -EOPNOTSUPP)
goto old_api;
return rc;
}
old_api:
rc = lustre_lnet_del_route(network, gateway, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_del_ni(int argc, char **argv)
{
struct cYAML *err_rc = NULL;
int rc, opt;
struct lnet_dlc_network_descr nw_descr;
const char *const short_options = "n:i:";
static const struct option long_options[] = {
{ .name = "net", .has_arg = required_argument, .val = 'n' },
{ .name = "if", .has_arg = required_argument, .val = 'i' },
{ .name = "nid", .has_arg = required_argument, .val = 'N' },
{ .name = NULL } };
bool nid_request = false;
char *net_id = NULL;
rc = check_cmd(net_cmds, "net", "del", 0, argc, argv);
if (rc)
return rc;
lustre_lnet_init_nw_descr(&nw_descr);
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'n':
nw_descr.nw_id = libcfs_str2net(optarg);
net_id = optarg;
break;
case 'N':
rc = lustre_lnet_parse_interfaces(optarg, &nw_descr);
if (rc != 0) {
cYAML_build_error(-1, -1, "ni", "del",
"bad NID list",
&err_rc);
goto out;
}
nid_request = true;
break;
case 'i':
rc = lustre_lnet_parse_interfaces(optarg, &nw_descr);
if (rc != 0) {
cYAML_build_error(-1, -1, "ni", "add",
"bad interface list",
&err_rc);
goto out;
}
break;
case '?':
print_help(net_cmds, "net", "del");
default:
return 0;
}
}
if (nid_request) {
if (net_id) {
fprintf(stdout, "--net is invalid with --nid option\n");
return -EINVAL;
}
net_id = libcfs_net2str(nw_descr.nw_id);
}
#ifdef HAVE_KFILND
/* kfi can convert linux network device names to cxi devices */
if (LNET_NETTYP(nw_descr.nw_id) == KFILND) {
rc = kfi_intflist2cxi(&nw_descr.nw_intflist);
if (rc)
return rc;
}
#endif
rc = yaml_lnet_config_ni(net_id, NULL, &nw_descr, NULL, -1, NULL,
LNET_GENL_VERSION, 0, stdout);
if (rc <= 0) {
if (rc != -EOPNOTSUPP)
return rc;
}
rc = lustre_lnet_del_ni(&nw_descr, -1, &err_rc);
out:
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_show_route(int argc, char **argv)
{
char *network = NULL, *gateway = NULL;
long int hop = -1, prio = -1;
int detail = 0, rc, opt;
struct cYAML *err_rc = NULL, *show_rc = NULL;
const char *const short_options = "c:n:g:p:v";
static const struct option long_options[] = {
{ .name = "net", .has_arg = required_argument, .val = 'n' },
{ .name = "gateway", .has_arg = required_argument, .val = 'g' },
{ .name = "hop-count", .has_arg = required_argument, .val = 'c' },
{ .name = "hop", .has_arg = required_argument, .val = 'c' },
{ .name = "priority", .has_arg = required_argument, .val = 'p' },
{ .name = "verbose", .has_arg = no_argument, .val = 'v' },
{ .name = NULL }
};
rc = check_cmd(route_cmds, "route", "show", 0, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'n':
network = optarg;
break;
case 'g':
gateway = optarg;
break;
case 'c':
rc = parse_long(optarg, &hop);
if (rc != 0) {
/* ignore option */
hop = -1;
continue;
}
break;
case 'p':
rc = parse_long(optarg, &prio);
if (rc != 0) {
/* ignore option */
prio = -1;
continue;
}
break;
case 'v':
detail = 1;
break;
case '?':
print_help(route_cmds, "route", "show");
default:
return 0;
}
}
rc = yaml_lnet_route(network, gateway, hop, prio,
detail, NLM_F_DUMP, stdout);
if (rc <= 0) {
if (rc == -EOPNOTSUPP)
goto old_api;
return rc;
}
old_api:
rc = lustre_lnet_show_route(network, gateway, hop, prio,
detail ? 1 : 0, -1,
&show_rc, &err_rc, false);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
else if (show_rc)
cYAML_print_tree(show_rc);
cYAML_free_tree(err_rc);
cYAML_free_tree(show_rc);
return rc;
}
static int yaml_lnet_config_ni_value(int healthv, bool all, char *nidstr,
int cpp, int lnd_timeout, __u32 net,
int seq_no, struct cYAML **err_rc)
{
struct lnet_ioctl_config_lnd_tunables tunables;
struct lnet_dlc_network_descr nw_descr;
char *net_id = "<255:65535>"; /* LNET_NET_ANY */
int rc = 0;
/* For NI you can't have both setting all NIDs and a requested NID */
if (all && nidstr)
return -EINVAL;
if (lnd_timeout > -1)
return lustre_lnet_config_lnd_timeout(lnd_timeout, net,
-1, err_rc);
if (cpp == -1 && healthv == -1)
return 0;
if (nidstr) {
net_id = strchr(nidstr, '@');
if (!net_id)
return -EINVAL;
net_id++;
}
lustre_lnet_init_nw_descr(&nw_descr);
nw_descr.nw_id = libcfs_str2net(net_id);
rc = lustre_lnet_parse_interfaces(nidstr ? nidstr : "<?>", &nw_descr);
if (rc != LUSTRE_CFG_RC_NO_ERR)
return -EINVAL;
memset(&tunables, 0, sizeof(tunables));
tunables.lt_cmn.lct_peer_timeout = -1;
if (nw_descr.nw_id == LNET_NET_ANY && cpp > -1)
tunables.lt_tun.lnd_tun_u.lnd_sock.lnd_conns_per_peer = cpp;
else if (LNET_NETTYP(nw_descr.nw_id) == SOCKLND && (cpp > -1))
tunables.lt_tun.lnd_tun_u.lnd_sock.lnd_conns_per_peer = cpp;
else if (LNET_NETTYP(nw_descr.nw_id) == O2IBLND && (cpp > -1))
tunables.lt_tun.lnd_tun_u.lnd_o2ib.lnd_conns_per_peer = cpp;
rc = yaml_lnet_config_ni(net_id, NULL, &nw_descr,
cpp != -1 ? &tunables : NULL, healthv, NULL,
LNET_GENL_VERSION, NLM_F_REPLACE, stdout);
if (rc <= 0) {
if (rc == -EOPNOTSUPP)
goto old_api;
return rc;
}
old_api:
if (cpp > -1)
rc = lustre_lnet_config_ni_conns_per_peer(cpp, all, nidstr,
-1, err_rc);
if (healthv > -1)
rc = lustre_lnet_config_ni_healthv(healthv, all, nidstr,
-1, err_rc);
return rc;
}
static int yaml_lnet_peer_display(yaml_parser_t *reply, bool list_only)
{
yaml_emitter_t debug;
int rc;
rc = yaml_emitter_initialize(&debug);
if (rc == 0)
goto out_err;
yaml_emitter_set_indent(&debug, 6);
yaml_emitter_set_output_file(&debug, stdout);
if (list_only) {
bool done = false;
while (!done) {
yaml_event_t event;
char *value;
rc = yaml_parser_parse(reply, &event);
if (rc == 0)
goto report_reply_error;
if (event.type != YAML_SCALAR_EVENT)
goto merge_event;
value = (char *)event.data.scalar.value;
if (strcmp(value, "peer") == 0) {
yaml_event_delete(&event);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"peer list",
strlen("peer list"),
1, 0,
YAML_PLAIN_SCALAR_STYLE);
} else if (strcmp(value, "primary nid") == 0) {
yaml_event_delete(&event);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"nid",
strlen("nid"),
1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&debug, &event);
if (rc == 0)
break;
/* Now print NID address */
rc = yaml_parser_parse(reply, &event);
if (rc == 0)
goto report_reply_error;
rc = yaml_emitter_emit(&debug, &event);
if (rc == 0)
break;
/* skip ALL peer_ni info */
while (event.type != YAML_SEQUENCE_END_EVENT) {
rc = yaml_parser_parse(reply, &event);
if (rc == 0)
goto report_reply_error;
}
/* But keep sequence end event */
rc = yaml_parser_parse(reply, &event);
if (rc == 0)
goto report_reply_error;
if (event.type == YAML_SEQUENCE_END_EVENT) {
yaml_event_delete(&event);
rc = yaml_parser_parse(reply, &event);
if (rc == 0)
goto report_reply_error;
}
}
merge_event:
rc = yaml_emitter_emit(&debug, &event);
if (rc == 0)
break;
done = (event.type == YAML_DOCUMENT_END_EVENT);
}
} else {
yaml_document_t errmsg;
rc = yaml_parser_load(reply, &errmsg);
if (rc == 1)
rc = yaml_emitter_dump(&debug, &errmsg);
yaml_document_delete(&errmsg);
}
out_err:
if (rc == 0) {
yaml_emitter_log_error(&debug, stderr);
rc = -EINVAL; /* Avoid reporting as reply error */
}
report_reply_error:
yaml_emitter_delete(&debug);
return rc;
}
static int yaml_lnet_peer(char *prim_nid, char *nidstr, bool disable_mr,
int health_value, int state, bool list_only,
int version, int flags, FILE *fp)
{
struct nl_sock *sk = NULL;
const char *msg = NULL;
yaml_emitter_t output;
yaml_parser_t reply;
yaml_event_t event;
int rc;
/* Create Netlink emitter to send request to kernel */
sk = nl_socket_alloc();
if (!sk)
return -EOPNOTSUPP;
/* Setup parser to receive Netlink packets */
rc = yaml_parser_initialize(&reply);
if (rc == 0) {
nl_socket_free(sk);
return -EOPNOTSUPP;
}
rc = yaml_parser_set_input_netlink(&reply, sk, false);
if (rc == 0) {
msg = yaml_parser_get_reader_error(&reply);
goto free_reply;
}
/* Create Netlink emitter to send request to kernel */
rc = yaml_emitter_initialize(&output);
if (rc == 0) {
msg = "failed to initialize emitter";
goto free_reply;
}
rc = yaml_emitter_set_output_netlink(&output, sk, LNET_GENL_NAME,
version, LNET_CMD_PEERS, flags);
if (rc == 0)
goto emitter_error;
yaml_emitter_open(&output);
yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"peer",
strlen("peer"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
if (prim_nid) {
yaml_sequence_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_SEQ_TAG,
1,
YAML_BLOCK_SEQUENCE_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1,
YAML_BLOCK_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"primary nid",
strlen("primary nid"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)prim_nid,
strlen(prim_nid), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
if (disable_mr) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"Multi-Rail",
strlen("Multi-Rail"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_BOOL_TAG,
(yaml_char_t *)"False",
strlen("False"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
}
if (state != -1) {
char peer_state[INT_STRING_LEN];
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"peer state",
strlen("peer state"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
snprintf(peer_state, sizeof(peer_state), "%d", state);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)peer_state,
strlen(peer_state), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
}
if (!nidstr && health_value == -1)
goto skip_peer_nis;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"peer ni",
strlen("peer ni"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_sequence_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_SEQ_TAG,
1, YAML_BLOCK_SEQUENCE_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
if (nidstr) {
struct nid_node head, *entry;
int count = 0;
/* If we have LNET_ANY_NID and its NLM_F_REPLACE we
* treat it as the all flag case for lnetctl peer set
*/
if (strcmp(nidstr, "<?>") == 0) {
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_BLOCK_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"nid",
strlen("nid"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)nidstr,
strlen(nidstr), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
goto handle_health;
}
NL_INIT_LIST_HEAD(&head.children);
nl_init_list_head(&head.list);
rc = lustre_lnet_parse_nid_range(&head, nidstr, &msg);
if (rc < 0) {
fprintf(stdout, "can't parse nidrange: \"%s\"\n", nidstr);
lustre_lnet_free_list(&head);
yaml_emitter_cleanup(&output);
errno = rc;
rc = 0;
goto free_reply;
}
if (nl_list_empty(&head.children)) {
lustre_lnet_free_list(&head);
yaml_emitter_cleanup(&output);
msg = "Unable to parse nidlist: did not expand to any nids";
errno = -ENOENT;
rc = 0;
goto free_reply;
}
rc = 1; /* one means its working */
nl_list_for_each_entry(entry, &head.children, list) {
char *nid = entry->nidstr;
if (count++ > LNET_MAX_NIDS_PER_PEER) {
lustre_lnet_free_list(&head);
yaml_emitter_cleanup(&output);
msg = "Unable to parse nidlist: specifies more NIDs than allowed";
errno = -E2BIG;
rc = 0;
goto free_reply;
}
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_BLOCK_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"nid",
strlen("nid"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)nid,
strlen(nid), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
}
lustre_lnet_free_list(&head);
}
handle_health:
if (health_value >= 0) {
char health[INT_STRING_LEN];
/* Create the mapping for 'health stats'. The value field for
* the mapping is not provided so its treated as a empty string.
*/
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_BLOCK_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"health stats",
strlen("health stats"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
/* Setup all mappings for data related to the 'health stats' */
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_BLOCK_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"health value",
strlen("health value"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
snprintf(health, sizeof(health), "%d", health_value);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)health,
strlen(health), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
}
yaml_sequence_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
skip_peer_nis:
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_sequence_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
} else {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"",
strlen(""), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
}
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_document_end_event_initialize(&event, 0);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
rc = yaml_emitter_close(&output);
emitter_error:
if (rc == 0) {
yaml_emitter_log_error(&output, stderr);
rc = -EINVAL;
} else {
rc = yaml_lnet_peer_display(&reply, list_only);
if (rc == 0) {
msg = yaml_parser_get_reader_error(&reply);
/* If we didn't find any peers just be silent */
if (msg && strcmp(msg, "No peers found") == 0)
rc = 1;
}
}
yaml_emitter_cleanup(&output);
free_reply:
if (rc == 0) {
yaml_lnet_print_error(flags, "peer", msg);
rc = -EINVAL;
}
yaml_parser_cleanup(&reply);
nl_socket_free(sk);
return rc == 1 ? 0 : rc;
}
static int yaml_lnet_config_peer_ni_healthv(int healthv, bool all,
char *lpni_nid, int state,
int seq_no, struct cYAML **err_rc)
{
int rc;
rc = yaml_lnet_peer(lpni_nid ? lpni_nid : "<?>", all ? "<?>" : NULL,
false, healthv, state, false, LNET_GENL_VERSION,
NLM_F_REPLACE, stdout);
if (rc <= 0) {
if (rc == -EOPNOTSUPP)
goto old_api;
return rc;
}
old_api:
if (state == -1)
rc = lustre_lnet_config_peer_ni_healthv(healthv, all, lpni_nid,
seq_no, err_rc);
else
rc = lustre_lnet_set_peer_state(state, lpni_nid, -1, err_rc);
return rc;
}
static int set_value_helper(int argc, char **argv, int cmd)
{
char *nidstr = NULL;
long healthv = -1;
__u32 net = 0;
int lnd_timeout = -1;
bool all = false;
long state = -1;
long cpp = -1;
int seq_no = -1;
int rc, opt;
struct cYAML *err_rc = NULL;
char err_str[LNET_MAX_STR_LEN] = "";
static const struct option long_options[] = {
{ .val = 'a', .name = "all", .has_arg = no_argument },
{ .val = 'i', .name = "net", .has_arg = required_argument },
{ .val = 'l', .name = "lnd-timeout",
.has_arg = required_argument },
{ .val = 'm', .name = "conns-per-peer",
.has_arg = required_argument },
{ .val = 'n', .name = "nid", .has_arg = required_argument },
{ .val = 's', .name = "state", .has_arg = required_argument },
{ .val = 't', .name = "health", .has_arg = required_argument },
{ .name = NULL }
};
while ((opt = getopt_long(argc, argv, "ai:l:m:n:s:t:",
long_options, NULL)) != -1) {
switch (opt) {
case 'a':
all = true;
break;
case 'i':
net = libcfs_str2net(optarg);
if (net == LNET_NET_ANY) {
rc = LUSTRE_CFG_RC_BAD_PARAM;
snprintf(err_str, sizeof(err_str),
"\"Invalid network type: %s\"",
optarg);
goto out;
}
break;
case 'l':
lnd_timeout = atoi(optarg);
if (lnd_timeout < 0) {
rc = LUSTRE_CFG_RC_BAD_PARAM;
snprintf(err_str, sizeof(err_str),
"\"Invalid LND timeout value '%s', must be >= 0\"",
optarg);
goto out;
}
break;
case 'm':
if (cmd != LNET_CMD_NETS ||
parse_long(optarg, &cpp) != 0)
cpp = -1;
break;
case 'n':
nidstr = optarg;
break;
case 's':
if (cmd != LNET_CMD_PEERS ||
parse_long(optarg, &state) != 0)
state = -1;
break;
case 't':
if (parse_long(optarg, &healthv) != 0)
healthv = -1;
break;
case '?':
rc = LUSTRE_CFG_RC_BAD_PARAM;
snprintf(err_str, sizeof(err_str),
"\"Invalid option or missing argument\"");
goto out;
default:
return 0;
}
}
if (lnd_timeout >= 0 && net == 0) {
rc = LUSTRE_CFG_RC_BAD_PARAM;
snprintf(err_str, sizeof(err_str),
"\"Specified --lnd-timeout without --net option\"");
goto out;
}
if (cmd == LNET_CMD_PEERS)
rc = yaml_lnet_config_peer_ni_healthv(healthv, all, nidstr,
state, seq_no, &err_rc);
else
rc = yaml_lnet_config_ni_value(healthv, all, nidstr, cpp,
lnd_timeout, net, seq_no,
&err_rc);
out:
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_build_error(rc, -1, "net", "set", err_str, &err_rc);
cYAML_print_tree2file(stderr, err_rc);
}
cYAML_free_tree(err_rc);
return rc;
}
static int jt_set_ni_value(int argc, char **argv)
{
int rc = check_cmd(net_cmds, "net", "set", 0, argc, argv);
if (rc)
return rc;
return set_value_helper(argc, argv, LNET_CMD_NETS);
}
static int jt_set_peer_ni_value(int argc, char **argv)
{
int rc = check_cmd(peer_cmds, "peer", "set", 0, argc, argv);
if (rc)
return rc;
return set_value_helper(argc, argv, LNET_CMD_PEERS);
}
static int yaml_debug_recovery(enum lnet_health_type type)
{
yaml_parser_t setup, reply;
yaml_document_t results;
yaml_emitter_t output;
const char *msg = NULL;
struct nl_sock *sk;
char *config;
int rc = 0;
switch (type) {
case LNET_HEALTH_TYPE_LOCAL_NI:
config = "dbg-recov:\n queue_type: 0\n";
break;
case LNET_HEALTH_TYPE_PEER_NI:
config = "dbg-recov:\n queue_type: 1\n";
break;
default:
rc = -EINVAL;
break;
}
if (rc < 0)
return rc;
/* Initialize configuration parser */
rc = yaml_parser_initialize(&setup);
if (rc == 0) {
yaml_parser_log_error(&setup, stderr, NULL);
yaml_parser_delete(&setup);
return -EOPNOTSUPP;
}
yaml_parser_set_input_string(&setup, (unsigned char *)config,
strlen(config));
rc = yaml_parser_load(&setup, &results);
if (rc == 0) {
yaml_parser_log_error(&setup, stderr, NULL);
yaml_parser_delete(&setup);
return -EOPNOTSUPP;
}
yaml_parser_delete(&setup);
/* Create Netlink emitter to send request to kernel */
sk = nl_socket_alloc();
if (!sk) {
yaml_document_delete(&results);
return -EOPNOTSUPP;
}
/* Setup parser to recieve Netlink packets */
rc = yaml_parser_initialize(&reply);
if (rc == 0) {
yaml_document_delete(&results);
nl_socket_free(sk);
return -EOPNOTSUPP;
}
rc = yaml_parser_set_input_netlink(&reply, sk, false);
if (rc == 0)
goto free_reply;
yaml_emitter_initialize(&output);
rc = yaml_emitter_set_output_netlink(&output, sk, LNET_GENL_NAME,
LNET_GENL_VERSION,
LNET_CMD_DBG_RECOV, NLM_F_DUMP);
if (rc == 1) /* 1 is success */
rc = yaml_emitter_dump(&output, &results);
if (rc == 0) {
yaml_emitter_log_error(&output, stderr);
rc = -EINVAL;
} else {
yaml_document_t errmsg;
rc = yaml_parser_load(&reply, &errmsg);
if (rc == 1) {
yaml_emitter_t debug;
rc = yaml_emitter_initialize(&debug);
if (rc == 1) {
yaml_emitter_set_indent(&debug,
LNET_DEFAULT_INDENT);
yaml_emitter_set_output_file(&debug,
stdout);
rc = yaml_emitter_dump(&debug, &errmsg);
}
yaml_emitter_delete(&debug);
} else {
msg = yaml_parser_get_reader_error(&reply);
if (errno == -ENOENT)
rc = 1;
}
yaml_document_delete(&errmsg);
}
yaml_emitter_cleanup(&output);
free_reply:
if (rc == 0) {
if (!msg)
msg = yaml_parser_get_reader_error(&reply);
fprintf(stdout, "Operation failed: %s\n", msg);
}
yaml_parser_cleanup(&reply);
nl_socket_free(sk);
return rc == 1 ? 0 : rc;
}
static int jt_show_recovery(int argc, char **argv)
{
int rc, opt;
struct cYAML *err_rc = NULL, *show_rc = NULL;
const char *const short_options = "lp";
static const struct option long_options[] = {
{ .name = "local", .has_arg = no_argument, .val = 'l' },
{ .name = "peer", .has_arg = no_argument, .val = 'p' },
{ .name = NULL }
};
enum lnet_health_type type = -1;
rc = check_cmd(debug_cmds, "debug", "recovery", 0, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'l':
type = LNET_HEALTH_TYPE_LOCAL_NI;
break;
case 'p':
type = LNET_HEALTH_TYPE_PEER_NI;
break;
default:
return 0;
}
}
rc = yaml_debug_recovery(type);
if (rc <= 0) {
if (rc == -EOPNOTSUPP)
goto old_api;
return rc;
}
old_api:
switch (type) {
case LNET_HEALTH_TYPE_LOCAL_NI:
rc = lustre_lnet_show_local_ni_recovq(-1, &show_rc, &err_rc);
break;
case LNET_HEALTH_TYPE_PEER_NI:
rc = lustre_lnet_show_peer_ni_recovq(-1, &show_rc, &err_rc);
break;
default:
rc = LUSTRE_CFG_RC_BAD_PARAM;
break;
}
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
else if (show_rc)
cYAML_print_tree(show_rc);
cYAML_free_tree(err_rc);
cYAML_free_tree(show_rc);
return rc;
}
static int jt_debug_nidlist(int argc, char **argv)
{
int rc;
if (argc < 2) {
fprintf(stderr, "Missing nidlist argument\n");
return -EINVAL;
} else if (argc == 2) {
rc = lustre_lnet_debug_nidlist(argv[1], NULL);
} else if (argc == 3) {
rc = lustre_lnet_debug_nidlist(argv[1], argv[2]);
} else {
fprintf(stderr, "Too many arguments\n");
return -EINVAL;
}
return rc;
}
static int jt_show_peer_debug_info(int argc, char **argv)
{
int rc, opt;
struct cYAML *err_rc = NULL;
char *peer_nid = optarg;
const char *const short_opts = "k";
const struct option long_opts[] = {
{ .name = "nid", .has_arg = required_argument, .val = 'k' },
{ .name = NULL } };
rc = check_cmd(debug_cmds, "debug", "peer", 0, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_opts,
long_opts, NULL)) != -1) {
switch (opt) {
case 'k':
peer_nid = optarg;
break;
default:
return 0;
}
}
rc = lustre_lnet_show_peer_debug_info(peer_nid, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_show_net(int argc, char **argv)
{
char *network = NULL;
int rc, opt;
struct cYAML *err_rc = NULL, *show_rc = NULL;
long int detail = 0;
const char *const short_options = "n:v";
static const struct option long_options[] = {
{ .name = "net", .has_arg = required_argument, .val = 'n' },
{ .name = "verbose", .has_arg = optional_argument, .val = 'v' },
{ .name = NULL } };
rc = check_cmd(net_cmds, "net", "show", 0, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'n':
network = optarg;
break;
case 'v':
/* '-v' has an optional argument. Default is 1. */
if (optarg || optind >= argc ||
argv[optind] == NULL || argv[optind][0] == '-' ||
parse_long(argv[optind++], &detail))
detail = 1;
break;
case '?':
print_help(net_cmds, "net", "show");
default:
return 0;
}
}
rc = yaml_lnet_config_ni(network, NULL, NULL, NULL, -1, NULL,
detail, NLM_F_DUMP, stdout);
if (rc <= 0) {
if (rc != -EOPNOTSUPP)
return rc;
}
rc = lustre_lnet_show_net(network, (int) detail, -1, &show_rc, &err_rc,
false);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
else if (show_rc)
cYAML_print_tree(show_rc);
cYAML_free_tree(err_rc);
cYAML_free_tree(show_rc);
return rc;
}
static int jt_show_routing(int argc, char **argv)
{
struct cYAML *err_rc = NULL, *show_rc = NULL;
int rc;
rc = check_cmd(routing_cmds, "routing", "show", 0, argc, argv);
if (rc)
return rc;
rc = lustre_lnet_show_routing(-1, &show_rc, &err_rc, false);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
else if (show_rc)
cYAML_print_tree(show_rc);
cYAML_free_tree(err_rc);
cYAML_free_tree(show_rc);
return rc;
}
static int jt_show_stats(int argc, char **argv)
{
int rc;
struct cYAML *show_rc = NULL, *err_rc = NULL;
rc = check_cmd(stats_cmds, "stats", "show", 0, argc, argv);
if (rc)
return rc;
rc = lustre_lnet_show_stats(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
else if (show_rc)
cYAML_print_tree(show_rc);
cYAML_free_tree(err_rc);
cYAML_free_tree(show_rc);
return rc;
}
static int jt_show_udsp(int argc, char **argv)
{
long int idx = -1;
int rc, opt;
struct cYAML *err_rc = NULL, *show_rc = NULL;
const char *const short_options = "i:";
static const struct option long_options[] = {
{ .name = "idx", .has_arg = required_argument, .val = 'i' },
{ .name = NULL }
};
rc = check_cmd(udsp_cmds, "udsp", "show", 0, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'i':
rc = parse_long(optarg, &idx);
if (rc != 0 || idx < -1) {
printf("Invalid index \"%s\"\n", optarg);
return -EINVAL;
}
break;
case '?':
print_help(net_cmds, "net", "show");
default:
return 0;
}
}
rc = lustre_lnet_show_udsp(idx, -1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
else if (show_rc)
cYAML_print_tree(show_rc);
cYAML_free_tree(err_rc);
cYAML_free_tree(show_rc);
return rc;
}
static int jt_show_global(int argc, char **argv)
{
int rc;
struct cYAML *show_rc = NULL, *err_rc = NULL;
rc = check_cmd(global_cmds, "global", "show", 0, argc, argv);
if (rc)
return rc;
rc = lustre_lnet_show_numa_range(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
rc = lustre_lnet_show_max_intf(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
rc = lustre_lnet_show_discovery(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
rc = lustre_lnet_show_drop_asym_route(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
rc = lustre_lnet_show_retry_count(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
rc = lustre_lnet_show_transaction_to(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
rc = lustre_lnet_show_hsensitivity(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
rc = lustre_lnet_show_recov_intrv(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
rc = lustre_lnet_show_rtr_sensitivity(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
rc = lustre_lnet_show_lnd_timeout(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
rc = lustre_lnet_show_response_tracking(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
rc = lustre_lnet_show_recovery_limit(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
rc = lustre_lnet_show_max_recovery_ping_interval(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(stderr, err_rc);
goto out;
}
if (show_rc)
cYAML_print_tree(show_rc);
out:
cYAML_free_tree(err_rc);
cYAML_free_tree(show_rc);
return rc;
}
static int jt_lnet(int argc, char **argv)
{
int rc;
rc = check_cmd(lnet_cmds, "lnet", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, lnet_cmds);
}
static int jt_route(int argc, char **argv)
{
int rc;
rc = check_cmd(route_cmds, "route", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, route_cmds);
}
static int jt_net(int argc, char **argv)
{
int rc;
rc = check_cmd(net_cmds, "net", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, net_cmds);
}
static int jt_routing(int argc, char **argv)
{
int rc;
rc = check_cmd(routing_cmds, "routing", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, routing_cmds);
}
static int jt_stats(int argc, char **argv)
{
int rc;
rc = check_cmd(stats_cmds, "stats", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, stats_cmds);
}
static int jt_debug(int argc, char **argv)
{
int rc;
rc = check_cmd(debug_cmds, "debug", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, debug_cmds);
}
static int jt_global(int argc, char **argv)
{
int rc;
rc = check_cmd(global_cmds, "global", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, global_cmds);
}
static int jt_peers(int argc, char **argv)
{
int rc;
rc = check_cmd(peer_cmds, "peer", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, peer_cmds);
}
static int jt_set(int argc, char **argv)
{
int rc;
rc = check_cmd(set_cmds, "set", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, set_cmds);
}
static int jt_udsp(int argc, char **argv)
{
int rc;
rc = check_cmd(udsp_cmds, "udsp", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, udsp_cmds);
}
static int jt_fault(int argc, char **argv)
{
int rc;
rc = check_cmd(fault_cmds, "fault", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, fault_cmds);
}
static int jt_fault_drop(int argc, char **argv)
{
int rc;
rc = check_cmd(fault_drop_cmds, "drop", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, fault_drop_cmds);
}
static int jt_fault_delay(int argc, char **argv)
{
int rc;
rc = check_cmd(fault_delay_cmds, "delay", NULL, 2, argc, argv);
if (rc)
return rc;
return cfs_parser(argc, argv, fault_delay_cmds);
}
static int yaml_import_global_settings(char *key, unsigned long value,
char cmd, struct cYAML *show_rc,
struct cYAML *err_rc)
{
int rc = 0;
if (strcmp("numa_range", key) == 0) {
if (cmd == 'a' || cmd == 'd') {
if (cmd == 'd')
value = 0;
rc = lustre_lnet_config_numa_range(value, -1,
&err_rc);
} else if (cmd == 's') {
rc = lustre_lnet_show_numa_range(-1, &show_rc,
&err_rc);
}
} else if (strcmp("max_interfaces", key) == 0 ||
strcmp("max_intf", key) == 0) {
if (cmd == 'a' || cmd == 'd') {
if (cmd == 'd')
value = LNET_INTERFACES_MAX_DEFAULT;
rc = lustre_lnet_config_max_intf(value, -1,
&err_rc);
} else if (cmd == 's') {
rc = lustre_lnet_show_max_intf(-1, &show_rc,
&err_rc);
}
} else if (strcmp("discovery", key) == 0) {
if (cmd == 'a' || cmd == 'd') {
if (cmd == 'd')
value = 1;
rc = lustre_lnet_config_discovery(value, -1,
&err_rc);
} else if (cmd == 's') {
rc = lustre_lnet_show_discovery(-1, &show_rc,
&err_rc);
}
} else if (strcmp("drop_asym_route", key) == 0) {
if (cmd == 'a') {
rc = lustre_lnet_config_drop_asym_route(value,
-1,
&err_rc);
} else if (cmd == 's') {
rc = lustre_lnet_show_drop_asym_route(-1, &show_rc,
&err_rc);
}
} else if (strcmp("retry_count", key) == 0) {
if (cmd == 'a') {
rc = lustre_lnet_config_retry_count(value, -1,
&err_rc);
} else if (cmd == 's') {
rc = lustre_lnet_show_retry_count(-1, &show_rc,
&err_rc);
}
} else if (strcmp("transaction_timeout", key) == 0) {
if (cmd == 'a') {
rc = lustre_lnet_config_transaction_to(value, -1,
&err_rc);
} else if (cmd == 's') {
rc = lustre_lnet_show_transaction_to(-1, &show_rc,
&err_rc);
}
} else if (strcmp("health_sensitivity", key) == 0) {
if (cmd == 'a') {
rc = lustre_lnet_config_hsensitivity(value, -1,
&err_rc);
} else if (cmd == 's') {
rc = lustre_lnet_show_hsensitivity(-1, &show_rc,
&err_rc);
}
} else if (strcmp("recovery_interval", key) == 0) {
if (cmd == 'a') {
rc = lustre_lnet_config_recov_intrv(value, -1,
&err_rc);
} else if (cmd == 's') {
rc = lustre_lnet_show_recov_intrv(-1, &show_rc,
&err_rc);
}
} else if (strcmp("router_sensitivity", key) == 0) {
if (cmd == 'a') {
rc = lustre_lnet_config_rtr_sensitivity(value, -1,
&err_rc);
} else if (cmd == 's') {
rc = lustre_lnet_show_rtr_sensitivity(-1, &show_rc,
&err_rc);
}
} else if (strcmp("lnd_timeout", key) == 0) {
if (cmd == 'a') {
} else if (cmd == 's') {
rc = lustre_lnet_show_lnd_timeout(-1, &show_rc,
&err_rc);
}
} else if (strcmp("response_tracking", key) == 0) {
if (cmd == 'a') {
rc = lustre_lnet_config_response_tracking(value, -1,
&err_rc);
} else if (cmd == 's') {
rc = lustre_lnet_show_response_tracking(-1, &show_rc,
&err_rc);
}
} else if (strcmp("recovery_limit", key) == 0) {
if (cmd == 'a') {
rc = lustre_lnet_config_recovery_limit(value, -1,
&err_rc);
} else if (cmd == 's') {
rc = lustre_lnet_show_recovery_limit(-1, &show_rc,
&err_rc);
}
} else if (strcmp("max_recovery_ping_interval", key) == 0) {
if (cmd == 'a') {
rc = lustre_lnet_config_max_recovery_ping_interval(value, -1,
&err_rc);
} else if (cmd == 's') {
rc = lustre_lnet_show_max_recovery_ping_interval(-1, &show_rc,
&err_rc);
}
}
return rc;
}
static char *global_params[] = {
"numa_range",
"max_interfaces",
"max_intf",
"discovery",
"drop_asym_route",
"retry_count",
"transaction_timeout",
"health_sensitivity",
"recovery_interval",
"router_sensitivity",
"lnd_timeout",
"response_tracking",
"recovery_limit",
"max_recovery_ping_interval"
};
static bool key_is_global_param(const char *key)
{
int i;
for (i = 0; i < sizeof(global_params)/sizeof(global_params[0]); i++) {
if (!strcmp(key, global_params[i]))
return true;
}
return false;
}
struct command_mapping {
const char *cm_name;
int cm_operation;
int cm_flags;
bool cm_exec_only;
};
static const struct command_mapping cmd_mappings[] = {
{"peer", LNET_CMD_PEERS, 0, false},
{"route", LNET_CMD_ROUTES, 0, false},
{"discover", LNET_CMD_PING, 0, true},
{"ping", LNET_CMD_PING, NLM_F_DUMP, true},
{"routing", LNET_CMD_ROUTING, 0, false},
{"buffers", LNET_CMD_BUFFERS, 0, false},
{"numa", LNET_CMD_NUMA, 0, false},
{NULL, 0, 0, false}
};
static int complete_and_setup_emitter(yaml_emitter_t *output,
struct nl_sock *sk, int flags, int new_op,
int *current_op)
{
if (*current_op != LNET_CMD_UNSPEC) {
if (!yaml_netlink_complete_emitter(output))
return 0;
}
*current_op = new_op;
return yaml_netlink_setup_emitter(output, sk, LNET_GENL_NAME,
LNET_GENL_VERSION, flags, new_op,
true);
}
static const struct command_mapping *find_command_mapping(const char *value,
char cmd,
int current_op)
{
const struct command_mapping *mapping = cmd_mappings;
/* The "route" yaml block can contain a "net" key */
if (current_op == LNET_CMD_ROUTES && !strcmp(value, "net"))
return NULL;
for (; mapping->cm_name; mapping++) {
if (!strcmp(value, mapping->cm_name)) {
// Check execute command restriction
if (cmd == 'e' && !mapping->cm_exec_only)
return NULL;
if (cmd != 'e' && mapping->cm_exec_only)
return NULL;
return mapping;
}
}
return NULL;
}
static int
yaml_lnet_extract_long(yaml_parser_t *setup, yaml_event_t *event, char *key,
long *value, int flags)
{
char *valstr;
char errmsg[LNET_MAX_STR_LEN];
int rc;
valstr = (char *)event->data.scalar.value;
if (!strlen(valstr)) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"no value specified for key '%s'", key);
goto print_error;
}
rc = parse_long(valstr, value);
if (rc) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"invalid value '%s' for key '%s'", valstr, key);
goto print_error;
}
return 0;
print_error:
errno = rc = -EINVAL;
yaml_lnet_print_error(flags, "import", errmsg);
return rc;
}
static int handle_udsp_sequences(yaml_parser_t *setup, char cmd, int flags,
struct cYAML *show_rc)
{
char *src = NULL, *dst = NULL, *rte = NULL;
long seq_no = -1, idx = -1, prio = -1;
union lnet_udsp_action action;
struct cYAML *err_rc = NULL;
yaml_event_t event;
bool done = false;
int rc = 1;
while (!done) {
char *value;
rc = yaml_parser_parse(setup, &event);
if (rc == 0)
goto failed;
/* Finished one of the UDSP rules. */
if (event.type == YAML_MAPPING_END_EVENT && idx != -1) {
switch (flags) {
case 0: /* delete */
rc = lustre_lnet_del_udsp(idx, seq_no,
&err_rc);
break;
case NLM_F_DUMP:
rc = lustre_lnet_show_udsp(idx, seq_no,
&show_rc, &err_rc);
break;
case NLM_F_CREATE:
default:
action.udsp_priority = prio;
rc = lustre_lnet_add_udsp(src, dst, rte,
prio ? "priority" : "",
&action, idx,
seq_no, &err_rc);
break;
}
/* reset values */
idx = -1;
if (src) {
free(src);
src = NULL;
}
if (dst) {
free(dst);
dst = NULL;
}
if (rte) {
free(rte);
rte = NULL;
}
if (rc < 0)
goto failed;
}
if (event.type != YAML_SCALAR_EVENT) {
if (event.type == YAML_SEQUENCE_END_EVENT)
done = true;
yaml_event_delete(&event);
continue;
}
value = (char *)event.data.scalar.value;
if (!strcmp(value, "idx") ||
!strcmp(value, "priority")) {
char *key = strdup(value);
long value;
yaml_event_delete(&event);
rc = yaml_parser_parse(setup, &event);
if (rc == 0) {
free(key);
goto failed;
}
rc = yaml_lnet_extract_long(setup, &event,
key, &value, flags);
if (rc) {
free(key);
goto failed;
}
if (!strcmp(key, "priority"))
prio = value;
else
idx = value;
free(key);
} else if (!strcmp(value, "src") ||
!strcmp(value, "dst") ||
!strcmp(value, "rte")) {
char *key = strdup(value);
yaml_event_delete(&event);
rc = yaml_parser_parse(setup, &event);
if (rc == 0) {
free(key);
goto failed;
}
value = (char *)event.data.scalar.value;
if (!strcmp(key, "src"))
src = strdup(value);
else if (!strcmp(key, "dst"))
dst = strdup(value);
else if (!strcmp(key, "rte"))
rte = strdup(value);
}
yaml_event_delete(&event);
}
failed:
return rc;
}
static int handle_global_parameter(yaml_parser_t *setup, yaml_event_t *event,
char cmd, int flags, struct cYAML *show_rc)
{
struct cYAML *err_rc = NULL;
long value;
char *key;
char errmsg[LNET_MAX_STR_LEN];
int rc;
key = strdup((char *)event->data.scalar.value);
if (!key_is_global_param(key)) {
snprintf(errmsg, LNET_MAX_STR_LEN, "invalid key '%s'", key);
errno = rc = -EINVAL;
yaml_lnet_print_error(flags, "import", errmsg);
goto out_free_key;
}
rc = yaml_parser_parse(setup, event);
if (rc == 0) {
yaml_parser_log_error(setup, stderr, "import: ");
goto out_free_key;
}
rc = yaml_lnet_extract_long(setup, event, key, &value, flags);
if (rc)
goto out_free_key;
rc = yaml_import_global_settings(key, value, cmd, show_rc, err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
else
rc = 1;
out_free_key:
free(key);
return rc;
}
static void
free_ip2nets_lists(struct lustre_lnet_ip2nets *ip2nets)
{
struct lustre_lnet_ip_range_descr *ip_range_descr = NULL,
*tmp = NULL;
struct lnet_dlc_intf_descr *intf_descr, *intf_tmp;
list_for_each_entry_safe(intf_descr, intf_tmp,
&ip2nets->ip2nets_net.nw_intflist,
intf_on_network) {
list_del(&intf_descr->intf_on_network);
free_intf_descr(intf_descr);
}
list_for_each_entry_safe(ip_range_descr, tmp,
&ip2nets->ip2nets_ip_ranges,
ipr_entry) {
struct cfs_expr_list *el, *el_tmp;
list_del(&ip_range_descr->ipr_entry);
list_for_each_entry_safe(el, el_tmp, &ip_range_descr->ipr_expr,
el_link) {
list_del(&el->el_link);
cfs_expr_list_free(el);
}
free(ip_range_descr);
}
}
/* Handles ip2nets "tunables" and "lnd tunables" */
static int
parse_yaml_tunables(__u32 net_id,
struct lnet_ioctl_config_lnd_tunables *tunables,
yaml_parser_t *setup, int flags,
int (*set_tunable)(__u32 net_id,
struct lnet_ioctl_config_lnd_tunables *tunables,
yaml_parser_t *, yaml_event_t *, int))
{
yaml_event_t event;
int rc;
if (!yaml_parser_parse(setup, &event))
return 0;
if (event.type != YAML_MAPPING_START_EVENT)
return -EINVAL;
yaml_event_delete(&event);
/* Parse the "key" event */
if (!yaml_parser_parse(setup, &event))
return 0;
while (event.type == YAML_SCALAR_EVENT) {
/* Consumes the "key" and "value" events */
rc = set_tunable(net_id, tunables, setup, &event, flags);
if (rc < 0)
return rc;
/* Parse the next "key" event" */
if (!yaml_parser_parse(setup, &event))
return 0;
}
return 1;
}
/* Handles ip2nets "interfaces" and "ip-range" */
static int parse_yaml_list(yaml_parser_t *setup, struct list_head *list,
int (*add_item)(struct list_head *, char *))
{
yaml_event_t event;
char *value;
int rc;
if (!yaml_parser_parse(setup, &event))
return 0;
if (event.type != YAML_MAPPING_START_EVENT)
return -EINVAL;
yaml_event_delete(&event);
/* Parse the "key" event */
if (!yaml_parser_parse(setup, &event))
return 0;
while (event.type == YAML_SCALAR_EVENT) {
/* Delete the "key" event */
yaml_event_delete(&event);
/* Parse the "value" event */
if (!yaml_parser_parse(setup, &event))
return 0;
if (event.type != YAML_SCALAR_EVENT)
return -EINVAL;
value = (char *)event.data.scalar.value;
rc = add_item(list, value);
if (rc != LUSTRE_CFG_RC_NO_ERR)
return rc;
/* Delete the "value" event */
yaml_event_delete(&event);
/* Parse the next "key" event */
if (!yaml_parser_parse(setup, &event))
return 0;
}
return 1;
}
static int
handle_cmn_tunable(__u32 net_id,
struct lnet_ioctl_config_lnd_tunables *tunables,
yaml_parser_t *setup, yaml_event_t *event, int flags)
{
struct lnet_ioctl_config_lnd_cmn_tunables *cmn_tun = &tunables->lt_cmn;
char *key;
long value;
int rc;
key = strdup((char *)event->data.scalar.value);
yaml_event_delete(event);
rc = yaml_parser_parse(setup, event);
if (!rc) {
yaml_parser_log_error(setup, stderr, "import: ");
goto out_free_key;
}
rc = yaml_lnet_extract_long(setup, event, key, &value, flags);
if (rc)
goto out_free_key;
if (!strcmp(key, "peer_timeout")) {
cmn_tun->lct_peer_timeout = value;
} else if (!strcmp(key, "peer_credits")) {
cmn_tun->lct_peer_tx_credits = value;
} else if (!strcmp(key, "peer_buffer_credits")) {
cmn_tun->lct_peer_rtr_credits = value;
} else if (!strcmp(key, "credits")) {
cmn_tun->lct_max_tx_credits = value;
} else {
fprintf(stderr,
"Ignoring unrecognized key '%s' for 'tunables'\n",
key);
}
yaml_event_delete(event);
rc = 1;
out_free_key:
free(key);
return rc;
}
static int
handle_lnd_tunable(__u32 net_id,
struct lnet_ioctl_config_lnd_tunables *tunables,
yaml_parser_t *setup, yaml_event_t *event, int flags)
{
struct lnet_lnd_tunables *lnd_tun = &tunables->lt_tun;
char *key, *valstr;
long value;
char errmsg[LNET_MAX_STR_LEN];
int rc;
key = strdup((char *)event->data.scalar.value);
yaml_event_delete(event);
rc = yaml_parser_parse(setup, event);
if (!rc) {
yaml_parser_log_error(setup, stderr, "import: ");
goto out_free_key;
}
#ifdef HAVE_KFILND
if (!strcmp(key, "traffic_class") && LNET_NETTYP(net_id) == KFILND) {
char *tc = &lnd_tun->lnd_tun_u.lnd_kfi.lnd_traffic_class_str[0];
valstr = (char *)event->data.scalar.value;
if (!strlen(valstr)) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"no value specified for key '%s'", key);
errno = rc = -EINVAL;
yaml_lnet_print_error(flags, "import", errmsg);
goto out_free_key;
} else if (strlen(valstr) < LNET_MAX_STR_LEN) {
strcpy(tc, valstr);
}
goto out_free_key;
}
#endif
if (LNET_NETTYP(net_id) == O2IBLND && !strcmp(key, "map_on_demand")) {
valstr = (char *)event->data.scalar.value;
if (!strlen(valstr)) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"no value specified for key '%s'", key);
errno = rc = -EINVAL;
yaml_lnet_print_error(flags, "import", errmsg);
goto out_free_key;
}
if (strcasecmp(valstr, "yes") == 0 ||
strcasecmp(valstr, "true") == 0 ||
strcasecmp(valstr, "on") == 0 ||
strcasecmp(valstr, "y") == 0 ||
strcmp(valstr, "1") == 0)
lnd_tun->lnd_tun_u.lnd_o2ib.lnd_map_on_demand = 1;
else if (strcasecmp(valstr, "no") == 0 ||
strcasecmp(valstr, "false") == 0 ||
strcasecmp(valstr, "off") == 0 ||
strcasecmp(valstr, "n") == 0 ||
strcasecmp(valstr, "0") == 0)
lnd_tun->lnd_tun_u.lnd_o2ib.lnd_map_on_demand = 0;
} else {
rc = yaml_lnet_extract_long(setup, event, key, &value, flags);
if (rc)
goto out_free_key;
}
#ifdef HAVE_KFILND
if (!strcmp(key, "auth_key") && LNET_NETTYP(net_id) == KFILND) {
lnd_tun->lnd_tun_u.lnd_kfi.lnd_auth_key = value;
goto out_free_key;
}
#endif
if (!strcmp(key, "conns_per_peer")) {
if (LNET_NETTYP(net_id) == SOCKLND)
lnd_tun->lnd_tun_u.lnd_sock.lnd_conns_per_peer = value;
else if (LNET_NETTYP(net_id) == O2IBLND)
lnd_tun->lnd_tun_u.lnd_o2ib.lnd_conns_per_peer = value;
} else if (!strcmp(key, "tos")) {
if (LNET_NETTYP(net_id) == SOCKLND)
lnd_tun->lnd_tun_u.lnd_sock.lnd_tos = value;
else if (LNET_NETTYP(net_id) == O2IBLND)
lnd_tun->lnd_tun_u.lnd_o2ib.lnd_tos = value;
} else if (LNET_NETTYP(net_id) == O2IBLND) {
/* handle o2iblnd tunables */
if (!strcmp(key, "peercredits_hiw")) {
lnd_tun->lnd_tun_u.lnd_o2ib.lnd_peercredits_hiw = value;
} else if (!strcmp(key, "concurrent_sends")) {
lnd_tun->lnd_tun_u.lnd_o2ib.lnd_concurrent_sends = value;
} else if (!strcmp(key, "fmr_pool_size")) {
lnd_tun->lnd_tun_u.lnd_o2ib.lnd_fmr_pool_size = value;
} else if (!strcmp(key, "fmr_flush_trigger")) {
lnd_tun->lnd_tun_u.lnd_o2ib.lnd_fmr_flush_trigger = value;
} else if (!strcmp(key, "fmr_cache")) {
lnd_tun->lnd_tun_u.lnd_o2ib.lnd_fmr_cache = value;
} else if (!strcmp(key, "ntx")) {
lnd_tun->lnd_tun_u.lnd_o2ib.lnd_ntx = value;
}
} else {
fprintf(stderr,
"Ignoring unrecognized key '%s' for 'lnd tunables'\n",
key);
}
yaml_event_delete(event);
rc = 1;
out_free_key:
free(key);
return rc;
}
static void
init_ip2nets_tunables(struct lustre_lnet_ip2nets *ip2nets,
struct lnet_ioctl_config_lnd_tunables *tunables)
{
INIT_LIST_HEAD(&ip2nets->ip2nets_ip_ranges);
INIT_LIST_HEAD(&ip2nets->ip2nets_net.network_on_rule);
INIT_LIST_HEAD(&ip2nets->ip2nets_net.nw_intflist);
ip2nets->ip2nets_net.nw_id = LNET_NET_ANY;
memset(tunables, 0, sizeof(*tunables));
tunables->lt_cmn.lct_peer_timeout = -1;
tunables->lt_cmn.lct_peer_tx_credits = -1;
tunables->lt_cmn.lct_peer_rtr_credits = -1;
tunables->lt_cmn.lct_max_tx_credits = -1;
}
static void
init_lnd_tunables(__u32 net_type,
struct lnet_ioctl_config_lnd_tunables *tunables,
bool *tunables_set)
{
if (net_type == SOCKLND) {
tunables->lt_tun.lnd_tun_u.lnd_sock.lnd_tos = -1;
*tunables_set = true;
} else if (net_type == O2IBLND) {
tunables->lt_tun.lnd_tun_u.lnd_o2ib.lnd_tos = -1;
*tunables_set = true;
}
}
static int
add_intf_helper(struct list_head *list, char *intf)
{
return lustre_lnet_add_intf_descr(list, intf, strlen(intf));
}
static int
handle_cpt_sequence(yaml_parser_t *setup, yaml_event_t *event,
struct cfs_expr_list **global_cpts, int flags)
{
int rc;
char errmsg[LNET_MAX_STR_LEN];
char *value;
yaml_event_delete(event);
rc = yaml_parser_parse(setup, event);
if (!rc)
goto yaml_parser_error;
if (event->type == YAML_SCALAR_EVENT) {
value = (char *)event->data.scalar.value;
rc = cfs_expr_list_parse(value, strlen(value), 0, UINT_MAX,
global_cpts);
if (rc) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"Unable to parse CPT '%s'", value);
goto print_error;
}
return 1;
}
if (event->type != YAML_SEQUENCE_START_EVENT) {
snprintf(errmsg, sizeof(errmsg),
"Unable to parse CPT configuration");
rc = -EINVAL;
goto print_error;
}
yaml_event_delete(event);
rc = yaml_parser_parse(setup, event);
if (!rc)
goto yaml_parser_error;
if (event->type != YAML_SCALAR_EVENT) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"Missing CPT configuration");
rc = -ENODATA;
goto print_error;
}
while (event->type != YAML_SEQUENCE_END_EVENT) {
struct cfs_expr_list *expr_list;
char *value;
char *tmp;
size_t tmpsize;
if (event->type != YAML_SCALAR_EVENT) {
snprintf(errmsg, sizeof(errmsg),
"Malformed CPT configuration");
rc = -EINVAL;
goto print_error;
}
value = (char *)event->data.scalar.value;
tmpsize = strlen(value) + 3;
tmp = malloc(tmpsize);
if (!tmp) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"No memory for CPT configuration");
rc = -ENOMEM;
goto print_error;
}
snprintf(tmp, tmpsize, "[%s]", value);
rc = cfs_expr_list_parse(tmp, strlen(tmp), 0, UINT_MAX,
&expr_list);
free(tmp);
if (rc) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"Unable to parse CPT '%s'", value);
goto print_error;
}
if (*global_cpts) {
list_splice_tail(&expr_list->el_exprs,
&global_cpts[0]->el_exprs);
free(expr_list);
} else {
*global_cpts = expr_list;
}
yaml_event_delete(event);
rc = yaml_parser_parse(setup, event);
if (!rc)
goto yaml_parser_error;
}
print_error:
yaml_event_delete(event);
if (rc < 0) {
errno = rc;
yaml_lnet_print_error(flags, "import", errmsg);
}
yaml_parser_error:
if (rc == 0) {
yaml_parser_log_error(setup, stderr, "import: ");
rc = -EINVAL;
}
return rc;
}
/*
* ip2nets:
* - net-spec: <net>[NUM]
* interfaces:
* 0: <intf name>['['<expr>']']
* 1: <intf name>['['<expr>']']
* ip-range:
* 0: <expr.expr.expr.expr>
* 1: <expr.expr.expr.expr>
* tunables:
* peer_timeout: <NUM>
* peer_credits: <NUM>
* peer_buffer_credits: <NUM>
* credits: <NUM>
* lnd tunables:
* <lnd_param1>: <val>
* <lnd_param2>: <val>
* <...>
* CPT: "[<expr]"
*
* or
*
* net:
* - net type: <net>[NUM]
* interfaces:
* 0: <intf name>['['<expr>']']
* 1: <intf name>['['<expr>']']
* tunables:
* peer_timeout: <NUM>
* peer_credits: <NUM>
* peer_buffer_credits: <NUM>
* credits: <NUM>
* lnd tunables:
* <lnd_param1>: <val>
* <lnd_param2>: <val>
* <...>
* CPT: "[<expr]"
*/
static int
handle_net_config_sequence(yaml_parser_t *setup, int flags,
bool is_ip2nets_sequence)
{
struct lustre_lnet_ip2nets ip2nets;
struct lnet_dlc_network_descr *nw_descr = &ip2nets.ip2nets_net;
struct lnet_ioctl_config_lnd_tunables tunables;
struct cfs_expr_list *global_cpts = NULL;
yaml_event_t event;
int rc = 1;
char errmsg[LNET_MAX_STR_LEN];
bool tunables_set = false;
bool lnd_tunables_set = false;
/* Track configured networks to ensure uniqueness for ip2nets */
__u32 *configured_nets = NULL;
size_t nets_cnt = 0;
unsigned int seq_depth = 0;
unsigned int map_depth = 0;
init_ip2nets_tunables(&ip2nets, &tunables);
while (1) {
char *value;
rc = yaml_parser_parse(setup, &event);
if (!rc)
goto yaml_parser_error;
switch (event.type) {
case YAML_SEQUENCE_START_EVENT:
seq_depth++;
break;
case YAML_SEQUENCE_END_EVENT:
seq_depth--;
break;
case YAML_MAPPING_START_EVENT:
map_depth++;
break;
case YAML_MAPPING_END_EVENT:
map_depth--;
break;
default:
break;
}
/* Reached the end of the ip2nets/net sequence */
if (event.type == YAML_SEQUENCE_END_EVENT && seq_depth == 0) {
yaml_event_delete(&event);
if (is_ip2nets_sequence && nets_cnt == 0) {
/* If none of the rules applied then return an
* error
*/
rc = -EINVAL;
snprintf(errmsg, LNET_MAX_STR_LEN,
"No ip2nets rules applied");
goto print_error;
}
goto out;
}
/* Reached the end of a network specification block */
if (event.type == YAML_MAPPING_END_EVENT && map_depth == 0) {
struct lnet_ioctl_config_lnd_tunables *tun = NULL;
char *net;
lnet_nid_t *nids = NULL;
__u32 nnids = 0;
bool duplicate_net = false;
size_t i;
__u32 *tmp;
rc = lustre_lnet_resolve_ip2nets_rule(&ip2nets, &nids,
&nnids, errmsg,
sizeof(errmsg));
if (nids)
free(nids);
/* NO_MATCH is okay for ip2nets, but anything else is
* an error
*/
if (rc != LUSTRE_CFG_RC_NO_ERR &&
!(is_ip2nets_sequence &&
rc == LUSTRE_CFG_RC_NO_MATCH))
goto print_error;
/* Skip configuration if resolution failed */
if (rc != LUSTRE_CFG_RC_NO_ERR)
goto cleanup_block;
/* Check for duplicate networks in ip2nets sequences */
for (i = 0; i < nets_cnt; i++) {
if (configured_nets[i] ==
ip2nets.ip2nets_net.nw_id) {
duplicate_net = true;
break;
}
}
/* Skip configuration for ip2nets if duplicate */
if (duplicate_net && is_ip2nets_sequence)
goto cleanup_block;
/* Configure the network interface */
net = libcfs_net2str(ip2nets.ip2nets_net.nw_id);
if (tunables_set || lnd_tunables_set)
tun = &tunables;
rc = yaml_lnet_config_ni(net, NULL,
&ip2nets.ip2nets_net, tun, -1,
global_cpts, LNET_GENL_VERSION,
flags, stdout);
if (rc < 0) {
snprintf(errmsg, sizeof(errmsg),
"Failed to configure NI on net '%s' rc = %d",
net, rc);
goto print_error;
}
/* Record successfully configured network for ip2nets */
tmp = realloc(configured_nets, (nets_cnt + 1) *
sizeof(*configured_nets));
if (!tmp) {
rc = -ENOMEM;
snprintf(errmsg, sizeof(errmsg),
"Out of memory tracking configured nets");
goto print_error;
}
configured_nets = tmp;
configured_nets[nets_cnt] = ip2nets.ip2nets_net.nw_id;
nets_cnt++;
cleanup_block:
free_ip2nets_lists(&ip2nets);
init_ip2nets_tunables(&ip2nets, &tunables);
if (global_cpts)
cfs_expr_list_free(global_cpts);
global_cpts = NULL;
tunables_set = lnd_tunables_set = false;
}
/* Skip other events we do not care about */
if (event.type != YAML_SCALAR_EVENT) {
yaml_event_delete(&event);
continue;
}
value = (char *)event.data.scalar.value;
/* "net-spec" must be the first scalar for an ip2nets sequence,
* and "net type" must be the first in a net sequence
*/
if (ip2nets.ip2nets_net.nw_id == LNET_NET_ANY) {
if (is_ip2nets_sequence && strcmp(value, "net-spec")) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"Malformed input. Expect 'net-spec' found '%s'",
value);
rc = -EINVAL;
goto print_error;
} else if (!is_ip2nets_sequence &&
strcmp(value, "net type")) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"Malformed input. Expect 'net type' found '%s'",
value);
rc = -EINVAL;
goto print_error;
}
}
if (!strcmp(value, "net-spec") || !strcmp(value, "net type")) {
yaml_event_delete(&event);
rc = yaml_parser_parse(setup, &event);
if (!rc)
goto yaml_parser_error;
value = (char *)event.data.scalar.value;
ip2nets.ip2nets_net.nw_id = libcfs_str2net(value);
if (ip2nets.ip2nets_net.nw_id == LNET_NET_ANY) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"Invalid network ID '%s'",
value);
rc = -EINVAL;
goto print_error;
}
init_lnd_tunables(LNET_NETTYP(ip2nets.ip2nets_net.nw_id),
&tunables, &lnd_tunables_set);
} else if (!strcmp(value, "interfaces")) {
yaml_event_delete(&event);
rc = parse_yaml_list(setup, &nw_descr->nw_intflist,
add_intf_helper);
if (rc < 0) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"Failed to parse interfaces list rc = %d",
rc);
goto print_error;
} else if (!rc) {
goto yaml_parser_error;
}
} else if (!strcmp(value, "local NI(s)")) {
if (is_ip2nets_sequence) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"local NI(s)' not valid for ip2nets");
rc = -EINVAL;
goto print_error;
}
} else if (!strcmp(value, "ip-range")) {
if (!is_ip2nets_sequence) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"'ip-range' only valid for ip2nets");
rc = -EINVAL;
goto print_error;
}
yaml_event_delete(&event);
rc = parse_yaml_list(setup, &ip2nets.ip2nets_ip_ranges,
lustre_lnet_add_ip_range);
if (rc < 0) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"Failed to parse ip-range list rc = %d",
rc);
goto print_error;
} else if (!rc) {
goto yaml_parser_error;
}
} else if (!strcmp(value, "tunables")) {
yaml_event_delete(&event);
rc = parse_yaml_tunables(ip2nets.ip2nets_net.nw_id,
&tunables, setup, flags,
handle_cmn_tunable);
if (rc < 0) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"Failed to parse tunables rc = %d",
rc);
goto print_error;
} else if (!rc) {
goto yaml_parser_error;
}
tunables_set = true;
} else if (!strcmp(value, "lnd tunables")) {
yaml_event_delete(&event);
rc = parse_yaml_tunables(ip2nets.ip2nets_net.nw_id,
&tunables, setup, flags,
handle_lnd_tunable);
if (rc < 0) {
snprintf(errmsg, LNET_MAX_STR_LEN,
"Failed to parse lnd tunables rc = %d",
rc);
goto print_error;
} else if (!rc) {
goto yaml_parser_error;
}
lnd_tunables_set = true;
} else if (!strcmp(value, "CPT")) {
rc = handle_cpt_sequence(setup, &event,
&global_cpts, flags);
if (rc < 0 || !global_cpts)
goto out;
/* handle_cpt_sequence() deletes the last event that
* it parsed
*/
continue;
}
yaml_event_delete(&event);
}
print_error:
if (rc < 0) {
errno = rc;
yaml_lnet_print_error(flags, "import", errmsg);
}
yaml_parser_error:
if (rc == 0) {
yaml_parser_log_error(setup, stderr, "ip2nets: ");
rc = -EINVAL;
}
out:
free_ip2nets_lists(&ip2nets);
if (configured_nets)
free(configured_nets);
if (global_cpts)
cfs_expr_list_free(global_cpts);
return (rc < 0) ? rc : 1;
}
static int jt_import(int argc, char **argv)
{
char *file = NULL;
struct cYAML *err_rc = NULL;
struct cYAML *show_rc = NULL;
int rc = 0, return_rc = 0, opt, opt_found = 0;
char *yaml_blk = NULL, *buf, cmd = 'a';
int flags = NLM_F_CREATE;
bool release = true;
bool oldapi = false;
char err_str[256];
struct stat st;
FILE *input;
size_t len;
const char *const short_options = "adseoh";
static const struct option long_options[] = {
{ .name = "add", .has_arg = no_argument, .val = 'a' },
{ .name = "del", .has_arg = no_argument, .val = 'd' },
{ .name = "show", .has_arg = no_argument, .val = 's' },
{ .name = "exec", .has_arg = no_argument, .val = 'e' },
{ .name = "old-api", .has_arg = no_argument, .val = 'o' },
{ .name = "help", .has_arg = no_argument, .val = 'h' },
{ .name = NULL }
};
bool done = false, unspec = true;
yaml_parser_t setup, reply;
struct nl_sock *sk = NULL;
int op = LNET_CMD_UNSPEC;
const char *msg = NULL;
yaml_emitter_t output;
yaml_event_t event;
struct cfs_expr_list *global_cpts = NULL;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
opt_found = 1;
switch (opt) {
case 'a':
/* default is NLM_F_CREATE */
cmd = opt;
break;
case 'd':
flags = 0; /* Netlink delete cmd */
cmd = opt;
break;
case 's':
flags = NLM_F_DUMP;
cmd = opt;
break;
case 'e':
/* use NLM_F_CREATE for discover */
cmd = opt;
break;
case 'o':
oldapi = true;
break;
case 'h':
printf("import FILE\n"
"import < FILE : import a file\n"
"\t--add: add configuration\n"
"\t--del: delete configuration\n"
"\t--show: show configuration\n"
"\t--exec: execute command\n"
"\t--old-api: do not use netlink (for tests)\n"
"\t--help: display this help\n"
"If no command option is given then --add"
" is assumed by default\n");
return 0;
default:
return 0;
}
}
/* grab the file name if one exists */
if (opt_found && argc == 3)
file = argv[2];
else if (!opt_found && argc == 2)
file = argv[1];
/* file always takes precedence */
if (file != NULL) {
/* Set a file input. */
input = fopen(file, "rb");
if (!input) {
rc = -errno;
snprintf(err_str, sizeof(err_str),
"cannot open '%s': %s", file,
strerror(errno));
cYAML_build_error(-1, -1, "yaml", "builder",
err_str,
&err_rc);
goto err;
}
} else {
input = stdin;
}
if (oldapi)
goto old_api;
/* Create Netlink emitter to send request to kernel */
sk = nl_socket_alloc();
if (!sk)
goto old_api;
/* Setup parser to receive Netlink packets */
rc = yaml_parser_initialize(&reply);
if (rc == 0) {
nl_socket_free(sk);
goto old_api;
}
rc = yaml_parser_set_input_netlink(&reply, sk, false);
if (rc == 0) {
msg = yaml_parser_get_reader_error(&reply);
goto free_reply;
}
/* Initialize configuration parser */
rc = yaml_parser_initialize(&setup);
if (rc == 0) {
yaml_parser_log_error(&setup, stderr, "import: ");
yaml_parser_delete(&setup);
return -EINVAL;
}
yaml_parser_set_input_file(&setup, input);
while (!done) {
const char *scalar_value;
const struct command_mapping *mapping;
rc = yaml_parser_parse(&setup, &event);
if (rc == 0) {
yaml_parser_log_error(&setup, stderr, "import: ");
break;
}
if (event.type != YAML_SCALAR_EVENT)
goto skip_test;
scalar_value = (char *)event.data.scalar.value;
mapping = find_command_mapping(scalar_value, cmd, op);
if (mapping) {
int emitter_flags = mapping->cm_flags ?: flags;
rc = complete_and_setup_emitter(&output, sk,
emitter_flags,
mapping->cm_operation,
&op);
if (rc == 0)
goto emitter_error;
unspec = false;
} else if (!strcmp(scalar_value, "udsp")) {
if (op != LNET_CMD_UNSPEC) {
rc = yaml_netlink_complete_emitter(&output);
if (rc == 0)
goto emitter_error;
}
op = LNET_CMD_UNSPEC;
rc = handle_udsp_sequences(&setup, cmd, flags,
show_rc);
if (rc < 0)
goto free_reply;
else if (rc == 0)
goto emitter_error;
} else if (!strcmp(scalar_value, "ip2nets") ||
!strcmp(scalar_value, "net")) {
bool is_ip2nets = strcmp(scalar_value, "ip2nets") == 0;
/* The "route" yaml block can contain a "net" key */
if (!is_ip2nets && op == LNET_CMD_ROUTES)
goto skip_test;
if (op != LNET_CMD_UNSPEC) {
rc = yaml_netlink_complete_emitter(&output);
if (rc == 0)
goto emitter_error;
}
op = LNET_CMD_UNSPEC;
rc = handle_net_config_sequence(&setup, flags,
is_ip2nets);
if (rc < 0)
goto free_reply;
else if (rc == 0)
goto emitter_error;
} else if (op == LNET_CMD_NETS &&
!strcmp(scalar_value, "CPT")) {
rc = handle_cpt_sequence(&setup, &event, &global_cpts,
flags);
if (rc < 0 || !global_cpts)
goto free_reply;
rc = lnet_yaml_emit_cpt_sequence(&output, global_cpts);
if (rc == 0)
goto emitter_error;
cfs_expr_list_free(global_cpts);
global_cpts = NULL;
continue;
} else if (!strcmp(scalar_value, "global")) {
if (op != LNET_CMD_UNSPEC) {
rc = yaml_netlink_complete_emitter(&output);
if (rc == 0)
goto emitter_error;
}
op = LNET_CMD_UNSPEC;
} else if (op == LNET_CMD_UNSPEC) {
rc = handle_global_parameter(&setup, &event, cmd, flags,
show_rc);
if (rc < 0)
goto free_reply;
else if (rc == 0)
goto emitter_error;
}
skip_test:
if (op != LNET_CMD_UNSPEC) {
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
break;
}
done = (event.type == YAML_STREAM_END_EVENT);
}
emitter_error:
if (rc == 0) {
yaml_emitter_log_error(&output, stderr);
yaml_emitter_cleanup(&output);
rc = -EINVAL;
} else if (!unspec) {
yaml_document_t errmsg;
rc = yaml_parser_load(&reply, &errmsg);
if (rc == 1 && (flags & NLM_F_DUMP)) {
yaml_emitter_t debug;
rc = yaml_emitter_initialize(&debug);
if (rc == 1) {
yaml_emitter_set_indent(&debug,
LNET_DEFAULT_INDENT);
yaml_emitter_set_output_file(&debug,
stdout);
rc = yaml_emitter_dump(&debug, &errmsg);
}
yaml_emitter_delete(&debug);
} else {
msg = yaml_parser_get_reader_error(&reply);
}
yaml_emitter_delete(&output);
yaml_document_delete(&errmsg);
}
free_reply:
if (rc == 0) {
yaml_lnet_print_error(flags, "import", msg);
rc = -EINVAL;
}
yaml_parser_cleanup(&reply);
yaml_parser_delete(&setup);
nl_socket_free(sk);
if (input)
fclose(input);
return rc == 1 ? 0 : rc;
old_api:
/* assume that we're getting our input from stdin */
rc = fstat(fileno(input), &st);
if (rc < 0) {
snprintf(err_str, sizeof(err_str),
"cannot get file stats '%s': %s", file,
strerror(-rc));
cYAML_build_error(-1, -1, "yaml", "builder",
err_str,
&err_rc);
goto err;
}
yaml_blk = buf = malloc(st.st_size + 1);
if (!yaml_blk) {
rc = -ENOMEM;
snprintf(err_str, sizeof(err_str),
"failed to allocate buffer: %s",
strerror(-rc));
cYAML_build_error(-1, -1, "yaml", "builder",
err_str,
&err_rc);
goto err;
}
len = st.st_size + 1;
while (len > 1 && fgets(buf, len, input) != NULL) {
char *seq = strstr(buf, "- ");
size_t n;
if (seq) {
int skip;
seq[0] = ' ';
skip = strspn(seq, " ");
if (skip) {
seq += skip - 2;
seq[0] = '-';
}
/* PyYAML format has libyaml free the
* buffer for us.
*/
release = false;
}
n = strlen(buf);
buf += n;
len -= n;
}
switch (cmd) {
case 'a':
rc = lustre_yaml_config(yaml_blk, st.st_size, &err_rc);
return_rc = lustre_yaml_exec(yaml_blk, st.st_size, &show_rc,
&err_rc);
cYAML_print_tree(show_rc);
cYAML_free_tree(show_rc);
break;
case 'd':
rc = lustre_yaml_del(yaml_blk, st.st_size, &err_rc);
break;
case 's':
rc = lustre_yaml_show(yaml_blk, st.st_size, &show_rc,
&err_rc);
cYAML_print_tree(show_rc);
cYAML_free_tree(show_rc);
break;
case 'e':
rc = lustre_yaml_exec(yaml_blk, st.st_size, &show_rc,
&err_rc);
cYAML_print_tree(show_rc);
cYAML_free_tree(show_rc);
break;
}
err:
if (yaml_blk && release)
free(yaml_blk);
if (rc || return_rc) {
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
}
return rc;
}
static int jt_export(int argc, char **argv)
{
struct cYAML *show_rc = NULL;
struct cYAML *err_rc = NULL;
int flags = NLM_F_DUMP;
int rc;
FILE *f = NULL;
int opt;
bool backup = false;
char *file = NULL;
const char *const short_options = "bh";
static const struct option long_options[] = {
{ .name = "backup", .has_arg = no_argument, .val = 'b' },
{ .name = "help", .has_arg = no_argument, .val = 'h' },
{ .name = NULL }
};
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'b':
flags |= NLM_F_DUMP_FILTERED;
backup = true;
break;
case 'h':
default:
printf("export > FILE.yaml : export configuration\n"
"\t--backup: export only what's necessary for reconfig\n"
"\t--help: display this help\n");
return 0;
}
}
if (backup && argc >= 3)
file = argv[2];
else if (!backup && argc >= 2)
file = argv[1];
else
f = stdout;
if (file) {
f = fopen(file, "w");
if (f == NULL)
return -1;
}
rc = yaml_lnet_config_ni(NULL, NULL, NULL, NULL, -1, NULL,
flags & NLM_F_DUMP_FILTERED ? 1 : 2,
flags, f);
if (rc < 0) {
if (rc == -EOPNOTSUPP)
goto old_api;
}
rc = yaml_lnet_route(NULL, NULL, -1, -1, LNET_GENL_VERSION,
flags, f);
if (rc < 0) {
if (rc == -EOPNOTSUPP)
goto old_route;
}
rc = lustre_lnet_show_routing(-1, &show_rc, &err_rc, backup);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
rc = yaml_lnet_peer(NULL, NULL, false, -1, false, false,
flags & NLM_F_DUMP_FILTERED ? 0 : 3,
flags, f);
if (rc < 0) {
if (rc == -EOPNOTSUPP)
goto old_peer;
}
goto show_others;
old_api:
rc = lustre_lnet_show_net(NULL, 2, -1, &show_rc, &err_rc, backup);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
old_route:
rc = lustre_lnet_show_route(NULL, NULL, -1, -1, 1, -1, &show_rc,
&err_rc, backup);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_routing(-1, &show_rc, &err_rc, backup);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
old_peer:
rc = lustre_lnet_show_peer(NULL, 2, -1, &show_rc, &err_rc, backup);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
show_others:
rc = lustre_lnet_show_numa_range(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_max_intf(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_discovery(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_drop_asym_route(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_retry_count(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_transaction_to(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_hsensitivity(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_recov_intrv(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_rtr_sensitivity(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_lnd_timeout(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_response_tracking(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_recovery_limit(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_max_recovery_ping_interval(-1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
rc = lustre_lnet_show_udsp(-1, -1, &show_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR) {
cYAML_print_tree2file(f, err_rc);
cYAML_free_tree(err_rc);
err_rc = NULL;
}
if (show_rc != NULL) {
cYAML_print_tree2file(f, show_rc);
cYAML_free_tree(show_rc);
}
if (argc >= 2)
fclose(f);
return 0;
}
static int jt_peer_nid_common(int argc, char **argv, int cmd)
{
int flags = cmd == LNETCTL_ADD_CMD ? NLM_F_CREATE : 0;
int rc = LUSTRE_CFG_RC_NO_ERR, opt;
bool is_mr = true;
char *prim_nid = NULL, *nidstr = NULL;
char err_str[LNET_MAX_STR_LEN] = "Error";
struct cYAML *err_rc = NULL;
int force_lock = 0;
const char *const short_opts = "k:m:n:f:l";
const struct option long_opts[] = {
{ .name = "prim_nid", .has_arg = required_argument, .val = 'k' },
{ .name = "non_mr", .has_arg = no_argument, .val = 'm' },
{ .name = "nid", .has_arg = required_argument, .val = 'n' },
{ .name = "force", .has_arg = no_argument, .val = 'f' },
{ .name = "lock_prim", .has_arg = no_argument, .val = 'l' },
{ .name = NULL } };
rc = check_cmd(peer_cmds, "peer",
cmd == LNETCTL_ADD_CMD ? "add" : "del", 2, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_opts,
long_opts, NULL)) != -1) {
switch (opt) {
case 'k':
prim_nid = optarg;
break;
case 'n':
nidstr = optarg;
break;
case 'm':
if (cmd == LNETCTL_DEL_CMD) {
rc = LUSTRE_CFG_RC_BAD_PARAM;
snprintf(err_str, LNET_MAX_STR_LEN,
"Unrecognized option '-%c'", opt);
goto build_error;
}
is_mr = false;
break;
case 'f':
if (cmd == LNETCTL_ADD_CMD) {
rc = LUSTRE_CFG_RC_BAD_PARAM;
snprintf(err_str, LNET_MAX_STR_LEN,
"Unrecognized option '-%c'", opt);
}
force_lock = 1;
flags |= NLM_F_EXCL;
break;
case 'l':
if (cmd == LNETCTL_DEL_CMD) {
rc = LUSTRE_CFG_RC_BAD_PARAM;
snprintf(err_str, LNET_MAX_STR_LEN,
"Unrecognized option '-%c'", opt);
}
force_lock = 1;
flags |= NLM_F_EXCL;
break;
case '?':
print_help(peer_cmds, "peer",
cmd == LNETCTL_ADD_CMD ? "add" : "del");
default:
return 0;
}
}
rc = yaml_lnet_peer(prim_nid, nidstr, !is_mr, -1, -1, false,
LNET_GENL_VERSION, flags, stdout);
if (rc <= 0) {
if (rc == -EOPNOTSUPP)
goto old_api;
return rc;
}
old_api:
rc = lustre_lnet_modify_peer(prim_nid, nidstr, is_mr, cmd,
force_lock, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
goto out;
build_error:
cYAML_build_error(rc, -1, "peer",
cmd == LNETCTL_ADD_CMD ? "add" : "del",
err_str, &err_rc);
out:
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_add_peer_nid(int argc, char **argv)
{
return jt_peer_nid_common(argc, argv, LNETCTL_ADD_CMD);
}
static int jt_del_peer_nid(int argc, char **argv)
{
return jt_peer_nid_common(argc, argv, LNETCTL_DEL_CMD);
}
static int jt_show_peer(int argc, char **argv)
{
char *nid = NULL;
int rc, opt;
struct cYAML *err_rc = NULL, *show_rc = NULL;
long int detail = 0;
const char *const short_opts = "hn:v::";
const struct option long_opts[] = {
{ .name = "help", .has_arg = no_argument, .val = 'h' },
{ .name = "nid", .has_arg = required_argument, .val = 'n' },
{ .name = "verbose", .has_arg = optional_argument, .val = 'v' },
{ .name = NULL }
};
rc = check_cmd(peer_cmds, "peer", "show", 1, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_opts,
long_opts, NULL)) != -1) {
switch (opt) {
case 'n':
nid = optarg;
break;
case 'v':
/* '-v' has an optional argument. Default is 1. */
if (optarg || optind >= argc ||
argv[optind] == NULL || argv[optind][0] == '-' ||
parse_long(argv[optind++], &detail))
detail = 1;
break;
case '?':
print_help(peer_cmds, "peer", "show");
default:
return 0;
}
}
rc = yaml_lnet_peer(nid, NULL, false, -1, -1, false, detail,
NLM_F_DUMP, stdout);
if (rc <= 0) {
if (rc == -EOPNOTSUPP)
goto old_api;
return rc;
}
old_api:
rc = lustre_lnet_show_peer(nid, (int) detail, -1, &show_rc, &err_rc,
false);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
else if (show_rc)
cYAML_print_tree(show_rc);
cYAML_free_tree(err_rc);
cYAML_free_tree(show_rc);
return rc;
}
static int jt_list_peer(int argc, char **argv)
{
struct cYAML *err_rc = NULL, *list_rc = NULL;
int rc;
rc = check_cmd(peer_cmds, "peer", "list", 0, argc, argv);
if (rc)
return rc;
rc = yaml_lnet_peer(NULL, NULL, false, -1, -1, true, 0, NLM_F_DUMP,
stdout);
if (rc <= 0) {
if (rc == -EOPNOTSUPP)
goto old_api;
return rc;
}
old_api:
rc = lustre_lnet_list_peer(-1, &list_rc, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
else if (list_rc)
cYAML_print_tree(list_rc);
cYAML_free_tree(err_rc);
cYAML_free_tree(list_rc);
return rc;
}
static int yaml_lnet_ping_display(yaml_parser_t *reply)
{
yaml_emitter_t debug;
bool done = false;
int rc, rc2 = 0;
long error = 0;
rc = yaml_emitter_initialize(&debug);
if (rc == 1)
yaml_emitter_set_output_file(&debug, stdout);
if (rc == 0)
goto emitter_error;
while (!done) {
yaml_event_t event;
rc = yaml_parser_parse(reply, &event);
if (rc == 0)
goto report_reply_error;
if (event.type != YAML_SCALAR_EVENT) {
rc = yaml_emitter_emit(&debug, &event);
if (rc == 0)
goto emitter_error;
done = (event.type == YAML_DOCUMENT_END_EVENT);
continue;
}
if (strcmp((char *)event.data.scalar.value, "errno") == 0) {
rc = yaml_emitter_emit(&debug, &event);
if (rc == 0)
goto emitter_error;
rc = yaml_parser_parse(reply, &event);
if (rc == 0)
goto report_reply_error;
rc = parse_long((char *)event.data.scalar.value,
&error);
if (rc != 0)
goto report_reply_error;
rc = yaml_emitter_emit(&debug, &event);
if (rc == 0)
goto emitter_error;
rc2 = -1;
} else if (error != 0 &&
strcmp((char *)event.data.scalar.value,
"descr") == 0) {
rc = yaml_emitter_emit(&debug, &event);
if (rc == 0)
goto emitter_error;
rc = yaml_parser_parse(reply, &event);
if (rc == 0)
goto report_reply_error;
if (strncmp((char *)event.data.scalar.value,
"failed to ", strlen("failed to ")) == 0) {
char err[256];
snprintf(err, sizeof(err), "%s: %s",
(char *)event.data.scalar.value,
strerror(-error));
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)err,
strlen(err), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
}
rc = yaml_emitter_emit(&debug, &event);
if (rc == 0)
goto emitter_error;
errno = 0;
} else {
rc = yaml_emitter_emit(&debug, &event);
if (rc == 0)
goto emitter_error;
}
}
emitter_error:
if (rc == 0)
yaml_emitter_log_error(&debug, stderr);
report_reply_error:
yaml_emitter_delete(&debug);
return rc2 ? rc2 : rc;
}
static int yaml_lnet_ping(char *group, int timeout, struct lnet_nid *src_nid,
int start, int end, char **nids, int flags)
{
struct nid_node head, *entry;
struct nl_sock *sk = NULL;
const char *msg = NULL;
yaml_emitter_t output;
yaml_parser_t reply;
yaml_event_t event;
int rc, i;
/* Create Netlink emitter to send request to kernel */
sk = nl_socket_alloc();
if (!sk)
return -EOPNOTSUPP;
/* Setup parser to receive Netlink packets */
rc = yaml_parser_initialize(&reply);
if (rc == 0) {
nl_socket_free(sk);
return -EOPNOTSUPP;
}
rc = yaml_parser_set_input_netlink(&reply, sk, false);
if (rc == 0) {
msg = yaml_parser_get_reader_error(&reply);
goto free_reply;
}
/* Create Netlink emitter to send request to kernel */
rc = yaml_emitter_initialize(&output);
if (rc == 0) {
msg = "failed to initialize emitter";
goto free_reply;
}
rc = yaml_emitter_set_output_netlink(&output, sk, LNET_GENL_NAME,
LNET_GENL_VERSION, LNET_CMD_PING,
flags);
if (rc == 0)
goto emitter_error;
yaml_emitter_open(&output);
yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)group,
strlen(group), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_MAP_TAG,
1, YAML_ANY_MAPPING_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
if (src_nid) {
char *src_nidstr = libcfs_nidstr(src_nid);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"source",
strlen("source"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)src_nidstr,
strlen(src_nidstr), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
}
if (timeout != 1000) {
char time[23];
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"timeout",
strlen("timeout"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
snprintf(time, sizeof(time), "%u", timeout);
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_INT_TAG,
(yaml_char_t *)time,
strlen(time), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
}
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)"nids",
strlen("nids"), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_sequence_start_event_initialize(&event, NULL,
(yaml_char_t *)YAML_SEQ_TAG,
1, YAML_FLOW_SEQUENCE_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
NL_INIT_LIST_HEAD(&head.children);
nl_init_list_head(&head.list);
for (i = start; i < end; i++) {
rc = lustre_lnet_parse_nid_range(&head, nids[i], &msg);
if (rc < 0) {
lustre_lnet_free_list(&head);
yaml_emitter_cleanup(&output);
errno = rc;
rc = 0;
goto free_reply;
}
}
if (nl_list_empty(&head.children))
goto skip_nids;
nl_list_for_each_entry(entry, &head.children, list) {
yaml_scalar_event_initialize(&event, NULL,
(yaml_char_t *)YAML_STR_TAG,
(yaml_char_t *)entry->nidstr,
strlen(entry->nidstr), 1, 0,
YAML_PLAIN_SCALAR_STYLE);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
}
skip_nids:
yaml_sequence_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_mapping_end_event_initialize(&event);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
yaml_document_end_event_initialize(&event, 0);
rc = yaml_emitter_emit(&output, &event);
if (rc == 0)
goto emitter_error;
rc = yaml_emitter_close(&output);
emitter_error:
if (rc == 0) {
yaml_emitter_log_error(&output, stderr);
rc = -EINVAL;
} else {
rc = yaml_lnet_ping_display(&reply);
if (rc == 0)
msg = yaml_parser_get_reader_error(&reply);
}
yaml_emitter_cleanup(&output);
free_reply:
if (rc == 0) {
yaml_lnet_print_error(-1, group, msg);
rc = -EINVAL;
}
yaml_parser_cleanup(&reply);
nl_socket_free(sk);
return rc == 1 ? 0 : rc;
}
static int jt_ping(int argc, char **argv)
{
struct cYAML *err_rc = NULL;
struct cYAML *show_rc = NULL;
struct lnet_nid src = { };
int timeout = 1000;
int rc = 0, opt;
char *src_nidstr = NULL;
const char *const short_options = "hs:t:";
const struct option long_options[] = {
{ .name = "help", .has_arg = no_argument, .val = 'h' },
{ .name = "timeout", .has_arg = required_argument, .val = 't' },
{ .name = "source", .has_arg = required_argument, .val = 's' },
{ .name = NULL }
};
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 's':
src_nidstr = optarg;
rc = libcfs_strnid(&src, src_nidstr);
break;
case 't':
timeout = 1000 * atol(optarg);
break;
case 'h':
printf("ping nid[,nid,...]\n"
"\t --source: source nid\n"
"\t --timeout: ping timeout\n"
"\t --help: display this help\n");
return 0;
default:
return 0;
}
}
if (rc < 0)
return rc;
rc = yaml_lnet_ping("ping", timeout, src_nidstr ? &src : NULL, optind,
argc, argv, NLM_F_DUMP);
if (rc <= 0) {
if (rc != -EOPNOTSUPP)
return rc;
}
for (; optind < argc; optind++) {
int rc2;
rc2 = lustre_lnet_ping_nid(argv[optind], src_nidstr, timeout,
-1, &show_rc, &err_rc);
if (rc2 != 0 && (rc > 0 || rc == -EOPNOTSUPP))
rc = rc2;
}
if (show_rc)
cYAML_print_tree(show_rc);
if (err_rc)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
cYAML_free_tree(show_rc);
return rc;
}
static int jt_discover(int argc, char **argv)
{
struct cYAML *err_rc = NULL;
struct cYAML *show_rc = NULL;
int flags = NLM_F_CREATE;
int force = 0;
int rc = 0, opt;
const char *const short_options = "fh";
const struct option long_options[] = {
{ .name = "force", .has_arg = no_argument, .val = 'f' },
{ .name = "help", .has_arg = no_argument, .val = 'h' },
{ .name = NULL }
};
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'f':
/* BSD treats NLM_F_CREATE | NLM_F_EXCL as an add */
flags |= NLM_F_EXCL;
force = 1;
break;
case 'h':
printf("discover nid[,nid,...]\n"
"\t --force: force discovery\n"
"\t --help: display this help\n");
return 0;
default:
return 0;
}
}
if (optind == argc) {
printf("Missing nid argument\n");
return -1;
}
rc = yaml_lnet_ping("discover", 1000, NULL, optind, argc, argv,
flags);
if (rc <= 0) {
if (rc != -EOPNOTSUPP)
return rc;
}
for (; optind < argc; optind++)
rc = lustre_lnet_discover_nid(argv[optind], force, -1, &show_rc,
&err_rc);
if (show_rc)
cYAML_print_tree(show_rc);
if (err_rc)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
cYAML_free_tree(show_rc);
return rc;
}
static int jt_add_udsp(int argc, char **argv)
{
char *src = NULL, *dst = NULL, *rte = NULL;
struct cYAML *err_rc = NULL;
union lnet_udsp_action udsp_action;
long int idx = -1, priority = -1;
int opt, rc = 0;
char *action_type = "pref";
const char *const short_options = "s:d:r:p:i:";
static const struct option long_options[] = {
{ .name = "src", .has_arg = required_argument, .val = 's' },
{ .name = "dst", .has_arg = required_argument, .val = 'd' },
{ .name = "rte", .has_arg = required_argument, .val = 'r' },
{ .name = "priority", .has_arg = required_argument, .val = 'p' },
{ .name = "idx", .has_arg = required_argument, .val = 'i' },
{ .name = NULL } };
rc = check_cmd(udsp_cmds, "udsp", "add", 0, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 's':
src = optarg;
break;
case 'd':
dst = optarg;
break;
case 'r':
rte = optarg;
break;
case 'p':
rc = parse_long(optarg, &priority);
if (rc != 0 || priority < 0) {
printf("Invalid priority \"%s\"\n", optarg);
return -EINVAL;
}
action_type = "priority";
udsp_action.udsp_priority = priority;
break;
case 'i':
rc = parse_long(optarg, &idx);
if (rc != 0 || idx < 0) {
printf("Invalid index \"%s\"\n", optarg);
return -EINVAL;
}
break;
case '?':
print_help(udsp_cmds, "udsp", "add");
default:
return 0;
}
}
if (!(src || dst || rte)) {
print_help(udsp_cmds, "udsp", "add");
return 0;
}
rc = lustre_lnet_add_udsp(src, dst, rte, action_type, &udsp_action,
idx, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int jt_del_udsp(int argc, char **argv)
{
struct cYAML *err_rc = NULL;
long int idx = -2;
int opt, rc = 0;
bool all = false;
const char *const short_options = "ai:";
static const struct option long_options[] = {
{ .name = "all", .has_arg = no_argument, .val = 'a' },
{ .name = "idx", .has_arg = required_argument, .val = 'i' },
{ .name = NULL } };
rc = check_cmd(udsp_cmds, "udsp", "del", 0, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'a':
all = true;
break;
case 'i':
rc = parse_long(optarg, &idx);
if (rc != 0 || idx < -1) {
printf("Invalid index \"%s\"\n", optarg);
return -EINVAL;
}
break;
case '?':
print_help(udsp_cmds, "udsp", "del");
default:
return 0;
}
}
if (all && idx != -2) {
printf("Cannot combine --all with --idx\n");
return -EINVAL;
} else if (all) {
idx = -1;
} else if (idx == -2) {
printf("Must specify --idx or --all\n");
return -EINVAL;
}
rc = lustre_lnet_del_udsp(idx, -1, &err_rc);
if (rc != LUSTRE_CFG_RC_NO_ERR)
cYAML_print_tree2file(stderr, err_rc);
cYAML_free_tree(err_rc);
return rc;
}
static int
fault_attr_health_error_parse(char *error, __u32 *mask)
{
if (!strcasecmp(error, "local_interrupt")) {
*mask |= HSTATUS_LOCAL_INTERRUPT_BIT;
return 0;
}
if (!strcasecmp(error, "local_dropped")) {
*mask |= HSTATUS_LOCAL_DROPPED_BIT;
return 0;
}
if (!strcasecmp(error, "local_aborted")) {
*mask |= HSTATUS_LOCAL_ABORTED_BIT;
return 0;
}
if (!strcasecmp(error, "local_no_route")) {
*mask |= HSTATUS_LOCAL_NO_ROUTE_BIT;
return 0;
}
if (!strcasecmp(error, "local_error")) {
*mask |= HSTATUS_LOCAL_ERROR_BIT;
return 0;
}
if (!strcasecmp(error, "local_timeout")) {
*mask |= HSTATUS_LOCAL_TIMEOUT_BIT;
return 0;
}
if (!strcasecmp(error, "remote_error")) {
*mask |= HSTATUS_REMOTE_ERROR_BIT;
return 0;
}
if (!strcasecmp(error, "remote_dropped")) {
*mask |= HSTATUS_REMOTE_DROPPED_BIT;
return 0;
}
if (!strcasecmp(error, "remote_timeout")) {
*mask |= HSTATUS_REMOTE_TIMEOUT_BIT;
return 0;
}
if (!strcasecmp(error, "network_timeout")) {
*mask |= HSTATUS_NETWORK_TIMEOUT_BIT;
return 0;
}
if (!strcasecmp(error, "random")) {
*mask = HSTATUS_RANDOM;
return 0;
}
return -1;
}
static int
fault_attr_msg_parse(char *msg_str, __u32 *mask_p)
{
if (!strcasecmp(msg_str, "put")) {
*mask_p |= LNET_PUT_BIT;
return 0;
} else if (!strcasecmp(msg_str, "ack")) {
*mask_p |= LNET_ACK_BIT;
return 0;
} else if (!strcasecmp(msg_str, "get")) {
*mask_p |= LNET_GET_BIT;
return 0;
} else if (!strcasecmp(msg_str, "reply")) {
*mask_p |= LNET_REPLY_BIT;
return 0;
}
fprintf(stderr, "unknown message type %s\n", msg_str);
return -1;
}
static int
fault_attr_ptl_parse(char *ptl_str, __u64 *mask_p)
{
unsigned long rc = strtoul(optarg, NULL, 0);
if (rc >= 64) {
fprintf(stderr, "invalid portal: %lu\n", rc);
return -1;
}
*mask_p |= (1ULL << rc);
return 0;
}
static int jt_fault_add(__u32 opc, int argc, char **argv)
{
static const struct option long_options[] = {
{ .name = "dest", .has_arg = required_argument, .val = 'd' },
{ .name = "health_error", .has_arg = required_argument, .val = 'e' },
{ .name = "interval", .has_arg = required_argument, .val = 'i' },
{ .name = "latency", .has_arg = required_argument, .val = 'l' },
{ .name = "message", .has_arg = required_argument, .val = 'm' },
{ .name = "random", .has_arg = no_argument, .val = 'n' },
{ .name = "local_nid", .has_arg = required_argument, .val = 'o' },
{ .name = "portal", .has_arg = required_argument, .val = 'p' },
{ .name = "rate", .has_arg = required_argument, .val = 'r' },
{ .name = "source", .has_arg = required_argument, .val = 's' },
{ .name = "rule_type", .has_arg = required_argument, .val = 't' },
{ .name = "drop_all", .has_arg = no_argument, .val = 'x' },
{ .name = NULL }
};
char *optstr, *cmd;
char *fa_src = NULL, *fa_dst = NULL, *fa_local_nid = NULL;
int opt, rc = 0;
struct lnet_fault_attr attr;
yaml_document_t results;
yaml_emitter_t debug;
if (opc == LNET_CTL_DROP_ADD) {
optstr = "d:e:i:m:no:p:r:s:t:x";
cmd = "drop";
rc = check_cmd(fault_drop_cmds, "drop", "add", 2, argc, argv);
} else {
optstr = "d:l:m:o:p:r:s:";
cmd = "delay";
rc = check_cmd(fault_delay_cmds, "delay", "add", 2, argc, argv);
}
if (rc)
return rc;
memset(&attr, 0, sizeof(attr));
while ((opt = getopt_long(argc, argv, optstr,
long_options, NULL)) != -1) {
switch (opt) {
case 'd': /* dest NID/NET */
fa_dst = optarg;
break;
case 'e':
if (opc == LNET_CTL_DROP_ADD) {
rc = fault_attr_health_error_parse(optarg,
&attr.u.drop.da_health_error_mask);
if (rc)
goto getopt_failed;
}
break;
case 'i': /* time interval (# seconds) for message drop */
if (opc == LNET_CTL_DROP_ADD)
attr.u.drop.da_interval = strtoul(optarg,
NULL, 0);
else
attr.u.delay.la_interval = strtoul(optarg,
NULL, 0);
break;
case 'l': /* seconds to wait before activating rule */
attr.u.delay.la_latency = strtoul(optarg, NULL, 0);
break;
case 'm': /* message types to filter */
rc = fault_attr_msg_parse(optarg, &attr.fa_msg_mask);
if (rc != 0)
goto getopt_failed;
break;
case 'n':
if (opc == LNET_CTL_DROP_ADD)
attr.u.drop.da_random = true;
break;
case 'o':
fa_local_nid = optarg;
break;
case 'p': /* portal to filter */
rc = fault_attr_ptl_parse(optarg, &attr.fa_ptl_mask);
if (rc != 0)
goto getopt_failed;
break;
case 'r': /* drop rate */
if (opc == LNET_CTL_DROP_ADD)
attr.u.drop.da_rate = strtoul(optarg, NULL, 0);
else
attr.u.delay.la_rate = strtoul(optarg, NULL, 0);
break;
case 's': /* source NID/NET */
fa_src = optarg;
break;
case 't':
/* Handled by our caller */
break;
case 'x':
if (opc == LNET_CTL_DROP_ADD)
attr.u.drop.da_drop_all = true;
break;
case '?':
fprintf(stderr, "Unrecognized option %c\n", opt);
break;
default:
fprintf(stderr, "Unrecognized character %c\n", opt);
return 0;
}
}
if (opc == LNET_CTL_DROP_ADD) {
/* NB: drop rate and interval are exclusive to each other */
if (!((attr.u.drop.da_rate == 0) ^
(attr.u.drop.da_interval == 0))) {
fprintf(stderr,
"please provide either drop rate or interval but not both at the same time.\n");
return -1;
}
if (attr.u.drop.da_random &&
attr.u.drop.da_interval == 0) {
fprintf(stderr,
"please provide an interval to randomize\n");
return -1;
}
} else if (opc == LNET_CTL_DELAY_ADD) {
if (!((attr.u.delay.la_rate == 0) ^
(attr.u.delay.la_interval == 0))) {
fprintf(stderr,
"please provide either delay rate or interval but not both at the same time.\n");
return -1;
}
if (attr.u.delay.la_latency == 0) {
fprintf(stderr, "latency cannot be zero\n");
return -1;
}
}
if (!(fa_src && fa_dst)) {
fprintf(stderr,
"Please provide both source and destination of %s rule\n",
cmd);
return -1;
}
rc = yaml_lnet_fault_rule(&results, opc, fa_src, fa_dst, fa_local_nid,
&attr);
if (rc < 0)
return rc;
rc = yaml_emitter_initialize(&debug);
if (rc == 0)
return -EINVAL;
yaml_emitter_set_indent(&debug, LNET_DEFAULT_INDENT);
yaml_emitter_set_output_file(&debug, stdout);
rc = yaml_emitter_dump(&debug, &results);
yaml_emitter_delete(&debug);
yaml_document_delete(&results);
return rc == 0 ? -EINVAL : 0;
getopt_failed:
optind = 1;
return -1;
}
static int jt_fault_drop_add(int argc, char **argv)
{
return jt_fault_add(LNET_CTL_DROP_ADD, argc, argv);
}
static int jt_fault_delay_add(int argc, char **argv)
{
return jt_fault_add(LNET_CTL_DELAY_ADD, argc, argv);
}
static int jt_fault_del_common(__u32 opc, int argc, char **argv)
{
const char *const short_options = "ad:s:";
static const struct option long_options[] = {
{ .name = "all", .has_arg = no_argument, .val = 'a' },
{ .name = "dest", .has_arg = required_argument, .val = 'd' },
{ .name = "source", .has_arg = required_argument, .val = 's' },
{ .name = NULL }
};
yaml_document_t results;
yaml_emitter_t debug;
char *fa_src = NULL, *fa_dst = NULL;
bool all = false;
int opt, rc;
if (opc == LNET_CTL_DROP_DEL)
rc = check_cmd(fault_drop_cmds, "drop", "del", 2, argc, argv);
else
rc = check_cmd(fault_delay_cmds, "delay", "del", 2, argc, argv);
if (rc)
return rc;
while ((opt = getopt_long(argc, argv, short_options,
long_options, NULL)) != -1) {
switch (opt) {
case 'a':
all = true;
case 'd': /* dest NID/NET */
fa_dst = optarg;
break;
case 's': /* source NID/NET */
fa_src = optarg;
break;
default:
return 0;
}
}
if (!all && !(fa_src && fa_dst)) {
fprintf(stderr,
"Failed, please provide source and destination of rule\n");
return -1;
} else if (all && (fa_src || fa_dst)) {
fprintf(stderr, "'-s' or '-d' cannot be combined with '-a'\n");
return -1;
}
rc = yaml_lnet_fault_rule(&results, opc, fa_src, fa_dst, NULL, NULL);
if (rc < 0)
return rc;
rc = yaml_emitter_initialize(&debug);
if (rc == 0)
return -EINVAL;
yaml_emitter_set_indent(&debug, LNET_DEFAULT_INDENT);
yaml_emitter_set_output_file(&debug, stdout);
rc = yaml_emitter_dump(&debug, &results);
yaml_emitter_delete(&debug);
yaml_document_delete(&results);
return rc == 0 ? -EINVAL : 0;
}
static int jt_fault_drop_del(int argc, char **argv)
{
return jt_fault_del_common(LNET_CTL_DROP_DEL, argc, argv);
}
static int jt_fault_delay_del(int argc, char **argv)
{
return jt_fault_del_common(LNET_CTL_DELAY_DEL, argc, argv);
}
static int jt_fault_reset_common(__u32 opc, int argc, char **argv)
{
yaml_document_t results;
yaml_emitter_t debug;
int rc;
if (opc == LNET_CTL_DROP_RESET)
rc = check_cmd(fault_drop_cmds, "drop", "reset", 2, argc, argv);
else
rc = check_cmd(fault_delay_cmds, "delay", "reset", 2, argc,
argv);
if (rc)
return rc;
rc = yaml_lnet_fault_rule(&results, opc, NULL, NULL, NULL, NULL);
if (rc < 0)
return rc;
rc = yaml_emitter_initialize(&debug);
if (rc == 0)
return -EINVAL;
yaml_emitter_set_indent(&debug, LNET_DEFAULT_INDENT);
yaml_emitter_set_output_file(&debug, stdout);
rc = yaml_emitter_dump(&debug, &results);
yaml_emitter_delete(&debug);
yaml_document_delete(&results);
return rc == 0 ? -EINVAL : 0;
}
static int jt_fault_drop_reset(int argc, char **argv)
{
return jt_fault_reset_common(LNET_CTL_DROP_RESET, argc, argv);
}
static int jt_fault_delay_reset(int argc, char **argv)
{
return jt_fault_reset_common(LNET_CTL_DELAY_RESET, argc, argv);
}
static int jt_fault_show_common(__u32 opc, int argc, char **argv)
{
yaml_document_t results;
yaml_emitter_t debug;
int rc;
if (opc == LNET_CTL_DROP_LIST)
rc = check_cmd(fault_drop_cmds, "drop", "show", 1, argc, argv);
else
rc = check_cmd(fault_delay_cmds, "delay", "show", 1, argc,
argv);
if (rc)
return rc;
rc = yaml_lnet_fault_rule(&results, opc, NULL, NULL, NULL, NULL);
if (rc < 0)
return rc;
rc = yaml_emitter_initialize(&debug);
if (rc == 0)
return -EINVAL;
yaml_emitter_set_indent(&debug, LNET_DEFAULT_INDENT);
yaml_emitter_set_output_file(&debug, stdout);
rc = yaml_emitter_dump(&debug, &results);
yaml_emitter_cleanup(&debug);
yaml_document_delete(&results);
return rc == 0 ? -EINVAL : 0;
}
static int jt_fault_drop_show(int argc, char **argv)
{
return jt_fault_show_common(LNET_CTL_DROP_LIST, argc, argv);
}
static int jt_fault_delay_show(int argc, char **argv)
{
return jt_fault_show_common(LNET_CTL_DELAY_LIST, argc, argv);
}
int main(int argc, char **argv)
{
int rc = 0;
struct cYAML *err_rc = NULL;
rc = lustre_lnet_config_lib_init();
if (rc < 0) {
cYAML_build_error(-1, -1, "lnetctl", "startup",
"cannot register LNet device", &err_rc);
cYAML_print_tree2file(stderr, err_rc);
return rc;
}
return cfs_parser(argc, argv, cmd_list);
}