Blame usr/transport.c

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
}