diff options
author | CoprDistGit <infra@openeuler.org> | 2024-09-03 03:24:28 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2024-09-03 03:24:28 +0000 |
commit | e45819fcb4a96649a4030db7684f140d5ca46735 (patch) | |
tree | 544dac3e30a0448eabdc50add41aa3a18982d9f1 /0066-cdi-support-modules-version-spec-spec_dirs-device.patch | |
parent | 1a71e3afebb4b43be63949dcc8e882fe7643f13b (diff) |
automatic import of iSuladopeneuler24.03_LTS
Diffstat (limited to '0066-cdi-support-modules-version-spec-spec_dirs-device.patch')
-rw-r--r-- | 0066-cdi-support-modules-version-spec-spec_dirs-device.patch | 1254 |
1 files changed, 1254 insertions, 0 deletions
diff --git a/0066-cdi-support-modules-version-spec-spec_dirs-device.patch b/0066-cdi-support-modules-version-spec-spec_dirs-device.patch new file mode 100644 index 0000000..6aff31b --- /dev/null +++ b/0066-cdi-support-modules-version-spec-spec_dirs-device.patch @@ -0,0 +1,1254 @@ +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 + |