1022 lines
30 KiB
C
1022 lines
30 KiB
C
|
|
/******************************************************************************
|
||
|
|
* Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved.
|
||
|
|
* clibcni licensed under the Mulan PSL v1.
|
||
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v1.
|
||
|
|
* You may obtain a copy of Mulan PSL v1 at:
|
||
|
|
* http://license.coscl.org.cn/MulanPSL
|
||
|
|
* 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 v1 for more details.
|
||
|
|
* Author: tanyifeng
|
||
|
|
* Create: 2019-04-25
|
||
|
|
* Description: provide cni api functions
|
||
|
|
********************************************************************************/
|
||
|
|
#ifndef _GNU_SOURCE
|
||
|
|
#define _GNU_SOURCE
|
||
|
|
#endif
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <limits.h>
|
||
|
|
|
||
|
|
#include "api.h"
|
||
|
|
|
||
|
|
#include "log.h"
|
||
|
|
#include "invoke_errno.h"
|
||
|
|
#include "current.h"
|
||
|
|
#include "conf.h"
|
||
|
|
#include "args.h"
|
||
|
|
#include "tools.h"
|
||
|
|
#include "exec.h"
|
||
|
|
#include "utils.h"
|
||
|
|
#include "types.h"
|
||
|
|
|
||
|
|
static int add_network_list(const struct network_config_list *list, const struct runtime_conf *rc,
|
||
|
|
const char * const *paths, size_t paths_len, struct result **pret, char **err);
|
||
|
|
|
||
|
|
static int del_network_list(const struct network_config_list *list, const struct runtime_conf *rc,
|
||
|
|
const char * const *paths, size_t paths_len, char **err);
|
||
|
|
|
||
|
|
static int add_network(const struct network_config *net, const struct runtime_conf *rc, const char * const *paths,
|
||
|
|
size_t paths_len, struct result **add_result, char **err);
|
||
|
|
|
||
|
|
static int del_network(const struct network_config *net, const struct runtime_conf *rc, const char * const *paths,
|
||
|
|
size_t paths_len, char **err);
|
||
|
|
|
||
|
|
static int args(const char *action, const struct runtime_conf *rc, const char * const *paths, size_t paths_len,
|
||
|
|
struct cni_args **cargs, char **err);
|
||
|
|
|
||
|
|
static int copy_cni_port_mapping(port_mapping *dst, const struct cni_port_mapping *src)
|
||
|
|
{
|
||
|
|
bool invalid_arg = (dst == NULL || src == NULL);
|
||
|
|
if (invalid_arg) {
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
if (src->protocol != NULL) {
|
||
|
|
dst->protocol = util_strdup_s(src->protocol);
|
||
|
|
}
|
||
|
|
if (src->host_ip != NULL) {
|
||
|
|
dst->host_ip = util_strdup_s(src->host_ip);
|
||
|
|
}
|
||
|
|
dst->container_port = src->container_port;
|
||
|
|
dst->host_port = src->host_port;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int inject_port_mappings(const struct runtime_conf *rt, net_conf_runtime_config *rt_config, char **err)
|
||
|
|
{
|
||
|
|
size_t j = 0;
|
||
|
|
|
||
|
|
if (rt_config->port_mappings != NULL) {
|
||
|
|
for (j = 0; j < rt_config->port_mappings_len; j++) {
|
||
|
|
free_port_mapping(rt_config->port_mappings[j]);
|
||
|
|
rt_config->port_mappings[j] = NULL;
|
||
|
|
}
|
||
|
|
free(rt_config->port_mappings);
|
||
|
|
rt_config->port_mappings = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (rt->p_mapping_len > (SIZE_MAX / sizeof(port_mapping *))) {
|
||
|
|
*err = util_strdup_s("Too many mapping");
|
||
|
|
ERROR("Too many mapping");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
rt_config->port_mappings = util_common_calloc_s(sizeof(port_mapping *) * (rt->p_mapping_len));
|
||
|
|
if (rt_config->port_mappings == NULL) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
ERROR("Out of memory");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
for (j = 0; j < rt->p_mapping_len; j++) {
|
||
|
|
rt_config->port_mappings[j] = util_common_calloc_s(sizeof(port_mapping));
|
||
|
|
if (rt_config->port_mappings[j] == NULL) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
ERROR("Out of memory");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
(rt_config->port_mappings_len)++;
|
||
|
|
if (copy_cni_port_mapping(rt_config->port_mappings[j], rt->p_mapping[j]) != 0) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
ERROR("Out of memory");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int inject_runtime_config_items(const struct network_config *orig, const struct runtime_conf *rt,
|
||
|
|
net_conf_runtime_config **rt_config, bool *inserted, char **err)
|
||
|
|
{
|
||
|
|
char *work = NULL;
|
||
|
|
bool value = false;
|
||
|
|
int ret = -1;
|
||
|
|
size_t i = 0;
|
||
|
|
|
||
|
|
*rt_config = util_common_calloc_s(sizeof(net_conf_runtime_config));
|
||
|
|
if (*rt_config == NULL) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
ERROR("Out of memory");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
for (i = 0; i < orig->network->capabilities->len; i++) {
|
||
|
|
work = orig->network->capabilities->keys[i];
|
||
|
|
value = orig->network->capabilities->values[i];
|
||
|
|
if (!value || work == NULL) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (strcmp(work, "portMappings") == 0 && rt->p_mapping_len > 0) {
|
||
|
|
if (inject_port_mappings(rt, *rt_config, err) != 0) {
|
||
|
|
ERROR("Inject port mappings failed");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
*inserted = true;
|
||
|
|
}
|
||
|
|
/* new capabilities add here */
|
||
|
|
}
|
||
|
|
ret = 0;
|
||
|
|
free_out:
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int do_generate_net_conf_json(const struct network_config *orig, char **result, char **err)
|
||
|
|
{
|
||
|
|
struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
|
||
|
|
parser_error jerr = NULL;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
/* generate new json str for injected config */
|
||
|
|
*result = net_conf_generate_json(orig->network, &ctx, &jerr);
|
||
|
|
if (*result == NULL) {
|
||
|
|
if (asprintf(err, "generate json failed: %s", jerr) < 0) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
ERROR("Out of memory");
|
||
|
|
}
|
||
|
|
ERROR("Generate json: %s", jerr);
|
||
|
|
ret = -1;
|
||
|
|
goto out;
|
||
|
|
}
|
||
|
|
|
||
|
|
out:
|
||
|
|
free(jerr);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline bool check_inject_runtime_config_args(const struct network_config *orig, const struct runtime_conf *rt,
|
||
|
|
char * const *result, char * const *err)
|
||
|
|
{
|
||
|
|
return (orig == NULL || rt == NULL || result == NULL || err == NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int inject_runtime_config(const struct network_config *orig, const struct runtime_conf *rt, char **result,
|
||
|
|
char **err)
|
||
|
|
{
|
||
|
|
bool insert_rt_config = false;
|
||
|
|
int ret = -1;
|
||
|
|
net_conf_runtime_config *rt_config = NULL;
|
||
|
|
net_conf_runtime_config *save_conf = NULL;
|
||
|
|
|
||
|
|
if (check_inject_runtime_config_args(orig, rt, result, err)) {
|
||
|
|
ERROR("Invalid arguments");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (orig->network == NULL || orig->network->capabilities == NULL) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
save_conf = orig->network->runtime_config;
|
||
|
|
|
||
|
|
ret = inject_runtime_config_items(orig, rt, &rt_config, &insert_rt_config, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("inject runtime config failed: %s", *err != NULL ? *err : "");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!insert_rt_config) {
|
||
|
|
goto generate_result;
|
||
|
|
}
|
||
|
|
|
||
|
|
orig->network->runtime_config = rt_config;
|
||
|
|
|
||
|
|
generate_result:
|
||
|
|
ret = do_generate_net_conf_json(orig, result, err);
|
||
|
|
|
||
|
|
free_out:
|
||
|
|
orig->network->runtime_config = save_conf;
|
||
|
|
free_net_conf_runtime_config(rt_config);
|
||
|
|
if (ret != 0) {
|
||
|
|
free(*result);
|
||
|
|
*result = NULL;
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int do_inject_prev_result(const struct result *prev_result, net_conf *work, char **err)
|
||
|
|
{
|
||
|
|
if (prev_result == NULL) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
free_result_curr(work->prev_result);
|
||
|
|
work->prev_result = result_curr_to_json_result(prev_result, err);
|
||
|
|
if (work->prev_result == NULL) {
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline bool check_build_one_config(const struct network_config_list *list, const struct network_config *orig,
|
||
|
|
const struct runtime_conf *rt, char * const *result, char * const *err)
|
||
|
|
{
|
||
|
|
return (list == NULL || orig == NULL || rt == NULL || result == NULL || err == NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int build_one_config(const struct network_config_list *list, struct network_config *orig,
|
||
|
|
const struct result *prev_result, const struct runtime_conf *rt, char **result, char **err)
|
||
|
|
{
|
||
|
|
int ret = -1;
|
||
|
|
net_conf *work = NULL;
|
||
|
|
|
||
|
|
if (check_build_one_config(list, orig, rt, result, err)) {
|
||
|
|
ERROR("Invalid arguments");
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
work = orig->network;
|
||
|
|
free(work->name);
|
||
|
|
work->name = util_strdup_s(list->list->name);
|
||
|
|
free(work->cni_version);
|
||
|
|
work->cni_version = util_strdup_s(list->list->cni_version);
|
||
|
|
|
||
|
|
if (do_inject_prev_result(prev_result, work, err) != 0) {
|
||
|
|
ERROR("Inject pre result failed: %s", *err != NULL ? *err : "");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (inject_runtime_config(orig, rt, result, err) != 0) {
|
||
|
|
ERROR("Inject runtime config failed: %s", *err != NULL ? *err : "");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = 0;
|
||
|
|
free_out:
|
||
|
|
if (ret != 0 && *err == NULL) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int do_check_generate_net_conf_json(char **full_conf_bytes, struct network_config *pnet, char **err)
|
||
|
|
{
|
||
|
|
struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
|
||
|
|
parser_error serr = NULL;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
if (*full_conf_bytes != NULL) {
|
||
|
|
pnet->bytes = *full_conf_bytes;
|
||
|
|
*full_conf_bytes = NULL;
|
||
|
|
} else {
|
||
|
|
pnet->bytes = net_conf_generate_json(pnet->network, &ctx, &serr);
|
||
|
|
if (pnet->bytes == NULL) {
|
||
|
|
if (asprintf(err, "Generate json failed: %s", serr) < 0) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
}
|
||
|
|
ERROR("Generate json: %s", serr);
|
||
|
|
ret = -1;
|
||
|
|
goto out;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
out:
|
||
|
|
free(serr);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int run_cni_plugin(const struct network_config_list *list, size_t i, const char *operator,
|
||
|
|
const struct runtime_conf *rc, const char * const *paths, size_t paths_len,
|
||
|
|
struct result **pret, char **err)
|
||
|
|
{
|
||
|
|
int ret = -1;
|
||
|
|
struct network_config net = { 0 };
|
||
|
|
char *plugin_path = NULL;
|
||
|
|
struct cni_args *cargs = NULL;
|
||
|
|
char *full_conf_bytes = NULL;
|
||
|
|
struct result *tmp_result = NULL;
|
||
|
|
int save_errno = 0;
|
||
|
|
|
||
|
|
net.network = list->list->plugins[i];
|
||
|
|
if (net.network == NULL) {
|
||
|
|
*err = util_strdup_s("Empty network");
|
||
|
|
ERROR("Empty network");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = find_in_path(net.network->type, paths, paths_len, &plugin_path, &save_errno);
|
||
|
|
if (ret != 0) {
|
||
|
|
if (asprintf(err, "find plugin: \"%s\" failed: %s", net.network->type, get_invoke_err_msg(save_errno)) < 0) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
}
|
||
|
|
ERROR("find plugin: \"%s\" failed: %s", net.network->type, get_invoke_err_msg(save_errno));
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
tmp_result = pret != NULL ? *pret : NULL;
|
||
|
|
ret = build_one_config(list, &net, tmp_result, rc, &full_conf_bytes, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("build config failed: %s", *err != NULL ? *err : "");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = do_check_generate_net_conf_json(&full_conf_bytes, &net, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("check gengerate net config failed: %s", *err != NULL ? *err : "");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = args(operator, rc, paths, paths_len, &cargs, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("get plugin arguments failed: %s", *err != NULL ? *err : "");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (pret == NULL) {
|
||
|
|
ret = exec_plugin_without_result(plugin_path, net.bytes, cargs, err);
|
||
|
|
} else {
|
||
|
|
free_result(*pret);
|
||
|
|
*pret = NULL;
|
||
|
|
ret = exec_plugin_with_result(plugin_path, net.bytes, cargs, pret, err);
|
||
|
|
}
|
||
|
|
free_out:
|
||
|
|
free_cni_args(cargs);
|
||
|
|
free(plugin_path);
|
||
|
|
free(net.bytes);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline bool check_add_network_list_args(const struct network_config_list *list, const struct runtime_conf *rc,
|
||
|
|
struct result * const *pret, char * const *err)
|
||
|
|
{
|
||
|
|
return (list == NULL || list->list == NULL || rc == NULL || pret == NULL || err == NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int add_network_list(const struct network_config_list *list, const struct runtime_conf *rc,
|
||
|
|
const char * const *paths, size_t paths_len, struct result **pret, char **err)
|
||
|
|
{
|
||
|
|
int ret = -1;
|
||
|
|
size_t i = 0;
|
||
|
|
struct result *prev_result = NULL;
|
||
|
|
|
||
|
|
if (check_add_network_list_args(list, rc, pret, err)) {
|
||
|
|
ERROR("Empty arguments");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (i = 0; i < list->list->plugins_len; i++) {
|
||
|
|
ret = run_cni_plugin(list, i, "ADD", rc, paths, paths_len, &prev_result, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("Run ADD cni failed: %s", *err != NULL ? *err : "");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
*pret = prev_result;
|
||
|
|
ret = 0;
|
||
|
|
free_out:
|
||
|
|
if (ret != 0) {
|
||
|
|
free_result(prev_result);
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline bool check_del_network_list_args(const struct network_config_list *list, const struct runtime_conf *rc,
|
||
|
|
char * const *err)
|
||
|
|
{
|
||
|
|
return (list == NULL || list->list == NULL || rc == NULL || err == NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int del_network_list(const struct network_config_list *list, const struct runtime_conf *rc,
|
||
|
|
const char * const *paths, size_t paths_len, char **err)
|
||
|
|
{
|
||
|
|
size_t i = 0;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
if (check_del_network_list_args(list, rc, err)) {
|
||
|
|
ERROR("Empty arguments");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (i = list->list->plugins_len; i > 0; i--) {
|
||
|
|
ret = run_cni_plugin(list, (i - 1), "DEL", rc, paths, paths_len, NULL, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("Run DEL cni failed: %s", *err != NULL ? *err : "");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
free_out:
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline bool check_add_network_args(const struct network_config *net, const struct runtime_conf *rc,
|
||
|
|
char * const *err)
|
||
|
|
{
|
||
|
|
return (net == NULL || rc == NULL || err == NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int add_network(const struct network_config *net, const struct runtime_conf *rc, const char * const *paths,
|
||
|
|
size_t paths_len, struct result **add_result, char **err)
|
||
|
|
{
|
||
|
|
int ret = 0;
|
||
|
|
char *plugin_path = NULL;
|
||
|
|
char *net_bytes = NULL;
|
||
|
|
struct cni_args *cargs = NULL;
|
||
|
|
int save_errno = 0;
|
||
|
|
|
||
|
|
if (check_add_network_args(net, rc, err)) {
|
||
|
|
ERROR("Empty arguments");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
ret = find_in_path(net->network->type, paths, paths_len, &plugin_path, &save_errno);
|
||
|
|
if (ret != 0) {
|
||
|
|
if (asprintf(err, "find plugin: \"%s\" failed: %s", net->network->type, get_invoke_err_msg(save_errno)) < 0) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
}
|
||
|
|
ERROR("find plugin: \"%s\" failed: %s", net->network->type, get_invoke_err_msg(save_errno));
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = inject_runtime_config(net, rc, &net_bytes, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("Inject runtime config: %s", *err != NULL ? *err : "");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = args("ADD", rc, paths, paths_len, &cargs, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("Get ADD cni arguments: %s", *err != NULL ? *err : "");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = exec_plugin_with_result(plugin_path, net_bytes, cargs, add_result, err);
|
||
|
|
free_out:
|
||
|
|
free(plugin_path);
|
||
|
|
free(net_bytes);
|
||
|
|
free_cni_args(cargs);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline bool check_del_network_args(const struct network_config *net, const struct runtime_conf *rc,
|
||
|
|
char * const *err)
|
||
|
|
{
|
||
|
|
return (net == NULL || net->network == NULL || rc == NULL || err == NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int del_network(const struct network_config *net, const struct runtime_conf *rc, const char * const *paths,
|
||
|
|
size_t paths_len, char **err)
|
||
|
|
{
|
||
|
|
int ret = 0;
|
||
|
|
char *plugin_path = NULL;
|
||
|
|
char *net_bytes = NULL;
|
||
|
|
struct cni_args *cargs = NULL;
|
||
|
|
int save_errno = 0;
|
||
|
|
|
||
|
|
if (check_del_network_args(net, rc, err)) {
|
||
|
|
ERROR("Empty arguments");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
ret = find_in_path(net->network->type, paths, paths_len, &plugin_path, &save_errno);
|
||
|
|
if (ret != 0) {
|
||
|
|
if (asprintf(err, "find plugin: \"%s\" failed: %s", net->network->type, get_invoke_err_msg(save_errno)) < 0) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
}
|
||
|
|
ERROR("find plugin: \"%s\" failed: %s", net->network->type, get_invoke_err_msg(save_errno));
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = inject_runtime_config(net, rc, &net_bytes, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("Inject runtime config: %s", *err != NULL ? *err : "");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = args("DEL", rc, paths, paths_len, &cargs, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("Get DEL cni arguments: %s", *err != NULL ? *err : "");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = exec_plugin_without_result(plugin_path, net_bytes, cargs, err);
|
||
|
|
free_out:
|
||
|
|
free(plugin_path);
|
||
|
|
free(net_bytes);
|
||
|
|
free_cni_args(cargs);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int do_copy_plugin_args(const struct runtime_conf *rc, struct cni_args **cargs)
|
||
|
|
{
|
||
|
|
size_t i = 0;
|
||
|
|
|
||
|
|
if (rc->args_len == 0) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (rc->args_len > (INT_MAX / sizeof(char *)) / 2) {
|
||
|
|
ERROR("Large arguments");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
(*cargs)->plugin_args = util_common_calloc_s((rc->args_len) * sizeof(char *) * 2);
|
||
|
|
if ((*cargs)->plugin_args == NULL) {
|
||
|
|
ERROR("Out of memory");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
for (i = 0; i < rc->args_len; i++) {
|
||
|
|
(*cargs)->plugin_args[i][0] = util_strdup_s(rc->args[i][0]);
|
||
|
|
(*cargs)->plugin_args[i][1] = util_strdup_s(rc->args[i][1]);
|
||
|
|
(*cargs)->plugin_args_len = (i + 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int copy_args(const struct runtime_conf *rc, struct cni_args **cargs)
|
||
|
|
{
|
||
|
|
if (rc->container_id != NULL) {
|
||
|
|
(*cargs)->container_id = util_strdup_s(rc->container_id);
|
||
|
|
}
|
||
|
|
if (rc->netns != NULL) {
|
||
|
|
(*cargs)->netns = util_strdup_s(rc->netns);
|
||
|
|
}
|
||
|
|
if (rc->ifname != NULL) {
|
||
|
|
(*cargs)->ifname = util_strdup_s(rc->ifname);
|
||
|
|
}
|
||
|
|
|
||
|
|
return do_copy_plugin_args(rc, cargs);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int do_copy_args_paths(const char * const *paths, size_t paths_len, struct cni_args **cargs)
|
||
|
|
{
|
||
|
|
if (paths == NULL) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (paths_len == 0) {
|
||
|
|
(*cargs)->path = util_strdup_s("");
|
||
|
|
} else {
|
||
|
|
(*cargs)->path = cni_util_string_join(":", paths, paths_len);
|
||
|
|
if ((*cargs)->path == NULL) {
|
||
|
|
ERROR("Out of memory");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline bool check_args_args(const struct runtime_conf *rc, struct cni_args * const *cargs, char * const *err)
|
||
|
|
{
|
||
|
|
return (rc == NULL || cargs == NULL || err == NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int args(const char *action, const struct runtime_conf *rc, const char * const *paths, size_t paths_len,
|
||
|
|
struct cni_args **cargs, char **err)
|
||
|
|
{
|
||
|
|
int ret = -1;
|
||
|
|
|
||
|
|
if (check_args_args(rc, cargs, err)) {
|
||
|
|
ERROR("Empty arguments");
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
*cargs = util_common_calloc_s(sizeof(struct cni_args));
|
||
|
|
if (*cargs == NULL) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
ERROR("Out of memory");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
if (action != NULL) {
|
||
|
|
(*cargs)->command = util_strdup_s(action);
|
||
|
|
}
|
||
|
|
if (do_copy_args_paths(paths, paths_len, cargs) != 0) {
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
ret = copy_args(rc, cargs);
|
||
|
|
|
||
|
|
free_out:
|
||
|
|
if (ret != 0) {
|
||
|
|
free_cni_args(*cargs);
|
||
|
|
*cargs = NULL;
|
||
|
|
if (*err == NULL) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
void free_cni_port_mapping(struct cni_port_mapping *val)
|
||
|
|
{
|
||
|
|
if (val != NULL) {
|
||
|
|
free(val->protocol);
|
||
|
|
free(val->host_ip);
|
||
|
|
free(val);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void free_cni_network_conf(struct cni_network_conf *val)
|
||
|
|
{
|
||
|
|
if (val != NULL) {
|
||
|
|
free(val->name);
|
||
|
|
free(val->type);
|
||
|
|
free(val->bytes);
|
||
|
|
free(val);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void free_cni_network_list_conf(struct cni_network_list_conf *val)
|
||
|
|
{
|
||
|
|
if (val != NULL) {
|
||
|
|
free(val->bytes);
|
||
|
|
free(val->name);
|
||
|
|
free(val->first_plugin_name);
|
||
|
|
free(val->first_plugin_type);
|
||
|
|
free(val);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void free_runtime_conf(struct runtime_conf *rc)
|
||
|
|
{
|
||
|
|
size_t i = 0;
|
||
|
|
|
||
|
|
if (rc == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
free(rc->container_id);
|
||
|
|
rc->container_id = NULL;
|
||
|
|
free(rc->netns);
|
||
|
|
rc->netns = NULL;
|
||
|
|
free(rc->ifname);
|
||
|
|
rc->ifname = NULL;
|
||
|
|
|
||
|
|
for (i = 0; i < rc->args_len; i++) {
|
||
|
|
free(rc->args[i][0]);
|
||
|
|
free(rc->args[i][1]);
|
||
|
|
}
|
||
|
|
free(rc->args);
|
||
|
|
rc->args = NULL;
|
||
|
|
|
||
|
|
for (i = 0; i < rc->p_mapping_len; i++) {
|
||
|
|
free_cni_port_mapping(rc->p_mapping[i]);
|
||
|
|
}
|
||
|
|
free(rc->p_mapping);
|
||
|
|
rc->p_mapping = NULL;
|
||
|
|
free(rc);
|
||
|
|
}
|
||
|
|
|
||
|
|
int cni_add_network_list(const char *net_list_conf_str, const struct runtime_conf *rc, char **paths,
|
||
|
|
struct result **pret, char **err)
|
||
|
|
{
|
||
|
|
struct network_config_list *list = NULL;
|
||
|
|
int ret = 0;
|
||
|
|
size_t len = 0;
|
||
|
|
|
||
|
|
if (err == NULL) {
|
||
|
|
ERROR("Empty arguments");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
if (net_list_conf_str == NULL) {
|
||
|
|
*err = util_strdup_s("Empty net list conf argument");
|
||
|
|
ERROR("Empty net list conf argument");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = conflist_from_bytes(net_list_conf_str, &list, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("Parse conf list failed: %s", *err != NULL ? *err : "");
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
len = util_array_len((const char * const *)paths);
|
||
|
|
ret = add_network_list(list, rc, (const char * const *)paths, len, pret, err);
|
||
|
|
|
||
|
|
DEBUG("Add network list return with: %d", ret);
|
||
|
|
free_network_config_list(list);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int cni_add_network(const char *net_conf_str, const struct runtime_conf *rc, char **paths, struct result **add_result,
|
||
|
|
char **err)
|
||
|
|
{
|
||
|
|
struct network_config *net = NULL;
|
||
|
|
int ret = 0;
|
||
|
|
size_t len = 0;
|
||
|
|
|
||
|
|
if (err == NULL) {
|
||
|
|
ERROR("Empty err");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
if (net_conf_str == NULL) {
|
||
|
|
*err = util_strdup_s("Empty net conf argument");
|
||
|
|
ERROR("Empty net conf argument");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = conf_from_bytes(net_conf_str, &net, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("Parse conf failed: %s", *err != NULL ? *err : "");
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
len = util_array_len((const char * const *)paths);
|
||
|
|
ret = add_network(net, rc, (const char * const *)paths, len, add_result, err);
|
||
|
|
free_network_config(net);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int cni_del_network_list(const char *net_list_conf_str, const struct runtime_conf *rc, char **paths, char **err)
|
||
|
|
{
|
||
|
|
struct network_config_list *list = NULL;
|
||
|
|
int ret = 0;
|
||
|
|
size_t len = 0;
|
||
|
|
|
||
|
|
if (err == NULL) {
|
||
|
|
ERROR("Empty err");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
if (net_list_conf_str == NULL) {
|
||
|
|
*err = util_strdup_s("Empty net list conf argument");
|
||
|
|
ERROR("Empty net list conf argument");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = conflist_from_bytes(net_list_conf_str, &list, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("Parse conf list failed: %s", *err != NULL ? *err : "");
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
len = util_array_len((const char * const *)paths);
|
||
|
|
ret = del_network_list(list, rc, (const char * const *)paths, len, err);
|
||
|
|
|
||
|
|
DEBUG("Delete network list return with: %d", ret);
|
||
|
|
free_network_config_list(list);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int cni_del_network(const char *net_conf_str, const struct runtime_conf *rc, char **paths, char **err)
|
||
|
|
{
|
||
|
|
struct network_config *net = NULL;
|
||
|
|
int ret = 0;
|
||
|
|
size_t len = 0;
|
||
|
|
|
||
|
|
if (err == NULL) {
|
||
|
|
ERROR("Empty err");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
if (net_conf_str == NULL) {
|
||
|
|
*err = util_strdup_s("Empty net conf argument");
|
||
|
|
ERROR("Empty net conf argument");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = conf_from_bytes(net_conf_str, &net, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("Parse conf failed: %s", *err != NULL ? *err : "");
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
len = util_array_len((const char * const *)paths);
|
||
|
|
ret = del_network(net, rc, (const char * const *)paths, len, err);
|
||
|
|
free_network_config(net);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int cni_get_version_info(const char *plugin_type, char **paths, struct plugin_info **pinfo, char **err)
|
||
|
|
{
|
||
|
|
int ret = 0;
|
||
|
|
char *plugin_path = NULL;
|
||
|
|
size_t len;
|
||
|
|
int save_errno = 0;
|
||
|
|
|
||
|
|
if (err == NULL) {
|
||
|
|
ERROR("Empty err");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
len = util_array_len((const char * const *)paths);
|
||
|
|
ret = find_in_path(plugin_type, (const char * const *)paths, len, &plugin_path, &save_errno);
|
||
|
|
if (ret != 0) {
|
||
|
|
if (asprintf(err, "find plugin: \"%s\" failed: %s", plugin_type, get_invoke_err_msg(save_errno)) < 0) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
}
|
||
|
|
ERROR("find plugin: \"%s\" failed: %s", plugin_type, get_invoke_err_msg(save_errno));
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = raw_get_version_info(plugin_path, pinfo, err);
|
||
|
|
free(plugin_path);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int cni_conf_files(const char *dir, const char **extensions, size_t ext_len, char ***result, char **err)
|
||
|
|
{
|
||
|
|
if (err == NULL) {
|
||
|
|
ERROR("Empty err");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
return conf_files(dir, extensions, ext_len, result, err);
|
||
|
|
}
|
||
|
|
|
||
|
|
int cni_conf_from_file(const char *filename, struct cni_network_conf **config, char **err)
|
||
|
|
{
|
||
|
|
int ret = 0;
|
||
|
|
struct network_config *netconf = NULL;
|
||
|
|
|
||
|
|
if (err == NULL) {
|
||
|
|
ERROR("Empty err");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
ret = conf_from_file(filename, &netconf, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
ERROR("Parse conf file: %s failed: %s", filename, *err != NULL ? *err : "");
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
*config = util_common_calloc_s(sizeof(struct cni_network_conf));
|
||
|
|
if (*config == NULL) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
ret = -1;
|
||
|
|
ERROR("Out of memory");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (netconf != NULL && netconf->network != NULL) {
|
||
|
|
(*config)->type = netconf->network->type ? util_strdup_s(netconf->network->type) : NULL;
|
||
|
|
(*config)->name = netconf->network->name ? util_strdup_s(netconf->network->name) : NULL;
|
||
|
|
}
|
||
|
|
if (netconf != NULL) {
|
||
|
|
(*config)->bytes = netconf->bytes;
|
||
|
|
netconf->bytes = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = 0;
|
||
|
|
|
||
|
|
free_out:
|
||
|
|
free_network_config(netconf);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void json_obj_to_cni_list_conf(struct network_config_list *src, struct cni_network_list_conf *list)
|
||
|
|
{
|
||
|
|
if (src == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
list->bytes = src->bytes;
|
||
|
|
src->bytes = NULL;
|
||
|
|
if (src->list != NULL) {
|
||
|
|
list->name = src->list->name ? util_strdup_s(src->list->name) : NULL;
|
||
|
|
list->plugin_len = src->list->plugins_len;
|
||
|
|
if (src->list->plugins_len > 0 && src->list->plugins != NULL && src->list->plugins[0] != NULL) {
|
||
|
|
list->first_plugin_name = src->list->plugins[0]->name != NULL ?
|
||
|
|
util_strdup_s(src->list->plugins[0]->name) : NULL;
|
||
|
|
list->first_plugin_type = src->list->plugins[0]->type != NULL ?
|
||
|
|
util_strdup_s(src->list->plugins[0]->type) : NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cni_conflist_from_bytes(const char *bytes, struct cni_network_list_conf **list, char **err)
|
||
|
|
{
|
||
|
|
struct network_config_list *tmp_net_conf_list = NULL;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
if (err == NULL) {
|
||
|
|
ERROR("Empty err");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
ret = conflist_from_bytes(bytes, &tmp_net_conf_list, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
*list = util_common_calloc_s(sizeof(struct cni_network_list_conf));
|
||
|
|
if (*list == NULL) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
ret = -1;
|
||
|
|
ERROR("Out of memory");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
json_obj_to_cni_list_conf(tmp_net_conf_list, *list);
|
||
|
|
|
||
|
|
ret = 0;
|
||
|
|
free_out:
|
||
|
|
free_network_config_list(tmp_net_conf_list);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int cni_conflist_from_file(const char *filename, struct cni_network_list_conf **list, char **err)
|
||
|
|
{
|
||
|
|
struct network_config_list *tmp_net_conf_list = NULL;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
if (err == NULL) {
|
||
|
|
ERROR("Empty err");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
ret = conflist_from_file(filename, &tmp_net_conf_list, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
*list = util_common_calloc_s(sizeof(struct cni_network_list_conf));
|
||
|
|
if (*list == NULL) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
ret = -1;
|
||
|
|
ERROR("Out of memory");
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
json_obj_to_cni_list_conf(tmp_net_conf_list, *list);
|
||
|
|
|
||
|
|
ret = 0;
|
||
|
|
free_out:
|
||
|
|
free_network_config_list(tmp_net_conf_list);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline bool check_cni_conflist_from_conf_args(const struct cni_network_conf *cni_conf,
|
||
|
|
struct cni_network_list_conf * const *cni_conf_list)
|
||
|
|
{
|
||
|
|
return (cni_conf == NULL || cni_conf_list == NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
int cni_conflist_from_conf(const struct cni_network_conf *cni_conf, struct cni_network_list_conf **cni_conf_list,
|
||
|
|
char **err)
|
||
|
|
{
|
||
|
|
struct network_config *net = NULL;
|
||
|
|
struct network_config_list *net_list = NULL;
|
||
|
|
int ret = 0;
|
||
|
|
bool invalid_arg = false;
|
||
|
|
|
||
|
|
if (err == NULL) {
|
||
|
|
ERROR("Empty err");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
invalid_arg = check_cni_conflist_from_conf_args(cni_conf, cni_conf_list);
|
||
|
|
if (invalid_arg) {
|
||
|
|
*err = util_strdup_s("Empty cni conf or conflist argument");
|
||
|
|
ERROR("Empty cni conf or conflist argument");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = conf_from_bytes(cni_conf->bytes, &net, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = conflist_from_conf(net, &net_list, err);
|
||
|
|
if (ret != 0) {
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
*cni_conf_list = util_common_calloc_s(sizeof(struct cni_network_list_conf));
|
||
|
|
if (*cni_conf_list == NULL) {
|
||
|
|
*err = util_strdup_s("Out of memory");
|
||
|
|
ERROR("Out of memory");
|
||
|
|
ret = -1;
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
json_obj_to_cni_list_conf(net_list, *cni_conf_list);
|
||
|
|
ret = 0;
|
||
|
|
|
||
|
|
free_out:
|
||
|
|
if (net != NULL) {
|
||
|
|
free_network_config(net);
|
||
|
|
}
|
||
|
|
free_network_config_list(net_list);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int cni_log_init(const char *driver, const char *file, const char *priority)
|
||
|
|
{
|
||
|
|
struct clibcni_log_config conf = { 0 };
|
||
|
|
|
||
|
|
conf.name = "clibcni";
|
||
|
|
conf.driver = driver;
|
||
|
|
conf.file = file;
|
||
|
|
conf.priority = priority;
|
||
|
|
return clibcni_log_enable(&conf);
|
||
|
|
}
|
||
|
|
|
||
|
|
void cni_set_log_prefix(const char *prefix)
|
||
|
|
{
|
||
|
|
clibcni_set_log_prefix(prefix);
|
||
|
|
}
|
||
|
|
|
||
|
|
void cni_free_log_prefix()
|
||
|
|
{
|
||
|
|
clibcni_free_log_prefix();
|
||
|
|
}
|
||
|
|
|