int clear_group(int vfio_group_fd) { int i; int socket_fd, ret; if (internal_config.process_type == RTE_PROC_PRIMARY) { i = get_vfio_group_idx(vfio_group_fd); if (i < 0) return -1; vfio_cfg.vfio_groups[i].group_no = -1; vfio_cfg.vfio_groups[i].fd = -1; vfio_cfg.vfio_groups[i].devices = 0; vfio_cfg.vfio_active_groups--; return 0; } /* This is just for SECONDARY processes */ socket_fd = vfio_mp_sync_connect_to_primary(); if (socket_fd < 0) { RTE_LOG(ERR, EAL, " cannot connect to primary process!\n"); return -1; } if (vfio_mp_sync_send_request(socket_fd, SOCKET_CLR_GROUP) < 0) { RTE_LOG(ERR, EAL, " cannot request container fd!\n"); close(socket_fd); return -1; } if (vfio_mp_sync_send_request(socket_fd, vfio_group_fd) < 0) { RTE_LOG(ERR, EAL, " cannot send group fd!\n"); close(socket_fd); return -1; } ret = vfio_mp_sync_receive_request(socket_fd); switch (ret) { case SOCKET_NO_FD: RTE_LOG(ERR, EAL, " BAD VFIO group fd!\n"); close(socket_fd); break; case SOCKET_OK: close(socket_fd); return 0; case SOCKET_ERR: RTE_LOG(ERR, EAL, " Socket error\n"); close(socket_fd); break; default: RTE_LOG(ERR, EAL, " UNKNOWN reply, %d\n", ret); close(socket_fd); } return -1; }
/* * socket listening thread for primary process */ static __attribute__((noreturn)) void * pci_vfio_mp_sync_thread(void __rte_unused * arg) { int ret, fd, vfio_group_no; /* wait for requests on the socket */ for (;;) { int conn_sock; struct sockaddr_un addr; socklen_t sockaddr_len = sizeof(addr); /* this is a blocking call */ conn_sock = accept(mp_socket_fd, (struct sockaddr *) &addr, &sockaddr_len); /* just restart on error */ if (conn_sock == -1) continue; /* set socket to linger after close */ struct linger l; l.l_onoff = 1; l.l_linger = 60; setsockopt(conn_sock, SOL_SOCKET, SO_LINGER, &l, sizeof(l)); ret = vfio_mp_sync_receive_request(conn_sock); switch (ret) { case SOCKET_REQ_CONTAINER: fd = pci_vfio_get_container_fd(); if (fd < 0) vfio_mp_sync_send_request(conn_sock, SOCKET_ERR); else vfio_mp_sync_send_fd(conn_sock, fd); break; case SOCKET_REQ_GROUP: /* wait for group number */ vfio_group_no = vfio_mp_sync_receive_request(conn_sock); if (vfio_group_no < 0) { close(conn_sock); continue; } fd = pci_vfio_get_group_fd(vfio_group_no); if (fd < 0) vfio_mp_sync_send_request(conn_sock, SOCKET_ERR); /* if VFIO group exists but isn't bound to VFIO driver */ else if (fd == 0) vfio_mp_sync_send_request(conn_sock, SOCKET_NO_FD); /* if group exists and is bound to VFIO driver */ else { vfio_mp_sync_send_request(conn_sock, SOCKET_OK); vfio_mp_sync_send_fd(conn_sock, fd); } break; default: vfio_mp_sync_send_request(conn_sock, SOCKET_ERR); break; } close(conn_sock); } }
int vfio_get_group_fd(int iommu_group_no) { int i; int vfio_group_fd; char filename[PATH_MAX]; struct vfio_group *cur_grp; /* check if we already have the group descriptor open */ for (i = 0; i < VFIO_MAX_GROUPS; i++) if (vfio_cfg.vfio_groups[i].group_no == iommu_group_no) return vfio_cfg.vfio_groups[i].fd; /* Lets see first if there is room for a new group */ if (vfio_cfg.vfio_active_groups == VFIO_MAX_GROUPS) { RTE_LOG(ERR, EAL, "Maximum number of VFIO groups reached!\n"); return -1; } /* Now lets get an index for the new group */ for (i = 0; i < VFIO_MAX_GROUPS; i++) if (vfio_cfg.vfio_groups[i].group_no == -1) { cur_grp = &vfio_cfg.vfio_groups[i]; break; } /* This should not happen */ if (i == VFIO_MAX_GROUPS) { RTE_LOG(ERR, EAL, "No VFIO group free slot found\n"); return -1; } /* if primary, try to open the group */ if (internal_config.process_type == RTE_PROC_PRIMARY) { /* try regular group format */ snprintf(filename, sizeof(filename), VFIO_GROUP_FMT, iommu_group_no); vfio_group_fd = open(filename, O_RDWR); if (vfio_group_fd < 0) { /* if file not found, it's not an error */ if (errno != ENOENT) { RTE_LOG(ERR, EAL, "Cannot open %s: %s\n", filename, strerror(errno)); return -1; } /* special case: try no-IOMMU path as well */ snprintf(filename, sizeof(filename), VFIO_NOIOMMU_GROUP_FMT, iommu_group_no); vfio_group_fd = open(filename, O_RDWR); if (vfio_group_fd < 0) { if (errno != ENOENT) { RTE_LOG(ERR, EAL, "Cannot open %s: %s\n", filename, strerror(errno)); return -1; } return 0; } /* noiommu group found */ } cur_grp->group_no = iommu_group_no; cur_grp->fd = vfio_group_fd; vfio_cfg.vfio_active_groups++; return vfio_group_fd; } /* if we're in a secondary process, request group fd from the primary * process via our socket */ else { int socket_fd, ret; socket_fd = vfio_mp_sync_connect_to_primary(); if (socket_fd < 0) { RTE_LOG(ERR, EAL, " cannot connect to primary process!\n"); return -1; } if (vfio_mp_sync_send_request(socket_fd, SOCKET_REQ_GROUP) < 0) { RTE_LOG(ERR, EAL, " cannot request container fd!\n"); close(socket_fd); return -1; } if (vfio_mp_sync_send_request(socket_fd, iommu_group_no) < 0) { RTE_LOG(ERR, EAL, " cannot send group number!\n"); close(socket_fd); return -1; } ret = vfio_mp_sync_receive_request(socket_fd); switch (ret) { case SOCKET_NO_FD: close(socket_fd); return 0; case SOCKET_OK: vfio_group_fd = vfio_mp_sync_receive_fd(socket_fd); /* if we got the fd, store it and return it */ if (vfio_group_fd > 0) { close(socket_fd); cur_grp->group_no = iommu_group_no; cur_grp->fd = vfio_group_fd; vfio_cfg.vfio_active_groups++; return vfio_group_fd; } /* fall-through on error */ default: RTE_LOG(ERR, EAL, " cannot get container fd!\n"); close(socket_fd); return -1; } } return -1; }
int vfio_get_container_fd(void) { int ret, vfio_container_fd; /* if we're in a primary process, try to open the container */ if (internal_config.process_type == RTE_PROC_PRIMARY) { vfio_container_fd = open(VFIO_CONTAINER_PATH, O_RDWR); if (vfio_container_fd < 0) { RTE_LOG(ERR, EAL, " cannot open VFIO container, " "error %i (%s)\n", errno, strerror(errno)); return -1; } /* check VFIO API version */ ret = ioctl(vfio_container_fd, VFIO_GET_API_VERSION); if (ret != VFIO_API_VERSION) { if (ret < 0) RTE_LOG(ERR, EAL, " could not get VFIO API version, " "error %i (%s)\n", errno, strerror(errno)); else RTE_LOG(ERR, EAL, " unsupported VFIO API version!\n"); close(vfio_container_fd); return -1; } ret = vfio_has_supported_extensions(vfio_container_fd); if (ret) { RTE_LOG(ERR, EAL, " no supported IOMMU " "extensions found!\n"); return -1; } return vfio_container_fd; } else { /* * if we're in a secondary process, request container fd from the * primary process via our socket */ int socket_fd; socket_fd = vfio_mp_sync_connect_to_primary(); if (socket_fd < 0) { RTE_LOG(ERR, EAL, " cannot connect to primary process!\n"); return -1; } if (vfio_mp_sync_send_request(socket_fd, SOCKET_REQ_CONTAINER) < 0) { RTE_LOG(ERR, EAL, " cannot request container fd!\n"); close(socket_fd); return -1; } vfio_container_fd = vfio_mp_sync_receive_fd(socket_fd); if (vfio_container_fd < 0) { RTE_LOG(ERR, EAL, " cannot get container fd!\n"); close(socket_fd); return -1; } close(socket_fd); return vfio_container_fd; } return -1; }