summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Rosenfeld <hans.rosenfeld@joyent.com>2018-03-12 17:41:06 +0100
committerHans Rosenfeld <hans.rosenfeld@joyent.com>2018-03-21 23:31:31 +0100
commitec03b232c131f2289fedb6a63a9990898bbe16c2 (patch)
tree72c55b06bd9b804cf1f26ac958f6553a45b5a9e8
parentf3195f72a46cb863b80329145921191a60882155 (diff)
downloadillumos-joyent-ec03b232c131f2289fedb6a63a9990898bbe16c2.tar.gz
OS-6765 support PCI passthru in bhyve zones
Reviewed by: Mike Gerdts <mike.gerdts@joyent.com> Reviewed by: John Levon <john.levon@joyent.com> Approved by: Patrick Mooney <patrick.mooney@joyent.com>
-rw-r--r--usr/src/cmd/zoneadmd/zoneadmd.c4
-rw-r--r--usr/src/lib/brand/bhyve/zone/boot.c158
2 files changed, 122 insertions, 40 deletions
diff --git a/usr/src/cmd/zoneadmd/zoneadmd.c b/usr/src/cmd/zoneadmd/zoneadmd.c
index 196ccaf263..608af8170e 100644
--- a/usr/src/cmd/zoneadmd/zoneadmd.c
+++ b/usr/src/cmd/zoneadmd/zoneadmd.c
@@ -901,8 +901,8 @@ setup_subproc_env(boolean_t debug)
* program. At such a time as brand callbacks can be executed as part
* of the zoneadmd process, this should be removed.
*
- * The bhyve brand only supports disk-like devices and does not support
- * regular expressions.
+ * The bhyve brand only supports disk-like and ppt devices and does not
+ * support regular expressions.
*/
if ((res = zonecfg_setdevent(snap_hndl)) != Z_OK)
goto done;
diff --git a/usr/src/lib/brand/bhyve/zone/boot.c b/usr/src/lib/brand/bhyve/zone/boot.c
index 51a363b8da..e76c9d65d4 100644
--- a/usr/src/lib/brand/bhyve/zone/boot.c
+++ b/usr/src/lib/brand/bhyve/zone/boot.c
@@ -128,63 +128,145 @@ add_ram(int *argc, char **argv)
}
int
-add_disks(int *argc, char **argv)
+add_disk(char *disk, char *path, char *slotconf, size_t slotconf_len)
{
- char *disks;
- char *disk;
+ static char *boot = NULL;
+ static int next_cd = 0;
+ static int next_other = 0;
+ int pcislot;
+ int pcifn;
+
+ /* Allow at most one "primary" disk */
+ if (is_env_true("device", disk, "boot")) {
+ if (boot != NULL) {
+ (void) printf("Error: multiple boot disks: %s %s\n",
+ boot, path);
+ return (-1);
+ }
+ boot = path;
+ pcislot = PCI_SLOT_BOOT_DISK;
+ pcifn = 0;
+ } else if (is_env_true("device", disk, "cdrom")) {
+ pcislot = PCI_SLOT_CD;
+ pcifn = next_cd;
+ next_cd++;
+ } else {
+ pcislot = PCI_SLOT_OTHER_DISKS;
+ pcifn = next_other;
+ next_other++;
+ }
+
+ if (snprintf(slotconf, slotconf_len, "%d:%d,virtio-blk,%s",
+ pcislot, pcifn, path) >= slotconf_len) {
+ (void) printf("Error: disk path '%s' too long\n", path);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+add_ppt(int *argc, char **argv, char *ppt, char *path, char *slotconf,
+ size_t slotconf_len)
+{
+ static boolean_t wired = B_FALSE;
+ static boolean_t acpi = B_FALSE;
+ unsigned int bus = 0, dev = 0, func = 0;
+ char *pcislot;
+
+ pcislot = get_zcfg_var("device", ppt, "pci_slot");
+
+ if (pcislot == NULL) {
+ (void) printf("Error: device %s has no PCI slot\n", ppt);
+ return (-1);
+ }
+
+ switch (sscanf(pcislot, "%u:%u:%u", &bus, &dev, &func)) {
+ case 3:
+ break;
+ case 2:
+ case 1:
+ func = dev;
+ dev = bus;
+ bus = 0;
+ break;
+ default:
+ (void) printf("Error: device %s has illegal PCI slot: %s\n",
+ dev, pcislot);
+ return (-1);
+ }
+
+ if (bus > 255 || dev > 31 || func > 7) {
+ (void) printf("Error: device %s has illegal PCI slot: %s\n",
+ dev, pcislot);
+ return (-1);
+ }
+
+ if (bus > 0) {
+ if (!acpi)
+ add_arg(argc, argv, "-A");
+ acpi = B_TRUE;
+ }
+
+ if (!wired)
+ add_arg(argc, argv, "-S");
+ wired = B_TRUE;
+
+ if (snprintf(slotconf, slotconf_len, "%d:%d:%d,passthru,%s",
+ bus, dev, func, path) >= slotconf_len) {
+ (void) printf("Error: device path '%s' too long\n", path);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+add_devices(int *argc, char **argv)
+{
+ char *devices;
+ char *dev;
char *lasts;
- int next_cd = 0;
- int next_other = 0;
char slotconf[MAXNAMELEN];
- char *boot = NULL;
- if ((disks = get_zcfg_var("device", "resources", NULL)) == NULL) {
+ if ((devices = get_zcfg_var("device", "resources", NULL)) == NULL) {
return (0);
}
- for (disk = strtok_r(disks, " ", &lasts); disk != NULL;
- disk = strtok_r(NULL, " ", &lasts)) {
- int pcislot;
- int pcifn;
+ for (dev = strtok_r(devices, " ", &lasts); dev != NULL;
+ dev = strtok_r(NULL, " ", &lasts)) {
+ int ret;
char *path;
+ char *model;
/* zoneadmd is not careful about a trailing delimiter. */
- if (disk[0] == '\0') {
+ if (dev[0] == '\0') {
continue;
}
- if ((path = get_zcfg_var("device", disk, "path")) == NULL) {
- (void) printf("Error: disk %s has no path\n", disk);
+ if ((path = get_zcfg_var("device", dev, "path")) == NULL) {
+ (void) printf("Error: device %s has no path\n", dev);
return (-1);
}
- /* Allow at most one "primary" disk */
- if (is_env_true("device", disk, "boot")) {
- if (boot != NULL) {
- (void) printf("Error: "
- "multiple boot disks: %s %s\n",
- boot, path);
- return (-1);
- }
- boot = path;
- pcislot = PCI_SLOT_BOOT_DISK;
- pcifn = 0;
- } else if (is_env_true("device", disk, "cdrom")) {
- pcislot = PCI_SLOT_CD;
- pcifn = next_cd;
- next_cd++;
+ if ((model = get_zcfg_var("device", dev, "model")) == NULL) {
+ (void) printf("Error: device %s has no model\n", dev);
+ return (-1);
+ }
+
+ if (strcmp(model, "virtio") == 0) {
+ ret = add_disk(dev, path, slotconf, sizeof (slotconf));
+ } else if (strcmp(model, "passthru") == 0) {
+ ret = add_ppt(argc, argv, dev, path, slotconf,
+ sizeof (slotconf));
} else {
- pcislot = PCI_SLOT_OTHER_DISKS;
- pcifn = next_other;
- next_other++;
+ (void) printf("Error: device %s has invalid model: "
+ "%s\n", dev, model);
+ ret = -1;
}
- if (snprintf(slotconf, sizeof (slotconf),
- "%d:%d,virtio-blk,%s", pcislot, pcifn, path) >=
- sizeof (slotconf)) {
- (void) printf("Error: disk path '%s' too long\n", path);
+ if (ret != 0)
return (-1);
- }
if (add_arg(argc, argv, "-s") != 0 ||
add_arg(argc, argv, slotconf) != 0) {
@@ -445,7 +527,7 @@ main(int argc, char **argv)
if (add_lpc(&zhargc, (char **)&zhargv) != 0 ||
add_cpu(&zhargc, (char **)&zhargv) != 0 ||
add_ram(&zhargc, (char **)&zhargv) != 0 ||
- add_disks(&zhargc, (char **)&zhargv) != 0 ||
+ add_devices(&zhargc, (char **)&zhargv) != 0 ||
add_nets(&zhargc, (char **)&zhargv) != 0 ||
add_bhyve_opts(&zhargc, (char **)&zhargv) != 0 ||
add_vmname(&zhargc, (char **)&zhargv) != 0) {