diff --git a/src/policy.c b/src/policy.c index 7c27b5a..eb48a8e 100644 --- a/src/policy.c +++ b/src/policy.c @@ -139,6 +139,8 @@ dump_rules(void) printf("default\n"); else if (rule->cmd == ALLOW) printf("allow\n"); + else if (rule->cmd == RUNNING) + printf("running\n"); else if (rule->cmd == DENY) printf("deny\n"); printf(" pos %d\n", rule->pos); @@ -255,8 +257,26 @@ vm_matches_rule(rule_t *rule, vm_t *vm) return true; } +static bool +rule_vm_running(rule_t *rule) +{ + vm_t *vm; + + /* If no VM UUID, then we never match */ + if (rule->vm_uuid == NULL) + return false; + + /* Lookup the VM */ + vm = vm_lookup_by_uuid(rule->vm_uuid); + if (vm == NULL) + return false; + + /* Is the vm running */ + return vm->domid > 0; +} + static rule_t* -rule_lookup(device_t *device, enum command cmd) +_rule_lookup(device_t *device, enum command cmd, bool check_vm_running) { struct list_head *pos; rule_t *rule; @@ -265,13 +285,32 @@ rule_lookup(device_t *device, enum command cmd) rule = list_entry(pos, rule_t, list); if (rule->cmd == cmd && device_matches_rule(rule, device)) { - return rule; + if (check_vm_running) { + if (rule_vm_running(rule)) { + return rule; + } + /* continue */ + } else { + return rule; + } } } return NULL; } +static rule_t * +rule_lookup(device_t *device, enum command cmd) +{ + return _rule_lookup(device, cmd, false); +} + +static rule_t * +rule_lookup_running(device_t *device, enum command cmd) +{ + return _rule_lookup(device, cmd, true); +} + static rule_t* sticky_lookup(device_t *device) { @@ -284,6 +323,12 @@ default_lookup(device_t *device) return rule_lookup(device, DEFAULT); } +static rule_t* +running_lookup(device_t *device) +{ + return rule_lookup_running(device, RUNNING); +} + void policy_add_rule(rule_t *new_rule) { @@ -550,6 +595,8 @@ policy_auto_assign_new_device(device_t *device) rule = sticky_lookup(device); if (rule == NULL) rule = default_lookup(device); + if (rule == NULL) + rule = running_lookup(device); if (rule != NULL) { vm = vm_lookup_by_uuid(rule->vm_uuid); } else { @@ -603,7 +650,7 @@ policy_auto_assign_devices_to_new_vm(vm_t *vm) * assign all devices that match the rule to the VM */ list_for_each_safe(pos, tmp, &rules.list) { rule = list_entry(pos, rule_t, list); - if ((rule->cmd == ALWAYS || rule->cmd == DEFAULT) && + if ((rule->cmd == ALWAYS || rule->cmd == DEFAULT || rule->cmd == RUNNING) && rule->vm_uuid != NULL && /* NULL vm_uuid means dom0, means no assignment */ !strcmp(rule->vm_uuid, vm->uuid)) { list_for_each(device_pos, &devices.list) { @@ -671,6 +718,7 @@ policy_parse_command_string(const char* cmd) if (strcasecmp(cmd, "always") == 0) return ALWAYS; if (strcasecmp(cmd, "default") == 0) return DEFAULT; if (strcasecmp(cmd, "deny") == 0) return DENY; + if (strcasecmp(cmd, "running") == 0) return RUNNING; return UNKNOWN; } @@ -690,6 +738,9 @@ policy_parse_command_enum(enum command cmd) case DEFAULT: strcpy(command, "default"); break; + case RUNNING: + strcpy(command, "running"); + break; default: strcpy(command, "deny"); break; diff --git a/src/policy.h b/src/policy.h index 64a4a62..c1ca35c 100644 --- a/src/policy.h +++ b/src/policy.h @@ -37,6 +37,7 @@ enum command { ALWAYS, /**< Always plug device to VM. implies ALLOW */ DEFAULT, /**< Plug device to VM by default, implies ALLOW */ ALLOW, /**< Allow device to be plugged to VM */ + RUNNING, /**< Plug device into running VM */ DENY, /**< Deny device to be plugged to VM */ UNKNOWN /**< Unknown command, usually due to input parsing */ }; diff --git a/src/project.h b/src/project.h index d2d32a6..6866035 100644 --- a/src/project.h +++ b/src/project.h @@ -124,6 +124,7 @@ typedef struct { struct list_head list; /**< Linux-kernel-style list item */ int domid; /**< VM domid */ char *uuid; /**< VM UUID */ + bool emulate; /**< Use stubdom for emulated passthrough */ } vm_t; /** diff --git a/src/vm.c b/src/vm.c index 4687a70..e3d006d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -110,6 +110,10 @@ vm_add(const int domid, const char *uuid) struct list_head *pos; vm_t *vm; char *new_uuid; + char path[64]; + char *pvaddons_version = NULL; + gboolean pvaddons = true; + gboolean force_emulate = false; /* The UUID may have "_"s instead of "-"s, like in the xenmgr dbus reply. Fix this while duplicating the UUID. */ @@ -134,10 +138,35 @@ vm_add(const int domid, const char *uuid) } } - xd_log(LOG_DEBUG, "Adding vm, domid=%d, uuid=%s", domid, new_uuid); + snprintf(path, sizeof(path), "/vm/%s", new_uuid); + for (char *p = path; *p; p++) { + if (*p == '-') { + *p = '_'; + } + } + + if (!property_get_com_citrix_xenclient_xenmgr_vm_pv_addons_(g_xcbus, XENMGR, path, &pvaddons)) { + xd_log(LOG_ERR, "Error retrieving pvaddon status: %s %d", new_uuid, domid); + } + + if (!property_get_com_citrix_xenclient_xenmgr_vm_pv_addons_version_(g_xcbus, XENMGR, path, &pvaddons_version)) { + xd_log(LOG_ERR, "Error retrieving pvaddon version: %s %d", new_uuid, domid); + pvaddons_version = NULL; + } + + if (pvaddons_version && strcmp(pvaddons_version, "force-emulate") == 0) { + xd_log(LOG_INFO, "Forcing emulation: %s %d", new_uuid, domid); + force_emulate = true; + } + + free(pvaddons_version); + + xd_log(LOG_DEBUG, "Adding vm, domid=%d, uuid=%s pvaddons=%d force_emulate=%d", + domid, new_uuid, pvaddons, force_emulate); vm = malloc(sizeof(vm_t)); vm->domid = domid; vm->uuid = new_uuid; + vm->emulate = force_emulate || !pvaddons; list_add(&vm->list, &vms.list); return vm; diff --git a/src/xenstore.c b/src/xenstore.c index 65c365a..943e81a 100644 --- a/src/xenstore.c +++ b/src/xenstore.c @@ -151,7 +151,24 @@ xenstore_dom_read(unsigned int domid, const char *format, ...) int xenstore_get_dominfo(int domid, dominfo_t *di) { + char *stubdomid; + int stubid = 0; + vm_t *vm; + di->di_domid = domid; + + vm = vm_lookup(domid); + if (vm && vm->emulate) { + stubdomid = xenstore_dom_read(domid, "image/device-model-domid"); + if (stubdomid) { + stubid = strtol(stubdomid, NULL, 0); + free(stubdomid); + } + if (stubid > 0 && stubid < DOMID_FIRST_RESERVED) { + di->di_domid = stubid; + } + } + di->di_dompath = xs_get_domain_path(xs_handle, di->di_domid); if (!di->di_dompath) { xd_log(LOG_ERR, "Could not get domain %d path from xenstore", domid);