From 0120b08f7e12f3bccb758cc4f5f2b3a5a1fdbfff Mon Sep 17 00:00:00 2001 From: Martin Belanger Date: Thu, 20 May 2021 13:49:44 -0400 Subject: [PATCH] Add --host-iface option --- Documentation/nvme-connect-all.txt | 10 ++++++++- Documentation/nvme-connect.txt | 10 ++++++++- Documentation/nvme-discover.txt | 20 ++++++++++++------ etc/discovery.conf.in | 2 +- fabrics.c | 33 ++++++++++++++++++++++++------ fabrics.h | 1 + nvme.h | 1 + 7 files changed, 62 insertions(+), 15 deletions(-) diff --git a/Documentation/nvme-connect-all.txt b/Documentation/nvme-connect-all.txt index 820dd6c6..1cb7822b 100644 --- a/Documentation/nvme-connect-all.txt +++ b/Documentation/nvme-connect-all.txt @@ -13,6 +13,7 @@ SYNOPSIS [--traddr= | -a ] [--trsvcid= | -s ] [--host-traddr= | -w ] + [--host-iface= | -f ] [--hostnqn= | -q ] [--hostid= | -I ] [--raw= | -r ] @@ -77,7 +78,14 @@ OPTIONS -w :: --host-traddr=:: This field specifies the network address used on the host to connect - to the Discovery Controller. + to the Controller. For TCP, this sets the source address on the socket. + +-f :: +--host-iface=:: + This field specifies the network interface used on the host to connect + to the Controller (e.g. IP eth1, enp2s0, enx78e7d1ea46da). This forces + the connection to be made on a specific interface instead of letting + the system decide. -q :: --hostnqn=:: diff --git a/Documentation/nvme-connect.txt b/Documentation/nvme-connect.txt index 757e3d02..4d7bb52b 100644 --- a/Documentation/nvme-connect.txt +++ b/Documentation/nvme-connect.txt @@ -14,6 +14,7 @@ SYNOPSIS [--traddr= | -a ] [--trsvcid= | -s ] [--host-traddr= | -w ] + [--host-iface= | -f ] [--hostnqn= | -q ] [--hostid= | -I ] [--nr-io-queues=<#> | -i <#>] @@ -69,7 +70,14 @@ OPTIONS -w :: --host-traddr=:: This field specifies the network address used on the host to connect - to the Controller. + to the Controller. For TCP, this sets the source address on the socket. + +-f :: +--host-iface=:: + This field specifies the network interface used on the host to connect + to the Controller (e.g. IP eth1, enp2s0, enx78e7d1ea46da). This forces + the connection to be made on a specific interface instead of letting + the system decide. -q :: --hostnqn=:: diff --git a/Documentation/nvme-discover.txt b/Documentation/nvme-discover.txt index 74add74c..d0a281a9 100644 --- a/Documentation/nvme-discover.txt +++ b/Documentation/nvme-discover.txt @@ -13,6 +13,7 @@ SYNOPSIS [--traddr= | -a ] [--trsvcid= | -s ] [--host-traddr= | -w ] + [--host-iface= | -f ] [--hostnqn= | -q ] [--hostid= | -I ] [--raw= | -r ] @@ -35,7 +36,7 @@ DESCRIPTION Send one or more Get Log Page requests to a NVMe-over-Fabrics Discovery Controller. -If no parameters are given, then 'nvme discover' will attempt to +If no parameters are given, then 'nvme discover' will attempt to find a /etc/nvme/discovery.conf file to use to supply a list of Discovery commands to run. If no /etc/nvme/discovery.conf file exists, the command will quit with an error. @@ -46,7 +47,7 @@ request will then be sent to the specified Discovery Controller. BACKGROUND ---------- -The NVMe-over-Fabrics specification defines the concept of a +The NVMe-over-Fabrics specification defines the concept of a Discovery Controller that an NVMe Host can query on a fabric network to discover NVMe subsystems contained in NVMe Targets which it can connect to on the network. The Discovery Controller @@ -66,7 +67,7 @@ resources are allocated to the NVMe Host for a connection. A Discovery Controller has it's own NQN defined in the NVMe-over-Fabrics specification, *nqn.2014-08.org.nvmexpress.discovery*. All Discovery Controllers must use this NQN name. This NQN is used by default by -nvme-cli for the 'discover' command. +nvme-cli for the 'discover' command. OPTIONS ------- @@ -99,11 +100,18 @@ OPTIONS -w :: --host-traddr=:: This field specifies the network address used on the host to connect - to the Discovery Controller. - + to the Controller. For TCP, this sets the source address on the socket. + +-f :: +--host-iface=:: + This field specifies the network interface used on the host to connect + to the Controller (e.g. IP eth1, enp2s0, enx78e7d1ea46da). This forces + the connection to be made on a specific interface instead of letting + the system decide. + -q :: --hostnqn=:: - Overrides the default host NQN that identifies the NVMe Host. + Overrides the default host NQN that identifies the NVMe Host. If this option is not specified, the default is read from /etc/nvme/hostnqn first. If that does not exist, the autogenerated NQN value from the NVMe Host kernel module is used next. diff --git a/etc/discovery.conf.in b/etc/discovery.conf.in index 14e0d9c3..cfdac1ea 100644 --- a/etc/discovery.conf.in +++ b/etc/discovery.conf.in @@ -1,4 +1,4 @@ # Used for extracting default parameters for discovery # # Example: -# --transport= --traddr= --trsvcid= --host-traddr= +# --transport= --traddr= --trsvcid= --host-traddr= --host-iface= diff --git a/fabrics.c b/fabrics.c index 77eb8f4e..db42ddbd 100644 --- a/fabrics.c +++ b/fabrics.c @@ -66,6 +66,7 @@ const char *conarg_transport = "transport"; const char *conarg_traddr = "traddr"; const char *conarg_trsvcid = "trsvcid"; const char *conarg_host_traddr = "host_traddr"; +const char *conarg_host_iface = "host_iface"; struct fabrics_config fabrics_cfg = { .ctrl_loss_tmo = -1, @@ -79,6 +80,7 @@ struct connect_args { char *traddr; char *trsvcid; char *host_traddr; + char *host_iface; struct connect_args *next; struct connect_args *tail; }; @@ -301,6 +303,7 @@ static bool ctrl_matches_connectargs(const char *name, struct connect_args *args cargs.traddr = parse_conn_arg(addr, ' ', conarg_traddr); cargs.trsvcid = parse_conn_arg(addr, ' ', conarg_trsvcid); cargs.host_traddr = parse_conn_arg(addr, ' ', conarg_host_traddr); + cargs.host_iface = parse_conn_arg(addr, ' ', conarg_host_iface); if (!strcmp(cargs.subsysnqn, NVME_DISC_SUBSYS_NAME)) { char *kato_str = nvme_get_ctrl_attr(path, "kato"), *p; @@ -332,7 +335,9 @@ static bool ctrl_matches_connectargs(const char *name, struct connect_args *args (!strcmp(cargs.trsvcid, args->trsvcid) || !strcmp(args->trsvcid, "none")) && (!strcmp(cargs.host_traddr, args->host_traddr) || - !strcmp(args->host_traddr, "none"))) + !strcmp(args->host_traddr, "none")) && + (!strcmp(cargs.host_iface, args->host_iface) || + !strcmp(args->host_iface, "none"))) found = true; free(cargs.subsysnqn); @@ -340,6 +345,7 @@ static bool ctrl_matches_connectargs(const char *name, struct connect_args *args free(cargs.traddr); free(cargs.trsvcid); free(cargs.host_traddr); + free(cargs.host_iface); free(addr); free(path); @@ -395,6 +401,7 @@ static struct connect_args *extract_connect_args(char *argstr) cargs->traddr = parse_conn_arg(argstr, ',', conarg_traddr); cargs->trsvcid = parse_conn_arg(argstr, ',', conarg_trsvcid); cargs->host_traddr = parse_conn_arg(argstr, ',', conarg_host_traddr); + cargs->host_iface = parse_conn_arg(argstr, ',', conarg_host_iface); return cargs; } @@ -405,6 +412,7 @@ static void destruct_connect_args(struct connect_args *cargs) free(cargs->traddr); free(cargs->trsvcid); free(cargs->host_traddr); + free(cargs->host_iface); } static void free_connect_args(struct connect_args *cargs) @@ -983,6 +991,7 @@ int build_options(char *argstr, int max_len, bool discover) if (add_argument(&argstr, &max_len, "transport", fabrics_cfg.transport) || add_argument(&argstr, &max_len, "traddr", fabrics_cfg.traddr) || add_argument(&argstr, &max_len, "host_traddr", fabrics_cfg.host_traddr) || + add_argument(&argstr, &max_len, "host_iface", fabrics_cfg.host_iface) || add_argument(&argstr, &max_len, "trsvcid", fabrics_cfg.trsvcid) || ((fabrics_cfg.hostnqn || nvmf_hostnqn_file()) && add_argument(&argstr, &max_len, "hostnqn", fabrics_cfg.hostnqn)) || @@ -1174,6 +1183,13 @@ retry: p+= len; } + if (fabrics_cfg.host_iface && strcmp(fabrics_cfg.host_iface, "none")) { + len = sprintf(p, ",host_iface=%s", fabrics_cfg.host_iface); + if (len < 0) + return -EINVAL; + p+= len; + } + if (fabrics_cfg.reconnect_delay) { len = sprintf(p, ",reconnect_delay=%d", fabrics_cfg.reconnect_delay); if (len < 0) @@ -1313,6 +1329,7 @@ static bool cargs_match_found(struct nvmf_disc_rsp_page_entry *entry) cargs.subsysnqn = strdup(entry->subnqn); cargs.trsvcid = strdup(entry->trsvcid); cargs.host_traddr = strdup(fabrics_cfg.host_traddr ?: "\0"); + cargs.host_iface = strdup(fabrics_cfg.host_iface ?: "\0"); /* check if we have a match in the discovery recursion */ while (c) { @@ -1320,7 +1337,8 @@ static bool cargs_match_found(struct nvmf_disc_rsp_page_entry *entry) !strcmp(cargs.transport, c->transport) && !strcmp(cargs.traddr, c->traddr) && !strcmp(cargs.trsvcid, c->trsvcid) && - !strcmp(cargs.host_traddr, c->host_traddr)) + !strcmp(cargs.host_traddr, c->host_traddr) && + !strcmp(cargs.host_iface, c->host_iface)) return true; c = c->next; } @@ -1550,7 +1568,8 @@ free_and_continue: free(all_args); free(argv); fabrics_cfg.transport = fabrics_cfg.traddr = - fabrics_cfg.trsvcid = fabrics_cfg.host_traddr = NULL; + fabrics_cfg.trsvcid = fabrics_cfg.host_traddr = + fabrics_cfg.host_iface = NULL; } out: @@ -1569,7 +1588,8 @@ int fabrics_discover(const char *desc, int argc, char **argv, bool connect) OPT_LIST("transport", 't', &fabrics_cfg.transport, "transport type"), OPT_LIST("traddr", 'a', &fabrics_cfg.traddr, "transport address"), OPT_LIST("trsvcid", 's', &fabrics_cfg.trsvcid, "transport service id (e.g. IP port)"), - OPT_LIST("host-traddr", 'w', &fabrics_cfg.host_traddr, "host traddr (e.g. FC WWN's)"), + OPT_LIST("host-traddr", 'w', &fabrics_cfg.host_traddr, "host traddr (e.g. FC WWN's or IP source address)"), + OPT_LIST("host-iface", 'f', &fabrics_cfg.host_iface, "host transport interface (e.g. IP eth1, enp2s0)"), OPT_LIST("hostnqn", 'q', &fabrics_cfg.hostnqn, "user-defined hostnqn (if default not used)"), OPT_LIST("hostid", 'I', &fabrics_cfg.hostid, "user-defined hostid (if default not used)"), OPT_LIST("raw", 'r', &fabrics_cfg.raw, "raw output file"), @@ -1586,7 +1606,7 @@ int fabrics_discover(const char *desc, int argc, char **argv, bool connect) OPT_INT("nr-poll-queues", 'P', &fabrics_cfg.nr_poll_queues, "number of poll queues to use (default 0)"), OPT_INT("queue-size", 'Q', &fabrics_cfg.queue_size, "number of io queue elements to use (default 128)"), OPT_FLAG("persistent", 'p', &fabrics_cfg.persistent, "persistent discovery connection"), - OPT_FLAG("quiet", 'S', &quiet, "suppress already connected errors"), + OPT_FLAG("quiet", 'S', &quiet, "suppress already connected errors"), OPT_FLAG("matching", 'm', &fabrics_cfg.matching_only, "connect only records matching the traddr"), OPT_FMT("output-format", 'o', &fabrics_cfg.output_format, output_format), OPT_END() @@ -1651,7 +1671,8 @@ int fabrics_connect(const char *desc, int argc, char **argv) OPT_LIST("nqn", 'n', &fabrics_cfg.nqn, "nqn name"), OPT_LIST("traddr", 'a', &fabrics_cfg.traddr, "transport address"), OPT_LIST("trsvcid", 's', &fabrics_cfg.trsvcid, "transport service id (e.g. IP port)"), - OPT_LIST("host-traddr", 'w', &fabrics_cfg.host_traddr, "host traddr (e.g. FC WWN's)"), + OPT_LIST("host-traddr", 'w', &fabrics_cfg.host_traddr, "host traddr (e.g. FC WWN's or IP source address)"), + OPT_LIST("host-iface", 'f', &fabrics_cfg.host_iface, "host transport interface (e.g. IP eth1, enp2s0)"), OPT_LIST("hostnqn", 'q', &fabrics_cfg.hostnqn, "user-defined hostnqn"), OPT_LIST("hostid", 'I', &fabrics_cfg.hostid, "user-defined hostid (if default not used)"), OPT_INT("nr-io-queues", 'i', &fabrics_cfg.nr_io_queues, "number of io queues to use (default is core count)"), diff --git a/fabrics.h b/fabrics.h index b98f6b0d..9b2554eb 100644 --- a/fabrics.h +++ b/fabrics.h @@ -20,6 +20,7 @@ struct fabrics_config { const char *traddr; const char *trsvcid; const char *host_traddr; + const char *host_iface; const char *hostnqn; const char *hostid; int nr_io_queues; diff --git a/nvme.h b/nvme.h index e33094d0..3b733675 100644 --- a/nvme.h +++ b/nvme.h @@ -82,6 +82,7 @@ struct nvme_ctrl { char *traddr; char *trsvcid; char *host_traddr; + char *host_iface; char *hostnqn; char *hostid; -- 2.50.1