嵌入式上 iscsi实现

前言

  去年公司设备(haisi3516)上需要提供iscsi的功能,于是花了几天时间探究了下。linux内核(2.6.xx)支持iscsi,只是我发现当时我们设备的内核编译时没有选上,于是重新编译了内核,以模块的形式加入即可。主要的驱动如下(加载的顺序很重要有依赖关系的):

iscsi整理

  下面是我收集总结的东西,希望对其他人有帮助(建议先在非嵌入式系统上做测试后...,那样简单些):

相关命令:
配置iscsi存储

[root@xifenfei ~]# iscsiadm -m discovery -t sendtargets -p 192.168.1.254:3260
[root@xifenfei ~]# iscsiadm -m node –T iqn.2006-01.com.openfiler:tsn.32b32087937b -p 192.168.1.254:3260 -l
[root@xifenfei ~]# iscsiadm -m node –T iqn.2006-01.com.openfiler:tsn.32b32087937b -p 192.168.1.254:3260
>--op update -n node.startup -v automatic

卸载iscsi存储

iscsiadm -m node --logoutall=all
iscsiadm -m node --op delete --targetname iqn.2006-01.com.openfiler:tsn.32b32087937b

增加iscsi存储

发现iscsi存储:iscsiadm -m discovery -t st -p ISCSI_IP
查看iscsi发现记录:iscsiadm -m node
登录iscsi存储:iscsiadm -m node -T LUN_NAME -p ISCSI_IP -l
开机自动: iscsiadm -m node –T LUN_NAME -p ISCSI_IP --op update -n node.startup -v automatic

删除iscsi存储

登出iscsi存储 iscsiadm -m node -T LUN_NAME -p ISCSI_IP -u
对出iscsi所有登录 iscsiadm -m node --logoutall=all
删除iscsi发现记录:iscsiadm -m node -o delete -T LUN_NAME -p ISCSI_IP

登入需验证码的节点

  1. 开启认证,*.使用-o同--op
iscsiadm -m node -T LUN_NAME -o update --name node.session.auth.authmethod --value=CHAP
  1. 添加用户
iscsiadm -m node -T LUN_NAME --op update --name node.session.auth.username --value=[用户名]

3. 添加密码

iscsiadm –m node –T LUN_NAME –op update –name node.session.auth.password –value=[密码]

参考: http://www.orasos.com/date/2012/06

查看当前会话

iscsiadm  -m session

