Skip to content

Commit

Permalink
iscsi tools: Add support to display a host's CHAP list and delete
Browse files Browse the repository at this point in the history
Drivers like qla4xxx store the CHAP info in a table that is
managed at the host level. This patch allows you to see
and delete the CHAP entries on the host.

Patch from: Nilesh Javali <nilesh.javali@qlogic.com>

[lots of bug fixes by Mike Christie]
Signed-off-by: Nilesh Javali <nilesh.javali@qlogic.com>
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
  • Loading branch information
Mike Christie committed Mar 6, 2012
1 parent d0cfc05 commit d94720a
Show file tree
Hide file tree
Showing 10 changed files with 333 additions and 4 deletions.
2 changes: 2 additions & 0 deletions include/iscsi_err.h
Expand Up @@ -60,6 +60,8 @@ enum {
ISCSI_ERR_ISNS_REG_FAILED = 26,
/* operation not supported */
ISCSI_ERR_OP_NOT_SUPP = 27,
/* device or resource in use */
ISCSI_ERR_BUSY = 28,

/* Always last. Indicates end of error code space */
ISCSI_MAX_ERR_VAL,
Expand Down
32 changes: 31 additions & 1 deletion include/iscsi_if.h
Expand Up @@ -66,8 +66,10 @@ enum iscsi_uevent_e {
ISCSI_UEVENT_PATH_UPDATE = UEVENT_BASE + 20,
ISCSI_UEVENT_SET_IFACE_PARAMS = UEVENT_BASE + 21,
ISCSI_UEVENT_PING = UEVENT_BASE + 22,
ISCSI_UEVENT_GET_CHAP = UEVENT_BASE + 23,
ISCSI_UEVENT_DELETE_CHAP = UEVENT_BASE + 24,

ISCSI_UEVENT_MAX = ISCSI_UEVENT_PING,
ISCSI_UEVENT_MAX = ISCSI_UEVENT_DELETE_CHAP,

/* up events */
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
Expand Down Expand Up @@ -205,6 +207,18 @@ struct iscsi_uevent {
uint32_t pid; /* unique ping id associated
with each ping request */
} iscsi_ping;
struct msg_get_chap {
uint32_t host_no;
uint32_t num_entries; /* number of CHAP entries
* on request, number of
* valid CHAP entries on
* response */
uint16_t chap_tbl_idx;
} get_chap;
struct msg_delete_chap {
uint32_t host_no;
uint16_t chap_tbl_idx;
} delete_chap;
} u;
union {
/* messages k -> u */
Expand Down Expand Up @@ -583,4 +597,20 @@ struct iscsi_stats {
__attribute__ ((aligned (sizeof(uint64_t))));
};

enum chap_type_e {
CHAP_TYPE_OUT,
CHAP_TYPE_IN,
};

#define ISCSI_CHAP_AUTH_NAME_MAX_LEN 256
#define ISCSI_CHAP_AUTH_SECRET_MAX_LEN 256

struct iscsi_chap_rec {
uint16_t chap_tbl_idx;
enum chap_type_e chap_type;
char username[ISCSI_CHAP_AUTH_NAME_MAX_LEN];
uint8_t password[ISCSI_CHAP_AUTH_SECRET_MAX_LEN];
uint8_t password_length;
};

#endif
3 changes: 3 additions & 0 deletions usr/host.h
Expand Up @@ -5,6 +5,9 @@
#include "types.h"
#include "config.h"

#define MAX_CHAP_BUF_SZ 4096
#define REQ_CHAP_BUF_SZ (MAX_CHAP_BUF_SZ + sizeof(struct iscsi_uevent))

struct host_info {
struct iface_rec iface;
uint32_t host_no;
Expand Down
34 changes: 34 additions & 0 deletions usr/idbm.c
Expand Up @@ -445,6 +445,30 @@ void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
__recinfo_uint16(IFACE_PORT, ri, r, port, IDBM_SHOW, num, 1);
}

static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
{
int num = 0;

__recinfo_uint16(HOST_AUTH_INDEX, ri, r, chap_tbl_idx, IDBM_SHOW,
num, 1);

if (r->chap_type == CHAP_TYPE_OUT) {
__recinfo_str(HOST_AUTH_USERNAME, ri, r, username, IDBM_SHOW,
num, 0);
__recinfo_str(HOST_AUTH_PASSWORD, ri, r, password, IDBM_MASKED,
num, 1);
__recinfo_int(HOST_AUTH_PASSWORD_LEN, ri, r, password_length,
IDBM_HIDE, num, 1);
} else {
__recinfo_str(HOST_AUTH_USERNAME_IN, ri, r, username, IDBM_SHOW,
num, 0);
__recinfo_str(HOST_AUTH_PASSWORD_IN, ri, r, password,
IDBM_MASKED, num, 1);
__recinfo_int(HOST_AUTH_PASSWORD_IN_LEN, ri, r, password_length,
IDBM_HIDE, num, 1);
}
}

recinfo_t *idbm_recinfo_alloc(int max_keys)
{
recinfo_t *info;
Expand Down Expand Up @@ -475,6 +499,9 @@ void idbm_print(int type, void *rec, int show, FILE *f)
case IDBM_PRINT_TYPE_IFACE:
idbm_recinfo_iface((struct iface_rec *)rec, info);
break;
case IDBM_PRINT_TYPE_HOST_CHAP:
idbm_recinfo_host_chap((struct iscsi_chap_rec *)rec, info);
break;
}

fprintf(f, "%s\n", ISCSI_BEGIN_REC);
Expand Down Expand Up @@ -845,6 +872,13 @@ int idbm_print_iface_info(void *data, struct iface_rec *iface)
return 0;
}

int idbm_print_host_chap_info(struct iscsi_chap_rec *chap)
{
/* User only calls this to print chap so always print */
idbm_print(IDBM_PRINT_TYPE_HOST_CHAP, chap, 1, stdout);
return 0;
}

int idbm_print_node_flat(void *data, node_rec_t *rec)
{
if (strchr(rec->conn[0].address, '.'))
Expand Down
3 changes: 3 additions & 0 deletions usr/idbm.h
Expand Up @@ -162,6 +162,7 @@ enum {
IDBM_PRINT_TYPE_DISCOVERY,
IDBM_PRINT_TYPE_NODE,
IDBM_PRINT_TYPE_IFACE,
IDBM_PRINT_TYPE_HOST_CHAP,
};

extern void idbm_print(int type, void *rec, int show, FILE *f);
Expand All @@ -174,4 +175,6 @@ extern struct node_rec *idbm_create_rec(char *targetname, int tpgt,
extern struct node_rec *
idbm_create_rec_from_boot_context(struct boot_context *context);

extern int idbm_print_host_chap_info(struct iscsi_chap_rec *chap);

#endif /* IDBM_H */
10 changes: 10 additions & 0 deletions usr/idbm_fields.h
Expand Up @@ -116,4 +116,14 @@
#define DISC_ISNS_ADDR "discovery.sendtargets.address"
#define DISC_ISNS_PORT "discovery.sendtargets.port"

/* host auth fields */
#define HOST_AUTH_INDEX "host.auth.tbl_idx"
#define HOST_AUTH_METHOD "host.auth.authmethod"
#define HOST_AUTH_USERNAME "host.auth.username"
#define HOST_AUTH_PASSWORD "host.auth.password"
#define HOST_AUTH_PASSWORD_LEN "host.auth.password_length"
#define HOST_AUTH_USERNAME_IN "host.auth.username_in"
#define HOST_AUTH_PASSWORD_IN "host.auth.password_in"
#define HOST_AUTH_PASSWORD_IN_LEN "host.auth.password_in_length"

#endif
1 change: 1 addition & 0 deletions usr/iscsi_err.c
Expand Up @@ -50,6 +50,7 @@ static char *iscsi_err_msgs[] = {
/* 25 */ "iSNS query failed",
/* 26 */ "iSNS registration failed",
/* 27 */ "operation not supported",
/* 28 */ "device or resource in use",
};

char *iscsi_err_to_str(int err)
Expand Down
7 changes: 7 additions & 0 deletions usr/iscsi_ipc.h
Expand Up @@ -138,6 +138,13 @@ struct iscsi_ipc {
int (*exec_ping) (uint64_t transport_handle, uint32_t host_no,
struct sockaddr *addr, uint32_t iface_num,
uint32_t iface_type, uint32_t size);

int (*get_chap) (uint64_t transport_handle, uint32_t host_no,
uint16_t chap_tbl_idx, uint32_t num_entries,
char *chap_buf, uint32_t *valid_chap_entries);

int (*delete_chap) (uint64_t transport_handle, uint32_t host_no,
uint16_t chap_tbl_idx);
};

#endif /* ISCSI_IPC_H */
165 changes: 162 additions & 3 deletions usr/iscsiadm.c
Expand Up @@ -67,6 +67,7 @@ enum iscsiadm_mode {
MODE_IFACE,
MODE_FW,
MODE_PING,
MODE_CHAP
};

enum iscsiadm_op {
Expand Down Expand Up @@ -191,6 +192,8 @@ str_to_submode(char *str)

if (!strcmp("ping", str))
sub_mode = MODE_PING;
else if (!strcmp("chap", str))
sub_mode = MODE_CHAP;
else
sub_mode = -1;

Expand Down Expand Up @@ -1297,6 +1300,146 @@ static int iface_apply_net_config(struct iface_rec *iface, int op)
return ISCSI_SUCCESS;
}

static int get_host_chap_info(uint32_t host_no)
{
struct iscsi_transport *t = NULL;
struct iscsi_chap_rec *crec = NULL;
char *req_buf = NULL;
uint32_t valid_chap_entries;
uint32_t num_entries;
uint16_t chap_tbl_idx = 0;
int rc = 0;
int fd, i = 0;

t = iscsi_sysfs_get_transport_by_hba(host_no);
if (!t) {
log_error("Could not match hostno %d to "
"transport.", host_no);
rc = ISCSI_ERR_TRANS_NOT_FOUND;
goto exit_chap_info;
}

num_entries = MAX_CHAP_BUF_SZ / sizeof(*crec);

req_buf = calloc(1, REQ_CHAP_BUF_SZ);
if (!req_buf) {
log_error("Could not allocate memory for CHAP request.");
rc = ISCSI_ERR_NOMEM;
goto exit_chap_info;
}

fd = ipc->ctldev_open();
if (fd < 0) {
rc = ISCSI_ERR_INTERNAL;
log_error("Netlink open failed.");
goto exit_chap_info;
}

get_chap:
memset(req_buf, 0, REQ_CHAP_BUF_SZ);

rc = ipc->get_chap(t->handle, host_no, chap_tbl_idx, num_entries,
req_buf, &valid_chap_entries);
if (rc < 0) {
log_error("get_chap_info failed. errno=%d", errno);
rc = ISCSI_ERR;
goto exit_chap_info;
}

log_info("Valid CHAP Entries = %d\n", valid_chap_entries);

crec = (struct iscsi_chap_rec *) (req_buf +
sizeof(struct iscsi_uevent));

if (valid_chap_entries)
chap_tbl_idx =
(crec + (valid_chap_entries - 1))->chap_tbl_idx + 1;

/* print chap info */
for (i = 0; i < valid_chap_entries; i++) {
idbm_print_host_chap_info(crec);
crec++;
}

if (valid_chap_entries != num_entries)
goto exit_chap_info;
else
goto get_chap;

ipc->ctldev_close();

exit_chap_info:
if (req_buf)
free(req_buf);

return rc;
}

static int delete_host_chap_info(uint32_t host_no, char *value)
{
struct iscsi_transport *t = NULL;
int fd, rc = 0;
uint16_t chap_tbl_idx;

if (!value) {
log_error("CHAP deletion requires --value=table_index.");
return ISCSI_ERR_INVAL;
}

chap_tbl_idx = (uint16_t)atoi(value);

t = iscsi_sysfs_get_transport_by_hba(host_no);
if (!t) {
log_error("Could not match hostno %d to "
"transport.", host_no);
rc = ISCSI_ERR_TRANS_NOT_FOUND;
goto exit_delete_chap;
}

fd = ipc->ctldev_open();
if (fd < 0) {
log_error("Netlink open failed.");
rc = ISCSI_ERR_INTERNAL;
goto exit_delete_chap;
}

log_info("Deleteing CHAP index: %d\n", chap_tbl_idx);
rc = ipc->delete_chap(t->handle, host_no, chap_tbl_idx);
if (rc < 0) {
log_error("CHAP Delete failed.");
if (rc == -EBUSY) {
rc = ISCSI_ERR_BUSY;
log_error("CHAP index %d is in use.", chap_tbl_idx);
} else
rc = ISCSI_ERR;
}

ipc->ctldev_close();

exit_delete_chap:
return rc;
}

static int exec_host_chap_op(int op, int info_level, uint32_t host_no,
char *value)
{
int rc = ISCSI_ERR_INVAL;

switch (op) {
case OP_SHOW:
rc = get_host_chap_info(host_no);
break;
case OP_DELETE:
rc = delete_host_chap_info(host_no, value);
break;
default:
log_error("Invalid operation.");
break;
}

return rc;
}

/* TODO: merge iter helpers and clean them up, so we can use them here */
static int exec_iface_op(int op, int do_show, int info_level,
struct iface_rec *iface, uint32_t host_no,
Expand Down Expand Up @@ -2393,14 +2536,30 @@ main(int argc, char **argv)

switch (mode) {
case MODE_HOST:
if ((rc = verify_mode_params(argc, argv, "HdmP", 0))) {
if ((rc = verify_mode_params(argc, argv, "CHdmPov", 0))) {
log_error("host mode: option '-%c' is not "
"allowed/supported", rc);
rc = ISCSI_ERR_INVAL;
goto out;
}

rc = host_info_print(info_level, host_no);
if (sub_mode != -1) {
switch (sub_mode) {
case MODE_CHAP:
if (!op || !host_no) {
log_error("CHAP mode requires host "
"no and valid operation");
rc = ISCSI_ERR_INVAL;
break;
}
rc = exec_host_chap_op(op, info_level, host_no,
value);
break;
default:
log_error("Invalid Sub Mode");
break;
}
} else
rc = host_info_print(info_level, host_no);
break;
case MODE_IFACE:
iface_setup_host_bindings();
Expand Down

0 comments on commit d94720a

Please sign in to comment.