Files
xen/tools/libs/util/libxlu_disk_l.l
T
Oleksandr Tyshchenko 66dd1c62b2 libxl: Add support for Virtio disk configuration
This patch adds basic support for configuring and assisting virtio-mmio
based virtio-disk backend (emulator) which is intended to run out of
Qemu and could be run in any domain.
Although the Virtio block device is quite different from traditional
Xen PV block device (vbd) from the toolstack's point of view:
 - as the frontend is virtio-blk which is not a Xenbus driver, nothing
   written to Xenstore are fetched by the frontend currently ("vdev"
   is not passed to the frontend). But this might need to be revised
   in future, so frontend data might be written to Xenstore in order to
   support hotplugging virtio devices or passing the backend domain id
   on arch where the device-tree is not available.
 - the ring-ref/event-channel are not used for the backend<->frontend
   communication, the proposed IPC for Virtio is IOREQ/DM
it is still a "block device" and ought to be integrated in existing
"disk" handling. So, re-use (and adapt) "disk" parsing/configuration
logic to deal with Virtio devices as well.

For the immediate purpose and an ability to extend that support for
other use-cases in future (Qemu, virtio-pci, etc) perform the following
actions:
- Add new disk backend type (LIBXL_DISK_BACKEND_STANDALONE) and reflect
  that in the configuration
- Introduce new disk "specification" and "transport" fields to struct
  libxl_device_disk. Both are written to the Xenstore. The transport
  field is only used for the specification "virtio" and it assumes
  only "mmio" value for now.
- Introduce new "specification" option with "xen" communication
  protocol being default value.
- Add new device kind (LIBXL__DEVICE_KIND_VIRTIO_DISK) as current
  one (LIBXL__DEVICE_KIND_VBD) doesn't fit into Virtio disk model

An example of domain configuration for Virtio disk:
disk = [ 'phy:/dev/mmcblk0p3, xvda1, backendtype=standalone, specification=virtio']

Nothing has changed for default Xen disk configuration.

Please note, this patch is not enough for virtio-disk to work
on Xen (Arm), as for every Virtio device (including disk) we need
to allocate Virtio MMIO params (IRQ and memory region) and pass
them to the backend, also update Guest device-tree. The subsequent
patch will add these missing bits. For the current patch,
the default "irq" and "base" are just written to the Xenstore.
This is not an ideal splitting, but this way we avoid breaking
the bisectability.

Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>
Acked-by: George Dunlap <george.dunlap@citrix.com>
Tested-by: Jiamei Xie <jiamei.xie@arm.com>
2022-07-28 19:25:43 +01:00

302 lines
11 KiB
Plaintext

