Ejemplo n.º 1
0
/*
 * Read all of the groups statistics information.
 *
 * IN:
 * @groups:                The lists of groups.
 * @device_name:           The given device name.
 */
int read_all_groups(cg_group_lists* groups, const char* device_name) {

	int ret = 0, level;
	void *handle;
	struct cgroup_file_info info;
	cg_group* group = NULL;
	if (!groups || !device_name) {
		fprintf(stderr, "rd_stats: the input parameters is invalid.\n");
		return -1;
	}
	/** Clear the history information.*/
	clear_group(groups);
	/** Start the traversing of the directory. */
	ret = cgroup_walk_tree_begin(device_name, BASE_DIR, DEPTH, &handle, &info,
			&level);
	if (ret)
		goto err;
	/** Walk to the next. */
	while (!(ret = cgroup_walk_tree_next(0, &handle, &info, level))) {
		if (info.type == CGROUP_FILE_TYPE_DIR) {
			/** Initialized the group but the cpuset statistics information and the io
			 *  statistics information is NULL.*/
			if ((ret = init_group(&group, info.path, info.full_path))) {
#ifdef DEBUG
				fprintf(stderr,
						"rd_stats: initialize the group failed, group name: %s, path: %s.\n",
						info.path, info.full_path);
#endif
				goto err;
			}
			/** Add the group into the lists.*/
			if (group && add_group(groups, group)) {
#ifdef DEBUG
				fprintf(stderr,
						"rd_stats: add the group into lists failed, group name: %s, path: %s.\n",
						info.path, info.full_path);
#endif
				goto err;
			}
			group = NULL;
		}
	}
	/** End the traversing.*/
	cgroup_walk_tree_end(&handle);
	return 0;

	err: if (group)
		uninit_group(group);
	group = NULL;
	clear_group(groups);
	cgroup_walk_tree_end(&handle);
	return ret;
}
Ejemplo n.º 2
0
/*
 * Uninitialized the head of groups.
 *
 * IN:
 * @group_lists:      The structure of cgroup_group_lists.
 */
void uninit_group_lists(cg_group_lists* group_lists) {

	if (!group_lists)
		return;
	if (!TAILQ_EMPTY(group_lists))
		clear_group(group_lists);
	if (group_lists)
		free(group_lists);
}
Ejemplo n.º 3
0
int
rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr,
		int *vfio_dev_fd, struct vfio_device_info *device_info)
{
	struct vfio_group_status group_status = {
			.argsz = sizeof(group_status)
	};
	int vfio_group_fd;
	int iommu_group_no;
	int ret;

	/* get group number */
	ret = vfio_get_group_no(sysfs_base, dev_addr, &iommu_group_no);
	if (ret == 0) {
		RTE_LOG(WARNING, EAL, "  %s not managed by VFIO driver, skipping\n",
			dev_addr);
		return 1;
	}

	/* if negative, something failed */
	if (ret < 0)
		return -1;

	/* get the actual group fd */
	vfio_group_fd = vfio_get_group_fd(iommu_group_no);
	if (vfio_group_fd < 0)
		return -1;

	/* if group_fd == 0, that means the device isn't managed by VFIO */
	if (vfio_group_fd == 0) {
		RTE_LOG(WARNING, EAL, " %s not managed by VFIO driver, skipping\n",
				dev_addr);
		return 1;
	}

	/*
	 * at this point, we know that this group is viable (meaning, all devices
	 * are either bound to VFIO or not bound to anything)
	 */

	/* check if the group is viable */
	ret = ioctl(vfio_group_fd, VFIO_GROUP_GET_STATUS, &group_status);
	if (ret) {
		RTE_LOG(ERR, EAL, "  %s cannot get group status, "
				"error %i (%s)\n", dev_addr, errno, strerror(errno));
		close(vfio_group_fd);
		clear_group(vfio_group_fd);
		return -1;
	} else if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
		RTE_LOG(ERR, EAL, "  %s VFIO group is not viable!\n", dev_addr);
		close(vfio_group_fd);
		clear_group(vfio_group_fd);
		return -1;
	}

	/* check if group does not have a container yet */
	if (!(group_status.flags & VFIO_GROUP_FLAGS_CONTAINER_SET)) {

		/* add group to a container */
		ret = ioctl(vfio_group_fd, VFIO_GROUP_SET_CONTAINER,
				&vfio_cfg.vfio_container_fd);
		if (ret) {
			RTE_LOG(ERR, EAL, "  %s cannot add VFIO group to container, "
					"error %i (%s)\n", dev_addr, errno, strerror(errno));
			close(vfio_group_fd);
			clear_group(vfio_group_fd);
			return -1;
		}

		/*
		 * pick an IOMMU type and set up DMA mappings for container
		 *
		 * needs to be done only once, only when first group is
		 * assigned to a container and only in primary process.
		 * Note this can happen several times with the hotplug
		 * functionality.
		 */
		if (internal_config.process_type == RTE_PROC_PRIMARY &&
				vfio_cfg.vfio_active_groups == 1) {
			/* select an IOMMU type which we will be using */
			const struct vfio_iommu_type *t =
				vfio_set_iommu_type(vfio_cfg.vfio_container_fd);
			if (!t) {
				RTE_LOG(ERR, EAL,
					"  %s failed to select IOMMU type\n",
					dev_addr);
				close(vfio_group_fd);
				clear_group(vfio_group_fd);
				return -1;
			}
			ret = t->dma_map_func(vfio_cfg.vfio_container_fd);
			if (ret) {
				RTE_LOG(ERR, EAL,
					"  %s DMA remapping failed, error %i (%s)\n",
					dev_addr, errno, strerror(errno));
				close(vfio_group_fd);
				clear_group(vfio_group_fd);
				return -1;
			}
		}
	}

	/* get a file descriptor for the device */
	*vfio_dev_fd = ioctl(vfio_group_fd, VFIO_GROUP_GET_DEVICE_FD, dev_addr);
	if (*vfio_dev_fd < 0) {
		/* if we cannot get a device fd, this implies a problem with
		 * the VFIO group or the container not having IOMMU configured.
		 */

		RTE_LOG(WARNING, EAL, "Getting a vfio_dev_fd for %s failed\n",
				dev_addr);
		close(vfio_group_fd);
		clear_group(vfio_group_fd);
		return -1;
	}

	/* test and setup the device */
	ret = ioctl(*vfio_dev_fd, VFIO_DEVICE_GET_INFO, device_info);
	if (ret) {
		RTE_LOG(ERR, EAL, "  %s cannot get device info, "
				"error %i (%s)\n", dev_addr, errno,
				strerror(errno));
		close(*vfio_dev_fd);
		close(vfio_group_fd);
		clear_group(vfio_group_fd);
		return -1;
	}
	vfio_group_device_get(vfio_group_fd);

	return 0;
}

