|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Copyright (C) 2017-2018 Red Hat, Inc.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is free software: you can redistribute it and/or modify
|
|
Packit |
eace71 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
eace71 |
* the Free Software Foundation, either version 3 of the License, or
|
|
Packit |
eace71 |
* (at your option) any later version.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
eace71 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
eace71 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
eace71 |
* GNU General Public License for more details.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
eace71 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Author: Gris Ge <fge@redhat.com>
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
#ifndef _GNU_SOURCE
|
|
Packit |
eace71 |
#define _GNU_SOURCE /* For NI_MAXHOST */
|
|
Packit |
eace71 |
#endif
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include <stdint.h>
|
|
Packit |
eace71 |
#include <stdio.h>
|
|
Packit |
eace71 |
#include <stdlib.h>
|
|
Packit |
eace71 |
#include <errno.h>
|
|
Packit |
eace71 |
#include <dirent.h>
|
|
Packit |
eace71 |
#include <string.h>
|
|
Packit |
eace71 |
#include <net/if.h>
|
|
Packit |
eace71 |
#include <assert.h>
|
|
Packit |
eace71 |
#include <inttypes.h>
|
|
Packit |
eace71 |
#include <unistd.h>
|
|
Packit |
eace71 |
#include <sys/stat.h>
|
|
Packit |
eace71 |
#include <sys/wait.h>
|
|
Packit |
eace71 |
#include <stdbool.h>
|
|
Packit |
eace71 |
#include <libkmod.h>
|
|
Packit |
eace71 |
#include <limits.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "libopeniscsiusr/libopeniscsiusr.h"
|
|
Packit |
eace71 |
#include "misc.h"
|
|
Packit |
eace71 |
#include "sysfs.h"
|
|
Packit |
eace71 |
#include "iface.h"
|
|
Packit |
eace71 |
#include "context.h"
|
|
Packit |
eace71 |
#include "idbm.h"
|
|
Packit |
eace71 |
#include "default.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define ISCSIUIO_PATH "/sbin/iscsiuio"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct _iscsi_net_drv {
|
|
Packit |
eace71 |
const char *net_driver_name; // Ethernet driver.
|
|
Packit |
eace71 |
const char *iscsi_driver_name; // iSCSI offload driver.
|
|
Packit |
eace71 |
const char *transport_name; // iSCSI transport name.
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static struct _iscsi_net_drv _ISCSI_NET_DRVS[] = {
|
|
Packit |
eace71 |
{"cxgb3", "cxgb3i", "cxgb3i"},
|
|
Packit |
eace71 |
{"cxgb4", "cxgb4i", "cxgb4i"},
|
|
Packit |
eace71 |
{"bnx2", "bnx2i" , "bnx2i"},
|
|
Packit |
eace71 |
{"bnx2x", "bnx2i", "bnx2i"},
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
const struct iscsi_iface _DEFAULT_IFACES[] = {
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
.name = "default",
|
|
Packit |
eace71 |
.transport_name = "tcp",
|
|
Packit |
eace71 |
},
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
.name = "iser",
|
|
Packit |
eace71 |
.transport_name = "iser",
|
|
Packit |
eace71 |
},
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int _load_kernel_module(struct iscsi_context *ctx, const char *drv_name);
|
|
Packit |
eace71 |
static int _iface_conf_write(struct iscsi_context *ctx,
|
|
Packit |
eace71 |
struct iscsi_iface *iface);
|
|
Packit |
eace71 |
static int _fill_hw_iface_from_sys(struct iscsi_context *ctx,
|
|
Packit |
eace71 |
struct iscsi_iface *iface,
|
|
Packit |
eace71 |
const char *iface_kern_id);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_iface, hwaddress, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_iface, transport_name, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_iface, ipaddress, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_iface, netdev, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_iface, iname, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_iface, port_state, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_iface, port_speed, const char *);
|
|
Packit |
eace71 |
_iscsi_getter_func_gen(iscsi_iface, name, const char *);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int _iscsi_iface_get_from_sysfs(struct iscsi_context *ctx, uint32_t host_id,
|
|
Packit |
eace71 |
uint32_t sid, char *iface_kern_id,
|
|
Packit |
eace71 |
struct iscsi_iface **iface)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = LIBISCSI_OK;
|
|
Packit |
eace71 |
char *sysfs_se_dir_path = NULL;
|
|
Packit |
eace71 |
char *sysfs_sh_dir_path = NULL;
|
|
Packit |
eace71 |
char *sysfs_scsi_host_dir_path = NULL;
|
|
Packit |
eace71 |
char proc_name[ISCSI_TRANSPORT_NAME_MAXLEN];
|
|
Packit |
eace71 |
struct iscsi_iface **ifaces = NULL;
|
|
Packit |
eace71 |
uint32_t iface_count = 0;
|
|
Packit |
eace71 |
uint32_t i = 0;
|
|
Packit |
eace71 |
struct iscsi_iface *tmp_iface = NULL;
|
|
Packit |
eace71 |
bool bound_by_hwaddr = false;
|
|
Packit |
eace71 |
bool bound_by_netdev = false;
|
|
Packit |
eace71 |
bool matched = false;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
assert(ctx != NULL);
|
|
Packit |
eace71 |
assert(iface != NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*iface = NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (sid != 0) {
|
|
Packit |
eace71 |
_good(_asprintf(&sysfs_se_dir_path, "%s/session%" PRIu32,
|
|
Packit |
eace71 |
_ISCSI_SYS_SESSION_DIR, sid), rc, out);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_asprintf(&sysfs_sh_dir_path, "%s/host%" PRIu32,
|
|
Packit |
eace71 |
_ISCSI_SYS_HOST_DIR, host_id),rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_asprintf(&sysfs_scsi_host_dir_path, "%s/host%" PRIu32,
|
|
Packit |
eace71 |
_SCSI_SYS_HOST_DIR, host_id), rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*iface = (struct iscsi_iface *) calloc(1, sizeof(struct iscsi_iface));
|
|
Packit |
eace71 |
_alloc_null_check(ctx, *iface, rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_scsi_host_dir_path, "proc_name",
|
|
Packit |
eace71 |
proc_name, sizeof(proc_name) / sizeof(char),
|
|
Packit |
eace71 |
NULL /* raise error if failed */),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strncmp(proc_name, "iscsi_", strlen("iscsi_")) == 0)
|
|
Packit |
eace71 |
_strncpy((*iface)->transport_name, proc_name + strlen("iscsi_"),
|
|
Packit |
eace71 |
sizeof((*iface)->transport_name) / sizeof(char));
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
_strncpy((*iface)->transport_name, proc_name,
|
|
Packit |
eace71 |
sizeof((*iface)->transport_name) / sizeof(char));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "hwaddress",
|
|
Packit |
eace71 |
(*iface)->hwaddress,
|
|
Packit |
eace71 |
sizeof((*iface)->hwaddress) / sizeof(char),
|
|
Packit |
eace71 |
DEFAULT_HWADDRESS),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
if (strcmp((*iface)->hwaddress, DEFAULT_HWADDRESS) != 0)
|
|
Packit |
eace71 |
bound_by_hwaddr = true;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "netdev",
|
|
Packit |
eace71 |
(*iface)->netdev,
|
|
Packit |
eace71 |
sizeof((*iface)->netdev) / sizeof(char),
|
|
Packit |
eace71 |
DEFAULT_NETDEV),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
if (strcmp((*iface)->netdev, DEFAULT_NETDEV) != 0)
|
|
Packit |
eace71 |
bound_by_netdev = true;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (sysfs_se_dir_path)
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "initiatorname",
|
|
Packit |
eace71 |
(*iface)->iname,
|
|
Packit |
eace71 |
sizeof((*iface)->iname) / sizeof(char), "");
|
|
Packit |
eace71 |
if (strcmp((*iface)->iname, "") == 0)
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path,
|
|
Packit |
eace71 |
"initiatorname", (*iface)->iname,
|
|
Packit |
eace71 |
sizeof((*iface)->iname) /
|
|
Packit |
eace71 |
sizeof(char), ""),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "port_state",
|
|
Packit |
eace71 |
(*iface)->port_state,
|
|
Packit |
eace71 |
sizeof((*iface)->port_state) / sizeof(char),
|
|
Packit |
eace71 |
"unknown"),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strcmp((*iface)->port_state, "Unknown!") == 0)
|
|
Packit |
eace71 |
_strncpy((*iface)->port_state, "unknown",
|
|
Packit |
eace71 |
sizeof((*iface)->port_state) / sizeof(char));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "port_speed",
|
|
Packit |
eace71 |
(*iface)->port_speed,
|
|
Packit |
eace71 |
sizeof((*iface)->port_speed) / sizeof(char),
|
|
Packit |
eace71 |
"unknown"),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strncmp((*iface)->port_speed, "Unknown", strlen("Unknown")) == 0)
|
|
Packit |
eace71 |
_strncpy((*iface)->port_speed, "unknown",
|
|
Packit |
eace71 |
sizeof((*iface)->port_speed) / sizeof(char));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (sysfs_se_dir_path != NULL)
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_se_dir_path, "ifacename",
|
|
Packit |
eace71 |
(*iface)->name,
|
|
Packit |
eace71 |
sizeof((*iface)->name)/sizeof(char), "");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (iface_kern_id != NULL) {
|
|
Packit |
eace71 |
_good(_fill_hw_iface_from_sys(ctx, *iface, iface_kern_id),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "ipaddress",
|
|
Packit |
eace71 |
(*iface)->ipaddress,
|
|
Packit |
eace71 |
sizeof((*iface)->ipaddress) /
|
|
Packit |
eace71 |
sizeof(char), DEFAULT_IPADDRESS),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
/* bnx2i does not create
|
|
Packit |
eace71 |
* /sys/class/iscsi_iface/<iface_kernl_id>
|
|
Packit |
eace71 |
* We need to use transport_name.hwaddress as iface name.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
_debug(ctx, "HAHA: hwaddress %s", (*iface)->hwaddress);
|
|
Packit |
eace71 |
if (bound_by_hwaddr)
|
|
Packit |
eace71 |
snprintf((*iface)->name,
|
|
Packit |
eace71 |
sizeof((*iface)->name)/sizeof(char),
|
|
Packit |
eace71 |
"%s.%s", (*iface)->transport_name,
|
|
Packit |
eace71 |
(*iface)->hwaddress);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strcmp((*iface)->name, "") == 0) {
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Before 2.0.870, we only could bind by netdeivce or hwaddress,
|
|
Packit |
eace71 |
* so we did a simple reverse lookup to go from sysfs info to
|
|
Packit |
eace71 |
* the iface name. After 2.0.870 we added a lot of options to
|
|
Packit |
eace71 |
* the iface binding so we added the ifacename to the kernel.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Below codes are for older kernels that do not export the
|
|
Packit |
eace71 |
* ifacename. If the user was doing iscsi_tcp session binding
|
|
Packit |
eace71 |
* we will find the iface by matching net info.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(iscsi_ifaces_get(ctx, &ifaces, &iface_count), rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < iface_count; ++i) {
|
|
Packit |
eace71 |
tmp_iface = ifaces[i];
|
|
Packit |
eace71 |
if ((bound_by_hwaddr == true) &&
|
|
Packit |
eace71 |
(strcmp(tmp_iface->hwaddress, (*iface)->hwaddress)
|
|
Packit |
eace71 |
== 0)) {
|
|
Packit |
eace71 |
_strncpy((*iface)->name, tmp_iface->name,
|
|
Packit |
eace71 |
sizeof((*iface)->name)/sizeof(char));
|
|
Packit |
eace71 |
matched = true;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if ((bound_by_netdev == true) &&
|
|
Packit |
eace71 |
(strcmp(tmp_iface->netdev, (*iface)->netdev)
|
|
Packit |
eace71 |
== 0)) {
|
|
Packit |
eace71 |
_strncpy((*iface)->name, tmp_iface->name,
|
|
Packit |
eace71 |
sizeof((*iface)->name)/sizeof(char));
|
|
Packit |
eace71 |
matched = true;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (!matched)
|
|
Packit |
eace71 |
_strncpy((*iface)->name, DEFAULT_IFACENAME,
|
|
Packit |
eace71 |
sizeof((*iface)->name) / sizeof(char));
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
out:
|
|
Packit |
eace71 |
if (rc != LIBISCSI_OK) {
|
|
Packit |
eace71 |
iscsi_iface_free(*iface);
|
|
Packit |
eace71 |
*iface = NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
free(sysfs_se_dir_path);
|
|
Packit |
eace71 |
free(sysfs_sh_dir_path);
|
|
Packit |
eace71 |
free(sysfs_scsi_host_dir_path);
|
|
Packit |
eace71 |
iscsi_ifaces_free(ifaces, iface_count);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* create all ifaces for a host from sysfs */
|
|
Packit |
eace71 |
int _iscsi_ifaces_get_from_sysfs(struct iscsi_context *ctx, uint32_t host_id,
|
|
Packit |
eace71 |
struct iscsi_iface ***ifaces, uint32_t *iface_count)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = LIBISCSI_OK;
|
|
Packit |
eace71 |
char **iface_kern_ids = NULL;
|
|
Packit |
eace71 |
uint32_t i = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
assert(ctx != NULL);
|
|
Packit |
eace71 |
assert(ifaces != NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*ifaces = NULL;
|
|
Packit |
eace71 |
*iface_count = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_iscsi_iface_kern_ids_of_host_id(ctx, host_id, &iface_kern_ids, iface_count),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
if (*iface_count > 0) {
|
|
Packit |
eace71 |
*ifaces = (struct iscsi_iface **) calloc(*iface_count,
|
|
Packit |
eace71 |
sizeof(struct iscsi_iface *));
|
|
Packit |
eace71 |
_alloc_null_check(ctx, *ifaces, rc, out);
|
|
Packit |
eace71 |
for (i = 0; i < *iface_count; i++) {
|
|
Packit |
eace71 |
_good(_iscsi_iface_get_from_sysfs(ctx, host_id, 0,
|
|
Packit |
eace71 |
iface_kern_ids[i], &(*ifaces)[i]), rc, out);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
/* if there's no iface exported in sysfs,
|
|
Packit |
eace71 |
* we should still be able to create one record per host */
|
|
Packit |
eace71 |
*ifaces = (struct iscsi_iface **) calloc(1, sizeof(struct iscsi_iface *));
|
|
Packit |
eace71 |
_alloc_null_check(ctx, *ifaces, rc, out);
|
|
Packit |
eace71 |
*iface_count = 1;
|
|
Packit |
eace71 |
_good(_iscsi_iface_get_from_sysfs(ctx, host_id, 0, NULL, &(*ifaces)[0]), rc, out);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
out:
|
|
Packit |
eace71 |
if (iface_kern_ids != NULL) {
|
|
Packit |
eace71 |
for (i = 0; i < *iface_count; i++) {
|
|
Packit |
eace71 |
free(iface_kern_ids[i]);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
free(iface_kern_ids);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (rc != LIBISCSI_OK) {
|
|
Packit |
eace71 |
iscsi_ifaces_free(*ifaces, *iface_count);
|
|
Packit |
eace71 |
*ifaces = NULL;
|
|
Packit |
eace71 |
*iface_count = 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int iscsi_default_iface_setup(struct iscsi_context *ctx)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = LIBISCSI_OK;
|
|
Packit |
eace71 |
char strerr_buff[_STRERR_BUFF_LEN];
|
|
Packit |
eace71 |
int errno_save = 0;
|
|
Packit |
eace71 |
struct _eth_if **eifs = NULL;
|
|
Packit |
eace71 |
uint32_t eif_count = 0;
|
|
Packit |
eace71 |
uint32_t i = 0;
|
|
Packit |
eace71 |
uint32_t n = 0;
|
|
Packit |
eace71 |
size_t j = 0;
|
|
Packit |
eace71 |
struct _iscsi_net_drv *ind = NULL;
|
|
Packit |
eace71 |
uint32_t *hids = NULL;
|
|
Packit |
eace71 |
uint32_t hid_count = 0;
|
|
Packit |
eace71 |
struct iscsi_iface **ifaces = NULL;
|
|
Packit |
eace71 |
uint32_t iface_count = 0;
|
|
Packit |
eace71 |
char *path = NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
assert(ctx != NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_idbm_lock(ctx), rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((access(IFACE_CONFIG_DIR, F_OK) != 0) &&
|
|
Packit |
eace71 |
(mkdir(IFACE_CONFIG_DIR, 0660) != 0)) {
|
|
Packit |
eace71 |
errno_save = errno;
|
|
Packit |
eace71 |
_idbm_unlock(ctx);
|
|
Packit |
eace71 |
_error(ctx, "Could not make %s folder(%d %s). "
|
|
Packit |
eace71 |
"HW/OFFLOAD iscsi may not be supported.",
|
|
Packit |
eace71 |
IFACE_CONFIG_DIR, errno_save,
|
|
Packit |
eace71 |
_strerror(errno_save, strerr_buff));
|
|
Packit |
eace71 |
if (errno_save == EACCES)
|
|
Packit |
eace71 |
return LIBISCSI_ERR_ACCESS;
|
|
Packit |
eace71 |
return LIBISCSI_ERR_BUG;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
_idbm_unlock(ctx);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Load kernel driver for iSCSI offload cards, like cxgb3i */
|
|
Packit |
eace71 |
_good(_eth_ifs_get(ctx, &eifs, &eif_count), rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < eif_count; ++i) {
|
|
Packit |
eace71 |
for (j = 0;
|
|
Packit |
eace71 |
j < sizeof(_ISCSI_NET_DRVS)/sizeof(struct _iscsi_net_drv);
|
|
Packit |
eace71 |
++j) {
|
|
Packit |
eace71 |
ind = &(_ISCSI_NET_DRVS[j]);
|
|
Packit |
eace71 |
if ((ind->net_driver_name == NULL) ||
|
|
Packit |
eace71 |
(strcmp(eifs[i]->driver_name,
|
|
Packit |
eace71 |
ind->net_driver_name) != 0))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* iSCSI hardware offload for bnx2{,x} is only supported
|
|
Packit |
eace71 |
* if the iscsiuio executable is available.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if ((strcmp(eifs[i]->driver_name, "bnx2x") == 0) ||
|
|
Packit |
eace71 |
(strcmp(eifs[i]->driver_name, "bnx2") == 0)) {
|
|
Packit |
eace71 |
if (access(ISCSIUIO_PATH, F_OK) != 0) {
|
|
Packit |
eace71 |
_debug(ctx, "iSCSI offload on %s(%s) "
|
|
Packit |
eace71 |
"via %s is not supported due to "
|
|
Packit |
eace71 |
"missing %s", eifs[i]->if_name,
|
|
Packit |
eace71 |
eifs[i]->driver_name,
|
|
Packit |
eace71 |
ind->iscsi_driver_name,
|
|
Packit |
eace71 |
ISCSIUIO_PATH);
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (_iscsi_transport_is_loaded(ind->transport_name))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_debug(ctx, "Loading kernel module %s for iSCSI "
|
|
Packit |
eace71 |
"offload on %s(%s)", ind->iscsi_driver_name,
|
|
Packit |
eace71 |
eifs[i]->if_name, eifs[i]->driver_name);
|
|
Packit |
eace71 |
_good(_load_kernel_module(ctx, ind->iscsi_driver_name),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_iscsi_hids_get(ctx, &hids, &hid_count), rc, out);
|
|
Packit |
eace71 |
for (i = 0; i < hid_count; ++i) {
|
|
Packit |
eace71 |
/* Create /etc/iscsi/ifaces/<iface_name> file if not found
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
_good(_iscsi_ifaces_get_from_sysfs(ctx, hids[i], &ifaces, &iface_count),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
for (n = 0; n < iface_count; n++) {
|
|
Packit |
eace71 |
if ( ! iscsi_is_default_iface(ifaces[n])) {
|
|
Packit |
eace71 |
_good(_asprintf(&path, "%s/%s", IFACE_CONFIG_DIR,
|
|
Packit |
eace71 |
ifaces[n]->name), rc, out);
|
|
Packit |
eace71 |
if (access(path, F_OK) != 0)
|
|
Packit |
eace71 |
rc = _iface_conf_write(ctx, ifaces[n]);
|
|
Packit |
eace71 |
free(path);
|
|
Packit |
eace71 |
path = NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
iscsi_iface_free(ifaces[n]);
|
|
Packit |
eace71 |
ifaces[n] = NULL;
|
|
Packit |
eace71 |
if (rc != LIBISCSI_OK)
|
|
Packit |
eace71 |
goto out;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
free(ifaces);
|
|
Packit |
eace71 |
ifaces = NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
out:
|
|
Packit |
eace71 |
if (ifaces != NULL) {
|
|
Packit |
eace71 |
for (i = 0; i < iface_count; i++)
|
|
Packit |
eace71 |
free(ifaces[i]);
|
|
Packit |
eace71 |
free(ifaces);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
_eth_ifs_free(eifs, eif_count);
|
|
Packit |
eace71 |
free(path);
|
|
Packit |
eace71 |
free(hids);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int _load_kernel_module(struct iscsi_context *ctx, const char *drv_name)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct kmod_ctx *kctx = NULL;
|
|
Packit |
eace71 |
struct kmod_module *mod = NULL;
|
|
Packit |
eace71 |
int rc = LIBISCSI_OK;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
kctx = kmod_new(NULL, NULL);
|
|
Packit |
eace71 |
_alloc_null_check(ctx, kctx, rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
kmod_load_resources(kctx);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (kmod_module_new_from_name(kctx, drv_name, &mod)) {
|
|
Packit |
eace71 |
_error(ctx, "Failed to load module %s.", drv_name);
|
|
Packit |
eace71 |
rc = LIBISCSI_ERR_TRANS_NOT_FOUND;
|
|
Packit |
eace71 |
goto out;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST,
|
|
Packit |
eace71 |
NULL, NULL, NULL, NULL)) {
|
|
Packit |
eace71 |
_error(ctx, "Could not insert module %s. Kmod error %d",
|
|
Packit |
eace71 |
drv_name, rc);
|
|
Packit |
eace71 |
rc = LIBISCSI_ERR_TRANS_NOT_FOUND;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
kmod_module_unref(mod);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
out:
|
|
Packit |
eace71 |
if (kctx != NULL)
|
|
Packit |
eace71 |
kmod_unref(kctx);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int _iface_conf_write(struct iscsi_context *ctx,
|
|
Packit |
eace71 |
struct iscsi_iface *iface)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
char *conf_path = NULL;
|
|
Packit |
eace71 |
char strerr_buff[_STRERR_BUFF_LEN];
|
|
Packit |
eace71 |
int errno_save = 0;
|
|
Packit |
eace71 |
FILE *f = NULL;
|
|
Packit |
eace71 |
int rc = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (iscsi_is_default_iface(iface)) {
|
|
Packit |
eace71 |
_error(ctx, "iface %s is not a special interface and "
|
|
Packit |
eace71 |
"is not stored in %s", iface->name, IFACE_CONFIG_DIR);
|
|
Packit |
eace71 |
return LIBISCSI_ERR_INVAL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_idbm_lock(ctx), rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_asprintf(&conf_path, "%s/%s", IFACE_CONFIG_DIR,
|
|
Packit |
eace71 |
iface->name), rc, out);
|
|
Packit |
eace71 |
_debug(ctx, "Creating iSCSI interface configuration file '%s' "
|
|
Packit |
eace71 |
"using kernel information", conf_path);
|
|
Packit |
eace71 |
f = fopen(conf_path, "w");
|
|
Packit |
eace71 |
errno_save = errno;
|
|
Packit |
eace71 |
if (!f) {
|
|
Packit |
eace71 |
_error(ctx, "Failed to open %s using write mode: %d %s",
|
|
Packit |
eace71 |
conf_path, errno_save,
|
|
Packit |
eace71 |
_strerror(errno_save, strerr_buff));
|
|
Packit |
eace71 |
rc = LIBISCSI_ERR_IDBM;
|
|
Packit |
eace71 |
goto out;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_idbm_iface_print(iface, f);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_idbm_unlock(ctx);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
out:
|
|
Packit |
eace71 |
free(conf_path);
|
|
Packit |
eace71 |
if (f != NULL)
|
|
Packit |
eace71 |
fclose(f);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
// mimic of iscsi_sysfs_read_iface() in iscsi_sysfs.c.
|
|
Packit |
eace71 |
static int _fill_hw_iface_from_sys(struct iscsi_context *ctx,
|
|
Packit |
eace71 |
struct iscsi_iface *iface,
|
|
Packit |
eace71 |
const char *iface_kern_id)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = LIBISCSI_OK;
|
|
Packit |
eace71 |
char *sysfs_iface_dir_path = NULL;
|
|
Packit |
eace71 |
uint32_t tmp_host_no = 0;
|
|
Packit |
eace71 |
uint32_t iface_num = 0;
|
|
Packit |
eace71 |
int iface_type = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
assert(ctx != NULL);
|
|
Packit |
eace71 |
assert(iface != NULL);
|
|
Packit |
eace71 |
assert(iface_kern_id != NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_asprintf(&sysfs_iface_dir_path, "%s/%s", _ISCSI_SYS_IFACE_DIR,
|
|
Packit |
eace71 |
iface_kern_id), rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"ipaddress",
|
|
Packit |
eace71 |
iface->ipaddress,
|
|
Packit |
eace71 |
sizeof(iface->ipaddress) /
|
|
Packit |
eace71 |
sizeof(char), DEFAULT_IPADDRESS),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strncmp(iface_kern_id, "ipv4", strlen("ipv4")) == 0) {
|
|
Packit |
eace71 |
iface->is_ipv6 = false;
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"bootproto", iface->bootproto,
|
|
Packit |
eace71 |
sizeof(iface->bootproto) / sizeof(char),
|
|
Packit |
eace71 |
"");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "gateway",
|
|
Packit |
eace71 |
iface->gateway,
|
|
Packit |
eace71 |
sizeof(iface->gateway) / sizeof(char),
|
|
Packit |
eace71 |
"");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "subnet",
|
|
Packit |
eace71 |
iface->subnet_mask,
|
|
Packit |
eace71 |
sizeof(iface->subnet_mask) / sizeof(char),
|
|
Packit |
eace71 |
"");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"dhcp_alt_client_id_en",
|
|
Packit |
eace71 |
iface->dhcp_alt_client_id,
|
|
Packit |
eace71 |
sizeof(iface->dhcp_alt_client_id) /
|
|
Packit |
eace71 |
sizeof(char),
|
|
Packit |
eace71 |
"");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"dhcp_alt_client_id",
|
|
Packit |
eace71 |
iface->dhcp_alt_client_id,
|
|
Packit |
eace71 |
sizeof(iface->dhcp_alt_client_id) /
|
|
Packit |
eace71 |
sizeof(char),
|
|
Packit |
eace71 |
"");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"dhcp_dns_address_en", iface->dhcp_dns,
|
|
Packit |
eace71 |
sizeof(iface->dhcp_dns) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"dhcp_learn_iqn_en", iface->dhcp_learn_iqn,
|
|
Packit |
eace71 |
sizeof(iface->dhcp_learn_iqn) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"dhcp_req_vendor_id_en",
|
|
Packit |
eace71 |
iface->dhcp_req_vendor_id_state,
|
|
Packit |
eace71 |
sizeof(iface->dhcp_req_vendor_id_state) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"dhcp_use_vendor_id_en",
|
|
Packit |
eace71 |
iface->dhcp_vendor_id_state,
|
|
Packit |
eace71 |
sizeof(iface->dhcp_vendor_id_state) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"dhcp_vendor_id", iface->dhcp_vendor_id,
|
|
Packit |
eace71 |
sizeof(iface->dhcp_vendor_id) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"dhcp_slp_da_info_en", iface->dhcp_slp_da,
|
|
Packit |
eace71 |
sizeof(iface->dhcp_slp_da) / sizeof(char),
|
|
Packit |
eace71 |
"");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"fragment_disable", iface->fragmentation,
|
|
Packit |
eace71 |
sizeof(iface->fragmentation) / sizeof(char),
|
|
Packit |
eace71 |
"");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"grat_arp_en", iface->gratuitous_arp,
|
|
Packit |
eace71 |
sizeof(iface->gratuitous_arp) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"incoming_forwarding_en",
|
|
Packit |
eace71 |
iface->incoming_forwarding,
|
|
Packit |
eace71 |
sizeof(iface->incoming_forwarding) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "tos_en",
|
|
Packit |
eace71 |
iface->tos_state, sizeof(iface->tos_state) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "tos",
|
|
Packit |
eace71 |
&iface->tos, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "ttl",
|
|
Packit |
eace71 |
&iface->ttl, 0, true);
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
iface->is_ipv6 = true;
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "ipaddr_autocfg",
|
|
Packit |
eace71 |
iface->ipv6_autocfg,
|
|
Packit |
eace71 |
sizeof(iface->ipv6_autocfg) / sizeof(char),
|
|
Packit |
eace71 |
"");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"link_local_addr", iface->ipv6_linklocal,
|
|
Packit |
eace71 |
sizeof(iface->ipv6_linklocal) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"link_local_autocfg",
|
|
Packit |
eace71 |
iface->linklocal_autocfg,
|
|
Packit |
eace71 |
sizeof(iface->linklocal_autocfg) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"router_addr", iface->ipv6_router,
|
|
Packit |
eace71 |
sizeof(iface->ipv6_router) / sizeof(char),
|
|
Packit |
eace71 |
"");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"router_state", iface->router_autocfg,
|
|
Packit |
eace71 |
sizeof(iface->router_autocfg) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"grat_neighbor_adv_en",
|
|
Packit |
eace71 |
iface->gratuitous_neighbor_adv,
|
|
Packit |
eace71 |
sizeof(iface->gratuitous_neighbor_adv) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "mld_en",
|
|
Packit |
eace71 |
iface->mld, sizeof(iface->mld) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_u8(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"dup_addr_detect_cnt",
|
|
Packit |
eace71 |
&iface->dup_addr_detect_cnt, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "hop_limit",
|
|
Packit |
eace71 |
&iface->hop_limit, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u32(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"flow_label", &iface->flow_label, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u32(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"nd_reachable_tmo",
|
|
Packit |
eace71 |
&iface->nd_reachable_tmo, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u32(ctx, sysfs_iface_dir_path, "nd_rexmit_time",
|
|
Packit |
eace71 |
&iface->nd_rexmit_time, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u32(ctx, sysfs_iface_dir_path, "nd_stale_tmo",
|
|
Packit |
eace71 |
&iface->nd_stale_tmo, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u32(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"router_adv_link_mtu",
|
|
Packit |
eace71 |
&iface->router_adv_link_mtu, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u32(ctx, sysfs_iface_dir_path, "traffic_class",
|
|
Packit |
eace71 |
&iface->traffic_class, 0, true);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_sysfs_prop_get_u16(ctx, sysfs_iface_dir_path, "port", &iface->port, 0,
|
|
Packit |
eace71 |
true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u16(ctx, sysfs_iface_dir_path, "mtu", &iface->mtu, 0,
|
|
Packit |
eace71 |
true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u16(ctx, sysfs_iface_dir_path, "vlan_id",
|
|
Packit |
eace71 |
&iface->vlan_id, UINT16_MAX, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "vlan_priority",
|
|
Packit |
eace71 |
&iface->vlan_priority, UINT8_MAX, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "vlan_enabled",
|
|
Packit |
eace71 |
iface->vlan_state, sizeof(iface->vlan_state) /
|
|
Packit |
eace71 |
sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "enabled", iface->state,
|
|
Packit |
eace71 |
sizeof(iface->state) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "delayed_ack_en",
|
|
Packit |
eace71 |
iface->delayed_ack,
|
|
Packit |
eace71 |
sizeof(iface->delayed_ack) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "tcp_nagle_disable",
|
|
Packit |
eace71 |
iface->nagle, sizeof(iface->nagle) / sizeof(char),
|
|
Packit |
eace71 |
"");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "tcp_wsf_disable",
|
|
Packit |
eace71 |
iface->tcp_wsf_state,
|
|
Packit |
eace71 |
sizeof(iface->tcp_wsf_state) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "tcp_wsf",
|
|
Packit |
eace71 |
&iface->tcp_wsf, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "tcp_timer_scale",
|
|
Packit |
eace71 |
&iface->tcp_timer_scale, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "tcp_timestamp_en",
|
|
Packit |
eace71 |
iface->tcp_timestamp,
|
|
Packit |
eace71 |
sizeof(iface->tcp_timestamp) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "redirect_en",
|
|
Packit |
eace71 |
iface->redirect,
|
|
Packit |
eace71 |
sizeof(iface->redirect) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_u16(ctx, sysfs_iface_dir_path, "def_taskmgmt_tmo",
|
|
Packit |
eace71 |
&iface->def_task_mgmt_tmo, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "header_digest",
|
|
Packit |
eace71 |
iface->header_digest,
|
|
Packit |
eace71 |
sizeof(iface->header_digest) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "data_digest",
|
|
Packit |
eace71 |
iface->data_digest,
|
|
Packit |
eace71 |
sizeof(iface->data_digest) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "immediate_data",
|
|
Packit |
eace71 |
iface->immediate_data,
|
|
Packit |
eace71 |
sizeof(iface->immediate_data) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "initial_r2t",
|
|
Packit |
eace71 |
iface->initial_r2t,
|
|
Packit |
eace71 |
sizeof(iface->initial_r2t) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "data_seq_in_order",
|
|
Packit |
eace71 |
iface->data_seq_inorder,
|
|
Packit |
eace71 |
sizeof(iface->data_seq_inorder) / sizeof(char),
|
|
Packit |
eace71 |
"");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "data_pdu_in_order",
|
|
Packit |
eace71 |
iface->data_pdu_inorder,
|
|
Packit |
eace71 |
sizeof(iface->data_pdu_inorder) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_u8(ctx, sysfs_iface_dir_path, "erl", &iface->erl, 0,
|
|
Packit |
eace71 |
true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u32(ctx, sysfs_iface_dir_path, "max_recv_dlength",
|
|
Packit |
eace71 |
&iface->max_recv_dlength, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u32(ctx, sysfs_iface_dir_path, "first_burst_len",
|
|
Packit |
eace71 |
&iface->first_burst_len, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u16(ctx, sysfs_iface_dir_path, "max_outstanding_r2t",
|
|
Packit |
eace71 |
&iface->max_out_r2t, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_u32(ctx, sysfs_iface_dir_path, "max_burst_len",
|
|
Packit |
eace71 |
&iface->max_burst_len, 0, true);
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "chap_auth",
|
|
Packit |
eace71 |
iface->chap_auth,
|
|
Packit |
eace71 |
sizeof(iface->chap_auth) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "bidi_chap",
|
|
Packit |
eace71 |
iface->bidi_chap,
|
|
Packit |
eace71 |
sizeof(iface->bidi_chap) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, "strict_login_comp_en",
|
|
Packit |
eace71 |
iface->strict_login_comp,
|
|
Packit |
eace71 |
sizeof(iface->strict_login_comp) / sizeof(char),
|
|
Packit |
eace71 |
"");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"discovery_auth_optional",
|
|
Packit |
eace71 |
iface->discovery_auth,
|
|
Packit |
eace71 |
sizeof(iface->discovery_auth) / sizeof(char), "");
|
|
Packit |
eace71 |
_sysfs_prop_get_str(ctx, sysfs_iface_dir_path,
|
|
Packit |
eace71 |
"discovery_logout",
|
|
Packit |
eace71 |
iface->discovery_logout,
|
|
Packit |
eace71 |
sizeof(iface->discovery_logout) / sizeof(char), "");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (sscanf(iface_kern_id, "ipv%d-iface-%" SCNu32 "-%" SCNu32,
|
|
Packit |
eace71 |
&iface_type, &tmp_host_no, &iface_num) == 3)
|
|
Packit |
eace71 |
iface->iface_num = iface_num;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
snprintf(iface->name, sizeof(iface->name)/sizeof(char),
|
|
Packit |
eace71 |
"%s.%s.%s.%u", iface->transport_name,
|
|
Packit |
eace71 |
iface->hwaddress, iface->is_ipv6 ? "ipv6" : "ipv4",
|
|
Packit |
eace71 |
iface->iface_num);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
out:
|
|
Packit |
eace71 |
free(sysfs_iface_dir_path);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int iscsi_ifaces_get(struct iscsi_context *ctx, struct iscsi_iface ***ifaces,
|
|
Packit |
eace71 |
uint32_t *iface_count)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = LIBISCSI_OK;
|
|
Packit |
eace71 |
struct dirent **namelist = NULL;
|
|
Packit |
eace71 |
int n = 0;
|
|
Packit |
eace71 |
size_t i = 0;
|
|
Packit |
eace71 |
struct iscsi_iface *iface = NULL;
|
|
Packit |
eace71 |
int j = 0;
|
|
Packit |
eace71 |
uint32_t real_iface_count = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
assert(ctx != NULL);
|
|
Packit |
eace71 |
assert(ifaces != NULL);
|
|
Packit |
eace71 |
assert(iface_count != NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*ifaces = NULL;
|
|
Packit |
eace71 |
*iface_count = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_idbm_lock(ctx), rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_good(_scandir(ctx, IFACE_CONFIG_DIR, &namelist, &n), rc, out);
|
|
Packit |
eace71 |
_debug(ctx, "Got %d iface from %s folder", n, IFACE_CONFIG_DIR);
|
|
Packit |
eace71 |
*iface_count = (n + sizeof(_DEFAULT_IFACES)/sizeof(struct iscsi_iface))
|
|
Packit |
eace71 |
& UINT32_MAX;
|
|
Packit |
eace71 |
*ifaces = (struct iscsi_iface **) calloc(*iface_count,
|
|
Packit |
eace71 |
sizeof(struct iscsi_iface *));
|
|
Packit |
eace71 |
_alloc_null_check(ctx, *ifaces, rc, out);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (j = 0; j < n; ++j) {
|
|
Packit |
eace71 |
_good(_idbm_iface_get(ctx, namelist[j]->d_name, &iface),
|
|
Packit |
eace71 |
rc, out);
|
|
Packit |
eace71 |
if (iface != NULL) {
|
|
Packit |
eace71 |
(*ifaces)[real_iface_count++] = iface;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < sizeof(_DEFAULT_IFACES)/sizeof(struct iscsi_iface);
|
|
Packit |
eace71 |
++i) {
|
|
Packit |
eace71 |
iface = calloc(1, sizeof(struct iscsi_iface));
|
|
Packit |
eace71 |
_alloc_null_check(ctx, iface, rc, out);
|
|
Packit |
eace71 |
(*ifaces)[real_iface_count++] = iface;
|
|
Packit |
eace71 |
memcpy(iface, &_DEFAULT_IFACES[i], sizeof(struct iscsi_iface));
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*iface_count = real_iface_count;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
out:
|
|
Packit |
eace71 |
_scandir_free(namelist, n);
|
|
Packit |
eace71 |
_idbm_unlock(ctx);
|
|
Packit |
eace71 |
if (rc != LIBISCSI_OK) {
|
|
Packit |
eace71 |
iscsi_ifaces_free(*ifaces, *iface_count);
|
|
Packit |
eace71 |
*ifaces = NULL;
|
|
Packit |
eace71 |
*iface_count = 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void iscsi_ifaces_free(struct iscsi_iface **ifaces, uint32_t iface_count)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
uint32_t i = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if ((ifaces == NULL) || (iface_count == 0))
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < iface_count; ++i)
|
|
Packit |
eace71 |
iscsi_iface_free(ifaces[i]);
|
|
Packit |
eace71 |
free (ifaces);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static bool _iface_is_bound_by_hwaddr(struct iscsi_iface *iface)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (iface && strlen(iface->hwaddress) &&
|
|
Packit |
eace71 |
strcmp(iface->hwaddress, DEFAULT_HWADDRESS))
|
|
Packit |
eace71 |
return true;
|
|
Packit |
eace71 |
return false;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static bool _iface_is_bound_by_netdev(struct iscsi_iface *iface)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (iface && strlen(iface->netdev) &&
|
|
Packit |
eace71 |
strcmp(iface->netdev, DEFAULT_NETDEV))
|
|
Packit |
eace71 |
return true;
|
|
Packit |
eace71 |
return false;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
bool _iface_is_valid(struct iscsi_iface *iface)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (!iface)
|
|
Packit |
eace71 |
return false;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strlen(iface->name) == 0)
|
|
Packit |
eace71 |
return false;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (strlen(iface->transport_name) == 0)
|
|
Packit |
eace71 |
return false;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (_iface_is_bound_by_hwaddr(iface))
|
|
Packit |
eace71 |
return true;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (_iface_is_bound_by_netdev(iface))
|
|
Packit |
eace71 |
return true;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* bound by transport name */
|
|
Packit |
eace71 |
return true;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
bool iscsi_is_default_iface(struct iscsi_iface *iface)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
size_t i = 0;
|
|
Packit |
eace71 |
for (; i < sizeof(_DEFAULT_IFACES)/sizeof(struct iscsi_iface); ++i) {
|
|
Packit |
eace71 |
if (strcmp(iface->name, _DEFAULT_IFACES[i].name) == 0)
|
|
Packit |
eace71 |
return true;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return false;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
const char *iscsi_iface_dump_config(struct iscsi_iface *iface)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
FILE *f = NULL;
|
|
Packit |
eace71 |
char *buff = NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
assert(iface != NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
buff = calloc(1, IDBM_DUMP_SIZE);
|
|
Packit |
eace71 |
if (buff == NULL)
|
|
Packit |
eace71 |
return NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
f = fmemopen(buff, IDBM_DUMP_SIZE - 1, "w");
|
|
Packit |
eace71 |
if (f == NULL) {
|
|
Packit |
eace71 |
free(buff);
|
|
Packit |
eace71 |
return NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_idbm_iface_print(iface, f);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
fclose(f);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return buff;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void iscsi_iface_print_config(struct iscsi_iface *iface)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
assert(iface != NULL);
|
|
Packit |
eace71 |
_idbm_iface_print(iface, stdout);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int iscsi_iface_get(struct iscsi_context *ctx, const char *iface_name,
|
|
Packit |
eace71 |
struct iscsi_iface **iface)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int rc = LIBISCSI_OK;
|
|
Packit |
eace71 |
assert(ctx != NULL);
|
|
Packit |
eace71 |
assert(iface_name != NULL);
|
|
Packit |
eace71 |
assert(strlen(iface_name) != 0);
|
|
Packit |
eace71 |
assert(iface != NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*iface = NULL;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
size_t i = 0;
|
|
Packit |
eace71 |
for (; i < sizeof(_DEFAULT_IFACES)/sizeof(struct iscsi_iface); ++i) {
|
|
Packit |
eace71 |
if (strcmp(iface_name, _DEFAULT_IFACES[i].name) == 0) {
|
|
Packit |
eace71 |
*iface = calloc(1, sizeof(struct iscsi_iface));
|
|
Packit |
eace71 |
_alloc_null_check(ctx, *iface, rc, out);
|
|
Packit |
eace71 |
memcpy(*iface, &_DEFAULT_IFACES[i],
|
|
Packit |
eace71 |
sizeof(struct iscsi_iface));
|
|
Packit |
eace71 |
goto out;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = _idbm_lock(ctx);
|
|
Packit |
eace71 |
if (rc != LIBISCSI_OK)
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = _idbm_iface_get(ctx, iface_name, iface);
|
|
Packit |
eace71 |
if (*iface == NULL)
|
|
Packit |
eace71 |
rc = LIBISCSI_ERR_IDBM;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
_idbm_unlock(ctx);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
out:
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void iscsi_iface_free(struct iscsi_iface *iface)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
free(iface);
|
|
Packit |
eace71 |
}
|