/* -*- fundamental -*- */
/*
* libxlu_disk_l.l - parser for disk specification strings
*
* Copyright (C) 2011 Citrix Ltd.
* Author Ian Jackson <ian.jackson@eu.citrix.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
/*
* Parsing the old xm/xend/xl-4.1 disk specs is a tricky problem,
* because the target string might in theory contain "," which is the
* delimiter we use for stripping off things on the RHS, and ":",
* which is the delimiter we use for stripping off things on the LHS.
*
* In this parser we do not support such target strings in the old
* syntax; if the target string has to contain "," or ":" the new
* syntax's "target=" should be used.
*/
%top{
#define _GNU_SOURCE
}
%{
#include "libxlu_disk_i.h"
#define YY_NO_INPUT
/* The code generated by flex is missing braces in single line expressions and
* is not properly indented, which triggers the clang misleading-indentation
* check that has been made part of -Wall since clang 10. In order to safely
* disable it on clang versions that don't have the diagnostic implemented
* also disable the unknown option and pragma warning. */
#ifdef __clang__
# pragma clang diagnostic ignored "-Wunknown-pragmas"
# pragma clang diagnostic ignored "-Wunknown-warning-option"
# pragma clang diagnostic ignored "-Wmisleading-indentation"
#endif
/* Some versions of flex have a bug (Fedora bugzilla 612465) which causes
* it to fail to declare these functions, which it defines. So declare
* them ourselves. Hopefully we won't have to simultaneously support
* a flex version which declares these differently somehow. */
int xlu__disk_yyget_column(yyscan_t yyscanner);
void xlu__disk_yyset_column(int column_no, yyscan_t yyscanner);
/*----- useful macros and functions used in actions -----
* we use macros in the actual rules to keep the actions short
* and particularly to avoid repeating boilerplate values such as
* DPC->disk, yytext, etc. */
/* Sets an enum, checking it hasn't already been set to a different value */
#define DSET(dpc,member,enumname,str,valname) do{ \
if (dpc->disk->member != LIBXL_DISK_##enumname##_UNKNOWN && \
dpc->disk->member != LIBXL_DISK_##enumname##_##valname) { \
xlu__disk_err(dpc, str, TOSTRING(member) " respecified"); \
} else { \
dpc->disk->member = LIBXL_DISK_##enumname##_##valname; \
} \
}while(0)
/* For actions whose patterns contain '=', finds the start of the value */
#define FROMEQUALS (strchr(yytext,'=')+1)
/* Chops the delimiter off, modifying yytext and yyleng. */
#define STRIP(delim) do{ \
if (yyleng>0 && yytext[yyleng-1]==(delim)) \
yytext[--yyleng] = 0; \
}while(0)
/* Sets a string value, checking it hasn't been set already. */
#define SAVESTRING(what,loc,val) do{ \
savestring(DPC, what " respecified", &DPC->disk->loc, (val)); \
}while(0)
static void savestring(DiskParseContext *dpc, const char *what_respecified,
char **update, const char *value) {
if (*update) {
if (**update) { xlu__disk_err(dpc,value,what_respecified); return; }
free(*update); /* do not complain about overwriting empty strings */
}
*update = strdup(value);
}
#define DPC dpc /* our convention in lexer helper functions */
/* Sets ->readwrite from the string. This ought to be an enum, perhaps. */
static void setaccess(DiskParseContext *dpc, const char *str) {
if (!strcmp(str, "r") || !strcmp(str, "ro")) {
dpc->disk->readwrite = 0;
} else if (!strcmp(str, "rw") || !strcmp(str, "w") || !strcmp(str,"")) {
dpc->disk->readwrite = 1;
} else {
xlu__disk_err(dpc,str,"unknown value for access");
}
}
/* Sets ->format from the string. IDL should provide something for this. */
static void setformat(DiskParseContext *dpc, const char *str) {
if (!strcmp(str,"")) DSET(dpc,format,FORMAT,str,RAW);
else if (!strcmp(str,"raw")) DSET(dpc,format,FORMAT,str,RAW);
else if (!strcmp(str,"qcow")) DSET(dpc,format,FORMAT,str,QCOW);
else if (!strcmp(str,"qcow2")) DSET(dpc,format,FORMAT,str,QCOW2);
else if (!strcmp(str,"vhd")) DSET(dpc,format,FORMAT,str,VHD);
else if (!strcmp(str,"empty")) DSET(dpc,format,FORMAT,str,EMPTY);
else if (!strcmp(str,"qed")) DSET(dpc,format,FORMAT,str,QED);
else xlu__disk_err(dpc,str,"unknown value for format");
}
/* Sets ->backend from the string. IDL should provide something for this. */
static void setbackendtype(DiskParseContext *dpc, const char *str) {
if ( !strcmp(str,"phy")) DSET(dpc,backend,BACKEND,str,PHY);
else if (!strcmp(str,"tap")) DSET(dpc,backend,BACKEND,str,TAP);
else if (!strcmp(str,"qdisk")) DSET(dpc,backend,BACKEND,str,QDISK);
else if (!strcmp(str,"standalone")) DSET(dpc,backend,BACKEND,str,STANDALONE);
else xlu__disk_err(dpc,str,"unknown value for backendtype");
}
/* Sets ->specification from the string. IDL should provide something for this. */
static void setspecification(DiskParseContext *dpc, const char *str) {
if (!strcmp(str,"xen")) DSET(dpc,specification,SPECIFICATION,str,XEN);
else if (!strcmp(str,"virtio")) DSET(dpc,specification,SPECIFICATION,str,VIRTIO);
else xlu__disk_err(dpc,str,"unknown value for specification");
}
/* Sets ->colo-port from the string. COLO need this. */
static void setcoloport(DiskParseContext *dpc, const char *str) {
int port = atoi(str);
if (port) {
dpc->disk->colo_port = port;
} else {
xlu__disk_err(dpc,str,"unknown value for colo_port");
}
}
#define DEPRECATE(usewhatinstead) /* not currently reported */
/* Handles a vdev positional parameter which includes a devtype. */
static int vdev_and_devtype(DiskParseContext *dpc, char *str) {
/* returns 1 if it was <vdev>:<devtype>, 0 (doing nothing) otherwise */
char *colon = strrchr(str, ':');
if (!colon)
return 0;
DEPRECATE("use `devtype=...'");
*colon++ = 0;
SAVESTRING("vdev", vdev, str);
if (!strcmp(colon,"cdrom")) {
DPC->disk->is_cdrom = 1;
} else if (!strcmp(colon,"disk")) {
DPC->disk->is_cdrom = 0;
} else {
xlu__disk_err(DPC,colon,"unknown deprecated type");
}
return 1;
}
#undef DPC /* needs to be defined differently the actual lexer */
#define DPC ((DiskParseContext*)yyextra)
%}
%option warn
%option nodefault
%option batch
%option 8bit
%option noyywrap
%option reentrant
%option prefix="xlu__disk_yy"
%option nounput
%x LEXERR
%%
/*----- the scanner rules which do the parsing -----*/
[ \t\n]+/([^ \t\n].*)? { /* ignore whitespace before parameters */ }
/* ordinary parameters setting enums or strings */
format=[^,]*,? { STRIP(','); setformat(DPC, FROMEQUALS); }
cdrom,? { DPC->disk->is_cdrom = 1; }
devtype=cdrom,? { DPC->disk->is_cdrom = 1; }
devtype=disk,? { DPC->disk->is_cdrom = 0; }
devtype=[^,]*,? { xlu__disk_err(DPC,yytext,"unknown value for type"); }
access=[^,]*,? { STRIP(','); setaccess(DPC, FROMEQUALS); }
backend=[^,]*,? { STRIP(','); SAVESTRING("backend", backend_domname, FROMEQUALS); }
backendtype=[^,]*,? { STRIP(','); setbackendtype(DPC,FROMEQUALS); }
specification=[^,]*,? { STRIP(','); setspecification(DPC,FROMEQUALS); }
vdev=[^,]*,? { STRIP(','); SAVESTRING("vdev", vdev, FROMEQUALS); }
script=[^,]*,? { STRIP(','); SAVESTRING("script", script, FROMEQUALS); }
direct-io-safe,? { DPC->disk->direct_io_safe = 1; }
discard,? { libxl_defbool_set(&DPC->disk->discard_enable, true); }
no-discard,? { libxl_defbool_set(&DPC->disk->discard_enable, false); }
/* Note that the COLO configuration settings should be considered unstable.
* They may change incompatibly in future versions of Xen. */
colo,? { libxl_defbool_set(&DPC->disk->colo_enable, true); }
no-colo,? { libxl_defbool_set(&DPC->disk->colo_enable, false); }
colo-host=[^,]*,? { STRIP(','); SAVESTRING("colo-host", colo_host, FROMEQUALS); }
colo-port=[^,]*,? { STRIP(','); setcoloport(DPC, FROMEQUALS); }
colo-export=[^,]*,? { STRIP(','); SAVESTRING("colo-export", colo_export, FROMEQUALS); }
active-disk=[^,]*,? { STRIP(','); SAVESTRING("active-disk", active_disk, FROMEQUALS); }
hidden-disk=[^,]*,? { STRIP(','); SAVESTRING("hidden-disk", hidden_disk, FROMEQUALS); }
trusted,? { libxl_defbool_set(&DPC->disk->trusted, true); }
untrusted,? { libxl_defbool_set(&DPC->disk->trusted, false); }
/* the target magic parameter, eats the rest of the string */
target=.* { STRIP(','); SAVESTRING("target", pdev_path, FROMEQUALS); }
/* unknown parameters */
[a-z][-a-z0-9]*=[^,],? { xlu__disk_err(DPC,yytext,"unknown parameter"); }
/* deprecated prefixes */
/* the "/.*" in these patterns ensures that they count as if they
* matched the whole string, so these patterns take precedence */
(raw|qcow2?|vhd):/.* {
STRIP(':');
DPC->had_depr_prefix=1; DEPRECATE("use `[format=]...,'");
setformat(DPC, yytext);
}
(iscsi|e?nbd|drbd):/.* {
char *newscript;
STRIP(':');
DPC->had_depr_prefix=1; DEPRECATE("use `script=...'");
if (asprintf(&newscript, "block-%s", yytext) < 0) {
xlu__disk_err(DPC,yytext,"unable to format script");
return 0;
}
savestring(DPC, "script respecified",
&DPC->disk->script, newscript);
free(newscript);
}
tapdisk:/.* { DPC->had_depr_prefix=1; DEPRECATE(0); }
tap2?:/.* { DPC->had_depr_prefix=1; DEPRECATE(0); }
aio:/.* { DPC->had_depr_prefix=1; DEPRECATE(0); }
ioemu:/.* { DPC->had_depr_prefix=1; DEPRECATE(0); }
file:/.* { DPC->had_depr_prefix=1; DEPRECATE(0); }
phy:/.* { DPC->had_depr_prefix=1; DEPRECATE(0); }
[a-z][a-z0-9]*:/([^a-z0-9].*)? {
xlu__disk_err(DPC,yytext,"unknown deprecated disk prefix");
return 0;
}
/* positional parameters */
[^=,]*,|[^=,]+,? {
STRIP(',');
if (DPC->err) {
/* previous errors may just lead to subsequent ones */
} else if (!DPC->disk->pdev_path) {
SAVESTRING("target", pdev_path, yytext);
} else if (!DPC->had_depr_prefix &&
DPC->disk->format == LIBXL_DISK_FORMAT_UNKNOWN) {
if (!*DPC->disk->pdev_path && vdev_and_devtype(DPC,yytext)) {
DPC->disk->format = LIBXL_DISK_FORMAT_EMPTY;
} else {
setformat(DPC,yytext);
}
} else if (!DPC->disk->vdev) {
if (!vdev_and_devtype(DPC,yytext))
SAVESTRING("vdev", vdev, yytext);
} else if (!DPC->access_set) {
DPC->access_set = 1;
setaccess(DPC,yytext);
} else {
xlu__disk_err(DPC,yytext,"too many positional parameters");
return 0; /* don't print any more errors */
}
}
. {
BEGIN(LEXERR);
yymore();
}
<LEXERR>.* {
xlu__disk_err(DPC,yytext,"bad disk syntax"); return 0;
}