1*65bbee46Sjsg /* $OpenBSD: vm_agentx.c,v 1.3 2024/09/26 01:45:13 jsg Exp $ */ 2f94ca20eSmartijn 3f94ca20eSmartijn /* 4f94ca20eSmartijn * Copyright (c) 2022 Martijn van Duren <martijn@openbsd.org> 5f94ca20eSmartijn * 6f94ca20eSmartijn * Permission to use, copy, modify, and distribute this software for any 7f94ca20eSmartijn * purpose with or without fee is hereby granted, provided that the above 8f94ca20eSmartijn * copyright notice and this permission notice appear in all copies. 9f94ca20eSmartijn * 10f94ca20eSmartijn * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11f94ca20eSmartijn * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12f94ca20eSmartijn * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13f94ca20eSmartijn * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14f94ca20eSmartijn * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15f94ca20eSmartijn * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16f94ca20eSmartijn * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17f94ca20eSmartijn */ 18f94ca20eSmartijn 19f94ca20eSmartijn #include <sys/types.h> 20f94ca20eSmartijn #include <sys/sysctl.h> 21f94ca20eSmartijn #include <sys/un.h> 22f94ca20eSmartijn 23f94ca20eSmartijn #include <agentx.h> 24f94ca20eSmartijn #include <grp.h> 25f94ca20eSmartijn #include <pwd.h> 26f94ca20eSmartijn #include <stdlib.h> 27f94ca20eSmartijn #include <string.h> 28f94ca20eSmartijn #include <unistd.h> 29f94ca20eSmartijn 30f94ca20eSmartijn #include "proc.h" 31f94ca20eSmartijn #include "vmd.h" 32f94ca20eSmartijn 33f94ca20eSmartijn struct conn { 34f94ca20eSmartijn struct event ev; 35f94ca20eSmartijn struct agentx *agentx; 36f94ca20eSmartijn }; 37f94ca20eSmartijn 38f94ca20eSmartijn void vm_agentx_run(struct privsep *, struct privsep_proc *, void *); 39f94ca20eSmartijn int vm_agentx_dispatch_parent(int, struct privsep_proc *, struct imsg *); 40f94ca20eSmartijn void vm_agentx_configure(struct vmd_agentx *); 41f94ca20eSmartijn static void vm_agentx_nofd(struct agentx *, void *, int); 42f94ca20eSmartijn static void vm_agentx_tryconnect(int, short, void *); 43f94ca20eSmartijn static void vm_agentx_read(int, short, void *); 44f94ca20eSmartijn static void vm_agentx_flush_pending(void); 45f94ca20eSmartijn static int vm_agentx_sortvir(const void *, const void *); 46f94ca20eSmartijn static int vm_agentx_adminstate(int); 47f94ca20eSmartijn static int vm_agentx_operstate(int); 48f94ca20eSmartijn static void vm_agentx_vmHvSoftware(struct agentx_varbind *); 49f94ca20eSmartijn static void vm_agentx_vmHvVersion(struct agentx_varbind *); 50f94ca20eSmartijn static void vm_agentx_vmHvObjectID(struct agentx_varbind *); 51f94ca20eSmartijn static void vm_agentx_vminfo(struct agentx_varbind *); 52f94ca20eSmartijn 53f94ca20eSmartijn static struct agentx_index *vmIndex; 54f94ca20eSmartijn static struct agentx_object *vmNumber, *vmName, *vmUUID, *vmOSType; 55f94ca20eSmartijn static struct agentx_object *vmAdminState, *vmOperState, *vmAutoStart; 56f94ca20eSmartijn static struct agentx_object *vmPersistent, *vmCurCpuNumber, *vmMinCpuNumber; 57f94ca20eSmartijn static struct agentx_object *vmMaxCpuNumber, *vmMemUnit, *vmCurMem, *vmMinMem; 58f94ca20eSmartijn static struct agentx_object *vmMaxMem; 59f94ca20eSmartijn 60f94ca20eSmartijn static struct vmd_agentx *vmd_agentx; 61f94ca20eSmartijn 62f94ca20eSmartijn static struct agentx_varbind **vminfo = NULL; 63f94ca20eSmartijn static size_t vminfolen = 0; 64f94ca20eSmartijn static size_t vminfosize = 0; 65f94ca20eSmartijn static int vmcollecting = 0; 66f94ca20eSmartijn 67f94ca20eSmartijn #define VMMIB AGENTX_MIB2, 236 68f94ca20eSmartijn #define VMOBJECTS VMMIB, 1 69f94ca20eSmartijn #define VMHVSOFTWARE VMOBJECTS, 1, 1 70f94ca20eSmartijn #define VMHVVERSION VMOBJECTS, 1, 2 71f94ca20eSmartijn #define VMHVOBJECTID VMOBJECTS, 1, 3 72f94ca20eSmartijn #define VMNUMBER VMOBJECTS, 2 73f94ca20eSmartijn #define VMENTRY VMOBJECTS, 4, 1 74f94ca20eSmartijn #define VMINDEX VMENTRY, 1 75f94ca20eSmartijn #define VMNAME VMENTRY, 2 76f94ca20eSmartijn #define VMUUID VMENTRY, 3 77f94ca20eSmartijn #define VMOSTYPE VMENTRY, 4 78f94ca20eSmartijn #define VMADMINSTATE VMENTRY, 5 79f94ca20eSmartijn #define VMOPERSTATE VMENTRY, 6 80f94ca20eSmartijn #define VMAUTOSTART VMENTRY, 7 81f94ca20eSmartijn #define VMPERSISTENT VMENTRY, 8 82f94ca20eSmartijn #define VMCURCPUNUMBER VMENTRY, 9 83f94ca20eSmartijn #define VMMINCPUNUMBER VMENTRY, 10 84f94ca20eSmartijn #define VMMAXCPUNUMBER VMENTRY, 11 85f94ca20eSmartijn #define VMMEMUNIT VMENTRY, 12 86f94ca20eSmartijn #define VMCURMEM VMENTRY, 13 87f94ca20eSmartijn #define VMMINMEM VMENTRY, 14 88f94ca20eSmartijn #define VMMAXMEM VMENTRY, 15 89f94ca20eSmartijn 90f94ca20eSmartijn #define AGENTX_GROUP "_agentx" 91f94ca20eSmartijn #define MEM_SCALE (1024 * 1024) 92f94ca20eSmartijn 93f94ca20eSmartijn static struct privsep_proc procs[] = { 94f94ca20eSmartijn { "parent", PROC_PARENT, vm_agentx_dispatch_parent }, 95f94ca20eSmartijn }; 96f94ca20eSmartijn 97f94ca20eSmartijn void 98f94ca20eSmartijn vm_agentx(struct privsep *ps, struct privsep_proc *p) 99f94ca20eSmartijn { 100f94ca20eSmartijn struct group *grp; 101f94ca20eSmartijn 102f94ca20eSmartijn /* 103f94ca20eSmartijn * Make sure we can connect to /var/agentx/master with the correct 104f94ca20eSmartijn * group permissions. 105f94ca20eSmartijn */ 106f94ca20eSmartijn if ((grp = getgrnam(AGENTX_GROUP)) == NULL) 10768ff4442Sdv fatal("failed to get group: %s", AGENTX_GROUP); 108f94ca20eSmartijn ps->ps_pw->pw_gid = grp->gr_gid; 109f94ca20eSmartijn 110f94ca20eSmartijn proc_run(ps, p, procs, nitems(procs), vm_agentx_run, NULL); 111f94ca20eSmartijn } 112f94ca20eSmartijn 113f94ca20eSmartijn void 114f94ca20eSmartijn vm_agentx_shutdown(void) 115f94ca20eSmartijn { 116f94ca20eSmartijn } 117f94ca20eSmartijn 118f94ca20eSmartijn void 119f94ca20eSmartijn vm_agentx_run(struct privsep *ps, struct privsep_proc *p, void *arg) 120f94ca20eSmartijn { 121f94ca20eSmartijn /* 122f94ca20eSmartijn * pledge in agentx process 123f94ca20eSmartijn * stdio - for malloc and basic I/O including events. 124f94ca20eSmartijn * recvfd - for the proc fd exchange. 125f94ca20eSmartijn * unix - for access to the agentx master socket. 126f94ca20eSmartijn */ 127f94ca20eSmartijn if (pledge("stdio recvfd unix", NULL) == -1) 128f94ca20eSmartijn fatal("pledge"); 129f94ca20eSmartijn } 130f94ca20eSmartijn 131f94ca20eSmartijn int 132f94ca20eSmartijn vm_agentx_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) 133f94ca20eSmartijn { 134f94ca20eSmartijn static struct vmop_info_result *vir = NULL; 135f94ca20eSmartijn static struct vmop_info_result *mvir = NULL; 136f94ca20eSmartijn struct vmd *env = p->p_ps->ps_env; 137f94ca20eSmartijn struct vmop_info_result *tvir; 138f94ca20eSmartijn struct agentx_object *reqObject; 139f94ca20eSmartijn static size_t nvir = 0; 140f94ca20eSmartijn static size_t virlen = 0; 141f94ca20eSmartijn static int error = 0; 142f94ca20eSmartijn size_t i, j, index; 143f94ca20eSmartijn enum agentx_request_type rtype; 144f94ca20eSmartijn 145f94ca20eSmartijn switch (imsg->hdr.type) { 146f94ca20eSmartijn case IMSG_VMDOP_GET_INFO_VM_DATA: 147f94ca20eSmartijn if (error) 148f94ca20eSmartijn break; 149f94ca20eSmartijn if (nvir + 1 > virlen) { 150f94ca20eSmartijn tvir = reallocarray(vir, virlen + 10, sizeof(*vir)); 151f94ca20eSmartijn if (tvir == NULL) { 152f94ca20eSmartijn log_warn("%s: Couldn't dispatch vm information", 153f94ca20eSmartijn __func__); 154f94ca20eSmartijn error = 1; 155f94ca20eSmartijn break; 156f94ca20eSmartijn } 157f94ca20eSmartijn virlen += 10; 158f94ca20eSmartijn vir = tvir; 159f94ca20eSmartijn } 160f94ca20eSmartijn memcpy(&(vir[nvir++]), imsg->data, sizeof(vir[nvir])); 161f94ca20eSmartijn break; 162f94ca20eSmartijn case IMSG_VMDOP_GET_INFO_VM_END_DATA: 163f94ca20eSmartijn vmcollecting = 0; 164f94ca20eSmartijn if (error) { 165f94ca20eSmartijn for (i = 0; i < vminfolen; i++) 166f94ca20eSmartijn agentx_varbind_error(vminfo[i]); 167f94ca20eSmartijn vminfolen = 0; 168f94ca20eSmartijn error = 0; 169f94ca20eSmartijn nvir = 0; 170f94ca20eSmartijn return (0); 171f94ca20eSmartijn } 172f94ca20eSmartijn 173f94ca20eSmartijn qsort(vir, nvir, sizeof(*vir), vm_agentx_sortvir); 174f94ca20eSmartijn for (i = 0; i < vminfolen; i++) { 175f94ca20eSmartijn reqObject = agentx_varbind_get_object(vminfo[i]); 176f94ca20eSmartijn if (reqObject == vmNumber) { 177f94ca20eSmartijn agentx_varbind_integer(vminfo[i], 178f94ca20eSmartijn (int32_t)nvir); 179f94ca20eSmartijn continue; 180f94ca20eSmartijn } 181f94ca20eSmartijn index = agentx_varbind_get_index_integer(vminfo[i], 182f94ca20eSmartijn vmIndex); 183f94ca20eSmartijn rtype = agentx_varbind_request(vminfo[i]); 184f94ca20eSmartijn for (j = 0; j < nvir; j++) { 185f94ca20eSmartijn if (vir[j].vir_info.vir_id < index) 186f94ca20eSmartijn continue; 187f94ca20eSmartijn if (vir[j].vir_info.vir_id == index && 188f94ca20eSmartijn (rtype == AGENTX_REQUEST_TYPE_GET || 189f94ca20eSmartijn rtype == 190f94ca20eSmartijn AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE)) 191f94ca20eSmartijn break; 192f94ca20eSmartijn if (vir[j].vir_info.vir_id > index && 193f94ca20eSmartijn (rtype == AGENTX_REQUEST_TYPE_GETNEXT || 194f94ca20eSmartijn rtype == 195f94ca20eSmartijn AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE)) 196f94ca20eSmartijn break; 197f94ca20eSmartijn } 198f94ca20eSmartijn if (j == nvir) { 199f94ca20eSmartijn agentx_varbind_notfound(vminfo[i]); 200f94ca20eSmartijn continue; 201f94ca20eSmartijn } 202f94ca20eSmartijn mvir = &(vir[j]); 203f94ca20eSmartijn agentx_varbind_set_index_integer(vminfo[i], vmIndex, 204f94ca20eSmartijn mvir->vir_info.vir_id); 205f94ca20eSmartijn if (reqObject == vmName) 206f94ca20eSmartijn agentx_varbind_string(vminfo[i], 207f94ca20eSmartijn mvir->vir_info.vir_name); 208f94ca20eSmartijn else if (reqObject == vmUUID) 209f94ca20eSmartijn agentx_varbind_string(vminfo[i], ""); 210f94ca20eSmartijn else if (reqObject == vmOSType) 211f94ca20eSmartijn agentx_varbind_string(vminfo[i], ""); 212f94ca20eSmartijn else if (reqObject == vmAdminState) 213f94ca20eSmartijn agentx_varbind_integer(vminfo[i], 214f94ca20eSmartijn vm_agentx_adminstate(mvir->vir_state)); 215f94ca20eSmartijn else if (reqObject == vmOperState) 216f94ca20eSmartijn agentx_varbind_integer(vminfo[i], 217f94ca20eSmartijn vm_agentx_operstate(mvir->vir_state)); 218f94ca20eSmartijn else if (reqObject == vmAutoStart) 219f94ca20eSmartijn agentx_varbind_integer(vminfo[i], 220f94ca20eSmartijn mvir->vir_state & VM_STATE_DISABLED ? 221f94ca20eSmartijn 3 : 2); 222f94ca20eSmartijn /* XXX We can dynamically create vm's but I don't know how to differentiate */ 223f94ca20eSmartijn else if (reqObject == vmPersistent) 224f94ca20eSmartijn agentx_varbind_integer(vminfo[i], 1); 225f94ca20eSmartijn /* We currently only support a single CPU */ 226f94ca20eSmartijn else if (reqObject == vmCurCpuNumber || 227f94ca20eSmartijn reqObject == vmMinCpuNumber || 228f94ca20eSmartijn reqObject == vmMaxCpuNumber) 229f94ca20eSmartijn agentx_varbind_integer(vminfo[i], 230f94ca20eSmartijn mvir->vir_info.vir_ncpus); 231f94ca20eSmartijn else if (reqObject == vmMemUnit) 232f94ca20eSmartijn agentx_varbind_integer(vminfo[i], MEM_SCALE); 233f94ca20eSmartijn else if (reqObject == vmCurMem) 234f94ca20eSmartijn agentx_varbind_integer(vminfo[i], 235f94ca20eSmartijn mvir->vir_info.vir_used_size / MEM_SCALE); 236f94ca20eSmartijn else if (reqObject == vmMinMem) 237f94ca20eSmartijn agentx_varbind_integer(vminfo[i], -1); 238f94ca20eSmartijn else if (reqObject == vmMaxMem) 239f94ca20eSmartijn agentx_varbind_integer(vminfo[i], 240f94ca20eSmartijn mvir->vir_info.vir_memory_size / MEM_SCALE); 241f94ca20eSmartijn /* We probably had a reload */ 242f94ca20eSmartijn else 243f94ca20eSmartijn agentx_varbind_notfound(vminfo[i]); 244f94ca20eSmartijn } 245f94ca20eSmartijn vminfolen = 0; 246f94ca20eSmartijn nvir = 0; 247f94ca20eSmartijn break; 248f94ca20eSmartijn case IMSG_VMDOP_CONFIG: 249f94ca20eSmartijn config_getconfig(env, imsg); 250f94ca20eSmartijn vm_agentx_configure(&env->vmd_cfg.cfg_agentx); 251f94ca20eSmartijn break; 252f94ca20eSmartijn default: 253f94ca20eSmartijn return (-1); 254f94ca20eSmartijn } 255f94ca20eSmartijn return (0); 256f94ca20eSmartijn } 257f94ca20eSmartijn 258f94ca20eSmartijn void 259f94ca20eSmartijn vm_agentx_configure(struct vmd_agentx *env) 260f94ca20eSmartijn { 261f94ca20eSmartijn static char curpath[sizeof(env->ax_path)]; 262f94ca20eSmartijn static char curcontext[sizeof(env->ax_context)]; 263f94ca20eSmartijn static struct conn *conn; 264f94ca20eSmartijn static struct agentx_session *sess; 265f94ca20eSmartijn static struct agentx_context *ctx; 266f94ca20eSmartijn struct agentx_region *vmMIB; 267f94ca20eSmartijn char *context = env->ax_context[0] == '\0' ? NULL : env->ax_context; 268f94ca20eSmartijn int changed = 0; 269f94ca20eSmartijn 270f94ca20eSmartijn vmd_agentx = env; 271f94ca20eSmartijn 272f94ca20eSmartijn agentx_log_fatal = fatalx; 273f94ca20eSmartijn agentx_log_warn = log_warnx; 274f94ca20eSmartijn agentx_log_info = log_info; 275f94ca20eSmartijn agentx_log_debug = log_debug; 276f94ca20eSmartijn 277f94ca20eSmartijn if (!vmd_agentx->ax_enabled) { 278f94ca20eSmartijn if (conn != NULL) { 279f94ca20eSmartijn agentx_free(conn->agentx); 280f94ca20eSmartijn conn = NULL; 281f94ca20eSmartijn sess = NULL; 282f94ca20eSmartijn ctx = NULL; 283f94ca20eSmartijn vm_agentx_flush_pending(); 284f94ca20eSmartijn } 285f94ca20eSmartijn return; 286f94ca20eSmartijn } 287f94ca20eSmartijn 288f94ca20eSmartijn if (strcmp(curpath, vmd_agentx->ax_path) != 0 || conn == NULL) { 289f94ca20eSmartijn if (conn != NULL) { 290f94ca20eSmartijn agentx_free(conn->agentx); 291f94ca20eSmartijn conn = NULL; 292f94ca20eSmartijn sess = NULL; 293f94ca20eSmartijn ctx = NULL; 294f94ca20eSmartijn vm_agentx_flush_pending(); 295f94ca20eSmartijn } 296f94ca20eSmartijn 297f94ca20eSmartijn if ((conn = malloc(sizeof(*conn))) == NULL) 298f94ca20eSmartijn fatal(NULL); 299f94ca20eSmartijn /* Set to something so we can safely event_del */ 300f94ca20eSmartijn evtimer_set(&conn->ev, vm_agentx_tryconnect, conn); 301f94ca20eSmartijn /* result assigned in vm_agentx_nofd */ 302f94ca20eSmartijn if (agentx(vm_agentx_nofd, conn) == NULL) 303f94ca20eSmartijn fatal("Can't setup agentx"); 304f94ca20eSmartijn sess = agentx_session(conn->agentx, NULL, 0, "vmd", 0); 305f94ca20eSmartijn if (sess == NULL) 306f94ca20eSmartijn fatal("Can't setup agentx session"); 307f94ca20eSmartijn (void) strlcpy(curpath, vmd_agentx->ax_path, sizeof(curpath)); 308f94ca20eSmartijn changed = 1; 309f94ca20eSmartijn } 310f94ca20eSmartijn 311f94ca20eSmartijn if (strcmp(curcontext, vmd_agentx->ax_context) != 0 || changed) { 312f94ca20eSmartijn if (!changed) { 313f94ca20eSmartijn agentx_context_free(ctx); 314f94ca20eSmartijn vm_agentx_flush_pending(); 315f94ca20eSmartijn } 316f94ca20eSmartijn if ((ctx = agentx_context(sess, context)) == NULL) 317f94ca20eSmartijn fatal("Can't setup agentx context"); 318f94ca20eSmartijn strlcpy(curcontext, vmd_agentx->ax_context, sizeof(curcontext)); 319f94ca20eSmartijn changed = 1; 320f94ca20eSmartijn } 321f94ca20eSmartijn 322f94ca20eSmartijn if (!changed) 323f94ca20eSmartijn return; 324f94ca20eSmartijn 325f94ca20eSmartijn if ((vmMIB = agentx_region(ctx, AGENTX_OID(VMMIB), 1)) == NULL) 326f94ca20eSmartijn fatal("agentx_region vmMIB"); 327f94ca20eSmartijn 328f94ca20eSmartijn if ((vmIndex = agentx_index_integer_dynamic(vmMIB, 329f94ca20eSmartijn AGENTX_OID(VMINDEX))) == NULL) 330f94ca20eSmartijn fatal("agentx_index_integer_dynamic"); 331f94ca20eSmartijn if ((agentx_object(vmMIB, AGENTX_OID(VMHVSOFTWARE), NULL, 0, 0, 332f94ca20eSmartijn vm_agentx_vmHvSoftware)) == NULL || 333f94ca20eSmartijn (agentx_object(vmMIB, AGENTX_OID(VMHVVERSION), NULL, 0, 0, 334f94ca20eSmartijn vm_agentx_vmHvVersion)) == NULL || 335f94ca20eSmartijn (agentx_object(vmMIB, AGENTX_OID(VMHVOBJECTID), NULL, 0, 0, 336f94ca20eSmartijn vm_agentx_vmHvObjectID)) == NULL || 337f94ca20eSmartijn (vmNumber = agentx_object(vmMIB, AGENTX_OID(VMNUMBER), NULL, 0, 0, 338f94ca20eSmartijn vm_agentx_vminfo)) == NULL || 339f94ca20eSmartijn (vmName = agentx_object(vmMIB, AGENTX_OID(VMNAME), &vmIndex, 1, 0, 340f94ca20eSmartijn vm_agentx_vminfo)) == NULL || 341f94ca20eSmartijn (vmUUID = agentx_object(vmMIB, AGENTX_OID(VMUUID), &vmIndex, 1, 0, 342f94ca20eSmartijn vm_agentx_vminfo)) == NULL || 343f94ca20eSmartijn (vmOSType = agentx_object(vmMIB, AGENTX_OID(VMOSTYPE), &vmIndex, 1, 344f94ca20eSmartijn 0, vm_agentx_vminfo)) == NULL || 345f94ca20eSmartijn (vmAdminState = agentx_object(vmMIB, AGENTX_OID(VMADMINSTATE), 346f94ca20eSmartijn &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL || 347f94ca20eSmartijn (vmOperState = agentx_object(vmMIB, AGENTX_OID(VMOPERSTATE), 348f94ca20eSmartijn &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL || 349f94ca20eSmartijn (vmAutoStart = agentx_object(vmMIB, AGENTX_OID(VMAUTOSTART), 350f94ca20eSmartijn &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL || 351f94ca20eSmartijn (vmPersistent = agentx_object(vmMIB, AGENTX_OID(VMPERSISTENT), 352f94ca20eSmartijn &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL || 353f94ca20eSmartijn (vmCurCpuNumber = agentx_object(vmMIB, AGENTX_OID(VMCURCPUNUMBER), 354f94ca20eSmartijn &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL || 355f94ca20eSmartijn (vmMinCpuNumber = agentx_object(vmMIB, AGENTX_OID(VMMINCPUNUMBER), 356f94ca20eSmartijn &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL || 357f94ca20eSmartijn (vmMaxCpuNumber = agentx_object(vmMIB, AGENTX_OID(VMMAXCPUNUMBER), 358f94ca20eSmartijn &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL || 359f94ca20eSmartijn (vmMemUnit = agentx_object(vmMIB, AGENTX_OID(VMMEMUNIT), 360f94ca20eSmartijn &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL || 361f94ca20eSmartijn (vmCurMem = agentx_object(vmMIB, AGENTX_OID(VMCURMEM), 362f94ca20eSmartijn &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL || 363f94ca20eSmartijn (vmMinMem = agentx_object(vmMIB, AGENTX_OID(VMMINMEM), 364f94ca20eSmartijn &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL || 365f94ca20eSmartijn (vmMaxMem = agentx_object(vmMIB, AGENTX_OID(VMMAXMEM), 366f94ca20eSmartijn &vmIndex, 1, 0, vm_agentx_vminfo)) == NULL) 367f94ca20eSmartijn fatal("agentx_object_ro"); 368f94ca20eSmartijn } 369f94ca20eSmartijn 370f94ca20eSmartijn static void 371f94ca20eSmartijn vm_agentx_nofd(struct agentx *agentx, void *cookie, int close) 372f94ca20eSmartijn { 373f94ca20eSmartijn struct conn *conn = cookie; 374f94ca20eSmartijn 375f94ca20eSmartijn conn->agentx = agentx; 376f94ca20eSmartijn event_del(&conn->ev); 377f94ca20eSmartijn if (close) 378f94ca20eSmartijn free(conn); 379f94ca20eSmartijn else 380f94ca20eSmartijn vm_agentx_tryconnect(-1, 0, conn); 381f94ca20eSmartijn } 382f94ca20eSmartijn 383f94ca20eSmartijn static void 384f94ca20eSmartijn vm_agentx_tryconnect(int fd, short event, void *cookie) 385f94ca20eSmartijn { 386f94ca20eSmartijn struct sockaddr_un sun; 387f94ca20eSmartijn struct timeval timeout = {3, 0}; 388f94ca20eSmartijn struct conn *conn = cookie; 389f94ca20eSmartijn 390f94ca20eSmartijn sun.sun_len = sizeof(sun); 391f94ca20eSmartijn sun.sun_family = AF_UNIX; 392f94ca20eSmartijn strlcpy(sun.sun_path, vmd_agentx->ax_path, sizeof(sun.sun_path)); 393f94ca20eSmartijn if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 394f94ca20eSmartijn log_warn("socket"); 395f94ca20eSmartijn goto fail; 396f94ca20eSmartijn } else if (connect(fd, (struct sockaddr *)&sun, sun.sun_len) == -1) { 397f94ca20eSmartijn log_warn("connect"); 398f94ca20eSmartijn close(fd); 399f94ca20eSmartijn goto fail; 400f94ca20eSmartijn } 401f94ca20eSmartijn agentx_connect(conn->agentx, fd); 402f94ca20eSmartijn 403f94ca20eSmartijn event_set(&conn->ev, fd, EV_READ|EV_PERSIST, vm_agentx_read, conn); 404f94ca20eSmartijn event_add(&conn->ev, NULL); 405f94ca20eSmartijn 406f94ca20eSmartijn return; 407f94ca20eSmartijn fail: 408f94ca20eSmartijn evtimer_set(&conn->ev, vm_agentx_tryconnect, conn); 409f94ca20eSmartijn evtimer_add(&conn->ev, &timeout); 410f94ca20eSmartijn } 411f94ca20eSmartijn 412f94ca20eSmartijn static void 413f94ca20eSmartijn vm_agentx_read(int fd, short event, void *cookie) 414f94ca20eSmartijn { 415f94ca20eSmartijn struct conn *conn = cookie; 416f94ca20eSmartijn 417f94ca20eSmartijn agentx_read(conn->agentx); 418f94ca20eSmartijn } 419f94ca20eSmartijn 420f94ca20eSmartijn static void 421f94ca20eSmartijn vm_agentx_flush_pending(void) 422f94ca20eSmartijn { 423f94ca20eSmartijn size_t i; 424f94ca20eSmartijn 425f94ca20eSmartijn for (i = 0; i < vminfolen; i++) 426f94ca20eSmartijn agentx_varbind_notfound(vminfo[i]); 427f94ca20eSmartijn vminfolen = 0; 428f94ca20eSmartijn } 429f94ca20eSmartijn 430f94ca20eSmartijn static int 431f94ca20eSmartijn vm_agentx_sortvir(const void *c1, const void *c2) 432f94ca20eSmartijn { 433f94ca20eSmartijn const struct vmop_info_result *v1 = c1, *v2 = c2; 434f94ca20eSmartijn 435f94ca20eSmartijn return (v1->vir_info.vir_id < v2->vir_info.vir_id ? -1 : 436f94ca20eSmartijn v1->vir_info.vir_id > v2->vir_info.vir_id); 437f94ca20eSmartijn } 438f94ca20eSmartijn 439f94ca20eSmartijn static int 440f94ca20eSmartijn vm_agentx_adminstate(int mask) 441f94ca20eSmartijn { 442f94ca20eSmartijn if (mask & VM_STATE_PAUSED) 443f94ca20eSmartijn return (3); 444f94ca20eSmartijn else if (mask & VM_STATE_RUNNING) 445f94ca20eSmartijn return (1); 446f94ca20eSmartijn else if (mask & VM_STATE_SHUTDOWN) 447f94ca20eSmartijn return (4); 448f94ca20eSmartijn /* Presence of absence of other flags */ 449f94ca20eSmartijn else if (!mask || (mask & VM_STATE_DISABLED)) 450f94ca20eSmartijn return (4); 451f94ca20eSmartijn 452f94ca20eSmartijn return 4; 453f94ca20eSmartijn } 454f94ca20eSmartijn 455f94ca20eSmartijn static int 456f94ca20eSmartijn vm_agentx_operstate(int mask) 457f94ca20eSmartijn { 458f94ca20eSmartijn if (mask & VM_STATE_PAUSED) 459f94ca20eSmartijn return (8); 460f94ca20eSmartijn else if (mask & VM_STATE_RUNNING) 461f94ca20eSmartijn return (4); 462f94ca20eSmartijn else if (mask & VM_STATE_SHUTDOWN) 463f94ca20eSmartijn return (11); 464f94ca20eSmartijn /* Presence of absence of other flags */ 465f94ca20eSmartijn else if (!mask || (mask & VM_STATE_DISABLED)) 466f94ca20eSmartijn return (11); 467f94ca20eSmartijn 468f94ca20eSmartijn return (11); 469f94ca20eSmartijn } 470f94ca20eSmartijn 471f94ca20eSmartijn static void 472f94ca20eSmartijn vm_agentx_vmHvSoftware(struct agentx_varbind *vb) 473f94ca20eSmartijn { 474f94ca20eSmartijn agentx_varbind_string(vb, "OpenBSD VMM"); 475f94ca20eSmartijn } 476f94ca20eSmartijn 477f94ca20eSmartijn static void 478f94ca20eSmartijn vm_agentx_vmHvVersion(struct agentx_varbind *vb) 479f94ca20eSmartijn { 480f94ca20eSmartijn int osversid[] = {CTL_KERN, KERN_OSRELEASE}; 481f94ca20eSmartijn static char osvers[10] = ""; 482f94ca20eSmartijn size_t osverslen; 483f94ca20eSmartijn 484f94ca20eSmartijn if (osvers[0] == '\0') { 485f94ca20eSmartijn osverslen = sizeof(osvers); 486f94ca20eSmartijn if (sysctl(osversid, 2, osvers, &osverslen, NULL, 487f94ca20eSmartijn 0) == -1) { 488f94ca20eSmartijn log_warn("Failed vmHvVersion sysctl"); 489f94ca20eSmartijn agentx_varbind_string(vb, "unknown"); 490f94ca20eSmartijn return; 491f94ca20eSmartijn } 492f94ca20eSmartijn if (osverslen >= sizeof(osvers)) 493f94ca20eSmartijn osverslen = sizeof(osvers) - 1; 494f94ca20eSmartijn osvers[osverslen] = '\0'; 495f94ca20eSmartijn } 496f94ca20eSmartijn agentx_varbind_string(vb, osvers); 497f94ca20eSmartijn } 498f94ca20eSmartijn 499f94ca20eSmartijn static void 500f94ca20eSmartijn vm_agentx_vmHvObjectID(struct agentx_varbind *vb) 501f94ca20eSmartijn { 502f94ca20eSmartijn agentx_varbind_oid(vb, AGENTX_OID(0, 0)); 503f94ca20eSmartijn } 504f94ca20eSmartijn 505f94ca20eSmartijn static void 506f94ca20eSmartijn vm_agentx_vminfo(struct agentx_varbind *vb) 507f94ca20eSmartijn { 508f94ca20eSmartijn extern struct vmd *env; 509f94ca20eSmartijn struct agentx_varbind **tvminfo; 510f94ca20eSmartijn 511f94ca20eSmartijn if (vminfolen >= vminfosize) { 512f94ca20eSmartijn if ((tvminfo = reallocarray(vminfo, vminfosize + 10, 513f94ca20eSmartijn sizeof(*vminfo))) == NULL) { 514f94ca20eSmartijn log_warn("%s: Couldn't retrieve vm information", 515f94ca20eSmartijn __func__); 516f94ca20eSmartijn agentx_varbind_error(vb); 517f94ca20eSmartijn return; 518f94ca20eSmartijn } 519f94ca20eSmartijn vminfo = tvminfo; 520f94ca20eSmartijn vminfosize += 10; 521f94ca20eSmartijn } 522f94ca20eSmartijn 523f94ca20eSmartijn if (!vmcollecting) { 524f94ca20eSmartijn if (proc_compose_imsg(&(env->vmd_ps), PROC_PARENT, -1, 525f94ca20eSmartijn IMSG_VMDOP_GET_INFO_VM_REQUEST, IMSG_AGENTX_PEERID, 526f94ca20eSmartijn -1, NULL, 0) == -1) { 527f94ca20eSmartijn log_warn("%s: Couldn't retrieve vm information", 528f94ca20eSmartijn __func__); 529f94ca20eSmartijn agentx_varbind_error(vb); 530f94ca20eSmartijn return; 531f94ca20eSmartijn } 532f94ca20eSmartijn vmcollecting = 1; 533f94ca20eSmartijn } 534f94ca20eSmartijn 535f94ca20eSmartijn vminfo[vminfolen++] = vb; 536f94ca20eSmartijn } 537