sync to v1.0.29-29-g9267509 9267509 fcoeadm: display strings for new port speeds 671b7f9 fcoemon: Fix IEEE state machine 4982e60 man: Fix typo in fcoemon documentation f90bbd7 FIPVLAN: Really break out of the recv_loop upon fip_recv error fa308a6 doc: Update QUICKSTART/INSTALL docs for systemd init file install 09caead fcoemon: systemd socket activation 41e9d79 fcoemon: add systemd service file d8deef2 fcnsq: Fixup 64bit integer handling 6750b2a fcnsq: Fixup help text e566b3e Fix integer formatting 9869390 build: Fix build with '-Wl,--as-needed' 0e5d536 build: Add missing 'DESTDIR' when installing bash completion 6bde8d1 fipvlan: filter interfaces from rtnl_getlink 45d0e70 fipvlan: handle errors from fip socket creation 78ea81a fipvlan: break out of receive loop on error 86928f2 fipvlan: Do not shut down FCoE connections on physical interface 08d9872 fipvlan: Update manpage to reflect correct timeout 0559d7d fipvlan: Leave link up if requested 9ade5c6 fipvlan: update manpage 3ded166 fipvlan: Re-send VLAN discovery 9f5e376 fipvlan: Update wait loop to wait for VLANs 16e421a fipvlan: Start FCoE from netlink handler ac1fc20 fipvlan: create VLANs from netlink handler 6ce709f fipvlan: Extract create_missing_vlan function from loop ef209fd fipvlan: start VLAN interface from netlink handler 29d1722 fipvlan: Only shutdown interfaces if no vlans are created 921a055 fipvlan fails on powerpc 0f63a3e Don't call AM_INIT_AUTOMAKE twice fd085bc man: Fix small typo regarding --fcf option --- INSTALL | 3 + Makefile.am | 16 ++- QUICKSTART | 3 + configure.ac | 9 +- doc/fcoeadm.8 | 18 +-- doc/fcoeadm.txt | 4 +- doc/fcoemon.8 | 2 +- doc/fcoemon.txt | 3 +- doc/fipvlan.8 | 17 ++- doc/fipvlan.txt | 9 +- etc/systemd/fcoe.service | 14 ++ etc/systemd/fcoemon.socket | 6 + fcnsq.c | 20 ++- fcoeadm_display.c | 10 +- fcoemon.c | 100 ++++++++++++-- fcping.c | 11 +- fipvlan.c | 327 ++++++++++++++++++++++++++------------------- lib/fip.c | 20 ++- 18 files changed, 394 insertions(+), 198 deletions(-) diff --git a/INSTALL b/INSTALL index 3abdf07..ea8c95e 100644 --- a/INSTALL +++ b/INSTALL @@ -19,6 +19,9 @@ DEPENDENCIES 1) Bootstrap, configure, make and make install # ./bootstrap.sh + Either execute the next line for System V init script install # rpm --eval "%configure" | sh + or the following line to install systemd unit scripts + # rpm --eval "%configure --with-systemdsystemunitdir=/" | sh # make # make install diff --git a/Makefile.am b/Makefile.am index 5cbc15f..e7df6f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,21 +9,18 @@ AM_CFLAGS = -Wall -Wformat=2 -Werror -Wmissing-prototypes -Wstrict-prototypes ## rules for building fcoeadm fcoeadm_SOURCES = fcoeadm.c fcoeadm_display.c -fcoeadm_LDADD = lib/libutil.a libopenfcoe.a +fcoeadm_LDADD = lib/libutil.a libopenfcoe.a $(HBAAPI_LIBS) fcoeadm_CFLAGS = $(AM_CFLAGS) $(HBAAPI_CFLAGS) -fcoeadm_LDFLAGS = $(AM_LDFLAGS) $(HBAAPI_LIBS) ## rules for building fcoemon fcoemon_SOURCES = fcoemon.c -fcoemon_LDADD = lib/libutil.a +fcoemon_LDADD = lib/libutil.a -lrt fcoemon_CFLAGS = $(AM_CFLAGS) $(DCBD_CFLAGS) -fcoemon_LDFLAGS = $(AM_LDFLAGS) -lrt ## rules for building fcping fcping_SOURCES = fcping.c -fcping_LDADD = lib/libutil.a +fcping_LDADD = lib/libutil.a $(HBAAPI_LIBS) -lrt fcping_CFLAGS = $(AM_CFLAGS) $(HBAAPI_CFLAGS) -fcping_LDFLAGS = $(AM_LDFLAGS) $(HBAAPI_LIBS) -lrt ## rules for building fipvlan fipvlan_SOURCES = fipvlan.c @@ -44,6 +41,11 @@ noinst_HEADERS = fcoeadm_display.h fcoe_clif.h fcoemon.h \ fcoe_configdir = ${sysconfdir}/fcoe dist_fcoe_config_DATA = etc/cfg-ethx +## install systemd service files +if HAVE_SYSTEMD +systemdsystemunit_DATA = etc/systemd/fcoe.service etc/systemd/fcoemon.socket +endif + ## man pages for fcoeadm and fcoemon dist_man_MANS = doc/fcoeadm.8 doc/fcoemon.8 doc/fipvlan.8 doc/fcrls.8 \ doc/fcnsq.8 doc/fcping.8 @@ -67,7 +69,7 @@ init_d_SCRIPTS = etc/initd/fcoe dist_noinst_DATA = README COPYING INSTALL fcoe-utils.spec etc/config -BASH_COMPLETION_DIR=/etc/bash_completion.d/ +BASH_COMPLETION_DIR=$(DESTDIR)/etc/bash_completion.d/ install-data-hook: if [ ! -f ${DESTDIR}${fcoe_configdir}/config ] ; then \ diff --git a/QUICKSTART b/QUICKSTART index 6fc82b3..c001bc1 100644 --- a/QUICKSTART +++ b/QUICKSTART @@ -201,7 +201,10 @@ PROCESS 2) Bootstrap, configure, make and make install # cd fcoe-utils # ./bootstrap.sh + Either execute the next line for System V init script install # rpm --eval "%configure" | sh + or the following line to install systemd unit scripts + # rpm --eval "%configure --with-systemdsystemunitdir=/" | sh # make # make install diff --git a/configure.ac b/configure.ac index 73c140f..107d039 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,4 @@ AC_INIT([fcoe-utils], [1.0.29], [fcoe-devel@open-fcoe.org]) -AM_INIT_AUTOMAKE([foreign]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) AM_INIT_AUTOMAKE([foreign]) @@ -18,6 +17,14 @@ AC_SUBST([LLDPAD_CFLAGS]) PKG_CHECK_MODULES([LIBHBALINUX], [libhbalinux >= 1.0.13]) AC_SUBST([LIBHBALINUX_CFLAGS]) +PKG_PROG_PKG_CONFIG +AC_ARG_WITH([systemdsystemunitdir], + AS_HELP_STRING([--with-systemdsystemunitdir=DIR], + [Directory for systemd service files]), [], + [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)]) +AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) +AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir"]) + AC_CONFIG_FILES([Makefile fcoe-utils.spec include/fcoe_utils_version.h]) AC_OUTPUT diff --git a/doc/fcoeadm.8 b/doc/fcoeadm.8 index 11da6e3..2fefd70 100644 --- a/doc/fcoeadm.8 +++ b/doc/fcoeadm.8 @@ -1,13 +1,13 @@ '\" t .\" Title: fcoeadm .\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.76.1 -.\" Date: 11/08/2012 +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 10/14/2013 .\" Manual: Open-FCoE Tools .\" Source: Open-FCoE .\" Language: English .\" -.TH "FCOEADM" "8" "11/08/2012" "Open\-FCoE" "Open\-FCoE Tools" +.TH "FCOEADM" "8" "10/14/2013" "Open\-FCoE" "Open\-FCoE Tools" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -39,7 +39,7 @@ fcoeadm \- The Open\-FCoE Administration Tool .sp \fBfcoeadm\fR \-i|\-\-interface [\fIethX\fR] .sp -\fBfcoeadm\fR \-f|\-\-fcfs [\fIethX\fR] +\fBfcoeadm\fR \-f|\-\-fcf [\fIethX\fR] .sp \fBfcoeadm\fR \-t|\-\-target [\fIethX\fR] .sp @@ -91,7 +91,7 @@ Rescan for new targets and LUNs on the provided instance\&. This command will no Show information about the FCoE instance on the specified network interface, or all FCoE instances if no network interface is specified\&. .RE .PP -\fB\-f\fR, \fB\-\-fcfs\fR [\fIethX\fR] +\fB\-f\fR, \fB\-\-fcf\fR [\fIethX\fR] .RS 4 Show information about the discovered Fibre Channel Forwarders (FCFs) on the specified network interface, or all discovered FCFs if no network interface is specified\&. .RE @@ -143,13 +143,9 @@ command\&. .RE .SH "INTERFACE NAMES" .sp -The actual name for \fIethX\fR depends on the \fBAUTO_VLAN\fR setting in -the fcoemon interface configuration (/etc/fcoe/cfg-ethX, see \fBfcoemon\fR)\&. +The actual name for \fIethX\fR depends on the \fBAUTO_VLAN\fR setting in the fcoemon interface configuration (/etc/fcoe/cfg\-ethX, see \fBfcoemon\fR)\&. .sp -If \fBAUTO_VLAN\fR is set to \fIyes\fR, the interface name \fIethX\fR -references the network device itself. If \fBAUTO_VLAN\fR is set to -\fIno\fR, the interface name \fIethX\fR references the VLAN device\&. -.RE +If \fBAUTO_VLAN\fR is set to \fIyes\fR, the interface name \fIethX\fR references the network device itself\&. If \fBAUTO_VLAN\fR is set to \fIno\fR, the interface name \fIethX\fR references the VLAN device\&. .SH "EXAMPLES" .sp Creates an FCoE instance on eth2\&.101 diff --git a/doc/fcoeadm.txt b/doc/fcoeadm.txt index 788625c..28ed482 100644 --- a/doc/fcoeadm.txt +++ b/doc/fcoeadm.txt @@ -29,7 +29,7 @@ SYNOPSIS *fcoeadm* -i|--interface [_ethX_] -*fcoeadm* -f|--fcfs [_ethX_] +*fcoeadm* -f|--fcf [_ethX_] *fcoeadm* -t|--target [_ethX_] @@ -89,7 +89,7 @@ OPERATIONS Show information about the FCoE instance on the specified network interface, or all FCoE instances if no network interface is specified. -*-f*, *--fcfs* [_ethX_]:: +*-f*, *--fcf* [_ethX_]:: Show information about the discovered Fibre Channel Forwarders (FCFs) on the specified network interface, or all discovered FCFs if no network interface is specified. diff --git a/doc/fcoemon.8 b/doc/fcoemon.8 index e9a045b..020394e 100644 --- a/doc/fcoemon.8 +++ b/doc/fcoemon.8 @@ -358,7 +358,7 @@ indicates whether a FIP responder should be activated on this device to support Note that the attached Ethernet peer device (e\&.g\&. FCoE capable switch port) must have compatible settings For DCB and FCoE to function properly\&. .SS "/etc/init\&.d/fcoe" .sp -This is the \fBfcoe\fR system service script\&. This script is invoked by the init process or by the service command to start and stop the \fBfcoemon\fR\&. +This is the \fBfcoe\fR system service script\&. This script is invoked by the init process or by the service command to start and stop the \fBfcoemon\fR\&. On systemd-enabled systems, \fBfcoemon\fR is controlled via the \fBfcoe.service\fR unit. .SH "VLAN NAMING CONVENTIONS" .sp If a new VLAN device is created (see the description of the \fIAUTO_VLAN\fR setting above), it will have the name \fIdev\fR\&.\fIvlan\fR\-fcoe; where \fIdev\fR is the name of the Ethernet parent device and \fIvlan\fR is the discovered VLAN ID number\&. diff --git a/doc/fcoemon.txt b/doc/fcoemon.txt index ec15197..7ccf892 100644 --- a/doc/fcoemon.txt +++ b/doc/fcoemon.txt @@ -56,7 +56,7 @@ OPTIONS *-d*, *--debug*:: Enable debugging messages. *-l*, *--legacy*:: - Force fcoemon to use the legacy /sys/modlue/libfcoe/parameters/ + Force fcoemon to use the legacy /sys/module/libfcoe/parameters/ interface. The default is to use the newer /sys/bus/fcoe/ interfaces if they are available. *-s*, *--syslog*:: @@ -214,6 +214,7 @@ must have compatible settings For DCB and FCoE to function properly. ~~~~~~~~~~~~~~~~ This is the *fcoe* system service script. This script is invoked by the init process or by the service command to start and stop the *fcoemon*. +On systemd-enabled systems, *fcoemon* is controlled via the *fcoe.service* unit. VLAN NAMING CONVENTIONS ----------------------- diff --git a/doc/fipvlan.8 b/doc/fipvlan.8 index f81cb3a..1d2b707 100644 --- a/doc/fipvlan.8 +++ b/doc/fipvlan.8 @@ -1,13 +1,13 @@ '\" t .\" Title: fipvlan .\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.76.1 -.\" Date: 03/18/2013 +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 12/02/2013 .\" Manual: Open-FCoE Tools .\" Source: Open-FCoE .\" Language: English .\" -.TH "FIPVLAN" "8" "03/18/2013" "Open\-FCoE" "Open\-FCoE Tools" +.TH "FIPVLAN" "8" "12/02/2013" "Open\-FCoE" "Open\-FCoE Tools" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -29,9 +29,9 @@ fipvlan \- Fibre Channel over Ethernet VLAN Discovery .SH "SYNOPSIS" .sp -\fBfipvlan\fR [\-c|\-\-create] [\-s|\-\-start] [\-m|\-\-mode fabric|vn2vn] \fIinterfaces\fR +\fBfipvlan\fR [\-c|\-\-create] [\-d|\-\-debug] [\-s|\-\-start] [\-m|\-\-mode fabric|vn2vn] [\-u|\-\-link\-up] \fIinterfaces\fR .sp -\fBfipvlan\fR \-a|\-\-auto [\-c|\-\-create] [\-d|\-\-debug] [\-s|\-\-start] [\-m|\-\-mode fabric|vn2vn] [\-l|\-\-link\-retry \fIcount\fR] +\fBfipvlan\fR \-a|\-\-auto [\-c|\-\-create] [\-d|\-\-debug] [\-s|\-\-start] [\-m|\-\-mode fabric|vn2vn] [\-l|\-\-link\-retry \fIcount\fR] [\-u|\-\-link\-up] .sp \fBfipvlan\fR \-h|\-\-help .sp @@ -83,7 +83,12 @@ to VLAN interface names\&. .RS 4 Retry check for link up to \fIcount\fR -times\&. The link state is checked every 500 ms\&. The default number of retries is 20\&. +times\&. The link state is checked every 1000 ms\&. The default number of retries is 20\&. +.RE +.PP +\fB\-u\fR, \fB\-\-link\-up\fR +.RS 4 +Leave link up if a FIP response has been received\&. .RE .PP \fB\-h\fR, \fB\-\-help\fR diff --git a/doc/fipvlan.txt b/doc/fipvlan.txt index 9699197..5ba0324 100644 --- a/doc/fipvlan.txt +++ b/doc/fipvlan.txt @@ -19,10 +19,12 @@ fipvlan - Fibre Channel over Ethernet VLAN Discovery SYNOPSIS -------- -*fipvlan* [-c|--create] [-s|--start] [-m|--mode fabric|vn2vn] _interfaces_ +*fipvlan* [-c|--create] [-d|--debug] [-s|--start] + [-m|--mode fabric|vn2vn] [-u|--link-up] _interfaces_ *fipvlan* -a|--auto [-c|--create] [-d|--debug] [-s|--start] [-m|--mode fabric|vn2vn] [-l|--link-retry _count_] + [-u|--link-up] *fipvlan* -h|--help @@ -73,7 +75,10 @@ OPTIONS *-l*, *--link-retry* _count_:: Retry check for link up to _count_ times. The link state is - checked every 500 ms. The default number of retries is 20. + checked every 1000 ms. The default number of retries is 20. + +*-u*, *--link-up*:: + Leave link up if a FIP response has been received. *-h*, *--help*:: Display a help message with basic usage instructions diff --git a/etc/systemd/fcoe.service b/etc/systemd/fcoe.service new file mode 100644 index 0000000..5e5c8a2 --- /dev/null +++ b/etc/systemd/fcoe.service @@ -0,0 +1,14 @@ +[Unit] +Description=Open-FCoE initiator daemon +After=syslog.target network.target + +[Service] +Type=simple +EnvironmentFile=/etc/sysconfig/fcoe +ExecStartPre=/sbin/modprobe -qa $SUPPORTED_DRIVERS +ExecStart=/usr/sbin/fcoemon $FCOEMON_OPTS + +[Install] +WantedBy=multi-user.target +Also=lldpad.socket +Also=fcoemon.socket diff --git a/etc/systemd/fcoemon.socket b/etc/systemd/fcoemon.socket new file mode 100644 index 0000000..4de8715 --- /dev/null +++ b/etc/systemd/fcoemon.socket @@ -0,0 +1,6 @@ +[Socket] +ListenDatagram=@/com/intel/fcoemon +PassCredentials=true + +[Install] +WantedBy=sockets.target diff --git a/fcnsq.c b/fcnsq.c index 7b45a32..1597cd5 100644 --- a/fcnsq.c +++ b/fcnsq.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -228,7 +229,7 @@ static int gpn_id(int bsg, u32 fcid) rjt = gn_id(bsg, fcid, FC_NS_GPN_ID, &wwpn); if (rjt) goto fail; - print_result("Port Name", "%16.16llx\n", wwpn); + print_result("Port Name", "%16.16jx\n", (uintmax_t)wwpn); return 0; fail: if (rjt == (u16) ~0) @@ -249,7 +250,7 @@ static int gnn_id(int bsg, u32 fcid) rjt = gn_id(bsg, fcid, FC_NS_GNN_ID, &wwnn); if (rjt) goto fail; - print_result("Node Name", "%16.16llx\n", wwnn); + print_result("Node Name", "%16.16jx\n", (uintmax_t)wwnn); return 0; fail: if (rjt == (u16) ~0) @@ -365,7 +366,7 @@ static void help(int status) " --gspn \n" " --gsnn \n" "Options:\n" - " --quiet print minimal results on success, and no error messages\n" + " --quiet|-q print minimal results on success, and no error messages\n" "\n" "Port IDs and World Wide Names must be specified in hexadecimal.\n" ); @@ -376,11 +377,12 @@ int main(int argc, char *argv[]) { char *bsg; int bsg_dev; - u32 port_id; - u64 wwnn; + u32 port_id = 0; + u64 wwnn = 0; int rc = 0; enum commands cmd = 0; char c; + uintmax_t wwnn_tmp = 0; while(1) { c = getopt_long_only(argc, argv, "", options, NULL); @@ -399,13 +401,17 @@ int main(int argc, char *argv[]) if (cmd) help(-1); cmd = c; - sscanf(optarg, "%x", &port_id); + if (sscanf(optarg, "%x", &port_id) != 1) + help(-1); break; case GSNN_NN: if (cmd) help(-1); cmd = c; - sscanf(optarg, "%llx", &wwnn); + if (sscanf(optarg, "%jx", &wwnn_tmp) == 1) + wwnn = (u64)wwnn_tmp; + else + help(-1); break; } } diff --git a/fcoeadm_display.c b/fcoeadm_display.c index 287e370..9b96170 100644 --- a/fcoeadm_display.c +++ b/fcoeadm_display.c @@ -110,7 +110,13 @@ struct sa_nameval port_speeds[] = { { "Unknown", HBA_PORTSPEED_UNKNOWN }, { "1 Gbit", HBA_PORTSPEED_1GBIT }, { "2 Gbit", HBA_PORTSPEED_2GBIT }, + { "4 Gbit", HBA_PORTSPEED_4GBIT }, { "10 Gbit", HBA_PORTSPEED_10GBIT }, + { "8 Gbit", HBA_PORTSPEED_8GBIT }, + { "16 Gbit", HBA_PORTSPEED_16GBIT }, + { "32 Gbit", HBA_PORTSPEED_32GBIT }, + { "20 Gbit", HBA_PORTSPEED_20GBIT }, + { "40 Gbit", HBA_PORTSPEED_40GBIT }, { "Not Negotiated", HBA_PORTSPEED_NOT_NEGOTIATED }, { NULL, 0 } }; @@ -1417,8 +1423,8 @@ static void print_fcoe_fcf_device(void *ep, UNUSED void *arg) if (!buf) buf = temp; printf(" Connection Mode: %s\n", buf); - printf(" Fabric Name: 0x%016lx\n", fcf->fabric_name); - printf(" Switch Name 0x%016lx\n", fcf->switch_name); + printf(" Fabric Name: 0x%016" PRIx64 "\n", fcf->fabric_name); + printf(" Switch Name 0x%016" PRIx64 "\n", fcf->switch_name); mac2str(fcf->mac, mac, MAX_STR_LEN); printf(" MAC Address: %s\n", mac); printf(" FCF Priority: %u\n", fcf->priority); diff --git a/fcoemon.c b/fcoemon.c index a5babfa..b3120bc 100644 --- a/fcoemon.c +++ b/fcoemon.c @@ -1357,12 +1357,8 @@ ieee_state_set(struct fcm_netif *ff, enum ieee_state new_state) getstr(&ieee_states, new_state)); } - if (new_state == IEEE_GET_STATE) { - ff->ieee_state = new_state; + if (new_state == IEEE_GET_STATE) clear_ieee_info(ff); - ieee_get_req(ff); - return; - } ff->ieee_state = new_state; ff->ieee_resp_pending = 0; @@ -2637,7 +2633,7 @@ static void fcm_dcbd_get_oper(struct fcm_netif *ff, char *resp, char *cp) if (ep) { FCM_LOG_DEV(ff, "Invalid get oper response " - "parse error byte %ld, resp %s", ep - cp, cp); + "parse error byte %td, resp %s", ep - cp, cp); fcm_dcbd_state_set(ff, FCD_ERROR); } else { if (val && fcoe_config.debug) @@ -3035,6 +3031,50 @@ static void fcm_fcoe_action(struct fcoe_port *p) /* * Called for all ports. For FCoE ports and candidates, + * get IEEE DCBX information and set the next action. + */ +static void fcm_netif_ieee_advance(struct fcm_netif *ff) +{ + enum fcp_action action; + + ASSERT(ff); + ASSERT(fcm_clif); + + if (fcm_clif->cl_busy) + return; + + if (ff->ieee_resp_pending) + return; + + switch (ff->ieee_state) { + case IEEE_INIT: + break; + case IEEE_GET_STATE: + ieee_get_req(ff); + break; + case IEEE_DONE: + action = validate_ieee_info(ff); + switch (action) { + case FCP_DESTROY_IF: + case FCP_ENABLE_IF: + case FCP_ACTIVATE_IF: + fcp_action_set(ff->ifname, action); + break; + case FCP_DISABLE_IF: + case FCP_ERROR: + fcp_action_set(ff->ifname, FCP_DISABLE_IF); + break; + case FCP_WAIT: + default: + break; + } + default: + break; + } +} + +/* + * Called for all ports. For FCoE ports and candidates, * get information and send to dcbd. */ static void fcm_netif_advance(struct fcm_netif *ff) @@ -3161,8 +3201,10 @@ static void fcm_handle_changes(void) /* * Perform pending actions (dcbd queries) on network interfaces. */ - TAILQ_FOREACH(ff, &fcm_netif_head, ff_list) + TAILQ_FOREACH(ff, &fcm_netif_head, ff_list) { fcm_netif_advance(ff); + fcm_netif_ieee_advance(ff); + } /* * Perform actions on FCoE ports @@ -3546,12 +3588,54 @@ err: sendto(snum, rbuf, MSG_RBUF, 0, (struct sockaddr *)&from, fromlen); } +static int fcm_systemd_socket(void) +{ + char *env, *ptr; + unsigned int p, l; + + env = getenv("LISTEN_PID"); + if (!env) + return -1; + + p = strtoul(env, &ptr, 10); + if (ptr && ptr == env) { + FCM_LOG_DBG("Invalid value '%s' for LISTEN_PID\n", env); + return -1; + } + if ((pid_t)p != getpid()) { + FCM_LOG_DBG("Invalid PID '%d' from LISTEN_PID\n", p); + return -1; + } + env = getenv("LISTEN_FDS"); + if (!env) { + FCM_LOG_DBG("LISTEN_FDS is not set\n"); + return -1; + } + l = strtoul(env, &ptr, 10); + if (ptr && ptr == env) { + FCM_LOG_DBG("Invalid value '%s' for LISTEN_FDS\n", env); + return -1; + } + if (l != 1) { + FCM_LOG_DBG("LISTEN_FDS specified %d fds\n", l); + return -1; + } + /* systemd returns fds with an offset of '3' */ + return 3; +} + static int fcm_srv_create(struct fcm_srv_info *srv_info) { socklen_t addrlen; struct sockaddr_un addr; int rc = 0; + srv_info->srv_sock = fcm_systemd_socket(); + if (srv_info->srv_sock > 0) { + FCM_LOG_DBG("Using systemd socket\n"); + goto out_done; + } + srv_info->srv_sock = socket(AF_LOCAL, SOCK_DGRAM, 0); if (srv_info->srv_sock < 0) { FCM_LOG_ERR(errno, "Failed to create socket\n"); @@ -3570,7 +3654,7 @@ static int fcm_srv_create(struct fcm_srv_info *srv_info) rc = errno; goto err_close; } - +out_done: sa_select_add_fd(srv_info->srv_sock, fcm_srv_receive, NULL, NULL, srv_info); diff --git a/fcping.c b/fcping.c index c6f74a6..399b778 100644 --- a/fcping.c +++ b/fcping.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -810,17 +811,17 @@ static void fp_check_data_len(void) printf("Maximum ECHO data allowed by the Fabric (0x%06x) : %d bytes.\n" "Maximum ECHO data allowed by the Source (0x%06x) : %d bytes.\n" "Maximum ECHO data allowed by the Target (0x%06x) : %d bytes.\n" - "Maximum ECHO data requested from user input (-s) : %lu " + "Maximum ECHO data requested from user input (-s) : %" PRIu32 " " "(default %d) bytes.\n", FC_WKA_FABRIC_CONTROLLER, flen, sid, slen, fp_did, dlen, - fp_len - FP_LEN_ECHO, FP_LEN_DEF); + (uint32_t)(fp_len - FP_LEN_ECHO), FP_LEN_DEF); /* fp_len is the total payload, including 4 bytes for ECHO command */ fp_len = MIN(fp_len, plen + FP_LEN_ECHO); - printf("Actual FC ELS ECHO data size used : %lu bytes.\n" + printf("Actual FC ELS ECHO data size used : %" PRIu32 " bytes.\n" "Actual FC ELS ECHO payload size used : %d bytes " - "(including %ld bytes ECHO command).\n", - fp_len - FP_LEN_ECHO, fp_len, FP_LEN_ECHO); + "(including %zu bytes ECHO command).\n", + (uint32_t)(fp_len - FP_LEN_ECHO), fp_len, FP_LEN_ECHO); } /* diff --git a/fipvlan.c b/fipvlan.c index 6f8cf39..cc71412 100644 --- a/fipvlan.c +++ b/fipvlan.c @@ -67,6 +67,7 @@ struct { bool start; bool vn2vn; bool debug; + bool link_up; int link_retry; char suffix[256]; } config = { @@ -76,6 +77,7 @@ struct { .create = false, .vn2vn = false, .debug = false, + .link_up = false, .link_retry = 20, .suffix = "", }; @@ -139,6 +141,7 @@ struct iff { bool req_sent; bool resp_recv; bool fip_ready; + bool fcoe_started; TAILQ_ENTRY(iff) list_node; struct iff_list_head vlans; }; @@ -157,6 +160,8 @@ struct fcf { struct fcf_list_head fcfs = TAILQ_HEAD_INITIALIZER(fcfs); static struct fcf_list_head vn2vns = TAILQ_HEAD_INITIALIZER(vn2vns); +static int create_and_start_vlan(struct fcf *fcf, bool vn2vn); + static struct fcf *lookup_fcf(struct fcf_list_head *head, int ifindex, uint16_t vlan, unsigned char *mac) { @@ -316,6 +321,9 @@ static int fip_recv_vlan_note(struct fiphdr *fh, int ifindex, bool vn2vn) fcf->vlan = vlan; memcpy(fcf->mac_addr, tlvs.mac->mac_addr, ETHER_ADDR_LEN); TAILQ_INSERT_TAIL(head, fcf, list_node); + if (!config.create) + continue; + create_and_start_vlan(fcf, vn2vn); } return 0; @@ -362,8 +370,14 @@ static void rtnl_recv_newlink(struct nlmsghdr *nh) struct rtattr *linkinfo[__IFLA_INFO_MAX]; struct rtattr *vlan[__IFLA_VLAN_MAX]; struct iff *iff, *real_dev; + struct fcf_list_head *head; bool running; + if (config.vn2vn) + head = &vn2vns; + else + head = &fcfs; + FIP_LOG_DBG("RTM_NEWLINK: ifindex %d, type %d, flags %x", ifm->ifi_index, ifm->ifi_type, ifm->ifi_flags); @@ -378,12 +392,38 @@ static void rtnl_recv_newlink(struct nlmsghdr *nh) running = !!(ifm->ifi_flags & (IFF_RUNNING | IFF_SLAVE)); iff = lookup_iff(ifm->ifi_index, NULL); if (iff) { + int ifindex; + /* already tracking, update operstate and return */ iff->running = running; - if (iff->running) - pfd_add(iff->ps); - else + if (!iff->running) { pfd_remove(iff->ps); + return; + } + pfd_add(iff->ps); + if (!config.start) + return; + + FIP_LOG_DBG("Checking for FCoE on %sif %d", + iff->is_vlan ? "VLAN " : "", iff->ifindex); + if (iff->is_vlan) { + real_dev = find_vlan_real_dev(iff); + if (!real_dev) { + FIP_LOG_ERR(ENODEV, "VLAN %d without a parent", + iff->ifindex); + return; + } + ifindex = real_dev->ifindex; + } else + ifindex = iff->ifindex; + + if (!iff->fcoe_started && + lookup_fcf(head, ifindex, iff->vid, NULL)) { + printf("Starting FCoE on interface %s\n", + iff->ifname); + fcoe_instance_start(iff->ifname); + iff->fcoe_started = true; + } return; } @@ -407,6 +447,19 @@ static void rtnl_recv_newlink(struct nlmsghdr *nh) memcpy(iff->mac_addr, RTA_DATA(ifla[IFLA_ADDRESS]), ETHER_ADDR_LEN); strncpy(iff->ifname, RTA_DATA(ifla[IFLA_IFNAME]), IFNAMSIZ); + if (!config.automode) { + int i, iff_selected = 0; + + for (i = 0; i < config.namec; i++) { + if (!strcmp(iff->ifname, config.namev[i])) + iff_selected = 1; + } + if (!iff_selected) { + FIP_LOG_DBG("ignoring if %s\n", iff->ifname); + free(iff); + return; + } + } if (ifla[IFLA_LINKINFO]) { parse_linkinfo(linkinfo, ifla[IFLA_LINKINFO]); /* Track VLAN devices separately */ @@ -416,11 +469,16 @@ static void rtnl_recv_newlink(struct nlmsghdr *nh) parse_vlaninfo(vlan, linkinfo[IFLA_INFO_DATA]); iff->vid = *(int *)RTA_DATA(vlan[IFLA_VLAN_ID]); real_dev = find_vlan_real_dev(iff); - if (real_dev) - TAILQ_INSERT_TAIL(&real_dev->vlans, - iff, list_node); - else + if (!real_dev) { free(iff); + return; + } + TAILQ_INSERT_TAIL(&real_dev->vlans, iff, list_node); + if (!iff->running) { + FIP_LOG_DBG("vlan if %d not running, " + "starting", iff->ifindex); + rtnl_set_iff_up(iff->ifindex, NULL); + } return; } /* ignore bonding interfaces */ @@ -435,7 +493,7 @@ static void rtnl_recv_newlink(struct nlmsghdr *nh) /* command line arguments */ -#define GETOPT_STR "acdf:l:m:shv" +#define GETOPT_STR "acdf:l:m:suhv" static const struct option long_options[] = { { "auto", no_argument, NULL, 'a' }, @@ -445,6 +503,7 @@ static const struct option long_options[] = { { "suffix", required_argument, NULL, 'f' }, { "link-retry", required_argument, NULL, 'l' }, { "mode", required_argument, NULL, 'm' }, + { "link-up", required_argument, NULL, 'u' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 } @@ -462,6 +521,7 @@ static void help(int status) " -f, --suffix Append the suffix to VLAN interface name\n" " -l, --link-retry Number of retries for link up\n" " -m, --mode Link mode, either fabric or vn2vn\n" + " -u, --link-up Leave link up after FIP response\n" " -h, --help Display this help and exit\n" " -v, --version Display version information and exit\n", exe); @@ -471,7 +531,7 @@ static void help(int status) static void parse_cmdline(int argc, char **argv) { - char c; + signed char c; while (1) { c = getopt_long(argc, argv, GETOPT_STR, long_options, NULL); @@ -508,6 +568,9 @@ static void parse_cmdline(int argc, char **argv) exit(1); } break; + case 'u': + config.link_up = true; + break; case 'h': help(0); break; @@ -539,59 +602,60 @@ static int rtnl_listener_handler(struct nlmsghdr *nh, UNUSED void *arg) return -1; } -static void -create_missing_vlans_list(struct fcf_list_head *list, const char *label) +static int +create_and_start_vlan(struct fcf *fcf, bool vn2vn) { - struct fcf *fcf; struct iff *real_dev, *vlan; char vlan_name[IFNAMSIZ]; int rc; - if (!config.create) - return; - - TAILQ_FOREACH(fcf, list, list_node) { - real_dev = lookup_iff(fcf->ifindex, NULL); - if (!real_dev) { - FIP_LOG_ERR(ENODEV, - "lost device %d with discovered %s?\n", - fcf->ifindex, label); - continue; - } - if (!fcf->vlan) { - /* - * If the vlan notification has VLAN id 0, - * skip creating vlan interface, and FCoE is - * started on the physical interface itself. - */ - FIP_LOG_DBG("VLAN id is 0 for %s\n", real_dev->ifname); - continue; - } + real_dev = lookup_iff(fcf->ifindex, NULL); + if (!real_dev) { + FIP_LOG_ERR(ENODEV, + "lost device %d with discovered %s?\n", + fcf->ifindex, vn2vn ? "VN2VN" : "FCF"); + return -ENXIO; + } + if (!fcf->vlan) { + /* + * If the vlan notification has VLAN id 0, + * skip creating vlan interface, and FCoE is + * started on the physical interface itself. + */ + FIP_LOG_DBG("VLAN id is 0 for %s\n", real_dev->ifname); + vlan = real_dev; + } else { vlan = lookup_vlan(fcf->ifindex, fcf->vlan); if (vlan) { FIP_LOG_DBG("VLAN %s.%d already exists as %s\n", real_dev->ifname, fcf->vlan, vlan->ifname); - continue; + return 0; } snprintf(vlan_name, IFNAMSIZ, "%s.%d%s", real_dev->ifname, fcf->vlan, config.suffix); rc = vlan_create(fcf->ifindex, fcf->vlan, vlan_name); - if (rc < 0) + if (rc < 0) { printf("Failed to create VLAN device %s\n\t%s\n", vlan_name, strerror(-rc)); - else - printf("Created VLAN device %s\n", vlan_name); - rtnl_set_iff_up(0, vlan_name); + return rc; + } + printf("Created VLAN device %s\n", vlan_name); } - printf("\n"); -} + if (!config.start) + return rc; -static void create_missing_vlans(void) -{ - if (!TAILQ_EMPTY(&fcfs)) - create_missing_vlans_list(&fcfs, "FCF"); - if (!TAILQ_EMPTY(&vn2vns)) - create_missing_vlans_list(&vn2vns, "VN2VN"); + if (!vlan->running) { + FIP_LOG_DBG("%s if %d not running, starting", + vlan == real_dev ? "real" : "vlan", + vlan->ifindex); + rtnl_set_iff_up(vlan->ifindex, NULL); + } else if (!vlan->fcoe_started) { + printf("Starting FCoE on interface %s\n", + vlan->ifname); + fcoe_instance_start(vlan->ifname); + vlan->fcoe_started = true; + } + return rc; } static int fcoe_mod_instance_start(const char *ifname) @@ -666,34 +730,6 @@ static void determine_libfcoe_interface(void) } } -static void start_fcoe(void) -{ - struct fcf_list_head *head; - struct fcf *fcf; - struct iff *iff; - - if (config.vn2vn) - head = &vn2vns; - else - head = &fcfs; - - TAILQ_FOREACH(fcf, head, list_node) { - if (fcf->vlan) - iff = lookup_vlan(fcf->ifindex, fcf->vlan); - else - iff = lookup_iff(fcf->ifindex, NULL); - if (!iff) { - FIP_LOG_ERR(ENODEV, - "Cannot start FCoE on VLAN %d, ifindex %d, " - "because the VLAN device does not exist", - fcf->vlan, fcf->ifindex); - continue; - } - printf("Starting FCoE on interface %s\n", iff->ifname); - fcoe_instance_start(iff->ifname); - } -} - static void print_list(struct fcf_list_head *list, const char *label) { struct iff *iff; @@ -749,9 +785,15 @@ static void recv_loop(int timeout) rtnl_recv(pfd[0].fd, rtnl_listener_handler, NULL); /* everything else should be FIP packet sockets */ for (i = 1; i < pfd_len; i++) { - if (pfd[i].revents & POLLIN) - fip_recv(pfd[i].fd, fip_vlan_handler, NULL); + if (pfd[i].revents & POLLIN) { + rc = fip_recv(pfd[i].fd, fip_vlan_handler, + NULL); + if (rc < 0) + break; + } } + if (i < pfd_len) + break; } } @@ -763,7 +805,7 @@ static void find_interfaces(int ns) static int probe_fip_interface(struct iff *iff) { - int origdev = 1; + int origdev = 1, rc; if (iff->resp_recv) return 0; @@ -785,6 +827,10 @@ static int probe_fip_interface(struct iff *iff) if (!iff->fip_ready) { iff->ps = fip_socket(iff->ifindex, FIP_NONE); + if (iff->ps < 0) { + FIP_LOG_DBG("if %d not ready\n", iff->ifindex); + return 0; + } setsockopt(iff->ps, SOL_PACKET, PACKET_ORIGDEV, &origdev, sizeof(origdev)); pfd_add(iff->ps); @@ -792,34 +838,23 @@ static int probe_fip_interface(struct iff *iff) } if (config.vn2vn) - fip_send_vlan_request(iff->ps, iff->ifindex, iff->mac_addr, - FIP_ALL_VN2VN); + rc = fip_send_vlan_request(iff->ps, iff->ifindex, + iff->mac_addr, FIP_ALL_VN2VN); else - fip_send_vlan_request(iff->ps, iff->ifindex, iff->mac_addr, - FIP_ALL_FCF); - iff->req_sent = true; - return 0; + rc = fip_send_vlan_request(iff->ps, iff->ifindex, + iff->mac_addr, FIP_ALL_FCF); + if (rc == 0) + iff->req_sent = true; + return rc == 0 ? 0 : 1; } static int send_vlan_requests(void) { struct iff *iff; - int i; int skipped = 0; - if (config.automode) { - TAILQ_FOREACH(iff, &interfaces, list_node) { - skipped += probe_fip_interface(iff); - } - } else { - for (i = 0; i < config.namec; i++) { - iff = lookup_iff(0, config.namev[i]); - if (!iff) { - skipped++; - continue; - } - skipped += probe_fip_interface(iff); - } + TAILQ_FOREACH(iff, &interfaces, list_node) { + skipped += probe_fip_interface(iff); } return skipped; } @@ -829,51 +864,70 @@ static void do_vlan_discovery(void) struct iff *iff; int retry_count = 0; int skip_retry_count = 0; - int skipped = 0; + int skipped = 0, retry_iff = 0; retry: skipped += send_vlan_requests(); if (skipped && skip_retry_count++ < config.link_retry) { - FIP_LOG_DBG("waiting for IFF_RUNNING [%d]\n", skip_retry_count); + FIP_LOG_DBG("waiting for IFF_RUNNING [%d/%d]\n", + skip_retry_count, config.link_retry); recv_loop(500); skipped = 0; retry_count = 0; goto retry; } recv_loop(200); - TAILQ_FOREACH(iff, &interfaces, list_node) + TAILQ_FOREACH(iff, &interfaces, list_node) { + if (!iff->fip_ready) { + FIP_LOG_DBG("if %d: skipping, FIP not ready\n", + iff->ifindex); + continue; + } + if (!iff->running && iff->linkup_sent) { + FIP_LOG_DBG("if %d: waiting for IFF_RUNNING [%d]\n", + iff->ifindex, retry_count); + retry_iff++; + continue; + } /* if we did not receive a response, retry */ - if (iff->req_sent && !iff->resp_recv && - retry_count++ < MAX_VLAN_RETRIES) { - FIP_LOG_DBG("VLAN discovery RETRY [%d]", retry_count); - goto retry; + if (iff->req_sent && !iff->resp_recv) { + FIP_LOG_DBG("if %d: VLAN discovery RETRY [%d]", + iff->ifindex, retry_count); + iff->req_sent = false; + retry_iff++; + continue; } + if (config.create) { + struct iff *vlan; + + TAILQ_FOREACH(vlan, &iff->vlans, list_node) { + if (!vlan->running) { + FIP_LOG_DBG("vlan %d: waiting for " + "IFF_RUNNING [%d]", + vlan->ifindex, retry_count); + retry_iff++; + continue; + } + } + } + } + if (retry_iff && retry_count++ < config.link_retry) { + recv_loop(1000); + retry_iff = 0; + goto retry; + } } static void cleanup_interfaces(void) { struct iff *iff; - int i; - int skipped = 0; - if (config.automode) { - TAILQ_FOREACH(iff, &interfaces, list_node) { - if (iff->linkup_sent && - (!iff->running || !iff->req_sent || !iff->resp_recv)) { - FIP_LOG_DBG("shutdown if %d", - iff->ifindex); - rtnl_set_iff_down(iff->ifindex, NULL); - iff->linkup_sent = false; - } - } - } else { - for (i = 0; i < config.namec; i++) { - iff = lookup_iff(0, config.namev[i]); - if (!iff) { - skipped++; + TAILQ_FOREACH(iff, &interfaces, list_node) { + if (iff->linkup_sent) { + if (config.link_up && iff->resp_recv) continue; - } - if (iff->linkup_sent && - (!iff->running || !iff->req_sent || !iff->resp_recv)) { + if (iff->fcoe_started) + continue; + if (TAILQ_EMPTY(&iff->vlans)) { FIP_LOG_DBG("shutdown if %d", iff->ifindex); rtnl_set_iff_down(iff->ifindex, NULL); @@ -881,8 +935,8 @@ static void cleanup_interfaces(void) } } } - } + /* this is to not require headers from libcap */ static inline int capget(cap_user_header_t hdrp, cap_user_data_t datap) { @@ -934,29 +988,24 @@ int main(int argc, char **argv) determine_libfcoe_interface(); find_interfaces(ns); - while ((TAILQ_EMPTY(&interfaces)) && ++find_cnt < 5) { - FIP_LOG_DBG("no interfaces found, trying again"); - find_interfaces(ns); - } + if (config.automode) + while ((TAILQ_EMPTY(&interfaces)) && ++find_cnt < 5) { + FIP_LOG_DBG("no interfaces found, trying again"); + find_interfaces(ns); + } if (TAILQ_EMPTY(&interfaces)) { - FIP_LOG_ERR(ENODEV, "no interfaces to perform discovery on"); + if (config.automode) + FIP_LOG_ERR(ENODEV, + "no interfaces to perform discovery on"); + else + FIP_LOG("no interfaces to perform discovery on"); exit(1); } do_vlan_discovery(); rc = print_results(); - if (!rc && config.create) { - create_missing_vlans(); - /* - * need to listen for the RTM_NETLINK messages - * about the new VLAN devices - */ - recv_loop(500); - } - if (!rc && config.start) - start_fcoe(); cleanup_interfaces(); diff --git a/lib/fip.c b/lib/fip.c index 73bf03e..6657b61 100644 --- a/lib/fip.c +++ b/lib/fip.c @@ -95,10 +95,11 @@ static int fip_get_sanmac(int ifindex, unsigned char *addr) * @mac: MAC address to add or delete * @multi: false if unicast, true if multicast address */ -static void +static int fip_socket_add_addr(int s, int ifindex, bool add, const __u8 *mac, bool multi) { struct packet_mreq mr; + int rc = 0; memset(&mr, 0, sizeof(mr)); mr.mr_ifindex = ifindex; @@ -107,9 +108,12 @@ fip_socket_add_addr(int s, int ifindex, bool add, const __u8 *mac, bool multi) memcpy(mr.mr_address, mac, ETHER_ADDR_LEN); if (setsockopt(s, SOL_PACKET, add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, - &mr, sizeof(mr)) < 0) + &mr, sizeof(mr)) < 0) { FIP_LOG_DBG("PACKET_%s_MEMBERSHIP:failed\n", add ? "ADD" : "DROP"); + rc = -errno; + } + return rc; } /** @@ -118,16 +122,16 @@ fip_socket_add_addr(int s, int ifindex, bool add, const __u8 *mac, bool multi) * @ifindex: network interface index to send on * @add: 1 to add 0 to del */ -static void fip_socket_sanmac(int s, int ifindex, int add) +static int fip_socket_sanmac(int s, int ifindex, int add) { unsigned char smac[ETHER_ADDR_LEN]; if (fip_get_sanmac(ifindex, smac)) { FIP_LOG_DBG("%s: no sanmac, ifindex %d\n", __func__, ifindex); - return; + return -ENXIO; } - fip_socket_add_addr(s, ifindex, add, smac, false); + return fip_socket_add_addr(s, ifindex, add, smac, false); } /** @@ -210,7 +214,11 @@ int fip_socket(int ifindex, enum fip_multi multi) if (s < 0) return s; - fip_socket_sanmac(s, ifindex, 1); + rc = fip_socket_sanmac(s, ifindex, 1); + if (rc < 0) { + close(s); + return rc; + } if (multi != FIP_NONE) fip_socket_multi(s, ifindex, true, multi);