1255 lines
40 KiB
Diff
1255 lines
40 KiB
Diff
|
|
From 684f0aa648061a13e777153e297a7064ba33ea17 Mon Sep 17 00:00:00 2001
|
||
|
|
From: liuxu <liuxu156@huawei.com>
|
||
|
|
Date: Thu, 11 Apr 2024 11:00:44 +0800
|
||
|
|
Subject: [PATCH 66/69] cdi:support modules version/spec/spec_dirs/device
|
||
|
|
|
||
|
|
---
|
||
|
|
.../modules/device/cdi/behavior/cdi_device.c | 100 +++++++-
|
||
|
|
.../modules/device/cdi/behavior/cdi_device.h | 12 +-
|
||
|
|
.../modules/device/cdi/behavior/cdi_spec.c | 220 ++++++++++++++++--
|
||
|
|
.../modules/device/cdi/behavior/cdi_spec.h | 16 +-
|
||
|
|
.../device/cdi/behavior/cdi_spec_dirs.c | 80 +++++++
|
||
|
|
.../device/cdi/behavior/cdi_spec_dirs.h | 2 +-
|
||
|
|
.../modules/device/cdi/behavior/cdi_version.c | 173 ++++++++++++--
|
||
|
|
.../modules/device/cdi/behavior/cdi_version.h | 1 -
|
||
|
|
src/daemon/modules/device/cdi/cdi_cache.c | 37 +--
|
||
|
|
src/daemon/modules/device/cdi/cdi_cache.h | 1 +
|
||
|
|
.../network/cni_operator/libcni/libcni_api.c | 98 +-------
|
||
|
|
src/utils/cutils/utils_version.c | 147 ++++++++++++
|
||
|
|
src/utils/cutils/utils_version.h | 36 +++
|
||
|
|
13 files changed, 748 insertions(+), 175 deletions(-)
|
||
|
|
create mode 100644 src/utils/cutils/utils_version.c
|
||
|
|
create mode 100644 src/utils/cutils/utils_version.h
|
||
|
|
|
||
|
|
diff --git a/src/daemon/modules/device/cdi/behavior/cdi_device.c b/src/daemon/modules/device/cdi/behavior/cdi_device.c
|
||
|
|
index 0fef8f42..aec3d7c0 100644
|
||
|
|
--- a/src/daemon/modules/device/cdi/behavior/cdi_device.c
|
||
|
|
+++ b/src/daemon/modules/device/cdi/behavior/cdi_device.c
|
||
|
|
@@ -14,27 +14,109 @@
|
||
|
|
******************************************************************************/
|
||
|
|
#include "cdi_device.h"
|
||
|
|
|
||
|
|
+#include <isula_libutils/log.h>
|
||
|
|
+#include <isula_libutils/auto_cleanup.h>
|
||
|
|
+
|
||
|
|
+#include "error.h"
|
||
|
|
+#include "cdi_parser.h"
|
||
|
|
+#include "cdi_spec.h"
|
||
|
|
+
|
||
|
|
+static int cdi_device_validate(struct cdi_cache_device *d);
|
||
|
|
+
|
||
|
|
void free_cdi_cache_device(struct cdi_cache_device *d)
|
||
|
|
{
|
||
|
|
- (void)d;
|
||
|
|
+ if (d == NULL) {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * free_cdi_cache_device should not be recursively free raw_device.
|
||
|
|
+ * Otherwise, the function conflicts with the raw_spec free raw_device
|
||
|
|
+ * when cdi_cache_spec free raw_spec, triggering double free.
|
||
|
|
+ */
|
||
|
|
+ d->raw_device = NULL;
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * free_cdi_cache_device should not be recursively free cache_spec.
|
||
|
|
+ * Otherwise, the function conflicts with the cache free specs,
|
||
|
|
+ * triggering double free.
|
||
|
|
+ */
|
||
|
|
+ d->cache_spec = NULL;
|
||
|
|
+
|
||
|
|
+ free(d);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+struct cdi_cache_device *cdi_device_new_device(struct cdi_cache_spec *spec, cdi_device *d)
|
||
|
|
+{
|
||
|
|
+ struct cdi_cache_device *dev = NULL;
|
||
|
|
+
|
||
|
|
+ if (spec == NULL || d == NULL) {
|
||
|
|
+ ERROR("Invalid params");
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ dev = util_common_calloc_s(sizeof(*dev));
|
||
|
|
+ if (dev == NULL) {
|
||
|
|
+ ERROR("Out of memory");
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ dev->raw_device = d;
|
||
|
|
+ dev->cache_spec = spec;
|
||
|
|
+
|
||
|
|
+ if (cdi_device_validate(dev) != 0) {
|
||
|
|
+ free_cdi_cache_device(dev);
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ return dev;
|
||
|
|
}
|
||
|
|
|
||
|
|
-struct cdi_cache_device *cdi_device_new_device(struct cdi_cache_spec *spec, cdi_device *d, char **error)
|
||
|
|
+const struct cdi_cache_spec *cdi_device_get_spec(const struct cdi_cache_device *d)
|
||
|
|
{
|
||
|
|
- return NULL;
|
||
|
|
+ if (d == NULL) {
|
||
|
|
+ ERROR("Invalid params");
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ return d->cache_spec;
|
||
|
|
}
|
||
|
|
|
||
|
|
-struct cdi_cache_spec *cdi_device_get_spec(struct cdi_cache_device *d)
|
||
|
|
+char *cdi_device_get_qualified_name(const struct cdi_cache_device *d)
|
||
|
|
{
|
||
|
|
- return NULL;
|
||
|
|
+ if (d == NULL || d->raw_device == NULL) {
|
||
|
|
+ ERROR("Invalid params");
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ return cdi_parser_qualified_name(cdi_spec_get_vendor(d->cache_spec),
|
||
|
|
+ cdi_spec_get_class(d->cache_spec), d->raw_device->name);
|
||
|
|
}
|
||
|
|
|
||
|
|
-char *cdi_device_get_qualified_name(struct cdi_cache_device *d)
|
||
|
|
+cdi_container_edits *cdi_device_get_edits(const struct cdi_cache_device *d)
|
||
|
|
{
|
||
|
|
- return NULL;
|
||
|
|
+ if (d == NULL || d->raw_device == NULL) {
|
||
|
|
+ ERROR("Invalid params");
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ return d->raw_device->container_edits;
|
||
|
|
}
|
||
|
|
|
||
|
|
-cdi_container_edits *cdi_device_get_edits(struct cdi_cache_device *d)
|
||
|
|
+static int cdi_device_validate(struct cdi_cache_device *d)
|
||
|
|
{
|
||
|
|
- return NULL;
|
||
|
|
+ cdi_container_edits *edits = NULL;
|
||
|
|
+
|
||
|
|
+ if (cdi_parser_validate_device_name(d->raw_device->name) != 0) {
|
||
|
|
+ ERROR("Failed to validate device name");
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // ignore validate annotations
|
||
|
|
+
|
||
|
|
+ edits = cdi_device_get_edits(d);
|
||
|
|
+ if (cdi_container_edits_is_empty(edits)) {
|
||
|
|
+ ERROR("Invalid device, empty device edits");
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+ if (cdi_container_edits_validate(edits) != 0) {
|
||
|
|
+ ERROR("Invalid device %s", d->raw_device->name);
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
}
|
||
|
|
diff --git a/src/daemon/modules/device/cdi/behavior/cdi_device.h b/src/daemon/modules/device/cdi/behavior/cdi_device.h
|
||
|
|
index 5d63a576..9b0a5eab 100644
|
||
|
|
--- a/src/daemon/modules/device/cdi/behavior/cdi_device.h
|
||
|
|
+++ b/src/daemon/modules/device/cdi/behavior/cdi_device.h
|
||
|
|
@@ -28,16 +28,16 @@ extern "C" {
|
||
|
|
struct cdi_cache_spec;
|
||
|
|
|
||
|
|
struct cdi_cache_device {
|
||
|
|
- cdi_device *raw_device;
|
||
|
|
- struct cdi_cache_spec *cache_spec;
|
||
|
|
+ const cdi_device *raw_device;
|
||
|
|
+ const struct cdi_cache_spec *cache_spec;
|
||
|
|
};
|
||
|
|
|
||
|
|
void free_cdi_cache_device(struct cdi_cache_device *d);
|
||
|
|
|
||
|
|
-struct cdi_cache_device *cdi_device_new_device(struct cdi_cache_spec *spec, cdi_device *d, char **error);
|
||
|
|
-struct cdi_cache_spec *cdi_device_get_spec(struct cdi_cache_device *d);
|
||
|
|
-char *cdi_device_get_qualified_name(struct cdi_cache_device *d);
|
||
|
|
-cdi_container_edits *cdi_device_get_edits(struct cdi_cache_device *d);
|
||
|
|
+struct cdi_cache_device *cdi_device_new_device(struct cdi_cache_spec *spec, cdi_device *d);
|
||
|
|
+const struct cdi_cache_spec *cdi_device_get_spec(const struct cdi_cache_device *d);
|
||
|
|
+char *cdi_device_get_qualified_name(const struct cdi_cache_device *d);
|
||
|
|
+cdi_container_edits *cdi_device_get_edits(const struct cdi_cache_device *d);
|
||
|
|
|
||
|
|
#ifdef __cplusplus
|
||
|
|
}
|
||
|
|
diff --git a/src/daemon/modules/device/cdi/behavior/cdi_spec.c b/src/daemon/modules/device/cdi/behavior/cdi_spec.c
|
||
|
|
index f79b5a44..235b1863 100644
|
||
|
|
--- a/src/daemon/modules/device/cdi/behavior/cdi_spec.c
|
||
|
|
+++ b/src/daemon/modules/device/cdi/behavior/cdi_spec.c
|
||
|
|
@@ -14,47 +14,235 @@
|
||
|
|
******************************************************************************/
|
||
|
|
#include "cdi_spec.h"
|
||
|
|
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#include <isula_libutils/log.h>
|
||
|
|
+#include <isula_libutils/auto_cleanup.h>
|
||
|
|
+
|
||
|
|
+#include "utils.h"
|
||
|
|
+#include "utils_version.h"
|
||
|
|
+#include "error.h"
|
||
|
|
+#include "path.h"
|
||
|
|
+#include "cdi_version.h"
|
||
|
|
+#include "cdi_parser.h"
|
||
|
|
+#include "cdi_device.h"
|
||
|
|
+
|
||
|
|
+static int cdi_spec_init(struct cdi_cache_spec *s);
|
||
|
|
+
|
||
|
|
void free_cdi_cache_spec(struct cdi_cache_spec *s)
|
||
|
|
{
|
||
|
|
- (void)s;
|
||
|
|
+ if (s == NULL) {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ free_cdi_spec(s->raw_spec);
|
||
|
|
+ s->raw_spec = NULL;
|
||
|
|
+ free(s->vendor);
|
||
|
|
+ s->vendor = NULL;
|
||
|
|
+ free(s->class);
|
||
|
|
+ s->class = NULL;
|
||
|
|
+ free(s->path);
|
||
|
|
+ s->path = NULL;
|
||
|
|
+ map_free(s->devices);
|
||
|
|
+ s->devices = NULL;
|
||
|
|
+
|
||
|
|
+ free(s);
|
||
|
|
}
|
||
|
|
|
||
|
|
-struct cdi_cache_spec *cdi_spec_read_spec(const char *path, int priority, char **error)
|
||
|
|
+struct cdi_cache_spec *cdi_spec_read_spec(const char *path, int priority)
|
||
|
|
{
|
||
|
|
- return NULL;
|
||
|
|
+ cdi_spec *raw_spec = NULL;
|
||
|
|
+ __isula_auto_free parser_error err = NULL;
|
||
|
|
+ char cleanpath[PATH_MAX] = { 0 };
|
||
|
|
+
|
||
|
|
+ if (util_clean_path(path, cleanpath, sizeof(cleanpath)) == NULL) {
|
||
|
|
+ ERROR("Failed to get clean path %s", path);
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ raw_spec = cdi_spec_parse_file(cleanpath, NULL, &err);
|
||
|
|
+ if (raw_spec == NULL) {
|
||
|
|
+ ERROR("Failed to read CDI Spec %s: %s", cleanpath, err);
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ DEBUG("Read cdi spec %s", cleanpath);
|
||
|
|
+
|
||
|
|
+ return cdi_spec_new_spec(raw_spec, cleanpath, priority);
|
||
|
|
}
|
||
|
|
|
||
|
|
-struct cdi_cache_spec *cdi_spec_new_spec(cdi_spec *raw, const char *path, int priority, char **error)
|
||
|
|
+struct cdi_cache_spec *cdi_spec_new_spec(cdi_spec *raw, const char *path, int priority)
|
||
|
|
{
|
||
|
|
+ struct cdi_cache_spec *spec = NULL;
|
||
|
|
+ __isula_auto_free char *checked_path = NULL;
|
||
|
|
+
|
||
|
|
+ if (raw == NULL) {
|
||
|
|
+ ERROR("Invalid param");
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!util_has_suffix(path, ".json")) {
|
||
|
|
+ checked_path = util_string_append(path, CDI_DEFAULT_SPEC_EXT);
|
||
|
|
+ if (checked_path == NULL) {
|
||
|
|
+ ERROR("Failed to append %s to path %s", CDI_DEFAULT_SPEC_EXT, path);
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ } else {
|
||
|
|
+ checked_path = util_strdup_s(path);
|
||
|
|
+ }
|
||
|
|
+ spec = util_common_calloc_s(sizeof(*spec));
|
||
|
|
+ if (spec == NULL) {
|
||
|
|
+ ERROR("Out of memory");
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ spec->raw_spec = raw;
|
||
|
|
+ spec->path = checked_path;
|
||
|
|
+ checked_path = NULL;
|
||
|
|
+ spec->priority = priority;
|
||
|
|
+
|
||
|
|
+ if (cdi_parser_parse_qualifier(raw->kind, &spec->vendor, &spec->class) != 0) {
|
||
|
|
+ ERROR("Failed to parse kind %s", raw->kind);
|
||
|
|
+ goto error_out;
|
||
|
|
+ }
|
||
|
|
+ if (cdi_spec_init(spec) != 0) {
|
||
|
|
+ ERROR("Invalid CDI Spec");
|
||
|
|
+ goto error_out;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return spec;
|
||
|
|
+
|
||
|
|
+error_out:
|
||
|
|
+ free_cdi_cache_spec(spec);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
-const char *cdi_spec_get_vendor(struct cdi_cache_spec *s)
|
||
|
|
+const char *cdi_spec_get_vendor(const struct cdi_cache_spec *s)
|
||
|
|
{
|
||
|
|
- return NULL;
|
||
|
|
+ if (s == NULL) {
|
||
|
|
+ ERROR("Invalid params");
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ return s->vendor;
|
||
|
|
}
|
||
|
|
|
||
|
|
-const char *cdi_spec_get_class(struct cdi_cache_spec *s)
|
||
|
|
+const char *cdi_spec_get_class(const struct cdi_cache_spec *s)
|
||
|
|
{
|
||
|
|
- return NULL;
|
||
|
|
+ if (s == NULL) {
|
||
|
|
+ ERROR("Invalid params");
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ return s->class;
|
||
|
|
}
|
||
|
|
|
||
|
|
-struct cdi_cache_device *cdi_spec_get_cache_device(struct cdi_cache_spec *s, const char *name)
|
||
|
|
+struct cdi_cache_device *cdi_spec_get_cache_device(const struct cdi_cache_spec *s, const char *name)
|
||
|
|
{
|
||
|
|
- return NULL;
|
||
|
|
+ if (s == NULL) {
|
||
|
|
+ ERROR("Invalid params");
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ return map_search(s->devices, (void *)name);;
|
||
|
|
}
|
||
|
|
|
||
|
|
-const char *cdi_spec_get_path(struct cdi_cache_spec *s)
|
||
|
|
+const char *cdi_spec_get_path(const struct cdi_cache_spec *s)
|
||
|
|
{
|
||
|
|
- return NULL;
|
||
|
|
+ if (s == NULL) {
|
||
|
|
+ ERROR("Invalid params");
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ return s->path;
|
||
|
|
}
|
||
|
|
|
||
|
|
-int cdi_spec_get_priority(struct cdi_cache_spec *s)
|
||
|
|
+int cdi_spec_get_priority(const struct cdi_cache_spec *s)
|
||
|
|
{
|
||
|
|
- return 0;
|
||
|
|
+ if (s == NULL) {
|
||
|
|
+ ERROR("Invalid params");
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+ return s->priority;
|
||
|
|
}
|
||
|
|
|
||
|
|
-cdi_container_edits *cdi_spec_get_edits(struct cdi_cache_spec *s)
|
||
|
|
+cdi_container_edits *cdi_spec_get_edits(const struct cdi_cache_spec *s)
|
||
|
|
{
|
||
|
|
- return NULL;
|
||
|
|
+ if (s == NULL || s->raw_spec == NULL) {
|
||
|
|
+ ERROR("Invalid params");
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ return s->raw_spec->container_edits;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void map_cdi_cache_device_kvfree(void *key, void *value)
|
||
|
|
+{
|
||
|
|
+ free(key);
|
||
|
|
+ free_cdi_cache_device((struct cdi_cache_device *)value);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static int cdi_spec_init(struct cdi_cache_spec *s)
|
||
|
|
+{
|
||
|
|
+ const char *min_version = NULL;
|
||
|
|
+ __isula_auto_free char *spec_version = NULL;
|
||
|
|
+ cdi_container_edits *edits = NULL;
|
||
|
|
+ struct cdi_cache_device *dev = NULL;
|
||
|
|
+ cdi_device *d = NULL;
|
||
|
|
+ size_t i;
|
||
|
|
+ bool version_result = true;
|
||
|
|
+
|
||
|
|
+ if (!cdi_is_valid_version(s->raw_spec->cdi_version)) {
|
||
|
|
+ ERROR("Failed to validate cdi spec version: %s", s->raw_spec->cdi_version);
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ min_version = cdi_minimum_required_version(s->raw_spec);
|
||
|
|
+ if (min_version == NULL) {
|
||
|
|
+ ERROR("Could not determine minimum required version");
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+ if (util_version_greater_than(min_version, s->raw_spec->cdi_version, &version_result) != 0) {
|
||
|
|
+ ERROR("Failed to compare version %s and %s", min_version, s->raw_spec->cdi_version);
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+ if (version_result) {
|
||
|
|
+ ERROR("The spec version must be at least v%s", min_version);
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (cdi_parser_validate_vendor_name(s->vendor) != 0) {
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+ if (cdi_parser_validate_class_name(s->class) != 0) {
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // ignore validate annotations
|
||
|
|
+
|
||
|
|
+ edits = cdi_spec_get_edits(s);
|
||
|
|
+ if (cdi_container_edits_validate(edits) != 0) {
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ s->devices = map_new(MAP_STR_PTR, MAP_DEFAULT_CMP_FUNC, map_cdi_cache_device_kvfree);
|
||
|
|
+ if (s->devices == NULL) {
|
||
|
|
+ ERROR("Out of memory");
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+ for (i = 0; i < s->raw_spec->devices_len; i++) {
|
||
|
|
+ d = s->raw_spec->devices[i];
|
||
|
|
+ dev = cdi_device_new_device(s, d);
|
||
|
|
+ if (dev == NULL) {
|
||
|
|
+ ERROR("Could not determine minimum required version");
|
||
|
|
+ goto error_out;
|
||
|
|
+ }
|
||
|
|
+ if (map_search(s->devices, (void *)d->name) != NULL) {
|
||
|
|
+ ERROR("Invalid spec, multiple device %s", d->name);
|
||
|
|
+ goto error_out;
|
||
|
|
+ }
|
||
|
|
+ if (!map_insert(s->devices, (void *)d->name, dev)) {
|
||
|
|
+ ERROR("Failed to insert device %s", d->name);
|
||
|
|
+ goto error_out;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+error_out:
|
||
|
|
+ map_free(s->devices);
|
||
|
|
+ s->devices = NULL;
|
||
|
|
+ return -1;
|
||
|
|
}
|
||
|
|
diff --git a/src/daemon/modules/device/cdi/behavior/cdi_spec.h b/src/daemon/modules/device/cdi/behavior/cdi_spec.h
|
||
|
|
index 87248041..ca7b2cfa 100644
|
||
|
|
--- a/src/daemon/modules/device/cdi/behavior/cdi_spec.h
|
||
|
|
+++ b/src/daemon/modules/device/cdi/behavior/cdi_spec.h
|
||
|
|
@@ -40,14 +40,14 @@ struct cdi_cache_spec {
|
||
|
|
|
||
|
|
void free_cdi_cache_spec(struct cdi_cache_spec *s);
|
||
|
|
|
||
|
|
-struct cdi_cache_spec *cdi_spec_read_spec(const char *path, int priority, char **error);
|
||
|
|
-struct cdi_cache_spec *cdi_spec_new_spec(cdi_spec *raw, const char *path, int priority, char **error);
|
||
|
|
-const char *cdi_spec_get_vendor(struct cdi_cache_spec *s);
|
||
|
|
-const char *cdi_spec_get_class(struct cdi_cache_spec *s);
|
||
|
|
-struct cdi_cache_device *cdi_spec_get_cache_device(struct cdi_cache_spec *s, const char *name);
|
||
|
|
-const char *cdi_spec_get_path(struct cdi_cache_spec *s);
|
||
|
|
-int cdi_spec_get_priority(struct cdi_cache_spec *s);
|
||
|
|
-cdi_container_edits *cdi_spec_get_edits(struct cdi_cache_spec *s);
|
||
|
|
+struct cdi_cache_spec *cdi_spec_read_spec(const char *path, int priority);
|
||
|
|
+struct cdi_cache_spec *cdi_spec_new_spec(cdi_spec *raw, const char *path, int priority);
|
||
|
|
+const char *cdi_spec_get_vendor(const struct cdi_cache_spec *s);
|
||
|
|
+const char *cdi_spec_get_class(const struct cdi_cache_spec *s);
|
||
|
|
+struct cdi_cache_device *cdi_spec_get_cache_device(const struct cdi_cache_spec *s, const char *name);
|
||
|
|
+const char *cdi_spec_get_path(const struct cdi_cache_spec *s);
|
||
|
|
+int cdi_spec_get_priority(const struct cdi_cache_spec *s);
|
||
|
|
+cdi_container_edits *cdi_spec_get_edits(const struct cdi_cache_spec *s);
|
||
|
|
|
||
|
|
#ifdef __cplusplus
|
||
|
|
}
|
||
|
|
diff --git a/src/daemon/modules/device/cdi/behavior/cdi_spec_dirs.c b/src/daemon/modules/device/cdi/behavior/cdi_spec_dirs.c
|
||
|
|
index e340abc0..cafb52b8 100644
|
||
|
|
--- a/src/daemon/modules/device/cdi/behavior/cdi_spec_dirs.c
|
||
|
|
+++ b/src/daemon/modules/device/cdi/behavior/cdi_spec_dirs.c
|
||
|
|
@@ -14,6 +14,17 @@
|
||
|
|
******************************************************************************/
|
||
|
|
#include "cdi_spec_dirs.h"
|
||
|
|
|
||
|
|
+#include <sys/stat.h>
|
||
|
|
+#include <isula_libutils/log.h>
|
||
|
|
+#include <isula_libutils/auto_cleanup.h>
|
||
|
|
+
|
||
|
|
+#include "utils.h"
|
||
|
|
+#include "path.h"
|
||
|
|
+#include "error.h"
|
||
|
|
+#include "utils_file.h"
|
||
|
|
+#include "utils_array.h"
|
||
|
|
+#include "cdi_spec.h"
|
||
|
|
+
|
||
|
|
#define DEFAULT_SPEC_DIRS_LEN 2
|
||
|
|
static char *default_spec_dirs_items[DEFAULT_SPEC_DIRS_LEN] = {CDI_DEFAULT_STATIC_DIR, CDI_DEFAULT_DYNAMIC_DIR};
|
||
|
|
|
||
|
|
@@ -23,7 +34,76 @@ string_array g_default_spec_dirs = {
|
||
|
|
.cap = DEFAULT_SPEC_DIRS_LEN,
|
||
|
|
};
|
||
|
|
|
||
|
|
+struct scan_spec_dir_cb_args {
|
||
|
|
+ struct cdi_scan_fn_maps *scan_fn_maps;
|
||
|
|
+ cdi_scan_spec_func scan_fn;
|
||
|
|
+ int priority;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+static bool scan_spec_dir_cb(const char *dir, const struct dirent *pdirent, void *context)
|
||
|
|
+{
|
||
|
|
+ struct scan_spec_dir_cb_args *args = (struct scan_spec_dir_cb_args *)context;
|
||
|
|
+ struct cdi_scan_fn_maps *scan_fn_maps = args->scan_fn_maps;
|
||
|
|
+ cdi_scan_spec_func scan_fn = args->scan_fn;
|
||
|
|
+ int priority = args->priority;
|
||
|
|
+ struct stat st = { 0 };
|
||
|
|
+ __isula_auto_free char *file_path = NULL;
|
||
|
|
+ struct cdi_cache_spec *cache_spec = NULL;
|
||
|
|
+
|
||
|
|
+ file_path = util_path_join(dir, pdirent->d_name);
|
||
|
|
+ if (file_path == NULL) {
|
||
|
|
+ ERROR("Failed to get path %s/%s", dir, pdirent->d_name);
|
||
|
|
+ goto error_out;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (lstat(file_path, &st) != 0) {
|
||
|
|
+ ERROR("Failed to lstat %s", file_path);
|
||
|
|
+ goto error_out;
|
||
|
|
+ }
|
||
|
|
+ if (S_ISDIR(st.st_mode)) {
|
||
|
|
+ DEBUG("Skip dir %s", file_path);
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!util_has_suffix(file_path, ".json")) {
|
||
|
|
+ DEBUG("Skip file %s", file_path);
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ cache_spec = cdi_spec_read_spec(file_path, priority);
|
||
|
|
+ if (cache_spec == NULL) {
|
||
|
|
+ ERROR("Failed to read spec %s", file_path);
|
||
|
|
+ goto error_out;
|
||
|
|
+ }
|
||
|
|
+ scan_fn(scan_fn_maps, file_path, priority, cache_spec);
|
||
|
|
+ return true;
|
||
|
|
+
|
||
|
|
+error_out:
|
||
|
|
+ *(scan_fn_maps->refresh_error_flag) = true;
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
int cdi_scan_spec_dirs(string_array *dirs, struct cdi_scan_fn_maps *scan_fn_maps, cdi_scan_spec_func scan_fn)
|
||
|
|
{
|
||
|
|
+ size_t i;
|
||
|
|
+ int nret = 0;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < dirs->len; i++) {
|
||
|
|
+ struct scan_spec_dir_cb_args args = {
|
||
|
|
+ .scan_fn_maps = scan_fn_maps,
|
||
|
|
+ .scan_fn = scan_fn,
|
||
|
|
+ .priority = i,
|
||
|
|
+ };
|
||
|
|
+ if (!util_dir_exists(dirs->items[i])) {
|
||
|
|
+ WARN("Cdi dir %s not exists", dirs->items[i]);
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ nret = util_scan_subdirs(dirs->items[i], scan_spec_dir_cb, &args);
|
||
|
|
+ if (nret != 0) {
|
||
|
|
+ ERROR("Failed to scan dir %s", dirs->items[i]);
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
diff --git a/src/daemon/modules/device/cdi/behavior/cdi_spec_dirs.h b/src/daemon/modules/device/cdi/behavior/cdi_spec_dirs.h
|
||
|
|
index eedcabad..b17a0cd8 100644
|
||
|
|
--- a/src/daemon/modules/device/cdi/behavior/cdi_spec_dirs.h
|
||
|
|
+++ b/src/daemon/modules/device/cdi/behavior/cdi_spec_dirs.h
|
||
|
|
@@ -35,7 +35,7 @@ struct cdi_scan_fn_maps {
|
||
|
|
bool *refresh_error_flag;
|
||
|
|
};
|
||
|
|
typedef void(*cdi_scan_spec_func)(struct cdi_scan_fn_maps *scan_fn_maps, const char *path, int priority,
|
||
|
|
- struct cdi_cache_spec *spec, char *error);
|
||
|
|
+ struct cdi_cache_spec *spec);
|
||
|
|
|
||
|
|
int cdi_scan_spec_dirs(string_array *dirs, struct cdi_scan_fn_maps *scan_fn_maps, cdi_scan_spec_func scan_fn);
|
||
|
|
|
||
|
|
diff --git a/src/daemon/modules/device/cdi/behavior/cdi_version.c b/src/daemon/modules/device/cdi/behavior/cdi_version.c
|
||
|
|
index 3e87c111..882a965e 100644
|
||
|
|
--- a/src/daemon/modules/device/cdi/behavior/cdi_version.c
|
||
|
|
+++ b/src/daemon/modules/device/cdi/behavior/cdi_version.c
|
||
|
|
@@ -14,27 +14,174 @@
|
||
|
|
******************************************************************************/
|
||
|
|
#include "cdi_version.h"
|
||
|
|
|
||
|
|
-#define CDI_V_CURRENT_VERSION "v"##CDI_CURRENT_VERSION
|
||
|
|
-
|
||
|
|
-#define CDI_V010 "v0.1.0"
|
||
|
|
-#define CDI_V020 "v0.2.0"
|
||
|
|
-#define CDI_V030 "v0.3.0"
|
||
|
|
-#define CDI_V040 "v0.4.0"
|
||
|
|
-#define CDI_V050 "v0.5.0"
|
||
|
|
-#define CDI_V060 "v0.6.0"
|
||
|
|
+#include <ctype.h>
|
||
|
|
+#include <isula_libutils/log.h>
|
||
|
|
+#include <isula_libutils/auto_cleanup.h>
|
||
|
|
+
|
||
|
|
+#include "error.h"
|
||
|
|
+#include "utils_version.h"
|
||
|
|
+#include "utils_string.h"
|
||
|
|
+#include "cdi_container_edits.h"
|
||
|
|
+#include "cdi_parser.h"
|
||
|
|
+
|
||
|
|
+#define CDI_V010 "0.1.0"
|
||
|
|
+#define CDI_V020 "0.2.0"
|
||
|
|
+#define CDI_V030 "0.3.0"
|
||
|
|
+#define CDI_V040 "0.4.0"
|
||
|
|
+#define CDI_V050 "0.5.0"
|
||
|
|
+#define CDI_V060 "0.6.0"
|
||
|
|
#define CDI_V_EARLIEST CDI_V030
|
||
|
|
|
||
|
|
-const char *cdi_minimum_required_version(cdi_spec *spec)
|
||
|
|
+typedef bool (*required_version_cb)(cdi_spec *spec);
|
||
|
|
+
|
||
|
|
+struct required_version_map {
|
||
|
|
+ char *version;
|
||
|
|
+ required_version_cb cb;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+static bool requires_v060(cdi_spec *spec)
|
||
|
|
+{
|
||
|
|
+ size_t i;
|
||
|
|
+ int ret = 0;
|
||
|
|
+ __isula_auto_free char *vendor = NULL;
|
||
|
|
+ __isula_auto_free char *class = NULL;
|
||
|
|
+
|
||
|
|
+ // The 0.6.0 spec allows annotations to be specified at a spec level
|
||
|
|
+ if (spec->annotations != NULL) {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // The 0.6.0 spec allows annotations to be specified at a device level
|
||
|
|
+ if (spec->devices != NULL) {
|
||
|
|
+ for (i = 0; i < spec->devices_len; i++) {
|
||
|
|
+ if (spec->devices[i]->annotations != NULL) {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // The 0.6.0 spec allows dots "." in Kind name label (class)
|
||
|
|
+ ret = cdi_parser_parse_qualifier(spec->kind, &vendor, &class);
|
||
|
|
+ if (ret == 0 && vendor != NULL) {
|
||
|
|
+ if (util_strings_count(class, '.') > 0) {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return false;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static bool check_host_path(cdi_container_edits *e)
|
||
|
|
{
|
||
|
|
- return NULL;
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ if (e == NULL) {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+ for (i = 0; i < e->device_nodes_len; i++) {
|
||
|
|
+ // The HostPath field was added in 0.5.0
|
||
|
|
+ if (e->device_nodes[i]->host_path != NULL) {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
-bool cdi_is_greater_than_version(const char *v, const char *o)
|
||
|
|
+static bool requires_v050(cdi_spec *spec)
|
||
|
|
{
|
||
|
|
- return true;
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < spec->devices_len; i++) {
|
||
|
|
+ // The 0.5.0 spec allowed device names to start with a digit instead of requiring a letter
|
||
|
|
+ if (spec->devices[i]->name != NULL && strlen(spec->devices[i]->name) > 0 &&
|
||
|
|
+ !isalpha(spec->devices[i]->name[0])) {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+ if (check_host_path(spec->devices[i]->container_edits)) {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return check_host_path(spec->container_edits);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static bool check_mount_type(cdi_container_edits *e)
|
||
|
|
+{
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ if (e == NULL) {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+ for (i = 0; i < e->mounts_len; i++) {
|
||
|
|
+ // The Type field was added in 0.4.0
|
||
|
|
+ if (e->mounts[i]->type != NULL) {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return false;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static bool requires_v040(cdi_spec *spec)
|
||
|
|
+{
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < spec->devices_len; i++) {
|
||
|
|
+ if (check_mount_type(spec->devices[i]->container_edits)) {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return check_mount_type(spec->container_edits);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+#define VALID_SPEC_VERSIONS_LEN 6
|
||
|
|
+static struct required_version_map g_valid_spec_versions[VALID_SPEC_VERSIONS_LEN] = {
|
||
|
|
+ {CDI_V010, NULL},
|
||
|
|
+ {CDI_V020, NULL},
|
||
|
|
+ {CDI_V030, NULL},
|
||
|
|
+ {CDI_V040, requires_v060},
|
||
|
|
+ {CDI_V050, requires_v050},
|
||
|
|
+ {CDI_V060, requires_v040}
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+const char *cdi_minimum_required_version(cdi_spec *spec)
|
||
|
|
+{
|
||
|
|
+ const char *min_version = CDI_V_EARLIEST;
|
||
|
|
+ int i;
|
||
|
|
+ bool result = true;
|
||
|
|
+
|
||
|
|
+ if (spec == NULL) {
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < VALID_SPEC_VERSIONS_LEN; i++) {
|
||
|
|
+ if (g_valid_spec_versions[i].cb == NULL) {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ if (g_valid_spec_versions[i].cb(spec)) {
|
||
|
|
+ if (util_version_greater_than(g_valid_spec_versions[i].version, min_version, &result) != 0) {
|
||
|
|
+ ERROR("Failed to compare version %s and %s", g_valid_spec_versions[i].version, min_version);
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ if (result) {
|
||
|
|
+ min_version = g_valid_spec_versions[i].version;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ if (strcmp(min_version, CDI_CURRENT_VERSION)) {
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return min_version;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool cdi_is_valid_version(const char *spec_version)
|
||
|
|
{
|
||
|
|
- return true;
|
||
|
|
+ int i;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < VALID_SPEC_VERSIONS_LEN; i++) {
|
||
|
|
+ if (strcmp(g_valid_spec_versions[i].version, spec_version) == 0) {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return false;
|
||
|
|
}
|
||
|
|
diff --git a/src/daemon/modules/device/cdi/behavior/cdi_version.h b/src/daemon/modules/device/cdi/behavior/cdi_version.h
|
||
|
|
index 99b7e692..6bd86340 100644
|
||
|
|
--- a/src/daemon/modules/device/cdi/behavior/cdi_version.h
|
||
|
|
+++ b/src/daemon/modules/device/cdi/behavior/cdi_version.h
|
||
|
|
@@ -24,7 +24,6 @@ extern "C" {
|
||
|
|
#define CDI_CURRENT_VERSION "0.6.0"
|
||
|
|
|
||
|
|
const char *cdi_minimum_required_version(cdi_spec *spec);
|
||
|
|
-bool cdi_is_greater_than_version(const char *v, const char *o);
|
||
|
|
bool cdi_is_valid_version(const char *spec_version);
|
||
|
|
|
||
|
|
#ifdef __cplusplus
|
||
|
|
diff --git a/src/daemon/modules/device/cdi/cdi_cache.c b/src/daemon/modules/device/cdi/cdi_cache.c
|
||
|
|
index 37767855..e637f7cd 100644
|
||
|
|
--- a/src/daemon/modules/device/cdi/cdi_cache.c
|
||
|
|
+++ b/src/daemon/modules/device/cdi/cdi_cache.c
|
||
|
|
@@ -206,13 +206,12 @@ static void map_cdi_cache_specs_kvfree(void *key, void *value)
|
||
|
|
static void map_cdi_cache_device_kvfree(void *key, void *value)
|
||
|
|
{
|
||
|
|
free(key);
|
||
|
|
- free_cdi_cache_device((struct cdi_cache_device *)value);
|
||
|
|
-}
|
||
|
|
-
|
||
|
|
-static void set_refresh_error_flag(bool *refresh_error_flag, const char *error, const char *path)
|
||
|
|
-{
|
||
|
|
- *refresh_error_flag = true;
|
||
|
|
- ERROR("Cdi refresh error: %s, spec %s", error, path);
|
||
|
|
+ /*
|
||
|
|
+ * map_cdi_cache_device_kvfree should not be recursively free cdi_cache_device.
|
||
|
|
+ * Otherwise, the function conflicts with the cdi_cache_specs free devices,
|
||
|
|
+ * triggering double free.
|
||
|
|
+ */
|
||
|
|
+ (void)value;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool resolve_conflict(struct cdi_scan_fn_maps *scan_fn_maps, const char *name,
|
||
|
|
@@ -220,8 +219,8 @@ static bool resolve_conflict(struct cdi_scan_fn_maps *scan_fn_maps, const char *
|
||
|
|
{
|
||
|
|
map_t *conflicts = scan_fn_maps->conflicts;
|
||
|
|
bool *refresh_error_flag = scan_fn_maps->refresh_error_flag;
|
||
|
|
- struct cdi_cache_spec *dev_spec = NULL;
|
||
|
|
- struct cdi_cache_spec *old_spec = NULL;
|
||
|
|
+ const struct cdi_cache_spec *dev_spec = NULL;
|
||
|
|
+ const struct cdi_cache_spec *old_spec = NULL;
|
||
|
|
int dev_prio;
|
||
|
|
int old_prio;
|
||
|
|
bool val = true;
|
||
|
|
@@ -251,7 +250,7 @@ static bool resolve_conflict(struct cdi_scan_fn_maps *scan_fn_maps, const char *
|
||
|
|
}
|
||
|
|
|
||
|
|
static void refresh_scan_spec_func(struct cdi_scan_fn_maps *scan_fn_maps, const char *path,
|
||
|
|
- int priority, struct cdi_cache_spec *spec, char *error)
|
||
|
|
+ int priority, struct cdi_cache_spec *spec)
|
||
|
|
{
|
||
|
|
map_t *specs = scan_fn_maps->specs;
|
||
|
|
map_t *devices = scan_fn_maps->devices;
|
||
|
|
@@ -267,12 +266,6 @@ static void refresh_scan_spec_func(struct cdi_scan_fn_maps *scan_fn_maps, const
|
||
|
|
|
||
|
|
if (util_clean_path(path, clean_path, sizeof(clean_path)) == NULL) {
|
||
|
|
ERROR("Failed to get clean path %s", path);
|
||
|
|
- format_errorf(&tmp_error, "Failed to get clean path %s", path);
|
||
|
|
- return;
|
||
|
|
- }
|
||
|
|
- if (error != NULL) {
|
||
|
|
- ERROR("Failed to load CDI Spec %s", error);
|
||
|
|
- format_errorf(&tmp_error, "Failed to load CDI Spec %s", error);
|
||
|
|
goto error_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -282,18 +275,15 @@ static void refresh_scan_spec_func(struct cdi_scan_fn_maps *scan_fn_maps, const
|
||
|
|
spec_array = util_common_array_new(1, (free_common_array_item_cb)free_cdi_cache_spec, util_clone_ptr);
|
||
|
|
if (spec_array == NULL) {
|
||
|
|
ERROR("Out of memory");
|
||
|
|
- tmp_error = util_strdup_s("Out of memory");
|
||
|
|
goto error_out;
|
||
|
|
}
|
||
|
|
if (!map_insert(specs, (void *)vendor, spec_array)) {
|
||
|
|
ERROR("Failed to insert spec array to specs");
|
||
|
|
- tmp_error = util_strdup_s("Failed to insert spec array to specs");
|
||
|
|
goto error_out;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (util_append_common_array(spec_array, spec) != 0) {
|
||
|
|
ERROR("Failed to append spec");
|
||
|
|
- tmp_error = util_strdup_s("Failed to append spec");
|
||
|
|
goto error_out;
|
||
|
|
}
|
||
|
|
spec_array = NULL;
|
||
|
|
@@ -301,7 +291,6 @@ static void refresh_scan_spec_func(struct cdi_scan_fn_maps *scan_fn_maps, const
|
||
|
|
itor = map_itor_new(spec->devices);
|
||
|
|
if (itor == NULL) {
|
||
|
|
ERROR("Out of memory, create new map itor failed");
|
||
|
|
- tmp_error = util_strdup_s("Out of memory, create new map itor failed");
|
||
|
|
goto error_out;
|
||
|
|
}
|
||
|
|
for (; map_itor_valid(itor); map_itor_next(itor)) {
|
||
|
|
@@ -315,7 +304,6 @@ static void refresh_scan_spec_func(struct cdi_scan_fn_maps *scan_fn_maps, const
|
||
|
|
}
|
||
|
|
if (!map_replace(devices, (void *)qualified, dev)) {
|
||
|
|
ERROR("Failed to insert device to devices by name %s", qualified);
|
||
|
|
- format_errorf(&tmp_error, "Failed to insert device to devices by name %s", qualified);
|
||
|
|
goto error_out;
|
||
|
|
}
|
||
|
|
free(qualified);
|
||
|
|
@@ -324,7 +312,7 @@ static void refresh_scan_spec_func(struct cdi_scan_fn_maps *scan_fn_maps, const
|
||
|
|
goto out;
|
||
|
|
|
||
|
|
error_out:
|
||
|
|
- set_refresh_error_flag(refresh_error_flag, tmp_error, path);
|
||
|
|
+ *refresh_error_flag = true;
|
||
|
|
out:
|
||
|
|
map_itor_free(itor);
|
||
|
|
return;
|
||
|
|
@@ -333,7 +321,6 @@ out:
|
||
|
|
static int refresh(struct cdi_cache *c)
|
||
|
|
{
|
||
|
|
int ret = 0;
|
||
|
|
- __isula_auto_free char *error = NULL;
|
||
|
|
map_t *specs = NULL;
|
||
|
|
map_t *devices = NULL;
|
||
|
|
map_t *conflicts = NULL;
|
||
|
|
@@ -559,8 +546,6 @@ error_out:
|
||
|
|
|
||
|
|
static void watch_setup(struct cdi_watch *w, string_array *dirs)
|
||
|
|
{
|
||
|
|
- __isula_auto_free char *error = NULL;
|
||
|
|
-
|
||
|
|
if (w == NULL || dirs == NULL || dirs->len == 0) {
|
||
|
|
ERROR("Invalid param");
|
||
|
|
return;
|
||
|
|
@@ -735,7 +720,6 @@ static void update_add_watch_dir(struct cdi_watch *w, const char *dir, bool *upd
|
||
|
|
{
|
||
|
|
int wd = -1;
|
||
|
|
bool tmp_value = true;
|
||
|
|
- __isula_auto_free char *error = NULL;
|
||
|
|
|
||
|
|
wd = inotify_add_watch(w->watcher_fd, dir, CDI_WATCH_EVENTS);
|
||
|
|
if (wd < 0) {
|
||
|
|
@@ -770,7 +754,6 @@ static bool watch_update(struct cdi_watch *w, const char *removed, int wd)
|
||
|
|
bool *ok = NULL;
|
||
|
|
bool update = false;
|
||
|
|
map_itor *itor = NULL;
|
||
|
|
- __isula_auto_free char *error = NULL;
|
||
|
|
|
||
|
|
itor = map_itor_new(w->tracked);
|
||
|
|
if (itor == NULL) {
|
||
|
|
diff --git a/src/daemon/modules/device/cdi/cdi_cache.h b/src/daemon/modules/device/cdi/cdi_cache.h
|
||
|
|
index da315de2..638e954e 100644
|
||
|
|
--- a/src/daemon/modules/device/cdi/cdi_cache.h
|
||
|
|
+++ b/src/daemon/modules/device/cdi/cdi_cache.h
|
||
|
|
@@ -52,6 +52,7 @@ struct cdi_cache {
|
||
|
|
pthread_mutex_t mutex;
|
||
|
|
string_array *spec_dirs; // cdi-spec-dirs will scan for CDI Spec files
|
||
|
|
map_t *specs; // MAP_STR_PTR specs[vendor] = common_array of cdi_cache_spec*
|
||
|
|
+ // This map holding the reference to cdi device, the devices will not released when the map is freed.
|
||
|
|
map_t *devices; // MAP_STR_PTR devices[cdi_device.name] = cdi_cache_device*
|
||
|
|
bool refresh_error_flag;
|
||
|
|
bool auto_refresh;
|
||
|
|
diff --git a/src/daemon/modules/network/cni_operator/libcni/libcni_api.c b/src/daemon/modules/network/cni_operator/libcni/libcni_api.c
|
||
|
|
index 068881be..7ba983af 100644
|
||
|
|
--- a/src/daemon/modules/network/cni_operator/libcni/libcni_api.c
|
||
|
|
+++ b/src/daemon/modules/network/cni_operator/libcni/libcni_api.c
|
||
|
|
@@ -28,6 +28,7 @@
|
||
|
|
#include <isula_libutils/auto_cleanup.h>
|
||
|
|
|
||
|
|
#include "utils.h"
|
||
|
|
+#include "utils_version.h"
|
||
|
|
#include "utils_network.h"
|
||
|
|
#include "libcni_cached.h"
|
||
|
|
#include "libcni_conf.h"
|
||
|
|
@@ -544,97 +545,6 @@ free_out:
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
-struct parse_version {
|
||
|
|
- int major;
|
||
|
|
- int minor;
|
||
|
|
- int micro;
|
||
|
|
-};
|
||
|
|
-
|
||
|
|
-static bool do_parse_version(const char **splits, size_t splits_len, struct parse_version *ret)
|
||
|
|
-{
|
||
|
|
- if (util_safe_int(splits[0], &ret->major) != 0) {
|
||
|
|
- ERROR("failed to convert major version part: %s", splits[0]);
|
||
|
|
- return false;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- if (splits_len >= 2 && util_safe_int(splits[1], &ret->minor) != 0) {
|
||
|
|
- ERROR("failed to convert minor version part: %s", splits[1]);
|
||
|
|
- return false;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- if (splits_len >= 3 && util_safe_int(splits[2], &ret->micro) != 0) {
|
||
|
|
- ERROR("failed to convert micro version part: %s", splits[2]);
|
||
|
|
- return false;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- return true;
|
||
|
|
-}
|
||
|
|
-
|
||
|
|
-static bool parse_version_from_str(const char *src_version, struct parse_version *result)
|
||
|
|
-{
|
||
|
|
- char **splits = NULL;
|
||
|
|
- const size_t max_len = 4;
|
||
|
|
- size_t tlen = 0;
|
||
|
|
- bool ret = false;
|
||
|
|
-
|
||
|
|
- splits = util_string_split(src_version, '.');
|
||
|
|
- if (splits == NULL) {
|
||
|
|
- ERROR("Split version: \"%s\" failed", src_version);
|
||
|
|
- return false;
|
||
|
|
- }
|
||
|
|
- tlen = util_array_len((const char **)splits);
|
||
|
|
- if (tlen < 1 || tlen >= max_len) {
|
||
|
|
- ERROR("Invalid version: \"%s\"", src_version);
|
||
|
|
- goto out;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- ret = do_parse_version((const char **)splits, tlen, result);
|
||
|
|
-
|
||
|
|
-out:
|
||
|
|
- util_free_array(splits);
|
||
|
|
- return ret;
|
||
|
|
-}
|
||
|
|
-
|
||
|
|
-static bool do_compare_version(const struct parse_version *p_first, const struct parse_version *p_second)
|
||
|
|
-{
|
||
|
|
- bool ret = false;
|
||
|
|
-
|
||
|
|
- if (p_first->major > p_second->major) {
|
||
|
|
- ret = true;
|
||
|
|
- } else if (p_first->major == p_second->major) {
|
||
|
|
- if (p_first->minor > p_second->minor) {
|
||
|
|
- ret = true;
|
||
|
|
- } else if (p_first->minor == p_second->minor && p_first->micro >= p_second->micro) {
|
||
|
|
- ret = true;
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- return ret;
|
||
|
|
-}
|
||
|
|
-
|
||
|
|
-static int version_greater_than_or_equal_to(const char *first, const char *second, bool *result)
|
||
|
|
-{
|
||
|
|
- struct parse_version first_parsed = { 0 };
|
||
|
|
- struct parse_version second_parsed = { 0 };
|
||
|
|
-
|
||
|
|
- if (result == NULL) {
|
||
|
|
- ERROR("Invalid argument");
|
||
|
|
- return -1;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- if (!parse_version_from_str(first, &first_parsed)) {
|
||
|
|
- return -1;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- if (!parse_version_from_str(second, &second_parsed)) {
|
||
|
|
- return -1;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- *result = do_compare_version(&first_parsed, &second_parsed);
|
||
|
|
-
|
||
|
|
- return 0;
|
||
|
|
-}
|
||
|
|
-
|
||
|
|
static inline bool check_add_network_args(const cni_net_conf *net, const struct runtime_conf *rc)
|
||
|
|
{
|
||
|
|
return (net == NULL || rc == NULL);
|
||
|
|
@@ -690,7 +600,7 @@ int cni_add_network_list(const struct cni_network_list_conf *list, const struct
|
||
|
|
}
|
||
|
|
|
||
|
|
if (*pret != NULL &&
|
||
|
|
- version_greater_than_or_equal_to((*pret)->cniversion, SUPPORT_CACHE_AND_CHECK_VERSION, &greater) != 0) {
|
||
|
|
+ util_version_greater_than_or_equal_to((*pret)->cniversion, SUPPORT_CACHE_AND_CHECK_VERSION, &greater) != 0) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -741,7 +651,7 @@ int cni_del_network_list(const struct cni_network_list_conf *list, const struct
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
- if (version_greater_than_or_equal_to(list->list->cni_version, SUPPORT_CACHE_AND_CHECK_VERSION, &greater) != 0) {
|
||
|
|
+ if (util_version_greater_than_or_equal_to(list->list->cni_version, SUPPORT_CACHE_AND_CHECK_VERSION, &greater) != 0) {
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -807,7 +717,7 @@ int cni_check_network_list(const struct cni_network_list_conf *list, const struc
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
- if (version_greater_than_or_equal_to(list->list->cni_version, SUPPORT_CACHE_AND_CHECK_VERSION, &greater) != 0) {
|
||
|
|
+ if (util_version_greater_than_or_equal_to(list->list->cni_version, SUPPORT_CACHE_AND_CHECK_VERSION, &greater) != 0) {
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
diff --git a/src/utils/cutils/utils_version.c b/src/utils/cutils/utils_version.c
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000..9dea5b09
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/src/utils/cutils/utils_version.c
|
||
|
|
@@ -0,0 +1,147 @@
|
||
|
|
+/******************************************************************************
|
||
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2022. All rights reserved.
|
||
|
|
+ * iSulad licensed under the Mulan PSL v2.
|
||
|
|
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||
|
|
+ * You may obtain a copy of Mulan PSL v2 at:
|
||
|
|
+ * http://license.coscl.org.cn/MulanPSL2
|
||
|
|
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
||
|
|
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
||
|
|
+ * PURPOSE.
|
||
|
|
+ * See the Mulan PSL v2 for more details.
|
||
|
|
+ * Author: liuxu
|
||
|
|
+ * Create: 2024-4-7
|
||
|
|
+ * Description: provide version functions
|
||
|
|
+ ********************************************************************************/
|
||
|
|
+
|
||
|
|
+#define _GNU_SOURCE
|
||
|
|
+#include "utils_version.h"
|
||
|
|
+
|
||
|
|
+#include <isula_libutils/log.h>
|
||
|
|
+
|
||
|
|
+#include "utils.h"
|
||
|
|
+#include "utils_string.h"
|
||
|
|
+
|
||
|
|
+struct parse_version {
|
||
|
|
+ int major;
|
||
|
|
+ int minor;
|
||
|
|
+ int micro;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+static bool do_parse_version(const char **splits, size_t splits_len, struct parse_version *ret)
|
||
|
|
+{
|
||
|
|
+ if (util_safe_int(splits[0], &ret->major) != 0) {
|
||
|
|
+ ERROR("Failed to convert major version part: %s", splits[0]);
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (splits_len >= 2 && util_safe_int(splits[1], &ret->minor) != 0) {
|
||
|
|
+ ERROR("Failed to convert minor version part: %s", splits[1]);
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (splits_len >= 3 && util_safe_int(splits[2], &ret->micro) != 0) {
|
||
|
|
+ ERROR("Failed to convert micro version part: %s", splits[2]);
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static bool parse_version_from_str(const char *src_version, struct parse_version *result)
|
||
|
|
+{
|
||
|
|
+ __isula_auto_array_t char **splits = NULL;
|
||
|
|
+ const size_t max_len = 4;
|
||
|
|
+ size_t tlen = 0;
|
||
|
|
+ bool ret = false;
|
||
|
|
+
|
||
|
|
+ splits = util_string_split(src_version, '.');
|
||
|
|
+ if (splits == NULL) {
|
||
|
|
+ ERROR("Split version: \"%s\" failed", src_version);
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+ tlen = util_array_len((const char **)splits);
|
||
|
|
+ if (tlen < 1 || tlen >= max_len) {
|
||
|
|
+ ERROR("Invalid version: \"%s\"", src_version);
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ret = do_parse_version((const char **)splits, tlen, result);
|
||
|
|
+
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static int do_compare_version(const struct parse_version *p_first, const struct parse_version *p_second)
|
||
|
|
+{
|
||
|
|
+ if (p_first->major != p_second->major) {
|
||
|
|
+ return p_first->major - p_second->major;
|
||
|
|
+ }
|
||
|
|
+ if (p_first->minor != p_second->minor) {
|
||
|
|
+ return p_first->minor - p_second->minor;
|
||
|
|
+ }
|
||
|
|
+ if (p_first->micro != p_second->micro) {
|
||
|
|
+ return p_first->micro - p_second->micro;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int util_version_compare(const char *first, const char *second, int *diff_value)
|
||
|
|
+{
|
||
|
|
+ struct parse_version first_parsed = { 0 };
|
||
|
|
+ struct parse_version second_parsed = { 0 };
|
||
|
|
+
|
||
|
|
+ if (first == NULL || second == NULL || diff_value == NULL) {
|
||
|
|
+ ERROR("Invalid argument");
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!parse_version_from_str(first, &first_parsed)) {
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!parse_version_from_str(second, &second_parsed)) {
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ *diff_value = do_compare_version(&first_parsed, &second_parsed);
|
||
|
|
+
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int util_version_greater_than(const char *first, const char *second, bool *result)
|
||
|
|
+{
|
||
|
|
+ int ret;
|
||
|
|
+ int diff_value = 0;
|
||
|
|
+
|
||
|
|
+ if (result == NULL) {
|
||
|
|
+ ERROR("Invalid argument");
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ret = util_version_compare(first, second, &diff_value);
|
||
|
|
+ if (ret != 0) {
|
||
|
|
+ return ret;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ *result = (diff_value > 0);
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int util_version_greater_than_or_equal_to(const char *first, const char *second, bool *result)
|
||
|
|
+{
|
||
|
|
+ int ret;
|
||
|
|
+ int diff_value = 0;
|
||
|
|
+
|
||
|
|
+ if (result == NULL) {
|
||
|
|
+ ERROR("Invalid argument");
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ret = util_version_compare(first, second, &diff_value);
|
||
|
|
+ if (ret != 0) {
|
||
|
|
+ return ret;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ *result = (diff_value >= 0);
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
diff --git a/src/utils/cutils/utils_version.h b/src/utils/cutils/utils_version.h
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000..f9b543b8
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/src/utils/cutils/utils_version.h
|
||
|
|
@@ -0,0 +1,36 @@
|
||
|
|
+/******************************************************************************
|
||
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2022. All rights reserved.
|
||
|
|
+ * iSulad licensed under the Mulan PSL v2.
|
||
|
|
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||
|
|
+ * You may obtain a copy of Mulan PSL v2 at:
|
||
|
|
+ * http://license.coscl.org.cn/MulanPSL2
|
||
|
|
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
|
||
|
|
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
|
||
|
|
+ * PURPOSE.
|
||
|
|
+ * See the Mulan PSL v2 for more details.
|
||
|
|
+ * Author: liuxu
|
||
|
|
+ * Create: 2024-4-7
|
||
|
|
+ * Description: provide version functions
|
||
|
|
+ ********************************************************************************/
|
||
|
|
+
|
||
|
|
+#ifndef UTILS_CUTILS_UTILS_VERSION_H
|
||
|
|
+#define UTILS_CUTILS_UTILS_VERSION_H
|
||
|
|
+
|
||
|
|
+#include <stdbool.h>
|
||
|
|
+#include <stddef.h>
|
||
|
|
+#include <stdint.h>
|
||
|
|
+#include <sys/types.h>
|
||
|
|
+
|
||
|
|
+#ifdef __cplusplus
|
||
|
|
+extern "C" {
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+int util_version_compare(const char *first, const char *second, int *diff_value);
|
||
|
|
+int util_version_greater_than(const char *first, const char *second, bool *result);
|
||
|
|
+int util_version_greater_than_or_equal_to(const char *first, const char *second, bool *result);
|
||
|
|
+
|
||
|
|
+#ifdef __cplusplus
|
||
|
|
+}
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+#endif // UTILS_CUTILS_UTILS_VERSION_H
|
||
|
|
\ No newline at end of file
|
||
|
|
--
|
||
|
|
2.34.1
|
||
|
|
|