mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-14 01:01:27 +00:00
Transport Target mode server need to able to function when running in containerized form factor in a secure and multi-tenant platform. Solution: Such applications when containerized can run in any container based platform such as Kubernetes/OpenShift or a custom one. These applications are generic in nature and all they need is access to SCST user storage device driver (/dev/scst_user). The security policy of the platform may not allow these applications to manage Fibre Channel (FC) port and /sys file-system. The platform, however, can manage the FC ports on behalf of these applications. The containerized applications can remain generic in nature and run on any containerized platforms. The sequence of operations would be 1. The platform converts the desired FC ports to target mode prior to starting the containerized application 2. The application does device registration using exported the SCST user storage device driver 3. The platform, at this point, asynchronously adds FC port LUNs to the user device registered by the application. As the application inside the container can auto or manual restart asynchronously, the platform would add the LUNs every time the application does device registration. Patch description: The SCST event mechanism is leveraged to achieve the asynchronous LUN additions when application does device registration. The current set of SCST events is extended to send a new event whenever there is a virtual user device registration happens. The platform can watch for the specific event and make business logic decisions to allow target mode applications function securely. By extending the set of event, the SCST module will be friendly to containerized applications and platforms. Signed-off-by: Vikas Goel <vikas.goel@veritas.com> git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@9210 d57e44dd-8a1f-0410-8b47-8ef2f437770f
337 lines
8.5 KiB
C
337 lines
8.5 KiB
C
/*
|
|
* events.c
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <stdint.h>
|
|
#include <getopt.h>
|
|
#include <malloc.h>
|
|
#include <inttypes.h>
|
|
#include <stdbool.h>
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
#include <sys/user.h>
|
|
#include <poll.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include "version.h"
|
|
#include "debug.h"
|
|
#include "scst_event.h"
|
|
|
|
char *app_name;
|
|
|
|
#if defined(DEBUG) || defined(TRACING)
|
|
|
|
#ifdef DEBUG
|
|
/*#define DEFAULT_LOG_FLAGS (TRACE_ALL & ~TRACE_MEMORY & ~TRACE_BUFF \
|
|
& ~TRACE_FUNCTION)
|
|
#define DEFAULT_LOG_FLAGS (TRACE_ALL & ~TRACE_MEMORY & ~TRACE_BUFF & \
|
|
~TRACE_SCSI & ~TRACE_SCSI_SERIALIZING & ~TRACE_DEBUG)
|
|
*/
|
|
#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_PID | \
|
|
TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | TRACE_MGMT_DEBUG | \
|
|
TRACE_TIME)
|
|
|
|
#define TRACE_SN(args...) TRACE(TRACE_SCSI_SERIALIZING, args)
|
|
|
|
#else /* DEBUG */
|
|
|
|
# ifdef TRACING
|
|
#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | \
|
|
TRACE_TIME | TRACE_SPECIAL)
|
|
# else
|
|
#define DEFAULT_LOG_FLAGS 0
|
|
# endif
|
|
#endif /* DEBUG */
|
|
|
|
bool log_daemon = false; /* needed for the tracing infrastructure */
|
|
unsigned long trace_flag = DEFAULT_LOG_FLAGS;
|
|
#endif /* defined(DEBUG) || defined(TRACING) */
|
|
|
|
static struct option const long_options[] = {
|
|
{"allowed_event", required_argument, 0, 'e'},
|
|
{"allowed_issuer", required_argument, 0, 'i'},
|
|
{"non_blocking", no_argument, 0, 'n'},
|
|
#if defined(DEBUG) || defined(TRACING)
|
|
{"debug", required_argument, 0, 'd'},
|
|
#endif
|
|
{"version", no_argument, 0, 'v'},
|
|
{"help", no_argument, 0, 'h'},
|
|
{0, 0, 0, 0},
|
|
};
|
|
|
|
#define MAX_ALLOWED_EVENTS 16
|
|
static struct scst_event allowed_events[MAX_ALLOWED_EVENTS];
|
|
static int allowed_events_num;
|
|
static int non_blocking;
|
|
|
|
static void usage(void)
|
|
{
|
|
printf("Usage: %s [OPTIONS]\n", app_name);
|
|
printf("\nSCST events testing program\n");
|
|
printf(" -e, --allowed_event=code Allowed event code, 0 - any event\n");
|
|
printf(" -i, --allowed_issuer=issuer Allowed issuer, * - any issuer\n");
|
|
printf(" -n, --non_blocking Use non-blocking operations\n");
|
|
#if defined(DEBUG) || defined(TRACING)
|
|
printf(" -d, --debug=level Debug tracing level\n");
|
|
#endif
|
|
}
|
|
|
|
static void handle_reg_vdev_received(struct scst_event_user *event_user)
|
|
{
|
|
struct scst_event_reg_vdev_payload *p = (struct scst_event_reg_vdev_payload *)event_user->out_event.payload;
|
|
printf("Virtual device %s registration received.\n", p->device_name);
|
|
|
|
return;
|
|
}
|
|
|
|
static void handle_tm_received(struct scst_event_user *event_user)
|
|
{
|
|
struct scst_event_tm_fn_received_payload *p = (struct scst_event_tm_fn_received_payload *)event_user->out_event.payload;
|
|
|
|
printf("fn %d, device %s\n", p->fn, p->device_name);
|
|
|
|
return;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int res = 0, i;
|
|
int ch, longindex;
|
|
int event_fd;
|
|
uint8_t event_user_buf[10240];
|
|
struct scst_event_user *event_user = (struct scst_event_user *)event_user_buf;
|
|
struct pollfd pl;
|
|
|
|
setlinebuf(stdout);
|
|
|
|
res = debug_init();
|
|
if (res != 0)
|
|
goto out;
|
|
|
|
app_name = argv[0];
|
|
|
|
while ((ch = getopt_long(argc, argv, "+e:i:d:nhv",
|
|
long_options, &longindex)) >= 0) {
|
|
switch (ch) {
|
|
case 'e':
|
|
if (allowed_events[allowed_events_num].event_code != 0) {
|
|
allowed_events_num++;
|
|
if (allowed_events_num >= MAX_ALLOWED_EVENTS) {
|
|
PRINT_ERROR("Too many allowed events %d",
|
|
allowed_events_num);
|
|
exit(1);
|
|
}
|
|
}
|
|
allowed_events[allowed_events_num].event_code = atoi(optarg);
|
|
break;
|
|
case 'i':
|
|
if (allowed_events[allowed_events_num].issuer_name[0] != '\0') {
|
|
allowed_events_num++;
|
|
if (allowed_events_num >= MAX_ALLOWED_EVENTS) {
|
|
PRINT_ERROR("Too many allowed events %d",
|
|
allowed_events_num);
|
|
exit(1);
|
|
}
|
|
}
|
|
strncpy(allowed_events[allowed_events_num].issuer_name,
|
|
optarg, sizeof(allowed_events[allowed_events_num].issuer_name));
|
|
allowed_events[allowed_events_num].issuer_name[
|
|
sizeof(allowed_events[allowed_events_num].issuer_name)-1] = '\0';
|
|
break;
|
|
case 'n':
|
|
non_blocking = 1;
|
|
break;
|
|
#if defined(DEBUG) || defined(TRACING)
|
|
case 'd':
|
|
trace_flag = strtol(optarg, (char **)NULL, 0);
|
|
break;
|
|
#endif
|
|
case 'v':
|
|
printf("%s version %s\n", app_name, VERSION_STR);
|
|
goto out_done;
|
|
default:
|
|
goto out_usage;
|
|
}
|
|
}
|
|
|
|
if (allowed_events_num == 0) {
|
|
if ((allowed_events[0].event_code == 0) &&
|
|
(allowed_events[0].issuer_name[0] == '\0'))
|
|
allowed_events[0].issuer_name[0] = '*';
|
|
}
|
|
|
|
allowed_events_num++;
|
|
|
|
#ifdef DEBUG
|
|
PRINT_INFO("trace_flag %lx", trace_flag);
|
|
#endif
|
|
|
|
if (non_blocking)
|
|
PRINT_INFO("%s", "NON-BLOCKING");
|
|
|
|
event_fd = open(SCST_EVENT_DEV, O_RDWR | (non_blocking ? O_NONBLOCK : 0));
|
|
if (event_fd < 0) {
|
|
res = -errno;
|
|
PRINT_ERROR("Unable to open SCST event device %s (%s)",
|
|
SCST_EVENT_DEV, strerror(-res));
|
|
goto out_done;
|
|
}
|
|
|
|
memset(&pl, 0, sizeof(pl));
|
|
pl.fd = event_fd;
|
|
pl.events = POLLIN;
|
|
|
|
for (i = 0; i < allowed_events_num; i++) {
|
|
struct scst_event e;
|
|
|
|
PRINT_INFO("Setting allowed event code %d, issuer_name %s",
|
|
allowed_events[i].event_code,
|
|
allowed_events[i].issuer_name);
|
|
memset(&e, 0, sizeof(e));
|
|
e.event_code = allowed_events[i].event_code;
|
|
strncpy(e.issuer_name, allowed_events[i].issuer_name,
|
|
sizeof(e.issuer_name));
|
|
e.issuer_name[sizeof(e.issuer_name)-1] = '\0';
|
|
|
|
res = ioctl(event_fd, SCST_EVENT_ALLOW_EVENT, &e);
|
|
if (res != 0) {
|
|
PRINT_ERROR("SCST_EVENT_ALLOW_EVENT failed: %s (res %d)",
|
|
strerror(errno), res);
|
|
goto out_done;
|
|
}
|
|
}
|
|
|
|
while (1) {
|
|
memset(event_user_buf, 0, sizeof(event_user_buf));
|
|
event_user->max_event_size = sizeof(event_user_buf);
|
|
res = ioctl(event_fd, SCST_EVENT_GET_NEXT_EVENT, event_user);
|
|
if (res != 0) {
|
|
res = errno;
|
|
switch (res) {
|
|
case ESRCH:
|
|
case EBUSY:
|
|
TRACE_MGMT_DBG("SCST_EVENT_GET_NEXT_EVENT returned "
|
|
"%d (%s)", res, strerror(res));
|
|
/* fall through */
|
|
case EINTR:
|
|
continue;
|
|
case EAGAIN:
|
|
TRACE_DBG("SCST_EVENT_GET_NEXT_EVENT, returned "
|
|
"EAGAIN (%d)", res);
|
|
if (non_blocking)
|
|
break;
|
|
else
|
|
continue;
|
|
default:
|
|
PRINT_ERROR("SCST_EVENT_GET_NEXT_EVENT failed: %s (res %d)",
|
|
strerror(errno), res);
|
|
goto out_done;
|
|
}
|
|
again_poll:
|
|
res = poll(&pl, 1, 2000);
|
|
if (res > 0)
|
|
continue;
|
|
else if (res == 0)
|
|
goto again_poll;
|
|
else {
|
|
res = errno;
|
|
switch (res) {
|
|
case ESRCH:
|
|
case EBUSY:
|
|
case EAGAIN:
|
|
TRACE_MGMT_DBG("poll() returned %d "
|
|
"(%s)", res, strerror(res));
|
|
case EINTR:
|
|
goto again_poll;
|
|
default:
|
|
PRINT_ERROR("poll() failed: %s", strerror(res));
|
|
#if 1
|
|
goto again_poll;
|
|
#else
|
|
goto out_close;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
PRINT_INFO("\nevent_code %d, issuer_name %s",
|
|
event_user->out_event.event_code,
|
|
event_user->out_event.issuer_name);
|
|
if (event_user->out_event.payload_len != 0)
|
|
PRINT_BUFFER("payoad", event_user->out_event.payload,
|
|
event_user->out_event.payload_len);
|
|
PRINT_INFO("%s", "");
|
|
|
|
if (event_user->out_event.event_code == 0x12345) {
|
|
struct scst_event_notify_done d;
|
|
|
|
PRINT_INFO("%s", "Press any key to send reply to event "
|
|
"0x12345");
|
|
getchar();
|
|
|
|
memset(&d, 0, sizeof(d));
|
|
d.event_id = event_user->out_event.event_id;
|
|
d.status = -19;
|
|
res = ioctl(event_fd, SCST_EVENT_NOTIFY_DONE, &d);
|
|
if (res != 0)
|
|
PRINT_ERROR("SCST_EVENT_NOTIFY_DONE failed: %s "
|
|
"(res %d)", strerror(errno), res);
|
|
} else if (event_user->out_event.event_code == SCST_EVENT_REG_VIRT_DEV) {
|
|
handle_reg_vdev_received(event_user);
|
|
} else if (event_user->out_event.event_code == SCST_EVENT_TM_FN_RECEIVED)
|
|
handle_tm_received(event_user);
|
|
else if (event_user->out_event.event_code == SCST_EVENT_TM_FN_RECEIVED) {
|
|
struct scst_event_notify_done d;
|
|
|
|
memset(&d, 0, sizeof(d));
|
|
d.event_id = event_user->out_event.event_id;
|
|
d.status = -20;
|
|
res = ioctl(event_fd, SCST_EVENT_NOTIFY_DONE, &d);
|
|
if (res != 0)
|
|
PRINT_ERROR("SCST_EVENT_NOTIFY_DONE failed: %s "
|
|
"(res %d)", strerror(errno), res);
|
|
}
|
|
|
|
#if 0
|
|
{
|
|
struct scst_event e;
|
|
|
|
PRINT_INFO("Deleting allowed event code %d, issuer_name %s",
|
|
allowed_events[0].event_code,
|
|
allowed_events[0].issuer_name);
|
|
memset(&e, 0, sizeof(e));
|
|
e.event_code = allowed_events[0].event_code;
|
|
strncpy(e.issuer_name, allowed_events[0].issuer_name,
|
|
sizeof(e.issuer_name));
|
|
e.issuer_name[sizeof(e.issuer_name)-1] = '\0';
|
|
|
|
res = ioctl(event_fd, SCST_EVENT_DISALLOW_EVENT, &e);
|
|
if (res != 0) {
|
|
PRINT_ERROR("SCST_EVENT_DISALLOW_EVENT failed: "
|
|
"%s (res %d)", strerror(errno), res);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
out_done:
|
|
debug_done();
|
|
|
|
out:
|
|
return res;
|
|
|
|
out_usage:
|
|
usage();
|
|
goto out_done;
|
|
}
|