下面是我写的一个简单的demo:



    头文件:
    #ifndef __JISCSI_H_
    #define __JISCSI_H_

    typedef struct JISCSI_S {
            char ip[32];
            short port;
            char target_name[512];
            int bchap;
            char username[512];
            char userpass[64];
            char discname[512];
            char discpass[64];
    }JISCSI_T;

    int jiscsi_init(char *name, int timeout);
    int jiscsi_uninit(void);
    int jiscsi_attach_target(JISCSI_T *stpJiscsi, int timeout);
    int jiscsi_detach_target(JISCSI_T *stpJiscsi, int timeout);

    #endif /*__JISCSI_H_*/


    c文件:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>

    #include <errno.h>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <pthread.h>

    #include "jiscsi.h"

    #define ISCSI_LOGIN "iscsiadm -m node -T %s -p %s:%d -l 2>&1"
    #define ISCSI_LOGOUT "iscsiadm -m node -T %s -p %s:%d -u 2>&1"
    #define ISCSI_EN_CHAP "iscsiadm -m node -T %s --op update --name node.session.auth.authmethod --value=CHAP 2>&1"
    #define ISCSI_ADD_USER "iscsiadm -m node -T %s --op update --name node.session.auth.username --value=%s 2>&1"
    #define ISCSI_ADD_PASS "iscsiadm -m node -T %s --op update --name node.session.auth.password --value=%s 2>&1"
    #define ISCSI_DISCOVERY_EX "iscsiadm -m discovery -t st -p %s:%d 2>&1 | cut -d ' ' -f 2"
    #define ISCSI_DISCOVERY "iscsiadm -m discovery -t st -p %s:%d 2>&1"
    #define ISCSI_SESSION_STATUS "iscsiadm -m session"

    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

    typedef struct {
            char *cmd;
            char *buf;
    }ARG_T;

    enum JISCSI_RET {
            SYSERR = -4,
            TIMEOUT,
            ARGV_INVALID,
            FAILED,
            SUCCESSED,
    };

    static void *do_work(void *arg)
    {
            ARG_T *stpArg = arg;
            char *buf = stpArg->buf;
            char *cmd = stpArg->cmd;

            pthread_detach(pthread_self());

    /* pthread_mutex_lock(&mutex);*/

            FILE *fp = popen(cmd, "r");
            if (NULL == fp) {
                    perror("popen");
                    return NULL;
            }
            
            fread(buf, 1, 1024, fp);
            pclose(fp);

            pthread_mutex_lock(&mutex);
            pthread_cond_signal(&cond);
            pthread_mutex_unlock(&mutex);

            pthread_exit(NULL);
    }

    static int exec_cmd(char *cmd, char *findstr, int time)
    {
            if (NULL == cmd || NULL == findstr)
                    return ARGV_INVALID;

            char buf[1024];
            ARG_T stArg = {.buf = buf, .cmd = cmd};

            pthread_t tid;
            pthread_mutex_lock(&mutex);
            if (pthread_create(&tid, NULL, do_work, &stArg) < 0) {
                    perror("pthread_create");
                    return SYSERR;
            }

            struct timeval now;
            struct timespec timeout;

            gettimeofday(&now, NULL);
            timeout.tv_sec = now.tv_sec+time;
            timeout.tv_nsec= now.tv_usec;

            int ret = pthread_cond_timedwait(&cond, &mutex, &timeout);
            if(ret == ETIMEDOUT) {
                    pthread_mutex_unlock(&mutex);
                    printf("timeout!!!\n");
                    return TIMEOUT;
            }

            pthread_mutex_unlock(&mutex);

            if (NULL == strstr(buf, findstr))
                    return FAILED;

            memset(buf, 0, 1024); //?

            return SUCCESSED;
    }

    static int jsystem(char *cmd)
    {
            int ret = -1;
            int status = system(cmd);
            if (-1 == status) {
                    ret = -1;
                    printf("error!!maybe fork failed...\n");
            } else if (WIFEXITED(status)) {
                    ret = WEXITSTATUS(status);
                    printf("normal termination, exit status = %d\n", ret);
            } else if (WIFSIGNALED(status)) {
                    ret = WEXITSTATUS(status);
                    printf("abnormal termination,signal number =%d\n", WTERMSIG(status));
            } else if (WIFSTOPPED(status)) {
                    ret = WEXITSTATUS(status);
                    printf("process stopped, signal number =%d\n", WSTOPSIG(status));
            }
            return ret;
    }

    #define J_EXEC_CMD(cmd) do {int ret; if ((ret = jsystem(cmd)) != 0) return ret;}while(0)
    /*void process_cfg_file()*/
    /*{*/
    /* J_EXEC_CMD("iscsiadm -m node -L all 2>&1"); */
    /*}*/

    static int jiscsi_set_own_name(char *name)
    {
            char cmd[1024];

            sprintf(cmd, "sed -i 's/\(InitiatorName=\).*/\1%s/g' /etc/iscsi/initiatorname.iscsi", name);
            return jsystem(cmd);
    }

    int jiscsi_init(char *name, int timeout)
    {
            system("insmod crc32c.ko; insmod scsi_mod.ko; insmod scsi_transport_iscsi.ko; \
                    insmod libiscsi.ko; insmod libiscsi_tcp.ko; insmod iscsi_tcp.ko; insmod sd_mod.ko ");
            system("mkdir /etc/iscsi 2>&1");
            system("mkdir -p /var/lock/iscsi 2>&1");
            system("cp iscsid.conf initiatorname.iscsi /etc/iscsi/ 2>&1");
            system("ln -s `pwd`/iscsid /sbin/iscsid ");
            system("ln -s `pwd`/iscsiadm /sbin/iscsiadm ");

            if (NULL != name)
                    jiscsi_set_own_name(name);

            system("iscsid &");

            return exec_cmd("ps | grep iscsid | grep -v grep", "iscsid", timeout);

    /* int ret = exec_cmd("ps | grep iscsid | grep -v iscsid", "iscsid");*/
    /* //read configuration file, and execute it */
    /* process_cfg_file();*/
    /* return ret;*/
    }

    int jiscsi_uninit(void)
    {
           J_EXEC_CMD("iscsiadm -m node -U all 2>&1");
           return SUCCESSED;
    }

    static int get_target_names(char *ip, short port, char name_buf[], int buf_size)
    {
            char cmd[1024];
            sprintf(cmd, ISCSI_DISCOVERY_EX, ip, port);
            
            FILE *fp = popen(cmd, "r");
            if (NULL == fp) {
                    perror("popen");
                    return FAILED;
            }

            fread(name_buf, 1, buf_size>2048?2048:buf_size, fp);

    /* printf("buf:%s\n", name_buf);*/
            pclose(fp);
            return SUCCESSED;
    }

    static int check_target_is_valid(char *buf_names, char *target_name)
    {
            return strstr(buf_names, target_name) == NULL ? SUCCESSED:FAILED;
    }

    int jiscsi_attach_target(JISCSI_T *stpJiscsi, int timeout)
    {
            if (NULL == stpJiscsi)
                    return ARGV_INVALID;

            char cmd[1024];
            char buf_names[2048];

            if (get_target_names(stpJiscsi->ip, stpJiscsi->port, buf_names, 2048) < 0)
                    return FAILED;

            if (!check_target_is_valid(buf_names, stpJiscsi->target_name))
                    return FAILED;

            if (stpJiscsi->bchap) {
                    sprintf(cmd, ISCSI_EN_CHAP, stpJiscsi->target_name);
                    J_EXEC_CMD(cmd);
                    sprintf(cmd, ISCSI_ADD_USER, stpJiscsi->target_name, stpJiscsi->username);
                    J_EXEC_CMD(cmd);
                    sprintf(cmd, ISCSI_ADD_PASS, stpJiscsi->target_name, stpJiscsi->userpass);
                    J_EXEC_CMD(cmd);
            }
            sprintf(cmd, ISCSI_LOGIN, stpJiscsi->target_name, stpJiscsi->ip, stpJiscsi->port);
    /* printf("cmd:%s\n", cmd);*/
            return exec_cmd(cmd, "success", timeout);
    }

    int jiscsi_detach_target(JISCSI_T *stpJiscsi, int timeout)
    {
            if (NULL == stpJiscsi)
                    return ARGV_INVALID;

            char cmd[1024];
            sprintf(cmd, ISCSI_LOGOUT, stpJiscsi->target_name, stpJiscsi->ip, stpJiscsi->port);
            return exec_cmd(cmd, "success", timeout);
    }

    //for test
    void help(void)
    {
            printf( "-d: means discovery mode, depend -a [-p]\n" \
                    "-l: means login mode, depend -a [-p] [-T] -t\n" \
                    "-u: means logout mode, depend -a [-p] [-T] -t\n" \
                    "-i: means init iscsi\n" \
                    "-I: means uninit iscsi\n" \
                    "-a: means set ipaddr, need ip argument\n" \
                    "-p: means set port, need port argument, default is 3260\n" \
                    "-t: means set target name, need target name argument\n" \
                    "-T: means set timeout time(s), need timeout argument, default is 2s\n"\
                    "-c: means use chap, need username*password argument, eg -c jxj*123456\n"\
                    "-s: means display current iscsi status\n");

            printf( "eg: init iscsi ./jiscsi -i\n"\
                    "eg: disp status ./jiscsi -s\n"\
                    "eg: discovery ./jiscsi -d -a xxx.xxx.xxx.xxx it will take back target_name\n"\
                    "target_name like: iqn.skysan.cn.com.bwstor:1343989129\n"\
                    "eg: login ./jiscsi -l -a xxx.xxx.xxx.xxx -t target_name\n"\
                    "eg: login ./jiscsi -u -a xxx.xxx.xxx.xxx -t target_name\n");

    }

    int main(int argc, char *argv[])
    {
            int c;
            int ret = -1;
            int mode = 0, timeout = 2;
            JISCSI_T stJiscsi = {.port = 3260};

            //handle input
    /* opterr = 0;*/
            while(-1 != (c = getopt(argc, argv, ":dlup:a:t:T:hsc:iI"))) {
                    switch(c) {
                    case 'd':
                            mode = 1;
                            break;
                    case 'l':
                            mode = 2;
                            break;
                    case 'u':
                            mode = 3;
                            break;
                    case 'a':
                            printf("ipaddr:%s\n", optarg);
                            strcpy(stJiscsi.ip, optarg);
                            break;
                    case 'c':
                            printf("username*password:%s\n", optarg);
                            if (sscanf(optarg, "%[^\*]*%s", stJiscsi.username, stJiscsi.userpass) != 2) {
                                    printf("argument is invalid!!!\n");
                                    printf("-c: means use chap, need username*password argument, eg -c jxj*123456\n");
                                    return -1;
                            }
    /* printf("username%s password:%s\n", stJiscsi.username, stJiscsi.userpass);*/
                            stJiscsi.bchap = 1;
                            break;
                    case 'p':
                            printf("port:%s\n", optarg);
                            stJiscsi.port = atoi(optarg);
                            break;
                    case 't':
                            printf("target name:%s\n", optarg);
                            strcpy(stJiscsi.target_name, optarg);
                            break;
                    case 'T':
                            printf("time:%s\n", optarg);
                            timeout = atoi(optarg);
                            break;
                    case 's':
                            mode = 4;
                            break;
                    case 'i':
                            ret = jiscsi_init(NULL, 2);
                            printf("jiscsi_init ret: %d\n", ret);
                            return 0;
                    case 'I':
                            ret = jiscsi_uninit();
                            printf("jiscsi_uninit ret: %d\n", ret);
                            return 0;
                    case 'h':
                            help();
                            return 0;
                    case '?':
                            printf("invalid option \'%c\'\n", optopt);
                            return -1;
                    case ':':
                            printf(": option \'%c\' need argument\n", optopt);
                            return -1;
                    default:
                            printf("default invalid option \'%c\' ret:%d\n", optopt, c);
                            return -1;
                    }
            }

            //execute
            char cmd[1024];
            switch(mode) {
                    case 1:
                            sprintf(cmd, ISCSI_DISCOVERY, stJiscsi.ip, stJiscsi.port);
                            J_EXEC_CMD(cmd);
                            break;
                    case 2:
                            ret = jiscsi_attach_target(&stJiscsi, timeout);
                            printf("jiscsi_attach_target ret:%d\n", ret);
                            break;
                    case 3:
                            ret = jiscsi_detach_target(&stJiscsi, timeout);
                            printf("jiscsi_detach_target ret:%d\n", ret);
                            break;
                    case 4:
                            J_EXEC_CMD(ISCSI_SESSION_STATUS);
                            break;
                    default:
                            printf("argument is invalid\n");
                            help();
                            return -1;
            }

            return 0;
    /* JISCSI_T stJiscsi1 = {.ip = "192.168.1.251", .port = 3260, */
    /* .target_name = "iqn.2012-11.com.example:storage.sdb1", .bchap = 1, */
    /* .username = "rongp", .userpass = "123456abcdef"}; */
    /**/
    /* JISCSI_T stJiscsi2 = {.ip = "192.168.1.251", .port = 3260, */
    /* .target_name = "iqn.2012-11.com.example:storage.sdb2", .bchap = 0, */
    /* .username = "", .userpass = ""}; */
    /**/
    /* JISCSI_T stJiscsi3 = {.ip = "192.168.1.251", .port = 3260, */
    /* .target_name = "iqn.2012-11.com.example:storage.sdb3", .bchap = 0, */
    /* .username = "", .userpass = ""}; */
    /*#if 0*/
    /* int ret = jiscsi_attach_target(&stJiscsi1, 1);*/
    /* printf("ret :%d\n", ret);*/
    /* ret = jiscsi_attach_target(&stJiscsi2, 1);*/
    /* printf("ret :%d\n", ret);*/
    /* ret = jiscsi_attach_target(&stJiscsi3, 1);*/
    /* printf("ret :%d\n", ret);*/
    /*#else */
    /* jiscsi_detach_target(&stJiscsi1, 1);*/
    /* jiscsi_detach_target(&stJiscsi2, 1);*/
    /* jiscsi_detach_target(&stJiscsi3, 1);*/
    /*#endif*/
    }

完!
2013年8月

posted @ 2017-10-14 10:13  rongpmcu  阅读(409)  评论(0编辑  收藏  举报