int
rte_vfio_release_device(const char *sysfs_base, const char *dev_addr,
		    int vfio_dev_fd)
{
	struct vfio_group_status group_status = {
			.argsz = sizeof(group_status)
	};
	int vfio_group_fd;
	int iommu_group_no;
	int ret;

	/* get group number */
	ret = vfio_get_group_no(sysfs_base, dev_addr, &iommu_group_no);
	if (ret <= 0) {
		RTE_LOG(WARNING, EAL, "  %s not managed by VFIO driver\n",
			dev_addr);
		/* This is an error at this point. */
		return -1;
	}

	/* get the actual group fd */
	vfio_group_fd = vfio_get_group_fd(iommu_group_no);
	if (vfio_group_fd <= 0) {
		RTE_LOG(INFO, EAL, "vfio_get_group_fd failed for %s\n",
				   dev_addr);
		return -1;
	}

	/* At this point we got an active group. Closing it will make the
	 * container detachment. If this is the last active group, VFIO kernel
	 * code will unset the container and the IOMMU mappings.
	 */

	/* Closing a device */
	if (close(vfio_dev_fd) < 0) {
		RTE_LOG(INFO, EAL, "Error when closing vfio_dev_fd for %s\n",
				   dev_addr);
		return -1;
	}

	/* An VFIO group can have several devices attached. Just when there is
	 * no devices remaining should the group be closed.
	 */
	vfio_group_device_put(vfio_group_fd);
	if (!vfio_group_device_count(vfio_group_fd)) {

		if (close(vfio_group_fd) < 0) {
			RTE_LOG(INFO, EAL, "Error when closing vfio_group_fd for %s\n",
				dev_addr);
			return -1;
		}

		if (clear_group(vfio_group_fd) < 0) {
			RTE_LOG(INFO, EAL, "Error when clearing group for %s\n",
					   dev_addr);
			return -1;
		}
	}

	return 0;
}

int
rte_vfio_enable(const char *modname)
{
	/* initialize group list */
	int i;
	int vfio_available;

	for (i = 0; i < VFIO_MAX_GROUPS; i++) {
		vfio_cfg.vfio_groups[i].fd = -1;
		vfio_cfg.vfio_groups[i].group_no = -1;
		vfio_cfg.vfio_groups[i].devices = 0;
	}

	/* inform the user that we are probing for VFIO */
	RTE_LOG(INFO, EAL, "Probing VFIO support...\n");

	/* check if vfio module is loaded */
	vfio_available = rte_eal_check_module(modname);

	/* return error directly */
	if (vfio_available == -1) {
		RTE_LOG(INFO, EAL, "Could not get loaded module details!\n");
		return -1;
	}

	/* return 0 if VFIO modules not loaded */
	if (vfio_available == 0) {
		RTE_LOG(DEBUG, EAL, "VFIO modules not loaded, "
			"skipping VFIO support...\n");
		return 0;
	}

	vfio_cfg.vfio_container_fd = vfio_get_container_fd();

	/* check if we have VFIO driver enabled */
	if (vfio_cfg.vfio_container_fd != -1) {
		RTE_LOG(NOTICE, EAL, "VFIO support initialized\n");
		vfio_cfg.vfio_enabled = 1;
	} else {
		RTE_LOG(NOTICE, EAL, "VFIO support could not be initialized\n");
	}

	return 0;
}

int
rte_vfio_is_enabled(const char *modname)
{
	const int mod_available = rte_eal_check_module(modname) > 0;
	return vfio_cfg.vfio_enabled && mod_available;
}

const struct vfio_iommu_type *
vfio_set_iommu_type(int vfio_container_fd)
{
	unsigned idx;
	for (idx = 0; idx < RTE_DIM(iommu_types); idx++) {
		const struct vfio_iommu_type *t = &iommu_types[idx];

		int ret = ioctl(vfio_container_fd, VFIO_SET_IOMMU,
				t->type_id);
		if (!ret) {
			RTE_LOG(NOTICE, EAL, "  using IOMMU type %d (%s)\n",
					t->type_id, t->name);
			return t;
		}
		/* not an error, there may be more supported IOMMU types */
		RTE_LOG(DEBUG, EAL, "  set IOMMU type %d (%s) failed, "
				"error %i (%s)\n", t->type_id, t->name, errno,
				strerror(errno));
	}
	/* if we didn't find a suitable IOMMU type, fail */
	return NULL;
}