File fcoe-utils-rc2-update of Package open-fcoe
updates to open-fcoe commit:-
From: Vasu Dev <vasu.dev@intel.com>
commit 95becb29bce2d8d94687f7c83d5f009e945be3de
Author: Chris Leech <christopher.leech@intel.com>
Date: Wed Mar 17 12:02:51 2010 -0700
fipvlan: make output able to show complete interface names up to IFNAMSIZ
This update adds auto fipvlan creations beside few minor fixes & improvements.
Signed-off-by: Vasu Dev <vasu.dev@intel.com>
---
Makefile.am | 20 +
QUICKSTART | 3
configure.ac | 3
debug/fcoedump.sh | 67 +++-
etc/cfg-ethx | 5
fcoe_utils.c | 191 -----------
fcoe_utils.h | 85 -----
fcoe_utils_version.h.in | 6
fcoemon.c | 200 ++++++++++-
fcoemon.h | 7
fcoemon_utils.c | 688 ---------------------------------------
fcoemon_utils.h | 268 ---------------
fipvlan.c | 683 ++++++++++++++++-----------------------
include/fcoe_utils.h | 85 +++++
include/fcoe_utils_version.h.in | 6
include/fcoemon_utils.h | 270 +++++++++++++++
include/fip.h | 25 +
include/list.h | 444 -------------------------
include/log.h | 15 -
include/rtnetlink.h | 63 ++++
lib/Makefile.am | 3
lib/fcoe_utils.c | 191 +++++++++++
lib/fip.c | 155 +++++++++
lib/rtnetlink.c | 429 ++++++++++++++++++++++++
lib/sa_log.c | 256 +++++++++++++++
lib/sa_other.c | 69 ++++
lib/sa_select.c | 213 ++++++++++++
lib/sa_timer.c | 226 +++++++++++++
log.c | 87 -----
29 files changed, 2530 insertions(+), 2233 deletions(-)
delete mode 100644 fcoe_utils.c
delete mode 100644 fcoe_utils.h
delete mode 100644 fcoe_utils_version.h.in
delete mode 100644 fcoemon_utils.c
delete mode 100644 fcoemon_utils.h
create mode 100644 include/fcoe_utils.h
create mode 100644 include/fcoe_utils_version.h.in
create mode 100644 include/fcoemon_utils.h
delete mode 100644 include/list.h
delete mode 100644 include/log.h
create mode 100644 include/rtnetlink.h
create mode 100644 lib/Makefile.am
create mode 100644 lib/fcoe_utils.c
create mode 100644 lib/fip.c
create mode 100644 lib/rtnetlink.c
create mode 100644 lib/sa_log.c
create mode 100644 lib/sa_other.c
create mode 100644 lib/sa_select.c
create mode 100644 lib/sa_timer.c
delete mode 100644 log.c
diff --git a/Makefile.am b/Makefile.am
index e533cf7..bdd510f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,3 +1,6 @@
+# build libutil first
+SUBDIRS = lib .
+
## target programs, to be built and installed in $(prefix)/sbin
sbin_PROGRAMS = fcoeadm fcping fipvlan fcnsq fcrls
if WITH_DCB
@@ -12,9 +15,10 @@ AM_CFLAGS = -DSYSCONFDIR="\"${sysconfdir}\""
## rules for building fcoeadm
## only listed sources get packaged, so must list all headers too
-fcoeadm_SOURCES = fcoeadm_display.c fcoeadm.c fcoeadm.h fcoe_utils.c \
-fcoe_utils.h fcoe_utils_version.h include/fc_scsi.h include/fc_types.h \
+fcoeadm_SOURCES = fcoeadm_display.c fcoeadm.c fcoeadm.h \
+include/fc_scsi.h include/fc_types.h \
include/net_types.h fcoe_clif.h
+fcoeadm_LDADD = lib/libutil.a
## fcoeadm uses HBAAPI, so get the right flags for compiling and linking
fcoeadm_CFLAGS = $(HBAAPI_CFLAGS)
@@ -22,7 +26,8 @@ fcoeadm_LDFLAGS = $(HBAAPI_LIBS)
## rules for building fcping
## only listed sources get packaged, so must list all headers too
-fcping_SOURCES = fcping.c fcoe_utils.c fcoe_utils.h
+fcping_SOURCES = fcping.c
+fcping_LDADD = lib/libutil.a
## fcping uses HBAAPI, so get the right flags for compiling and linking
fcping_CFLAGS = $(HBAAPI_CFLAGS)
@@ -30,9 +35,10 @@ fcping_LDFLAGS = $(HBAAPI_LIBS) -lrt
## rules for building fcoemon
## only listed sources get packaged, so must list all headers too
-fcoemon_SOURCES = fcoemon_utils.c fcoemon.c fcoemon.h fcoemon_utils.h \
-fcoe_utils.c fcoe_utils.h fcoe_utils_version.h include/fc_scsi.h \
+fcoemon_SOURCES = fcoemon.c fcoemon.h \
+include/fc_scsi.h \
include/fc_types.h include/net_types.h fcoe_clif.h
+fcoemon_LDADD = lib/libutil.a
## fcoemon needs headers from dcbd, get the right include path for them
fcoemon_CFLAGS = $(DCBD_CFLAGS)
@@ -40,8 +46,8 @@ fcoemon_LDFLAGS = -lrt
## rules for building fipvlan
## only listed sources get packaged, so must list all headers too
-fipvlan_SOURCES = fipvlan.c fcoe_utils_version.h include/fip.h \
-log.c include/log.h include/list.h
+fipvlan_SOURCES = fipvlan.c include/fip.h
+fipvlan_LDADD = lib/libutil.a
## install configuration file in $(prefix)/etc/fcoe
fcoe_configdir = ${sysconfdir}/fcoe
diff --git a/QUICKSTART b/QUICKSTART
index 766c068..e1d0e00 100644
--- a/QUICKSTART
+++ b/QUICKSTART
@@ -54,6 +54,9 @@ git://open-fcoe.org/openfc/fcoe-utils.git
LibFCoE
FCoE
+ Enable the block layer
+ Block layer SG support v4
+
Device Drivers -> Network Device Support -> Ethernet (10000 Mbit)
Intel(R) 10GbE PCI Express adapters support
Data Center Bridging (DCB) Support
diff --git a/configure.ac b/configure.ac
index 517b9c2..db4e55c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,6 +3,7 @@ AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CC
AM_PROG_CC_C_O
+AC_PROG_RANLIB
PKG_CHECK_MODULES([HBAAPI], [HBAAPI])
AC_SUBST([HBAAPI_CFLAGS])
@@ -19,6 +20,6 @@ AS_IF([test "X$with_dcb" != Xno],
[PKG_CHECK_MODULES([DCBD], [dcbd])
AC_SUBST([DCBD_CFLAGS])])
-AC_CONFIG_FILES([Makefile fcoe-utils.spec fcoe_utils_version.h])
+AC_CONFIG_FILES([Makefile lib/Makefile fcoe-utils.spec include/fcoe_utils_version.h])
AC_OUTPUT
diff --git a/debug/fcoedump.sh b/debug/fcoedump.sh
index 3c4bac6..44e858a 100755
--- a/debug/fcoedump.sh
+++ b/debug/fcoedump.sh
@@ -1,3 +1,4 @@
+#!/bin/bash
###############################################################################
#
# fcoe_debug: print debugging information for fcoe
@@ -17,24 +18,51 @@ else
PHYSDEV=$DEVICE
fi
-kernel_info () {
+kernel_info()
+{
echo -e "\n###KERNEL INFO###"
uname -a
+
+ if [ -f "/proc/config.gz" ]
+ then
+ echo -e "\nzcat /proc/config.gz"
+ zcat /proc/config.gz
+ else
+ echo -e "\n/proc/config.gz does not exist."
+ fi
}
-system_info () {
+system_info()
+{
echo -e "\n###System Info###"
- echo -e "#lsscsi:"
+
+ echo -e "#lsscsi"
lsscsi
- echo -e "#lspci:"
+
+ echo -e "#lspci"
lspci
- echo -e "#check symbols:"
+ echo -e "#grep dcbnl_init /proc/kallsyms"
grep dcbnl_init /proc/kallsyms
- grep fcoe /proc/kallsyms
+
+ echo -e "#grep scsi_transport_fc /proc/kallsyms"
+ grep scsi_transport_fc /proc/kallsyms
+
+ echo -e "#grep libfc /proc/kallsyms"
+ grep libfc /proc/kallsyms | grep -v libfcoe
+
+ echo -e "#grep libfcoe /proc/kallsyms"
+ grep libfcoe /proc/kallsyms
+
+ echo -e "#grep fcoe /proc/kallsyms"
+ grep fcoe /proc/kallsyms | grep -v libfcoe
+
+ echo -e "#lsmod"
+ lsmod
}
-adapter_info () {
+adapter_info()
+{
if [ $DEVICE != $PHYSDEV ]
then
echo -e "\n###Adapter INFO VLAN $DEVICE"
@@ -63,7 +91,8 @@ adapter_info () {
ifconfig $PHYSDEV
}
-dcb_info () {
+dcb_info()
+{
echo -e "\n###DCB INFO"
echo -e "#tc config"
tc qdisc
@@ -99,7 +128,8 @@ dcb_info () {
dcbtool gp $PHYSDEV ll:0
}
-fcoe_info () {
+fcoe_info()
+{
echo -e "\n###FCOE Info"
echo -e "#service fcoe status"
service fcoe status
@@ -111,8 +141,16 @@ fcoe_info () {
fcoeadm -t
}
-sysfs_dump () {
- echo -e "###SYSFS dump"
+bsg_info()
+{
+ echo -e "\n###BSG Info"
+ echo -e "#find /dev/bsg/"
+ find /dev/bsg/ 2>&1
+}
+
+sysfs_dump()
+{
+ echo -e "\n###SYSFS dump"
echo -e "#sysfs fc_host dump"
find /sys/class/fc_host/host*/ -type f -print -exec cat '{}' \;
echo -e "#sysfs fc_transport dump"
@@ -123,7 +161,8 @@ sysfs_dump () {
find /sys/class/fc_vports/*/ -type f -print -exec cat '{}' \;
}
-logfile_dump() {
+logfile_dump()
+{
echo "###LOGFILES"
echo "#/var/log/messages"
cat /var/log/messages
@@ -132,12 +171,14 @@ logfile_dump() {
dmesg
}
-fcoe_debug () {
+fcoe_debug()
+{
kernel_info
system_info
adapter_info
dcb_info
fcoe_info
+ bsg_info
sysfs_dump
logfile_dump
}
diff --git a/etc/cfg-ethx b/etc/cfg-ethx
index 96eca59..b7274ac 100644
--- a/etc/cfg-ethx
+++ b/etc/cfg-ethx
@@ -7,3 +7,8 @@ FCOE_ENABLE="yes"
## Default: yes
# Indicate if DCB service is required at the Ethernet port
DCB_REQUIRED="yes"
+
+## Type: yes/no
+## Default: yes
+# Indicate if VLAN discovery should be handled by fcoemon
+AUTO_VLAN="yes"
diff --git a/fcoe_utils.c b/fcoe_utils.c
deleted file mode 100644
index 506356d..0000000
--- a/fcoe_utils.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright(c) 2010 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Maintained at www.Open-FCoE.org
- */
-
-#include "fcoe_utils.h"
-
-static int fcoe_sysfs_read(char *buf, int size, const char *path)
-{
- FILE *fp;
- int i, rc = -EINVAL;
-
- fp = fopen(path, "r");
- if (fp) {
- if (fgets(buf, size, fp)) {
- /*
- * Strip trailing newline by replacing
- * any '\r' or '\n' instances with '\0'.
- * It's not as elegant as it could be, but
- * we know that the symbolic name won't
- * have either of those characters until
- * the end of the line.
- */
- for (i = 0; i < strlen(buf); i++) {
- if (buf[i] == '\n' ||
- buf[i] == '\r') {
- buf[i] = '\0';
- break;
- }
- }
- rc = 0;
- }
-
- fclose(fp);
- }
-
- return rc;
-}
-
-static int fcoe_check_fchost(const char *ifname, const char *dname)
-{
- char buf[MAX_STR_LEN];
- char path[MAX_PATH_LEN];
- int rc = -EINVAL;
-
- sprintf(path, "%s/%s/symbolic_name", SYSFS_FCHOST, dname);
-
- if (!fcoe_sysfs_read(buf, MAX_STR_LEN, path))
- rc = check_symbolic_name_for_interface(buf, ifname);
-
- return rc;
-}
-
-enum fcoe_err fcoe_find_fchost(char *ifname, char *fchost, int len)
-{
- int n, dname_len;
- struct dirent **namelist;
- int rc = ENOFCOECONN;
-
- n = scandir(SYSFS_FCHOST, &namelist, 0, alphasort);
-
- for (n-- ; n >= 0 ; n--) {
- if (rc) {
- /* check symbolic name */
- if (!fcoe_check_fchost(ifname, namelist[n]->d_name)) {
- dname_len = strnlen(namelist[n]->d_name, len);
-
- if (len > dname_len) {
- strncpy(fchost, namelist[n]->d_name,
- dname_len + 1);
- /* rc = 0 indicates found */
- rc = NOERR;
- } else {
- /*
- * The fc_host is too large
- * for the buffer.
- */
- rc = EINTERR;
- }
- }
- }
- free(namelist[n]);
-
- }
- free(namelist);
-
- return rc;
-}
-
-enum fcoe_err fcoe_validate_interface(char *ifname)
-{
- enum fcoe_err rc = NOERR;
- char path[MAX_PATH_LEN];
-
-
- if (!strlen(ifname))
- rc = ENOETHDEV;
-
- /*
- * TODO: Is there a better way to check if the
- * interface name is correct?
- */
- sprintf(path, "%s/%s", SYSFS_NET, ifname);
- if (!rc && fcoe_checkdir(path))
- rc = ENOETHDEV;
-
- return rc;
-}
-
-/*
- * Validate an existing instance for an FC interface
- */
-enum fcoe_err fcoe_validate_fcoe_conn(char *ifname)
-{
- char fchost[FCHOSTBUFLEN];
- enum fcoe_err rc = NOERR;
-
- rc = fcoe_validate_interface(ifname);
-
- if (!rc)
- rc = fcoe_find_fchost(ifname, fchost, FCHOSTBUFLEN);
-
- return rc;
-}
-
-/*
- * Open and close to check if directory exists
- */
-int fcoe_checkdir(char *dir)
-{
- DIR *d = NULL;
-
- if (!dir)
- return -EINVAL;
- /* check if we have sysfs */
- d = opendir(dir);
- if (!d)
- return -EINVAL;
- closedir(d);
- return 0;
-}
-
-char *get_ifname_from_symbolic_name(const char *symbolic_name)
-{
- int symbolic_name_len = strlen(symbolic_name);
- int lead_len = strlen(SYMB_NAME_LEAD);
-
- if (lead_len < symbolic_name_len)
- return (char *)(symbolic_name + lead_len);
-
- return NULL;
-}
-
-int check_symbolic_name_for_interface(const char *symbolic_name,
- const char *ifname)
-{
- int rc = -EINVAL;
- char *symb;
-
- if (!ifname)
- return rc;
-
- symb = get_ifname_from_symbolic_name(symbolic_name);
-
- /*
- * It's important to use the length of the ifname
- * from the symbolic_name here. If the ifname length
- * were used then if the user passed in a substring
- * of the the interface name it would match because
- * we'd only be looking for the first few characters,
- * not the whole string.
- */
- if (symb && !strncmp(ifname, symb, strlen(symb)))
- rc = 0;
-
- return rc;
-}
diff --git a/fcoe_utils.h b/fcoe_utils.h
deleted file mode 100644
index 3c43304..0000000
--- a/fcoe_utils.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright(c) 2010 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Maintained at www.Open-FCoE.org
- */
-
-#ifndef _FCOE_UTILS_H_
-#define _FCOE_UTILS_H_
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <libgen.h>
-#include <dirent.h>
-#include <errno.h>
-
-/*
- * Used when trying to get the interface name from the symbolic_name.
- * Not very elegant as this code will need to change if fcoe.ko changes
- * its version.
- */
-#define FCOE_MODULE_VERSION "v0.1"
-#define SYMB_NAME_LEAD "fcoe " FCOE_MODULE_VERSION " over "
-
-#define MAX_STR_LEN 512
-#define MAX_PATH_LEN MAX_STR_LEN
-
-#define SYSFS_MOUNT "/sys"
-#define SYSFS_NET SYSFS_MOUNT "/class/net"
-#define SYSFS_FCHOST SYSFS_MOUNT "/class/fc_host"
-#define SYSFS_FCOE SYSFS_MOUNT "/module/fcoe/parameters"
-
-#define FCHOSTBUFLEN 64
-
-/*
- * This macro assumes that progname has been set
- */
-#define FCOE_LOG_ERR(fmt, args...) \
- do { \
- fprintf(stderr, "%s: " fmt, progname, ##args); \
- } while (0)
-
-
-enum fcoe_err {
- NOERR = 0, /* No error */
- EFCOECONN, /* FCoE connection already exists */
- ENOFCOECONN, /* No FCoE connection on interface */
- EINTERR, /* Internal error */
- EINVALARG, /* Invalid argument */
- EBADNUMARGS, /* Invalid number of arguments */
- EIGNORE, /* Ignore this error value */
- ENOSYSFS, /* sysfs is not present */
- ENOETHDEV, /* Not a valid Ethernet interface */
- ENOMONCONN, /* Not connected to fcoemon */
- ECONNTMOUT, /* Connection to fcoemon timed out */
- EHBAAPIERR, /* Error using HBAAPI/libhbalinux */
-};
-
-enum fcoe_err fcoe_validate_interface(char *ifname);
-enum fcoe_err fcoe_validate_fcoe_conn(char *ifname);
-enum fcoe_err fcoe_find_fchost(char *ifname, char *fchost, int len);
-int fcoe_checkdir(char *dir);
-int check_symbolic_name_for_interface(const char *symbolic_name,
- const char *ifname);
-char *get_ifname_from_symbolic_name(const char *symbolic_name);
-
-#endif /* _FCOE_UTILS_H_ */
diff --git a/fcoe_utils_version.h.in b/fcoe_utils_version.h.in
deleted file mode 100644
index 642f37d..0000000
--- a/fcoe_utils_version.h.in
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _FCOE_UTILS_VERSION_H_
-#define _FCOE_UTILS_VERSION_H_
-
-#define FCOE_UTILS_VERSION "@VERSION@"
-
-#endif /* _FCOE_UTILS_VERSION_H_ */
diff --git a/fcoemon.c b/fcoemon.c
index 8cb31ea..5af8507 100644
--- a/fcoemon.c
+++ b/fcoemon.c
@@ -55,6 +55,9 @@
#include "fcoemon.h"
#include "fcoe_clif.h"
+#include "fip.h"
+#include "rtnetlink.h"
+
#ifndef SYSCONFDIR
#define SYSCONFDIR "/etc"
#endif
@@ -103,12 +106,16 @@ struct fcoe_port {
is a VLAN */
int fcoe_enable;
int dcb_required;
+ int auto_vlan;
/* following track data required to manage FCoE interface state */
enum fcp_action action; /* current state */
enum fcp_action last_action; /* last action */
int last_msg_type; /* last rtnetlink msg type received on if name */
struct sock_info *sock_reply;
+
+ int ifindex;
+ unsigned char mac[ETHER_ADDR_LEN];
};
enum fcoeport_ifname {
@@ -153,6 +160,8 @@ static void fcm_link_getlink(void);
static int fcm_link_buf_check(size_t);
static void clear_dcbd_info(struct fcm_netif *ff);
+static int fcm_fip_socket;
+
/*
* Table for getopt_long(3).
*/
@@ -350,9 +359,21 @@ static int fcm_read_config_files(void)
continue;
}
/* if not found, default to "no" */
- if (!strncasecmp(val, "yes", 3) && rc == 1) {
+ if (!strncasecmp(val, "yes", 3) && rc == 1)
next->dcb_required = 1;
+
+ /* AUTO_VLAN */
+ rc = fcm_read_config_variable(file, val, sizeof(val),
+ fp, "AUTO_VLAN");
+ if (rc < 0) {
+ FCM_LOG("%s invalid format for AUTO_VLAN setting");
+ fclose(fp);
+ free(next);
+ continue;
}
+ /* if not found, default to "no" */
+ if (!strncasecmp(val, "yes", 3) && rc == 1)
+ next->auto_vlan = 1;
fclose(fp);
@@ -460,6 +481,92 @@ static int fcm_link_init(void)
return 0;
}
+static struct fcoe_port *fcm_port_create(char *ifname, int cmd);
+
+void fcm_new_vlan(int ifindex, int vid)
+{
+ char real_name[IFNAMSIZ];
+ char vlan_name[IFNAMSIZ];
+
+ FCM_LOG_DBG("Auto VLAN Found FCF on VID %d\n", vid);
+
+ if (rtnl_find_vlan(ifindex, vid, vlan_name)) {
+ rtnl_get_linkname(ifindex, real_name);
+ snprintf(vlan_name, IFNAMSIZ, "%s.%d-fcoe", real_name, vid);
+ vlan_create(ifindex, vid, vlan_name);
+ }
+ rtnl_set_iff_up(0, vlan_name);
+ fcm_port_create(vlan_name, FCP_CREATE_IF);
+}
+
+
+int fcm_vlan_disc_handler(struct fiphdr *fh, struct sockaddr_ll *sa, void *arg)
+{
+ int vid;
+ unsigned char mac[ETHER_ADDR_LEN];
+ int len = ntohs(fh->fip_desc_len);
+ struct fip_tlv_hdr *tlv = (struct fip_tlv_hdr *)(fh + 1);
+
+ FCM_LOG_DBG("%s", __func__);
+
+ if (ntohs(fh->fip_proto) != FIP_PROTO_VLAN) {
+ FCM_LOG_DBG("ignoring FIP frame that is not of type VLAN");
+ return -1;
+ }
+
+ if (fh->fip_subcode != FIP_VLAN_NOTE) {
+ FCM_LOG_DBG("ignoring FIP VLAN Discovery Request");
+ return -1;
+ }
+
+ while (len > 0) {
+ switch (tlv->tlv_type) {
+ case FIP_TLV_MAC_ADDR:
+ memcpy(mac, ((struct fip_tlv_mac_addr *)tlv)->mac_addr,
+ ETHER_ADDR_LEN);
+ break;
+ /*
+ * this expects to see the MAC_ADDR TLV first,
+ * and is broken if not
+ */
+ case FIP_TLV_VLAN:
+ if (tlv->tlv_len != 1) {
+ FCM_LOG_ERR(EINVAL, "bad length on VLAN TLV");
+ break;
+ }
+ vid = ntohs(((struct fip_tlv_vlan *)tlv)->vlan);
+ fcm_new_vlan(sa->sll_ifindex, vid);
+ break;
+ default:
+ /* unexpected or unrecognized descriptor */
+ FCM_LOG_DBG("ignoring TLV type %d", tlv->tlv_type);
+ break;
+ }
+ len -= tlv->tlv_len;
+ tlv = ((void *) tlv) + (tlv->tlv_len << 2);
+ };
+ return 0;
+}
+
+static void fcm_fip_recv(void *arg)
+{
+ fip_recv(fcm_fip_socket, fcm_vlan_disc_handler, NULL);
+}
+
+static int fcm_vlan_disc_init(void)
+{
+ int fd;
+
+ fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_FIP));
+ if (fd < 0) {
+ FCM_LOG_ERR(errno, "socket error");
+ return fd;
+ }
+ fcm_fip_socket = fd;
+ sa_select_add_fd(fd, fcm_fip_recv, NULL, NULL, NULL);
+ return 0;
+}
+
/* fcm_vlan_dev_real_dev - query vlan real_dev
* @vlan_ifname - vlan device ifname to find real interface name for
@@ -542,7 +649,10 @@ static void fcp_set_next_action(struct fcoe_port *p, enum fcp_action action)
p->action = action;
break;
case FCP_ACTIVATE_IF:
- p->action = FCP_ENABLE_IF;
+ if (p->auto_vlan)
+ p->action = FCP_VLAN_DISC;
+ else
+ p->action = FCP_ENABLE_IF;
break;
default:
p->action = FCP_WAIT;
@@ -552,10 +662,11 @@ static void fcp_set_next_action(struct fcoe_port *p, enum fcp_action action)
case FCP_DESTROY_IF:
switch (action) {
case FCP_CREATE_IF:
- p->action = action;
- break;
case FCP_ACTIVATE_IF:
- p->action = FCP_CREATE_IF;
+ if (p->auto_vlan)
+ p->action = FCP_VLAN_DISC;
+ else
+ p->action = FCP_CREATE_IF;
break;
default:
p->action = FCP_WAIT;
@@ -578,12 +689,15 @@ static void fcp_set_next_action(struct fcoe_port *p, enum fcp_action action)
case FCP_DISABLE_IF:
switch (action) {
case FCP_DESTROY_IF:
- case FCP_ENABLE_IF:
case FCP_RESET_IF:
p->action = action;
break;
+ case FCP_ENABLE_IF:
case FCP_ACTIVATE_IF:
- p->action = FCP_ENABLE_IF;
+ if (p->auto_vlan)
+ p->action = FCP_VLAN_DISC;
+ else
+ p->action = FCP_ENABLE_IF;
break;
default:
p->action = FCP_WAIT;
@@ -594,14 +708,30 @@ static void fcp_set_next_action(struct fcoe_port *p, enum fcp_action action)
case FCP_SCAN_IF:
switch (action) {
case FCP_DESTROY_IF:
- case FCP_ENABLE_IF:
case FCP_DISABLE_IF:
case FCP_RESET_IF:
case FCP_SCAN_IF:
p->action = action;
break;
+ case FCP_ENABLE_IF:
case FCP_ACTIVATE_IF:
- p->action = FCP_ENABLE_IF;
+ if (p->auto_vlan)
+ p->action = FCP_VLAN_DISC;
+ else
+ p->action = FCP_ENABLE_IF;
+ break;
+ default:
+ p->action = FCP_WAIT;
+ break;
+ }
+ break;
+ case FCP_VLAN_DISC:
+ switch (action) {
+ case FCP_DESTROY_IF:
+ case FCP_DISABLE_IF:
+ case FCP_RESET_IF:
+ case FCP_SCAN_IF:
+ p->action = action;
break;
default:
p->action = FCP_WAIT;
@@ -727,12 +857,15 @@ void fcm_process_link_msg(struct ifinfomsg *ip, int len, unsigned type)
char ifname[IFNAMSIZ];
char real_dev[IFNAMSIZ];
u_int8_t operstate;
- u_int64_t mac;
+ unsigned char mac[ETHER_ADDR_LEN];
int is_vlan;
+ int ifindex;
- mac = is_vlan = 0;
+ is_vlan = 0;
operstate = IF_OPER_UNKNOWN;
+ ifindex = ip->ifi_index;
+
if (ip->ifi_type != ARPHRD_ETHER)
return;
@@ -742,7 +875,7 @@ void fcm_process_link_msg(struct ifinfomsg *ip, int len, unsigned type)
switch (ap->rta_type) {
case IFLA_ADDRESS:
if (RTA_PAYLOAD(ap) == 6)
- mac = net48_get(RTA_DATA(ap));
+ memcpy(mac, RTA_DATA(ap), ETHER_ADDR_LEN);
break;
case IFLA_IFNAME:
@@ -772,6 +905,12 @@ void fcm_process_link_msg(struct ifinfomsg *ip, int len, unsigned type)
if (!p)
return;
+ p->ifindex = ifindex;
+ memcpy(p->mac, mac, ETHER_ADDR_LEN);
+
+ /* don't do VLAN discovery on a VLAN */
+ p->auto_vlan = 0;
+
/* try to find the real device name */
real_dev[0] = '\0';
fcm_vlan_dev_real_dev(ifname, real_dev);
@@ -784,6 +923,8 @@ void fcm_process_link_msg(struct ifinfomsg *ip, int len, unsigned type)
* an FCoE interface configured on it.
*/
if (p) {
+ p->ifindex = ifindex;
+ memcpy(p->mac, mac, ETHER_ADDR_LEN);
strncpy(p->real_ifname, ifname, strlen(ifname)+1);
update_fcoe_port_state(p, type, operstate,
FCP_REAL_IFNAME);
@@ -1795,6 +1936,13 @@ err_out:
return ret;
}
+int fcm_start_vlan_disc(struct fcoe_port *p)
+{
+ FCM_LOG_DBG("%s", __func__);
+ fip_send_vlan_request(fcm_fip_socket, p->ifindex, p->mac);
+ return 0;
+}
+
/*
*
* Input: action = 1 Destroy the FCoE interface
@@ -1857,6 +2005,10 @@ static void fcm_fcoe_action(struct fcm_netif *ff, struct fcoe_port *p)
SYSFS_FCHOST, fchost, fchost);
rc = fcm_fcoe_if_action(path, "- - -");
break;
+ case FCP_VLAN_DISC:
+ FCM_LOG_DBG("OP: VLAN DISC %s\n", p->ifname);
+ rc = fcm_start_vlan_disc(p);
+ break;
default:
return;
break;
@@ -2070,7 +2222,7 @@ static void fcm_pidfile_create(void)
}
}
-static int fcm_cli_create(char *ifname, int cmd, struct sock_info **r)
+static struct fcoe_port *fcm_port_create(char *ifname, int cmd)
{
struct fcoe_port *p;
struct fcoe_port *curr;
@@ -2081,11 +2233,10 @@ static int fcm_cli_create(char *ifname, int cmd, struct sock_info **r)
if (!p->fcoe_enable) {
p->fcoe_enable = 1;
fcp_set_next_action(p, cmd);
- p->sock_reply = *r;
if (p->dcb_required) {
ff = fcm_netif_lookup(p->real_ifname);
if (!ff)
- return fcm_success;
+ return p;
fcm_dcbd_state_set(ff, FCD_GET_DCB_STATE);
if (ff->ff_dcbd_state == FCD_GET_DCB_STATE)
fcp_set_next_action(p, FCP_WAIT);
@@ -2094,13 +2245,13 @@ static int fcm_cli_create(char *ifname, int cmd, struct sock_info **r)
p->fcoe_enable = 1;
fcp_set_next_action(p, cmd);
}
- return fcm_success;
+ return p;
}
p = alloc_fcoe_port(ifname);
if (!p) {
FCM_LOG_ERR(errno, "fail to allocate fcoe_port %s", ifname);
- return fcm_fail;
+ return NULL;
}
fcm_vlan_dev_real_dev(ifname, p->real_ifname);
@@ -2109,7 +2260,6 @@ static int fcm_cli_create(char *ifname, int cmd, struct sock_info **r)
p->fcoe_enable = 1;
p->dcb_required = 0;
fcp_set_next_action(p, cmd);
- p->sock_reply = *r;
p->next = NULL;
if (!fcoe_config.port)
@@ -2125,9 +2275,19 @@ static int fcm_cli_create(char *ifname, int cmd, struct sock_info **r)
ff = fcm_netif_lookup_create(p->real_ifname);
if (!ff) {
FCM_LOG_ERR(errno, "fail to allocate fcm_netif %s", ifname);
- return fcm_fail;
+ return NULL;
}
+ return p;
+}
+
+static int fcm_cli_create(char *ifname, int cmd, struct sock_info **r)
+{
+ struct fcoe_port *p;
+ p = fcm_port_create(ifname, cmd);
+ if (!p)
+ return fcm_fail;
+ p->sock_reply = *r;
return fcm_success;
}
@@ -2350,6 +2510,7 @@ int main(int argc, char **argv)
break;
case 'd':
fcoe_config.debug = 1;
+ enable_debug_log(1);
break;
case 's':
fcoe_config.use_syslog = 1;
@@ -2421,6 +2582,7 @@ int main(int argc, char **argv)
fcm_fcoe_init();
fcm_link_init(); /* NETLINK_ROUTE protocol */
fcm_dcbd_init();
+ fcm_vlan_disc_init();
fcm_srv_create(&srv_info);
sa_select_set_callback(fcm_handle_changes);
diff --git a/fcoemon.h b/fcoemon.h
index a36128d..9917d76 100644
--- a/fcoemon.h
+++ b/fcoemon.h
@@ -43,14 +43,12 @@ struct fcoe_config {
#define FCM_LOG_DBG(fmt, args...) \
do { \
- if (fcoe_config.debug) \
- sa_log(fmt, ##args); \
+ sa_log_debug(fmt, ##args); \
} while (0)
#define FCM_LOG_DEV_DBG(fcm, fmt, args...) \
do { \
- if (fcoe_config.debug) \
- sa_log("%s, " fmt, fcm->ifname, ##args); \
+ sa_log_debug("%s, " fmt, fcm->ifname, ##args); \
} while (0)
#define FCM_LOG_DEV(fcm, fmt, args...) \
@@ -95,6 +93,7 @@ enum fcp_action {
FCP_DISABLE_IF, /* disable FCoE interface */
FCP_ACTIVATE_IF, /* create or enable FCoE interface */
FCP_ERROR, /* error condition */
+ FCP_VLAN_DISC, /* start VLAN discovery */
};
#define FCM_DCBD_STATES { \
diff --git a/fcoemon_utils.c b/fcoemon_utils.c
deleted file mode 100644
index 5f1cd10..0000000
--- a/fcoemon_utils.c
+++ /dev/null
@@ -1,688 +0,0 @@
-/*
- * Copyright(c) 2009 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Maintained at www.Open-FCoE.org
- */
-
-#include "fcoemon_utils.h"
-#include "net_types.h"
-#include "fc_types.h"
-
-u_char libsa_lock_hier; /* for lock debugging non-log related */
-
-int use_syslog;
-
-/*
- * Size of on-stack line buffers.
- * These shouldn't be to large for a kernel stack frame.
- */
-#define SA_LOG_BUF_LEN 200 /* on-stack line buffer size */
-
-void enable_syslog(int enable)
-{
- use_syslog = enable;
-}
-
-/*
- * log with a variable argument list.
- */
-static void
-sa_log_va(const char *func, const char *format, va_list arg)
-{
- size_t len;
- size_t flen;
- int add_newline;
- char sa_buf[SA_LOG_BUF_LEN];
- char *bp;
-
- /*
- * If the caller didn't provide a newline at the end, we will.
- */
- len = strlen(format);
- add_newline = 0;
- if (!len || format[len - 1] != '\n')
- add_newline = 1;
- bp = sa_buf;
- len = sizeof(sa_buf);
- if (func) {
- flen = snprintf(bp, len, "%s: ", func);
- len -= flen;
- bp += flen;
- }
- flen = vsnprintf(bp, len, format, arg);
- if (add_newline && flen < len) {
- bp += flen;
- *bp++ = '\n';
- *bp = '\0';
- }
- sa_log_output(sa_buf);
-}
-
-/*
- * log
- */
-void
-sa_log(const char *format, ...)
-{
- va_list arg;
-
- va_start(arg, format);
- sa_log_va(NULL, format, arg);
- va_end(arg);
-}
-
-/*
- * log with error number.
- */
-void
-sa_log_err(int error, const char *func, const char *format, ...)
-{
- va_list arg;
- char buf[SA_LOG_BUF_LEN];
-
- if (func)
- sa_log("%s: error %d %s", func, error,
- strerror_r(error, buf, sizeof(buf)));
- else
- sa_log("error %d %s", error,
- strerror_r(error, buf, sizeof(buf)));
- va_start(arg, format);
- sa_log_va(func, format, arg);
- va_end(arg);
-}
-
-/*
- * Size of on-stack line buffers.
- * These shouldn't be to large for a kernel stack frame.
- */
-#define SA_LOG_BUF_LEN 200 /* on-stack line buffer size */
-
-/*
- * Assert failures.
- */
-void
-assert_failed(const char *format, ...)
-{
- va_list arg;
- char buf[SA_LOG_BUF_LEN];
-
- va_start(arg, format);
- vsnprintf(buf, sizeof(buf), format, arg);
- va_end(arg);
- sa_log_abort(buf);
-}
-
-/*
- * Log options.
- * These may be set directly by callers.
- */
-u_int sa_log_flags; /* timestamp and other option flags */
-int sa_log_time_delta_min = 1; /* minimum diff to print in millisec */
-char *sa_log_prefix; /* string to print before any message */
-
-void
-sa_log_set_option(u_int flags)
-{
- sa_log_flags = flags;
-}
-
-/*
- * Put timestamp on front of each log line, as controlled by tunables above.
- */
-static void
-sa_log_timestamp(void)
-{
- static struct timeval tlast;
- char ctime_buf[30];
- struct timeval t;
- struct timeval diff;
-
- gettimeofday(&t, NULL);
- if (sa_log_flags & SA_LOGF_TIME) {
- ctime_r(&t.tv_sec, ctime_buf);
- ctime_buf[11 + 8] = '\0'; /* trim ctime after seconds */
- fprintf(stderr, "%s.%3.3ld ",
- ctime_buf + 11, t.tv_usec / 1000);
- }
- if (sa_log_flags & SA_LOGF_DELTA) {
- if (tlast.tv_sec == 0)
- tlast = t;
- timersub(&t, &tlast, &diff);
- tlast = t;
- if (diff.tv_sec != 0 ||
- diff.tv_usec >= sa_log_time_delta_min * 1000)
- fprintf(stderr, "%4ld.%3.3ld ",
- diff.tv_sec, diff.tv_usec / 1000);
- else
- fprintf(stderr, "%8s ", "");
- }
- if (sa_log_prefix)
- fprintf(stderr, "%s: ", sa_log_prefix);
-}
-
-void
-sa_log_output(const char *buf)
-{
- if (use_syslog) {
- syslog(LOG_INFO, "%s", buf);
- return;
- }
- sa_log_timestamp();
- fprintf(stderr, "%s", buf);
- fflush(stderr);
-}
-
-void
-sa_log_abort(const char *buf)
-{
- sa_log_output(buf);
- abort();
-}
-
-/*
- * Make a printable NUL-terminated copy of the string.
- * The source buffer might not be NUL-terminated.
- */
-char *
-sa_strncpy_safe(char *dest, size_t len, const char *src, size_t src_len)
-{
- char *dp = dest;
- const char *sp = src;
-
- while (len-- > 1 && src_len-- > 0 && *sp != '\0') {
- *dp++ = isprint(*sp) ? *sp : (isspace(*sp) ? ' ' : '.');
- sp++;
- }
- *dp = '\0';
-
- /*
- * Take off trailing blanks.
- */
- while (--dp >= dest && isspace(*dp))
- *dp = '\0';
- return dest;
-}
-
-/** sa_enum_decode(buf, len, tp, val)
- *
- * @param buf buffer for result (may be used or not).
- * @param len size of buffer (at least 32 bytes recommended).
- * @param tp pointer to table of names and values, struct sa_nameval.
- * @param val value to be decoded into a name.
- * @returns pointer to name string. Unknown values are put into buffer in hex.
- */
-const char *
-sa_enum_decode(char *buf, size_t len, const struct sa_nameval *tp, u_int val)
-{
- for (; tp->nv_name != NULL; tp++) {
- if (tp->nv_val == val)
- return tp->nv_name;
- }
- snprintf(buf, len, "Unknown (code 0x%X)", val);
- return buf;
-}
-
-#define SA_TIMER_HZ (1000 * 1000 * 1000ULL) /* nanoseconds per second */
-#define SA_TIMER_FUZZ (500 * 1000ULL) /* 500 microseconds is close enough */
-
-static struct sa_timer *sa_timer_head; /* queue of scheduled events */
-static u_int64_t sa_timer_nsec; /* nanoseconds since start */
-
-/*
- * Initialize a timer structure. Set handler.
- */
-void
-sa_timer_init(struct sa_timer *tm, void (*handler)(void *), void *arg)
-{
- ASSERT(handler != NULL);
- memset(tm, 0, sizeof(*tm));
- tm->tm_handler = handler;
- tm->tm_handler_arg = arg;
-}
-
-/*
- * Allocate a timer structure. Set handler.
- */
-struct sa_timer *
-sa_timer_alloc(void (*handler)(void *arg), void *arg)
-{
- struct sa_timer *tm;
-
- tm = malloc(sizeof(*tm));
- if (tm)
- sa_timer_init(tm, handler, arg);
- return tm;
-}
-
-u_int64_t
-sa_timer_get(void)
-{
- u_int64_t nsec;
-#ifndef _POSIX_TIMERS
- struct timeval tv;
-
- gettimeofday(&tv, NULL); /* XXX want monotonic time, not TOD */
- nsec = tv.tv_sec * SA_TIMER_HZ + tv.tv_usec * 1000;
-#else /* _POSIX_TIMERS */
- struct timespec ts;
- int rc;
-
- rc = clock_gettime(CLOCK_MONOTONIC, &ts);
- ASSERT_NOTIMPL(rc == 0);
- nsec = ts.tv_sec * SA_TIMER_HZ + ts.tv_nsec;
-#endif /* _POSIX_TIMERS */
-
-#if 0 /* XXX */
- ASSERT(nsec >= sa_timer_nsec); /* really must be monotonic */
-#else
- if (nsec < sa_timer_nsec)
- sa_log("sa_timer_get: negative time lapse "
- "old %qud new %qud diff %qd nsec\n",
- (long long unsigned int) sa_timer_nsec,
- (long long unsigned int) nsec,
- (long long int) (nsec - sa_timer_nsec));
-#endif
- sa_timer_nsec = nsec;
- return nsec;
-}
-
-/*
- * Get monotonic time since some arbitrary time in the past.
- * If _POSIX_MONOTONIC_CLOCK isn't available, we'll use time of day.
- */
-u_int
-sa_timer_get_secs(void)
-{
- u_int sec;
-
-#ifndef _POSIX_TIMERS
- struct timeval tv;
-
- gettimeofday(&tv, NULL); /* XXX want monotonic time, not TOD */
- sec = tv.tv_sec;
-#else /* _POSIX_TIMERS */
- struct timespec ts;
- int rc;
-
- rc = clock_gettime(CLOCK_MONOTONIC, &ts);
- ASSERT_NOTIMPL(rc == 0);
- sec = ts.tv_sec;
-#endif /* _POSIX_TIMERS */
- return sec;
-}
-
-/*
- * Set timer to fire. Delta is in microseconds from now.
- */
-void
-sa_timer_set(struct sa_timer *tm, u_long delta_usec)
-{
- struct sa_timer *cur;
- struct sa_timer **prev;
-
- ASSERT(delta_usec != 0);
- ASSERT(tm->tm_handler != NULL);
- sa_timer_cancel(tm);
- ASSERT(sa_timer_active(tm) == 0);
- tm->tm_nsec =
- sa_timer_get() + delta_usec * SA_TIMER_HZ / SA_TIMER_UNITS;
- ASSERT(tm->tm_nsec != 0);
-
- /*
- * Insert timer into sorted linked list.
- * Find insertion point, before cur.
- */
- for (prev = &sa_timer_head;
- (cur = *prev) != NULL && cur->tm_nsec <= tm->tm_nsec;
- prev = &cur->tm_next)
- ;
- *prev = tm;
- tm->tm_next = cur;
-}
-
-/*
- * Cancel timer if it is active.
- */
-void
-sa_timer_cancel(struct sa_timer *tm)
-{
- struct sa_timer *cur;
- struct sa_timer **prev;
-
- if (sa_timer_active(tm)) {
- for (prev = &sa_timer_head; (cur = *prev) != NULL;
- prev = &cur->tm_next)
- if (cur == tm) {
- tm->tm_nsec = 0;
- *prev = tm->tm_next;
- break;
- }
- ASSERT(cur == tm);
- }
-}
-
-/*
- * Free (and cancel) timer.
- */
-void
-sa_timer_free(struct sa_timer *tm)
-{
- if (sa_timer_active(tm))
- sa_timer_cancel(tm);
- free(tm);
-}
-
-/*
- * Handle timer checks. Called from select loop or other periodic function.
- *
- * The struct timeval is set before returning to the maximum amount of time
- * that should elapse before the next call.
- *
- * Returns 1 if any timer functions were called, 0 otherwise.
- */
-int
-sa_timer_check(struct timeval *tv)
-{
- u_int64_t now = 0;
- u_int64_t next_due = 0;
- struct sa_timer *tm;
- int ret = 0;
-
- /*
- * Remember, the list may change during the handler.
- */
- for (;;) {
- now = sa_timer_get();
- tm = sa_timer_head;
- if (tm == NULL) {
- next_due = now;
- break;
- }
-
- next_due = tm->tm_nsec;
- if (next_due > now + SA_TIMER_FUZZ)
- break;
-
- /*
- * Remove this element from the list.
- */
- sa_timer_head = tm->tm_next;
- tm->tm_next = NULL;
-
- /*
- * Mark cancelled and call handler.
- */
- tm->tm_nsec = 0;
- ASSERT(tm->tm_handler != NULL);
- (*tm->tm_handler)(tm->tm_handler_arg);
- ret = 1;
- }
-
- ASSERT(next_due >= now);
- next_due -= now;
- tv->tv_sec = (time_t) (next_due / SA_TIMER_HZ);
- tv->tv_usec = (long) (next_due % SA_TIMER_HZ) / 1000;
-
- return ret;
-}
-
-#define NFC_NFDS 64
-
-/*
- * Deferred procedure call.
- */
-struct sa_defer_ent {
- TAILQ_ENTRY(sa_defer_ent) de_next;
- void (*de_func)(void *arg);
- void *de_arg;
-};
-
-/*
- * Static module state.
- */
-static struct sa_sel_state {
- fd_set ts_rx_fds;
- fd_set ts_tx_fds;
- fd_set ts_ex_fds;
- int ts_max_fd;
- u_char ts_exit;
- struct sa_sel_fd {
- void (*ts_rx_handler)(void *);
- void (*ts_tx_handler)(void *);
- void (*ts_ex_handler)(void *);
- void *ts_handler_arg;
- } ts_fd[NFC_NFDS];
- void (*ts_callback)(void);
- TAILQ_HEAD(, sa_defer_ent) ts_defer_list;
-} sa_sel_state;
-
-int sa_select_loop(void)
-{
- struct sa_sel_state *ss = &sa_sel_state;
- struct sa_sel_fd *fp;
- fd_set rx_fds;
- fd_set tx_fds;
- fd_set ex_fds;
- struct timeval tval;
- struct timeval *tvp;
- int rv, i;
-
- ss->ts_exit = 0;
- while (ss->ts_exit == 0) {
- sa_timer_check(&tval);
- if (ss->ts_exit)
- break;
- if (tval.tv_sec == 0 && tval.tv_usec == 0)
- tvp = NULL;
- else
- tvp = &tval;
- rx_fds = ss->ts_rx_fds;
- tx_fds = ss->ts_tx_fds;
- ex_fds = ss->ts_ex_fds;
- rv = select(ss->ts_max_fd + 1, &rx_fds, &tx_fds, &ex_fds, tvp);
- if (rv == -1) {
- if (errno == EINTR)
- continue;
- return errno;
- }
-
- fp = ss->ts_fd;
- for (i = 0; rv > 0 && i <= sa_sel_state.ts_max_fd; i++, fp++) {
- if (FD_ISSET(i, &rx_fds)) {
- if (fp->ts_rx_handler != NULL)
- (*fp->ts_rx_handler)
- (fp->ts_handler_arg);
- else
- ASSERT(!FD_ISSET(i, &ss->ts_rx_fds));
- --rv;
- }
- if (FD_ISSET(i, &tx_fds)) {
- if (fp->ts_tx_handler != NULL)
- (*fp->ts_tx_handler)
- (fp->ts_handler_arg);
- else
- ASSERT(!FD_ISSET(i, &ss->ts_tx_fds));
- --rv;
- }
- if (FD_ISSET(i, &ex_fds)) {
- if (fp->ts_ex_handler != NULL)
- (*fp->ts_ex_handler)
- (fp->ts_handler_arg);
- else
- ASSERT(!FD_ISSET(i, &ss->ts_ex_fds));
- --rv;
- }
- }
- if (ss->ts_callback != NULL)
- (*ss->ts_callback)();
- }
- return 0;
-}
-
-void
-sa_select_add_fd(int fd,
- void (*rx_handler)(void *),
- void (*tx_handler)(void *),
- void (*ex_handler)(void *),
- void *arg)
-{
- struct sa_sel_state *ss = &sa_sel_state;
- struct sa_sel_fd *fp;
-
- ASSERT_NOTIMPL(fd < NFC_NFDS);
- ASSERT(rx_handler != NULL || tx_handler != NULL || ex_handler != NULL);
- if (ss->ts_max_fd < fd)
- ss->ts_max_fd = fd;
- fp = &ss->ts_fd[fd];
- fp->ts_handler_arg = arg;
- if (rx_handler != NULL) {
- fp->ts_rx_handler = rx_handler;
- FD_SET(fd, &ss->ts_rx_fds);
- }
- if (tx_handler != NULL) {
- fp->ts_tx_handler = tx_handler;
- FD_SET(fd, &ss->ts_tx_fds);
- }
- if (ex_handler != NULL) {
- fp->ts_ex_handler = ex_handler;
- FD_SET(fd, &ss->ts_ex_fds);
- }
-}
-
-void
-sa_select_set_rx(int fd, void (*handler)(void *))
-{
- struct sa_sel_state *ss = &sa_sel_state;
-
- ASSERT(fd <= ss->ts_max_fd);
- ss->ts_fd[fd].ts_rx_handler = handler;
- if (handler != NULL)
- FD_SET(fd, &ss->ts_rx_fds);
- else
- FD_CLR(fd, &ss->ts_rx_fds);
-}
-
-void
-sa_select_set_tx(int fd, void (*handler)(void *))
-{
- struct sa_sel_state *ss = &sa_sel_state;
-
- ASSERT(fd <= ss->ts_max_fd);
- ss->ts_fd[fd].ts_tx_handler = handler;
- if (handler != NULL)
- FD_SET(fd, &ss->ts_tx_fds);
- else
- FD_CLR(fd, &ss->ts_tx_fds);
-}
-
-void
-sa_select_set_ex(int fd, void (*handler)(void *))
-{
- struct sa_sel_state *ss = &sa_sel_state;
-
- ASSERT(fd <= ss->ts_max_fd);
- ss->ts_fd[fd].ts_ex_handler = handler;
- if (handler != NULL)
- FD_SET(fd, &ss->ts_ex_fds);
- else
- FD_CLR(fd, &ss->ts_ex_fds);
-}
-
-void
-sa_select_rem_fd(int fd)
-{
- struct sa_sel_state *ss = &sa_sel_state;
- struct sa_sel_fd *fp;
-
- ASSERT_NOTIMPL(fd < NFC_NFDS);
- FD_CLR(fd, &ss->ts_rx_fds);
- FD_CLR(fd, &ss->ts_tx_fds);
- FD_CLR(fd, &ss->ts_ex_fds);
- fp = &ss->ts_fd[fd];
- fp->ts_rx_handler = NULL;
- fp->ts_tx_handler = NULL;
- fp->ts_ex_handler = NULL;
- fp->ts_handler_arg = NULL;
-}
-
-/*
- * Set callback for every time through the select loop.
- */
-void
-sa_select_set_callback(void (*cb)(void))
-{
- sa_sel_state.ts_callback = cb;
-}
-
-/*
- * Cause select loop to exit.
- * This is invoked from a handler which wants the select loop to return
- * after the handler is finished. For example, during receipt of a network
- * packet, the program may decide to clean up and exit, but in order to do
- * this cleanly, all lower-level protocol handlers should return first.
- */
-void
-sa_select_exit(void)
-{
- sa_sel_state.ts_exit = 1;
-}
-
-/*
- * Convert 48-bit IEEE MAC address to 64-bit FC WWN.
- */
-fc_wwn_t
-fc_wwn_from_mac(u_int64_t mac, u_int scheme, u_int port)
-{
- fc_wwn_t wwn;
-
- ASSERT(mac < (1ULL << 48));
- wwn = mac | ((fc_wwn_t) scheme << 60);
- switch (scheme) {
- case 1:
- ASSERT(port == 0);
- break;
- case 2:
- ASSERT(port < 0xfff);
- wwn |= (fc_wwn_t) port << 48;
- break;
- default:
- ASSERT_NOTREACHED;
- break;
- }
- return wwn;
-}
-
-/* assumes input is pointer to two hex digits */
-/* returns -1 on error */
-int
-hex2int(char *b)
-{
- int i;
- int n = 0;
- int m;
-
- for (i = 0, m = 1; i < 2; i++, m--) {
- if (isxdigit(*(b+i))) {
- if (*(b+i) <= '9')
- n |= (*(b+i) & 0x0f) << (4*m);
- else
- n |= ((*(b+i) & 0x0f) + 9) << (4*m);
- } else
- return -1;
- }
- return n;
-}
-
diff --git a/fcoemon_utils.h b/fcoemon_utils.h
deleted file mode 100644
index 35ab19e..0000000
--- a/fcoemon_utils.h
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright(c) 2009 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Maintained at www.Open-FCoE.org
- */
-
-#ifndef _FCOEMON_UTILS_H_
-#define _FCOEMON_UTILS_H_
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <time.h>
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
-#include <syslog.h>
-
-#include "fc_types.h"
-
-void sa_log(const char *format, ...);
-void sa_log_err(int, const char *func, const char *format, ...);
-
-/*
- * These functions can be provided outside of libsa for those environments
- * that want to redirect them.
- */
-void sa_log_output(const char *); /* log message */
-void sa_log_abort(const char *); /* log message and abort */
-
-#define __SA_STRING(x) #x
-
-/*
- * Logging options.
- */
-#define SA_LOGF_TIME 0x0001 /* include timestamp in message */
-#define SA_LOGF_DELTA 0x0002 /* include time since last message */
-
-extern u_int sa_log_flags; /* timestamp and other option flags */
-extern int sa_log_time_delta_min; /* minimum diff to print in millisec */
-extern char *sa_log_prefix; /* string to print before any message */
-
-extern void assert_failed(const char *s, ...)
- __attribute__ ((format(printf, 1, 2)));
-
-#ifndef UNLIKELY
-#define UNLIKELY(_x) (_x)
-#endif /* UNLIKELY */
-
-/*
- * ASSERT macros
- *
- * ASSERT(expr) - this calls assert_failed() if expr is false. This variant
- * is not present in production code or if DEBUG_ASSERTS is not defined.
- * Be careful not to rely on expr being evaluated.
- */
-#if defined(DEBUG_ASSERTS)
-#define ASSERT(_x) do { \
- if (UNLIKELY(!(_x))) { \
- assert_failed("ASSERT FAILED (%s) @ %s:%d\n", \
- "" #_x, __FILE__, __LINE__); \
- } \
- } while (0)
-#else
-#define ASSERT(_x)
-#endif /* DEBUG_ASSERTS */
-
-/*
- * ASSERT_NOTIMPL(expr) - this calls assert_failed() if expr is false.
- * The implication is that the condition is not handled by the current
- * implementation, and work should be done eventually to handle this.
- */
-#define ASSERT_NOTIMPL(_x) do { \
- if (UNLIKELY(!(_x))) { \
- assert_failed("ASSERT (NOT IMPL) " \
- "(%s) @ %s:%d\n", \
- "" #_x, __FILE__, __LINE__); \
- } \
- } while (0)
-
-/*
- * ASSERT_NOTREACHED - this is the same as ASSERT_NOTIMPL(0).
- */
-#define ASSERT_NOTREACHED do { \
- assert_failed("ASSERT (NOT REACHED) @ %s:%d\n", \
- __FILE__, __LINE__); \
- } while (0)
-
-/*
- * ASSERT_BUG(bugno, expr). This variant is used when a bug number has
- * been assigned to any one of the other assertion failures. It is always
- * present in code. It gives the bug number which helps locate
- * documentation and helps prevent duplicate bug filings.
- */
-#define ASSERT_BUG(_bugNr, _x) do { \
- if (UNLIKELY(!(_x))) { \
- assert_failed("ASSERT (BUG %d) (%s) @ %s:%d\n", \
- (_bugNr), #_x, __FILE__, __LINE__); \
- } \
- } while (0)
-
-#ifndef LIBSA_USE_DANGEROUS_ROUTINES
-#define strcpy DONT_USE_strcpy
-#define strcat DONT_USE_strcat
-#define gets DONT_USE_gets
-#endif /* LIBSA_USE_DANGEROUS_ROUTINES */
-
-char *sa_strncpy_safe(char *dest, size_t len, const char *src, size_t src_len);
-char *sa_hex_format(char *buf, size_t buflen,
- const unsigned char *data, size_t data_len,
- unsigned int group_len, char *inter_group_sep);
-
-/*
- * Structure for tables encoding and decoding name-value pairs such as enums.
- */
-struct sa_nameval {
- char *nv_name;
- u_int nv_val;
-};
-
-const char *sa_enum_decode(char *, size_t, const struct sa_nameval *, u_int);
-int sa_enum_encode(const struct sa_nameval *tp, const char *, u_int *);
-const char *sa_flags_decode(char *, size_t, const struct sa_nameval *, u_int);
-
-/*
- * Timer facility.
- */
-
-struct sa_timer {
- struct sa_timer *tm_next;
- u_int64_t tm_nsec; /* relative time to event (nSec) */
- void (*tm_handler)(void *arg);
- void *tm_handler_arg;
- struct sa_timer **timer_head;
-};
-
-
-#define SA_TIMER_UNITS (1000 * 1000UL) /* number of timer ticks per second */
-
-/*
- * Initialize a pre-allocated timer structure.
- */
-void sa_timer_init(struct sa_timer *, void (*handler)(void *), void *arg);
-
-/*
- * Test whether the timer is active.
- */
-static inline int sa_timer_active(struct sa_timer *tm)
-{
- return tm->tm_nsec != 0;
-}
-
-/*
- * Allocate a timer structure. Set handler.
- */
-struct sa_timer *sa_timer_alloc(void (*)(void *arg), void *arg);
-
-/*
- * Set timer to fire. Delta is in microseconds from now.
- */
-void sa_timer_set(struct sa_timer *, u_long delta);
-
-/*
- * Cancel timer.
- */
-void sa_timer_cancel(struct sa_timer *);
-
-/*
- * Free (and cancel) timer.
- */
-void sa_timer_free(struct sa_timer *);
-
-
-/*
- * Handle timer checks. Called from select loop or other periodic function.
- *
- * The struct timeval passed in indicates how much time has passed since
- * the last call, and is set before returning to the maximum amount of time
- * that should elapse before the next call.
- *
- * Returns 1 if any timer handlers were invoked, 0 otherwise.
- */
-int sa_timer_check(struct timeval *);
-
-/*
- * Get time in nanoseconds since some arbitrary time.
- */
-u_int64_t sa_timer_get(void);
-
-/*
- * Get time in seconds since some arbitrary time.
- */
-u_int sa_timer_get_secs(void);
-
-/*
- * sa_select - Server Array select facility.
- *
- * This is a thin layer to poll files with a select loop.
- */
-
-/*
- * Enter the polling loop which never exits.
- */
-int sa_select_loop(void);
-
-/*
- * Set callback for every time through the select loop.
- */
-void sa_select_set_callback(void (*)(void));
-
-/*
- * Add a callback to handle files which are ready for receive, transmit,
- * or to handle exceptions.
- */
-void sa_select_add_fd(int fd, void (*rx_handler)(void *),
- void (*tx_handler)(void *),
- void (*ex_handler)(void *), void *arg);
-
-/*
- * Change a single callback for a descriptor that's already been added.
- */
-void sa_select_set_rx(int fd, void (*handler)(void *));
-void sa_select_set_tx(int fd, void (*handler)(void *));
-void sa_select_set_ex(int fd, void (*handler)(void *));
-
-/*
- * Remove all callbacks for a file descriptor.
- */
-void sa_select_rem_fd(int fd);
-
-/*
- * Cause select loop to return.
- */
-void sa_select_exit(void);
-
-/*
- * Convert 48-bit IEEE MAC address to 64-bit FC WWN.
- */
-extern fc_wwn_t
-fc_wwn_from_mac(u_int64_t, u_int32_t scheme, u_int32_t port);
-
-extern int hex2int(char *b);
-
-int use_syslog;
-void enable_syslog(int);
-
-#endif /* _FCOEMON_UTILS_H_ */
diff --git a/fipvlan.c b/fipvlan.c
index cc8a785..5b428e2 100644
--- a/fipvlan.c
+++ b/fipvlan.c
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
+#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
@@ -29,6 +30,7 @@
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <sys/queue.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
@@ -36,103 +38,99 @@
#include <arpa/inet.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
#include "fcoe_utils_version.h"
#include "fip.h"
-#include "log.h"
-#include "list.h"
+#include "fcoemon_utils.h"
+#include "fcoe_utils.h"
+#include "rtnetlink.h"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define FIP_LOG(...) sa_log(__VA_ARGS__)
+#define FIP_LOG_ERR(error, ...) sa_log_err(error, __func__, __VA_ARGS__)
+#define FIP_LOG_ERRNO(...) sa_log_err(errno, __func__, __VA_ARGS__)
+#define FIP_LOG_DBG(...) sa_log_debug(__VA_ARGS__)
+
/* global configuration */
+struct {
+ char **namev;
+ int namec;
+ bool automode;
+ bool create;
+ bool start;
+} config = {
+ .namev = NULL,
+ .namec = 0,
+ .automode = false,
+ .create = false,
+};
+
char *exe;
+TAILQ_HEAD(iff_list_head, iff);
+
struct iff {
int ifindex;
- char *ifname;
+ int iflink;
+ char ifname[IFNAMSIZ];
unsigned char mac_addr[ETHER_ADDR_LEN];
- struct list_head list;
+ bool is_vlan;
+ short int vid;
+ TAILQ_ENTRY(iff) list_node;
+ struct iff_list_head vlans;
};
-LIST_HEAD(interfaces);
+struct iff_list_head interfaces = TAILQ_HEAD_INITIALIZER(interfaces);
+
+TAILQ_HEAD(fcf_list_head, fcf);
struct fcf {
- struct iff *interface;
+ int ifindex;
uint16_t vlan;
unsigned char mac_addr[ETHER_ADDR_LEN];
- struct list_head list;
+ TAILQ_ENTRY(fcf) list_node;
};
-LIST_HEAD(fcfs);
+struct fcf_list_head fcfs = TAILQ_HEAD_INITIALIZER(fcfs);
-/**
- * packet_socket - create a packet socket bound to the FIP ethertype
- */
-int packet_socket(void)
+struct iff *lookup_iff(int ifindex, char *ifname)
{
- int s;
+ struct iff *iff;
- log_debug(1, "creating ETH_P_FIP packet socket");
- s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_FIP));
- if (s < 0)
- log_errno("packet socket error");
+ if (!ifindex && !ifname)
+ return NULL;
- return s;
+ TAILQ_FOREACH(iff, &interfaces, list_node)
+ if ((!ifindex || ifindex == iff->ifindex) &&
+ (!ifname || strcmp(ifname, iff->ifname) == 0))
+ return iff;
+ return NULL;
}
-/**
- * fip_send_vlan_request - send a FIP VLAN request
- * @s: ETH_P_FIP packet socket
- * @iff: network interface to send from
- *
- * Note: sends to FIP_ALL_FCF_MACS
- */
-ssize_t fip_send_vlan_request(int s, struct iff *iff)
+struct iff *lookup_vlan(int ifindex, short int vid)
{
- struct sockaddr_ll sa = {
- .sll_family = AF_PACKET,
- .sll_protocol = htons(ETH_P_FIP),
- .sll_ifindex = iff->ifindex,
- .sll_hatype = ARPHRD_ETHER,
- .sll_pkttype = PACKET_MULTICAST,
- .sll_halen = ETHER_ADDR_LEN,
- .sll_addr = FIP_ALL_FCF_MACS,
- };
- struct fiphdr fh = {
- .fip_version = FIP_VERSION(1),
- .fip_proto = htons(FIP_PROTO_VLAN),
- .fip_subcode = FIP_VLAN_REQ,
- .fip_desc_len = htons(2),
- .fip_flags = 0,
- };
- struct {
- struct fip_tlv_mac_addr mac;
- } tlvs = {
- .mac = {
- .hdr.tlv_type = FIP_TLV_MAC_ADDR,
- .hdr.tlv_len = 2,
- },
- };
- struct iovec iov[] = {
- { .iov_base = &fh, .iov_len = sizeof(fh), },
- { .iov_base = &tlvs, .iov_len = sizeof(tlvs), },
- };
- struct msghdr msg = {
- .msg_name = &sa,
- .msg_namelen = sizeof(sa),
- .msg_iov = iov,
- .msg_iovlen = ARRAY_SIZE(iov),
- };
- int rc;
-
- memcpy(tlvs.mac.mac_addr, iff->mac_addr, ETHER_ADDR_LEN);
-
- log_debug(1, "sending FIP VLAN request");
- rc = sendmsg(s, &msg, 0);
- if (rc < 0)
- log_errno("sendmsg error");
+ struct iff *real_dev, *vlan;
+ TAILQ_FOREACH(real_dev, &interfaces, list_node)
+ if (real_dev->ifindex == ifindex)
+ TAILQ_FOREACH(vlan, &real_dev->vlans, list_node)
+ if (vlan->vid == vid)
+ return vlan;
+ return NULL;
+}
- return rc;
+struct iff *find_vlan_real_dev(struct iff *vlan)
+{
+ struct iff *real_dev;
+ TAILQ_FOREACH(real_dev, &interfaces, list_node) {
+ if (real_dev->ifindex == vlan->iflink)
+ return real_dev;
+ }
+ return NULL;
}
struct fip_tlv_ptrs {
@@ -146,7 +144,7 @@ struct fip_tlv_ptrs {
#define TLV_LEN_CHECK(t, l) ({ \
int _tlc = ((t)->tlv_len != (l)) ? 1 : 0; \
if (_tlc) \
- log_warn("bad length for TLV of type %d", (t)->tlv_type); \
+ FIP_LOG("bad length for TLV of type %d", (t)->tlv_type); \
_tlc; \
})
@@ -178,7 +176,7 @@ unsigned int fip_parse_tlvs(void *ptr, int len, struct fip_tlv_ptrs *tlv_ptrs)
break;
default:
/* unexpected or unrecognized descriptor */
- log_warn("unrecognized TLV type %d", tlv->tlv_type);
+ FIP_LOG("unrecognized TLV type %d", tlv->tlv_type);
break;
}
len -= tlv->tlv_len;
@@ -190,180 +188,62 @@ unsigned int fip_parse_tlvs(void *ptr, int len, struct fip_tlv_ptrs *tlv_ptrs)
/**
* fip_recv_vlan_note - parse a FIP VLAN Notification
* @fh: FIP header, the beginning of the received FIP frame
- * @len: total length of the received FIP frame
- * @iff: interface this notification was received on
+ * @ifindex: index of interface this was received on
*/
-int fip_recv_vlan_note(struct fiphdr *fh, ssize_t len, struct iff *iff)
+int fip_recv_vlan_note(struct fiphdr *fh, int ifindex)
{
struct fip_tlv_ptrs tlvs;
struct fcf *fcf;
unsigned int bitmap, required_tlvs;
- int desc_len;
+ int len;
int i;
- log_debug(1, "received FIP VLAN Notification");
+ FIP_LOG_DBG("received FIP VLAN Notification");
- desc_len = ntohs(fh->fip_desc_len);
- if (len < (sizeof(*fh) + (desc_len << 2)))
- return -1;
+ len = ntohs(fh->fip_desc_len);
required_tlvs = (1 << FIP_TLV_MAC_ADDR) | (1 << FIP_TLV_VLAN);
- bitmap = fip_parse_tlvs((fh + 1), desc_len, &tlvs);
+ bitmap = fip_parse_tlvs((fh + 1), len, &tlvs);
if ((bitmap & required_tlvs) != required_tlvs)
return -1;
for (i = 0; i < tlvs.vlanc; i++) {
fcf = malloc(sizeof(*fcf));
if (!fcf) {
- log_errno("malloc failed");
+ FIP_LOG_ERRNO("malloc failed");
break;
}
memset(fcf, 0, sizeof(*fcf));
- fcf->interface = iff;
+ fcf->ifindex = ifindex;
fcf->vlan = ntohs(tlvs.vlan[i]->vlan);
memcpy(fcf->mac_addr, tlvs.mac->mac_addr, ETHER_ADDR_LEN);
- list_add_tail(&fcf->list, &fcfs);
+ TAILQ_INSERT_TAIL(&fcfs, fcf, list_node);
}
return 0;
}
-/**
- * fip_recv - receive from a FIP packet socket
- * @s: packet socket with data ready to be received
- */
-int fip_recv(int s)
+int fip_vlan_handler(struct fiphdr *fh, struct sockaddr_ll *sa, void *arg)
{
- char buf[4096];
- struct sockaddr_ll sa;
- struct iovec iov[] = {
- { .iov_base = &buf[0], .iov_len = sizeof(buf), },
- };
- struct msghdr msg = {
- .msg_name = &sa,
- .msg_namelen = sizeof(sa),
- .msg_iov = iov,
- .msg_iovlen = ARRAY_SIZE(iov),
- };
- struct fiphdr *fh;
- struct iff *iff;
- ssize_t len;
-
- log_debug(1, "%s", __func__);
-
- len = recvmsg(s, &msg, 0);
- if (len < 0) {
- log_errno("packet socket recv error");
- return len;
- }
-
- if (len < sizeof(*fh)) {
- log_err("received packed smaller that FIP header length");
- return -1;
- }
-
- fh = (struct fiphdr *) buf;
+ int rc = -1;
/* We only care about VLAN Notifications */
if (ntohs(fh->fip_proto) != FIP_PROTO_VLAN) {
- log_debug(1, "ignoring FIP packet, protocol %d",
- ntohs(fh->fip_proto));
- return -1;
- }
-
- list_for_each_entry(iff, &interfaces, list) {
- if (iff->ifindex == sa.sll_ifindex)
- break;
- }
- if (&iff->list == &interfaces) {
- log_warn("received packet on unexpected interface");
+ FIP_LOG_DBG("ignoring FIP packet, protocol %d",
+ ntohs(fh->fip_proto));
return -1;
}
switch (fh->fip_subcode) {
case FIP_VLAN_NOTE:
- fip_recv_vlan_note(fh, len, iff);
+ rc = fip_recv_vlan_note(fh, sa->sll_ifindex);
break;
default:
- log_warn("FIP packet with unknown subcode %d", fh->fip_subcode);
- return -1;
- }
-
- return 0;
-}
-
-/**
- * rtnl_socket - create and bind a routing netlink socket
- */
-int rtnl_socket(void)
-{
- struct sockaddr_nl sa = {
- .nl_family = AF_NETLINK,
- .nl_pid = getpid(),
- .nl_groups = RTMGRP_LINK,
- };
- int s;
- int rc;
-
- log_debug(1, "creating netlink socket");
- s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (s < 0) {
- log_errno("netlink socket error");
- return s;
- }
-
- rc = bind(s, (struct sockaddr *) &sa, sizeof(sa));
- if (rc < 0) {
- log_errno("netlink bind error");
- close(s);
- return rc;
+ FIP_LOG_DBG("ignored FIP VLAN packet with subcode %d",
+ fh->fip_subcode);
+ break;
}
-
- return s;
-}
-
-/**
- * send_getlink_dump - send an RTM_GETLINK dump request to list all interfaces
- * @s: routing netlink socket to use
- */
-ssize_t send_getlink_dump(int s)
-{
- struct sockaddr_nl sa = {
- .nl_family = AF_NETLINK,
- .nl_pid = 0,
- };
- struct {
- struct nlmsghdr nh;
- struct ifinfomsg ifm;
- } req = {
- .nh = {
- .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
- .nlmsg_type = RTM_GETLINK,
- .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
- .nlmsg_pid = 0,
- },
- .ifm = {
- .ifi_family = AF_UNSPEC,
- .ifi_type = ARPHRD_ETHER,
- },
- };
- struct iovec iov[] = {
- { .iov_base = &req, .iov_len = sizeof(req), },
- };
- struct msghdr msg = {
- .msg_name = &sa,
- .msg_namelen = sizeof(sa),
- .msg_iov = iov,
- .msg_iovlen = ARRAY_SIZE(iov),
- };
- int rc;
-
- log_debug(1, "sending RTM_GETLINK dump request");
- rc = sendmsg(s, &msg, 0);
- if (rc < 0)
- log_errno("netlink sendmsg error");
-
return rc;
}
@@ -373,125 +253,64 @@ ssize_t send_getlink_dump(int s)
*/
void rtnl_recv_newlink(struct nlmsghdr *nh)
{
- struct ifinfomsg *ifm;
- struct rtattr *rta;
- struct iff *iff;
- unsigned int len;
-
- log_debug(1, "RTM_NEWLINK");
+ struct ifinfomsg *ifm = NLMSG_DATA(nh);
+ struct rtattr *ifla[__IFLA_MAX];
+ struct rtattr *linkinfo[__IFLA_INFO_MAX];
+ struct rtattr *vlan[__IFLA_VLAN_MAX];
+ struct iff *iff, *real_dev;
- ifm = NLMSG_DATA(nh);
- log_debug(1, "ifindex %d, type %d", ifm->ifi_index, ifm->ifi_type);
+ FIP_LOG_DBG("RTM_NEWLINK: ifindex %d, type %d",
+ ifm->ifi_index, ifm->ifi_type);
/* We only deal with Ethernet interfaces */
if (ifm->ifi_type != ARPHRD_ETHER)
return;
- /* if there's no link, we're not going to wait for it */
- if ((ifm->ifi_flags & IFF_RUNNING) != IFF_RUNNING)
- return;
-
iff = malloc(sizeof(*iff));
if (!iff) {
- log_errno("malloc failed");
+ FIP_LOG_ERRNO("malloc failed");
return;
}
memset(iff, 0, sizeof(*iff));
+ TAILQ_INIT(&iff->vlans);
- iff->ifindex = ifm->ifi_index;
-
- len = IFLA_PAYLOAD(nh);
- for (rta = IFLA_RTA(ifm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
- switch (rta->rta_type) {
- case IFLA_ADDRESS:
- memcpy(iff->mac_addr, RTA_DATA(rta), ETHER_ADDR_LEN);
- log_debug(1, "\tIFLA_ADDRESS\t%x:%x:%x:%x:%x:%x",
- iff->mac_addr[0], iff->mac_addr[1],
- iff->mac_addr[2], iff->mac_addr[3],
- iff->mac_addr[4], iff->mac_addr[5]);
- break;
- case IFLA_IFNAME:
- iff->ifname = strdup(RTA_DATA(rta));
- log_debug(1, "\tIFLA_IFNAME\t%s", iff->ifname);
- break;
- default:
- /* other attributes don't matter */
- break;
- }
- }
-
- list_add_tail(&iff->list, &interfaces);
-}
+ parse_ifinfo(ifla, nh);
-#define NLMSG(c) ((struct nlmsghdr *) (c))
-
-/**
- * rtnl_recv - receive from a routing netlink socket
- * @s: routing netlink socket with data ready to be received
- *
- * Returns: 0 when NLMSG_DONE is received
- * <0 on error
- * >0 when more data is expected
- */
-int rtnl_recv(int s)
-{
- char buf[8192];
- struct sockaddr_nl sa;
- struct iovec iov[] = {
- [0] = { .iov_base = buf, .iov_len = sizeof(buf), },
- };
- struct msghdr msg = {
- .msg_name = &sa,
- .msg_namelen = sizeof(sa),
- .msg_iov = iov,
- .msg_iovlen = ARRAY_SIZE(iov),
- };
- struct nlmsghdr *nh;
- int len;
- int rc;
-
- log_debug(1, "%s", __func__);
-
- len = recvmsg(s, &msg, 0);
- if (len < 0) {
- log_errno("netlink recvmsg error");
- return len;
- }
-
- rc = 1;
- for (nh = NLMSG(buf); NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
- switch (nh->nlmsg_type) {
- case RTM_NEWLINK:
- rtnl_recv_newlink(nh);
- break;
- case NLMSG_DONE:
- log_debug(1, "NLMSG_DONE");
- break;
- case NLMSG_ERROR:
- log_debug(1, "NLMSG_ERROR");
- break;
- default:
- log_warn("unexpected netlink message type %d",
- nh->nlmsg_type);
- break;
- }
-
- if (nh->nlmsg_type == NLMSG_DONE) {
- rc = 0;
- break;
+ iff->ifindex = ifm->ifi_index;
+ if (ifla[IFLA_LINK])
+ iff->iflink = *(int *)RTA_DATA(ifla[IFLA_LINK]);
+ else
+ iff->iflink = iff->ifindex;
+ memcpy(iff->mac_addr, RTA_DATA(ifla[IFLA_ADDRESS]), ETHER_ADDR_LEN);
+ strncpy(iff->ifname, RTA_DATA(ifla[IFLA_IFNAME]), IFNAMSIZ);
+
+ if (ifla[IFLA_LINKINFO]) {
+ parse_linkinfo(linkinfo, ifla[IFLA_LINKINFO]);
+ if (linkinfo[IFLA_INFO_KIND] &&
+ !strcmp(RTA_DATA(linkinfo[IFLA_INFO_KIND]), "vlan")) {
+ iff->is_vlan = true;
+ 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) {
+ FIP_LOG_ERR(ENODEV, "VLAN found without parent");
+ return;
+ }
+ TAILQ_INSERT_TAIL(&real_dev->vlans, iff, list_node);
+ return;
}
- if (!(nh->nlmsg_flags & NLM_F_MULTI))
- break;
}
- return rc;
+ TAILQ_INSERT_TAIL(&interfaces, iff, list_node);
}
/* command line arguments */
-#define GETOPT_STR "ahv"
+#define GETOPT_STR "acshv"
static const struct option long_options[] = {
{ "auto", no_argument, NULL, 'a' },
+ { "create", no_argument, NULL, 'c' },
+ { "start", no_argument, NULL, 's' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
@@ -503,6 +322,8 @@ static void help(int status)
"Usage: %s [ options ] [ network interfaces ]\n"
"Options:\n"
" -a, --auto Auto select Ethernet interfaces\n"
+" -c, --create Create system VLAN devices\n"
+" -s, --start Start FCoE login automatically\n"
" -h, --help Display this help and exit\n"
" -v, --version Display version information and exit\n",
exe);
@@ -510,15 +331,9 @@ static void help(int status)
exit(status);
}
-/* array of interface names to use */
-char **namev;
-/* length of namev */
-int namec;
-
-int parse_cmdline(int argc, char **argv)
+void parse_cmdline(int argc, char **argv)
{
char c;
- int automode = 0;
while (1) {
c = getopt_long(argc, argv, GETOPT_STR, long_options, NULL);
@@ -526,7 +341,13 @@ int parse_cmdline(int argc, char **argv)
break;
switch (c) {
case 'a':
- automode = 1;
+ config.automode = true;
+ break;
+ case 'c':
+ config.create = true;
+ break;
+ case 's':
+ config.start = true;
break;
case 'h':
help(0);
@@ -542,137 +363,174 @@ int parse_cmdline(int argc, char **argv)
}
}
- if ((optind == argc) && (!automode))
+ if ((optind == argc) && (!config.automode))
help(1);
- namev = &argv[optind];
- namec = argc - optind;
- return automode;
+ config.namev = &argv[optind];
+ config.namec = argc - optind;
}
-/* exit after waiting 2 seconds without receiving anything */
-#define TIMEOUT 2000
+int rtnl_listener_handler(struct nlmsghdr *nh, void *arg)
+{
+ switch (nh->nlmsg_type) {
+ case RTM_NEWLINK:
+ rtnl_recv_newlink(nh);
+ return 0;
+ }
+ return -1;
+}
-int autodetect()
+void create_missing_vlans()
{
- struct pollfd pfd[1];
- int ns;
+ struct fcf *fcf;
+ struct iff *real_dev, *vlan;
+ char vlan_name[IFNAMSIZ];
int rc;
- ns = rtnl_socket();
- if (ns < 0)
- return ns;
-
- send_getlink_dump(ns);
- pfd[0].fd = ns;
- pfd[0].events = POLLIN;
+ if (!config.create)
+ return;
- while (1) {
- rc = poll(pfd, ARRAY_SIZE(pfd), TIMEOUT);
- log_debug(1, "return from poll %d", rc);
- if (rc == 0) /* timeout */
- break;
- if (rc == -1) {
- log_errno("poll error");
- break;
+ TAILQ_FOREACH(fcf, &fcfs, list_node) {
+ vlan = lookup_vlan(fcf->ifindex, fcf->vlan);
+ if (vlan) {
+ FIP_LOG_DBG("VLAN %s.%d already exists as %s",
+ fcf->ifindex, fcf->vlan, vlan->ifname);
+ continue;
}
- if (pfd[0].revents) {
- rc = rtnl_recv(pfd[0].fd);
- if (rc == 0)
- break;
+ real_dev = lookup_iff(fcf->ifindex, NULL);
+ if (!real_dev) {
+ FIP_LOG_ERR(ENODEV, "lost device %d with discoved FCF?",
+ fcf->ifindex);
+ continue;
}
- pfd[0].revents = 0;
+ snprintf(vlan_name, IFNAMSIZ, "%s.%d-fcoe",
+ real_dev->ifname, fcf->vlan);
+ rc = vlan_create(fcf->ifindex, fcf->vlan, vlan_name);
+ if (rc < 0)
+ printf("Failed to crate 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);
}
- close(ns);
- return 0;
+ printf("\n");
}
-int check_interface(char *name, int ps)
+int fcoe_instance_start(char *ifname)
{
- struct ifreq ifr;
- struct iff *iff;
-
- iff = malloc(sizeof(*iff));
- if (!iff) {
- log_errno("malloc failed");
- return -1;
+ int fd, rc;
+ FIP_LOG_DBG("%s on %s\n", __func__, ifname);
+ fd = open(SYSFS_FCOE "/create", O_WRONLY);
+ if (fd < 0) {
+ FIP_LOG_ERRNO("failed to open fcoe create file");
+ return fd;
}
- memset(iff, 0, sizeof(*iff));
+ rc = write(fd, ifname, strlen(ifname));
+ close(fd);
+ return rc < 0 ? rc : 0;
+}
- strncpy(ifr.ifr_name, name, IFNAMSIZ);
- if (ioctl(ps, SIOCGIFINDEX, &ifr) != 0) {
- log_errno("SIOCGIFINDEX");
- goto err;
- }
- iff->ifname = strdup(ifr.ifr_name);
- iff->ifindex = ifr.ifr_ifindex;
+void start_fcoe()
+{
+ struct fcf *fcf;
+ struct iff *iff;
- if (ioctl(ps, SIOCGIFHWADDR, &ifr) != 0) {
- log_errno("SIOCGIFHWADDR");
- goto err;
- }
- if (ifr.ifr_addr.sa_family != ARPHRD_ETHER) {
- log_err("%s is not an Ethernet interface", name);
- goto err;
+ TAILQ_FOREACH(fcf, &fcfs, list_node) {
+ iff = lookup_vlan(fcf->ifindex, fcf->vlan);
+ 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);
}
- memcpy(iff->mac_addr, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
-
- list_add_tail(&iff->list, &interfaces);
- return 0;
-err:
- free(iff);
- return -1;
}
void print_results()
{
+ struct iff *iff;
struct fcf *fcf;
- if (list_empty(&fcfs)) {
+ if (TAILQ_EMPTY(&fcfs)) {
printf("No Fibre Channel Forwarders Found\n");
return;
}
printf("Fibre Channel Forwarders Discovered\n");
- printf("%-10.10s| %-5.5s| %-10.10s\n", "interface", "VLAN", "FCF MAC");
- printf("------------------------------------\n");
- list_for_each_entry(fcf, &fcfs, list) {
- printf("%-10.10s| %-5d| %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
- fcf->interface->ifname, fcf->vlan,
+ printf("%-16.16s| %-5.5s| %-17.17s\n", "interface", "VLAN", "FCF MAC");
+ printf("------------------------------------------\n");
+ TAILQ_FOREACH(fcf, &fcfs, list_node) {
+ iff = lookup_iff(fcf->ifindex, NULL);
+ printf("%-16.16s| %-5d| %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
+ iff->ifname, fcf->vlan,
fcf->mac_addr[0], fcf->mac_addr[1], fcf->mac_addr[2],
fcf->mac_addr[3], fcf->mac_addr[4], fcf->mac_addr[5]);
}
+ printf("\n");
}
-void recv_loop(int ps)
+/* exit after waiting 1 second without receiving anything */
+#define TIMEOUT 1000
+
+void recv_loop(int ns, int ps)
{
- struct pollfd pfd[1] = {
- [0].fd = ps,
+ struct pollfd pfd[2] = {
+ [0].fd = ns,
[0].events = POLLIN,
+ [1].fd = ps,
+ [1].events = POLLIN,
};
int rc;
while (1) {
rc = poll(pfd, ARRAY_SIZE(pfd), TIMEOUT);
- log_debug(1, "return from poll %d", rc);
+ FIP_LOG_DBG("return from poll %d", rc);
if (rc == 0) /* timeout */
break;
if (rc == -1) {
- log_errno("poll error");
+ FIP_LOG_ERRNO("poll error");
break;
}
if (pfd[0].revents)
- fip_recv(pfd[0].fd);
+ rtnl_recv(ns, rtnl_listener_handler, NULL);
+ if (pfd[1].revents)
+ fip_recv(ps, fip_vlan_handler, NULL);
pfd[0].revents = 0;
+ pfd[1].revents = 0;
}
}
-int main(int argc, char **argv)
+void find_interfaces(int ns)
+{
+ send_getlink_dump(ns);
+ rtnl_recv(ns, rtnl_listener_handler, NULL);
+}
+
+void send_vlan_requests(int ps)
{
- int ps;
struct iff *iff;
int i;
- int automode;
+
+ if (config.automode) {
+ TAILQ_FOREACH(iff, &interfaces, list_node)
+ fip_send_vlan_request(ps, iff->ifindex, iff->mac_addr);
+ } else {
+ for (i = 0; i < config.namec; i++) {
+ iff = lookup_iff(0, config.namev[i]);
+ if (!iff)
+ continue;
+ fip_send_vlan_request(ps, iff->ifindex, iff->mac_addr);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int ps, ns;
+ int rc = 0;
exe = strrchr(argv[0], '/');
if (exe)
@@ -680,33 +538,48 @@ int main(int argc, char **argv)
else
exe = argv[0];
- automode = parse_cmdline(argc, argv);
- log_start(exe, 0, 0);
-
- ps = packet_socket();
+ parse_cmdline(argc, argv);
+ sa_log_prefix = exe;
+ sa_log_flags = 0;
+ enable_debug_log(0);
- if (automode) {
- autodetect();
- } else {
- for (i = 0; i < namec; i++)
- check_interface(namev[i], ps);
+ ps = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_FIP));
+ if (ps < 0) {
+ rc = ps;
+ goto ps_err;
+ }
+ ns = rtnl_socket();
+ if (ns < 0) {
+ rc = ns;
+ goto ns_err;
}
- if (list_empty(&interfaces)) {
- log_err("no interfaces to perform discovery on");
+ find_interfaces(ns);
+
+ if (TAILQ_EMPTY(&interfaces)) {
+ FIP_LOG_ERR(ENODEV, "no interfaces to perform discovery on");
close(ps);
- log_stop();
exit(1);
}
- list_for_each_entry(iff, &interfaces, list)
- fip_send_vlan_request(ps, iff);
+ send_vlan_requests(ps);
+ recv_loop(ns, ps);
- recv_loop(ps);
print_results();
-
+ if (config.create) {
+ create_missing_vlans();
+ /*
+ * need to listen for the RTM_NETLINK messages
+ * about the new VLAN devices
+ */
+ recv_loop(ns, ps);
+ }
+ if (config.start)
+ start_fcoe();
+ close(ns);
+ns_err:
close(ps);
- log_stop();
- exit(0);
+ps_err:
+ exit(rc);
}
diff --git a/include/fcoe_utils.h b/include/fcoe_utils.h
new file mode 100644
index 0000000..3c43304
--- /dev/null
+++ b/include/fcoe_utils.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright(c) 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#ifndef _FCOE_UTILS_H_
+#define _FCOE_UTILS_H_
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <libgen.h>
+#include <dirent.h>
+#include <errno.h>
+
+/*
+ * Used when trying to get the interface name from the symbolic_name.
+ * Not very elegant as this code will need to change if fcoe.ko changes
+ * its version.
+ */
+#define FCOE_MODULE_VERSION "v0.1"
+#define SYMB_NAME_LEAD "fcoe " FCOE_MODULE_VERSION " over "
+
+#define MAX_STR_LEN 512
+#define MAX_PATH_LEN MAX_STR_LEN
+
+#define SYSFS_MOUNT "/sys"
+#define SYSFS_NET SYSFS_MOUNT "/class/net"
+#define SYSFS_FCHOST SYSFS_MOUNT "/class/fc_host"
+#define SYSFS_FCOE SYSFS_MOUNT "/module/fcoe/parameters"
+
+#define FCHOSTBUFLEN 64
+
+/*
+ * This macro assumes that progname has been set
+ */
+#define FCOE_LOG_ERR(fmt, args...) \
+ do { \
+ fprintf(stderr, "%s: " fmt, progname, ##args); \
+ } while (0)
+
+
+enum fcoe_err {
+ NOERR = 0, /* No error */
+ EFCOECONN, /* FCoE connection already exists */
+ ENOFCOECONN, /* No FCoE connection on interface */
+ EINTERR, /* Internal error */
+ EINVALARG, /* Invalid argument */
+ EBADNUMARGS, /* Invalid number of arguments */
+ EIGNORE, /* Ignore this error value */
+ ENOSYSFS, /* sysfs is not present */
+ ENOETHDEV, /* Not a valid Ethernet interface */
+ ENOMONCONN, /* Not connected to fcoemon */
+ ECONNTMOUT, /* Connection to fcoemon timed out */
+ EHBAAPIERR, /* Error using HBAAPI/libhbalinux */
+};
+
+enum fcoe_err fcoe_validate_interface(char *ifname);
+enum fcoe_err fcoe_validate_fcoe_conn(char *ifname);
+enum fcoe_err fcoe_find_fchost(char *ifname, char *fchost, int len);
+int fcoe_checkdir(char *dir);
+int check_symbolic_name_for_interface(const char *symbolic_name,
+ const char *ifname);
+char *get_ifname_from_symbolic_name(const char *symbolic_name);
+
+#endif /* _FCOE_UTILS_H_ */
diff --git a/include/fcoe_utils_version.h.in b/include/fcoe_utils_version.h.in
new file mode 100644
index 0000000..642f37d
--- /dev/null
+++ b/include/fcoe_utils_version.h.in
@@ -0,0 +1,6 @@
+#ifndef _FCOE_UTILS_VERSION_H_
+#define _FCOE_UTILS_VERSION_H_
+
+#define FCOE_UTILS_VERSION "@VERSION@"
+
+#endif /* _FCOE_UTILS_VERSION_H_ */
diff --git a/include/fcoemon_utils.h b/include/fcoemon_utils.h
new file mode 100644
index 0000000..8680f46
--- /dev/null
+++ b/include/fcoemon_utils.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright(c) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#ifndef _FCOEMON_UTILS_H_
+#define _FCOEMON_UTILS_H_
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <time.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <syslog.h>
+
+#include "fc_types.h"
+
+void sa_log(const char *format, ...);
+void sa_log_debug(const char *format, ...);
+void sa_log_err(int, const char *func, const char *format, ...);
+
+/*
+ * These functions can be provided outside of libsa for those environments
+ * that want to redirect them.
+ */
+void sa_log_output(const char *); /* log message */
+void sa_log_abort(const char *); /* log message and abort */
+
+#define __SA_STRING(x) #x
+
+/*
+ * Logging options.
+ */
+#define SA_LOGF_TIME 0x0001 /* include timestamp in message */
+#define SA_LOGF_DELTA 0x0002 /* include time since last message */
+
+extern u_int sa_log_flags; /* timestamp and other option flags */
+extern int sa_log_time_delta_min; /* minimum diff to print in millisec */
+extern char *sa_log_prefix; /* string to print before any message */
+
+extern void assert_failed(const char *s, ...)
+ __attribute__ ((format(printf, 1, 2)));
+
+#ifndef UNLIKELY
+#define UNLIKELY(_x) (_x)
+#endif /* UNLIKELY */
+
+/*
+ * ASSERT macros
+ *
+ * ASSERT(expr) - this calls assert_failed() if expr is false. This variant
+ * is not present in production code or if DEBUG_ASSERTS is not defined.
+ * Be careful not to rely on expr being evaluated.
+ */
+#if defined(DEBUG_ASSERTS)
+#define ASSERT(_x) do { \
+ if (UNLIKELY(!(_x))) { \
+ assert_failed("ASSERT FAILED (%s) @ %s:%d\n", \
+ "" #_x, __FILE__, __LINE__); \
+ } \
+ } while (0)
+#else
+#define ASSERT(_x)
+#endif /* DEBUG_ASSERTS */
+
+/*
+ * ASSERT_NOTIMPL(expr) - this calls assert_failed() if expr is false.
+ * The implication is that the condition is not handled by the current
+ * implementation, and work should be done eventually to handle this.
+ */
+#define ASSERT_NOTIMPL(_x) do { \
+ if (UNLIKELY(!(_x))) { \
+ assert_failed("ASSERT (NOT IMPL) " \
+ "(%s) @ %s:%d\n", \
+ "" #_x, __FILE__, __LINE__); \
+ } \
+ } while (0)
+
+/*
+ * ASSERT_NOTREACHED - this is the same as ASSERT_NOTIMPL(0).
+ */
+#define ASSERT_NOTREACHED do { \
+ assert_failed("ASSERT (NOT REACHED) @ %s:%d\n", \
+ __FILE__, __LINE__); \
+ } while (0)
+
+/*
+ * ASSERT_BUG(bugno, expr). This variant is used when a bug number has
+ * been assigned to any one of the other assertion failures. It is always
+ * present in code. It gives the bug number which helps locate
+ * documentation and helps prevent duplicate bug filings.
+ */
+#define ASSERT_BUG(_bugNr, _x) do { \
+ if (UNLIKELY(!(_x))) { \
+ assert_failed("ASSERT (BUG %d) (%s) @ %s:%d\n", \
+ (_bugNr), #_x, __FILE__, __LINE__); \
+ } \
+ } while (0)
+
+#ifndef LIBSA_USE_DANGEROUS_ROUTINES
+#define strcpy DONT_USE_strcpy
+#define strcat DONT_USE_strcat
+#define gets DONT_USE_gets
+#endif /* LIBSA_USE_DANGEROUS_ROUTINES */
+
+char *sa_strncpy_safe(char *dest, size_t len, const char *src, size_t src_len);
+char *sa_hex_format(char *buf, size_t buflen,
+ const unsigned char *data, size_t data_len,
+ unsigned int group_len, char *inter_group_sep);
+
+/*
+ * Structure for tables encoding and decoding name-value pairs such as enums.
+ */
+struct sa_nameval {
+ char *nv_name;
+ u_int nv_val;
+};
+
+const char *sa_enum_decode(char *, size_t, const struct sa_nameval *, u_int);
+int sa_enum_encode(const struct sa_nameval *tp, const char *, u_int *);
+const char *sa_flags_decode(char *, size_t, const struct sa_nameval *, u_int);
+
+/*
+ * Timer facility.
+ */
+
+struct sa_timer {
+ struct sa_timer *tm_next;
+ u_int64_t tm_nsec; /* relative time to event (nSec) */
+ void (*tm_handler)(void *arg);
+ void *tm_handler_arg;
+ struct sa_timer **timer_head;
+};
+
+
+#define SA_TIMER_UNITS (1000 * 1000UL) /* number of timer ticks per second */
+
+/*
+ * Initialize a pre-allocated timer structure.
+ */
+void sa_timer_init(struct sa_timer *, void (*handler)(void *), void *arg);
+
+/*
+ * Test whether the timer is active.
+ */
+static inline int sa_timer_active(struct sa_timer *tm)
+{
+ return tm->tm_nsec != 0;
+}
+
+/*
+ * Allocate a timer structure. Set handler.
+ */
+struct sa_timer *sa_timer_alloc(void (*)(void *arg), void *arg);
+
+/*
+ * Set timer to fire. Delta is in microseconds from now.
+ */
+void sa_timer_set(struct sa_timer *, u_long delta);
+
+/*
+ * Cancel timer.
+ */
+void sa_timer_cancel(struct sa_timer *);
+
+/*
+ * Free (and cancel) timer.
+ */
+void sa_timer_free(struct sa_timer *);
+
+
+/*
+ * Handle timer checks. Called from select loop or other periodic function.
+ *
+ * The struct timeval passed in indicates how much time has passed since
+ * the last call, and is set before returning to the maximum amount of time
+ * that should elapse before the next call.
+ *
+ * Returns 1 if any timer handlers were invoked, 0 otherwise.
+ */
+int sa_timer_check(struct timeval *);
+
+/*
+ * Get time in nanoseconds since some arbitrary time.
+ */
+u_int64_t sa_timer_get(void);
+
+/*
+ * Get time in seconds since some arbitrary time.
+ */
+u_int sa_timer_get_secs(void);
+
+/*
+ * sa_select - Server Array select facility.
+ *
+ * This is a thin layer to poll files with a select loop.
+ */
+
+/*
+ * Enter the polling loop which never exits.
+ */
+int sa_select_loop(void);
+
+/*
+ * Set callback for every time through the select loop.
+ */
+void sa_select_set_callback(void (*)(void));
+
+/*
+ * Add a callback to handle files which are ready for receive, transmit,
+ * or to handle exceptions.
+ */
+void sa_select_add_fd(int fd, void (*rx_handler)(void *),
+ void (*tx_handler)(void *),
+ void (*ex_handler)(void *), void *arg);
+
+/*
+ * Change a single callback for a descriptor that's already been added.
+ */
+void sa_select_set_rx(int fd, void (*handler)(void *));
+void sa_select_set_tx(int fd, void (*handler)(void *));
+void sa_select_set_ex(int fd, void (*handler)(void *));
+
+/*
+ * Remove all callbacks for a file descriptor.
+ */
+void sa_select_rem_fd(int fd);
+
+/*
+ * Cause select loop to return.
+ */
+void sa_select_exit(void);
+
+/*
+ * Convert 48-bit IEEE MAC address to 64-bit FC WWN.
+ */
+extern fc_wwn_t
+fc_wwn_from_mac(u_int64_t, u_int32_t scheme, u_int32_t port);
+
+extern int hex2int(char *b);
+
+extern int use_syslog;
+void enable_syslog(int);
+void enable_debug_log(int);
+
+#endif /* _FCOEMON_UTILS_H_ */
diff --git a/include/fip.h b/include/fip.h
index 91a017f..5f39763 100644
--- a/include/fip.h
+++ b/include/fip.h
@@ -20,6 +20,9 @@
#ifndef FIP_H
#define FIP_H
+#include <stdint.h>
+#include <net/ethernet.h>
+
#define ETH_P_FCOE 0x8906
#define ETH_P_FIP 0x8914
@@ -123,4 +126,26 @@ struct fip_tlv_vlan {
uint16_t vlan; /* only lower 12 bits matter */
};
+
+/* libutil / fip.c functionality */
+
+/* FIP message handler, passed into fip_recv */
+typedef int fip_handler(struct fiphdr *fh, struct sockaddr_ll *sa, void *arg);
+
+/**
+ * fip_recv - receive from a FIP packet socket
+ * @s: packet socket with data ready to be received
+ */
+int fip_recv(int s, fip_handler *fn, void *arg);
+
+/**
+ * fip_send_vlan_request - send a FIP VLAN request
+ * @s: ETH_P_FIP packet socket to send on
+ * @ifindex: network interface index to send on
+ * @mac: mac address of the netif
+ *
+ * Note: sends to FIP_ALL_FCF_MACS
+ */
+ssize_t fip_send_vlan_request(int s, int ifindex, unsigned char *mac);
+
#endif /* FIP_H */
diff --git a/include/list.h b/include/list.h
deleted file mode 100644
index 35da9fd..0000000
--- a/include/list.h
+++ /dev/null
@@ -1,444 +0,0 @@
-/* Adapted from the Linux kernel, under the terms of the GPLv2 */
-
-#ifndef LIST_H
-#define LIST_H
-
-#include <stddef.h>
-
-#define container_of(ptr, type, member) ({ \
- const typeof(((type *) 0)->member) * __mptr = (ptr); \
- (type *)((char *) __mptr - offsetof(type, member)); \
-})
-
-/*
- * Simple doubly linked list implementation.
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
-
-struct list_head {
- struct list_head *next, *prev;
-};
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
- struct list_head name = LIST_HEAD_INIT(name)
-
-static inline void INIT_LIST_HEAD(struct list_head *list)
-{
- list->next = list;
- list->prev = list;
-}
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_add(struct list_head *new,
- struct list_head *prev,
- struct list_head *next)
-{
- next->prev = new;
- new->next = next;
- new->prev = prev;
- prev->next = new;
-}
-
-/**
- * list_add - add a new entry
- * @new: new entry to be added
- * @head: list head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static inline void list_add(struct list_head *new, struct list_head *head)
-{
- __list_add(new, head, head->next);
-}
-
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
-{
- __list_add(new, head->prev, head);
-}
-
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_del(struct list_head *prev, struct list_head *next)
-{
- next->prev = prev;
- prev->next = next;
-}
-
-/**
- * list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- * Note: list_empty() on entry does not return true after this, the entry is
- * in an undefined state.
- */
-static inline void list_del(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
- entry->next = NULL;
- entry->prev = NULL;
-}
-
-/**
- * list_replace - replace old entry by new one
- * @old : the element to be replaced
- * @new : the new element to insert
- *
- * If @old was empty, it will be overwritten.
- */
-static inline void list_replace(struct list_head *old,
- struct list_head *new)
-{
- new->next = old->next;
- new->next->prev = new;
- new->prev = old->prev;
- new->prev->next = new;
-}
-
-static inline void list_replace_init(struct list_head *old,
- struct list_head *new)
-{
- list_replace(old, new);
- INIT_LIST_HEAD(old);
-}
-
-/**
- * list_del_init - deletes entry from list and reinitialize it.
- * @entry: the element to delete from the list.
- */
-static inline void list_del_init(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
- INIT_LIST_HEAD(entry);
-}
-
-/**
- * list_move - delete from one list and add as another's head
- * @list: the entry to move
- * @head: the head that will precede our entry
- */
-static inline void list_move(struct list_head *list, struct list_head *head)
-{
- __list_del(list->prev, list->next);
- list_add(list, head);
-}
-
-/**
- * list_move_tail - delete from one list and add as another's tail
- * @list: the entry to move
- * @head: the head that will follow our entry
- */
-static inline void list_move_tail(struct list_head *list,
- struct list_head *head)
-{
- __list_del(list->prev, list->next);
- list_add_tail(list, head);
-}
-
-/**
- * list_is_last - tests whether @list is the last entry in list @head
- * @list: the entry to test
- * @head: the head of the list
- */
-static inline int list_is_last(const struct list_head *list,
- const struct list_head *head)
-{
- return list->next == head;
-}
-
-/**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
- */
-static inline int list_empty(const struct list_head *head)
-{
- return head->next == head;
-}
-
-/**
- * list_empty_careful - tests whether a list is empty and not being modified
- * @head: the list to test
- *
- * Description:
- * tests whether a list is empty _and_ checks that no other CPU might be
- * in the process of modifying either member (next or prev)
- *
- * NOTE: using list_empty_careful() without synchronization
- * can only be safe if the only activity that can happen
- * to the list entry is list_del_init(). Eg. it cannot be used
- * if another CPU could re-list_add() it.
- */
-static inline int list_empty_careful(const struct list_head *head)
-{
- struct list_head *next = head->next;
- return (next == head) && (next == head->prev);
-}
-
-/**
- * list_is_singular - tests whether a list has just one entry.
- * @head: the list to test.
- */
-static inline int list_is_singular(const struct list_head *head)
-{
- return !list_empty(head) && (head->next == head->prev);
-}
-
-static inline void __list_splice(const struct list_head *list,
- struct list_head *head)
-{
- struct list_head *first = list->next;
- struct list_head *last = list->prev;
- struct list_head *at = head->next;
-
- first->prev = head;
- head->next = first;
-
- last->next = at;
- at->prev = last;
-}
-
-/**
- * list_splice - join two lists
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- */
-static inline void list_splice(const struct list_head *list,
- struct list_head *head)
-{
- if (!list_empty(list))
- __list_splice(list, head);
-}
-
-/**
- * list_splice_init - join two lists and reinitialise the emptied list.
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- *
- * The list at @list is reinitialised
- */
-static inline void list_splice_init(struct list_head *list,
- struct list_head *head)
-{
- if (!list_empty(list)) {
- __list_splice(list, head);
- INIT_LIST_HEAD(list);
- }
-}
-
-/**
- * list_entry - get the struct for this entry
- * @ptr: the &struct list_head pointer.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the list_struct within the struct.
- */
-#define list_entry(ptr, type, member) \
- container_of(ptr, type, member)
-
-/**
- * list_first_entry - get the first element from a list
- * @ptr: the list head to take the element from.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the list_struct within the struct.
- *
- * Note, that list is expected to be not empty.
- */
-#define list_first_entry(ptr, type, member) \
- list_entry((ptr)->next, type, member)
-
-/**
- * list_for_each - iterate over a list
- * @pos: the &struct list_head to use as a loop cursor.
- * @head: the head for your list.
- */
-#define list_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); pos = pos->next)
-
-/**
- * list_for_each_prev - iterate over a list backwards
- * @pos: the &struct list_head to use as a loop cursor.
- * @head: the head for your list.
- */
-#define list_for_each_prev(pos, head) \
- for (pos = (head)->prev; pos != (head); pos = pos->prev)
-
-/**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @pos: the &struct list_head to use as a loop cursor.
- * @n: another &struct list_head to use as temporary storage
- * @head: the head for your list.
- */
-#define list_for_each_safe(pos, n, head) \
- for (pos = (head)->next, n = pos->next; \
- pos != (head); \
- pos = n, n = pos->next)
-
-/**
- * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
- * @pos: the &struct list_head to use as a loop cursor.
- * @n: another &struct list_head to use as temporary storage
- * @head: the head for your list.
- */
-#define list_for_each_prev_safe(pos, n, head) \
- for (pos = (head)->prev, n = pos->prev; \
- pos != (head); \
- pos = n, n = pos->prev)
-
-/**
- * list_for_each_entry - iterate over list of given type
- * @pos: the type * to use as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
-#define list_for_each_entry(pos, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_reverse - iterate backwards over list of given type.
- * @pos: the type * to use as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
-#define list_for_each_entry_reverse(pos, head, member) \
- for (pos = list_entry((head)->prev, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_entry(pos->member.prev, typeof(*pos), member))
-
-/**
- * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
- * @pos: the type * to use as a start point
- * @head: the head of the list
- * @member: the name of the list_struct within the struct.
- *
- * Prepares a pos entry for use as a start point in
- * list_for_each_entry_continue().
- */
-#define list_prepare_entry(pos, head, member) \
- ((pos) ? : list_entry(head, typeof(*pos), member))
-
-/**
- * list_for_each_entry_continue - continue iteration over list of given type
- * @pos: the type * to use as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * Continue to iterate over list of given type, continuing after
- * the current position.
- */
-#define list_for_each_entry_continue(pos, head, member) \
- for (pos = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_continue_reverse - iterate backwards from the given point
- * @pos: the type * to use as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * Start to iterate over list of given type backwards, continuing after
- * the current position.
- */
-#define list_for_each_entry_continue_reverse(pos, head, member) \
- for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_entry(pos->member.prev, typeof(*pos), member))
-
-/**
- * list_for_each_entry_from - iterate over list of given type from the current point
- * @pos: the type * to use as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * Iterate over list of given type, continuing from current position.
- */
-#define list_for_each_entry_from(pos, head, member) \
- for (; &pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos: the type * to use as a loop cursor.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
-#define list_for_each_entry_safe(pos, n, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member), \
- n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_for_each_entry_safe_continue
- * @pos: the type * to use as a loop cursor.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * Iterate over list of given type, continuing after current point,
- * safe against removal of list entry.
- */
-#define list_for_each_entry_safe_continue(pos, n, head, member) \
- for (pos = list_entry(pos->member.next, typeof(*pos), member), \
- n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_for_each_entry_safe_from
- * @pos: the type * to use as a loop cursor.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * Iterate over list of given type from current point, safe against
- * removal of list entry.
- */
-#define list_for_each_entry_safe_from(pos, n, head, member) \
- for (n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_for_each_entry_safe_reverse
- * @pos: the type * to use as a loop cursor.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * Iterate backwards over list of given type, safe against removal
- * of list entry.
- */
-#define list_for_each_entry_safe_reverse(pos, n, head, member) \
- for (pos = list_entry((head)->prev, typeof(*pos), member), \
- n = list_entry(pos->member.prev, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = list_entry(n->member.prev, typeof(*n), member))
-
-#endif /* LIST_H */
diff --git a/include/log.h b/include/log.h
deleted file mode 100644
index 7a2a138..0000000
--- a/include/log.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef LOG_H
-#define LOG_H
-
-void log_start(char *program, int daemon, int level);
-void log_stop();
-void do_log(int priority, const char *fmt, va_list ap);
-void log_debug(int level, char *fmt, ...);
-void log_warn(char *fmt, ...);
-void log_err(char *fmt, ...);
-void _log_errno(const char *func, char *call, int errnum);
-
-#define log_errno(s) _log_errno(__func__, s, errno)
-
-#endif /* LOG_H */
-
diff --git a/include/rtnetlink.h b/include/rtnetlink.h
new file mode 100644
index 0000000..167748e
--- /dev/null
+++ b/include/rtnetlink.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright(c) 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#ifndef _RTNETLINK_
+#define _RTNETLINK_
+
+int rtnl_socket(void);
+typedef int rtnl_handler(struct nlmsghdr *nh, void *arg);
+int rtnl_recv(int s, rtnl_handler *fn, void *arg);
+ssize_t send_getlink_dump(int s);
+int rtnl_set_iff_up(int ifindex, char *ifname);
+int vlan_create(int ifindex, int vid, char *name);
+int rtnl_find_vlan(int ifindex, int vid, char *ifname);
+int rtnl_get_linkname(int ifindex, char *name);
+
+static inline void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+{
+ memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
+ while (RTA_OK(rta, len)) {
+ if (rta->rta_type <= max)
+ tb[rta->rta_type] = rta;
+ rta = RTA_NEXT(rta, len);
+ }
+}
+
+static inline void parse_nested_rtattr(struct rtattr *tb[], int max, struct rtattr *rta)
+{
+ parse_rtattr(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta));
+}
+
+static inline void parse_ifinfo(struct rtattr *tb[], struct nlmsghdr *nh)
+{
+ struct ifinfomsg *ifm = NLMSG_DATA(nh);
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), IFLA_PAYLOAD(nh));
+}
+
+static inline void parse_linkinfo(struct rtattr *tb[], struct rtattr *linkinfo)
+{
+ parse_nested_rtattr(tb, IFLA_INFO_MAX, linkinfo);
+}
+
+static inline void parse_vlaninfo(struct rtattr *tb[], struct rtattr *vlan)
+{
+ parse_nested_rtattr(tb, IFLA_VLAN_MAX, vlan);
+}
+
+#endif /* _RTNETLINK_ */
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..ebe259f
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,3 @@
+AM_CPPFLAGS = -I${top_srcdir}/include
+noinst_LIBRARIES = libutil.a
+libutil_a_SOURCES = fcoe_utils.c sa_log.c sa_select.c sa_timer.c sa_other.c fip.c rtnetlink.c
diff --git a/lib/fcoe_utils.c b/lib/fcoe_utils.c
new file mode 100644
index 0000000..506356d
--- /dev/null
+++ b/lib/fcoe_utils.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright(c) 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#include "fcoe_utils.h"
+
+static int fcoe_sysfs_read(char *buf, int size, const char *path)
+{
+ FILE *fp;
+ int i, rc = -EINVAL;
+
+ fp = fopen(path, "r");
+ if (fp) {
+ if (fgets(buf, size, fp)) {
+ /*
+ * Strip trailing newline by replacing
+ * any '\r' or '\n' instances with '\0'.
+ * It's not as elegant as it could be, but
+ * we know that the symbolic name won't
+ * have either of those characters until
+ * the end of the line.
+ */
+ for (i = 0; i < strlen(buf); i++) {
+ if (buf[i] == '\n' ||
+ buf[i] == '\r') {
+ buf[i] = '\0';
+ break;
+ }
+ }
+ rc = 0;
+ }
+
+ fclose(fp);
+ }
+
+ return rc;
+}
+
+static int fcoe_check_fchost(const char *ifname, const char *dname)
+{
+ char buf[MAX_STR_LEN];
+ char path[MAX_PATH_LEN];
+ int rc = -EINVAL;
+
+ sprintf(path, "%s/%s/symbolic_name", SYSFS_FCHOST, dname);
+
+ if (!fcoe_sysfs_read(buf, MAX_STR_LEN, path))
+ rc = check_symbolic_name_for_interface(buf, ifname);
+
+ return rc;
+}
+
+enum fcoe_err fcoe_find_fchost(char *ifname, char *fchost, int len)
+{
+ int n, dname_len;
+ struct dirent **namelist;
+ int rc = ENOFCOECONN;
+
+ n = scandir(SYSFS_FCHOST, &namelist, 0, alphasort);
+
+ for (n-- ; n >= 0 ; n--) {
+ if (rc) {
+ /* check symbolic name */
+ if (!fcoe_check_fchost(ifname, namelist[n]->d_name)) {
+ dname_len = strnlen(namelist[n]->d_name, len);
+
+ if (len > dname_len) {
+ strncpy(fchost, namelist[n]->d_name,
+ dname_len + 1);
+ /* rc = 0 indicates found */
+ rc = NOERR;
+ } else {
+ /*
+ * The fc_host is too large
+ * for the buffer.
+ */
+ rc = EINTERR;
+ }
+ }
+ }
+ free(namelist[n]);
+
+ }
+ free(namelist);
+
+ return rc;
+}
+
+enum fcoe_err fcoe_validate_interface(char *ifname)
+{
+ enum fcoe_err rc = NOERR;
+ char path[MAX_PATH_LEN];
+
+
+ if (!strlen(ifname))
+ rc = ENOETHDEV;
+
+ /*
+ * TODO: Is there a better way to check if the
+ * interface name is correct?
+ */
+ sprintf(path, "%s/%s", SYSFS_NET, ifname);
+ if (!rc && fcoe_checkdir(path))
+ rc = ENOETHDEV;
+
+ return rc;
+}
+
+/*
+ * Validate an existing instance for an FC interface
+ */
+enum fcoe_err fcoe_validate_fcoe_conn(char *ifname)
+{
+ char fchost[FCHOSTBUFLEN];
+ enum fcoe_err rc = NOERR;
+
+ rc = fcoe_validate_interface(ifname);
+
+ if (!rc)
+ rc = fcoe_find_fchost(ifname, fchost, FCHOSTBUFLEN);
+
+ return rc;
+}
+
+/*
+ * Open and close to check if directory exists
+ */
+int fcoe_checkdir(char *dir)
+{
+ DIR *d = NULL;
+
+ if (!dir)
+ return -EINVAL;
+ /* check if we have sysfs */
+ d = opendir(dir);
+ if (!d)
+ return -EINVAL;
+ closedir(d);
+ return 0;
+}
+
+char *get_ifname_from_symbolic_name(const char *symbolic_name)
+{
+ int symbolic_name_len = strlen(symbolic_name);
+ int lead_len = strlen(SYMB_NAME_LEAD);
+
+ if (lead_len < symbolic_name_len)
+ return (char *)(symbolic_name + lead_len);
+
+ return NULL;
+}
+
+int check_symbolic_name_for_interface(const char *symbolic_name,
+ const char *ifname)
+{
+ int rc = -EINVAL;
+ char *symb;
+
+ if (!ifname)
+ return rc;
+
+ symb = get_ifname_from_symbolic_name(symbolic_name);
+
+ /*
+ * It's important to use the length of the ifname
+ * from the symbolic_name here. If the ifname length
+ * were used then if the user passed in a substring
+ * of the the interface name it would match because
+ * we'd only be looking for the first few characters,
+ * not the whole string.
+ */
+ if (symb && !strncmp(ifname, symb, strlen(symb)))
+ rc = 0;
+
+ return rc;
+}
diff --git a/lib/fip.c b/lib/fip.c
new file mode 100644
index 0000000..a5430c9
--- /dev/null
+++ b/lib/fip.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright(c) 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+/* Routines for automatic FIP VLAN discovery and creation */
+/* Shared by fcoemon and fipvlan */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <netpacket/packet.h>
+#include <arpa/inet.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include "fip.h"
+#include "fcoemon_utils.h"
+
+#define FIP_LOG(...) sa_log(__VA_ARGS__)
+#define FIP_LOG_ERR(error, ...) sa_log_err(error, __func__, __VA_ARGS__)
+#define FIP_LOG_ERRNO(...) sa_log_err(errno, __func__, __VA_ARGS__)
+#define FIP_LOG_DBG(...) sa_log_debug(__VA_ARGS__)
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+/**
+ * fip_send_vlan_request - send a FIP VLAN request
+ * @s: ETH_P_FIP packet socket to send on
+ * @ifindex: network interface index to send on
+ * @mac: mac address of the sending network interface
+ *
+ * Note: sends to FIP_ALL_FCF_MACS
+ */
+ssize_t fip_send_vlan_request(int s, int ifindex, unsigned char *mac)
+{
+ struct sockaddr_ll sa = {
+ .sll_family = AF_PACKET,
+ .sll_protocol = htons(ETH_P_FIP),
+ .sll_ifindex = ifindex,
+ .sll_hatype = ARPHRD_ETHER,
+ .sll_pkttype = PACKET_MULTICAST,
+ .sll_halen = ETHER_ADDR_LEN,
+ .sll_addr = FIP_ALL_FCF_MACS,
+ };
+ struct fiphdr fh = {
+ .fip_version = FIP_VERSION(1),
+ .fip_proto = htons(FIP_PROTO_VLAN),
+ .fip_subcode = FIP_VLAN_REQ,
+ .fip_desc_len = htons(2),
+ .fip_flags = 0,
+ };
+ struct {
+ struct fip_tlv_mac_addr mac;
+ } tlvs = {
+ .mac = {
+ .hdr.tlv_type = FIP_TLV_MAC_ADDR,
+ .hdr.tlv_len = 2,
+ },
+ };
+ struct iovec iov[] = {
+ { .iov_base = &fh, .iov_len = sizeof(fh), },
+ { .iov_base = &tlvs, .iov_len = sizeof(tlvs), },
+ };
+ struct msghdr msg = {
+ .msg_name = &sa,
+ .msg_namelen = sizeof(sa),
+ .msg_iov = iov,
+ .msg_iovlen = ARRAY_SIZE(iov),
+ };
+ int rc;
+
+ memcpy(tlvs.mac.mac_addr, mac, ETHER_ADDR_LEN);
+
+ FIP_LOG_DBG("sending FIP VLAN request");
+ rc = sendmsg(s, &msg, 0);
+ if (rc < 0) {
+ rc = -errno;
+ FIP_LOG_ERRNO("sendmsg error");
+ }
+ return rc;
+}
+
+/**
+ * fip_recv - receive from a FIP packet socket
+ * @s: packet socket with data ready to be received
+ * @fn: FIP receive callback to process the payload
+ * @arg: argument to pass through to @fn
+ */
+int fip_recv(int s, fip_handler *fn, void *arg)
+{
+ char buf[4096];
+ struct sockaddr_ll sa;
+ struct iovec iov[] = {
+ { .iov_base = buf, .iov_len = sizeof(buf), },
+ };
+ struct msghdr msg = {
+ .msg_name = &sa,
+ .msg_namelen = sizeof(sa),
+ .msg_iov = iov,
+ .msg_iovlen = ARRAY_SIZE(iov),
+ };
+ struct fiphdr *fh;
+ ssize_t len, desc_len;
+
+ FIP_LOG_DBG("%s", __func__);
+
+ len = recvmsg(s, &msg, 0);
+ if (len < 0) {
+ FIP_LOG_ERRNO("packet socket recv error");
+ return len;
+ }
+
+ if (len < sizeof(*fh)) {
+ FIP_LOG_ERR(EINVAL, "received packed smaller that FIP header");
+ return -1;
+ }
+
+ fh = (struct fiphdr *) buf;
+
+ desc_len = ntohs(fh->fip_desc_len);
+ if (len < (sizeof(*fh) + (desc_len << 2))) {
+ FIP_LOG_ERR(EINVAL, "received data less that FIP descriptor");
+ return -1;
+ }
+
+ if (fn)
+ return fn(fh, &sa, arg);
+ return 0;
+}
diff --git a/lib/rtnetlink.c b/lib/rtnetlink.c
new file mode 100644
index 0000000..b7a32f2
--- /dev/null
+++ b/lib/rtnetlink.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright(c) 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+#include <poll.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <netpacket/packet.h>
+#include <arpa/inet.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include "rtnetlink.h"
+#include "fcoemon_utils.h"
+
+#define RTNL_LOG(...) sa_log(__VA_ARGS__)
+#define RTNL_LOG_ERR(error, ...) sa_log_err(error, __func__, __VA_ARGS__)
+#define RTNL_LOG_ERRNO(...) sa_log_err(errno, __func__, __VA_ARGS__)
+#define RTNL_LOG_DBG(...) sa_log_debug(__VA_ARGS__)
+
+/**
+ * rtnl_socket - create and bind a routing netlink socket
+ */
+int rtnl_socket(void)
+{
+ struct sockaddr_nl sa = {
+ .nl_family = AF_NETLINK,
+ .nl_groups = RTMGRP_LINK,
+ };
+ int s;
+ int rc;
+
+ RTNL_LOG_DBG("creating netlink socket");
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ RTNL_LOG_ERRNO("netlink socket error");
+ return s;
+ }
+
+ rc = bind(s, (struct sockaddr *) &sa, sizeof(sa));
+ if (rc < 0) {
+ RTNL_LOG_ERRNO("netlink bind error");
+ close(s);
+ return rc;
+ }
+
+ return s;
+}
+
+/**
+ * send_getlink_dump - send an RTM_GETLINK dump request to list all interfaces
+ * @s: routing netlink socket to use
+ */
+ssize_t send_getlink_dump(int s)
+{
+ struct {
+ struct nlmsghdr nh;
+ struct ifinfomsg ifm;
+ } req = {
+ .nh = {
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+ .nlmsg_type = RTM_GETLINK,
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
+ },
+ .ifm = {
+ .ifi_type = ARPHRD_ETHER,
+ },
+ };
+ int rc;
+
+ RTNL_LOG_DBG("sending RTM_GETLINK dump request");
+ rc = send(s, &req, req.nh.nlmsg_len, 0);
+ if (rc < 0)
+ RTNL_LOG_ERRNO("netlink sendmsg error");
+
+ return rc;
+}
+
+#define NLMSG(c) ((struct nlmsghdr *) (c))
+
+/**
+ * rtnl_recv - receive from a routing netlink socket
+ * @s: routing netlink socket with data ready to be received
+ *
+ * Returns: 0 when NLMSG_DONE is received
+ * <0 on error
+ * >0 when more data is expected
+ */
+int rtnl_recv(int s, rtnl_handler *fn, void *arg)
+{
+ char buf[8192];
+ struct nlmsghdr *nh;
+ int len;
+ int rc = 0;
+ bool more = false;
+
+ RTNL_LOG_DBG("%s", __func__);
+more:
+ len = recv(s, buf, sizeof(buf), 0);
+ if (len < 0) {
+ RTNL_LOG_ERRNO("netlink recvmsg error");
+ return len;
+ }
+
+ for (nh = NLMSG(buf); NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
+ if (nh->nlmsg_flags & NLM_F_MULTI)
+ more = true;
+
+ switch (nh->nlmsg_type) {
+ case NLMSG_NOOP:
+ RTNL_LOG_DBG("NLMSG_NOOP");
+ break;
+ case NLMSG_ERROR:
+ rc = ((struct nlmsgerr *)NLMSG_DATA(nh))->error;
+ RTNL_LOG_DBG("NLMSG_ERROR (%d) %s", rc, strerror(-rc));
+ break;
+ case NLMSG_DONE:
+ more = false;
+ RTNL_LOG_DBG("NLMSG_DONE");
+ break;
+ default:
+ if (!fn || fn(nh, arg) < 0)
+ RTNL_LOG("unexpected netlink message type %d",
+ nh->nlmsg_type);
+ break;
+ }
+ }
+ if (more)
+ goto more;
+ return rc;
+}
+
+#define NLMSG_TAIL(nmsg) \
+ ((struct rtattr *)(((void *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+
+static void add_rtattr(struct nlmsghdr *n, int type, const void *data, int alen)
+{
+ struct rtattr *rta = NLMSG_TAIL(n);
+ int len = RTA_LENGTH(alen);
+
+ rta->rta_type = type;
+ rta->rta_len = len;
+ memcpy(RTA_DATA(rta), data, alen);
+ n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
+}
+
+static struct rtattr *add_rtattr_nest(struct nlmsghdr *n, int type)
+{
+ struct rtattr *nest = NLMSG_TAIL(n);
+
+ add_rtattr(n, type, NULL, 0);
+ return nest;
+}
+
+static void end_rtattr_nest(struct nlmsghdr *n, struct rtattr *nest)
+{
+ nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
+}
+
+static ssize_t rtnl_send_set_iff_up(int s, int ifindex, char *ifname)
+{
+ struct {
+ struct nlmsghdr nh;
+ struct ifinfomsg ifm;
+ char attrbuf[RTA_SPACE(IFNAMSIZ)];
+ } req = {
+ .nh = {
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+ .nlmsg_type = RTM_SETLINK,
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
+ },
+ .ifm = {
+ .ifi_index = ifindex,
+ .ifi_flags = IFF_UP,
+ .ifi_change = IFF_UP,
+ },
+ };
+ int rc;
+
+ if (ifname)
+ add_rtattr(&req.nh, IFLA_IFNAME, ifname, strlen(ifname));
+
+ RTNL_LOG_DBG("sending RTM_SETLINK request");
+ rc = send(s, &req, req.nh.nlmsg_len, 0);
+ if (rc < 0)
+ RTNL_LOG_ERRNO("netlink send error");
+
+ return rc;
+}
+
+int rtnl_set_iff_up(int ifindex, char *ifname)
+{
+ int s;
+ int rc;
+
+ s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (s < 0)
+ return s;
+ rc = rtnl_send_set_iff_up(s, ifindex, ifname);
+ if (rc < 0)
+ goto out;
+ rc = rtnl_recv(s, NULL, NULL);
+out:
+ close(s);
+ return rc;
+}
+
+static ssize_t rtnl_send_vlan_newlink(int s, int ifindex, int vid, char *name)
+{
+ struct {
+ struct nlmsghdr nh;
+ struct ifinfomsg ifm;
+ char attrbuf[1024];
+ } req = {
+ .nh = {
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+ .nlmsg_type = RTM_NEWLINK,
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE |
+ NLM_F_EXCL | NLM_F_ACK,
+ },
+ };
+ struct rtattr *linkinfo, *data;
+ int rc;
+
+ add_rtattr(&req.nh, IFLA_LINK, &ifindex, 4);
+ add_rtattr(&req.nh, IFLA_IFNAME, name, strlen(name));
+ linkinfo = add_rtattr_nest(&req.nh, IFLA_LINKINFO);
+ add_rtattr(&req.nh, IFLA_INFO_KIND, "vlan", strlen("vlan"));
+ data = add_rtattr_nest(&req.nh, IFLA_INFO_DATA);
+ add_rtattr(&req.nh, IFLA_VLAN_ID, &vid, 2);
+ end_rtattr_nest(&req.nh, data);
+ end_rtattr_nest(&req.nh, linkinfo);
+
+ RTNL_LOG_DBG("sending RTM_NEWLINK request");
+ rc = send(s, &req, req.nh.nlmsg_len, 0);
+ if (rc < 0)
+ RTNL_LOG_ERRNO("netlink send error");
+
+ return rc;
+}
+
+int vlan_create(int ifindex, int vid, char *name)
+{
+ int s;
+ int rc;
+
+ s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (s < 0)
+ return s;
+
+ rc = rtnl_send_vlan_newlink(s, ifindex, vid, name);
+ if (rc < 0)
+ goto out;
+ rc = rtnl_recv(s, NULL, NULL);
+out:
+ close(s);
+ return rc;
+}
+
+static ssize_t rtnl_send_getlink(int s, int ifindex, char *name)
+{
+ struct {
+ struct nlmsghdr nh;
+ struct ifinfomsg ifm;
+ char attrbuf[RTA_SPACE(IFNAMSIZ)];
+ } req = {
+ .nh = {
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+ .nlmsg_type = RTM_GETLINK,
+ .nlmsg_flags = NLM_F_REQUEST,
+ },
+ .ifm = {
+ .ifi_family = AF_UNSPEC,
+ .ifi_index = ifindex,
+ },
+ };
+ int rc;
+
+ if (!ifindex && !name)
+ return -1;
+
+ if (name)
+ add_rtattr(&req.nh, IFLA_IFNAME, name, strlen(name));
+
+ RTNL_LOG_DBG("sending RTM_GETLINK");
+ rc = send(s, &req, req.nh.nlmsg_len, 0);
+ if (rc < 0)
+ RTNL_LOG_ERRNO("netlink send error");
+
+ return rc;
+}
+
+static int rtnl_getlinkname_handler(struct nlmsghdr *nh, void *arg)
+{
+ char *name = arg;
+ struct ifinfomsg *ifm;
+ struct rtattr *ifla[__IFLA_MAX];
+
+ switch (nh->nlmsg_type) {
+ case RTM_NEWLINK:
+ ifm = NLMSG_DATA(nh);
+ parse_ifinfo(ifla, nh);
+ strncpy(name, RTA_DATA(ifla[IFLA_IFNAME]), IFNAMSIZ);
+ return 0;
+ }
+ return -1;
+}
+
+int rtnl_get_linkname(int ifindex, char *name)
+{
+ int s;
+ int rc;
+
+ s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (s < 0)
+ return s;
+ rc = rtnl_send_getlink(s, ifindex, NULL);
+ if (rc < 0)
+ return rc;
+ rc = rtnl_recv(s, rtnl_getlinkname_handler, name);
+ if (rc < 0)
+ goto out;
+out:
+ close(s);
+ return rc;
+}
+
+struct vlan_identifier {
+ int ifindex;
+ int vid;
+ int found;
+ unsigned char ifname[IFNAMSIZ];
+};
+
+static int rtnl_find_vlan_handler(struct nlmsghdr *nh, void *arg)
+{
+ struct vlan_identifier *vlan = arg;
+ struct ifinfomsg *ifm;
+ struct rtattr *ifla[__IFLA_MAX];
+ struct rtattr *linkinfo[__IFLA_INFO_MAX];
+ struct rtattr *vlaninfo[__IFLA_VLAN_MAX];
+
+ switch (nh->nlmsg_type) {
+ case RTM_NEWLINK:
+ ifm = NLMSG_DATA(nh);
+ parse_ifinfo(ifla, nh);
+ if (!ifla[IFLA_LINK])
+ break;
+ if (vlan->ifindex != *(int *)RTA_DATA(ifla[IFLA_LINK]))
+ break;
+ if (!ifla[IFLA_LINKINFO])
+ break;
+ parse_linkinfo(linkinfo, ifla[IFLA_LINKINFO]);
+ if (!linkinfo[IFLA_INFO_KIND])
+ break;
+ if (strcmp(RTA_DATA(linkinfo[IFLA_INFO_KIND]), "vlan"))
+ break;
+ if (!linkinfo[IFLA_INFO_DATA])
+ break;
+ parse_vlaninfo(vlaninfo, linkinfo[IFLA_INFO_DATA]);
+ if (!vlaninfo[IFLA_VLAN_ID])
+ break;
+ if (vlan->vid != *(int *)RTA_DATA(vlaninfo[IFLA_VLAN_ID]))
+ break;
+ if (!ifla[IFLA_IFNAME])
+ break;
+ vlan->found = 1;
+ memcpy(vlan->ifname, RTA_DATA(ifla[IFLA_IFNAME]), IFNAMSIZ);
+ }
+ return 0;
+}
+
+int rtnl_find_vlan(int ifindex, int vid, char *ifname)
+{
+ int s;
+ int rc;
+ struct vlan_identifier vlan = {
+ .ifindex = ifindex,
+ .vid = vid,
+ .found = 0,
+ };
+
+ s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (s < 0)
+ return s;
+ rc = send_getlink_dump(s);
+ if (rc < 0)
+ goto out;
+ rc = rtnl_recv(s, rtnl_find_vlan_handler, &vlan);
+ if (rc < 0)
+ goto out;
+ if (vlan.found) {
+ memcpy(ifname, vlan.ifname, IFNAMSIZ);
+ rc = 0;
+ } else {
+ rc = -ENODEV;
+ }
+out:
+ close(s);
+ return rc;
+}
diff --git a/lib/sa_log.c b/lib/sa_log.c
new file mode 100644
index 0000000..91c256f
--- /dev/null
+++ b/lib/sa_log.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright(c) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#include "fcoemon_utils.h"
+#include "net_types.h"
+#include "fc_types.h"
+
+int use_syslog;
+static int debug;
+
+/*
+ * Size of on-stack line buffers.
+ * These shouldn't be to large for a kernel stack frame.
+ */
+#define SA_LOG_BUF_LEN 200 /* on-stack line buffer size */
+
+void enable_syslog(int enable)
+{
+ use_syslog = enable;
+}
+
+void enable_debug_log(int enable)
+{
+ debug = enable;
+}
+
+/*
+ * log with a variable argument list.
+ */
+static void
+sa_log_va(const char *func, const char *format, va_list arg)
+{
+ size_t len;
+ size_t flen;
+ int add_newline;
+ char sa_buf[SA_LOG_BUF_LEN];
+ char *bp;
+
+ /*
+ * If the caller didn't provide a newline at the end, we will.
+ */
+ len = strlen(format);
+ add_newline = 0;
+ if (!len || format[len - 1] != '\n')
+ add_newline = 1;
+ bp = sa_buf;
+ len = sizeof(sa_buf);
+ if (func) {
+ flen = snprintf(bp, len, "%s: ", func);
+ len -= flen;
+ bp += flen;
+ }
+ flen = vsnprintf(bp, len, format, arg);
+ if (add_newline && flen < len) {
+ bp += flen;
+ *bp++ = '\n';
+ *bp = '\0';
+ }
+ sa_log_output(sa_buf);
+}
+
+/*
+ * log
+ */
+void
+sa_log(const char *format, ...)
+{
+ va_list arg;
+
+ va_start(arg, format);
+ sa_log_va(NULL, format, arg);
+ va_end(arg);
+}
+
+/*
+ * debug log, controlled by static debug flag
+ */
+void
+sa_log_debug(const char *format, ...)
+{
+ va_list arg;
+
+ if (!debug)
+ return;
+
+ va_start(arg, format);
+ sa_log_va(NULL, format, arg);
+ va_end(arg);
+}
+
+/*
+ * log with error number.
+ */
+void
+sa_log_err(int error, const char *func, const char *format, ...)
+{
+ va_list arg;
+ char buf[SA_LOG_BUF_LEN];
+
+ if (func)
+ sa_log("%s: error %d %s", func, error,
+ strerror_r(error, buf, sizeof(buf)));
+ else
+ sa_log("error %d %s", error,
+ strerror_r(error, buf, sizeof(buf)));
+ va_start(arg, format);
+ sa_log_va(func, format, arg);
+ va_end(arg);
+}
+
+/*
+ * Size of on-stack line buffers.
+ * These shouldn't be to large for a kernel stack frame.
+ */
+#define SA_LOG_BUF_LEN 200 /* on-stack line buffer size */
+
+/*
+ * Assert failures.
+ */
+void
+assert_failed(const char *format, ...)
+{
+ va_list arg;
+ char buf[SA_LOG_BUF_LEN];
+
+ va_start(arg, format);
+ vsnprintf(buf, sizeof(buf), format, arg);
+ va_end(arg);
+ sa_log_abort(buf);
+}
+
+/*
+ * Log options.
+ * These may be set directly by callers.
+ */
+u_int sa_log_flags; /* timestamp and other option flags */
+int sa_log_time_delta_min = 1; /* minimum diff to print in millisec */
+char *sa_log_prefix; /* string to print before any message */
+
+void
+sa_log_set_option(u_int flags)
+{
+ sa_log_flags = flags;
+}
+
+/*
+ * Put timestamp on front of each log line, as controlled by tunables above.
+ */
+static void
+sa_log_timestamp(void)
+{
+ static struct timeval tlast;
+ char ctime_buf[30];
+ struct timeval t;
+ struct timeval diff;
+
+ gettimeofday(&t, NULL);
+ if (sa_log_flags & SA_LOGF_TIME) {
+ ctime_r(&t.tv_sec, ctime_buf);
+ ctime_buf[11 + 8] = '\0'; /* trim ctime after seconds */
+ fprintf(stderr, "%s.%3.3ld ",
+ ctime_buf + 11, t.tv_usec / 1000);
+ }
+ if (sa_log_flags & SA_LOGF_DELTA) {
+ if (tlast.tv_sec == 0)
+ tlast = t;
+ timersub(&t, &tlast, &diff);
+ tlast = t;
+ if (diff.tv_sec != 0 ||
+ diff.tv_usec >= sa_log_time_delta_min * 1000)
+ fprintf(stderr, "%4ld.%3.3ld ",
+ diff.tv_sec, diff.tv_usec / 1000);
+ else
+ fprintf(stderr, "%8s ", "");
+ }
+ if (sa_log_prefix)
+ fprintf(stderr, "%s: ", sa_log_prefix);
+}
+
+void
+sa_log_output(const char *buf)
+{
+ if (use_syslog) {
+ syslog(LOG_INFO, "%s", buf);
+ return;
+ }
+ sa_log_timestamp();
+ fprintf(stderr, "%s", buf);
+ fflush(stderr);
+}
+
+void
+sa_log_abort(const char *buf)
+{
+ sa_log_output(buf);
+ abort();
+}
+
+/*
+ * Make a printable NUL-terminated copy of the string.
+ * The source buffer might not be NUL-terminated.
+ */
+char *
+sa_strncpy_safe(char *dest, size_t len, const char *src, size_t src_len)
+{
+ char *dp = dest;
+ const char *sp = src;
+
+ while (len-- > 1 && src_len-- > 0 && *sp != '\0') {
+ *dp++ = isprint(*sp) ? *sp : (isspace(*sp) ? ' ' : '.');
+ sp++;
+ }
+ *dp = '\0';
+
+ /*
+ * Take off trailing blanks.
+ */
+ while (--dp >= dest && isspace(*dp))
+ *dp = '\0';
+ return dest;
+}
+
+/** sa_enum_decode(buf, len, tp, val)
+ *
+ * @param buf buffer for result (may be used or not).
+ * @param len size of buffer (at least 32 bytes recommended).
+ * @param tp pointer to table of names and values, struct sa_nameval.
+ * @param val value to be decoded into a name.
+ * @returns pointer to name string. Unknown values are put into buffer in hex.
+ */
+const char *
+sa_enum_decode(char *buf, size_t len, const struct sa_nameval *tp, u_int val)
+{
+ for (; tp->nv_name != NULL; tp++) {
+ if (tp->nv_val == val)
+ return tp->nv_name;
+ }
+ snprintf(buf, len, "Unknown (code 0x%X)", val);
+ return buf;
+}
diff --git a/lib/sa_other.c b/lib/sa_other.c
new file mode 100644
index 0000000..af53a54
--- /dev/null
+++ b/lib/sa_other.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright(c) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#include "fcoemon_utils.h"
+#include "net_types.h"
+#include "fc_types.h"
+
+/*
+ * Convert 48-bit IEEE MAC address to 64-bit FC WWN.
+ */
+fc_wwn_t
+fc_wwn_from_mac(u_int64_t mac, u_int scheme, u_int port)
+{
+ fc_wwn_t wwn;
+
+ ASSERT(mac < (1ULL << 48));
+ wwn = mac | ((fc_wwn_t) scheme << 60);
+ switch (scheme) {
+ case 1:
+ ASSERT(port == 0);
+ break;
+ case 2:
+ ASSERT(port < 0xfff);
+ wwn |= (fc_wwn_t) port << 48;
+ break;
+ default:
+ ASSERT_NOTREACHED;
+ break;
+ }
+ return wwn;
+}
+
+/* assumes input is pointer to two hex digits */
+/* returns -1 on error */
+int
+hex2int(char *b)
+{
+ int i;
+ int n = 0;
+ int m;
+
+ for (i = 0, m = 1; i < 2; i++, m--) {
+ if (isxdigit(*(b+i))) {
+ if (*(b+i) <= '9')
+ n |= (*(b+i) & 0x0f) << (4*m);
+ else
+ n |= ((*(b+i) & 0x0f) + 9) << (4*m);
+ } else
+ return -1;
+ }
+ return n;
+}
+
diff --git a/lib/sa_select.c b/lib/sa_select.c
new file mode 100644
index 0000000..1b18a6e
--- /dev/null
+++ b/lib/sa_select.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright(c) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#include "fcoemon_utils.h"
+#include "net_types.h"
+#include "fc_types.h"
+
+#define NFC_NFDS 64
+
+/*
+* Static module state.
+*/
+static struct sa_sel_state {
+ fd_set ts_rx_fds;
+ fd_set ts_tx_fds;
+ fd_set ts_ex_fds;
+ int ts_max_fd;
+ u_char ts_exit;
+ struct sa_sel_fd {
+ void (*ts_rx_handler)(void *);
+ void (*ts_tx_handler)(void *);
+ void (*ts_ex_handler)(void *);
+ void *ts_handler_arg;
+ } ts_fd[NFC_NFDS];
+ void (*ts_callback)(void);
+} sa_sel_state;
+
+int sa_select_loop(void)
+{
+ struct sa_sel_state *ss = &sa_sel_state;
+ struct sa_sel_fd *fp;
+ fd_set rx_fds;
+ fd_set tx_fds;
+ fd_set ex_fds;
+ struct timeval tval;
+ struct timeval *tvp;
+ int rv, i;
+
+ ss->ts_exit = 0;
+ while (ss->ts_exit == 0) {
+ sa_timer_check(&tval);
+ if (ss->ts_exit)
+ break;
+ if (tval.tv_sec == 0 && tval.tv_usec == 0)
+ tvp = NULL;
+ else
+ tvp = &tval;
+ rx_fds = ss->ts_rx_fds;
+ tx_fds = ss->ts_tx_fds;
+ ex_fds = ss->ts_ex_fds;
+ rv = select(ss->ts_max_fd + 1, &rx_fds, &tx_fds, &ex_fds, tvp);
+ if (rv == -1) {
+ if (errno == EINTR)
+ continue;
+ return errno;
+ }
+
+ fp = ss->ts_fd;
+ for (i = 0; rv > 0 && i <= sa_sel_state.ts_max_fd; i++, fp++) {
+ if (FD_ISSET(i, &rx_fds)) {
+ if (fp->ts_rx_handler != NULL)
+ (*fp->ts_rx_handler)
+ (fp->ts_handler_arg);
+ else
+ ASSERT(!FD_ISSET(i, &ss->ts_rx_fds));
+ --rv;
+ }
+ if (FD_ISSET(i, &tx_fds)) {
+ if (fp->ts_tx_handler != NULL)
+ (*fp->ts_tx_handler)
+ (fp->ts_handler_arg);
+ else
+ ASSERT(!FD_ISSET(i, &ss->ts_tx_fds));
+ --rv;
+ }
+ if (FD_ISSET(i, &ex_fds)) {
+ if (fp->ts_ex_handler != NULL)
+ (*fp->ts_ex_handler)
+ (fp->ts_handler_arg);
+ else
+ ASSERT(!FD_ISSET(i, &ss->ts_ex_fds));
+ --rv;
+ }
+ }
+ if (ss->ts_callback != NULL)
+ (*ss->ts_callback)();
+ }
+ return 0;
+}
+
+void
+sa_select_add_fd(int fd,
+ void (*rx_handler)(void *),
+ void (*tx_handler)(void *),
+ void (*ex_handler)(void *),
+ void *arg)
+{
+ struct sa_sel_state *ss = &sa_sel_state;
+ struct sa_sel_fd *fp;
+
+ ASSERT_NOTIMPL(fd < NFC_NFDS);
+ ASSERT(rx_handler != NULL || tx_handler != NULL || ex_handler != NULL);
+ if (ss->ts_max_fd < fd)
+ ss->ts_max_fd = fd;
+ fp = &ss->ts_fd[fd];
+ fp->ts_handler_arg = arg;
+ if (rx_handler != NULL) {
+ fp->ts_rx_handler = rx_handler;
+ FD_SET(fd, &ss->ts_rx_fds);
+ }
+ if (tx_handler != NULL) {
+ fp->ts_tx_handler = tx_handler;
+ FD_SET(fd, &ss->ts_tx_fds);
+ }
+ if (ex_handler != NULL) {
+ fp->ts_ex_handler = ex_handler;
+ FD_SET(fd, &ss->ts_ex_fds);
+ }
+}
+
+void
+sa_select_set_rx(int fd, void (*handler)(void *))
+{
+ struct sa_sel_state *ss = &sa_sel_state;
+
+ ASSERT(fd <= ss->ts_max_fd);
+ ss->ts_fd[fd].ts_rx_handler = handler;
+ if (handler != NULL)
+ FD_SET(fd, &ss->ts_rx_fds);
+ else
+ FD_CLR(fd, &ss->ts_rx_fds);
+}
+
+void
+sa_select_set_tx(int fd, void (*handler)(void *))
+{
+ struct sa_sel_state *ss = &sa_sel_state;
+
+ ASSERT(fd <= ss->ts_max_fd);
+ ss->ts_fd[fd].ts_tx_handler = handler;
+ if (handler != NULL)
+ FD_SET(fd, &ss->ts_tx_fds);
+ else
+ FD_CLR(fd, &ss->ts_tx_fds);
+}
+
+void
+sa_select_set_ex(int fd, void (*handler)(void *))
+{
+ struct sa_sel_state *ss = &sa_sel_state;
+
+ ASSERT(fd <= ss->ts_max_fd);
+ ss->ts_fd[fd].ts_ex_handler = handler;
+ if (handler != NULL)
+ FD_SET(fd, &ss->ts_ex_fds);
+ else
+ FD_CLR(fd, &ss->ts_ex_fds);
+}
+
+void
+sa_select_rem_fd(int fd)
+{
+ struct sa_sel_state *ss = &sa_sel_state;
+ struct sa_sel_fd *fp;
+
+ ASSERT_NOTIMPL(fd < NFC_NFDS);
+ FD_CLR(fd, &ss->ts_rx_fds);
+ FD_CLR(fd, &ss->ts_tx_fds);
+ FD_CLR(fd, &ss->ts_ex_fds);
+ fp = &ss->ts_fd[fd];
+ fp->ts_rx_handler = NULL;
+ fp->ts_tx_handler = NULL;
+ fp->ts_ex_handler = NULL;
+ fp->ts_handler_arg = NULL;
+}
+
+/*
+ * Set callback for every time through the select loop.
+ */
+void
+sa_select_set_callback(void (*cb)(void))
+{
+ sa_sel_state.ts_callback = cb;
+}
+
+/*
+ * Cause select loop to exit.
+ * This is invoked from a handler which wants the select loop to return
+ * after the handler is finished. For example, during receipt of a network
+ * packet, the program may decide to clean up and exit, but in order to do
+ * this cleanly, all lower-level protocol handlers should return first.
+ */
+void
+sa_select_exit(void)
+{
+ sa_sel_state.ts_exit = 1;
+}
diff --git a/lib/sa_timer.c b/lib/sa_timer.c
new file mode 100644
index 0000000..aee213f
--- /dev/null
+++ b/lib/sa_timer.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright(c) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#include "fcoemon_utils.h"
+#include "net_types.h"
+#include "fc_types.h"
+
+#define SA_TIMER_HZ (1000 * 1000 * 1000ULL) /* nanoseconds per second */
+#define SA_TIMER_FUZZ (500 * 1000ULL) /* 500 microseconds is close enough */
+
+static struct sa_timer *sa_timer_head; /* queue of scheduled events */
+static u_int64_t sa_timer_nsec; /* nanoseconds since start */
+
+/*
+ * Initialize a timer structure. Set handler.
+ */
+void
+sa_timer_init(struct sa_timer *tm, void (*handler)(void *), void *arg)
+{
+ ASSERT(handler != NULL);
+ memset(tm, 0, sizeof(*tm));
+ tm->tm_handler = handler;
+ tm->tm_handler_arg = arg;
+}
+
+/*
+ * Allocate a timer structure. Set handler.
+ */
+struct sa_timer *
+sa_timer_alloc(void (*handler)(void *arg), void *arg)
+{
+ struct sa_timer *tm;
+
+ tm = malloc(sizeof(*tm));
+ if (tm)
+ sa_timer_init(tm, handler, arg);
+ return tm;
+}
+
+u_int64_t
+sa_timer_get(void)
+{
+ u_int64_t nsec;
+#ifndef _POSIX_TIMERS
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL); /* XXX want monotonic time, not TOD */
+ nsec = tv.tv_sec * SA_TIMER_HZ + tv.tv_usec * 1000;
+#else /* _POSIX_TIMERS */
+ struct timespec ts;
+ int rc;
+
+ rc = clock_gettime(CLOCK_MONOTONIC, &ts);
+ ASSERT_NOTIMPL(rc == 0);
+ nsec = ts.tv_sec * SA_TIMER_HZ + ts.tv_nsec;
+#endif /* _POSIX_TIMERS */
+
+#if 0 /* XXX */
+ ASSERT(nsec >= sa_timer_nsec); /* really must be monotonic */
+#else
+ if (nsec < sa_timer_nsec)
+ sa_log("sa_timer_get: negative time lapse "
+ "old %qud new %qud diff %qd nsec\n",
+ (long long unsigned int) sa_timer_nsec,
+ (long long unsigned int) nsec,
+ (long long int) (nsec - sa_timer_nsec));
+#endif
+ sa_timer_nsec = nsec;
+ return nsec;
+}
+
+/*
+ * Get monotonic time since some arbitrary time in the past.
+ * If _POSIX_MONOTONIC_CLOCK isn't available, we'll use time of day.
+ */
+u_int
+sa_timer_get_secs(void)
+{
+ u_int sec;
+
+#ifndef _POSIX_TIMERS
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL); /* XXX want monotonic time, not TOD */
+ sec = tv.tv_sec;
+#else /* _POSIX_TIMERS */
+ struct timespec ts;
+ int rc;
+
+ rc = clock_gettime(CLOCK_MONOTONIC, &ts);
+ ASSERT_NOTIMPL(rc == 0);
+ sec = ts.tv_sec;
+#endif /* _POSIX_TIMERS */
+ return sec;
+}
+
+/*
+ * Set timer to fire. Delta is in microseconds from now.
+ */
+void
+sa_timer_set(struct sa_timer *tm, u_long delta_usec)
+{
+ struct sa_timer *cur;
+ struct sa_timer **prev;
+
+ ASSERT(delta_usec != 0);
+ ASSERT(tm->tm_handler != NULL);
+ sa_timer_cancel(tm);
+ ASSERT(sa_timer_active(tm) == 0);
+ tm->tm_nsec =
+ sa_timer_get() + delta_usec * SA_TIMER_HZ / SA_TIMER_UNITS;
+ ASSERT(tm->tm_nsec != 0);
+
+ /*
+ * Insert timer into sorted linked list.
+ * Find insertion point, before cur.
+ */
+ for (prev = &sa_timer_head;
+ (cur = *prev) != NULL && cur->tm_nsec <= tm->tm_nsec;
+ prev = &cur->tm_next)
+ ;
+ *prev = tm;
+ tm->tm_next = cur;
+}
+
+/*
+ * Cancel timer if it is active.
+ */
+void
+sa_timer_cancel(struct sa_timer *tm)
+{
+ struct sa_timer *cur;
+ struct sa_timer **prev;
+
+ if (sa_timer_active(tm)) {
+ for (prev = &sa_timer_head; (cur = *prev) != NULL;
+ prev = &cur->tm_next)
+ if (cur == tm) {
+ tm->tm_nsec = 0;
+ *prev = tm->tm_next;
+ break;
+ }
+ ASSERT(cur == tm);
+ }
+}
+
+/*
+ * Free (and cancel) timer.
+ */
+void
+sa_timer_free(struct sa_timer *tm)
+{
+ if (sa_timer_active(tm))
+ sa_timer_cancel(tm);
+ free(tm);
+}
+
+/*
+ * Handle timer checks. Called from select loop or other periodic function.
+ *
+ * The struct timeval is set before returning to the maximum amount of time
+ * that should elapse before the next call.
+ *
+ * Returns 1 if any timer functions were called, 0 otherwise.
+ */
+int
+sa_timer_check(struct timeval *tv)
+{
+ u_int64_t now = 0;
+ u_int64_t next_due = 0;
+ struct sa_timer *tm;
+ int ret = 0;
+
+ /*
+ * Remember, the list may change during the handler.
+ */
+ for (;;) {
+ now = sa_timer_get();
+ tm = sa_timer_head;
+ if (tm == NULL) {
+ next_due = now;
+ break;
+ }
+
+ next_due = tm->tm_nsec;
+ if (next_due > now + SA_TIMER_FUZZ)
+ break;
+
+ /*
+ * Remove this element from the list.
+ */
+ sa_timer_head = tm->tm_next;
+ tm->tm_next = NULL;
+
+ /*
+ * Mark cancelled and call handler.
+ */
+ tm->tm_nsec = 0;
+ ASSERT(tm->tm_handler != NULL);
+ (*tm->tm_handler)(tm->tm_handler_arg);
+ ret = 1;
+ }
+
+ ASSERT(next_due >= now);
+ next_due -= now;
+ tv->tv_sec = (time_t) (next_due / SA_TIMER_HZ);
+ tv->tv_usec = (long) (next_due % SA_TIMER_HZ) / 1000;
+
+ return ret;
+}
diff --git a/log.c b/log.c
deleted file mode 100644
index a99ab93..0000000
--- a/log.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright(c) 2009 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Maintained at www.Open-FCoE.org
- */
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <syslog.h>
-#include <string.h>
-
-static int log_syslog;
-static int log_debug_level;
-static char log_prefix[256];
-
-void log_start(char *program, int daemon, int level)
-{
- log_syslog = daemon;
- log_debug_level = level;
- strncpy(log_prefix, program, 256);
- log_prefix[255] = '\0';
-
- if (log_syslog)
- openlog(log_prefix, 0, LOG_DAEMON);
-}
-
-void log_stop()
-{
- if (log_syslog)
- closelog();
-}
-
-void do_log(int priority, const char *fmt, va_list ap)
-{
- if (log_syslog)
- vsyslog(priority, fmt, ap);
- else {
- printf("%s: ", log_prefix);
- vprintf(fmt, ap);
- printf("\n");
- }
-}
-
-void log_debug(int level, char *fmt, ...)
-{
- va_list ap;
- if (log_debug_level >= level) {
- va_start(ap, fmt);
- do_log(LOG_DEBUG, fmt, ap);
- va_end(ap);
- }
-}
-
-void log_warn(char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- do_log(LOG_WARNING, fmt, ap);
- va_end(ap);
-}
-
-void log_err(char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- do_log(LOG_ERR, fmt, ap);
- va_end(ap);
-}
-
-void _log_errno(const char *func, char *call, int errnum)
-{
- log_err("%s %s: %s", func, call, strerror(errnum));
-}
-