|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* iSCSI transport
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Copyright (C) 2006 Mike Christie
|
|
Packit |
eace71 |
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
|
|
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
|
|
Packit |
eace71 |
* by the Free Software Foundation; either version 2 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, but
|
|
Packit |
eace71 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
eace71 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
eace71 |
* General Public License for more details.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
#include <stdlib.h>
|
|
Packit |
eace71 |
#include <string.h>
|
|
Packit |
eace71 |
#include <stdio.h>
|
|
Packit |
eace71 |
#include <unistd.h>
|
|
Packit |
eace71 |
#include <errno.h>
|
|
Packit |
eace71 |
#include <libkmod.h>
|
|
Packit |
eace71 |
#include <net/if.h>
|
|
Packit |
eace71 |
#include <sys/ioctl.h>
|
|
Packit |
eace71 |
#include <sys/socket.h>
|
|
Packit |
eace71 |
#include <sys/types.h>
|
|
Packit |
eace71 |
#include <sys/wait.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "sysdeps.h"
|
|
Packit |
eace71 |
#include "iscsi_err.h"
|
|
Packit |
eace71 |
#include "initiator.h"
|
|
Packit |
eace71 |
#include "transport.h"
|
|
Packit |
eace71 |
#include "log.h"
|
|
Packit |
eace71 |
#include "iscsi_util.h"
|
|
Packit |
eace71 |
#include "iscsi_sysfs.h"
|
|
Packit |
eace71 |
#include "uip_mgmt_ipc.h"
|
|
Packit |
eace71 |
#include "cxgbi.h"
|
|
Packit |
eace71 |
#include "be2iscsi.h"
|
|
Packit |
eace71 |
#include "iser.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_transport_template iscsi_tcp = {
|
|
Packit |
eace71 |
.name = "tcp",
|
|
Packit |
eace71 |
.ep_connect = iscsi_io_tcp_connect,
|
|
Packit |
eace71 |
.ep_poll = iscsi_io_tcp_poll,
|
|
Packit |
eace71 |
.ep_disconnect = iscsi_io_tcp_disconnect,
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_transport_template iscsi_iser = {
|
|
Packit |
eace71 |
.name = "iser",
|
|
Packit |
eace71 |
.rdma = 1,
|
|
Packit |
eace71 |
.ep_connect = ktransport_ep_connect,
|
|
Packit |
eace71 |
.ep_poll = ktransport_ep_poll,
|
|
Packit |
eace71 |
.ep_disconnect = ktransport_ep_disconnect,
|
|
Packit |
eace71 |
.create_conn = iser_create_conn,
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_transport_template cxgb3i = {
|
|
Packit |
eace71 |
.name = "cxgb3i",
|
|
Packit |
eace71 |
.set_host_ip = SET_HOST_IP_OPT,
|
|
Packit |
eace71 |
.bind_ep_required = 1,
|
|
Packit |
eace71 |
.ep_connect = ktransport_ep_connect,
|
|
Packit |
eace71 |
.ep_poll = ktransport_ep_poll,
|
|
Packit |
eace71 |
.ep_disconnect = ktransport_ep_disconnect,
|
|
Packit |
eace71 |
.create_conn = cxgbi_create_conn,
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_transport_template cxgb4i = {
|
|
Packit |
eace71 |
.name = "cxgb4i",
|
|
Packit |
eace71 |
.set_host_ip = SET_HOST_IP_NOT_REQ,
|
|
Packit |
eace71 |
.bind_ep_required = 1,
|
|
Packit |
eace71 |
.ep_connect = ktransport_ep_connect,
|
|
Packit |
eace71 |
.ep_poll = ktransport_ep_poll,
|
|
Packit |
eace71 |
.ep_disconnect = ktransport_ep_disconnect,
|
|
Packit |
eace71 |
.create_conn = cxgbi_create_conn,
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_transport_template bnx2i = {
|
|
Packit |
eace71 |
.name = "bnx2i",
|
|
Packit |
eace71 |
.set_host_ip = SET_HOST_IP_REQ,
|
|
Packit |
eace71 |
.use_boot_info = 1,
|
|
Packit |
eace71 |
.bind_ep_required = 1,
|
|
Packit |
eace71 |
.ep_connect = ktransport_ep_connect,
|
|
Packit |
eace71 |
.ep_poll = ktransport_ep_poll,
|
|
Packit |
eace71 |
.ep_disconnect = ktransport_ep_disconnect,
|
|
Packit |
eace71 |
.set_net_config = uip_broadcast_params,
|
|
Packit |
eace71 |
.exec_ping = uip_broadcast_ping_req,
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_transport_template be2iscsi = {
|
|
Packit |
eace71 |
.name = "be2iscsi",
|
|
Packit |
eace71 |
.bind_ep_required = 1,
|
|
Packit |
eace71 |
.sync_vlan_settings = 1,
|
|
Packit |
eace71 |
.create_conn = be2iscsi_create_conn,
|
|
Packit |
eace71 |
.ep_connect = ktransport_ep_connect,
|
|
Packit |
eace71 |
.ep_poll = ktransport_ep_poll,
|
|
Packit |
eace71 |
.ep_disconnect = ktransport_ep_disconnect,
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_transport_template qla4xxx = {
|
|
Packit |
eace71 |
.name = "qla4xxx",
|
|
Packit |
eace71 |
.set_host_ip = SET_HOST_IP_NOT_REQ,
|
|
Packit |
eace71 |
.bind_ep_required = 1,
|
|
Packit |
eace71 |
.ep_connect = ktransport_ep_connect,
|
|
Packit |
eace71 |
.ep_poll = ktransport_ep_poll,
|
|
Packit |
eace71 |
.ep_disconnect = ktransport_ep_disconnect,
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_transport_template ocs = {
|
|
Packit |
eace71 |
.name = "ocs",
|
|
Packit |
eace71 |
.bind_ep_required = 1,
|
|
Packit |
eace71 |
.ep_connect = ktransport_ep_connect,
|
|
Packit |
eace71 |
.ep_poll = ktransport_ep_poll,
|
|
Packit |
eace71 |
.ep_disconnect = ktransport_ep_disconnect,
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsi_transport_template qedi = {
|
|
Packit |
eace71 |
.name = "qedi",
|
|
Packit |
eace71 |
.set_host_ip = SET_HOST_IP_REQ,
|
|
Packit |
eace71 |
.use_boot_info = 1,
|
|
Packit |
eace71 |
.bind_ep_required = 1,
|
|
Packit |
eace71 |
.no_netdev = 1,
|
|
Packit |
eace71 |
.ep_connect = ktransport_ep_connect,
|
|
Packit |
eace71 |
.ep_poll = ktransport_ep_poll,
|
|
Packit |
eace71 |
.ep_disconnect = ktransport_ep_disconnect,
|
|
Packit |
eace71 |
.set_net_config = uip_broadcast_params,
|
|
Packit |
eace71 |
.exec_ping = uip_broadcast_ping_req,
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static struct iscsi_transport_template *iscsi_transport_templates[] = {
|
|
Packit |
eace71 |
&iscsi_tcp,
|
|
Packit |
eace71 |
&iscsi_iser,
|
|
Packit |
eace71 |
&cxgb3i,
|
|
Packit |
eace71 |
&cxgb4i,
|
|
Packit |
eace71 |
&bnx2i,
|
|
Packit |
eace71 |
&qla4xxx,
|
|
Packit |
eace71 |
&be2iscsi,
|
|
Packit |
eace71 |
&ocs,
|
|
Packit |
eace71 |
&qedi,
|
|
Packit |
eace71 |
NULL
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int transport_probe_for_offload(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct if_nameindex *ifni;
|
|
Packit |
eace71 |
char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN];
|
|
Packit |
eace71 |
int i, sockfd;
|
|
Packit |
eace71 |
struct ifreq if_hwaddr;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ifni = if_nameindex();
|
|
Packit |
eace71 |
if (!ifni) {
|
|
Packit |
eace71 |
log_error("Could not search for transport modules: %s",
|
|
Packit |
eace71 |
strerror(errno));
|
|
Packit |
eace71 |
return ISCSI_ERR_TRANS_NOT_FOUND;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
Packit |
eace71 |
if (sockfd < 0) {
|
|
Packit |
eace71 |
log_error("Could not open socket for ioctl: %s",
|
|
Packit |
eace71 |
strerror(errno));
|
|
Packit |
eace71 |
goto free_ifni;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; ifni[i].if_index && ifni[i].if_name; i++) {
|
|
Packit |
eace71 |
struct if_nameindex *n = &ifni[i];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_debug(6, "kmod probe found %s", n->if_name);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
strlcpy(if_hwaddr.ifr_name, n->if_name, IFNAMSIZ);
|
|
Packit |
eace71 |
if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* check for ARPHRD_ETHER (ethernet) */
|
|
Packit |
eace71 |
if (if_hwaddr.ifr_hwaddr.sa_family != 1)
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (net_get_transport_name_from_netdev(n->if_name,
|
|
Packit |
eace71 |
transport_name))
|
|
Packit |
eace71 |
continue;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
transport_load_kmod(transport_name);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
close(sockfd);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
free_ifni:
|
|
Packit |
eace71 |
if_freenameindex(ifni);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Most distros still do not have wide libkmod use, so
|
|
Packit |
eace71 |
* use modprobe for now
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int transport_load_kmod(char *transport_name)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct kmod_ctx *ctx;
|
|
Packit |
eace71 |
struct kmod_module *mod;
|
|
Packit |
eace71 |
int rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
ctx = kmod_new(NULL, NULL);
|
|
Packit |
eace71 |
if (!ctx) {
|
|
Packit |
eace71 |
log_error("Could not load transport module %s. Out of "
|
|
Packit |
eace71 |
"memory.", transport_name);
|
|
Packit |
eace71 |
return ISCSI_ERR_NOMEM;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
kmod_load_resources(ctx);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* dumb dumb dumb - named iscsi_tcp and ib_iser differently from
|
|
Packit |
eace71 |
* transport name
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (!strcmp(transport_name, "tcp"))
|
|
Packit |
eace71 |
rc = kmod_module_new_from_name(ctx, "iscsi_tcp", &mod);
|
|
Packit |
eace71 |
else if (!strcmp(transport_name, "iser"))
|
|
Packit |
eace71 |
rc = kmod_module_new_from_name(ctx, "ib_iser", &mod);
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
rc = kmod_module_new_from_name(ctx, transport_name, &mod);
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
log_error("Failed to load module %s.", transport_name);
|
|
Packit |
eace71 |
rc = ISCSI_ERR_TRANS_NOT_FOUND;
|
|
Packit |
eace71 |
goto unref_mod;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rc = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST,
|
|
Packit |
eace71 |
NULL, NULL, NULL, NULL);
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
log_error("Could not insert module %s. Kmod error %d",
|
|
Packit |
eace71 |
transport_name, rc);
|
|
Packit |
eace71 |
rc = ISCSI_ERR_TRANS_NOT_FOUND;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
kmod_module_unref(mod);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
unref_mod:
|
|
Packit |
eace71 |
kmod_unref(ctx);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int set_transport_template(struct iscsi_transport *t)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsi_transport_template *tmpl;
|
|
Packit |
eace71 |
int j;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (j = 0; iscsi_transport_templates[j] != NULL; j++) {
|
|
Packit |
eace71 |
tmpl = iscsi_transport_templates[j];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!strcmp(tmpl->name, t->name)) {
|
|
Packit |
eace71 |
t->template = tmpl;
|
|
Packit |
eace71 |
log_debug(3, "Matched transport %s", t->name);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_error("Could not find template for %s. An updated iscsiadm "
|
|
Packit |
eace71 |
"is probably needed.", t->name);
|
|
Packit |
eace71 |
return ENOSYS;
|
|
Packit |
eace71 |
}
|